mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2026-07-15 15:19:52 +00:00
Compare commits
1000 Commits
release/15
...
16.0-beta2
| Author | SHA1 | Date | |
|---|---|---|---|
| e4620d5832 | |||
| cf48f866eb | |||
| 3c30f962d4 | |||
| 3fb3006dff | |||
| 0ab5b6df1b | |||
| a961e64928 | |||
| 9f8ac2aaa1 | |||
| 0c6de46b4c | |||
| 83f20c3375 | |||
| 85e6f020f9 | |||
| 83ce49f6cb | |||
| 44b51a94c5 | |||
| f5e4bd1ed7 | |||
| 5303aa6516 | |||
| 5403257dca | |||
| 05e596661e | |||
| e95f43a720 | |||
| 51af63cc9f | |||
| 8e89414d9e | |||
| 24333d76a9 | |||
| ac51eab537 | |||
| 0f09b4b371 | |||
| bf7bb3efaf | |||
| 9ba2e386ac | |||
| 21d9af637a | |||
| 788e112be1 | |||
| bf70c61fb8 | |||
| c18b3a8a04 | |||
| 8e08f1a3c5 | |||
| 8303b2d694 | |||
| 4d7e1385f9 | |||
| d2a3f52257 | |||
| 01919af55b | |||
| 9c3f5bc375 | |||
| 0a9aa3d20b | |||
| 8db7db5569 | |||
| d9d7f441db | |||
| 76265b8451 | |||
| 1310531139 | |||
| 0bd12558d4 | |||
| bdbe305771 | |||
| 71ca79c6d5 | |||
| afbe2d3070 | |||
| f72a239b97 | |||
| df20fed464 | |||
| af1e9864a0 | |||
| 3f557fb673 | |||
| 36551ba6b5 | |||
| 11f46bc5f4 | |||
| 099df1054e | |||
| d3d1de822d | |||
| ef0d26f9f7 | |||
| 8a8ece49ec | |||
| a01a2f8401 | |||
| d0dcd1b134 | |||
| a5430717b1 | |||
| c367b10bde | |||
| 2934eca24a | |||
| 02becd50c5 | |||
| 3ba0706a5c | |||
| 1acbb1c654 | |||
| 6f6551c08d | |||
| b4d16d319f | |||
| 8e637cefed | |||
| 5923d105ec | |||
| a76ba0d3d4 | |||
| b7d07252e7 | |||
| f8af6bbc2f | |||
| 8b83bac31f | |||
| b02242d5fc | |||
| 4344ffb7a0 | |||
| 4e9645e9d0 | |||
| 947767a2ff | |||
| 4b93bd74ef | |||
| 061e5c9cd3 | |||
| 5b3b7995bb | |||
| 3666eb23a1 | |||
| f9e6b8b7dd | |||
| 2a6a65662d | |||
| b7e693ced6 | |||
| b9986cdadf | |||
| dc87cd3d7a | |||
| 8ca99f96ee | |||
| 790a6903af | |||
| 98dfc7376c | |||
| cc92e3d421 | |||
| 42fe1133ad | |||
| fc0ad4bb0a | |||
| 5bb87d39b7 | |||
| f8ad1a4999 | |||
| f0a1b507fe | |||
| 2f4ae80226 | |||
| 11e713ce9a | |||
| c77a363d68 | |||
| a713b15183 | |||
| 7c4781c333 | |||
| 69dce301e7 | |||
| 1a00026929 | |||
| 578ec33556 | |||
| 0833396cdf | |||
| 2a5607d373 | |||
| ba9d673518 | |||
| 23b3efdae8 | |||
| 3763e338c0 | |||
| 366ec786f1 | |||
| e763d1b2ec | |||
| fa6152d91f | |||
| 1a59742990 | |||
| 867326094a | |||
| 27d2792ef0 | |||
| a1d6ac57e2 | |||
| 03a6767874 | |||
| 3e166ca4d0 | |||
| 20c25df71e | |||
| 4bcdc09934 | |||
| 0766bed833 | |||
| af51914427 | |||
| f7d17082d1 | |||
| 50847bf88e | |||
| a55bd4e041 | |||
| 26e5e38761 | |||
| d81eefcdc8 | |||
| ec727fe440 | |||
| 32f9e4df6c | |||
| 2ca3623670 | |||
| 8b49441b6b | |||
| 487971bffb | |||
| 495bc37dc3 | |||
| 1f0fd6dfab | |||
| 9f49ea4177 | |||
| a57eb70e05 | |||
| 7bd9fbc733 | |||
| 720d10536d | |||
| 71536313ba | |||
| 437d93b6fc | |||
| 5756bcc721 | |||
| bf67ba9a3b | |||
| 3efe107a6f | |||
| 27e8312d21 | |||
| 4a4ed2da22 | |||
| 3b8b089dd4 | |||
| 45065fb6d5 | |||
| 9e85e23cbc | |||
| b2c9e33e0f | |||
| 10cad52ebb | |||
| 185e942b44 | |||
| fdc5ef30de | |||
| 3fc52e758d | |||
| 33ae037aaa | |||
| 3aa3113033 | |||
| f8c8fedad7 | |||
| 2d5c1a9af8 | |||
| d938292243 | |||
| 34a419ca24 | |||
| 04c1af9902 | |||
| c76cfc7dfb | |||
| f0ce749025 | |||
| 5a6469ad6f | |||
| 2df98643ad | |||
| 760cd803c5 | |||
| 52793c0e8b | |||
| d519cad60f | |||
| fcd33b25a7 | |||
| ff055aa1ce | |||
| 1a2a527530 | |||
| d6c6ca2879 | |||
| 3008ffa9d2 | |||
| 2365f1e525 | |||
| fe989c3dc4 | |||
| 62d71bd43f | |||
| 412c692afe | |||
| bd86fe69c0 | |||
| 457275a87c | |||
| 9c71a0c925 | |||
| 1baea6b0fb | |||
| 0af287511f | |||
| eb789ed3da | |||
| d4f03f3c61 | |||
| c3b0d71973 | |||
| c991564e12 | |||
| 02792d8332 | |||
| 3aee9889c2 | |||
| ed1817897a | |||
| 23ed6cd3c4 | |||
| 234b022d75 | |||
| 8335479c07 | |||
| f022017461 | |||
| 146d499d0b | |||
| 8453494170 | |||
| 6e9a5cee2a | |||
| 6da4aa8648 | |||
| bba260e300 | |||
| 85ca2c20cd | |||
| a268f99f3f | |||
| f4cad11b40 | |||
| d92cd26a1f | |||
| acbbea4238 | |||
| f5ee6a5ec3 | |||
| 0149e4a349 | |||
| 09a475f30a | |||
| 61a8c9fd55 | |||
| eb54cbcd97 | |||
| 1766f17609 | |||
| 4e6a5ca362 | |||
| 3e880e8cd4 | |||
| 0021d5d6bd | |||
| 30fe17a49c | |||
| 9356748003 | |||
| 33d9b82c0c | |||
| 4b3d621569 | |||
| 31f8d76754 | |||
| 2effec96e8 | |||
| dbb8096a52 | |||
| 8ac4112aba | |||
| c9cf141813 | |||
| 7e2bcaf792 | |||
| 0ff5f81319 | |||
| 0eb9a47a96 | |||
| 8d0a0b5e16 | |||
| ba582b88ed | |||
| 9d233c441d | |||
| fa02d7aecb | |||
| 552ad919a8 | |||
| b5ae563df1 | |||
| 14be71cb5f | |||
| 231d946624 | |||
| e97e182630 | |||
| ebb77e592c | |||
| 549f357a19 | |||
| e41d4a0243 | |||
| 6bc486a578 | |||
| a85d10bf7c | |||
| a49dc81082 | |||
| a894ddf665 | |||
| a892d8e848 | |||
| 2ef1623c05 | |||
| 4175aee782 | |||
| 37983cf2d0 | |||
| 4c2d4ec73e | |||
| a8606613a4 | |||
| 55be58a31d | |||
| dbf56751b7 | |||
| 3314f4955b | |||
| dcb3810840 | |||
| ef48503276 | |||
| a51dd8e053 | |||
| 06af27d52e | |||
| f9dfbd59a3 | |||
| 40a29ebc67 | |||
| 2aa2b340eb | |||
| 0e951f3528 | |||
| a144bf2f8b | |||
| 28cd6a3d33 | |||
| a687f02e87 | |||
| 62669a24d3 | |||
| d6783335ca | |||
| f010c21f1a | |||
| 356ca9c6d9 | |||
| 0e0e8056a7 | |||
| 37f1a046e4 | |||
| a7c078dcaf | |||
| ee0d9f662e | |||
| ebc61380f6 | |||
| e4b6666fef | |||
| 8bac7bd519 | |||
| 0d2aed3b87 | |||
| 2ff631caa2 | |||
| 4b44d0a376 | |||
| 89201f80fb | |||
| e97a4e1b06 | |||
| af6868198e | |||
| 9fabd511b6 | |||
| bc8b16a99b | |||
| 81bdc44d1a | |||
| d68553bbd6 | |||
| 1d8d07e561 | |||
| 568c7bb259 | |||
| e6cf643103 | |||
| f7d1108934 | |||
| da0a244db6 | |||
| ae1ca76596 | |||
| 89f730bfb7 | |||
| c74431e734 | |||
| c0cb8b74e1 | |||
| 807436b3ea | |||
| a5ec6823c6 | |||
| 46ee856057 | |||
| 33874571a5 | |||
| d490243c7f | |||
| 2fcb7f2b02 | |||
| c4b642668d | |||
| 233c616425 | |||
| 06b0b59c92 | |||
| 6c39def287 | |||
| fa1a5b998e | |||
| 1860355246 | |||
| fa387fe129 | |||
| 4d809f4b43 | |||
| f47af07945 | |||
| fce33c5015 | |||
| 957184ae90 | |||
| 39d4fe24a0 | |||
| 4519b5db69 | |||
| bb2c3aed71 | |||
| 507b50223c | |||
| 052a6f15b4 | |||
| 68a03db17f | |||
| f2aeed9cb9 | |||
| b13cf794bc | |||
| 01ae236eec | |||
| dbc0aa4cdb | |||
| b2e01a9afa | |||
| bcda4a72ee | |||
| a9a2965131 | |||
| 4e58f4dffa | |||
| 2cebcc50f4 | |||
| bf03ca2303 | |||
| ad87be3a6b | |||
| a6db43ea59 | |||
| 3177583cdd | |||
| 54d8c3f8e3 | |||
| 98c9297134 | |||
| 49c36f1b39 | |||
| 7a0d9ba2d7 | |||
| d349295091 | |||
| e4803dbe54 | |||
| e7845e48dc | |||
| 7d03e0c4b7 | |||
| 36a4a10a01 | |||
| a2b8d38a73 | |||
| 2868060660 | |||
| 7d70a7b9e9 | |||
| 81c07db934 | |||
| c59d64c132 | |||
| 31424f700e | |||
| 2dba7ac196 | |||
| 2a7bd3fc60 | |||
| 71bda38826 | |||
| a5b1394b9e | |||
| 4817364a7f | |||
| 030c5d9c67 | |||
| 7a15d3c017 | |||
| 20b387b91f | |||
| a2b380830e | |||
| 8b7f7f7bc0 | |||
| 4abec621b5 | |||
| 54e32255a0 | |||
| 4decdedff4 | |||
| e8658995e3 | |||
| ebba01a4c8 | |||
| fdbc25a941 | |||
| ce506230c0 | |||
| 01b5b35b74 | |||
| d026e7098c | |||
| 275ba48eea | |||
| 0cc9f02e86 | |||
| 1be2cd0c9a | |||
| b5abd08a52 | |||
| eb52e2448d | |||
| 8875e12956 | |||
| 30fbc0aab8 | |||
| a7a025623e | |||
| f1fd17be8f | |||
| a4e1865cd7 | |||
| 792f6d99a3 | |||
| cd597f79ad | |||
| 7e624beadc | |||
| 420abb3865 | |||
| b220cc1a29 | |||
| 7bb3774d7f | |||
| a8e151c10a | |||
| ceac1258d8 | |||
| 1707b5ddea | |||
| e8cc0f5dc5 | |||
| 77be3fc12d | |||
| 89174e891a | |||
| 826e9a3c8c | |||
| d17e32d4b5 | |||
| a2e98f880f | |||
| 7eafa497d1 | |||
| 88dd010618 | |||
| 8feffc9eba | |||
| bbe5dbf230 | |||
| 4a7cbf29f0 | |||
| a4d142eddb | |||
| def17a75b2 | |||
| 38dd2e59eb | |||
| 77403627a8 | |||
| b90aefbf49 | |||
| 8b5c4ae96b | |||
| 174ff5d914 | |||
| 32d61a8938 | |||
| 66df1188c4 | |||
| 99c8a637b4 | |||
| a2e99c9cfa | |||
| f62eeada65 | |||
| 53799cc39a | |||
| 4a69cafe9a | |||
| a0ce1f94ed | |||
| 44c63bc400 | |||
| 146499ab99 | |||
| c14de5faa5 | |||
| c45aa3c9b6 | |||
| 962a550d1b | |||
| c2fbc6fdeb | |||
| 8341beb345 | |||
| a6db99765a | |||
| b46b660b0b | |||
| 3b5d46e0bb | |||
| 6823a1bc9e | |||
| bd1bb3adc8 | |||
| 2bf84ea78c | |||
| 16b192d61f | |||
| ea4964371d | |||
| 8bbad0dfaf | |||
| ba209c8745 | |||
| b75390ba60 | |||
| e4bc01d172 | |||
| 3437a58d5e | |||
| 7f1d17df46 | |||
| 9a87f184c4 | |||
| e24f92ce82 | |||
| b7c51a9332 | |||
| 678dfe658a | |||
| 8568f1f7bc | |||
| 5cef1ca68a | |||
| d15f105974 | |||
| fd855aa61d | |||
| e09cca949f | |||
| fe5171a6c5 | |||
| 98805561f8 | |||
| 3f4984ebaa | |||
| f60bb23268 | |||
| 8a7bc482ad | |||
| 9494881e14 | |||
| 631d6ba641 | |||
| 2b530751dd | |||
| 76c277805d | |||
| 73dafe5021 | |||
| b33b0d92a0 | |||
| a5a60c8615 | |||
| dab82fdff0 | |||
| 778839894d | |||
| eb9b648587 | |||
| 1adfb81aa9 | |||
| 7434052eb6 | |||
| 636fcf3af3 | |||
| 7c6da0ae6d | |||
| 053f17c63d | |||
| f5061df387 | |||
| a0ff1ec595 | |||
| c41f893428 | |||
| ae2d11c9da | |||
| dd1c5c1a8a | |||
| 1e17c62f3a | |||
| 43c8681ee9 | |||
| 7016d2bee3 | |||
| 042facf96c | |||
| 7f0be1f27f | |||
| 037cd53803 | |||
| b3b407acaf | |||
| a6c042855e | |||
| 4db1672611 | |||
| bcd98a6ba5 | |||
| 01568ce0b1 | |||
| 736ed61c1c | |||
| 1d10e8ee64 | |||
| a9d7397a77 | |||
| 9acfa96cb3 | |||
| 0ad97043bb | |||
| 316eac1208 | |||
| 2e77b6f9f4 | |||
| 9f849fcd9a | |||
| 817a47773a | |||
| c858e0c90a | |||
| 6dce7fdca3 | |||
| 9f287a7828 | |||
| 78bc829886 | |||
| 5aae8e2d64 | |||
| 93a6aa77c6 | |||
| 04f7adb7b7 | |||
| 74b0b080e7 | |||
| c3f1372d74 | |||
| 0b29a2560a | |||
| fed04d0a03 | |||
| 4707f78744 | |||
| 3bb17ce2d7 | |||
| 41a0a8967a | |||
| dd233a9b70 | |||
| cdb548c252 | |||
| bf6898290d | |||
| 4da085e598 | |||
| 4355855b85 | |||
| 34f5f1eaea | |||
| 5f20b45cd8 | |||
| ea5e87651f | |||
| 08563632f3 | |||
| 48a8903d85 | |||
| 856a02ae53 | |||
| cd4fb5dea3 | |||
| 95fbc7abf5 | |||
| c36f9d2d2a | |||
| 41a4917211 | |||
| f864aaf131 | |||
| 9a0af4387b | |||
| cdfbb113ce | |||
| 3c9a75a387 | |||
| 36878bfbc8 | |||
| 3efaeb0eea | |||
| 2ac2fa79b9 | |||
| 935f39ecab | |||
| e40c7f0c81 | |||
| d2dd4d4e4a | |||
| cca03f3112 | |||
| b856899a13 | |||
| 8fdc503448 | |||
| ff2028c7d6 | |||
| 423bf8d5cd | |||
| 56f7d87b56 | |||
| d15cbef897 | |||
| 915bc00ea0 | |||
| 10ac3a22e0 | |||
| bc9e786f84 | |||
| 877af52d61 | |||
| a9b32664ca | |||
| f1f31c1481 | |||
| aeddd30a48 | |||
| 34fdaec58e | |||
| 56342308eb | |||
| fc3b81a313 | |||
| d9c35037d4 | |||
| b325575105 | |||
| 11d5558c60 | |||
| 673d696989 | |||
| 9abaf555a0 | |||
| 4b40c1fefb | |||
| 600df4caaa | |||
| 8237a44152 | |||
| 36869844d5 | |||
| bcc0476d18 | |||
| 60ed1fb779 | |||
| ba3c2a43f1 | |||
| f949f3487b | |||
| 4cee9e72d6 | |||
| f296606c92 | |||
| d2da30debe | |||
| 812a74f821 | |||
| 511d3794ce | |||
| a1cf40448e | |||
| d02d57b348 | |||
| d685fc97f1 | |||
| 38b74639be | |||
| 01ecbe5798 | |||
| d4f5ded0d2 | |||
| 37118b93c7 | |||
| 61d17c959e | |||
| 12392fd295 | |||
| 92dae45773 | |||
| 54aaae4ffd | |||
| 984ae8e707 | |||
| 265dde1f28 | |||
| 3f3ee69d0f | |||
| dd812125dc | |||
| fd8a28ef9b | |||
| b5489e9b90 | |||
| 71d59aaf3d | |||
| 182a2c5100 | |||
| 4125514ee1 | |||
| 6db72d1f59 | |||
| 48703f0a75 | |||
| 450dd6f789 | |||
| 85a6c4b65d | |||
| c868a25245 | |||
| e30113c01c | |||
| 9eaab1cfb9 | |||
| 829745f28c | |||
| 6b336c206c | |||
| d13887bca4 | |||
| 1baaa74679 | |||
| 281d70c185 | |||
| 259086ca18 | |||
| 700701bf18 | |||
| 6c508d9046 | |||
| f7317c22a4 | |||
| efed900b09 | |||
| 52cc44a96e | |||
| c806bee528 | |||
| e5c9025ad5 | |||
| 5e9d20d57e | |||
| f574fb30c5 | |||
| 29991c93c3 | |||
| 3f3ced5fea | |||
| 71bf7d3b04 | |||
| ccf816a44d | |||
| a683f1c96b | |||
| 6370859c7e | |||
| 52b25b981f | |||
| 6b25087c56 | |||
| f7e20ecb4e | |||
| 7f66f87af4 | |||
| f1390b9cf8 | |||
| 0670c096f7 | |||
| 1883bb6731 | |||
| 2cce03e2e1 | |||
| ffa961d8b5 | |||
| b266a044c4 | |||
| f1ef2ab76d | |||
| 5b37a7b35c | |||
| 504b5e656e | |||
| 2ac0811ff9 | |||
| 3c8d7df657 | |||
| 5943382cf5 | |||
| 21bee91fa7 | |||
| 7a6b7fb1f0 | |||
| 01776bf161 | |||
| e0d2843fd7 | |||
| a5cb0529cb | |||
| 6438bb4d07 | |||
| 9a5187bac8 | |||
| a4a807cd1b | |||
| 940a3b12ce | |||
| 89ffb429c5 | |||
| 7179ea8b02 | |||
| dde097a080 | |||
| 21b4248fe9 | |||
| de3fa9ada6 | |||
| 90c8dfa03d | |||
| 698dc9cb08 | |||
| 549d555be7 | |||
| 8f9ceeec75 | |||
| aeadfb2f67 | |||
| d067bfe577 | |||
| 5226ae3f53 | |||
| c868b2ee61 | |||
| 1af77a7f75 | |||
| fb817f456d | |||
| 02e73ae4ba | |||
| ce5058aac8 | |||
| 671b62e073 | |||
| ab968555e5 | |||
| 81f2f4e2e8 | |||
| 7e8fad95c6 | |||
| b387f55ff7 | |||
| 8bc3c13a7e | |||
| d6d6ab1b4f | |||
| e5295f86fa | |||
| 977dc23f06 | |||
| fd7f211351 | |||
| 6be4e353bc | |||
| c859d34c66 | |||
| a1708450f7 | |||
| f469cfb761 | |||
| 7ddeac8810 | |||
| 781eb4cea4 | |||
| 10379441bc | |||
| 7c7f74c551 | |||
| 33a0d59d1d | |||
| 50110602aa | |||
| 0e25f9245c | |||
| a92dba290b | |||
| 2123fca5ea | |||
| 23dcc9dd07 | |||
| 7c9f2c71f4 | |||
| e33d53e37e | |||
| b1e1d56aba | |||
| 863355f0a6 | |||
| 1c095ba464 | |||
| d09b91cd92 | |||
| a5d028e892 | |||
| 7aecc268b6 | |||
| 02438e9934 | |||
| 0b3c448ea1 | |||
| 581a038913 | |||
| 190e91f19d | |||
| 269633f77b | |||
| 465f2c340a | |||
| 68a46f460c | |||
| da4dd91887 | |||
| a6803199d5 | |||
| 65216111b1 | |||
| 55870b4331 | |||
| 480040c86e | |||
| c7468a6922 | |||
| a0b173b43c | |||
| 308eff6eeb | |||
| 3fc6bbd5bf | |||
| ce676a6300 | |||
| 72e4955a09 | |||
| 9000092e78 | |||
| 341e097b5a | |||
| 5c28e41f6a | |||
| b4bfa06054 | |||
| 0e9b3a81ad | |||
| 341ab30c4a | |||
| 7b88c518cf | |||
| 396aa75a84 | |||
| 39dfb7c27b | |||
| c52c8e04a8 | |||
| f56b17571e | |||
| 04436b7401 | |||
| 8e75626b49 | |||
| 83f58b3fbd | |||
| ba82ba27a1 | |||
| b5eea625cd | |||
| 1fdcccbd49 | |||
| 6090865874 | |||
| ae80a47c7d | |||
| 840e4316c6 | |||
| 4ba0208437 | |||
| 9cc9a9702b | |||
| 5e491ebc1b | |||
| d62c9b132f | |||
| 7adf44e474 | |||
| 43af8e94d0 | |||
| 41c3dbe8ef | |||
| 4d4e37dbf1 | |||
| 59d9619fc1 | |||
| 4438209683 | |||
| 4bd9d657ca | |||
| 9a52dec15c | |||
| 10d3c7b293 | |||
| 22d6a7b5ad | |||
| 2e619f31c2 | |||
| 3d844d3f1d | |||
| 4e767224df | |||
| 7341c4d9aa | |||
| 1cb2015694 | |||
| 10f9f13c64 | |||
| 9ed9e42b2a | |||
| 092fe307ce | |||
| 5c2a37d03e | |||
| 17cab9b29d | |||
| bcaf3eaec2 | |||
| c6c06e13eb | |||
| f25e1f8be1 | |||
| cb562ef33c | |||
| 2347a56d7c | |||
| 58f3255f01 | |||
| ab43f57d40 | |||
| c77bbcba9a | |||
| 1c68cc5f03 | |||
| 13bd34fcbd | |||
| 73232058d9 | |||
| ae7af6c463 | |||
| 67fac86149 | |||
| dedcd78da0 | |||
| 31531e616e | |||
| e869d4f2bd | |||
| b23d4b6e56 | |||
| d675a71eaf | |||
| 1dd3d65574 | |||
| 664b507fe2 | |||
| 6cac80a158 | |||
| 7b5bfe2ac6 | |||
| d17f662490 | |||
| 2de2c5d31d | |||
| a706ac7dc9 | |||
| a42ba2493e | |||
| 79588cbfe3 | |||
| 7d70d70e0e | |||
| 954ac16c8c | |||
| 920fc5657b | |||
| f49924e749 | |||
| 03c24810b1 | |||
| 7092162a97 | |||
| 2bb01bd0e4 | |||
| 526ee6434d | |||
| 4adf494ebc | |||
| 014bf7e750 | |||
| bec75bc22a | |||
| 140ca5d3e6 | |||
| 802a31cdb0 | |||
| fb8d4e880e | |||
| 3937d7ed6f | |||
| 89ddc87c16 | |||
| 98f27ed83c | |||
| 70404850e2 | |||
| 44612d5b59 | |||
| 24a4f3b1a6 | |||
| 402ab7cf5f | |||
| 2bcbea2694 | |||
| e661db0396 | |||
| 6addf5c704 | |||
| 6e356eb267 | |||
| a8d0241c0b | |||
| 1716d36ebb | |||
| 97f3e5b70f | |||
| 7d34e09f94 | |||
| 84863e73a9 | |||
| 0519f82a37 | |||
| 6b3eaba308 | |||
| 009905e39e | |||
| 2d6fe7d9c6 | |||
| ab68e3616d | |||
| df7bf03cc8 | |||
| 9545d255ce | |||
| d18cf47c10 | |||
| 639cf2aa76 | |||
| 0f0f19092b | |||
| 0c0f55302d | |||
| 23d8a3df1b | |||
| f2d0e3342a | |||
| 4be378bc08 | |||
| f983a74f2e | |||
| 2bb6d3350f | |||
| 16dc1fc8bd | |||
| d685a5034b | |||
| f1adfd58ef | |||
| e1e0583d1b | |||
| 5cc954321a | |||
| 2e8d76386b | |||
| d4f0ff927e | |||
| d2757ca5f6 | |||
| df74656996 | |||
| 25184a23fc | |||
| 322ce224b4 | |||
| b556dc24b8 | |||
| 810dae240a | |||
| e1d474d47d | |||
| 6afdf51aba | |||
| 46fd829267 | |||
| 22f5b6111f | |||
| aa6309e784 | |||
| 54b0fcf6dc | |||
| cb4787b92a | |||
| 6fd761d7f6 | |||
| 7933b0417d | |||
| 5e4af50768 | |||
| 86f621b838 | |||
| 0500198bea | |||
| e1d90d7b69 | |||
| 5a906f8a30 | |||
| 2d8cb5314c | |||
| 5418a8c6f8 | |||
| 5f7d11a6c5 | |||
| c49f1da09e | |||
| e0be9f09f9 | |||
| 9e9b51369e | |||
| dc15cd30e8 | |||
| d925595ad1 | |||
| cc28e19052 | |||
| 18f2f7eb2d | |||
| 6a06a76b5d | |||
| 7ccfd0a658 | |||
| 666073fc7b | |||
| 14e0917ae4 | |||
| 4131a36e5a | |||
| 0794287b30 | |||
| bd9ced2ec2 | |||
| 241b5fcdfe | |||
| d405e4cb09 | |||
| 52d6a579e5 | |||
| fadeeb6da1 | |||
| bee3bc0ce5 | |||
| 80f19546d2 | |||
| b41e23270d | |||
| 09a8b1cf5c | |||
| e97213e7e2 | |||
| 9c6100c32a | |||
| 55f05846a5 | |||
| a6915cd5a3 | |||
| 8ba1860eaa | |||
| 463e1131da | |||
| 317dc71c6a | |||
| 97a4e1b59e | |||
| 98799c9b9c | |||
| f291e3c68e | |||
| 88a467db19 | |||
| 58abbf9e67 | |||
| d2b1253583 | |||
| 9406e8b36c | |||
| dc663d7b0a | |||
| 9e7cb99dc2 | |||
| fed2149846 | |||
| 710c78a0bb | |||
| 50e890eeb5 | |||
| f0105607dc | |||
| 7935253ee4 | |||
| 46a05315b0 | |||
| 13cf05c941 | |||
| e9e7e4af51 | |||
| 2e6f8fe191 | |||
| ee9e8ab9b2 | |||
| 2fcd4e189a | |||
| bc842811fc | |||
| e39932c245 | |||
| ebbb7cf3e9 | |||
| 1464d5fd06 | |||
| 091035b533 | |||
| 7d32bf24d5 | |||
| fdf75775d9 | |||
| 9add77a790 | |||
| 27c5f9a5cd | |||
| f57c2cc56e | |||
| 0ec507d4c5 | |||
| 1bac36a8c3 | |||
| 29a26b7f93 | |||
| 3a41738d9f | |||
| 2a6798cc43 | |||
| 0d9844a815 | |||
| e5f58ab7c9 | |||
| a0f80e1935 | |||
| 4776837675 | |||
| dd2cf93164 | |||
| 851310108f | |||
| eaa066990e | |||
| 42cffe0e16 | |||
| a900f5656c | |||
| 5c96a2c19a | |||
| b2fd405e55 | |||
| dc115cc785 | |||
| fb15730fc7 | |||
| 8f598b442a | |||
| 5683ddb99a | |||
| 02449652e4 | |||
| d80ed069b5 | |||
| a6d66343ac | |||
| fb79508968 | |||
| 2406d22830 | |||
| 8a4d60b812 | |||
| c7f6971729 | |||
| 48bc08dbfb | |||
| c2532fac3e | |||
| 0019f3831e | |||
| 900192e2cd | |||
| cb06ca69e8 | |||
| 9ac7623608 | |||
| 2515fc802d | |||
| 98b0197d53 | |||
| e8424c0ae2 | |||
| 13ec1816dc | |||
| d7942c3fd0 | |||
| 33c967a558 | |||
| ed687c6e10 | |||
| c918a29e49 | |||
| 07353973a1 | |||
| b36c78b2de | |||
| b881d8ef5c | |||
| bf2ff83c67 | |||
| dbecf010eb | |||
| 95b913bbb7 | |||
| 0a88c084ad | |||
| c6679bbcab | |||
| 75f1c36eff | |||
| ec5e7ed5e0 | |||
| 36ccc5e005 | |||
| d15dd3a036 | |||
| ee789a1197 | |||
| fd7f6fcf91 | |||
| 67d9daed47 | |||
| f34c45c36d | |||
| f1e831233a | |||
| 39f30692fe | |||
| 598d8fd65c | |||
| ca1c0007b6 | |||
| 53178d0549 | |||
| 5d702a96d6 | |||
| 9a47f53db0 | |||
| 938c3de640 | |||
| 9ad161b7e9 | |||
| 483f1f0afa | |||
| ebdc82ad54 | |||
| b1c0198d3f | |||
| 447959b214 | |||
| f6eba87e47 | |||
| 859b56a066 | |||
| e1333abc3e | |||
| 4e69ef938b | |||
| 3351975133 | |||
| 7b69a0b7fa | |||
| 5e2df6d028 | |||
| 36589abb33 | |||
| ed318b0154 | |||
| d3420e6e4c | |||
| a3393af26c | |||
| 0ec8842232 | |||
| 6851cb53e8 | |||
| 13ea783bd8 | |||
| b03347f00c | |||
| 973514adc3 | |||
| 0778687ed5 | |||
| 1091fa6071 | |||
| 688958da8a | |||
| 8a5c052933 | |||
| 392f743bcd | |||
| 81b4075095 | |||
| ef4687895e | |||
| a2304154d4 | |||
| f32646743a | |||
| 542dd1a597 | |||
| 19b65cd3e7 | |||
| 1e6153e875 | |||
| fef0d830b2 | |||
| 9695de9e1c | |||
| 2162983054 | |||
| 8e35553208 | |||
| 0d59ecf7de | |||
| 2c8a15cf36 | |||
| 40be27503d | |||
| 170c29b376 |
@@ -1,50 +0,0 @@
|
||||
name: 'Setup vcpkg'
|
||||
description: 'Installs vcpkg and initialises binary caching via NuGet'
|
||||
inputs:
|
||||
vcpkg-location:
|
||||
description: 'Where to install vcpkg'
|
||||
required: true
|
||||
mono-install-command:
|
||||
description: 'Command to run to install mono'
|
||||
required: false
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install vcpkg
|
||||
shell: bash
|
||||
run: |
|
||||
git clone https://github.com/microsoft/vcpkg "${{ inputs.vcpkg-location }}"
|
||||
cd "${{ inputs.vcpkg-location }}"
|
||||
./bootstrap-vcpkg.$(if [ "${{ runner.os }}" = "Windows" ]; then echo "bat"; else echo "sh"; fi) -disableMetrics
|
||||
|
||||
- name: Install mono
|
||||
if: inputs.mono-install-command
|
||||
shell: bash
|
||||
run: |
|
||||
${{ inputs.mono-install-command }}
|
||||
echo "MONO=mono" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Setup NuGet Credentials
|
||||
shell: bash
|
||||
env:
|
||||
FEED_URL: 'https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json'
|
||||
run: |
|
||||
cd "${{ inputs.vcpkg-location }}"
|
||||
${{ env.MONO }} $(./vcpkg fetch nuget | tail -n 1) \
|
||||
sources add \
|
||||
-source "${{ env.FEED_URL }}" \
|
||||
-storepasswordincleartext \
|
||||
-name "GitHub" \
|
||||
-username "${{ github.repository_owner }}" \
|
||||
-password "${{ github.token }}"
|
||||
${{ env.MONO }} $(./vcpkg fetch nuget | tail -n 1) \
|
||||
setapikey "${{ github.token }}" \
|
||||
-source "${{ env.FEED_URL }}"
|
||||
|
||||
- name: Setup vcpkg caching
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
core.exportVariable('VCPKG_BINARY_SOURCES', 'clear;nuget,GitHub,readwrite')
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
"""
|
||||
Script to scan the OpenTTD source-tree for doxygen @file annotations.
|
||||
Checks whether they exist, are recognised by doxygen and match coding style.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
END_OF_SENTENCE = [".", "!", "?"]
|
||||
SOURCE_FILE_EXTENSION = ["cpp", "c", "hpp", "h", "mm", "m", "cc"]
|
||||
TEMPLATE_FILE_EXTENSION = ["preamble", "in"]
|
||||
REPO_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||||
EXCLUDED_FILES = [
|
||||
os.path.join(REPO_DIR, "src", "script", "api", "squirrel_export.sq.hpp.in"),
|
||||
os.path.join(REPO_DIR, "src", "script", "api", "script_includes.hpp.in"),
|
||||
]
|
||||
|
||||
|
||||
def read_files_list_from_file(file_path):
|
||||
with open(file_path, "r") as f:
|
||||
while line := f.readline():
|
||||
yield line[:-1]
|
||||
|
||||
|
||||
def list_files_walk(start_path="."):
|
||||
for root, dirs, files in os.walk(start_path):
|
||||
for file in files:
|
||||
yield os.path.join(root, file)
|
||||
|
||||
|
||||
def check_descriptions(files):
|
||||
errors = []
|
||||
for path in files:
|
||||
if os.path.abspath(path) in EXCLUDED_FILES:
|
||||
continue
|
||||
if path.find("3rdparty") != -1 or path.find("lang") != -1:
|
||||
continue
|
||||
if not os.path.isfile(path):
|
||||
continue
|
||||
name = path[path.rfind("/") + 1 :]
|
||||
while True:
|
||||
extension = name[name.rfind('.') + 1 :]
|
||||
if extension not in TEMPLATE_FILE_EXTENSION:
|
||||
break
|
||||
name = name[0 : -len(extension) - 1]
|
||||
if extension not in SOURCE_FILE_EXTENSION:
|
||||
continue
|
||||
with open(path, "r") as f:
|
||||
content = f.read()
|
||||
ann = content.find(f"@file {name} ")
|
||||
reason = f'Should be of the form "/** @file {name} Brief description of the file here. */"'
|
||||
if ann == -1:
|
||||
if content.find("@file") == -1:
|
||||
errors.append(f'File "{path}" does not provide description. {reason}')
|
||||
continue
|
||||
else:
|
||||
end = content.find("\n", ann)
|
||||
start = content.rfind("\n", 0, ann) + 1
|
||||
if content[start : ann] == "/** " and content[end - 3 : end] == " */" and content[end - 4] in END_OF_SENTENCE:
|
||||
continue
|
||||
elif content[start : ann] == " * ":
|
||||
if content[start - 4 : start - 1] == "/**" and content[end - 1] in END_OF_SENTENCE and content[end + 1 : end + 4] != " */":
|
||||
continue
|
||||
reason = f"Should be of the form:\n/**\n * @file {name} Brief description of the file here.\n * Detailed description of the file here.\n */"
|
||||
errors.append(f'Description of file "{path}" does not match coding style. {reason}')
|
||||
return errors
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) == 1:
|
||||
files = list_files_walk(os.path.join(REPO_DIR, "src"))
|
||||
else:
|
||||
files = read_files_list_from_file(sys.argv[1])
|
||||
|
||||
errors = check_descriptions(files)
|
||||
|
||||
if errors:
|
||||
print("\n".join(errors))
|
||||
sys.exit(1)
|
||||
|
||||
print("OK")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,26 @@
|
||||
name: Install Doxygen
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Install Doxygen
|
||||
run: |
|
||||
echo "::group::Downloading"
|
||||
# Download currently (at the time of creation this action) latest version of Doxygen
|
||||
# because version in ubuntu repository (1.9.8) is outdated and buggy.
|
||||
wget -O doxygen.tar.gz "https://github.com/doxygen/doxygen/releases/download/Release_1_17_0/doxygen-1.17.0.linux.bin.tar.gz"
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Unpacking"
|
||||
tar -xzf doxygen.tar.gz
|
||||
rm doxygen.tar.gz
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Installing"
|
||||
cd doxygen*
|
||||
sudo make install
|
||||
echo "::endgroup::"
|
||||
|
||||
cd ..
|
||||
rm -r doxygen*
|
||||
shell: bash
|
||||
@@ -0,0 +1,28 @@
|
||||
""" Script that sorts warnings generated by doxygen to maintain consistent order. """
|
||||
import sys
|
||||
|
||||
def read_by_line(file_path):
|
||||
with open(file_path, "r") as f:
|
||||
while line := f.readline():
|
||||
yield line[:-1]
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
print("Wrong number of arguments provided, expected two.")
|
||||
print("Usage: python3 sort_doxygen_warnings.py [input_file] [output_file]")
|
||||
sys.exit(1)
|
||||
warnings = []
|
||||
for line in read_by_line(sys.argv[1]):
|
||||
if "warning:" in line or "error:" in line:
|
||||
warnings.append(line)
|
||||
continue
|
||||
# Doxygen warnings can span multiple lines, keep these lines together.
|
||||
warnings[-1] = f"{warnings[-1]}\n{line}"
|
||||
warnings = sorted(set(warnings))
|
||||
with open(sys.argv[2], "w") as out:
|
||||
out.write("\n".join(warnings))
|
||||
out.write("\n")
|
||||
print("Doxygen warnings sorted successfully.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -105,4 +105,4 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Check annotations
|
||||
uses: OpenTTD/actions/annotation-check@v5
|
||||
uses: OpenTTD/actions/annotation-check@v6
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
container:
|
||||
# If you change this version, change the numbers in the cache step,
|
||||
# .github/workflows/preview-build.yml (2x) and os/emscripten/Dockerfile too.
|
||||
image: emscripten/emsdk:3.1.57
|
||||
image: emscripten/emsdk:6.0.1
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -24,20 +24,13 @@ jobs:
|
||||
run: |
|
||||
git config --global --add safe.directory ${GITHUB_WORKSPACE}
|
||||
|
||||
- name: Update to modern GCC
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y gcc-12 g++-12
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 100
|
||||
|
||||
- name: Setup cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
# If you change this version, change the numbers in the image configuration step,
|
||||
# .github/workflows/preview-build.yml (2x) and os/emscripten/Dockerfile too.
|
||||
path: /emsdk/upstream/emscripten/cache
|
||||
key: 3.1.57-${{ runner.os }}
|
||||
key: 6.0.1-${{ runner.os }}
|
||||
|
||||
- name: Add liblzma support
|
||||
run: |
|
||||
|
||||
@@ -33,10 +33,8 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup vcpkg
|
||||
uses: ./.github/actions/setup-vcpkg
|
||||
with:
|
||||
vcpkg-location: ${{ runner.temp }}/vcpkg
|
||||
mono-install-command: 'sudo apt-get install -y --no-install-recommends mono-complete'
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -67,7 +65,7 @@ jobs:
|
||||
|
||||
# We only use breakpad from vcpkg, as its CMake files
|
||||
# are a bit special. So the Ubuntu's variant doesn't work.
|
||||
${{ runner.temp }}/vcpkg/vcpkg install breakpad
|
||||
${{ steps.vcpkg.outputs.vcpkg }} install breakpad
|
||||
|
||||
echo "::endgroup::"
|
||||
env:
|
||||
|
||||
@@ -35,10 +35,8 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup vcpkg
|
||||
uses: ./.github/actions/setup-vcpkg
|
||||
with:
|
||||
vcpkg-location: ${{ runner.temp }}/vcpkg
|
||||
mono-install-command: 'brew install mono'
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
|
||||
- name: Install OpenGFX
|
||||
run: |
|
||||
@@ -67,7 +65,7 @@ jobs:
|
||||
cmake .. \
|
||||
-DCMAKE_OSX_ARCHITECTURES=${{ inputs.full_arch }} \
|
||||
-DVCPKG_TARGET_TRIPLET=${{ inputs.arch }}-osx \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${{ runner.temp }}/vcpkg/scripts/buildsystems/vcpkg.cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${{ steps.vcpkg.outputs.vcpkg-cmake }} \
|
||||
${{ inputs.extra-cmake-parameters }} \
|
||||
# EOF
|
||||
echo "::endgroup::"
|
||||
|
||||
@@ -31,15 +31,16 @@ jobs:
|
||||
install: >-
|
||||
git
|
||||
make
|
||||
mingw-w64-${{ inputs.arch }}-cmake
|
||||
mingw-w64-${{ inputs.arch }}-gcc
|
||||
mingw-w64-${{ inputs.arch }}-lzo2
|
||||
mingw-w64-${{ inputs.arch }}-libpng
|
||||
mingw-w64-${{ inputs.arch }}-lld
|
||||
mingw-w64-${{ inputs.arch }}-ninja
|
||||
mingw-w64-${{ inputs.arch }}-libogg
|
||||
mingw-w64-${{ inputs.arch }}-opus
|
||||
mingw-w64-${{ inputs.arch }}-opusfile
|
||||
pacboy: >-
|
||||
cmake:p
|
||||
gcc:p
|
||||
lzo2:p
|
||||
libpng:p
|
||||
lld:p
|
||||
ninja:p
|
||||
libogg:p
|
||||
opus:p
|
||||
opusfile:p
|
||||
|
||||
- name: Install OpenGFX
|
||||
shell: bash
|
||||
|
||||
@@ -31,10 +31,8 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- msystem: MINGW64
|
||||
- msystem: UCRT64
|
||||
arch: x86_64
|
||||
- msystem: MINGW32
|
||||
arch: i686
|
||||
|
||||
name: MinGW (${{ matrix.arch }})
|
||||
|
||||
@@ -57,4 +55,4 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Check annotations
|
||||
uses: OpenTTD/actions/annotation-check@v5
|
||||
uses: OpenTTD/actions/annotation-check@v6
|
||||
|
||||
@@ -21,9 +21,8 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup vcpkg
|
||||
uses: ./.github/actions/setup-vcpkg
|
||||
with:
|
||||
vcpkg-location: ${{ runner.temp }}/vcpkg
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
|
||||
- name: Install OpenGFX
|
||||
shell: bash
|
||||
@@ -61,7 +60,7 @@ jobs:
|
||||
cmake .. \
|
||||
-GNinja \
|
||||
-DVCPKG_TARGET_TRIPLET=${{ inputs.arch }}-windows-static \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${{ runner.temp }}\vcpkg\scripts\buildsystems\vcpkg.cmake" \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${{ steps.vcpkg.outputs.vcpkg-cmake }}" \
|
||||
# EOF
|
||||
echo "::endgroup::"
|
||||
|
||||
|
||||
@@ -28,10 +28,8 @@ jobs:
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup vcpkg
|
||||
uses: ./.github/actions/setup-vcpkg
|
||||
with:
|
||||
vcpkg-location: ${{ runner.temp }}/vcpkg
|
||||
mono-install-command: 'sudo apt-get install -y --no-install-recommends mono-complete'
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -61,7 +59,7 @@ jobs:
|
||||
|
||||
# We only use breakpad from vcpkg, as its CMake files
|
||||
# are a bit special. So the Ubuntu's variant doesn't work.
|
||||
${{ runner.temp }}/vcpkg/vcpkg install breakpad
|
||||
${{ steps.vcpkg.outputs.vcpkg }} install breakpad
|
||||
|
||||
echo "::endgroup::"
|
||||
env:
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
fetch-depth: 4
|
||||
|
||||
- name: Get pull-request commits
|
||||
uses: OpenTTD/actions/checkout-pull-request@v5
|
||||
uses: OpenTTD/actions/checkout-pull-request@v6
|
||||
|
||||
- name: Check commits
|
||||
uses: OpenTTD/OpenTTD-git-hooks@main
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
name: Docs checker
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
|
||||
|
||||
jobs:
|
||||
docs-checker:
|
||||
name: New doxygen warnings checker
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 4
|
||||
|
||||
- name: Get pull-request commits
|
||||
uses: OpenTTD/actions/checkout-pull-request@v6
|
||||
|
||||
- name: Install Doxygen
|
||||
uses: ./.github/install-doxygen
|
||||
|
||||
- name: Build docs for PR
|
||||
run: |
|
||||
mkdir build
|
||||
|
||||
echo "::group::CMake"
|
||||
cmake -S . -B build -DOPTION_DOCS_ONLY=ON -DOPTION_LINE_IN_DOXYGEN_WARNINGS=OFF -DOPTION_DOXYGEN_GS_WARN_FILE="Warnings.GS" -DOPTION_DOXYGEN_AI_WARN_FILE="Warnings.AI" -DOPTION_DOXYGEN_WARN_FILE="Warnings.source"
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Build Source"
|
||||
cmake --build build --target docs_source
|
||||
python3 .github/sort_doxygen_warnings.py build/Warnings.source doxygen_warnings.PR
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Build AI"
|
||||
cmake --build build --target docs_ai
|
||||
python3 .github/sort_doxygen_warnings.py build/Warnings.AI doxygen_AI_warnings.PR
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Build GS"
|
||||
cmake --build build --target docs_game
|
||||
python3 .github/sort_doxygen_warnings.py build/Warnings.GS doxygen_GS_warnings.PR
|
||||
echo "::endgroup::"
|
||||
|
||||
rm -r build
|
||||
|
||||
- name: Build docs for base branch
|
||||
run: |
|
||||
git checkout HEAD^
|
||||
mkdir build
|
||||
|
||||
echo "::group::CMake"
|
||||
cmake -S . -B build -DOPTION_DOCS_ONLY=ON -DOPTION_LINE_IN_DOXYGEN_WARNINGS=OFF -DOPTION_DOXYGEN_GS_WARN_FILE="Warnings.GS" -DOPTION_DOXYGEN_AI_WARN_FILE="Warnings.AI" -DOPTION_DOXYGEN_WARN_FILE="Warnings.source"
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Build Source"
|
||||
cmake --build build --target docs_source
|
||||
python3 .github/sort_doxygen_warnings.py build/Warnings.source doxygen_warnings.base
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Build AI"
|
||||
cmake --build build --target docs_ai
|
||||
python3 .github/sort_doxygen_warnings.py build/Warnings.AI doxygen_AI_warnings.base
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Build GS"
|
||||
cmake --build build --target docs_game
|
||||
python3 .github/sort_doxygen_warnings.py build/Warnings.GS doxygen_GS_warnings.base
|
||||
echo "::endgroup::"
|
||||
|
||||
rm -r build
|
||||
|
||||
- name: Compare doxygen warnings and errors
|
||||
run: |
|
||||
unset FAIL
|
||||
|
||||
diff doxygen_warnings.base doxygen_warnings.PR | grep '^>' && FAIL=1
|
||||
diff doxygen_AI_warnings.base doxygen_AI_warnings.PR | grep '^>' && FAIL=1
|
||||
diff doxygen_GS_warnings.base doxygen_GS_warnings.PR | grep '^>' && FAIL=1
|
||||
|
||||
if [ $FAIL ]; then
|
||||
exit 1;
|
||||
fi
|
||||
@@ -0,0 +1,29 @@
|
||||
name: File descriptions
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
|
||||
|
||||
jobs:
|
||||
file-descriptions:
|
||||
name: File descriptions
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 4
|
||||
|
||||
- name: Get pull-request commits
|
||||
uses: OpenTTD/actions/checkout-pull-request@v6
|
||||
|
||||
- name: Check descriptions of source files
|
||||
run: |
|
||||
git diff-tree --no-commit-id --name-only -r HEAD HEAD^ > modified_files.txt
|
||||
cat modified_files.txt
|
||||
set -ex
|
||||
python3 .github/file-descriptions.py modified_files.txt
|
||||
@@ -2,27 +2,16 @@ name: Preview build
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
secrets:
|
||||
PREVIEW_CLOUDFLARE_API_TOKEN:
|
||||
description: API token to upload a preview to Cloudflare Pages
|
||||
required: true
|
||||
PREVIEW_CLOUDFLARE_ACCOUNT_ID:
|
||||
description: Account ID to upload a preview to Cloudflare Pages
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
preview:
|
||||
name: Build preview
|
||||
|
||||
environment:
|
||||
name: preview
|
||||
url: https://preview.openttd.org/pr${{ github.event.pull_request.number }}/
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
# If you change this version, change the numbers in the cache step,
|
||||
# .github/workflows/ci-emscripten.yml (2x) and os/emscripten/Dockerfile too.
|
||||
image: emscripten/emsdk:3.1.57
|
||||
image: emscripten/emsdk:6.0.1
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -35,20 +24,13 @@ jobs:
|
||||
git config --global --add safe.directory ${GITHUB_WORKSPACE}
|
||||
git checkout -b pr${{ github.event.pull_request.number }}
|
||||
|
||||
- name: Update to modern GCC
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get install -y gcc-12 g++-12
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 100
|
||||
|
||||
- name: Setup cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: /emsdk/upstream/emscripten/cache
|
||||
# If you change this version, change the numbers in the image configuration step,
|
||||
# .github/workflows/ci-emscripten.yml (2x) and os/emscripten/Dockerfile too.
|
||||
key: 3.1.57-${{ runner.os }}
|
||||
key: 6.0.1-${{ runner.os }}
|
||||
|
||||
- name: Add liblzma support
|
||||
run: |
|
||||
@@ -97,16 +79,14 @@ jobs:
|
||||
cp build/openttd.js public/
|
||||
cp build/openttd.wasm public/
|
||||
|
||||
# Ensure we use the latest version of npm; the one we get with current
|
||||
# emscripten doesn't allow running "npx wrangler" as root.
|
||||
# Current emscripten can't install npm>=10.0.0 because node is too old.
|
||||
npm install -g npm@9
|
||||
mkdir pr
|
||||
echo ${{ github.event.pull_request.number }} > ./pr/number
|
||||
|
||||
- name: Publish preview
|
||||
uses: cloudflare/pages-action@v1
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
apiToken: ${{ secrets.PREVIEW_CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.PREVIEW_CLOUDFLARE_ACCOUNT_ID }}
|
||||
projectName: ${{ vars.PREVIEW_CLOUDFLARE_PROJECT_NAME }}
|
||||
directory: public
|
||||
branch: pr${{ github.event.pull_request.number }}
|
||||
name: pr${{ github.event.pull_request.number }}
|
||||
path: |
|
||||
public
|
||||
pr
|
||||
retention-days: 1
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
name: Preview publish
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- Preview
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
preview:
|
||||
name: Publish preview
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
github.event.workflow_run.event == 'pull_request' &&
|
||||
github.event.workflow_run.conclusion == 'success'
|
||||
|
||||
steps:
|
||||
- name: Create deployment
|
||||
id: deployment
|
||||
run: |
|
||||
curl -L \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "X-GitHub-Api-Version: 2026-03-10" \
|
||||
https://api.github.com/repos/${{ github.repository }}/deployments \
|
||||
-d '{"ref":"${{ github.event.workflow_run.head_sha }}","environment":"preview","required_contexts":[]}' \
|
||||
| jq --raw-output0 '"url=\(.statuses_url)"' >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
run-id: ${{github.event.workflow_run.id }}
|
||||
|
||||
- name: Get PR number
|
||||
id: pr
|
||||
run: |
|
||||
echo "number=$(cat pr/number)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Publish preview
|
||||
uses: cloudflare/wrangler-action@v3
|
||||
with:
|
||||
apiToken: ${{ secrets.PREVIEW_CLOUDFLARE_API_TOKEN }}
|
||||
accountId: ${{ secrets.PREVIEW_CLOUDFLARE_ACCOUNT_ID }}
|
||||
command: pages deploy public --project-name=${{ vars.PREVIEW_CLOUDFLARE_PROJECT_NAME }} --branch pr${{ steps.pr.outputs.number }}
|
||||
|
||||
- name: Update deployment
|
||||
if: always()
|
||||
run: |
|
||||
curl -L \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "X-GitHub-Api-Version: 2026-03-10" \
|
||||
${{ steps.deployment.outputs.url }} \
|
||||
-d '{"state":"${{ job.status }}","log_url":"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}","environment_url":"https://preview.openttd.org/pr${{ steps.pr.outputs.number }}/","auto_inactive":false}'
|
||||
@@ -1,7 +1,7 @@
|
||||
name: Preview
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
pull_request:
|
||||
types:
|
||||
- labeled
|
||||
- synchronize
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Download source
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: internal-source
|
||||
|
||||
@@ -23,19 +23,8 @@ jobs:
|
||||
run: |
|
||||
tar -xf source.tar.gz --strip-components=1
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
echo "::group::Update apt"
|
||||
sudo apt-get update
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Install dependencies"
|
||||
sudo apt-get install -y --no-install-recommends \
|
||||
doxygen \
|
||||
# EOF
|
||||
echo "::endgroup::"
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
- name: Install Doxygen
|
||||
uses: ./.github/install-doxygen
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
@@ -78,7 +67,7 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Store bundles
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: openttd-docs
|
||||
path: build/bundles/*.tar.xz
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Download source
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: internal-source
|
||||
|
||||
@@ -40,9 +40,11 @@ jobs:
|
||||
echo "::group::Install system dependencies"
|
||||
# perl-IPC-Cmd, wget, and zip are needed to run vcpkg.
|
||||
# autoconf-archive is needed to build ICU.
|
||||
# perl-Time-Piece is needed to build OpenSSL.
|
||||
yum install -y \
|
||||
autoconf-archive \
|
||||
perl-IPC-Cmd \
|
||||
perl-Time-Piece \
|
||||
wget \
|
||||
zip \
|
||||
# EOF
|
||||
@@ -81,6 +83,7 @@ jobs:
|
||||
yum install -y \
|
||||
alsa-lib-devel \
|
||||
pulseaudio-libs-devel \
|
||||
pipewire-devel \
|
||||
# EOF
|
||||
echo "::endgroup::"
|
||||
|
||||
@@ -110,7 +113,8 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Setup vcpkg
|
||||
uses: ./.github/actions/setup-vcpkg
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
with:
|
||||
vcpkg-location: /vcpkg
|
||||
mono-install-command: 'yum install -y mono-complete'
|
||||
@@ -125,7 +129,7 @@ jobs:
|
||||
|
||||
echo "::group::CMake"
|
||||
cmake ${GITHUB_WORKSPACE} \
|
||||
-DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${{ steps.vcpkg.outputs.vcpkg-cmake }} \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DOPTION_SURVEY_KEY=${{ inputs.survey_key }} \
|
||||
-DOPTION_PACKAGE_DEPENDENCIES=ON \
|
||||
@@ -156,14 +160,14 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Store bundles
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: openttd-linux-generic
|
||||
path: build/bundles
|
||||
retention-days: 5
|
||||
|
||||
- name: Store symbols
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: symbols-linux-generic
|
||||
path: build/symbols
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
xcode-version: latest-stable
|
||||
|
||||
- name: Download source
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: internal-source
|
||||
|
||||
@@ -38,10 +38,8 @@ jobs:
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Setup vcpkg
|
||||
uses: ./.github/actions/setup-vcpkg
|
||||
with:
|
||||
vcpkg-location: ${{ runner.temp }}/vcpkg
|
||||
mono-install-command: 'brew install mono'
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
|
||||
- name: Install dependencies
|
||||
env:
|
||||
@@ -79,7 +77,7 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Import code signing certificates
|
||||
uses: Apple-Actions/import-codesign-certs@v5
|
||||
uses: Apple-Actions/import-codesign-certs@v7
|
||||
with:
|
||||
# The certificates in a PKCS12 file encoded as a base64 string
|
||||
p12-file-base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }}
|
||||
@@ -97,7 +95,7 @@ jobs:
|
||||
cmake ${GITHUB_WORKSPACE} \
|
||||
-DCMAKE_OSX_ARCHITECTURES=arm64 \
|
||||
-DVCPKG_TARGET_TRIPLET=arm64-osx \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${{ runner.temp }}/vcpkg/scripts/buildsystems/vcpkg.cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${{ steps.vcpkg.outputs.vcpkg-cmake }} \
|
||||
-DHOST_BINARY_DIR=${GITHUB_WORKSPACE}/build-host \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DOPTION_SURVEY_KEY=${{ inputs.survey_key }} \
|
||||
@@ -118,7 +116,7 @@ jobs:
|
||||
cmake ${GITHUB_WORKSPACE} \
|
||||
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
|
||||
-DVCPKG_TARGET_TRIPLET=x64-osx \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${{ runner.temp }}/vcpkg/scripts/buildsystems/vcpkg.cmake \
|
||||
-DCMAKE_TOOLCHAIN_FILE=${{ steps.vcpkg.outputs.vcpkg-cmake }} \
|
||||
-DHOST_BINARY_DIR=${GITHUB_WORKSPACE}/build-host \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DOPTION_SURVEY_KEY=${{ inputs.survey_key }} \
|
||||
@@ -205,14 +203,14 @@ jobs:
|
||||
mv _CPack_Packages/*/Bundle/openttd-*.zip bundles/
|
||||
|
||||
- name: Store bundles
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: openttd-macos-universal
|
||||
path: build-x64/bundles
|
||||
retention-days: 5
|
||||
|
||||
- name: Store symbols
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: symbols-macos-universal
|
||||
path: build-x64/symbols
|
||||
|
||||
@@ -202,14 +202,14 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Store bundles
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: openttd-source
|
||||
path: build/bundles/*
|
||||
retention-days: 5
|
||||
|
||||
- name: Store source (for other jobs)
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: internal-source
|
||||
path: source.tar.gz
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Download source
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: internal-source
|
||||
|
||||
@@ -25,17 +25,17 @@ jobs:
|
||||
tar -xf source.tar.gz --strip-components=1
|
||||
|
||||
- name: Download x86 build
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: openttd-windows-x86
|
||||
|
||||
- name: Download x64 build
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: openttd-windows-x64
|
||||
|
||||
- name: Download arm64 build
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: openttd-windows-arm64
|
||||
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
run: |
|
||||
cd builds
|
||||
|
||||
REM We need to provide a signed .appx to the Windows Store, so generate a certificate with password 'password'
|
||||
REM We need to provide a signed .msix to the Windows Store, so generate a certificate with password 'password'
|
||||
call ..\os\windows\winstore\generate-key.bat "CN=78024DA8-4BE4-4C77-B12E-547BBF7359D2" password cert.pfx
|
||||
|
||||
- name: Generate assets
|
||||
@@ -176,16 +176,16 @@ jobs:
|
||||
|
||||
REM Build and sign the package
|
||||
makeappx build /v /f PackagingLayout.xml /op output\ /bv %OTTD_VERSION% /pv %OTTD_VERSION% /ca
|
||||
SignTool sign /fd sha256 /a /f cert.pfx /p password "output\OpenTTD.appxbundle"
|
||||
SignTool sign /fd sha256 /a /f cert.pfx /p password "output\OpenTTD.msixbundle"
|
||||
|
||||
REM Move resulting files to bundles folder
|
||||
mkdir bundles
|
||||
mkdir bundles\internal
|
||||
move cert.pfx bundles\internal\openttd-${{ inputs.version }}-windows-store.pfx
|
||||
move output\OpenTTD.appxbundle bundles\internal\openttd-${{ inputs.version }}-windows-store.appxbundle
|
||||
move output\OpenTTD.msixbundle bundles\internal\openttd-${{ inputs.version }}-windows-store.msixbundle
|
||||
|
||||
- name: Store bundles
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: openttd-windows-store
|
||||
path: builds/bundles
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Download source
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: internal-source
|
||||
|
||||
@@ -46,15 +46,14 @@ jobs:
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Setup vcpkg
|
||||
uses: ./.github/actions/setup-vcpkg
|
||||
with:
|
||||
vcpkg-location: ${{ runner.temp }}/vcpkg
|
||||
id: vcpkg
|
||||
uses: OpenTTD/actions/setup-vcpkg@v6
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::Install choco dependencies"
|
||||
choco install pandoc
|
||||
choco install pandoc nsis
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Install breakpad dependencies"
|
||||
@@ -103,7 +102,7 @@ jobs:
|
||||
cmake ${GITHUB_WORKSPACE} \
|
||||
-GNinja \
|
||||
-DVCPKG_TARGET_TRIPLET=${{ matrix.arch }}-windows-static \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${{ runner.temp }}\vcpkg\scripts\buildsystems\vcpkg.cmake" \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${{ steps.vcpkg.outputs.vcpkg-cmake }}" \
|
||||
-DOPTION_USE_NSIS=ON \
|
||||
-DHOST_BINARY_DIR=${GITHUB_WORKSPACE}/build-host \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
@@ -133,7 +132,7 @@ jobs:
|
||||
cmake ${GITHUB_WORKSPACE} \
|
||||
-GNinja \
|
||||
-DVCPKG_TARGET_TRIPLET=${{ matrix.arch }}-windows-static \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${{ runner.temp }}\vcpkg\scripts\buildsystems\vcpkg.cmake" \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${{ steps.vcpkg.outputs.vcpkg-cmake }}" \
|
||||
-DHOST_BINARY_DIR=${GITHUB_WORKSPACE}/build-host \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DOPTION_SURVEY_KEY=${{ inputs.survey_key }} \
|
||||
@@ -194,14 +193,14 @@ jobs:
|
||||
AZURE_CODESIGN_PROFILE_NAME: ${{ secrets.AZURE_CODESIGN_PROFILE_NAME }}
|
||||
|
||||
- name: Store bundles
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: openttd-windows-${{ matrix.arch }}
|
||||
path: build/bundles
|
||||
retention-days: 5
|
||||
|
||||
- name: Store symbols
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: symbols-windows-${{ matrix.arch }}
|
||||
path: build/symbols
|
||||
|
||||
@@ -153,3 +153,18 @@ jobs:
|
||||
|
||||
with:
|
||||
version: ${{ needs.source.outputs.version }}
|
||||
|
||||
upload-windows-store:
|
||||
name: Upload (Windows Store)
|
||||
needs:
|
||||
- upload
|
||||
|
||||
# Only upload final release builds to Windows Store; "-beta" or "-RC" tags should be ignored
|
||||
if: needs.source.outputs.is_tag == 'true' && !contains(needs.source.outputs.version, '-')
|
||||
|
||||
uses: ./.github/workflows/upload-windows-store.yml
|
||||
secrets: inherit
|
||||
|
||||
with:
|
||||
version: ${{ needs.source.outputs.version }}
|
||||
trigger_type: ${{ needs.source.outputs.trigger_type }}
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Download all bundles
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
|
||||
- name: Calculate checksums
|
||||
run: |
|
||||
@@ -70,14 +70,14 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Store bundles
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: cdn-bundles
|
||||
path: bundles/*
|
||||
retention-days: 5
|
||||
|
||||
- name: Store breakpad symbols
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: cdn-symbols
|
||||
path: symbols/*
|
||||
@@ -88,7 +88,7 @@ jobs:
|
||||
- prepare
|
||||
|
||||
name: Publish bundles
|
||||
uses: OpenTTD/actions/.github/workflows/rw-cdn-upload.yml@v5
|
||||
uses: OpenTTD/actions/.github/workflows/rw-cdn-upload.yml@v6
|
||||
secrets:
|
||||
CDN_SIGNING_KEY: ${{ secrets.CDN_SIGNING_KEY }}
|
||||
DEPLOYMENT_APP_ID: ${{ secrets.DEPLOYMENT_APP_ID }}
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
- prepare
|
||||
|
||||
name: Publish symbols
|
||||
uses: OpenTTD/actions/.github/workflows/rw-symbols-upload.yml@v5
|
||||
uses: OpenTTD/actions/.github/workflows/rw-symbols-upload.yml@v6
|
||||
secrets:
|
||||
SYMBOLS_SIGNING_KEY: ${{ secrets.SYMBOLS_SIGNING_KEY }}
|
||||
with:
|
||||
|
||||
@@ -15,40 +15,39 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Download source
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: internal-source
|
||||
path: internal-source
|
||||
|
||||
- name: Download bundle (Windows x86)
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: openttd-windows-x86
|
||||
path: openttd-windows-x86
|
||||
|
||||
- name: Download bundle (Windows x64)
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: openttd-windows-x64
|
||||
path: openttd-windows-x64
|
||||
|
||||
- name: Download bundle (MacOS)
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: openttd-macos-universal
|
||||
path: openttd-macos-universal
|
||||
|
||||
- name: Download bundle (Linux)
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: openttd-linux-generic
|
||||
path: openttd-linux-generic
|
||||
|
||||
- name: Install GOG Galaxy Build Creator
|
||||
run: |
|
||||
wget https://cdn.gog.com/open/galaxy/pipeline/build_creator/gnu-linux/GOGGalaxyBuildCreator-1.4.0.AppImage
|
||||
7z x GOGGalaxyBuildCreator-1.4.0.AppImage
|
||||
chmod +x ./app/GOGGalaxyPipelineBuilder
|
||||
wget https://cdn.gog.com/open/galaxy/pipeline/10.6.7.17/gnu-linux/GOGGalaxyPipelineBuilder
|
||||
chmod +x ./GOGGalaxyPipelineBuilder
|
||||
|
||||
- name: Install OpenGFX
|
||||
shell: bash
|
||||
@@ -145,8 +144,8 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Upload to GOG"
|
||||
../app/GOGGalaxyPipelineBuilder build-game --username "${{ secrets.GOG_USERNAME }}" --password "${{ secrets.GOG_PASSWORD }}" --branch Testing windows.json
|
||||
../app/GOGGalaxyPipelineBuilder build-game --username "${{ secrets.GOG_USERNAME }}" --password "${{ secrets.GOG_PASSWORD }}" --branch Testing macos.json
|
||||
../app/GOGGalaxyPipelineBuilder build-game --username "${{ secrets.GOG_USERNAME }}" --password "${{ secrets.GOG_PASSWORD }}" --branch Testing linux.json
|
||||
../GOGGalaxyPipelineBuilder build-game --username "${{ secrets.GOG_USERNAME }}" --password "${{ secrets.GOG_PASSWORD }}" --branch Testing windows.json
|
||||
../GOGGalaxyPipelineBuilder build-game --username "${{ secrets.GOG_USERNAME }}" --password "${{ secrets.GOG_PASSWORD }}" --branch Testing macos.json
|
||||
../GOGGalaxyPipelineBuilder build-game --username "${{ secrets.GOG_USERNAME }}" --password "${{ secrets.GOG_PASSWORD }}" --branch Testing linux.json
|
||||
echo "::endgroup::"
|
||||
)
|
||||
|
||||
@@ -18,31 +18,31 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Download source
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: internal-source
|
||||
path: internal-source
|
||||
|
||||
- name: Download bundle (Windows x86)
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: openttd-windows-x86
|
||||
path: openttd-windows-x86
|
||||
|
||||
- name: Download bundle (Windows x64)
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: openttd-windows-x64
|
||||
path: openttd-windows-x64
|
||||
|
||||
- name: Download bundle (MacOS)
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: openttd-macos-universal
|
||||
path: openttd-macos-universal
|
||||
|
||||
- name: Download bundle (Linux)
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: openttd-linux-generic
|
||||
path: openttd-linux-generic
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
name: Upload (Windows Store)
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
version:
|
||||
required: true
|
||||
type: string
|
||||
trigger_type:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
upload:
|
||||
name: Upload (Windows Store)
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- name: Download bundle (Windows Store)
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: openttd-windows-store
|
||||
path: openttd-windows-store
|
||||
|
||||
- name: Configure Microsoft Store CLI
|
||||
uses: microsoft/microsoft-store-apppublisher@v1.3
|
||||
|
||||
- name: Reconfigure store credentials
|
||||
run: msstore reconfigure `
|
||||
--tenantId ${{ secrets.AZURE_TENANT_ID }} `
|
||||
--sellerId ${{ secrets.WINSTORE_SELLER_ID }} `
|
||||
--clientId ${{ secrets.AZURE_WINSTORE_APPLICATION_CLIENT_ID }} `
|
||||
--clientSecret ${{ secrets.AZURE_WINSTORE_APPLICATION_SECRET }}
|
||||
|
||||
- name: Publish msix package
|
||||
shell: pwsh
|
||||
run: |
|
||||
$bundle = Get-ChildItem openttd-windows-store/internal/openttd-*.msixbundle | Select-Object -First 1
|
||||
if (-not $bundle) {
|
||||
throw "No msixbundle found"
|
||||
}
|
||||
|
||||
msstore publish $bundle.FullName -id 9NCJG5RVRR1C -v
|
||||
+9
-5
@@ -5,7 +5,7 @@ if(NOT BINARY_NAME)
|
||||
endif()
|
||||
|
||||
project(${BINARY_NAME}
|
||||
VERSION 15.0
|
||||
VERSION 16.0
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
@@ -75,6 +75,10 @@ add_custom_target(find_version
|
||||
-DREV_MAJOR=${PROJECT_VERSION_MAJOR}
|
||||
-DREV_MINOR=${PROJECT_VERSION_MINOR}
|
||||
-DWINDOWS=${WIN32}
|
||||
-DDOXYGEN_WARN_FORMAT_LINE=${DOXYGEN_WARN_FORMAT_LINE}
|
||||
-DDOXYGEN_WARN_FILE=${DOXYGEN_WARN_FILE}
|
||||
-DDOXYGEN_GS_WARN_FILE=${DOXYGEN_GS_WARN_FILE}
|
||||
-DDOXYGEN_AI_WARN_FILE=${DOXYGEN_AI_WARN_FILE}
|
||||
-P "${CMAKE_SOURCE_DIR}/cmake/scripts/FindVersion.cmake"
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
BYPRODUCTS ${GENERATED_SOURCE_FILES}
|
||||
@@ -185,7 +189,7 @@ if(UNIX AND NOT APPLE AND NOT OPTION_DEDICATED)
|
||||
if(NOT SDL2_FOUND AND NOT ALLEGRO_FOUND)
|
||||
message(FATAL_ERROR "SDL2 or Allegro is required for this platform")
|
||||
endif()
|
||||
if(HARFBUZZ_FOUND AND NOT ICU_i18n_FOUND)
|
||||
if(HARFBUZZ_FOUND AND NOT ICU_I18N_FOUND)
|
||||
message(WARNING "HarfBuzz depends on ICU i18n to function; HarfBuzz will be disabled")
|
||||
endif()
|
||||
if(NOT HARFBUZZ_FOUND)
|
||||
@@ -323,8 +327,8 @@ if(NOT OPTION_DEDICATED)
|
||||
link_package(FREETYPE TARGET Freetype::Freetype)
|
||||
link_package(Fontconfig TARGET Fontconfig::Fontconfig)
|
||||
link_package(Harfbuzz TARGET harfbuzz::harfbuzz)
|
||||
link_package(ICU_i18n)
|
||||
link_package(ICU_uc)
|
||||
link_package(ICU_I18N TARGET ICU::i18n)
|
||||
link_package(ICU_UC TARGET ICU::uc)
|
||||
link_package(OpusFile TARGET OpusFile::opusfile)
|
||||
|
||||
if(SDL2_FOUND AND OPENGL_FOUND AND UNIX)
|
||||
@@ -366,7 +370,7 @@ if(EMSCRIPTEN)
|
||||
add_definitions(-s DISABLE_EXCEPTION_CATCHING=0)
|
||||
|
||||
# Export functions to Javascript.
|
||||
target_link_libraries(WASM::WASM INTERFACE "-s EXPORTED_FUNCTIONS='[\"_main\", \"_em_openttd_add_server\"]' -s EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
|
||||
target_link_libraries(WASM::WASM INTERFACE "-s EXPORTED_FUNCTIONS='[\"_main\", \"_em_openttd_add_server\"]' -s EXPORTED_RUNTIME_METHODS='[\"cwrap\", \"HEAPU8\"]'")
|
||||
|
||||
# Preload all the files we generate during build.
|
||||
# As we do not compile with FreeType / FontConfig, we also have no way to
|
||||
|
||||
+19
-15
@@ -45,7 +45,9 @@ PYTHON_DOCSTRING = YES
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 2
|
||||
ALIASES =
|
||||
ALIASES = important="@attention" # @important is available in newer versions of doxygen.
|
||||
ALIASES += split_group{1}="@}^^@{^^@ingroup \1^^" \
|
||||
split_group{3;}="^^@defgroup \1_\2 \3^^@ingroup \1^^@{^^@}^^@}^^@{^^@ingroup \1_\2^^"
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
@@ -59,7 +61,7 @@ BUILTIN_STL_SUPPORT = NO
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
DISTRIBUTE_GROUP_DOC = YES
|
||||
GROUP_NESTED_COMPOUNDS = NO
|
||||
SUBGROUPING = YES
|
||||
INLINE_GROUPED_CLASSES = NO
|
||||
@@ -118,11 +120,12 @@ WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_IF_INCOMPLETE_DOC = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_NO_PARAMDOC = YES
|
||||
WARN_IF_UNDOC_ENUM_VAL = YES
|
||||
WARN_AS_ERROR = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LINE_FORMAT = "at line $line of file $file"
|
||||
WARN_LOGFILE =
|
||||
WARN_FORMAT = "$file:$${DOXYGEN_WARN_FORMAT_LINE}: $text"
|
||||
WARN_LINE_FORMAT = "at line $${DOXYGEN_WARN_FORMAT_LINE} of file $file"
|
||||
WARN_LOGFILE = ${DOXYGEN_WARN_FILE}
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -134,12 +137,15 @@ FILE_PATTERNS = *.c \
|
||||
*.cpp \
|
||||
*.c++ \
|
||||
*.h \
|
||||
*.hpp
|
||||
*.hpp \
|
||||
*.mm \
|
||||
*.m
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS = */3rdparty \
|
||||
*/script/api
|
||||
*/script/api \
|
||||
*/tests
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
@@ -185,7 +191,6 @@ HTML_EXTRA_FILES =
|
||||
HTML_COLORSTYLE_HUE = 220
|
||||
HTML_COLORSTYLE_SAT = 100
|
||||
HTML_COLORSTYLE_GAMMA = 80
|
||||
HTML_TIMESTAMP = NO
|
||||
HTML_DYNAMIC_MENUS = YES
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
HTML_INDEX_NUM_ENTRIES = 100
|
||||
@@ -221,7 +226,6 @@ EXT_LINKS_IN_WINDOW = NO
|
||||
OBFUSCATE_EMAILS = YES
|
||||
HTML_FORMULA_FORMAT = png
|
||||
FORMULA_FONTSIZE = 10
|
||||
FORMULA_TRANSPARENT = YES
|
||||
FORMULA_MACROFILE =
|
||||
USE_MATHJAX = NO
|
||||
MATHJAX_VERSION = MathJax_2
|
||||
@@ -256,7 +260,6 @@ USE_PDFLATEX = NO
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_BIB_STYLE = plain
|
||||
LATEX_TIMESTAMP = NO
|
||||
LATEX_EMOJI_DIRECTORY =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the RTF output
|
||||
@@ -317,10 +320,14 @@ PREDEFINED = WITH_ZLIB \
|
||||
WITH_HARFBUZZ \
|
||||
WITH_ICU_I18N \
|
||||
UNICODE \
|
||||
DOXYGEN_API \
|
||||
_UNICODE \
|
||||
_GNU_SOURCE \
|
||||
CDECL= \
|
||||
CALLBACK= \
|
||||
APIENTRY= \
|
||||
FINAL=
|
||||
EXPAND_AS_DEFINED =
|
||||
EXPAND_AS_DEFINED = DEFINE_POOL_METHOD
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to external references
|
||||
@@ -337,8 +344,6 @@ DIA_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
DOT_NUM_THREADS = 0
|
||||
DOT_FONTNAME = Helvetica
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
@@ -366,7 +371,6 @@ PLANTUML_CFG_FILE =
|
||||
PLANTUML_INCLUDE_PATH =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
|
||||
@@ -15,6 +15,7 @@ set(AI_COMPAT_SOURCE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/compat_12.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/compat_13.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/compat_14.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/compat_15.nut
|
||||
)
|
||||
|
||||
foreach(AI_COMPAT_SOURCE_FILE IN LISTS AI_COMPAT_SOURCE_FILES)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
|
||||
*/
|
||||
|
||||
/* This file contains code to downgrade the API from 16 to 15. */
|
||||
@@ -12,6 +12,7 @@ set(GS_COMPAT_SOURCE_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/compat_12.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/compat_13.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/compat_14.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/compat_15.nut
|
||||
)
|
||||
|
||||
foreach(GS_COMPAT_SOURCE_FILE IN LISTS GS_COMPAT_SOURCE_FILES)
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
|
||||
*/
|
||||
|
||||
/* This file contains code to downgrade the API from 16 to 15. */
|
||||
|
||||
/*
|
||||
* These window/widget related enumerations have never been stable, but breaking anything using them
|
||||
* is a really big ask when restructuring code. If in the future things are removed from the underlying
|
||||
* enumerations, feel free to remove them from this compatibility script.
|
||||
*/
|
||||
GSWindow.WN_GAME_OPTIONS_AI <- GSWindow.GameOptionsWindowNumber.AI;
|
||||
GSWindow.WN_GAME_OPTIONS_GS <- GSWindow.GameOptionsWindowNumber.GS;
|
||||
GSWindow.WN_GAME_OPTIONS_ABOUT <- GSWindow.GameOptionsWindowNumber.About;
|
||||
GSWindow.WN_GAME_OPTIONS_NEWGRF_STATE <- GSWindow.GameOptionsWindowNumber.NewGRFState;
|
||||
GSWindow.WN_GAME_OPTIONS_GAME_OPTIONS <- GSWindow.GameOptionsWindowNumber.GameOptions;
|
||||
GSWindow.WN_GAME_OPTIONS_GAME_SETTINGS <- GSWindow.GameOptionsWindowNumber.GameOptions;
|
||||
GSWindow.WN_QUERY_STRING <- GSWindow.QueryStringWindowNumber.Default;
|
||||
GSWindow.WN_QUERY_STRING_SIGN <- GSWindow.QueryStringWindowNumber.Sign;
|
||||
GSWindow.WN_CONFIRM_POPUP_QUERY <- GSWindow.ConfirmPopupQueryWindowNumber.Default;
|
||||
GSWindow.WN_CONFIRM_POPUP_QUERY_BOOTSTRAP <- GSWindow.ConfirmPopupQueryWindowNumber.Bootstrap;
|
||||
GSWindow.WN_NETWORK_WINDOW_GAME <- GSWindow.NetworkWindowNumber.Game;
|
||||
GSWindow.WN_NETWORK_WINDOW_CONTENT_LIST <- GSWindow.NetworkWindowNumber.ContentList;
|
||||
GSWindow.WN_NETWORK_WINDOW_START <- GSWindow.NetworkWindowNumber.StartServer;
|
||||
GSWindow.WN_NETWORK_STATUS_WINDOW_JOIN <- GSWindow.NetworkStatusWindowNumber.Join;
|
||||
GSWindow.WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD <- GSWindow.NetworkStatusWindowNumber.ContentDownload;
|
||||
|
||||
GSWindow.WC_NONE <- GSWindow.WindowClass.None;
|
||||
GSWindow.WC_MAIN_WINDOW <- GSWindow.WindowClass.MainWindow;
|
||||
GSWindow.WC_MAIN_TOOLBAR <- GSWindow.WindowClass.MainToolbar;
|
||||
GSWindow.WC_STATUS_BAR <- GSWindow.WindowClass.Statusbar;
|
||||
GSWindow.WC_BUILD_TOOLBAR <- GSWindow.WindowClass.BuildToolbar;
|
||||
GSWindow.WC_SCEN_BUILD_TOOLBAR <- GSWindow.WindowClass.ScenarioBuildToolbar;
|
||||
GSWindow.WC_BUILD_TREES <- GSWindow.WindowClass.BuildTrees;
|
||||
GSWindow.WC_TRANSPARENCY_TOOLBAR <- GSWindow.WindowClass.TransparencyToolbar;
|
||||
GSWindow.WC_BUILD_SIGNAL <- GSWindow.WindowClass.BuildSignal;
|
||||
GSWindow.WC_SMALLMAP <- GSWindow.WindowClass.SmallMap;
|
||||
GSWindow.WC_ERRMSG <- GSWindow.WindowClass.ErrorMessage;
|
||||
GSWindow.WC_TOOLTIPS <- GSWindow.WindowClass.ToolTips;
|
||||
GSWindow.WC_QUERY_STRING <- GSWindow.WindowClass.QueryString;
|
||||
GSWindow.WC_CONFIRM_POPUP_QUERY <- GSWindow.WindowClass.ConfirmPopupQuery;
|
||||
GSWindow.WC_GOAL_QUESTION <- GSWindow.WindowClass.GoalQuestion;
|
||||
GSWindow.WC_SAVELOAD <- GSWindow.WindowClass.SaveLoad;
|
||||
GSWindow.WC_LAND_INFO <- GSWindow.WindowClass.LandInfo;
|
||||
GSWindow.WC_DROPDOWN_MENU <- GSWindow.WindowClass.DropdownMenu;
|
||||
GSWindow.WC_OSK <- GSWindow.WindowClass.OnScreenKeyboard;
|
||||
GSWindow.WC_SET_DATE <- GSWindow.WindowClass.SetDate;
|
||||
GSWindow.WC_SCRIPT_SETTINGS <- GSWindow.WindowClass.ScriptSettings;
|
||||
GSWindow.WC_GRF_PARAMETERS <- GSWindow.WindowClass.NewGRFParameters;
|
||||
GSWindow.WC_TEXTFILE <- GSWindow.WindowClass.Textfile;
|
||||
GSWindow.WC_TOWN_AUTHORITY <- GSWindow.WindowClass.TownAuthority;
|
||||
GSWindow.WC_VEHICLE_DETAILS <- GSWindow.WindowClass.VehicleDetails;
|
||||
GSWindow.WC_VEHICLE_REFIT <- GSWindow.WindowClass.VehicleRefit;
|
||||
GSWindow.WC_VEHICLE_ORDERS <- GSWindow.WindowClass.VehicleOrders;
|
||||
GSWindow.WC_REPLACE_VEHICLE <- GSWindow.WindowClass.ReplaceVehicle;
|
||||
GSWindow.WC_VEHICLE_TIMETABLE <- GSWindow.WindowClass.VehicleTimetable;
|
||||
GSWindow.WC_COMPANY_COLOUR <- GSWindow.WindowClass.CompanyLivery;
|
||||
GSWindow.WC_COMPANY_MANAGER_FACE <- GSWindow.WindowClass.CompanyManagerFace;
|
||||
GSWindow.WC_SELECT_STATION <- GSWindow.WindowClass.JoinStation;
|
||||
GSWindow.WC_NEWS_WINDOW <- GSWindow.WindowClass.News;
|
||||
GSWindow.WC_TOWN_DIRECTORY <- GSWindow.WindowClass.TownDirectory;
|
||||
GSWindow.WC_SUBSIDIES_LIST <- GSWindow.WindowClass.SubsidyList;
|
||||
GSWindow.WC_INDUSTRY_DIRECTORY <- GSWindow.WindowClass.IndustryDirectory;
|
||||
GSWindow.WC_MESSAGE_HISTORY <- GSWindow.WindowClass.MessageHistory;
|
||||
GSWindow.WC_SIGN_LIST <- GSWindow.WindowClass.SignList;
|
||||
GSWindow.WC_SCRIPT_LIST <- GSWindow.WindowClass.ScriptList;
|
||||
GSWindow.WC_GOALS_LIST <- GSWindow.WindowClass.GoalList;
|
||||
GSWindow.WC_STORY_BOOK <- GSWindow.WindowClass.StoryBook;
|
||||
GSWindow.WC_STATION_LIST <- GSWindow.WindowClass.StationList;
|
||||
GSWindow.WC_TRAINS_LIST <- GSWindow.WindowClass.TrainList;
|
||||
GSWindow.WC_ROADVEH_LIST <- GSWindow.WindowClass.RoadVehicleList;
|
||||
GSWindow.WC_SHIPS_LIST <- GSWindow.WindowClass.ShipList;
|
||||
GSWindow.WC_AIRCRAFT_LIST <- GSWindow.WindowClass.AircraftList;
|
||||
GSWindow.WC_TOWN_VIEW <- GSWindow.WindowClass.TownView;
|
||||
GSWindow.WC_VEHICLE_VIEW <- GSWindow.WindowClass.VehicleView;
|
||||
GSWindow.WC_STATION_VIEW <- GSWindow.WindowClass.StationView;
|
||||
GSWindow.WC_VEHICLE_DEPOT <- GSWindow.WindowClass.VehicleDepot;
|
||||
GSWindow.WC_WAYPOINT_VIEW <- GSWindow.WindowClass.WaypointView;
|
||||
GSWindow.WC_INDUSTRY_VIEW <- GSWindow.WindowClass.IndustryView;
|
||||
GSWindow.WC_COMPANY <- GSWindow.WindowClass.Company;
|
||||
GSWindow.WC_BUILD_OBJECT <- GSWindow.WindowClass.BuildObject;
|
||||
GSWindow.WC_BUILD_HOUSE <- GSWindow.WindowClass.BuildHouse;
|
||||
GSWindow.WC_BUILD_VEHICLE <- GSWindow.WindowClass.BuildVehicle;
|
||||
GSWindow.WC_BUILD_BRIDGE <- GSWindow.WindowClass.BuildBridge;
|
||||
GSWindow.WC_BUILD_STATION <- GSWindow.WindowClass.BuildStation;
|
||||
GSWindow.WC_BUS_STATION <- GSWindow.WindowClass.BuildBusStation;
|
||||
GSWindow.WC_TRUCK_STATION <- GSWindow.WindowClass.BuildTruckStation;
|
||||
GSWindow.WC_BUILD_DEPOT <- GSWindow.WindowClass.BuildDepot;
|
||||
GSWindow.WC_BUILD_WAYPOINT <- GSWindow.WindowClass.BuildWaypoint;
|
||||
GSWindow.WC_FOUND_TOWN <- GSWindow.WindowClass.FoundTown;
|
||||
GSWindow.WC_BUILD_INDUSTRY <- GSWindow.WindowClass.BuildIndustry;
|
||||
GSWindow.WC_SELECT_GAME <- GSWindow.WindowClass.SelectGame;
|
||||
GSWindow.WC_SCEN_LAND_GEN <- GSWindow.WindowClass.ScenarioGenerateLandscape;
|
||||
GSWindow.WC_GENERATE_LANDSCAPE <- GSWindow.WindowClass.GenerateLandscape;
|
||||
GSWindow.WC_MODAL_PROGRESS <- GSWindow.WindowClass.ModalProgress;
|
||||
GSWindow.WC_NETWORK_WINDOW <- GSWindow.WindowClass.Network;
|
||||
GSWindow.WC_CLIENT_LIST <- GSWindow.WindowClass.NetworkClientList;
|
||||
GSWindow.WC_NETWORK_STATUS_WINDOW <- GSWindow.WindowClass.NetworkStatus;
|
||||
GSWindow.WC_NETWORK_ASK_RELAY <- GSWindow.WindowClass.NetworkAskRelay;
|
||||
GSWindow.WC_NETWORK_ASK_SURVEY <- GSWindow.WindowClass.NetworkAskSurvey;
|
||||
GSWindow.WC_SEND_NETWORK_MSG <- GSWindow.WindowClass.NetworkChat;
|
||||
GSWindow.WC_INDUSTRY_CARGOES <- GSWindow.WindowClass.IndustryCargoes;
|
||||
GSWindow.WC_GRAPH_LEGEND <- GSWindow.WindowClass.GraphLegend;
|
||||
GSWindow.WC_FINANCES <- GSWindow.WindowClass.Finances;
|
||||
GSWindow.WC_INCOME_GRAPH <- GSWindow.WindowClass.IncomeGraph;
|
||||
GSWindow.WC_OPERATING_PROFIT <- GSWindow.WindowClass.OperatingProfitGraph;
|
||||
GSWindow.WC_DELIVERED_CARGO <- GSWindow.WindowClass.DeliveredCargoGraph;
|
||||
GSWindow.WC_PERFORMANCE_HISTORY <- GSWindow.WindowClass.PerformanceGraph;
|
||||
GSWindow.WC_COMPANY_VALUE <- GSWindow.WindowClass.CompanyValueGraph;
|
||||
GSWindow.WC_COMPANY_LEAGUE <- GSWindow.WindowClass.CompanyLeague;
|
||||
GSWindow.WC_PAYMENT_RATES <- GSWindow.WindowClass.CargoPaymentRatesGraph;
|
||||
GSWindow.WC_PERFORMANCE_DETAIL <- GSWindow.WindowClass.PerformanceDetail;
|
||||
GSWindow.WC_INDUSTRY_PRODUCTION <- GSWindow.WindowClass.IndustryProductionGraph;
|
||||
GSWindow.WC_TOWN_CARGO_GRAPH <- GSWindow.WindowClass.TownCargoGraph;
|
||||
GSWindow.WC_COMPANY_INFRASTRUCTURE <- GSWindow.WindowClass.CompanyInfrastructure;
|
||||
GSWindow.WC_BUY_COMPANY <- GSWindow.WindowClass.BuyCompany;
|
||||
GSWindow.WC_ENGINE_PREVIEW <- GSWindow.WindowClass.EnginePreview;
|
||||
GSWindow.WC_MUSIC_WINDOW <- GSWindow.WindowClass.Music;
|
||||
GSWindow.WC_MUSIC_TRACK_SELECTION <- GSWindow.WindowClass.MusicTrackSelection;
|
||||
GSWindow.WC_GAME_OPTIONS <- GSWindow.WindowClass.GameOptions;
|
||||
GSWindow.WC_CUSTOM_CURRENCY <- GSWindow.WindowClass.CustomCurrenty;
|
||||
GSWindow.WC_CHEATS <- GSWindow.WindowClass.Cheat;
|
||||
GSWindow.WC_EXTRA_VIEWPORT <- GSWindow.WindowClass.ExtraViewport;
|
||||
GSWindow.WC_CONSOLE <- GSWindow.WindowClass.Console;
|
||||
GSWindow.WC_BOOTSTRAP <- GSWindow.WindowClass.Bootstrap;
|
||||
GSWindow.WC_HIGHSCORE <- GSWindow.WindowClass.Highscore;
|
||||
GSWindow.WC_ENDSCREEN <- GSWindow.WindowClass.Endscreen;
|
||||
GSWindow.WC_SCRIPT_DEBUG <- GSWindow.WindowClass.ScriptDebug;
|
||||
GSWindow.WC_NEWGRF_INSPECT <- GSWindow.WindowClass.NewGRFInspect;
|
||||
GSWindow.WC_SPRITE_ALIGNER <- GSWindow.WindowClass.SpriteAligner;
|
||||
GSWindow.WC_LINKGRAPH_LEGEND <- GSWindow.WindowClass.LinkGraphLegend;
|
||||
GSWindow.WC_SAVE_PRESET <- GSWindow.WindowClass.SavePreset;
|
||||
GSWindow.WC_FRAMERATE_DISPLAY <- GSWindow.WindowClass.FramerateDisplay;
|
||||
GSWindow.WC_FRAMETIME_GRAPH <- GSWindow.WindowClass.FrametimeGraph;
|
||||
GSWindow.WC_SCREENSHOT <- GSWindow.WindowClass.Screenshot;
|
||||
GSWindow.WC_HELPWIN <- GSWindow.WindowClass.Help;
|
||||
GSWindow.WC_INVALID <- GSWindow.WindowClass.Invalid;
|
||||
+212
@@ -1,5 +1,217 @@
|
||||
## 16.x
|
||||
|
||||
### 16.0-beta2 (2026-07-12)
|
||||
|
||||
- Feature: Allow bridges over depots (#15836)
|
||||
- Feature: Increase maximum number of vehicles per type to 10,000 (#15810)
|
||||
- Feature: Add and remove whole classes to picker collections (#15808)
|
||||
- Feature: Station list can be filtered by name (#15772)
|
||||
- Change: Use "bridge ... too low" message for bridgeable objects (#15838)
|
||||
- Fix: Use meaningful tooltips for graph range toggle buttons (#15842)
|
||||
- Fix #15826: Exclude allow any/all options for AI companies (#15834)
|
||||
- Fix #7992: Fix for catenary road and tram catenary sprites not being drawn on bridges (#15811)
|
||||
- Fix #15784: Crash due to incorrect road build toolbar when switching road tram types (#15789)
|
||||
- Fix: [NewGRF] Make 'signals on traffic side' consistent with explicit settings (#15661)
|
||||
- Fix: [Win32] Explicitly initialize COM in Win32 video driver (#15553)
|
||||
|
||||
### 16.0-beta1 (2026-06-25)
|
||||
|
||||
- Feature: Add default road and tram selection (#15585)
|
||||
- Feature: Trains with an engine on the rear can drive backwards when reversing (#15379)
|
||||
- Feature: Add worldgen setting for average height of terrain (#14989)
|
||||
- Feature: Add text filter to dropdown lists (#14842)
|
||||
- Feature: User-defined collections of saved items in the picker window (#14813)
|
||||
- Feature: Configurable sign text colors in scenario editor (#14743)
|
||||
- Feature: Allow placing an area of 1x1 houses in scenario editor (#14708)
|
||||
- Feature: Scale cargo payment aging rate (#14635)
|
||||
- Feature: Support automatic detection of data from Atari's Transport Tycoon Deluxe re-release (#15483)
|
||||
- Add: [NewGRF] Implement custom waypoint layouts by callback 24 (#15616)
|
||||
- Add: List 'Place object' in landscaping dropdown (#15609)
|
||||
- Add: Setting to disable aircraft range limit (#15433)
|
||||
- Add: Show maximum reliability in vehicle info (#15401)
|
||||
- Add: Lower the Send To Depot button when a vehicle is on its way to one (#15397)
|
||||
- Add: Setting to disallow train magic flip, and reverse at reduced speed (#15391)
|
||||
- Add: [NewGRF] Variable for when a train is driving backwards (#15379)
|
||||
- Add: [NewGRF] Flag to allow unpowered wagon to lead train when backing up (#15379)
|
||||
- Add: [NewGRF] Station flag to divide cargo by area instead of perimeter (#15253)
|
||||
- Add: Company allow-list can be set to allow anyone (#15204)
|
||||
- Add: Record history of cargo delivered to towns (#15184)
|
||||
- Add: Show additional vehicle details based on sort criteria (#15158)
|
||||
- Add: Setting to control minimum distance between towns (#14893)
|
||||
- Change: Selecting Rail/Roadtype updates build toolbar instead of closing and reopening (#15589)
|
||||
- Change: Default setting to review orders excludes stopped vehicles (#15565)
|
||||
- Change: Most used rail type takes ownership into account (#15489)
|
||||
- Change: Test font for eligibility before adding as fallback (#15412)
|
||||
- Change: Clarify max age shown in vehicle info window (#15403)
|
||||
- Change: Show "Delete All" in order window delete button when applicable (#15370)
|
||||
- Change: Make continuation error messages consistent (#15328)
|
||||
- Change: Distinguish between 'Flat land required' and 'Land sloped in wrong direction' for building depots (#15327)
|
||||
- Change: Allow subsidies with CargoDist (#15189)
|
||||
- Change: Removing river tiles reduces local authority rating (#15180)
|
||||
- Change: Protect rivers from removal when terraforming (#15176)
|
||||
- Change: [Script] Reformat callstack output (#15171)
|
||||
- Change: Apply slightly more padding to image-text buttons (#15077)
|
||||
- Change: [NewGRF] Display rail and road type speed limit text in yellow (#15076)
|
||||
- Change: Make smallmap show infinite water, if enabled (#15041)
|
||||
- Change: Add support for next/previous/first/last rail/road/tram type hotkeys (#15028)
|
||||
- Change: Allow rocks on desert tiles (#14979)
|
||||
- Change: [Script] Include Array/PriorityQueye/ScriptList contents in script memory allocation total (#14954)
|
||||
- Change: [Script] Various ScriptList methods are now suspendable (#14943, #14762)
|
||||
- Change: Improve generation of coasts at map edges (#14868)
|
||||
- Change: Show only selected badge in badge filter dropdown buttons (#14855)
|
||||
- Change: River springs must be surrounded by hills (#14845)
|
||||
- Change: Vehicles loading at stations don't lose reliability (#14841)
|
||||
- Change: Generate lighthouses along coasts and near towns (#14828)
|
||||
- Change: Transmitter object only spawns after original base year (#14786)
|
||||
- Change: Share one window for engine preview pop ups (#14703)
|
||||
- Fix: [NewGRF] Town name language incorrectly decoded (#15691)
|
||||
- Fix #15606: Undefined behaviour may cause buttons to be invisible (#15686)
|
||||
- Fix #14975: Show correct tile for tunnel error message (#15660)
|
||||
- Fix: [NewGRF] Incorrect language IDs passed to TranslateTTDPatchCodes (#15655)
|
||||
- Fix: Scenario editor random industry generation (#15626)
|
||||
- Fix: [NewGRF] Ignore blocked waypoint tiles (#15620)
|
||||
- Fix: [NewGRF] Pylons and no-wires flags were ignored for waypoint tiles (#15619)
|
||||
- Fix: Dedicated server signal handling for SIGTERM/SIGINT/SIGQUIT (#15607)
|
||||
- Fix: [NewGRF] Potential out-of-bounds read when performing GRM (#15600)
|
||||
- Fix: Badge offsets not ignored when determining width (#15588)
|
||||
- Fix: Account for NewGRF's global train width when drawing dual-head engines (#15587)
|
||||
- Fix: Station list facility buttons do not produce click sound (#15569)
|
||||
- Fix #15495: Fix incorrectly built default waypoints (#15562)
|
||||
- Fix #15495: Unable to build bridge over default waypoints (#15562)
|
||||
- Fix #15235: Make GameScripts obey town road construction setting (#15559)
|
||||
- Fix: Crash when loading crash save with no viewport coordinates (#15550)
|
||||
- Fix #15520: Fix viewport snap back on stop following vehicle (#15520) (#15531)
|
||||
- Fix: Buttons for choosing engine in preview window show for single engine (#15514)
|
||||
- Fix #15511: Vehicle passed to commands must be a company buildable type (#15512)
|
||||
- Fix #15497: [Script] ScriptController::Break not pausing in TestMode (#15498)
|
||||
- Fix: Coordinate transformation for JSON town placement when anticlockwise (#15490)
|
||||
- Fix: NewGRF debug handler for towns in wrong place since badges (#15467)
|
||||
- Fix: Object id overrides were not reset between games (#15465)
|
||||
- Fix: Debug saveload errors were clobbered (#15452)
|
||||
- Fix: Refresh client list when client renames (#15439)
|
||||
- Fix #15428: [Fluidsynth] Treat configured synth.gain as maximum instead of hardcoded value (#15429)
|
||||
- Fix: Refresh string width cache for all loaded fonts (#15427)
|
||||
- Fix: Typo in Hungarian town name suffix ("kak" -> "lak") (#15421)
|
||||
- Fix: [NewGRF] Variable 0x69 has not been added for waypoints (#15396)
|
||||
- Fix: Dropdown text filter could interfere with hotkeys after closing (#15395)
|
||||
- Fix: Rejecting or accepting engine preview incorrectly closed preview window (#15378)
|
||||
- Fix #15318: Nonsensical error message when trying to send aircraft to hangar with no usable airports (#15334)
|
||||
- Fix #15234: Null pointer dereference opening sign edit window when sign 0 does not exist (#15236)
|
||||
- Fix: [GS] Docs are missing or do not match the code (#15230)
|
||||
- Fix: Off by one and redundant logic in snowy road checks (#15214)
|
||||
- Fix #15137: Roads built on steep slopes at the minimum snow level height have inconsistent snowiness (#15190)
|
||||
- Fix: Station view window fold/unfold not refreshing scrollbar (#15187)
|
||||
- Fix: Use consistent description for invalid orders (#15177)
|
||||
- Fix: [Script] Give GetPrimary/SecondaryLiveryColour preconditions (#15169)
|
||||
- Fix: Cocoa video driver did not register (#15145)
|
||||
- Fix: MacOS version detection was broken (#15145)
|
||||
- Fix #13600: Make terraform click+draggable in scenario editor (#15135)
|
||||
- Fix: [Script] Map some error strings to existing errors (#15113)
|
||||
- Fix: Allow to build buoys at (0x0) (#14983)
|
||||
- Fix #14610: Do not treat aircraft with only depot orders as having valid orders (#14961)
|
||||
- Fix #12937: Allow the computer to go to sleep while the game is paused (#14948)
|
||||
- Fix: Company query popups do not update in multiplayer (#14947)
|
||||
- Fix #14892: Potential crash when logging fonts for survey (#14896)
|
||||
- Fix #14827: Store random trigger information per-tile (#14830)
|
||||
|
||||
## 15.x
|
||||
|
||||
### 15.3 (2026-04-04)
|
||||
|
||||
- Fix: Conditional orders could require a maximum reliability over 100% (#15409)
|
||||
- Fix: Improve appearance of toolbars and main menu images/text with some non-default base sets (#15402)
|
||||
- Fix: [Script] IsBuildableRectangle for a 0x0 tile should return false (#15357)
|
||||
- Fix: Desync caused by train crashes (#15338)
|
||||
- Fix: Incorrect scroll bar capacity for train details window total cargo tab (#15329)
|
||||
- Fix #15310: Crash caused by a helicopter running out of fuel near map edge (#15311)
|
||||
|
||||
### 15.2 (2026-02-18)
|
||||
|
||||
- Fix: Crashed zeppelin not blocking runway (#15281)
|
||||
- Fix #15269: Crash when building drive-through stop on unowned one-way road (#15270)
|
||||
- Fix #15247: Crash when handling invalid sprite in OpenGL cursor sprite system (#15248)
|
||||
- Fix #15105: Czech townname generation causing crashes (#15231)
|
||||
- Fix: Incorrect ground type test when placing towns (#15217)
|
||||
- Fix: Town supplied cargo history incorrectly clamped to 16 bit values (#15183)
|
||||
- Fix #15085: Crash when GUI scale changes before video driver is fully initialised (#15175)
|
||||
- Fix: Articulated road vehicle following with immediately sequential u-turns (#15170)
|
||||
- Fix #15166: Foundations missing adjacent to NewGRF objects without foundation (#15168)
|
||||
- Fix #14035: [Fluidsynth] Read settings from config files if available (#15044)
|
||||
- Fix #15263: Badge filter toggles no longer worked (#14972)
|
||||
|
||||
### 15.1 (2026-01-24)
|
||||
|
||||
- Fix #15088: When building a new train, the refit button state may be incorrect (#15162)
|
||||
- Fix #15160: Incorrect company names displayed in load game window (#15161)
|
||||
- Fix #15153: Wrong tile used to get bridge reservation overlay (#15154)
|
||||
- Fix #15116: Old cargo/industry sets without cargo translation table broken (#15150)
|
||||
- Fix: Possible crash converting company liveries in older savegames/scenarios (#15148)
|
||||
- Fix: Allow infinite water to be (de)selected when loading heightmap (#15146)
|
||||
- Fix: Tile suitability test for farm field no longer handled snow tiles (#15134)
|
||||
- Fix #15131: Trees no longer spread on partially snowy tiles (#15133)
|
||||
- Fix: Change tooltips to match change from checkboxes to switches (#15123)
|
||||
- Fix: [Script] Potential out of bounds array/string slice indexes (#15106)
|
||||
- Fix: [Script] Potential out of bounds indexed string access (#15106)
|
||||
- Fix: [Script] Check if array sort function modified array (#15106)
|
||||
- Fix #15069: World generation map edges GUI starts in an invalid state (#15082)
|
||||
- Fix #15079: Incorrect dates shown on town cargo history graph (#15080)
|
||||
- Fix #15067: Mark NewGRF settings as modified after moving by drag & drop (#15068)
|
||||
- Fix: Incorrect error message for aqueducts reaching northern map borders (#14974)
|
||||
- Fix: Standardize wording of GRF/NewGRF (#15059)
|
||||
- Fix #15046: Crash on loading game due to invalid group parents (#15049)
|
||||
- Fix: Disable_elrails handling with engines that use both RAIL and ELRL (#15045)
|
||||
- Fix: [Fluidsynth] Read settings from system and user config files if available (#15044)
|
||||
- Fix #15039: Name and version can disappear from content list (#15040)
|
||||
- Fix #15026: Remove incorrect info from base sounds tooltip (#15029)
|
||||
- Fix: [Script] Improve reporting of invalid GetAPIVersion return (#15015)
|
||||
- Fix: [Script] Undefined behaviour after calling SwapList during iteration (#14805)
|
||||
|
||||
### 15.0 (2026-01-01)
|
||||
|
||||
- Fix: Small ufos would loop over vehicles in depots forever (#15008)
|
||||
- Fix #14982: Can't place buoys under bridges (#15007)
|
||||
- Fix #15004: Crashes when dropdown is held open during endgame screen (#15006)
|
||||
- Fix: Further improve town spawning near water (#15002)
|
||||
- Fix: Use correct 'minutes per year' setting for old savegames (#14995)
|
||||
- Fix: Rare crash dividing by 0 when drawing a line (#14994)
|
||||
- Fix #14992: Respect non-stop order setting when adding waypoint orders (#14993)
|
||||
|
||||
### 15.0-RC4 (2025-12-26)
|
||||
|
||||
- Fix: Incorrect text colour in fund industry window (#14987)
|
||||
- Fix: Towns failed to find spawn locations near water (#14988)
|
||||
- Fix: Don't draw bridge deck rail sprites for default bridges (#14985)
|
||||
- Fix: "(Invalid parameter)" in error message when trying to remove another player's object (#14981)
|
||||
- Fix #14978: Don't clear water tiles after removing buoys (#14980)
|
||||
- Fix #14973: Composed strings are incorrect colour (#14976)
|
||||
- Fix: Badge filter toggles no longer worked (#14972)
|
||||
- Fix #12465: Click/tooltip alignment of industry chain cargo lines (#14963)
|
||||
- Fix #14951: Possible incorrect data in industry production graphs (#14962)
|
||||
- Fix #14958: Crash when opening station window (#14959)
|
||||
- Fix #14938: Don't allow cacti to die off (#14956)
|
||||
- Fix: Don't allow joining a company after it was taken over (#14955)
|
||||
- Fix #14949: Crash when moving station sign in a network game (#14950)
|
||||
- Fix #14945: Hang when deleting implicit orders during vehicle loading (#14946)
|
||||
|
||||
### 15.0-RC3 (2025-12-20)
|
||||
|
||||
- Fix #14932: [NewGRF] Increase internal badge index size to avoid overflowing BadgeIDs (#14933)
|
||||
- Fix: Crash related to object picker recolours in Scenario Editor (#14929)
|
||||
- Fix #14921: Crash during station autorefit if station doesn't accept current cargo type (#14924)
|
||||
- Fix #14917: Crash when opening house picker with no houses available (#14920)
|
||||
- Fix #14916: Duration of error message window could be too short (#14919)
|
||||
- Fix #14915: Crash due to divide-by-zero of industry probabilities (#14918)
|
||||
- Fix: Script configs were cleared by intro game (#14910)
|
||||
- Fix: [NewGRF] Automatically push/pop colours when formatting a sub-string (#14006)
|
||||
|
||||
### 15.0-RC2 (2025-12-13)
|
||||
|
||||
- Fix #14677: Desync due to using newgame time settings to validate savegame time settings (#14904)
|
||||
- Fix: Graph label allocated size could be too small (#14901)
|
||||
- Fix #14891: Minimum sprite zoomlevel could break in some cases showing placeholder sprites instead (#14894)
|
||||
- Fix #14889: [FluidSynth] Don't try to load a soundfont that doesn't exist (#14890)
|
||||
- Revert: Dynamic font loading changes removed (#14903)
|
||||
|
||||
### 15.0-RC1 (2025-12-07)
|
||||
|
||||
- Feature: Automatically load extra fonts for missing glyphs (#13303, #14856)
|
||||
|
||||
@@ -100,9 +100,6 @@ macro(compile_flags)
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
include(CheckCXXCompilerFlag)
|
||||
check_cxx_compiler_flag("-flifetime-dse=1" LIFETIME_DSE_FOUND)
|
||||
|
||||
add_compile_options(
|
||||
# GCC 4.2+ automatically assumes that signed overflows do
|
||||
# not occur in signed arithmetics, whereas we are not
|
||||
@@ -110,10 +107,6 @@ macro(compile_flags)
|
||||
# about its own optimized code in some places.
|
||||
"-fno-strict-overflow"
|
||||
|
||||
# -flifetime-dse=2 (default since GCC 6) doesn't play
|
||||
# well with our custom pool item allocator
|
||||
"$<$<BOOL:${LIFETIME_DSE_FOUND}>:-flifetime-dse=1>"
|
||||
|
||||
# We have a fight between clang wanting std::move() and gcc not wanting it
|
||||
# and of course they both warn when the other compiler is happy
|
||||
"-Wno-redundant-move"
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
#
|
||||
# create_regression(file1 ...)
|
||||
#
|
||||
macro(create_regression)
|
||||
macro(create_regression SCRIPT_FOLDER)
|
||||
set(REGRESSION_SOURCE_FILES ${ARGN})
|
||||
|
||||
foreach(REGRESSION_SOURCE_FILE IN LISTS REGRESSION_SOURCE_FILES)
|
||||
string(REPLACE "${CMAKE_SOURCE_DIR}/regression/" "" REGRESSION_SOURCE_FILE_NAME "${REGRESSION_SOURCE_FILE}")
|
||||
string(CONCAT REGRESSION_BINARY_FILE "${CMAKE_BINARY_DIR}/ai/" "${REGRESSION_SOURCE_FILE_NAME}")
|
||||
string(CONCAT REGRESSION_BINARY_FILE "${CMAKE_BINARY_DIR}/${SCRIPT_FOLDER}/" "${REGRESSION_SOURCE_FILE_NAME}")
|
||||
|
||||
add_custom_command(OUTPUT ${REGRESSION_BINARY_FILE}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
@@ -38,6 +38,7 @@ macro(create_regression)
|
||||
-DOPENTTD_EXECUTABLE=$<TARGET_FILE:openttd>
|
||||
-DEDITBIN_EXECUTABLE=${EDITBIN_EXECUTABLE}
|
||||
-DREGRESSION_TEST=${REGRESSION_TEST_NAME}
|
||||
-DSCRIPT_FOLDER=${SCRIPT_FOLDER}
|
||||
-P "${CMAKE_SOURCE_DIR}/cmake/scripts/Regression.cmake"
|
||||
DEPENDS openttd regression_${REGRESSION_TEST_NAME}_files
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
@@ -50,9 +51,12 @@ macro(create_regression)
|
||||
-DOPENTTD_EXECUTABLE=$<TARGET_FILE:openttd>
|
||||
-DEDITBIN_EXECUTABLE=${EDITBIN_EXECUTABLE}
|
||||
-DREGRESSION_TEST=${REGRESSION_TEST_NAME}
|
||||
-DSCRIPT_FOLDER=${SCRIPT_FOLDER}
|
||||
-P "${CMAKE_SOURCE_DIR}/cmake/scripts/Regression.cmake"
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
set_property(TEST regression_${REGRESSION_TEST_NAME} PROPERTY RUN_SERIAL TRUE)
|
||||
|
||||
add_dependencies(regression regression_${REGRESSION_TEST_NAME})
|
||||
endmacro()
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
# CMake provides a FindICU module since version 3.7.
|
||||
# But it doesn't use pkgconfig, doesn't set expected variables,
|
||||
# And it returns incomplete dependencies if only some modules are searched.
|
||||
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
FindICU
|
||||
-------
|
||||
|
||||
Finds components of the ICU library.
|
||||
|
||||
Accepted components are: uc, i18n, le, lx, io, data
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``ICU_FOUND``
|
||||
True if components of ICU library are found.
|
||||
``ICU_VERSION``
|
||||
The version of the ICU library which was found.
|
||||
``ICU_<c>_FOUND``
|
||||
True if the system has the <c> component of ICU library.
|
||||
``ICU_<c>_INCLUDE_DIRS``
|
||||
Include directories needed to use the <c> component of ICU library.
|
||||
``ICU_<c>_LIBRARIES``
|
||||
Libraries needed to link to the <c> component of ICU library.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
|
||||
set(ICU_KNOWN_COMPONENTS "uc" "i18n" "le" "lx" "io" "data")
|
||||
|
||||
foreach(MOD_NAME IN LISTS ICU_FIND_COMPONENTS)
|
||||
if(NOT MOD_NAME IN_LIST ICU_KNOWN_COMPONENTS)
|
||||
message(FATAL_ERROR "Unknown ICU component: ${MOD_NAME}")
|
||||
endif()
|
||||
pkg_check_modules(PC_ICU_${MOD_NAME} QUIET icu-${MOD_NAME})
|
||||
|
||||
# Check the libraries returned by pkg-config really exist.
|
||||
unset(PC_LIBRARIES)
|
||||
foreach(LIBRARY IN LISTS PC_ICU_${MOD_NAME}_LIBRARIES)
|
||||
unset(PC_LIBRARY CACHE)
|
||||
find_library(PC_LIBRARY NAMES ${LIBRARY})
|
||||
if(NOT PC_LIBRARY)
|
||||
unset(PC_ICU_${MOD_NAME}_FOUND)
|
||||
endif()
|
||||
list(APPEND PC_LIBRARIES ${PC_LIBRARY})
|
||||
endforeach()
|
||||
unset(PC_LIBRARY CACHE)
|
||||
|
||||
if(${PC_ICU_${MOD_NAME}_FOUND})
|
||||
set(ICU_COMPONENT_FOUND TRUE)
|
||||
set(ICU_${MOD_NAME}_FOUND TRUE)
|
||||
set(ICU_${MOD_NAME}_LIBRARIES ${PC_LIBRARIES})
|
||||
set(ICU_${MOD_NAME}_INCLUDE_DIRS ${PC_ICU_${MOD_NAME}_INCLUDE_DIRS})
|
||||
set(ICU_VERSION ${PC_ICU_${MOD_NAME}_VERSION})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(ICU
|
||||
FOUND_VAR ICU_FOUND
|
||||
REQUIRED_VARS ICU_COMPONENT_FOUND
|
||||
VERSION_VAR ICU_VERSION
|
||||
HANDLE_COMPONENTS
|
||||
)
|
||||
@@ -190,29 +190,7 @@ elseif(UNIX)
|
||||
set(CPACK_GENERATOR "TXZ")
|
||||
set(PLATFORM "unknown")
|
||||
else()
|
||||
find_program(LSB_RELEASE_EXEC lsb_release)
|
||||
execute_process(COMMAND ${LSB_RELEASE_EXEC} -is
|
||||
OUTPUT_VARIABLE LSB_RELEASE_ID
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(LSB_RELEASE_ID)
|
||||
if(LSB_RELEASE_ID STREQUAL "Ubuntu" OR LSB_RELEASE_ID STREQUAL "Debian" OR LSB_RELEASE_ID STREQUAL "Linuxmint")
|
||||
execute_process(COMMAND ${LSB_RELEASE_EXEC} -cs
|
||||
OUTPUT_VARIABLE LSB_RELEASE_CODENAME
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
string(TOLOWER "${LSB_RELEASE_ID}-${LSB_RELEASE_CODENAME}" PLATFORM)
|
||||
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
include(PackageDeb)
|
||||
elseif(LSB_RELEASE_ID STREQUAL "Fedora")
|
||||
set(PLATFORM "fedora")
|
||||
set(CPACK_GENERATOR "RPM")
|
||||
include(PackageRPM)
|
||||
else()
|
||||
set(UNSUPPORTED_PLATFORM_NAME "LSB-based Linux distribution '${LSB_RELEASE_ID}'")
|
||||
endif()
|
||||
elseif(EXISTS "/etc/os-release")
|
||||
if(EXISTS "/etc/os-release")
|
||||
file(STRINGS "/etc/os-release" OS_RELEASE_CONTENTS REGEX "^ID=")
|
||||
string(REGEX MATCH "ID=(.*)" _ ${OS_RELEASE_CONTENTS})
|
||||
set(DISTRO_ID ${CMAKE_MATCH_1})
|
||||
@@ -223,11 +201,43 @@ elseif(UNIX)
|
||||
set(PLATFORM "fedora")
|
||||
set(CPACK_GENERATOR "RPM")
|
||||
include(PackageRPM)
|
||||
elseif(DISTRO_ID STREQUAL "ubuntu" OR DISTRO_ID STREQUAL "debian" OR DISTRO_ID STREQUAL "linuxmint")
|
||||
file(STRINGS "/etc/os-release" OS_RELEASE_CODENAME REGEX "^VERSION_CODENAME=")
|
||||
string(REGEX MATCH "VERSION_CODENAME=(.*)" _ ${OS_RELEASE_CODENAME})
|
||||
set(RELEASE_CODENAME ${CMAKE_MATCH_1})
|
||||
string(TOLOWER "${DISTRO_ID}-${RELEASE_CODENAME}" PLATFORM)
|
||||
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
include(PackageDeb)
|
||||
else()
|
||||
set(UNSUPPORTED_PLATFORM_NAME "Linux distribution '${DISTRO_ID}' from /etc/os-release")
|
||||
endif()
|
||||
else()
|
||||
set(UNSUPPORTED_PLATFORM_NAME "Linux distribution")
|
||||
find_program(LSB_RELEASE_EXEC lsb_release)
|
||||
execute_process(COMMAND ${LSB_RELEASE_EXEC} -is
|
||||
OUTPUT_VARIABLE LSB_RELEASE_ID
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
if(LSB_RELEASE_ID)
|
||||
if(LSB_RELEASE_ID STREQUAL "Ubuntu" OR LSB_RELEASE_ID STREQUAL "Debian" OR LSB_RELEASE_ID STREQUAL "Linuxmint")
|
||||
execute_process(COMMAND ${LSB_RELEASE_EXEC} -cs
|
||||
OUTPUT_VARIABLE LSB_RELEASE_CODENAME
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
string(TOLOWER "${LSB_RELEASE_ID}-${LSB_RELEASE_CODENAME}" PLATFORM)
|
||||
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
include(PackageDeb)
|
||||
elseif(LSB_RELEASE_ID STREQUAL "Fedora")
|
||||
set(PLATFORM "fedora")
|
||||
set(CPACK_GENERATOR "RPM")
|
||||
include(PackageRPM)
|
||||
else()
|
||||
set(UNSUPPORTED_PLATFORM_NAME "LSB-based Linux distribution '${LSB_RELEASE_ID}'")
|
||||
endif()
|
||||
else()
|
||||
set(UNSUPPORTED_PLATFORM_NAME "Linux distribution")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT PLATFORM)
|
||||
|
||||
@@ -61,12 +61,32 @@ function(set_options)
|
||||
option(OPTION_TOOLS_ONLY "Build only tools target" OFF)
|
||||
option(OPTION_DOCS_ONLY "Build only docs target" OFF)
|
||||
option(OPTION_ALLOW_INVALID_SIGNATURE "Allow loading of content with invalid signatures" OFF)
|
||||
option(OPTION_LINE_IN_DOXYGEN_WARNINGS "Print line number in doxygen warnings" ON)
|
||||
|
||||
if (OPTION_DOCS_ONLY)
|
||||
set(OPTION_TOOLS_ONLY ON PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if (OPTION_LINE_IN_DOXYGEN_WARNINGS)
|
||||
set(DOXYGEN_WARN_FORMAT_LINE "line" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
option(OPTION_SURVEY_KEY "Survey-key to use for the opt-in survey (empty if you have none)" "")
|
||||
option(OPTION_DOXYGEN_WARN_FILE "File to write doxygen warnings into (if empty warnings are written to standard error)" "")
|
||||
option(OPTION_DOXYGEN_GS_WARN_FILE "File to write doxygen warnings from game script docs into (if empty warnings are written to standard error)" "")
|
||||
option(OPTION_DOXYGEN_AI_WARN_FILE "File to write doxygen warnings from AI docs into (if empty warnings are written to standard error)" "")
|
||||
|
||||
if(OPTION_DOXYGEN_WARN_FILE)
|
||||
set(DOXYGEN_WARN_FILE ${CMAKE_BINARY_DIR}/${OPTION_DOXYGEN_WARN_FILE} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if(OPTION_DOXYGEN_GS_WARN_FILE)
|
||||
set(DOXYGEN_GS_WARN_FILE ${CMAKE_BINARY_DIR}/${OPTION_DOXYGEN_GS_WARN_FILE} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if(OPTION_DOXYGEN_AI_WARN_FILE)
|
||||
set(DOXYGEN_AI_WARN_FILE ${CMAKE_BINARY_DIR}/${OPTION_DOXYGEN_AI_WARN_FILE} PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Show the values of the generic options.
|
||||
|
||||
@@ -135,6 +135,9 @@ if(GENERATE_OTTDREV)
|
||||
message(STATUS "Generating .ottdrev")
|
||||
file(WRITE ${CMAKE_SOURCE_DIR}/.ottdrev "${REV_VERSION}\t${REV_ISODATE}\t${REV_MODIFIED}\t${REV_HASH}\t${REV_ISTAG}\t${REV_ISSTABLETAG}\n")
|
||||
else()
|
||||
if(REV_ISSTABLETAG AND NOT (REV_VERSION STREQUAL "${REV_MAJOR}.${REV_MINOR}"))
|
||||
message(FATAL_ERROR "Tag (${REV_VERSION}) doesn't match internal version (${REV_MAJOR}.${REV_MINOR})")
|
||||
endif()
|
||||
message(STATUS "Generating rev.cpp")
|
||||
configure_file("${CMAKE_SOURCE_DIR}/src/rev.cpp.in"
|
||||
"${FIND_VERSION_BINARY_DIR}/rev.cpp")
|
||||
|
||||
@@ -25,6 +25,13 @@ endif()
|
||||
|
||||
file(STRINGS ${GENERATE_SOURCE_FILE} ENUM_LINES REGEX "@enum")
|
||||
|
||||
function(remove_invalid_links VARIABLE)
|
||||
string(REGEX REPLACE "#([A-Za-z0-9_]*Widgets)" "@hash \\1" VARIABLE "${VARIABLE}")
|
||||
string(REPLACE "#" "" VARIABLE "${VARIABLE}")
|
||||
string(REPLACE "@hash " "#" VARIABLE "${VARIABLE}")
|
||||
set(NO_INVALID_LINKS ${VARIABLE} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
foreach(ENUM IN LISTS ENUM_LINES)
|
||||
string(REGEX REPLACE "^( )// @enum ([^ ]+) ([^ ]+)@([^ ]+)@" "\\4" PLACE_HOLDER "${ENUM}")
|
||||
set(ADD_INDENT "${CMAKE_MATCH_1}")
|
||||
@@ -49,14 +56,17 @@ foreach(ENUM IN LISTS ENUM_LINES)
|
||||
|
||||
# Remember possible doxygen comment before enum declaration
|
||||
if((NOT ACTIVE) AND "${LINE}" MATCHES "/\\*\\*")
|
||||
set(COMMENT "${ADD_INDENT}${LINE}")
|
||||
remove_invalid_links("${LINE}")
|
||||
set(COMMENT "${ADD_INDENT}${NO_INVALID_LINKS}")
|
||||
set(ACTIVE_COMMENT 1)
|
||||
elseif(ACTIVE_COMMENT EQUAL 1)
|
||||
string(APPEND COMMENT "\n${ADD_INDENT}${LINE}")
|
||||
remove_invalid_links("${LINE}")
|
||||
string(APPEND COMMENT "\n${ADD_INDENT}${NO_INVALID_LINKS}")
|
||||
endif()
|
||||
|
||||
# Check for enum match
|
||||
if("${LINE}" MATCHES "^ *enum *${ENUM_PATTERN}( *: *[^ ]*)? *\{")
|
||||
if("${LINE}" MATCHES "^ *enum *(class)? *(${ENUM_PATTERN})( *: *[^ ]*)? *\{")
|
||||
set(ENUM_NAME "${CMAKE_MATCH_2}")
|
||||
# REGEX REPLACE does a REGEX MATCHALL and fails if an empty string is matched
|
||||
string(REGEX MATCH "[^ ]*" RESULT "${LINE}")
|
||||
string(REPLACE "${RESULT}" "" RM_INDENT "${LINE}")
|
||||
@@ -100,23 +110,23 @@ foreach(ENUM IN LISTS ENUM_LINES)
|
||||
endforeach()
|
||||
|
||||
if(CMAKE_MATCH_3)
|
||||
string(APPEND ${PLACE_HOLDER} "\n${ADD_INDENT}${CMAKE_MATCH_1}${CMAKE_MATCH_2}${SPACES} = ::${CMAKE_MATCH_2},${SPACES}${CMAKE_MATCH_3}")
|
||||
# CMAKE_MATCH_3 contains inline comment.
|
||||
remove_invalid_links("${CMAKE_MATCH_3}")
|
||||
string(APPEND ${PLACE_HOLDER} "\n${ADD_INDENT}${CMAKE_MATCH_1}${CMAKE_MATCH_2}${SPACES} = to_underlying(::${ENUM_NAME}::${CMAKE_MATCH_2}),${SPACES}${NO_INVALID_LINKS}")
|
||||
else()
|
||||
string(APPEND ${PLACE_HOLDER} "\n${ADD_INDENT}${CMAKE_MATCH_1}${CMAKE_MATCH_2}${SPACES} = ::${CMAKE_MATCH_2},")
|
||||
string(APPEND ${PLACE_HOLDER} "\n${ADD_INDENT}${CMAKE_MATCH_1}${CMAKE_MATCH_2}${SPACES} = to_underlying(::${ENUM_NAME}::${CMAKE_MATCH_2}),")
|
||||
endif()
|
||||
elseif("${LINE}" STREQUAL "")
|
||||
string(APPEND ${PLACE_HOLDER} "\n")
|
||||
elseif("${LINE}" MATCHES "^ *\};")
|
||||
string(APPEND ${PLACE_HOLDER} "\n${ADD_INDENT}${LINE}\n")
|
||||
unset(ACTIVE)
|
||||
else()
|
||||
string(APPEND ${PLACE_HOLDER} "\n${ADD_INDENT}${LINE}")
|
||||
# Line is not an enum member, so it might be a comment.
|
||||
remove_invalid_links("${LINE}")
|
||||
string(APPEND ${PLACE_HOLDER} "\n${ADD_INDENT}${NO_INVALID_LINKS}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if("${LINE}" MATCHES "^ *\};")
|
||||
if(ACTIVE)
|
||||
string(APPEND ${PLACE_HOLDER} "\n")
|
||||
endif()
|
||||
unset(ACTIVE)
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
@@ -7,11 +7,14 @@ cmake_minimum_required(VERSION 3.17)
|
||||
if(NOT REGRESSION_TEST)
|
||||
message(FATAL_ERROR "Script needs REGRESSION_TEST defined (tip: use -DREGRESSION_TEST=..)")
|
||||
endif()
|
||||
if(NOT SCRIPT_FOLDER)
|
||||
message(FATAL_ERROR "Script needs SCRIPT_FOLDER defined (tip: use -DSCRIPT_FOLDER=..)")
|
||||
endif()
|
||||
if(NOT OPENTTD_EXECUTABLE)
|
||||
message(FATAL_ERROR "Script needs OPENTTD_EXECUTABLE defined (tip: use -DOPENTTD_EXECUTABLE=..)")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS ai/${REGRESSION_TEST}/test.sav)
|
||||
if(NOT EXISTS ${SCRIPT_FOLDER}/${REGRESSION_TEST}/test.sav)
|
||||
message(FATAL_ERROR "Regression test ${REGRESSION_TEST} does not exist (tip: check regression folder for the correct spelling)")
|
||||
endif()
|
||||
|
||||
@@ -35,7 +38,7 @@ endif()
|
||||
execute_process(COMMAND ${OPENTTD_EXECUTABLE}
|
||||
-x
|
||||
-c regression/regression.cfg
|
||||
-g ai/${REGRESSION_TEST}/test.sav
|
||||
-g ${SCRIPT_FOLDER}/${REGRESSION_TEST}/test.sav
|
||||
-snull
|
||||
-mnull
|
||||
-vnull:ticks=30000
|
||||
@@ -77,7 +80,7 @@ string(REGEX REPLACE "\\\[script:[0-9]\\\]" "" REGRESSION_RESULT "${REGRESSION_R
|
||||
|
||||
# Convert the output to a format that is expected (and more readable) by result.txt
|
||||
string(REPLACE "dbg: " "ERROR: " REGRESSION_RESULT "${REGRESSION_RESULT}")
|
||||
string(REPLACE "ERROR: [1] " "" REGRESSION_RESULT "${REGRESSION_RESULT}")
|
||||
string(REGEX REPLACE "ERROR: \\\[18?\\\] " "" REGRESSION_RESULT "${REGRESSION_RESULT}")
|
||||
string(REPLACE "[P] " "" REGRESSION_RESULT "${REGRESSION_RESULT}")
|
||||
string(REPLACE "[S] " "" REGRESSION_RESULT "${REGRESSION_RESULT}")
|
||||
string(REGEX REPLACE "dbg: ([^\n]*)\n?" "" REGRESSION_RESULT "${REGRESSION_RESULT}")
|
||||
@@ -88,7 +91,7 @@ string(REGEX REPLACE "ERROR: [12]([^\n]*)\n?" "" REGRESSION_RESULT "${REGRESSI
|
||||
string(REGEX REPLACE "ERROR: The first([^\n]*)\n?" "" REGRESSION_RESULT "${REGRESSION_RESULT}")
|
||||
|
||||
# Read the expected result
|
||||
file(READ ai/${REGRESSION_TEST}/result.txt REGRESSION_EXPECTED)
|
||||
file(READ ${SCRIPT_FOLDER}/${REGRESSION_TEST}/result.txt REGRESSION_EXPECTED)
|
||||
|
||||
# Convert the string to a list
|
||||
string(REPLACE "\n" ";" REGRESSION_RESULT "${REGRESSION_RESULT}")
|
||||
|
||||
@@ -215,6 +215,10 @@ foreach(LINE IN LISTS SOURCE_LINES)
|
||||
continue()
|
||||
endif()
|
||||
|
||||
if("${LINE}" MATCHES "^([\t ]*)\\* @suspendable.*$")
|
||||
set(SUSPENDABLE TRUE)
|
||||
endif()
|
||||
|
||||
# Ignore the comments
|
||||
if("${LINE}" MATCHES "^#")
|
||||
continue()
|
||||
@@ -258,7 +262,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
|
||||
endif()
|
||||
|
||||
# We need to make specialized conversions for enums
|
||||
if("${LINE}" MATCHES "^(\t*)enum ([^ ]*)")
|
||||
if("${LINE}" MATCHES "^(\t*)enum *(class)? *([^ ]*)")
|
||||
math(EXPR CLS_LEVEL "${CLS_LEVEL} + 1")
|
||||
|
||||
# Check if we want to publish this enum
|
||||
@@ -276,7 +280,10 @@ foreach(LINE IN LISTS SOURCE_LINES)
|
||||
endif()
|
||||
|
||||
set(IN_ENUM TRUE)
|
||||
list(APPEND ENUMS "${CLS}::${CMAKE_MATCH_2}")
|
||||
if(CMAKE_MATCH_2 STREQUAL "class")
|
||||
set(IN_SCOPED_ENUM TRUE)
|
||||
endif()
|
||||
list(APPEND ENUMS "${CLS}::${CMAKE_MATCH_3}")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
@@ -285,6 +292,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
|
||||
math(EXPR CLS_LEVEL "${CLS_LEVEL} - 1")
|
||||
if(CLS_LEVEL)
|
||||
unset(IN_ENUM)
|
||||
unset(IN_SCOPED_ENUM)
|
||||
continue()
|
||||
endif()
|
||||
|
||||
@@ -361,168 +369,86 @@ foreach(LINE IN LISTS SOURCE_LINES)
|
||||
string(APPEND SQUIRREL_EXPORT "\n")
|
||||
|
||||
# Enum values
|
||||
set(MLEN 0)
|
||||
foreach(ENUM_VALUE IN LISTS ENUM_VALUES)
|
||||
string(LENGTH "${ENUM_VALUE}" LEN)
|
||||
if(MLEN LESS LEN)
|
||||
set(MLEN ${LEN})
|
||||
|
||||
macro(add_scoped_enum_end_if_needed)
|
||||
if(CURRENT_ENUM_NAME)
|
||||
unset(CURRENT_ENUM_NAME)
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.AddScopedEnumEnd(engine);\n")
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
set(CURRENT_ENUM_NAME 0)
|
||||
foreach(ENUM_VALUE IN LISTS ENUM_VALUES)
|
||||
string(LENGTH "${ENUM_VALUE}" LEN)
|
||||
math(EXPR LEN "${MLEN} - ${LEN}")
|
||||
unset(SPACES)
|
||||
foreach(i RANGE ${LEN})
|
||||
string(APPEND SPACES " ")
|
||||
endforeach()
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQConst(engine, ${CLS}::${ENUM_VALUE},${SPACES}\"${ENUM_VALUE}\");")
|
||||
if(ENUM_VALUE MATCHES "::")
|
||||
string(REGEX REPLACE ".*:" "" ENUM_VALUE_NAME "${ENUM_VALUE}")
|
||||
string(REGEX MATCH "::(.*)::" ENUM_NAME "${ENUM_VALUE}")
|
||||
set(ENUM_NAME ${CMAKE_MATCH_1})
|
||||
if(CURRENT_ENUM_NAME STREQUAL ENUM_NAME)
|
||||
else()
|
||||
add_scoped_enum_end_if_needed()
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.AddScopedEnumBegin(engine, \"${ENUM_NAME}\");")
|
||||
set(CURRENT_ENUM_NAME ${ENUM_NAME})
|
||||
endif()
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQConst(engine, to_underlying(${ENUM_VALUE}), \"${ENUM_VALUE_NAME}\");")
|
||||
continue()
|
||||
endif()
|
||||
add_scoped_enum_end_if_needed()
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQConst(engine, ${CLS}::${ENUM_VALUE}, \"${ENUM_VALUE}\");")
|
||||
endforeach()
|
||||
if(MLEN)
|
||||
string(APPEND SQUIRREL_EXPORT "\n")
|
||||
endif()
|
||||
add_scoped_enum_end_if_needed()
|
||||
|
||||
# Const values
|
||||
set(MLEN 0)
|
||||
foreach(CONST_VALUE IN LISTS CONST_VALUES)
|
||||
string(LENGTH "${CONST_VALUE}" LEN)
|
||||
if(MLEN LESS LEN)
|
||||
set(MLEN ${LEN})
|
||||
endif()
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQConst(engine, ${CLS}::${CONST_VALUE}, \"${CONST_VALUE}\");")
|
||||
endforeach()
|
||||
foreach(CONST_VALUE IN LISTS CONST_VALUES)
|
||||
string(LENGTH "${CONST_VALUE}" LEN)
|
||||
math(EXPR LEN "${MLEN} - ${LEN}")
|
||||
unset(SPACES)
|
||||
foreach(i RANGE ${LEN})
|
||||
string(APPEND SPACES " ")
|
||||
endforeach()
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQConst(engine, ${CLS}::${CONST_VALUE},${SPACES}\"${CONST_VALUE}\");")
|
||||
endforeach()
|
||||
if(MLEN)
|
||||
string(APPEND SQUIRREL_EXPORT "\n")
|
||||
endif()
|
||||
|
||||
# Mapping of OTTD strings to errors
|
||||
set(MLEN 0)
|
||||
foreach(ENUM_STRING_TO_ERROR IN LISTS ENUM_STRING_TO_ERRORS)
|
||||
string(REPLACE ":" ";" ENUM_STRING_TO_ERROR "${ENUM_STRING_TO_ERROR}")
|
||||
list(GET ENUM_STRING_TO_ERROR 0 ENUM_STRING)
|
||||
string(LENGTH "${ENUM_STRING}" LEN)
|
||||
if(MLEN LESS LEN)
|
||||
set(MLEN ${LEN})
|
||||
endif()
|
||||
endforeach()
|
||||
foreach(ENUM_STRING_TO_ERROR IN LISTS ENUM_STRING_TO_ERRORS)
|
||||
string(REPLACE ":" ";" ENUM_STRING_TO_ERROR "${ENUM_STRING_TO_ERROR}")
|
||||
list(GET ENUM_STRING_TO_ERROR 0 ENUM_STRING)
|
||||
list(GET ENUM_STRING_TO_ERROR 1 ENUM_ERROR)
|
||||
string(LENGTH "${ENUM_STRING}" LEN)
|
||||
math(EXPR LEN "${MLEN} - ${LEN}")
|
||||
unset(SPACES)
|
||||
foreach(i RANGE ${LEN})
|
||||
string(APPEND SPACES " ")
|
||||
endforeach()
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tScriptError::RegisterErrorMap(${ENUM_STRING},${SPACES}${CLS}::${ENUM_ERROR});")
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tScriptError::RegisterErrorMap(${ENUM_STRING}, ${CLS}::${ENUM_ERROR});")
|
||||
endforeach()
|
||||
if(MLEN)
|
||||
string(APPEND SQUIRREL_EXPORT "\n")
|
||||
endif()
|
||||
|
||||
# Mapping of errors to human 'readable' strings.
|
||||
set(MLEN 0)
|
||||
foreach(ENUM_ERROR_TO_STRING IN LISTS ENUM_ERROR_TO_STRINGS)
|
||||
string(LENGTH "${ENUM_ERROR_TO_STRING}" LEN)
|
||||
if(MLEN LESS LEN)
|
||||
set(MLEN ${LEN})
|
||||
endif()
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tScriptError::RegisterErrorMapString(${CLS}::${ENUM_ERROR_TO_STRING}, \"${ENUM_ERROR_TO_STRING}\");")
|
||||
endforeach()
|
||||
foreach(ENUM_ERROR_TO_STRING IN LISTS ENUM_ERROR_TO_STRINGS)
|
||||
string(LENGTH "${ENUM_ERROR_TO_STRING}" LEN)
|
||||
math(EXPR LEN "${MLEN} - ${LEN}")
|
||||
unset(SPACES)
|
||||
foreach(i RANGE ${LEN})
|
||||
string(APPEND SPACES " ")
|
||||
endforeach()
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tScriptError::RegisterErrorMapString(${CLS}::${ENUM_ERROR_TO_STRING},${SPACES}\"${ENUM_ERROR_TO_STRING}\");")
|
||||
endforeach()
|
||||
if(MLEN)
|
||||
string(APPEND SQUIRREL_EXPORT "\n")
|
||||
endif()
|
||||
|
||||
# Static methods
|
||||
set(MLEN 0)
|
||||
foreach(STATIC_METHOD IN LISTS STATIC_METHODS)
|
||||
string(REPLACE ":" ";" STATIC_METHOD "${STATIC_METHOD}")
|
||||
list(GET STATIC_METHOD 0 FUNCNAME)
|
||||
string(LENGTH "${FUNCNAME}" LEN)
|
||||
if(MLEN LESS LEN)
|
||||
set(MLEN ${LEN})
|
||||
endif()
|
||||
endforeach()
|
||||
foreach(STATIC_METHOD IN LISTS STATIC_METHODS)
|
||||
string(REPLACE ":" ";" STATIC_METHOD "${STATIC_METHOD}")
|
||||
list(GET STATIC_METHOD 0 FUNCNAME)
|
||||
list(GET STATIC_METHOD 1 TYPES)
|
||||
string(LENGTH "${FUNCNAME}" LEN)
|
||||
math(EXPR LEN "${MLEN} - ${LEN}")
|
||||
if("${TYPES}" STREQUAL "v")
|
||||
if(LEN GREATER 8)
|
||||
math(EXPR LEN "${LEN} - 8")
|
||||
else()
|
||||
set(LEN 0)
|
||||
endif()
|
||||
list(GET STATIC_METHOD 2 SUSPENDABLE)
|
||||
if(SUSPENDABLE)
|
||||
set(SUSPENDABLE ", true")
|
||||
endif()
|
||||
unset(SPACES)
|
||||
foreach(i RANGE ${LEN})
|
||||
string(APPEND SPACES " ")
|
||||
endforeach()
|
||||
if("${TYPES}" STREQUAL "v")
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQAdvancedStaticMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\");")
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQAdvancedStaticMethod(engine, &${CLS}::${FUNCNAME}, \"${FUNCNAME}\"${SUSPENDABLE});")
|
||||
else()
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQStaticMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\",${SPACES}\"${TYPES}\");")
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQStaticMethod(engine, &${CLS}::${FUNCNAME}, \"${FUNCNAME}\", \"${TYPES}\"${SUSPENDABLE});")
|
||||
endif()
|
||||
endforeach()
|
||||
if(MLEN)
|
||||
string(APPEND SQUIRREL_EXPORT "\n")
|
||||
endif()
|
||||
|
||||
# Non-static methods
|
||||
set(MLEN 0)
|
||||
foreach(METHOD IN LISTS METHODS)
|
||||
string(REPLACE ":" ";" METHOD "${METHOD}")
|
||||
list(GET METHOD 0 FUNCNAME)
|
||||
string(LENGTH "${FUNCNAME}" LEN)
|
||||
if(MLEN LESS LEN)
|
||||
set(MLEN ${LEN})
|
||||
endif()
|
||||
endforeach()
|
||||
foreach(METHOD IN LISTS METHODS)
|
||||
string(REPLACE ":" ";" METHOD "${METHOD}")
|
||||
list(GET METHOD 0 FUNCNAME)
|
||||
list(GET METHOD 1 TYPES)
|
||||
string(LENGTH "${FUNCNAME}" LEN)
|
||||
math(EXPR LEN "${MLEN} - ${LEN}")
|
||||
if("${TYPES}" STREQUAL "v")
|
||||
if(LEN GREATER 8)
|
||||
math(EXPR LEN "${LEN} - 8")
|
||||
else()
|
||||
set(LEN 0)
|
||||
endif()
|
||||
list(GET METHOD 2 SUSPENDABLE)
|
||||
if(SUSPENDABLE)
|
||||
set(SUSPENDABLE ", true")
|
||||
endif()
|
||||
unset(SPACES)
|
||||
foreach(i RANGE ${LEN})
|
||||
string(APPEND SPACES " ")
|
||||
endforeach()
|
||||
if("${TYPES}" STREQUAL "v")
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQAdvancedMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\");")
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQAdvancedMethod(engine, &${CLS}::${FUNCNAME}, \"${FUNCNAME}\"${SUSPENDABLE});")
|
||||
else()
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQMethod(engine, &${CLS}::${FUNCNAME},${SPACES}\"${FUNCNAME}\",${SPACES}\"${TYPES}\");")
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.DefSQMethod(engine, &${CLS}::${FUNCNAME}, \"${FUNCNAME}\", \"${TYPES}\"${SUSPENDABLE});")
|
||||
endif()
|
||||
endforeach()
|
||||
if(MLEN)
|
||||
string(APPEND SQUIRREL_EXPORT "\n")
|
||||
endif()
|
||||
|
||||
string(APPEND SQUIRREL_EXPORT "\n")
|
||||
string(APPEND SQUIRREL_EXPORT "\n\tSQ${API_CLS}.PostRegister(engine);")
|
||||
string(APPEND SQUIRREL_EXPORT "\n}")
|
||||
|
||||
@@ -542,11 +468,16 @@ foreach(LINE IN LISTS SOURCE_LINES)
|
||||
|
||||
# Add enums
|
||||
if(IN_ENUM)
|
||||
string(REGEX MATCH "([^,\t ]+)" ENUM_VALUE "${LINE}")
|
||||
list(APPEND ENUM_VALUES "${ENUM_VALUE}")
|
||||
|
||||
# Check if this a special error enum
|
||||
list(GET ENUMS -1 ENUM)
|
||||
|
||||
string(REGEX MATCH "([^,\t ]+)" ENUM_VALUE "${LINE}")
|
||||
if(IN_SCOPED_ENUM)
|
||||
list(APPEND ENUM_VALUES "${ENUM}::${ENUM_VALUE}")
|
||||
else()
|
||||
list(APPEND ENUM_VALUES "${ENUM_VALUE}")
|
||||
endif()
|
||||
|
||||
if("${ENUM}" MATCHES ".*::ErrorMessages")
|
||||
# syntax:
|
||||
# enum ErrorMessages {
|
||||
@@ -672,10 +603,11 @@ foreach(LINE IN LISTS SOURCE_LINES)
|
||||
set(CLS_TYPES "${TYPES}")
|
||||
elseif("${FUNCNAME}" MATCHES "^_" AND NOT "${TYPES}" STREQUAL "v")
|
||||
elseif(IS_STATIC)
|
||||
list(APPEND STATIC_METHODS "${FUNCNAME}:${TYPES}")
|
||||
list(APPEND STATIC_METHODS "${FUNCNAME}:${TYPES}:${SUSPENDABLE}")
|
||||
else()
|
||||
list(APPEND METHODS "${FUNCNAME}:${TYPES}")
|
||||
list(APPEND METHODS "${FUNCNAME}:${TYPES}:${SUSPENDABLE}")
|
||||
endif()
|
||||
unset(SUSPENDABLE)
|
||||
continue()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
+66
-66
@@ -38,7 +38,7 @@ Last updated: 2024-03-26
|
||||
packets are dropped in favour of a new packet.
|
||||
|
||||
This though will be reflected in the protocol version as announced in the
|
||||
`ADMIN_PACKET_SERVER_PROTOCOL` in section 2.0).
|
||||
`PacketAdminType::ServerProtocol` in section 2.0).
|
||||
|
||||
A reference implementation in Java for a client connecting to the admin interface
|
||||
can be found at: [http://dev.openttdcoop.org/projects/joan](http://dev.openttdcoop.org/projects/joan)
|
||||
@@ -49,18 +49,18 @@ Last updated: 2024-03-26
|
||||
Create a TCP connection to the server on port 3977. The application is
|
||||
expected to authenticate within 10 seconds.
|
||||
|
||||
To authenticate send either an `ADMIN_PACKET_ADMIN_JOIN` or an
|
||||
`ADMIN_PACKET_ADMIN_JOIN_SECURE` packet.
|
||||
To authenticate send either an `PacketAdminType::AdminJoin` or an
|
||||
`PacketAdminType::AdminJoinSecure` packet.
|
||||
|
||||
The `ADMIN_PACKET_ADMIN_JOIN` packet sends the password without any
|
||||
The `PacketAdminType::AdminJoin` packet sends the password without any
|
||||
encryption or safeguards over the connection, and as such has been disabled
|
||||
by default.
|
||||
|
||||
The `ADMIN_PACKET_ADMIN_JOIN_SECURE` packet initiates a key exchange
|
||||
The `PacketAdminType::AdminJoinSecure` packet initiates a key exchange
|
||||
authentication schema which tells te server which methods the client
|
||||
supports and the server makes a choice. The server will then send an
|
||||
`ADMIN_PACKET_SERVER_AUTH_REQUEST` packet to which the client has to respond
|
||||
with an `ADMIN_PACKET_ADMIN_AUTH_RESPONSE` packet.
|
||||
`PacketAdminType::ServerAuthenticationRequest` packet to which the client has to respond
|
||||
with an `PacketAdminType::AdminAuthenticationResponse` packet.
|
||||
|
||||
The current choices for secure authentication are authorized keys, where
|
||||
the client has a private key and the server a list of authorized public
|
||||
@@ -69,41 +69,41 @@ Last updated: 2024-03-26
|
||||
The server falls back to password authentication when the client's key is
|
||||
not in the list of authorized keys.
|
||||
|
||||
When authentication has succeeded for either of the `JOIN` schemas, the
|
||||
server will reply with `ADMIN_PACKET_SERVER_PROTOCOL` followed directly
|
||||
by `ADMIN_PACKET_SERVER_WELCOME`.
|
||||
When authentication has succeeded for either of the `AdminJoin` schemas, the
|
||||
server will reply with `PacketAdminType::ServerProtocol` followed directly
|
||||
by `PacketAdminType::ServerWelcome`.
|
||||
|
||||
`ADMIN_PACKET_SERVER_PROTOCOL` contains details about the protocol version.
|
||||
`PacketAdminType::ServerProtocol` contains details about the protocol version.
|
||||
It is the job of your application to check this number and decide whether
|
||||
it will remain connected or not.
|
||||
Furthermore, this packet holds details on every `AdminUpdateType` and the
|
||||
supported `AdminFrequencyTypes` (bitwise representation).
|
||||
|
||||
`ADMIN_PACKET_SERVER_WELCOME` contains details on the server and the map,
|
||||
`PacketAdminType::ServerWelcome` contains details on the server and the map,
|
||||
e.g. if the server is dedicated, its NetworkLanguage, size of the Map, etc.
|
||||
|
||||
Once you have received `ADMIN_PACKET_SERVER_WELCOME` you are connected and
|
||||
Once you have received `PacketAdminType::ServerWelcome` you are connected and
|
||||
authorized to do your thing.
|
||||
|
||||
The server will not provide any game related updates unless you ask for them.
|
||||
There are four packets the server will none the less send, if applicable:
|
||||
|
||||
- ADMIN_PACKET_SERVER_ERROR
|
||||
- ADMIN_PACKET_SERVER_WELCOME
|
||||
- ADMIN_PACKET_SERVER_NEWGAME
|
||||
- ADMIN_PACKET_SERVER_SHUTDOWN
|
||||
- PacketAdminType::ServerError
|
||||
- PacketAdminType::ServerWelcome
|
||||
- PacketAdminType::ServerNewGame
|
||||
- PacketAdminType::ServerShutdown
|
||||
|
||||
However, `ADMIN_PACKET_SERVER_WELCOME` only after a `ADMIN_PACKET_SERVER_NEWGAME`
|
||||
However, `PacketAdminType::ServerWelcome` only after a `PacketAdminType::ServerNewGame`
|
||||
|
||||
|
||||
## 3.0) Asking for updates
|
||||
|
||||
Asking for updates is done with `ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY`.
|
||||
Asking for updates is done with `PacketAdminType::AdminUpdateFrequency`.
|
||||
With this packet you define which update you wish to receive at which
|
||||
frequency.
|
||||
|
||||
Note: not every update type supports every frequency. If in doubt, you can
|
||||
verify against the data received in `ADMIN_PACKET_SERVER_PROTOCOL`.
|
||||
verify against the data received in `PacketAdminType::ServerProtocol`.
|
||||
|
||||
Please note the potential gotcha in the "Certain packet information" section below
|
||||
when using the `ADMIN_UPDATE_FREQUENCY` packet.
|
||||
@@ -114,61 +114,61 @@ Last updated: 2024-03-26
|
||||
|
||||
Additional debug information can be found with a debug level of `net=3`.
|
||||
|
||||
`ADMIN_UPDATE_DATE` results in the server sending:
|
||||
`AdminUpdateType::Date` results in the server sending:
|
||||
|
||||
- ADMIN_PACKET_SERVER_DATE
|
||||
- PacketAdminType::ServerDate
|
||||
|
||||
`ADMIN_UPDATE_CLIENT_INFO` results in the server sending:
|
||||
`AdminUpdateType::ClientInfo` results in the server sending:
|
||||
|
||||
- ADMIN_PACKET_SERVER_CLIENT_JOIN
|
||||
- ADMIN_PACKET_SERVER_CLIENT_INFO
|
||||
- ADMIN_PACKET_SERVER_CLIENT_UPDATE
|
||||
- ADMIN_PACKET_SERVER_CLIENT_QUIT
|
||||
- ADMIN_PACKET_SERVER_CLIENT_ERROR
|
||||
- PacketAdminType::ServerClientJoin
|
||||
- PacketAdminType::ServerClientInfo
|
||||
- PacketAdminType::ServerClientUpdate
|
||||
- PacketAdminType::ServerClientQuit
|
||||
- PacketAdminType::ServerClientError
|
||||
|
||||
`ADMIN_UPDATE_COMPANY_INFO` results in the server sending:
|
||||
`AdminUpdateType::CompanyInfo` results in the server sending:
|
||||
|
||||
- ADMIN_PACKET_SERVER_COMPANY_NEW
|
||||
- ADMIN_PACKET_SERVER_COMPANY_INFO
|
||||
- ADMIN_PACKET_SERVER_COMPANY_UPDATE
|
||||
- ADMIN_PACKET_SERVER_COMPANY_REMOVE
|
||||
- PacketAdminType::ServerCompanyNew
|
||||
- PacketAdminType::ServerCompanyInfo
|
||||
- PacketAdminType::ServerCompanyUpdate
|
||||
- PacketAdminType::ServerCompanyRemove
|
||||
|
||||
`ADMIN_UPDATE_COMPANY_ECONOMY` results in the server sending:
|
||||
`AdminUpdateType::CompanyEconomy` results in the server sending:
|
||||
|
||||
- ADMIN_PACKET_SERVER_COMPANY_ECONOMY
|
||||
- PacketAdminType::ServerCompanyEconomy
|
||||
|
||||
`ADMIN_UPDATE_COMPANY_STATS` results in the server sending:
|
||||
`AdminUpdateType::CompanyStats` results in the server sending:
|
||||
|
||||
- ADMIN_PACKET_SERVER_COMPANY_STATS
|
||||
- PacketAdminType::ServerCompanyStatistics
|
||||
|
||||
`ADMIN_UPDATE_CHAT` results in the server sending:
|
||||
`AdminUpdateType::Chat` results in the server sending:
|
||||
|
||||
- ADMIN_PACKET_SERVER_CHAT
|
||||
- PacketAdminType::ServerChat
|
||||
|
||||
`ADMIN_UPDATE_CONSOLE` results in the server sending:
|
||||
`AdminUpdateType::Console` results in the server sending:
|
||||
|
||||
- ADMIN_PACKET_SERVER_CONSOLE
|
||||
- PacketAdminType::ServerConsole
|
||||
|
||||
|
||||
`ADMIN_UPDATE_CMD_LOGGING` results in the server sending:
|
||||
`AdminUpdateType::CmdLogging` results in the server sending:
|
||||
|
||||
- ADMIN_PACKET_SERVER_CMD_LOGGING
|
||||
- PacketAdminType::ServerCommandLogging
|
||||
|
||||
## 3.1) Polling manually
|
||||
|
||||
Certain `AdminUpdateTypes` can also be polled:
|
||||
|
||||
- ADMIN_UPDATE_DATE
|
||||
- ADMIN_UPDATE_CLIENT_INFO
|
||||
- ADMIN_UPDATE_COMPANY_INFO
|
||||
- ADMIN_UPDATE_COMPANY_ECONOMY
|
||||
- ADMIN_UPDATE_COMPANY_STATS
|
||||
- ADMIN_UPDATE_CMD_NAMES
|
||||
- AdminUpdateType::Date
|
||||
- AdminUpdateType::ClientInfo
|
||||
- AdminUpdateType::CompanyInfo
|
||||
- AdminUpdateType::CompanyEconomy
|
||||
- AdminUpdateType::CompanyStats
|
||||
- AdminUpdateType::CmdNames
|
||||
|
||||
Please note the potential gotcha in the "Certain packet information" section below
|
||||
when using the `ADMIN_POLL` packet.
|
||||
|
||||
`ADMIN_UPDATE_CLIENT_INFO` and `ADMIN_UPDATE_COMPANY_INFO` accept an additional
|
||||
`AdminUpdateType::ClientInfo` and `AdminUpdateType::CompanyInfo` accept an additional
|
||||
parameter. This parameter is used to specify a certain client or company.
|
||||
Setting this parameter to `UINT32_MAX (0xFFFFFFFF)` will tell the server you
|
||||
want to receive updates for all clients or companies.
|
||||
@@ -181,16 +181,16 @@ Last updated: 2024-03-26
|
||||
|
||||
## 4.0) Sending rcon commands
|
||||
|
||||
Rcon runs separate from the `ADMIN_UPDATE_CONSOLE` `AdminUpdateType`. Requesting
|
||||
Rcon runs separate from the `AdminUpdateType::Console` `AdminUpdateType`. Requesting
|
||||
the execution of a remote console command is done with the packet
|
||||
`ADMIN_PACKET_ADMIN_RCON`.
|
||||
`PacketAdminType::AdminRemoteConsoleCommand`.
|
||||
|
||||
Note: No additional authentication is required for rcon commands.
|
||||
|
||||
The server will reply with one or more `ADMIN_PACKET_SERVER_RCON` packets.
|
||||
Finally an `ADMIN_PACKET_ADMIN_RCON_END` packet will be sent. Applications
|
||||
The server will reply with one or more `PacketAdminType::ServerRemoteConsoleCommand` packets.
|
||||
Finally an `PacketAdminType::AdminRemoteConsoleCommandEnd` packet will be sent. Applications
|
||||
will not receive the answer twice if they have asked for the `AdminUpdateType`
|
||||
`ADMIN_UPDATE_CONSOLE`, as the result is not printed on the servers console
|
||||
`AdminUpdateType::Console`, as the result is not printed on the servers console
|
||||
(just like clients rcon commands).
|
||||
|
||||
Furthermore, sending a `say` command (or any similar command) will not
|
||||
@@ -199,7 +199,7 @@ Last updated: 2024-03-26
|
||||
was not sent from the admin network.
|
||||
|
||||
Note that when content is queried or updated via rcon, the processing
|
||||
happens asynchronously. But the `ADMIN_PACKET_ADMIN_RCON_END` packet is sent
|
||||
happens asynchronously. But the `PacketAdminType::AdminRemoteConsoleCommandEnd` packet is sent
|
||||
already right after the content is requested as there's no immediate output.
|
||||
Thus other packages and the output of content rcon command may be sent at
|
||||
an arbitrary later time, mixing into the output of other console activity,
|
||||
@@ -208,7 +208,7 @@ Last updated: 2024-03-26
|
||||
|
||||
## 5.0) Sending chat
|
||||
|
||||
Sending a `ADMIN_PACKET_ADMIN_CHAT` results in chat originating from the server.
|
||||
Sending a `PacketAdminType::AdminChat` results in chat originating from the server.
|
||||
|
||||
Currently four types of chat are supported:
|
||||
|
||||
@@ -223,7 +223,7 @@ Last updated: 2024-03-26
|
||||
|
||||
## 5.1) Receiving chat
|
||||
|
||||
Register `ADMIN_UPDATE_CHAT` at `AdminUpdateFrequency::Automatic` to receive chat.
|
||||
Register `AdminUpdateType::Chat` at `AdminUpdateFrequency::Automatic` to receive chat.
|
||||
The application will be able to receive all chat the server can see.
|
||||
|
||||
The configuration option `network.server_admin_chat` specifies whether
|
||||
@@ -233,12 +233,12 @@ Last updated: 2024-03-26
|
||||
## 6.0) Disconnecting
|
||||
|
||||
It is a kind thing to say good bye before leaving. Do this by sending the
|
||||
`ADMIN_PACKET_ADMIN_QUIT` packet.
|
||||
`PacketAdminType::AdminQuit` packet.
|
||||
|
||||
|
||||
## 7.0) Certain packet information
|
||||
|
||||
`ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY` and `ADMIN_PACKET_ADMIN_POLL`
|
||||
`PacketAdminType::AdminUpdateFrequency` and `PacketAdminType::AdminPoll`
|
||||
|
||||
Potential gotcha: the AdminUpdateType integer type used is a
|
||||
uint16 for `UPDATE_FREQUENCY`, and a uint8 for `POLL`.
|
||||
@@ -246,21 +246,21 @@ Last updated: 2024-03-26
|
||||
It is safe to cast between the two when sending
|
||||
(i.e cast from a uint8 to a uint16).
|
||||
|
||||
All `ADMIN_PACKET_SERVER_*` packets have an enum value greater 100.
|
||||
All `PacketAdminType::Server*` packets have an enum value greater 100.
|
||||
|
||||
`ADMIN_PACKET_SERVER_WELCOME`
|
||||
`PacketAdminType::ServerWelcome`
|
||||
|
||||
Either directly follows `ADMIN_PACKET_SERVER_PROTOCOL` or is sent
|
||||
Either directly follows `PacketAdminType::ServerProtocol` or is sent
|
||||
after a new game has been started or a map loaded, i.e. also
|
||||
after ADMIN_PACKET_SERVER_NEWGAME.
|
||||
after PacketAdminType::ServerNewGame.
|
||||
|
||||
`ADMIN_PACKET_SERVER_CLIENT_JOIN` and `ADMIN_PACKET_SERVER_COMPANY_NEW`
|
||||
`PacketAdminType::ServerClientJoin` and `PacketAdminType::ServerCompanyNew`
|
||||
|
||||
These packets directly follow their respective INFO packets. If you receive
|
||||
a CLIENT_JOIN / COMPANY_NEW packet without having received the INFO packet
|
||||
it may be a good idea to POLL for the specific ID.
|
||||
|
||||
`ADMIN_PACKET_SERVER_CMD_NAMES` and `ADMIN_PACKET_SERVER_CMD_LOGGING`
|
||||
`PacketAdminType::ServerCommandNames` and `PacketAdminType::ServerCommandLogging`
|
||||
|
||||
Data provided with these packets is not stable and will not be
|
||||
treated as such. Do not rely on IDs or names to be constant
|
||||
|
||||
@@ -38,6 +38,17 @@ your operating system:
|
||||
|
||||
It includes the OpenTTD files (grf+lng) and it will work as long as they
|
||||
are not touched
|
||||
7. The Atari Transport Tycoon Deluxe directory, if installed (path may vary)
|
||||
|
||||
This refers to the `CD` folder within the Transport Tycoon Deluxe
|
||||
installation folder (2026 Atari re-release). OpenTTD detects the presence
|
||||
of this folder based upon the contents of the `installpath.ini` file located
|
||||
in:
|
||||
- Windows: `%APPDATA%\Atari\Transport Tycoon Deluxe`
|
||||
- macOS: `~/Library/Application Support/Atari/Transport Tycoon Deluxe`
|
||||
- Linux: `$XDG_DATA_HOME/Atari/Transport Tycoon Deluxe`
|
||||
|
||||
This is used only for the loading of base sets (graphics, sound, music).
|
||||
|
||||
Different types of data or extensions go into different subdirectories of the
|
||||
chosen main OpenTTD directory:
|
||||
|
||||
+98
-94
@@ -16,7 +16,7 @@
|
||||
<a href="landscape_grid.html">Landscape grid</a> page.
|
||||
</p>
|
||||
<p>Nine attributes (counting "<span style="font-weight: bold;">type</span>" and
|
||||
"<span style="font-weight: bold;">height</span>") hold the information about a tile.<BR>
|
||||
"<span style="font-weight: bold;">height</span>") hold the information about a tile.<br>
|
||||
These attributes are referred to as
|
||||
"<span style="font-weight: bold;">type</span>",
|
||||
"<span style="font-weight: bold;">height</span>",
|
||||
@@ -50,6 +50,7 @@
|
||||
<tr><td><tt>0A</tt></td><td>Objects</td></tr>
|
||||
</table>
|
||||
</li>
|
||||
<li>
|
||||
Bits 3..2:
|
||||
<table border="1" style="width: 30em;">
|
||||
<tr bgcolor="#CCCCCC"><td colspan="2">Presence and direction of bridge above.</td></tr>
|
||||
@@ -57,6 +58,7 @@
|
||||
<tr><td><tt>01</tt></td><td>Axis X (North-East)</td></tr>
|
||||
<tr><td><tt>02</tt></td><td>Axis Y (South-West)</td></tr>
|
||||
</table>
|
||||
</li>
|
||||
<li>
|
||||
<a name="tropic_zone"></a>
|
||||
Bits 1..0:
|
||||
@@ -69,13 +71,14 @@
|
||||
In any other climate these 2 bits are theoretically free of use, however using them does not seem useful.
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><span style="font-weight: bold;">m1</span>
|
||||
<ul>
|
||||
<li>
|
||||
<a name="WaterClass"></a>
|
||||
Bits 6..5:
|
||||
<table border="1" style="width: 30em;">
|
||||
<tr bgcolor="#CCCCCC"><td colspan="2">The type of water that is on a tile.
|
||||
<tr bgcolor="#CCCCCC"><td colspan="2">The type of water that is on a tile.</td></tr>
|
||||
<tr><td style="width: 5em;"><tt>00</tt></td><td align=left>Sea</td></tr>
|
||||
<tr><td><tt>01</tt></td><td align=left>Canal</td></tr>
|
||||
<tr><td><tt>02</tt></td><td align=left>River</td></tr>
|
||||
@@ -87,7 +90,7 @@
|
||||
<a name="OwnershipInfo"></a>
|
||||
Bits 4..0:
|
||||
<table border="1" style="width: 30em;">
|
||||
<tr bgcolor="#CCCCCC"><td colspan="2">The owner of a tile can be either companies (human or AI) or "Game entities".
|
||||
<tr bgcolor="#CCCCCC"><td colspan="2">The owner of a tile can be either companies (human or AI) or "Game entities".</td></tr>
|
||||
<tr><td style="width: 5em;"><tt>00..0E</tt></td><td align=left>Normal companies</td></tr>
|
||||
<tr><td><tt>0F</tt></td><td align=left>a town owns the tile</td></tr>
|
||||
<tr><td><tt>10</tt></td><td align=left>nobody owns the tile</td></tr>
|
||||
@@ -152,8 +155,8 @@
|
||||
<li>m4 bits 7..5: type of hedge on the SW border of the tile (1 through 6, or 0=none)</li>
|
||||
<li>m4 bits 4..2: same as 7..5, but for the SE border</li>
|
||||
<li>m5 bits 7..5: update counter, incremented on every periodic processing for tile types,
|
||||
other than <tt>03</tt>, <tt>07</tt>, <tt>0B</tt>, <tt>10</tt> and above.<BR>
|
||||
on wraparound, the tile is updated (for fields, the type of fields in m3 is increased, for other types the tile type in m5 is increased).<BR>
|
||||
other than <tt>03</tt>, <tt>07</tt>, <tt>0B</tt>, <tt>10</tt> and above.<br>
|
||||
on wraparound, the tile is updated (for fields, the type of fields in m3 is increased, for other types the tile type in m5 is increased).<br>
|
||||
For snow and desert, these bits are not used, tile is updated on every periodic processing.</li>
|
||||
<li>m5 bits 4..2: tile type:
|
||||
<table>
|
||||
@@ -390,7 +393,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li>m5 bit 6 set = with signals:<BR>
|
||||
<li>m5 bit 6 set = with signals:<br>
|
||||
There are at most 4 signals on a tile. The signals 0..3 belong to the directions:
|
||||
<table>
|
||||
<tr>
|
||||
@@ -562,7 +565,7 @@
|
||||
<td>
|
||||
<ul>
|
||||
<li>m2: Index into the array of towns (owning town for town roads; closest town otherwise, INVALID_TOWN if there is no town or we are creating a town)</li>
|
||||
<li>m3 bits 7..4: <a href="#OwnershipInfo">owner</a> of road type 1 (tram); OWNER_NONE (<tt>10</tt>) is stored as OWNER_TOWN (<tt>0F</tt>)
|
||||
<li>m3 bits 7..4: <a href="#OwnershipInfo">owner</a> of road type 1 (tram); OWNER_NONE (<tt>10</tt>) is stored as OWNER_TOWN (<tt>0F</tt>)</li>
|
||||
<li>m4 bits 5..0: <a href="#RoadType">Roadtype</a></li>
|
||||
<li>m7 bit 5 set = on snow or desert</li>
|
||||
<li>m8 bits 11..6: <a href="#TramType">Tramtype</a></li>
|
||||
@@ -721,6 +724,7 @@
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>m3 bit 6 : free</li>
|
||||
<li>m3 bit 5 : The house is protected from the town upgrading it</li>
|
||||
<li>m3 bits 4..0 : triggers activated <a href="#newhouses">(newhouses)</a></li>
|
||||
@@ -1050,97 +1054,96 @@
|
||||
<td>
|
||||
<ul>
|
||||
<li>m1 bit 7: Ship docking tile status</li>
|
||||
<li>m1 bits 6..5 : Water class (sea, canal or river)
|
||||
<li>m1 bits 6..5 : Water class (sea, canal or river)</li>
|
||||
<li>m1 bits 4..0: <a href="#OwnershipInfo">owner</a> (for sea, rivers, and coasts normally <tt>11</tt>)</li>
|
||||
<li>m2: Depot index (for depots only)</li>
|
||||
<li>m3 bit 0: Non-flooding state</li>
|
||||
<li>m4: Random data for canal or river tiles</li>
|
||||
<li>m5 bits 7..4: Water tile type:
|
||||
<table>
|
||||
<tr>
|
||||
<td><tt>0</tt> </td>
|
||||
<td>water, canal or river</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>1</tt> </td>
|
||||
<td>coast or riverbank</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td nowrap valign=top><tt>2</tt> </td>
|
||||
<td>canal lock<br>
|
||||
<ul>
|
||||
<li>m5 bits 3..2: Lock part
|
||||
<table>
|
||||
<tr>
|
||||
<td><tt>0</tt> </td>
|
||||
<td>Middle part</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>1</tt> </td>
|
||||
<td>Lower part</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>2</tt> </td>
|
||||
<td>Upper part</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li>m5 bits 1..0: Lock direction
|
||||
<table>
|
||||
<tr>
|
||||
<td><tt>0</tt> </td>
|
||||
<td>NE raised</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>1</tt> </td>
|
||||
<td>SE raised</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>2</tt> </td>
|
||||
<td>SW raised</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>3</tt> </td>
|
||||
<td>NW raised</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td nowrap valign=top><tt>3</tt> </td>
|
||||
<td>depot<br>
|
||||
<ul>
|
||||
<li>m5 bit 1: Depot axis
|
||||
<table>
|
||||
<tr>
|
||||
<td><tt>0</tt> </td>
|
||||
<td>X direction (NE-SW)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>1</tt> </td>
|
||||
<td>Y direction (NW-SE)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li>m5 bit 0: Depot part
|
||||
<table>
|
||||
<tr>
|
||||
<td><tt>0</tt> </td>
|
||||
<td>North part</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>1</tt> </td>
|
||||
<td>South part</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<tr>
|
||||
<td><tt>0</tt> </td>
|
||||
<td>water, canal or river</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>1</tt> </td>
|
||||
<td>coast or riverbank</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td nowrap valign=top><tt>2</tt> </td>
|
||||
<td>canal lock<br>
|
||||
<ul>
|
||||
<li>m5 bits 3..2: Lock part
|
||||
<table>
|
||||
<tr>
|
||||
<td><tt>0</tt> </td>
|
||||
<td>Middle part</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>1</tt> </td>
|
||||
<td>Lower part</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>2</tt> </td>
|
||||
<td>Upper part</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li>m5 bits 1..0: Lock direction
|
||||
<table>
|
||||
<tr>
|
||||
<td><tt>0</tt> </td>
|
||||
<td>NE raised</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>1</tt> </td>
|
||||
<td>SE raised</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>2</tt> </td>
|
||||
<td>SW raised</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>3</tt> </td>
|
||||
<td>NW raised</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td nowrap valign=top><tt>3</tt> </td>
|
||||
<td>depot<br>
|
||||
<ul>
|
||||
<li>m5 bit 1: Depot axis
|
||||
<table>
|
||||
<tr>
|
||||
<td><tt>0</tt> </td>
|
||||
<td>X direction (NE-SW)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>1</tt> </td>
|
||||
<td>Y direction (NW-SE)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li>m5 bit 0: Depot part
|
||||
<table>
|
||||
<tr>
|
||||
<td><tt>0</tt> </td>
|
||||
<td>North part</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>1</tt> </td>
|
||||
<td>South part</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
@@ -1167,7 +1170,7 @@
|
||||
<ul>
|
||||
<li>m1 bit 7: clear = under construction
|
||||
<ul>
|
||||
<li>m1 bits 6..5 : Water class (sea, canal, river or land)
|
||||
<li>m1 bits 6..5 : Water class (sea, canal, river or land)</li>
|
||||
<li>m1 bits 3..2: construction counter, for buildings under construction incremented on every periodic tile processing</li>
|
||||
<li>m1 bits 1..0: stage of construction (<tt>3</tt> = completed), incremented when the construction counter wraps around<br>
|
||||
the meaning is different for some animated tiles which are never under construction (types <tt>01</tt>, <tt>1E</tt>..<tt>20</tt>, <tt>30</tt>, <tt>58</tt>; see above)</li>
|
||||
@@ -1323,7 +1326,8 @@
|
||||
<td nowrap valign=top><tt>58</tt> </td>
|
||||
<td align=left>wheel tower when animated; animation state in m7 bits 5..0; m7 bit 6 set = sound already generated</td>
|
||||
</tr>
|
||||
</table></td>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
@@ -92,7 +92,7 @@ the array so you can quickly see what is used and what is not.
|
||||
<tr>
|
||||
<td class="caption">farmland</td>
|
||||
<td class="bits"><span class="pool" title="Industry index on pool">XXXX XXXX XXXX XXXX</span></td>
|
||||
<td class="bits"><span class="used" title="Type of hedge on NE border">XXX</span> <span class="used" title="Field production stage">XXXXX</span></td>
|
||||
<td class="bits"><span class="used" title="Type of hedge on NE border">XXX</span> <span class="used" title="Snow presence">X</span><span class="used" title="Field production stage">XXXX</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan=3>1</td>
|
||||
@@ -165,14 +165,14 @@ the array so you can quickly see what is used and what is not.
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="caption">house under construction</td>
|
||||
<td class="bits"><span class="used" title="House is complete/in construction (see m5)">O</span><span class="used" title="House type (m4 + m3[6])">X</span><span class="used" title="The house is protected from the town upgrading it.">X</span><span class="usable" title="Activated triggers (bits 2..4 don't have a meaning)">X XX</span><span class="used" title="Activated triggers (bits 2..4 don't have a meaning)">XX</span></td>
|
||||
<td class="bits"><span class="used" title="House is complete/in construction (see m5)">O</span><span class="free">O</span><span class="used" title="The house is protected from the town upgrading it.">X</span><span class="usable" title="Activated triggers (bits 2..4 don't have a meaning)">X XX</span><span class="used" title="Activated triggers (bits 2..4 don't have a meaning)">XX</span></td>
|
||||
<td class="bits"><span class="free">OOO</span><span class="used" title="Construction stage">X X</span><span class="used" title="Construction counter">XXX</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>4</td>
|
||||
<td class="caption">trees</td>
|
||||
<td class="bits"><span class="free">O</span><span class="used" title="Water class">XX</span><span class="usable" title="Owner (always OWNER_NONE)">1 OOOO</span></td>
|
||||
<td class="bits"><span class="free">OOOO OOO</span><span class="used" title="Tree ground">XXX</span> <span class="used" title="Tree density">XX</span> <span class="used" title="Tree counter">XXXX</span></td>
|
||||
<td class="bits"><span class="free">OOOO OOO</span><span class="used" title="Tree ground">XXX</span> <span class="used" title="Tree density">XX</span> <span class="free">OOOO</span></td>
|
||||
<td class="bits"><span class="usable" title="Tree type unused bits">XX</span><span class="used" title="Tree type">XX XXXX</span></td>
|
||||
<td class="bits"><span class="free">OOOO OOOO</span></td>
|
||||
<td class="bits"><span class="used" title="Number of trees on tile (+1)">XX</span><span class="free">OO O</span><span class="used" title="Tree growth">XXX</span></td>
|
||||
|
||||
+16
-16
@@ -69,19 +69,19 @@ An example of a valid tag is `PLYR` when looking at it via ASCII, which contains
|
||||
`[4..4]` - Next follows a byte where the lower 4 bits contain the type.
|
||||
The possible valid types are:
|
||||
|
||||
- `0` - `CH_RIFF` - This chunk is a binary blob.
|
||||
- `1` - `CH_ARRAY` - This chunk is a list of items.
|
||||
- `2` - `CH_SPARSE_ARRAY` - This chunk is a list of items.
|
||||
- `3` - `CH_TABLE` - This chunk is self-describing list of items.
|
||||
- `4` - `CH_SPARSE_TABLE` - This chunk is self-describing list of items.
|
||||
- `0` - `ChunkType::Riff` - This chunk is a binary blob.
|
||||
- `1` - `ChunkType::Array` - This chunk is a list of items.
|
||||
- `2` - `ChunkType::SparseArray` - This chunk is a list of items.
|
||||
- `3` - `ChunkType::Table` - This chunk is self-describing list of items.
|
||||
- `4` - `ChunkType::SparseTable` - This chunk is self-describing list of items.
|
||||
|
||||
Now per type the format is (slightly) different.
|
||||
|
||||
### CH_RIFF
|
||||
### ChunkType::Riff
|
||||
|
||||
(since savegame version 295, this chunk type is only used for MAP-chunks, containing bit-information about each tile on the map)
|
||||
|
||||
A `CH_RIFF` starts with an `uint24` which together with the upper-bits of the type defines the length of the chunk.
|
||||
A `ChunkType::Riff` starts with an `uint24` which together with the upper-bits of the type defines the length of the chunk.
|
||||
In pseudo-code:
|
||||
|
||||
```
|
||||
@@ -94,11 +94,11 @@ if type == 0
|
||||
The next `length` bytes are part of the chunk.
|
||||
What those bytes mean depends on the tag of the chunk; further details per chunk can be found in the source-code.
|
||||
|
||||
### CH_ARRAY / CH_SPARSE_ARRAY
|
||||
### ChunkType::Array / ChunkType::SparseArray
|
||||
|
||||
(this chunk type is deprecated since savegame version 295 and is no longer in use)
|
||||
|
||||
`[0..G1]` - A `CH_ARRAY` / `CH_SPARSE_ARRAY` starts with a `gamma`, indicating the size of the next item plus one.
|
||||
`[0..G1]` - A `ChunkType::Array` / `ChunkType::SparseArray` starts with a `gamma`, indicating the size of the next item plus one.
|
||||
If this size value is zero, it indicates the end of the list.
|
||||
This indicates the full length of the next item minus one.
|
||||
In psuedo-code:
|
||||
@@ -111,21 +111,21 @@ loop
|
||||
read <size> bytes
|
||||
```
|
||||
|
||||
`[]` - For `CH_ARRAY` there is an implicit index.
|
||||
`[]` - For `ChunkType::Array` there is an implicit index.
|
||||
The loop starts at zero, and every iteration adds one to the index.
|
||||
For entries in the game that were not allocated, the `size` will be zero.
|
||||
|
||||
`[G1+1..G2]` - For `CH_SPARSE_ARRAY` there is an explicit index.
|
||||
`[G1+1..G2]` - For `ChunkType::SparseArray` there is an explicit index.
|
||||
The `gamma` following the size indicates the index.
|
||||
|
||||
The content of the item is a binary blob, and similar to `CH_RIFF`, it depends on the tag of the chunk what it means.
|
||||
The content of the item is a binary blob, and similar to `ChunkType::Riff`, it depends on the tag of the chunk what it means.
|
||||
Please check the source-code for further details.
|
||||
|
||||
### CH_TABLE / CH_SPARSE_TABLE
|
||||
### ChunkType::Table / ChunkType::SparseTable
|
||||
|
||||
(this chunk type only exists since savegame version 295)
|
||||
|
||||
Both `CH_TABLE` and `CH_SPARSE_TABLE` are very similar to `CH_ARRAY` / `CH_SPARSE_ARRAY` respectively.
|
||||
Both `ChunkType::Table` and `ChunkType::SparseTable` are very similar to `ChunkType::Array` / `ChunkType::SparseArray` respectively.
|
||||
The only change is that the chunk starts with a header.
|
||||
This header describes the chunk in details; with the header you know the meaning of each byte in the binary blob that follows.
|
||||
|
||||
@@ -168,7 +168,7 @@ struct | substruct3
|
||||
The headers will be, in order: `table`, `substruct1`, `substruct3`, `substruct2`, each ending with a `type` is zero field.
|
||||
|
||||
After reading all the fields of all the headers, there is a list of records.
|
||||
To read this, see `CH_ARRAY` / `CH_SPARSE_ARRAY` for details.
|
||||
To read this, see `ChunkType::Array` / `ChunkType::SparseArray` for details.
|
||||
|
||||
As each `type` has a well defined length, you can read the records even without knowing anything about the chunk-tag yourself.
|
||||
|
||||
@@ -187,7 +187,7 @@ The prefix is strongly advised to avoid conflicts with future-settings in an unp
|
||||
|
||||
## Scripts custom data format
|
||||
|
||||
Script chunks (`AIPL` and `GSDT`) use `CH_TABLE` chunk type.
|
||||
Script chunks (`AIPL` and `GSDT`) use `ChunkType::Table` chunk type.
|
||||
|
||||
At the end of each record there's an `uint8` to indicate if there's custom data (1) or not (0).
|
||||
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
# If you change this version, change the numbers in .github/workflows/ci-emscripten.yml (2x)
|
||||
# and .github/workflows/preview-build.yml (2x) too.
|
||||
FROM emscripten/emsdk:3.1.57
|
||||
FROM emscripten/emsdk:6.0.1
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y gcc-12 g++-12 \
|
||||
&& update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100 \
|
||||
&& update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-12 100 \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
@@ -63,6 +63,6 @@
|
||||
<Resource Language="cy-gb" />
|
||||
</Resources>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17134.0" MaxVersionTested="10.0.18363.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17701.0" MaxVersionTested="10.0.18363.0" />
|
||||
</Dependencies>
|
||||
</Package>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17134.0" MaxVersionTested="10.0.18363.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17701.0" MaxVersionTested="10.0.18363.0" />
|
||||
</Dependencies>
|
||||
<Resources>
|
||||
<Resource Language="en-gb" />
|
||||
|
||||
@@ -22,3 +22,5 @@
|
||||
|
||||
add_subdirectory(regression)
|
||||
add_subdirectory(stationlist)
|
||||
add_subdirectory(gs)
|
||||
add_subdirectory(gs_compat)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
include(CreateRegression)
|
||||
create_regression("game"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/info.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/main.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/require.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/result.txt
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test.sav
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
class Regression extends GSInfo {
|
||||
function GetAuthor() { return "OpenTTD GS Developers Team"; }
|
||||
function GetName() { return "Regression"; }
|
||||
function GetShortName() { return "REGR"; }
|
||||
function GetDescription() { return "This runs regression-tests on some commands. On the same map the result should always be the same."; }
|
||||
function GetVersion() { return 1; }
|
||||
function GetAPIVersion() { return "16"; }
|
||||
function GetDate() { return "2026-05-19"; }
|
||||
function CreateInstance() { return "Regression"; }
|
||||
function UseAsRandomAI() { return false; }
|
||||
}
|
||||
|
||||
RegisterGS(Regression());
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
class Regression extends GSController {
|
||||
function Start();
|
||||
};
|
||||
|
||||
|
||||
|
||||
function Regression::TestInit()
|
||||
{
|
||||
print("");
|
||||
print("--TestInit--");
|
||||
print(" Ops: " + this.GetOpsTillSuspend());
|
||||
print(" TickTest: " + this.GetTick());
|
||||
this.Sleep(1);
|
||||
print(" TickTest: " + this.GetTick());
|
||||
print(" Ops: " + this.GetOpsTillSuspend());
|
||||
print(" SetCommandDelay: " + GSController.SetCommandDelay(1));
|
||||
print(" IsValid(vehicle.plane_speed): " + GSGameSettings.IsValid("vehicle.plane_speed"));
|
||||
print(" vehicle.plane_speed: " + GSGameSettings.GetValue("vehicle.plane_speed"));
|
||||
require("require.nut");
|
||||
print(" TestEnum.value1: " + ::TestEnum.value1);
|
||||
print(" test_constant: " + ::test_constant);
|
||||
print(" TestEnum.value2: " + TestEnum.value2);
|
||||
print(" test_constant: " + test_constant);
|
||||
print(" min(6, 3): " + min(6, 3));
|
||||
print(" min(3, 6): " + min(3, 6));
|
||||
print(" max(6, 3): " + max(6, 3));
|
||||
print(" max(3, 6): " + max(3, 6));
|
||||
}
|
||||
|
||||
function Regression::Company()
|
||||
{
|
||||
print("");
|
||||
print("--Company--");
|
||||
|
||||
/* Test GSXXXMode() in scopes */
|
||||
{
|
||||
local test = GSTestMode();
|
||||
print(" SetName(): " + GSCompany.SetName("Regression"));
|
||||
print(" SetName(): " + GSCompany.SetName("Regression"));
|
||||
{
|
||||
local exec = GSExecMode();
|
||||
print(" SetName(): " + GSCompany.SetName("Regression"));
|
||||
print(" SetName(): " + GSCompany.SetName("Regression"));
|
||||
print(" GetLastErrorString(): " + GSError.GetLastErrorString());
|
||||
}
|
||||
}
|
||||
|
||||
print(" GetName(): " + GSCompany.GetName(GSCompany.COMPANY_SELF));
|
||||
print(" GetPresidentName(): " + GSCompany.GetPresidentName(GSCompany.COMPANY_SELF));
|
||||
print(" SetPresidentName(): " + GSCompany.SetPresidentName("Regression GS"));
|
||||
print(" GetPresidentName(): " + GSCompany.GetPresidentName(GSCompany.COMPANY_SELF));
|
||||
|
||||
print("");
|
||||
print("--CompanyMode--");
|
||||
|
||||
local company = GSCompanyMode(GSCompany.COMPANY_FIRST);
|
||||
{
|
||||
local test = GSTestMode();
|
||||
print(" SetName(): " + GSCompany.SetName("Regression"));
|
||||
print(" SetName(): " + GSCompany.SetName("Regression"));
|
||||
{
|
||||
local exec = GSExecMode();
|
||||
print(" SetName(): " + GSCompany.SetName("Regression"));
|
||||
print(" SetName(): " + GSCompany.SetName("Regression"));
|
||||
print(" GetLastErrorString(): " + GSError.GetLastErrorString());
|
||||
}
|
||||
}
|
||||
|
||||
print(" GetName(): " + GSCompany.GetName(GSCompany.COMPANY_SELF));
|
||||
print(" GetPresidentName(): " + GSCompany.GetPresidentName(GSCompany.COMPANY_SELF));
|
||||
print(" SetPresidentName(): " + GSCompany.SetPresidentName("Regression GS"));
|
||||
print(" GetPresidentName(): " + GSCompany.GetPresidentName(GSCompany.COMPANY_SELF));
|
||||
}
|
||||
|
||||
function Regression::Start()
|
||||
{
|
||||
this.TestInit();
|
||||
this.Company();
|
||||
|
||||
print("");
|
||||
print("Done...");
|
||||
print("");
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
print(" Required this file");
|
||||
|
||||
const test_constant = 1;
|
||||
|
||||
enum TestEnum {
|
||||
value0,
|
||||
value1,
|
||||
value2
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
|
||||
--TestInit--
|
||||
Ops: 9988
|
||||
TickTest: 1
|
||||
TickTest: 2
|
||||
Ops: 9990
|
||||
SetCommandDelay: (null : 0x00000000)
|
||||
IsValid(vehicle.plane_speed): true
|
||||
vehicle.plane_speed: 4
|
||||
Required this file
|
||||
TestEnum.value1: 1
|
||||
test_constant: 1
|
||||
TestEnum.value2: 2
|
||||
test_constant: 1
|
||||
min(6, 3): 3
|
||||
min(3, 6): 3
|
||||
max(6, 3): 6
|
||||
max(3, 6): 6
|
||||
|
||||
--Company--
|
||||
SetName(): false
|
||||
SetName(): false
|
||||
SetName(): false
|
||||
SetName(): false
|
||||
GetLastErrorString(): ERR_PRECONDITION_INVALID_COMPANY
|
||||
GetName(): (null : 0x00000000)
|
||||
GetPresidentName(): (null : 0x00000000)
|
||||
SetPresidentName(): false
|
||||
GetPresidentName(): (null : 0x00000000)
|
||||
|
||||
--CompanyMode--
|
||||
SetName(): true
|
||||
SetName(): true
|
||||
SetName(): true
|
||||
SetName(): false
|
||||
GetLastErrorString(): ERR_NAME_IS_NOT_UNIQUE
|
||||
GetName(): Regression
|
||||
GetPresidentName(): S. G. Bloggs
|
||||
SetPresidentName(): true
|
||||
GetPresidentName(): Regression GS
|
||||
|
||||
Done...
|
||||
|
||||
ERROR: The script died unexpectedly.
|
||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
include(CreateRegression)
|
||||
create_regression("game"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/info.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/main.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/result.txt
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/test.sav
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
class CompatRegression extends GSInfo {
|
||||
function GetAuthor() { return "OpenTTD GS Developers Team"; }
|
||||
function GetName() { return "Compat Regression"; }
|
||||
function GetShortName() { return "REGC"; }
|
||||
function GetDescription() { return "This runs regression on the compat scripts."; }
|
||||
function GetVersion() { return 1; }
|
||||
function GetAPIVersion() { return "1.2"; }
|
||||
function GetDate() { return "2026-05-19"; }
|
||||
function CreateInstance() { return "CompatRegression"; }
|
||||
function UseAsRandomAI() { return false; }
|
||||
}
|
||||
|
||||
RegisterGS(CompatRegression());
|
||||
@@ -0,0 +1,6 @@
|
||||
class CompatRegression extends GSController {
|
||||
function Start()
|
||||
{
|
||||
print("Done...");
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
Done...
|
||||
ERROR: The script died unexpectedly.
|
||||
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
include(CreateRegression)
|
||||
create_regression(
|
||||
create_regression("ai"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/info.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/main.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/require.nut
|
||||
|
||||
@@ -4,7 +4,7 @@ class Regression extends AIInfo {
|
||||
function GetShortName() { return "REGR"; }
|
||||
function GetDescription() { return "This runs regression-tests on some commands. On the same map the result should always be the same."; }
|
||||
function GetVersion() { return 1; }
|
||||
function GetAPIVersion() { return "15"; }
|
||||
function GetAPIVersion() { return "16"; }
|
||||
function GetDate() { return "2007-03-18"; }
|
||||
function CreateInstance() { return "Regression"; }
|
||||
function UseAsRandomAI() { return false; }
|
||||
|
||||
@@ -842,6 +842,7 @@ function Regression::List()
|
||||
}
|
||||
list[4000] = 50;
|
||||
list[4006] = 12;
|
||||
list[4012] = true;
|
||||
|
||||
print(" foreach():");
|
||||
foreach (idx, val in list) {
|
||||
@@ -849,6 +850,7 @@ function Regression::List()
|
||||
}
|
||||
print(" []:");
|
||||
print(" 4000 => " + list[4000]);
|
||||
print(" 4012 => " + list[4012]);
|
||||
|
||||
print(" clone:");
|
||||
local list3 = clone list;
|
||||
@@ -865,25 +867,25 @@ function Regression::List()
|
||||
}
|
||||
|
||||
local it = list.Begin();
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")");
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
list.Sort(list.SORT_BY_VALUE, list.SORT_ASCENDING);
|
||||
it = list.Next();
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")");
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
|
||||
it = list.Begin();
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")");
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
|
||||
list.SetValue(it + 1, -5);
|
||||
it = list.Next();
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")");
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
|
||||
list.RemoveValue(list.GetValue(it) + 1);
|
||||
it = list.Next();
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")");
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
|
||||
list.RemoveAboveValue(list.GetValue(it));
|
||||
it = list.Next();
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")");
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
|
||||
while (!list.IsEnd()) {
|
||||
it = list.Next();
|
||||
@@ -895,6 +897,232 @@ function Regression::List()
|
||||
print(" " + idx + " => " + val);
|
||||
}
|
||||
|
||||
list.RemoveItem(0);
|
||||
local list4 = clone list;
|
||||
|
||||
foreach (sorter_type in [ AIList.SORT_BY_VALUE, AIList.SORT_BY_ITEM ]) {
|
||||
foreach (sorter_direction in [ AIList.SORT_DESCENDING, AIList.SORT_ASCENDING ]) {
|
||||
local type = sorter_type == AIList.SORT_BY_VALUE ? "Value" : "Item";
|
||||
local direction = sorter_direction == AIList.SORT_DESCENDING ? "Descending" : "Ascending";
|
||||
local sorter = " (" + type + " " + direction + ")";
|
||||
list = clone list4;
|
||||
list.Sort(sorter_type, sorter_direction);
|
||||
print("");
|
||||
|
||||
print(" ListDump:" + sorter);
|
||||
foreach (idx, val in list) {
|
||||
print(" " + idx + " => " + val);
|
||||
}
|
||||
it = list.Begin();
|
||||
print(" Begin(): " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Next(): " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Next(): " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Next(): " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Next(): " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
|
||||
print(" foreach (idx, val in list) {print}:" + sorter);
|
||||
foreach (idx, val in list) {
|
||||
print(" " + idx + " => " + val + " (" + list.IsEnd() + ")");
|
||||
}
|
||||
print(" Post loop: (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
|
||||
print(" for (Begin / !IsEnd / Next) {print}:" + sorter);
|
||||
for (it = list.Begin(); !list.IsEnd(); it = list.Next()) {
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
}
|
||||
print(" Post loop: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
|
||||
print(" Begin / while (!IsEnd) {print / Next}:" + sorter);
|
||||
it = list.Begin();
|
||||
while (!list.IsEnd()) {
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
}
|
||||
print(" Post loop: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
|
||||
print(" Begin / do {{print / Next} while (!IsEnd)}:" + sorter);
|
||||
it = list.Begin();
|
||||
do {
|
||||
print(" " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
} while (!list.IsEnd());
|
||||
print(" Post loop: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
|
||||
print(" GetValue / SetValue:" + sorter);
|
||||
for (it = list.Begin(); !list.IsEnd(); it = list.Next()) {
|
||||
local old_val = list.GetValue(it);
|
||||
local old_isend = list.IsEnd();
|
||||
local res = list.SetValue(it, old_val);
|
||||
local val = list.GetValue(it);
|
||||
local isend = list.IsEnd();
|
||||
local new_val_to_set = old_val * 1111;
|
||||
local new_res = list.SetValue(it, new_val_to_set);
|
||||
local new_val = list.GetValue(it);
|
||||
local new_isend = list.IsEnd();
|
||||
print(" " + it + " => " + old_val + " (" + old_isend + ")");
|
||||
print(" => SetValue(" + it + ", " + old_val + ") ? " + res + " => " + val + " (" + isend + ")");
|
||||
print(" => SetValue(" + it + ", " + new_val_to_set + ") ? " + new_res + " => " + new_val + " (" + new_isend + ")");
|
||||
}
|
||||
print(" Post loop: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
|
||||
list.Clear();
|
||||
list.AddList(list4);
|
||||
print(" GetValue / AddItem:" + sorter);
|
||||
for (it = list.Begin(); !list.IsEnd(); it = list.Next()) {
|
||||
local old_val = list.GetValue(it);
|
||||
local old_isend = list.IsEnd();
|
||||
list.AddItem(it, old_val);
|
||||
local val = list.GetValue(it);
|
||||
local isend = list.IsEnd();
|
||||
local new_val_to_set = old_val * 1111;
|
||||
list.AddItem(it, new_val_to_set);
|
||||
local new_val = list.GetValue(it);
|
||||
local new_isend = list.IsEnd();
|
||||
print(" " + it + " => " + old_val + " (" + old_isend + ")");
|
||||
print(" => AddItem(" + it + ", " + old_val + ") => " + val + " (" + isend + ")");
|
||||
print(" => AddItem(" + it + ", " + new_val_to_set + ") => " + new_val + " (" + new_isend + ")");
|
||||
}
|
||||
print(" Post loop: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
|
||||
list.Clear();
|
||||
list.AddList(list4);
|
||||
print(" RemoveItem / HasItem / AddItem:" + sorter);
|
||||
for (it = list.Begin(); !list.IsEnd(); it = list.Next()) {
|
||||
local val = list.GetValue(it);
|
||||
print(" " + it + " => " + val + " / " + list.HasItem(it) + " (" + list.IsEnd() + ")");
|
||||
list.RemoveItem(it);
|
||||
print(" => RemoveItem(" + it + ") => " + list.GetValue(it) + " / " + list.HasItem(it) + " (" + list.IsEnd() + ")");
|
||||
if (list.IsEnd()) {
|
||||
list.AddItem(it, val);
|
||||
print(" => AddItem(" + it + ", " + val + ") => " + list.GetValue(it) + " / " + list.HasItem(it) + " (" + list.IsEnd() + ")");
|
||||
}
|
||||
}
|
||||
print(" Post loop: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
it = list.Next();
|
||||
print(" Post loop Next: " + it + " => " + list.GetValue(it) + " (" + list.IsEnd() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
list.Clear(),
|
||||
list.AddList(list4);
|
||||
|
||||
local list1 = list;
|
||||
local list2 = list3;
|
||||
|
||||
foreach (sorter_type_1 in [ AIList.SORT_BY_VALUE, AIList.SORT_BY_ITEM ]) {
|
||||
foreach (sorter_direction_1 in [ AIList.SORT_DESCENDING, AIList.SORT_ASCENDING ]) {
|
||||
local type_1 = sorter_type_1 == AIList.SORT_BY_VALUE ? "Value" : "Item";
|
||||
local direction_1 = sorter_direction_1 == AIList.SORT_DESCENDING ? "Descending" : "Ascending";
|
||||
local sorter_1 = " (" + type_1 + " " + direction_1 + ")";
|
||||
|
||||
foreach (sorter_type_2 in [ AIList.SORT_BY_VALUE, AIList.SORT_BY_ITEM ]) {
|
||||
foreach (sorter_direction_2 in [ AIList.SORT_DESCENDING, AIList.SORT_ASCENDING ]) {
|
||||
local type_2 = sorter_type_2 == AIList.SORT_BY_VALUE ? "Value" : "Item";
|
||||
local direction_2 = sorter_direction_2 == AIList.SORT_DESCENDING ? "Descending" : "Ascending";
|
||||
local sorter_2 = " (" + type_2 + " " + direction_2 + ")";
|
||||
|
||||
local sorter = sorter_1 + sorter_2;
|
||||
|
||||
list1.Clear(),
|
||||
list1.AddList(list4);
|
||||
|
||||
list1.Sort(sorter_type_1, sorter_direction_1);
|
||||
list2.Sort(sorter_type_2, sorter_direction_2);
|
||||
|
||||
print("");
|
||||
print(" SwapList:" + sorter);
|
||||
print(" DumpList 1:" + sorter_1);
|
||||
foreach (idx, val in list1) {
|
||||
print(" " + idx + " => " + val);
|
||||
}
|
||||
print(" DumpList 2:" + sorter_2);
|
||||
foreach (idx, val in list2) {
|
||||
print(" " + idx + " => " + val);
|
||||
}
|
||||
local it1 = list1.Begin();
|
||||
print(" List 1 Begin: " + it1 + " => " + list1.GetValue(it1) + " (" + list1.IsEnd() + ")");
|
||||
local it2 = list2.Begin();
|
||||
print(" List 2 Begin: " + it2 + " => " + list2.GetValue(it2) + " (" + list2.IsEnd() + ")");
|
||||
it2 = list2.Next();
|
||||
print(" List 2 Next: " + it2 + " => " + list2.GetValue(it2) + " (" + list2.IsEnd() + ")");
|
||||
print(" => Swap list 1 with list 2 " + list1.SwapList(list2));
|
||||
it1 = list1.Next();
|
||||
print(" List 1 Next: " + it1 + " => " + list1.GetValue(it1) + " (" + list1.IsEnd() + ")");
|
||||
it2 = list2.Next();
|
||||
print(" List 2 Next: " + it2 + " => " + list2.GetValue(it2) + " (" + list2.IsEnd() + ")");
|
||||
it2 = list2.Next();
|
||||
print(" List 2 Next: " + it2 + " => " + list2.GetValue(it2) + " (" + list2.IsEnd() + ")");
|
||||
print(" => Swap list 1 with list 2 " + list1.SwapList(list2));
|
||||
it1 = list1.Next();
|
||||
print(" List 1 Next: " + it1 + " => " + list1.GetValue(it1) + " (" + list1.IsEnd() + ")");
|
||||
it2 = list2.Next();
|
||||
print(" List 2 Next: " + it2 + " >= " + list2.GetValue(it2) + " (" + list2.IsEnd() + ")");
|
||||
it2 = list2.Next();
|
||||
print(" List 2 Next: " + it2 + " >= " + list2.GetValue(it2) + " (" + list2.IsEnd() + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list.Clear();
|
||||
print(" IsEmpty(): " + list.IsEmpty());
|
||||
|
||||
list2 = AIList();
|
||||
for (local i = -10; i < 10; i++) {
|
||||
list2.AddItem(i, -i * i / 2);
|
||||
}
|
||||
list.SwapList(list2);
|
||||
|
||||
print(" Negative ListDump:");
|
||||
for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) {
|
||||
print(" " + i + " => " + list.GetValue(i));
|
||||
}
|
||||
print(" KeepBelowValue(-12):");
|
||||
list.KeepBelowValue(-12);
|
||||
for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) {
|
||||
print(" " + i + " => " + list.GetValue(i));
|
||||
}
|
||||
print(" KeepAboveValue(-40):");
|
||||
list.KeepAboveValue(-40);
|
||||
for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) {
|
||||
print(" " + i + " => " + list.GetValue(i));
|
||||
}
|
||||
print(" KeepValue(-24):");
|
||||
list.KeepValue(-24);
|
||||
for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) {
|
||||
print(" " + i + " => " + list.GetValue(i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function Regression::Map()
|
||||
@@ -2072,6 +2300,67 @@ function Regression::PriorityQueue()
|
||||
print(" Count(): " + queue.Count());
|
||||
}
|
||||
|
||||
function Regression::Terraforming()
|
||||
{
|
||||
print("");
|
||||
print("--Terraforming--");
|
||||
print(" DemolishTile(): " + AITile.DemolishTile(4033));
|
||||
print(" DemolishTile(): " + AITile.DemolishTile(60766));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" LowerTile(): " + AITile.LowerTile(8205, AITile.SLOPE_ENW));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(8205, AITile.SLOPE_ENW));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" LowerTile(): " + AITile.LowerTile(8205, AITile.SLOPE_ENW));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" LowerTile(): " + AITile.LowerTile(4113, AITile.SLOPE_SW));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(5902, AITile.SLOPE_NE));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(7958, AITile.SLOPE_SE));
|
||||
print(" LowerTile(): " + AITile.LowerTile(7958, AITile.SLOPE_NE));
|
||||
print(" LowerTile(): " + AITile.LowerTile(7958, AITile.SLOPE_SE));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(7958, AITile.SLOPE_SE));
|
||||
print(" LowerTile(): " + AITile.LowerTile(7958, AITile.SLOPE_EW));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" LowerTile(): " + AITile.LowerTile(33924, AITile.SLOPE_ELEVATED));
|
||||
print(" LowerTile(): " + AITile.LowerTile(33923, AITile.SLOPE_ELEVATED));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(34193, AITile.SLOPE_ELEVATED));
|
||||
print(" LowerTile(): " + AITile.LowerTile(34193, AITile.SLOPE_ELEVATED));
|
||||
print(" LowerTile(): " + AITile.LowerTile(34192, AITile.SLOPE_NE));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(34193, AITile.SLOPE_ELEVATED));
|
||||
print(" LowerTile(): " + AITile.LowerTile(34192, AITile.SLOPE_NE));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(5687, AITile.SLOPE_N));
|
||||
print(" LowerTile(): " + AITile.LowerTile(5687, AITile.SLOPE_SE));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(23596, AITile.SLOPE_NE));
|
||||
print(" LowerTile(): " + AITile.LowerTile(23596, AITile.SLOPE_NE));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(28536, AITile.SLOPE_E));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(28536, AITile.SLOPE_E));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" LevelTiles(): " + AITile.LevelTiles(28536, 29053));
|
||||
print(" LevelTiles(): " + AITile.LevelTiles(28536, 29053));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" LevelTiles(): " + AITile.LevelTiles(22348, 24405));
|
||||
print(" LevelTiles(): " + AITile.LevelTiles(27717, 29772));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" LowerTile(): " + AITile.LowerTile(61534, AITile.SLOPE_W));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(61534, AITile.SLOPE_NE));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(61534, AITile.SLOPE_N));
|
||||
print(" LowerTile(): " + AITile.LowerTile(61534, AITile.SLOPE_W));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(61534, AITile.SLOPE_N));
|
||||
print(" LowerTile(): " + AITile.LowerTile(61533, AITile.SLOPE_E));
|
||||
print(" LowerTile(): " + AITile.LowerTile(61534, AITile.SLOPE_E));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(4033, AITile.SLOPE_S));
|
||||
print(" LowerTile(): " + AITile.LowerTile(4033, AITile.SLOPE_S));
|
||||
print(" LowerTile(): " + AITile.LowerTile(4033, AITile.SLOPE_E));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(4033, AITile.SLOPE_E));
|
||||
print(" RaiseTile(): " + AITile.RaiseTile(4033, AITile.SLOPE_NWS));
|
||||
print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF));
|
||||
}
|
||||
|
||||
function Regression::Start()
|
||||
{
|
||||
this.TestInit();
|
||||
@@ -2170,6 +2459,7 @@ function Regression::Start()
|
||||
|
||||
this.Math();
|
||||
this.PriorityQueue();
|
||||
this.Terraforming();
|
||||
|
||||
/* Check Valuate() is actually limited, MUST BE THE LAST TEST. */
|
||||
print("--Valuate() with excessive CPU usage--")
|
||||
|
||||
@@ -573,8 +573,10 @@
|
||||
4001 => 8002
|
||||
4002 => 8004
|
||||
4006 => 12
|
||||
4012 => 1
|
||||
[]:
|
||||
4000 => 50
|
||||
4012 => 1
|
||||
clone:
|
||||
Clone ListDump:
|
||||
1005 => 1005
|
||||
@@ -582,21 +584,779 @@
|
||||
4001 => 8002
|
||||
4002 => 8004
|
||||
4006 => 12
|
||||
4012 => 1
|
||||
IsEmpty(): true
|
||||
0 => 5 (true)
|
||||
0 => 5 (false)
|
||||
ERROR: Next() is invalid as Begin() is never called
|
||||
ERROR: IsEnd() is invalid as Begin() is never called
|
||||
0 => 5 (false)
|
||||
0 => 5 (true)
|
||||
2 => 6 (true)
|
||||
3 => 6 (true)
|
||||
0 => 5 (false)
|
||||
2 => 6 (false)
|
||||
3 => 6 (false)
|
||||
0 => 5 (true)
|
||||
Clone ListDump:
|
||||
1005 => 1005
|
||||
4000 => 50
|
||||
4001 => 8002
|
||||
4002 => 8004
|
||||
4006 => 12
|
||||
4012 => 1
|
||||
|
||||
ListDump: (Value Descending)
|
||||
3 => 6
|
||||
2 => 6
|
||||
1 => -5
|
||||
Begin(): 3 => 6 (false)
|
||||
Next(): 2 => 6 (false)
|
||||
Next(): 1 => -5 (false)
|
||||
Next(): 0 => 0 (true)
|
||||
Next(): 0 => 0 (true)
|
||||
foreach (idx, val in list) {print}: (Value Descending)
|
||||
3 => 6 (false)
|
||||
2 => 6 (false)
|
||||
1 => -5 (false)
|
||||
Post loop: (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
for (Begin / !IsEnd / Next) {print}: (Value Descending)
|
||||
3 => 6 (false)
|
||||
2 => 6 (false)
|
||||
1 => -5 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Begin / while (!IsEnd) {print / Next}: (Value Descending)
|
||||
3 => 6 (false)
|
||||
2 => 6 (false)
|
||||
1 => -5 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Begin / do {{print / Next} while (!IsEnd)}: (Value Descending)
|
||||
3 => 6 (false)
|
||||
2 => 6 (false)
|
||||
1 => -5 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
GetValue / SetValue: (Value Descending)
|
||||
3 => 6 (false)
|
||||
=> SetValue(3, 6) ? true => 6 (false)
|
||||
=> SetValue(3, 6666) ? true => 6666 (false)
|
||||
2 => 6 (false)
|
||||
=> SetValue(2, 6) ? true => 6 (false)
|
||||
=> SetValue(2, 6666) ? true => 6666 (false)
|
||||
1 => -5 (false)
|
||||
=> SetValue(1, -5) ? true => -5 (false)
|
||||
=> SetValue(1, -5555) ? true => -5555 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
GetValue / AddItem: (Value Descending)
|
||||
3 => 6 (false)
|
||||
=> AddItem(3, 6) => 6 (false)
|
||||
=> AddItem(3, 6666) => 6 (false)
|
||||
2 => 6 (false)
|
||||
=> AddItem(2, 6) => 6 (false)
|
||||
=> AddItem(2, 6666) => 6 (false)
|
||||
1 => -5 (false)
|
||||
=> AddItem(1, -5) => -5 (false)
|
||||
=> AddItem(1, -5555) => -5 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
RemoveItem / HasItem / AddItem: (Value Descending)
|
||||
3 => 6 / true (false)
|
||||
=> RemoveItem(3) => 0 / false (false)
|
||||
2 => 6 / true (false)
|
||||
=> RemoveItem(2) => 0 / false (false)
|
||||
1 => -5 / true (false)
|
||||
=> RemoveItem(1) => 0 / false (true)
|
||||
=> AddItem(1, -5) => -5 / true (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
|
||||
ListDump: (Value Ascending)
|
||||
1 => -5
|
||||
2 => 6
|
||||
3 => 6
|
||||
Begin(): 1 => -5 (false)
|
||||
Next(): 2 => 6 (false)
|
||||
Next(): 3 => 6 (false)
|
||||
Next(): 0 => 0 (true)
|
||||
Next(): 0 => 0 (true)
|
||||
foreach (idx, val in list) {print}: (Value Ascending)
|
||||
1 => -5 (false)
|
||||
2 => 6 (false)
|
||||
3 => 6 (false)
|
||||
Post loop: (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
for (Begin / !IsEnd / Next) {print}: (Value Ascending)
|
||||
1 => -5 (false)
|
||||
2 => 6 (false)
|
||||
3 => 6 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Begin / while (!IsEnd) {print / Next}: (Value Ascending)
|
||||
1 => -5 (false)
|
||||
2 => 6 (false)
|
||||
3 => 6 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Begin / do {{print / Next} while (!IsEnd)}: (Value Ascending)
|
||||
1 => -5 (false)
|
||||
2 => 6 (false)
|
||||
3 => 6 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
GetValue / SetValue: (Value Ascending)
|
||||
1 => -5 (false)
|
||||
=> SetValue(1, -5) ? true => -5 (false)
|
||||
=> SetValue(1, -5555) ? true => -5555 (false)
|
||||
2 => 6 (false)
|
||||
=> SetValue(2, 6) ? true => 6 (false)
|
||||
=> SetValue(2, 6666) ? true => 6666 (false)
|
||||
3 => 6 (false)
|
||||
=> SetValue(3, 6) ? true => 6 (false)
|
||||
=> SetValue(3, 6666) ? true => 6666 (false)
|
||||
2 => 6666 (false)
|
||||
=> SetValue(2, 6666) ? true => 6666 (false)
|
||||
=> SetValue(2, 7405926) ? true => 7405926 (false)
|
||||
3 => 6666 (false)
|
||||
=> SetValue(3, 6666) ? true => 6666 (false)
|
||||
=> SetValue(3, 7405926) ? true => 7405926 (false)
|
||||
2 => 7405926 (false)
|
||||
=> SetValue(2, 7405926) ? true => 7405926 (false)
|
||||
=> SetValue(2, 8227983786) ? true => 8227983786 (false)
|
||||
3 => 7405926 (false)
|
||||
=> SetValue(3, 7405926) ? true => 7405926 (false)
|
||||
=> SetValue(3, 8227983786) ? true => 8227983786 (false)
|
||||
2 => 8227983786 (false)
|
||||
=> SetValue(2, 8227983786) ? true => 8227983786 (false)
|
||||
=> SetValue(2, 9141289986246) ? true => 9141289986246 (false)
|
||||
3 => 8227983786 (false)
|
||||
=> SetValue(3, 8227983786) ? true => 8227983786 (false)
|
||||
=> SetValue(3, 9141289986246) ? true => 9141289986246 (false)
|
||||
2 => 9141289986246 (false)
|
||||
=> SetValue(2, 9141289986246) ? true => 9141289986246 (false)
|
||||
=> SetValue(2, 10155973174719306) ? true => 10155973174719306 (false)
|
||||
3 => 9141289986246 (false)
|
||||
=> SetValue(3, 9141289986246) ? true => 9141289986246 (false)
|
||||
=> SetValue(3, 10155973174719306) ? true => 10155973174719306 (false)
|
||||
2 => 10155973174719306 (false)
|
||||
=> SetValue(2, 10155973174719306) ? true => 10155973174719306 (false)
|
||||
=> SetValue(2, -7163457876596402650) ? true => -7163457876596402650 (false)
|
||||
3 => 10155973174719306 (false)
|
||||
=> SetValue(3, 10155973174719306) ? true => 10155973174719306 (false)
|
||||
=> SetValue(3, -7163457876596402650) ? true => -7163457876596402650 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
GetValue / AddItem: (Value Ascending)
|
||||
1 => -5 (false)
|
||||
=> AddItem(1, -5) => -5 (false)
|
||||
=> AddItem(1, -5555) => -5 (false)
|
||||
2 => 6 (false)
|
||||
=> AddItem(2, 6) => 6 (false)
|
||||
=> AddItem(2, 6666) => 6 (false)
|
||||
3 => 6 (false)
|
||||
=> AddItem(3, 6) => 6 (false)
|
||||
=> AddItem(3, 6666) => 6 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
RemoveItem / HasItem / AddItem: (Value Ascending)
|
||||
1 => -5 / true (false)
|
||||
=> RemoveItem(1) => 0 / false (false)
|
||||
2 => 6 / true (false)
|
||||
=> RemoveItem(2) => 0 / false (false)
|
||||
3 => 6 / true (false)
|
||||
=> RemoveItem(3) => 0 / false (true)
|
||||
=> AddItem(3, 6) => 6 / true (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
|
||||
ListDump: (Item Descending)
|
||||
3 => 6
|
||||
2 => 6
|
||||
1 => -5
|
||||
Begin(): 3 => 6 (false)
|
||||
Next(): 2 => 6 (false)
|
||||
Next(): 1 => -5 (false)
|
||||
Next(): 0 => 0 (true)
|
||||
Next(): 0 => 0 (true)
|
||||
foreach (idx, val in list) {print}: (Item Descending)
|
||||
3 => 6 (false)
|
||||
2 => 6 (false)
|
||||
1 => -5 (false)
|
||||
Post loop: (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
for (Begin / !IsEnd / Next) {print}: (Item Descending)
|
||||
3 => 6 (false)
|
||||
2 => 6 (false)
|
||||
1 => -5 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Begin / while (!IsEnd) {print / Next}: (Item Descending)
|
||||
3 => 6 (false)
|
||||
2 => 6 (false)
|
||||
1 => -5 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Begin / do {{print / Next} while (!IsEnd)}: (Item Descending)
|
||||
3 => 6 (false)
|
||||
2 => 6 (false)
|
||||
1 => -5 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
GetValue / SetValue: (Item Descending)
|
||||
3 => 6 (false)
|
||||
=> SetValue(3, 6) ? true => 6 (false)
|
||||
=> SetValue(3, 6666) ? true => 6666 (false)
|
||||
2 => 6 (false)
|
||||
=> SetValue(2, 6) ? true => 6 (false)
|
||||
=> SetValue(2, 6666) ? true => 6666 (false)
|
||||
1 => -5 (false)
|
||||
=> SetValue(1, -5) ? true => -5 (false)
|
||||
=> SetValue(1, -5555) ? true => -5555 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
GetValue / AddItem: (Item Descending)
|
||||
3 => 6 (false)
|
||||
=> AddItem(3, 6) => 6 (false)
|
||||
=> AddItem(3, 6666) => 6 (false)
|
||||
2 => 6 (false)
|
||||
=> AddItem(2, 6) => 6 (false)
|
||||
=> AddItem(2, 6666) => 6 (false)
|
||||
1 => -5 (false)
|
||||
=> AddItem(1, -5) => -5 (false)
|
||||
=> AddItem(1, -5555) => -5 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
RemoveItem / HasItem / AddItem: (Item Descending)
|
||||
3 => 6 / true (false)
|
||||
=> RemoveItem(3) => 0 / false (false)
|
||||
2 => 6 / true (false)
|
||||
=> RemoveItem(2) => 0 / false (false)
|
||||
1 => -5 / true (false)
|
||||
=> RemoveItem(1) => 0 / false (true)
|
||||
=> AddItem(1, -5) => -5 / true (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
|
||||
ListDump: (Item Ascending)
|
||||
1 => -5
|
||||
2 => 6
|
||||
3 => 6
|
||||
Begin(): 1 => -5 (false)
|
||||
Next(): 2 => 6 (false)
|
||||
Next(): 3 => 6 (false)
|
||||
Next(): 0 => 0 (true)
|
||||
Next(): 0 => 0 (true)
|
||||
foreach (idx, val in list) {print}: (Item Ascending)
|
||||
1 => -5 (false)
|
||||
2 => 6 (false)
|
||||
3 => 6 (false)
|
||||
Post loop: (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
for (Begin / !IsEnd / Next) {print}: (Item Ascending)
|
||||
1 => -5 (false)
|
||||
2 => 6 (false)
|
||||
3 => 6 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Begin / while (!IsEnd) {print / Next}: (Item Ascending)
|
||||
1 => -5 (false)
|
||||
2 => 6 (false)
|
||||
3 => 6 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Begin / do {{print / Next} while (!IsEnd)}: (Item Ascending)
|
||||
1 => -5 (false)
|
||||
2 => 6 (false)
|
||||
3 => 6 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
GetValue / SetValue: (Item Ascending)
|
||||
1 => -5 (false)
|
||||
=> SetValue(1, -5) ? true => -5 (false)
|
||||
=> SetValue(1, -5555) ? true => -5555 (false)
|
||||
2 => 6 (false)
|
||||
=> SetValue(2, 6) ? true => 6 (false)
|
||||
=> SetValue(2, 6666) ? true => 6666 (false)
|
||||
3 => 6 (false)
|
||||
=> SetValue(3, 6) ? true => 6 (false)
|
||||
=> SetValue(3, 6666) ? true => 6666 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
GetValue / AddItem: (Item Ascending)
|
||||
1 => -5 (false)
|
||||
=> AddItem(1, -5) => -5 (false)
|
||||
=> AddItem(1, -5555) => -5 (false)
|
||||
2 => 6 (false)
|
||||
=> AddItem(2, 6) => 6 (false)
|
||||
=> AddItem(2, 6666) => 6 (false)
|
||||
3 => 6 (false)
|
||||
=> AddItem(3, 6) => 6 (false)
|
||||
=> AddItem(3, 6666) => 6 (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
RemoveItem / HasItem / AddItem: (Item Ascending)
|
||||
1 => -5 / true (false)
|
||||
=> RemoveItem(1) => 0 / false (false)
|
||||
2 => 6 / true (false)
|
||||
=> RemoveItem(2) => 0 / false (false)
|
||||
3 => 6 / true (false)
|
||||
=> RemoveItem(3) => 0 / false (true)
|
||||
=> AddItem(3, 6) => 6 / true (false)
|
||||
Post loop: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
Post loop Next: 0 => 0 (true)
|
||||
|
||||
SwapList: (Value Descending) (Value Descending)
|
||||
DumpList 1: (Value Descending)
|
||||
3 => 6
|
||||
2 => 6
|
||||
1 => -5
|
||||
DumpList 2: (Value Descending)
|
||||
4002 => 8004
|
||||
4001 => 8002
|
||||
1005 => 1005
|
||||
4000 => 50
|
||||
4006 => 12
|
||||
4012 => 1
|
||||
List 1 Begin: 3 => 6 (false)
|
||||
List 2 Begin: 4002 => 8004 (false)
|
||||
List 2 Next: 4001 => 8002 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 1005 => 1005 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 1 => -5 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 4000 >= 50 (false)
|
||||
List 2 Next: 4006 >= 12 (false)
|
||||
|
||||
SwapList: (Value Descending) (Value Ascending)
|
||||
DumpList 1: (Value Descending)
|
||||
3 => 6
|
||||
2 => 6
|
||||
1 => -5
|
||||
DumpList 2: (Value Ascending)
|
||||
4012 => 1
|
||||
4006 => 12
|
||||
4000 => 50
|
||||
1005 => 1005
|
||||
4001 => 8002
|
||||
4002 => 8004
|
||||
List 1 Begin: 3 => 6 (false)
|
||||
List 2 Begin: 4012 => 1 (false)
|
||||
List 2 Next: 4006 => 12 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 4000 => 50 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 1 => -5 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 1005 >= 1005 (false)
|
||||
List 2 Next: 4001 >= 8002 (false)
|
||||
|
||||
SwapList: (Value Descending) (Item Descending)
|
||||
DumpList 1: (Value Descending)
|
||||
3 => 6
|
||||
2 => 6
|
||||
1 => -5
|
||||
DumpList 2: (Item Descending)
|
||||
4012 => 1
|
||||
4006 => 12
|
||||
4002 => 8004
|
||||
4001 => 8002
|
||||
4000 => 50
|
||||
1005 => 1005
|
||||
List 1 Begin: 3 => 6 (false)
|
||||
List 2 Begin: 4012 => 1 (false)
|
||||
List 2 Next: 4006 => 12 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 4002 => 8004 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 1 => -5 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 4001 >= 8002 (false)
|
||||
List 2 Next: 4000 >= 50 (false)
|
||||
|
||||
SwapList: (Value Descending) (Item Ascending)
|
||||
DumpList 1: (Value Descending)
|
||||
3 => 6
|
||||
2 => 6
|
||||
1 => -5
|
||||
DumpList 2: (Item Ascending)
|
||||
1005 => 1005
|
||||
4000 => 50
|
||||
4001 => 8002
|
||||
4002 => 8004
|
||||
4006 => 12
|
||||
4012 => 1
|
||||
List 1 Begin: 3 => 6 (false)
|
||||
List 2 Begin: 1005 => 1005 (false)
|
||||
List 2 Next: 4000 => 50 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 4001 => 8002 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 1 => -5 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 4002 >= 8004 (false)
|
||||
List 2 Next: 4006 >= 12 (false)
|
||||
|
||||
SwapList: (Value Ascending) (Value Descending)
|
||||
DumpList 1: (Value Ascending)
|
||||
1 => -5
|
||||
2 => 6
|
||||
3 => 6
|
||||
DumpList 2: (Value Descending)
|
||||
4002 => 8004
|
||||
4001 => 8002
|
||||
1005 => 1005
|
||||
4000 => 50
|
||||
4006 => 12
|
||||
4012 => 1
|
||||
List 1 Begin: 1 => -5 (false)
|
||||
List 2 Begin: 4002 => 8004 (false)
|
||||
List 2 Next: 4001 => 8002 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 1005 => 1005 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 3 => 6 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 4000 >= 50 (false)
|
||||
List 2 Next: 4006 >= 12 (false)
|
||||
|
||||
SwapList: (Value Ascending) (Value Ascending)
|
||||
DumpList 1: (Value Ascending)
|
||||
1 => -5
|
||||
2 => 6
|
||||
3 => 6
|
||||
DumpList 2: (Value Ascending)
|
||||
4012 => 1
|
||||
4006 => 12
|
||||
4000 => 50
|
||||
1005 => 1005
|
||||
4001 => 8002
|
||||
4002 => 8004
|
||||
List 1 Begin: 1 => -5 (false)
|
||||
List 2 Begin: 4012 => 1 (false)
|
||||
List 2 Next: 4006 => 12 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 4000 => 50 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 3 => 6 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 1005 >= 1005 (false)
|
||||
List 2 Next: 4001 >= 8002 (false)
|
||||
|
||||
SwapList: (Value Ascending) (Item Descending)
|
||||
DumpList 1: (Value Ascending)
|
||||
1 => -5
|
||||
2 => 6
|
||||
3 => 6
|
||||
DumpList 2: (Item Descending)
|
||||
4012 => 1
|
||||
4006 => 12
|
||||
4002 => 8004
|
||||
4001 => 8002
|
||||
4000 => 50
|
||||
1005 => 1005
|
||||
List 1 Begin: 1 => -5 (false)
|
||||
List 2 Begin: 4012 => 1 (false)
|
||||
List 2 Next: 4006 => 12 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 4002 => 8004 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 3 => 6 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 4001 >= 8002 (false)
|
||||
List 2 Next: 4000 >= 50 (false)
|
||||
|
||||
SwapList: (Value Ascending) (Item Ascending)
|
||||
DumpList 1: (Value Ascending)
|
||||
1 => -5
|
||||
2 => 6
|
||||
3 => 6
|
||||
DumpList 2: (Item Ascending)
|
||||
1005 => 1005
|
||||
4000 => 50
|
||||
4001 => 8002
|
||||
4002 => 8004
|
||||
4006 => 12
|
||||
4012 => 1
|
||||
List 1 Begin: 1 => -5 (false)
|
||||
List 2 Begin: 1005 => 1005 (false)
|
||||
List 2 Next: 4000 => 50 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 4001 => 8002 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 3 => 6 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 4002 >= 8004 (false)
|
||||
List 2 Next: 4006 >= 12 (false)
|
||||
|
||||
SwapList: (Item Descending) (Value Descending)
|
||||
DumpList 1: (Item Descending)
|
||||
3 => 6
|
||||
2 => 6
|
||||
1 => -5
|
||||
DumpList 2: (Value Descending)
|
||||
4002 => 8004
|
||||
4001 => 8002
|
||||
1005 => 1005
|
||||
4000 => 50
|
||||
4006 => 12
|
||||
4012 => 1
|
||||
List 1 Begin: 3 => 6 (false)
|
||||
List 2 Begin: 4002 => 8004 (false)
|
||||
List 2 Next: 4001 => 8002 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 1005 => 1005 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 1 => -5 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 4000 >= 50 (false)
|
||||
List 2 Next: 4006 >= 12 (false)
|
||||
|
||||
SwapList: (Item Descending) (Value Ascending)
|
||||
DumpList 1: (Item Descending)
|
||||
3 => 6
|
||||
2 => 6
|
||||
1 => -5
|
||||
DumpList 2: (Value Ascending)
|
||||
4012 => 1
|
||||
4006 => 12
|
||||
4000 => 50
|
||||
1005 => 1005
|
||||
4001 => 8002
|
||||
4002 => 8004
|
||||
List 1 Begin: 3 => 6 (false)
|
||||
List 2 Begin: 4012 => 1 (false)
|
||||
List 2 Next: 4006 => 12 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 4000 => 50 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 1 => -5 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 1005 >= 1005 (false)
|
||||
List 2 Next: 4001 >= 8002 (false)
|
||||
|
||||
SwapList: (Item Descending) (Item Descending)
|
||||
DumpList 1: (Item Descending)
|
||||
3 => 6
|
||||
2 => 6
|
||||
1 => -5
|
||||
DumpList 2: (Item Descending)
|
||||
4012 => 1
|
||||
4006 => 12
|
||||
4002 => 8004
|
||||
4001 => 8002
|
||||
4000 => 50
|
||||
1005 => 1005
|
||||
List 1 Begin: 3 => 6 (false)
|
||||
List 2 Begin: 4012 => 1 (false)
|
||||
List 2 Next: 4006 => 12 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 4002 => 8004 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 1 => -5 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 4001 >= 8002 (false)
|
||||
List 2 Next: 4000 >= 50 (false)
|
||||
|
||||
SwapList: (Item Descending) (Item Ascending)
|
||||
DumpList 1: (Item Descending)
|
||||
3 => 6
|
||||
2 => 6
|
||||
1 => -5
|
||||
DumpList 2: (Item Ascending)
|
||||
1005 => 1005
|
||||
4000 => 50
|
||||
4001 => 8002
|
||||
4002 => 8004
|
||||
4006 => 12
|
||||
4012 => 1
|
||||
List 1 Begin: 3 => 6 (false)
|
||||
List 2 Begin: 1005 => 1005 (false)
|
||||
List 2 Next: 4000 => 50 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 4001 => 8002 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 1 => -5 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 4002 >= 8004 (false)
|
||||
List 2 Next: 4006 >= 12 (false)
|
||||
|
||||
SwapList: (Item Ascending) (Value Descending)
|
||||
DumpList 1: (Item Ascending)
|
||||
1 => -5
|
||||
2 => 6
|
||||
3 => 6
|
||||
DumpList 2: (Value Descending)
|
||||
4002 => 8004
|
||||
4001 => 8002
|
||||
1005 => 1005
|
||||
4000 => 50
|
||||
4006 => 12
|
||||
4012 => 1
|
||||
List 1 Begin: 1 => -5 (false)
|
||||
List 2 Begin: 4002 => 8004 (false)
|
||||
List 2 Next: 4001 => 8002 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 1005 => 1005 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 3 => 6 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 4000 >= 50 (false)
|
||||
List 2 Next: 4006 >= 12 (false)
|
||||
|
||||
SwapList: (Item Ascending) (Value Ascending)
|
||||
DumpList 1: (Item Ascending)
|
||||
1 => -5
|
||||
2 => 6
|
||||
3 => 6
|
||||
DumpList 2: (Value Ascending)
|
||||
4012 => 1
|
||||
4006 => 12
|
||||
4000 => 50
|
||||
1005 => 1005
|
||||
4001 => 8002
|
||||
4002 => 8004
|
||||
List 1 Begin: 1 => -5 (false)
|
||||
List 2 Begin: 4012 => 1 (false)
|
||||
List 2 Next: 4006 => 12 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 4000 => 50 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 3 => 6 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 1005 >= 1005 (false)
|
||||
List 2 Next: 4001 >= 8002 (false)
|
||||
|
||||
SwapList: (Item Ascending) (Item Descending)
|
||||
DumpList 1: (Item Ascending)
|
||||
1 => -5
|
||||
2 => 6
|
||||
3 => 6
|
||||
DumpList 2: (Item Descending)
|
||||
4012 => 1
|
||||
4006 => 12
|
||||
4002 => 8004
|
||||
4001 => 8002
|
||||
4000 => 50
|
||||
1005 => 1005
|
||||
List 1 Begin: 1 => -5 (false)
|
||||
List 2 Begin: 4012 => 1 (false)
|
||||
List 2 Next: 4006 => 12 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 4002 => 8004 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 3 => 6 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 4001 >= 8002 (false)
|
||||
List 2 Next: 4000 >= 50 (false)
|
||||
|
||||
SwapList: (Item Ascending) (Item Ascending)
|
||||
DumpList 1: (Item Ascending)
|
||||
1 => -5
|
||||
2 => 6
|
||||
3 => 6
|
||||
DumpList 2: (Item Ascending)
|
||||
1005 => 1005
|
||||
4000 => 50
|
||||
4001 => 8002
|
||||
4002 => 8004
|
||||
4006 => 12
|
||||
4012 => 1
|
||||
List 1 Begin: 1 => -5 (false)
|
||||
List 2 Begin: 1005 => 1005 (false)
|
||||
List 2 Next: 4000 => 50 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 4001 => 8002 (false)
|
||||
List 2 Next: 2 => 6 (false)
|
||||
List 2 Next: 3 => 6 (false)
|
||||
=> Swap list 1 with list 2 (null : 0x00000000)
|
||||
List 1 Next: 0 => 0 (true)
|
||||
List 2 Next: 4002 >= 8004 (false)
|
||||
List 2 Next: 4006 >= 12 (false)
|
||||
IsEmpty(): true
|
||||
Negative ListDump:
|
||||
1 => 0
|
||||
0 => 0
|
||||
-1 => 0
|
||||
2 => -2
|
||||
-2 => -2
|
||||
3 => -4
|
||||
-3 => -4
|
||||
4 => -8
|
||||
-4 => -8
|
||||
5 => -12
|
||||
-5 => -12
|
||||
6 => -18
|
||||
-6 => -18
|
||||
7 => -24
|
||||
-7 => -24
|
||||
8 => -32
|
||||
-8 => -32
|
||||
9 => -40
|
||||
-9 => -40
|
||||
-10 => -50
|
||||
KeepBelowValue(-12):
|
||||
6 => -18
|
||||
-6 => -18
|
||||
7 => -24
|
||||
-7 => -24
|
||||
8 => -32
|
||||
-8 => -32
|
||||
9 => -40
|
||||
-9 => -40
|
||||
-10 => -50
|
||||
KeepAboveValue(-40):
|
||||
6 => -18
|
||||
-6 => -18
|
||||
7 => -24
|
||||
-7 => -24
|
||||
8 => -32
|
||||
-8 => -32
|
||||
KeepValue(-24):
|
||||
7 => -24
|
||||
-7 => -24
|
||||
|
||||
--Company--
|
||||
SetName(): true
|
||||
@@ -9778,9 +10538,9 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
GetLocation(): 33417
|
||||
GetEngineType(): 153
|
||||
GetUnitNumber(): 1
|
||||
GetAge(): 1
|
||||
GetAge(): 0
|
||||
GetMaxAge(): 5490
|
||||
GetAgeLeft(): 5489
|
||||
GetAgeLeft(): 5490
|
||||
GetCurrentSpeed(): 7
|
||||
GetRunningCost(): 421
|
||||
GetProfitThisYear(): 0
|
||||
@@ -9793,7 +10553,7 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
IsInDepot(): false
|
||||
GetNumWagons(): 1
|
||||
GetWagonEngineType(): 153
|
||||
GetWagonAge(): 1
|
||||
GetWagonAge(): 0
|
||||
GetLength(): 8
|
||||
GetOwner(): 1
|
||||
BuildVehicle(): 14
|
||||
@@ -9868,11 +10628,11 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
14 => 1
|
||||
12 => 1
|
||||
Age ListDump:
|
||||
12 => 1
|
||||
17 => 0
|
||||
16 => 0
|
||||
14 => 0
|
||||
13 => 0
|
||||
12 => 0
|
||||
MaxAge ListDump:
|
||||
16 => 10980
|
||||
14 => 10980
|
||||
@@ -9884,7 +10644,7 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
14 => 10980
|
||||
17 => 7320
|
||||
13 => 5490
|
||||
12 => 5489
|
||||
12 => 5490
|
||||
CurrentSpeed ListDump:
|
||||
12 => 27
|
||||
17 => 0
|
||||
@@ -10112,15 +10872,73 @@ ERROR: IsEnd() is invalid as Begin() is never called
|
||||
Clear(): (null : 0x00000000)
|
||||
IsEmpty(): true
|
||||
Count(): 0
|
||||
|
||||
--Terraforming--
|
||||
DemolishTile(): true
|
||||
DemolishTile(): true
|
||||
GetBankBalance(): 1999216685
|
||||
LowerTile(): false
|
||||
RaiseTile(): true
|
||||
GetBankBalance(): 1999156124
|
||||
LowerTile(): true
|
||||
GetBankBalance(): 1999155563
|
||||
LowerTile(): true
|
||||
RaiseTile(): true
|
||||
GetBankBalance(): 1999124603
|
||||
RaiseTile(): false
|
||||
LowerTile(): false
|
||||
LowerTile(): true
|
||||
RaiseTile(): true
|
||||
LowerTile(): true
|
||||
GetBankBalance(): 1999122125
|
||||
LowerTile(): false
|
||||
LowerTile(): true
|
||||
RaiseTile(): false
|
||||
LowerTile(): true
|
||||
LowerTile(): false
|
||||
RaiseTile(): true
|
||||
LowerTile(): true
|
||||
GetBankBalance(): 1999116574
|
||||
RaiseTile(): true
|
||||
LowerTile(): true
|
||||
GetBankBalance(): 1999100519
|
||||
RaiseTile(): false
|
||||
LowerTile(): true
|
||||
GetBankBalance(): 1999098443
|
||||
RaiseTile(): true
|
||||
RaiseTile(): true
|
||||
GetBankBalance(): 1999088221
|
||||
LevelTiles(): true
|
||||
LevelTiles(): false
|
||||
GetBankBalance(): 1999078593
|
||||
LevelTiles(): true
|
||||
LevelTiles(): true
|
||||
GetBankBalance(): 1998792514
|
||||
LowerTile(): false
|
||||
RaiseTile(): true
|
||||
RaiseTile(): false
|
||||
LowerTile(): true
|
||||
GetBankBalance(): 1998786415
|
||||
RaiseTile(): true
|
||||
LowerTile(): true
|
||||
LowerTile(): false
|
||||
GetBankBalance(): 1998785248
|
||||
RaiseTile(): false
|
||||
LowerTile(): true
|
||||
LowerTile(): false
|
||||
RaiseTile(): false
|
||||
RaiseTile(): true
|
||||
GetBankBalance(): 1998738752
|
||||
--Valuate() with excessive CPU usage--
|
||||
constructor failed with: excessive CPU usage in list filter function
|
||||
Your script made an error: excessive CPU usage in valuator function
|
||||
|
||||
CALLSTACK
|
||||
*FUNCTION [Start()] regression/main.nut line [2184]
|
||||
|
||||
LOCALS
|
||||
[Infinite] CLOSURE
|
||||
[list] INSTANCE
|
||||
[this] INSTANCE
|
||||
CALLSTACK WITH LOCALS
|
||||
*FUNCTION [Valuate()] Valuate line [5]
|
||||
[args] ARRAY
|
||||
[this] INSTANCE
|
||||
*FUNCTION [Start()] regression/main.nut line [2474]
|
||||
[Infinite] CLOSURE
|
||||
[list] INSTANCE
|
||||
[this] INSTANCE
|
||||
ERROR: The script died unexpectedly.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
include(CreateRegression)
|
||||
create_regression(
|
||||
create_regression("ai"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/info.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/main.nut
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/result.txt
|
||||
|
||||
@@ -4,7 +4,7 @@ class StationList extends AIInfo {
|
||||
function GetShortName() { return "REGS"; }
|
||||
function GetDescription() { return "This runs stationlist-tests on some commands. On the same map the result should always be the same."; }
|
||||
function GetVersion() { return 1; }
|
||||
function GetAPIVersion() { return "15"; }
|
||||
function GetAPIVersion() { return "16"; }
|
||||
function GetDate() { return "2007-03-18"; }
|
||||
function CreateInstance() { return "StationList"; }
|
||||
function UseAsRandomAI() { return false; }
|
||||
|
||||
Vendored
+1
-1
@@ -3,5 +3,5 @@ add_subdirectory(tests)
|
||||
add_files(
|
||||
scriptrun.cpp
|
||||
scriptrun.h
|
||||
CONDITION ICU_i18n_FOUND
|
||||
CONDITION ICU_I18N_FOUND
|
||||
)
|
||||
|
||||
Vendored
+1
-1
@@ -152,7 +152,7 @@ UBool ScriptRun::next()
|
||||
// if it's an open character, push it onto the stack.
|
||||
// if it's a close character, find the matching open on the
|
||||
// stack, and use that script code. Any non-matching open
|
||||
// characters above it on the stack will be poped.
|
||||
// characters above it on the stack will be popped.
|
||||
if (pairIndex >= 0) {
|
||||
if ((pairIndex & 1) == 0) {
|
||||
parenStack[++parenSP].pairIndex = pairIndex;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
add_test_files(
|
||||
test_srtest.cpp
|
||||
CONDITION ICU_i18n_FOUND
|
||||
CONDITION ICU_I18N_FOUND
|
||||
)
|
||||
|
||||
+18
-24
@@ -19,7 +19,7 @@ void sqstd_printcallstack(HSQUIRRELVM v)
|
||||
SQInteger level=1; //1 is to skip this function that is level 0
|
||||
SQInteger seq=0;
|
||||
pf(v,"\n");
|
||||
pf(v,"CALLSTACK\n");
|
||||
pf(v,"CALLSTACK WITH LOCALS\n");
|
||||
while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si)))
|
||||
{
|
||||
std::string_view fn="unknown";
|
||||
@@ -35,13 +35,6 @@ void sqstd_printcallstack(HSQUIRRELVM v)
|
||||
src = (p == std::string_view::npos) ? si.source : si.source.substr(p + 4);
|
||||
}
|
||||
pf(v,fmt::format("*FUNCTION [{}()] {} line [{}]\n",fn,src,si.line));
|
||||
level++;
|
||||
}
|
||||
level=0;
|
||||
pf(v,"\n");
|
||||
pf(v,"LOCALS\n");
|
||||
|
||||
for(level=0;level<10;level++){
|
||||
seq=0;
|
||||
std::optional<std::string_view> opt;
|
||||
while ((opt = sq_getlocal(v,level,seq)).has_value()) {
|
||||
@@ -50,64 +43,65 @@ void sqstd_printcallstack(HSQUIRRELVM v)
|
||||
switch(sq_gettype(v,-1))
|
||||
{
|
||||
case OT_NULL:
|
||||
pf(v,fmt::format("[{}] NULL\n",name));
|
||||
pf(v,fmt::format(" [{}] NULL\n",name));
|
||||
break;
|
||||
case OT_INTEGER:
|
||||
sq_getinteger(v,-1,&i);
|
||||
pf(v,fmt::format("[{}] {}\n",name,i));
|
||||
pf(v,fmt::format(" [{}] {}\n",name,i));
|
||||
break;
|
||||
case OT_FLOAT:
|
||||
sq_getfloat(v,-1,&f);
|
||||
pf(v,fmt::format("[{}] {:14g}\n",name,f));
|
||||
pf(v,fmt::format(" [{}] {:14g}\n",name,f));
|
||||
break;
|
||||
case OT_USERPOINTER:
|
||||
pf(v,fmt::format("[{}] USERPOINTER\n",name));
|
||||
pf(v,fmt::format(" [{}] USERPOINTER\n",name));
|
||||
break;
|
||||
case OT_STRING: {
|
||||
std::string_view view;
|
||||
sq_getstring(v,-1,view);
|
||||
pf(v,fmt::format("[{}] \"{}\"\n",name,view));
|
||||
pf(v,fmt::format(" [{}] \"{}\"\n",name,view));
|
||||
break;
|
||||
}
|
||||
case OT_TABLE:
|
||||
pf(v,fmt::format("[{}] TABLE\n",name));
|
||||
pf(v,fmt::format(" [{}] TABLE\n",name));
|
||||
break;
|
||||
case OT_ARRAY:
|
||||
pf(v,fmt::format("[{}] ARRAY\n",name));
|
||||
pf(v,fmt::format(" [{}] ARRAY\n",name));
|
||||
break;
|
||||
case OT_CLOSURE:
|
||||
pf(v,fmt::format("[{}] CLOSURE\n",name));
|
||||
pf(v,fmt::format(" [{}] CLOSURE\n",name));
|
||||
break;
|
||||
case OT_NATIVECLOSURE:
|
||||
pf(v,fmt::format("[{}] NATIVECLOSURE\n",name));
|
||||
pf(v,fmt::format(" [{}] NATIVECLOSURE\n",name));
|
||||
break;
|
||||
case OT_GENERATOR:
|
||||
pf(v,fmt::format("[{}] GENERATOR\n",name));
|
||||
pf(v,fmt::format(" [{}] GENERATOR\n",name));
|
||||
break;
|
||||
case OT_USERDATA:
|
||||
pf(v,fmt::format("[{}] USERDATA\n",name));
|
||||
pf(v,fmt::format(" [{}] USERDATA\n",name));
|
||||
break;
|
||||
case OT_THREAD:
|
||||
pf(v,fmt::format("[{}] THREAD\n",name));
|
||||
pf(v,fmt::format(" [{}] THREAD\n",name));
|
||||
break;
|
||||
case OT_CLASS:
|
||||
pf(v,fmt::format("[{}] CLASS\n",name));
|
||||
pf(v,fmt::format(" [{}] CLASS\n",name));
|
||||
break;
|
||||
case OT_INSTANCE:
|
||||
pf(v,fmt::format("[{}] INSTANCE\n",name));
|
||||
pf(v,fmt::format(" [{}] INSTANCE\n",name));
|
||||
break;
|
||||
case OT_WEAKREF:
|
||||
pf(v,fmt::format("[{}] WEAKREF\n",name));
|
||||
pf(v,fmt::format(" [{}] WEAKREF\n",name));
|
||||
break;
|
||||
case OT_BOOL:{
|
||||
sq_getbool(v,-1,&b);
|
||||
pf(v,fmt::format("[{}] {}\n",name,b?"true":"false"));
|
||||
pf(v,fmt::format(" [{}] {}\n",name,b?"true":"false"));
|
||||
}
|
||||
break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
sq_pop(v,1);
|
||||
}
|
||||
level++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -472,7 +472,7 @@ SQRESULT sq_setroottable(HSQUIRRELVM v)
|
||||
v->Pop();
|
||||
return SQ_OK;
|
||||
}
|
||||
return sq_throwerror(v, "ivalid type");
|
||||
return sq_throwerror(v, "invalid type");
|
||||
}
|
||||
|
||||
SQRESULT sq_setconsttable(HSQUIRRELVM v)
|
||||
@@ -483,7 +483,7 @@ SQRESULT sq_setconsttable(HSQUIRRELVM v)
|
||||
v->Pop();
|
||||
return SQ_OK;
|
||||
}
|
||||
return sq_throwerror(v, "ivalid type, expected table");
|
||||
return sq_throwerror(v, "invalid type, expected table");
|
||||
}
|
||||
|
||||
void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p)
|
||||
@@ -796,7 +796,7 @@ SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx)
|
||||
switch(type) {
|
||||
case OT_TABLE:
|
||||
if(type(mt) == OT_TABLE) {
|
||||
if(!_table(self)->SetDelegate(_table(mt))) return sq_throwerror(v, "delagate cycle");
|
||||
if(!_table(self)->SetDelegate(_table(mt))) return sq_throwerror(v, "delegate cycle");
|
||||
v->Pop();}
|
||||
else if(type(mt)==OT_NULL) {
|
||||
_table(self)->SetDelegate(nullptr); v->Pop(); }
|
||||
|
||||
+12
-3
@@ -519,6 +519,7 @@ bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQ
|
||||
|
||||
bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bottom, SQInteger func)
|
||||
{
|
||||
SQInteger initial_size = arr->Size();
|
||||
SQInteger maxChild;
|
||||
SQInteger done = 0;
|
||||
SQInteger ret;
|
||||
@@ -531,6 +532,10 @@ bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bott
|
||||
else {
|
||||
if(!_sort_compare(v,arr->_values[root2],arr->_values[root2 + 1],func,ret))
|
||||
return false;
|
||||
if (initial_size != arr->Size()) {
|
||||
v->Raise_Error("compare function modified array");
|
||||
return false;
|
||||
}
|
||||
if (ret > 0) {
|
||||
maxChild = root2;
|
||||
}
|
||||
@@ -542,10 +547,14 @@ bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bott
|
||||
|
||||
if(!_sort_compare(v,arr->_values[root],arr->_values[maxChild],func,ret))
|
||||
return false;
|
||||
if (initial_size != arr->Size()) {
|
||||
v->Raise_Error("compare function modified array");
|
||||
return false;
|
||||
}
|
||||
if (ret < 0) {
|
||||
if (root == maxChild) {
|
||||
v->Raise_Error("inconsistent compare function");
|
||||
return false; // We'd be swapping ourselve. The compare function is incorrect
|
||||
return false; // We'd be swapping ourself. The compare function is incorrect
|
||||
}
|
||||
_Swap(arr->_values[root],arr->_values[maxChild]);
|
||||
root = maxChild;
|
||||
@@ -596,7 +605,7 @@ static SQInteger array_slice(HSQUIRRELVM v)
|
||||
if(sidx < 0)sidx = alen + sidx;
|
||||
if(eidx < 0)eidx = alen + eidx;
|
||||
if(eidx < sidx)return sq_throwerror(v,"wrong indexes");
|
||||
if(eidx > alen)return sq_throwerror(v,"slice out of range");
|
||||
if(sidx < 0 || eidx > alen) return sq_throwerror(v,"slice out of range");
|
||||
SQArray *arr=SQArray::Create(_ss(v),eidx-sidx);
|
||||
SQObjectPtr t;
|
||||
SQInteger count=0;
|
||||
@@ -637,7 +646,7 @@ static SQInteger string_slice(HSQUIRRELVM v)
|
||||
if(sidx < 0)sidx = slen + sidx;
|
||||
if(eidx < 0)eidx = slen + eidx;
|
||||
if(eidx < sidx) return sq_throwerror(v,"wrong indexes");
|
||||
if(eidx > slen) return sq_throwerror(v,"slice out of range");
|
||||
if(sidx < 0 || eidx > slen) return sq_throwerror(v,"slice out of range");
|
||||
v->Push(SQString::Create(_ss(v),_stringval(o).substr(sidx,eidx-sidx)));
|
||||
return 1;
|
||||
}
|
||||
|
||||
+1
-1
@@ -245,7 +245,7 @@ bool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer de
|
||||
bool SafeRead(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUserPointer dest,SQInteger size)
|
||||
{
|
||||
if(size && read(up,dest,size) != size) {
|
||||
v->Raise_Error("io error, read function failure, the origin stream could be corrupted/trucated");
|
||||
v->Raise_Error("io error, read function failure, the origin stream could be corrupted/truncated");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
+2
-2
@@ -193,7 +193,7 @@ SQSharedState::~SQSharedState()
|
||||
t = nx;
|
||||
}
|
||||
}
|
||||
// assert(_gc_chain==nullptr); //just to proove a theory
|
||||
// assert(_gc_chain==nullptr); //just to prove a theory
|
||||
while(_gc_chain){
|
||||
_gc_chain->_uiRef--;
|
||||
_gc_chain->Release();
|
||||
@@ -227,7 +227,7 @@ SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name)
|
||||
* This is done internally by a vector onto which the to be freed instances are pushed. When
|
||||
* this is called when not already processing, this method will actually call the FinalFree
|
||||
* function which might cause more elements to end up in the queue which this method then
|
||||
* picks up continueing until it has processed all instances in that queue.
|
||||
* picks up continuing until it has processed all instances in that queue.
|
||||
* @param collectable The collectable to (eventually) free.
|
||||
*/
|
||||
void SQSharedState::DelayFinalFree(SQCollectable *collectable)
|
||||
|
||||
+3
-3
@@ -424,7 +424,7 @@ bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval)
|
||||
else retval = _null_;
|
||||
}
|
||||
else {
|
||||
if(target != -1) { //-1 is when a class contructor ret value has to be ignored
|
||||
if(target != -1) { //-1 is when a class constructor ret value has to be ignored
|
||||
if (_arg0 != MAX_FUNC_STACKSIZE)
|
||||
STK(target) = _stack._vals[oldstackbase+_arg1];
|
||||
else
|
||||
@@ -1285,8 +1285,8 @@ bool SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPt
|
||||
if(sq_isnumeric(key)){
|
||||
SQInteger n=tointeger(key);
|
||||
std::string_view str = _stringval(self);
|
||||
if(std::abs(n) < static_cast<SQInteger>(str.size())){
|
||||
if(n<0)n=str.size()+n;
|
||||
if (n < 0) n = str.size() + n;
|
||||
if (n >= 0 && n < static_cast<SQInteger>(str.size())) {
|
||||
dest=SQInteger(str[n]);
|
||||
return true;
|
||||
}
|
||||
|
||||
+5
-2
@@ -37,7 +37,7 @@ add_files(
|
||||
add_files(
|
||||
gfx_layout_icu.cpp
|
||||
gfx_layout_icu.h
|
||||
CONDITION ICU_i18n_FOUND AND HARFBUZZ_FOUND
|
||||
CONDITION ICU_I18N_FOUND AND HARFBUZZ_FOUND
|
||||
)
|
||||
|
||||
add_files(
|
||||
@@ -133,7 +133,8 @@ add_files(
|
||||
crashlog.cpp
|
||||
crashlog.h
|
||||
currency.cpp
|
||||
currency.h
|
||||
currency_func.h
|
||||
currency_type.h
|
||||
date_gui.cpp
|
||||
date_gui.h
|
||||
debug.cpp
|
||||
@@ -209,6 +210,7 @@ add_files(
|
||||
goal_base.h
|
||||
goal_cmd.h
|
||||
goal_gui.cpp
|
||||
goal_gui.h
|
||||
goal_type.h
|
||||
graph_gui.cpp
|
||||
graph_gui.h
|
||||
@@ -334,6 +336,7 @@ add_files(
|
||||
newgrf_town.h
|
||||
newgrf_townname.cpp
|
||||
newgrf_townname.h
|
||||
newgrf_type.h
|
||||
news_cmd.h
|
||||
news_func.h
|
||||
news_gui.cpp
|
||||
|
||||
+13
-7
@@ -37,6 +37,7 @@ public:
|
||||
|
||||
/**
|
||||
* Get the current AI tick.
|
||||
* @return The tick number.
|
||||
*/
|
||||
static uint GetTick();
|
||||
|
||||
@@ -97,30 +98,35 @@ public:
|
||||
|
||||
/**
|
||||
* Queue a new event for an AI.
|
||||
* @param company The company to receive the event.
|
||||
* @param event The event.
|
||||
*/
|
||||
static void NewEvent(CompanyID company, ScriptEvent *event);
|
||||
|
||||
/**
|
||||
* Broadcast a new event to all active AIs.
|
||||
* @param event The event to broadcast.
|
||||
* @param skip_company The optional company not to send the event to.
|
||||
*/
|
||||
static void BroadcastNewEvent(ScriptEvent *event, CompanyID skip_company = CompanyID::Invalid());
|
||||
|
||||
/**
|
||||
* Save data from an AI to a savegame.
|
||||
* @param company To company to save.
|
||||
*/
|
||||
static void Save(CompanyID company);
|
||||
|
||||
/** Wrapper function for AIScanner::GetAIConsoleList */
|
||||
/** @copydoc ScriptScanner::GetConsoleList */
|
||||
static void GetConsoleList(std::back_insert_iterator<std::string> &output_iterator, bool newest_only);
|
||||
/** Wrapper function for AIScanner::GetAIConsoleLibraryList */
|
||||
static void GetConsoleLibraryList(std::back_insert_iterator<std::string> &output_iterator);
|
||||
/** Wrapper function for AIScanner::GetAIInfoList */
|
||||
/** @copydoc ScriptScanner::GetConsoleList */
|
||||
static void GetConsoleLibraryList(std::back_insert_iterator<std::string> &output_iterator, bool newest_only);
|
||||
/** @copydoc ScriptScanner::GetInfoList */
|
||||
static const ScriptInfoList *GetInfoList();
|
||||
/** Wrapper function for AIScanner::GetUniqueAIInfoList */
|
||||
/** @copydoc ScriptScanner::GetUniqueInfoList */
|
||||
static const ScriptInfoList *GetUniqueInfoList();
|
||||
/** Wrapper function for AIScanner::FindInfo */
|
||||
/** @copydoc ScriptConfig::FindInfo */
|
||||
static class AIInfo *FindInfo(const std::string &name, int version, bool force_exact_match);
|
||||
/** Wrapper function for AIScanner::FindLibrary */
|
||||
/** @copydoc ScriptInstance::FindLibrary */
|
||||
static class AILibrary *FindLibrary(const std::string &library, int version);
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
{
|
||||
assert(company < MAX_COMPANIES);
|
||||
|
||||
if (_game_mode == GM_MENU) source = SSS_FORCE_NEWGAME;
|
||||
if (source == ScriptSettingSource::Default && _game_mode == GameMode::Menu) source = ScriptSettingSource::ForceNewGame;
|
||||
|
||||
if (source == SSS_DEFAULT) {
|
||||
if (source == ScriptSettingSource::Default) {
|
||||
Company *c = Company::GetIfValid(company);
|
||||
if (c != nullptr && c->ai_config != nullptr) return c->ai_config.get();
|
||||
}
|
||||
|
||||
auto &config = (source == SSS_FORCE_NEWGAME) ? _settings_newgame.script_config.ai[company] : _settings_game.script_config.ai[company];
|
||||
auto &config = (source == ScriptSettingSource::ForceNewGame) ? _settings_newgame.script_config.ai[company] : _settings_game.script_config.ai[company];
|
||||
if (config == nullptr) config = std::make_unique<AIConfig>();
|
||||
|
||||
return config.get();
|
||||
|
||||
+11
-2
@@ -13,21 +13,30 @@
|
||||
#include "../script/script_config.hpp"
|
||||
#include "../company_type.h"
|
||||
|
||||
/** AI instantion of script configuration. */
|
||||
class AIConfig : public ScriptConfig {
|
||||
public:
|
||||
/**
|
||||
* Get the config of a company.
|
||||
* Get the AI configuration of specific company.
|
||||
* @param company The company to get the configuration for.
|
||||
* @param source The context, i.e. current / new game mode.
|
||||
* @return The configuration.
|
||||
*/
|
||||
static AIConfig *GetConfig(CompanyID company, ScriptSettingSource source = SSS_DEFAULT);
|
||||
static AIConfig *GetConfig(CompanyID company, ScriptSettingSource source = ScriptSettingSource::Default);
|
||||
|
||||
AIConfig() :
|
||||
ScriptConfig()
|
||||
{}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
* @param config The configuration to copy.
|
||||
*/
|
||||
AIConfig(const AIConfig &config) :
|
||||
ScriptConfig(config)
|
||||
{}
|
||||
|
||||
/** @copydoc ScriptConfig::GetInfo. */
|
||||
class AIInfo *GetInfo() const;
|
||||
|
||||
/**
|
||||
|
||||
+46
-38
@@ -40,12 +40,12 @@
|
||||
/* Clients shouldn't start AIs */
|
||||
if (_networking && !_network_server) return;
|
||||
|
||||
Backup<CompanyID> cur_company(_current_company, company);
|
||||
AutoRestoreBackup cur_company(_current_company, company);
|
||||
Company *c = Company::Get(company);
|
||||
|
||||
AIConfig *config = c->ai_config.get();
|
||||
if (config == nullptr) {
|
||||
c->ai_config = std::make_unique<AIConfig>(*AIConfig::GetConfig(company, AIConfig::SSS_FORCE_GAME));
|
||||
c->ai_config = std::make_unique<AIConfig>(*AIConfig::GetConfig(company, AIConfig::ScriptSettingSource::ForceCurrentGame));
|
||||
config = c->ai_config.get();
|
||||
}
|
||||
|
||||
@@ -65,12 +65,20 @@
|
||||
c->ai_instance->LoadOnStack(config->GetToLoadData());
|
||||
config->SetToLoadData(nullptr);
|
||||
|
||||
cur_company.Restore();
|
||||
|
||||
InvalidateWindowClassesData(WC_SCRIPT_DEBUG, -1);
|
||||
InvalidateWindowClassesData(WindowClass::ScriptDebug, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the \c PerformanceElement for the AI of the given company.
|
||||
* @param company The company to get the PerformanceElement for.
|
||||
* @return The \c PerformanceElement.
|
||||
*/
|
||||
static constexpr PerformanceElement GetAIPerformanceElement(CompanyID company)
|
||||
{
|
||||
return static_cast<PerformanceElement>(PerformanceElement::AI0 + company);
|
||||
}
|
||||
|
||||
/* static */ void AI::GameLoop()
|
||||
{
|
||||
/* If we are in networking, only servers run this function, and that only if it is allowed */
|
||||
@@ -81,11 +89,10 @@
|
||||
assert(_settings_game.difficulty.competitor_speed <= 4);
|
||||
if ((AI::frame_counter & ((1 << (4 - _settings_game.difficulty.competitor_speed)) - 1)) != 0) return;
|
||||
|
||||
Backup<CompanyID> cur_company(_current_company);
|
||||
for (const Company *c : Company::Iterate()) {
|
||||
if (c->is_ai) {
|
||||
PerformanceMeasurer framerate((PerformanceElement)(PFE_AI0 + c->index));
|
||||
cur_company.Change(c->index);
|
||||
PerformanceMeasurer framerate(GetAIPerformanceElement(c->index));
|
||||
AutoRestoreBackup cur_company(_current_company, c->index);
|
||||
c->ai_instance->GameLoop();
|
||||
/* Occasionally collect garbage; every 255 ticks do one company.
|
||||
* Effectively collecting garbage once every two months per AI. */
|
||||
@@ -93,10 +100,9 @@
|
||||
c->ai_instance->CollectGarbage();
|
||||
}
|
||||
} else {
|
||||
PerformanceMeasurer::SetInactive((PerformanceElement)(PFE_AI0 + c->index));
|
||||
PerformanceMeasurer::SetInactive(GetAIPerformanceElement(c->index));
|
||||
}
|
||||
}
|
||||
cur_company.Restore();
|
||||
}
|
||||
|
||||
/* static */ uint AI::GetTick()
|
||||
@@ -107,18 +113,16 @@
|
||||
/* static */ void AI::Stop(CompanyID company)
|
||||
{
|
||||
if (_networking && !_network_server) return;
|
||||
PerformanceMeasurer::SetInactive((PerformanceElement)(PFE_AI0 + company));
|
||||
PerformanceMeasurer::SetInactive(GetAIPerformanceElement(company));
|
||||
|
||||
Backup<CompanyID> cur_company(_current_company, company);
|
||||
AutoRestoreBackup cur_company(_current_company, company);
|
||||
Company *c = Company::Get(company);
|
||||
|
||||
c->ai_instance.reset();
|
||||
c->ai_info = nullptr;
|
||||
c->ai_config.reset();
|
||||
|
||||
cur_company.Restore();
|
||||
|
||||
InvalidateWindowClassesData(WC_SCRIPT_DEBUG, -1);
|
||||
InvalidateWindowClassesData(WindowClass::ScriptDebug, -1);
|
||||
}
|
||||
|
||||
/* static */ void AI::Pause(CompanyID company)
|
||||
@@ -128,28 +132,20 @@
|
||||
* for the server owner to unpause the script again. */
|
||||
if (_network_dedicated) return;
|
||||
|
||||
Backup<CompanyID> cur_company(_current_company, company);
|
||||
AutoRestoreBackup cur_company(_current_company, company);
|
||||
Company::Get(company)->ai_instance->Pause();
|
||||
|
||||
cur_company.Restore();
|
||||
}
|
||||
|
||||
/* static */ void AI::Unpause(CompanyID company)
|
||||
{
|
||||
Backup<CompanyID> cur_company(_current_company, company);
|
||||
AutoRestoreBackup cur_company(_current_company, company);
|
||||
Company::Get(company)->ai_instance->Unpause();
|
||||
|
||||
cur_company.Restore();
|
||||
}
|
||||
|
||||
/* static */ bool AI::IsPaused(CompanyID company)
|
||||
{
|
||||
Backup<CompanyID> cur_company(_current_company, company);
|
||||
bool paused = Company::Get(company)->ai_instance->IsPaused();
|
||||
|
||||
cur_company.Restore();
|
||||
|
||||
return paused;
|
||||
AutoRestoreBackup cur_company(_current_company, company);
|
||||
return Company::Get(company)->ai_instance->IsPaused();
|
||||
}
|
||||
|
||||
/* static */ void AI::KillAll()
|
||||
@@ -247,9 +243,8 @@
|
||||
}
|
||||
|
||||
/* Queue the event */
|
||||
Backup<CompanyID> cur_company(_current_company, company);
|
||||
AutoRestoreBackup cur_company(_current_company, company);
|
||||
Company::Get(_current_company)->ai_instance->InsertEvent(event);
|
||||
cur_company.Restore();
|
||||
}
|
||||
|
||||
/* static */ void AI::BroadcastNewEvent(ScriptEvent *event, CompanyID skip_company)
|
||||
@@ -275,9 +270,8 @@
|
||||
|
||||
/* When doing emergency saving, an AI can be not fully initialised. */
|
||||
if (c->ai_instance != nullptr) {
|
||||
Backup<CompanyID> cur_company(_current_company, company);
|
||||
AutoRestoreBackup cur_company(_current_company, company);
|
||||
c->ai_instance->Save();
|
||||
cur_company.Restore();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -290,9 +284,9 @@
|
||||
AI::scanner_info->GetConsoleList(output_iterator, newest_only);
|
||||
}
|
||||
|
||||
/* static */ void AI::GetConsoleLibraryList(std::back_insert_iterator<std::string> &output_iterator)
|
||||
/* static */ void AI::GetConsoleLibraryList(std::back_insert_iterator<std::string> &output_iterator, bool newest_only)
|
||||
{
|
||||
AI::scanner_library->GetConsoleList(output_iterator, true);
|
||||
AI::scanner_library->GetConsoleList(output_iterator, newest_only);
|
||||
}
|
||||
|
||||
/* static */ const ScriptInfoList *AI::GetInfoList()
|
||||
@@ -323,32 +317,46 @@
|
||||
AI::scanner_library->RescanDir();
|
||||
ResetConfig();
|
||||
|
||||
InvalidateWindowData(WC_SCRIPT_LIST, 0, 1);
|
||||
SetWindowClassesDirty(WC_SCRIPT_DEBUG);
|
||||
InvalidateWindowClassesData(WC_SCRIPT_SETTINGS);
|
||||
InvalidateWindowData(WindowClass::ScriptList, 0, 1);
|
||||
SetWindowClassesDirty(WindowClass::ScriptDebug);
|
||||
InvalidateWindowClassesData(WindowClass::ScriptSettings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we have an AI (library) with the exact characteristics as ci.
|
||||
* Check whether we have an AI with the exact characteristics as ci.
|
||||
* @param ci the characteristics to search on (shortname and md5sum)
|
||||
* @param md5sum whether to check the MD5 checksum
|
||||
* @return true iff we have an AI (library) matching.
|
||||
* @return true iff we have an AI matching.
|
||||
*/
|
||||
/* static */ bool AI::HasAI(const ContentInfo &ci, bool md5sum)
|
||||
{
|
||||
return AI::scanner_info->HasScript(ci, md5sum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we have an AI library with the exact characteristics as ci.
|
||||
* @param ci the characteristics to search on (shortname and md5sum)
|
||||
* @param md5sum whether to check the MD5 checksum
|
||||
* @return true iff we have an AI library matching.
|
||||
*/
|
||||
/* static */ bool AI::HasAILibrary(const ContentInfo &ci, bool md5sum)
|
||||
{
|
||||
return AI::scanner_library->HasScript(ci, md5sum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scanner info for AIs.
|
||||
* @return The AI scanner info.
|
||||
*/
|
||||
/* static */ AIScannerInfo *AI::GetScannerInfo()
|
||||
{
|
||||
return AI::scanner_info.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scanner info for AI libraries.
|
||||
* @return The AI library scanner info.
|
||||
*/
|
||||
/* static */ AIScannerLibrary *AI::GetScannerLibrary()
|
||||
{
|
||||
return AI::scanner_library.get();
|
||||
|
||||
+43
-41
@@ -5,7 +5,7 @@
|
||||
* 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
|
||||
*/
|
||||
|
||||
/** @file ai_gui.cpp %Window for configuring the AIs */
|
||||
/** @file ai_gui.cpp %Window for configuring the AIs. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../error.h"
|
||||
@@ -30,51 +30,51 @@
|
||||
/** Widgets for the configure AI window. */
|
||||
static constexpr std::initializer_list<NWidgetPart> _nested_ai_config_widgets = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
|
||||
NWidget(WWT_CAPTION, COLOUR_MAUVE), SetStringTip(STR_AI_CONFIG_CAPTION_AI, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
NWidget(WWT_CLOSEBOX, Colours::Mauve),
|
||||
NWidget(WWT_CAPTION, Colours::Mauve), SetStringTip(STR_AI_CONFIG_CAPTION_AI, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
EndContainer(),
|
||||
NWidget(WWT_PANEL, COLOUR_MAUVE, WID_AIC_BACKGROUND),
|
||||
NWidget(WWT_PANEL, Colours::Mauve, WID_AIC_BACKGROUND),
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0), SetPadding(WidgetDimensions::unscaled.sparse),
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_sparse, 0),
|
||||
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0),
|
||||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_DECREASE_NUMBER), SetArrowWidgetTypeTip(AWV_DECREASE),
|
||||
NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_INCREASE_NUMBER), SetArrowWidgetTypeTip(AWV_INCREASE),
|
||||
NWidget(WWT_PUSHARROWBTN, Colours::Yellow, WID_AIC_DECREASE_NUMBER), SetArrowWidgetTypeTip(ArrowWidgetType::Decrease),
|
||||
NWidget(WWT_PUSHARROWBTN, Colours::Yellow, WID_AIC_INCREASE_NUMBER), SetArrowWidgetTypeTip(ArrowWidgetType::Increase),
|
||||
EndContainer(),
|
||||
NWidget(WWT_TEXT, INVALID_COLOUR, WID_AIC_NUMBER), SetFill(1, 0),
|
||||
NWidget(WWT_TEXT, Colours::Invalid, WID_AIC_NUMBER), SetFill(1, 0),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0),
|
||||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_DECREASE_INTERVAL), SetArrowWidgetTypeTip(AWV_DECREASE),
|
||||
NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_INCREASE_INTERVAL), SetArrowWidgetTypeTip(AWV_INCREASE),
|
||||
NWidget(WWT_PUSHARROWBTN, Colours::Yellow, WID_AIC_DECREASE_INTERVAL), SetArrowWidgetTypeTip(ArrowWidgetType::Decrease),
|
||||
NWidget(WWT_PUSHARROWBTN, Colours::Yellow, WID_AIC_INCREASE_INTERVAL), SetArrowWidgetTypeTip(ArrowWidgetType::Increase),
|
||||
EndContainer(),
|
||||
NWidget(WWT_TEXT, INVALID_COLOUR, WID_AIC_INTERVAL), SetFill(1, 0),
|
||||
NWidget(WWT_TEXT, Colours::Invalid, WID_AIC_INTERVAL), SetFill(1, 0),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_UP), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_AI_CONFIG_MOVE_UP, STR_AI_CONFIG_MOVE_UP_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_DOWN), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_AI_CONFIG_MOVE_DOWN, STR_AI_CONFIG_MOVE_DOWN_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_MOVE_UP), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_AI_CONFIG_MOVE_UP, STR_AI_CONFIG_MOVE_UP_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_MOVE_DOWN), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_AI_CONFIG_MOVE_DOWN, STR_AI_CONFIG_MOVE_DOWN_TOOLTIP),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
NWidget(WWT_FRAME, COLOUR_MAUVE), SetStringTip(STR_AI_CONFIG_AI), SetPIP(0, WidgetDimensions::unscaled.vsep_sparse, 0),
|
||||
NWidget(WWT_FRAME, Colours::Mauve), SetStringTip(STR_AI_CONFIG_AI), SetPIP(0, WidgetDimensions::unscaled.vsep_sparse, 0),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_LIST), SetMinimalSize(288, 112), SetFill(1, 0), SetMatrixDataTip(1, 8, STR_AI_CONFIG_AILIST_TOOLTIP), SetScrollbar(WID_AIC_SCROLLBAR),
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_AIC_SCROLLBAR),
|
||||
NWidget(WWT_MATRIX, Colours::Mauve, WID_AIC_LIST), SetMinimalSize(288, 112), SetFill(1, 0), SetMatrixDataTip(1, 8, STR_AI_CONFIG_AILIST_TOOLTIP), SetScrollbar(WID_AIC_SCROLLBAR),
|
||||
NWidget(NWID_VSCROLLBAR, Colours::Mauve, WID_AIC_SCROLLBAR),
|
||||
EndContainer(),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONFIGURE), SetFill(1, 0), SetStringTip(STR_AI_CONFIG_CONFIGURE, STR_AI_CONFIG_CONFIGURE_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_CONFIGURE), SetFill(1, 0), SetStringTip(STR_AI_CONFIG_CONFIGURE, STR_AI_CONFIG_CONFIGURE_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0),
|
||||
NWidget(NWID_VERTICAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CHANGE), SetFill(1, 1), SetStringTip(STR_AI_CONFIG_CHANGE_AI, STR_AI_CONFIG_CHANGE_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONTENT_DOWNLOAD), SetFill(1, 1), SetStringTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_CHANGE), SetFill(1, 1), SetStringTip(STR_AI_CONFIG_CHANGE_AI, STR_AI_CONFIG_CHANGE_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_CONTENT_DOWNLOAD), SetFill(1, 1), SetStringTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VERTICAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_OPEN_URL), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_README), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_README, STR_TEXTFILE_VIEW_README_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_OPEN_URL), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_TEXTFILE + TFT_README), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_README, STR_TEXTFILE_VIEW_README_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_LICENSE), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_LICENCE, STR_TEXTFILE_VIEW_LICENCE_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_TEXTFILE_VIEW_CHANGELOG_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, Colours::Yellow, WID_AIC_TEXTFILE + TFT_LICENSE), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TEXTFILE_VIEW_LICENCE, STR_TEXTFILE_VIEW_LICENCE_TOOLTIP),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
@@ -84,8 +84,8 @@ static constexpr std::initializer_list<NWidgetPart> _nested_ai_config_widgets =
|
||||
|
||||
/** Window definition for the configure AI window. */
|
||||
static WindowDesc _ai_config_desc(
|
||||
WDP_CENTER, {}, 0, 0,
|
||||
WC_GAME_OPTIONS, WC_NONE,
|
||||
WindowPosition::Center, {}, 0, 0,
|
||||
WindowClass::GameOptions, WindowClass::None,
|
||||
{},
|
||||
_nested_ai_config_widgets
|
||||
);
|
||||
@@ -100,7 +100,7 @@ struct AIConfigWindow : public Window {
|
||||
|
||||
AIConfigWindow() : Window(_ai_config_desc)
|
||||
{
|
||||
this->InitNested(WN_GAME_OPTIONS_AI); // Initializes 'this->line_height' as a side effect.
|
||||
this->InitNested(GameOptionsWindowNumber::AI); // Initializes 'this->line_height' as a side effect.
|
||||
this->vscroll = this->GetScrollbar(WID_AIC_SCROLLBAR);
|
||||
this->selected_slot = CompanyID::Invalid();
|
||||
NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_AIC_LIST);
|
||||
@@ -111,8 +111,8 @@ struct AIConfigWindow : public Window {
|
||||
|
||||
void Close([[maybe_unused]] int data = 0) override
|
||||
{
|
||||
CloseWindowByClass(WC_SCRIPT_LIST);
|
||||
CloseWindowByClass(WC_SCRIPT_SETTINGS);
|
||||
CloseWindowByClass(WindowClass::ScriptList);
|
||||
CloseWindowByClass(WindowClass::ScriptSettings);
|
||||
this->Window::Close();
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ struct AIConfigWindow : public Window {
|
||||
break;
|
||||
|
||||
case WID_AIC_LIST:
|
||||
this->line_height = GetCharacterHeight(FS_NORMAL) + padding.height;
|
||||
this->line_height = GetCharacterHeight(FontSize::Normal) + padding.height;
|
||||
fill.height = resize.height = this->line_height;
|
||||
size.height = 8 * this->line_height;
|
||||
break;
|
||||
@@ -155,7 +155,7 @@ struct AIConfigWindow : public Window {
|
||||
*/
|
||||
static bool IsEditable(CompanyID slot)
|
||||
{
|
||||
if (_game_mode != GM_NORMAL) {
|
||||
if (_game_mode != GameMode::Normal) {
|
||||
return slot > 0 && slot < MAX_COMPANIES;
|
||||
}
|
||||
return slot < MAX_COMPANIES && !Company::IsValidID(slot);
|
||||
@@ -168,7 +168,7 @@ struct AIConfigWindow : public Window {
|
||||
*/
|
||||
std::string GetSlotText(CompanyID cid) const
|
||||
{
|
||||
if ((_game_mode != GM_NORMAL && cid == 0) || (_game_mode == GM_NORMAL && Company::IsValidHumanID(cid))) return GetString(STR_AI_CONFIG_HUMAN_PLAYER);
|
||||
if ((_game_mode != GameMode::Normal && cid == 0) || (_game_mode == GameMode::Normal && Company::IsValidHumanID(cid))) return GetString(STR_AI_CONFIG_HUMAN_PLAYER);
|
||||
if (const AIInfo *info = AIConfig::GetConfig(cid)->GetInfo(); info != nullptr) return info->GetName();
|
||||
return GetString(STR_AI_CONFIG_RANDOM_AI);
|
||||
}
|
||||
@@ -181,10 +181,10 @@ struct AIConfigWindow : public Window {
|
||||
*/
|
||||
TextColour GetSlotColour(CompanyID cid, CompanyID max_slot) const
|
||||
{
|
||||
if (this->selected_slot == cid) return TC_WHITE;
|
||||
if (IsEditable(cid)) return cid < max_slot ? TC_ORANGE : TC_SILVER;
|
||||
if (Company::IsValidAiID(cid)) return TC_GREEN;
|
||||
return TC_SILVER;
|
||||
if (this->selected_slot == cid) return TextColour::White;
|
||||
if (IsEditable(cid)) return cid < max_slot ? TextColour::Orange : TextColour::Silver;
|
||||
if (Company::IsValidAiID(cid)) return TextColour::Green;
|
||||
return TextColour::Silver;
|
||||
}
|
||||
|
||||
void DrawWidget(const Rect &r, WidgetID widget) const override
|
||||
@@ -193,7 +193,7 @@ struct AIConfigWindow : public Window {
|
||||
case WID_AIC_LIST: {
|
||||
Rect tr = r.Shrink(WidgetDimensions::scaled.matrix);
|
||||
int max_slot = GetGameSettings().difficulty.max_no_competitors;
|
||||
if (_game_mode == GM_NORMAL) {
|
||||
if (_game_mode == GameMode::Normal) {
|
||||
for (const Company *c : Company::Iterate()) {
|
||||
if (c->is_ai) max_slot--;
|
||||
}
|
||||
@@ -258,7 +258,8 @@ struct AIConfigWindow : public Window {
|
||||
|
||||
case WID_AIC_MOVE_UP:
|
||||
if (IsEditable(this->selected_slot) && IsEditable(static_cast<CompanyID>(this->selected_slot - 1))) {
|
||||
std::swap(GetGameSettings().script_config.ai[this->selected_slot], GetGameSettings().script_config.ai[this->selected_slot - 1]);
|
||||
auto it = std::next(std::begin(GetGameSettings().script_config.ai), this->selected_slot.base());
|
||||
std::swap(*it, *std::prev(it));
|
||||
this->selected_slot = static_cast<CompanyID>(this->selected_slot - 1);
|
||||
this->vscroll->ScrollTowards(this->selected_slot.base());
|
||||
this->InvalidateData();
|
||||
@@ -267,7 +268,8 @@ struct AIConfigWindow : public Window {
|
||||
|
||||
case WID_AIC_MOVE_DOWN:
|
||||
if (IsEditable(this->selected_slot) && IsEditable(static_cast<CompanyID>(this->selected_slot + 1))) {
|
||||
std::swap(GetGameSettings().script_config.ai[this->selected_slot], GetGameSettings().script_config.ai[this->selected_slot + 1]);
|
||||
auto it = std::next(std::begin(GetGameSettings().script_config.ai), this->selected_slot.base());
|
||||
std::swap(*it, *std::next(it));
|
||||
++this->selected_slot;
|
||||
this->vscroll->ScrollTowards(this->selected_slot.base());
|
||||
this->InvalidateData();
|
||||
@@ -291,9 +293,9 @@ struct AIConfigWindow : public Window {
|
||||
|
||||
case WID_AIC_CONTENT_DOWNLOAD:
|
||||
if (!_network_available) {
|
||||
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_NOTAVAILABLE), {}, WL_ERROR);
|
||||
ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_NOTAVAILABLE), {}, WarningLevel::Error);
|
||||
} else {
|
||||
ShowNetworkContentListWindow(nullptr, CONTENT_TYPE_AI);
|
||||
ShowNetworkContentListWindow(nullptr, ContentType::Ai);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -324,7 +326,7 @@ struct AIConfigWindow : public Window {
|
||||
this->SetWidgetDisabledState(WID_AIC_MOVE_DOWN, !IsEditable(this->selected_slot) || !IsEditable(static_cast<CompanyID>(this->selected_slot + 1)));
|
||||
|
||||
this->SetWidgetDisabledState(WID_AIC_OPEN_URL, this->selected_slot == CompanyID::Invalid() || config->GetInfo() == nullptr || config->GetInfo()->GetURL().empty());
|
||||
for (TextfileType tft = TFT_CONTENT_BEGIN; tft < TFT_CONTENT_END; tft++) {
|
||||
for (TextfileType tft : EnumRange(TFT_CONTENT_BEGIN, TFT_CONTENT_END)) {
|
||||
this->SetWidgetDisabledState(WID_AIC_TEXTFILE + tft, this->selected_slot == CompanyID::Invalid() || !config->GetTextfile(tft, this->selected_slot).has_value());
|
||||
}
|
||||
}
|
||||
@@ -333,7 +335,7 @@ struct AIConfigWindow : public Window {
|
||||
/** Open the AI config window. */
|
||||
void ShowAIConfigWindow()
|
||||
{
|
||||
CloseWindowByClass(WC_GAME_OPTIONS);
|
||||
CloseWindowByClass(WindowClass::GameOptions);
|
||||
new AIConfigWindow();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
* 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
|
||||
*/
|
||||
|
||||
/** @file ai_gui.hpp %Window for configuring the AIs */
|
||||
/** @file ai_gui.hpp %Window for configuring the AIs. */
|
||||
|
||||
#ifndef AI_GUI_HPP
|
||||
#define AI_GUI_HPP
|
||||
|
||||
+3
-2
@@ -5,7 +5,7 @@
|
||||
* 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
|
||||
*/
|
||||
|
||||
/** @file ai_info.cpp Implementation of AIInfo and AILibrary */
|
||||
/** @file ai_info.cpp Implementation of AIInfo and AILibrary. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
/**
|
||||
* Check if the API version provided by the AI is supported.
|
||||
* @param api_version The API version as provided by the AI.
|
||||
* @return \c true if the given version is supported by this version of OpenTTD.
|
||||
*/
|
||||
static bool CheckAPIVersion(const std::string &api_version)
|
||||
{
|
||||
@@ -80,7 +81,7 @@ template <> SQInteger PushClassName<AIInfo, ScriptType::AI>(HSQUIRRELVM vm) { sq
|
||||
if (info->engine->MethodExists(info->SQ_instance, "GetAPIVersion")) {
|
||||
if (!info->engine->CallStringMethod(info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR;
|
||||
if (!CheckAPIVersion(info->api_version)) {
|
||||
Debug(script, 1, "Loading info.nut from ({}.{}): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion());
|
||||
sq_throwerror(vm, fmt::format("Loading info.nut from ({}.{}): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion()));
|
||||
return SQ_ERROR;
|
||||
}
|
||||
} else {
|
||||
|
||||
+15
-2
@@ -15,38 +15,47 @@
|
||||
/** All static information from an AI like name, version, etc. */
|
||||
class AIInfo : public ScriptInfo {
|
||||
public:
|
||||
/* All valid AI API versions, in order. */
|
||||
static constexpr std::string_view ApiVersions[]{ "0.7", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "12", "13", "14", "15" };
|
||||
/** All valid AI API versions, in order. */
|
||||
static constexpr std::string_view ApiVersions[]{ "0.7", "1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "12", "13", "14", "15", "16" };
|
||||
|
||||
AIInfo();
|
||||
|
||||
/**
|
||||
* Register the functions of this class.
|
||||
* @param engine The engine to register to.
|
||||
*/
|
||||
static void RegisterAPI(Squirrel &engine);
|
||||
|
||||
/**
|
||||
* Create an AI, using this AIInfo as start-template.
|
||||
* @param vm The virtual machine to push the instance to.
|
||||
* @return The number of stack places occupied.
|
||||
*/
|
||||
static SQInteger Constructor(HSQUIRRELVM vm);
|
||||
|
||||
/**
|
||||
* Create a dummy-AI.
|
||||
* @param vm The virtual machine to push the instance to.
|
||||
* @return The number of stack places occupied.
|
||||
*/
|
||||
static SQInteger DummyConstructor(HSQUIRRELVM vm);
|
||||
|
||||
/**
|
||||
* Check if we can start this AI.
|
||||
* @param version The version to check.
|
||||
* @return \c true if this script can load the data from that version.
|
||||
*/
|
||||
bool CanLoadFromVersion(int version) const;
|
||||
|
||||
/**
|
||||
* Use this AI as a random AI.
|
||||
* @return \c true when it can be used as random AI, \c false when the user must specifically request it.
|
||||
*/
|
||||
bool UseAsRandomAI() const { return this->use_as_random; }
|
||||
|
||||
/**
|
||||
* Get the API version this AI is written for.
|
||||
* @return The API version.
|
||||
*/
|
||||
const std::string &GetAPIVersion() const { return this->api_version; }
|
||||
|
||||
@@ -63,16 +72,20 @@ public:
|
||||
|
||||
/**
|
||||
* Register the functions of this class.
|
||||
* @param engine The engine to register to.
|
||||
*/
|
||||
static void RegisterAPI(Squirrel &engine);
|
||||
|
||||
/**
|
||||
* Create an AI, using this AIInfo as start-template.
|
||||
* @param vm The virtual machine to push the instance to.
|
||||
* @return The number of stack places occupied.
|
||||
*/
|
||||
static SQInteger Constructor(HSQUIRRELVM vm);
|
||||
|
||||
/**
|
||||
* Get the category this library is in.
|
||||
* @return The category.
|
||||
*/
|
||||
const std::string &GetCategory() const { return this->category; }
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ void AIInstance::RegisterAPI()
|
||||
/* Register all classes */
|
||||
SQAI_RegisterAll(*this->engine);
|
||||
|
||||
if (!this->LoadCompatibilityScripts(AI_DIR, AIInfo::ApiVersions)) this->Died();
|
||||
if (!this->LoadCompatibilityScripts(Subdirectory::Ai, AIInfo::ApiVersions)) this->Died();
|
||||
}
|
||||
|
||||
void AIInstance::Died()
|
||||
@@ -63,16 +63,16 @@ void AIInstance::Died()
|
||||
ScriptInstance::Died();
|
||||
|
||||
/* Intro is not supposed to use AI, but it may have 'dummy' AI which instant dies. */
|
||||
if (_game_mode == GM_MENU) return;
|
||||
if (_game_mode == GameMode::Menu) return;
|
||||
|
||||
/* Don't show errors while loading savegame. They will be shown at end of loading anyway. */
|
||||
if (_switch_mode != SM_NONE) return;
|
||||
if (_switch_mode != SwitchMode::None) return;
|
||||
|
||||
ShowScriptDebugWindow(_current_company);
|
||||
|
||||
const AIInfo *info = AIConfig::GetConfig(_current_company)->GetInfo();
|
||||
if (info != nullptr) {
|
||||
ShowErrorMessage(GetEncodedString(STR_ERROR_AI_PLEASE_REPORT_CRASH), {}, WL_WARNING);
|
||||
ShowErrorMessage(GetEncodedString(STR_ERROR_AI_PLEASE_REPORT_CRASH), {}, WarningLevel::Warning);
|
||||
|
||||
if (!info->GetURL().empty()) {
|
||||
ScriptLog::Info("Please report the error to the following URL:");
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
|
||||
*/
|
||||
|
||||
/** @file ai_scanner.cpp allows scanning AI scripts */
|
||||
/** @file ai_scanner.cpp Allows scanning AI scripts. */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include <ranges>
|
||||
@@ -53,7 +53,7 @@ void AIScannerInfo::RegisterAPI(class Squirrel &engine)
|
||||
|
||||
AIInfo *AIScannerInfo::SelectRandomAI() const
|
||||
{
|
||||
if (_game_mode == GM_MENU) {
|
||||
if (_game_mode == GameMode::Menu) {
|
||||
Debug(script, 0, "The intro game should not use AI, loading 'dummy' AI.");
|
||||
return this->info_dummy.get();
|
||||
}
|
||||
|
||||
@@ -5,17 +5,18 @@
|
||||
* 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
|
||||
*/
|
||||
|
||||
/** @file ai_scanner.hpp declarations of the class for AI scanner */
|
||||
/** @file ai_scanner.hpp Declarations of the class for AI scanner. */
|
||||
|
||||
#ifndef AI_SCANNER_HPP
|
||||
#define AI_SCANNER_HPP
|
||||
|
||||
#include "../script/script_scanner.hpp"
|
||||
|
||||
/** AI instantiation of a ScriptScanner. */
|
||||
class AIScannerInfo : public ScriptScanner {
|
||||
public:
|
||||
AIScannerInfo();
|
||||
~AIScannerInfo();
|
||||
~AIScannerInfo() override;
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
@@ -36,13 +37,14 @@ public:
|
||||
|
||||
/**
|
||||
* Set the Dummy AI.
|
||||
* @param info The new dummy AI.
|
||||
*/
|
||||
void SetDummyAI(std::unique_ptr<class AIInfo> &&info);
|
||||
|
||||
protected:
|
||||
std::string GetScriptName(ScriptInfo &info) override;
|
||||
std::string_view GetFileName() const override { return PATHSEP "info.nut"; }
|
||||
Subdirectory GetDirectory() const override { return AI_DIR; }
|
||||
Subdirectory GetDirectory() const override { return Subdirectory::Ai; }
|
||||
std::string_view GetScannerName() const override { return "AIs"; }
|
||||
void RegisterAPI(class Squirrel &engine) override;
|
||||
|
||||
@@ -50,6 +52,7 @@ private:
|
||||
std::unique_ptr<AIInfo> info_dummy; ///< The dummy AI.
|
||||
};
|
||||
|
||||
/** AI instantiation of a ScriptScanner for libraries. */
|
||||
class AIScannerLibrary : public ScriptScanner {
|
||||
public:
|
||||
void Initialize() override;
|
||||
@@ -65,7 +68,7 @@ public:
|
||||
protected:
|
||||
std::string GetScriptName(ScriptInfo &info) override;
|
||||
std::string_view GetFileName() const override { return PATHSEP "library.nut"; }
|
||||
Subdirectory GetDirectory() const override { return AI_LIBRARY_DIR; }
|
||||
Subdirectory GetDirectory() const override { return Subdirectory::AiLibrary; }
|
||||
std::string_view GetScannerName() const override { return "AI Libraries"; }
|
||||
void RegisterAPI(class Squirrel &engine) override;
|
||||
};
|
||||
|
||||
+14
-12
@@ -33,18 +33,21 @@ enum AircraftSubType : uint8_t {
|
||||
};
|
||||
|
||||
/** Flags for air vehicles; shared with disaster vehicles. */
|
||||
enum AirVehicleFlags : uint8_t {
|
||||
VAF_DEST_TOO_FAR = 0, ///< Next destination is too far away.
|
||||
enum class VehicleAirFlag : uint8_t {
|
||||
DestinationTooFar = 0, ///< Next destination is too far away.
|
||||
|
||||
/* The next two flags are to prevent stair climbing of the aircraft. The idea is that the aircraft
|
||||
* will ascend or descend multiple flight levels at a time instead of following the contours of the
|
||||
* landscape at a fixed altitude. This only has effect when there are more than 15 height levels. */
|
||||
VAF_IN_MAX_HEIGHT_CORRECTION = 1, ///< The vehicle is currently lowering its altitude because it hit the upper bound.
|
||||
VAF_IN_MIN_HEIGHT_CORRECTION = 2, ///< The vehicle is currently raising its altitude because it hit the lower bound.
|
||||
InMaximumHeightCorrection = 1, ///< The vehicle is currently lowering its altitude because it hit the upper bound.
|
||||
InMinimumHeightCorrection = 2, ///< The vehicle is currently raising its altitude because it hit the lower bound.
|
||||
|
||||
VAF_HELI_DIRECT_DESCENT = 3, ///< The helicopter is descending directly at its destination (helipad or in front of hangar)
|
||||
HelicopterDirectDescent = 3, ///< The helicopter is descending directly at its destination (helipad or in front of hangar)
|
||||
};
|
||||
|
||||
/** Bitset of \c VehicleAirFlag elements. */
|
||||
using VehicleAirFlags = EnumBitSet<VehicleAirFlag, uint8_t>;
|
||||
|
||||
static const int ROTOR_Z_OFFSET = 5; ///< Z Offset between helicopter- and rotorsprite.
|
||||
|
||||
void HandleAircraftEnterHangar(Aircraft *v);
|
||||
@@ -69,27 +72,26 @@ struct AircraftCache {
|
||||
/**
|
||||
* Aircraft, helicopters, rotors and their shadows belong to this class.
|
||||
*/
|
||||
struct Aircraft final : public SpecializedVehicle<Aircraft, VEH_AIRCRAFT> {
|
||||
struct Aircraft final : public SpecializedVehicle<Aircraft, VehicleType::Aircraft> {
|
||||
uint16_t crashed_counter = 0; ///< Timer for handling crash animations.
|
||||
uint8_t pos = 0; ///< Next desired position of the aircraft.
|
||||
uint8_t previous_pos = 0; ///< Previous desired position of the aircraft.
|
||||
StationID targetairport = StationID::Invalid(); ///< Airport to go to next.
|
||||
uint8_t state = 0; ///< State of the airport. @see AirportMovementStates
|
||||
Direction last_direction = INVALID_DIR;
|
||||
Direction last_direction = Direction::Invalid;
|
||||
uint8_t number_consecutive_turns = 0; ///< Protection to prevent the aircraft of making a lot of turns in order to reach a specific point.
|
||||
uint8_t turn_counter = 0; ///< Ticks between each turn to prevent > 45 degree turns.
|
||||
uint8_t flags = 0; ///< Aircraft flags. @see AirVehicleFlags
|
||||
VehicleAirFlags flags{}; ///< Aircraft flags. @see VehicleAirFlags
|
||||
|
||||
AircraftCache acache{};
|
||||
|
||||
/** We don't want GCC to zero our struct! It already is zeroed and has an index! */
|
||||
Aircraft() : SpecializedVehicleBase() {}
|
||||
Aircraft(VehicleID index) : SpecializedVehicleBase(index) {}
|
||||
/** We want to 'destruct' the right class. */
|
||||
virtual ~Aircraft() { this->PreDestructor(); }
|
||||
~Aircraft() override { this->PreDestructor(); }
|
||||
|
||||
void MarkDirty() override;
|
||||
void UpdateDeltaXY() override;
|
||||
ExpensesType GetExpenseType(bool income) const override { return income ? EXPENSES_AIRCRAFT_REVENUE : EXPENSES_AIRCRAFT_RUN; }
|
||||
ExpensesType GetExpenseType(bool income) const override { return income ? ExpensesType::AircraftRevenue : ExpensesType::AircraftRun; }
|
||||
bool IsPrimaryVehicle() const override { return this->IsNormalAircraft(); }
|
||||
void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const override;
|
||||
int GetDisplaySpeed() const override { return this->cur_speed; }
|
||||
|
||||
+127
-121
@@ -5,10 +5,7 @@
|
||||
* 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file aircraft_cmd.cpp
|
||||
* This file deals with aircraft and airport movements functionalities
|
||||
*/
|
||||
/** @file aircraft_cmd.cpp This file deals with aircraft and airport movements functionalities. */
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "aircraft.h"
|
||||
@@ -96,8 +93,9 @@ static const SpriteID _aircraft_sprite[] = {
|
||||
0x0EBD, 0x0EC5
|
||||
};
|
||||
|
||||
/** @copydoc IsValidImageIndex */
|
||||
template <>
|
||||
bool IsValidImageIndex<VEH_AIRCRAFT>(uint8_t image_index)
|
||||
bool IsValidImageIndex<VehicleType::Aircraft>(uint8_t image_index)
|
||||
{
|
||||
return image_index < lengthof(_aircraft_sprite);
|
||||
}
|
||||
@@ -121,7 +119,7 @@ static StationID FindNearestHangar(const Aircraft *v)
|
||||
{
|
||||
uint best = 0;
|
||||
StationID index = StationID::Invalid();
|
||||
TileIndex vtile = TileVirtXY(v->x_pos, v->y_pos);
|
||||
TileIndex vtile = TileVirtXYClampedToMap(v->x_pos, v->y_pos);
|
||||
const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type);
|
||||
uint max_range = v->acache.cached_max_range_sqr;
|
||||
|
||||
@@ -180,8 +178,8 @@ void Aircraft::GetImage(Direction direction, EngineImageType image_type, Vehicle
|
||||
spritenum = this->GetEngine()->original_image_index;
|
||||
}
|
||||
|
||||
assert(IsValidImageIndex<VEH_AIRCRAFT>(spritenum));
|
||||
result->Set(direction + _aircraft_sprite[spritenum]);
|
||||
assert(IsValidImageIndex<VehicleType::Aircraft>(spritenum));
|
||||
result->Set(to_underlying(direction) + _aircraft_sprite[spritenum]);
|
||||
}
|
||||
|
||||
void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result)
|
||||
@@ -204,14 +202,14 @@ static void GetAircraftIcon(EngineID engine, EngineImageType image_type, Vehicle
|
||||
uint8_t spritenum = e->VehInfo<AircraftVehicleInfo>().image_index;
|
||||
|
||||
if (IsCustomVehicleSpriteNum(spritenum)) {
|
||||
GetCustomVehicleIcon(engine, DIR_W, image_type, result);
|
||||
GetCustomVehicleIcon(engine, Direction::W, image_type, result);
|
||||
if (result->IsValid()) return;
|
||||
|
||||
spritenum = e->original_image_index;
|
||||
}
|
||||
|
||||
assert(IsValidImageIndex<VEH_AIRCRAFT>(spritenum));
|
||||
result->Set(DIR_W + _aircraft_sprite[spritenum]);
|
||||
assert(IsValidImageIndex<VehicleType::Aircraft>(spritenum));
|
||||
result->Set(to_underlying(Direction::W) + _aircraft_sprite[spritenum]);
|
||||
}
|
||||
|
||||
void DrawAircraftEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
|
||||
@@ -278,11 +276,11 @@ CommandCost CmdBuildAircraft(DoCommandFlags flags, TileIndex tile, const Engine
|
||||
tile = st->airport.GetHangarTile(st->airport.GetHangarNum(tile));
|
||||
|
||||
if (flags.Test(DoCommandFlag::Execute)) {
|
||||
Aircraft *v = new Aircraft(); // aircraft
|
||||
Aircraft *u = new Aircraft(); // shadow
|
||||
Aircraft *v = Aircraft::Create(); // aircraft
|
||||
Aircraft *u = Aircraft::Create(); // shadow
|
||||
*ret = v;
|
||||
|
||||
v->direction = DIR_SE;
|
||||
v->direction = Direction::SE;
|
||||
|
||||
v->owner = u->owner = _current_company;
|
||||
|
||||
@@ -369,9 +367,9 @@ CommandCost CmdBuildAircraft(DoCommandFlags flags, TileIndex tile, const Engine
|
||||
|
||||
/* Aircraft with 3 vehicles (chopper)? */
|
||||
if (v->subtype == AIR_HELICOPTER) {
|
||||
Aircraft *w = new Aircraft();
|
||||
Aircraft *w = Aircraft::Create();
|
||||
w->engine_type = e->index;
|
||||
w->direction = DIR_N;
|
||||
w->direction = Direction::N;
|
||||
w->owner = _current_company;
|
||||
w->x_pos = v->x_pos;
|
||||
w->y_pos = v->y_pos;
|
||||
@@ -429,10 +427,10 @@ static void CheckIfAircraftNeedsService(Aircraft *v)
|
||||
/* only goto depot if the target airport has a depot */
|
||||
if (st->airport.HasHangar() && CanVehicleUseStation(v, st)) {
|
||||
v->current_order.MakeGoToDepot(st->index, OrderDepotTypeFlag::Service);
|
||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
|
||||
SetWindowWidgetDirty(WindowClass::VehicleView, v->index, WID_VV_START_STOP);
|
||||
} else if (v->current_order.IsType(OT_GOTO_DEPOT)) {
|
||||
v->current_order.MakeDummy();
|
||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
|
||||
SetWindowWidgetDirty(WindowClass::VehicleView, v->index, WID_VV_START_STOP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,7 +438,7 @@ Money Aircraft::GetRunningCost() const
|
||||
{
|
||||
const Engine *e = this->GetEngine();
|
||||
uint cost_factor = GetVehicleProperty(this, PROP_AIRCRAFT_RUNNING_COST_FACTOR, e->VehInfo<AircraftVehicleInfo>().running_cost);
|
||||
return GetPrice(PR_RUNNING_AIRCRAFT, cost_factor, e->GetGRF());
|
||||
return GetPrice(Price::RunningAircraft, cost_factor, e->GetGRF());
|
||||
}
|
||||
|
||||
/** Calendar day handler */
|
||||
@@ -465,15 +463,15 @@ void Aircraft::OnNewEconomyDay()
|
||||
|
||||
if (this->running_ticks == 0) return;
|
||||
|
||||
CommandCost cost(EXPENSES_AIRCRAFT_RUN, this->GetRunningCost() * this->running_ticks / (CalendarTime::DAYS_IN_YEAR * Ticks::DAY_TICKS));
|
||||
CommandCost cost(ExpensesType::AircraftRun, this->GetRunningCost() * this->running_ticks / (CalendarTime::DAYS_IN_YEAR * Ticks::DAY_TICKS));
|
||||
|
||||
this->profit_this_year -= cost.GetCost();
|
||||
this->running_ticks = 0;
|
||||
|
||||
SubtractMoneyFromCompanyFract(this->owner, cost);
|
||||
|
||||
SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
|
||||
SetWindowClassesDirty(WC_AIRCRAFT_LIST);
|
||||
SetWindowDirty(WindowClass::VehicleDetails, this->index);
|
||||
SetWindowClassesDirty(WindowClass::AircraftList);
|
||||
}
|
||||
|
||||
static void HelicopterTickHandler(Aircraft *v)
|
||||
@@ -506,13 +504,13 @@ static void HelicopterTickHandler(Aircraft *v)
|
||||
VehicleSpriteSeq seq;
|
||||
if (spd == 0) {
|
||||
u->state = HRS_ROTOR_STOPPED;
|
||||
GetRotorImage(v, EIT_ON_MAP, &seq);
|
||||
GetRotorImage(v, EngineImageType::OnMap, &seq);
|
||||
if (u->sprite_cache.sprite_seq == seq) return;
|
||||
} else if (tick >= spd) {
|
||||
u->tick_counter = 0;
|
||||
u->state++;
|
||||
if (u->state > HRS_ROTOR_MOVING_3) u->state = HRS_ROTOR_MOVING_1;
|
||||
GetRotorImage(v, EIT_ON_MAP, &seq);
|
||||
GetRotorImage(v, EngineImageType::OnMap, &seq);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@@ -538,7 +536,7 @@ void SetAircraftPosition(Aircraft *v, int x, int y, int z)
|
||||
v->UpdatePosition();
|
||||
v->UpdateViewport(true, false);
|
||||
if (v->subtype == AIR_HELICOPTER) {
|
||||
GetRotorImage(v, EIT_ON_MAP, &v->Next()->Next()->sprite_cache.sprite_seq);
|
||||
GetRotorImage(v, EngineImageType::OnMap, &v->Next()->Next()->sprite_cache.sprite_seq);
|
||||
}
|
||||
|
||||
Aircraft *u = v->Next();
|
||||
@@ -618,7 +616,7 @@ void UpdateAircraftCache(Aircraft *v, bool update_range)
|
||||
|
||||
/* Update aircraft range. */
|
||||
if (update_range) {
|
||||
v->acache.cached_max_range = GetVehicleProperty(v, PROP_AIRCRAFT_RANGE, AircraftVehInfo(v->engine_type)->max_range);
|
||||
v->acache.cached_max_range = Engine::Get(v->engine_type)->GetRange();
|
||||
/* Squared it now so we don't have to do it later all the time. */
|
||||
v->acache.cached_max_range_sqr = v->acache.cached_max_range * v->acache.cached_max_range;
|
||||
}
|
||||
@@ -685,7 +683,7 @@ static int UpdateAircraftSpeed(Aircraft *v, uint speed_limit = SPEED_LIMIT_NONE,
|
||||
/* updates statusbar only if speed have changed to save CPU time */
|
||||
if (spd != v->cur_speed) {
|
||||
v->cur_speed = spd;
|
||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
|
||||
SetWindowWidgetDirty(WindowClass::VehicleView, v->index, WID_VV_START_STOP);
|
||||
}
|
||||
|
||||
/* Adjust distance moved by plane speed setting */
|
||||
@@ -726,7 +724,7 @@ int GetTileHeightBelowAircraft(const Vehicle *v)
|
||||
void GetAircraftFlightLevelBounds(const Vehicle *v, int *min_level, int *max_level)
|
||||
{
|
||||
int base_altitude = GetTileHeightBelowAircraft(v);
|
||||
if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->subtype == AIR_HELICOPTER) {
|
||||
if (v->type == VehicleType::Aircraft && Aircraft::From(v)->subtype == AIR_HELICOPTER) {
|
||||
base_altitude += HELICOPTER_HOLD_MAX_FLYING_ALTITUDE - PLANE_HOLD_MAX_FLYING_ALTITUDE;
|
||||
}
|
||||
|
||||
@@ -734,10 +732,10 @@ void GetAircraftFlightLevelBounds(const Vehicle *v, int *min_level, int *max_lev
|
||||
* other by providing them with vertical separation
|
||||
*/
|
||||
switch (v->direction) {
|
||||
case DIR_N:
|
||||
case DIR_NE:
|
||||
case DIR_E:
|
||||
case DIR_SE:
|
||||
case Direction::N:
|
||||
case Direction::NE:
|
||||
case Direction::E:
|
||||
case Direction::SE:
|
||||
base_altitude += 10;
|
||||
break;
|
||||
|
||||
@@ -781,24 +779,24 @@ int GetAircraftFlightLevel(T *v, bool takeoff)
|
||||
|
||||
int z = v->z_pos;
|
||||
if (z < aircraft_min_altitude ||
|
||||
(HasBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION) && z < aircraft_middle_altitude)) {
|
||||
(v->flags.Test(VehicleAirFlag::InMinimumHeightCorrection) && z < aircraft_middle_altitude)) {
|
||||
/* Ascend. And don't fly into that mountain right ahead.
|
||||
* And avoid our aircraft become a stairclimber, so if we start
|
||||
* correcting altitude, then we stop correction not too early. */
|
||||
SetBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION);
|
||||
v->flags.Set(VehicleAirFlag::InMinimumHeightCorrection);
|
||||
z += takeoff ? 2 : 1;
|
||||
} else if (!takeoff && (z > aircraft_max_altitude ||
|
||||
(HasBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION) && z > aircraft_middle_altitude))) {
|
||||
(v->flags.Test(VehicleAirFlag::InMaximumHeightCorrection) && z > aircraft_middle_altitude))) {
|
||||
/* Descend lower. You are an aircraft, not an space ship.
|
||||
* And again, don't stop correcting altitude too early. */
|
||||
SetBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION);
|
||||
v->flags.Set(VehicleAirFlag::InMaximumHeightCorrection);
|
||||
z--;
|
||||
} else if (HasBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION) && z >= aircraft_middle_altitude) {
|
||||
} else if (v->flags.Test(VehicleAirFlag::InMinimumHeightCorrection) && z >= aircraft_middle_altitude) {
|
||||
/* Now, we have corrected altitude enough. */
|
||||
ClrBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION);
|
||||
} else if (HasBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION) && z <= aircraft_middle_altitude) {
|
||||
v->flags.Reset(VehicleAirFlag::InMinimumHeightCorrection);
|
||||
} else if (v->flags.Test(VehicleAirFlag::InMaximumHeightCorrection) && z <= aircraft_middle_altitude) {
|
||||
/* Now, we have corrected altitude enough. */
|
||||
ClrBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION);
|
||||
v->flags.Reset(VehicleAirFlag::InMaximumHeightCorrection);
|
||||
}
|
||||
|
||||
return z;
|
||||
@@ -843,13 +841,13 @@ static uint8_t AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *a
|
||||
DiagDirection dir;
|
||||
if (abs(delta_y) < abs(delta_x)) {
|
||||
/* We are northeast or southwest of the airport */
|
||||
dir = delta_x < 0 ? DIAGDIR_NE : DIAGDIR_SW;
|
||||
dir = delta_x < 0 ? DiagDirection::NE : DiagDirection::SW;
|
||||
} else {
|
||||
/* We are northwest or southeast of the airport */
|
||||
dir = delta_y < 0 ? DIAGDIR_NW : DIAGDIR_SE;
|
||||
dir = delta_y < 0 ? DiagDirection::NW : DiagDirection::SE;
|
||||
}
|
||||
dir = ChangeDiagDir(dir, DiagDirDifference(DIAGDIR_NE, DirToDiagDir(rotation)));
|
||||
return apc->entry_points[dir];
|
||||
dir = ChangeDiagDir(dir, DiagDirDifference(DiagDirection::NE, DirToDiagDir(rotation)));
|
||||
return apc->entry_points[to_underlying(dir)];
|
||||
}
|
||||
|
||||
|
||||
@@ -868,7 +866,7 @@ static bool AircraftController(Aircraft *v)
|
||||
const Station *st = Station::GetIfValid(v->targetairport);
|
||||
/* INVALID_TILE if there is no station */
|
||||
TileIndex tile = INVALID_TILE;
|
||||
Direction rotation = DIR_N;
|
||||
Direction rotation = Direction::N;
|
||||
uint size_x = 1, size_y = 1;
|
||||
if (st != nullptr) {
|
||||
if (st->airport.tile != INVALID_TILE) {
|
||||
@@ -887,7 +885,7 @@ static bool AircraftController(Aircraft *v)
|
||||
if (st == nullptr || st->airport.tile == INVALID_TILE) {
|
||||
/* Jump into our "holding pattern" state machine if possible */
|
||||
if (v->pos >= afc->nofelements) {
|
||||
v->pos = v->previous_pos = AircraftGetEntryPoint(v, afc, DIR_N);
|
||||
v->pos = v->previous_pos = AircraftGetEntryPoint(v, afc, Direction::N);
|
||||
} else if (v->targetairport != v->current_order.GetDestination()) {
|
||||
/* If not possible, just get out of here fast */
|
||||
v->state = FLYING;
|
||||
@@ -943,7 +941,7 @@ static bool AircraftController(Aircraft *v)
|
||||
|
||||
/* Helicopter landing. */
|
||||
if (amd.flags.Test(AirportMovingDataFlag::HeliLower)) {
|
||||
SetBit(v->flags, VAF_HELI_DIRECT_DESCENT);
|
||||
v->flags.Set(VehicleAirFlag::HelicopterDirectDescent);
|
||||
|
||||
if (st == nullptr) {
|
||||
v->state = FLYING;
|
||||
@@ -970,7 +968,7 @@ static bool AircraftController(Aircraft *v)
|
||||
|
||||
/* Increase speed of rotors. When speed is 80, we've landed. */
|
||||
if (u->cur_speed >= 80) {
|
||||
ClrBit(v->flags, VAF_HELI_DIRECT_DESCENT);
|
||||
v->flags.Reset(VehicleAirFlag::HelicopterDirectDescent);
|
||||
return true;
|
||||
}
|
||||
u->cur_speed += 4;
|
||||
@@ -999,14 +997,14 @@ static bool AircraftController(Aircraft *v)
|
||||
DirDiff dirdiff = DirDifference(amd.direction, v->direction);
|
||||
/* if distance is 0, and plane points in right direction, no point in calling
|
||||
* UpdateAircraftSpeed(). So do it only afterwards */
|
||||
if (dirdiff == DIRDIFF_SAME) {
|
||||
if (dirdiff == DirDiff::Same) {
|
||||
v->cur_speed = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!UpdateAircraftSpeed(v, SPEED_LIMIT_TAXI)) return false;
|
||||
|
||||
v->direction = ChangeDir(v->direction, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
|
||||
v->direction = ChangeDir(v->direction, LimitDirDiff(dirdiff));
|
||||
v->cur_speed >>= 1;
|
||||
|
||||
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
|
||||
@@ -1184,6 +1182,7 @@ static bool AircraftController(Aircraft *v)
|
||||
/**
|
||||
* Handle crashed aircraft \a v.
|
||||
* @param v Crashed aircraft.
|
||||
* @return \c false iff the aircraft has been deleted.
|
||||
*/
|
||||
static bool HandleCrashedAircraft(Aircraft *v)
|
||||
{
|
||||
@@ -1208,7 +1207,7 @@ static bool HandleCrashedAircraft(Aircraft *v)
|
||||
uint32_t r;
|
||||
if (Chance16R(1, 32, r)) {
|
||||
static const DirDiff delta[] = {
|
||||
DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
|
||||
DirDiff::Left45, DirDiff::Same, DirDiff::Same, DirDiff::Right45
|
||||
};
|
||||
|
||||
v->direction = ChangeDir(v->direction, delta[GB(r, 16, 2)]);
|
||||
@@ -1224,7 +1223,7 @@ static bool HandleCrashedAircraft(Aircraft *v)
|
||||
/* remove rubble of crashed airplane */
|
||||
|
||||
/* clear runway-in on all airports, set by crashing plane
|
||||
* small airports use AIRPORT_BUSY, city airports use AirportBlock::RunwayInOut, etc.
|
||||
* small airports use AirportBlock::AirportBusy, city airports use AirportBlock::RunwayInOut, etc.
|
||||
* but they all share the same number */
|
||||
if (st != nullptr) {
|
||||
st->airport.blocks.Reset(AirportBlock::RunwayIn);
|
||||
@@ -1248,19 +1247,16 @@ static bool HandleCrashedAircraft(Aircraft *v)
|
||||
*/
|
||||
static void HandleAircraftSmoke(Aircraft *v, bool mode)
|
||||
{
|
||||
static const struct {
|
||||
int8_t x;
|
||||
int8_t y;
|
||||
} smoke_pos[] = {
|
||||
{ 5, 5 },
|
||||
{ 6, 0 },
|
||||
{ 5, -5 },
|
||||
{ 0, -6 },
|
||||
{ -5, -5 },
|
||||
{ -6, 0 },
|
||||
{ -5, 5 },
|
||||
{ 0, 6 }
|
||||
};
|
||||
static constexpr DirectionIndexArray<Coord2D<int8_t>> smoke_pos{{{
|
||||
{ 5, 5},
|
||||
{ 6, 0},
|
||||
{ 5, -5},
|
||||
{ 0, -6},
|
||||
{-5, -5},
|
||||
{-6, 0},
|
||||
{-5, 5},
|
||||
{ 0, 6},
|
||||
}}};
|
||||
|
||||
if (!v->vehstatus.Test(VehState::AircraftBroken)) return;
|
||||
|
||||
@@ -1301,9 +1297,8 @@ void HandleMissingAircraftOrders(Aircraft *v)
|
||||
*/
|
||||
const Station *st = GetTargetAirportIfValid(v);
|
||||
if (st == nullptr) {
|
||||
Backup<CompanyID> cur_company(_current_company, v->owner);
|
||||
CommandCost ret = Command<CMD_SEND_VEHICLE_TO_DEPOT>::Do(DoCommandFlag::Execute, v->index, DepotCommandFlag{}, {});
|
||||
cur_company.Restore();
|
||||
AutoRestoreBackup cur_company(_current_company, v->owner);
|
||||
CommandCost ret = Command<Commands::SendVehicleToDepot>::Do(DoCommandFlag::Execute, v->index, DepotCommandFlag{}, {});
|
||||
|
||||
if (ret.Failed()) CrashAirplane(v);
|
||||
} else if (!v->current_order.IsType(OT_GOTO_DEPOT)) {
|
||||
@@ -1328,7 +1323,7 @@ void Aircraft::MarkDirty()
|
||||
this->colourmap = PAL_NONE;
|
||||
this->UpdateViewport(true, false);
|
||||
if (this->subtype == AIR_HELICOPTER) {
|
||||
GetRotorImage(this, EIT_ON_MAP, &this->Next()->Next()->sprite_cache.sprite_seq);
|
||||
GetRotorImage(this, EngineImageType::OnMap, &this->Next()->Next()->sprite_cache.sprite_seq);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1354,7 +1349,7 @@ static void CrashAirplane(Aircraft *v)
|
||||
v->cargo.Truncate();
|
||||
v->Next()->cargo.Truncate();
|
||||
const Station *st = GetTargetAirportIfValid(v);
|
||||
TileIndex vt = TileVirtXY(v->x_pos, v->y_pos);
|
||||
TileIndex vt = TileVirtXYClampedToMap(v->x_pos, v->y_pos);
|
||||
|
||||
EncodedString headline;
|
||||
if (st == nullptr) {
|
||||
@@ -1420,8 +1415,8 @@ static void AircraftEntersTerminal(Aircraft *v)
|
||||
v->last_station_visited = v->targetairport;
|
||||
|
||||
/* Check if station was ever visited before */
|
||||
if (!(st->had_vehicle_of_type & HVOT_AIRCRAFT)) {
|
||||
st->had_vehicle_of_type |= HVOT_AIRCRAFT;
|
||||
if (!st->had_vehicle_of_type.Test(StationVehicleType::Aircraft)) {
|
||||
st->had_vehicle_of_type.Set(StationVehicleType::Aircraft);
|
||||
/* show newsitem of celebrating citizens */
|
||||
AddVehicleNewsItem(
|
||||
GetEncodedString(STR_NEWS_FIRST_AIRCRAFT_ARRIVAL, st->index),
|
||||
@@ -1456,7 +1451,10 @@ static void AircraftLandAirplane(Aircraft *v)
|
||||
}
|
||||
|
||||
|
||||
/** set the right pos when heading to other airports after takeoff */
|
||||
/**
|
||||
* Set the right pos when heading to other airports after takeoff
|
||||
* @param v The aircraft to consider.
|
||||
*/
|
||||
void AircraftNextAirportPos_and_Order(Aircraft *v)
|
||||
{
|
||||
if (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT)) {
|
||||
@@ -1465,7 +1463,7 @@ void AircraftNextAirportPos_and_Order(Aircraft *v)
|
||||
|
||||
const Station *st = GetTargetAirportIfValid(v);
|
||||
const AirportFTAClass *apc = st == nullptr ? GetAirport(AT_DUMMY) : st->airport.GetFTA();
|
||||
Direction rotation = st == nullptr ? DIR_N : st->airport.rotation;
|
||||
Direction rotation = st == nullptr ? Direction::N : st->airport.rotation;
|
||||
v->pos = v->previous_pos = AircraftGetEntryPoint(v, apc, rotation);
|
||||
}
|
||||
|
||||
@@ -1499,35 +1497,29 @@ void AircraftLeaveHangar(Aircraft *v, Direction exit_dir)
|
||||
VehicleServiceInDepot(v);
|
||||
v->LeaveUnbunchingDepot();
|
||||
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
|
||||
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
|
||||
SetWindowClassesDirty(WC_AIRCRAFT_LIST);
|
||||
InvalidateWindowData(WindowClass::VehicleDepot, v->tile);
|
||||
SetWindowClassesDirty(WindowClass::AircraftList);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////// AIRCRAFT MOVEMENT SCHEME ////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** Aircraft arrives at the terminal. @copydoc AircraftStateHandler */
|
||||
static void AircraftEventHandler_EnterTerminal(Aircraft *v, const AirportFTAClass *apc)
|
||||
{
|
||||
AircraftEntersTerminal(v);
|
||||
v->state = apc->layout[v->pos].heading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aircraft arrived in an airport hangar.
|
||||
* @param v Aircraft in the hangar.
|
||||
* @param apc Airport description containing the hangar.
|
||||
*/
|
||||
/** Aircraft arrived in an airport hangar. @copydoc AircraftStateHandler */
|
||||
static void AircraftEventHandler_EnterHangar(Aircraft *v, const AirportFTAClass *apc)
|
||||
{
|
||||
VehicleEnterDepot(v);
|
||||
v->state = apc->layout[v->pos].heading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle aircraft movement/decision making in an airport hangar.
|
||||
* @param v Aircraft in the hangar.
|
||||
* @param apc Airport description containing the hangar.
|
||||
*/
|
||||
/** Handle aircraft movement/decision making in an airport hangar. @copydoc AircraftStateHandler */
|
||||
static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *apc)
|
||||
{
|
||||
/* if we just arrived, execute EnterHangar first */
|
||||
@@ -1576,7 +1568,7 @@ static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *ap
|
||||
AirportMove(v, apc);
|
||||
}
|
||||
|
||||
/** At one of the Airport's Terminals */
|
||||
/** At one of the Airport's Terminals. @copydoc AircraftStateHandler */
|
||||
static void AircraftEventHandler_AtTerminal(Aircraft *v, const AirportFTAClass *apc)
|
||||
{
|
||||
/* if we just arrived, execute EnterTerminal first */
|
||||
@@ -1591,7 +1583,7 @@ static void AircraftEventHandler_AtTerminal(Aircraft *v, const AirportFTAClass *
|
||||
v->date_of_last_service_newgrf = TimerGameCalendar::date;
|
||||
v->breakdowns_since_last_service = 0;
|
||||
v->reliability = v->GetEngine()->reliability;
|
||||
SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
|
||||
SetWindowDirty(WindowClass::VehicleDetails, v->index);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -1631,31 +1623,30 @@ static void AircraftEventHandler_AtTerminal(Aircraft *v, const AirportFTAClass *
|
||||
AirportMove(v, apc);
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_General(Aircraft *, const AirportFTAClass *)
|
||||
{
|
||||
FatalError("OK, you shouldn't be here, check your Airport Scheme!");
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_TakeOff(Aircraft *v, const AirportFTAClass *)
|
||||
/** Aircraft is taking off (rolling). @copydoc AircraftStateHandler */
|
||||
static void AircraftEventHandler_TakeOff(Aircraft *v, [[maybe_unused]] const AirportFTAClass *apc)
|
||||
{
|
||||
PlayAircraftSound(v); // play takeoffsound for airplanes
|
||||
v->state = STARTTAKEOFF;
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_StartTakeOff(Aircraft *v, const AirportFTAClass *)
|
||||
/** Aircraft is taking off (rotation). @copydoc AircraftStateHandler */
|
||||
static void AircraftEventHandler_StartTakeOff(Aircraft *v, [[maybe_unused]] const AirportFTAClass *apc)
|
||||
{
|
||||
v->state = ENDTAKEOFF;
|
||||
v->UpdateDeltaXY();
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_EndTakeOff(Aircraft *v, const AirportFTAClass *)
|
||||
/** Aircraft has taken off. @copydoc AircraftStateHandler */
|
||||
static void AircraftEventHandler_EndTakeOff(Aircraft *v, [[maybe_unused]] const AirportFTAClass *apc)
|
||||
{
|
||||
v->state = FLYING;
|
||||
/* get the next position to go to, differs per airport */
|
||||
AircraftNextAirportPos_and_Order(v);
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_HeliTakeOff(Aircraft *v, const AirportFTAClass *)
|
||||
/** Helicopter takes off. @copydoc AircraftStateHandler */
|
||||
static void AircraftEventHandler_HeliTakeOff(Aircraft *v, [[maybe_unused]] const AirportFTAClass *apc)
|
||||
{
|
||||
v->state = FLYING;
|
||||
v->UpdateDeltaXY();
|
||||
@@ -1665,12 +1656,12 @@ static void AircraftEventHandler_HeliTakeOff(Aircraft *v, const AirportFTAClass
|
||||
|
||||
/* Send the helicopter to a hangar if needed for replacement */
|
||||
if (v->NeedsAutomaticServicing()) {
|
||||
Backup<CompanyID> cur_company(_current_company, v->owner);
|
||||
Command<CMD_SEND_VEHICLE_TO_DEPOT>::Do(DoCommandFlag::Execute, v->index, DepotCommandFlag::Service, {});
|
||||
cur_company.Restore();
|
||||
AutoRestoreBackup cur_company(_current_company, v->owner);
|
||||
Command<Commands::SendVehicleToDepot>::Do(DoCommandFlag::Execute, v->index, DepotCommandFlag::Service, {});
|
||||
}
|
||||
}
|
||||
|
||||
/** Aircraft is flying around. @copydoc AircraftStateHandler */
|
||||
static void AircraftEventHandler_Flying(Aircraft *v, const AirportFTAClass *apc)
|
||||
{
|
||||
Station *st = Station::Get(v->targetairport);
|
||||
@@ -1691,7 +1682,7 @@ static void AircraftEventHandler_Flying(Aircraft *v, const AirportFTAClass *apc)
|
||||
uint16_t tsubspeed = v->subspeed;
|
||||
if (!AirportHasBlock(v, current, apc)) {
|
||||
v->state = landingtype; // LANDING / HELILANDING
|
||||
if (v->state == HELILANDING) SetBit(v->flags, VAF_HELI_DIRECT_DESCENT);
|
||||
if (v->state == HELILANDING) v->flags.Set(VehicleAirFlag::HelicopterDirectDescent);
|
||||
/* it's a bit dirty, but I need to set position to next position, otherwise
|
||||
* if there are multiple runways, plane won't know which one it took (because
|
||||
* they all have heading LANDING). And also occupy that block! */
|
||||
@@ -1709,25 +1700,27 @@ static void AircraftEventHandler_Flying(Aircraft *v, const AirportFTAClass *apc)
|
||||
v->pos = apc->layout[v->pos].next_position;
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_Landing(Aircraft *v, const AirportFTAClass *)
|
||||
/** Aircraft is landing (touchdown). @copydoc AircraftStateHandler */
|
||||
static void AircraftEventHandler_Landing(Aircraft *v, [[maybe_unused]] const AirportFTAClass *apc)
|
||||
{
|
||||
v->state = ENDLANDING;
|
||||
AircraftLandAirplane(v); // maybe crash airplane
|
||||
|
||||
/* check if the aircraft needs to be replaced or renewed and send it to a hangar if needed */
|
||||
if (v->NeedsAutomaticServicing()) {
|
||||
Backup<CompanyID> cur_company(_current_company, v->owner);
|
||||
Command<CMD_SEND_VEHICLE_TO_DEPOT>::Do(DoCommandFlag::Execute, v->index, DepotCommandFlag::Service, {});
|
||||
cur_company.Restore();
|
||||
AutoRestoreBackup cur_company(_current_company, v->owner);
|
||||
Command<Commands::SendVehicleToDepot>::Do(DoCommandFlag::Execute, v->index, DepotCommandFlag::Service, {});
|
||||
}
|
||||
}
|
||||
|
||||
static void AircraftEventHandler_HeliLanding(Aircraft *v, const AirportFTAClass *)
|
||||
/** Helicopter is starting to land. @copydoc AircraftStateHandler */
|
||||
static void AircraftEventHandler_HeliLanding(Aircraft *v, [[maybe_unused]] const AirportFTAClass *apc)
|
||||
{
|
||||
v->state = HELIENDLANDING;
|
||||
v->UpdateDeltaXY();
|
||||
}
|
||||
|
||||
/** Aircraft is has landed. @copydoc AircraftStateHandler */
|
||||
static void AircraftEventHandler_EndLanding(Aircraft *v, const AirportFTAClass *apc)
|
||||
{
|
||||
/* next block busy, don't do a thing, just wait */
|
||||
@@ -1741,9 +1734,9 @@ static void AircraftEventHandler_EndLanding(Aircraft *v, const AirportFTAClass *
|
||||
if (AirportFindFreeTerminal(v, apc)) return;
|
||||
}
|
||||
v->state = HANGAR;
|
||||
|
||||
}
|
||||
|
||||
/** Helicopter has landed. @copydoc AircraftStateHandler */
|
||||
static void AircraftEventHandler_HeliEndLanding(Aircraft *v, const AirportFTAClass *apc)
|
||||
{
|
||||
/* next block busy, don't do a thing, just wait */
|
||||
@@ -1767,10 +1760,11 @@ static void AircraftEventHandler_HeliEndLanding(Aircraft *v, const AirportFTACla
|
||||
* @param v Aircraft to handle.
|
||||
* @param apc Airport state machine.
|
||||
*/
|
||||
typedef void AircraftStateHandler(Aircraft *v, const AirportFTAClass *apc);
|
||||
using AircraftStateHandler = void(Aircraft *v, const AirportFTAClass *apc);
|
||||
|
||||
/** Array of handler functions for each target of the aircraft. */
|
||||
static AircraftStateHandler * const _aircraft_state_handlers[] = {
|
||||
AircraftEventHandler_General, // TO_ALL = 0
|
||||
[](Aircraft *, const AirportFTAClass *) { NOT_REACHED(); }, // TO_ALL = 0
|
||||
AircraftEventHandler_InHangar, // HANGAR = 1
|
||||
AircraftEventHandler_AtTerminal, // TERM1 = 2
|
||||
AircraftEventHandler_AtTerminal, // TERM2 = 3
|
||||
@@ -1868,7 +1862,13 @@ static bool AirportMove(Aircraft *v, const AirportFTAClass *apc)
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
/** returns true if the road ahead is busy, eg. you must wait before proceeding. */
|
||||
/**
|
||||
* Checks whether the next block the aircraft wants to travel on is busy.
|
||||
* @param v The aircraft to consider.
|
||||
* @param current_pos The current position in the state machine the aircraft is at.
|
||||
* @param apc The airport's state machine.
|
||||
* @return \c true iff the road ahead is busy, eg. you must wait before proceeding.
|
||||
*/
|
||||
static bool AirportHasBlock(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc)
|
||||
{
|
||||
const AirportFTA *reference = &apc->layout[v->pos];
|
||||
@@ -2075,9 +2075,9 @@ static bool AirportFindFreeHelipad(Aircraft *v, const AirportFTAClass *apc)
|
||||
static void AircraftHandleDestTooFar(Aircraft *v, bool too_far)
|
||||
{
|
||||
if (too_far) {
|
||||
if (!HasBit(v->flags, VAF_DEST_TOO_FAR)) {
|
||||
SetBit(v->flags, VAF_DEST_TOO_FAR);
|
||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
|
||||
if (!v->flags.Test(VehicleAirFlag::DestinationTooFar)) {
|
||||
v->flags.Set(VehicleAirFlag::DestinationTooFar);
|
||||
SetWindowWidgetDirty(WindowClass::VehicleView, v->index, WID_VV_START_STOP);
|
||||
AI::NewEvent(v->owner, new ScriptEventAircraftDestTooFar(v->index));
|
||||
if (v->owner == _local_company) {
|
||||
/* Post a news message. */
|
||||
@@ -2087,14 +2087,20 @@ static void AircraftHandleDestTooFar(Aircraft *v, bool too_far)
|
||||
return;
|
||||
}
|
||||
|
||||
if (HasBit(v->flags, VAF_DEST_TOO_FAR)) {
|
||||
if (v->flags.Test(VehicleAirFlag::DestinationTooFar)) {
|
||||
/* Not too far anymore, clear flag and message. */
|
||||
ClrBit(v->flags, VAF_DEST_TOO_FAR);
|
||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
|
||||
v->flags.Reset(VehicleAirFlag::DestinationTooFar);
|
||||
SetWindowWidgetDirty(WindowClass::VehicleView, v->index, WID_VV_START_STOP);
|
||||
DeleteVehicleNews(v->index, AdviceType::AircraftDestinationTooFar);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler loop for a single aircraft.
|
||||
* @param v Aircraft to process events for.
|
||||
* @param loop How many times has this been called during this tick.
|
||||
* @return \c true iff another loop can take place, i.e. the vehicle still exists.
|
||||
*/
|
||||
static bool AircraftEventHandler(Aircraft *v, int loop)
|
||||
{
|
||||
if (v->vehstatus.Test(VehState::Crashed)) {
|
||||
@@ -2126,7 +2132,7 @@ static bool AircraftEventHandler(Aircraft *v, int loop)
|
||||
}
|
||||
}
|
||||
|
||||
if (!HasBit(v->flags, VAF_DEST_TOO_FAR)) AirportGoToNextPosition(v);
|
||||
if (!v->flags.Test(VehicleAirFlag::DestinationTooFar)) AirportGoToNextPosition(v);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2135,7 +2141,7 @@ bool Aircraft::Tick()
|
||||
{
|
||||
if (!this->IsNormalAircraft()) return true;
|
||||
|
||||
PerformanceAccumulator framerate(PFE_GL_AIRCRAFT);
|
||||
PerformanceAccumulator framerate(PerformanceElement::GameLoopAircraft);
|
||||
|
||||
this->tick_counter++;
|
||||
|
||||
@@ -2162,7 +2168,7 @@ bool Aircraft::Tick()
|
||||
*/
|
||||
Station *GetTargetAirportIfValid(const Aircraft *v)
|
||||
{
|
||||
assert(v->type == VEH_AIRCRAFT);
|
||||
assert(v->type == VehicleType::Aircraft);
|
||||
|
||||
Station *st = Station::GetIfValid(v->targetairport);
|
||||
if (st == nullptr) return nullptr;
|
||||
@@ -2178,7 +2184,7 @@ void UpdateAirplanesOnNewStation(const Station *st)
|
||||
{
|
||||
/* only 1 station is updated per function call, so it is enough to get entry_point once */
|
||||
const AirportFTAClass *ap = st->airport.GetFTA();
|
||||
Direction rotation = st->airport.tile == INVALID_TILE ? DIR_N : st->airport.rotation;
|
||||
Direction rotation = st->airport.tile == INVALID_TILE ? Direction::N : st->airport.rotation;
|
||||
|
||||
for (Aircraft *v : Aircraft::Iterate()) {
|
||||
if (!v->IsNormalAircraft() || v->targetairport != st->index) continue;
|
||||
@@ -2190,7 +2196,7 @@ void UpdateAirplanesOnNewStation(const Station *st)
|
||||
if (o->IsType(OT_GOTO_DEPOT) && !o->GetDepotOrderType().Test(OrderDepotTypeFlag::PartOfOrders) && o->GetDestination() == st->index &&
|
||||
(!st->airport.HasHangar() || !CanVehicleUseStation(v, st))) {
|
||||
o->MakeDummy();
|
||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
|
||||
SetWindowWidgetDirty(WindowClass::VehicleView, v->index, WID_VV_START_STOP);
|
||||
}
|
||||
v->pos = v->previous_pos = AircraftGetEntryPoint(v, ap, rotation);
|
||||
UpdateAircraftCache(v);
|
||||
|
||||
@@ -34,14 +34,14 @@ void DrawAircraftDetails(const Aircraft *v, const Rect &r)
|
||||
for (const Aircraft *u = v; u != nullptr; u = u->Next()) {
|
||||
if (u->IsNormalAircraft()) {
|
||||
DrawString(r.left, r.right, y, GetString(STR_VEHICLE_INFO_BUILT_VALUE, PackEngineNameDParam(u->engine_type, EngineNameContext::VehicleDetails), u->build_year, u->value));
|
||||
y += GetCharacterHeight(FS_NORMAL);
|
||||
y += GetCharacterHeight(FontSize::Normal);
|
||||
|
||||
if (u->Next()->cargo_cap != 0) {
|
||||
DrawString(r.left, r.right, y, GetString(STR_VEHICLE_INFO_CAPACITY_CAPACITY, u->cargo_type, u->cargo_cap, u->Next()->cargo_type, u->Next()->cargo_cap, GetCargoSubtypeText(u)));
|
||||
} else {
|
||||
DrawString(r.left, r.right, y, GetString(STR_VEHICLE_INFO_CAPACITY, u->cargo_type, u->cargo_cap, GetCargoSubtypeText(u)));
|
||||
}
|
||||
y += GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal;
|
||||
y += GetCharacterHeight(FontSize::Normal) + WidgetDimensions::scaled.vsep_normal;
|
||||
}
|
||||
|
||||
if (u->cargo_cap != 0) {
|
||||
@@ -50,7 +50,7 @@ void DrawAircraftDetails(const Aircraft *v, const Rect &r)
|
||||
if (cargo_count != 0) {
|
||||
/* Cargo names (fix pluralness) */
|
||||
DrawString(r.left, r.right, y, GetString(STR_VEHICLE_DETAILS_CARGO_FROM, u->cargo_type, cargo_count, u->cargo.GetFirstStation()));
|
||||
y += GetCharacterHeight(FS_NORMAL);
|
||||
y += GetCharacterHeight(FontSize::Normal);
|
||||
feeder_share += u->cargo.GetFeederShare();
|
||||
}
|
||||
}
|
||||
@@ -66,13 +66,14 @@ void DrawAircraftDetails(const Aircraft *v, const Rect &r)
|
||||
* @param v Front vehicle
|
||||
* @param r Rect to draw at
|
||||
* @param selection Selected vehicle to draw a frame around
|
||||
* @param image_type Context where the image is being drawn.
|
||||
*/
|
||||
void DrawAircraftImage(const Vehicle *v, const Rect &r, VehicleID selection, EngineImageType image_type)
|
||||
{
|
||||
bool rtl = _current_text_dir == TD_RTL;
|
||||
|
||||
VehicleSpriteSeq seq;
|
||||
v->GetImage(rtl ? DIR_E : DIR_W, image_type, &seq);
|
||||
v->GetImage(rtl ? Direction::E : Direction::W, image_type, &seq);
|
||||
|
||||
Rect rect;
|
||||
seq.GetBounds(&rect);
|
||||
@@ -111,6 +112,6 @@ void DrawAircraftImage(const Vehicle *v, const Rect &r, VehicleID selection, Eng
|
||||
x += x_offs;
|
||||
y += UnScaleGUI(rect.top) - heli_offs;
|
||||
Rect hr = {x, y, x + width - 1, y + UnScaleGUI(rect.Height()) + heli_offs - 1};
|
||||
DrawFrameRect(hr.Expand(WidgetDimensions::scaled.bevel), COLOUR_WHITE, FrameFlag::BorderOnly);
|
||||
DrawFrameRect(hr.Expand(WidgetDimensions::scaled.bevel), Colours::White, FrameFlag::BorderOnly);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
@@ -82,24 +82,24 @@ AirportMovingData RotateAirportMovingData(const AirportMovingData *orig, Directi
|
||||
{
|
||||
AirportMovingData amd;
|
||||
amd.flags = orig->flags;
|
||||
amd.direction = ChangeDir(orig->direction, (DirDiff)rotation);
|
||||
amd.direction = ChangeDir(orig->direction, static_cast<DirDiff>(rotation));
|
||||
switch (rotation) {
|
||||
case DIR_N:
|
||||
case Direction::N:
|
||||
amd.x = orig->x;
|
||||
amd.y = orig->y;
|
||||
break;
|
||||
|
||||
case DIR_E:
|
||||
case Direction::E:
|
||||
amd.x = orig->y;
|
||||
amd.y = num_tiles_y * TILE_SIZE - orig->x - 1;
|
||||
break;
|
||||
|
||||
case DIR_S:
|
||||
case Direction::S:
|
||||
amd.x = num_tiles_x * TILE_SIZE - orig->x - 1;
|
||||
amd.y = num_tiles_y * TILE_SIZE - orig->y - 1;
|
||||
break;
|
||||
|
||||
case DIR_W:
|
||||
case Direction::W:
|
||||
amd.x = num_tiles_x * TILE_SIZE - orig->y - 1;
|
||||
amd.y = orig->x;
|
||||
break;
|
||||
@@ -134,6 +134,8 @@ AirportFTAClass::AirportFTAClass(
|
||||
* Get the number of elements of a source Airport state automata
|
||||
* Since it is actually just a big array of AirportFTA types, we only
|
||||
* know one element from the other by differing 'position' identifiers
|
||||
* @param apFA The state machine builder.
|
||||
* @return The number of elements.
|
||||
*/
|
||||
static uint16_t AirportGetNofElements(const AirportFTAbuildup *apFA)
|
||||
{
|
||||
|
||||
+29
-25
@@ -5,7 +5,7 @@
|
||||
* 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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
|
||||
*/
|
||||
|
||||
/** @file airport.h Various declarations for airports */
|
||||
/** @file airport.h Various declarations for airports. */
|
||||
|
||||
#ifndef AIRPORT_H
|
||||
#define AIRPORT_H
|
||||
@@ -56,6 +56,7 @@ enum class AirportMovingDataFlag : uint8_t {
|
||||
Hold, ///< Holding pattern movement (above the airport).
|
||||
};
|
||||
|
||||
/** Bitset of \c AirportMovingDataFlag elements. */
|
||||
using AirportMovingDataFlags = EnumBitSet<AirportMovingDataFlag, uint16_t>;
|
||||
|
||||
/** Movement States on Airports (headings target) */
|
||||
@@ -96,40 +97,41 @@ enum class AirportBlock : uint8_t {
|
||||
Term6 = 5, ///< Block belonging to terminal 6.
|
||||
Helipad1 = 6, ///< Block belonging to helipad 1.
|
||||
Helipad2 = 7, ///< Block belonging to helipad 2.
|
||||
RunwayInOut = 8,
|
||||
RunwayIn = 8,
|
||||
AirportBusy = 8,
|
||||
RunwayOut = 9,
|
||||
TaxiwayBusy = 10,
|
||||
OutWay = 11,
|
||||
InWay = 12,
|
||||
AirportEntrance = 13,
|
||||
TermGroup1 = 14,
|
||||
TermGroup2 = 15,
|
||||
Hangar2Area = 16,
|
||||
TermGroup2Enter1 = 17,
|
||||
TermGroup2Enter2 = 18,
|
||||
TermGroup2Exit1 = 19,
|
||||
TermGroup2Exit2 = 20,
|
||||
PreHelipad = 21,
|
||||
RunwayInOut = 8, ///< Runway used for landing and take-off (commuter / city airports).
|
||||
RunwayIn = 8, ///< Runway used for landing (metropolitan / international / intercontinental airports).
|
||||
AirportBusy = 8, ///< Complete airport is busy (small airport / heliport).
|
||||
RunwayOut = 9, ///< Runway used for take off.
|
||||
TaxiwayBusy = 10, ///< Taxiway is occupied (commuter / city airports / helistation).
|
||||
OutWay = 11, ///< Holding point just before take off.
|
||||
InWay = 12, ///< Holding point just after take off.
|
||||
AirportEntrance = 13, ///< Entrance point before terminals.
|
||||
TermGroup1 = 14, ///< First set of terminals.
|
||||
TermGroup2 = 15, ///< Second set of terminals.
|
||||
Hangar2Area = 16, ///< Area in front of the second hangar.
|
||||
TermGroup2Enter1 = 17, ///< First holding point before terminal.
|
||||
TermGroup2Enter2 = 18, ///< Second holding point before terminal.
|
||||
TermGroup2Exit1 = 19, ///< First holding point after terminal.
|
||||
TermGroup2Exit2 = 20, ///< Second holding point after terminal.
|
||||
PreHelipad = 21, ///< Holding point for helicopter landings.
|
||||
|
||||
/* blocks for new airports */
|
||||
Term7 = 22, ///< Block belonging to terminal 7.
|
||||
Term8 = 23, ///< Block belonging to terminal 8.
|
||||
Helipad3 = 24, ///< Block belonging to helipad 3.
|
||||
Hangar1Area = 26,
|
||||
OutWay2 = 27,
|
||||
InWay2 = 28,
|
||||
RunwayIn2 = 29,
|
||||
RunwayOut2 = 10, ///< @note re-uses #AirportBlock::TaxiwayBusy
|
||||
HelipadGroup = 13, ///< @note re-uses #AirportBlock::AirportEntrance
|
||||
OutWay3 = 31,
|
||||
Hangar1Area = 26, ///< Area in front of the first hangar.
|
||||
OutWay2 = 27, ///< Second holding point just before take off.
|
||||
InWay2 = 28, ///< Second holding point just after take off.
|
||||
RunwayIn2 = 29, ///< Second runway for landing.
|
||||
RunwayOut2 = 10, ///< Second runway for take off. @note re-uses #AirportBlock::TaxiwayBusy
|
||||
OutWay3 = 31, ///< Third holding point just before take off.
|
||||
/* end of new blocks */
|
||||
|
||||
Nothing = 30,
|
||||
Nothing = 30, ///< Nothing is blocked, for example being in the hanger.
|
||||
Zeppeliner = 62, ///< Block for the zeppeliner disaster vehicle.
|
||||
AirportClosed = 63, ///< Dummy block for indicating a closed airport.
|
||||
};
|
||||
|
||||
/** Bitset of \c AirportBlock elements. */
|
||||
using AirportBlocks = EnumBitSet<AirportBlock, uint64_t>;
|
||||
|
||||
/** A single location on an airport where aircraft can move to. */
|
||||
@@ -164,6 +166,8 @@ public:
|
||||
Helicopters = 1, ///< Can helicopters land on this airport type?
|
||||
ShortStrip = 2, ///< This airport has a short landing strip, dangerous for fast aircraft.
|
||||
};
|
||||
|
||||
/** Bitset of \c Flag elements. */
|
||||
using Flags = EnumBitSet<Flag, uint8_t>;
|
||||
|
||||
AirportFTAClass(
|
||||
|
||||
+62
-57
@@ -73,9 +73,9 @@ static void PlaceAirport(TileIndex tile)
|
||||
|
||||
auto proc = [=](bool test, StationID to_join) -> bool {
|
||||
if (test) {
|
||||
return Command<CMD_BUILD_AIRPORT>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_AIRPORT>()), tile, airport_type, layout, StationID::Invalid(), adjacent).Succeeded();
|
||||
return Command<Commands::BuildAirport>::Do(CommandFlagsToDCFlags(GetCommandFlags<Commands::BuildAirport>()), tile, airport_type, layout, StationID::Invalid(), adjacent).Succeeded();
|
||||
} else {
|
||||
return Command<CMD_BUILD_AIRPORT>::Post(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE, CcBuildAirport, tile, airport_type, layout, to_join, adjacent);
|
||||
return Command<Commands::BuildAirport>::Post(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE, CcBuildAirport, tile, airport_type, layout, to_join, adjacent);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -84,7 +84,7 @@ static void PlaceAirport(TileIndex tile)
|
||||
|
||||
/** Airport build toolbar window handler. */
|
||||
struct BuildAirToolbarWindow : Window {
|
||||
WidgetID last_user_action = INVALID_WIDGET; // Last started user action.
|
||||
WidgetID last_user_action = INVALID_WIDGET; ///< Last started user action.
|
||||
|
||||
BuildAirToolbarWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
|
||||
{
|
||||
@@ -96,7 +96,7 @@ struct BuildAirToolbarWindow : Window {
|
||||
void Close([[maybe_unused]] int data = 0) override
|
||||
{
|
||||
if (this->IsWidgetLowered(WID_AT_AIRPORT)) SetViewportCatchmentStation(nullptr, true);
|
||||
if (_settings_client.gui.link_terraform_toolbar) CloseWindowById(WC_SCEN_LAND_GEN, 0, false);
|
||||
if (_settings_client.gui.link_terraform_toolbar) CloseWindowById(WindowClass::ScenarioGenerateLandscape, 0, false);
|
||||
this->Window::Close();
|
||||
}
|
||||
|
||||
@@ -109,10 +109,10 @@ struct BuildAirToolbarWindow : Window {
|
||||
{
|
||||
if (!gui_scope) return;
|
||||
|
||||
bool can_build = CanBuildVehicleInfrastructure(VEH_AIRCRAFT);
|
||||
bool can_build = CanBuildVehicleInfrastructure(VehicleType::Aircraft);
|
||||
this->SetWidgetDisabledState(WID_AT_AIRPORT, !can_build);
|
||||
if (!can_build) {
|
||||
CloseWindowById(WC_BUILD_STATION, TRANSPORT_AIR);
|
||||
CloseWindowById(WindowClass::BuildStation, TransportType::Air);
|
||||
|
||||
/* Show in the tooltip why this button is disabled. */
|
||||
this->GetWidget<NWidgetCore>(WID_AT_AIRPORT)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE);
|
||||
@@ -179,20 +179,20 @@ struct BuildAirToolbarWindow : Window {
|
||||
|
||||
this->RaiseButtons();
|
||||
|
||||
CloseWindowById(WC_BUILD_STATION, TRANSPORT_AIR);
|
||||
CloseWindowById(WC_SELECT_STATION, 0);
|
||||
CloseWindowById(WindowClass::BuildStation, TransportType::Air);
|
||||
CloseWindowById(WindowClass::JoinStation, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for global hotkeys of the BuildAirToolbarWindow.
|
||||
* @param hotkey Hotkey
|
||||
* @return ES_HANDLED if hotkey was accepted.
|
||||
* @return EventState::Handled if hotkey was accepted.
|
||||
*/
|
||||
static EventState AirportToolbarGlobalHotkeys(int hotkey)
|
||||
{
|
||||
if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED;
|
||||
if (_game_mode != GameMode::Normal) return EventState::NotHandled;
|
||||
Window *w = ShowBuildAirToolbar();
|
||||
if (w == nullptr) return ES_NOT_HANDLED;
|
||||
if (w == nullptr) return EventState::NotHandled;
|
||||
return w->OnHotkey(hotkey);
|
||||
}
|
||||
|
||||
@@ -204,20 +204,21 @@ struct BuildAirToolbarWindow : Window {
|
||||
|
||||
static constexpr std::initializer_list<NWidgetPart> _nested_air_toolbar_widgets = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_TOOLBAR_AIRCRAFT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_CLOSEBOX, Colours::DarkGreen),
|
||||
NWidget(WWT_CAPTION, Colours::DarkGreen), SetStringTip(STR_TOOLBAR_AIRCRAFT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
NWidget(WWT_STICKYBOX, Colours::DarkGreen),
|
||||
EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_AIRPORT), SetFill(0, 1), SetToolbarMinimalSize(2), SetSpriteTip(SPR_IMG_AIRPORT, STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP),
|
||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetToolbarSpacerMinimalSize(), SetFill(1, 1), EndContainer(),
|
||||
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_DEMOLISH), SetFill(0, 1), SetToolbarMinimalSize(1), SetSpriteTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
|
||||
NWidget(WWT_IMGBTN, Colours::DarkGreen, WID_AT_AIRPORT), SetFill(0, 1), SetToolbarMinimalSize(2), SetSpriteTip(SPR_IMG_AIRPORT, STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP),
|
||||
NWidget(WWT_PANEL, Colours::DarkGreen), SetToolbarSpacerMinimalSize(), SetFill(1, 1), EndContainer(),
|
||||
NWidget(WWT_IMGBTN, Colours::DarkGreen, WID_AT_DEMOLISH), SetFill(0, 1), SetToolbarMinimalSize(1), SetSpriteTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
/** Window definition for the air toolbar. */
|
||||
static WindowDesc _air_toolbar_desc(
|
||||
WDP_MANUAL, "toolbar_air", 0, 0,
|
||||
WC_BUILD_TOOLBAR, WC_NONE,
|
||||
WindowPosition::Manual, "toolbar_air", 0, 0,
|
||||
WindowClass::BuildToolbar, WindowClass::None,
|
||||
WindowDefaultFlag::Construction,
|
||||
_nested_air_toolbar_widgets,
|
||||
&BuildAirToolbarWindow::hotkeys
|
||||
@@ -234,8 +235,8 @@ Window *ShowBuildAirToolbar()
|
||||
{
|
||||
if (!Company::IsValidID(_local_company)) return nullptr;
|
||||
|
||||
CloseWindowByClass(WC_BUILD_TOOLBAR);
|
||||
return AllocateWindowDescFront<BuildAirToolbarWindow>(_air_toolbar_desc, TRANSPORT_AIR);
|
||||
CloseWindowByClass(WindowClass::BuildToolbar);
|
||||
return AllocateWindowDescFront<BuildAirToolbarWindow>(_air_toolbar_desc, TransportType::Air);
|
||||
}
|
||||
|
||||
class BuildAirportWindow : public PickerWindowBase {
|
||||
@@ -243,13 +244,16 @@ class BuildAirportWindow : public PickerWindowBase {
|
||||
int line_height = 0;
|
||||
Scrollbar *vscroll = nullptr;
|
||||
|
||||
/** Build a dropdown list of available airport classes */
|
||||
/**
|
||||
* Build a dropdown list of available airport classes.
|
||||
* @return The constructed dropdown list.
|
||||
*/
|
||||
static DropDownList BuildAirportClassDropDown()
|
||||
{
|
||||
DropDownList list;
|
||||
|
||||
for (const auto &cls : AirportClass::Classes()) {
|
||||
list.push_back(MakeDropDownListStringItem(cls.name, cls.Index()));
|
||||
list.push_back(MakeDropDownListStringItem(cls.name, cls.Index().base()));
|
||||
}
|
||||
|
||||
return list;
|
||||
@@ -264,14 +268,14 @@ public:
|
||||
this->vscroll->SetCapacity(5);
|
||||
this->vscroll->SetPosition(0);
|
||||
|
||||
this->FinishInitNested(TRANSPORT_AIR);
|
||||
this->FinishInitNested(TransportType::Air);
|
||||
|
||||
this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT, !_settings_client.gui.station_show_coverage);
|
||||
this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT, _settings_client.gui.station_show_coverage);
|
||||
this->OnInvalidateData();
|
||||
|
||||
/* Ensure airport class is valid (changing NewGRFs). */
|
||||
_selected_airport_class = Clamp(_selected_airport_class, APC_BEGIN, (AirportClassID)(AirportClass::GetClassCount() - 1));
|
||||
_selected_airport_class = Clamp(_selected_airport_class, AirportClassID::Begin(), static_cast<AirportClassID>(AirportClass::GetClassCount() - 1));
|
||||
const AirportClass *ac = AirportClass::Get(_selected_airport_class);
|
||||
this->vscroll->SetCount(ac->GetSpecCount());
|
||||
|
||||
@@ -295,7 +299,7 @@ public:
|
||||
|
||||
void Close([[maybe_unused]] int data = 0) override
|
||||
{
|
||||
CloseWindowById(WC_SELECT_STATION, 0);
|
||||
CloseWindowById(WindowClass::JoinStation, 0);
|
||||
this->PickerWindowBase::Close();
|
||||
}
|
||||
|
||||
@@ -344,7 +348,7 @@ public:
|
||||
size.width = std::max(size.width, GetStringBoundingBox(as->name).width + padding.width);
|
||||
}
|
||||
|
||||
this->line_height = GetCharacterHeight(FS_NORMAL) + padding.height;
|
||||
this->line_height = GetCharacterHeight(FontSize::Normal) + padding.height;
|
||||
size.height = 5 * this->line_height;
|
||||
break;
|
||||
}
|
||||
@@ -394,9 +398,9 @@ public:
|
||||
for (auto it = first; it != last; ++it) {
|
||||
const AirportSpec *as = *it;
|
||||
if (!as->IsAvailable()) {
|
||||
GfxFillRect(row, PC_BLACK, FILLRECT_CHECKER);
|
||||
GfxFillRect(row, PC_BLACK, FillRectMode::Checker);
|
||||
}
|
||||
DrawString(text, as->name, (static_cast<int>(as->index) == _selected_airport_index) ? TC_WHITE : TC_BLACK);
|
||||
DrawString(text, as->name, (static_cast<int>(as->index) == _selected_airport_index) ? TextColour::White : TextColour::Black);
|
||||
row = row.Translate(0, this->line_height);
|
||||
text = text.Translate(0, this->line_height);
|
||||
}
|
||||
@@ -415,7 +419,7 @@ public:
|
||||
const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index);
|
||||
StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_ADDITIONAL_TEXT);
|
||||
if (string != STR_UNDEFINED) {
|
||||
DrawStringMultiLine(r, string, TC_BLACK);
|
||||
DrawStringMultiLine(r, string, TextColour::Black);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -438,17 +442,17 @@ public:
|
||||
if (_settings_game.economy.station_noise_level) {
|
||||
/* show the noise of the selected airport */
|
||||
DrawString(r, GetString(STR_STATION_BUILD_NOISE, as->noise_level));
|
||||
r.top += GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal;
|
||||
r.top += GetCharacterHeight(FontSize::Normal) + WidgetDimensions::scaled.vsep_normal;
|
||||
}
|
||||
|
||||
if (_settings_game.economy.infrastructure_maintenance) {
|
||||
Money monthly = _price[PR_INFRASTRUCTURE_AIRPORT] * as->maintenance_cost >> 3;
|
||||
Money monthly = _price[Price::InfrastructureAirport] * as->maintenance_cost >> 3;
|
||||
DrawString(r, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_STATION_BUILD_INFRASTRUCTURE_COST_PERIOD : STR_STATION_BUILD_INFRASTRUCTURE_COST_YEAR, monthly * 12));
|
||||
r.top += GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal;
|
||||
r.top += GetCharacterHeight(FontSize::Normal) + WidgetDimensions::scaled.vsep_normal;
|
||||
}
|
||||
|
||||
/* strings such as 'Size' and 'Coverage Area' */
|
||||
r.top = DrawBadgeNameList(r, as->badges, GSF_AIRPORTS) + WidgetDimensions::scaled.vsep_normal;
|
||||
r.top = DrawBadgeNameList(r, as->badges, GrfSpecFeature::Airports) + WidgetDimensions::scaled.vsep_normal;
|
||||
r.top = DrawStationCoverageAreaText(r, SCT_ALL, rad, false) + WidgetDimensions::scaled.vsep_normal;
|
||||
r.top = DrawStationCoverageAreaText(r, SCT_ALL, rad, true);
|
||||
}
|
||||
@@ -481,7 +485,7 @@ public:
|
||||
int w = as->size_x;
|
||||
int h = as->size_y;
|
||||
Direction rotation = as->layouts[_selected_airport_layout].rotation;
|
||||
if (rotation == DIR_E || rotation == DIR_W) std::swap(w, h);
|
||||
if (rotation == Direction::E || rotation == Direction::W) std::swap(w, h);
|
||||
SetTileSelectSize(w, h);
|
||||
|
||||
this->preview_sprite = GetCustomAirportSprite(as, _selected_airport_layout);
|
||||
@@ -498,7 +502,7 @@ public:
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_AP_CLASS_DROPDOWN:
|
||||
ShowDropDownList(this, BuildAirportClassDropDown(), _selected_airport_class, WID_AP_CLASS_DROPDOWN);
|
||||
ShowDropDownList(this, BuildAirportClassDropDown(), _selected_airport_class.base(), WID_AP_CLASS_DROPDOWN);
|
||||
break;
|
||||
|
||||
case WID_AP_AIRPORT_LIST: {
|
||||
@@ -580,51 +584,52 @@ public:
|
||||
CheckRedrawStationCoverage(this);
|
||||
}
|
||||
|
||||
const IntervalTimer<TimerGameCalendar> yearly_interval = {{TimerGameCalendar::YEAR, TimerGameCalendar::Priority::NONE}, [this](auto) {
|
||||
const IntervalTimer<TimerGameCalendar> yearly_interval = {{TimerGameCalendar::Trigger::Year, TimerGameCalendar::Priority::None}, [this](auto) {
|
||||
this->InvalidateData();
|
||||
}};
|
||||
};
|
||||
|
||||
static constexpr std::initializer_list<NWidgetPart> _nested_build_airport_widgets = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_STATION_BUILD_AIRPORT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
NWidget(WWT_CLOSEBOX, Colours::DarkGreen),
|
||||
NWidget(WWT_CAPTION, Colours::DarkGreen), SetStringTip(STR_STATION_BUILD_AIRPORT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
|
||||
EndContainer(),
|
||||
NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
|
||||
NWidget(WWT_PANEL, Colours::DarkGreen),
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), SetPadding(WidgetDimensions::unscaled.picker),
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_picker, 0),
|
||||
NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL), SetFill(1, 0),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_AP_CLASS_DROPDOWN), SetFill(1, 0), SetToolTip(STR_STATION_BUILD_AIRPORT_TOOLTIP),
|
||||
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_AP_AIRPORT_SPRITE), SetFill(1, 0),
|
||||
NWidget(WWT_LABEL, Colours::Invalid), SetStringTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL), SetFill(1, 0),
|
||||
NWidget(WWT_DROPDOWN, Colours::Grey, WID_AP_CLASS_DROPDOWN), SetFill(1, 0), SetToolTip(STR_STATION_BUILD_AIRPORT_TOOLTIP),
|
||||
NWidget(WWT_EMPTY, Colours::Invalid, WID_AP_AIRPORT_SPRITE), SetFill(1, 0),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_MATRIX, COLOUR_GREY, WID_AP_AIRPORT_LIST), SetFill(1, 0), SetMatrixDataTip(1, 5, STR_STATION_BUILD_AIRPORT_TOOLTIP), SetScrollbar(WID_AP_SCROLLBAR),
|
||||
NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_AP_SCROLLBAR),
|
||||
NWidget(WWT_MATRIX, Colours::Grey, WID_AP_AIRPORT_LIST), SetFill(1, 0), SetMatrixDataTip(1, 5, STR_STATION_BUILD_AIRPORT_TOOLTIP), SetScrollbar(WID_AP_SCROLLBAR),
|
||||
NWidget(NWID_VSCROLLBAR, Colours::Grey, WID_AP_SCROLLBAR),
|
||||
EndContainer(),
|
||||
NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_STATION_BUILD_ORIENTATION), SetFill(1, 0),
|
||||
NWidget(WWT_LABEL, Colours::Invalid), SetStringTip(STR_STATION_BUILD_ORIENTATION), SetFill(1, 0),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_DECREASE), SetMinimalSize(12, 0), SetArrowWidgetTypeTip(AWV_DECREASE),
|
||||
NWidget(WWT_LABEL, INVALID_COLOUR, WID_AP_LAYOUT_NUM), SetResize(1, 0), SetFill(1, 0),
|
||||
NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_INCREASE), SetMinimalSize(12, 0), SetArrowWidgetTypeTip(AWV_INCREASE),
|
||||
NWidget(WWT_PUSHARROWBTN, Colours::Grey, WID_AP_LAYOUT_DECREASE), SetMinimalSize(12, 0), SetArrowWidgetTypeTip(ArrowWidgetType::Decrease),
|
||||
NWidget(WWT_LABEL, Colours::Invalid, WID_AP_LAYOUT_NUM), SetResize(1, 0), SetFill(1, 0),
|
||||
NWidget(WWT_PUSHARROWBTN, Colours::Grey, WID_AP_LAYOUT_INCREASE), SetMinimalSize(12, 0), SetArrowWidgetTypeTip(ArrowWidgetType::Increase),
|
||||
EndContainer(),
|
||||
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_AP_EXTRA_TEXT), SetFill(1, 0), SetMinimalSize(150, 0),
|
||||
NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE), SetFill(1, 0),
|
||||
NWidget(WWT_EMPTY, Colours::Invalid, WID_AP_EXTRA_TEXT), SetFill(1, 0), SetMinimalSize(150, 0),
|
||||
NWidget(WWT_LABEL, Colours::Invalid), SetStringTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE), SetFill(1, 0),
|
||||
NWidget(NWID_HORIZONTAL), SetPIP(14, 0, 14), SetPIPRatio(1, 0, 1),
|
||||
NWidget(NWID_HORIZONTAL, NWidContainerFlag::EqualSize),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DONTHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0),
|
||||
NWidget(WWT_TEXTBTN, Colours::Grey, WID_AP_BTN_DONTHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0),
|
||||
SetStringTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DOHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0),
|
||||
NWidget(WWT_TEXTBTN, Colours::Grey, WID_AP_BTN_DOHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0),
|
||||
SetStringTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
NWidget(WWT_EMPTY, INVALID_COLOUR, WID_AP_ACCEPTANCE), SetResize(0, 1), SetFill(1, 0), SetMinimalTextLines(2, WidgetDimensions::unscaled.vsep_normal),
|
||||
NWidget(WWT_EMPTY, Colours::Invalid, WID_AP_ACCEPTANCE), SetResize(0, 1), SetFill(1, 0), SetMinimalTextLines(2, WidgetDimensions::unscaled.vsep_normal),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
/** Window definition for the airport build window. */
|
||||
static WindowDesc _build_airport_desc(
|
||||
WDP_AUTO, {}, 0, 0,
|
||||
WC_BUILD_STATION, WC_BUILD_TOOLBAR,
|
||||
WindowPosition::Automatic, {}, 0, 0,
|
||||
WindowClass::BuildStation, WindowClass::BuildToolbar,
|
||||
WindowDefaultFlag::Construction,
|
||||
_nested_build_airport_widgets
|
||||
);
|
||||
@@ -636,6 +641,6 @@ static void ShowBuildAirportPicker(Window *parent)
|
||||
|
||||
void InitializeAirportGui()
|
||||
{
|
||||
_selected_airport_class = APC_BEGIN;
|
||||
_selected_airport_class = AirportClassID::Begin();
|
||||
_selected_airport_index = -1;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ void AddAnimatedTile(TileIndex tile, bool mark_dirty)
|
||||
*/
|
||||
void AnimateAnimatedTiles()
|
||||
{
|
||||
PerformanceAccumulator landscape_framerate(PFE_GL_LANDSCAPE);
|
||||
PerformanceAccumulator landscape_framerate(PerformanceElement::GameLoopLandscape);
|
||||
|
||||
for (auto it = std::begin(_animated_tiles); it != std::end(_animated_tiles); /* nothing */) {
|
||||
TileIndex &tile = *it;
|
||||
|
||||
@@ -35,6 +35,7 @@ inline AnimatedTileState GetAnimatedTileState(Tile t)
|
||||
/**
|
||||
* Set the animated state of a tile.
|
||||
* @param t The tile.
|
||||
* @param state The new state.
|
||||
*/
|
||||
inline void SetAnimatedTileState(Tile t, AnimatedTileState state)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user