Files
@ r23068:3f6d98eba246
Branch filter:
Location: cpp/openttd-patchpack/source/src/newgrf_config.cpp - annotation
r23068:3f6d98eba246
27.5 KiB
text/x-c
Fix: Spelling in code comment (#6984)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 | r5584:545d748cc681 r5584:545d748cc681 r12768:980ae0491352 r12768:980ae0491352 r12768:980ae0491352 r12768:980ae0491352 r12768:980ae0491352 r12768:980ae0491352 r12768:980ae0491352 r9111:983de9c5a848 r6348:a905c3e6d8fa r5584:545d748cc681 r5584:545d748cc681 r12767:3d23682b3fda r5584:545d748cc681 r13054:319ef5c8a6c7 r10066:d73a08a8dd72 r15579:ec523aee641f r15588:8aad267fa5ef r17977:5601372941d2 r17999:efe4e10ba6ab r18336:f5d99f393cb2 r19067:8b759022e9ee r5584:545d748cc681 r10039:727fb45b0424 r5584:545d748cc681 r5584:545d748cc681 r21383:942c32fb8b0e r21383:942c32fb8b0e r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r15581:4edf751ff5e7 r17403:bbaee031fd60 r17403:bbaee031fd60 r18637:6db0bce1fa51 r15581:4edf751ff5e7 r14667:a7ee51a0cfe3 r21410:ae5961f02724 r17403:bbaee031fd60 r17403:bbaee031fd60 r18637:6db0bce1fa51 r14667:a7ee51a0cfe3 r14667:a7ee51a0cfe3 r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r15614:2fd6c22346ef r15578:4df52cbd221a r17403:bbaee031fd60 r17403:bbaee031fd60 r18637:6db0bce1fa51 r15589:fd456a62bb1c r16249:929ddeef42a2 r16399:691df58e2b63 r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r15581:4edf751ff5e7 r15907:70e379b9c8d1 r15907:70e379b9c8d1 r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r21410:ae5961f02724 r17403:bbaee031fd60 r17403:bbaee031fd60 r18637:6db0bce1fa51 r21498:c603a3d7e3d7 r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r14667:a7ee51a0cfe3 r14667:a7ee51a0cfe3 r21410:ae5961f02724 r14667:a7ee51a0cfe3 r14667:a7ee51a0cfe3 r14667:a7ee51a0cfe3 r14667:a7ee51a0cfe3 r17403:bbaee031fd60 r17403:bbaee031fd60 r18637:6db0bce1fa51 r15585:151b3e97ecca r15585:151b3e97ecca r14667:a7ee51a0cfe3 r5584:545d748cc681 r14701:3d820af7badc r21498:c603a3d7e3d7 r21498:c603a3d7e3d7 r21498:c603a3d7e3d7 r21498:c603a3d7e3d7 r21498:c603a3d7e3d7 r21498:c603a3d7e3d7 r21498:c603a3d7e3d7 r21498:c603a3d7e3d7 r21498:c603a3d7e3d7 r21498:c603a3d7e3d7 r21498:c603a3d7e3d7 r14701:3d820af7badc r14701:3d820af7badc r14701:3d820af7badc r14701:3d820af7badc r14701:3d820af7badc r14701:3d820af7badc r17403:bbaee031fd60 r15579:ec523aee641f r14701:3d820af7badc r14701:3d820af7badc r14701:3d820af7badc r14701:3d820af7badc r14701:3d820af7badc r14701:3d820af7badc r14701:3d820af7badc r14701:3d820af7badc r17403:bbaee031fd60 r14701:3d820af7badc r14701:3d820af7badc r18637:6db0bce1fa51 r18637:6db0bce1fa51 r18637:6db0bce1fa51 r18637:6db0bce1fa51 r18637:6db0bce1fa51 r18637:6db0bce1fa51 r18637:6db0bce1fa51 r18637:6db0bce1fa51 r18637:6db0bce1fa51 r15907:70e379b9c8d1 r15907:70e379b9c8d1 r15907:70e379b9c8d1 r15910:d159c4eed185 r15910:d159c4eed185 r15910:d159c4eed185 r15907:70e379b9c8d1 r15907:70e379b9c8d1 r15907:70e379b9c8d1 r15907:70e379b9c8d1 r15907:70e379b9c8d1 r15907:70e379b9c8d1 r15907:70e379b9c8d1 r15907:70e379b9c8d1 r15582:6daf5f9adce7 r15582:6daf5f9adce7 r15582:6daf5f9adce7 r15582:6daf5f9adce7 r15582:6daf5f9adce7 r15582:6daf5f9adce7 r15582:6daf5f9adce7 r15584:5fce62ffde01 r15584:5fce62ffde01 r15584:5fce62ffde01 r15584:5fce62ffde01 r17635:2e67e206a89e r15584:5fce62ffde01 r15583:941df37daa12 r15582:6daf5f9adce7 r15582:6daf5f9adce7 r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r22525:8b64738b95fa r5584:545d748cc681 r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r14662:8798e984ee81 r14662:8798e984ee81 r14662:8798e984ee81 r14662:8798e984ee81 r14662:8798e984ee81 r14662:8798e984ee81 r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r15614:2fd6c22346ef r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r18943:3e25b87ea626 r15578:4df52cbd221a r21410:ae5961f02724 r21410:ae5961f02724 r15578:4df52cbd221a r15578:4df52cbd221a r15578:4df52cbd221a r14662:8798e984ee81 r14662:8798e984ee81 r14662:8798e984ee81 r14662:8798e984ee81 r14665:3e40198321ce r5584:545d748cc681 r10077:8eaa30adac4c r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15907:70e379b9c8d1 r15585:151b3e97ecca r15585:151b3e97ecca r20983:4b9faf9002d5 r20983:4b9faf9002d5 r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15907:70e379b9c8d1 r15585:151b3e97ecca r15585:151b3e97ecca r19401:96b7d1ecdefe r19401:96b7d1ecdefe r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15585:151b3e97ecca r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r18743:bbdd9a165607 r15588:8aad267fa5ef r15588:8aad267fa5ef r15588:8aad267fa5ef r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r19401:96b7d1ecdefe r10077:8eaa30adac4c r17635:2e67e206a89e r17635:2e67e206a89e r17635:2e67e206a89e r10077:8eaa30adac4c r17635:2e67e206a89e r10077:8eaa30adac4c r15582:6daf5f9adce7 r15582:6daf5f9adce7 r17635:2e67e206a89e r17635:2e67e206a89e r10077:8eaa30adac4c r10077:8eaa30adac4c r15610:623a23fb6560 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r20996:741ab417bbc0 r20996:741ab417bbc0 r20996:741ab417bbc0 r20996:741ab417bbc0 r20996:741ab417bbc0 r20996:741ab417bbc0 r20996:741ab417bbc0 r20996:741ab417bbc0 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r19020:24d71054fe13 r15610:623a23fb6560 r14938:f0f284e68313 r18007:5ef6f0cf0861 r14938:f0f284e68313 r14938:f0f284e68313 r18007:5ef6f0cf0861 r5584:545d748cc681 r5584:545d748cc681 r8133:beb8760dad9b r8133:beb8760dad9b r7574:bb4845f3b405 r5584:545d748cc681 r5584:545d748cc681 r18007:5ef6f0cf0861 r5584:545d748cc681 r5584:545d748cc681 r20987:a313d4924904 r19020:24d71054fe13 r20984:a4da9302878d r20987:a313d4924904 r20984:a4da9302878d r20984:a4da9302878d r20984:a4da9302878d r19020:24d71054fe13 r5584:545d748cc681 r7574:bb4845f3b405 r7574:bb4845f3b405 r8133:beb8760dad9b r5584:545d748cc681 r14666:896110212413 r5584:545d748cc681 r7592:61dd21c1e893 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r15610:623a23fb6560 r15610:623a23fb6560 r14938:f0f284e68313 r14938:f0f284e68313 r18007:5ef6f0cf0861 r14938:f0f284e68313 r14938:f0f284e68313 r18007:5ef6f0cf0861 r5584:545d748cc681 r18007:5ef6f0cf0861 r6229:a69564e4eb2e r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r18007:5ef6f0cf0861 r15632:f0869f88fe5b r19401:96b7d1ecdefe r5584:545d748cc681 r22516:ed10ea44b974 r22516:ed10ea44b974 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r22514:7345381ee779 r5584:545d748cc681 r5584:545d748cc681 r7928:a80e7e05d6c5 r5584:545d748cc681 r5584:545d748cc681 r18007:5ef6f0cf0861 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r15610:623a23fb6560 r15610:623a23fb6560 r14938:f0f284e68313 r14938:f0f284e68313 r14938:f0f284e68313 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r14667:a7ee51a0cfe3 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r15610:623a23fb6560 r15610:623a23fb6560 r5584:545d748cc681 r6073:7d9b29ccbda4 r6956:6398843f1341 r15613:193c12018337 r15613:193c12018337 r6956:6398843f1341 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r15578:4df52cbd221a r13055:ad502f16f76d r7929:67846e70abf8 r7931:4c17a74c399e r6956:6398843f1341 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r14666:896110212413 r5675:dc81b4d0bd0a r5584:545d748cc681 r14667:a7ee51a0cfe3 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r6956:6398843f1341 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r15610:623a23fb6560 r15610:623a23fb6560 r6481:534c9f0317ec r15613:193c12018337 r15613:193c12018337 r6108:580a9fc2a546 r6073:7d9b29ccbda4 r6073:7d9b29ccbda4 r6073:7d9b29ccbda4 r6108:580a9fc2a546 r6108:580a9fc2a546 r6073:7d9b29ccbda4 r6073:7d9b29ccbda4 r6073:7d9b29ccbda4 r5584:545d748cc681 r14938:f0f284e68313 r5584:545d748cc681 r5584:545d748cc681 r6956:6398843f1341 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r15610:623a23fb6560 r15610:623a23fb6560 r15320:d9619cca229a r5647:efd04e64f814 r5647:efd04e64f814 r15594:ba7e42fbae24 r6229:a69564e4eb2e r5647:efd04e64f814 r6229:a69564e4eb2e r15613:193c12018337 r15613:193c12018337 r15320:d9619cca229a r5584:545d748cc681 r6229:a69564e4eb2e r5584:545d748cc681 r15320:d9619cca229a r16246:b0e8840a555e r17067:d8300f20b7a7 r5652:bf07a5316cc6 r5647:efd04e64f814 r5647:efd04e64f814 r5647:efd04e64f814 r16247:0b3fc1f1c234 r5647:efd04e64f814 r14666:896110212413 r14666:896110212413 r15321:b66ded98380f r15321:b66ded98380f r15321:b66ded98380f r15321:b66ded98380f r15321:b66ded98380f r5584:545d748cc681 r5647:efd04e64f814 r6229:a69564e4eb2e r5647:efd04e64f814 r5647:efd04e64f814 r5584:545d748cc681 r5647:efd04e64f814 r14666:896110212413 r14666:896110212413 r5647:efd04e64f814 r6229:a69564e4eb2e r6229:a69564e4eb2e r5584:545d748cc681 r5647:efd04e64f814 r14666:896110212413 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r7928:a80e7e05d6c5 r5584:545d748cc681 r21410:ae5961f02724 r14666:896110212413 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r6103:436b6b65ad3d r16063:2ea39df1dc9d r16247:0b3fc1f1c234 r16063:2ea39df1dc9d r16063:2ea39df1dc9d r16063:2ea39df1dc9d r16063:2ea39df1dc9d r16063:2ea39df1dc9d r16063:2ea39df1dc9d r16063:2ea39df1dc9d r16063:2ea39df1dc9d r16063:2ea39df1dc9d r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r10036:45f5444a2a0e r10036:45f5444a2a0e r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r10036:45f5444a2a0e r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r18073:853f8705886d r10036:45f5444a2a0e r10036:45f5444a2a0e r10036:45f5444a2a0e r10036:45f5444a2a0e r10036:45f5444a2a0e r18003:2d66578e7015 r17978:c07585e51a28 r17978:c07585e51a28 r17978:c07585e51a28 r17978:c07585e51a28 r10036:45f5444a2a0e r10036:45f5444a2a0e r10036:45f5444a2a0e r18073:853f8705886d r7572:7265401378fc r14667:a7ee51a0cfe3 r5584:545d748cc681 r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r8592:b79e66665a5d r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r14666:896110212413 r7572:7265401378fc r7573:0a72989ad9ee r7573:0a72989ad9ee r14701:3d820af7badc r8592:b79e66665a5d r8592:b79e66665a5d r8592:b79e66665a5d r8592:b79e66665a5d r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17978:c07585e51a28 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r7572:7265401378fc r7572:7265401378fc r8592:b79e66665a5d r14667:a7ee51a0cfe3 r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r7572:7265401378fc r5584:545d748cc681 r7644:3e396e72857f r7644:3e396e72857f r7644:3e396e72857f r7644:3e396e72857f r7644:3e396e72857f r7644:3e396e72857f r13016:a61b770ac6ad r7644:3e396e72857f r13016:a61b770ac6ad r13016:a61b770ac6ad r7644:3e396e72857f r21909:cf5e3292f853 r7644:3e396e72857f r7644:3e396e72857f r17971:2adf1b724154 r17977:5601372941d2 r17971:2adf1b724154 r17971:2adf1b724154 r17977:5601372941d2 r5584:545d748cc681 r17977:5601372941d2 r17977:5601372941d2 r5584:545d748cc681 r18376:e66b27d1ff1d r5584:545d748cc681 r5584:545d748cc681 r10036:45f5444a2a0e r7644:3e396e72857f r5584:545d748cc681 r17952:b3b330b8aebd r17952:b3b330b8aebd r21851:d6e7af1973e0 r21851:d6e7af1973e0 r17952:b3b330b8aebd r7644:3e396e72857f r17952:b3b330b8aebd r17952:b3b330b8aebd r17952:b3b330b8aebd r17952:b3b330b8aebd r17952:b3b330b8aebd r17952:b3b330b8aebd r7644:3e396e72857f r17952:b3b330b8aebd r7644:3e396e72857f r17952:b3b330b8aebd r17952:b3b330b8aebd r17952:b3b330b8aebd r17952:b3b330b8aebd r17952:b3b330b8aebd r9133:8ef222bc2a90 r17952:b3b330b8aebd r13054:319ef5c8a6c7 r13054:319ef5c8a6c7 r17952:b3b330b8aebd r13054:319ef5c8a6c7 r17952:b3b330b8aebd r17952:b3b330b8aebd r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17952:b3b330b8aebd r17977:5601372941d2 r18743:bbdd9a165607 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r5584:545d748cc681 r5584:545d748cc681 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r17977:5601372941d2 r18001:8d1b53a88f0a r18001:8d1b53a88f0a r18001:8d1b53a88f0a r18001:8d1b53a88f0a r18001:8d1b53a88f0a r22463:71520ac0d007 r17977:5601372941d2 r17981:36db410918c7 r17977:5601372941d2 r17981:36db410918c7 r17977:5601372941d2 r18001:8d1b53a88f0a r18001:8d1b53a88f0a r17977:5601372941d2 r17977:5601372941d2 r5584:545d748cc681 r15610:623a23fb6560 r15610:623a23fb6560 r14938:f0f284e68313 r16246:b0e8840a555e r16246:b0e8840a555e r16247:0b3fc1f1c234 r14938:f0f284e68313 r14938:f0f284e68313 r16247:0b3fc1f1c234 r5584:545d748cc681 r16246:b0e8840a555e r15589:fd456a62bb1c r5646:df89a7ff5d5e r16246:b0e8840a555e r15589:fd456a62bb1c r16246:b0e8840a555e r16246:b0e8840a555e r17067:d8300f20b7a7 r17067:d8300f20b7a7 r16247:0b3fc1f1c234 r16247:0b3fc1f1c234 r16246:b0e8840a555e r15589:fd456a62bb1c r5584:545d748cc681 r5584:545d748cc681 r15589:fd456a62bb1c r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5765:cfade44195bc r17629:21e9dfd343cd r17629:21e9dfd343cd r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r5584:545d748cc681 r17403:bbaee031fd60 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5609:a56ae00a9125 r5584:545d748cc681 r5584:545d748cc681 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r17403:bbaee031fd60 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r15610:623a23fb6560 r15610:623a23fb6560 r14938:f0f284e68313 r14938:f0f284e68313 r14938:f0f284e68313 r14938:f0f284e68313 r10781:758b3ae29fdd r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r14666:896110212413 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r14938:f0f284e68313 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r10299:def8dff34f3b r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r5584:545d748cc681 r7882:cdf03a4ac84a r7882:cdf03a4ac84a r7882:cdf03a4ac84a r7882:cdf03a4ac84a r18402:1f4ab80cb227 r18403:c5ec10907d18 r18402:1f4ab80cb227 r18332:829a699e80c9 r18403:c5ec10907d18 r18332:829a699e80c9 r19067:8b759022e9ee r18332:829a699e80c9 | /* $Id$ */
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file newgrf_config.cpp Finding NewGRFs and configuring them. */
#include "stdafx.h"
#include "debug.h"
#include "3rdparty/md5/md5.h"
#include "newgrf.h"
#include "network/network_func.h"
#include "gfx_func.h"
#include "newgrf_text.h"
#include "window_func.h"
#include "progress.h"
#include "video/video_driver.hpp"
#include "strings_func.h"
#include "textfile_gui.h"
#include "fileio_func.h"
#include "fios.h"
#include "safeguards.h"
/** Create a new GRFTextWrapper. */
GRFTextWrapper::GRFTextWrapper() :
text(NULL)
{
}
/** Cleanup a GRFTextWrapper object. */
GRFTextWrapper::~GRFTextWrapper()
{
CleanUpGRFText(this->text);
}
/**
* Create a new GRFConfig.
* @param filename Set the filename of this GRFConfig to filename. The argument
* is copied so the original string isn't needed after the constructor.
*/
GRFConfig::GRFConfig(const char *filename) :
name(new GRFTextWrapper()),
info(new GRFTextWrapper()),
url(new GRFTextWrapper()),
num_valid_params(lengthof(param))
{
if (filename != NULL) this->filename = stredup(filename);
this->name->AddRef();
this->info->AddRef();
this->url->AddRef();
}
/**
* Create a new GRFConfig that is a deep copy of an existing config.
* @param config The GRFConfig object to make a copy of.
*/
GRFConfig::GRFConfig(const GRFConfig &config) :
ZeroedMemoryAllocator(),
ident(config.ident),
name(config.name),
info(config.info),
url(config.url),
version(config.version),
min_loadable_version(config.min_loadable_version),
flags(config.flags & ~(1 << GCF_COPY)),
status(config.status),
grf_bugs(config.grf_bugs),
num_params(config.num_params),
num_valid_params(config.num_valid_params),
palette(config.palette),
has_param_defaults(config.has_param_defaults)
{
MemCpyT<uint8>(this->original_md5sum, config.original_md5sum, lengthof(this->original_md5sum));
MemCpyT<uint32>(this->param, config.param, lengthof(this->param));
if (config.filename != NULL) this->filename = stredup(config.filename);
this->name->AddRef();
this->info->AddRef();
this->url->AddRef();
if (config.error != NULL) this->error = new GRFError(*config.error);
for (uint i = 0; i < config.param_info.Length(); i++) {
if (config.param_info[i] == NULL) {
*this->param_info.Append() = NULL;
} else {
*this->param_info.Append() = new GRFParameterInfo(*config.param_info[i]);
}
}
}
/** Cleanup a GRFConfig object. */
GRFConfig::~GRFConfig()
{
/* GCF_COPY as in NOT stredupped/alloced the filename */
if (!HasBit(this->flags, GCF_COPY)) {
free(this->filename);
delete this->error;
}
this->name->Release();
this->info->Release();
this->url->Release();
for (uint i = 0; i < this->param_info.Length(); i++) delete this->param_info[i];
}
/**
* Copy the parameter information from the \a src config.
* @param src Source config.
*/
void GRFConfig::CopyParams(const GRFConfig &src)
{
this->num_params = src.num_params;
this->num_valid_params = src.num_valid_params;
MemCpyT<uint32>(this->param, src.param, lengthof(this->param));
}
/**
* Get the name of this grf. In case the name isn't known
* the filename is returned.
* @return The name of filename of this grf.
*/
const char *GRFConfig::GetName() const
{
const char *name = GetGRFStringFromGRFText(this->name->text);
return StrEmpty(name) ? this->filename : name;
}
/**
* Get the grf info.
* @return A string with a description of this grf.
*/
const char *GRFConfig::GetDescription() const
{
return GetGRFStringFromGRFText(this->info->text);
}
/**
* Get the grf url.
* @return A string with an url of this grf.
*/
const char *GRFConfig::GetURL() const
{
return GetGRFStringFromGRFText(this->url->text);
}
/** Set the default value for all parameters as specified by action14. */
void GRFConfig::SetParameterDefaults()
{
this->num_params = 0;
MemSetT<uint32>(this->param, 0, lengthof(this->param));
if (!this->has_param_defaults) return;
for (uint i = 0; i < this->param_info.Length(); i++) {
if (this->param_info[i] == NULL) continue;
this->param_info[i]->SetValue(this, this->param_info[i]->def_value);
}
}
/**
* Set the palette of this GRFConfig to something suitable.
* That is either the setting coming from the NewGRF or
* the globally used palette.
*/
void GRFConfig::SetSuitablePalette()
{
PaletteType pal;
switch (this->palette & GRFP_GRF_MASK) {
case GRFP_GRF_DOS: pal = PAL_DOS; break;
case GRFP_GRF_WINDOWS: pal = PAL_WINDOWS; break;
default: pal = _settings_client.gui.newgrf_default_palette == 1 ? PAL_WINDOWS : PAL_DOS; break;
}
SB(this->palette, GRFP_USE_BIT, 1, pal == PAL_WINDOWS ? GRFP_USE_WINDOWS : GRFP_USE_DOS);
}
/**
* Finalize Action 14 info after file scan is finished.
*/
void GRFConfig::FinalizeParameterInfo()
{
for (GRFParameterInfo **info = this->param_info.Begin(); info != this->param_info.End(); ++info) {
if (*info == NULL) continue;
(*info)->Finalize();
}
}
GRFConfig *_all_grfs;
GRFConfig *_grfconfig;
GRFConfig *_grfconfig_newgame;
GRFConfig *_grfconfig_static;
uint _missing_extra_graphics = 0;
/**
* Construct a new GRFError.
* @param severity The severity of this error.
* @param message The actual error-string.
*/
GRFError::GRFError(StringID severity, StringID message) :
message(message),
severity(severity)
{
}
/**
* Create a new GRFError that is a deep copy of an existing error message.
* @param error The GRFError object to make a copy of.
*/
GRFError::GRFError(const GRFError &error) :
ZeroedMemoryAllocator(),
custom_message(error.custom_message),
data(error.data),
message(error.message),
severity(error.severity)
{
if (error.custom_message != NULL) this->custom_message = stredup(error.custom_message);
if (error.data != NULL) this->data = stredup(error.data);
memcpy(this->param_value, error.param_value, sizeof(this->param_value));
}
GRFError::~GRFError()
{
free(this->custom_message);
free(this->data);
}
/**
* Create a new empty GRFParameterInfo object.
* @param nr The newgrf parameter that is changed.
*/
GRFParameterInfo::GRFParameterInfo(uint nr) :
name(NULL),
desc(NULL),
type(PTYPE_UINT_ENUM),
min_value(0),
max_value(UINT32_MAX),
def_value(0),
param_nr(nr),
first_bit(0),
num_bit(32),
complete_labels(false)
{}
/**
* Create a new GRFParameterInfo object that is a deep copy of an existing
* parameter info object.
* @param info The GRFParameterInfo object to make a copy of.
*/
GRFParameterInfo::GRFParameterInfo(GRFParameterInfo &info) :
name(DuplicateGRFText(info.name)),
desc(DuplicateGRFText(info.desc)),
type(info.type),
min_value(info.min_value),
max_value(info.max_value),
def_value(info.def_value),
param_nr(info.param_nr),
first_bit(info.first_bit),
num_bit(info.num_bit),
complete_labels(info.complete_labels)
{
for (uint i = 0; i < info.value_names.Length(); i++) {
SmallPair<uint32, GRFText *> *data = info.value_names.Get(i);
this->value_names.Insert(data->first, DuplicateGRFText(data->second));
}
}
/** Cleanup all parameter info. */
GRFParameterInfo::~GRFParameterInfo()
{
CleanUpGRFText(this->name);
CleanUpGRFText(this->desc);
for (uint i = 0; i < this->value_names.Length(); i++) {
SmallPair<uint32, GRFText *> *data = this->value_names.Get(i);
CleanUpGRFText(data->second);
}
}
/**
* Get the value of this user-changeable parameter from the given config.
* @param config The GRFConfig to get the value from.
* @return The value of this parameter.
*/
uint32 GRFParameterInfo::GetValue(struct GRFConfig *config) const
{
/* GB doesn't work correctly with nbits == 32, so handle that case here. */
if (this->num_bit == 32) return config->param[this->param_nr];
return GB(config->param[this->param_nr], this->first_bit, this->num_bit);
}
/**
* Set the value of this user-changeable parameter in the given config.
* @param config The GRFConfig to set the value in.
* @param value The new value.
*/
void GRFParameterInfo::SetValue(struct GRFConfig *config, uint32 value)
{
/* SB doesn't work correctly with nbits == 32, so handle that case here. */
if (this->num_bit == 32) {
config->param[this->param_nr] = value;
} else {
SB(config->param[this->param_nr], this->first_bit, this->num_bit, value);
}
config->num_params = max<uint>(config->num_params, this->param_nr + 1);
SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE);
}
/**
* Finalize Action 14 info after file scan is finished.
*/
void GRFParameterInfo::Finalize()
{
this->complete_labels = true;
for (uint32 value = this->min_value; value <= this->max_value; value++) {
if (!this->value_names.Contains(value)) {
this->complete_labels = false;
break;
}
}
}
/**
* Update the palettes of the graphics from the config file.
* Called when changing the default palette in advanced settings.
* @param p1 Unused.
* @return Always true.
*/
bool UpdateNewGRFConfigPalette(int32 p1)
{
for (GRFConfig *c = _grfconfig_newgame; c != NULL; c = c->next) c->SetSuitablePalette();
for (GRFConfig *c = _grfconfig_static; c != NULL; c = c->next) c->SetSuitablePalette();
for (GRFConfig *c = _all_grfs; c != NULL; c = c->next) c->SetSuitablePalette();
return true;
}
/**
* Get the data section size of a GRF.
* @param f GRF.
* @return Size of the data section or SIZE_MAX if the file has no separate data section.
*/
size_t GRFGetSizeOfDataSection(FILE *f)
{
extern const byte _grf_cont_v2_sig[];
static const uint header_len = 14;
byte data[header_len];
if (fread(data, 1, header_len, f) == header_len) {
if (data[0] == 0 && data[1] == 0 && MemCmpT(data + 2, _grf_cont_v2_sig, 8) == 0) {
/* Valid container version 2, get data section size. */
size_t offset = ((size_t)data[13] << 24) | ((size_t)data[12] << 16) | ((size_t)data[11] << 8) | (size_t)data[10];
if (offset >= 1 * 1024 * 1024 * 1024) {
DEBUG(grf, 0, "Unexpectedly large offset for NewGRF");
/* Having more than 1 GiB of data is very implausible. Mostly because then
* all pools in OpenTTD are flooded already. Or it's just Action C all over.
* In any case, the offsets to graphics will likely not work either. */
return SIZE_MAX;
}
return header_len + offset;
}
}
return SIZE_MAX;
}
/**
* Calculate the MD5 sum for a GRF, and store it in the config.
* @param config GRF to compute.
* @param subdir The subdirectory to look in.
* @return MD5 sum was successfully computed
*/
static bool CalcGRFMD5Sum(GRFConfig *config, Subdirectory subdir)
{
FILE *f;
Md5 checksum;
uint8 buffer[1024];
size_t len, size;
/* open the file */
f = FioFOpenFile(config->filename, "rb", subdir, &size);
if (f == NULL) return false;
long start = ftell(f);
size = min(size, GRFGetSizeOfDataSection(f));
if (start < 0 || fseek(f, start, SEEK_SET) < 0) {
FioFCloseFile(f);
return false;
}
/* calculate md5sum */
while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
size -= len;
checksum.Append(buffer, len);
}
checksum.Finish(config->ident.md5sum);
FioFCloseFile(f);
return true;
}
/**
* Find the GRFID of a given grf, and calculate its md5sum.
* @param config grf to fill.
* @param is_static grf is static.
* @param subdir the subdirectory to search in.
* @return Operation was successfully completed.
*/
bool FillGRFDetails(GRFConfig *config, bool is_static, Subdirectory subdir)
{
if (!FioCheckFileExists(config->filename, subdir)) {
config->status = GCS_NOT_FOUND;
return false;
}
/* Find and load the Action 8 information */
LoadNewGRFFile(config, CONFIG_SLOT, GLS_FILESCAN, subdir);
config->SetSuitablePalette();
config->FinalizeParameterInfo();
/* Skip if the grfid is 0 (not read) or if it is an internal GRF */
if (config->ident.grfid == 0 || HasBit(config->flags, GCF_SYSTEM)) return false;
if (is_static) {
/* Perform a 'safety scan' for static GRFs */
LoadNewGRFFile(config, CONFIG_SLOT, GLS_SAFETYSCAN, subdir);
/* GCF_UNSAFE is set if GLS_SAFETYSCAN finds unsafe actions */
if (HasBit(config->flags, GCF_UNSAFE)) return false;
}
return CalcGRFMD5Sum(config, subdir);
}
/**
* Clear a GRF Config list, freeing all nodes.
* @param config Start of the list.
* @post \a config is set to \c NULL.
*/
void ClearGRFConfigList(GRFConfig **config)
{
GRFConfig *c, *next;
for (c = *config; c != NULL; c = next) {
next = c->next;
delete c;
}
*config = NULL;
}
/**
* Copy a GRF Config list
* @param dst pointer to destination list
* @param src pointer to source list values
* @param init_only the copied GRF will be processed up to GLS_INIT
* @return pointer to the last value added to the destination list
*/
GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_only)
{
/* Clear destination as it will be overwritten */
ClearGRFConfigList(dst);
for (; src != NULL; src = src->next) {
GRFConfig *c = new GRFConfig(*src);
ClrBit(c->flags, GCF_INIT_ONLY);
if (init_only) SetBit(c->flags, GCF_INIT_ONLY);
*dst = c;
dst = &c->next;
}
return dst;
}
/**
* Removes duplicates from lists of GRFConfigs. These duplicates
* are introduced when the _grfconfig_static GRFs are appended
* to the _grfconfig on a newgame or savegame. As the parameters
* of the static GRFs could be different that the parameters of
* the ones used non-statically. This can result in desyncs in
* multiplayers, so the duplicate static GRFs have to be removed.
*
* This function _assumes_ that all static GRFs are placed after
* the non-static GRFs.
*
* @param list the list to remove the duplicates from
*/
static void RemoveDuplicatesFromGRFConfigList(GRFConfig *list)
{
GRFConfig *prev;
GRFConfig *cur;
if (list == NULL) return;
for (prev = list, cur = list->next; cur != NULL; prev = cur, cur = cur->next) {
if (cur->ident.grfid != list->ident.grfid) continue;
prev->next = cur->next;
delete cur;
cur = prev; // Just go back one so it continues as normal later on
}
RemoveDuplicatesFromGRFConfigList(list->next);
}
/**
* Appends the static GRFs to a list of GRFs
* @param dst the head of the list to add to
*/
void AppendStaticGRFConfigs(GRFConfig **dst)
{
GRFConfig **tail = dst;
while (*tail != NULL) tail = &(*tail)->next;
CopyGRFConfigList(tail, _grfconfig_static, false);
RemoveDuplicatesFromGRFConfigList(*dst);
}
/**
* Appends an element to a list of GRFs
* @param dst the head of the list to add to
* @param el the new tail to be
*/
void AppendToGRFConfigList(GRFConfig **dst, GRFConfig *el)
{
GRFConfig **tail = dst;
while (*tail != NULL) tail = &(*tail)->next;
*tail = el;
RemoveDuplicatesFromGRFConfigList(*dst);
}
/** Reset the current GRF Config to either blank or newgame settings. */
void ResetGRFConfig(bool defaults)
{
CopyGRFConfigList(&_grfconfig, _grfconfig_newgame, !defaults);
AppendStaticGRFConfigs(&_grfconfig);
}
/**
* Check if all GRFs in the GRF config from a savegame can be loaded.
* @param grfconfig GrfConfig to check
* @return will return any of the following 3 values:<br>
* <ul>
* <li> GLC_ALL_GOOD: No problems occurred, all GRF files were found and loaded
* <li> GLC_COMPATIBLE: For one or more GRF's no exact match was found, but a
* compatible GRF with the same grfid was found and used instead
* <li> GLC_NOT_FOUND: For one or more GRF's no match was found at all
* </ul>
*/
GRFListCompatibility IsGoodGRFConfigList(GRFConfig *grfconfig)
{
GRFListCompatibility res = GLC_ALL_GOOD;
for (GRFConfig *c = grfconfig; c != NULL; c = c->next) {
const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, c->ident.md5sum);
if (f == NULL || HasBit(f->flags, GCF_INVALID)) {
char buf[256];
/* If we have not found the exactly matching GRF try to find one with the
* same grfid, as it most likely is compatible */
f = FindGRFConfig(c->ident.grfid, FGCM_COMPATIBLE, NULL, c->version);
if (f != NULL) {
md5sumToString(buf, lastof(buf), c->ident.md5sum);
DEBUG(grf, 1, "NewGRF %08X (%s) not found; checksum %s. Compatibility mode on", BSWAP32(c->ident.grfid), c->filename, buf);
if (!HasBit(c->flags, GCF_COMPATIBLE)) {
/* Preserve original_md5sum after it has been assigned */
SetBit(c->flags, GCF_COMPATIBLE);
memcpy(c->original_md5sum, c->ident.md5sum, sizeof(c->original_md5sum));
}
/* Non-found has precedence over compatibility load */
if (res != GLC_NOT_FOUND) res = GLC_COMPATIBLE;
goto compatible_grf;
}
/* No compatible grf was found, mark it as disabled */
md5sumToString(buf, lastof(buf), c->ident.md5sum);
DEBUG(grf, 0, "NewGRF %08X (%s) not found; checksum %s", BSWAP32(c->ident.grfid), c->filename, buf);
c->status = GCS_NOT_FOUND;
res = GLC_NOT_FOUND;
} else {
compatible_grf:
DEBUG(grf, 1, "Loading GRF %08X from %s", BSWAP32(f->ident.grfid), f->filename);
/* The filename could be the filename as in the savegame. As we need
* to load the GRF here, we need the correct filename, so overwrite that
* in any case and set the name and info when it is not set already.
* When the GCF_COPY flag is set, it is certain that the filename is
* already a local one, so there is no need to replace it. */
if (!HasBit(c->flags, GCF_COPY)) {
free(c->filename);
c->filename = stredup(f->filename);
memcpy(c->ident.md5sum, f->ident.md5sum, sizeof(c->ident.md5sum));
c->name->Release();
c->name = f->name;
c->name->AddRef();
c->info->Release();
c->info = f->name;
c->info->AddRef();
c->error = NULL;
c->version = f->version;
c->min_loadable_version = f->min_loadable_version;
c->num_valid_params = f->num_valid_params;
c->has_param_defaults = f->has_param_defaults;
for (uint i = 0; i < f->param_info.Length(); i++) {
if (f->param_info[i] == NULL) {
*c->param_info.Append() = NULL;
} else {
*c->param_info.Append() = new GRFParameterInfo(*f->param_info[i]);
}
}
}
}
}
return res;
}
/** Helper for scanning for files with GRF as extension */
class GRFFileScanner : FileScanner {
uint next_update; ///< The next (realtime tick) we do update the screen.
uint num_scanned; ///< The number of GRFs we have scanned.
public:
GRFFileScanner() : next_update(_realtime_tick), num_scanned(0)
{
}
/* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename);
/** Do the scan for GRFs. */
static uint DoScan()
{
GRFFileScanner fs;
int ret = fs.Scan(".grf", NEWGRF_DIR);
/* The number scanned and the number returned may not be the same;
* duplicate NewGRFs and base sets are ignored in the return value. */
_settings_client.gui.last_newgrf_count = fs.num_scanned;
return ret;
}
};
bool GRFFileScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
{
GRFConfig *c = new GRFConfig(filename + basepath_length);
bool added = true;
if (FillGRFDetails(c, false)) {
if (_all_grfs == NULL) {
_all_grfs = c;
} else {
/* Insert file into list at a position determined by its
* name, so the list is sorted as we go along */
GRFConfig **pd, *d;
bool stop = false;
for (pd = &_all_grfs; (d = *pd) != NULL; pd = &d->next) {
if (c->ident.grfid == d->ident.grfid && memcmp(c->ident.md5sum, d->ident.md5sum, sizeof(c->ident.md5sum)) == 0) added = false;
/* Because there can be multiple grfs with the same name, make sure we checked all grfs with the same name,
* before inserting the entry. So insert a new grf at the end of all grfs with the same name, instead of
* just after the first with the same name. Avoids doubles in the list. */
if (strcasecmp(c->GetName(), d->GetName()) <= 0) {
stop = true;
} else if (stop) {
break;
}
}
if (added) {
c->next = d;
*pd = c;
}
}
} else {
added = false;
}
this->num_scanned++;
if (this->next_update <= _realtime_tick) {
_modal_progress_work_mutex->EndCritical();
_modal_progress_paint_mutex->BeginCritical();
const char *name = NULL;
if (c->name != NULL) name = GetGRFStringFromGRFText(c->name->text);
if (name == NULL) name = c->filename;
UpdateNewGRFScanStatus(this->num_scanned, name);
_modal_progress_work_mutex->BeginCritical();
_modal_progress_paint_mutex->EndCritical();
this->next_update = _realtime_tick + 200;
}
if (!added) {
/* File couldn't be opened, or is either not a NewGRF or is a
* 'system' NewGRF or it's already known, so forget about it. */
delete c;
}
return added;
}
/**
* Simple sorter for GRFS
* @param p1 the first GRFConfig *
* @param p2 the second GRFConfig *
* @return the same strcmp would return for the name of the NewGRF.
*/
static int CDECL GRFSorter(GRFConfig * const *p1, GRFConfig * const *p2)
{
const GRFConfig *c1 = *p1;
const GRFConfig *c2 = *p2;
return strnatcmp(c1->GetName(), c2->GetName());
}
/**
* Really perform the scan for all NewGRFs.
* @param callback The callback to call after the scanning is complete.
*/
void DoScanNewGRFFiles(void *callback)
{
_modal_progress_work_mutex->BeginCritical();
ClearGRFConfigList(&_all_grfs);
TarScanner::DoScan(TarScanner::NEWGRF);
DEBUG(grf, 1, "Scanning for NewGRFs");
uint num = GRFFileScanner::DoScan();
DEBUG(grf, 1, "Scan complete, found %d files", num);
if (num != 0 && _all_grfs != NULL) {
/* Sort the linked list using quicksort.
* For that we first have to make an array, then sort and
* then remake the linked list. */
GRFConfig **to_sort = MallocT<GRFConfig*>(num);
uint i = 0;
for (GRFConfig *p = _all_grfs; p != NULL; p = p->next, i++) {
to_sort[i] = p;
}
/* Number of files is not necessarily right */
num = i;
QSortT(to_sort, num, &GRFSorter);
for (i = 1; i < num; i++) {
to_sort[i - 1]->next = to_sort[i];
}
to_sort[num - 1]->next = NULL;
_all_grfs = to_sort[0];
free(to_sort);
#ifdef ENABLE_NETWORK
NetworkAfterNewGRFScan();
#endif
}
_modal_progress_work_mutex->EndCritical();
_modal_progress_paint_mutex->BeginCritical();
/* Yes... these are the NewGRF windows */
InvalidateWindowClassesData(WC_SAVELOAD, 0, true);
InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE, GOID_NEWGRF_RESCANNED, true);
if (callback != NULL) ((NewGRFScanCallback*)callback)->OnNewGRFsScanned();
DeleteWindowByClass(WC_MODAL_PROGRESS);
SetModalProgress(false);
MarkWholeScreenDirty();
_modal_progress_paint_mutex->EndCritical();
}
/**
* Scan for all NewGRFs.
* @param callback The callback to call after the scanning is complete.
*/
void ScanNewGRFFiles(NewGRFScanCallback *callback)
{
/* First set the modal progress. This ensures that it will eventually let go of the paint mutex. */
SetModalProgress(true);
/* Only then can we really start, especially by marking the whole screen dirty. Get those other windows hidden!. */
MarkWholeScreenDirty();
if (!VideoDriver::GetInstance()->HasGUI() || !ThreadObject::New(&DoScanNewGRFFiles, callback, NULL, "ottd:newgrf-scan")) {
_modal_progress_work_mutex->EndCritical();
_modal_progress_paint_mutex->EndCritical();
DoScanNewGRFFiles(callback);
_modal_progress_paint_mutex->BeginCritical();
_modal_progress_work_mutex->BeginCritical();
} else {
UpdateNewGRFScanStatus(0, NULL);
}
}
/**
* Find a NewGRF in the scanned list.
* @param grfid GRFID to look for,
* @param mode Restrictions for matching grfs
* @param md5sum Expected MD5 sum
* @param desired_version Requested version
* @return The matching grf, if it exists in #_all_grfs, else \c NULL.
*/
const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const uint8 *md5sum, uint32 desired_version)
{
assert((mode == FGCM_EXACT) != (md5sum == NULL));
const GRFConfig *best = NULL;
for (const GRFConfig *c = _all_grfs; c != NULL; c = c->next) {
/* if md5sum is set, we look for an exact match and continue if not found */
if (!c->ident.HasGrfIdentifier(grfid, md5sum)) continue;
/* return it, if the exact same newgrf is found, or if we do not care about finding "the best" */
if (md5sum != NULL || mode == FGCM_ANY) return c;
/* Skip incompatible stuff, unless explicitly allowed */
if (mode != FGCM_NEWEST && HasBit(c->flags, GCF_INVALID)) continue;
/* check version compatibility */
if (mode == FGCM_COMPATIBLE && (c->version < desired_version || c->min_loadable_version > desired_version)) continue;
/* remember the newest one as "the best" */
if (best == NULL || c->version > best->version) best = c;
}
return best;
}
#ifdef ENABLE_NETWORK
/** Structure for UnknownGRFs; this is a lightweight variant of GRFConfig */
struct UnknownGRF : public GRFIdentifier {
UnknownGRF *next; ///< The next unknown GRF.
GRFTextWrapper *name; ///< Name of the GRF.
};
/**
* Finds the name of a NewGRF in the list of names for unknown GRFs. An
* unknown GRF is a GRF where the .grf is not found during scanning.
*
* The names are resolved via UDP calls to servers that should know the name,
* though the replies may not come. This leaves "<Unknown>" as name, though
* that shouldn't matter _very_ much as they need GRF crawler or so to look
* up the GRF anyway and that works better with the GRF ID.
*
* @param grfid the GRF ID part of the 'unique' GRF identifier
* @param md5sum the MD5 checksum part of the 'unique' GRF identifier
* @param create whether to create a new GRFConfig if the GRFConfig did not
* exist in the fake list of GRFConfigs.
* @return The GRFTextWrapper of the name of the GRFConfig with the given GRF ID
* and MD5 checksum or NULL when it does not exist and create is false.
* This value must NEVER be freed by the caller.
*/
GRFTextWrapper *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create)
{
UnknownGRF *grf;
static UnknownGRF *unknown_grfs = NULL;
for (grf = unknown_grfs; grf != NULL; grf = grf->next) {
if (grf->grfid == grfid) {
if (memcmp(md5sum, grf->md5sum, sizeof(grf->md5sum)) == 0) return grf->name;
}
}
if (!create) return NULL;
grf = CallocT<UnknownGRF>(1);
grf->grfid = grfid;
grf->next = unknown_grfs;
grf->name = new GRFTextWrapper();
grf->name->AddRef();
AddGRFTextToList(&grf->name->text, UNKNOWN_GRF_NAME_PLACEHOLDER);
memcpy(grf->md5sum, md5sum, sizeof(grf->md5sum));
unknown_grfs = grf;
return grf->name;
}
#endif /* ENABLE_NETWORK */
/**
* Retrieve a NewGRF from the current config by its grfid.
* @param grfid grf to look for.
* @param mask GRFID mask to allow for partial matching.
* @return The grf config, if it exists, else \c NULL.
*/
GRFConfig *GetGRFConfig(uint32 grfid, uint32 mask)
{
GRFConfig *c;
for (c = _grfconfig; c != NULL; c = c->next) {
if ((c->ident.grfid & mask) == (grfid & mask)) return c;
}
return NULL;
}
/** Build a string containing space separated parameter values, and terminate */
char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last)
{
uint i;
/* Return an empty string if there are no parameters */
if (c->num_params == 0) return strecpy(dst, "", last);
for (i = 0; i < c->num_params; i++) {
if (i > 0) dst = strecpy(dst, " ", last);
dst += seprintf(dst, last, "%d", c->param[i]);
}
return dst;
}
/** Base GRF ID for OpenTTD's base graphics GRFs. */
static const uint32 OPENTTD_GRAPHICS_BASE_GRF_ID = BSWAP32(0xFF4F5400);
/**
* Search a textfile file next to this NewGRF.
* @param type The type of the textfile to search for.
* @return The filename for the textfile, \c NULL otherwise.
*/
const char *GRFConfig::GetTextfile(TextfileType type) const
{
return ::GetTextfile(type, NEWGRF_DIR, this->filename);
}
|