├── .github └── workflows │ ├── compile.yml │ └── package.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── addons └── sourcemod │ ├── configs │ └── textstore │ │ ├── crafting.cfg │ │ ├── examples │ │ └── tf2-weapons │ │ │ ├── crafting.cfg │ │ │ └── store.cfg │ │ └── store.cfg │ └── scripting │ ├── include │ └── textstore.inc │ ├── textstore.sp │ ├── textstore │ ├── adminmenu.sp │ ├── crafting.sp │ ├── forwards.sp │ ├── natives.sp │ ├── stocks.sp │ ├── trading.sp │ └── unique.sp │ ├── textstore_defaults.sp │ ├── textstore_defaults │ ├── boxes.sp │ ├── chat.sp │ ├── command.sp │ ├── multi.sp │ ├── tf2 │ │ ├── ff2.sp │ │ └── items.sp │ ├── trails.sp │ ├── tvip.sp │ └── voting.sp │ ├── textstore_ftp.sp │ ├── textstore_generic.sp │ ├── textstore_mysql.sp │ ├── textstore_sqlite.sp │ └── textstore_tf2.sp └── scripts ├── date.sh ├── install.sh └── package.sh /.github/workflows/compile.yml: -------------------------------------------------------------------------------- 1 | name: Compile 2 | 3 | on: 4 | pull_request: 5 | branches: master 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v1 14 | 15 | - name: Environments 16 | run: | 17 | echo "SM_VERSION=1.11" >> $GITHUB_ENV 18 | 19 | - name: Install 20 | run: | 21 | bash scripts/install.sh 22 | 23 | - name: Compile 24 | run: | 25 | cd build/addons/sourcemod/scripting 26 | ./spcomp -E textstore.sp -o ../plugins/textstore.smx 27 | ./spcomp -E textstore_defaults.sp -o ../plugins/textstore_defaults.smx 28 | ./spcomp -E textstore_generic.sp -o ../plugins/textstore_generic.smx 29 | ./spcomp textstore_sqlite.sp -o ../plugins/textstore_sqlite.smx 30 | ./spcomp textstore_mysql.sp -o ../plugins/textstore_mysql.smx 31 | ./spcomp -E textstore_tf2.sp -o ../plugins/textstore_tf2.smx 32 | -------------------------------------------------------------------------------- /.github/workflows/package.yml: -------------------------------------------------------------------------------- 1 | name: Package 2 | 3 | on: 4 | push: 5 | branches: master 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v1 14 | 15 | - name: Environments 16 | run: | 17 | echo "SM_VERSION=1.11" >> $GITHUB_ENV 18 | 19 | - name: Install 20 | run: | 21 | bash scripts/install.sh 22 | 23 | - name: Set Version 24 | run: | 25 | bash scripts/date.sh 26 | 27 | - name: Compile 28 | run: | 29 | cd build/addons/sourcemod/scripting 30 | ./spcomp textstore.sp -o ../plugins/textstore.smx 31 | ./spcomp textstore_defaults.sp -o ../plugins/textstore_defaults.smx 32 | ./spcomp textstore_generic.sp -o ../plugins/textstore_generic.smx 33 | ./spcomp textstore_sqlite.sp -o ../plugins/textstore_sqlite.smx 34 | ./spcomp textstore_mysql.sp -o ../plugins/textstore_mysql.smx 35 | ./spcomp textstore_tf2.sp -o ../plugins/textstore_tf2.smx 36 | 37 | - name: Package 38 | run: | 39 | bash scripts/package.sh 40 | 41 | - name: Upload Artifacts 42 | uses: actions/upload-artifact@master 43 | with: 44 | name: Text-Store-${{env.DATE_VERSION}} 45 | path: ./build/package 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.dat 2 | *.exe 3 | *.smx 4 | *.inc 5 | [Cc]compiled/ 6 | [Dd]esktop.ini 7 | [Tt]humbs.db 8 | !textstore.inc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Text Store 2 | ## A store replacement driven on a subplugin based system and a text file database! 3 | 4 | ### Stable Releases 5 | Go to [Releases](https://github.com/Batfoxkid/Text-Store/releases "Releases • Batfoxkid/Text-Store") and choose out the [lastest release](https://github.com/Batfoxkid/Text-Store/releases/latest) or older versions. 6 | 7 | ### Development Releases 8 | You can clone via git or [download](https://github.com/Batfoxkid/Text-Store/archive/master.zip) for source code. Compiled binaries can be downloaded at [Actions](https://github.com/Batfoxkid/Text-Store/actions?query=workflow%3APackage+is%3Asuccess "Actions • Batfoxkid/Text-Store"). 9 | (Click on "Package" and download the "Text-Store-#" zip file.) 10 | -------------------------------------------------------------------------------- /addons/sourcemod/configs/textstore/crafting.cfg: -------------------------------------------------------------------------------- 1 | "Crafting" 2 | { 3 | "Category 1" 4 | { 5 | "Recipe 1A" 6 | { 7 | "admin" "" 8 | "cost" "0" 9 | 10 | "Item 1Aa" 11 | { 12 | "cost" "1" 13 | "consume" "1" 14 | } 15 | "Item 1Ab" 16 | { 17 | "gain" "1" 18 | } 19 | } 20 | "Recipe 1B" 21 | { 22 | "admin" "" 23 | "cost" "50" 24 | 25 | "Item 1Aa" 26 | { 27 | "cost" "1" 28 | "consume" "0" 29 | } 30 | "Item 1Ab" 31 | { 32 | "gain" "1" 33 | } 34 | } 35 | "Recipe 1C" 36 | { 37 | "admin" "" 38 | "cost" "-10" 39 | 40 | "Item 1Aa" 41 | { 42 | "cost" "5" 43 | "consume" "0" 44 | } 45 | "Item 1Ab" 46 | { 47 | "cost" "2" 48 | "consume" "1" 49 | } 50 | "Item 1Ba1Aa1" 51 | { 52 | "gain" "1" 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /addons/sourcemod/configs/textstore/examples/tf2-weapons/crafting.cfg: -------------------------------------------------------------------------------- 1 | "Crafting" 2 | { 3 | "Common Items" 4 | { 5 | "Multi-Class" 6 | { 7 | "Fabricate Reserve Shooter" 8 | { 9 | "cost" "12" 10 | 11 | "Frontier Justice" 12 | { 13 | "cost" "1" 14 | } 15 | "Reserve Shooter" 16 | { 17 | "gain" "1" 18 | } 19 | } 20 | "Fabricate Panic Attack" 21 | { 22 | "cost" "12" 23 | 24 | "Back Scatter" 25 | { 26 | "cost" "1" 27 | } 28 | "Panic Attack" 29 | { 30 | "gain" "1" 31 | } 32 | } 33 | "Fabricate Pain Train" 34 | { 35 | "cost" "2" 36 | 37 | "Sandman" 38 | { 39 | "cost" "1" 40 | } 41 | "Pain Train" 42 | { 43 | "gain" "1" 44 | } 45 | } 46 | "Fabricate Half-Zatoichi" 47 | { 48 | "cost" "6" 49 | 50 | "Eyelander" 51 | { 52 | "cost" "2" 53 | } 54 | "Half-Zatoichi" 55 | { 56 | "gain" "1" 57 | } 58 | } 59 | } 60 | "Scout" 61 | { 62 | "Fabricate Shortstop" 63 | { 64 | "cost" "6" 65 | 66 | "Force-A-Nature" 67 | { 68 | "cost" "1" 69 | } 70 | "The Shortstop" 71 | { 72 | "gain" "1" 73 | } 74 | } 75 | "Fabricate Soda Popper" 76 | { 77 | "cost" "6" 78 | 79 | "Bonk! Atomic Punch" 80 | { 81 | "cost" "1" 82 | } 83 | "Force-A-Nature" 84 | { 85 | "cost" "1" 86 | } 87 | "The Soda Popper" 88 | { 89 | "gain" "1" 90 | } 91 | } 92 | "Fabricate Baby Face's Blaster" 93 | { 94 | "cost" "6" 95 | 96 | "The Shortstop" 97 | { 98 | "cost" "2" 99 | } 100 | "Baby Face's Blaster" 101 | { 102 | "gain" "1" 103 | } 104 | } 105 | "Fabricate Back Scatter" 106 | { 107 | "cost" "6" 108 | 109 | "The Shortstop" 110 | { 111 | "cost" "2" 112 | } 113 | "Crit-a-Cola" 114 | { 115 | "cost" "1" 116 | } 117 | "Back Scatter" 118 | { 119 | "gain" "1" 120 | } 121 | } 122 | "Fabricate Crit-a-Cola" 123 | { 124 | "cost" "0" 125 | 126 | "Kritzkrieg" 127 | { 128 | "cost" "1" 129 | } 130 | "Bonk! Atomic Punch" 131 | { 132 | "cost" "1" 133 | } 134 | "Crit-a-Cola" 135 | { 136 | "gain" "1" 137 | } 138 | } 139 | "Fabricate Mad Milk" 140 | { 141 | "cost" "6" 142 | 143 | "Jarate" 144 | { 145 | "cost" "1" 146 | } 147 | "Mad Milk" 148 | { 149 | "gain" "1" 150 | } 151 | } 152 | "Fabricate Winger" 153 | { 154 | "cost" "6" 155 | 156 | "The Shortstop" 157 | { 158 | "cost" "1" 159 | } 160 | "Winger" 161 | { 162 | "gain" "1" 163 | } 164 | } 165 | "Fabricate Pretty Boy's Pocket Pistol" 166 | { 167 | "cost" "6" 168 | 169 | "Mad Milk" 170 | { 171 | "cost" "1" 172 | } 173 | "Winger" 174 | { 175 | "cost" "1" 176 | } 177 | "Pretty Boy's Pocket Pistol" 178 | { 179 | "gain" "1" 180 | } 181 | } 182 | "Fabricate Flying Guillotine" 183 | { 184 | "cost" "6" 185 | 186 | "Mad Milk" 187 | { 188 | "cost" "3" 189 | } 190 | "Flying Guillotine" 191 | { 192 | "gain" "1" 193 | } 194 | } 195 | "Fabricate Holy Mackerel" 196 | { 197 | "cost" "6" 198 | 199 | "Sandman" 200 | { 201 | "cost" "1" 202 | } 203 | "Holy Mackerel" 204 | { 205 | "gain" "1" 206 | } 207 | } 208 | "Fabricate Boston Basher" 209 | { 210 | "cost" "0" 211 | 212 | "Sandman" 213 | { 214 | "cost" "1" 215 | } 216 | "Tribalman's Shiv" 217 | { 218 | "cost" "1" 219 | } 220 | "Boston Basher" 221 | { 222 | "gain" "1" 223 | } 224 | } 225 | "Fabricate Candy Cane" 226 | { 227 | "cost" "0" 228 | 229 | "Kritzkrieg" 230 | { 231 | "cost" "1" 232 | } 233 | "Pain Train" 234 | { 235 | "cost" "1" 236 | } 237 | "Candy Cane" 238 | { 239 | "gain" "1" 240 | } 241 | } 242 | "Fabricate Sun-on-a-Stick" 243 | { 244 | "cost" "12" 245 | 246 | "Boston Basher" 247 | { 248 | "cost" "1" 249 | } 250 | "Sun-on-a-Stick" 251 | { 252 | "gain" "1" 253 | } 254 | } 255 | "Fabricate Fan O'War" 256 | { 257 | "cost" "3" 258 | 259 | "Mad Milk" 260 | { 261 | "cost" "1" 262 | } 263 | "Fan O'War" 264 | { 265 | "gain" "1" 266 | } 267 | } 268 | "Fabricate Atomizer" 269 | { 270 | "cost" "6" 271 | 272 | "Bonk! Atomic Punch" 273 | { 274 | "cost" "1" 275 | } 276 | "Sandman" 277 | { 278 | "cost" "1" 279 | } 280 | "Atomizer" 281 | { 282 | "gain" "1" 283 | } 284 | } 285 | "Fabricate Wrap Assassin" 286 | { 287 | "cost" "6" 288 | 289 | "Southern Hospitality" 290 | { 291 | "cost" "1" 292 | } 293 | "Wrap Assassin" 294 | { 295 | "gain" "1" 296 | } 297 | } 298 | } 299 | "Soldier" 300 | { 301 | "Fabricate Black Box" 302 | { 303 | "cost" "6" 304 | 305 | "Direct Hit" 306 | { 307 | "cost" "1" 308 | } 309 | "Black Box" 310 | { 311 | "gain" "1" 312 | } 313 | } 314 | "Fabricate Rocket Jumper" 315 | { 316 | "cost" "6" 317 | 318 | "Mantreads" 319 | { 320 | "cost" "3" 321 | } 322 | "Rocket Jumper" 323 | { 324 | "gain" "1" 325 | } 326 | } 327 | "Fabricate Liberty Launcher" 328 | { 329 | "cost" "12" 330 | 331 | "Black Box" 332 | { 333 | "cost" "1" 334 | } 335 | "Liberty Launcher" 336 | { 337 | "gain" "1" 338 | } 339 | } 340 | "Fabricate Cow Mangler 5000" 341 | { 342 | "cost" "6" 343 | 344 | "Black Box" 345 | { 346 | "cost" "1" 347 | } 348 | "Cow Mangler 5000" 349 | { 350 | "gain" "1" 351 | } 352 | } 353 | "Fabricate Beggar's Bazooka" 354 | { 355 | "cost" "6" 356 | 357 | "Direct Hit" 358 | { 359 | "cost" "3" 360 | } 361 | "Beggar's Bazooka" 362 | { 363 | "gain" "1" 364 | } 365 | } 366 | "Fabricate Air Strike" 367 | { 368 | "cost" "6" 369 | 370 | "Beggar's Bazooka" 371 | { 372 | "cost" "1" 373 | } 374 | "Gunboats" 375 | { 376 | "cost" "1" 377 | } 378 | "Air Strike" 379 | { 380 | "gain" "1" 381 | } 382 | } 383 | "Fabricate Battalion's Backup" 384 | { 385 | "cost" "6" 386 | 387 | "Buff Banner" 388 | { 389 | "cost" "1" 390 | } 391 | "Battalion's Backup" 392 | { 393 | "gain" "1" 394 | } 395 | } 396 | "Fabricate Mantreads" 397 | { 398 | "cost" "18" 399 | 400 | "Gunboats" 401 | { 402 | "cost" "1" 403 | } 404 | "Mantreads" 405 | { 406 | "gain" "1" 407 | } 408 | } 409 | "Fabricate Concheror" 410 | { 411 | "cost" "2" 412 | 413 | "Battalion's Backup" 414 | { 415 | "cost" "1" 416 | } 417 | "Concheror" 418 | { 419 | "gain" "1" 420 | } 421 | } 422 | "Fabricate Righteous Bison" 423 | { 424 | "cost" "6" 425 | 426 | "Battalion's Backup" 427 | { 428 | "cost" "1" 429 | } 430 | "Righteous Bison" 431 | { 432 | "gain" "1" 433 | } 434 | } 435 | "Fabricate Disciplinary Action" 436 | { 437 | "cost" "12" 438 | 439 | "Pain Train" 440 | { 441 | "cost" "1" 442 | } 443 | "Disciplinary Action" 444 | { 445 | "gain" "1" 446 | } 447 | } 448 | "Fabricate Market Gardener" 449 | { 450 | "cost" "6" 451 | 452 | "Gunboats" 453 | { 454 | "cost" "1" 455 | } 456 | "Pain Train" 457 | { 458 | "cost" "1" 459 | } 460 | "Market Gardener" 461 | { 462 | "gain" "1" 463 | } 464 | } 465 | "Fabricate Escape Plan" 466 | { 467 | "cost" "2" 468 | 469 | "Disciplinary Action" 470 | { 471 | "cost" "1" 472 | } 473 | "Escape Plan" 474 | { 475 | "gain" "1" 476 | } 477 | } 478 | } 479 | "Pyro" 480 | { 481 | "Fabricate Degreaser" 482 | { 483 | "cost" "6" 484 | 485 | "Backburner" 486 | { 487 | "cost" "1" 488 | } 489 | "Degreaser" 490 | { 491 | "gain" "1" 492 | } 493 | } 494 | "Fabricate Phlogistinator" 495 | { 496 | "cost" "6" 497 | 498 | "The Soda Popper" 499 | { 500 | "cost" "1" 501 | } 502 | "Backburner" 503 | { 504 | "cost" "1" 505 | } 506 | "Phlogistinator" 507 | { 508 | "gain" "1" 509 | } 510 | } 511 | "Fabricate Detonator" 512 | { 513 | "cost" "12" 514 | 515 | "Flare Gun" 516 | { 517 | "cost" "1" 518 | } 519 | "Detonator" 520 | { 521 | "gain" "1" 522 | } 523 | } 524 | "Fabricate Manmelter" 525 | { 526 | "cost" "6" 527 | 528 | "Detonator" 529 | { 530 | "cost" "1" 531 | } 532 | "Manmelter" 533 | { 534 | "gain" "1" 535 | } 536 | } 537 | "Fabricate Scorch Shot" 538 | { 539 | "cost" "6" 540 | 541 | "Flare Gun" 542 | { 543 | "cost" "1" 544 | } 545 | "Degreaser" 546 | { 547 | "cost" "1" 548 | } 549 | "Scorch Shot" 550 | { 551 | "gain" "1" 552 | } 553 | } 554 | "Fabricate Homewrecker" 555 | { 556 | "cost" "2" 557 | 558 | "Equalizer" 559 | { 560 | "cost" "1" 561 | } 562 | "Homewrecker" 563 | { 564 | "gain" "1" 565 | } 566 | } 567 | "Fabricate Powerjack" 568 | { 569 | "cost" "6" 570 | 571 | "Axtinguisher" 572 | { 573 | "cost" "1" 574 | } 575 | "Powerjack" 576 | { 577 | "gain" "1" 578 | } 579 | } 580 | "Fabricate Back Scratcher" 581 | { 582 | "cost" "0" 583 | 584 | "Axtinguisher" 585 | { 586 | "cost" "1" 587 | } 588 | "Scotsman's Skullcutter" 589 | { 590 | "cost" "1" 591 | } 592 | "Back Scratcher" 593 | { 594 | "gain" "1" 595 | } 596 | } 597 | "Fabricate Third Degree" 598 | { 599 | "cost" "6" 600 | 601 | "Axtinguisher" 602 | { 603 | "cost" "1" 604 | } 605 | "Powerjack" 606 | { 607 | "cost" "1" 608 | } 609 | "Third Degree" 610 | { 611 | "gain" "1" 612 | } 613 | } 614 | "Fabricate Sharpened Volcano Fragment" 615 | { 616 | "cost" "12" 617 | 618 | "Axtinguisher" 619 | { 620 | "cost" "1" 621 | } 622 | "Sharpened Volcano Fragment" 623 | { 624 | "gain" "1" 625 | } 626 | } 627 | "Fabricate Neon Annihilator" 628 | { 629 | "cost" "6" 630 | 631 | "Third Degree" 632 | { 633 | "cost" "1" 634 | } 635 | "Neon Annihilator" 636 | { 637 | "gain" "1" 638 | } 639 | } 640 | } 641 | "Demoman" 642 | { 643 | "Fabricate Loch-n-Load" 644 | { 645 | "cost" "6" 646 | 647 | "Scottish Resistance" 648 | { 649 | "cost" "1" 650 | } 651 | "Loch-n-Load" 652 | { 653 | "gain" "1" 654 | } 655 | } 656 | "Fabricate Ali Baba's Wee Booties" 657 | { 658 | "cost" "0" 659 | 660 | "Mantreads" 661 | { 662 | "cost" "1" 663 | } 664 | "Gloves of Running Urgently" 665 | { 666 | "cost" "1" 667 | } 668 | "Ali Baba's Wee Booties" 669 | { 670 | "gain" "1" 671 | } 672 | } 673 | "Fabricate Loose Cannon" 674 | { 675 | "cost" "6" 676 | 677 | "Loch-n-Load" 678 | { 679 | "cost" "3" 680 | } 681 | "Loose Cannon" 682 | { 683 | "gain" "1" 684 | } 685 | } 686 | "Fabricate Iron Bomber" 687 | { 688 | "cost" "12" 689 | 690 | "Air Strike" 691 | { 692 | "cost" "1" 693 | } 694 | "Iron Bomber" 695 | { 696 | "gain" "1" 697 | } 698 | } 699 | "Fabricate Sticky Jumper" 700 | { 701 | "cost" "6" 702 | 703 | "Ullapool Caber" 704 | { 705 | "cost" "3" 706 | } 707 | "Sticky Jumper" 708 | { 709 | "gain" "1" 710 | } 711 | } 712 | "Fabricate Scotsman's Skullcutter" 713 | { 714 | "cost" "0" 715 | 716 | "Jarate" 717 | { 718 | "cost" "1" 719 | } 720 | "Axtinguisher" 721 | { 722 | "cost" "1" 723 | } 724 | "Scotsman's Skullcutter" 725 | { 726 | "gain" "1" 727 | } 728 | } 729 | "Fabricate Ullapool Caber" 730 | { 731 | "cost" "4" 732 | 733 | "Pain Train" 734 | { 735 | "cost" "1" 736 | } 737 | "Ullapool Caber" 738 | { 739 | "gain" "1" 740 | } 741 | } 742 | "Fabricate Persian Persuader" 743 | { 744 | "cost" "2" 745 | 746 | "Half-Zatoichi" 747 | { 748 | "cost" "2" 749 | } 750 | "Persian Persuader" 751 | { 752 | "gain" "1" 753 | } 754 | } 755 | } 756 | "Heavy" 757 | { 758 | "Fabricate Brass Beast" 759 | { 760 | "cost" "6" 761 | 762 | "Natascha" 763 | { 764 | "cost" "1" 765 | } 766 | "Brass Beast" 767 | { 768 | "gain" "1" 769 | } 770 | } 771 | "Fabricate Tomislav" 772 | { 773 | "cost" "12" 774 | 775 | "Brass Beast" 776 | { 777 | "cost" "1" 778 | } 779 | "Tomislav" 780 | { 781 | "gain" "1" 782 | } 783 | } 784 | "Fabricate Huo-Long Heater" 785 | { 786 | "cost" "6" 787 | 788 | "Family Business" 789 | { 790 | "cost" "3" 791 | } 792 | "Huo-Long Heater" 793 | { 794 | "gain" "1" 795 | } 796 | } 797 | "Fabricate Dalokohs Bar" 798 | { 799 | "cost" "2" 800 | 801 | "Sandvich" 802 | { 803 | "cost" "1" 804 | } 805 | "Dalokohs Bar" 806 | { 807 | "gain" "1" 808 | } 809 | } 810 | "Fabricate Buffalo Steak Sandvich" 811 | { 812 | "cost" "6" 813 | 814 | "Sandvich" 815 | { 816 | "cost" "1" 817 | } 818 | "Buffalo Steak Sandvich" 819 | { 820 | "gain" "1" 821 | } 822 | } 823 | "Fabricate Family Business" 824 | { 825 | "cost" "6" 826 | 827 | "Frontier Justice" 828 | { 829 | "cost" "1" 830 | } 831 | "Homewrecker" 832 | { 833 | "cost" "1" 834 | } 835 | "Family Business" 836 | { 837 | "gain" "1" 838 | } 839 | } 840 | "Fabricate Gloves of Running Urgently" 841 | { 842 | "cost" "4" 843 | 844 | "Killing Gloves of Boxing" 845 | { 846 | "cost" "1" 847 | } 848 | "Gloves of Running Urgently" 849 | { 850 | "gain" "1" 851 | } 852 | } 853 | "Fabricate Warrior's Spirit" 854 | { 855 | "cost" "2" 856 | 857 | "Gloves of Running Urgently" 858 | { 859 | "cost" "1" 860 | } 861 | "Warrior's Spirit" 862 | { 863 | "gain" "1" 864 | } 865 | } 866 | "Fabricate Fists of Steel" 867 | { 868 | "cost" "6" 869 | 870 | "Killing Gloves of Boxing" 871 | { 872 | "cost" "1" 873 | } 874 | "Fists of Steel" 875 | { 876 | "gain" "1" 877 | } 878 | } 879 | "Fabricate Eviction Notice" 880 | { 881 | "cost" "12" 882 | 883 | "Fists of Steel" 884 | { 885 | "cost" "1" 886 | } 887 | "Eviction Notice" 888 | { 889 | "gain" "1" 890 | } 891 | } 892 | "Fabricate Holiday Punch" 893 | { 894 | "cost" "6" 895 | 896 | "Holy Mackerel" 897 | { 898 | "cost" "1" 899 | } 900 | "Gloves of Running Urgently" 901 | { 902 | "cost" "1" 903 | } 904 | "Holiday Punch" 905 | { 906 | "gain" "1" 907 | } 908 | } 909 | } 910 | "Engineer" 911 | { 912 | "Fabricate Pomson 6000" 913 | { 914 | "cost" "6" 915 | 916 | "Righteous Bison" 917 | { 918 | "cost" "1" 919 | } 920 | "Short Circuit" 921 | { 922 | "cost" "1" 923 | } 924 | "Pomson 6000" 925 | { 926 | "gain" "1" 927 | } 928 | } 929 | "Fabricate Rescue Ranger" 930 | { 931 | "cost" "6" 932 | 933 | "Eureka Effect" 934 | { 935 | "cost" "3" 936 | } 937 | "Rescue Ranger" 938 | { 939 | "gain" "1" 940 | } 941 | } 942 | "Fabricate Widowmaker" 943 | { 944 | "cost" "12" 945 | 946 | "L'Etranger" 947 | { 948 | "cost" "1" 949 | } 950 | "Widowmaker" 951 | { 952 | "gain" "1" 953 | } 954 | } 955 | "Fabricate Short Circuit" 956 | { 957 | "cost" "8" 958 | 959 | "Gunslinger" 960 | { 961 | "cost" "1" 962 | } 963 | "Short Circuit" 964 | { 965 | "gain" "1" 966 | } 967 | } 968 | "Fabricate Southern Hospitality" 969 | { 970 | "cost" "2" 971 | 972 | "Ambassador" 973 | { 974 | "cost" "1" 975 | } 976 | "Southern Hospitality" 977 | { 978 | "gain" "1" 979 | } 980 | } 981 | "Fabricate Jag" 982 | { 983 | "cost" "2" 984 | 985 | "Southern Hospitality" 986 | { 987 | "cost" "1" 988 | } 989 | "Jag" 990 | { 991 | "gain" "1" 992 | } 993 | } 994 | "Fabricate Eureka Effect" 995 | { 996 | "cost" "6" 997 | 998 | "Jag" 999 | { 1000 | "cost" "2" 1001 | } 1002 | "Eureka Effect" 1003 | { 1004 | "gain" "1" 1005 | } 1006 | } 1007 | } 1008 | "Medic" 1009 | { 1010 | "Fabricate Crusader's Crossbow" 1011 | { 1012 | "cost" "4" 1013 | 1014 | "Huntsman" 1015 | { 1016 | "cost" "1" 1017 | } 1018 | "Crusader's Crossbow" 1019 | { 1020 | "gain" "1" 1021 | } 1022 | } 1023 | "Fabricate Overdose" 1024 | { 1025 | "cost" "6" 1026 | 1027 | "Gloves of Running Urgently" 1028 | { 1029 | "cost" "1" 1030 | } 1031 | "Crusader's Crossbow" 1032 | { 1033 | "cost" "1" 1034 | } 1035 | "Overdose" 1036 | { 1037 | "gain" "1" 1038 | } 1039 | } 1040 | "Fabricate Quick-Fix" 1041 | { 1042 | "cost" "6" 1043 | 1044 | "Mad Milk" 1045 | { 1046 | "cost" "1" 1047 | } 1048 | "Kritzkrieg" 1049 | { 1050 | "cost" "1" 1051 | } 1052 | "Quick-Fix" 1053 | { 1054 | "gain" "1" 1055 | } 1056 | } 1057 | "Fabricate Vaccinator" 1058 | { 1059 | "cost" "6" 1060 | 1061 | "Quick-Fix" 1062 | { 1063 | "cost" "3" 1064 | } 1065 | "Vaccinator" 1066 | { 1067 | "gain" "1" 1068 | } 1069 | } 1070 | "Fabricate Vita-Saw" 1071 | { 1072 | "cost" "4" 1073 | 1074 | "Übersaw" 1075 | { 1076 | "cost" "1" 1077 | } 1078 | "Vita-Saw" 1079 | { 1080 | "gain" "1" 1081 | } 1082 | } 1083 | "Fabricate Amputator" 1084 | { 1085 | "cost" "2" 1086 | 1087 | "Vita-Saw" 1088 | { 1089 | "cost" "1" 1090 | } 1091 | "Amputator" 1092 | { 1093 | "gain" "1" 1094 | } 1095 | } 1096 | "Fabricate Solemn Vow" 1097 | { 1098 | "cost" "6" 1099 | 1100 | "Jarate" 1101 | { 1102 | "cost" "8" 1103 | } 1104 | "Solemn Vow" 1105 | { 1106 | "gain" "1" 1107 | } 1108 | } 1109 | } 1110 | "Sniper" 1111 | { 1112 | "Fabricate Sydney Sleeper" 1113 | { 1114 | "cost" "6" 1115 | 1116 | "Huntsman" 1117 | { 1118 | "cost" "1" 1119 | } 1120 | "Sydney Sleeper" 1121 | { 1122 | "gain" "1" 1123 | } 1124 | } 1125 | "Fabricate Bazaar Bargain" 1126 | { 1127 | "cost" "6" 1128 | 1129 | "Sydney Sleeper" 1130 | { 1131 | "cost" "1" 1132 | } 1133 | "Eyelander" 1134 | { 1135 | "cost" "1" 1136 | } 1137 | "Bazaar Bargain" 1138 | { 1139 | "gain" "1" 1140 | } 1141 | } 1142 | "Fabricate Machina" 1143 | { 1144 | "cost" "6" 1145 | 1146 | "Righteous Bison" 1147 | { 1148 | "cost" "1" 1149 | } 1150 | "Sydney Sleeper" 1151 | { 1152 | "cost" "1" 1153 | } 1154 | "Machina" 1155 | { 1156 | "gain" "1" 1157 | } 1158 | } 1159 | "Fabricate Hitman's Heatmaker" 1160 | { 1161 | "cost" "6" 1162 | 1163 | "Machina" 1164 | { 1165 | "cost" "1" 1166 | } 1167 | "Bazaar Bargain" 1168 | { 1169 | "cost" "1" 1170 | } 1171 | "Hitman's Heatmaker" 1172 | { 1173 | "gain" "1" 1174 | } 1175 | } 1176 | "Fabricate Classic" 1177 | { 1178 | "cost" "6" 1179 | 1180 | "Huntsman" 1181 | { 1182 | "cost" "1" 1183 | } 1184 | "Bazaar Bargain" 1185 | { 1186 | "cost" "1" 1187 | } 1188 | "Classic" 1189 | { 1190 | "gain" "1" 1191 | } 1192 | } 1193 | "Fabricate Cleaner's Carbine" 1194 | { 1195 | "cost" "6" 1196 | 1197 | "Bushwacka" 1198 | { 1199 | "cost" "3" 1200 | } 1201 | "Cleaner's Carbine" 1202 | { 1203 | "gain" "1" 1204 | } 1205 | } 1206 | "Fabricate Tribalman's Shiv" 1207 | { 1208 | "cost" "0" 1209 | 1210 | "Dead Ringer" 1211 | { 1212 | "cost" "1" 1213 | } 1214 | "Huntsman" 1215 | { 1216 | "cost" "1" 1217 | } 1218 | "Tribalman's Shiv" 1219 | { 1220 | "gain" "1" 1221 | } 1222 | } 1223 | "Fabricate Bushwacka" 1224 | { 1225 | "cost" "6" 1226 | 1227 | "Eyelander" 1228 | { 1229 | "cost" "1" 1230 | } 1231 | "Bushwacka" 1232 | { 1233 | "gain" "1" 1234 | } 1235 | } 1236 | "Fabricate Shahanshah" 1237 | { 1238 | "cost" "6" 1239 | 1240 | "Amputator" 1241 | { 1242 | "cost" "1" 1243 | } 1244 | "Bushwacka" 1245 | { 1246 | "cost" "1" 1247 | } 1248 | "Shahanshah" 1249 | { 1250 | "gain" "1" 1251 | } 1252 | } 1253 | "Fabricate L'Etranger" 1254 | { 1255 | "cost" "6" 1256 | 1257 | "Dead Ringer" 1258 | { 1259 | "cost" "1" 1260 | } 1261 | "L'Etranger" 1262 | { 1263 | "gain" "1" 1264 | } 1265 | } 1266 | "Fabricate Enforcer" 1267 | { 1268 | "cost" "8" 1269 | 1270 | "L'Etranger" 1271 | { 1272 | "cost" "1" 1273 | } 1274 | "Enforcer" 1275 | { 1276 | "gain" "1" 1277 | } 1278 | } 1279 | "Fabricate Diamondback" 1280 | { 1281 | "cost" "6" 1282 | 1283 | "Frontier Justice" 1284 | { 1285 | "cost" "1" 1286 | } 1287 | "Dead Ringer" 1288 | { 1289 | "cost" "1" 1290 | } 1291 | "Diamondback" 1292 | { 1293 | "gain" "1" 1294 | } 1295 | } 1296 | "Fabricate Red-Tape Recorder" 1297 | { 1298 | "cost" "6" 1299 | 1300 | "Spy-cicle" 1301 | { 1302 | "cost" "3" 1303 | } 1304 | "Red-Tape Recorder" 1305 | { 1306 | "gain" "1" 1307 | } 1308 | } 1309 | "Fabricate Your Eternal Reward" 1310 | { 1311 | "cost" "6" 1312 | 1313 | "Cloak and Dagger" 1314 | { 1315 | "cost" "1" 1316 | } 1317 | "Your Eternal Reward" 1318 | { 1319 | "gain" "1" 1320 | } 1321 | } 1322 | "Fabricate Big Earner" 1323 | { 1324 | "cost" "6" 1325 | 1326 | "Conniver's Kunai" 1327 | { 1328 | "cost" "1" 1329 | } 1330 | "L'Etranger" 1331 | { 1332 | "cost" "1" 1333 | } 1334 | "Big Earner" 1335 | { 1336 | "gain" "1" 1337 | } 1338 | } 1339 | "Fabricate Spy-cicle" 1340 | { 1341 | "cost" "6" 1342 | 1343 | "Your Eternal Reward" 1344 | { 1345 | "cost" "1" 1346 | } 1347 | "Spy-cicle" 1348 | { 1349 | "gain" "1" 1350 | } 1351 | } 1352 | "Fabricate Conniver's Kunai" 1353 | { 1354 | "cost" "2" 1355 | 1356 | "Your Eternal Reward" 1357 | { 1358 | "cost" "1" 1359 | } 1360 | "Conniver's Kunai" 1361 | { 1362 | "gain" "1" 1363 | } 1364 | } 1365 | } 1366 | } 1367 | } 1368 | -------------------------------------------------------------------------------- /addons/sourcemod/configs/textstore/store.cfg: -------------------------------------------------------------------------------- 1 | "Store" 2 | { 3 | "Category 1" 4 | { 5 | "Category 1A" 6 | { 7 | "Item 1Aa" 8 | { 9 | // Item Specific Settings 10 | "type" "command" 11 | "command" "sm_slay #{userid}" 12 | "fail" "This command can only" 13 | "success" "" 14 | 15 | // Store Specific Settings 16 | "admin" "" 17 | "cost" "10" 18 | "desc" "You Just Die" 19 | "hidden" "0" 20 | "plugin" "textstore_defaults" 21 | "sell" "7" 22 | "slot" "0" 23 | "stack" "1" 24 | } 25 | "Item 1Ab" 26 | { 27 | "type" "voting" // Subplugin knowing the type of item 28 | "title" "Enable Friendly Fire?" // Vote Title 29 | "command" "mp_friendlyfire 1" // Command(s) to run on success 30 | "once" "1" // Can be used more than once per map 31 | "maptime" "5.0" // How much time to extend the map for 32 | 33 | "admin" "" // Admin permissions to buy this item (Def: 0) 34 | "cost" "10" // Cost of the item (Required argument) 35 | "desc" "Example Item" // Description of the item 36 | "hidden" "0" // If the item is hidden from buying (Def: 1/6 chance of being hidden each map rotation) 37 | "plugin" "textstore_defaults" // Subplugin to use for the item 38 | "sell" "8" // Sell price (Def: 3/4 of cost of item) 39 | "slot" "0" // Equippment slot index (Def: 0, aka none) 40 | "stack" "1" // If the client can have more than one owned at a time 41 | } 42 | } 43 | "Category 1B" 44 | { 45 | "Category 1Ba" 46 | { 47 | "Category 1Ba1" 48 | { 49 | "Category 1Ba1A" 50 | { 51 | "Category 1Ba1Aa" 52 | { 53 | "Category 1Ba1Aa" 54 | { 55 | "Item 1Ba1Aa1" 56 | { 57 | // Maximum Limit of Categories 58 | } 59 | } 60 | } 61 | } 62 | } 63 | } 64 | } 65 | "Item 1C" // Items and categories can be mixed 66 | { 67 | "type" "trail" 68 | "material" "example/path.vmt" 69 | "color" "255 255 255 255" 70 | "width" "10.0" 71 | 72 | "admin" "" 73 | "cost" "5" 74 | "desc" "Example Item" 75 | "hidden" "0" 76 | "plugin" "textstore_defaults" 77 | "sell" "3" 78 | "slot" "1" 79 | "stack" "1" 80 | } 81 | } 82 | "Category 2" 83 | { 84 | } 85 | "Category 3" 86 | { 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /addons/sourcemod/scripting/include/textstore.inc: -------------------------------------------------------------------------------- 1 | #if defined _textstore_included 2 | #endinput 3 | #endif 4 | #define _textstore_included 5 | 6 | #define STORE_PREFIX "{green}[Store]{snow} " 7 | #define STORE_PREFIX2 "{green}[Store] " 8 | #define STORE_COLOR "{snow}" 9 | #define STORE_COLOR2 "{green}" 10 | 11 | enum ItemResult 12 | { 13 | Item_None = 0, // Do nothing to the item 14 | Item_Used, // Delete one use of the item 15 | Item_On, // Equip the item on the client 16 | Item_Off // Unequip the item on the client 17 | }; 18 | 19 | /** 20 | * Change a client's inventory count/equippment 21 | * 22 | * @param client Client index of using item 23 | * @param item Index of the item 24 | * @param count Amount of the item 25 | * @param equip If to force unequip or equip the item 26 | * 27 | * @noreturn 28 | */ 29 | native void TextStore_SetInv(int client, int item, int count=-1, int equip=-1); 30 | 31 | /** 32 | * Get a client's inventory count/equippment 33 | * 34 | * @param client Client index 35 | * @param item Item index 36 | * @param count Amount of the item in the client's inventory 37 | * 38 | * @return If the item is equipped 39 | */ 40 | native bool TextStore_GetInv(int client, int item, int &count=0); 41 | 42 | /** 43 | * Get, give, remove cash on a client 44 | * 45 | * @param client Client index 46 | * @param cash Cash to give/remove 47 | * 48 | * @return New cash value 49 | */ 50 | native int TextStore_Cash(int client, int cash=0); 51 | 52 | /** 53 | * Forces the client to save their current items into the database 54 | * 55 | * @param client Client index 56 | * 57 | * @noreturn 58 | */ 59 | native void TextStore_ClientSave(int client); 60 | 61 | /** 62 | * Forces the client to get their current items from previous save 63 | * 64 | * @param client Client index 65 | * 66 | * @noreturn 67 | */ 68 | native void TextStore_ClientReload(int client); 69 | 70 | /** 71 | * If the client has their inventory loaded from a save 72 | * 73 | * @param client Client index 74 | * 75 | * @return If the client has items loaded 76 | */ 77 | native bool TextStore_GetClientLoad(int client); 78 | 79 | /** 80 | * Sets if the client has their inventory loaded from a save (If to call saving or not) 81 | * 82 | * @param client Client index 83 | * @param status If the player is considered loaded 84 | * 85 | * @noreturn 86 | */ 87 | native void TextStore_SetClientLoad(int client, bool status); 88 | 89 | /** 90 | * Gets the current amount of items and categories in the store 91 | * 92 | * @param uniques Number of unique items 93 | * 94 | * @return Amount of items and categories 95 | */ 96 | native int TextStore_GetItems(int &uniques=0); 97 | 98 | /** 99 | * Gets the name of the item 100 | * 101 | * @note Do not close the KeyValues handle given 102 | * 103 | * @param item Item index 104 | * 105 | * @return KeyValues handle 106 | */ 107 | native KeyValues TextStore_GetItemKv(int item); 108 | 109 | /** 110 | * Gets the name of the item 111 | * 112 | * @param item Item index 113 | * @param buffer String to write to 114 | * @param count Size of the string 115 | * 116 | * @return Number of bytes written 117 | */ 118 | native int TextStore_GetItemName(int item, char[] buffer, int length); 119 | 120 | /** 121 | * Sets the name of a unique item 122 | * 123 | * @param item Item index 124 | * @param name Custom item name 125 | * 126 | * @noreturn 127 | */ 128 | native void TextStore_SetItemName(int item, const char[] name=""); 129 | 130 | /** 131 | * Gets data of a unique item 132 | * 133 | * @param item Item index 134 | * @param buffer String to write to 135 | * @param count Size of the string 136 | * 137 | * @return Number of bytes written 138 | */ 139 | native int TextStore_GetItemData(int item, char[] buffer, int length); 140 | 141 | /** 142 | * Sets data of a unique item 143 | * 144 | * @param item Item index 145 | * @param data Item data string 146 | * 147 | * @noreturn 148 | */ 149 | native void TextStore_SetItemData(int item, const char[] data); 150 | 151 | /** 152 | * Creates a unique variant of an item 153 | * 154 | * @param client Client index 155 | * @param item Base item index 156 | * @param data Item data string 157 | * @param name Custom item name 158 | * @param equipped If given equipped 159 | * 160 | * @return Given item index 161 | */ 162 | native int TextStore_CreateUniqueItem(int client, int item, const char[] data, const char[] name="", bool equipped=false); 163 | 164 | /** 165 | * Activates an item from the client 166 | * 167 | * @param client Client index 168 | * @param item Item index 169 | * @param auto If to consider this an auto equip 170 | * 171 | * @return For common items: true if success. For unique items: true if the owner is still valid, false otherwise 172 | */ 173 | native bool TextStore_UseItem(int client, int item, bool auto=false); 174 | 175 | /** 176 | * Gets if the item is hidden in the store 177 | * 178 | * @param item Item index 179 | * 180 | * @return If the item is hidden 181 | */ 182 | native bool TextStore_GetItemHidden(int item); 183 | 184 | /** 185 | * Sets if the item is hidden in the store 186 | * 187 | * @param item Item index 188 | * @param hidden If the item is hidden 189 | * 190 | * @noreturn 191 | */ 192 | native void TextStore_SetItemHidden(int item, bool hidden); 193 | 194 | /** 195 | * Gets the item's parent category 196 | * 197 | * @param item Item index 198 | * 199 | * @return Parent item index 200 | */ 201 | native int TextStore_GetItemParent(int item); 202 | 203 | /** 204 | * Sets the item's parent category 205 | * 206 | * @param item Item index 207 | * @param parent Parent item index 208 | * 209 | * @noreturn 210 | */ 211 | native void TextStore_SetItemParent(int item, bool parent); 212 | 213 | /** 214 | * Called when a client's item is about to be sold 215 | * 216 | * @param client Client index 217 | * @param item Item index 218 | * @param cash The current "cash" the client has 219 | * @param count The current amount of the item the client has 220 | * @param sell The amount the item is being sold for 221 | * 222 | * @return Plugin_Changed to change values, Plugin_Handled/Plugin_Stop to prevent the sell 223 | */ 224 | forward Action TextStore_OnSellItem(int client, int item, int cash, int &count, int &sell); 225 | 226 | /** 227 | * Called when a description of an item is about to be shown 228 | * 229 | * @param client Client index 230 | * @param item Item index 231 | * @param desc Description of the item 232 | * 233 | * @noreturn 234 | */ 235 | forward void TextStore_OnDescItem(int client, int item, char[] desc); 236 | 237 | /** 238 | * Called when a client's items are loading into cache 239 | * 240 | * @param client Client index 241 | * @param file TextStore save file 242 | * 243 | * @return Plugin_Changed to change the filepath, Plugin_Handled to not load items but consider client loaded, Plugin_Stop to prevent loading 244 | */ 245 | forward Action TextStore_OnClientLoad(int client, char file[PLATFORM_MAX_PATH]); 246 | 247 | /** 248 | * Called when a client's items are loaded into cache 249 | * 250 | * @param client Client index 251 | * @param file TextStore save file 252 | * 253 | * @noreturn 254 | */ 255 | forward void TextStore_OnClientLoaded(int client, const char[] file); 256 | 257 | /** 258 | * Called when a client's items are saving into a file 259 | * 260 | * @param client Client index 261 | * @param file TextStore save file 262 | * 263 | * @return Plugin_Changed to change the filepath, Plugin_Handled/Plugin_Stop to not save items 264 | */ 265 | forward Action TextStore_OnClientSave(int client, char file[PLATFORM_MAX_PATH]); 266 | 267 | /** 268 | * Called when a client's items are saved into a file 269 | * 270 | * @param client Client index 271 | * @param file TextStore save file 272 | * 273 | * @noreturn 274 | */ 275 | forward void TextStore_OnClientSaved(int client, const char[] file); 276 | 277 | /** 278 | * Called when a client enters the main menu 279 | * 280 | * @param client Client index 281 | * @param menu Menu handle, don't close this handle 282 | * 283 | * @return Plugin_Handled/Plugin_Stop to prevent the menu from showing 284 | */ 285 | forward Action TextStore_OnMainMenu(int client, Menu menu); 286 | 287 | /** 288 | * Called when a client is about to enter a store page 289 | * 290 | * @param client Client index 291 | * 292 | * @noreturn 293 | */ 294 | forward void TextStore_OnCatalog(int client); 295 | 296 | /** 297 | * Called when a client is about to buy an item 298 | * 299 | * @param client Client index 300 | * @param item Item index 301 | * @param cash The current "cash" the client has 302 | * @param count The current amount of the item the client has 303 | * @param cost The amount the item is being sold for 304 | * 305 | * @return Plugin_Changed to change values, Plugin_Handled/Plugin_Stop to prevent buying 306 | */ 307 | forward Action TextStore_OnBuyItem(int client, int item, int cash, int &count, int &cost); 308 | 309 | /** 310 | * Called when an item's price displayed to the client 311 | * 312 | * @param client Client index 313 | * @param item Item index 314 | * @param price Item's price 315 | * 316 | * @return Plugin_Changed to change values, Plugin_Handled/Plugin_Stop to prevent buying 317 | */ 318 | forward Action TextStore_OnPriceItem(int client, int item, int &price); 319 | 320 | /** 321 | * Called to a given plugin when a item is used 322 | * 323 | * @note This is not actually a forward, this is called per plugin 324 | * @note Do not close the KeyValues handle given 325 | * 326 | * @param client Client index 327 | * @param equipped If the item is already equipped on the client 328 | * @param item KeyValue of the item (already in place) 329 | * @param index Item Index 330 | * @param name Name of the item 331 | * @param count Amount of the item in the client's inventory 332 | * @param auto If the item was used automatically, usually by connecting 333 | * 334 | * @return Item result 335 | */ 336 | forward ItemResult TextStore_Item(int client, bool equipped, KeyValues item, int index, const char[] name, int &count, bool auto); 337 | 338 | /** 339 | * Prints a color message with the store's prefix 340 | * 341 | * Uses the same params and return values as CPrintToChat, CPrintToChatAll, and CReplyToCommand 342 | */ 343 | #if defined _colors_included 344 | stock void SPrintToChat(int client, const char[] message, any ...) 345 | { 346 | SetGlobalTransTarget(client); 347 | char buffer[192]; 348 | VFormat(buffer, sizeof(buffer), message, 3); 349 | CPrintToChat(client, "%s%s", STORE_PREFIX, buffer); 350 | } 351 | stock void SPrintToChatAll(const char[] message, any ...) 352 | { 353 | char buffer[192]; 354 | VFormat(buffer, sizeof(buffer), message, 2); 355 | CPrintToChatAll("%s%s", STORE_PREFIX, buffer); 356 | } 357 | stock void SReplyToCommand(int client, const char[] message, any ...) 358 | { 359 | SetGlobalTransTarget(client); 360 | char buffer[192]; 361 | VFormat(buffer, sizeof(buffer), message, 3); 362 | if(!client) 363 | { 364 | CRemoveTags(buffer, sizeof(buffer)); 365 | PrintToServer("[Store] %s", buffer); 366 | } 367 | else if(GetCmdReplySource() == SM_REPLY_TO_CONSOLE) 368 | { 369 | CRemoveTags(buffer, sizeof(buffer)); 370 | PrintToConsole(client, "[Store] %s", buffer); 371 | } 372 | else 373 | { 374 | CPrintToChat(client, "%s%s", STORE_PREFIX, buffer); 375 | } 376 | } 377 | #endif 378 | 379 | public SharedPlugin __pl_TextStore = 380 | { 381 | name = "textstore", 382 | file = "textstore.smx", 383 | #if defined REQUIRE_PLUGIN 384 | required = 1, 385 | #else 386 | required = 0, 387 | #endif 388 | }; 389 | 390 | #if !defined REQUIRE_PLUGIN 391 | public void __pl_TextStore_SetNTVOptional() 392 | { 393 | MarkNativeAsOptional("TextStore_GetInv"); 394 | MarkNativeAsOptional("TextStore_SetInv"); 395 | MarkNativeAsOptional("TextStore_Cash"); 396 | MarkNativeAsOptional("TextStore_ClientSave"); 397 | MarkNativeAsOptional("TextStore_ClientReload"); 398 | MarkNativeAsOptional("TextStore_GetClientLoad"); 399 | MarkNativeAsOptional("TextStore_SetClientLoad"); 400 | MarkNativeAsOptional("TextStore_GetItems"); 401 | MarkNativeAsOptional("TextStore_GetItemKv"); 402 | MarkNativeAsOptional("TextStore_GetItemName"); 403 | MarkNativeAsOptional("TextStore_SetItemName"); 404 | MarkNativeAsOptional("TextStore_GetItemData"); 405 | MarkNativeAsOptional("TextStore_SetItemData"); 406 | MarkNativeAsOptional("TextStore_CreateUniqueItem"); 407 | MarkNativeAsOptional("TextStore_UseItem"); 408 | MarkNativeAsOptional("TextStore_GetItemHidden"); 409 | MarkNativeAsOptional("TextStore_SetItemHidden"); 410 | MarkNativeAsOptional("TextStore_GetItemParent"); 411 | MarkNativeAsOptional("TextStore_SetItemParent"); 412 | } 413 | #endif 414 | -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore/adminmenu.sp: -------------------------------------------------------------------------------- 1 | #define ADMINMENU_TEXTSTORE "TextStoreCommands" 2 | 3 | static TopMenu StoreTop; 4 | 5 | void AdminMenu_PluginStart() 6 | { 7 | TopMenu topmenu; 8 | if(LibraryExists("adminmenu") && ((topmenu=GetAdminTopMenu())!=null)) 9 | OnAdminMenuReady(topmenu); 10 | } 11 | 12 | bool AdminMenu_Return(int client) 13 | { 14 | if(!StoreTop) 15 | return false; 16 | 17 | StoreTop.Display(client, TopMenuPosition_LastCategory); 18 | return true; 19 | } 20 | 21 | public void OnAdminMenuCreated(Handle topmenu) 22 | { 23 | TopMenu menu = TopMenu.FromHandle(topmenu); 24 | if(menu.FindCategory(ADMINMENU_TEXTSTORE) == INVALID_TOPMENUOBJECT) 25 | menu.AddCategory(ADMINMENU_TEXTSTORE, TopMenuCategory); 26 | } 27 | 28 | public void OnAdminMenuReady(Handle topmenu) 29 | { 30 | TopMenu menu = TopMenu.FromHandle(topmenu); 31 | if(menu == StoreTop) 32 | return; 33 | 34 | StoreTop = menu; 35 | TopMenuObject topobject = StoreTop.FindCategory(ADMINMENU_TEXTSTORE); 36 | if(topobject == INVALID_TOPMENUOBJECT) 37 | { 38 | topobject = StoreTop.AddCategory(ADMINMENU_TEXTSTORE, TopMenuCategory); 39 | if(topobject == INVALID_TOPMENUOBJECT) 40 | return; 41 | } 42 | 43 | StoreTop.AddItem("sm_buy", StoreT, topobject, "sm_buy", 0); 44 | StoreTop.AddItem("sm_sell", InventoryT, topobject, "sm_sell", 0); 45 | StoreTop.AddItem("sm_store_admin", AdminMenuT, topobject, "sm_store_admin", ADMFLAG_ROOT); 46 | } 47 | 48 | public void OnLibraryRemoved(const char[] name) 49 | { 50 | if(StrEqual(name, "adminmenu")) 51 | StoreTop = null; 52 | } 53 | 54 | public void TopMenuCategory(TopMenu topmenu, TopMenuAction action, TopMenuObject topobject, int client, char[] buffer, int maxlength) 55 | { 56 | switch(action) 57 | { 58 | case TopMenuAction_DisplayTitle: 59 | strcopy(buffer, maxlength, "Text Store:"); 60 | 61 | case TopMenuAction_DisplayOption: 62 | strcopy(buffer, maxlength, "Text Store"); 63 | } 64 | } 65 | 66 | public void StoreT(TopMenu topmenu, TopMenuAction action, TopMenuObject topobject, int client, char[] buffer, int maxlength) 67 | { 68 | switch(action) 69 | { 70 | case TopMenuAction_DisplayOption: 71 | strcopy(buffer, maxlength, "Store Menu"); 72 | 73 | case TopMenuAction_SelectOption: 74 | CommandStore(client, -1); 75 | } 76 | } 77 | 78 | public void InventoryT(TopMenu topmenu, TopMenuAction action, TopMenuObject topobject, int client, char[] buffer, int maxlength) 79 | { 80 | switch(action) 81 | { 82 | case TopMenuAction_DisplayOption: 83 | strcopy(buffer, maxlength, "Inventory Menu"); 84 | 85 | case TopMenuAction_SelectOption: 86 | CommandInven(client, -1); 87 | } 88 | } 89 | 90 | public void AdminMenuT(TopMenu topmenu, TopMenuAction action, TopMenuObject topobject, int client, char[] buffer, int maxlength) 91 | { 92 | switch(action) 93 | { 94 | case TopMenuAction_DisplayOption: 95 | strcopy(buffer, maxlength, "Admin Menu"); 96 | 97 | case TopMenuAction_SelectOption: 98 | CommandAdmin(client, -1); 99 | } 100 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore/crafting.sp: -------------------------------------------------------------------------------- 1 | #define DATA_CRAFTING "configs/textstore/crafting.cfg" 2 | 3 | enum struct CraftEnum 4 | { 5 | int Parent; 6 | int Admin; 7 | char Name[MAX_ITEM_LENGTH]; 8 | KeyValues Kv; 9 | } 10 | ArrayList Crafts; 11 | 12 | void Crafting_ConfigsExecuted() 13 | { 14 | if(Crafts != INVALID_HANDLE) 15 | { 16 | CraftEnum craft; 17 | int length = Crafts.Length; 18 | for(int i; i Client[client].Cash) 129 | continue; 130 | 131 | craft.Kv.GotoFirstSubKey(); 132 | do 133 | { 134 | if(!craft.Kv.GetSectionName(buffer, sizeof(buffer)) || !buffer[0]) 135 | break; 136 | 137 | for(int id; id item.Count[client]) 143 | { 144 | deny = true; 145 | } 146 | else if(craft.Kv.GetNum("gain")>0 && item.Count[client]) 147 | { 148 | item.Kv.Rewind(); 149 | if(!item.Kv.GetNum("stack", 1)) 150 | deny = true; 151 | } 152 | break; 153 | } 154 | } 155 | } while(!deny && craft.Kv.GotoNextKey()); 156 | 157 | if(deny) 158 | { 159 | deny = false; 160 | continue; 161 | } 162 | 163 | found = true; 164 | IntToString(i, buffer, sizeof(buffer)); 165 | menu.AddItem(buffer, craft.Name); 166 | } 167 | 168 | if(!found) 169 | menu.AddItem("", "No Recipes", ITEMDRAW_DISABLED); 170 | 171 | menu.ExitBackButton = true; 172 | menu.ExitButton = true; 173 | menu.Display(client, MENU_TIME_FOREVER); 174 | return; 175 | } 176 | 177 | if(primary != POS_NONE) 178 | Crafts.GetArray(primary, craft); 179 | 180 | if(!craft.Kv) 181 | { 182 | Menu menu = new Menu(CraftingH); 183 | if(primary == POS_NONE) 184 | { 185 | menu.SetTitle("Crafting\n \nCredits: %d\n ", Client[client].Cash); 186 | 187 | IntToString(POS_ALLITEM, buffer, sizeof(buffer)); 188 | menu.AddItem(buffer, "Available Recipes"); 189 | } 190 | else 191 | { 192 | menu.SetTitle("Crafting: %s\n ", craft.Name); 193 | } 194 | 195 | int length = Crafts.Length; 196 | for(int i; i 0) 220 | { 221 | if(Client[client].Cash < value) 222 | deny = true; 223 | 224 | FormatEx(buffer, sizeof(buffer), "Credits (%d/%d)", Client[client].Cash, value); 225 | panel.DrawText(buffer); 226 | } 227 | 228 | ItemEnum item; 229 | int length = Items.Length; 230 | craft.Kv.GotoFirstSubKey(); 231 | do 232 | { 233 | if(!craft.Kv.GetSectionName(buffer, sizeof(buffer)) || !buffer[0]) 234 | break; 235 | 236 | for(int i; i 0) 243 | { 244 | if(value > item.Count[client]) 245 | deny = true; 246 | 247 | if(craft.Kv.GetNum("consume", 1)) 248 | { 249 | FormatEx(buffer, sizeof(buffer), "%s (%d/%d)", item.Name, item.Count[client], value); 250 | } 251 | else 252 | { 253 | FormatEx(buffer, sizeof(buffer), "%s (%d/%d) [Tool]", item.Name, item.Count[client], value); 254 | } 255 | panel.DrawText(buffer); 256 | } 257 | break; 258 | } 259 | } 260 | } while(craft.Kv.GotoNextKey()); 261 | 262 | panel.DrawText(" \nResult:"); 263 | 264 | craft.Kv.GoBack(); 265 | craft.Kv.GotoFirstSubKey(); 266 | do 267 | { 268 | if(!craft.Kv.GetSectionName(buffer, sizeof(buffer)) || !buffer[0]) 269 | break; 270 | 271 | for(int i; i 1) 278 | { 279 | if(item.Count[client] > 0) 280 | { 281 | FormatEx(buffer, sizeof(buffer), "%s x%d (Own %d)", item.Name, value, item.Count[client]); 282 | } 283 | else 284 | { 285 | FormatEx(buffer, sizeof(buffer), "%s x%d", item.Name, value); 286 | } 287 | panel.DrawText(buffer); 288 | } 289 | else if(value == 1) 290 | { 291 | if(item.Count[client] < 1) 292 | { 293 | panel.DrawText(item.Name); 294 | } 295 | else 296 | { 297 | item.Kv.Rewind(); 298 | if(item.Kv.GetNum("stack", 1)) 299 | { 300 | FormatEx(buffer, sizeof(buffer), "%s (Own %d)", item.Name, item.Count[client]); 301 | panel.DrawText(buffer); 302 | } 303 | else 304 | { 305 | deny = true; 306 | FormatEx(buffer, sizeof(buffer), "%s (Already Own)", item.Name); 307 | panel.DrawText(buffer); 308 | } 309 | } 310 | } 311 | break; 312 | } 313 | } 314 | } while(craft.Kv.GotoNextKey()); 315 | 316 | panel.DrawText(" "); 317 | panel.DrawItem("Craft", deny ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT); 318 | panel.DrawText(" "); 319 | panel.CurrentKey = 8; 320 | panel.DrawItem("Back"); 321 | panel.DrawText(" "); 322 | panel.CurrentKey = 10; 323 | panel.DrawItem("Exit"); 324 | panel.Send(client, CraftingItemH, MENU_TIME_FOREVER); 325 | delete panel; 326 | } 327 | 328 | public int CraftingH(Menu menu, MenuAction action, int client, int choice) 329 | { 330 | switch(action) 331 | { 332 | case MenuAction_End: 333 | { 334 | delete menu; 335 | } 336 | case MenuAction_Cancel: 337 | { 338 | if(choice != MenuCancel_ExitBack) 339 | return 0; 340 | 341 | if(Client[client].RemovePos()) 342 | { 343 | Crafting(client); 344 | } 345 | else if(!Client[client].BackOutAdmin || !AdminMenu_Return(client)) 346 | { 347 | Main(client); 348 | } 349 | } 350 | case MenuAction_Select: 351 | { 352 | static char buffer[MAX_NUM_LENGTH]; 353 | menu.GetItem(choice, buffer, sizeof(buffer)); 354 | if(buffer[0]) 355 | Client[client].AddPos(StringToInt(buffer)); 356 | 357 | Crafting(client); 358 | } 359 | } 360 | return 0; 361 | } 362 | 363 | public int CraftingItemH(Menu panel, MenuAction action, int client, int choice) 364 | { 365 | if(action != MenuAction_Select) 366 | return 0; 367 | 368 | switch(choice) 369 | { 370 | case 1: 371 | { 372 | CraftEnum craft; 373 | Crafts.GetArray(Client[client].GetPos(), craft); 374 | 375 | craft.Kv.Rewind(); 376 | int cash = craft.Kv.GetNum("cost"); 377 | if(cash <= Client[client].Cash) 378 | { 379 | static char buffer[MAX_ITEM_LENGTH]; 380 | 381 | ItemEnum item; 382 | bool deny; 383 | int length = Items.Length; 384 | craft.Kv.GotoFirstSubKey(); 385 | int[] amount = new int[length]; 386 | do 387 | { 388 | if(!craft.Kv.GetSectionName(buffer, sizeof(buffer)) || !buffer[0]) 389 | break; 390 | 391 | for(int i; i item.Count[client]) 405 | { 406 | deny = true; 407 | } 408 | else if(gain>0 && item.Count[client]) 409 | { 410 | item.Kv.Rewind(); 411 | if(!item.Kv.GetNum("stack", 1)) 412 | deny = true; 413 | } 414 | 415 | if(!deny) 416 | { 417 | amount[i] = gain; 418 | if(craft.Kv.GetNum("consume", 1)) 419 | amount[i] -= cost; 420 | } 421 | break; 422 | } 423 | } 424 | } while(!deny && craft.Kv.GotoNextKey()); 425 | 426 | if(!deny) 427 | { 428 | Client[client].Cash -= cash; 429 | 430 | for(int i; iMAXPLAYERS) 35 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_CLIENTINDEX, client); 36 | 37 | int index = GetNativeCell(2); 38 | if(-UniqueList.Length>index || index>=Items.Length) 39 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, index); 40 | 41 | if(index < 0) 42 | { 43 | UniqueEnum unique; 44 | UniqueList.GetArray(-1-index, unique); 45 | SetNativeCellRef(3, unique.Owner==client ? 1 : 0); 46 | return unique.Owner==client ? unique.Equipped : false; 47 | } 48 | 49 | ItemEnum item; 50 | Items.GetArray(index, item); 51 | SetNativeCellRef(3, item.Count[client]); 52 | return item.Equip[client]; 53 | } 54 | 55 | public any Native_SetInv(Handle plugin, int numParams) 56 | { 57 | if(Items == INVALID_HANDLE) 58 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 59 | 60 | int client = GetNativeCell(1); 61 | if(client<0 || client>MAXPLAYERS) 62 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_CLIENTINDEX, client); 63 | 64 | int index = GetNativeCell(2); 65 | if(-UniqueList.Length>index || index>=Items.Length) 66 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, index); 67 | 68 | int value = GetNativeCell(3); 69 | if(index < 0) 70 | { 71 | index = -1-index; 72 | UniqueEnum unique; 73 | UniqueList.GetArray(index, unique); 74 | 75 | if(value > 0) 76 | { 77 | unique.Owner = client; 78 | } 79 | else if(!value) 80 | { 81 | unique.Owner = 0; 82 | } 83 | 84 | value = GetNativeCell(4); 85 | if(value > 0) 86 | { 87 | unique.Equipped = true; 88 | } 89 | else if(!value) 90 | { 91 | unique.Equipped = false; 92 | } 93 | 94 | UniqueList.SetArray(index, unique); 95 | } 96 | else 97 | { 98 | ItemEnum item; 99 | Items.GetArray(index, item); 100 | 101 | if(value >= 0) 102 | item.Count[client] = value; 103 | 104 | value = GetNativeCell(4); 105 | if(value > 0) 106 | { 107 | item.Equip[client] = true; 108 | } 109 | else if(!value) 110 | { 111 | item.Equip[client] = false; 112 | } 113 | 114 | Items.SetArray(index, item); 115 | } 116 | return 0; 117 | } 118 | 119 | public any Native_Cash(Handle plugin, int numParams) 120 | { 121 | int client = GetNativeCell(1); 122 | if(client<0 || client>MAXPLAYERS) 123 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_CLIENTINDEX, client); 124 | 125 | int cash = GetNativeCell(2); 126 | if(cash) 127 | Client[client].Cash += cash; 128 | 129 | return Client[client].Cash; 130 | } 131 | 132 | public any Native_ClientSave(Handle plugin, int numParams) 133 | { 134 | if(Items == INVALID_HANDLE) 135 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 136 | 137 | int client = GetNativeCell(1); 138 | if(client<0 || client>MaxClients || !IsClientInGame(client)) 139 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_CLIENTINDEX, client); 140 | 141 | SaveClient(client); 142 | return 0; 143 | } 144 | 145 | public any Native_ClientReload(Handle plugin, int numParams) 146 | { 147 | if(Items == INVALID_HANDLE) 148 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 149 | 150 | int client = GetNativeCell(1); 151 | if(client<0 || client>MaxClients || !IsClientInGame(client)) 152 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_CLIENTINDEX, client); 153 | 154 | SetupClient(client); 155 | return 0; 156 | } 157 | 158 | public any Native_GetClientLoad(Handle plugin, int numParams) 159 | { 160 | int client = GetNativeCell(1); 161 | if(client<0 || client>MAXPLAYERS) 162 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_CLIENTINDEX, client); 163 | 164 | return Client[client].Ready; 165 | } 166 | 167 | public any Native_SetClientLoad(Handle plugin, int numParams) 168 | { 169 | int client = GetNativeCell(1); 170 | if(client<0 || client>MAXPLAYERS) 171 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_CLIENTINDEX, client); 172 | 173 | Client[client].Ready = GetNativeCell(2); 174 | return 0; 175 | } 176 | 177 | public any Native_GetItems(Handle plugin, int numParams) 178 | { 179 | if(Items == INVALID_HANDLE) 180 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 181 | 182 | if(numParams) 183 | SetNativeCellRef(1, UniqueList.Length); 184 | 185 | return Items.Length; 186 | } 187 | 188 | public any Native_GetItemKv(Handle plugin, int numParams) 189 | { 190 | if(Items == INVALID_HANDLE) 191 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 192 | 193 | int index = GetNativeCell(1); 194 | if(-UniqueList.Length>index || index>=Items.Length) 195 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, index); 196 | 197 | if(index < 0) 198 | { 199 | UniqueEnum unique; 200 | UniqueList.GetArray(-1-index, unique); 201 | index = unique.BaseItem; 202 | } 203 | 204 | ItemEnum item; 205 | Items.GetArray(index, item); 206 | if(item.Kv) 207 | item.Kv.Rewind(); 208 | 209 | return item.Kv; 210 | } 211 | 212 | public any Native_GetItemName(Handle plugin, int numParams) 213 | { 214 | if(Items == INVALID_HANDLE) 215 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 216 | 217 | int index = GetNativeCell(1); 218 | if(-UniqueList.Length>index || index>=Items.Length) 219 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, index); 220 | 221 | bool add; 222 | if(index < 0) 223 | { 224 | UniqueEnum unique; 225 | UniqueList.GetArray(-1-index, unique); 226 | if(unique.Name[0]) 227 | { 228 | SetNativeString(2, unique.Name, GetNativeCell(3), _, index); 229 | return index; 230 | } 231 | 232 | add = true; 233 | index = unique.BaseItem; 234 | } 235 | 236 | ItemEnum item; 237 | Items.GetArray(index, item); 238 | 239 | if(add) 240 | { 241 | index = strlen(item.Name); 242 | item.Name[index] = '*'; 243 | item.Name[index+1] = '\0'; 244 | } 245 | 246 | SetNativeString(2, item.Name, GetNativeCell(3), _, index); 247 | return index; 248 | } 249 | 250 | public any Native_SetItemName(Handle plugin, int numParams) 251 | { 252 | if(UniqueList == INVALID_HANDLE) 253 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 254 | 255 | int index = -1-GetNativeCell(1); 256 | if(index>=UniqueList.Length || index<0) 257 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, -1-index); 258 | 259 | UniqueEnum unique; 260 | UniqueList.GetArray(index, unique); 261 | GetNativeString(2, unique.Name, sizeof(unique.Name)); 262 | UniqueList.SetArray(index, unique); 263 | return 0; 264 | } 265 | 266 | public any Native_GetItemData(Handle plugin, int numParams) 267 | { 268 | if(UniqueList == INVALID_HANDLE) 269 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 270 | 271 | int index = -1-GetNativeCell(1); 272 | if(index>=UniqueList.Length || index<0) 273 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, -1-index); 274 | 275 | UniqueEnum unique; 276 | UniqueList.GetArray(index, unique); 277 | SetNativeString(2, unique.Data, GetNativeCell(3), _, index); 278 | return index; 279 | } 280 | 281 | public any Native_SetItemData(Handle plugin, int numParams) 282 | { 283 | if(UniqueList == INVALID_HANDLE) 284 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 285 | 286 | int index = -1-GetNativeCell(1); 287 | if(index>=UniqueList.Length || index<0) 288 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, -1-index); 289 | 290 | UniqueEnum unique; 291 | UniqueList.GetArray(index, unique); 292 | GetNativeString(2, unique.Data, sizeof(unique.Data)); 293 | UniqueList.SetArray(index, unique); 294 | return 0; 295 | } 296 | 297 | public any Native_NewUniqueItem(Handle plugin, int numParams) 298 | { 299 | if(UniqueList == INVALID_HANDLE) 300 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 301 | 302 | int client = GetNativeCell(1); 303 | if(client<0 || client>MAXPLAYERS) 304 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_CLIENTINDEX, client); 305 | 306 | int index = GetNativeCell(2); 307 | if(index<0 || index>=Items.Length) 308 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, index); 309 | 310 | char data[MAX_DATA_LENGTH]; 311 | GetNativeString(3, data, sizeof(data)); 312 | 313 | char name[MAX_ITEM_LENGTH]; 314 | GetNativeString(4, name, sizeof(name)); 315 | 316 | return -1-Unique_AddItem(index, client, GetNativeCell(5), name, data); 317 | } 318 | 319 | public any Native_UseItem(Handle plugin, int numParams) 320 | { 321 | if(Items == INVALID_HANDLE) 322 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 323 | 324 | int client = GetNativeCell(1); 325 | if(client<0 || client>MaxClients || !IsClientInGame(client)) 326 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_CLIENTINDEX, client); 327 | 328 | int index = GetNativeCell(2); 329 | if(index >= Items.Length) 330 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, index); 331 | 332 | if(index < 0) 333 | { 334 | index = -1-index; 335 | if(index >= UniqueList.Length) 336 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, -1-index); 337 | 338 | return Unique_UseItem(client, index, GetNativeCell(3)); 339 | } 340 | 341 | ItemEnum item; 342 | Items.GetArray(index, item); 343 | return UseThisItem(client, index, item, GetNativeCell(3)); 344 | } 345 | 346 | public any Native_GetItemHidden(Handle plugin, int numParams) 347 | { 348 | if(Items == INVALID_HANDLE) 349 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 350 | 351 | int index = GetNativeCell(1); 352 | if(-UniqueList.Length>index || index>=Items.Length) 353 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, index); 354 | 355 | if(index < 0) 356 | { 357 | UniqueEnum unique; 358 | UniqueList.GetArray(-1-index, unique); 359 | index = unique.BaseItem; 360 | } 361 | 362 | ItemEnum item; 363 | Items.GetArray(index, item); 364 | return item.Hidden; 365 | } 366 | 367 | public any Native_SetItemHidden(Handle plugin, int numParams) 368 | { 369 | if(Items == INVALID_HANDLE) 370 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 371 | 372 | int index = GetNativeCell(1); 373 | if(-UniqueList.Length>index || index>=Items.Length) 374 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, index); 375 | 376 | if(index < 0) 377 | { 378 | UniqueEnum unique; 379 | UniqueList.GetArray(-1-index, unique); 380 | index = unique.BaseItem; 381 | } 382 | 383 | ItemEnum item; 384 | Items.GetArray(index, item); 385 | item.Hidden = GetNativeCell(2); 386 | Items.SetArray(index, item); 387 | return 0; 388 | } 389 | 390 | public any Native_GetItemParent(Handle plugin, int numParams) 391 | { 392 | if(Items == INVALID_HANDLE) 393 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 394 | 395 | int index = GetNativeCell(1); 396 | if(-UniqueList.Length>index || index>=Items.Length) 397 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, index); 398 | 399 | if(index < 0) 400 | { 401 | UniqueEnum unique; 402 | UniqueList.GetArray(-1-index, unique); 403 | index = unique.BaseItem; 404 | } 405 | 406 | ItemEnum item; 407 | Items.GetArray(index, item); 408 | return item.Parent; 409 | } 410 | 411 | public any Native_SetItemParent(Handle plugin, int numParams) 412 | { 413 | if(Items == INVALID_HANDLE) 414 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_NOTREADY); 415 | 416 | int index = GetNativeCell(1); 417 | if(-UniqueList.Length>index || index>=Items.Length) 418 | ThrowNativeError(SP_ERROR_NATIVE, ERROR_ITEMINDEX, index); 419 | 420 | if(index < 0) 421 | { 422 | UniqueEnum unique; 423 | UniqueList.GetArray(-1-index, unique); 424 | index = unique.BaseItem; 425 | } 426 | 427 | ItemEnum item; 428 | Items.GetArray(index, item); 429 | item.Parent = GetNativeCell(2); 430 | Items.SetArray(index, item); 431 | return 0; 432 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore/stocks.sp: -------------------------------------------------------------------------------- 1 | #define IsValidClient(%1) (%1>0 && %1<=MaxClients && IsClientInGame(%1) && !IsFakeClient(%1) && !IsClientSourceTV(%1) && !IsClientReplay(%1)) 2 | 3 | stock void GenerateClientList(Menu menu, int client=0) 4 | { 5 | for(int target=1; target<=MaxClients; target++) 6 | { 7 | if(!IsValidClient(target)) 8 | continue; 9 | 10 | static char name[64]; 11 | GetClientName(target, name, sizeof(name)); 12 | if(client && !CanUserTarget(client, target)) 13 | { 14 | menu.AddItem("", name, ITEMDRAW_DISABLED); 15 | continue; 16 | } 17 | 18 | static char userid[16]; 19 | IntToString(GetClientUserId(target), userid, sizeof(userid)); 20 | menu.AddItem(userid, name); 21 | } 22 | } 23 | 24 | stock any abs(any i) 25 | { 26 | return i<0 ? -i : i; 27 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore/unique.sp: -------------------------------------------------------------------------------- 1 | enum struct UniqueEnum 2 | { 3 | int BaseItem; 4 | int Owner; 5 | bool Equipped; 6 | char Name[MAX_ITEM_LENGTH]; 7 | char Data[MAX_DATA_LENGTH]; 8 | } 9 | ArrayList UniqueList; 10 | 11 | void Unique_PluginStart() 12 | { 13 | UniqueList = new ArrayList(sizeof(UniqueEnum)); 14 | } 15 | 16 | void Unique_Disconnect(int client) 17 | { 18 | UniqueEnum unique; 19 | int length = UniqueList.Length; 20 | for(int i; i= 0) 67 | { 68 | Items.GetArray(primary, item); 69 | 70 | Menu menu = new Menu(UniqueH); 71 | menu.SetTitle("%s\n ", item.Name); 72 | 73 | int length = strlen(item.Name); 74 | item.Name[length] = '*'; 75 | item.Name[length+1] = '\0'; 76 | 77 | length = UniqueList.Length; 78 | bool found; 79 | for(int i; i 0) 130 | { 131 | panel.CurrentKey = 3; 132 | FormatEx(buffer, sizeof(buffer), "Sell (%d Credits)", sell); 133 | panel.DrawItem(buffer, unique.Equipped ? ITEMDRAW_DISABLED : ITEMDRAW_DEFAULT); 134 | panel.DrawText(" "); 135 | } 136 | } 137 | 138 | panel.CurrentKey = 8; 139 | panel.DrawItem("Back"); 140 | panel.DrawText(" "); 141 | panel.CurrentKey = 10; 142 | panel.DrawItem("Exit"); 143 | panel.Send(client, UniqueItemH, MENU_TIME_FOREVER); 144 | delete panel; 145 | } 146 | 147 | public int UniqueH(Menu menu, MenuAction action, int client, int choice) 148 | { 149 | switch(action) 150 | { 151 | case MenuAction_End: 152 | { 153 | delete menu; 154 | } 155 | case MenuAction_Cancel: 156 | { 157 | if(choice != MenuCancel_ExitBack) 158 | return 0; 159 | 160 | ReturnStoreType(client); 161 | } 162 | case MenuAction_Select: 163 | { 164 | static char buffer[MAX_NUM_LENGTH]; 165 | menu.GetItem(choice, buffer, sizeof(buffer)); 166 | if(buffer[0]) 167 | Client[client].AddPos(StringToInt(buffer)); 168 | 169 | Unique(client); 170 | } 171 | } 172 | return 0; 173 | } 174 | 175 | public int UniqueItemH(Menu panel, MenuAction action, int client, int choice) 176 | { 177 | if(action != MenuAction_Select) 178 | return 0; 179 | 180 | switch(choice) 181 | { 182 | case 1: 183 | { 184 | if(Unique_UseItem(client, -1-Client[client].GetPos())) 185 | Client[client].RemovePos(); 186 | } 187 | case 3: 188 | { 189 | int id = Client[client].GetPos(); 190 | int index = -1-id; 191 | 192 | UniqueEnum unique; 193 | UniqueList.GetArray(index, unique); 194 | if(unique.Owner==client && !unique.Equipped) 195 | { 196 | ItemEnum item; 197 | Items.GetArray(unique.BaseItem, item); 198 | int sell = GetSellPrice(unique.Data, item.Kv); 199 | if(sell > 0) 200 | { 201 | int temp = 1; 202 | int sell2 = sell; 203 | switch(Forward_OnSellItem(client, id, Client[client].Cash, temp, sell2)) 204 | { 205 | case Plugin_Changed: 206 | { 207 | sell = sell2; 208 | } 209 | case Plugin_Handled, Plugin_Stop: 210 | { 211 | Unique(client); 212 | return 0; 213 | } 214 | } 215 | 216 | Client[client].Cash += sell; 217 | unique.Owner = 0; 218 | UniqueList.SetArray(index, unique); 219 | Client[client].RemovePos(); 220 | } 221 | } 222 | } 223 | case 8: 224 | { 225 | Client[client].RemovePos(); 226 | } 227 | case 10: 228 | { 229 | Client[client].RemovePos(); 230 | return 0; 231 | } 232 | } 233 | Unique(client); 234 | return 0; 235 | } 236 | 237 | bool Unique_UseItem(int client, int index, bool auto=false) 238 | { 239 | UniqueEnum unique; 240 | UniqueList.GetArray(index, unique); 241 | 242 | if(unique.Owner == client) 243 | { 244 | ItemEnum item; 245 | Items.GetArray(unique.BaseItem, item); 246 | 247 | static char buffer[256]; 248 | item.Kv.GetString("plugin", buffer, sizeof(buffer)); 249 | 250 | static char name[48]; 251 | if(unique.Name[0]) 252 | { 253 | strcopy(name, sizeof(name), unique.Name); 254 | } 255 | else 256 | { 257 | FormatEx(name, sizeof(name), "%s*", item.Name); 258 | } 259 | 260 | int temp = 1; 261 | ItemResult result = Item_None; 262 | if(Forward_OnUseItem(result, buffer, client, unique.Equipped, item.Kv, -1-index, name, temp, auto)) 263 | { 264 | switch(result) 265 | { 266 | case Item_Used: 267 | { 268 | unique.Owner = 0; 269 | } 270 | case Item_On: 271 | { 272 | unique.Equipped = true; 273 | } 274 | case Item_Off: 275 | { 276 | unique.Equipped = false; 277 | } 278 | } 279 | 280 | UniqueList.SetArray(index, unique); 281 | } 282 | else if(CheckCommandAccess(client, "textstore_dev", ADMFLAG_RCON)) 283 | { 284 | SPrintToChat(client, "'%s' could not find plugin '%s'", item.Name, buffer); 285 | } 286 | else 287 | { 288 | SPrintToChat(client, "%s can't be used right now!", item.Name); 289 | } 290 | } 291 | return !unique.Owner; 292 | } 293 | 294 | static int GetSellPrice(const char[] data, KeyValues kv) 295 | { 296 | int sell = StrContains(data, "sell"); 297 | if(sell == -1) 298 | { 299 | sell = kv.GetNum("sell", RoundFloat(kv.GetNum("cost")*SELLRATIO)); 300 | } 301 | else 302 | { 303 | sell += 4; 304 | char buffer[16]; 305 | int size = strlen(data); 306 | for(int i; ; i++) 307 | { 308 | if(sell>=size || !IsCharNumeric(data[sell])) 309 | { 310 | buffer[i] = '\0'; 311 | break; 312 | } 313 | 314 | buffer[i] = data[sell]; 315 | sell++; 316 | } 317 | sell = StringToInt(buffer); 318 | } 319 | return sell; 320 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore_defaults.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #undef REQUIRE_EXTENSIONS 9 | #include 10 | #tryinclude 11 | #define REQUIRE_EXTENSIONS 12 | 13 | #undef REQUIRE_PLUGIN 14 | #tryinclude 15 | #tryinclude 16 | #tryinclude 17 | #define REQUIRE_PLUGIN 18 | 19 | #pragma newdecls required 20 | 21 | #define PLUGIN_VERSION "0.5.0" 22 | 23 | #define FAR_FUTURE 100000000.0 24 | #define MAX_MATERIAL_LENGTH 128 25 | #define MAX_CLASSNAME_LENGTH 64 26 | #define MAX_ITEM_LENGTH 48 27 | #define MAX_DESC_LENGTH 256 28 | #define MAX_TITLE_LENGTH 192 29 | #define MAX_DATA_LENGTH 256 30 | #define MAX_NUM_LENGTH 5 31 | 32 | EngineVersion GameType = Engine_Unknown; 33 | 34 | enum struct FullItemEnum 35 | { 36 | int Index; 37 | char Name[MAX_ITEM_LENGTH]; 38 | char Data[MAX_DATA_LENGTH]; 39 | } 40 | 41 | // SourceMod Events 42 | 43 | public Plugin myinfo = 44 | { 45 | name = "The Text Store: Defaults", 46 | author = "Batfoxkid", 47 | description = "Default store items", 48 | version = PLUGIN_VERSION 49 | }; 50 | 51 | public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) 52 | { 53 | #if defined _tVip_included 54 | MarkNativeAsOptional("tVip_GrantVip"); 55 | #endif 56 | 57 | #if defined _FF2_included 58 | MarkNativeAsOptional("FF2_GetBossIndex"); 59 | MarkNativeAsOptional("FF2_GetBossUserId"); 60 | MarkNativeAsOptional("FF2_GetBossName"); 61 | MarkNativeAsOptional("FF2_GetBossSpecial"); 62 | MarkNativeAsOptional("FF2_GetQueuePoints"); 63 | MarkNativeAsOptional("FF2_GetSpecialKV"); 64 | MarkNativeAsOptional("FF2_SelectBoss"); 65 | #endif 66 | 67 | #if defined _tf2items_included 68 | MarkNativeAsOptional("TF2Items_CreateItem"); 69 | MarkNativeAsOptional("TF2Items_SetClassname"); 70 | MarkNativeAsOptional("TF2Items_SetItemIndex"); 71 | MarkNativeAsOptional("TF2Items_SetLevel"); 72 | MarkNativeAsOptional("TF2Items_SetQuality"); 73 | MarkNativeAsOptional("TF2Items_SetNumAttributes"); 74 | MarkNativeAsOptional("TF2Items_SetAttribute"); 75 | MarkNativeAsOptional("TF2Items_GiveNamedItem"); 76 | #endif 77 | 78 | return APLRes_Success; 79 | } 80 | 81 | public void OnPluginStart() 82 | { 83 | char buffer[8]; 84 | GetGameFolderName(buffer, sizeof(buffer)); 85 | if(StrEqual(buffer, "csgo")) 86 | { 87 | GameType = Engine_CSGO; 88 | } 89 | else if(StrEqual(buffer, "tf")) 90 | { 91 | GameType = Engine_TF2; 92 | HookEvent("arena_round_start", OnArenaRoundStart, EventHookMode_PostNoCopy); 93 | HookEvent("post_inventory_application", OnPostInventoryApplication); 94 | } 95 | 96 | LoadTranslations("common.phrases"); 97 | } 98 | 99 | // Stocks 100 | 101 | stock bool IsValidClient(int client, bool replaycheck=true) 102 | { 103 | if(client<=0 || client>MaxClients) 104 | return false; 105 | 106 | if(!IsClientInGame(client)) 107 | return false; 108 | 109 | if(GameType==Engine_TF2 && GetEntProp(client, Prop_Send, "m_bIsCoaching")) 110 | return false; 111 | 112 | if(replaycheck && (IsClientSourceTV(client) || IsClientReplay(client))) 113 | return false; 114 | 115 | return true; 116 | } 117 | 118 | stock void GetClassesFromString(const char[] buffer, bool classes[10]) 119 | { 120 | classes[TFClass_Unknown] = StrContains(buffer, "mer", false)!=-1; 121 | classes[TFClass_Scout] = StrContains(buffer, "sco", false)!=-1; 122 | classes[TFClass_Soldier] = StrContains(buffer, "sol", false)!=-1; 123 | classes[TFClass_Pyro] = StrContains(buffer, "pyr", false)!=-1; 124 | classes[TFClass_DemoMan] = StrContains(buffer, "dem", false)!=-1; 125 | classes[TFClass_Heavy] = StrContains(buffer, "hea", false)!=-1; 126 | classes[TFClass_Engineer] = StrContains(buffer, "eng", false)!=-1; 127 | classes[TFClass_Medic] = StrContains(buffer, "med", false)!=-1; 128 | classes[TFClass_Sniper] = StrContains(buffer, "sni", false)!=-1; 129 | classes[TFClass_Spy] = StrContains(buffer, "spy", false)!=-1; 130 | } 131 | 132 | // Modules 133 | 134 | #tryinclude "textstore_defaults/boxes.sp" 135 | #tryinclude "textstore_defaults/chat.sp" 136 | #tryinclude "textstore_defaults/command.sp" 137 | #tryinclude "textstore_defaults/multi.sp" 138 | #tryinclude "textstore_defaults/trails.sp" 139 | #tryinclude "textstore_defaults/tvip.sp" 140 | #tryinclude "textstore_defaults/voting.sp" 141 | #tryinclude "textstore_defaults/tf2/ff2.sp" 142 | #tryinclude "textstore_defaults/tf2/items.sp" 143 | 144 | // Store Events 145 | 146 | public ItemResult TextStore_Item(int client, bool equipped, KeyValues item, int index, const char[] name, int &count) 147 | { 148 | static char buffer[MAX_MATERIAL_LENGTH]; 149 | item.GetString("type", buffer, MAX_MATERIAL_LENGTH); 150 | 151 | #if defined ITEM_BOXES 152 | if(StrEqual(buffer, ITEM_BOXES)) 153 | return Boxes_Use(client, equipped, item, index, name, count); 154 | #endif 155 | 156 | #if defined ITEM_CHAT 157 | if(StrEqual(buffer, ITEM_CHAT)) 158 | return Chat_Use(client, equipped, item, index, name, count); 159 | #endif 160 | 161 | #if defined ITEM_COMMAND 162 | if(StrEqual(buffer, ITEM_COMMAND)) 163 | return Command_Use(client, equipped, item, index, name, count); 164 | #endif 165 | 166 | #if defined ITEM_MULTI 167 | if(StrEqual(buffer, ITEM_MULTI)) 168 | return Multi_Use(client, equipped, item, index, name, count); 169 | #endif 170 | 171 | #if defined ITEM_TRAIL 172 | if(StrEqual(buffer, ITEM_TRAIL)) 173 | return Trail_Use(client, equipped, item, index, name, count); 174 | #endif 175 | 176 | #if defined ITEM_TVIP 177 | if(StrEqual(buffer, ITEM_TVIP)) 178 | return tVip_Use(client, equipped, item, index, name, count); 179 | #endif 180 | 181 | #if defined ITEM_VOTE 182 | if(StrEqual(buffer, ITEM_VOTE)) 183 | return Vote_Use(client, equipped, item, index, name, count); 184 | #endif 185 | 186 | #if defined ITEM_TF2_FF2 187 | if(StrEqual(buffer, ITEM_TF2_FF2)) 188 | return FF2_Use(client, equipped, item, index, name, count); 189 | #endif 190 | 191 | #if defined ITEM_TF2_ITEMS 192 | if(StrEqual(buffer, ITEM_TF2_ITEMS)) 193 | return TF2Items_Use(client, equipped, item, index, name, count); 194 | #endif 195 | 196 | SPrintToChat(client, "This item has no effect!"); 197 | return Item_None; 198 | } 199 | 200 | public void OnArenaRoundStart(Event event, const char[] name, bool dontBroadcast) 201 | { 202 | #if defined ITEM_TF2_FF2 203 | FF2_OnArenaRoundStart(); 204 | #endif 205 | } 206 | 207 | public void OnPostInventoryApplication(Event event, const char[] name, bool dontBroadcast) 208 | { 209 | #if defined ITEM_TF2_ITEMS 210 | TF2Items_OnPostInventoryApplication(event); 211 | #endif 212 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore_defaults/boxes.sp: -------------------------------------------------------------------------------- 1 | #define ITEM_BOXES "boxes" 2 | 3 | stock ItemResult Boxes_Use(int client, bool equipped, KeyValues kv, int index, const char[] name, int &count) 4 | { 5 | int maxItems = TextStore_GetItems(); 6 | int amount; 7 | static char buffer[MAX_ITEM_LENGTH], buffer2[MAX_ITEM_LENGTH+MAX_ITEM_LENGTH+MAX_DATA_LENGTH]; 8 | kv.GetString("locked", buffer, sizeof(buffer)); 9 | if(buffer[0]) 10 | { 11 | bool found; 12 | for(int i; i 0) 20 | { 21 | TextStore_SetInv(client, i, amount-1); 22 | found = true; 23 | } 24 | break; 25 | } 26 | 27 | if(!found) 28 | { 29 | SPrintToChat(client, "This item requires %s%s", STORE_COLOR2, buffer); 30 | return Item_None; 31 | } 32 | } 33 | 34 | static char buffers[3][MAX_DATA_LENGTH]; 35 | ArrayList list = new ArrayList(sizeof(FullItemEnum)); 36 | ArrayList bonus = new ArrayList(sizeof(FullItemEnum)); 37 | if(kv.GotoFirstSubKey()) 38 | { 39 | kv.GetSectionName(buffer, sizeof(buffer)); 40 | do 41 | { 42 | if(StrContains(buffer, ".") != -1) 43 | { 44 | float chance = StringToFloat(buffer); 45 | if(chance >= GetRandomFloat()) 46 | { 47 | for(amount=1; ; amount++) 48 | { 49 | IntToString(amount, buffer, sizeof(buffer)); 50 | kv.GetString(buffer, buffer2, sizeof(buffer2)); 51 | if(!buffer2[0]) 52 | break; 53 | } 54 | 55 | if(amount != 1) 56 | { 57 | amount = GetRandomInt(1, amount-1); 58 | IntToString(amount, buffer, sizeof(buffer)); 59 | kv.GetString(buffer, buffer2, sizeof(buffer2)); 60 | 61 | amount = ExplodeString(buffer2, ";", buffers, sizeof(buffers), sizeof(buffers[])); 62 | for(int i; i 1) 72 | { 73 | strcopy(item.Data, sizeof(item.Data), buffers[1]); 74 | if(amount > 2) 75 | strcopy(item.Name, sizeof(item.Name), buffers[2]); 76 | } 77 | 78 | bonus.PushArray(item); 79 | break; 80 | } 81 | } 82 | } 83 | continue; 84 | } 85 | 86 | int chance = StringToInt(buffer); 87 | if(chance < 1) 88 | continue; 89 | 90 | for(int i=1; ; i++) 91 | { 92 | IntToString(i, buffer, sizeof(buffer)); 93 | kv.GetString(buffer, buffer2, sizeof(buffer2)); 94 | if(!buffer2[0]) 95 | break; 96 | 97 | amount = ExplodeString(buffer2, ";", buffers, sizeof(buffers), sizeof(buffers[])); 98 | for(int a; a 1) 108 | { 109 | strcopy(item.Data, sizeof(item.Data), buffers[1]); 110 | if(amount > 2) 111 | strcopy(item.Name, sizeof(item.Name), buffers[2]); 112 | } 113 | 114 | for(amount=0; amount= 0) 9 | { 10 | IntToString(client, buffer2, sizeof(buffer2)); 11 | ReplaceString(buffer, sizeof(buffer), "{clientid}", buffer2); 12 | } 13 | 14 | if(StrContains(buffer, "{userid}") >= 0) 15 | { 16 | IntToString(GetClientUserId(client), buffer2, sizeof(buffer2)); 17 | ReplaceString(buffer, sizeof(buffer), "{userid}", buffer2); 18 | } 19 | 20 | if(StrContains(buffer, "{steamid}") >= 0) 21 | { 22 | if(GetClientAuthId(client, AuthId_Steam2, buffer2, sizeof(buffer2))) 23 | ReplaceString(buffer, sizeof(buffer), "{steamid}", buffer2); 24 | } 25 | 26 | if(StrContains(buffer, "{name}") >= 0) 27 | { 28 | if(GetClientName(client, buffer2, sizeof(buffer2))) 29 | ReplaceString(buffer, sizeof(buffer), "{name}", buffer2); 30 | } 31 | 32 | item.GetString("fail", buffer2, sizeof(buffer2)); 33 | if(!buffer2[0]) 34 | { 35 | item.GetString("success", buffer2, sizeof(buffer2)); 36 | if(!buffer2[0]) 37 | { 38 | switch(item.GetNum("client")) 39 | { 40 | case 1: 41 | ClientCommand(client, buffer); 42 | 43 | case 2: 44 | FakeClientCommand(client, buffer); 45 | 46 | case 3: 47 | FakeClientCommandEx(client, buffer); 48 | 49 | default: 50 | ServerCommand(buffer); 51 | } 52 | return Item_Used; 53 | } 54 | } 55 | 56 | ServerCommandEx(buffer2, sizeof(buffer2), buffer); 57 | 58 | item.GetString("fail", buffer, sizeof(buffer)); 59 | if(buffer[0] && StrContains(buffer2, buffer)>=0) 60 | return Item_None; 61 | 62 | item.GetString("success", buffer, sizeof(buffer)); 63 | if(buffer[0] && StrContains(buffer2, buffer)<0) 64 | return Item_None; 65 | 66 | return Item_Used; 67 | } 68 | -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore_defaults/multi.sp: -------------------------------------------------------------------------------- 1 | #define ITEM_MULTI "multi" 2 | 3 | stock ItemResult Multi_Use(int client, bool equipped, KeyValues kv, int index, const char[] name, int &count) 4 | { 5 | int maxItems = TextStore_GetItems(); 6 | int amount; 7 | static char buffer[MAX_ITEM_LENGTH], buffer2[MAX_DATA_LENGTH+MAX_ITEM_LENGTH+MAX_ITEM_LENGTH]; 8 | kv.GetString("locked", buffer, sizeof(buffer)); 9 | if(buffer[0]) 10 | { 11 | bool found; 12 | for(int i; i 0) 20 | { 21 | TextStore_SetInv(client, i, amount-1); 22 | found = true; 23 | } 24 | break; 25 | } 26 | 27 | if(!found) 28 | { 29 | SPrintToChat(client, "This item requires %s%s", STORE_COLOR2, buffer); 30 | return Item_None; 31 | } 32 | } 33 | 34 | for(int i=1; ; i++) 35 | { 36 | IntToString(i, buffer, sizeof(buffer)); 37 | kv.GetString(buffer, buffer2, sizeof(buffer2)); 38 | if(!buffer2[0]) 39 | break; 40 | 41 | static char buffers[3][MAX_DATA_LENGTH]; 42 | amount = ExplodeString(buffer2, ";", buffers, sizeof(buffers), sizeof(buffers[])); 43 | 44 | for(int a; a 1) 51 | { 52 | TextStore_CreateUniqueItem(client, a, buffers[1], amount>2 ? buffers[2] : NULL_STRING); 53 | } 54 | else 55 | { 56 | TextStore_GetInv(client, a, amount); 57 | TextStore_SetInv(client, a, amount+1); 58 | } 59 | 60 | SPrintToChat(client, "You unboxed %s%s", STORE_COLOR2, amount>2 ? buffers[2] : buffer2); 61 | break; 62 | } 63 | } 64 | return Item_Used; 65 | } 66 | -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore_defaults/tf2/ff2.sp: -------------------------------------------------------------------------------- 1 | #if !defined _FF2_included 2 | #endinput 3 | #endif 4 | 5 | #define ITEM_TF2_FF2 "freak_fortress_2" 6 | 7 | static ArrayList FF2Changes[36]; 8 | static char FF2Selection[36][64]; 9 | static int FF2StoreIndex[36]; 10 | 11 | stock ItemResult FF2_Use(int client, bool equipped, KeyValues item, int index, const char[] name, int &count) 12 | { 13 | if(GameType != Engine_TF2) 14 | { 15 | if(CheckCommandAccess(client, "textstore_dev", ADMFLAG_RCON)) 16 | { 17 | SPrintToChat(client, "Incorrect game type for %s", name); 18 | } 19 | else 20 | { 21 | SPrintToChat(client, "This can't be used right now!"); 22 | } 23 | return Item_None; 24 | } 25 | 26 | static char buffer[256]; 27 | if(GetFeatureStatus(FeatureType_Native, "FF2_GetQueuePoints") != FeatureStatus_Available) 28 | { 29 | if(CheckCommandAccess(client, "textstore_dev", ADMFLAG_RCON)) 30 | { 31 | item.GetString("plugin", buffer, sizeof(buffer)); 32 | SPrintToChat(client, "%s can't find Freak Fortress 2 natives!", buffer); 33 | } 34 | else 35 | { 36 | SPrintToChat(client, "This can't be used right now!"); 37 | } 38 | return Item_None; 39 | } 40 | 41 | bool used; 42 | // Give queue points 43 | { 44 | int points = item.GetNum("points"); 45 | if(points) 46 | { 47 | FF2_SetQueuePoints(client, FF2_GetQueuePoints(client)+points); 48 | SPrintToChat(client, "You have %s %i queue point(s)", points<0 ? "lost" : "gained", points); 49 | used = true; 50 | } 51 | } 52 | 53 | static char boss[64]; 54 | // Unlock a boss 55 | item.GetString("unlock", buffer, sizeof(buffer)); 56 | if(buffer[0]) 57 | { 58 | for(int i; ; i++) 59 | { 60 | KeyValues kv = view_as(FF2_GetSpecialKV(i, 1)); 61 | if(kv == INVALID_HANDLE) 62 | break; 63 | 64 | kv.GetString("filename", boss, sizeof(boss)); 65 | if(StrEqual(buffer, boss, false)) 66 | { 67 | kv.SetNum("blocked", 0); 68 | kv.SetNum("donator", 0); 69 | kv.SetNum("admin", 0); 70 | kv.SetNum("owner", 0); 71 | kv.SetNum("theme", 0); 72 | kv.SetNum("hidden", 0); 73 | kv.GetString("name", boss, sizeof(boss)); 74 | for(int target=1; target<=MaxClients; target++) 75 | { 76 | if(!IsValidClient(target)) 77 | continue; 78 | 79 | FF2_GetName(i, boss, sizeof(boss), 1, target); 80 | SPrintToChat(target, "%s%s%s is now unlocked for the map duration!", STORE_COLOR2, buffer, STORE_COLOR); 81 | } 82 | used = true; 83 | break; 84 | } 85 | } 86 | 87 | if(used) 88 | { 89 | if(index < 0) 90 | { 91 | if(TextStore_GetItemData(index, buffer, sizeof(buffer)) && StrContains(buffer, "infinite")!=-1) 92 | used = false; 93 | } 94 | } 95 | else 96 | { 97 | SPrintToChat(client, "%s%s%s is not available right now!", STORE_COLOR2, buffer, STORE_COLOR); 98 | } 99 | } 100 | 101 | // Select a boss (Unofficial FF2) 102 | item.GetString("select", buffer, sizeof(buffer)); 103 | if(buffer[0] && GetFeatureStatus(FeatureType_Native, "FF2_SelectBoss")==FeatureStatus_Available) 104 | { 105 | for(int i; ; i++) 106 | { 107 | KeyValues kv = view_as(FF2_GetSpecialKV(i, 1)); 108 | if(kv == INVALID_HANDLE) 109 | break; 110 | 111 | kv.GetString("filename", boss, sizeof(boss)); 112 | if(StrEqual(buffer, boss, false)) 113 | { 114 | kv.GetString("name", boss, sizeof(boss)); 115 | FF2_SelectBoss(client, boss, true); 116 | strcopy(FF2Selection[client], sizeof(FF2Selection[]), boss); 117 | FF2StoreIndex[client] = index; 118 | FF2_GetName(i, boss, sizeof(boss), 1, client); 119 | SPrintToChat(client, "%s%s%s is now selected!", STORE_COLOR2, boss, STORE_COLOR); 120 | used = true; 121 | break; 122 | } 123 | } 124 | 125 | if(!used) 126 | SPrintToChat(client, "%s%s%s is not available right now!", STORE_COLOR2, buffer, STORE_COLOR); 127 | 128 | used = false; 129 | } 130 | 131 | if(used) 132 | return Item_Used; 133 | 134 | // Change bosses 135 | item.GetString("change", buffer, sizeof(buffer)); 136 | if(buffer[0]) 137 | { 138 | if(FF2Changes[client] == INVALID_HANDLE) 139 | FF2Changes[client] = new ArrayList(); 140 | 141 | int length = FF2Changes[client].Length; 142 | for(int i; i 0) 204 | { 205 | if(FF2StoreIndex[client]>=0 || !TextStore_GetItemData(FF2StoreIndex[client], buffer, sizeof(buffer)) || StrContains(buffer, "infinite")==-1) 206 | { 207 | TextStore_SetInv(client, FF2StoreIndex[client], items-1, items==1 ? 0 : -1); 208 | } 209 | } 210 | else 211 | { 212 | LogError("Exploit detected with Select FF2 Item! Client: %N Index: %i Count: %i Boss: %s", client, FF2StoreIndex[client], items, FF2Selection[client]); 213 | } 214 | } 215 | FF2StoreIndex[client] = 0; 216 | return Plugin_Changed; 217 | } 218 | } 219 | return Plugin_Continue; 220 | } 221 | 222 | void FF2_OnArenaRoundStart() 223 | { 224 | if(GetFeatureStatus(FeatureType_Native, "FF2_SelectBoss") != FeatureStatus_Available) 225 | return; 226 | 227 | for(int client=1; client<=MaxClients; client++) 228 | { 229 | if(!FF2StoreIndex[client] || !IsValidClient(client)) 230 | continue; 231 | 232 | int boss = FF2_GetBossIndex(client); 233 | if(boss == -1) 234 | continue; 235 | 236 | static char buffer[256]; 237 | FF2_GetBossSpecial(boss, buffer, sizeof(buffer), 0); 238 | if(StrEqual(buffer, FF2Selection[client])) 239 | { 240 | FF2_SelectBoss(client, "", false); 241 | 242 | int items; 243 | TextStore_GetInv(client, FF2StoreIndex[client], items); 244 | if(items > 0) 245 | { 246 | if(FF2StoreIndex[client]>=0 || !TextStore_GetItemData(FF2StoreIndex[client], buffer, sizeof(buffer)) || StrContains(buffer, "infinite")==-1) 247 | { 248 | TextStore_SetInv(client, FF2StoreIndex[client], items-1, items==1 ? 0 : -1); 249 | } 250 | } 251 | else 252 | { 253 | LogError("Exploit detected with Select FF2 Item! Client: %N Index: %i Count: %i Boss: %s", client, FF2StoreIndex[client], items, FF2Selection[client]); 254 | } 255 | } 256 | 257 | FF2StoreIndex[client] = 0; 258 | } 259 | } 260 | 261 | public Action TextStore_OnSellItem(int client, int item, int cash, int &count, int &sell) 262 | { 263 | if(count>1 || FF2StoreIndex[client]!=item) 264 | return Plugin_Continue; 265 | 266 | SPrintToChat(client, "You can not sell this item right now!"); 267 | return Plugin_Handled; 268 | } 269 | 270 | static void FF2_GetName(int boss, char[] buffer, int length, int mode, int client) 271 | { 272 | if(GetFeatureStatus(FeatureType_Native, "FF2_GetBossName") == FeatureStatus_Available) 273 | { 274 | FF2_GetBossName(boss, buffer, length, mode, client); 275 | } 276 | else 277 | { 278 | FF2_GetBossSpecial(boss, buffer, length, mode); 279 | } 280 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore_defaults/tf2/items.sp: -------------------------------------------------------------------------------- 1 | #if !defined _tf2items_included 2 | #endinput 3 | #endif 4 | 5 | #define ITEM_TF2_ITEMS "tf2items" 6 | 7 | static const char DefaultClasses[] = "soldier pyro heavy"; 8 | static const char DefaultClassname[] = "tf_weapon_shotgun"; 9 | static const int DefaultIndex = 199; 10 | static const int DefaultSlot = TFWeaponSlot_Secondary; 11 | static ArrayList Loadout[36]; 12 | 13 | stock ItemResult TF2Items_Use(int client, bool equipped, KeyValues item, int index, const char[] name, int &count) 14 | { 15 | if(GameType != Engine_TF2) 16 | { 17 | if(CheckCommandAccess(client, "textstore_dev", ADMFLAG_RCON)) 18 | { 19 | SPrintToChat(client, "Incorrect game type for %s", name); 20 | } 21 | else 22 | { 23 | SPrintToChat(client, "This can't be used right now!"); 24 | } 25 | return Item_None; 26 | } 27 | 28 | static char buffer[128]; 29 | item.GetString("class", buffer, sizeof(buffer), DefaultClasses); 30 | 31 | static bool classes[10]; 32 | GetClassesFromString(buffer, classes); 33 | 34 | int slot = item.GetNum("weapon", DefaultSlot); 35 | 36 | if(Loadout[client] == INVALID_HANDLE) 37 | Loadout[client] = new ArrayList(); 38 | 39 | static char buffer2[128]; 40 | int length = Loadout[client].Length; 41 | for(int i; i=0 && level<6) 105 | TF2_RemoveWeaponSlot(client, level); 106 | 107 | level = kv.GetNum("level", 5); 108 | static char name[36]; 109 | kv.GetString("classname", name, sizeof(name), DefaultClassname); 110 | GiveWeapon(client, name, index, level, buffer, class); 111 | } 112 | } 113 | } 114 | } 115 | 116 | static void GiveWeapon(int client, char[] name, int index, int level, const char[] attributes, TFClassType class) 117 | { 118 | if(StrEqual(name, "saxxy", false)) 119 | { 120 | switch(class) 121 | { 122 | case TFClass_Scout: strcopy(name, 36, "tf_weapon_bat"); 123 | case TFClass_Pyro: strcopy(name, 36, "tf_weapon_fireaxe"); 124 | case TFClass_DemoMan: strcopy(name, 36, "tf_weapon_bottle"); 125 | case TFClass_Heavy: strcopy(name, 36, "tf_weapon_fists"); 126 | case TFClass_Engineer: strcopy(name, 36, "tf_weapon_wrench"); 127 | case TFClass_Medic: strcopy(name, 36, "tf_weapon_bonesaw"); 128 | case TFClass_Sniper: strcopy(name, 36, "tf_weapon_club"); 129 | case TFClass_Spy: strcopy(name, 36, "tf_weapon_knife"); 130 | default: strcopy(name, 36, "tf_weapon_shovel"); 131 | } 132 | } 133 | else if(StrEqual(name, "tf_weapon_shotgun", false)) 134 | { 135 | switch(class) 136 | { 137 | case TFClass_Pyro: strcopy(name, 36, "tf_weapon_shotgun_pyro"); 138 | case TFClass_Heavy: strcopy(name, 36, "tf_weapon_shotgun_hwg"); 139 | case TFClass_Engineer: strcopy(name, 36, "tf_weapon_shotgun_primary"); 140 | default: strcopy(name, 36, "tf_weapon_shotgun_soldier"); 141 | } 142 | } 143 | 144 | char atts[40][40]; 145 | int count = ExplodeString(attributes, ";", atts, sizeof(atts), sizeof(atts[])); 146 | 147 | if(count % 2) 148 | count--; 149 | 150 | int entity = OVERRIDE_ALL|FORCE_GENERATION; 151 | if(!count) 152 | entity |= PRESERVE_ATTRIBUTES; 153 | 154 | Handle weapon = TF2Items_CreateItem(entity); 155 | if(weapon != INVALID_HANDLE) 156 | { 157 | TF2Items_SetClassname(weapon, name); 158 | TF2Items_SetItemIndex(weapon, index); 159 | TF2Items_SetLevel(weapon, level); 160 | TF2Items_SetQuality(weapon, 10); 161 | 162 | TF2Items_SetNumAttributes(weapon, count/2); 163 | entity = 0; 164 | for(int i; i MaxClients) 174 | { 175 | EquipPlayerWeapon(client, entity); 176 | SetEntProp(entity, Prop_Send, "m_bValidatedAttachedEntity", 1); 177 | SetEntProp(entity, Prop_Send, "m_iAccountID", GetSteamAccountID(client)); 178 | 179 | if(StrEqual(name, "tf_weapon_builder", false) && index!=735) 180 | { 181 | SetEntProp(entity, Prop_Send, "m_aBuildableObjectTypes", 1, _, 0); 182 | SetEntProp(entity, Prop_Send, "m_aBuildableObjectTypes", 1, _, 1); 183 | SetEntProp(entity, Prop_Send, "m_aBuildableObjectTypes", 1, _, 2); 184 | SetEntProp(entity, Prop_Send, "m_aBuildableObjectTypes", 0, _, 3); 185 | } 186 | else if(StrEqual(name, "tf_weapon_sapper", false) || index==735) 187 | { 188 | SetEntProp(entity, Prop_Send, "m_iObjectType", 3); 189 | SetEntProp(entity, Prop_Data, "m_iSubType", 3); 190 | SetEntProp(entity, Prop_Send, "m_aBuildableObjectTypes", 0, _, 0); 191 | SetEntProp(entity, Prop_Send, "m_aBuildableObjectTypes", 0, _, 1); 192 | SetEntProp(entity, Prop_Send, "m_aBuildableObjectTypes", 0, _, 2); 193 | SetEntProp(entity, Prop_Send, "m_aBuildableObjectTypes", 1, _, 3); 194 | } 195 | } 196 | } 197 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore_defaults/trails.sp: -------------------------------------------------------------------------------- 1 | #define ITEM_TRAIL "trail" 2 | 3 | enum struct TrailEnum 4 | { 5 | char Path[MAX_MATERIAL_LENGTH]; 6 | int Color[4]; 7 | float Width; 8 | int Precache; 9 | int Entity; 10 | 11 | int Setup(const char[] material, float width, int color[4]) 12 | { 13 | this.Width = width; 14 | this.Color[0] = color[0]; 15 | this.Color[1] = color[1]; 16 | this.Color[2] = color[2]; 17 | this.Color[3] = color[3]; 18 | strcopy(this.Path, MAX_MATERIAL_LENGTH, material); 19 | this.Precache = PrecacheModel(material); 20 | if(!this.Precache) 21 | this.Path[0] = 0; 22 | 23 | return this.Precache; 24 | } 25 | 26 | void Clear(int client) 27 | { 28 | this.Path[0] = 0; 29 | Trail_Remove(client); 30 | } 31 | } 32 | 33 | static TrailEnum Trail[MAXPLAYERS+1]; 34 | static int TrailOwner[2048]; 35 | 36 | stock ItemResult Trail_Use(int client, bool equipped, KeyValues item, int index, const char[] name, int &count) 37 | { 38 | if(equipped) 39 | { 40 | Trail[client].Clear(client); 41 | return Item_Off; 42 | } 43 | 44 | if(!IsPlayerAlive(client)) 45 | { 46 | SPrintToChat(client, "You must be alive to equip this!"); 47 | return Item_None; 48 | } 49 | 50 | int color[4]; 51 | static char buffer[MAX_MATERIAL_LENGTH]; 52 | item.GetString("material", buffer, MAX_MATERIAL_LENGTH); 53 | item.GetColor4("color", color); 54 | if(!color[3]) 55 | { 56 | for(int i; i<4; i++) 57 | { 58 | color[i] = 255; 59 | } 60 | } 61 | 62 | Trail[client].Setup(buffer, item.GetFloat("width", 10.0), color); 63 | RequestFrame(Trail_Create, GetClientUserId(client)); 64 | return Item_On; 65 | } 66 | 67 | public void Trail_Create(int userid) 68 | { 69 | int client = GetClientOfUserId(userid); 70 | if(!IsValidClient(client)) 71 | return; 72 | 73 | if(!Trail[client].Path[0]) 74 | return; 75 | 76 | if(GameType == Engine_CSGO) 77 | { 78 | if(!Trail[client].Entity || !IsValidEdict(Trail[client].Entity)) 79 | { 80 | Trail[client].Entity = CreateEntityByName("env_sprite"); 81 | DispatchKeyValue(Trail[client].Entity, "classname", "env_sprite"); 82 | DispatchKeyValue(Trail[client].Entity, "spawnflags", "1"); 83 | DispatchKeyValue(Trail[client].Entity, "scale", "0.0"); 84 | DispatchKeyValue(Trail[client].Entity, "rendermode", "10"); 85 | DispatchKeyValue(Trail[client].Entity, "rendercolor", "255 255 255 0"); 86 | { 87 | char num[6]; 88 | IntToString(Trail[client].Precache, num, sizeof(num)); 89 | DispatchKeyValue(Trail[client].Entity, "model", num); 90 | } 91 | DispatchSpawn(Trail[client].Entity); 92 | Trail_Attach(Trail[client].Entity, client); 93 | SDKHook(Trail[client].Entity, SDKHook_SetTransmit, Trail_Transmit); 94 | } 95 | 96 | int color[4]; 97 | color[0] = Trail[client].Color[0]; 98 | color[1] = Trail[client].Color[1]; 99 | color[2] = Trail[client].Color[2]; 100 | color[3] = Trail[client].Color[3]; 101 | TE_SetupBeamFollow(Trail[client].Entity, Trail[client].Precache, 0, 0.8, Trail[client].Width, Trail[client].Width, 10, color); 102 | TE_SendToAll(); 103 | return; 104 | } 105 | 106 | Trail[client].Entity = CreateEntityByName("env_spritetrail"); 107 | SetEntPropFloat(Trail[client].Entity, Prop_Send, "m_flTextureRes", 0.05); 108 | 109 | char temp[17]; 110 | FormatEx(temp, sizeof(temp), "%i %i %i %i", Trail[client].Color[0], Trail[client].Color[1], Trail[client].Color[2], Trail[client].Color[3]); 111 | DispatchKeyValue(Trail[client].Entity, "renderamt", "255"); 112 | DispatchKeyValue(Trail[client].Entity, "rendercolor", temp); 113 | DispatchKeyValue(Trail[client].Entity, "lifetime", "0.8"); 114 | DispatchKeyValue(Trail[client].Entity, "rendermode", "5"); 115 | DispatchKeyValue(Trail[client].Entity, "spritename", Trail[client].Path); 116 | 117 | FloatToString(Trail[client].Width, temp, sizeof(temp)); 118 | DispatchKeyValue(Trail[client].Entity, "startwidth", temp); 119 | DispatchKeyValue(Trail[client].Entity, "endwidth", temp); 120 | 121 | DispatchSpawn(Trail[client].Entity); 122 | Trail_Attach(Trail[client].Entity, client); 123 | 124 | SDKHook(Trail[client].Entity, SDKHook_SetTransmit, Trail_Transmit); 125 | TrailOwner[Trail[client].Entity] = client; 126 | } 127 | 128 | static void Trail_Remove(int client) 129 | { 130 | if(Trail[client].Entity && IsValidEdict(Trail[client].Entity)) 131 | { 132 | TrailOwner[Trail[client].Entity] = 0; 133 | static char classname[MAX_CLASSNAME_LENGTH]; 134 | GetEdictClassname(Trail[client].Entity, classname, MAX_CLASSNAME_LENGTH); 135 | if(StrEqual("env_spritetrail", classname)) 136 | { 137 | SDKUnhook(Trail[client].Entity, SDKHook_SetTransmit, Trail_Transmit); 138 | AcceptEntityInput(Trail[client].Entity, "Kill"); 139 | } 140 | } 141 | Trail[client].Entity = 0; 142 | } 143 | 144 | static void Trail_Attach(int entity, int client) 145 | { 146 | static float org[3], ang[3]; 147 | static const float temp[3] = {0.0, 90.0, 0.0}; 148 | static const float pos[3] = {0.0, 0.0, 5.0}; 149 | GetEntPropVector(client, Prop_Data, "m_angAbsRotation", ang); 150 | SetEntPropVector(client, Prop_Data, "m_angAbsRotation", temp); 151 | GetClientAbsOrigin(client, org); 152 | AddVectors(org, pos, org); 153 | TeleportEntity(entity, org, temp, NULL_VECTOR); 154 | SetVariantString("!activator"); 155 | AcceptEntityInput(entity, "SetParent", client, entity); 156 | SetEntPropVector(client, Prop_Data, "m_angAbsRotation", ang); 157 | } 158 | 159 | public Action Trail_Transmit(int entity, int client) 160 | { 161 | if(!IsValidClient(TrailOwner[entity])) 162 | return Plugin_Handled; 163 | 164 | if(!IsPlayerAlive(TrailOwner[entity])) 165 | return Plugin_Handled; 166 | 167 | if(GameType != Engine_TF2) 168 | return Plugin_Continue; 169 | 170 | return (GetClientTeam(TrailOwner[entity])!=GetClientTeam(client) && (TF2_IsPlayerInCondition(TrailOwner[entity], TFCond_Cloaked) || TF2_IsPlayerInCondition(TrailOwner[entity], TFCond_Stealthed))) ? Plugin_Handled : Plugin_Continue; 171 | } 172 | -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore_defaults/tvip.sp: -------------------------------------------------------------------------------- 1 | #if defined _tVip_included 2 | #define ITEM_TVIP "tvip" 3 | 4 | public ItemResult tVip_Use(int client, bool equipped, KeyValues item, int index, const char[] name, int &count) 5 | { 6 | if(CheckCommandAccess(client, "batstore_donator", ADMFLAG_RESERVATION, true)) 7 | { 8 | SPrintToChat(client, "You already have donator status!"); 9 | return Item_None; 10 | } 11 | 12 | if(GetFeatureStatus(FeatureType_Native, "tVip_GrantVip") != FeatureStatus_Available) 13 | { 14 | if(CheckCommandAccess(client, "textstore_dev", ADMFLAG_RCON)) 15 | { 16 | char buffer[256]; 17 | item.GetString("plugin", buffer, sizeof(buffer)); 18 | SPrintToChat(client, "%s can't find tVip natives!", buffer); 19 | } 20 | else 21 | { 22 | SPrintToChat(client, "This can't be used right now!"); 23 | } 24 | return Item_None; 25 | } 26 | 27 | tVip_GrantVip(client, 0, item.GetNum("duration", 60), 1); 28 | return Item_Used; 29 | } 30 | #endif 31 | -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore_defaults/voting.sp: -------------------------------------------------------------------------------- 1 | #define ITEM_VOTE "voting" 2 | 3 | char VoteCommand[512]; 4 | ArrayList VoteDone; 5 | int VoteCaster; 6 | int VoteIndex; 7 | float VoteMap; 8 | 9 | public ItemResult Vote_Use(int client, bool equipped, KeyValues item, int index, const char[] name, int &count) 10 | { 11 | if(VoteDone!=INVALID_HANDLE && VoteDone.FindValue(index)!=-1) 12 | { 13 | SPrintToChat(client, "This has already been casted before!"); 14 | return Item_None; 15 | } 16 | 17 | if(IsVoteInProgress()) 18 | { 19 | PrintToChat(client, "[SM] %t", "Vote in Progress"); 20 | return Item_None; 21 | } 22 | 23 | if(!TestVoteDelay(client)) 24 | return Item_None; 25 | 26 | VoteCaster = GetClientUserId(client); 27 | VoteIndex = index; 28 | 29 | if(item.GetNum("once")) 30 | { 31 | if(VoteDone == INVALID_HANDLE) 32 | VoteDone = new ArrayList(); 33 | 34 | VoteDone.Push(index); 35 | } 36 | 37 | VoteMap = item.GetFloat("maptime"); 38 | 39 | Menu menu = CreateMenu(Vote_UseH, view_as(MENU_ACTIONS_ALL)); 40 | item.GetString("title", VoteCommand, sizeof(VoteCommand)); 41 | menu.SetTitle(VoteCommand); 42 | 43 | item.GetString("command", VoteCommand, sizeof(VoteCommand)); 44 | 45 | menu.AddItem("", "Yes"); 46 | menu.AddItem("", "No"); 47 | 48 | menu.ExitButton = false; 49 | menu.DisplayVoteToAll(20); 50 | return Item_None; 51 | } 52 | 53 | public int Vote_UseH(Menu menu, MenuAction action, int choice, int param) 54 | { 55 | switch(action) 56 | { 57 | case MenuAction_End: 58 | { 59 | delete menu; 60 | } 61 | case MenuAction_VoteCancel: 62 | { 63 | int client = GetClientOfUserId(VoteCaster); 64 | if(IsValidClient(client)) 65 | SPrintToChat(client, "Your item was not used up!"); 66 | } 67 | case MenuAction_VoteEnd: 68 | { 69 | int client = GetClientOfUserId(VoteCaster); 70 | if(!IsValidClient(client)) 71 | return 0; 72 | 73 | if(choice) 74 | { 75 | SPrintToChat(client, "Your item was not used up!"); 76 | return 0; 77 | } 78 | 79 | int items; 80 | TextStore_GetInv(client, VoteIndex, items); 81 | if(items < 1) 82 | return 0; 83 | 84 | TextStore_SetInv(client, VoteIndex, items-1, items==1 ? 0 : -1); 85 | if(VoteMap) 86 | { 87 | ConVar timelimit = FindConVar("mp_timelimit"); 88 | timelimit.FloatValue = timelimit.FloatValue + VoteMap; 89 | } 90 | ServerCommand(VoteCommand); 91 | } 92 | } 93 | return 0; 94 | } 95 | 96 | bool TestVoteDelay(int client) 97 | { 98 | int delay = CheckVoteDelay(); 99 | if(delay <= 0) 100 | return true; 101 | 102 | if(delay > 60) 103 | { 104 | PrintToChat(client, "[SM] %t", "Vote Delay Minutes", delay % 60); 105 | } 106 | else 107 | { 108 | PrintToChat(client, "[SM] %t", "Vote Delay Seconds", delay); 109 | } 110 | return false; 111 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore_ftp.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #pragma newdecls required 8 | 9 | #define DEBUG 10 | #define PLUGIN_VERSION "0.1" 11 | 12 | #define DATA_PATH1 "data/textstore" 13 | #define DATA_PATH2 "data/textstore/user" 14 | 15 | ConVar CvarFTPUrl; 16 | ConVar CvarFTPPort; 17 | ConVar CvarFTPUser; 18 | ConVar CvarFTPPass; 19 | bool IgnoreLoad; 20 | 21 | public Plugin myinfo = 22 | { 23 | name = "The Text Store: FTP", 24 | author = "Batfoxkid", 25 | description = "Text Files from FTP", 26 | version = PLUGIN_VERSION 27 | }; 28 | 29 | public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) 30 | { 31 | CreateNative("_textstore_saveaddon", _textstore_saveaddon); 32 | return APLRes_Success; 33 | } 34 | 35 | public any _textstore_saveaddon(Handle plugin, int numParams) 36 | { 37 | return 0; 38 | } 39 | 40 | public void OnPluginStart() 41 | { 42 | /*RegServerCmd("sm_textstore_convert", Command_Convert, "Trasnfer all existing TXT files to SQL"); 43 | RegServerCmd("sm_textstore_import", Command_Import, "Import a TXT file to SQL"); 44 | RegServerCmd("sm_textstore_check", Command_Check, "Checks data given a steamid"); 45 | RegServerCmd("sm_textstore_modify", Command_Modify, "Change data given a steamid"); 46 | */ 47 | 48 | CvarFTPUrl = CreateConVar("textstore_ftp_url", "", "FTP url to path (ftp://example.com/textstore)", FCVAR_PROTECTED); 49 | CvarFTPPort = CreateConVar("textstore_ftp_port", "21", "FTP port", FCVAR_PROTECTED); 50 | CvarFTPUser = CreateConVar("textstore_ftp_username", "", "FTP username", FCVAR_PROTECTED); 51 | CvarFTPPass = CreateConVar("textstore_ftp_password", "", "FTP password", FCVAR_PROTECTED); 52 | 53 | AutoExecConfig(); 54 | } 55 | 56 | public Action TextStore_OnClientLoad(int client, char file[PLATFORM_MAX_PATH]) 57 | { 58 | if(IgnoreLoad) 59 | { 60 | IgnoreLoad = false; 61 | return Plugin_Continue; 62 | } 63 | 64 | char ftpurl[PLATFORM_MAX_PATH]; 65 | CvarFTPUrl.GetString(ftpurl, sizeof(ftpurl)); 66 | if(!ftpurl[0]) 67 | return Plugin_Continue; 68 | 69 | char buffer1[PLATFORM_MAX_PATH], buffer2[PLATFORM_MAX_PATH]; 70 | BuildPath(Path_SM, buffer2, sizeof(buffer2), NULL_STRING); // addons/sourcemod/ 71 | if(!StrContains(file, buffer2)) 72 | { 73 | int size = strlen(buffer2); 74 | if(!StrContains(file[size], "data")) // addons/sourcemod/data/ 75 | { 76 | size += 5; 77 | if(!StrContains(file[size], "textstore")) // addons/sourcemod/data/textstore/ 78 | size += 10; 79 | } 80 | 81 | strcopy(buffer1, sizeof(buffer1), file[size]); 82 | } 83 | else 84 | { 85 | strcopy(buffer1, sizeof(buffer1), file); 86 | } 87 | 88 | ReplaceString(buffer1, sizeof(buffer1), "\\", "/"); 89 | 90 | #if defined DEBUG 91 | PrintToServer("TextStore_OnClientLoad::%s/%s", ftpurl, buffer1); 92 | #endif 93 | 94 | int port = 21; 95 | int pos1 = FindCharInString(ftpurl, '@'); 96 | if(pos1 != -1) 97 | { 98 | int pos2 = FindCharInString(ftpurl[pos1], ':'); 99 | if(pos2 != -1) 100 | port = StringToInt(ftpurl[pos1 + pos2 + 1]); 101 | } 102 | 103 | #if defined DEBUG 104 | PrintToServer("TextStore_OnClientLoad::Port%d", port); 105 | #endif 106 | 107 | char username[64], password[64]; 108 | CvarFTPUser.GetString(username, sizeof(username)); 109 | CvarFTPPass.GetString(password, sizeof(password)); 110 | 111 | System2FTPRequest request = new System2FTPRequest(FTPRetreived, "%s/%s", ftpurl, buffer1); 112 | request.Any = GetClientUserId(client); 113 | request.SetPort(CvarFTPPort.IntValue); 114 | request.SetAuthentication(username, password); 115 | request.SetOutputFile(file); 116 | request.StartRequest(); 117 | return Plugin_Stop; 118 | } 119 | 120 | public void FTPRetreived(bool success, const char[] error, System2FTPRequest request, System2FTPResponse response) 121 | { 122 | if(!success) 123 | { 124 | LogError(error); 125 | } 126 | 127 | int client = GetClientOfUserId(request.Any); 128 | if(client) 129 | { 130 | IgnoreLoad = true; 131 | TextStore_ClientReload(client); 132 | IgnoreLoad = false; 133 | } 134 | } 135 | 136 | public void TextStore_OnClientSaved(int client, const char[] file) 137 | { 138 | char ftpurl[PLATFORM_MAX_PATH]; 139 | CvarFTPUrl.GetString(ftpurl, sizeof(ftpurl)); 140 | if(ftpurl[0]) 141 | { 142 | char buffer1[PLATFORM_MAX_PATH], buffer2[PLATFORM_MAX_PATH]; 143 | BuildPath(Path_SM, buffer2, sizeof(buffer2), NULL_STRING); // addons/sourcemod/ 144 | if(!StrContains(file, buffer2)) 145 | { 146 | int size = strlen(buffer2); 147 | if(!StrContains(file[size], "data")) // addons/sourcemod/data/ 148 | { 149 | size += 5; 150 | if(!StrContains(file[size], "textstore")) // addons/sourcemod/data/textstore/ 151 | size += 10; 152 | } 153 | 154 | strcopy(buffer1, sizeof(buffer1), file[size]); 155 | } 156 | else 157 | { 158 | strcopy(buffer1, sizeof(buffer1), file); 159 | } 160 | 161 | ReplaceString(buffer1, sizeof(buffer1), "\\", "/"); 162 | 163 | #if defined DEBUG 164 | PrintToServer("TextStore_OnClientSaved::%s/%s", ftpurl, buffer1); 165 | #endif 166 | 167 | int port = 21; 168 | int pos1 = FindCharInString(ftpurl, '@'); 169 | if(pos1 != -1) 170 | { 171 | int pos2 = FindCharInString(ftpurl[pos1], ':'); 172 | if(pos2 != -1) 173 | port = StringToInt(ftpurl[pos1 + pos2 + 1]); 174 | } 175 | 176 | #if defined DEBUG 177 | PrintToServer("TextStore_OnClientSaved::Port%d", port); 178 | #endif 179 | 180 | char username[64], password[64]; 181 | CvarFTPUser.GetString(username, sizeof(username)); 182 | CvarFTPPass.GetString(password, sizeof(password)); 183 | 184 | System2FTPRequest request = new System2FTPRequest(FTPRetreived, "%s/%s", ftpurl, buffer1); 185 | request.CreateMissingDirs = true; 186 | request.SetPort(CvarFTPPort.IntValue); 187 | request.SetAuthentication(username, password); 188 | request.SetInputFile(file); 189 | request.StartRequest(); 190 | } 191 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore_generic.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #pragma newdecls required 8 | 9 | #define PLUGIN_VERSION "0.1.0" 10 | 11 | ConVar CashKill; 12 | ConVar CashWin; 13 | ConVar CashTeamScore; 14 | ConVar CashScore; 15 | ConVar CashEntity; 16 | 17 | public Plugin myinfo = 18 | { 19 | name = "The Text Store: Generic Events", 20 | author = "Batfoxkid", 21 | description = "Generic game events for gaining credits", 22 | version = PLUGIN_VERSION 23 | }; 24 | 25 | public void OnPluginStart() 26 | { 27 | HookEventEx("player_death", OnDeath); 28 | CashKill = CreateConVar("textstore_cash_kill", "0", "Amount gained on a player kill."); 29 | 30 | HookEventEx("round_end", OnRoundEnd); 31 | CashWin = CreateConVar("textstore_cash_win", "0", "Amount gained on a player/team win."); 32 | 33 | HookEventEx("team_score", OnTeamScore); 34 | CashTeamScore = CreateConVar("textstore_cash_team_score", "0.0", "Ratio of team score gained to cash."); 35 | 36 | HookEventEx("player_score", OnScore); 37 | CashScore = CreateConVar("textstore_cash_score", "0.0", "Ratio of score gained to cash."); 38 | 39 | HookEventEx("entity_killed", OnKill); 40 | CashEntity = CreateConVar("textstore_cash_entity_kill", "0", "Amount gained on an entity kill."); 41 | 42 | AutoExecConfig(true, "TextStore_Generic"); 43 | } 44 | 45 | /* 46 | Player Kill 47 | */ 48 | public void OnDeath(Event event, const char[] name, bool dontBroadcast) 49 | { 50 | int client = GetClientOfUserId(event.GetInt("userid")); 51 | if(!IsValidClient(client) || IsFakeClient(client)) 52 | return; 53 | 54 | int attacker = GetClientOfUserId(event.GetInt("attacker")); 55 | if(client!=attacker && IsValidClient(attacker)) 56 | AddCash(attacker, CashKill.IntValue); 57 | } 58 | 59 | /* 60 | Win 61 | */ 62 | public void OnRoundEnd(Event event, const char[] name, bool dontBroadcast) 63 | { 64 | int winner = event.GetInt("winner"); 65 | int client = GetClientOfUserId(winner); 66 | if(IsValidClient(client)) 67 | { 68 | AddCash(client, CashWin.IntValue); 69 | return; 70 | } 71 | 72 | for(client=1; client<=MaxClients; client++) 73 | { 74 | if(IsValidClient(client) && GetClientTeam(client)==winner) 75 | AddCash(client, CashWin.IntValue); 76 | } 77 | } 78 | 79 | /* 80 | Team Score 81 | */ 82 | public void OnTeamScore(Event event, const char[] name, bool dontBroadcast) 83 | { 84 | float ratio = CashTeamScore.FloatValue; 85 | if(!ratio) 86 | return; 87 | 88 | int team = event.GetInt("teamid"); 89 | if(team<0 || team>MAXPLAYERS) 90 | return; 91 | 92 | int score = event.GetInt("score"); 93 | static int lastScore[MAXPLAYERS+1]; 94 | if(score <= lastScore[team]) 95 | return; 96 | 97 | int changedScore = RoundFloat((score-lastScore[team])*ratio); 98 | for(int client=1; client<=MaxClients; client++) 99 | { 100 | if(IsValidClient(client) && GetClientTeam(client)==team) 101 | AddCash(client, changedScore); 102 | } 103 | lastScore[team] = score; 104 | } 105 | 106 | /* 107 | Player Score 108 | */ 109 | public void OnScore(Event event, const char[] name, bool dontBroadcast) 110 | { 111 | float ratio = CashScore.FloatValue; 112 | if(!ratio) 113 | return; 114 | 115 | int client = GetClientOfUserId(event.GetInt("userid")); 116 | if(!IsValidClient(client)) 117 | return; 118 | 119 | int score = event.GetInt("score"); 120 | static int lastScore[MAXPLAYERS+1]; 121 | if(score <= lastScore[client]) 122 | return; 123 | 124 | AddCash(client, RoundFloat((score-lastScore[client])*ratio)); 125 | lastScore[client] = score; 126 | } 127 | 128 | /* 129 | Entity Kill 130 | */ 131 | public void OnKill(Event event, const char[] name, bool dontBroadcast) 132 | { 133 | int client = event.GetInt("entindex_attacker"); 134 | if(IsValidClient(client)) 135 | AddCash(client, CashEntity.IntValue); 136 | } 137 | 138 | stock bool IsValidClient(int client, bool replaycheck=true) 139 | { 140 | if(client<=0 || client>MaxClients) 141 | return false; 142 | 143 | if(!IsClientInGame(client)) 144 | return false; 145 | 146 | if(replaycheck && (IsClientSourceTV(client) || IsClientReplay(client))) 147 | return false; 148 | 149 | return true; 150 | } 151 | 152 | stock void AddCash(int client, int amount) 153 | { 154 | if(amount) 155 | TextStore_Cash(client, amount); 156 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore_mysql.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | 6 | #pragma newdecls required 7 | 8 | //#define DEBUG 9 | #define PLUGIN_VERSION "1.6" 10 | 11 | enum struct LastItem 12 | { 13 | int Item; 14 | int Count; 15 | bool Equipped; 16 | } 17 | 18 | enum struct QueryEnum 19 | { 20 | Transaction Tr; 21 | SQLTxnSuccess OnSuccess; 22 | SQLTxnFailure OnError; 23 | any Data; 24 | DBPriority Priority; 25 | } 26 | 27 | ConVar CvarBackup; 28 | Database DataBase; 29 | bool IgnoreLoad; 30 | bool InQuery; 31 | bool DeleteConvert; 32 | ArrayList QueryQueue; 33 | ArrayList LastItems[MAXPLAYERS]; 34 | ArrayList LastUnique[MAXPLAYERS]; 35 | 36 | public Plugin myinfo = 37 | { 38 | name = "The Text Store: MySQL", 39 | author = "Batfoxkid", 40 | description = "Text Files to MySQL", 41 | version = PLUGIN_VERSION 42 | }; 43 | 44 | public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) 45 | { 46 | CreateNative("_textstore_saveaddon", _textstore_saveaddon); 47 | return APLRes_Success; 48 | } 49 | 50 | public any _textstore_saveaddon(Handle plugin, int numParams) 51 | { 52 | return 0; 53 | } 54 | 55 | public void OnPluginStart() 56 | { 57 | RegServerCmd("sm_textstore_convert", Command_Convert, "Trasnfer all existing TXT files to SQL"); 58 | RegServerCmd("sm_textstore_import", Command_Import, "Import a TXT file to SQL"); 59 | RegServerCmd("sm_textstore_check", Command_Check, "Checks data given a steamid"); 60 | RegServerCmd("sm_textstore_modify", Command_Modify, "Change data given a steamid"); 61 | 62 | CvarBackup = CreateConVar("textstore_sql_hybrid", "0", "If to also save text files alongside SQL", _, true, 0.0, true, 1.0); 63 | 64 | Database.Connect(Database_Connected, "textstore"); 65 | } 66 | 67 | public void Database_Connected(Database db, const char[] error, any data) 68 | { 69 | if(db) 70 | { 71 | Transaction tr = new Transaction(); 72 | 73 | tr.AddQuery("CREATE TABLE IF NOT EXISTS misc_data (" 74 | ... "steamid INTEGER PRIMARY KEY, " 75 | ... "cash INTEGER NOT NULL DEFAULT 0);"); 76 | 77 | tr.AddQuery("CREATE TABLE IF NOT EXISTS common_items (" 78 | ... "steamid INTEGER NOT NULL, " 79 | ... "item TEXT NOT NULL, " 80 | ... "count INTEGER NOT NULL, " 81 | ... "equip INTEGER NOT NULL);"); 82 | 83 | tr.AddQuery("CREATE TABLE IF NOT EXISTS unique_items (" 84 | ... "steamid INTEGER NOT NULL, " 85 | ... "item TEXT NOT NULL, " 86 | ... "name TEXT NOT NULL, " 87 | ... "equip INTEGER NOT NULL, " 88 | ... "data TEXT NOT NULL);"); 89 | 90 | db.Execute(tr, Database_SetupSuccess, Database_SetupFail, db); 91 | } 92 | else 93 | { 94 | SetFailState(error); 95 | } 96 | } 97 | 98 | public void Database_SetupSuccess(Database db, any data, int numQueries, DBResultSet[] results, any[] queryData) 99 | { 100 | #if defined DEBUG 101 | PrintToServer("Database_SetupSuccess"); 102 | #endif 103 | 104 | for(int client = 1; client <= MaxClients; client++) 105 | { 106 | if(IsClientInGame(client)) 107 | { 108 | if(TextStore_GetClientLoad(client)) 109 | TextStore_ClientSave(client); 110 | } 111 | } 112 | 113 | DataBase = data; 114 | 115 | for(int client = 1; client <= MaxClients; client++) 116 | { 117 | if(IsClientInGame(client)) 118 | TextStore_ClientReload(client); 119 | } 120 | } 121 | 122 | public void Database_SetupFail(Database db, any data, int numQueries, const char[] error, int failIndex, any[] queryData) 123 | { 124 | SetFailState(error); 125 | } 126 | 127 | public Action TextStore_OnClientLoad(int client, char file[PLATFORM_MAX_PATH]) 128 | { 129 | #if defined DEBUG 130 | PrintToServer("TextStore_OnClientLoad"); 131 | #endif 132 | 133 | if(IgnoreLoad) 134 | return Plugin_Continue; 135 | 136 | delete LastItems[client]; 137 | delete LastUnique[client]; 138 | 139 | if(DataBase) 140 | { 141 | int id = GetSteamAccountID(client); 142 | if(!id) 143 | ThrowError("TextStore_OnClientLoad called but GetSteamAccountID is invalid?"); 144 | 145 | Transaction tr = new Transaction(); 146 | 147 | char buffer[256]; 148 | FormatEx(buffer, sizeof(buffer), "SELECT * FROM misc_data WHERE steamid = %d;", id); 149 | tr.AddQuery(buffer); 150 | 151 | AddToQueryQueue(tr, Database_ClientSetup1, Database_Fail, GetClientUserId(client)); 152 | } 153 | else if(CvarBackup.BoolValue) 154 | { 155 | return Plugin_Continue; 156 | } 157 | 158 | return Plugin_Stop; 159 | } 160 | 161 | public void Database_ClientSetup1(Database db, any userid, int numQueries, DBResultSet[] results, any[] queryData) 162 | { 163 | StartNextQuery(); 164 | 165 | #if defined DEBUG 166 | PrintToServer("Database_ClientSetup1"); 167 | #endif 168 | 169 | int client = GetClientOfUserId(userid); 170 | if(client) 171 | { 172 | delete LastItems[client]; 173 | LastItems[client] = new ArrayList(sizeof(LastItem)); 174 | 175 | delete LastUnique[client]; 176 | LastUnique[client] = new ArrayList(ByteCountToCells(48)); 177 | 178 | static char data[256]; 179 | if(results[0].FetchRow()) 180 | { 181 | int cash = results[0].FetchInt(1) - TextStore_Cash(client); 182 | TextStore_Cash(client, cash); 183 | } 184 | else if(!results[0].MoreRows) 185 | { 186 | Transaction tr = new Transaction(); 187 | 188 | Format(data, sizeof(data), "INSERT INTO misc_data (steamid) VALUES (%d)", GetSteamAccountID(client)); 189 | tr.AddQuery(data); 190 | 191 | AddToQueryQueue(tr, Database_Success, Database_Fail); 192 | 193 | IgnoreLoad = true; 194 | TextStore_ClientReload(client); 195 | IgnoreLoad = false; 196 | 197 | if(TextStore_GetClientLoad(client)) 198 | TextStore_OnClientSave(client, ""); 199 | 200 | return; 201 | } 202 | else 203 | { 204 | ThrowError("Unable to fetch first row"); 205 | } 206 | 207 | int id = GetSteamAccountID(client); 208 | if(id) 209 | { 210 | Transaction tr = new Transaction(); 211 | 212 | Format(data, sizeof(data), "SELECT * FROM common_items WHERE steamid = %d;", id); 213 | tr.AddQuery(data); 214 | 215 | AddToQueryQueue(tr, Database_ClientSetup2, Database_Fail, GetClientUserId(client)); 216 | } 217 | } 218 | } 219 | 220 | public void Database_ClientSetup2(Database db, any userid, int numQueries, DBResultSet[] results, any[] queryData) 221 | { 222 | StartNextQuery(); 223 | 224 | #if defined DEBUG 225 | PrintToServer("Database_ClientSetup2"); 226 | #endif 227 | 228 | int client = GetClientOfUserId(userid); 229 | if(client) 230 | { 231 | while(results[0].MoreRows) 232 | { 233 | if(results[0].FetchRow()) 234 | { 235 | static char item[48]; 236 | results[0].FetchString(1, item, sizeof(item)); 237 | GiveNamedItem(client, item, results[0].FetchInt(2), view_as(results[0].FetchInt(3))); 238 | } 239 | } 240 | 241 | int id = GetSteamAccountID(client); 242 | if(id) 243 | { 244 | Transaction tr = new Transaction(); 245 | 246 | char buffer[256]; 247 | FormatEx(buffer, sizeof(buffer), "SELECT * FROM unique_items WHERE steamid = %d;", id); 248 | tr.AddQuery(buffer); 249 | 250 | AddToQueryQueue(tr, Database_ClientSetup3, Database_Fail, GetClientUserId(client)); 251 | } 252 | } 253 | } 254 | 255 | public void Database_ClientSetup3(Database db, any userid, int numQueries, DBResultSet[] results, any[] queryData) 256 | { 257 | StartNextQuery(); 258 | 259 | #if defined DEBUG 260 | PrintToServer("Database_ClientSetup3"); 261 | #endif 262 | 263 | int client = GetClientOfUserId(userid); 264 | if(client) 265 | { 266 | while(results[0].MoreRows) 267 | { 268 | if(results[0].FetchRow()) 269 | { 270 | static char item[48], name[48], data[256]; 271 | results[0].FetchString(1, item, sizeof(item)); 272 | results[0].FetchString(2, name, sizeof(name)); 273 | results[0].FetchString(4, data, sizeof(data)); 274 | 275 | GiveNamedUnique(client, item, name, view_as(results[0].FetchInt(3)), data); 276 | } 277 | } 278 | 279 | TextStore_SetClientLoad(client, true); 280 | } 281 | } 282 | 283 | public Action TextStore_OnClientSave(int client, char file[PLATFORM_MAX_PATH]) 284 | { 285 | //StartNextQuery(); 286 | 287 | #if defined DEBUG 288 | PrintToServer("TextStore_OnClientSave"); 289 | #endif 290 | 291 | if(DataBase && LastItems[client]) 292 | { 293 | int id = GetSteamAccountID(client); 294 | if(!id) 295 | ThrowError("TextStore_OnClientSave called but GetSteamAccountID is invalid?"); 296 | 297 | Transaction tr = new Transaction(); 298 | 299 | static char buffer[1024]; 300 | Format(buffer, sizeof(buffer), "UPDATE misc_data SET cash = %d WHERE steamid = %d;", TextStore_Cash(client), id); 301 | tr.AddQuery(buffer); 302 | 303 | AddToQueryQueue(tr, Database_Success, Database_Fail); 304 | 305 | tr = new Transaction(); 306 | 307 | LastItem last; 308 | ArrayList list = new ArrayList(sizeof(LastItem)); 309 | 310 | int amount; 311 | int uniques; 312 | int items = TextStore_GetItems(uniques); 313 | for(int i; i 0) 320 | { 321 | TextStore_GetItemName(i, buffer, sizeof(buffer)); 322 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO common_items (steamid, item, count, equip) VALUES ('%d', '%s', '%d', '%d')", id, buffer, amount, equipped); 323 | 324 | tr.AddQuery(buffer); 325 | } 326 | else 327 | { 328 | continue; 329 | } 330 | } 331 | else if(amount > 0) 332 | { 333 | LastItems[client].GetArray(index, last); 334 | if(last.Count != amount || last.Equipped != equipped) 335 | { 336 | TextStore_GetItemName(i, buffer, sizeof(buffer)); 337 | DataBase.Format(buffer, sizeof(buffer), "UPDATE common_items SET count = '%d', equip = '%d' WHERE steamid = %d AND item = '%s';", amount, equipped, id, buffer); 338 | 339 | tr.AddQuery(buffer); 340 | } 341 | } 342 | else 343 | { 344 | TextStore_GetItemName(i, buffer, sizeof(buffer)); 345 | DataBase.Format(buffer, sizeof(buffer), "DELETE FROM common_items WHERE steamid = %d AND item = '%s';", id, buffer); 346 | 347 | tr.AddQuery(buffer); 348 | continue; 349 | } 350 | 351 | last.Item = i; 352 | last.Count = amount; 353 | last.Equipped = equipped; 354 | list.PushArray(last); 355 | } 356 | 357 | AddToQueryQueue(tr, Database_Success, Database_Fail); 358 | 359 | delete LastItems[client]; 360 | LastItems[client] = list; 361 | 362 | if(uniques) 363 | { 364 | tr = new Transaction(); 365 | 366 | uniques = -uniques; 367 | 368 | if(LastUnique[client]) 369 | { 370 | int length = LastUnique[client].Length; 371 | for(int i; i=uniques; i--) 392 | { 393 | bool equipped = TextStore_GetInv(client, i, amount); 394 | if(amount) 395 | { 396 | if(TextStore_GetItemKv(i).GetSectionName(item, sizeof(item))) 397 | { 398 | TextStore_GetItemName(i, name, sizeof(name)); 399 | if(StrEqual(name, item, false)) 400 | name[0] = 0; 401 | 402 | TextStore_GetItemData(i, buffer, sizeof(buffer)); 403 | 404 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO unique_items (steamid, item, name, equip, data) VALUES ('%d', '%s', '%s', '%d', '%s')", id, item, name, equipped, buffer); 405 | 406 | tr.AddQuery(buffer); 407 | 408 | LastUnique[client].PushString(item); 409 | } 410 | else 411 | { 412 | LogError("KeyValues.GetSectionName failed with unique item"); 413 | } 414 | } 415 | } 416 | 417 | AddToQueryQueue(tr, Database_Success, Database_Fail); 418 | } 419 | 420 | if(!CvarBackup.BoolValue) 421 | return Plugin_Handled; 422 | } 423 | return Plugin_Continue; 424 | } 425 | 426 | public Action Command_Convert(int args) 427 | { 428 | if(args == 1) 429 | { 430 | char filepath[PLATFORM_MAX_PATH]; 431 | GetCmdArg(1, filepath, sizeof(filepath)); 432 | 433 | DeleteConvert = StringToInt(filepath) == 1; 434 | 435 | BuildPath(Path_SM, filepath, sizeof(filepath), "data/textstore/user"); 436 | DirectoryListing dir = OpenDirectory(filepath); 437 | if(dir) 438 | { 439 | CreateTimer(1.0, Timer_Convert, dir, TIMER_REPEAT); 440 | } 441 | else 442 | { 443 | PrintToServer("Could not open '%s'", filepath); 444 | } 445 | } 446 | else 447 | { 448 | PrintToServer("[SM] Usage: sm_textstore_convert <0/1 if to delete files on success>"); 449 | } 450 | return Plugin_Handled; 451 | } 452 | 453 | public Action Command_Import(int args) 454 | { 455 | if(args == 1) 456 | { 457 | char filename[512]; 458 | GetCmdArg(1, filename, sizeof(filename)); 459 | 460 | int steamid; 461 | if(GetSteam32FromSteam64(filename, steamid)) 462 | { 463 | BuildPath(Path_SM, filename, sizeof(filename), "data/textstore/user/%s.txt", filename); 464 | File file = OpenFile(filename, "r"); 465 | if(file) 466 | { 467 | PrintToServer("Imported %d items", PortFileToSQL(file, steamid)); 468 | delete file; 469 | } 470 | else 471 | { 472 | PrintToServer("Could not open '%s'", filename); 473 | } 474 | } 475 | else 476 | { 477 | PrintToServer("Invalid Steam64 ID"); 478 | } 479 | } 480 | else 481 | { 482 | PrintToServer("[SM] Usage: sm_textstore_import "); 483 | } 484 | return Plugin_Handled; 485 | } 486 | 487 | public Action Command_Check(int args) 488 | { 489 | if(args == 1) 490 | { 491 | char buffer[256]; 492 | GetCmdArg(1, buffer, sizeof(buffer)); 493 | int id = StringToInt(buffer); 494 | 495 | Transaction tr = new Transaction(); 496 | 497 | FormatEx(buffer, sizeof(buffer), "SELECT * FROM misc_data WHERE steamid = %d;", id); 498 | tr.AddQuery(buffer); 499 | 500 | AddToQueryQueue(tr, Database_Check1, Database_FailPrint, id); 501 | } 502 | else 503 | { 504 | PrintToServer("[SM] Usage: sm_textstore_check "); 505 | } 506 | return Plugin_Handled; 507 | } 508 | 509 | public void Database_Check1(Database db, any id, int numQueries, DBResultSet[] results, any[] queryData) 510 | { 511 | StartNextQuery(); 512 | 513 | if(results[0].FetchRow()) 514 | { 515 | PrintToServer("Cash: %d", results[0].FetchInt(1)); 516 | 517 | Transaction tr = new Transaction(); 518 | 519 | char buffer[256]; 520 | Format(buffer, sizeof(buffer), "SELECT * FROM common_items WHERE steamid = %d;", id); 521 | tr.AddQuery(buffer); 522 | 523 | AddToQueryQueue(tr, Database_Check2, Database_FailPrint, id); 524 | } 525 | else 526 | { 527 | PrintToServer("No entry for %d", id); 528 | } 529 | } 530 | 531 | public void Database_Check2(Database db, any id, int numQueries, DBResultSet[] results, any[] queryData) 532 | { 533 | StartNextQuery(); 534 | 535 | char buffer[256]; 536 | while(results[0].MoreRows) 537 | { 538 | if(results[0].FetchRow()) 539 | { 540 | results[0].FetchString(1, buffer, sizeof(buffer)); 541 | PrintToServer("%s: %d%s", buffer, results[0].FetchInt(2), results[0].FetchInt(3) ? " (Equipped)" : ""); 542 | } 543 | } 544 | 545 | Transaction tr = new Transaction(); 546 | 547 | FormatEx(buffer, sizeof(buffer), "SELECT * FROM unique_items WHERE steamid = %d;", id); 548 | tr.AddQuery(buffer); 549 | 550 | AddToQueryQueue(tr, Database_Check3, Database_FailPrint, id); 551 | } 552 | 553 | public void Database_Check3(Database db, any id, int numQueries, DBResultSet[] results, any[] queryData) 554 | { 555 | StartNextQuery(); 556 | 557 | char item[48], name[48], data[256]; 558 | while(results[0].MoreRows) 559 | { 560 | if(results[0].FetchRow()) 561 | { 562 | results[0].FetchString(1, item, sizeof(item)); 563 | results[0].FetchString(2, name, sizeof(name)); 564 | results[0].FetchString(4, data, sizeof(data)); 565 | 566 | PrintToServer("%s: '%s' '%s'%s", item, name, data, results[0].FetchInt(3) ? " (Equipped)" : ""); 567 | } 568 | } 569 | } 570 | 571 | public Action Command_Modify(int args) 572 | { 573 | if(args > 2 && args < 7) 574 | { 575 | char buffer[512]; 576 | GetCmdArg(1, buffer, sizeof(buffer)); 577 | int id = StringToInt(buffer); 578 | 579 | char item[64]; 580 | GetCmdArg(2, item, sizeof(item)); 581 | 582 | GetCmdArg(3, buffer, sizeof(buffer)); 583 | int amount = StringToInt(buffer); 584 | 585 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO common_items (steamid, item, count, equip) VALUES ('%d', '%s', '1', '0')", id, item); 586 | 587 | int equip; 588 | if(args > 3) 589 | { 590 | GetCmdArg(4, buffer, sizeof(buffer)); 591 | equip = StringToInt(buffer); 592 | } 593 | 594 | Transaction tr = new Transaction(); 595 | 596 | if(args > 4) 597 | { 598 | GetCmdArg(5, buffer, sizeof(buffer)); 599 | 600 | char name[64]; 601 | GetCmdArg(6, name, sizeof(name)); 602 | 603 | if(amount > 0) 604 | { 605 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO unique_items (steamid, item, name, equip, data) VALUES ('%d', '%s', '%s', '%s', '%s')", id, item, name, equip, buffer); 606 | } 607 | else if(args > 5) 608 | { 609 | DataBase.Format(buffer, sizeof(buffer), "DELETE FROM unique_items WHERE steamid = %d AND item = '%s' AND name = '%s';", id, item, name); 610 | } 611 | else 612 | { 613 | DataBase.Format(buffer, sizeof(buffer), "DELETE FROM unique_items WHERE steamid = %d AND item = '%s' AND data = '%s';", id, item, buffer); 614 | } 615 | 616 | tr.AddQuery(buffer); 617 | } 618 | else 619 | { 620 | DataBase.Format(buffer, sizeof(buffer), "DELETE FROM common_items WHERE steamid = %d AND item = '%s';", id, item); 621 | tr.AddQuery(buffer); 622 | 623 | if(amount > 0) 624 | { 625 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO common_items (steamid, item, count, equip) VALUES ('%d', '%s', '%d', '%d')", id, item, amount, equip); 626 | tr.AddQuery(buffer); 627 | } 628 | } 629 | 630 | AddToQueryQueue(tr, Database_Success, Database_FailPrint, id); 631 | PrintToServer(buffer); 632 | } 633 | else 634 | { 635 | PrintToServer("[SM] Usage: sm_textstore_modify [Equipped] [Data] [Name]"); 636 | } 637 | return Plugin_Handled; 638 | } 639 | 640 | public void Database_Success(Database db, any data, int numQueries, DBResultSet[] results, any[] queryData) 641 | { 642 | #if defined DEBUG 643 | PrintToServer("Database_Success"); 644 | #endif 645 | 646 | StartNextQuery(); 647 | } 648 | 649 | public void Database_Fail(Database db, any data, int numQueries, const char[] error, int failIndex, any[] queryData) 650 | { 651 | #if defined DEBUG 652 | PrintToServer("Database_Fail"); 653 | #endif 654 | 655 | LogError(error); 656 | 657 | StartNextQuery(); 658 | } 659 | 660 | public void Database_FailPrint(Database db, any data, int numQueries, const char[] error, int failIndex, any[] queryData) 661 | { 662 | PrintToServer(error); 663 | 664 | StartNextQuery(); 665 | } 666 | 667 | public Action Timer_Convert(Handle timer, DirectoryListing dir) 668 | { 669 | if(QueryQueue.Length > 10) 670 | return Plugin_Continue; 671 | 672 | FileType type; 673 | char filename[512]; 674 | if(!dir.GetNext(filename, sizeof(filename), type)) 675 | { 676 | delete dir; 677 | PrintToServer("> Finished querying TXT to SQL <"); 678 | return Plugin_Stop; 679 | } 680 | 681 | char filepath[PLATFORM_MAX_PATH]; 682 | BuildPath(Path_SM, filepath, sizeof(filepath), "data/textstore/user"); 683 | 684 | if(type == FileType_File) 685 | { 686 | if(ReplaceString(filename, sizeof(filename), ".txt", "")) 687 | { 688 | int steamid; 689 | if(GetSteam32FromSteam64(filename, steamid)) 690 | { 691 | Format(filename, sizeof(filename), "%s/%s.txt", filepath, filename); 692 | File file = OpenFile(filename, "r"); 693 | if(file) 694 | { 695 | PrintToServer("Processing '%s'", filename); 696 | 697 | PortFileToSQL(file, steamid); 698 | delete file; 699 | 700 | if(DeleteConvert) 701 | DeleteFile(filename); 702 | } 703 | else 704 | { 705 | PrintToServer("> Could not open '%s' <", filename); 706 | } 707 | } 708 | else 709 | { 710 | PrintToServer("> Failed to get steamid of '%s' <", filename); 711 | } 712 | } 713 | else 714 | { 715 | PrintToServer("> Invalid file '%s' <", filename); 716 | } 717 | } 718 | return Plugin_Continue; 719 | } 720 | 721 | void GiveNamedItem(int client, const char[] item, int amount, bool equipped) 722 | { 723 | #if defined DEBUG 724 | PrintToServer("GiveNamedItem"); 725 | #endif 726 | 727 | LastItem last; 728 | int items = TextStore_GetItems(); 729 | for(int i; i 3) 801 | { 802 | if(!unique) 803 | { 804 | unique = new Transaction(); 805 | 806 | Format(buffer, sizeof(buffer), "DELETE FROM unique_items WHERE steamid = %d;", steamid); 807 | unique.AddQuery(buffer); 808 | } 809 | 810 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO unique_items (steamid, item, name, equip, data) VALUES ('%d', '%s', '%s', '%s', '%s')", steamid, buffers[0], buffers[1], buffers[2], buffers[3]); 811 | unique.AddQuery(buffer); 812 | } 813 | else 814 | { 815 | if(!common) 816 | { 817 | common = new Transaction(); 818 | 819 | Format(buffer, sizeof(buffer), "DELETE FROM common_items WHERE steamid = %d;", steamid); 820 | common.AddQuery(buffer); 821 | } 822 | 823 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO common_items (steamid, item, count, equip) VALUES ('%d', '%s', '%s', '%s')", steamid, buffers[0], buffers[1], buffers[2]); 824 | common.AddQuery(buffer); 825 | } 826 | } 827 | 828 | if(common) 829 | AddToQueryQueue(common, Database_Success, Database_FailPrint, steamid); 830 | 831 | if(unique) 832 | AddToQueryQueue(unique, Database_Success, Database_FailPrint, steamid); 833 | 834 | return found; 835 | } 836 | 837 | /* 838 | https://github.com/alliedmodders/sourcemod/issues/1505 839 | */ 840 | 841 | void AddToQueryQueue(Transaction tr, SQLTxnSuccess onSuccess = INVALID_FUNCTION, SQLTxnFailure onError = INVALID_FUNCTION, any data = 0, DBPriority priority = DBPrio_Normal) 842 | { 843 | #if defined DEBUG 844 | PrintToServer("Timer_QueryQueue -> New Added"); 845 | #endif 846 | 847 | if(!QueryQueue) 848 | QueryQueue = new ArrayList(sizeof(QueryEnum)); 849 | 850 | QueryEnum query; 851 | query.Tr = tr; 852 | query.OnSuccess = onSuccess; 853 | query.OnError = onError; 854 | query.Data = data; 855 | query.Priority = priority; 856 | QueryQueue.PushArray(query); 857 | 858 | if(!InQuery) 859 | StartNextQuery(); 860 | } 861 | 862 | void StartNextQuery() 863 | { 864 | if(!QueryQueue.Length) 865 | { 866 | InQuery = false; 867 | return; 868 | } 869 | 870 | InQuery = true; 871 | 872 | QueryEnum query; 873 | QueryQueue.GetArray(0, query); 874 | QueryQueue.Erase(0); 875 | 876 | #if defined DEBUG 877 | PrintToServer("Timer_QueryQueue -> Started New | %x %d %d", query.Tr, view_as(query.OnSuccess), view_as(query.OnError)); 878 | #endif 879 | 880 | DataBase.Execute(query.Tr, query.OnSuccess, query.OnError, query.Data, query.Priority); 881 | } 882 | 883 | /* 884 | https://forums.alliedmods.net/showthread.php?t=60899&page=36 885 | */ 886 | 887 | stock bool GetSteam32FromSteam64(const char[] szSteam64Original, int &iSteam32) 888 | { 889 | char szSteam32[20]; 890 | char szSteam64[20]; 891 | 892 | // We don't want to actually edit the original string. 893 | // We make a new string for the editing. 894 | strcopy(szSteam64, sizeof szSteam64, szSteam64Original); 895 | 896 | // Remove the first three numbers 897 | ReplaceStringEx(szSteam64, sizeof(szSteam64), "765", ""); 898 | 899 | // Because pawn does not support numbers bigger than 2147483647, we will need to subtract using a combination of numbers. 900 | // The combination can be 901 | // 1 number to max integers 902 | char szSubtractionString[] = "61197960265728"; 903 | 904 | // First integer is the integer from szSteam64 905 | // Second is from the subtraction string szSubtractionString 906 | char szFirstInteger[11], szSecondInteger[11]; 907 | int iFirstInteger, iSecondInteger; 908 | 909 | char szResultInt[11]; 910 | 911 | // Ugly hack 912 | // Make the strings 00000000000 so when we use StringToInt the zeroes won't affect the result 913 | // sizeof - 1 because we need the last End of string (0) byte; 914 | SetStringZeros(szFirstInteger, sizeof(szFirstInteger), sizeof(szFirstInteger) - 1); 915 | SetStringZeros(szSecondInteger, sizeof(szSecondInteger), sizeof(szSecondInteger) - 1); 916 | 917 | // Start from the end of the string, because subtraction should always start from the first number in the right. 918 | int iResultInt; 919 | 920 | int iSteam64Position = strlen(szSteam64); 921 | int iIntegerPosition = strlen(szFirstInteger); 922 | 923 | int iNumCount; 924 | int iResultLen; 925 | char szStringZeroes[11]; 926 | 927 | while(--iSteam64Position > -1) 928 | { 929 | iIntegerPosition -= 1; 930 | 931 | ++iNumCount; 932 | szFirstInteger[iIntegerPosition] = szSteam64[iSteam64Position]; 933 | szSecondInteger[iIntegerPosition] = szSubtractionString[iSteam64Position]; 934 | 935 | iFirstInteger = StringToInt(szFirstInteger); 936 | iSecondInteger = StringToInt(szSecondInteger); 937 | 938 | // Can we subtract without getting a negative number? 939 | if(iFirstInteger >= iSecondInteger) 940 | { 941 | iResultInt = iFirstInteger - iSecondInteger; 942 | // 69056897 943 | if(iResultInt) 944 | { 945 | IntToString(iResultInt, szResultInt, sizeof szResultInt); 946 | 947 | if( iNumCount != (iResultLen = strlen(szResultInt) ) ) 948 | { 949 | SetStringZeros(szStringZeroes, sizeof szStringZeroes, iNumCount - iResultLen); 950 | } 951 | 952 | else 953 | { 954 | szStringZeroes = ""; 955 | } 956 | } 957 | 958 | else 959 | { 960 | szResultInt = ""; 961 | 962 | SetStringZeros(szStringZeroes, sizeof szStringZeroes, iNumCount); 963 | } 964 | 965 | Format(szSteam32, sizeof szSteam32, "%s%s%s", szStringZeroes, szResultInt, szSteam32); 966 | 967 | // Reset our stuff. 968 | SetStringZeros(szFirstInteger, sizeof(szFirstInteger), sizeof(szFirstInteger) - 1); 969 | SetStringZeros(szSecondInteger, sizeof(szSecondInteger), sizeof(szSecondInteger) - 1); 970 | 971 | iIntegerPosition = strlen(szFirstInteger); 972 | iNumCount = 0; 973 | } 974 | 975 | if(iIntegerPosition - 1 < 0) 976 | { 977 | // We failed, and this calculation can not be done in pawn. 978 | return false; 979 | } 980 | 981 | // if not, lets add more numbers. 982 | } 983 | 984 | iSteam32 = StringToInt(szSteam32); 985 | return true; 986 | } 987 | 988 | stock void SetStringZeros(char[] szString, int iSize, int iNumZeros) 989 | { 990 | int i; 991 | for(i = 0; i < iNumZeros && i < iSize; i++) 992 | { 993 | szString[i] = '0'; 994 | } 995 | 996 | szString[i] = 0; 997 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore_sqlite.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | 6 | #pragma newdecls required 7 | 8 | //#define DEBUG 9 | #define PLUGIN_VERSION "1.5" 10 | 11 | enum struct LastItem 12 | { 13 | int Item; 14 | int Count; 15 | bool Equipped; 16 | } 17 | 18 | ConVar CvarBackup; 19 | Database DataBase; 20 | bool IgnoreLoad; 21 | bool InQuery; 22 | int QueryCount; 23 | bool DeleteConvert; 24 | ArrayList LastItems[MAXPLAYERS]; 25 | ArrayList LastUnique[MAXPLAYERS]; 26 | 27 | public Plugin myinfo = 28 | { 29 | name = "The Text Store: SQLite", 30 | author = "Batfoxkid", 31 | description = "Text Files to SQLite", 32 | version = PLUGIN_VERSION 33 | }; 34 | 35 | public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) 36 | { 37 | CreateNative("_textstore_saveaddon", _textstore_saveaddon); 38 | return APLRes_Success; 39 | } 40 | 41 | public any _textstore_saveaddon(Handle plugin, int numParams) 42 | { 43 | return 0; 44 | } 45 | 46 | public void OnPluginStart() 47 | { 48 | RegServerCmd("sm_textstore_convert", Command_Convert, "Trasnfer all existing TXT files to SQL"); 49 | RegServerCmd("sm_textstore_import", Command_Import, "Import a TXT file to SQL"); 50 | RegServerCmd("sm_textstore_check", Command_Check, "Checks data given a steamid"); 51 | RegServerCmd("sm_textstore_modify", Command_Modify, "Change data given a steamid"); 52 | 53 | CvarBackup = CreateConVar("textstore_sql_hybrid", "0", "If to also save text files alongside SQL", _, true, 0.0, true, 1.0); 54 | 55 | char error[512]; 56 | Database db = SQLite_UseDatabase("textstore", error, sizeof(error)); 57 | if(!db) 58 | SetFailState(error); 59 | 60 | Transaction tr = new Transaction(); 61 | 62 | tr.AddQuery("CREATE TABLE IF NOT EXISTS misc_data (" 63 | ... "steamid INTEGER PRIMARY KEY, " 64 | ... "cash INTEGER NOT NULL DEFAULT 0);"); 65 | 66 | tr.AddQuery("CREATE TABLE IF NOT EXISTS common_items (" 67 | ... "steamid INTEGER NOT NULL, " 68 | ... "item TEXT NOT NULL, " 69 | ... "count INTEGER NOT NULL, " 70 | ... "equip INTEGER NOT NULL);"); 71 | 72 | tr.AddQuery("CREATE TABLE IF NOT EXISTS unique_items (" 73 | ... "steamid INTEGER NOT NULL, " 74 | ... "item TEXT NOT NULL, " 75 | ... "name TEXT NOT NULL, " 76 | ... "equip INTEGER NOT NULL, " 77 | ... "data TEXT NOT NULL);"); 78 | 79 | db.Execute(tr, Database_SetupSuccess, Database_SetupFail, db); 80 | } 81 | 82 | public void Database_SetupSuccess(Database db, any data, int numQueries, DBResultSet[] results, any[] queryData) 83 | { 84 | #if defined DEBUG 85 | PrintToServer("Database_SetupSuccess"); 86 | #endif 87 | 88 | for(int client = 1; client <= MaxClients; client++) 89 | { 90 | if(IsClientInGame(client)) 91 | { 92 | if(TextStore_GetClientLoad(client)) 93 | TextStore_ClientSave(client); 94 | } 95 | } 96 | 97 | DataBase = data; 98 | 99 | for(int client = 1; client <= MaxClients; client++) 100 | { 101 | if(IsClientInGame(client)) 102 | TextStore_ClientReload(client); 103 | } 104 | } 105 | 106 | public void Database_SetupFail(Database db, any data, int numQueries, const char[] error, int failIndex, any[] queryData) 107 | { 108 | SetFailState(error); 109 | } 110 | 111 | public Action TextStore_OnClientLoad(int client, char file[PLATFORM_MAX_PATH]) 112 | { 113 | #if defined DEBUG 114 | PrintToServer("TextStore_OnClientLoad"); 115 | #endif 116 | 117 | if(IgnoreLoad) 118 | return Plugin_Continue; 119 | 120 | delete LastItems[client]; 121 | delete LastUnique[client]; 122 | 123 | if(DataBase) 124 | { 125 | int id = GetSteamAccountID(client); 126 | if(!id) 127 | ThrowError("TextStore_OnClientLoad called but GetSteamAccountID is invalid?"); 128 | 129 | Transaction tr = new Transaction(); 130 | 131 | char buffer[256]; 132 | FormatEx(buffer, sizeof(buffer), "SELECT * FROM misc_data WHERE steamid = %d;", id); 133 | tr.AddQuery(buffer); 134 | 135 | AddToQueryQueue(tr, Database_ClientSetup1, Database_Fail, GetClientUserId(client)); 136 | } 137 | else if(CvarBackup.BoolValue) 138 | { 139 | return Plugin_Continue; 140 | } 141 | 142 | return Plugin_Stop; 143 | } 144 | 145 | public void Database_ClientSetup1(Database db, any userid, int numQueries, DBResultSet[] results, any[] queryData) 146 | { 147 | InQuery = false; 148 | 149 | #if defined DEBUG 150 | PrintToServer("Database_ClientSetup1"); 151 | #endif 152 | 153 | int client = GetClientOfUserId(userid); 154 | if(client) 155 | { 156 | delete LastItems[client]; 157 | LastItems[client] = new ArrayList(sizeof(LastItem)); 158 | 159 | delete LastUnique[client]; 160 | LastUnique[client] = new ArrayList(ByteCountToCells(48)); 161 | 162 | static char data[256]; 163 | if(results[0].FetchRow()) 164 | { 165 | int cash = results[0].FetchInt(1) - TextStore_Cash(client); 166 | TextStore_Cash(client, cash); 167 | } 168 | else if(!results[0].MoreRows) 169 | { 170 | Transaction tr = new Transaction(); 171 | 172 | Format(data, sizeof(data), "INSERT INTO misc_data (steamid) VALUES (%d)", GetSteamAccountID(client)); 173 | tr.AddQuery(data); 174 | 175 | AddToQueryQueue(tr, Database_Success, Database_Fail); 176 | 177 | IgnoreLoad = true; 178 | TextStore_ClientReload(client); 179 | IgnoreLoad = false; 180 | 181 | if(TextStore_GetClientLoad(client)) 182 | TextStore_OnClientSave(client, ""); 183 | 184 | return; 185 | } 186 | else 187 | { 188 | ThrowError("Unable to fetch first row"); 189 | } 190 | 191 | int id = GetSteamAccountID(client); 192 | if(id) 193 | { 194 | Transaction tr = new Transaction(); 195 | 196 | Format(data, sizeof(data), "SELECT * FROM common_items WHERE steamid = %d;", id); 197 | tr.AddQuery(data); 198 | 199 | AddToQueryQueue(tr, Database_ClientSetup2, Database_Fail, GetClientUserId(client)); 200 | } 201 | } 202 | } 203 | 204 | public void Database_ClientSetup2(Database db, any userid, int numQueries, DBResultSet[] results, any[] queryData) 205 | { 206 | InQuery = false; 207 | 208 | #if defined DEBUG 209 | PrintToServer("Database_ClientSetup2"); 210 | #endif 211 | 212 | int client = GetClientOfUserId(userid); 213 | if(client) 214 | { 215 | while(results[0].MoreRows) 216 | { 217 | if(results[0].FetchRow()) 218 | { 219 | static char item[48]; 220 | results[0].FetchString(1, item, sizeof(item)); 221 | GiveNamedItem(client, item, results[0].FetchInt(2), view_as(results[0].FetchInt(3))); 222 | } 223 | } 224 | 225 | int id = GetSteamAccountID(client); 226 | if(id) 227 | { 228 | Transaction tr = new Transaction(); 229 | 230 | char buffer[256]; 231 | FormatEx(buffer, sizeof(buffer), "SELECT * FROM unique_items WHERE steamid = %d;", id); 232 | tr.AddQuery(buffer); 233 | 234 | AddToQueryQueue(tr, Database_ClientSetup3, Database_Fail, GetClientUserId(client)); 235 | } 236 | } 237 | } 238 | 239 | public void Database_ClientSetup3(Database db, any userid, int numQueries, DBResultSet[] results, any[] queryData) 240 | { 241 | InQuery = false; 242 | 243 | #if defined DEBUG 244 | PrintToServer("Database_ClientSetup3"); 245 | #endif 246 | 247 | int client = GetClientOfUserId(userid); 248 | if(client) 249 | { 250 | while(results[0].MoreRows) 251 | { 252 | if(results[0].FetchRow()) 253 | { 254 | static char item[48], name[48], data[256]; 255 | results[0].FetchString(1, item, sizeof(item)); 256 | results[0].FetchString(2, name, sizeof(name)); 257 | results[0].FetchString(4, data, sizeof(data)); 258 | 259 | GiveNamedUnique(client, item, name, view_as(results[0].FetchInt(3)), data); 260 | } 261 | } 262 | 263 | TextStore_SetClientLoad(client, true); 264 | } 265 | } 266 | 267 | public Action TextStore_OnClientSave(int client, char file[PLATFORM_MAX_PATH]) 268 | { 269 | InQuery = false; 270 | 271 | #if defined DEBUG 272 | PrintToServer("TextStore_OnClientSave"); 273 | #endif 274 | 275 | if(DataBase && LastItems[client]) 276 | { 277 | int id = GetSteamAccountID(client); 278 | if(!id) 279 | ThrowError("TextStore_OnClientSave called but GetSteamAccountID is invalid?"); 280 | 281 | Transaction tr = new Transaction(); 282 | 283 | static char buffer[1024]; 284 | Format(buffer, sizeof(buffer), "UPDATE misc_data SET cash = %d WHERE steamid = %d;", TextStore_Cash(client), id); 285 | tr.AddQuery(buffer); 286 | 287 | AddToQueryQueue(tr, Database_Success, Database_Fail); 288 | 289 | tr = new Transaction(); 290 | 291 | LastItem last; 292 | ArrayList list = new ArrayList(sizeof(LastItem)); 293 | 294 | int amount; 295 | int uniques; 296 | int items = TextStore_GetItems(uniques); 297 | for(int i; i 0) 304 | { 305 | TextStore_GetItemName(i, buffer, sizeof(buffer)); 306 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO common_items (steamid, item, count, equip) VALUES ('%d', '%s', '%d', '%d')", id, buffer, amount, equipped); 307 | 308 | tr.AddQuery(buffer); 309 | } 310 | else 311 | { 312 | continue; 313 | } 314 | } 315 | else if(amount > 0) 316 | { 317 | LastItems[client].GetArray(index, last); 318 | if(last.Count != amount || last.Equipped != equipped) 319 | { 320 | TextStore_GetItemName(i, buffer, sizeof(buffer)); 321 | DataBase.Format(buffer, sizeof(buffer), "UPDATE common_items SET count = '%d', equip = '%d' WHERE steamid = %d AND item = '%s';", amount, equipped, id, buffer); 322 | 323 | tr.AddQuery(buffer); 324 | } 325 | } 326 | else 327 | { 328 | TextStore_GetItemName(i, buffer, sizeof(buffer)); 329 | DataBase.Format(buffer, sizeof(buffer), "DELETE FROM common_items WHERE steamid = %d AND item = '%s';", id, buffer); 330 | 331 | tr.AddQuery(buffer); 332 | continue; 333 | } 334 | 335 | last.Item = i; 336 | last.Count = amount; 337 | last.Equipped = equipped; 338 | list.PushArray(last); 339 | } 340 | 341 | AddToQueryQueue(tr, Database_Success, Database_Fail); 342 | 343 | delete LastItems[client]; 344 | LastItems[client] = list; 345 | 346 | if(uniques) 347 | { 348 | tr = new Transaction(); 349 | 350 | uniques = -uniques; 351 | 352 | if(LastUnique[client]) 353 | { 354 | int length = LastUnique[client].Length; 355 | for(int i; i=uniques; i--) 376 | { 377 | bool equipped = TextStore_GetInv(client, i, amount); 378 | if(amount) 379 | { 380 | if(TextStore_GetItemKv(i).GetSectionName(item, sizeof(item))) 381 | { 382 | TextStore_GetItemName(i, name, sizeof(name)); 383 | if(StrEqual(name, item, false)) 384 | name[0] = 0; 385 | 386 | TextStore_GetItemData(i, buffer, sizeof(buffer)); 387 | 388 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO unique_items (steamid, item, name, equip, data) VALUES ('%d', '%s', '%s', '%d', '%s')", id, item, name, equipped, buffer); 389 | 390 | tr.AddQuery(buffer); 391 | 392 | LastUnique[client].PushString(item); 393 | } 394 | else 395 | { 396 | LogError("KeyValues.GetSectionName failed with unique item"); 397 | } 398 | } 399 | } 400 | 401 | AddToQueryQueue(tr, Database_Success, Database_Fail); 402 | } 403 | 404 | if(!CvarBackup.BoolValue) 405 | return Plugin_Handled; 406 | } 407 | return Plugin_Continue; 408 | } 409 | 410 | public Action Command_Convert(int args) 411 | { 412 | if(args == 1) 413 | { 414 | char filepath[PLATFORM_MAX_PATH]; 415 | GetCmdArg(1, filepath, sizeof(filepath)); 416 | 417 | DeleteConvert = StringToInt(filepath) == 1; 418 | 419 | BuildPath(Path_SM, filepath, sizeof(filepath), "data/textstore/user"); 420 | DirectoryListing dir = OpenDirectory(filepath); 421 | if(dir) 422 | { 423 | CreateTimer(1.0, Timer_Convert, dir, TIMER_REPEAT); 424 | } 425 | else 426 | { 427 | PrintToServer("Could not open '%s'", filepath); 428 | } 429 | } 430 | else 431 | { 432 | PrintToServer("[SM] Usage: sm_textstore_convert <0/1 if to delete files on success>"); 433 | } 434 | return Plugin_Handled; 435 | } 436 | 437 | public Action Command_Import(int args) 438 | { 439 | if(args == 1) 440 | { 441 | char filename[512]; 442 | GetCmdArg(1, filename, sizeof(filename)); 443 | 444 | int steamid; 445 | if(GetSteam32FromSteam64(filename, steamid)) 446 | { 447 | BuildPath(Path_SM, filename, sizeof(filename), "data/textstore/user/%s.txt", filename); 448 | File file = OpenFile(filename, "r"); 449 | if(file) 450 | { 451 | PrintToServer("Imported %d items", PortFileToSQL(file, steamid)); 452 | delete file; 453 | } 454 | else 455 | { 456 | PrintToServer("Could not open '%s'", filename); 457 | } 458 | } 459 | else 460 | { 461 | PrintToServer("Invalid Steam64 ID"); 462 | } 463 | } 464 | else 465 | { 466 | PrintToServer("[SM] Usage: sm_textstore_import "); 467 | } 468 | return Plugin_Handled; 469 | } 470 | 471 | public Action Command_Check(int args) 472 | { 473 | if(args == 1) 474 | { 475 | char buffer[256]; 476 | GetCmdArg(1, buffer, sizeof(buffer)); 477 | int id = StringToInt(buffer); 478 | 479 | Transaction tr = new Transaction(); 480 | 481 | FormatEx(buffer, sizeof(buffer), "SELECT * FROM misc_data WHERE steamid = %d;", id); 482 | tr.AddQuery(buffer); 483 | 484 | AddToQueryQueue(tr, Database_Check1, Database_FailPrint, id); 485 | } 486 | else 487 | { 488 | PrintToServer("[SM] Usage: sm_textstore_check "); 489 | } 490 | return Plugin_Handled; 491 | } 492 | 493 | public void Database_Check1(Database db, any id, int numQueries, DBResultSet[] results, any[] queryData) 494 | { 495 | InQuery = false; 496 | 497 | if(results[0].FetchRow()) 498 | { 499 | PrintToServer("Cash: %d", results[0].FetchInt(1)); 500 | 501 | Transaction tr = new Transaction(); 502 | 503 | char buffer[256]; 504 | Format(buffer, sizeof(buffer), "SELECT * FROM common_items WHERE steamid = %d;", id); 505 | tr.AddQuery(buffer); 506 | 507 | AddToQueryQueue(tr, Database_Check2, Database_FailPrint, id); 508 | } 509 | else 510 | { 511 | PrintToServer("No entry for %d", id); 512 | } 513 | } 514 | 515 | public void Database_Check2(Database db, any id, int numQueries, DBResultSet[] results, any[] queryData) 516 | { 517 | InQuery = false; 518 | 519 | char buffer[256]; 520 | while(results[0].MoreRows) 521 | { 522 | if(results[0].FetchRow()) 523 | { 524 | results[0].FetchString(1, buffer, sizeof(buffer)); 525 | PrintToServer("%s: %d%s", buffer, results[0].FetchInt(2), results[0].FetchInt(3) ? " (Equipped)" : ""); 526 | } 527 | } 528 | 529 | Transaction tr = new Transaction(); 530 | 531 | FormatEx(buffer, sizeof(buffer), "SELECT * FROM unique_items WHERE steamid = %d;", id); 532 | tr.AddQuery(buffer); 533 | 534 | AddToQueryQueue(tr, Database_Check3, Database_FailPrint, id); 535 | } 536 | 537 | public void Database_Check3(Database db, any id, int numQueries, DBResultSet[] results, any[] queryData) 538 | { 539 | InQuery = false; 540 | 541 | char item[48], name[48], data[256]; 542 | while(results[0].MoreRows) 543 | { 544 | if(results[0].FetchRow()) 545 | { 546 | results[0].FetchString(1, item, sizeof(item)); 547 | results[0].FetchString(2, name, sizeof(name)); 548 | results[0].FetchString(4, data, sizeof(data)); 549 | 550 | PrintToServer("%s: '%s' '%s'%s", item, name, data, results[0].FetchInt(3) ? " (Equipped)" : ""); 551 | } 552 | } 553 | } 554 | 555 | public Action Command_Modify(int args) 556 | { 557 | if(args > 2 && args < 7) 558 | { 559 | char buffer[512]; 560 | GetCmdArg(1, buffer, sizeof(buffer)); 561 | int id = StringToInt(buffer); 562 | 563 | char item[64]; 564 | GetCmdArg(2, item, sizeof(item)); 565 | 566 | GetCmdArg(3, buffer, sizeof(buffer)); 567 | int amount = StringToInt(buffer); 568 | 569 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO common_items (steamid, item, count, equip) VALUES ('%d', '%s', '1', '0')", id, item); 570 | 571 | int equip; 572 | if(args > 3) 573 | { 574 | GetCmdArg(4, buffer, sizeof(buffer)); 575 | equip = StringToInt(buffer); 576 | } 577 | 578 | Transaction tr = new Transaction(); 579 | 580 | if(args > 4) 581 | { 582 | GetCmdArg(5, buffer, sizeof(buffer)); 583 | 584 | char name[64]; 585 | GetCmdArg(6, name, sizeof(name)); 586 | 587 | if(amount > 0) 588 | { 589 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO unique_items (steamid, item, name, equip, data) VALUES ('%d', '%s', '%s', '%s', '%s')", id, item, name, equip, buffer); 590 | } 591 | else if(args > 5) 592 | { 593 | DataBase.Format(buffer, sizeof(buffer), "DELETE FROM unique_items WHERE steamid = %d AND item = '%s' AND name = '%s';", id, item, name); 594 | } 595 | else 596 | { 597 | DataBase.Format(buffer, sizeof(buffer), "DELETE FROM unique_items WHERE steamid = %d AND item = '%s' AND data = '%s';", id, item, buffer); 598 | } 599 | 600 | tr.AddQuery(buffer); 601 | } 602 | else 603 | { 604 | DataBase.Format(buffer, sizeof(buffer), "DELETE FROM common_items WHERE steamid = %d AND item = '%s';", id, item); 605 | tr.AddQuery(buffer); 606 | 607 | if(amount > 0) 608 | { 609 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO common_items (steamid, item, count, equip) VALUES ('%d', '%s', '%d', '%d')", id, item, amount, equip); 610 | tr.AddQuery(buffer); 611 | } 612 | } 613 | 614 | AddToQueryQueue(tr, Database_Success, Database_FailPrint, id); 615 | PrintToServer(buffer); 616 | } 617 | else 618 | { 619 | PrintToServer("[SM] Usage: sm_textstore_modify [Equipped] [Data] [Name]"); 620 | } 621 | return Plugin_Handled; 622 | } 623 | 624 | public void Database_Success(Database db, any data, int numQueries, DBResultSet[] results, any[] queryData) 625 | { 626 | InQuery = false; 627 | 628 | #if defined DEBUG 629 | PrintToServer("Database_Success"); 630 | #endif 631 | } 632 | 633 | public void Database_Fail(Database db, any data, int numQueries, const char[] error, int failIndex, any[] queryData) 634 | { 635 | InQuery = false; 636 | 637 | #if defined DEBUG 638 | PrintToServer("Database_Fail"); 639 | #endif 640 | 641 | LogError(error); 642 | } 643 | 644 | public void Database_FailPrint(Database db, any data, int numQueries, const char[] error, int failIndex, any[] queryData) 645 | { 646 | InQuery = false; 647 | PrintToServer(error); 648 | } 649 | 650 | public Action Timer_Convert(Handle timer, DirectoryListing dir) 651 | { 652 | if(QueryCount > 10) 653 | return Plugin_Continue; 654 | 655 | FileType type; 656 | char filename[512]; 657 | if(!dir.GetNext(filename, sizeof(filename), type)) 658 | { 659 | delete dir; 660 | PrintToServer("> Finished querying TXT to SQL <"); 661 | return Plugin_Stop; 662 | } 663 | 664 | char filepath[PLATFORM_MAX_PATH]; 665 | BuildPath(Path_SM, filepath, sizeof(filepath), "data/textstore/user"); 666 | 667 | if(type == FileType_File) 668 | { 669 | if(ReplaceString(filename, sizeof(filename), ".txt", "")) 670 | { 671 | int steamid; 672 | if(GetSteam32FromSteam64(filename, steamid)) 673 | { 674 | Format(filename, sizeof(filename), "%s/%s.txt", filepath, filename); 675 | File file = OpenFile(filename, "r"); 676 | if(file) 677 | { 678 | PrintToServer("Processing '%s'", filename); 679 | 680 | PortFileToSQL(file, steamid); 681 | delete file; 682 | 683 | if(DeleteConvert) 684 | DeleteFile(filename); 685 | } 686 | else 687 | { 688 | PrintToServer("> Could not open '%s' <", filename); 689 | } 690 | } 691 | else 692 | { 693 | PrintToServer("> Failed to get steamid of '%s' <", filename); 694 | } 695 | } 696 | else 697 | { 698 | PrintToServer("> Invalid file '%s' <", filename); 699 | } 700 | } 701 | return Plugin_Continue; 702 | } 703 | 704 | void GiveNamedItem(int client, const char[] item, int amount, bool equipped) 705 | { 706 | #if defined DEBUG 707 | PrintToServer("GiveNamedItem"); 708 | #endif 709 | 710 | LastItem last; 711 | int items = TextStore_GetItems(); 712 | for(int i; i 3) 784 | { 785 | if(!unique) 786 | { 787 | unique = new Transaction(); 788 | 789 | Format(buffer, sizeof(buffer), "DELETE FROM unique_items WHERE steamid = %d;", steamid); 790 | unique.AddQuery(buffer); 791 | } 792 | 793 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO unique_items (steamid, item, name, equip, data) VALUES ('%d', '%s', '%s', '%s', '%s')", steamid, buffers[0], buffers[1], buffers[2], buffers[3]); 794 | unique.AddQuery(buffer); 795 | } 796 | else 797 | { 798 | if(!common) 799 | { 800 | common = new Transaction(); 801 | 802 | Format(buffer, sizeof(buffer), "DELETE FROM common_items WHERE steamid = %d;", steamid); 803 | common.AddQuery(buffer); 804 | } 805 | 806 | DataBase.Format(buffer, sizeof(buffer), "INSERT INTO common_items (steamid, item, count, equip) VALUES ('%d', '%s', '%s', '%s')", steamid, buffers[0], buffers[1], buffers[2]); 807 | common.AddQuery(buffer); 808 | } 809 | } 810 | 811 | if(common) 812 | AddToQueryQueue(common, Database_Success, Database_FailPrint, steamid); 813 | 814 | if(unique) 815 | AddToQueryQueue(unique, Database_Success, Database_FailPrint, steamid); 816 | 817 | return found; 818 | } 819 | 820 | /* 821 | https://github.com/alliedmodders/sourcemod/issues/1505 822 | */ 823 | 824 | void AddToQueryQueue(Transaction tr, SQLTxnSuccess onSuccess = INVALID_FUNCTION, SQLTxnFailure onError = INVALID_FUNCTION, any data = 0, DBPriority priority = DBPrio_Normal) 825 | { 826 | QueryCount++; 827 | 828 | #if defined DEBUG 829 | PrintToServer("Timer_QueryQueue -> New Added"); 830 | #endif 831 | 832 | DataPack pack; 833 | CreateDataTimer(0.3, Timer_QueryQueue, pack, TIMER_REPEAT); 834 | pack.WriteCell(tr); 835 | pack.WriteFunction(onSuccess); 836 | pack.WriteFunction(onError); 837 | pack.WriteCell(data); 838 | pack.WriteCell(priority); 839 | } 840 | 841 | public Action Timer_QueryQueue(Handle timer, DataPack pack) 842 | { 843 | #if defined DEBUG 844 | PrintToServer("Timer_QueryQueue -> Pending"); 845 | #endif 846 | 847 | if(InQuery) 848 | return Plugin_Continue; 849 | 850 | QueryCount--; 851 | 852 | InQuery = true; 853 | pack.Reset(); 854 | Transaction tr = pack.ReadCell(); 855 | SQLTxnSuccess onSuccess = view_as(pack.ReadFunction()); 856 | SQLTxnFailure onError = view_as(pack.ReadFunction()); 857 | any data = pack.ReadCell(); 858 | 859 | #if defined DEBUG 860 | PrintToServer("Timer_QueryQueue -> Started New | %x %d %d", tr, view_as(onSuccess), view_as(onError)); 861 | #endif 862 | 863 | DataBase.Execute(tr, onSuccess, onError, data, pack.ReadCell()); 864 | return Plugin_Stop; 865 | } 866 | 867 | /* 868 | https://forums.alliedmods.net/showthread.php?t=60899&page=36 869 | */ 870 | 871 | stock bool GetSteam32FromSteam64(const char[] szSteam64Original, int &iSteam32) 872 | { 873 | char szSteam32[20]; 874 | char szSteam64[20]; 875 | 876 | // We don't want to actually edit the original string. 877 | // We make a new string for the editing. 878 | strcopy(szSteam64, sizeof szSteam64, szSteam64Original); 879 | 880 | // Remove the first three numbers 881 | ReplaceStringEx(szSteam64, sizeof(szSteam64), "765", ""); 882 | 883 | // Because pawn does not support numbers bigger than 2147483647, we will need to subtract using a combination of numbers. 884 | // The combination can be 885 | // 1 number to max integers 886 | char szSubtractionString[] = "61197960265728"; 887 | 888 | // First integer is the integer from szSteam64 889 | // Second is from the subtraction string szSubtractionString 890 | char szFirstInteger[11], szSecondInteger[11]; 891 | int iFirstInteger, iSecondInteger; 892 | 893 | char szResultInt[11]; 894 | 895 | // Ugly hack 896 | // Make the strings 00000000000 so when we use StringToInt the zeroes won't affect the result 897 | // sizeof - 1 because we need the last End of string (0) byte; 898 | SetStringZeros(szFirstInteger, sizeof(szFirstInteger), sizeof(szFirstInteger) - 1); 899 | SetStringZeros(szSecondInteger, sizeof(szSecondInteger), sizeof(szSecondInteger) - 1); 900 | 901 | // Start from the end of the string, because subtraction should always start from the first number in the right. 902 | int iResultInt; 903 | 904 | int iSteam64Position = strlen(szSteam64); 905 | int iIntegerPosition = strlen(szFirstInteger); 906 | 907 | int iNumCount; 908 | int iResultLen; 909 | char szStringZeroes[11]; 910 | 911 | while(--iSteam64Position > -1) 912 | { 913 | iIntegerPosition -= 1; 914 | 915 | ++iNumCount; 916 | szFirstInteger[iIntegerPosition] = szSteam64[iSteam64Position]; 917 | szSecondInteger[iIntegerPosition] = szSubtractionString[iSteam64Position]; 918 | 919 | iFirstInteger = StringToInt(szFirstInteger); 920 | iSecondInteger = StringToInt(szSecondInteger); 921 | 922 | // Can we subtract without getting a negative number? 923 | if(iFirstInteger >= iSecondInteger) 924 | { 925 | iResultInt = iFirstInteger - iSecondInteger; 926 | // 69056897 927 | if(iResultInt) 928 | { 929 | IntToString(iResultInt, szResultInt, sizeof szResultInt); 930 | 931 | if( iNumCount != (iResultLen = strlen(szResultInt) ) ) 932 | { 933 | SetStringZeros(szStringZeroes, sizeof szStringZeroes, iNumCount - iResultLen); 934 | } 935 | 936 | else 937 | { 938 | szStringZeroes = ""; 939 | } 940 | } 941 | 942 | else 943 | { 944 | szResultInt = ""; 945 | 946 | SetStringZeros(szStringZeroes, sizeof szStringZeroes, iNumCount); 947 | } 948 | 949 | Format(szSteam32, sizeof szSteam32, "%s%s%s", szStringZeroes, szResultInt, szSteam32); 950 | 951 | // Reset our stuff. 952 | SetStringZeros(szFirstInteger, sizeof(szFirstInteger), sizeof(szFirstInteger) - 1); 953 | SetStringZeros(szSecondInteger, sizeof(szSecondInteger), sizeof(szSecondInteger) - 1); 954 | 955 | iIntegerPosition = strlen(szFirstInteger); 956 | iNumCount = 0; 957 | } 958 | 959 | if(iIntegerPosition - 1 < 0) 960 | { 961 | // We failed, and this calculation can not be done in pawn. 962 | return false; 963 | } 964 | 965 | // if not, lets add more numbers. 966 | } 967 | 968 | iSteam32 = StringToInt(szSteam32); 969 | return true; 970 | } 971 | 972 | stock void SetStringZeros(char[] szString, int iSize, int iNumZeros) 973 | { 974 | int i; 975 | for(i = 0; i < iNumZeros && i < iSize; i++) 976 | { 977 | szString[i] = '0'; 978 | } 979 | 980 | szString[i] = 0; 981 | } -------------------------------------------------------------------------------- /addons/sourcemod/scripting/textstore_tf2.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #pragma newdecls required 9 | 10 | #define PLUGIN_VERSION "0.1.0" 11 | 12 | ConVar CashKill; 13 | ConVar CashAssist; 14 | ConVar CashFlag; 15 | ConVar CashTeamFlag; 16 | ConVar CashTeamPoint; 17 | ConVar CashTeam; 18 | ConVar CashDefend; 19 | ConVar CashBalance; 20 | ConVar CashDestroy; 21 | ConVar CashDestroy2; 22 | ConVar CashExtinguish; 23 | ConVar CashTeleport; 24 | ConVar CashDamage; 25 | ConVar CashHeal; 26 | ConVar CashMvp1; 27 | ConVar CashMvp2; 28 | ConVar CashMvp3; 29 | ConVar CashStun; 30 | ConVar CashJarate; 31 | ConVar CashMedic; 32 | ConVar CashAirblast; 33 | ConVar CashBoss; 34 | ConVar CashMvM; 35 | ConVar CashScore; 36 | 37 | public Plugin myinfo = 38 | { 39 | name = "The Text Store: TF2 Events", 40 | author = "Batfoxkid", 41 | description = "Generic game events for gaining credits", 42 | version = PLUGIN_VERSION 43 | }; 44 | 45 | public void OnPluginStart() 46 | { 47 | HookEvent("player_death", OnDeath); 48 | CashKill = CreateConVar("textstore_cash_kill", "0", "Amount gained on a player kill."); 49 | CashAssist = CreateConVar("textstore_cash_assist", "0", "Amount gained on a player assist."); 50 | 51 | HookEvent("teamplay_flag_event", OnFlagCapture); 52 | CashFlag = CreateConVar("textstore_cash_flag", "0", "Amount gained on a briefcase capture."); 53 | 54 | HookEventEx("ctf_flag_captured", OnFlagTeamCapture); 55 | CashTeamFlag = CreateConVar("textstore_cash_team_flag", "0", "Amount gained to the team upon capturing the briefcase."); 56 | 57 | HookEvent("teamplay_point_captured", OnPointTeamCapture); 58 | CashTeamPoint = CreateConVar("textstore_cash_team_point", "0", "Amount gained to the team upon capturing the control point."); 59 | 60 | HookEvent("teamplay_round_win", OnRoundEnd); 61 | CashTeam = CreateConVar("textstore_cash_team", "0", "Amount gained to the team upon winning the match."); 62 | 63 | HookEvent("teamplay_capture_blocked", OnPointBlock); 64 | CashDefend = CreateConVar("textstore_cash_block", "0", "Amount gained to a defending player."); 65 | 66 | HookEvent("teamplay_teambalanced_player", OnBalance); 67 | CashBalance = CreateConVar("textstore_cash_balance", "0", "Amount gained to an autobalanced player."); 68 | 69 | HookEvent("object_destroyed", OnDestroy); 70 | CashDestroy = CreateConVar("textstore_cash_destroy", "0", "Amount gained on a building kill."); 71 | CashDestroy2 = CreateConVar("textstore_cash_destroy2", "0", "Amount gained on a building assist."); 72 | 73 | HookEvent("player_extinguished", OnExtinguish); 74 | CashExtinguish = CreateConVar("textstore_cash_extinguish", "0", "Amount gained on an extinguish."); 75 | 76 | HookEvent("player_teleported", OnTeleport); 77 | CashTeleport = CreateConVar("textstore_cash_teleport", "0", "Amount gained on a teleport."); 78 | 79 | HookEvent("player_hurt", OnHurt); 80 | CashDamage = CreateConVar("textstore_cash_damage", "0", "Amount of damage dealt per cash."); 81 | 82 | HookEvent("player_healed", OnHeal); 83 | HookEvent("building_healed", OnBuildingHeal); 84 | CashHeal = CreateConVar("textstore_cash_heal", "0", "Amount of damage healed per cash."); 85 | 86 | HookEvent("teamplay_win_panel", OnRoundPanel); 87 | HookEventEx("arena_win_panel", OnRoundPanel); 88 | CashMvp1 = CreateConVar("textstore_cash_mvp1", "0", "Amount gained to the 1st place MVP."); 89 | CashMvp2 = CreateConVar("textstore_cash_mvp2", "0", "Amount gained to the 2nd place MVP."); 90 | CashMvp3 = CreateConVar("textstore_cash_mvp3", "0", "Amount gained to the 3rd place MVP."); 91 | 92 | HookEvent("player_stunned", OnStun); 93 | HookEvent("eyeball_boss_stunned", OnEyeball); 94 | CashStun = CreateConVar("textstore_cash_stun", "0", "Amount gained on a stun."); 95 | 96 | HookEvent("player_jarated", OnJarate); 97 | CashJarate = CreateConVar("textstore_cash_jarate", "0", "Amount gained on a jarate hit."); 98 | 99 | HookEvent("medic_death", OnMedic); 100 | CashMedic = CreateConVar("textstore_cash_medic", "0", "Amount gained on a fully charged Medic kill."); 101 | 102 | HookEvent("object_deflected", OnDeflect); 103 | CashAirblast = CreateConVar("textstore_cash_airblast", "0", "Amount gained on an airblast."); 104 | 105 | HookEvent("pumpkin_lord_killed", OnBoss, EventHookMode_PostNoCopy); 106 | HookEvent("merasmus_killed", OnBoss, EventHookMode_PostNoCopy); 107 | HookEvent("eyeball_boss_killed", OnBoss, EventHookMode_PostNoCopy); 108 | CashBoss = CreateConVar("textstore_cash_halloween", "0", "Amount gained to everyone on a boss killed."); 109 | 110 | HookEventEx("mvm_mission_complete", OnMvM, EventHookMode_PostNoCopy); 111 | CashMvM = CreateConVar("textstore_cash_mvm", "0.0", "Ratio of leftover cash kept."); 112 | 113 | HookEvent("player_score_changed", OnScore); 114 | CashScore = CreateConVar("textstore_cash_score", "0.0", "Ratio of score gained to cash."); 115 | 116 | AutoExecConfig(true, "TextStore_TF2"); 117 | } 118 | 119 | /* 120 | Kill 121 | Kill Assist 122 | */ 123 | public void OnDeath(Event event, const char[] name, bool dontBroadcast) 124 | { 125 | int flags = event.GetInt("death_flags"); 126 | if(flags & TF_DEATHFLAG_DEADRINGER) 127 | return; 128 | 129 | int client = GetClientOfUserId(event.GetInt("userid")); 130 | if(!IsValidClient(client) || IsFakeClient(client)) 131 | return; 132 | 133 | int attacker = GetClientOfUserId(event.GetInt("attacker")); 134 | if(client==attacker || !IsValidClient(attacker) || IsFakeClient(attacker)) 135 | return; 136 | 137 | AddCash(attacker, CashKill.IntValue); 138 | client = GetClientOfUserId(event.GetInt("assister")); 139 | if(IsValidClient(client)) 140 | AddCash(client, CashAssist.IntValue); 141 | } 142 | 143 | /* 144 | Flag Capture 145 | Objective Defend 146 | */ 147 | public void OnFlagCapture(Event event, const char[] name, bool dontBroadcast) 148 | { 149 | int client = event.GetInt("player"); 150 | if(!IsValidClient(client)) 151 | return; 152 | 153 | switch(event.GetInt("eventtype")) 154 | { 155 | case TF_FLAGEVENT_CAPTURED: 156 | { 157 | AddCash(client, CashFlag.IntValue); 158 | } 159 | case TF_FLAGEVENT_DEFENDED: 160 | { 161 | int victim = event.GetInt("carrier"); 162 | if(IsValidClient(victim) && !IsFakeClient(victim)) 163 | AddCash(client, CashDefend.IntValue); 164 | } 165 | } 166 | } 167 | 168 | /* 169 | Team Flag Capture 170 | */ 171 | public void OnFlagTeamCapture(Event event, const char[] name, bool dontBroadcast) 172 | { 173 | int team = event.GetInt("capping_team"); 174 | if(team!=2 && team!=3) 175 | return; 176 | 177 | for(int client=1; client<=MaxClients; client++) 178 | { 179 | if(IsValidClient(client) && GetClientTeam(client)==team) 180 | AddCash(client, CashTeamFlag.IntValue); 181 | } 182 | } 183 | 184 | /* 185 | Point Capture 186 | */ 187 | public void OnPointTeamCapture(Event event, const char[] name, bool dontBroadcast) 188 | { 189 | int team = event.GetInt("team"); 190 | if(team!=2 && team!=3) 191 | return; 192 | 193 | for(int client=1; client<=MaxClients; client++) 194 | { 195 | if(IsValidClient(client) && GetClientTeam(client)==team) 196 | AddCash(client, CashTeamPoint.IntValue); 197 | } 198 | } 199 | 200 | /* 201 | Round Win 202 | */ 203 | public void OnRoundEnd(Event event, const char[] name, bool dontBroadcast) 204 | { 205 | int team = event.GetInt("team"); 206 | if(team!=2 && team!=3) 207 | return; 208 | 209 | for(int client=1; client<=MaxClients; client++) 210 | { 211 | if(IsValidClient(client) && GetClientTeam(client)==team) 212 | AddCash(client, CashTeam.IntValue); 213 | } 214 | } 215 | 216 | /* 217 | Objective Defend 218 | */ 219 | public void OnPointBlock(Event event, const char[] name, bool dontBroadcast) 220 | { 221 | int client = event.GetInt("victim"); 222 | if(!IsValidClient(client) || IsFakeClient(client)) 223 | return; 224 | 225 | client = event.GetInt("blocker"); 226 | if(IsValidClient(client)) 227 | AddCash(client, CashDefend.IntValue); 228 | } 229 | 230 | /* 231 | Autobalance 232 | */ 233 | public void OnBalance(Event event, const char[] name, bool dontBroadcast) 234 | { 235 | int client = event.GetInt("player"); 236 | if(IsValidClient(client)) 237 | AddCash(client, CashBalance.IntValue); 238 | } 239 | 240 | /* 241 | Building Destroyed 242 | */ 243 | public void OnDestroy(Event event, const char[] name, bool dontBroadcast) 244 | { 245 | int client = GetClientOfUserId(event.GetInt("userid")); 246 | if(!IsValidClient(client) || IsFakeClient(client)) 247 | return; 248 | 249 | int attacker = GetClientOfUserId(event.GetInt("attacker")); 250 | if(client==attacker || !IsValidClient(attacker) || IsFakeClient(attacker)) 251 | return; 252 | 253 | AddCash(attacker, CashDestroy.IntValue); 254 | client = GetClientOfUserId(event.GetInt("assister")); 255 | if(IsValidClient(client)) 256 | AddCash(client, CashDestroy2.IntValue); 257 | } 258 | 259 | /* 260 | Extinguish 261 | */ 262 | public void OnExtinguish(Event event, const char[] name, bool dontBroadcast) 263 | { 264 | int client = event.GetInt("victim"); 265 | if(!IsValidClient(client) || IsFakeClient(client)) 266 | return; 267 | 268 | client = event.GetInt("healer"); 269 | if(IsValidClient(client)) 270 | AddCash(client, CashExtinguish.IntValue); 271 | } 272 | 273 | /* 274 | Teleport 275 | */ 276 | public void OnTeleport(Event event, const char[] name, bool dontBroadcast) 277 | { 278 | if(event.GetFloat("dist") < 400) 279 | return; 280 | 281 | int client = GetClientOfUserId(event.GetInt("userid")); 282 | if(!IsValidClient(client) || IsFakeClient(client)) 283 | return; 284 | 285 | client = GetClientOfUserId(event.GetInt("builderid")); 286 | if(IsValidClient(client)) 287 | AddCash(client, CashTeleport.IntValue); 288 | } 289 | 290 | /* 291 | Damage 292 | */ 293 | public void OnHurt(Event event, const char[] name, bool dontBroadcast) 294 | { 295 | int value = CashDamage.IntValue; 296 | if(value < 1) 297 | return; 298 | 299 | int client = GetClientOfUserId(event.GetInt("userid")); 300 | if(!IsValidClient(client) || IsFakeClient(client)) 301 | return; 302 | 303 | client = GetClientOfUserId(event.GetInt("attacker")); 304 | if(!IsValidClient(client)) 305 | return; 306 | 307 | static int damage[MAXPLAYERS+1]; 308 | damage[client] += event.GetInt("damageamount"); 309 | int cash; 310 | while(damage[client] >= value) 311 | { 312 | cash++; 313 | damage[client] -= value; 314 | } 315 | AddCash(client, cash); 316 | } 317 | 318 | /* 319 | Healing 320 | */ 321 | public void OnHeal(Event event, const char[] name, bool dontBroadcast) 322 | { 323 | int value = CashHeal.IntValue; 324 | if(value < 1) 325 | return; 326 | 327 | int client = GetClientOfUserId(event.GetInt("patient")); 328 | if(!IsValidClient(client) || IsFakeClient(client)) 329 | return; 330 | 331 | client = GetClientOfUserId(event.GetInt("healer")); 332 | if(!IsValidClient(client)) 333 | return; 334 | 335 | static int healing[MAXPLAYERS+1]; 336 | healing[client] += event.GetInt("amount"); 337 | int cash; 338 | while(healing[client] >= value) 339 | { 340 | cash++; 341 | healing[client] -= value; 342 | } 343 | AddCash(client, cash); 344 | } 345 | 346 | /* 347 | Healing 348 | */ 349 | public void OnBuildingHeal(Event event, const char[] name, bool dontBroadcast) 350 | { 351 | int value = CashHeal.IntValue; 352 | if(value < 1) 353 | return; 354 | 355 | int client = GetClientOfUserId(event.GetInt("healer")); 356 | if(!IsValidClient(client)) 357 | return; 358 | 359 | static int healing[MAXPLAYERS+1]; 360 | healing[client] += event.GetInt("amount"); 361 | int cash; 362 | while(healing[client] >= value) 363 | { 364 | cash++; 365 | healing[client] -= value; 366 | } 367 | AddCash(client, cash); 368 | } 369 | 370 | /* 371 | MVPs 372 | */ 373 | public void OnRoundPanel(Event event, const char[] name, bool dontBroadcast) 374 | { 375 | int client = GetClientOfUserId(event.GetInt("player_1")); 376 | if(IsValidClient(client)) 377 | AddCash(client, CashMvp1.IntValue); 378 | 379 | client = GetClientOfUserId(event.GetInt("player_2")); 380 | if(IsValidClient(client)) 381 | AddCash(client, CashMvp2.IntValue); 382 | 383 | client = GetClientOfUserId(event.GetInt("player_3")); 384 | if(IsValidClient(client)) 385 | AddCash(client, CashMvp3.IntValue); 386 | } 387 | 388 | /* 389 | Stun 390 | */ 391 | public void OnStun(Event event, const char[] name, bool dontBroadcast) 392 | { 393 | int client = GetClientOfUserId(event.GetInt("victim")); 394 | if(!IsValidClient(client) || IsFakeClient(client)) 395 | return; 396 | 397 | client = GetClientOfUserId(event.GetInt("stunner")); 398 | if(IsValidClient(client)) 399 | AddCash(client, CashStun.IntValue); 400 | } 401 | 402 | /* 403 | Stun 404 | */ 405 | public void OnEyeball(Event event, const char[] name, bool dontBroadcast) 406 | { 407 | int client = event.GetInt("player_entindex"); 408 | if(IsValidClient(client)) 409 | AddCash(client, CashStun.IntValue); 410 | } 411 | 412 | /* 413 | Jarate 414 | */ 415 | public void OnJarate(Event event, const char[] name, bool dontBroadcast) 416 | { 417 | int client = event.GetInt("victim_entindex"); 418 | if(!IsValidClient(client) || IsFakeClient(client)) 419 | return; 420 | 421 | client = event.GetInt("thrower_entindex"); 422 | if(IsValidClient(client)) 423 | AddCash(client, CashJarate.IntValue); 424 | } 425 | 426 | /* 427 | Full Charged Kill 428 | */ 429 | public void OnMedic(Event event, const char[] name, bool dontBroadcast) 430 | { 431 | if(!event.GetBool("charged")) 432 | return; 433 | 434 | int client = GetClientOfUserId(event.GetInt("userid")); 435 | if(!IsValidClient(client) || IsFakeClient(client)) 436 | return; 437 | 438 | client = GetClientOfUserId(event.GetInt("attacker")); 439 | if(IsValidClient(client)) 440 | AddCash(client, CashMedic.IntValue); 441 | } 442 | 443 | /* 444 | Deflect 445 | */ 446 | public void OnDeflect(Event event, const char[] name, bool dontBroadcast) 447 | { 448 | int client = GetClientOfUserId(event.GetInt("ownerid")); 449 | if(!IsValidClient(client) || IsFakeClient(client)) 450 | return; 451 | 452 | client = GetClientOfUserId(event.GetInt("userid")); 453 | if(IsValidClient(client)) 454 | AddCash(client, CashAirblast.IntValue); 455 | } 456 | 457 | /* 458 | Boss Death 459 | */ 460 | public void OnBoss(Event event, const char[] name, bool dontBroadcast) 461 | { 462 | for(int client=1; client<=MaxClients; client++) 463 | { 464 | if(IsValidClient(client)) 465 | AddCash(client, CashBoss.IntValue); 466 | } 467 | } 468 | 469 | /* 470 | MvM Gameover 471 | */ 472 | public void OnMvM(Event event, const char[] name, bool dontBroadcast) 473 | { 474 | for(int client=1; client<=MaxClients; client++) 475 | { 476 | if(IsValidClient(client) && !IsFakeClient(client)) 477 | AddCash(client, RoundFloat(GetEntProp(client, Prop_Send, "m_nCurrency")*CashMvM.FloatValue)); 478 | } 479 | } 480 | 481 | /* 482 | Score 483 | */ 484 | public void OnScore(Event event, const char[] name, bool dontBroadcast) 485 | { 486 | int client = event.GetInt("player"); 487 | if(IsValidClient(client)) 488 | AddCash(client, RoundFloat(event.GetInt("delta")*CashScore.FloatValue)); 489 | } 490 | 491 | stock bool IsValidClient(int client, bool replaycheck=true) 492 | { 493 | if(client<=0 || client>MaxClients) 494 | return false; 495 | 496 | if(!IsClientInGame(client)) 497 | return false; 498 | 499 | if(GetEntProp(client, Prop_Send, "m_bIsCoaching")) 500 | return false; 501 | 502 | if(replaycheck && (IsClientSourceTV(client) || IsClientReplay(client))) 503 | return false; 504 | 505 | return true; 506 | } 507 | 508 | 509 | stock void AddCash(int client, int amount) 510 | { 511 | if(amount) 512 | TextStore_Cash(client, amount); 513 | } -------------------------------------------------------------------------------- /scripts/date.sh: -------------------------------------------------------------------------------- 1 | SEC=$(date "+%s") 2 | export DATA_VERSION=$(expr $((SEC)) / 60) 3 | echo "DATA_VERSION<> $GITHUB_ENV 4 | echo $DATA_VERSION >> $GITHUB_ENV 5 | echo 'EOF' >> $GITHUB_ENV -------------------------------------------------------------------------------- /scripts/install.sh: -------------------------------------------------------------------------------- 1 | # Create build folder 2 | mkdir build 3 | cd build 4 | 5 | # Install SourceMod 6 | wget --input-file=http://sourcemod.net/smdrop/$SM_VERSION/sourcemod-latest-linux 7 | tar -xzf $(cat sourcemod-latest-linux) 8 | 9 | # Copy sp to build dir 10 | cp -r ../addons/sourcemod/scripting addons/sourcemod 11 | cd addons/sourcemod/scripting 12 | 13 | # Install Dependency 14 | wget "https://raw.githubusercontent.com/DoctorMcKay/sourcemod-plugins/master/scripting/include/morecolors.inc" -O include/morecolors.inc 15 | 16 | # Install Third-Parties 17 | wget "https://raw.githubusercontent.com/Drixevel/Chat-Processor/master/scripting/include/chat-processor.inc" -O include/chat-processor.inc 18 | //wget "https://raw.githubusercontent.com/Batfoxkid/FreakFortressBat/development/addons/sourcemod/scripting/include/freak_fortress_2.inc" -O include/freak_fortress_2.inc 19 | wget "https://raw.githubusercontent.com/Totenfluch/tVip/master/include/tVip.inc" -O include/tVip.inc 20 | -------------------------------------------------------------------------------- /scripts/package.sh: -------------------------------------------------------------------------------- 1 | # Go to build dir 2 | cd build 3 | 4 | # Create package dir 5 | mkdir -p package/addons/sourcemod/plugins/disabled 6 | mkdir -p package/addons/sourcemod/data/textstore 7 | mkdir -p package/addons/sourcemod/configs 8 | 9 | # Copy all required stuffs to package 10 | cp -r addons/sourcemod/plugins/textstore.smx package/addons/sourcemod/plugins 11 | cp -r addons/sourcemod/plugins/textstore_defaults.smx package/addons/sourcemod/plugins/disabled 12 | cp -r addons/sourcemod/plugins/textstore_generic.smx package/addons/sourcemod/plugins/disabled 13 | cp -r addons/sourcemod/plugins/textstore_sqlite.smx package/addons/sourcemod/plugins/disabled 14 | cp -r addons/sourcemod/plugins/textstore_mysql.smx package/addons/sourcemod/plugins/disabled 15 | cp -r addons/sourcemod/plugins/textstore_tf2.smx package/addons/sourcemod/plugins/disabled 16 | cp -r ../addons/sourcemod/configs/textstore package/addons/sourcemod/configs --------------------------------------------------------------------------------