1
0
mirror of https://github.com/OpenTTD/OpenTTD.git synced 2025-08-13 17:49:10 +00:00

Compare commits

..

149 Commits
13.2 ... 0.5.2

Author SHA1 Message Date
rubidium
9df8a3bd4c (svn r9978) -Release 0.5.2. 2007-05-29 18:13:06 +00:00
rubidium
4f757bb914 (svn r9977) [0.5] -Prepare 0.5 branch for release of 0.5.2. 2007-05-29 18:02:14 +00:00
rubidium
aafb49b3c4 (svn r9968) [0.5] -Backport from trunk (r9966):
- Fix: bridges and tunnels were not always removed on bankruptcy, thus leaving tunnels/bridges with an invalid owner that would crash the game when clicking with the query tool on them.
2007-05-28 22:11:42 +00:00
glx
4bbc264c72 (svn r9864) [0.5] -Codechange (win32): Remove references to MSLU and hide UNICODE notice for win9x users in installer 2007-05-17 19:47:04 +00:00
rubidium
f042798507 (svn r9863) [0.5] -Backport from trunk (r9759, r9861):
- Feature: Add threading support for MorphOS (r9759)
- Fix: Null pointer dereference under MorphOS and AmigaOS (r9861)
2007-05-17 15:04:28 +00:00
rubidium
909edb84af (svn r9859) [0.5] -Prepare 0.5 branch for release of 0.5.2-RC1. 2007-05-16 21:41:34 +00:00
rubidium
906a606418 (svn r9858) [0.5] -Backport from trunk (r9771, r9856):
- Feature: Add password protected status to 'players' (network server) console command (r9771)
- Fix: Loading some TTDP savegames caused an instant assertion on loading (r9857)
2007-05-16 21:33:07 +00:00
rubidium
2c6a0e46a9 (svn r9856) [0.5] -Backport from trunk (r9855):
- Fix: Do not perform any commands on MP_VOID tiles [FS#779] (r9855)
2007-05-16 08:21:16 +00:00
rubidium
236237740a (svn r9854) [0.5] -Backport from trunk (r9715, r9724, r9774, r9796, r9811, r9847): language updates. 2007-05-15 23:32:50 +00:00
rubidium
3a195edcad (svn r9853) [0.5] -Backport from trunk (r9837, r9827, r9785, r9775, r9758, r9716):
- Feature: Add server_lang in [network] section of openttd.cfg (r9716)
- Fix: [NewGRF] Catch occurance of division-by-zero in varaction handling (r9837)
- Fix: Only non dedicated servers cannot have 0 players [FS#765] (r9785)
- Fix: Remove arbitrary limit on length of NewGRF strings (r9775)
- Fix: [NewGRF] Ignore axis-bit of station tile layouts [FS#756] (r9758)
2007-05-15 22:02:32 +00:00
glx
c50cf74889 (svn r9852) [0.5] -Backport from trunk (r9728, r9834):
- Fix: [win32] Dead key and open/close console. (r9728)
- Add: win9x check in win32 builds
2007-05-15 22:00:41 +00:00
rubidium
4b6d1f9027 (svn r9851) [0.5] -Backport from trunk (r9731, r9741, r9743, r9753, r9757):
- Fix: when you have closed the "Load game"/"New game" windows which you started from the "start server" menu, you shouldn't start a server when starting a new game [SF#1244842] (r9757)
- Fix: Trains were lost after autorenewal/autoreplace [FS#732] (r9753)
- Fix: Stop flooded towns from building roads on water [FS#598] (r9743)
- Fix: Station signs were not resized when the language changed [FS#672] (r9741)
- Fix: In news history, newlines were not replaced with spaces [FS#677] (r9731)
2007-05-15 21:42:27 +00:00
rubidium
c9c087e858 (svn r9849) [0.5] -Backport from trunk (r9693, r9694, r9697, r9718, r9719, r9725 and 9726):
- Fix: Crash when destroying bridge with train partially on it [FS#738] (r9726)
- Fix: Planes made a 270 degree turn instead of a 90 degree turn on the southern runway of the intercontinental airport [FS#743] (r9725)
- Fix: In-game private messages did not work for clients with high ClientIDs (r9719)
- Fix: Do not allow building of rail vehicles whose railtype is not available (r9718)
- Fix: [YAPF] The guessed path was ignored for ships [FS#736] (r9694)
2007-05-15 21:24:18 +00:00
rubidium
ac66e29910 (svn r9698) [0.5] -Prepare 0.5 branch for release of 0.5.1. 2007-04-20 19:45:38 +00:00
rubidium
b7749bde91 (svn r9695) [0.5] -Backport from trunk (r9668, r9680, r9681, r9687): language updates. 2007-04-20 19:40:07 +00:00
rubidium
635eff5e51 (svn r9660) [0.5] -Prepare 0.5 branch for release of 0.5.1-RC3. 2007-04-17 20:11:11 +00:00
truelight
4cd6870777 (svn r9659) [0.5] -Fix r9656: missed 2 hunks in last commit 2007-04-17 19:08:08 +00:00
truelight
54cfb12334 (svn r9657) [0.5] -Backport from trunk (r9585, r9613, r9615, r9633, r9640, r9649):
- Language updates (r9585, r9613, r9615, r9633, r9640, r9649)
2007-04-17 19:05:47 +00:00
rubidium
2d746c52c8 (svn r9656) [0.5] -Backport from trunk (r9602, r9641, r9647):
- Fix: Building rail on steep slopes ignored build_on_slopes patch setting (r9602)
- Fix: namegen.cpp was not UTF-8, which caused artefacts in Finnish town names (r9641)
- Fix: Select "Custom" in the difficulty settings gui when changing a setting [FS#733] (r9647)
2007-04-17 18:09:12 +00:00
truelight
cb001e017a (svn r9589) [0.5] -Fix (r9587, r9588): this time I really do hope turkish.txt went okay... 2007-04-10 13:12:15 +00:00
truelight
9bee2fc641 (svn r9588) [0.5] -Fix r9587: something went wrong in turkish.txt update 2007-04-10 13:04:44 +00:00
truelight
7399e107e1 (svn r9587) [0.5] -Backport from trunk (r9585):
- Language updates (r9585)
2007-04-10 13:02:01 +00:00
truelight
70db6b3f40 (svn r9586) [0.5] -Backport from trunk (r9525, r9527, r9547, r9548, r9570, r9571, r9572, r9576):
- Language updates (r9525, r9527, r9547, r9548, r9570, r9571, r9572, r9576)
2007-04-10 12:58:05 +00:00
truelight
ac6aefa07b (svn r9584) [0.5] -Backport frmo trunk (r9542, r9565, r9573):
- Fix: when checking for no vehicle on ground-tiles, don't take into account vehicles that are in the air (r9542)
- Feature: add list_patches to console commands; shows all patches and values (r9565)
- Fix: enclose settings names containing spaces with quotes (r9573)
2007-04-10 09:57:35 +00:00
truelight
c04f0af19b (svn r9583) [0.5] -Backport from trunk (r9529, r9533, r9540, r9541):
- Fix: when 2 clients joined together, the second asserted on the NewCompany command of the first (r9529)
- Fix: when company is removed, sell all shares he has first, then sell all shares other people might have in this company (r9533)
- Fix: bankrupt AIs no longer buy over themselves (also added safeguards to prevent in future) (r9540 / r9541)
2007-04-10 09:49:41 +00:00
truelight
c8c8667dc8 (svn r9582) [0.5] -Backport from trunk (r9425, r9437, r9455, r9519):
- Fix: housekeeping in convert rail functions (r9425)
- Fix: dedicated server crashed when the y part of the resolution was less than 10 (r9437)
- Fix: values of diff_custom and snow_line in .cfg weren't checked properly (r9455)
- Fix: free the malloc'd variable, not the pointer to that variable (r9519)
2007-04-10 09:40:36 +00:00
belugas
a0688e8d85 (svn r9471) [0.5] -Backport from trunk (r9467 & r9469):
Reset the whole currency array while preserving custom one.  Also, max data of to_euro is now 300, not 1000, disabling any proper loading of the patch setting
2007-03-26 00:20:22 +00:00
truelight
c85022e3db (svn r9430) [0.5] -Backport r9429: when deleting a vehicle which has shared orders with one more vehicle and no orders, segfaulted 2007-03-24 15:16:41 +00:00
rubidium
be39b87154 (svn r9422) [0.5] -Prepare 0.5 branch for release of 0.5.1-RC2. 2007-03-23 22:54:19 +00:00
rubidium
71aa3a4de2 (svn r9421) [0.5] -Backport from trunk (r9392, r9415, r9420, custom):
- Fix: crashes when the chatbox would be drawn outside of the main window [FS#701] (r9420)
- Language updates (r9392, r9414, custom Simplified Chinese)
2007-03-23 22:44:03 +00:00
rubidium
f7fd8eca21 (svn r9394) [0.5] -Fix (r9343): reading out of an array caused a segmentation fault. 2007-03-21 23:06:01 +00:00
bjarni
ab77a35093 (svn r9384) [0.5] -Fix: [MorphOS] updated make release to avoid the need to specify RELEASE when building 2007-03-21 00:00:08 +00:00
rubidium
a808b77b2b (svn r9382) [0.5] -Prepare 0.5 branch for release of 0.5.1-RC1. 2007-03-20 21:12:18 +00:00
rubidium
52a0d04473 (svn r9380) [0.5] -Backport from trunk (r9378):
- Fix: cancel in password queries reduces amount of players in the network game when they haven't joined the game yet (r9378)
2007-03-20 20:36:45 +00:00
glx
64f7b3a059 (svn r9358) [0.5] -Backport from trunk (r9055, r9082, r9083, r9084, r9085, r9086):
- Codechange: Change windows unicode handling and allow a pure non-unicode build to function. (r9055)
- Codechange: [win32] Update VS2003 and VS2005 project files to build in UNICODE mode. When making a release it is probably better to make two binaries, one without UNICODE, the other with, guaranteeing full Win9x compatibility (UNICODE with MSLU also works, without it's even better). (r9082)
- Codechange: Be more lenient when trimming UTF-8 strings and don't terminate the string when an invalid encoding is encountered, but only focus on maximum length. (r9083)
- Fix: [win9x] Clipboard paste for Windows95 (doesn't have CF_UNICODETEXT) correctly converts the input to the current locale. (r9084)
- Fix: [win32] Move the initialisation of _codepage (non-UNICODE) to winMain as a dedicated server, or different video driver will not have a win32 messageloop. (r9085)
- Fix: [win32] Rewrite keyboard input and handle all keypresses in a WM_CHAR event. This saves us from doing translation (ToUnicode[Ex], ToAscii[Ex]), and we get free IME-input support as a plus. (r9086)
2007-03-20 00:02:18 +00:00
rubidium
b70c3613fa (svn r9355) [0.5] -Backport from trunk (r8906):
- Feature: translation dependant formatting of dates (r8906)
2007-03-19 22:08:18 +00:00
glx
3158cdaa7a (svn r9354) [0.5] -Backport from trunk (r8975, r9003, r9011, r9012):
-Regression: [win32] Possible buffer overflow if unicode text is pasted into an input box and needs trimming. (r8975)
-Codechange: Introduce a function Utf8PrevCharLen that finds the starting character of an UTF-8 sequence from a given position and returns the length to the first UTF-8 encoding byte of that sequence. (r9003)
-Codechange: Rework Utf8PrevChar so that it returns a pointer to the previous UTF8 character's first byte instead of a byte-length offset (r9011)
-Fix: When cutting strings into multiple lines also take into consideration whitespace characters of more than 1 byte length (eg IDEOGRAPHIC SPACE, IsWhitespace() function). When trimming such strings, account for multiple-byte long sequences so use *Utf8PrevChar(v) = '\0'. (r9012)
-Codechange: Add a function Utf8TrimString() that properly trims a string to an UTF8 encoding seperation instead of somewhere in the wild (and use it in the chat area) (r9012)
2007-03-19 21:42:05 +00:00
rubidium
140abde4ef (svn r9353) [0.5] -Backport language updates from trunk (r8957, r9002, r9005, r9013, r9014, r9020, r9021, r9054, r9116, r9118, r9132, r9286, r9292) 2007-03-19 21:04:06 +00:00
rubidium
850f73719f (svn r9351) [0.5] -Backport from trunk (r9147, r9205, r9251, r9298):
- Fix: when loadin games, enroute_from was updated in the wrong place, causing issues with TTD savegames/scenarios (r9147)
- Fix: when you started openttd with '-g' you got the same map every run (r9205)
- Fix: use a less CPU-intensive algorithm to find a random industry for the AI to prevent it slowing down the game (r9251)
- Fix: A34-1000, Z-Shuttle, and Kelling K1 are now listed as small aircraft (r9298)
2007-03-19 20:38:26 +00:00
rubidium
d2ce2009b5 (svn r9350) [0.5] -Backport from trunk (r9105, r9115, r9117, r9146):
- Fix: disable the ability to make flooding water with the canal build tool. In the scenario editor you can still make both canals and flooding water at height level 0 (r9105)
- Fix: make clear in the tooltips when the canal build tool (in the scenario editor) makes flooding water (r9115)
- Fix: difficulty level button was not selected when opening the difficulty window (r9117)
- Fix: "Train is lost" message is generated incorrectly (r9146)
2007-03-19 20:23:27 +00:00
rubidium
6ad4716dc1 (svn r9349) [0.5] -Backport from trunk (r9043, r9062, r9064, r9070):
- Fix: the personal (.openttd) directories were hidden in the load/save directory listings (r9043)
- Fix: the station list, sorted by cargo rating, now takes stations into account that have no cargo waiting (r9062)
- Fix: don't keep on scrolling for non-numeric values in settings, but require reclick (r9064)
- Fix: when a bribe failed and you haven't picked up cargo yet, you would never be able to do so for a given station (r9070)
2007-03-19 20:17:24 +00:00
rubidium
0ec558f99f (svn r9348) [0.5] -Backport from trunk (r8974, r8994, r9074):
- Fix: support compilation with the Vista Platform SDK (r8974)
- Fix: resolution doubled in cfg file when fullscreen mode used (r8994)
- Fix: win32 dedicated console now doesn't need an extra 'enter' to fully quit (r9074)
2007-03-19 20:05:49 +00:00
rubidium
41727b6e23 (svn r9347) [0.5] -Backport from trunk (r9019, r9076, r9077):
- Fix: use <> for system-headers (r9019)
- Fix: the intercontinental airport used 'T-junction' runway sprites when there is no exit in the middle of the runway as in the city airport (r9076)
- Fix: the wrong catenary wires were drawn for tunnel entrances (r9077)
2007-03-19 19:56:16 +00:00
rubidium
c559703312 (svn r9345) [0.5] -Backport from trunk (r9277, r9337, r9338):
- Fix: shared orders got messed up when the 'first' trains got removed in the depot (r9277)
- Fix: assert() when you removed the orders of a shared list while having the shared order vehicle list open (r9337)
- Fix: close the Shared Order Vehicle List if you remove the shared link with only 2 vehicles (r9338)
2007-03-19 19:42:40 +00:00
rubidium
1e7cca8f8b (svn r9344) [0.5] -Backport from trunk (r9027, r9038, r9061, r9071):
- Fix: desync caused by buffer overflow (r9027)
- Feature: kick inactive initial network connections after some time (r9038, r9061)
- Fix: take over companies properly in multiplayer games (r9071)
2007-03-19 19:34:44 +00:00
rubidium
759d155b08 (svn r9343) [0.5] -Backport from trunk (r9000, r9001, r9097, r9137):
- Fix: new locomotive names were not announced in the news, it said "new railway locomotive available - railway locomotive" (r9000, r9001)
- Feature: add an extra news group for opening and closing of industries (r9097)
- Fix: when all news-setting buttons are 'full', make the for-all button show 'full' too (r9137)
2007-03-19 19:22:26 +00:00
rubidium
11b1c6f2ee (svn r9342) [0.5] -Backport from trunk (r8980, r9065, r9339):
- Fix: the industry list should also be (re)set when the number of industries is 0 (r8980)
- Fix: possible dereference of NULL pointer (r9065)
- Codechange: disable shares by default and increase the default maximum distance from edge for oil refineries (r9339)
2007-03-19 18:54:48 +00:00
rubidium
98f77876e6 (svn r9341) [0.5] -Backport from trunk (r8943, r8955, r8976, r8999, r9009):
- Fix: NewGRF support for vehicle variable 48 (r8943)
- Fix: crash on loading savegames with GRFs that do not have their GRF info/name set (r8955)
- Fix: reinitialize all engines after grf files have been reloaded/changed (r8976)
- Fix: do not select a disabled platform length/number of track count when going out of drag-drop mode (r8999)
- Fix: play the correct engine sound based on the engine type instead of the sprite (r9009)
2007-03-19 18:47:10 +00:00
rubidium
5a703390ec (svn r9128) [0.5] -Fix: trains slow down under bridges when they were going down on the tile before the bridge tile. 2007-03-11 23:03:14 +00:00
Darkvater
e925f8b2c3 (svn r8930) [0.5] -Backport from trunk (r8929):
- [win32] Installer update (r8929)
2007-02-27 22:13:15 +00:00
Darkvater
01e3d92118 (svn r8923) [0.5] -Prepare (again) 0.5 branch for release, update a few dates and changelog 2007-02-27 16:29:22 +00:00
Darkvater
9321458918 (svn r8922) [0.5] -Backport from trunk (r8907, r8919, r8920, r8921):
- [OSX] Reading from an unitialized variable (r8907)
 - [Win9x] FindFile with C:\\* doesn't work, don't append a slash doubly (r8919)
 - Do not require to press 'Apply changes' in the newgrf GUI if the changes in there are not activated (this happens in the title screen) (r8920)
 - Possible crashes, problems with aircraft and airport removal (r8921)
2007-02-27 16:23:02 +00:00
Darkvater
cd6d6d32d3 (svn r8917) [0.5] -Codechange (win32): Do not empty the data-path for the installer if you press the 'Back' button. 2007-02-27 15:51:52 +00:00
Darkvater
5bfdc6e75a (svn r8916) [0.5] -Codechange (win32): Update the installer, add proper indentation, use MUI throughout and add a custom page about UNICODE and MSLU (remove some obsolete files) 2007-02-27 15:29:11 +00:00
Darkvater
274f841c61 (svn r8915) [0.5] -Codechange: Renamed remotely 2007-02-27 15:19:36 +00:00
matthijs
2b8a0dfacb (svn r8910) [Debian] -Fix: Remove old reference to rc4. 2007-02-26 21:37:14 +00:00
matthijs
4ba3761ab1 (svn r8909) [Debian] -Change: Update debian packaging files to those used for releases.
- Compile with freetype / fontconfig support.
	- Make menu files translatable.
	- Other packaging cleanups.
	- Bump version number to 0.5.0-1.
2007-02-26 21:18:57 +00:00
Darkvater
93586cb6b6 (svn r8905) [0.5] -Update readme's, bugs, installers, changelogs etc. to prepare for 0.5.0.
[0.5] -Remove the limitation that games are refused to be loaded if no newgrf is present (was already like this in trunk/).
2007-02-26 00:19:31 +00:00
Darkvater
c4768438b7 (svn r8895) [0.5] -Backport from trunk (r8645, r8671, r8686, r8690, r8719, r8728, r8729,
r8736, r8742, r8751, r8764, r8788, r8829, r8848, custom):
 - Language file updates.
 - Ukrainian(2), Lithuanian(15), Galician(151)
2007-02-25 10:05:33 +00:00
Darkvater
b3b28dced2 (svn r8883) [0.5] -Backport from trunk (r8740, r8793, r8865, r8878):
- GCC warnings for r8738 (r8740)
 - Correct spelling of real french townnames and 'remove' a duplicate (r8793)
 - (NewGRF) Ignore 1 byte action 0s during safety check (r8865)
 - Stricter checks for CmdMoveRailVehicle() parameters (r8878)
2007-02-24 16:46:36 +00:00
Darkvater
3b2bcbf0f0 (svn r8874) [0.5] -Backport from trunk (r8744, r8685):
- Call GetFirstVehicleInChain only for trains thus increasing performance in large games (r8744)
 - (Feature) Selecting "end of orders" and deleting will delete all the vehicle's orders (in unshared mode, shared is unchanged) (r8685)
2007-02-24 01:47:26 +00:00
Darkvater
1cdfa87b21 (svn r8873) [0.5] -Backport from trunk (r8766, r8836, r8869):
- Rail station platform penalty not calculated properly (r8766)
 - Don't tell destination was found if it was only guessed (r8836)
 - Large Train Stations/Trains causes assert due to wrong cost calculation (r8869)
2007-02-24 01:39:59 +00:00
Darkvater
9e3f020ae8 (svn r8872) [0.5] -Backport from trunk (r8784, r8821, r8823, r8824):
- Unable to load TTDP (on *NIX) games (r8784)
 - Unable to browse directories on *nix if the filesystem is not in UTF-8 charset and special characters are used (r8821, r8823, r8824)
2007-02-24 01:21:31 +00:00
Darkvater
36134a7285 (svn r8871) [0.5] -Backport from trunk (r8689, r8794, r8802, r8808):
- Crash when an old savegame had buoys on the northern edge of the map (r8689)
 - It was possible to take over buoys by building a station next to them (r8794)
 - Adhere order types for ship order insertion to determine destination type (r8802)
 - Do not show the 'edit sign' window for spectators (r8808)
2007-02-24 01:14:54 +00:00
Darkvater
edc2ac8bbf (svn r8870) [0.5] -Backport from trunk (r8684, r8709, r8738, r8777, r8828):
- Bool (uint32 in PPC) was written to as a uint8 (r8684)
 - Fix a problem where loading times for overhanging trains are miscomputed (r8709)
 - Load newer TTDP games (update coastal tiles) (r8738)
 - Cloning unaware of articulated locomotives that could refit without refitting the front unit (r8777)
 - Load station rectangle for all savegames, not only after version 27 (r8828)
2007-02-24 01:02:15 +00:00
Darkvater
c92b6e1e8b (svn r8861) [0.5] -Backport from trunk (r8526, r8792, r8825, r8843):
- Add stubs for unsupported newgrf station properties (r8526)
 - Be more strict about grf-string input (r8792, r8825)
 - Fix an off-by-one error in GRFComment (r8843)
2007-02-23 18:25:11 +00:00
rubidium
524919326b (svn r8761) [0.5] -Update: add some missing strings that are in 0.5, but not in trunk. 2007-02-16 18:36:36 +00:00
rubidium
2d3a64ffcc (svn r8687) [0.5] -Fix [FS#617]: assertion when getting the height of a bridge from the ramp tile. 2007-02-12 10:03:42 +00:00
rubidium
9aa9579283 (svn r8650) [0.5] -Fix: 'Searching Server' is not worthy of debug level 0, as this opens an extra window on MorphOS for no reason. 2007-02-09 11:13:03 +00:00
rubidium
3f987f460d (svn r8649) [0.5] -Fix (8630): accidentally removed strings that were still in use for by 0.5 and forgot to add new languages to langs*.vcproj. 2007-02-09 10:52:21 +00:00
bjarni
23e62bfb15 (svn r8643) [0.5] -Fix: [OSX] link statically to freetype when STATIC is set 2007-02-08 19:24:36 +00:00
rubidium
bbbe65e1e5 (svn r8639) [0.5] -Update readme's, bugs, installers, changelogs etc. to prepare for 0.5.0-RC5. 2007-02-08 16:18:11 +00:00
rubidium
e3c71534e1 (svn r8638) [0.5] -Backport from trunk (8637):
-Fix: CTRL-clicking on a hangar in the order list segfaulted as hangars are part of a station instead of real depots
2007-02-08 16:17:15 +00:00
rubidium
f8b2fb4484 (svn r8636) [0.5] -Backport from trunk (8634, 8635):
-Fix: draw canal edges under buoys that are in a canal
-Codechange: replace missing sprites with a red question mark
2007-02-08 14:10:14 +00:00
rubidium
87bbb7a413 (svn r8630) [0.5] -Backport lots of language updates from trunk 2007-02-08 11:26:09 +00:00
rubidium
61b95ff1fc (svn r8627) [0.5] -Backport from trunk (8409, 8420 + 8421, 8533, 8612):
-Regression: When the latest news was deleted, the news queue wrapped back to the oldest item, showing all news again.
-Regression [FS#573]: ShowLastNewsMessage could show an out-of-bounds news item because it did not checked if a previous item actually existed the first time it is called (forced news is INVALID_NEWS).
-Codechange: Rename the 'New <vehtype>' button of the global vehicle lists to 'Available <vehtype>' as it is a view-only list, not one from which you can purchase (rolling) stock.
-Fix: segmentation fault when the toolbar gets removed and you have selected one of the items in a submenu of the toolbar. 
-Fix [FS#582]: When the currently selected player in the performance details window is no longer active, choose the first active player instead of the first player as that may also be inactive.
2007-02-08 11:03:00 +00:00
rubidium
0543461f5e (svn r8626) [0.5] -Backport from trunk (8294, 8296, 8536, 8540, 8609):
-Fix: deleting a vehicle with shared orders, but no orders would fail to reset prev_shared and next_shared
-Fix: GenerateVehicleSortList()/CmdMassStartStopVehicle() tried to put a TileIndex into an uint16
-Fix (FS#577): Road Vehicles now can obtain a slot even if the station is very spread out 
-Fix[YAPF]: Assert when buoy is placed on NE or NW map edge (Dan)
-Fix: a road vehicle that is very close after another (slower) road vehicle gets its speed reset to 0 when entering a tunnel, which causes a traffic jam outside of the tunnel.
2007-02-08 10:41:45 +00:00
rubidium
4e3652f337 (svn r8625) [0.5] -Backport from trunk (8253, 8273, 8497, 8520 + 8542):
-Codechange: Be more strict about language generation and fail any languages not having the mandatory ##name, ##ownname and ##isocode pragma's.
-Fix: return value from clamp was ignored 
-Codechange: Increase the size of the sound/video/music-drivers to 32 bytes (instead of 16) so their actual parameters can be passed. Sound has for example 'bufsize' and 'hz'.
-Fix/Feature: requery gameservers that did not respond to their first query.
2007-02-08 10:19:03 +00:00
rubidium
1584e061eb (svn r8624) [0.5] -Backport from trunk (8239, 8240, 8315):
-Regression (r7278): Help window was empty for UNICODE builds 
-Fix (r8013): Put the output of -h to stdout and not to stderr (through ShowInfo) 
-Fix: use ShowInfo over fprintf(stderr, as Windows doesn't always have a stderr visible/available
2007-02-08 10:04:57 +00:00
rubidium
03bfa6e525 (svn r8623) [0.5] -Backport from trunk (8593, 8608, 8619, 8620)
-Fix (FS#564): bridges do not get destroyed when the bridge head gets flooded and there is a vehicle on the bridge.
-Fix: you were unable to build roads in the scenario editor when there is no town 0, even though there are other towns. 
-Fix: store the ownership of a water tile in the buoy tile and set the ownership of the water tile when the buoy is removed. This solves the issue of removing ownership from canal tiles thus making is possible for other players to remove the canal tile.
-Fix: buoys on canal tiles do not flood anymore.
2007-02-08 10:00:22 +00:00
bjarni
5467635bf9 (svn r8500) [0.5] -Fix: [OSX] freetype failed to be detected (now it's always enabled because Xcode installs it)
-Fix: [OSX] fontconfig is disabled even if it's found because the default one in OSX is 2.1.0 and OpenTTD needs at least 2.3.0
      -Fix: FREETYPE_CONFIG is only set when it's undefined. This makes it possible to add it as argument to make
2007-01-31 22:08:23 +00:00
rubidium
47c158bbc5 (svn r8490) [0.5] -Add: logging of the IP address and port of invalid/illegal UDP packets. 2007-01-31 12:47:35 +00:00
rubidium
4e1c7b8197 (svn r8489) [0.5] -Backport from trunk (8459, 8461): check for NewGRF compatability before actually downloading the map from a game server when connecting from the command prompt and internal console. 2007-01-31 12:39:41 +00:00
Darkvater
1ec915e1c8 (svn r8228) [0.5] -Revert win32 changes 2007-01-18 00:52:33 +00:00
Darkvater
b30c56d15a (svn r8227) [0.5] -Fix:?
- Prepare 0.5 branch for release. Update readme's, bugs, installers, changelog, etc. to 0.5.0-RC4
2007-01-18 00:50:56 +00:00
Darkvater
c3fcb2ef2a (svn r8222) [0.5] -Backport from trunk (lang, r8171, r8186, r8218):
- last missed chunk of danish language changes (lang)
 - (FS#556) return SL_ERROR when unthreaded saves failed (r8171)
 - (FS#557) apply railtype offset to station graphics if no custom station is in use (r8186)
 - Increase spritecache size to 2MB (r8218).
2007-01-17 23:39:13 +00:00
Darkvater
1a5957ef7f (svn r8217) [0.5] -Backport some mixed changes for WT2, remove wrong norwegian languages:
- Untranslated strings: Polish (4), Icelandic (221!), Galician (144)
2007-01-17 23:13:19 +00:00
Darkvater
0867ed49a3 (svn r8213) [0.5] -Backport from trunk (r7975, r7983, r7986, r7987, r8012, r8039, r8051,
r8053,  r8068, r8069, r8073, r8082, r8084, r8085, r8086, r8087, r8088, r8108,
 r8121, r8122, r8148, r8162, r8163, r8193, r8206):
 - Language file updates.
 - Untranslated strings: Polish (4), Icelandic (221!), Galician (144), Brazilian-Portugese (4).
 - Add Japanese, Norwegian bokmal/nynorsk, Slovenian as finished.
2007-01-17 22:37:14 +00:00
Darkvater
6c3b245d88 (svn r8182) -Backport from trunk (r8137, r8147, r8157):
- (FS#551) roadstop->num_vehicles was wrong for old savegames loaded for MP (r8137)
 - v->leave_depot_instantly was not always reset correctly (r8147)
 - moving cargo during auto replaces did not update the cached vehicle weight for trains properly (r8157)
 *NOTE* This fixes several desync issues. Big props to Rubidium for finding, debugging
 and fixing them!
2007-01-17 01:23:50 +00:00
Darkvater
a74b15af79 (svn r8181) -Backport from trunk (r8133):
- (FS#535) "out of sprite memory" warning messages (smatz)
2007-01-17 01:19:09 +00:00
Darkvater
ac3b1883ed (svn r8180) -Backport from trunk (r8093, r8094, r8105, r8106, (r8107), r8111, r8165):
- Show the activated status of the GRF after pressing apply in window (r8094)
 - Add the ability to load savegames without matching grf's.
   *NOTE*: currently this feature is different from trunk in behaviour as it does NOT
   allow you to load savegames with MISSING grfs only compatible (matching GRFID, non-
   matching MD5SUM).
2007-01-17 01:17:44 +00:00
Darkvater
40245ce496 (svn r8179) -Backport from trunk (r8065, r8101, r8119, r8123, r8140, r8150):
- The station list does now remember the sort settings (r8065)
 - Uninitializing windows calls WE_DESTROY to free dynamic memory used (r8101, r8119)
 - (FS#538) Findfirstbit returns first bit (bouys now numbered 1..9) (r8123)
 - FS#54) Combat helicopter shoots from right position, (r8140)
 - Submarine disaster did not move around (r8158)
2007-01-17 01:02:51 +00:00
Darkvater
c73bbe531e (svn r8178) -Backport from turnk (r8049, r8079, r8080, r8135):
- oe more news-window fix and fix up ShowLastNewsMessage (r8049)
 - float division by 0 in YAPF code on Win9x (r8079, r8080)
 - do not assert when removing duplicates would remove non-static grf (r8135)
2007-01-17 00:51:04 +00:00
matthijs
8576c2cc40 (svn r8177) - [Debian] Prepare debian packaging files for 0.5.0-rc4 2007-01-17 00:38:51 +00:00
Darkvater
1778566ab8 (svn r8176) -Backport from trunk (r8042, r8089, r8090, r8112):
- OS/2 compilation with GCC (thanks to Paul Smedley and TrueBrain for help) (r8042)
 - [win32] *nprintf functions are broken, 'len = count' wasn't handled (r8089, r8090)
 - MSVC solution files will make openttd THE startup project (r8112)
2007-01-17 00:38:27 +00:00
Darkvater
a4bab5f17f (svn r8175) -Backport from trunk (r8030, r8070, r8071, r8074):
- crash when removing a town in the scenario editor and the query tool is open for a town's tile (r8030)
 - (FS#537) heightmap crashes when rescaling, or using 24bpp bitmaps (r8070, r8074)
 - (FS#536) inauguration date of companies from TTDP games was wrong (r8071)
2007-01-17 00:29:16 +00:00
Darkvater
06367834c6 (svn r8174) -Backport from trunk (r8027, r8028, r8043, r8132):
- (FS#486) pause command issues with shift-pressed did not pause the game, interference with pause_on_join (r8027)
 - overflow of ticks was not handled properly, possibly resulting a non-reacting gameserver/gameclient (r8028, r8043)
 - The game could crash when the chat key (<ENTER>) is pressed too quickly during join (r8132)
2007-01-17 00:20:23 +00:00
Darkvater
f08141ae48 (svn r8173) -Backport from trunk (r8026):
- picking up transferring cargo, trains will now also have the virtual profit deducted
2007-01-17 00:08:49 +00:00
Darkvater
25059d28df (svn r8172) -Backport from trunk (r8013, r8134):
- Show error messages about our own data files as ShowInfo(F) and output console error to stderr and not stdout.
2007-01-17 00:05:51 +00:00
Darkvater
b57b2224e9 (svn r8170) -Backport from trunk (r7984, r8118, r8167, r8168):
- out-of-bounds read access on _clients array (Quark) (r7984)
 - change the ordering of the network list (r8118)
 - (FS#556): a network client crashes, due to a division by zero (r8167)
 - ParseConnectionstring didn't use the port parameter if a player was also specified (r8168)
2007-01-16 23:59:03 +00:00
celestar
70920944d8 (svn r7979) [0.5] - Fix: Segfault in the newgrf loading code (grfmsg => DEBUG). Do it in the right directory this time. Sorry for da mess :S 2007-01-08 14:01:05 +00:00
Darkvater
06b5d32983 (svn r7970) -Backport from trunk (r7968, r7969):
- Update year throughout the program to 2007
 - Minor update to changelog, known-bugs file (Bjarni)
2007-01-07 17:38:58 +00:00
Darkvater
34f8ab2f81 (svn r7967) - Prepare 0.5 branch for release. Update readme's, bugs, installers, changelog, etc. to 0.5.0-RC3 2007-01-07 16:43:46 +00:00
Darkvater
315ec78344 (svn r7963) -Backport from trunk (r7716, r7717, r7718):
- Bad signal propagation through tunnel-ends, incompatible railtype signal propagation
 still possible (not fixed).
2007-01-07 14:10:56 +00:00
Darkvater
0bf1d6c49d (svn r7962) -Backport from trunk (r7689, r7696, r7699, r7701, r7704, r7706, r7707, r7713,
r7715, r7723, r7732, r7738, r7742, r7743, r7746, r7754, r7756, r7787, r7800,
 r7803, r7806, r7807, r7819, r7828, r7857, r7884, r7896, r7905):
 - Language file updates.
 - Untranslated strings: Icelandic (217!), Hungarian (2), Galician (140), Finnish (3),
   Brazilian-Portugese (3).
 - Moved Lithuanian from unfinished to finished.
2007-01-07 13:49:54 +00:00
matthijs
6f291a7e6d (svn r7958) - [Debian] Prepare debian packing files for 0.5.0-rc3 2007-01-07 12:44:45 +00:00
Darkvater
04d77258c5 (svn r7957) -Backport from trunk (r7936):
- Only update the signals and YAPF cache on a DC_EXEC action for bridge-building
2007-01-07 12:20:48 +00:00
Darkvater
fbfa0b8009 (svn r7956) -Backport from trunk (r7930):
- wrong TTDPatch GRF flag was set for gradual loading
2007-01-07 12:19:56 +00:00
Darkvater
8960b5740f (svn r7955) -Backport from trunk (r7886):
- [osx] control+enter no longer fullscreens, interfered with team-chat.
2007-01-07 12:19:08 +00:00
Darkvater
30fadfb54b (svn r7954) -Backport from trunk (r7864):
- offset engines/wagons by half width in details window; fixes overflowing for display
2007-01-07 12:18:05 +00:00
Darkvater
b342991853 (svn r7953) -Backport from trunk (r7840, r7843):
- [win32] Update crash window text (+crash.dmp -submit)
2007-01-07 12:16:53 +00:00
Darkvater
0a635c692e (svn r7952) -Backport from trunk (r7823, r7861):
- News windows could still crash due to moving news items around while a news window was still open.
2007-01-07 12:15:36 +00:00
Darkvater
0a211097ac (svn r7951) -Backport from trunk (r7810, r7812):
- Building airport whose size exceeds max station spread-out caused assert. (r7810)
 - rail station build window was not correctly updated after station_spread change (r7812)
2007-01-07 12:13:57 +00:00
Darkvater
1277599c30 (svn r7950) -Backport from trunk (r7760, r7766):
- Sprite usage debug message showed the starting sprite, not current sprite, and only do this during activation (r7760).
 - [OSX] Remove incorrect debug message about missing grf files.
2007-01-07 12:11:54 +00:00
Darkvater
bae0695ac9 (svn r7949) -Backport from trunk (r7733):
- do not use WP(w, querystr_d) and WP(w, def_d) for the same window
2007-01-07 12:07:07 +00:00
Darkvater
630f81c382 (svn r7948) -Backport from trunk (r7731):
- off-by-one error in the date to YMD calculation for first 4 years of a century that was not divisable by 400
2007-01-07 12:06:34 +00:00
Darkvater
2684cb2525 (svn r7947) -Backport from trunk (r7727):
- [sdl] sometimes ALT-TAB could trigger the fast forward
2007-01-07 12:05:47 +00:00
Darkvater
610b6e3953 (svn r7946) -Backport from trunk (r7711, r7795, r7831):
- NewGRF Action 7, GRF check condition 10 didn't ignore unknown GRF IDs (r7354)
 - NewGRF safety scan fixes action E (allow unifont.grf) and Action 0 prop D (bridge) (r7795, r7831)
2007-01-07 11:53:12 +00:00
Darkvater
563857d5bd (svn r7945) -Backport from trunk (r7700):
- Caret randomly jumping back&forth for new randomseed (r7182)
2007-01-07 11:37:23 +00:00
Darkvater
58d18a3ef3 (svn r7944) -Backport from trunk (r7692):
- -OpenTTD didn't compile without network enabled (newgrf sync code)
2007-01-07 11:34:20 +00:00
rubidium
0b7ab719f3 (svn r7893) [0.5] -Fix (FS#485): the configure script did not work work for dash, a sh compatible shell. 2007-01-05 23:43:20 +00:00
Darkvater
f5439821c1 (svn r7694) -Update known-bugs file. 2006-12-31 11:28:42 +00:00
Darkvater
d11a6a439a (svn r7685) - Prepare 0.5 branch for release. Update readme's, bugs, installers, changelog, etc. to 0.5.0-RC2 2006-12-31 01:21:00 +00:00
Darkvater
99096b83bd (svn r7684) -Backport from trunk (r7620):
- Bad signal update through incompatible rail types, bridge.
2006-12-31 00:52:33 +00:00
Darkvater
75c538962d (svn r7683) -Backport from trunk (r7552, r7553, r7574, r7581, r7601, r7611, r7654, r7658):
- Language file updates.
 - Untranslated strings: Turkish (2), Swedish (1), Romanian (3), Norwegian (2),
   Icelandic (217!), Hungarian (2), German (1), Galician (173), Finnish (26),
   Danish (23), Czech (34), Bulgarian (39), Brazilian-Portugese (3)
2006-12-31 00:01:07 +00:00
Darkvater
51cd7bd43b (svn r7682) -Backport from trunk (r7539, r7541, r7603):
- Added esperanto language files to MS projects (r7539).
 - Polish townname generator uses proper UNICODE characters (r7603).
2006-12-30 23:38:41 +00:00
Darkvater
0b67caa8ad (svn r7681) -Backport from trunk (r7585, r7590, r7599):
- Drastically reduce CheckStationSpreadOut CPU usage which got called way too much by the AI.
2006-12-30 23:35:01 +00:00
Darkvater
4ec96ba2d0 (svn r7680) -Backport from trunk (r7586):
- Remove landscaping toolbar from road-toolbar in scenario editor
2006-12-30 23:32:22 +00:00
Darkvater
b93e8d6c71 (svn r7679) -Backport from trunk (r7628):
- [YAPF] suppress 'Train is lost' message if pathfinding ended on the first
   two-way red signal
2006-12-30 23:30:21 +00:00
Darkvater
ac945ced7e (svn r7678) -Fix (r7674): DEBUG macro has been changed 2006-12-30 23:29:33 +00:00
Darkvater
5c190a0c33 (svn r7677) -Backport from trunk (r7657):
- 'Goto Depot' did not work for helicopters going to an airport without depot
2006-12-30 23:26:47 +00:00
Darkvater
b5715acaf8 (svn r7676) -Backport from trunk (r7630, r7631):
- cur/old economy memmove magic (r7630).
 - wrong pointer arithmetic that totally corrupted animated_tiles table, desyncing
   between different endiannes-machines in multiplayer (r7631).
2006-12-30 23:25:57 +00:00
Darkvater
0e7701fbe6 (svn r7675) -Backport from trunk (r7606):
- [NewStations] Add support for variables 45 and 65.
2006-12-30 23:23:43 +00:00
Darkvater
59167f686e (svn r7674) -Backport from trunk (r7580):
- Wrong bounding boxes were computed for certain strings.
2006-12-30 23:22:55 +00:00
Darkvater
0adf61e7fa (svn r7673) -Backport from trunk (r7563):
- [FS#468] Removing towns in scenario editor didn't remove their subsidies.
2006-12-30 23:21:55 +00:00
Darkvater
6fa93f4a7a (svn r7672) -Backport from trunk (r7562):
- [win32] OpenTTD didn't always remember its maximized state on restart.
2006-12-30 23:21:02 +00:00
Darkvater
f3424f51bc (svn r7671) -Backport from trunk (r7560, r7561, r7566):
- No new company could join if 8 clients were connected in less than 8 companies (r7560).
 - [FS#431] internal and visible settings of autorenew could go out of sync (r8561).
 - Server told clients to start syncing from a bad position, causing asserts/crashes (r7566).
2006-12-30 23:20:00 +00:00
Darkvater
6c8f12de78 (svn r7670) -Backport from trunk (r7558, r7559):
- [FS#464] do not wait till a crashed vehicle is removed before starting to load
 other vehicles (r7558).
 - [FS#456] clicking 'full load' can change depot order under certain circumstances (r7559).
2006-12-30 23:14:39 +00:00
Darkvater
953fc9e196 (svn r7669) -Backport from trunk (r7556):
- screenshot no_con didn't remove console from screenshot.
2006-12-30 23:12:05 +00:00
Darkvater
737220f39c (svn r7668) -Backport from trunk (r7555):
- off-by-one error due do truncation on division by 2 in heightmap code.
2006-12-30 23:11:14 +00:00
Darkvater
e00a47d47d (svn r7667) -Backport from trunk (r7549, r7551, r7554, r7582, r7594):
- change size of newgrf GUI to same size as TTDP (no overflows) (r7549).
 - segmentation fault on showing NewGRF settings of a network game (r7551).
 - in Action 0xE, don't deactivate the current GRF (r7554).
 - appending static GRF's could cause duplicate GRF's in the list (r7582).
 - GRF config not cleared when no GRF's are used (r7594).
2006-12-30 23:09:27 +00:00
Darkvater
cf52f00f46 (svn r7666) -Backport from trunk (r7548):
- Some MorphOS changes to get OpenTTD compiled, packaged.
2006-12-30 23:04:14 +00:00
Darkvater
d4b335fffb (svn r7665) -Backport from trunk (r7547):
- When removing a rail station, the cost was added for the full rectangle not for
   only the removed tiles themselves.
2006-12-30 23:03:15 +00:00
Darkvater
652e834ee7 (svn r7664) -Backport from trunk (r7587, r7588, r7600, r7605, r7626, r7629):
- [OSX] universal binary docs, makefile (r7587, r7588, r7626).
 - General documentation update (r7600, r7605).
 - openttd -h showed outdated help for '-n' switch (r7629).
2006-12-30 23:00:52 +00:00
Darkvater
dfab8c779b (svn r7662) -Backport from trunk (r7557, r7624):
- [OSX] makefile fixes (static libfontconfig) (r7557).
 - [FS#470] Install openttd.32.bmp on install so that SDL window has icon (r76240.
2006-12-30 22:55:31 +00:00
Darkvater
bbdbdf3818 (svn r7661) -Backport from trunk (r7550):
- [win32] x64 compile fixed.
2006-12-30 22:53:05 +00:00
Darkvater
0264283116 (svn r7660) -Backport from trunk (r7537, r7539):
- Changelog updates
2006-12-30 22:50:49 +00:00
matthijs
6f97748c80 (svn r7659) - [Debian] Prepare debian packing files for 0.5.0-rc2 2006-12-30 22:36:22 +00:00
Darkvater
65d6403497 (svn r7536) -Branch: add 0.5 branch 2006-12-21 20:56:57 +00:00
2045 changed files with 289470 additions and 773521 deletions

View File

@@ -1,16 +0,0 @@
notifications:
global:
irc:
- openttd
- openttd.notice
push:
only:
- master
only-by:
- DorpsGek
commit-comment:
discussion:
pull-request:
issue:
tag-created:

View File

@@ -1,9 +0,0 @@
root = true
[*]
insert_final_newline = true
trim_trailing_whitespace = true
[*.{c,cpp,h,hpp}]
indent_style = tab
charset = utf-8

1
.github/FUNDING.yml vendored
View File

@@ -1 +0,0 @@
custom: https://www.openttd.org/donate.html

View File

@@ -1,41 +0,0 @@
name: Bug Report
description: Found a bug in OpenTTD?
title: "[Bug]: "
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: input
id: version
attributes:
label: Version of OpenTTD
description: Fill in below what version of OpenTTD you are using, including your OS.
placeholder: ex. 1.11.2, Windows 10
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected result
description: Describe in a few words what you expected to happen.
validations:
required: true
- type: textarea
id: actual
attributes:
label: Actual result
description: Describe in a few words what actually happens.
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: Steps to reproduce
description: As detailed as possible, please tell us how we can reproduce this. Feel free to attach a savegame (zip it first) to make it more clear.
placeholder: |
1. Loaded the attached savegame.
2. Click on the button left of that other icon.
3. The window doesn't open.
validations:
required: true

View File

@@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Suggestions and ideas?
url: https://www.tt-forums.net/viewforum.php?f=32
about: Have a suggestion or an idea for a cool new feature? Post them on our forum!

View File

@@ -1,37 +0,0 @@
name: Crash
description: Did OpenTTD crash?
title: "[Crash]: "
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this crash report!
- type: input
id: version
attributes:
label: Version of OpenTTD
description: Fill in below what version of OpenTTD you are using, including your OS.
placeholder: ex. 1.11.2, Windows 10
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: Steps to reproduce
description: Please spend a few words if you can reproduce this problem.
placeholder: |
1. Bought a new train.
2. The game crashed.
validations:
required: true
- type: textarea
id: crashlogs
attributes:
label: Upload crash files
description: With the `crash.log`, `crash.dmp`, and `crash.sav` we can analyze the crash in detail; this way you allow us to easier triage and fix the problem.
placeholder: |
1. Zip the `crash.log`, `crash.dmp` and `crash.sav`.
2. Click on this field.
3. Drag and drop the zip file in here.
validations:
required: true

View File

@@ -1,49 +0,0 @@
## Motivation / Problem
<!--
Describe here shortly
* For bug fixes:
* What problem does this solve?
* If there is already an issue, link the issue, otherwise describe the problem here.
* For features or gameplay changes:
* What was the motivation to develop this feature?
* Does this address any problem with the gameplay or interface?
* Which group of players do you think would enjoy this feature?
-->
## Description
<!--
Describe here shortly
* For bug fixes:
* How is the problem solved?
* For features or gameplay changes:
* What does this feature do?
* How does it improve/solve the situation described under 'motivation'.
-->
## Limitations
<!--
Describe here
* Is the problem solved in all scenarios?
* Is this feature complete? Are there things that could be added in the future?
* Are there things that are intentionally left out?
* Do you know of a bug or corner case that does not work?
-->
## Checklist for review
Some things are not automated, and forgotten often. This list is a reminder for the reviewers.
* The bug fix is important enough to be backported? (label: 'backport requested')
* This PR touches english.txt or translations? Check the [guidelines](https://github.com/OpenTTD/OpenTTD/blob/master/docs/eints.md)
* This PR affects the save game format? (label 'savegame upgrade')
* This PR affects the GS/AI API? (label 'needs review: Script API')
* ai_changelog.hpp, gs_changelog.hpp need updating.
* The compatibility wrappers (compat_*.nut) need updating.
* This PR affects the NewGRF API? (label 'needs review: NewGRF')
* newgrf_debug_data.h may need updating.
* [PR must be added to API tracker](https://wiki.openttd.org/en/Development/NewGRF/Specification%20Status)

16
.github/changelog.sh vendored
View File

@@ -1,16 +0,0 @@
#!/bin/sh
tag=$(git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null | sed 's@\^0$@@')
# If we are a tag, show the part of the changelog till (but excluding) the last stable
if [ -n "$tag" ]; then
grep='^[0-9]\+\.[0-9]\+[^-]'
next=$(cat changelog.txt | grep '^[0-9]' | awk 'BEGIN { show="false" } // { if (show=="true") print $0; if ($1=="'$tag'") show="true"} ' | grep "$grep" | head -n1 | sed 's/ .*//')
cat changelog.txt | awk 'BEGIN { show="false" } /^[0-9]+.[0-9]+/ { if ($1=="'$next'") show="false"; if ($1=="'$tag'") show="true";} // { if (show=="true") print $0 }'
exit 0
fi
# In all other cases, show the git log of the last 7 days
revdate=$(git log -1 --pretty=format:"%ci")
last_week=$(date -d "$revdate -7days" +"%Y-%m-%d %H:%M")
git log --after="${last_week}" --pretty=fuller

View File

@@ -1,221 +0,0 @@
"""
Script to scan the OpenTTD source-tree for STR_ entries that are defined but
no longer used.
This is not completely trivial, as OpenTTD references a lot of strings in
relation to another string. The most obvious example of this is a list. OpenTTD
only references the first entry in the list, and does "+ <var>" to get to the
correct string.
There are other ways OpenTTD does use relative values. This script tries to
account for all of them, to give the best approximation we have for "this
string is unused".
"""
import glob
import os
import re
import subprocess
import sys
from enum import Enum
LENGTH_NAME_LOOKUP = {
"VEHICLE_TYPES": 4,
}
class SkipType(Enum):
NONE = 1
LENGTH = 2
EXTERNAL = 3
ZERO_IS_SPECIAL = 4
EXPECT_NEWLINE = 5
def read_language_file(filename, strings_found, errors):
strings_defined = []
skip = SkipType.NONE
length = 0
common_prefix = ""
last_tiny_string = ""
with open(filename) as fp:
for line in fp.readlines():
if not line.strip():
if skip == SkipType.EXPECT_NEWLINE:
skip = SkipType.NONE
continue
line = line.strip()
if skip == SkipType.EXPECT_NEWLINE:
# The only thing allowed after a list, is this next marker, or a newline.
if line == "###next-name-looks-similar":
# "###next-name-looks-similar"
# Indicates the common prefix of the last list has a very
# similar name to the next entry, but isn't part of the
# list. So do not emit a warning about them looking very
# similar.
if length != 0:
errors.append(f"ERROR: list around {name} is shorted than indicated by ###length")
common_prefix = ""
else:
errors.append(f"ERROR: expected a newline after a list, but didn't find any around {name}. Did you add an entry to the list without increasing the length?")
skip = SkipType.NONE
if line[0] == "#":
if line.startswith("###length "):
# "###length <count>"
# Indicates the next few entries are part of a list. Only
# the first entry is possibly referenced, and the rest are
# indirectly.
if length != 0:
errors.append(f"ERROR: list around {name} is shorted than indicated by ###length")
length = line.split(" ")[1].strip()
if length.isnumeric():
length = int(length)
else:
length = LENGTH_NAME_LOOKUP[length]
skip = SkipType.LENGTH
elif line.startswith("###external "):
# "###external <count>"
# Indicates the next few entries are used outside the
# source and will not be referenced.
if length != 0:
errors.append(f"ERROR: list around {name} is shorted than indicated by ###length")
length = line.split(" ")[1].strip()
length = int(length)
skip = SkipType.EXTERNAL
elif line.startswith("###setting-zero-is-special"):
# "###setting-zero-is-special"
# Indicates the next entry is part of the "zero is special"
# flag of settings. These entries are not referenced
# directly in the code.
if length != 0:
errors.append(f"ERROR: list around {name} is shorted than indicated by ###length")
skip = SkipType.ZERO_IS_SPECIAL
continue
name = line.split(":")[0].strip()
strings_defined.append(name)
# If a string ends on _TINY or _SMALL, it can be the {TINY} variant.
# Check for this by some fuzzy matching.
if name.endswith(("_SMALL", "_TINY")):
last_tiny_string = name
elif last_tiny_string:
matching_name = "_".join(last_tiny_string.split("_")[:-1])
if name == matching_name:
strings_found.add(last_tiny_string)
else:
last_tiny_string = ""
if skip == SkipType.EXTERNAL:
strings_found.add(name)
skip = SkipType.LENGTH
if skip == SkipType.LENGTH:
skip = SkipType.NONE
length -= 1
common_prefix = name
elif skip == SkipType.ZERO_IS_SPECIAL:
strings_found.add(name)
elif length > 0:
strings_found.add(name)
length -= 1
# Find the common prefix of these strings
for i in range(len(common_prefix)):
if common_prefix[0 : i + 1] != name[0 : i + 1]:
common_prefix = common_prefix[0:i]
break
if length == 0:
skip = SkipType.EXPECT_NEWLINE
if len(common_prefix) < 6:
errors.append(f"ERROR: common prefix of block including {name} was reduced to {common_prefix}. This means the names in the list are not consistent.")
elif common_prefix:
if name.startswith(common_prefix):
errors.append(f"ERROR: {name} looks a lot like block above with prefix {common_prefix}. This mostly means that the list length was too short. Use '###next-name-looks-similar' if it is not.")
common_prefix = ""
return strings_defined
def scan_source_files(path, strings_found):
for new_path in glob.glob(f"{path}/*"):
if os.path.isdir(new_path):
scan_source_files(new_path, strings_found)
continue
if not new_path.endswith((".c", ".h", ".cpp", ".hpp", ".ini")):
continue
# Most files we can just open, but some use magic, that requires the
# G++ preprocessor before we can make sense out of it.
if new_path == "src/table/cargo_const.h":
p = subprocess.run(["g++", "-E", new_path], stdout=subprocess.PIPE)
output = p.stdout.decode()
else:
with open(new_path) as fp:
output = fp.read()
# Find all the string references.
matches = re.findall(r"[^A-Z_](STR_[A-Z0-9_]*)", output)
strings_found.update(matches)
def main():
strings_found = set()
errors = []
scan_source_files("src", strings_found)
strings_defined = read_language_file("src/lang/english.txt", strings_found, errors)
# STR_LAST_STRINGID is special, and not really a string.
strings_found.remove("STR_LAST_STRINGID")
# These are mentioned in comments, not really a string.
strings_found.remove("STR_XXX")
strings_found.remove("STR_NEWS")
strings_found.remove("STR_CONTENT_TYPE_")
# This string is added for completion, but never used.
strings_defined.remove("STR_JUST_DATE_SHORT")
strings_defined = sorted(strings_defined)
strings_found = sorted(list(strings_found))
for string in strings_found:
if string not in strings_defined:
errors.append(f"ERROR: {string} found but never defined.")
for string in strings_defined:
if string not in strings_found:
errors.append(f"ERROR: {string} is (possibly) no longer needed.")
if errors:
for error in errors:
print(error)
sys.exit(1)
else:
print("OK")
if __name__ == "__main__":
main()

View File

@@ -1,420 +0,0 @@
name: CI
on:
pull_request:
push:
branches:
- master
env:
CTEST_OUTPUT_ON_FAILURE: 1
jobs:
emscripten:
name: Emscripten
runs-on: ubuntu-20.04
container:
# If you change this version, change the number in the cache step too.
image: emscripten/emsdk:3.1.28
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup cache
uses: actions/cache@v3
with:
path: /emsdk/upstream/emscripten/cache
key: 3.1.28-${{ runner.os }}
- name: Patch Emscripten to support LZMA
run: |
cd /emsdk/upstream/emscripten
patch -p1 < ${GITHUB_WORKSPACE}/os/emscripten/emsdk-liblzma.patch
- name: Build (host tools)
run: |
mkdir build-host
cd build-host
echo "::group::CMake"
cmake .. -DOPTION_TOOLS_ONLY=ON
echo "::endgroup::"
echo "::group::Build"
echo "Running on $(nproc) cores"
cmake --build . -j $(nproc) --target tools
echo "::endgroup::"
- name: Install GCC problem matcher
uses: ammaraskar/gcc-problem-matcher@master
- name: Build
run: |
mkdir build
cd build
echo "::group::CMake"
emcmake cmake .. -DHOST_BINARY_DIR=../build-host
echo "::endgroup::"
echo "::group::Build"
echo "Running on $(nproc) cores"
cmake --build . -j $(nproc)
echo "::endgroup::"
linux:
name: Linux
strategy:
fail-fast: false
matrix:
include:
- compiler: clang
cxxcompiler: clang++
libsdl: libsdl2-dev
- compiler: gcc
cxxcompiler: g++
libsdl: libsdl2-dev
- compiler: gcc
cxxcompiler: g++
libsdl: libsdl1.2-dev
- compiler: gcc
cxxcompiler: g++
extra-cmake-parameters: -DOPTION_DEDICATED=ON -DCMAKE_CXX_FLAGS_INIT="-DRANDOM_DEBUG"
runs-on: ubuntu-20.04
env:
CC: ${{ matrix.compiler }}
CXX: ${{ matrix.cxxcompiler }}
steps:
- name: Checkout
uses: actions/checkout@v3
- 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 \
liballegro4-dev \
libfontconfig-dev \
libicu-dev \
liblzma-dev \
liblzo2-dev \
${{ matrix.libsdl }} \
zlib1g-dev \
# EOF
echo "::endgroup::"
env:
DEBIAN_FRONTEND: noninteractive
- name: Get OpenGFX
run: |
mkdir -p ~/.local/share/openttd/baseset
cd ~/.local/share/openttd/baseset
echo "::group::Download OpenGFX"
curl -L https://cdn.openttd.org/opengfx-releases/0.6.0/opengfx-0.6.0-all.zip -o opengfx-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip opengfx-all.zip
echo "::endgroup::"
rm -f opengfx-all.zip
- name: Install GCC problem matcher
uses: ammaraskar/gcc-problem-matcher@master
- name: Build
run: |
mkdir build
cd build
echo "::group::CMake"
cmake .. ${{ matrix.extra-cmake-parameters }}
echo "::endgroup::"
echo "::group::Build"
echo "Running on $(nproc) cores"
cmake --build . -j $(nproc)
echo "::endgroup::"
- name: Test
run: |
cd build
ctest -j $(nproc) --timeout 120
macos:
name: Mac OS
strategy:
fail-fast: false
matrix:
include:
- arch: x64
full_arch: x86_64
runs-on: macos-latest
env:
MACOSX_DEPLOYMENT_TARGET: 10.13
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install dependencies
env:
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install \
pkg-config \
# EOF
- name: Prepare cache key
id: key
run: |
echo "image=$ImageOS-$ImageVersion" >> $GITHUB_OUTPUT
- name: Enable vcpkg cache
uses: actions/cache@v3
with:
path: /usr/local/share/vcpkg/installed
key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-0 # Increase the number whenever dependencies are modified
restore-keys: |
${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}
- name: Prepare vcpkg
run: |
vcpkg install --triplet=${{ matrix.arch }}-osx \
liblzma \
libpng \
lzo \
zlib \
# EOF
- name: Install OpenGFX
run: |
mkdir -p ~/Documents/OpenTTD/baseset
cd ~/Documents//OpenTTD/baseset
echo "::group::Download OpenGFX"
curl -L https://cdn.openttd.org/opengfx-releases/0.6.0/opengfx-0.6.0-all.zip -o opengfx-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip opengfx-all.zip
echo "::endgroup::"
rm -f opengfx-all.zip
- name: Install GCC problem matcher
uses: ammaraskar/gcc-problem-matcher@master
- name: Build
run: |
mkdir build
cd build
echo "::group::CMake"
cmake ${GITHUB_WORKSPACE} \
-DCMAKE_OSX_ARCHITECTURES=${{ matrix.full_arch }} \
-DVCPKG_TARGET_TRIPLET=${{ matrix.arch }}-osx \
-DCMAKE_TOOLCHAIN_FILE=/usr/local/share/vcpkg/scripts/buildsystems/vcpkg.cmake \
# EOF
echo "::endgroup::"
echo "::group::Build"
echo "Running on $(sysctl -n hw.logicalcpu) cores"
cmake --build . -j $(sysctl -n hw.logicalcpu)
echo "::endgroup::"
- name: Test
run: |
cd build
ctest -j $(sysctl -n hw.logicalcpu) --timeout 120
windows:
name: Windows
strategy:
fail-fast: false
matrix:
os: [windows-latest, windows-2019]
arch: [x86, x64]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Prepare cache key
id: key
shell: powershell
run: |
# Work around caching failure with GNU tar
New-Item -Type Junction -Path vcpkg -Target c:\vcpkg
Write-Output "image=$env:ImageOS-$env:ImageVersion" >> $env:GITHUB_OUTPUT
- name: Enable vcpkg cache
uses: actions/cache@v3
with:
path: vcpkg/installed
key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-0 # Increase the number whenever dependencies are modified
restore-keys: |
${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}
- name: Prepare vcpkg
shell: bash
run: |
vcpkg install --triplet=${{ matrix.arch }}-windows-static \
liblzma \
libpng \
lzo \
zlib \
# EOF
- name: Install OpenGFX
shell: bash
run: |
mkdir -p "C:/Users/Public/Documents/OpenTTD/baseset"
cd "C:/Users/Public/Documents/OpenTTD/baseset"
echo "::group::Download OpenGFX"
curl -L https://cdn.openttd.org/opengfx-releases/0.6.0/opengfx-0.6.0-all.zip -o opengfx-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip opengfx-all.zip
echo "::endgroup::"
rm -f opengfx-all.zip
- name: Install MSVC problem matcher
uses: ammaraskar/msvc-problem-matcher@master
- name: Configure developer command prompt for ${{ matrix.arch }}
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ matrix.arch }}
- name: Build
shell: bash
run: |
mkdir build
cd build
echo "::group::CMake"
cmake .. \
-GNinja \
-DVCPKG_TARGET_TRIPLET=${{ matrix.arch }}-windows-static \
-DCMAKE_TOOLCHAIN_FILE="c:\vcpkg\scripts\buildsystems\vcpkg.cmake" \
# EOF
echo "::endgroup::"
echo "::group::Build"
cmake --build .
echo "::endgroup::"
- name: Test
shell: bash
run: |
cd ${GITHUB_WORKSPACE}/build
ctest --timeout 120
msys2:
name: msys2
strategy:
fail-fast: false
matrix:
include:
- msystem: MINGW64
arch: x86_64
- msystem: MINGW32
arch: i686
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.msystem }}
release: false
install: >-
git
make
mingw-w64-${{ matrix.arch }}-cmake
mingw-w64-${{ matrix.arch }}-gcc
mingw-w64-${{ matrix.arch }}-lzo2
mingw-w64-${{ matrix.arch }}-libpng
- name: Install OpenGFX
shell: bash
run: |
mkdir -p "C:/Users/Public/Documents/OpenTTD/baseset"
cd "C:/Users/Public/Documents/OpenTTD/baseset"
echo "::group::Download OpenGFX"
curl -L https://cdn.openttd.org/opengfx-releases/0.6.0/opengfx-0.6.0-all.zip -o opengfx-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip opengfx-all.zip
echo "::endgroup::"
rm -f opengfx-all.zip
- name: Install GCC problem matcher
uses: ammaraskar/gcc-problem-matcher@master
- name: Build
shell: msys2 {0}
run: |
mkdir build
cd build
echo "::group::CMake"
cmake .. -G"MSYS Makefiles"
echo "::endgroup::"
echo "::group::Build"
echo "Running on $(nproc) cores"
cmake --build . -j $(nproc)
echo "::endgroup::"
- name: Test
shell: msys2 {0}
run: |
cd build
ctest -j $(nproc) --timeout 120
check_annotations:
name: Check Annotations
needs:
- emscripten
- linux
- macos
- windows
- msys2
if: always() && github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Check annotations
uses: OpenTTD/actions/annotation-check@v3

View File

@@ -1,21 +0,0 @@
name: Commit checker
on:
pull_request:
jobs:
commit-checker:
name: Commit checker
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 4
- name: Get pull-request commits
uses: OpenTTD/actions/checkout-pull-request@v2
- name: Check commits
uses: OpenTTD/OpenTTD-git-hooks@main

View File

@@ -1,133 +0,0 @@
name: Preview build
on:
repository_dispatch:
types:
- Preview*
jobs:
preview:
name: Build preview
runs-on: ubuntu-20.04
container:
# If you change this version, change the number in the cache step too.
image: emscripten/emsdk:3.1.28
steps:
- name: Update deployment status to in progress
uses: octokit/request-action@v2.x
with:
route: POST /repos/{owner}/{repo}/deployments/{deployment_id}/statuses
mediaType: |
previews:
- ant-man
- flash
owner: ${{ github.event.repository.owner.login }}
repo: ${{ github.event.repository.name }}
deployment_id: ${{ github.event.client_payload.deployment_id }}
state: in_progress
env:
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
- name: Checkout
uses: actions/checkout@v3
with:
ref: ${{ github.event.client_payload.sha }}
- name: Name branch
run: |
name=$(echo "${{ github.event.client_payload.folder }}")
git checkout -b ${name}
- name: Setup cache
uses: actions/cache@v3
with:
path: /emsdk/upstream/emscripten/cache
key: 3.1.28-${{ runner.os }}
- name: Patch Emscripten to support LZMA
run: |
cd /emsdk/upstream/emscripten
patch -p1 < ${GITHUB_WORKSPACE}/os/emscripten/emsdk-liblzma.patch
- name: Build (host tools)
run: |
mkdir build-host
cd build-host
echo "::group::CMake"
cmake .. -DOPTION_TOOLS_ONLY=ON
echo "::endgroup::"
echo "::group::Build"
echo "Running on $(nproc) cores"
make -j$(nproc) tools
echo "::endgroup::"
- name: Install GCC problem matcher
uses: ammaraskar/gcc-problem-matcher@master
- name: Build
run: |
mkdir build
cd build
echo "::group::CMake"
emcmake cmake .. \
-DHOST_BINARY_DIR=../build-host \
-DCMAKE_BUILD_TYPE=Release \
# EOF
echo "::endgroup::"
echo "::group::Build"
echo "Running on $(nproc) cores"
emmake make -j$(nproc)
echo "::endgroup::"
- name: Publish preview
run: |
pip3 install awscli
aws s3 cp --only-show-errors build/openttd.data s3://${{ secrets.PREVIEW_S3_BUCKET }}/${{ github.event.client_payload.folder }}/
aws s3 cp --only-show-errors build/openttd.html s3://${{ secrets.PREVIEW_S3_BUCKET }}/${{ github.event.client_payload.folder }}/
aws s3 cp --only-show-errors build/openttd.js s3://${{ secrets.PREVIEW_S3_BUCKET }}/${{ github.event.client_payload.folder }}/
aws s3 cp --only-show-errors build/openttd.wasm s3://${{ secrets.PREVIEW_S3_BUCKET }}/${{ github.event.client_payload.folder }}/
# Invalidate the cache of the CloudFront distribution
aws cloudfront create-invalidation --distribution-id ${{ secrets.PREVIEW_CF_DISTRIBUTION_ID }} --paths "/${{ github.event.client_payload.folder }}/*"
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Update deployment status to success
uses: octokit/request-action@v2.x
with:
route: POST /repos/{owner}/{repo}/deployments/{deployment_id}/statuses
mediaType: |
previews:
- ant-man
- flash
owner: ${{ github.event.repository.owner.login }}
repo: ${{ github.event.repository.name }}
deployment_id: ${{ github.event.client_payload.deployment_id }}
state: success
environment_url: https://preview.openttd.org/${{ github.event.client_payload.folder }}/
env:
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
- if: failure()
name: Update deployment status to failure
uses: octokit/request-action@v2.x
with:
route: POST /repos/{owner}/{repo}/deployments/{deployment_id}/statuses
mediaType: |
previews:
- ant-man
- flash
owner: ${{ github.event.repository.owner.login }}
repo: ${{ github.event.repository.name }}
deployment_id: ${{ github.event.client_payload.deployment_id }}
state: failure
env:
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}

View File

@@ -1,66 +0,0 @@
name: Preview label
on:
pull_request_target:
types:
- labeled
env:
TEAM_CORE_DEVELOPER: core-developers
jobs:
check_preview_label:
name: Check for preview label
if: github.event.action == 'labeled' && github.event.label.name == 'preview'
runs-on: ubuntu-20.04
steps:
- name: Check if label was added by core developer
id: core_developer
continue-on-error: true
uses: octokit/request-action@v2.x
with:
route: GET /orgs/OpenTTD/teams/${{ env.TEAM_CORE_DEVELOPER }}/memberships/${{ github.event.sender.login }}
env:
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
- if: steps.core_developer.outcome == 'failure'
name: Remove preview label if not core developer
uses: octokit/request-action@v2.x
with:
route: DELETE /repos/{owner}/{repo}/issues/{issue_number}/labels/preview
owner: ${{ github.event.repository.owner.login }}
repo: ${{ github.event.repository.name }}
issue_number: ${{ github.event.number }}
env:
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
- if: steps.core_developer.outcome == 'success'
name: Create deployment
id: deployment
uses: octokit/request-action@v2.x
with:
route: POST /repos/{owner}/{repo}/deployments
mediaType: |
previews:
- ant-man
- flash
owner: ${{ github.event.repository.owner.login }}
repo: ${{ github.event.repository.name }}
ref: ${{ github.event.pull_request.head.sha }}
task: deploy:preview
auto_merge: false
required_contexts: "[]"
environment: preview-pr-${{ github.event.number }}
description: "Preview for Pull Request #${{ github.event.number }}"
env:
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
- if: steps.core_developer.outcome == 'success'
name: Trigger 'preview build'
uses: peter-evans/repository-dispatch@v2
with:
token: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
event-type: "Preview build #${{ github.event.number }}"
client-payload: '{"folder": "pr${{ github.event.number }}", "sha": "${{ github.event.pull_request.head.sha }}", "deployment_id": "${{ fromJson(steps.deployment.outputs.data).id }}"}'

View File

@@ -1,66 +0,0 @@
name: Preview push
on:
pull_request_target:
types:
- synchronize
jobs:
check_new_preview:
name: Check preview needs update
runs-on: ubuntu-20.04
steps:
- name: Check if earlier preview exists
id: earlier_preview
uses: octokit/request-action@v2.x
with:
route: GET /repos/{owner}/{repo}/deployments
owner: ${{ github.event.repository.owner.login }}
repo: ${{ github.event.repository.name }}
environment: preview-pr-${{ github.event.number }}
per_page: 1
env:
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
- if: toJson(fromJson(steps.earlier_preview.outputs.data)) != '[]'
name: Check for preview label
id: preview_label
uses: octokit/request-action@v2.x
with:
route: GET /repos/{owner}/{repo}/issues/{issue_number}/labels
owner: ${{ github.event.repository.owner.login }}
repo: ${{ github.event.repository.name }}
issue_number: ${{ github.event.number }}
env:
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
- if: toJson(fromJson(steps.earlier_preview.outputs.data)) != '[]' && contains(fromJson(steps.preview_label.outputs.data).*.name, 'preview')
name: Create deployment
id: deployment
uses: octokit/request-action@v2.x
with:
route: POST /repos/{owner}/{repo}/deployments
mediaType: |
previews:
- ant-man
- flash
owner: ${{ github.event.repository.owner.login }}
repo: ${{ github.event.repository.name }}
ref: ${{ github.event.pull_request.head.sha }}
task: deploy:preview
auto_merge: false
required_contexts: "[]"
environment: preview-pr-${{ github.event.number }}
description: "Preview for Pull Request #${{ github.event.number }}"
env:
GITHUB_TOKEN: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
- if: toJson(fromJson(steps.earlier_preview.outputs.data)) != '[]' && contains(fromJson(steps.preview_label.outputs.data).*.name, 'preview')
name: Trigger 'preview build'
uses: peter-evans/repository-dispatch@v2
with:
token: ${{ secrets.PREVIEW_GITHUB_TOKEN }}
event-type: "Preview build #${{ github.event.number }}"
client-payload: '{"folder": "pr${{ github.event.number }}", "sha": "${{ github.event.pull_request.head.sha }}", "deployment_id": "${{ fromJson(steps.deployment.outputs.data).id }}"}'

View File

@@ -1,85 +0,0 @@
name: Release (Docs)
on:
workflow_call:
inputs:
version:
required: true
type: string
jobs:
docs:
name: Docs
runs-on: ubuntu-20.04
steps:
- name: Download source
uses: actions/download-artifact@v3
with:
name: internal-source
- name: Unpack source
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: Build
run: |
mkdir -p ${GITHUB_WORKSPACE}/build
cd ${GITHUB_WORKSPACE}/build
echo "::group::CMake"
cmake ${GITHUB_WORKSPACE} \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DOPTION_DOCS_ONLY=ON \
# EOF
echo "::endgroup::"
echo "::group::Build"
cmake --build . --target docs
echo "::endgroup::"
- name: Create bundles
run: |
BASENAME=openttd-${{ inputs.version }}
cd ${GITHUB_WORKSPACE}/build
mv docs/source ${BASENAME}-docs
mv docs/ai-api ${BASENAME}-docs-ai
mv docs/gs-api ${BASENAME}-docs-gs
mkdir -p bundles
echo "::group::Create docs bundle"
tar --xz -cf bundles/${BASENAME}-docs.tar.xz ${BASENAME}-docs
echo "::endgroup::"
echo "::group::Create AI API docs bundle"
tar --xz -cf bundles/${BASENAME}-docs-ai.tar.xz ${BASENAME}-docs-ai
echo "::endgroup::"
echo "::group::Create GameScript API docs bundle"
tar --xz -cf bundles/${BASENAME}-docs-gs.tar.xz ${BASENAME}-docs-gs
echo "::endgroup::"
- name: Store bundles
uses: actions/upload-artifact@v3
with:
name: openttd-docs
path: build/bundles/*.tar.xz
retention-days: 5

View File

@@ -1,100 +0,0 @@
name: Release (Linux)
on:
workflow_call:
jobs:
linux:
name: Linux (Generic)
runs-on: ubuntu-20.04
container:
# manylinux2014 is based on CentOS 7, but already has a lot of things
# installed and preconfigured. It makes it easier to build OpenTTD.
image: quay.io/pypa/manylinux2014_x86_64
steps:
- name: Download source
uses: actions/download-artifact@v3
with:
name: internal-source
- name: Unpack source
run: |
tar -xf source.tar.gz --strip-components=1
- name: Install dependencies
run: |
echo "::group::Install dependencies"
yum install -y \
fontconfig-devel \
freetype-devel \
libicu-devel \
libpng-devel \
lzo-devel \
SDL2-devel \
wget \
xz-devel \
zlib-devel \
# EOF
echo "::endgroup::"
# The yum variant of fluidsynth depends on all possible audio drivers,
# like jack, ALSA, pulseaudio, etc. This is not really useful for us,
# as we route the output of fluidsynth back via our sound driver, and
# as such do not use these audio driver outputs at all. So instead,
# we compile fluidsynth ourselves, with as little dependencies as
# possible. This currently means it picks up SDL2, but this is fine,
# as we need SDL2 anyway.
echo "::group::Install fluidsynth"
wget https://github.com/FluidSynth/fluidsynth/archive/v2.1.6.tar.gz
tar xf v2.1.6.tar.gz
(
cd fluidsynth-2.1.6
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
cmake --build . -j $(nproc)
cmake --install .
)
echo "::endgroup::"
- name: Install GCC problem matcher
uses: ammaraskar/gcc-problem-matcher@master
- name: Build
run: |
mkdir -p build
cd build
echo "::group::CMake"
cmake ${GITHUB_WORKSPACE} \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DOPTION_PACKAGE_DEPENDENCIES=ON \
# EOF
echo "::endgroup::"
echo "::group::Build"
echo "Running on $(nproc) cores"
cmake --build . -j $(nproc)
echo "::endgroup::"
- name: Create bundles
run: |
cd ${GITHUB_WORKSPACE}/build
echo "::group::Run CPack"
cpack
echo "::endgroup::"
echo "::group::Cleanup"
# Remove the sha256 files CPack generates; we will do this ourself at
# the end of this workflow.
rm -f bundles/*.sha256
echo "::endgroup::"
- name: Store bundles
uses: actions/upload-artifact@v3
with:
name: openttd-linux-generic
path: build/bundles
retention-days: 5

View File

@@ -1,198 +0,0 @@
name: Release (MacOS)
on:
workflow_call:
jobs:
macos:
name: MacOS
runs-on: macos-11
env:
MACOSX_DEPLOYMENT_TARGET: 10.13
steps:
- name: Download source
uses: actions/download-artifact@v3
with:
name: internal-source
- name: Unpack source
run: |
tar -xf source.tar.gz --strip-components=1
- name: Install dependencies
env:
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew install \
pandoc \
pkg-config \
# EOF
- name: Prepare cache key
id: key
run: |
echo "image=$ImageOS-$ImageVersion" >> $GITHUB_OUTPUT
- name: Enable vcpkg cache
uses: actions/cache@v3
with:
path: /usr/local/share/vcpkg/installed
key: ${{ steps.key.outputs.image }}-vcpkg-release-0 # Increase the number whenever dependencies are modified
restore-keys: |
${{ steps.key.outputs.image }}-vcpkg-release
${{ steps.key.outputs.image }}-vcpkg-x64
- name: Prepare vcpkg
run: |
vcpkg install \
liblzma:x64-osx \
liblzma:arm64-osx \
libpng:x64-osx \
libpng:arm64-osx \
lzo:x64-osx \
lzo:arm64-osx \
zlib:x64-osx \
zlib:arm64-osx \
# EOF
- name: Install GCC problem matcher
uses: ammaraskar/gcc-problem-matcher@master
- name: Build tools
run: |
mkdir build-host
cd build-host
echo "::group::CMake"
cmake ${GITHUB_WORKSPACE} \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DOPTION_TOOLS_ONLY=ON \
# EOF
echo "::endgroup::"
echo "::group::Build tools"
echo "Running on $(sysctl -n hw.logicalcpu) cores"
cmake --build . -j $(sysctl -n hw.logicalcpu) --target tools
echo "::endgroup::"
- name: Import code signing certificates
uses: Apple-Actions/import-codesign-certs@v1
with:
# The certificates in a PKCS12 file encoded as a base64 string
p12-file-base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }}
# The password used to import the PKCS12 file.
p12-password: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }}
# If this is run on a fork, there may not be a certificate set up - continue in this case
continue-on-error: true
- name: Build arm64
run: |
mkdir build-arm64
cd build-arm64
echo "::group::CMake"
cmake ${GITHUB_WORKSPACE} \
-DCMAKE_OSX_ARCHITECTURES=arm64 \
-DVCPKG_TARGET_TRIPLET=arm64-osx \
-DCMAKE_TOOLCHAIN_FILE=/usr/local/share/vcpkg/scripts/buildsystems/vcpkg.cmake \
-DHOST_BINARY_DIR=${GITHUB_WORKSPACE}/build-host \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
# EOF
echo "::endgroup::"
echo "::group::Build"
echo "Running on $(sysctl -n hw.logicalcpu) cores"
cmake --build . -j $(sysctl -n hw.logicalcpu)
echo "::endgroup::"
- name: Build x64
run: |
mkdir build-x64
cd build-x64
echo "::group::CMake"
cmake ${GITHUB_WORKSPACE} \
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DVCPKG_TARGET_TRIPLET=x64-osx \
-DCMAKE_TOOLCHAIN_FILE=/usr/local/share/vcpkg/scripts/buildsystems/vcpkg.cmake \
-DHOST_BINARY_DIR=${GITHUB_WORKSPACE}/build-host \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCPACK_BUNDLE_APPLE_CERT_APP=${{ secrets.APPLE_DEVELOPER_CERTIFICATE_ID }} \
"-DCPACK_BUNDLE_APPLE_CODESIGN_PARAMETER=--deep -f --options runtime" \
-DAPPLE_UNIVERSAL_PACKAGE=1 \
# EOF
echo "::endgroup::"
echo "::group::Build"
echo "Running on $(sysctl -n hw.logicalcpu) cores"
cmake --build . -j $(sysctl -n hw.logicalcpu)
echo "::endgroup::"
- name: Create bundles
run: |
cd build-x64
echo "::group::Create universal binary"
# Combine the `openttd` binaries from each build into a single file
lipo -create -output openttd-universal ../build-*/openttd
mv openttd-universal openttd
echo "::endgroup::"
echo "::group::Run CPack"
cpack
echo "::endgroup::"
echo "::group::Cleanup"
# Remove the sha256 files CPack generates; we will do this ourself at
# the end of this workflow.
rm -f bundles/*.sha256
echo "::endgroup::"
- name: Install gon
env:
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew tap mitchellh/gon
brew install mitchellh/gon/gon
- name: Notarize
env:
AC_USERNAME: ${{ secrets.APPLE_DEVELOPER_APP_USERNAME }}
AC_PASSWORD: ${{ secrets.APPLE_DEVELOPER_APP_PASSWORD }}
run: |
cd build-x64
../os/macosx/notarize.sh
- name: Build zip
run: |
cd build-x64
pushd _CPack_Packages/*/Bundle/openttd-*/
# Remove the Applications symlink from the staging folder
rm -f Applications
# Remove the original dmg built by CPack to avoid a conflict when resolving
# the zip_filename variable below
rm -f ../*.dmg
zip_filename=(../openttd-*)
# Package up the existing, notarised .app into a zip file
zip -r -9 ${zip_filename}.zip OpenTTD.app
popd
# Now move it into place to be uploaded
mv _CPack_Packages/*/Bundle/openttd-*.zip bundles/
- name: Store bundles
uses: actions/upload-artifact@v3
with:
name: openttd-macos-universal
path: build-x64/bundles
retention-days: 5

View File

@@ -1,186 +0,0 @@
name: Release (Source)
on:
workflow_call:
outputs:
version:
value: ${{ jobs.source.outputs.version }}
is_tag:
value: ${{ jobs.source.outputs.is_tag }}
trigger_type:
value: ${{ jobs.source.outputs.trigger_type }}
folder:
value: ${{ jobs.source.outputs.folder }}
jobs:
source:
name: Source
runs-on: ubuntu-20.04
outputs:
version: ${{ steps.metadata.outputs.version }}
is_tag: ${{ steps.metadata.outputs.is_tag }}
trigger_type: ${{ steps.metadata.outputs.trigger_type }}
folder: ${{ steps.metadata.outputs.folder }}
steps:
- name: Checkout (Release)
if: github.event_name == 'release'
uses: actions/checkout@v3
with:
# We generate a changelog; for this we need the full git log.
fetch-depth: 0
- name: Checkout (Manual)
if: github.event_name == 'workflow_dispatch'
uses: actions/checkout@v3
with:
ref: ${{ github.event.inputs.ref }}
# We generate a changelog; for this we need the full git log.
fetch-depth: 0
- name: Checkout (Trigger)
if: github.event_name == 'repository_dispatch'
uses: actions/checkout@v3
with:
ref: ${{ github.event.client_payload.ref }}
# We generate a changelog; for this we need the full git log.
fetch-depth: 0
- name: Check valid branch name
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
REF="${{ github.event.inputs.ref }}"
elif [ "${{ github.event_name }}" = "repository_dispatch" ]; then
REF="${{ github.event.client_payload.ref }}"
else
REF="${{ github.ref }}"
fi
# Check if we are a tag.
if [ -n "$(git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null || false)" ]; then
exit 0
fi
# Check if the checkout caused the branch to be named.
if [ "$(git rev-parse --abbrev-ref HEAD)" != "HEAD" ]; then
exit 0
fi
# Check if this was a pull request.
if [ -n "$(echo ${REF} | grep '^refs/pull/[0-9]*')" ]; then
PULL=$(echo ${REF} | cut -d/ -f3)
git checkout -b pr${PULL}
fi
# Are we still in a detached state? Error out.
if [ "$(git rev-parse --abbrev-ref HEAD)" == "HEAD" ]; then
echo "The 'ref' given resulted in a checkout of a detached HEAD."
echo "We cannot detect the version for these checkout accurate."
echo ""
echo "If you want to build a Pull Request, make sure you use 'refs/pull/NNN/head'."
echo ""
echo "Cancelling build, as without a version we cannot store the artifacts."
exit 1
fi
- name: Generate metadata
id: metadata
run: |
echo "::group::Prepare metadata files"
cmake -DGENERATE_OTTDREV=1 -P cmake/scripts/FindVersion.cmake
./.github/changelog.sh > .changelog
TZ='UTC' date +"%Y-%m-%d %H:%M UTC" > .release_date
cat .ottdrev | cut -f 1 -d$'\t' > .version
if [ $(cat .ottdrev | cut -f 5 -d$'\t') = '1' ]; then
# Assume that all tags are always releases. Why else make a tag?
IS_TAG="true"
FOLDER="${{ env.FOLDER_RELEASES }}"
TRIGGER_TYPE="new-tag"
else
IS_TAG="false"
BRANCH=$(git symbolic-ref -q HEAD | sed 's@.*/@@')
if [ -z "${BRANCH}" ]; then
echo "Internal error: branch name is empty."
echo "An earlier step should have prevented this from happening."
echo "Cancelling build, as without a branch name we cannot store the artifacts"
exit 1
fi
if [ "${BRANCH}" = "${{ env.NIGHTLIES_BRANCH }}" ]; then
# The "master" branch is special, and we call a nightly.
FOLDER="${{ env.FOLDER_NIGHTLIES }}/$(date +%Y)"
TRIGGER_TYPE="new-master"
else
# All other branches, which can be builds of Pull Requests, are
# put in their own folder.
FOLDER="${{ env.FOLDER_BRANCHES }}/${BRANCH}"
TRIGGER_TYPE="new-branch"
fi
fi
mkdir -p build/bundles
cp .changelog build/bundles/changelog.txt
cp .release_date build/bundles/released.txt
cp README.md build/bundles/README.md
echo "::endgroup::"
echo "Release Date: $(cat .release_date)"
echo "Revision: $(cat .ottdrev)"
echo "Version: $(cat .version)"
echo "Is tag: ${IS_TAG}"
echo "Folder on CDN: ${FOLDER}"
echo "Workflow trigger: ${TRIGGER_TYPE}"
echo "version=$(cat .version)" >> $GITHUB_OUTPUT
echo "is_tag=${IS_TAG}" >> $GITHUB_OUTPUT
echo "folder=${FOLDER}" >> $GITHUB_OUTPUT
echo "trigger_type=${TRIGGER_TYPE}" >> $GITHUB_OUTPUT
env:
NIGHTLIES_BRANCH: master
FOLDER_RELEASES: openttd-releases
FOLDER_NIGHTLIES: openttd-nightlies
FOLDER_BRANCHES: openttd-branches
- name: Remove VCS information
run: |
rm -rf .git
- name: Create bundles
run: |
FOLDER_NAME=openttd-${{ steps.metadata.outputs.version }}
# Rename the folder to openttd-NNN
mkdir ${FOLDER_NAME}
find . -maxdepth 1 -not -name . -not -name build -not -name ${FOLDER_NAME} -exec mv {} ${FOLDER_NAME}/ \;
echo "::group::Create tarball (xz) bundle"
tar --xz -cvf build/bundles/${FOLDER_NAME}-source.tar.xz ${FOLDER_NAME}
echo "::endgroup::"
# This tarball is only to be used within this workflow.
echo "::group::Create tarball (gz) bundle"
tar --gzip -cvf source.tar.gz ${FOLDER_NAME}
echo "::endgroup::"
echo "::group::Create zip bundle"
zip -9 -r build/bundles/${FOLDER_NAME}-source.zip ${FOLDER_NAME}
echo "::endgroup::"
- name: Store bundles
uses: actions/upload-artifact@v3
with:
name: openttd-source
path: build/bundles/*
retention-days: 5
- name: Store source (for other jobs)
uses: actions/upload-artifact@v3
with:
name: internal-source
path: source.tar.gz
retention-days: 1

View File

@@ -1,192 +0,0 @@
name: Release (Windows Store)
on:
workflow_call:
inputs:
version:
required: true
type: string
jobs:
windows-store:
name: Windows Store
runs-on: windows-latest
steps:
- name: Download source
uses: actions/download-artifact@v3
with:
name: internal-source
- name: Unpack source
shell: bash
run: |
tar -xf source.tar.gz --strip-components=1
- name: Download x86 build
uses: actions/download-artifact@v3
with:
name: openttd-windows-x86
- name: Download x64 build
uses: actions/download-artifact@v3
with:
name: openttd-windows-x64
- name: Download arm64 build
uses: actions/download-artifact@v3
with:
name: openttd-windows-arm64
- name: Unpack builds
shell: bash
run: |
mkdir builds
cd builds
function extract {
mkdir $1
# Extract the zip version of the release
unzip ../openttd-*-windows-$2.zip -d $1
# Remove the extraneous directory
mv $1/openttd-*-windows-$2/* $1/
rmdir $1/openttd-*-windows-$2
# Move the openttd.exe to the '{arch}-binaries' folder
mkdir $1-binaries
mv $1/openttd.exe $1-binaries/
}
extract x86 win32
extract x64 win64
extract arm64 arm64
# Use the "x86" folder as the source of the common binaries (lang files, etc) and remove the others
mv x86 common-binaries
rm -rf x64 arm64
- name: Install OpenGFX
shell: bash
run: |
mkdir -p builds/common-binaries/baseset
cd builds/common-binaries/baseset
echo "::group::Download OpenGFX"
curl -L https://cdn.openttd.org/opengfx-releases/7.1/opengfx-7.1-all.zip -o opengfx-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip opengfx-all.zip
tar xf opengfx-*.tar
echo "::endgroup::"
rm -f opengfx-all.zip opengfx-*.tar
- name: Install OpenMSX
shell: bash
run: |
mkdir -p builds/common-binaries/baseset
cd builds/common-binaries/baseset
echo "::group::Download OpenMSX"
curl -L https://cdn.openttd.org/openmsx-releases/0.4.2/openmsx-0.4.2-all.zip -o openmsx-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip openmsx-all.zip
tar xf openmsx-*.tar
echo "::endgroup::"
rm -f openmsx-all.zip openmsx-*.tar
- name: Install OpenSFX
shell: bash
run: |
mkdir -p builds/common-binaries/baseset/opensfx
cd builds/common-binaries/baseset/opensfx
echo "::group::Download OpenSFX"
curl -L https://cdn.openttd.org/opensfx-releases/1.0.3/opensfx-1.0.3-all.zip -o opensfx-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenSFX"
unzip opensfx-all.zip
tar xf opensfx-*.tar
echo "::endgroup::"
rm -f opensfx-all.zip opensfx-*.tar
- name: Generate signing certificate
shell: cmd
run: |
cd builds
REM We need to provide a signed .appx 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
shell: cmd
run: |
cd os\windows\winstore
call generate-assets.bat
- name: Prepare manifests
shell: cmd
run: |
cd builds
mkdir manifests
REM Set the version environment variable
call ..\os\windows\winstore\set-version.bat x86-binaries\openttd.exe
call ..\os\windows\winstore\prepare-manifests.bat manifests "CN=78024DA8-4BE4-4C77-B12E-547BBF7359D2" "57420OpenTTDDevelopers.OpenTTDofficial"
- name: Prepare binaries
shell: bash
run: |
cd builds
# Copy the Windows Store assets
mkdir common-binaries/Assets
cp -R ../os/windows/winstore/assets-common/* common-binaries/Assets/
mkdir Assets
cp -R ../os/windows/winstore/assets/* Assets/
cp manifests/*.xml .
- name: Build
shell: cmd
run: |
REM Add the Windows SDK tools to the PATH
echo|set /p="SET VS_INSTALLDIR=" > _vspath.bat
vswhere -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath >> _vspath.bat
call _vspath.bat
call "%VS_INSTALLDIR%\Common7\Tools\VsDevCmd.bat"
REM Set the version environment variable
call os\windows\winstore\set-version.bat builds\x86-binaries\openttd.exe
cd builds
mkdir output
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"
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
- name: Store bundles
uses: actions/upload-artifact@v3
with:
name: openttd-windows-store
path: builds/bundles
retention-days: 5

View File

@@ -1,201 +0,0 @@
name: Release (Windows)
on:
workflow_call:
inputs:
is_tag:
required: true
type: string
jobs:
windows:
name: Windows
strategy:
fail-fast: false
matrix:
include:
- arch: x86
host: x86
- arch: x64
host: x64
- arch: arm64
host: x64_arm64
runs-on: windows-latest
steps:
- name: Download source
uses: actions/download-artifact@v3
with:
name: internal-source
- name: Unpack source
shell: bash
run: |
tar -xf source.tar.gz --strip-components=1
- name: Install dependencies
shell: bash
run: |
choco install pandoc
- name: Prepare cache key
id: key
shell: powershell
run: |
# Work around caching failure with GNU tar
New-Item -Type Junction -Path vcpkg -Target c:\vcpkg
Write-Output "image=$env:ImageOS-$env:ImageVersion" >> $env:GITHUB_OUTPUT
- name: Enable vcpkg cache
uses: actions/cache@v3
with:
path: vcpkg/installed
key: ${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}-0 # Increase the number whenever dependencies are modified
restore-keys: |
${{ steps.key.outputs.image }}-vcpkg-${{ matrix.arch }}
- name: Prepare vcpkg
shell: bash
run: |
vcpkg install --triplet=${{ matrix.arch }}-windows-static \
liblzma \
libpng \
lzo \
zlib \
# EOF
- name: Install MSVC problem matcher
uses: ammaraskar/msvc-problem-matcher@master
- name: Configure developer command prompt for tools
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- name: Build tools
shell: bash
run: |
mkdir build-host
cd build-host
echo "::group::CMake"
cmake ${GITHUB_WORKSPACE} \
-GNinja \
-DOPTION_TOOLS_ONLY=ON \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
# EOF
echo "::endgroup::"
echo "::group::Build"
cmake --build . --target tools
echo "::endgroup::"
- name: Configure developer command prompt for ${{ matrix.arch }}
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ matrix.host }}
- name: Import code signing certificate
shell: powershell
# If this is run on a fork, there may not be a certificate set up - continue in this case
continue-on-error: true
run: |
$tempFile = [System.IO.Path]::GetTempFileName()
$bytes = [System.Convert]::FromBase64String($env:WINDOWS_CERTIFICATE_P12)
[IO.File]::WriteAllBytes($tempFile, $bytes)
$pwd = ConvertTo-SecureString $env:WINDOWS_CERTIFICATE_PASSWORD -AsPlainText -Force
Import-PfxCertificate -FilePath $tempFile -CertStoreLocation Cert:\CurrentUser\My -Password $pwd
Remove-Item $tempFile
env:
WINDOWS_CERTIFICATE_P12: ${{ secrets.WINDOWS_CERTIFICATE_P12 }}
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
- name: Build (with installer)
if: inputs.is_tag == 'true'
shell: bash
run: |
mkdir build
cd build
echo "::group::CMake"
cmake ${GITHUB_WORKSPACE} \
-GNinja \
-DVCPKG_TARGET_TRIPLET=${{ matrix.arch }}-windows-static \
-DCMAKE_TOOLCHAIN_FILE="c:\vcpkg\scripts\buildsystems\vcpkg.cmake" \
-DOPTION_USE_NSIS=ON \
-DHOST_BINARY_DIR=${GITHUB_WORKSPACE}/build-host \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DWINDOWS_CERTIFICATE_COMMON_NAME="${WINDOWS_CERTIFICATE_COMMON_NAME}" \
# EOF
echo "::endgroup::"
echo "::group::Build"
cmake --build .
echo "::endgroup::"
env:
WINDOWS_CERTIFICATE_COMMON_NAME: ${{ secrets.WINDOWS_CERTIFICATE_COMMON_NAME }}
- name: Build (without installer)
if: inputs.is_tag != 'true'
shell: bash
run: |
mkdir build
cd build
echo "::group::CMake"
cmake ${GITHUB_WORKSPACE} \
-GNinja \
-DVCPKG_TARGET_TRIPLET=${{ matrix.arch }}-windows-static \
-DCMAKE_TOOLCHAIN_FILE="c:\vcpkg\scripts\buildsystems\vcpkg.cmake" \
-DHOST_BINARY_DIR=${GITHUB_WORKSPACE}/build-host \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DWINDOWS_CERTIFICATE_COMMON_NAME="${WINDOWS_CERTIFICATE_COMMON_NAME}" \
# EOF
echo "::endgroup::"
echo "::group::Build"
cmake --build .
echo "::endgroup::"
env:
WINDOWS_CERTIFICATE_COMMON_NAME: ${{ secrets.WINDOWS_CERTIFICATE_COMMON_NAME }}
- name: Create bundles
shell: bash
run: |
cd ${GITHUB_WORKSPACE}/build
echo "::group::Run CPack"
cpack
echo "::endgroup::"
echo "::group::Prepare PDB to be bundled"
PDB=$(ls bundles/*.zip | cut -d/ -f2 | sed 's/.zip$/.pdb/')
cp openttd.pdb bundles/${PDB}
xz -9 bundles/${PDB}
echo "::endgroup::"
echo "::group::Cleanup"
# Remove the sha256 files CPack generates; we will do this ourself at
# the end of this workflow.
rm -f bundles/*.sha256
echo "::endgroup::"
- name: Sign installer
if: inputs.is_tag == 'true'
shell: bash
# If this is run on a fork, there may not be a certificate set up - continue in this case
continue-on-error: true
run: |
cd ${GITHUB_WORKSPACE}/build/bundles
../../os/windows/sign.bat *.exe "${WINDOWS_CERTIFICATE_COMMON_NAME}"
env:
WINDOWS_CERTIFICATE_COMMON_NAME: ${{ secrets.WINDOWS_CERTIFICATE_COMMON_NAME }}
- name: Store bundles
uses: actions/upload-artifact@v3
with:
name: openttd-windows-${{ matrix.arch }}
path: build/bundles
retention-days: 5

View File

@@ -1,125 +0,0 @@
name: Release
on:
workflow_dispatch:
inputs:
ref:
description: 'Ref to build (for Pull Requests, use refs/pull/NNN/head)'
required: true
repository_dispatch:
# client_payload should be the same as the inputs for workflow_dispatch.
types:
- Build*
release:
types:
- published
jobs:
source:
name: Source
uses: ./.github/workflows/release-source.yml
secrets: inherit
docs:
name: Docs
needs: source
uses: ./.github/workflows/release-docs.yml
secrets: inherit
with:
version: ${{ needs.source.outputs.version }}
linux:
name: Linux (Generic)
needs: source
uses: ./.github/workflows/release-linux.yml
secrets: inherit
macos:
name: MacOS
needs: source
uses: ./.github/workflows/release-macos.yml
secrets: inherit
windows:
name: Windows
needs: source
uses: ./.github/workflows/release-windows.yml
secrets: inherit
with:
is_tag: ${{ needs.source.outputs.is_tag }}
windows-store:
name: Windows Store
needs:
- source
- windows
if: needs.source.outputs.is_tag == 'true'
uses: ./.github/workflows/release-windows-store.yml
secrets: inherit
with:
version: ${{ needs.source.outputs.version }}
upload-aws:
name: Upload (AWS)
needs:
- source
- docs
- linux
- macos
- windows
- windows-store
# As windows-store is condition, we need to check ourselves if we need to run.
# The always() makes sure the rest is always evaluated.
if: always() && needs.source.result == 'success' && needs.docs.result == 'success' && needs.linux.result == 'success' && needs.macos.result == 'success' && needs.windows.result == 'success' && (needs.windows-store.result == 'success' || needs.windows-store.result == 'skipped')
uses: ./.github/workflows/upload-aws.yml
secrets: inherit
with:
version: ${{ needs.source.outputs.version }}
folder: ${{ needs.source.outputs.folder }}
trigger_type: ${{ needs.source.outputs.trigger_type }}
upload-steam:
name: Upload (Steam)
needs:
- source
- linux
- macos
- windows
if: needs.source.outputs.trigger_type == 'new-master' || needs.source.outputs.trigger_type == 'new-tag'
uses: ./.github/workflows/upload-steam.yml
secrets: inherit
with:
version: ${{ needs.source.outputs.version }}
trigger_type: ${{ needs.source.outputs.trigger_type }}
upload-gog:
name: Upload (GOG)
needs:
- source
- linux
- macos
- windows
if: needs.source.outputs.trigger_type == 'new-tag'
uses: ./.github/workflows/upload-gog.yml
secrets: inherit
with:
version: ${{ needs.source.outputs.version }}

View File

@@ -1,18 +0,0 @@
name: Unused strings
on:
pull_request:
jobs:
unused-strings:
name: Unused strings
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Check for unused strings
run: |
set -ex
python3 .github/unused-strings.py

View File

@@ -1,76 +0,0 @@
name: Upload (AWS)
on:
workflow_call:
inputs:
version:
required: true
type: string
folder:
required: true
type: string
trigger_type:
required: true
type: string
jobs:
upload:
name: Upload (AWS)
runs-on: ubuntu-20.04
steps:
- name: Download all bundles
uses: actions/download-artifact@v3
- name: Calculate checksums
run: |
echo "::group::Move bundles to a single folder"
mkdir bundles
mv openttd-*/* bundles/
echo "::endgroup::"
cd bundles
for i in $(ls openttd-*); do
echo "::group::Calculating checksums for ${i}"
openssl dgst -r -md5 -hex $i > $i.md5sum
openssl dgst -r -sha1 -hex $i > $i.sha1sum
openssl dgst -r -sha256 -hex $i > $i.sha256sum
echo "::endgroup::"
done
# Some targets generate files that are meant for our-eyes-only.
# They are stored in the "internal" folder, and contains bundles
# for targets like Windows Store. No user has a benefit of knowing
# they exist, hence: internal.
if [ -e internal ]; then
cd internal
for i in $(ls openttd-*); do
echo "::group::Calculating checksums for ${i}"
openssl dgst -r -md5 -hex $i > $i.md5sum
openssl dgst -r -sha1 -hex $i > $i.sha1sum
openssl dgst -r -sha256 -hex $i > $i.sha256sum
echo "::endgroup::"
done
fi
- name: Upload bundles to AWS
run: |
aws s3 cp --recursive --only-show-errors bundles/ s3://${{ secrets.CDN_S3_BUCKET }}/${{ inputs.folder }}/${{ inputs.version }}/
# We do not invalidate the CloudFront distribution here. The trigger
# for "New OpenTTD release" first updated the manifest files and
# creates an index.html. We invalidate after that, so everything
# becomes visible at once.
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }}
- name: Trigger 'New OpenTTD release'
uses: peter-evans/repository-dispatch@v2
with:
token: ${{ secrets.DEPLOYMENT_TOKEN }}
repository: OpenTTD/workflows
event-type: ${{ inputs.trigger_type }}
client-payload: '{"version": "${{ inputs.version }}", "folder": "${{ inputs.folder }}"}'

View File

@@ -1,124 +0,0 @@
name: Upload (GOG)
on:
workflow_call:
inputs:
version:
required: true
type: string
jobs:
upload:
name: Upload (GOG)
runs-on: ubuntu-20.04
steps:
- name: Download all bundles
uses: actions/download-artifact@v3
- 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
- name: Install OpenGFX
shell: bash
run: |
mkdir -p gog/opengfx/baseset
cd gog/opengfx/baseset
echo "::group::Download OpenGFX"
curl -L https://cdn.openttd.org/opengfx-releases/7.1/opengfx-7.1-all.zip -o opengfx-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip opengfx-all.zip
echo "::endgroup::"
rm -f opengfx-all.zip
- name: Install OpenMSX
shell: bash
run: |
mkdir -p gog/openmsx/baseset
cd gog/openmsx/baseset
echo "::group::Download OpenMSX"
curl -L https://cdn.openttd.org/openmsx-releases/0.4.2/openmsx-0.4.2-all.zip -o openmsx-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenGFX"
unzip openmsx-all.zip
tar xf openmsx-*.tar
echo "::endgroup::"
rm -f openmsx-all.zip openmsx-*.tar
- name: Install OpenSFX
shell: bash
run: |
mkdir -p gog/opensfx/baseset
cd gog/opensfx/baseset
echo "::group::Download OpenSFX"
curl -L https://cdn.openttd.org/opensfx-releases/1.0.3/opensfx-1.0.3-all.zip -o opensfx-all.zip
echo "::endgroup::"
echo "::group::Unpack OpenSFX"
unzip opensfx-all.zip
tar xf opensfx-*.tar
echo "::endgroup::"
rm -f opensfx-all.zip opensfx-*.tar
- name: Upload to GOG
run: |
echo "::group::Extracting source"
mkdir source
(
cd source
tar -xf ../internal-source/source.tar.gz --strip-components=1
)
echo "::endgroup::"
(
cd gog
echo "::group::Prepare Win32"
unzip ../openttd-windows-x86/openttd-*-windows-win32.zip
mv openttd-*-windows-win32 win32
echo "::endgroup::"
echo "::group::Prepare Win64"
unzip ../openttd-windows-x64/openttd-*-windows-win64.zip
mv openttd-*-windows-win64 win64
echo "::endgroup::"
echo "::group::Prepare macOS"
mkdir macos
(
cd macos
unzip ../../openttd-macos-universal/openttd-*-macos-universal.zip
)
echo "::endgroup::"
echo "::group::Prepare Linux"
tar xvf ../openttd-linux-generic/openttd-*-linux-generic-amd64.tar.xz
mv openttd-*-linux-generic-amd64 linux
echo "::endgroup::"
echo "::group::Preparing build files"
cp ../source/os/gog/*.json .
for json in $(ls *.json); do
sed -i 's/VERSION/${{ inputs.version }}/g;s/CLIENT_ID/${{ secrets.GOG_CLIENT_ID }}/g;s/CLIENT_SECRET/${{ secrets.GOG_CLIENT_SECRET }}/g' ${json}
done
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
echo "::endgroup::"
)

View File

@@ -1,82 +0,0 @@
name: Upload (Steam)
on:
workflow_call:
inputs:
version:
required: true
type: string
trigger_type:
required: true
type: string
jobs:
upload:
name: Upload (Steam)
runs-on: ubuntu-20.04
steps:
- name: Download all bundles
uses: actions/download-artifact@v3
- name: Setup steamcmd
uses: CyberAndrii/setup-steamcmd@v1
- name: Generate Steam auth code
id: steam-totp
uses: CyberAndrii/steam-totp@v1
with:
shared_secret: ${{ secrets.STEAM_SHARED_SECRET }}
- name: Upload to Steam
run: |
echo "::group::Extracting source"
mkdir source
(
cd source
tar -xf ../internal-source/source.tar.gz --strip-components=1
)
echo "::endgroup::"
mkdir steam
(
cd steam
echo "::group::Prepare Win32"
unzip ../openttd-windows-x86/openttd-*-windows-win32.zip
mv openttd-*-windows-win32 steam-win32
echo "::endgroup::"
echo "::group::Prepare Win64"
unzip ../openttd-windows-x64/openttd-*-windows-win64.zip
mv openttd-*-windows-win64 steam-win64
echo "::endgroup::"
echo "::group::Prepare macOS"
mkdir steam-macos
(
cd steam-macos
unzip ../../openttd-macos-universal/openttd-*-macos-universal.zip
)
echo "::endgroup::"
echo "::group::Prepare Linux"
tar xvf ../openttd-linux-generic/openttd-*-linux-generic-amd64.tar.xz
mv openttd-*-linux-generic-amd64 steam-linux
echo "::endgroup::"
echo "::group::Preparing build file"
if [ "${{ inputs.trigger_type }}" = "new-tag" ]; then
BRANCH="testing"
else
BRANCH="nightly"
fi
cat ../source/os/steam/release.vdf | sed 's/@@DESCRIPTION@@/openttd-${{ inputs.version }}/;s/@@BRANCH@@/'${BRANCH}'/' > release.vdf
cat release.vdf
echo "::endgroup::"
echo "::group::Upload to Steam"
steamcmd +login ${{ secrets.STEAM_USERNAME }} ${{ secrets.STEAM_PASSWORD }} ${{ steps.steam-totp.outputs.code }} +run_app_build $(pwd)/release.vdf +quit
echo "::endgroup::"
)

7
.gitignore vendored
View File

@@ -1,7 +0,0 @@
/.vs
/build*
CMakeSettings.json
docs/aidocs/*
docs/gamedocs/*
docs/source/*
/out

7
BUGS Normal file
View File

@@ -0,0 +1,7 @@
/* $Id$ */
KNOWN BUGS / PROBLEMS:
Normal and elrail depots look the same. Use 'X' (transparent buildings)
to distinguish between them
Missing curors / icons for construction (currently using the conventional ones)

View File

@@ -1,387 +0,0 @@
cmake_minimum_required(VERSION 3.9)
if(NOT BINARY_NAME)
set(BINARY_NAME openttd)
endif()
project(${BINARY_NAME}
VERSION 13.1
)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
message(FATAL_ERROR "In-source builds not allowed. Please run \"cmake ..\" from the build directory. You may need to delete \"${CMAKE_SOURCE_DIR}/CMakeCache.txt\" first.")
endif()
# Debug mode by default.
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
if (EMSCRIPTEN)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/os/emscripten/cmake")
endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.13)
# Use GNUInstallDirs to allow customisation
# but set our own default data and bin dir
if(NOT CMAKE_INSTALL_DATADIR)
set(CMAKE_INSTALL_DATADIR "share/games")
endif()
if(NOT CMAKE_INSTALL_BINDIR)
set(CMAKE_INSTALL_BINDIR "games")
endif()
include(GNUInstallDirs)
include(Options)
set_options()
set_directory_options()
include(Static)
set_static_if_needed()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_CXX_EXTENSIONS NO)
set(CMAKE_EXPORT_COMPILE_COMMANDS YES)
# An empty target for the tools
add_custom_target(tools)
include(Endian)
add_endian_definition()
include(CompileFlags)
compile_flags()
if(APPLE OR UNIX)
add_definitions(-DUNIX)
endif()
if(UNIX)
find_package(Doxygen)
endif()
list(APPEND GENERATED_SOURCE_FILES "${CMAKE_BINARY_DIR}/generated/rev.cpp")
if(WIN32)
list(APPEND GENERATED_SOURCE_FILES "${CMAKE_BINARY_DIR}/generated/ottdres.rc")
endif()
# Generate a target to determine version, which is execute every 'make' run
add_custom_target(find_version
${CMAKE_COMMAND}
-DFIND_VERSION_BINARY_DIR=${CMAKE_BINARY_DIR}/generated
-DCPACK_BINARY_DIR=${CMAKE_BINARY_DIR}
-DREV_MAJOR=${PROJECT_VERSION_MAJOR}
-DREV_MINOR=${PROJECT_VERSION_MINOR}
-DWINDOWS=${WIN32}
-P "${CMAKE_SOURCE_DIR}/cmake/scripts/FindVersion.cmake"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
BYPRODUCTS ${GENERATED_SOURCE_FILES}
)
# Documentation
if(DOXYGEN_EXECUTABLE)
add_custom_target(docs)
add_custom_target(docs_source
${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/docs
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMENT "Generating documentation for source"
)
add_dependencies(docs_source
find_version
)
add_dependencies(docs
docs_source
)
endif()
include(AddCustomXXXTimestamp)
if(OPTION_TOOLS_ONLY)
if(HOST_BINARY_DIR)
unset(HOST_BINARY_DIR CACHE)
endif()
add_subdirectory(${CMAKE_SOURCE_DIR}/src)
return()
endif()
if(APPLE)
# Avoid searching for headers in Frameworks, and libraries in LIBDIR.
set(CMAKE_FIND_FRAMEWORK LAST)
endif()
# Prefer -pthread over -lpthread, which is often the better option of the two.
set(CMAKE_THREAD_PREFER_PTHREAD YES)
# Make sure we have Threads available.
find_package(Threads REQUIRED)
find_package(ZLIB)
find_package(LibLZMA)
find_package(LZO)
find_package(PNG)
if(NOT OPTION_DEDICATED)
if(NOT WIN32)
find_package(Allegro)
if(NOT APPLE)
find_package(Freetype)
find_package(SDL2)
if(NOT SDL2_FOUND)
find_package(SDL)
endif()
find_package(Fluidsynth)
find_package(Fontconfig)
find_package(ICU OPTIONAL_COMPONENTS i18n lx)
endif()
endif()
endif()
if(APPLE)
find_package(Iconv)
find_library(AUDIOTOOLBOX_LIBRARY AudioToolbox)
find_library(AUDIOUNIT_LIBRARY AudioUnit)
find_library(COCOA_LIBRARY Cocoa)
find_library(QUARTZCORE_LIBRARY QuartzCore)
endif()
if(NOT EMSCRIPTEN AND NOT OPTION_DEDICATED)
find_package(OpenGL COMPONENTS OpenGL)
endif()
if(MSVC)
find_package(Editbin REQUIRED)
endif()
find_package(SSE)
find_package(Xaudio2)
find_package(Grfcodec)
include(CheckIPOSupported)
check_ipo_supported(RESULT IPO_FOUND)
show_options()
if(UNIX AND NOT APPLE AND NOT OPTION_DEDICATED)
if(NOT SDL_FOUND AND NOT SDL2_FOUND AND NOT ALLEGRO_FOUND)
message(FATAL_ERROR "SDL, SDL2 or Allegro is required for this platform")
endif()
endif()
if(APPLE)
if(NOT AUDIOTOOLBOX_LIBRARY)
message(FATAL_ERROR "AudioToolbox is required for this platform")
endif()
if(NOT AUDIOUNIT_LIBRARY)
message(FATAL_ERROR "AudioUnit is required for this platform")
endif()
if(NOT COCOA_LIBRARY)
message(FATAL_ERROR "Cocoa is required for this platform")
endif()
if(NOT QUARTZCORE_LIBRARY)
message(FATAL_ERROR "QuartzCore is required for this platform")
endif()
endif()
if(OPTION_PACKAGE_DEPENDENCIES)
if(NOT UNIX)
message(FATAL_ERROR "Can only package dependencies on Linux")
endif()
if(OPTION_INSTALL_FHS)
message(FATAL_ERROR "Cannot install in FHS folders when we are packaging dependencies")
endif()
if(${CMAKE_VERSION} VERSION_LESS "3.16.0")
message(FATAL_ERROR "OPTION_PACKAGE_DEPENDENCIES can only work with CMake 3.16+; you are using ${CMAKE_VERSION}")
endif()
# If we are packaging dependencies, we do two things:
# 1) set the RPATH to include $ORIGIN/lib; $ORIGIN (that literal string)
# is a Linux indicator for "path where application is". In CMake, we
# have to do this before add_executable() is executed.
# 2) copy the libraries that we compile against to the "lib" folder.
# This is done in InstallAndPackage.cmake.
set(CMAKE_INSTALL_RPATH "\$ORIGIN/lib")
set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
endif()
include(SourceList)
# Needed by rev.cpp
include_directories(${CMAKE_SOURCE_DIR}/src)
# Needed by everything that uses Squirrel
include_directories(${CMAKE_SOURCE_DIR}/src/3rdparty/squirrel/include)
include(MSVCFilters)
add_executable(openttd WIN32 ${GENERATED_SOURCE_FILES})
set_target_properties(openttd PROPERTIES OUTPUT_NAME "${BINARY_NAME}")
# All other files are added via target_sources()
if(MSVC)
# Add DPI manifest to project; other WIN32 targets get this via ottdres.rc
target_sources(openttd PRIVATE "${CMAKE_SOURCE_DIR}/os/windows/openttd.manifest")
endif()
add_subdirectory(${CMAKE_SOURCE_DIR}/bin)
add_subdirectory(${CMAKE_SOURCE_DIR}/src)
add_subdirectory(${CMAKE_SOURCE_DIR}/media)
add_dependencies(openttd
find_version)
target_link_libraries(openttd
openttd::languages
openttd::settings
openttd::media
openttd::basesets
openttd::script_api
Threads::Threads
)
if(HAIKU)
target_link_libraries(openttd "be" "network" "midi")
endif()
if(IPO_FOUND)
set_target_properties(openttd PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE True)
set_target_properties(openttd PROPERTIES INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL True)
set_target_properties(openttd PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO True)
endif()
set_target_properties(openttd PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
process_compile_flags()
include(LinkPackage)
link_package(PNG TARGET PNG::PNG ENCOURAGED)
link_package(ZLIB TARGET ZLIB::ZLIB ENCOURAGED)
link_package(LIBLZMA TARGET LibLZMA::LibLZMA ENCOURAGED)
link_package(LZO)
if(NOT OPTION_DEDICATED)
link_package(Fluidsynth)
link_package(SDL)
link_package(SDL2 TARGET SDL2::SDL2)
link_package(Allegro)
link_package(FREETYPE TARGET Freetype::Freetype)
link_package(Fontconfig TARGET Fontconfig::Fontconfig)
link_package(ICU_lx)
link_package(ICU_i18n)
if(SDL2_FOUND AND OPENGL_FOUND AND UNIX)
# SDL2 dynamically loads OpenGL if needed, so do not link to OpenGL when
# on Linux. For Windows, we need to link to OpenGL as we also have a win32
# driver using it.
add_definitions(-DWITH_OPENGL)
message(STATUS "OpenGL found -- -DWITH_OPENGL -- (via SDL2)")
else()
link_package(OpenGL TARGET OpenGL::GL)
endif()
endif()
include(CheckAtomic)
if(APPLE)
link_package(Iconv TARGET Iconv::Iconv)
target_link_libraries(openttd
${AUDIOTOOLBOX_LIBRARY}
${AUDIOUNIT_LIBRARY}
${COCOA_LIBRARY}
${QUARTZCORE_LIBRARY}
)
add_definitions(
-DWITH_COCOA
)
endif()
if(EMSCRIPTEN)
add_library(WASM::WASM INTERFACE IMPORTED)
# Allow heap-growth, and start with a bigger memory size.
target_link_libraries(WASM::WASM INTERFACE "-s ALLOW_MEMORY_GROWTH=1")
target_link_libraries(WASM::WASM INTERFACE "-s INITIAL_MEMORY=33554432")
target_link_libraries(WASM::WASM INTERFACE "-s DISABLE_EXCEPTION_CATCHING=0")
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\"]'")
# Preload all the files we generate during build.
# As we do not compile with FreeType / FontConfig, we also have no way to
# render several languages (like Chinese, ..), so where do you draw the
# line what languages to include and which not? In the end, especially as
# the more languages you add the slower downloading becomes, we decided to
# only ship the English language.
target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_BINARY_DIR}/baseset@/baseset")
target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_BINARY_DIR}/lang/english.lng@/lang/english.lng")
target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_SOURCE_DIR}/bin/ai@/ai")
target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_SOURCE_DIR}/bin/game@/game")
# We use IDBFS for persistent storage.
target_link_libraries(WASM::WASM INTERFACE "-lidbfs.js")
# Use custom pre-js and shell.html.
target_link_libraries(WASM::WASM INTERFACE "--pre-js ${CMAKE_SOURCE_DIR}/os/emscripten/pre.js")
target_link_libraries(WASM::WASM INTERFACE "--shell-file ${CMAKE_SOURCE_DIR}/os/emscripten/shell.html")
# Build the .html (which builds the .js, .wasm, and .data too).
set_target_properties(openttd PROPERTIES SUFFIX ".html")
target_link_libraries(openttd WASM::WASM)
endif()
if(NOT PERSONAL_DIR STREQUAL "(not set)")
add_definitions(
-DWITH_PERSONAL_DIR
-DPERSONAL_DIR="${PERSONAL_DIR}"
)
endif()
if(NOT SHARED_DIR STREQUAL "(not set)")
add_definitions(
-DWITH_SHARED_DIR
-DSHARED_DIR="${SHARED_DIR}"
)
endif()
if(NOT GLOBAL_DIR STREQUAL "(not set)")
add_definitions(
-DGLOBAL_DATA_DIR="${GLOBAL_DIR}"
)
endif()
link_package(SSE)
add_definitions_based_on_options()
if(WIN32)
add_definitions(
-DUNICODE
-D_UNICODE
-DWITH_UNISCRIBE
-DPSAPI_VERSION=1
)
target_link_libraries(openttd
ws2_32
winmm
imm32
usp10
psapi
)
endif()
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
add_definitions(-DPOINTER_IS_64BIT)
endif()
include(CreateRegression)
create_regression()
if(APPLE OR WIN32)
find_package(Pandoc)
endif()
include(InstallAndPackage)

View File

@@ -1,150 +0,0 @@
# Compiling OpenTTD
## Required/optional libraries
OpenTTD makes use of the following external libraries:
- (encouraged) zlib: (de)compressing of old (0.3.0-1.0.5) savegames, content downloads,
heightmaps
- (encouraged) liblzma: (de)compressing of savegames (1.1.0 and later)
- (encouraged) libpng: making screenshots and loading heightmaps
- (optional) liblzo2: (de)compressing of old (pre 0.3.0) savegames
For Linux, the following additional libraries are used (for non-dedicated only):
- libSDL2: hardware access (video, sound, mouse)
- libfreetype: loading generic fonts and rendering them
- libfontconfig: searching for fonts, resolving font names to actual fonts
- libicu: handling of right-to-left scripts (e.g. Arabic and Persian) and
natural sorting of strings
OpenTTD does not require any of the libraries to be present, but without
liblzma you cannot open most recent savegames and without zlib you cannot
open most older savegames or use the content downloading system.
## Windows
You need Microsoft Visual Studio 2017 or more recent.
You can download the free Visual Studio Community Edition from Microsoft at
https://visualstudio.microsoft.com/vs/community/.
OpenTTD needs the Platform SDK, if it isn't installed already. This can be
done during installing Visual Studio, by selecting
`Visual C++ MFC for x86 and x64` (and possibly
`Visual C++ ATL for x86 and x64` depending on your version). If not, you
can get download it as [MS Windows Platform SDK](https://developer.microsoft.com/en-US/windows/downloads/windows-10-sdk).
Install the SDK by following the instructions as given.
Dependencies for OpenTTD on Windows are handled via
[vcpkg](https://github.com/Microsoft/vcpkg/). First you need to install vcpkg
by following the `Quick Start` instructions of their
[README](https://github.com/Microsoft/vcpkg/blob/master/README.md).
After this, you can install the dependencies OpenTTD needs. We advise to use
the `static` versions, and OpenTTD currently needs the following dependencies:
- liblzma
- libpng
- lzo
- zlib
To install both the x64 (64bit) and x86 (32bit) variants (though only one is necessary), you can use:
```ps
.\vcpkg install liblzma:x64-windows-static libpng:x64-windows-static lzo:x64-windows-static zlib:x64-windows-static
.\vcpkg install liblzma:x86-windows-static libpng:x86-windows-static lzo:x86-windows-static zlib:x86-windows-static
```
You can open the folder (as a CMake project). CMake will be detected, and you can compile from there.
If libraries are installed but not found, you need to set VCPKG_TARGET_TRIPLET in CMake parameters.
For Visual Studio 2017 you also need to set CMAKE_TOOLCHAIN_FILE.
(Typical values are shown in the MSVC project file command line example)
Alternatively, you can create a MSVC project file via CMake. For this
either download CMake from https://cmake.org/download/ or use the version
that comes with vcpkg. After that, you can run something similar to this:
```powershell
mkdir build
cd build
cmake.exe .. -G"Visual Studio 16 2019" -DCMAKE_TOOLCHAIN_FILE="<location of vcpkg>\vcpkg\scripts\buildsystems\vcpkg.cmake" -DVCPKG_TARGET_TRIPLET="x64-windows-static"
```
Change `<location of vcpkg>` to where you have installed vcpkg. After this
in the build folder are MSVC project files. MSVC can rebuild the project
files himself via the `ZERO_CHECK` project.
## All other platforms
Minimum required version of CMake is 3.9.
By default this produces a Debug build with assertations enabled.
This is a far slower build than release builds.
```bash
mkdir build
cd build
cmake ..
make
```
For more information on how to use CMake (including how to make Release builds),
we urge you to read [their excellent manual](https://cmake.org/cmake/help/latest/guide/user-interaction/index.html).
## CMake Options
Via CMake, several options can be influenced to get different types of
builds.
- `-DCMAKE_BUILD_TYPE=RelWithDebInfo`: build a release build. This is
significant faster than a debug build, but has far less useful information
in case of a crash.
- `-DOPTION_DEDICATED=ON`: build OpenTTD without a GUI. Useful if you are
running a headless server, as it requires less libraries to operate.
- `-DOPTION_USE_ASSERTS=OFF`: disable asserts. Use with care, as assert
statements capture early signs of trouble. Release builds have them
disabled by default.
- `-DOPTION_USE_THREADS=OFF`: disable the use of threads. This will block
the interface in many places, and in general gives a worse experience of
the game. Use with care.
- `-DOPTION_TOOLS_ONLY=ON`: only build tools like `strgen`. Does not build
the game itself. Useful for cross-compiling.
## Supported compilers
Every compiler that is supported by CMake and supports C++17, should be
able to compile OpenTTD. As the exact list of compilers changes constantly,
we refer to the compiler manual to see if it supports C++17, and to CMake
to see if it supports your compiler.
## Compilation of base sets
To recompile the extra graphics needed to play with the original Transport
Tycoon Deluxe graphics you need GRFCodec (which includes NFORenum) as well.
GRFCodec can be found at
https://www.openttd.org/downloads/grfcodec-releases/latest.html.
Having GRFCodec installed can cause regeneration of the `.grf` files, which
are written in the source directory. This can leave your repository in a
modified state, as different GRFCodec versions can cause binary differences
in the resulting `.grf` files. Also translations might have been added for
the base sets which are not yet included in the base set information files.
To avoid this behaviour, disable GRFCodec (and NFORenum) in CMake cache
(`GRFCODEC_EXECUTABLE` and `NFORENUM_EXECUTABLE`).
## Developers settings
You can control some flags directly via `CXXFLAGS` (any combination
of these flags will work fine too):
- `-DRANDOM_DEBUG`: this helps with debugging desyncs.
- `-fno-inline`: this avoids creating inline functions; this can make
debugging a lot easier.
- `-O0`: this disables all optimizations; this can make debugging a
lot easier.
- `-p`: this enables profiling.
Always use a clean buildfolder if you changing `CXXFLAGS`, as this
value is otherwise cached. Example use:
`CXXFLAGS="-fno-inline" cmake ..`

View File

@@ -1,269 +0,0 @@
# Contributing to OpenTTD
Looking to contribute something to OpenTTD? **Here's how you can help.**
Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved.
Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project.
In return, they should reciprocate that respect in addressing your issue or assessing patches and features.
## Using the issue tracker
The [issue tracker](https://github.com/OpenTTD/OpenTTD/issues) is the preferred channel for [bug reports](#bug-reports), but please respect the following restrictions:
* Please **do not** use the issue tracker for help playing or using OpenTTD.
Please try [irc](https://wiki.openttd.org/en/Development/IRC%20channel), or the [forums](https://www.tt-forums.net/)
* Please **do not** derail or troll issues. Keep the discussion on topic and respect the opinions of others.
* Please **do not** post comments consisting solely of "+1" or ":thumbsup:".
Use [GitHub's "reactions" feature](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments) instead.
We reserve the right to delete comments which violate this rule.
* Please **do not** open issues or pull requests regarding add-on content in NewGRF, GameScripts, AIs, etc.
These are created by third-parties. Please try [irc](https://wiki.openttd.org/en/Development/IRC%20channel) or the [forums](https://www.tt-forums.net/) to discuss these.
* Please use [the web translator](https://translator.openttd.org/) to submit corrections and improvements to translations of the game.
## Bug reports
A bug is a _demonstrable problem_ that is caused by the code in the repository.
Good bug reports are extremely helpful, so thanks!
Guidelines for bug reports:
0. Please don't report issues with games where you changed NewGRFs mid-game. (This can be verified with the `gamelog` console command in-game.)
1. Please don't report issues with modified versions of OpenTTD (patchpacks, unofficial ports, and similar).
2. **Use the GitHub issue search** — check if the issue has already been
reported.
3. **Check if the issue has been fixed** — try to reproduce it using the latest `nightly` build of OpenTTD, available from https://www.openttd.org
4. **Isolate the problem** — ideally create reproducible steps with an attached savegame and screenshots. Try to use few or no NewGRFs, AIs etc if possible.
A good bug report shouldn't leave others needing to chase you up for more information.
Please try to be as detailed as possible in your report.
* What is your environment?
* What steps will reproduce the issue?
* Which operating system(s) experience the problem?
* What would you expect to be the outcome?
All these details will help people to fix any potential bugs.
Example:
> Short and descriptive example bug report title
>
> A summary of the issue and the OS environment in which it occurs. If
> suitable, include the steps required to reproduce the bug.
>
> 1. This is the first step
> 2. This is the second step
> 3. Further steps, etc.
>
> Attached savegame
> Attached screenshots showing the issue
> Crashlogs if the bug causes a crash
>
> Any other information you want to share that is relevant to the issue being
> reported. This might include the lines of code that you have identified as
> causing the bug, and potential solutions (and your opinions on their
> merits).
## Feature requests
Before opening a feature request, please take a moment to find out whether your idea fits with the [scope and goals](./CONTRIBUTING.md#project-goals) of the project.
It's up to *you* to make a strong case to convince the project's developers of the merits of this feature.
Please provide as much detail and context as possible.
This means don't request for a solution, but describe the problem you see and how/why you think it should be fixed.
For feature request we have a strict policy.
Keeping issues around with "a good idea" or "not really a bug but we should maybe fix it" turns out to have the reversed effect: nobody looks at it anymore.
Although we really appreciate feedback and ideas, we will close feature requests that we don't expect to fulfill in the next year.
Many of those ideas etc do have a place on the [forums](https://www.tt-forums.net); and if enough people like it, someone will stand up and make it.
It's usually best to discuss on [Discord](https://discord.gg/openttd) before opening a feature request or working on a large feature in a fork.
Discussion can take time, but it can be productive and avoid disappointment. :)
## Pull requests
Good pull requests—patches, improvements, new features—are a fantastic help.
Pull requests should fit with the [goals of the project](./CONTRIBUTING.md#project-goals).
**Please do ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code, porting to a different language), otherwise you risk spending a lot of time working on something that the project's developers might not want to merge into the project.
Every pull request should have a clear scope, with no unrelated commits.
[Code style](https://wiki.openttd.org/en/Development/Coding%20style) must be complied with for pull requests to be accepted; this also includes [commit message format](https://wiki.openttd.org/en/Development/Coding%20style#commit-message).
Adhering to the following process is the best way to get your work included in the project:
1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork, and configure the remotes:
```bash
git clone https://github.com/<your-username>/OpenTTD.git openttd
git clone https://github.com/OpenTTD/OpenTTD-git-hooks.git openttd_hooks
cd openttd
git remote add upstream https://github.com/OpenTTD/OpenTTD.git
cd .git/hooks
ln -s ../../../openttd_hooks/hooks/* .
```
2. If you cloned a while ago, get the latest changes from upstream:
```bash
git fetch upstream
```
3. Create a new topic branch (off the main project development branch) to
contain your feature, change, or fix:
```bash
git checkout upstream/master -b <topic-branch-name>
```
4. Commit your changes in logical chunks. Please adhere to these [git commit message guidelines](https://wiki.openttd.org/en/Development/Coding%20style#commit-message) or your code is unlikely to be merged into the main project.
Use Git's [interactive rebase](https://docs.github.com/en/get-started/using-git/about-git-rebase) feature to tidy up your commits before making them public.
5. Locally rebase the upstream development branch into your topic branch:
```bash
git fetch upstream
git rebase upstream/master
```
6. Push your topic branch up to your fork the first time:
```bash
git push --set-upstream origin <topic-branch-name>
```
And any time after that:
```bash
git push
```
7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description against the `master` branch.
**IMPORTANT**: By submitting a pull request or patch, you agree to the [License](#license) and the [Privacy Notice](CONTRIBUTING.md#privacy-notice).
### Pull request validation
Continuous integration (CI) tools monitor pull requests, and help us identify build and code quality issues.
The results of the CI tests will show on your pull request.
By clicking on Details you can further zoom in; in case of a failure it will show you why it failed.
In case of success it will report how awesome you were.
Tip: [commit message format](https://wiki.openttd.org/en/Development/Coding%20style#commit-message) is a common reason for pull requests to fail validation.
### Are there any development docs?
There is no single source for OpenTTD development docs. It's a complex project with a long history, and multiple APIs.
A good entry point is [Development](https://wiki.openttd.org/en/Development/) on the OpenTTD wiki; this provides links to wiki documentation and other sources.
The GitHub repo also includes some non-comprehensive documentation in [/docs](./docs).
You may also want the guide to [compiling OpenTTD](./COMPILING.md).
## Project goals
### What are the goals of the official branch?
The main goals of the official branch are:
- Stay faithful to the original gameplay from Transport Tycoon Deluxe
- Improve the user interface
- Allow extending the gameplay with add-ons / mods via supported content APIs
- Provide a (relatively) stable core for both players of the official branch, and for authors of add-ons and maintainers of patchpacks
In contrast, extending or altering the gameplay of the base game is not encouraged.
The rationale behind these goals is that people have different opinions about what OpenTTD is and what it should be.
When it comes to gameplay, there are at least these groups of people:
- *Model railway (mostly singleplayer)*: build "realistic" landscapes, roleplay a world, or even replicate historical scenarios
- *Economical challenge (mostly singleplayer)*: run a business with economical challenges
- *Transport challenge (singleplayer or cooperative multiplayer)*: build efficient track layouts with high cargo throughput and tons of vehicles
- *Competitive speed run (competitive multiplayer)*: maximize some goal in some limited amount of time
When it comes to gameplay features there are at least these groups of interests:
- *Control freak:* micromanagement like conditional orders, refitting and loading etc.
- *Casual:* automatisation like cargodist, path based signalling etc.
To please everyone, the official branch tries to stay close to the original gameplay; after all, that is what brought everyone here.
The preferred method to alter and extend the gameplay is via add-ons like NewGRF and GameScripts.
For a long time, the official branch was also open to features which could be enabled/disabled, but the corner-cases that came with some configurations have rendered some parts of the code very complicated.
Today, new features have to work with all the already existing features, which is not only challenging in corner cases, but also requires spending considerable more work than just "making it work in the game mode that I play".
The preferred method to introduce new gameplay features is to extend the content APIs, supporting ever more add-on content / mods.
This moves conflict-solving away from the codebase to content authors / players.
It is more accepted for add-ons not working together than the base game not working with certain setting combinations.
In general the game should allow anything that doesn't violate basic rules, but it should warn players if they take potentially dangerous or "stupid" actions.
For example, players are not prevented from starting vehicles without orders, but will receive a warning about vehicles having too few orders.
This lack of limitation has led to players challenging themselves to create networks where all vehicles have no orders, increasing gameplay possibilities.
### I do not agree with the goals of the official branch, what can I do instead?
Fork! There is a rich history of experimental patches for OpenTTD.
Many of these will never be accepted for core, but are creative and interesting ways to modify OpenTTD.
Sometimes patches are combined into long-running patchpacks, modified OpenTTD versions which can be downloaded by anyone, or modified OpenTTD clients for dedicated multiplayer servers.
One of the reasons to keep core relatively stable is to make life easier for patch authors and patchpack maintainers where possible.
Patchpack discussions and related topics may be found in community sites such as [TT-Forums development section](https://www.tt-forums.net/viewforum.php?f=33).
## Legal stuff
### License
By contributing your code, you agree to license your contribution under the [GPL v2](https://github.com/OpenTTD/OpenTTD/blob/master/COPYING.md).
### Privacy Notice
We would like to make you aware that contributing to OpenTTD via git will permanently store the name and email address you provide as well as the actual changes and the time and date you made it inside git's version history.
This is inevitable, because it is a main feature of git.
If you are concerned about your privacy, we strongly recommend to use "Anonymous &lt;anonymous@openttd.org&gt;" as the git commit author. We might refuse anonymous contributions if malicious intent is suspected.
Please note that the contributor identity, once given, is used for copyright verification and to provide proof should a malicious commit be made.
As such, the [EU GDPR](https://www.eugdpr.org/key-changes.html) "right to be forgotten" does not apply, as this is an overriding legitimate interest.
Please also note that your commit is public and as such will potentially be processed by many third-parties.
Git's distributed nature makes it impossible to track where exactly your commit, and thus your personal data, will be stored and be processed.
If you would not like to accept this risk, please do either commit anonymously or refrain from contributing to the OpenTTD project.
### Attribution of this Contributing Guide
This contributing guide is adapted from [Bootstrap](https://github.com/twbs/bootstrap/blob/main/.github/CONTRIBUTING.md) under the [Creative Commons Attribution 3.0 Unported License](https://creativecommons.org/licenses/by/3.0/) terms for Bootstrap documentation.
The GDPR notice is adapted from [rsyslog](https://github.com/rsyslog/rsyslog/blob/master/CONTRIBUTING.md) under the [GNU General Public License](https://github.com/rsyslog/rsyslog/blob/master/COPYING).

View File

@@ -1,19 +1,14 @@
This is the license which applies to OpenTTD with the exception of some
3rd party modules. See [./README.md](./README.md) for details
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
GNU General Public License
==========================
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
_Version 2, June 1991_
_Copyright © 1989, 1991 Free Software Foundation, Inc.,_
_51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA_
Preamble
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
### Preamble
The licenses for most software are designed to take away your
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
@@ -23,47 +18,48 @@ using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: **(1)** copyright the software, and
**(2)** offer you this license which gives you legal permission to copy,
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
The precise terms and conditions for copying, distribution and
modification follow.
### TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
**0.** This License applies to any program or other work which contains
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
@@ -80,7 +76,7 @@ is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
**1.** You may copy and distribute verbatim copies of the Program's
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
@@ -91,27 +87,29 @@ along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
**2.** You may modify your copy or copies of the Program or any portion
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
* **a)** You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
* **b)** You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
* **c)** If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
@@ -133,24 +131,26 @@ with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
**3.** You may copy and distribute the Program (or a work based on it,
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
* **a)** Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
* **b)** Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
* **c)** Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
@@ -169,7 +169,7 @@ access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
**4.** You may not copy, modify, sublicense, or distribute the Program
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
@@ -177,7 +177,7 @@ However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
**5.** You are not required to accept this License, since you have not
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
@@ -186,7 +186,7 @@ Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
**6.** Each time you redistribute the Program (or any work based on the
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
@@ -194,7 +194,7 @@ restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
**7.** If, as a consequence of a court judgment or allegation of patent
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
@@ -226,7 +226,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
**8.** If the distribution and/or use of the Program is restricted in
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
@@ -234,7 +234,7 @@ those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
**9.** The Free Software Foundation may publish revised and/or new versions
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
@@ -247,7 +247,7 @@ Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
**10.** If you wish to incorporate parts of the Program into other free
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
@@ -255,9 +255,9 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
### NO WARRANTY
NO WARRANTY
**11.** BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
@@ -267,7 +267,7 @@ TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
**12.** IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
@@ -277,15 +277,15 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS
### How to Apply These Terms to Your New Programs
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
@@ -317,20 +317,20 @@ when it starts in an interactive mode:
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w` and `show c` should show the appropriate
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w` and `show c`; they could even be
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may

View File

@@ -1,12 +0,0 @@
# Make the current version available to CPack
set(CPACK_PACKAGE_VERSION "@REV_VERSION@")
# Name the output file with the correct version
string(REPLACE "#CPACK_PACKAGE_VERSION#" "@REV_VERSION@" CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}")
if (CPACK_BUNDLE_PLIST_SOURCE)
# Rewrite the Info.plist.in to contain the correct version
file(READ ${CPACK_BUNDLE_PLIST_SOURCE} INFO_PLIST_CONTENT)
string(REPLACE "#CPACK_PACKAGE_VERSION#" "@REV_VERSION@" INFO_PLIST_CONTENT "${INFO_PLIST_CONTENT}")
file(WRITE ${CPACK_BUNDLE_PLIST} "${INFO_PLIST_CONTENT}")
endif (CPACK_BUNDLE_PLIST_SOURCE)

View File

@@ -1,61 +0,0 @@
### The OpenTTD team (in alphabetical order):
- Matthijs Kooijman (blathijs) - Pathfinder-guru, Debian port (since 0.3)
- Christoph Elsenhans (frosch) - General coding (since 0.6)
- Loïc Guilloux (glx) - General / Windows Expert (since 0.4.5)
- Charles Pigott (LordAro) - General / Correctness police (since 1.9)
- Michael Lutz (michi_cc) - General / Path based signals (since 0.7)
- Niels Martin Hansen (nielsm) - Music system, general coding (since 1.9)
- Owen Rudge (orudge) - Forum host, OS/2 port (since 0.1)
- Peter Nelson (peter1138) - Spiritual descendant from newGRF gods (since 0.4.5)
- Remko Bijker (Rubidium) - Coder and way more (since 0.4.5)
- Patric Stout (TrueBrain) - NoProgrammer (since 0.3), sys op
- Tyler Trahan (2TallTyler) - General coding (since 13)
### Inactive Developers:
- Grzegorz Duczyński (adf88) - General coding (1.7 - 1.8)
- Albert Hofkamp (Alberth) - GUI expert (0.7 - 1.9)
- Jean-François Claeys (Belugas) - GUI, newindustries and more (0.4.5 - 1.0)
- Bjarni Corfitzen (Bjarni) - macOS port, coder and vehicles (0.3 - 0.7)
- Victor Fischer (Celestar) - Programming everywhere you need him to (0.3 - 0.6)
- Ulf Hermann (fonsinchen) - Cargo Distribution (1.3 - 1.6)
- Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;) (0.4.5 - 0.6)
- Jonathan Coome (Maedhros) - High priest of the NewGRF Temple (0.5 - 0.6)
- Attila Bán (MiHaMiX) - Developer WebTranslator 1 and 2 (0.3 - 0.5)
- Ingo von Borstel (planetmaker) - General coding, Support (1.1 - 1.9)
- Zdeněk Sojka (SmatZ) - Bug finder and fixer (0.6 - 1.3)
- José Soler (Terkhen) - General coding (1.0 - 1.4)
- Christoph Mallon (Tron) - Programmer, code correctness police (0.3 - 0.5)
- Thijs Marinussen (Yexo) - AI Framework, General (0.6 - 1.3)
- Leif Linse (Zuu) - AI/Game Script (1.2 - 1.6)
### Retired Developers:
- Tamás Faragó (Darkvater) - Ex-Lead coder (0.3 - 0.5)
- Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3 - 0.3)
- Emil Djupfeld (egladil) - macOS port (0.4.5 - 0.6)
- Simon Sasburg (HackyKid) - Bug fixer (0.4 - 0.4.5)
- Ludvig Strigeus (ludde) - Original author of OpenTTD, main coder (0.1 - 0.3)
- Cian Duffy (MYOB) - BeOS port / manual writing (0.1 - 0.3)
- Petr Baudiš (pasky) - Many patches, newgrf support (0.3 - 0.3)
- Benedikt Brüggemeier (skidd13) - Bug fixer and code reworker (0.6 - 0.7)
- Serge Paquet (vurlix) - 2nd contributor after ludde (0.1 - 0.3)
### Thanks to:
- Josef Drexler - For his great work on TTDPatch.
- Marcin Grzegorczyk - For his TTDPatch work and documentation of Transport Tycoon Deluxe internals and track foundations
- Stefan Meißner (sign_de) - For his work on the console
- Mike Ragsdale - OpenTTD installer
- Christian Rosentreter (tokai) - MorphOS / AmigaOS port
- Richard Kempton (RichK67) - Additional airports, initial TGP implementation
- Alberto Demichelis - Squirrel scripting language
- L. Peter Deutsch - MD5 implementation
- Michael Blunck - For revolutionizing TTD with awesome graphics
- George - Canal/Lock graphics
- Andrew Parkhouse (andythenorth) - River graphics
- David Dallaston (Pikka) - Tram tracks
- All Translators - For their support to make OpenTTD a truly international game
- Bug Reporters - Thanks for all bug reports
- Chris Sawyer - For an amazing game!

View File

@@ -1,24 +1,16 @@
# This file is part of OpenTTD.
# OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
# OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
# Doxyfile 1.5.4
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "OpenTTD AI API"
PROJECT_NUMBER = ${REV_VERSION}
OUTPUT_DIRECTORY = ${CPACK_BINARY_DIR}/docs/ai-api/
PROJECT_NAME = openttd
OUTPUT_DIRECTORY = docs/source/
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class " \
"The $name widget " \
"The $name file " \
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
@@ -34,48 +26,43 @@ STRIP_FROM_PATH = ./
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
DISTRIBUTE_GROUP_DOC = NO
TAB_SIZE = 2
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
TYPEDEF_HIDES_STRUCT = NO
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_PRIVATE = YES
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = YES
EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = YES
INTERNAL_DOCS = YES
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = NO
GENERATE_TESTLIST = NO
GENERATE_BUGLIST = NO
GENERATE_DEPRECATEDLIST= NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = NO
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = YES
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
@@ -84,43 +71,45 @@ QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = YES
WARN_FORMAT = "$file:$line: $text "
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = . ${FIND_VERSION_BINARY_DIR}/script/api
INPUT_ENCODING = UTF-8
FILE_PATTERNS = script_*.hpp \
ai_*.hpp
INPUT = ./
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.h \
table/*.h
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS = ai_includes.hpp
EXCLUDE_SYMBOLS = GetClassName DECLARE_ENUM_AS_BIT_SET DECLARE_POSTFIX_INCREMENT
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER = "./doxygen_filter.sh AI"
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
REFERENCES_LINK_SOURCE = YES
USE_HTAGS = NO
VERBATIM_HEADERS = NO
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
@@ -131,16 +120,16 @@ HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
GENERATE_HTMLHELP = NO
HTML_DYNAMIC_SECTIONS = NO
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = YES
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
TOC_EXPAND = YES
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 1
GENERATE_TREEVIEW = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = YES
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
@@ -150,7 +139,7 @@ LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = NO
@@ -169,7 +158,7 @@ RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
GENERATE_MAN = YES
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
@@ -178,6 +167,8 @@ MAN_LINKS = NO
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
@@ -194,21 +185,22 @@ PERLMOD_MAKEVAR_PREFIX =
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = DOXYGEN_API
EXPAND_AS_DEFINED = DEF_COMMAND
PREDEFINED =
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE = ${CPACK_BINARY_DIR}/docs/openttd_ai_api.tag
GENERATE_TAGFILE = openttd.tag
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
@@ -223,17 +215,17 @@ TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine

View File

@@ -1,348 +0,0 @@
# This file is part of OpenTTD.
# OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
# OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "OpenTTD Source"
PROJECT_NUMBER = ${REV_VERSION}
PROJECT_BRIEF =
PROJECT_LOGO =
OUTPUT_DIRECTORY = ${CPACK_BINARY_DIR}/docs/source/
CREATE_SUBDIRS = YES
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH = ./
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 2
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 0
AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
GROUP_NESTED_COMPOUNDS = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = YES
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = YES
EXTRACT_ANON_NSPACES = YES
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
HIDE_COMPOUND_REFERENCE= NO
SHOW_INCLUDE_FILES = YES
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_MEMBERS_CTORS_1ST = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_FILES = YES
SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
LAYOUT_FILE =
CITE_BIB_FILES =
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_AS_ERROR = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = ./src/
INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.h \
*.hpp
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS = */3rdparty \
*/script/api
EXCLUDE_SYMBOLS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH = ./docs/
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE =
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_EXTRA_STYLESHEET =
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
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME = Publisher
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = YES
GENERATE_QHP = NO
QCH_FILE =
QHP_NAMESPACE = org.doxygen.Project
QHP_VIRTUAL_FOLDER = doc
QHP_CUST_FILTER_NAME =
QHP_CUST_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
QHG_LOCATION =
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
GENERATE_TREEVIEW = YES
ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
USE_MATHJAX = NO
MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.2/
MATHJAX_EXTENSIONS =
MATHJAX_CODEFILE =
SEARCHENGINE = NO
SERVER_BASED_SEARCH = NO
EXTERNAL_SEARCH = NO
SEARCHENGINE_URL =
SEARCHDATA_FILE = searchdata.xml
EXTERNAL_SEARCH_ID =
EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
LATEX_EXTRA_STYLESHEET =
LATEX_EXTRA_FILES =
PDF_HYPERLINKS = NO
USE_PDFLATEX = NO
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
RTF_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_SUBDIR =
MAN_LINKS = NO
#---------------------------------------------------------------------------
# Configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = YES
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED = WITH_ZLIB \
WITH_LZO \
WITH_LIBLZMA \
WITH_SDL \
WITH_PNG \
WITH_FONTCONFIG \
WITH_FREETYPE \
WITH_ICU_I18N \
WITH_ICU_LX \
UNICODE \
_UNICODE \
_GNU_SOURCE \
FINAL=
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration options related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE = ${CPACK_BINARY_DIR}/docs/openttd.tag
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
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
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
INTERACTIVE_SVG = NO
DOT_PATH =
DOTFILE_DIRS =
MSCFILE_DIRS =
DIAFILE_DIRS =
PLANTUML_JAR_PATH =
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

1125
Makefile Normal file

File diff suppressed because it is too large Load Diff

186
README.md
View File

@@ -1,186 +0,0 @@
# OpenTTD
## Table of contents
- 1.0) [About](#10-about)
- 1.1) [Downloading OpenTTD](#11-downloading-openttd)
- 1.2) [OpenTTD gameplay manual](#12-openttd-gameplay-manual)
- 1.3) [Supported platforms](#13-supported-platforms)
- 1.4) [Installing and running OpenTTD](#14-installing-and-running-openttd)
- 1.5) [Add-on content / mods](#15-add-on-content--mods)
- 1.6) [OpenTTD directories](#16-openttd-directories)
- 1.7) [Compiling OpenTTD](#17-compiling-openttd)
- 2.0) [Contact and community](#20-contact-and-community)
- 2.1) [Contributing to OpenTTD](#21-contributing-to-openttd)
- 2.2) [Reporting bugs](#22-reporting-bugs)
- 2.3) [Translating](#23-translating)
- 3.0) [Licensing](#30-licensing)
- 4.0) [Credits](#40-credits)
## 1.0) About
OpenTTD is a transport simulation game based upon the popular game Transport Tycoon Deluxe, written by Chris Sawyer.
It attempts to mimic the original game as closely as possible while extending it with new features.
OpenTTD is licensed under the GNU General Public License version 2.0, but includes some 3rd party software under different licenses.
See the section ["Licensing"](#30-licensing) below for details.
## 1.1) Downloading OpenTTD
OpenTTD can be downloaded from the [official OpenTTD website](https://www.openttd.org/).
Both 'stable' and 'nightly' versions are available for download:
- most people should choose the 'stable' version, as this has been more extensively tested
- the 'nightly' version includes the latest changes and features, but may sometimes be less reliable
OpenTTD is also available for free on [Steam](https://store.steampowered.com/app/1536610/OpenTTD/), [GOG.com](https://www.gog.com/game/openttd), and the [Microsoft Store](https://www.microsoft.com/p/openttd-official/9ncjg5rvrr1c). On some platforms OpenTTD will be available via your OS package manager or a similar service.
## 1.2) OpenTTD gameplay manual
OpenTTD has a [community-maintained wiki](https://wiki.openttd.org/), including a gameplay manual and tips.
## 1.3) Supported platforms
OpenTTD has been ported to several platforms and operating systems.
The currently supported platforms are:
- Linux (SDL (OpenGL and non-OpenGL))
- macOS (universal) (Cocoa)
- Windows (Win32 GDI / OpenGL)
Other platforms may also work (in particular various BSD systems), but we don't actively test or maintain these.
### 1.3.1) Legacy support
Platforms, languages and compilers change.
We'll keep support going on old platforms as long as someone is interested in supporting them, except where it means the project can't move forward to keep up with language and compiler features.
We guarantee that every revision of OpenTTD will be able to load savegames from every older revision (excepting where the savegame is corrupt).
Please report a bug if you find a save that doesn't load.
## 1.4) Installing and running OpenTTD
OpenTTD is usually straightforward to install, but for more help the wiki [includes an installation guide](https://wiki.openttd.org/en/Manual/Installation).
OpenTTD needs some additional graphics and sound files to run.
For some platforms these will be downloaded during the installation process if required.
For some platforms, you will need to refer to [the installation guide](https://wiki.openttd.org/en/Manual/Installation).
### 1.4.1) Free graphics and sound files
The free data files, split into OpenGFX for graphics, OpenSFX for sounds and
OpenMSX for music can be found at:
- https://www.openttd.org/downloads/opengfx-releases/latest for OpenGFX
- https://www.openttd.org/downloads/opensfx-releases/latest for OpenSFX
- https://www.openttd.org/downloads/openmsx-releases/latest for OpenMSX
Please follow the readme of these packages about the installation procedure.
The Windows installer can optionally download and install these packages.
### 1.4.2) Original Transport Tycoon Deluxe graphics and sound files
If you want to play with the original Transport Tycoon Deluxe data files you have to copy the data files from the CD-ROM into the baseset/ directory.
It does not matter whether you copy them from the DOS or Windows version of Transport Tycoon Deluxe.
The Windows install can optionally copy these files.
You need to copy the following files:
- sample.cat
- trg1r.grf or TRG1.GRF
- trgcr.grf or TRGC.GRF
- trghr.grf or TRGH.GRF
- trgir.grf or TRGI.GRF
- trgtr.grf or TRGT.GRF
### 1.4.3) Original Transport Tycoon Deluxe music
If you want the Transport Tycoon Deluxe music, copy the appropriate files from the original game into the baseset folder.
- TTD for Windows: All files in the gm/ folder (gm_tt00.gm up to gm_tt21.gm)
- TTD for DOS: The GM.CAT file
- Transport Tycoon Original: The GM.CAT file, but rename it to GM-TTO.CAT
## 1.5) Add-on content / mods
OpenTTD features multiple types of add-on content, which modify gameplay in different ways.
Most types of add-on content can be downloaded within OpenTTD via the 'Check Online Content' button in the main menu.
Add-on content can also be installed manually, but that's more complicated; the [OpenTTD wiki](https://wiki.openttd.org/) may offer help with that, or the [OpenTTD directory structure guide](./docs/directory_structure.md).
### 1.6) OpenTTD directories
OpenTTD uses its own directory structure to store game data, add-on content etc.
For more information, see the [directory structure guide](./docs/directory_structure.md).
### 1.7) Compiling OpenTTD
If you want to compile OpenTTD from source, instructions can be found in [COMPILING.md](./COMPILING.md).
## 2.0) Contact and Community
'Official' channels
- [OpenTTD website](https://www.openttd.org)
- [OpenTTD official Discord](https://discord.gg/openttd)
- IRC chat using #openttd on irc.oftc.net [more info about our irc channel](https://wiki.openttd.org/en/Development/IRC%20channel)
- [OpenTTD on Github](https://github.com/OpenTTD/) for code repositories and for reporting issues
- [forum.openttd.org](https://forum.openttd.org/) - the primary community forum site for discussing OpenTTD and related games
- [OpenTTD wiki](https://wiki.openttd.org/) community-maintained wiki, including topics like gameplay guide, detailed explanation of some game mechanics, how to use add-on content (mods) and much more
'Unofficial' channels
- the OpenTTD wiki has a [page listing OpenTTD communities](https://wiki.openttd.org/en/Community/Community) including some in languages other than English
### 2.1) Contributing to OpenTTD
We welcome contributors to OpenTTD. More information for contributors can be found in [CONTRIBUTING.md](./CONTRIBUTING.md)
### 2.2) Reporting bugs
Good bug reports are very helpful. We have a [guide to reporting bugs](./CONTRIBUTING.md#bug-reports) to help with this.
Desyncs in multiplayer are complex to debug and report (some software development skils are required).
Instructions can be found in [debugging and reporting desyncs](./docs/debugging_desyncs.md).
### 2.3) Translating
OpenTTD is translated into many languages. Translations are added and updated via the [online translation tool](https://translator.openttd.org).
## 3.0) Licensing
OpenTTD is licensed under the GNU General Public License version 2.0.
For the complete license text, see the file '[COPYING.md](./COPYING.md)'.
This license applies to all files in this distribution, except as noted below.
The squirrel implementation in `src/3rdparty/squirrel` is licensed under the Zlib license.
See `src/3rdparty/squirrel/COPYRIGHT` for the complete license text.
The md5 implementation in `src/3rdparty/md5` is licensed under the Zlib license.
See the comments in the source files in `src/3rdparty/md5` for the complete license text.
The implementations of Posix `getaddrinfo` and `getnameinfo` for OS/2 in `src/3rdparty/os2` are distributed partly under the GNU Lesser General Public License 2.1, and partly under the (3-clause) BSD license.
The exact licensing terms can be found in `src/3rdparty/os2/getaddrinfo.c` resp. `src/3rdparty/os2/getnameinfo.c`.
The fmt implementation in `src/3rdparty/fmt` is licensed under the MIT license.
See `src/3rdparty/fmt/LICENSE.rst` for the complete license text.
## 4.0 Credits
See [CREDITS.md](./CREDITS.md)

247
ai/ai.c Normal file
View File

@@ -0,0 +1,247 @@
/* $Id$ */
#include "../stdafx.h"
#include "../openttd.h"
#include "../variables.h"
#include "../command.h"
#include "../network.h"
#include "ai.h"
#include "default/default.h"
/**
* Dequeues commands put in the queue via AI_PutCommandInQueue.
*/
static void AI_DequeueCommands(PlayerID player)
{
AICommand *com, *entry_com;
entry_com = _ai_player[player].queue;
/* It happens that DoCommandP issues a new DoCommandAI which adds a new command
* to this very same queue (don't argue about this, if it currently doesn't
* happen I can tell you it will happen with AIScript -- TrueLight). If we
* do not make the queue NULL, that commands will be dequeued immediatly.
* Therefor we safe the entry-point to entry_com, and make the queue NULL, so
* the new queue can be safely built up. */
_ai_player[player].queue = NULL;
_ai_player[player].queue_tail = NULL;
/* Dequeue all commands */
while ((com = entry_com) != NULL) {
_current_player = player;
_cmd_text = com->text;
DoCommandP(com->tile, com->p1, com->p2, com->callback, com->procc);
/* Free item */
entry_com = com->next;
free(com->text);
free(com);
}
}
/**
* Needed for SP; we need to delay DoCommand with 1 tick, because else events
* will make infinite loops (AIScript).
*/
static void AI_PutCommandInQueue(PlayerID player, TileIndex tile, uint32 p1, uint32 p2, uint procc, CommandCallback* callback)
{
AICommand *com;
if (_ai_player[player].queue_tail == NULL) {
/* There is no item in the queue yet, create the queue */
_ai_player[player].queue = malloc(sizeof(AICommand));
_ai_player[player].queue_tail = _ai_player[player].queue;
} else {
/* Add an item at the end */
_ai_player[player].queue_tail->next = malloc(sizeof(AICommand));
_ai_player[player].queue_tail = _ai_player[player].queue_tail->next;
}
/* This is our new item */
com = _ai_player[player].queue_tail;
/* Assign the info */
com->tile = tile;
com->p1 = p1;
com->p2 = p2;
com->procc = procc;
com->callback = callback;
com->next = NULL;
com->text = NULL;
/* Copy the cmd_text, if needed */
if (_cmd_text != NULL) {
com->text = strdup(_cmd_text);
_cmd_text = NULL;
}
}
/**
* Executes a raw DoCommand for the AI.
*/
int32 AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback* callback)
{
PlayerID old_lp;
int32 res = 0;
const char* tmp_cmdtext;
/* If you enable DC_EXEC with DC_QUERY_COST you are a really strange
* person.. should we check for those funny jokes?
*/
/* The test already resets _cmd_text, so backup the pointer */
tmp_cmdtext = _cmd_text;
/* First, do a test-run to see if we can do this */
res = DoCommand(tile, p1, p2, flags & ~DC_EXEC, procc);
/* The command failed, or you didn't want to execute, or you are quering, return */
if (CmdFailed(res) || !(flags & DC_EXEC) || (flags & DC_QUERY_COST)) {
return res;
}
/* Restore _cmd_text */
_cmd_text = tmp_cmdtext;
/* If we did a DC_EXEC, and the command did not return an error, execute it
* over the network */
if (flags & DC_AUTO) procc |= CMD_AUTO;
if (flags & DC_NO_WATER) procc |= CMD_NO_WATER;
/* NetworkSend_Command needs _local_player to be set correctly, so
* adjust it, and put it back right after the function */
old_lp = _local_player;
_local_player = _current_player;
#ifdef ENABLE_NETWORK
/* Send the command */
if (_networking) {
/* Network is easy, send it to his handler */
NetworkSend_Command(tile, p1, p2, procc, callback);
} else {
#else
{
#endif
/* If we execute BuildCommands directly in SP, we have a big problem with events
* so we need to delay is for 1 tick */
AI_PutCommandInQueue(_current_player, tile, p1, p2, procc, callback);
}
/* Set _local_player back */
_local_player = old_lp;
return res;
}
int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc)
{
return AI_DoCommandCc(tile, p1, p2, flags, procc, NULL);
}
/**
* Run 1 tick of the AI. Don't overdo it, keep it realistic.
*/
static void AI_RunTick(PlayerID player)
{
extern void AiNewDoGameLoop(Player *p);
Player *p = GetPlayer(player);
_current_player = player;
if (_patches.ainew_active) {
AiNewDoGameLoop(p);
} else {
/* Enable all kind of cheats the old AI needs in order to operate correctly... */
_is_old_ai_player = true;
AiDoGameLoop(p);
_is_old_ai_player = false;
}
}
/**
* The gameloop for AIs.
* Handles one tick for all the AIs.
*/
void AI_RunGameLoop(void)
{
/* Don't do anything if ai is disabled */
if (!_ai.enabled) return;
/* Don't do anything if we are a network-client, or the AI has been disabled */
if (_networking && (!_network_server || !_patches.ai_in_multiplayer)) return;
/* New tick */
_ai.tick++;
/* Make sure the AI follows the difficulty rule.. */
assert(_opt.diff.competitor_speed <= 4);
if ((_ai.tick & ((1 << (4 - _opt.diff.competitor_speed)) - 1)) != 0) return;
/* Check for AI-client (so joining a network with an AI) */
if (!_networking || _network_server) {
/* Check if we want to run AIs (server or SP only) */
const Player* p;
FOR_ALL_PLAYERS(p) {
if (p->is_active && p->is_ai) {
/* This should always be true, else something went wrong... */
assert(_ai_player[p->index].active);
/* Run the script */
AI_DequeueCommands(p->index);
AI_RunTick(p->index);
}
}
}
_current_player = OWNER_NONE;
}
/**
* A new AI sees the day of light. You can do here what ever you think is needed.
*/
void AI_StartNewAI(PlayerID player)
{
assert(IsValidPlayer(player));
/* Called if a new AI is booted */
_ai_player[player].active = true;
}
/**
* This AI player died. Give it some chance to make a final puf.
*/
void AI_PlayerDied(PlayerID player)
{
/* Called if this AI died */
_ai_player[player].active = false;
}
/**
* Initialize some AI-related stuff.
*/
void AI_Initialize(void)
{
/* First, make sure all AIs are DEAD! */
AI_Uninitialize();
memset(&_ai, 0, sizeof(_ai));
memset(&_ai_player, 0, sizeof(_ai_player));
_ai.enabled = true;
}
/**
* Deinitializer for AI-related stuff.
*/
void AI_Uninitialize(void)
{
const Player* p;
FOR_ALL_PLAYERS(p) {
if (p->is_active && p->is_ai) AI_PlayerDied(p->index);
}
}

111
ai/ai.h Normal file
View File

@@ -0,0 +1,111 @@
#ifndef AI_H
#define AI_H
#include "../functions.h"
#include "../network.h"
#include "../player.h"
#include "../command.h"
/* How DoCommands look like for an AI */
typedef struct AICommand {
uint32 tile;
uint32 p1;
uint32 p2;
uint32 procc;
CommandCallback* callback;
char *text;
uint uid;
struct AICommand *next;
} AICommand;
/* The struct for an AIScript Player */
typedef struct AIPlayer {
bool active; ///< Is this AI active?
AICommand *queue; ///< The commands that he has in his queue
AICommand *queue_tail; ///< The tail of this queue
} AIPlayer;
/* The struct to keep some data about the AI in general */
typedef struct AIStruct {
/* General */
bool enabled; ///< Is AI enabled?
uint tick; ///< The current tick (something like _frame_counter, only for AIs)
} AIStruct;
VARDEF AIStruct _ai;
VARDEF AIPlayer _ai_player[MAX_PLAYERS];
// ai.c
void AI_StartNewAI(PlayerID player);
void AI_PlayerDied(PlayerID player);
void AI_RunGameLoop(void);
void AI_Initialize(void);
void AI_Uninitialize(void);
int32 AI_DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc);
int32 AI_DoCommandCc(TileIndex tile, uint32 p1, uint32 p2, uint32 flags, uint procc, CommandCallback* callback);
/** Is it allowed to start a new AI.
* This function checks some boundries to see if we should launch a new AI.
* @return True if we can start a new AI.
*/
static inline bool AI_AllowNewAI(void)
{
/* If disabled, no AI */
if (!_ai.enabled)
return false;
/* If in network, but no server, no AI */
if (_networking && !_network_server)
return false;
/* If in network, and server, possible AI */
if (_networking && _network_server) {
/* Do we want AIs in multiplayer? */
if (!_patches.ai_in_multiplayer)
return false;
/* Only the NewAI is allowed... sadly enough the old AI just doesn't support this
* system, because all commands are delayed by at least 1 tick, which causes
* a big problem, because it uses variables that are only set AFTER the command
* is really executed... */
if (!_patches.ainew_active)
return false;
}
return true;
}
#define AI_CHANCE16(a,b) ((uint16) AI_Random() <= (uint16)((65536 * a) / b))
#define AI_CHANCE16R(a,b,r) ((uint16)(r = AI_Random()) <= (uint16)((65536 * a) / b))
/**
* The random-function that should be used by ALL AIs.
*/
static inline uint AI_RandomRange(uint max)
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client.
*/
if (_networking)
return InteractiveRandomRange(max);
else
return RandomRange(max);
}
/**
* The random-function that should be used by ALL AIs.
*/
static inline uint32 AI_Random(void)
{
/* We pick RandomRange if we are in SP (so when saved, we do the same over and over)
* but we pick InteractiveRandomRange if we are a network_server or network-client.
*/
if (_networking)
return InteractiveRandom();
else
return Random();
}
#endif /* AI_H */

3941
ai/default/default.c Normal file

File diff suppressed because it is too large Load Diff

8
ai/default/default.h Normal file
View File

@@ -0,0 +1,8 @@
/* $Id$ */
#ifndef DEFAULT_H
#define DEFAULT_H
void AiDoGameLoop(Player*);
#endif

324
ai/trolly/build.c Normal file
View File

@@ -0,0 +1,324 @@
/* $Id$ */
#include "../../stdafx.h"
#include "../../openttd.h"
#include "../../debug.h"
#include "../../functions.h"
#include "../../map.h"
#include "../../road_map.h"
#include "../../tile.h"
#include "../../vehicle.h"
#include "../../command.h"
#include "trolly.h"
#include "../../engine.h"
#include "../../station.h"
#include "../../variables.h"
#include "../../bridge.h"
#include "../ai.h"
// Build HQ
// Params:
// tile : tile where HQ is going to be build
bool AiNew_Build_CompanyHQ(Player *p, TileIndex tile)
{
if (CmdFailed(AI_DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ)))
return false;
AI_DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_COMPANY_HQ);
return true;
}
// Build station
// Params:
// type : AI_TRAIN/AI_BUS/AI_TRUCK : indicates the type of station
// tile : tile where station is going to be build
// length : in case of AI_TRAIN: length of station
// numtracks : in case of AI_TRAIN: tracks of station
// direction : the direction of the station
// flag : flag passed to DoCommand (normally 0 to get the cost or DC_EXEC to build it)
int AiNew_Build_Station(Player *p, byte type, TileIndex tile, byte length, byte numtracks, byte direction, byte flag)
{
if (type == AI_TRAIN)
return AI_DoCommand(tile, direction + (numtracks << 8) + (length << 16), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_RAILROAD_STATION);
if (type == AI_BUS)
return AI_DoCommand(tile, direction, RS_BUS, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP);
return AI_DoCommand(tile, direction, RS_TRUCK, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_STOP);
}
// Builds a brdige. The second best out of the ones available for this player
// Params:
// tile_a : starting point
// tile_b : end point
// flag : flag passed to DoCommand
int AiNew_Build_Bridge(Player *p, TileIndex tile_a, TileIndex tile_b, byte flag)
{
int bridge_type, bridge_len, type, type2;
// Find a good bridgetype (the best money can buy)
bridge_len = GetBridgeLength(tile_a, tile_b);
type = type2 = 0;
for (bridge_type = MAX_BRIDGES-1; bridge_type >= 0; bridge_type--) {
if (CheckBridge_Stuff(bridge_type, bridge_len)) {
type2 = type;
type = bridge_type;
// We found two bridges, exit
if (type2 != 0) break;
}
}
// There is only one bridge that can be built
if (type2 == 0 && type != 0) type2 = type;
// Now, simply, build the bridge!
if (p->ainew.tbt == AI_TRAIN) {
return AI_DoCommand(tile_a, tile_b, (0x00 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
} else {
return AI_DoCommand(tile_a, tile_b, (0x80 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE);
}
}
// Build the route part by part
// Basicly what this function do, is build that amount of parts of the route
// that go in the same direction. It sets 'part' to the last part of the route builded.
// The return value is the cost for the builded parts
//
// Params:
// PathFinderInfo : Pointer to the PathFinderInfo used for AiPathFinder
// part : Which part we need to build
//
// TODO: skip already builded road-pieces (e.g.: cityroad)
int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag)
{
int part = PathFinderInfo->position;
byte *route_extra = PathFinderInfo->route_extra;
TileIndex *route = PathFinderInfo->route;
int dir;
int old_dir = -1;
int cost = 0;
int res;
// We need to calculate the direction with the parent of the parent.. so we skip
// the first pieces and the last piece
if (part < 1) part = 1;
// When we are done, stop it
if (part >= PathFinderInfo->route_length - 1) {
PathFinderInfo->position = -2;
return 0;
}
if (PathFinderInfo->rail_or_road) {
// Tunnel code
if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
cost += AI_DoCommand(route[part], 0, 0, flag, CMD_BUILD_TUNNEL);
PathFinderInfo->position++;
// TODO: problems!
if (CmdFailed(cost)) {
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be built!");
return 0;
}
return cost;
}
// Bridge code
if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
cost += AiNew_Build_Bridge(p, route[part], route[part-1], flag);
PathFinderInfo->position++;
// TODO: problems!
if (CmdFailed(cost)) {
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be built!");
return 0;
}
return cost;
}
// Build normal rail
// Keep it doing till we go an other way
if (route_extra[part - 1] == 0 && route_extra[part] == 0) {
while (route_extra[part] == 0) {
// Get the current direction
dir = AiNew_GetRailDirection(route[part-1], route[part], route[part+1]);
// Is it the same as the last one?
if (old_dir != -1 && old_dir != dir) break;
old_dir = dir;
// Build the tile
res = AI_DoCommand(route[part], 0, dir, flag, CMD_BUILD_SINGLE_RAIL);
if (CmdFailed(res)) {
// Problem.. let's just abort it all!
p->ainew.state = AI_STATE_NOTHING;
return 0;
}
cost += res;
// Go to the next tile
part++;
// Check if it is still in range..
if (part >= PathFinderInfo->route_length - 1) break;
}
part--;
}
// We want to return the last position, so we go back one
PathFinderInfo->position = part;
} else {
// Tunnel code
if ((AI_PATHFINDER_FLAG_TUNNEL & route_extra[part]) != 0) {
cost += AI_DoCommand(route[part], 0x200, 0, flag, CMD_BUILD_TUNNEL);
PathFinderInfo->position++;
// TODO: problems!
if (CmdFailed(cost)) {
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: tunnel could not be built!");
return 0;
}
return cost;
}
// Bridge code
if ((AI_PATHFINDER_FLAG_BRIDGE & route_extra[part]) != 0) {
cost += AiNew_Build_Bridge(p, route[part], route[part+1], flag);
PathFinderInfo->position++;
// TODO: problems!
if (CmdFailed(cost)) {
DEBUG(ai,0)("[AiNew - BuildPath] We have a serious problem: bridge could not be built!");
return 0;
}
return cost;
}
// Build normal road
// Keep it doing till we go an other way
// EnsureNoVehicle makes sure we don't build on a tile where a vehicle is. This way
// it will wait till the vehicle is gone..
if (route_extra[part-1] == 0 && route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
while (route_extra[part] == 0 && (flag != DC_EXEC || EnsureNoVehicle(route[part]))) {
// Get the current direction
dir = AiNew_GetRoadDirection(route[part-1], route[part], route[part+1]);
// Is it the same as the last one?
if (old_dir != -1 && old_dir != dir) break;
old_dir = dir;
// There is already some road, and it is a bridge.. don't build!!!
if (!IsTileType(route[part], MP_TUNNELBRIDGE)) {
// Build the tile
res = AI_DoCommand(route[part], dir, 0, flag | DC_NO_WATER, CMD_BUILD_ROAD);
// Currently, we ignore CMD_ERRORs!
if (CmdFailed(res) && flag == DC_EXEC && !IsTileType(route[part], MP_STREET) && !EnsureNoVehicle(route[part])) {
// Problem.. let's just abort it all!
DEBUG(ai,0)("Darn, the route could not be built.. aborting!");
p->ainew.state = AI_STATE_NOTHING;
return 0;
}
if (!CmdFailed(res)) cost += res;
}
// Go to the next tile
part++;
// Check if it is still in range..
if (part >= PathFinderInfo->route_length - 1) break;
}
part--;
// We want to return the last position, so we go back one
}
if (!EnsureNoVehicle(route[part]) && flag == DC_EXEC) part--;
PathFinderInfo->position = part;
}
return cost;
}
// This functions tries to find the best vehicle for this type of cargo
// It returns INVALID_ENGINE if not suitable engine is found
EngineID AiNew_PickVehicle(Player *p)
{
if (p->ainew.tbt == AI_TRAIN) {
// Not supported yet
return INVALID_ENGINE;
} else {
EngineID best_veh_index = INVALID_ENGINE;
int32 best_veh_rating = 0;
EngineID start = ROAD_ENGINES_INDEX;
EngineID end = ROAD_ENGINES_INDEX + NUM_ROAD_ENGINES;
EngineID i;
/* Loop through all road vehicles */
for (i = start; i != end; i++) {
const RoadVehicleInfo *rvi = RoadVehInfo(i);
const Engine* e = GetEngine(i);
int32 rating;
int32 ret;
/* Skip vehicles which can't take our cargo type */
if (rvi->cargo_type != p->ainew.cargo && !CanRefitTo(i, p->ainew.cargo)) continue;
// Is it availiable?
// Also, check if the reliability of the vehicle is above the AI_VEHICLE_MIN_RELIABILTY
if (!HASBIT(e->player_avail, _current_player) || e->reliability * 100 < AI_VEHICLE_MIN_RELIABILTY << 16) continue;
/* Rate and compare the engine by speed & capacity */
rating = rvi->max_speed * rvi->capacity;
if (rating <= best_veh_rating) continue;
// Can we build it?
ret = AI_DoCommand(0, i, 0, DC_QUERY_COST, CMD_BUILD_ROAD_VEH);
if (CmdFailed(ret)) continue;
best_veh_rating = rating;
best_veh_index = i;
}
return best_veh_index;
}
}
void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
Player* p = GetPlayer(_current_player);
if (success) {
p->ainew.state = AI_STATE_GIVE_ORDERS;
p->ainew.veh_id = _new_vehicle_id;
if (GetVehicle(p->ainew.veh_id)->cargo_type != p->ainew.cargo) {
/* Cargo type doesn't match, so refit it */
if (CmdFailed(DoCommand(tile, p->ainew.veh_id, p->ainew.cargo, DC_EXEC, CMD_REFIT_ROAD_VEH))) {
/* Refit failed, so sell the vehicle */
DoCommand(tile, p->ainew.veh_id, 0, DC_EXEC, CMD_SELL_ROAD_VEH);
p->ainew.state = AI_STATE_NOTHING;
}
}
} else {
/* XXX this should be handled more gracefully */
p->ainew.state = AI_STATE_NOTHING;
}
}
// Builds the best vehicle possible
int AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag)
{
EngineID i = AiNew_PickVehicle(p);
if (i == INVALID_ENGINE) return CMD_ERROR;
if (p->ainew.tbt == AI_TRAIN) return CMD_ERROR;
if (flag & DC_EXEC) {
return AI_DoCommandCc(tile, i, 0, flag, CMD_BUILD_ROAD_VEH, CcAI);
} else {
return AI_DoCommand(tile, i, 0, flag, CMD_BUILD_ROAD_VEH);
}
}
int AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag)
{
int ret, ret2;
if (p->ainew.tbt == AI_TRAIN) {
return AI_DoCommand(tile, 0, direction, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRAIN_DEPOT);
} else {
ret = AI_DoCommand(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_DEPOT);
if (CmdFailed(ret)) return ret;
// Try to build the road from the depot
ret2 = AI_DoCommand(tile + TileOffsByDiagDir(direction), DiagDirToRoadBits(ReverseDiagDir(direction)), 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
// If it fails, ignore it..
if (CmdFailed(ret2)) return ret;
return ret + ret2;
}
}

510
ai/trolly/pathfinder.c Normal file
View File

@@ -0,0 +1,510 @@
/* $Id$ */
#include "../../stdafx.h"
#include "../../openttd.h"
#include "../../bridge_map.h"
#include "../../debug.h"
#include "../../functions.h"
#include "../../map.h"
#include "../../tile.h"
#include "../../command.h"
#include "trolly.h"
#include "../../depot.h"
#include "../../tunnel_map.h"
#include "../../bridge.h"
#include "../ai.h"
#define TEST_STATION_NO_DIR 0xFF
// Tests if a station can be build on the given spot
// TODO: make it train compatible
static bool TestCanBuildStationHere(TileIndex tile, byte dir)
{
Player *p = GetPlayer(_current_player);
if (dir == TEST_STATION_NO_DIR) {
int32 ret;
// TODO: currently we only allow spots that can be access from al 4 directions...
// should be fixed!!!
for (dir = 0; dir < 4; dir++) {
ret = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST);
if (!CmdFailed(ret)) return true;
}
return false;
}
// return true if command succeeded, so the inverse of CmdFailed()
return !CmdFailed(AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST));
}
static bool IsRoad(TileIndex tile)
{
return
// MP_STREET, but not a road depot?
(IsTileType(tile, MP_STREET) && !IsTileDepotType(tile, TRANSPORT_ROAD)) ||
(IsTileType(tile, MP_TUNNELBRIDGE) && (
(IsTunnel(tile) && GetTunnelTransportType(tile) == TRANSPORT_ROAD) ||
(IsBridge(tile) && GetBridgeTransportType(tile) == TRANSPORT_ROAD)
));
}
// Checks if a tile 'a' is between the tiles 'b' and 'c'
#define TILES_BETWEEN(a, b, c) (TileX(a) >= TileX(b) && TileX(a) <= TileX(c) && TileY(a) >= TileY(b) && TileY(a) <= TileY(c))
// Check if the current tile is in our end-area
static int32 AyStar_AiPathFinder_EndNodeCheck(AyStar *aystar, OpenListNode *current)
{
const Ai_PathFinderInfo* PathFinderInfo = aystar->user_target;
// It is not allowed to have a station on the end of a bridge or tunnel ;)
if (current->path.node.user_data[0] != 0) return AYSTAR_DONE;
if (TILES_BETWEEN(current->path.node.tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br))
if (IsTileType(current->path.node.tile, MP_CLEAR) || IsTileType(current->path.node.tile, MP_TREES))
if (current->path.parent == NULL || TestCanBuildStationHere(current->path.node.tile, AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile)))
return AYSTAR_FOUND_END_NODE;
return AYSTAR_DONE;
}
// Calculates the hash
// Currently it is a 10 bit hash, so the hash array has a max depth of 6 bits (so 64)
static uint AiPathFinder_Hash(uint key1, uint key2)
{
return (TileX(key1) & 0x1F) + ((TileY(key1) & 0x1F) << 5);
}
// Clear the memory of all the things
static void AyStar_AiPathFinder_Free(AyStar *aystar)
{
AyStarMain_Free(aystar);
free(aystar);
}
static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current);
static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current);
// This creates the AiPathFinder
AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo)
{
PathNode start_node;
uint x;
uint y;
// Create AyStar
AyStar *result = malloc(sizeof(AyStar));
init_AyStar(result, AiPathFinder_Hash, 1 << 10);
// Set the function pointers
result->CalculateG = AyStar_AiPathFinder_CalculateG;
result->CalculateH = AyStar_AiPathFinder_CalculateH;
result->EndNodeCheck = AyStar_AiPathFinder_EndNodeCheck;
result->FoundEndNode = AyStar_AiPathFinder_FoundEndNode;
result->GetNeighbours = AyStar_AiPathFinder_GetNeighbours;
result->free = AyStar_AiPathFinder_Free;
// Set some information
result->loops_per_tick = AI_PATHFINDER_LOOPS_PER_TICK;
result->max_path_cost = 0;
result->max_search_nodes = AI_PATHFINDER_MAX_SEARCH_NODES;
// Set the user_data to the PathFinderInfo
result->user_target = PathFinderInfo;
// Set the start node
start_node.parent = NULL;
start_node.node.direction = 0;
start_node.node.user_data[0] = 0;
// Now we add all the starting tiles
for (x = TileX(PathFinderInfo->start_tile_tl); x <= TileX(PathFinderInfo->start_tile_br); x++) {
for (y = TileY(PathFinderInfo->start_tile_tl); y <= TileY(PathFinderInfo->start_tile_br); y++) {
start_node.node.tile = TileXY(x, y);
result->addstart(result, &start_node.node, 0);
}
}
return result;
}
// To reuse AyStar we sometimes have to clean all the memory
void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo)
{
PathNode start_node;
uint x;
uint y;
aystar->clear(aystar);
// Set the user_data to the PathFinderInfo
aystar->user_target = PathFinderInfo;
// Set the start node
start_node.parent = NULL;
start_node.node.direction = 0;
start_node.node.user_data[0] = 0;
start_node.node.tile = PathFinderInfo->start_tile_tl;
// Now we add all the starting tiles
for (x = TileX(PathFinderInfo->start_tile_tl); x <= TileX(PathFinderInfo->start_tile_br); x++) {
for (y = TileY(PathFinderInfo->start_tile_tl); y <= TileY(PathFinderInfo->start_tile_br); y++) {
TileIndex tile = TileXY(x, y);
if (!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES)) continue;
if (!TestCanBuildStationHere(tile, TEST_STATION_NO_DIR)) continue;
start_node.node.tile = tile;
aystar->addstart(aystar, &start_node.node, 0);
}
}
}
// The h-value, simple calculation
static int32 AyStar_AiPathFinder_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
{
const Ai_PathFinderInfo* PathFinderInfo = aystar->user_target;
int r, r2;
if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION) {
// The station is pointing to a direction, add a tile towards that direction, so the H-value is more accurate
r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl + TileOffsByDiagDir(PathFinderInfo->end_direction));
r2 = DistanceManhattan(current->tile, PathFinderInfo->end_tile_br + TileOffsByDiagDir(PathFinderInfo->end_direction));
} else {
// No direction, so just get the fastest route to the station
r = DistanceManhattan(current->tile, PathFinderInfo->end_tile_tl);
r2 = DistanceManhattan(current->tile, PathFinderInfo->end_tile_br);
}
// See if the bottomright is faster than the topleft..
if (r2 < r) r = r2;
return r * AI_PATHFINDER_H_MULTIPLER;
}
// We found the end.. let's get the route back and put it in an array
static void AyStar_AiPathFinder_FoundEndNode(AyStar *aystar, OpenListNode *current)
{
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
uint i = 0;
PathNode *parent = &current->path;
do {
PathFinderInfo->route_extra[i] = parent->node.user_data[0];
PathFinderInfo->route[i++] = parent->node.tile;
if (i > lengthof(PathFinderInfo->route)) {
// We ran out of space for the PathFinder
DEBUG(ai, 0)("[AiPathFinder] Ran out of space in the route[] array!!!");
PathFinderInfo->route_length = -1; // -1 indicates out of space
return;
}
parent = parent->parent;
} while (parent != NULL);
PathFinderInfo->route_length = i;
DEBUG(ai, 1)("[Ai-PathFinding] Found route of %d nodes long in %d nodes of searching", i, Hash_Size(&aystar->ClosedListHash));
}
// What tiles are around us.
static void AyStar_AiPathFinder_GetNeighbours(AyStar *aystar, OpenListNode *current)
{
uint i;
int ret;
int dir;
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
aystar->num_neighbours = 0;
// Go through all surrounding tiles and check if they are within the limits
for (i = 0; i < 4; i++) {
TileIndex ctile = current->path.node.tile; // Current tile
TileIndex atile = ctile + TileOffsByDiagDir(i); // Adjacent tile
if (TileX(atile) > 1 && TileX(atile) < MapMaxX() - 1 &&
TileY(atile) > 1 && TileY(atile) < MapMaxY() - 1) {
// We also directly test if the current tile can connect to this tile..
// We do this simply by just building the tile!
// If the next step is a bridge, we have to enter it the right way
if (!PathFinderInfo->rail_or_road && IsRoad(atile)) {
if (IsTileType(atile, MP_TUNNELBRIDGE)) {
if (IsTunnel(atile)) {
if (GetTunnelDirection(atile) != i) continue;
} else {
if ((_m[atile].m5 & 1U) != DiagDirToAxis(i)) continue;
}
}
}
// But also if we are on a bridge, we can only move a certain direction
if (!PathFinderInfo->rail_or_road && IsRoad(ctile)) {
if (IsTileType(ctile, MP_TUNNELBRIDGE)) {
// An existing bridge/tunnel... let's test the direction ;)
if ((_m[ctile].m5 & 1U) != (i & 1)) continue;
}
}
if ((AI_PATHFINDER_FLAG_BRIDGE & current->path.node.user_data[0]) != 0 ||
(AI_PATHFINDER_FLAG_TUNNEL & current->path.node.user_data[0]) != 0) {
// We are a bridge/tunnel, how cool!!
// This means we can only point forward.. get the direction from the user_data
if (i != (current->path.node.user_data[0] >> 8)) continue;
}
dir = 0;
// First, check if we have a parent
if (current->path.parent == NULL && current->path.node.user_data[0] == 0) {
// If not, this means we are at the starting station
if (PathFinderInfo->start_direction != AI_PATHFINDER_NO_DIRECTION) {
// We do need a direction?
if (AiNew_GetDirection(ctile, atile) != PathFinderInfo->start_direction) {
// We are not pointing the right way, invalid tile
continue;
}
}
} else if (current->path.node.user_data[0] == 0) {
if (PathFinderInfo->rail_or_road) {
// Rail check
dir = AiNew_GetRailDirection(current->path.parent->node.tile, ctile, atile);
ret = AI_DoCommand(ctile, 0, dir, DC_AUTO | DC_NO_WATER, CMD_BUILD_SINGLE_RAIL);
if (CmdFailed(ret)) continue;
#ifdef AI_PATHFINDER_NO_90DEGREES_TURN
if (current->path.parent->parent != NULL) {
// Check if we don't make a 90degree curve
int dir1 = AiNew_GetRailDirection(current->path.parent->parent->node.tile, current->path.parent->node.tile, ctile);
if (_illegal_curves[dir1] == dir || _illegal_curves[dir] == dir1) {
continue;
}
}
#endif
} else {
// Road check
dir = AiNew_GetRoadDirection(current->path.parent->node.tile, ctile, atile);
if (IsRoad(ctile)) {
if (IsTileType(ctile, MP_TUNNELBRIDGE)) {
// We have a bridge, how nicely! We should mark it...
dir = 0;
} else {
// It already has road.. check if we miss any bits!
if ((_m[ctile].m5 & dir) != dir) {
// We do miss some pieces :(
dir &= ~_m[ctile].m5;
} else {
dir = 0;
}
}
}
// Only destruct things if it is MP_CLEAR of MP_TREES
if (dir != 0) {
ret = AI_DoCommand(ctile, dir, 0, DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD);
if (CmdFailed(ret)) continue;
}
}
}
// The tile can be connected
aystar->neighbours[aystar->num_neighbours].tile = atile;
aystar->neighbours[aystar->num_neighbours].user_data[0] = 0;
aystar->neighbours[aystar->num_neighbours++].direction = 0;
}
}
// Next step, check for bridges and tunnels
if (current->path.parent != NULL && current->path.node.user_data[0] == 0) {
// First we get the dir from this tile and his parent
DiagDirection dir = AiNew_GetDirection(current->path.parent->node.tile, current->path.node.tile);
// It means we can only walk with the track, so the bridge has to be in the same direction
TileIndex tile = current->path.node.tile;
TileIndex new_tile = tile;
Slope tileh = GetTileSlope(tile, NULL);
// Bridges can only be build on land that is not flat
// And if there is a road or rail blocking
if (tileh != SLOPE_FLAT ||
(PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDiagDir(dir), MP_STREET)) ||
(!PathFinderInfo->rail_or_road && IsTileType(tile + TileOffsByDiagDir(dir), MP_RAILWAY))) {
for (;;) {
new_tile += TileOffsByDiagDir(dir);
// Precheck, is the length allowed?
if (!CheckBridge_Stuff(0, GetBridgeLength(tile, new_tile))) break;
// Check if we hit the station-tile.. we don't like that!
if (TILES_BETWEEN(new_tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br)) break;
// Try building the bridge..
ret = AI_DoCommand(tile, new_tile, (0 << 8) + (MAX_BRIDGES / 2), DC_AUTO, CMD_BUILD_BRIDGE);
if (CmdFailed(ret)) continue;
// We can build a bridge here.. add him to the neighbours
aystar->neighbours[aystar->num_neighbours].tile = new_tile;
aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_BRIDGE + (dir << 8);
aystar->neighbours[aystar->num_neighbours++].direction = 0;
// We can only have 12 neighbours, and we need 1 left for tunnels
if (aystar->num_neighbours == 11) break;
}
}
// Next, check for tunnels!
// Tunnels can only be built on slopes corresponding to the direction
// For now, we check both sides for this tile.. terraforming gives fuzzy result
if ((dir == DIAGDIR_NE && tileh == SLOPE_NE) ||
(dir == DIAGDIR_SE && tileh == SLOPE_SE) ||
(dir == DIAGDIR_SW && tileh == SLOPE_SW) ||
(dir == DIAGDIR_NW && tileh == SLOPE_NW)) {
// Now simply check if a tunnel can be build
ret = AI_DoCommand(tile, (PathFinderInfo->rail_or_road?0:0x200), 0, DC_AUTO, CMD_BUILD_TUNNEL);
tileh = GetTileSlope(_build_tunnel_endtile, NULL);
if (!CmdFailed(ret) && (tileh == SLOPE_SW || tileh == SLOPE_SE || tileh == SLOPE_NW || tileh == SLOPE_NE)) {
aystar->neighbours[aystar->num_neighbours].tile = _build_tunnel_endtile;
aystar->neighbours[aystar->num_neighbours].user_data[0] = AI_PATHFINDER_FLAG_TUNNEL + (dir << 8);
aystar->neighbours[aystar->num_neighbours++].direction = 0;
}
}
}
}
extern uint GetRailFoundation(Slope tileh, TrackBits bits); // XXX function declaration in .c
extern uint GetRoadFoundation(Slope tileh, uint bits); // XXX function declaration in .c
extern uint GetBridgeFoundation(Slope tileh, Axis); // XXX function declaration in .c
enum {
BRIDGE_NO_FOUNDATION = 1 << 0 | 1 << 3 | 1 << 6 | 1 << 9 | 1 << 12,
};
// The most important function: it calculates the g-value
static int32 AyStar_AiPathFinder_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
{
Ai_PathFinderInfo *PathFinderInfo = (Ai_PathFinderInfo*)aystar->user_target;
int r, res = 0;
Slope tileh = GetTileSlope(current->tile, NULL);
Slope parent_tileh = GetTileSlope(parent->path.node.tile, NULL);
// Check if we hit the end-tile
if (TILES_BETWEEN(current->tile, PathFinderInfo->end_tile_tl, PathFinderInfo->end_tile_br)) {
// We are at the end-tile, check if we had a direction or something...
if (PathFinderInfo->end_direction != AI_PATHFINDER_NO_DIRECTION && AiNew_GetDirection(current->tile, parent->path.node.tile) != PathFinderInfo->end_direction) {
// We are not pointing the right way, invalid tile
return AYSTAR_INVALID_NODE;
}
// If it was valid, drop out.. we don't build on the endtile
return 0;
}
// Give everything a small penalty
res += AI_PATHFINDER_PENALTY;
if (!PathFinderInfo->rail_or_road) {
// Road has the lovely advantage it can use other road... check if
// the current tile is road, and if so, give a good bonus
if (IsRoad(current->tile)) {
res -= AI_PATHFINDER_ROAD_ALREADY_EXISTS_BONUS;
}
}
// We should give a penalty when the tile is going up or down.. this is one way to do so!
// Too bad we have to count it from the parent.. but that is not so bad.
// We also dislike long routes on slopes, since they do not look too realistic
// when there is a flat land all around, they are more expensive to build, and
// especially they essentially block the ability to connect or cross the road
// from one side.
if (parent_tileh != SLOPE_FLAT && parent->path.parent != NULL) {
// Skip if the tile was from a bridge or tunnel
if (parent->path.node.user_data[0] == 0 && current->user_data[0] == 0) {
if (PathFinderInfo->rail_or_road) {
r = GetRailFoundation(parent_tileh, 1 << AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
// Maybe is BRIDGE_NO_FOUNDATION a bit strange here, but it contains just the right information..
if (r >= 15 || (r == 0 && HASBIT(BRIDGE_NO_FOUNDATION, tileh))) {
res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
} else {
res += AI_PATHFINDER_FOUNDATION_PENALTY;
}
} else {
if (!IsRoad(parent->path.node.tile) || !IsTileType(parent->path.node.tile, MP_TUNNELBRIDGE)) {
r = GetRoadFoundation(parent_tileh, AiNew_GetRoadDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile));
if (r >= 15 || r == 0) {
res += AI_PATHFINDER_TILE_GOES_UP_PENALTY;
} else {
res += AI_PATHFINDER_FOUNDATION_PENALTY;
}
}
}
}
}
// Are we part of a tunnel?
if ((AI_PATHFINDER_FLAG_TUNNEL & current->user_data[0]) != 0) {
// Tunnels are very expensive when build on long routes..
// Ironicly, we are using BridgeCode here ;)
r = AI_PATHFINDER_TUNNEL_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
res += r + (r >> 8);
}
// Are we part of a bridge?
if ((AI_PATHFINDER_FLAG_BRIDGE & current->user_data[0]) != 0) {
// That means for every length a penalty
res += AI_PATHFINDER_BRIDGE_PENALTY * GetBridgeLength(current->tile, parent->path.node.tile);
// Check if we are going up or down, first for the starting point
// In user_data[0] is at the 8th bit the direction
if (!HASBIT(BRIDGE_NO_FOUNDATION, parent_tileh)) {
if (GetBridgeFoundation(parent_tileh, (current->user_data[0] >> 8) & 1) < 15) {
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
}
}
// Second for the end point
if (!HASBIT(BRIDGE_NO_FOUNDATION, tileh)) {
if (GetBridgeFoundation(tileh, (current->user_data[0] >> 8) & 1) < 15) {
res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
}
}
if (parent_tileh == SLOPE_FLAT) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
if (tileh == SLOPE_FLAT) res += AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY;
}
// To prevent the AI from taking the fastest way in tiles, but not the fastest way
// in speed, we have to give a good penalty to direction changing
// This way, we get almost the fastest way in tiles, and a very good speed on the track
if (!PathFinderInfo->rail_or_road) {
if (parent->path.parent != NULL &&
AiNew_GetDirection(current->tile, parent->path.node.tile) != AiNew_GetDirection(parent->path.node.tile, parent->path.parent->node.tile)) {
// When road exists, we don't like turning, but its free, so don't be to piggy about it
if (IsRoad(parent->path.node.tile)) {
res += AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY;
} else {
res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
}
}
} else {
// For rail we have 1 exeption: diagonal rail..
// So we fetch 2 raildirection. That of the current one, and of the one before that
if (parent->path.parent != NULL && parent->path.parent->parent != NULL) {
int dir1 = AiNew_GetRailDirection(parent->path.parent->node.tile, parent->path.node.tile, current->tile);
int dir2 = AiNew_GetRailDirection(parent->path.parent->parent->node.tile, parent->path.parent->node.tile, parent->path.node.tile);
// First, see if we are on diagonal path, that is better than straight path
if (dir1 > 1) res -= AI_PATHFINDER_DIAGONAL_BONUS;
// First see if they are different
if (dir1 != dir2) {
// dir 2 and 3 are 1 diagonal track, and 4 and 5.
if (!(((dir1 == 2 || dir1 == 3) && (dir2 == 2 || dir2 == 3)) || ((dir1 == 4 || dir1 == 5) && (dir2 == 4 || dir2 == 5)))) {
// It is not, so we changed of direction
res += AI_PATHFINDER_DIRECTION_CHANGE_PENALTY;
}
if (parent->path.parent->parent->parent != NULL) {
int dir3 = AiNew_GetRailDirection(parent->path.parent->parent->parent->node.tile, parent->path.parent->parent->node.tile, parent->path.parent->node.tile);
// Check if we changed 3 tiles of direction in 3 tiles.. bad!!!
if ((dir1 == 0 || dir1 == 1) && dir2 > 1 && (dir3 == 0 || dir3 == 1)) {
res += AI_PATHFINDER_CURVE_PENALTY;
}
}
}
}
}
return (res < 0) ? 0 : res;
}

118
ai/trolly/shared.c Normal file
View File

@@ -0,0 +1,118 @@
/* $Id$ */
#include "../../stdafx.h"
#include "../../openttd.h"
#include "../../debug.h"
#include "../../map.h"
#include "trolly.h"
#include "../../vehicle.h"
int AiNew_GetRailDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c)
{
// 0 = vert
// 1 = horz
// 2 = dig up-left
// 3 = dig down-right
// 4 = dig down-left
// 5 = dig up-right
uint x1 = TileX(tile_a);
uint x2 = TileX(tile_b);
uint x3 = TileX(tile_c);
uint y1 = TileY(tile_a);
uint y2 = TileY(tile_b);
uint y3 = TileY(tile_c);
if (y1 == y2 && y2 == y3) return 0;
if (x1 == x2 && x2 == x3) return 1;
if (y2 > y1) return x2 > x3 ? 2 : 4;
if (x2 > x1) return y2 > y3 ? 2 : 5;
if (y1 > y2) return x2 > x3 ? 5 : 3;
if (x1 > x2) return y2 > y3 ? 4 : 3;
return 0;
}
int AiNew_GetRoadDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c)
{
int x1, x2, x3;
int y1, y2, y3;
int r;
x1 = TileX(tile_a);
x2 = TileX(tile_b);
x3 = TileX(tile_c);
y1 = TileY(tile_a);
y2 = TileY(tile_b);
y3 = TileY(tile_c);
r = 0;
if (x1 < x2) r += 8;
if (y1 < y2) r += 1;
if (x1 > x2) r += 2;
if (y1 > y2) r += 4;
if (x2 < x3) r += 2;
if (y2 < y3) r += 4;
if (x2 > x3) r += 8;
if (y2 > y3) r += 1;
return r;
}
// Get's the direction between 2 tiles seen from tile_a
DiagDirection AiNew_GetDirection(TileIndex tile_a, TileIndex tile_b)
{
if (TileY(tile_a) < TileY(tile_b)) return DIAGDIR_SE;
if (TileY(tile_a) > TileY(tile_b)) return DIAGDIR_NW;
if (TileX(tile_a) < TileX(tile_b)) return DIAGDIR_SW;
return DIAGDIR_NE;
}
// This functions looks up if this vehicle is special for this AI
// and returns his flag
uint AiNew_GetSpecialVehicleFlag(Player* p, Vehicle* v)
{
uint i;
for (i = 0; i < AI_MAX_SPECIAL_VEHICLES; i++) {
if (p->ainew.special_vehicles[i].veh_id == v->index) {
return p->ainew.special_vehicles[i].flag;
}
}
// Not found :(
return 0;
}
bool AiNew_SetSpecialVehicleFlag(Player* p, Vehicle* v, uint flag)
{
int new_id = -1;
uint i;
for (i = 0; i < AI_MAX_SPECIAL_VEHICLES; i++) {
if (p->ainew.special_vehicles[i].veh_id == v->index) {
p->ainew.special_vehicles[i].flag |= flag;
return true;
}
if (new_id == -1 &&
p->ainew.special_vehicles[i].veh_id == 0 &&
p->ainew.special_vehicles[i].flag == 0) {
new_id = i;
}
}
// Out of special_vehicle spots :s
if (new_id == -1) {
DEBUG(ai, 1)("special_vehicles list is too small :(");
return false;
}
p->ainew.special_vehicles[new_id].veh_id = v->index;
p->ainew.special_vehicles[new_id].flag = flag;
return true;
}

1356
ai/trolly/trolly.c Normal file

File diff suppressed because it is too large Load Diff

262
ai/trolly/trolly.h Normal file
View File

@@ -0,0 +1,262 @@
/* $Id$ */
#ifndef AI_TROLLY_H
#define AI_TROLLY_H
#include "../../aystar.h"
#include "../../player.h"
/*
* These defines can be altered to change the behavoir of the AI
*
* WARNING:
* This can also alter the AI in a negative way. I will never claim these settings
* are perfect, but don't change them if you don't know what the effect is.
*/
// How many times it the H multiplied. The higher, the more it will go straight to the
// end point. The lower, how more it will find the route with the lowest cost.
// also: the lower, the longer it takes before route is calculated..
#define AI_PATHFINDER_H_MULTIPLER 100
// How many loops may AyStar do before it stops
// 0 = infinite
#define AI_PATHFINDER_LOOPS_PER_TICK 5
// How long may the AI search for one route?
// 0 = infinite
// This number is the number of tiles tested.
// It takes (AI_PATHFINDER_MAX_SEARCH_NODES / AI_PATHFINDER_LOOPS_PER_TICK) ticks
// to get here.. with 5000 / 10 = 500. 500 / 74 (one day) = 8 days till it aborts
// (that is: if the AI is on VERY FAST! :p
#define AI_PATHFINDER_MAX_SEARCH_NODES 5000
// If you enable this, the AI is not allowed to make 90degree turns
#define AI_PATHFINDER_NO_90DEGREES_TURN
// Below are defines for the g-calculation
// Standard penalty given to a tile
#define AI_PATHFINDER_PENALTY 150
// The penalty given to a tile that is going up
#define AI_PATHFINDER_TILE_GOES_UP_PENALTY 450
// The penalty given to a tile which would have to use fundation
#define AI_PATHFINDER_FOUNDATION_PENALTY 100
// Changing direction is a penalty, to prevent curved ways (with that: slow ways)
#define AI_PATHFINDER_DIRECTION_CHANGE_PENALTY 200
// Same penalty, only for when road already exists
#define AI_PATHFINDER_DIRECTION_CHANGE_ON_EXISTING_ROAD_PENALTY 50
// A diagonal track cost the same as a straigh, but a diagonal is faster... so give
// a bonus for using diagonal track
#ifdef AI_PATHFINDER_NO_90DEGREES_TURN
#define AI_PATHFINDER_DIAGONAL_BONUS 95
#else
#define AI_PATHFINDER_DIAGONAL_BONUS 75
#endif
// If a roadblock already exists, it gets a bonus
#define AI_PATHFINDER_ROAD_ALREADY_EXISTS_BONUS 140
// To prevent 3 direction changes in 3 tiles, this penalty is given in such situation
#define AI_PATHFINDER_CURVE_PENALTY 200
// Penalty a bridge gets per length
#define AI_PATHFINDER_BRIDGE_PENALTY 180
// The penalty for a bridge going up
#define AI_PATHFINDER_BRIDGE_GOES_UP_PENALTY 1000
// Tunnels are expensive...
// Because of that, every tile the cost is increased with 1/8th of his value
// This is also true if you are building a tunnel yourself
#define AI_PATHFINDER_TUNNEL_PENALTY 350
/*
* Ai_New defines
*/
// How long may we search cities and industry for a new route?
#define AI_LOCATE_ROUTE_MAX_COUNTER 200
// How many days must there be between building the first station and the second station
// within one city. This number is in days and should be more than 4 months.
#define AI_CHECKCITY_DATE_BETWEEN 180
// How many cargo is needed for one station in a city?
#define AI_CHECKCITY_CARGO_PER_STATION 60
// How much cargo must there not be used in a city before we can build a new station?
#define AI_CHECKCITY_NEEDED_CARGO 50
// When there is already a station which takes the same good and the rating of that
// city is higher then this numer, we are not going to attempt to build anything
// there
#define AI_CHECKCITY_CARGO_RATING 50
// But, there is a chance of 1 out of this number, that we do ;)
#define AI_CHECKCITY_CARGO_RATING_CHANCE 5
// If a city is too small to contain a station, there is a small chance
// that we still do so.. just to make the city bigger!
#define AI_CHECKCITY_CITY_CHANCE 5
// This number indicates for every unit of cargo, how many tiles two stations maybe be away
// from eachother. In other words: if we have 120 units of cargo in one station, and 120 units
// of the cargo in the other station, both stations can be 96 units away from eachother, if the
// next number is 0.4.
#define AI_LOCATEROUTE_BUS_CARGO_DISTANCE 0.4
#define AI_LOCATEROUTE_TRUCK_CARGO_DISTANCE 0.7
// In whole tiles, the minimum distance for a truck route
#define AI_LOCATEROUTE_TRUCK_MIN_DISTANCE 30
// The amount of tiles in a square from -X to +X that is scanned for a station spot
// (so if this number is 10, 20x20 = 400 tiles are scanned for _the_ perfect spot
// Safe values are between 15 and 5
#define AI_FINDSTATION_TILE_RANGE 10
// Building on normal speed goes very fast. Idle this amount of ticks between every
// building part. It is calculated like this: (4 - competitor_speed) * num + 1
// where competitor_speed is between 0 (very slow) to 4 (very fast)
#define AI_BUILDPATH_PAUSE 10
// Minimum % of reliabilty a vehicle has to have before the AI buys it
#define AI_VEHICLE_MIN_RELIABILTY 60
// The minimum amount of money a player should always have
#define AI_MINIMUM_MONEY 15000
// If the most cheap route is build, how much is it going to cost..
// This is to prevent the AI from trying to build a route which can not be paid for
#define AI_MINIMUM_BUS_ROUTE_MONEY 25000
#define AI_MINIMUM_TRUCK_ROUTE_MONEY 35000
// The minimum amount of money before we are going to repay any money
#define AI_MINIMUM_LOAN_REPAY_MONEY 40000
// How many repays do we do if we have enough money to do so?
// Every repay is 10000
#define AI_LOAN_REPAY 2
// How much income must we have before paying back a loan? Month-based (and looked at the last month)
#define AI_MINIMUM_INCOME_FOR_LOAN 7000
// If there is <num> time as much cargo in the station then the vehicle can handle
// reuse the station instead of building a new one!
#define AI_STATION_REUSE_MULTIPLER 2
// No more than this amount of vehicles per station..
#define AI_CHECK_MAX_VEHICLE_PER_STATION 10
// How many thick between building 2 vehicles
#define AI_BUILD_VEHICLE_TIME_BETWEEN DAY_TICKS
// How many days must there between vehicle checks
// The more often, the less non-money-making lines there will be
// but the unfair it may seem to a human player
#define AI_DAYS_BETWEEN_VEHICLE_CHECKS 30
// How money profit does a vehicle needs to make to stay in order
// This is the profit of this year + profit of last year
// But also for vehicles that are just one year old. In other words:
// Vehicles of 2 years do easier meet this setting then vehicles
// of one year. This is a very good thing. New vehicles are filtered,
// while old vehicles stay longer, because we do get less in return.
#define AI_MINIMUM_ROUTE_PROFIT 1000
// A vehicle is considered lost when he his cargo is more than 180 days old
#define AI_VEHICLE_LOST_DAYS 180
// How many times may the AI try to find a route before it gives up
#define AI_MAX_TRIES_FOR_SAME_ROUTE 8
/*
* End of defines
*/
// This stops 90degrees curves
static const byte _illegal_curves[6] = {
255, 255, // Horz and vert, don't have the effect
5, // upleft and upright are not valid
4, // downright and downleft are not valid
2, // downleft and upleft are not valid
3, // upright and downright are not valid
};
enum {
AI_STATE_STARTUP = 0,
AI_STATE_FIRST_TIME,
AI_STATE_NOTHING,
AI_STATE_WAKE_UP,
AI_STATE_LOCATE_ROUTE,
AI_STATE_FIND_STATION,
AI_STATE_FIND_PATH,
AI_STATE_FIND_DEPOT,
AI_STATE_VERIFY_ROUTE,
AI_STATE_BUILD_STATION,
AI_STATE_BUILD_PATH,
AI_STATE_BUILD_DEPOT,
AI_STATE_BUILD_VEHICLE,
AI_STATE_WAIT_FOR_BUILD,
AI_STATE_GIVE_ORDERS,
AI_STATE_START_VEHICLE,
AI_STATE_REPAY_MONEY,
AI_STATE_CHECK_ALL_VEHICLES,
AI_STATE_ACTION_DONE,
AI_STATE_STOP, // Temporary function to stop the AI
};
// Used for tbt (train/bus/truck)
enum {
AI_TRAIN = 0,
AI_BUS,
AI_TRUCK,
};
enum {
AI_ACTION_NONE = 0,
AI_ACTION_BUS_ROUTE,
AI_ACTION_TRUCK_ROUTE,
AI_ACTION_REPAY_LOAN,
AI_ACTION_CHECK_ALL_VEHICLES,
};
// Used for from_type/to_type
enum {
AI_NO_TYPE = 0,
AI_CITY,
AI_INDUSTRY,
};
// Flags for in the vehicle
enum {
AI_VEHICLEFLAG_SELL = 1,
// Remember, flags must be in power of 2
};
#define AI_NO_CARGO 0xFF // Means that there is no cargo defined yet (used for industry)
#define AI_NEED_CARGO 0xFE // Used when the AI needs to find out a cargo for the route
#define AI_STATION_RANGE TileXY(MapMaxX(), MapMaxY())
#define AI_PATHFINDER_NO_DIRECTION (byte)-1
// Flags used in user_data
#define AI_PATHFINDER_FLAG_BRIDGE 1
#define AI_PATHFINDER_FLAG_TUNNEL 2
typedef void AiNew_StateFunction(Player *p);
// ai_new.c
void AiNewDoGameLoop(Player *p);
// ai_pathfinder.c
AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo);
void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo);
// ai_shared.c
int AiNew_GetRailDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c);
int AiNew_GetRoadDirection(TileIndex tile_a, TileIndex tile_b, TileIndex tile_c);
DiagDirection AiNew_GetDirection(TileIndex tile_a, TileIndex tile_b);
bool AiNew_SetSpecialVehicleFlag(Player *p, Vehicle *v, uint flag);
uint AiNew_GetSpecialVehicleFlag(Player *p, Vehicle *v);
// ai_build.c
bool AiNew_Build_CompanyHQ(Player *p, TileIndex tile);
int AiNew_Build_Station(Player *p, byte type, TileIndex tile, byte length, byte numtracks, byte direction, byte flag);
int AiNew_Build_Bridge(Player *p, TileIndex tile_a, TileIndex tile_b, byte flag);
int AiNew_Build_RoutePart(Player *p, Ai_PathFinderInfo *PathFinderInfo, byte flag);
EngineID AiNew_PickVehicle(Player *p);
int AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag);
int AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag);
#endif /* AI_TROLLY_H */

26
aircraft.h Normal file
View File

@@ -0,0 +1,26 @@
/* $Id$ */
#ifndef AIRCRAFT_H
#define AIRCRAFT_H
#include "station_map.h"
#include "vehicle.h"
static inline bool IsAircraftInHangar(const Vehicle* v)
{
assert(v->type == VEH_Aircraft);
return v->vehstatus & VS_HIDDEN && IsHangarTile(v->tile);
}
static inline bool IsAircraftInHangarStopped(const Vehicle* v)
{
return IsAircraftInHangar(v) && v->vehstatus & VS_STOPPED;
}
uint16 AircraftDefaultCargoCapacity(CargoID cid, EngineID engine_type);
void CcCloneAircraft(bool success, TileIndex tile, uint32 p1, uint32 p2);
void HandleAircraftEnterHangar(Vehicle *v);
#endif /* AIRCRAFT_H */

2146
aircraft_cmd.c Normal file

File diff suppressed because it is too large Load Diff

350
aircraft_gui.c Normal file
View File

@@ -0,0 +1,350 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "aircraft.h"
#include "debug.h"
#include "functions.h"
#include "table/sprites.h"
#include "table/strings.h"
#include "map.h"
#include "window.h"
#include "gui.h"
#include "vehicle.h"
#include "gfx.h"
#include "command.h"
#include "engine.h"
#include "viewport.h"
#include "player.h"
#include "depot.h"
#include "vehicle_gui.h"
#include "newgrf_engine.h"
void CcCloneAircraft(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
if (success) ShowAircraftViewWindow(GetVehicle(_new_vehicle_id));
}
static void AircraftDetailsWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_PAINT: {
const Vehicle *v = GetVehicle(w->window_number);
SetWindowWidgetDisabledState(w, 2, v->owner != _local_player);
/* Disable service-scroller when interval is set to disabled */
SetWindowWidgetDisabledState(w, 5, !_patches.servint_aircraft);
SetWindowWidgetDisabledState(w, 6, !_patches.servint_aircraft);
SetDParam(0, v->string_id);
SetDParam(1, v->unitnumber);
DrawWindowWidgets(w);
/* Draw running cost */
{
int year = v->age / 366;
SetDParam(1, year);
SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
SetDParam(2, v->max_age / 366);
SetDParam(3, _price.aircraft_running * AircraftVehInfo(v->engine_type)->running_cost >> 8);
DrawString(2, 15, STR_A00D_AGE_RUNNING_COST_YR, 0);
}
/* Draw max speed */
{
SetDParam(0, v->max_speed * 128 / 10);
DrawString(2, 25, STR_A00E_MAX_SPEED, 0);
}
/* Draw profit */
{
SetDParam(0, v->profit_this_year);
SetDParam(1, v->profit_last_year);
DrawString(2, 35, STR_A00F_PROFIT_THIS_YEAR_LAST_YEAR, 0);
}
/* Draw breakdown & reliability */
{
SetDParam(0, v->reliability * 100 >> 16);
SetDParam(1, v->breakdowns_since_last_service);
DrawString(2, 45, STR_A010_RELIABILITY_BREAKDOWNS, 0);
}
/* Draw service interval text */
{
SetDParam(0, v->service_interval);
SetDParam(1, v->date_of_last_service);
DrawString(13, 103, _patches.servint_ispercent?STR_SERVICING_INTERVAL_PERCENT:STR_883C_SERVICING_INTERVAL_DAYS, 0);
}
DrawAircraftImage(v, 3, 57, INVALID_VEHICLE);
{
const Vehicle *u;
int y = 57;
do {
if (v->subtype <= 2) {
SetDParam(0, GetCustomEngineName(v->engine_type));
SetDParam(1, v->build_year);
SetDParam(2, v->value);
DrawString(60, y, STR_A011_BUILT_VALUE, 0);
y += 10;
SetDParam(0, v->cargo_type);
SetDParam(1, v->cargo_cap);
u = v->next;
SetDParam(2, u->cargo_type);
SetDParam(3, u->cargo_cap);
DrawString(60, y, (u->cargo_cap != 0) ? STR_A019_CAPACITY : STR_A01A_CAPACITY, 0);
y += 14;
}
if (v->cargo_count != 0) {
/* Cargo names (fix pluralness) */
SetDParam(0, v->cargo_type);
SetDParam(1, v->cargo_count);
SetDParam(2, v->cargo_source);
DrawString(60, y, STR_8813_FROM, 0);
y += 10;
}
} while ( (v=v->next) != NULL);
}
} break;
case WE_CLICK: {
int mod;
const Vehicle *v;
switch (e->we.click.widget) {
case 2: /* rename */
v = GetVehicle(w->window_number);
SetDParam(0, v->unitnumber);
ShowQueryString(v->string_id, STR_A030_NAME_AIRCRAFT, 31, 150, w->window_class, w->window_number, CS_ALPHANUMERAL);
break;
case 5: /* increase int */
mod = _ctrl_pressed? 5 : 10;
goto do_change_service_int;
case 6: /* decrease int */
mod = _ctrl_pressed?- 5 : -10;
do_change_service_int:
v = GetVehicle(w->window_number);
mod = GetServiceIntervalClamped(mod + v->service_interval);
if (mod == v->service_interval) return;
DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
break;
}
} break;
case WE_ON_EDIT_TEXT:
if (e->we.edittext.str[0] != '\0') {
_cmd_text = e->we.edittext.str;
DoCommandP(0, w->window_number, 0, NULL,
CMD_NAME_VEHICLE | CMD_MSG(STR_A031_CAN_T_NAME_AIRCRAFT));
}
break;
}
}
static const Widget _aircraft_details_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 349, 0, 13, STR_A00C_DETAILS, STR_018C_WINDOW_TITLE_DRAG_THIS },
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 350, 389, 0, 13, STR_01AA_NAME, STR_A032_NAME_AIRCRAFT },
{ WWT_PANEL, RESIZE_NONE, 14, 0, 389, 14, 55, 0x0, STR_NULL },
{ WWT_PANEL, RESIZE_NONE, 14, 0, 389, 56, 101, 0x0, STR_NULL },
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 102, 107, STR_0188, STR_884D_INCREASE_SERVICING_INTERVAL },
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 10, 108, 113, STR_0189, STR_884E_DECREASE_SERVICING_INTERVAL },
{ WWT_PANEL, RESIZE_NONE, 14, 11, 389, 102, 113, 0x0, STR_NULL },
{ WIDGETS_END},
};
static const WindowDesc _aircraft_details_desc = {
WDP_AUTO, WDP_AUTO, 390, 114,
WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_aircraft_details_widgets,
AircraftDetailsWndProc
};
static void ShowAircraftDetailsWindow(const Vehicle *v)
{
Window *w;
VehicleID veh = v->index;
DeleteWindowById(WC_VEHICLE_ORDERS, veh);
DeleteWindowById(WC_VEHICLE_DETAILS, veh);
w = AllocateWindowDescFront(&_aircraft_details_desc, veh);
w->caption_color = v->owner;
// w->vscroll.cap = 6;
// w->traindetails_d.tab = 0;
}
static const Widget _aircraft_view_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
{ WWT_CAPTION, RESIZE_RIGHT, 14, 11, 237, 0, 13, STR_A00A, STR_018C_WINDOW_TITLE_DRAG_THIS },
{ WWT_STICKYBOX, RESIZE_LR, 14, 238, 249, 0, 13, 0x0, STR_STICKY_BUTTON },
{ WWT_PANEL, RESIZE_RB, 14, 0, 231, 14, 103, 0x0, STR_NULL },
{ WWT_INSET, RESIZE_RB, 14, 2, 229, 16, 101, 0x0, STR_NULL },
{ WWT_PUSHBTN, RESIZE_RTB, 14, 0, 237, 104, 115, 0x0, STR_A027_CURRENT_AIRCRAFT_ACTION },
{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 14, 31, SPR_CENTRE_VIEW_VEHICLE, STR_A029_CENTER_MAIN_VIEW_ON_AIRCRAFT },
{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 32, 49, SPR_SEND_AIRCRAFT_TODEPOT,STR_A02A_SEND_AIRCRAFT_TO_HANGAR },
{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 50, 67, SPR_REFIT_VEHICLE, STR_A03B_REFIT_AIRCRAFT_TO_CARRY },
{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 68, 85, SPR_SHOW_ORDERS, STR_A028_SHOW_AIRCRAFT_S_ORDERS },
{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 86, 103, SPR_SHOW_VEHICLE_DETAILS, STR_A02B_SHOW_AIRCRAFT_DETAILS },
{ WWT_PUSHIMGBTN, RESIZE_LR, 14, 232, 249, 32, 49, SPR_CLONE_AIRCRAFT, STR_CLONE_AIRCRAFT_INFO },
{ WWT_PANEL, RESIZE_LRB, 14, 232, 249, 104, 103, 0x0, STR_NULL },
{ WWT_RESIZEBOX, RESIZE_LRTB, 14, 238, 249, 104, 115, 0x0, STR_NULL },
{ WIDGETS_END},
};
static void AircraftViewWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_PAINT: {
const Vehicle *v = GetVehicle(w->window_number);
StringID str;
bool is_localplayer = v->owner == _local_player;
SetWindowWidgetDisabledState(w, 7, !is_localplayer);
SetWindowWidgetDisabledState(w, 8, !IsAircraftInHangarStopped(v) || !is_localplayer);
SetWindowWidgetDisabledState(w, 11, !is_localplayer);
/* draw widgets & caption */
SetDParam(0, v->string_id);
SetDParam(1, v->unitnumber);
DrawWindowWidgets(w);
if (v->vehstatus & VS_CRASHED) {
str = STR_8863_CRASHED;
} else if (v->vehstatus & VS_STOPPED) {
str = STR_8861_STOPPED;
} else {
switch (v->current_order.type) {
case OT_GOTO_STATION: {
SetDParam(0, v->current_order.dest);
SetDParam(1, v->cur_speed * 128 / 10);
str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
} break;
case OT_GOTO_DEPOT: {
/* Aircrafts always go to a station, even if you say depot */
SetDParam(0, v->current_order.dest);
SetDParam(1, v->cur_speed * 128 / 10);
if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS)) {
str = STR_HEADING_FOR_HANGAR + _patches.vehicle_speed;
} else {
str = STR_HEADING_FOR_HANGAR_SERVICE + _patches.vehicle_speed;
}
} break;
case OT_LOADING:
str = STR_882F_LOADING_UNLOADING;
break;
default:
if (v->num_orders == 0) {
str = STR_NO_ORDERS + _patches.vehicle_speed;
SetDParam(0, v->cur_speed * 128 / 10);
} else {
str = STR_EMPTY;
}
break;
}
}
/* draw the flag plus orders */
DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, 2, w->widget[5].top + 1);
DrawStringCenteredTruncated(w->widget[5].left + 8, w->widget[5].right, w->widget[5].top + 1, str, 0);
DrawWindowViewport(w);
} break;
case WE_CLICK: {
const Vehicle *v = GetVehicle(w->window_number);
switch (e->we.click.widget) {
case 5: /* start stop */
DoCommandP(v->tile, v->index, 0, NULL, CMD_START_STOP_AIRCRAFT | CMD_MSG(STR_A016_CAN_T_STOP_START_AIRCRAFT));
break;
case 6: /* center main view */
ScrollMainWindowTo(v->x_pos, v->y_pos);
break;
case 7: /* goto hangar */
DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL, CMD_SEND_AIRCRAFT_TO_HANGAR | CMD_MSG(STR_A012_CAN_T_SEND_AIRCRAFT_TO));
break;
case 8: /* refit */
ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
break;
case 9: /* show orders */
ShowOrdersWindow(v);
break;
case 10: /* show details */
ShowAircraftDetailsWindow(v);
break;
case 11:
/* clone vehicle */
DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneAircraft, CMD_CLONE_VEHICLE | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
break;
}
} break;
case WE_RESIZE:
w->viewport->width += e->we.sizing.diff.x;
w->viewport->height += e->we.sizing.diff.y;
w->viewport->virtual_width += e->we.sizing.diff.x;
w->viewport->virtual_height += e->we.sizing.diff.y;
break;
case WE_DESTROY:
DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
break;
case WE_MOUSELOOP: {
const Vehicle *v = GetVehicle(w->window_number);
bool plane_stopped = IsAircraftInHangarStopped(v);
/* Widget 7 (send to hangar) must be hidden if the plane is already stopped in hangar.
* Widget 11 (clone) should then be shown, since cloning is allowed only while in hangar and stopped.
* This sytem allows to have two buttons, on top of each other*/
if (plane_stopped != IsWindowWidgetHidden(w, 7) || plane_stopped == IsWindowWidgetHidden(w, 11)) {
SetWindowWidgetHiddenState(w, 7, plane_stopped); // send to hangar
SetWindowWidgetHiddenState(w, 11, !plane_stopped); // clone
SetWindowDirty(w);
}
} break;
}
}
static const WindowDesc _aircraft_view_desc = {
WDP_AUTO, WDP_AUTO, 250, 116,
WC_VEHICLE_VIEW ,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_aircraft_view_widgets,
AircraftViewWndProc
};
void ShowAircraftViewWindow(const Vehicle *v)
{
Window *w = AllocateWindowDescFront(&_aircraft_view_desc, v->index);
if (w != NULL) {
w->caption_color = v->owner;
AssignWindowViewport(w, 3, 17, 0xE2, 0x54, w->window_number | (1 << 31), 0);
}
}

489
airport.c Normal file
View File

@@ -0,0 +1,489 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "debug.h"
#include "map.h"
#include "airport.h"
#include "macros.h"
#include "variables.h"
#include "airport_movement.h"
#include "date.h"
/* Uncomment this to print out a full report of the airport-structure
* You should either use
* - true: full-report, print out every state and choice with string-names
* OR
* - false: give a summarized report which only shows current and next position */
//#define DEBUG_AIRPORT false
static AirportFTAClass *CountryAirport;
static AirportFTAClass *CityAirport;
static AirportFTAClass *Oilrig;
static AirportFTAClass *Heliport;
static AirportFTAClass *MetropolitanAirport;
static AirportFTAClass *InternationalAirport;
static AirportFTAClass *CommuterAirport;
static AirportFTAClass *HeliDepot;
static AirportFTAClass *IntercontinentalAirport;
static AirportFTAClass *HeliStation;
static void AirportFTAClass_Constructor(AirportFTAClass *apc,
const byte *terminals, const byte *helipads,
const byte entry_point, const byte acc_planes,
const AirportFTAbuildup *apFA,
const TileIndexDiffC *depots, const byte nof_depots,
uint size_x, uint size_y
);
static void AirportFTAClass_Destructor(AirportFTAClass *apc);
static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA);
static void AirportBuildAutomata(AirportFTAClass *apc, const AirportFTAbuildup *apFA);
static byte AirportGetTerminalCount(const byte *terminals, byte *groups);
static byte AirportTestFTA(const AirportFTAClass *apc);
#ifdef DEBUG_AIRPORT
static void AirportPrintOut(const AirportFTAClass *apc, bool full_report);
#endif /* DEBUG_AIRPORT */
void InitializeAirports(void)
{
// country airport
CountryAirport = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
CountryAirport,
_airport_terminal_country,
NULL,
16,
ALL,
_airport_fta_country,
_airport_depots_country,
lengthof(_airport_depots_country),
4, 3
);
// city airport
CityAirport = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
CityAirport,
_airport_terminal_city,
NULL,
19,
ALL,
_airport_fta_city,
_airport_depots_city,
lengthof(_airport_depots_city),
6, 6
);
// metropolitan airport
MetropolitanAirport = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
MetropolitanAirport,
_airport_terminal_metropolitan,
NULL,
20,
ALL,
_airport_fta_metropolitan,
_airport_depots_metropolitan,
lengthof(_airport_depots_metropolitan),
6, 6
);
// international airport
InternationalAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
InternationalAirport,
_airport_terminal_international,
_airport_helipad_international,
37,
ALL,
_airport_fta_international,
_airport_depots_international,
lengthof(_airport_depots_international),
7, 7
);
// intercontintental airport
IntercontinentalAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
IntercontinentalAirport,
_airport_terminal_intercontinental,
_airport_helipad_intercontinental,
43,
ALL,
_airport_fta_intercontinental,
_airport_depots_intercontinental,
lengthof(_airport_depots_intercontinental),
9,11
);
// heliport, oilrig
Heliport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
Heliport,
NULL,
_airport_helipad_heliport_oilrig,
7,
HELICOPTERS_ONLY,
_airport_fta_heliport_oilrig,
NULL,
0,
1, 1
);
Oilrig = Heliport; // exactly the same structure for heliport/oilrig, so share state machine
// commuter airport
CommuterAirport = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
CommuterAirport,
_airport_terminal_commuter,
_airport_helipad_commuter,
22,
ALL,
_airport_fta_commuter,
_airport_depots_commuter,
lengthof(_airport_depots_commuter),
5,4
);
// helidepot airport
HeliDepot = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
HeliDepot,
NULL,
_airport_helipad_helidepot,
4,
HELICOPTERS_ONLY,
_airport_fta_helidepot,
_airport_depots_helidepot,
lengthof(_airport_depots_helidepot),
2,2
);
// helistation airport
HeliStation = malloc(sizeof(AirportFTAClass));
AirportFTAClass_Constructor(
HeliStation,
NULL,
_airport_helipad_helistation,
25,
HELICOPTERS_ONLY,
_airport_fta_helistation,
_airport_depots_helistation,
lengthof(_airport_depots_helistation),
4,2
);
}
void UnInitializeAirports(void)
{
AirportFTAClass_Destructor(CountryAirport);
AirportFTAClass_Destructor(CityAirport);
AirportFTAClass_Destructor(Heliport);
AirportFTAClass_Destructor(MetropolitanAirport);
AirportFTAClass_Destructor(InternationalAirport);
AirportFTAClass_Destructor(CommuterAirport);
AirportFTAClass_Destructor(HeliDepot);
AirportFTAClass_Destructor(IntercontinentalAirport);
AirportFTAClass_Destructor(HeliStation);
}
static void AirportFTAClass_Constructor(AirportFTAClass *apc,
const byte *terminals, const byte *helipads,
const byte entry_point, const byte acc_planes,
const AirportFTAbuildup *apFA,
const TileIndexDiffC *depots, const byte nof_depots,
uint size_x, uint size_y
)
{
byte nofterminals, nofhelipads;
byte nofterminalgroups, nofhelipadgroups;
apc->size_x = size_x;
apc->size_y = size_y;
/* Set up the terminal and helipad count for an airport.
* TODO: If there are more than 10 terminals or 4 helipads, internal variables
* need to be changed, so don't allow that for now */
nofterminals = AirportGetTerminalCount(terminals, &nofterminalgroups);
if (nofterminals > MAX_TERMINALS) {
DEBUG(misc, 0) ("[Ap] Currently only maximum of %d terminals are supported (you wanted %d)", MAX_TERMINALS, nofterminals);
assert(nofterminals <= MAX_TERMINALS);
}
apc->terminals = terminals;
nofhelipads = AirportGetTerminalCount(helipads, &nofhelipadgroups);
if (nofhelipads > MAX_HELIPADS) {
DEBUG(misc, 0) ("[Ap] Currently only maximum of %d helipads are supported (you wanted %d)", MAX_HELIPADS, nofhelipads);
assert(nofhelipads <= MAX_HELIPADS);
}
apc->helipads = helipads;
/* Get the number of elements from the source table. We also double check this
* with the entry point which must be within bounds and use this information
* later on to build and validate the state machine */
apc->nofelements = AirportGetNofElements(apFA);
if (entry_point >= apc->nofelements) {
DEBUG(misc, 0) ("[Ap] Entry (%d) must be within the airport (maximum %d)", entry_point, apc->nofelements);
assert(entry_point < apc->nofelements);
}
apc->acc_planes = acc_planes;
apc->entry_point = entry_point;
apc->airport_depots = depots;
apc->nof_depots = nof_depots;
/* Build the state machine itself */
AirportBuildAutomata(apc, apFA);
DEBUG(misc, 1) ("[Ap] #count %3d; #term %2d (%dgrp); #helipad %2d (%dgrp); entry %3d",
apc->nofelements, nofterminals, nofterminalgroups, nofhelipads, nofhelipadgroups, apc->entry_point);
/* Test if everything went allright. This is only a rude static test checking
* the symantic correctness. By no means does passing the test mean that the
* airport is working correctly or will not deadlock for example */
{ byte ret = AirportTestFTA(apc);
if (ret != MAX_ELEMENTS) DEBUG(misc, 0) ("[Ap] ERROR with element: %d", ret - 1);
assert(ret == MAX_ELEMENTS);
}
#ifdef DEBUG_AIRPORT
AirportPrintOut(apc, DEBUG_AIRPORT);
#endif
}
static void AirportFTAClass_Destructor(AirportFTAClass *apc)
{
int i;
AirportFTA *current, *next;
for (i = 0; i < apc->nofelements; i++) {
current = apc->layout[i].next;
while (current != NULL) {
next = current->next;
free(current);
current = next;
};
}
free(apc->layout);
free(apc);
}
/** 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 */
static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA)
{
int i;
uint16 nofelements = 0;
int temp = apFA[0].position;
for (i = 0; i < MAX_ELEMENTS; i++) {
if (temp != apFA[i].position) {
nofelements++;
temp = apFA[i].position;
}
if (apFA[i].position == MAX_ELEMENTS) break;
}
return nofelements;
}
/* We calculate the terminal/helipod count based on the data passed to us
* This data (terminals) contains an index as a first element as to how many
* groups there are, and then the number of terminals for each group */
static byte AirportGetTerminalCount(const byte *terminals, byte *groups)
{
byte i;
byte nof_terminals = 0;
*groups = 0;
if (terminals != NULL) {
i = terminals[0];
*groups = i;
while (i-- > 0) {
terminals++;
assert(*terminals != 0); // no empty groups please
nof_terminals += *terminals;
}
}
return nof_terminals;
}
static void AirportBuildAutomata(AirportFTAClass *apc, const AirportFTAbuildup *apFA)
{
AirportFTA *current;
AirportFTA *FAutomata = malloc(sizeof(AirportFTA) * apc->nofelements);
uint16 internalcounter = 0;
uint16 i;
apc->layout = FAutomata;
for (i = 0; i < apc->nofelements; i++) {
current = &apc->layout[i];
current->position = apFA[internalcounter].position;
current->heading = apFA[internalcounter].heading;
current->block = apFA[internalcounter].block;
current->next_position = apFA[internalcounter].next;
// outgoing nodes from the same position, create linked list
while (current->position == apFA[internalcounter + 1].position) {
AirportFTA *newNode = malloc(sizeof(AirportFTA));
newNode->position = apFA[internalcounter + 1].position;
newNode->heading = apFA[internalcounter + 1].heading;
newNode->block = apFA[internalcounter + 1].block;
newNode->next_position = apFA[internalcounter + 1].next;
// create link
current->next = newNode;
current = current->next;
internalcounter++;
} // while
current->next = NULL;
internalcounter++;
}
}
static byte AirportTestFTA(const AirportFTAClass *apc)
{
byte position, i, next_position;
AirportFTA *current, *first;
next_position = 0;
for (i = 0; i < apc->nofelements; i++) {
position = apc->layout[i].position;
if (position != next_position) return i;
current = first = &apc->layout[i];
for (; current != NULL; current = current->next) {
/* A heading must always be valid. The only exceptions are
* - multiple choices as start, identified by a special value of 255
* - terminal group which is identified by a special value of 255 */
if (current->heading > MAX_HEADINGS) {
if (current->heading != 255) return i;
if (current == first && current->next == NULL) return i;
if (current != first && current->next_position > apc->terminals[0]) return i;
}
/* If there is only one choice, it must be at the end */
if (current->heading == 0 && current->next != NULL) return i;
/* Obviously the elements of the linked list must have the same identifier */
if (position != current->position) return i;
/* A next position must be within bounds */
if (current->next_position >= apc->nofelements) return i;
}
next_position++;
}
return MAX_ELEMENTS;
}
#ifdef DEBUG_AIRPORT
static const char* const _airport_heading_strings[] = {
"TO_ALL",
"HANGAR",
"TERM1",
"TERM2",
"TERM3",
"TERM4",
"TERM5",
"TERM6",
"HELIPAD1",
"HELIPAD2",
"TAKEOFF",
"STARTTAKEOFF",
"ENDTAKEOFF",
"HELITAKEOFF",
"FLYING",
"LANDING",
"ENDLANDING",
"HELILANDING",
"HELIENDLANDING",
"TERM7",
"TERM8",
"HELIPAD3",
"HELIPAD4",
"DUMMY" // extra heading for 255
};
static uint AirportBlockToString(uint32 block)
{
uint i = 0;
if (block & 0xffff0000) { block >>= 16; i += 16; }
if (block & 0x0000ff00) { block >>= 8; i += 8; }
if (block & 0x000000f0) { block >>= 4; i += 4; }
if (block & 0x0000000c) { block >>= 2; i += 2; }
if (block & 0x00000002) { i += 1; }
return i;
}
static void AirportPrintOut(const AirportFTAClass *apc, bool full_report)
{
uint16 i;
if (!full_report) printf("(P = Current Position; NP = Next Position)\n");
for (i = 0; i < apc->nofelements; i++) {
AirportFTA *current = &apc->layout[i];
for (; current != NULL; current = current->next) {
if (full_report) {
byte heading = (current->heading == 255) ? MAX_HEADINGS + 1 : current->heading;
printf("\tPos:%2d NPos:%2d Heading:%15s Block:%2d\n", current->position,
current->next_position, _airport_heading_strings[heading],
AirportBlockToString(current->block));
} else {
printf("P:%2d NP:%2d", current->position, current->next_position);
}
}
printf("\n");
}
}
#endif
const AirportFTAClass *GetAirport(const byte airport_type)
{
//FIXME -- AircraftNextAirportPos_and_Order -> Needs something nicer, don't like this code
// needs constant change if more airports are added
switch (airport_type) {
default: NOT_REACHED();
case AT_SMALL: return CountryAirport;
case AT_LARGE: return CityAirport;
case AT_METROPOLITAN: return MetropolitanAirport;
case AT_HELIPORT: return Heliport;
case AT_OILRIG: return Oilrig;
case AT_INTERNATIONAL: return InternationalAirport;
case AT_COMMUTER: return CommuterAirport;
case AT_HELIDEPOT: return HeliDepot;
case AT_INTERCON: return IntercontinentalAirport;
case AT_HELISTATION: return HeliStation;
}
}
const AirportMovingData *GetAirportMovingData(byte airport_type, byte position)
{
assert(airport_type < lengthof(_airport_moving_datas));
assert(position < GetAirport(airport_type)->nofelements);
return &_airport_moving_datas[airport_type][position];
}
uint32 GetValidAirports(void)
{
uint32 bytemask = _avail_aircraft; /// sets the first 3 bytes, 0 - 2, @see AdjustAvailAircraft()
if (_cur_year >= 1980) SETBIT(bytemask, 3); // metropolitan airport
if (_cur_year >= 1990) SETBIT(bytemask, 4); // international airport
if (_cur_year >= 1983) SETBIT(bytemask, 5); // commuter airport
if (_cur_year >= 1976) SETBIT(bytemask, 6); // helidepot
if (_cur_year >= 2002) SETBIT(bytemask, 7); // intercontinental airport
if (_cur_year >= 1980) SETBIT(bytemask, 8); // helistation
return bytemask;
}

163
airport.h Normal file
View File

@@ -0,0 +1,163 @@
/* $Id$ */
#ifndef AIRPORT_H
#define AIRPORT_H
enum {MAX_TERMINALS = 10};
enum {MAX_HELIPADS = 4};
enum {MAX_ELEMENTS = 255};
enum {MAX_HEADINGS = 22};
// Airport types
enum {
AT_SMALL = 0,
AT_LARGE = 1,
AT_HELIPORT = 2,
AT_METROPOLITAN = 3,
AT_INTERNATIONAL = 4,
AT_COMMUTER = 5,
AT_HELIDEPOT = 6,
AT_INTERCON = 7,
AT_HELISTATION = 8,
AT_OILRIG = 15
};
// do not change unless you change v->subtype too. This aligns perfectly with its current setting
enum {
AIRCRAFT_ONLY = 0,
ALL = 1,
HELICOPTERS_ONLY = 2,
};
enum {
AMED_NOSPDCLAMP = 1 << 0,
AMED_TAKEOFF = 1 << 1,
AMED_SLOWTURN = 1 << 2,
AMED_LAND = 1 << 3,
AMED_EXACTPOS = 1 << 4,
AMED_BRAKE = 1 << 5,
AMED_HELI_RAISE = 1 << 6,
AMED_HELI_LOWER = 1 << 7,
};
/* Movement States on Airports (headings target) */
enum {
TO_ALL = 0,
HANGAR = 1,
TERM1 = 2,
TERM2 = 3,
TERM3 = 4,
TERM4 = 5,
TERM5 = 6,
TERM6 = 7,
HELIPAD1 = 8,
HELIPAD2 = 9,
TAKEOFF = 10,
STARTTAKEOFF = 11,
ENDTAKEOFF = 12,
HELITAKEOFF = 13,
FLYING = 14,
LANDING = 15,
ENDLANDING = 16,
HELILANDING = 17,
HELIENDLANDING = 18,
TERM7 = 19,
TERM8 = 20,
HELIPAD3 = 21,
HELIPAD4 = 22
};
// this maps the terminal to its corresponding state and block flag
// currently set for 10 terms, 4 helipads
static const byte _airport_terminal_state[] = {2, 3, 4, 5, 6, 7, 19, 20, 0, 0, 8, 9, 21, 22};
static const byte _airport_terminal_flag[] = {0, 1, 2, 3, 4, 5, 22, 23, 0, 0, 6, 7, 24, 25};
/* Movement Blocks on Airports */
// blocks (eg_airport_flags)
enum {
TERM1_block = 1 << 0,
TERM2_block = 1 << 1,
TERM3_block = 1 << 2,
TERM4_block = 1 << 3,
TERM5_block = 1 << 4,
TERM6_block = 1 << 5,
HELIPAD1_block = 1 << 6,
HELIPAD2_block = 1 << 7,
RUNWAY_IN_OUT_block = 1 << 8,
RUNWAY_IN_block = 1 << 8,
AIRPORT_BUSY_block = 1 << 8,
RUNWAY_OUT_block = 1 << 9,
TAXIWAY_BUSY_block = 1 << 10,
OUT_WAY_block = 1 << 11,
IN_WAY_block = 1 << 12,
AIRPORT_ENTRANCE_block = 1 << 13,
TERM_GROUP1_block = 1 << 14,
TERM_GROUP2_block = 1 << 15,
HANGAR2_AREA_block = 1 << 16,
TERM_GROUP2_ENTER1_block = 1 << 17,
TERM_GROUP2_ENTER2_block = 1 << 18,
TERM_GROUP2_EXIT1_block = 1 << 19,
TERM_GROUP2_EXIT2_block = 1 << 20,
PRE_HELIPAD_block = 1 << 21,
// blocks for new airports
TERM7_block = 1 << 22,
TERM8_block = 1 << 23,
TERM9_block = 1 << 24,
HELIPAD3_block = 1 << 24,
TERM10_block = 1 << 25,
HELIPAD4_block = 1 << 25,
HANGAR1_AREA_block = 1 << 26,
OUT_WAY2_block = 1 << 27,
IN_WAY2_block = 1 << 28,
RUNWAY_IN2_block = 1 << 29,
RUNWAY_OUT2_block = 1 << 10, // note re-uses TAXIWAY_BUSY
HELIPAD_GROUP_block = 1 << 13, // note re-uses AIRPORT_ENTRANCE
OUT_WAY_block2 = 1 << 31,
// end of new blocks
NOTHING_block = 1 << 30
};
typedef struct AirportMovingData {
int x,y;
byte flag;
byte direction;
} AirportMovingData;
// Finite sTate mAchine --> FTA
typedef struct AirportFTAClass {
byte nofelements; // number of positions the airport consists of
const byte *terminals;
const byte *helipads;
byte entry_point; // when an airplane arrives at this airport, enter it at position entry_point
byte acc_planes; // accept airplanes or helicopters or both
const TileIndexDiffC *airport_depots; // gives the position of the depots on the airports
byte nof_depots; // number of depots this airport has
struct AirportFTA *layout; // state machine for airport
byte size_x;
byte size_y;
} AirportFTAClass;
// internal structure used in openttd - Finite sTate mAchine --> FTA
typedef struct AirportFTA {
byte position; // the position that an airplane is at
byte next_position; // next position from this position
uint32 block; // 32 bit blocks (st->airport_flags), should be enough for the most complex airports
byte heading; // heading (current orders), guiding an airplane to its target on an airport
struct AirportFTA *next; // possible extra movement choices from this position
} AirportFTA;
void InitializeAirports(void);
void UnInitializeAirports(void);
const AirportFTAClass *GetAirport(const byte airport_type);
const AirportMovingData *GetAirportMovingData(byte airport_type, byte position);
/** Get buildable airport bitmask.
* @return get all buildable airports at this given time, bitmasked.
* Bit 0 means the small airport is buildable, etc.
* @todo set availability of airports by year, instead of airplane
*/
uint32 GetValidAirports(void);
#endif /* AIRPORT_H */

286
airport_gui.c Normal file
View File

@@ -0,0 +1,286 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "table/sprites.h"
#include "table/strings.h"
#include "functions.h"
#include "map.h"
#include "window.h"
#include "gui.h"
#include "viewport.h"
#include "gfx.h"
#include "sound.h"
#include "command.h"
#include "vehicle.h"
#include "station.h"
#include "airport.h"
#include "depot.h"
static byte _selected_airport_type;
static void ShowBuildAirportPicker(void);
void CcBuildAirport(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
if (success) {
SndPlayTileFx(SND_1F_SPLAT, tile);
ResetObjectToPlace();
}
}
static void PlaceAirport(TileIndex tile)
{
DoCommandP(tile, _selected_airport_type, 0, CcBuildAirport, CMD_BUILD_AIRPORT | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_A001_CAN_T_BUILD_AIRPORT_HERE));
}
static void PlaceAir_DemolishArea(TileIndex tile)
{
VpStartPlaceSizing(tile, 4);
}
enum {
ATW_AIRPORT = 3,
ATW_DEMOLISH = 4
};
static void BuildAirClick_Airport(Window *w)
{
if (HandlePlacePushButton(w, ATW_AIRPORT, SPR_CURSOR_AIRPORT, 1, PlaceAirport)) ShowBuildAirportPicker();
}
static void BuildAirClick_Demolish(Window *w)
{
HandlePlacePushButton(w, ATW_DEMOLISH, ANIMCURSOR_DEMOLISH, 1, PlaceAir_DemolishArea);
}
static void BuildAirClick_Landscaping(Window *w)
{
ShowTerraformToolbar();
}
typedef void OnButtonClick(Window *w);
static OnButtonClick * const _build_air_button_proc[] = {
BuildAirClick_Airport,
BuildAirClick_Demolish,
BuildAirClick_Landscaping,
};
static void BuildAirToolbWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_PAINT:
DrawWindowWidgets(w);
break;
case WE_CLICK:
if (e->we.click.widget - 3 >= 0)
_build_air_button_proc[e->we.click.widget - 3](w);
break;
case WE_KEYPRESS: {
switch (e->we.keypress.keycode) {
case '1': BuildAirClick_Airport(w); break;
case '2': BuildAirClick_Demolish(w); break;
case 'l': BuildAirClick_Landscaping(w); break;
default: return;
}
} break;
case WE_PLACE_OBJ:
_place_proc(e->we.place.tile);
break;
case WE_PLACE_DRAG:
VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.userdata);
break;
case WE_PLACE_MOUSEUP:
if (e->we.place.pt.x != -1) {
DoCommandP(e->we.place.tile, e->we.place.starttile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
}
break;
case WE_ABORT_PLACE_OBJ:
RaiseWindowButtons(w);
w = FindWindowById(WC_BUILD_STATION, 0);
if (w != 0)
WP(w,def_d).close = true;
break;
case WE_DESTROY:
if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
break;
}
}
static const Widget _air_toolbar_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 73, 0, 13, STR_A000_AIRPORTS, STR_018C_WINDOW_TITLE_DRAG_THIS },
{ WWT_STICKYBOX, RESIZE_NONE, 7, 74, 85, 0, 13, 0x0, STR_STICKY_BUTTON },
{ WWT_IMGBTN, RESIZE_NONE, 7, 0, 41, 14, 35, SPR_IMG_AIRPORT, STR_A01E_BUILD_AIRPORT },
{ WWT_IMGBTN, RESIZE_NONE, 7, 42, 63, 14, 35, SPR_IMG_DYNAMITE, STR_018D_DEMOLISH_BUILDINGS_ETC },
{ WWT_IMGBTN, RESIZE_NONE, 7, 64, 85, 14, 35, SPR_IMG_LANDSCAPING, STR_LANDSCAPING_TOOLBAR_TIP },
{ WIDGETS_END},
};
static const WindowDesc _air_toolbar_desc = {
WDP_ALIGN_TBR, 22, 86, 36,
WC_BUILD_TOOLBAR, 0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_air_toolbar_widgets,
BuildAirToolbWndProc
};
void ShowBuildAirToolbar(void)
{
if (!IsValidPlayer(_current_player)) return;
DeleteWindowById(WC_BUILD_TOOLBAR, 0);
AllocateWindowDescFront(&_air_toolbar_desc, 0);
if (_patches.link_terraform_toolbar) ShowTerraformToolbar();
}
static void BuildAirportPickerWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_CREATE:
SetWindowWidgetLoweredState(w, 16, !_station_show_coverage);
SetWindowWidgetLoweredState(w, 17, _station_show_coverage);
LowerWindowWidget(w, _selected_airport_type + 7);
break;
case WE_PAINT: {
int i; // airport enabling loop
int rad = 4; // default catchment radious
uint32 avail_airports;
const AirportFTAClass *airport;
if (WP(w,def_d).close) return;
avail_airports = GetValidAirports();
RaiseWindowWidget(w, _selected_airport_type + 7);
if (!HASBIT(avail_airports, 0) && _selected_airport_type == AT_SMALL) _selected_airport_type = AT_LARGE;
if (!HASBIT(avail_airports, 1) && _selected_airport_type == AT_LARGE) _selected_airport_type = AT_SMALL;
LowerWindowWidget(w, _selected_airport_type + 7);
/* 'Country Airport' starts at widget 7, and if its bit is set, it is
* available, so take its opposite value to set the disabled state.
* There are 9 buildable airports
* XXX TODO : all airports should be held in arrays, with all relevant data.
* This should be part of newgrf-airports, i suppose
*/
for (i = 0; i < 9; i++) SetWindowWidgetDisabledState(w, i + 7, !HASBIT(avail_airports, i));
// select default the coverage area to 'Off' (16)
airport = GetAirport(_selected_airport_type);
SetTileSelectSize(airport->size_x, airport->size_y);
if (_patches.modified_catchment) {
switch (_selected_airport_type) {
case AT_OILRIG: rad = CA_AIR_OILPAD; break;
case AT_HELIPORT: rad = CA_AIR_HELIPORT; break;
case AT_SMALL: rad = CA_AIR_SMALL; break;
case AT_LARGE: rad = CA_AIR_LARGE; break;
case AT_METROPOLITAN: rad = CA_AIR_METRO; break;
case AT_INTERNATIONAL: rad = CA_AIR_INTER; break;
case AT_COMMUTER: rad = CA_AIR_COMMUTER; break;
case AT_HELIDEPOT: rad = CA_AIR_HELIDEPOT; break;
case AT_INTERCON: rad = CA_AIR_INTERCON; break;
case AT_HELISTATION: rad = CA_AIR_HELISTATION; break;
}
}
if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
DrawWindowWidgets(w);
// strings such as 'Size' and 'Coverage Area'
// 'Coverage Area'
DrawStationCoverageAreaText(2, 206, (uint)-1, rad);
break;
}
case WE_CLICK: {
switch (e->we.click.widget) {
case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15:
RaiseWindowWidget(w, _selected_airport_type + 7);
_selected_airport_type = e->we.click.widget - 7;
LowerWindowWidget(w, _selected_airport_type + 7);
SndPlayFx(SND_15_BEEP);
SetWindowDirty(w);
break;
case 16: case 17:
_station_show_coverage = e->we.click.widget - 16;
SetWindowWidgetLoweredState(w, 16, !_station_show_coverage);
SetWindowWidgetLoweredState(w, 17, _station_show_coverage);
SndPlayFx(SND_15_BEEP);
SetWindowDirty(w);
break;
}
} break;
case WE_MOUSELOOP: {
if (WP(w,def_d).close) {
DeleteWindow(w);
return;
}
CheckRedrawStationCoverage(w);
} break;
case WE_DESTROY:
if (!WP(w,def_d).close) ResetObjectToPlace();
break;
}
}
static const Widget _build_airport_picker_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 147, 0, 13, STR_3001_AIRPORT_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 14, 52, 0x0, STR_NULL},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 53, 89, 0x0, STR_NULL},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 90, 127, 0x0, STR_NULL},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 128, 177, 0x0, STR_NULL},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 178, 239, 0x0, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 27, 38, STR_SMALL_AIRPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 65, 76, STR_CITY_AIRPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 141, 152, STR_HELIPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 77, 88, STR_METRO_AIRPORT , STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 103, 114, STR_INTERNATIONAL_AIRPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 39, 50, STR_COMMUTER_AIRPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 165, 176, STR_HELIDEPOT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 115, 126, STR_INTERCONTINENTAL_AIRPORT, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 145, 153, 164, STR_HELISTATION, STR_3058_SELECT_SIZE_TYPE_OF_AIRPORT},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 14, 73, 191, 202, STR_02DB_OFF, STR_3065_DON_T_HIGHLIGHT_COVERAGE},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 74, 133, 191, 202, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA},
{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 14, 27, STR_SMALL_AIRPORTS, STR_NULL},
{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 52, 65, STR_LARGE_AIRPORTS, STR_NULL},
{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 90, 103, STR_HUB_AIRPORTS, STR_NULL},
{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 128, 141, STR_HELIPORTS, STR_NULL},
{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 178, 191, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
{ WIDGETS_END},
};
static const WindowDesc _build_airport_desc = {
WDP_AUTO, WDP_AUTO, 148, 240,
WC_BUILD_STATION, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_airport_picker_widgets,
BuildAirportPickerWndProc
};
static void ShowBuildAirportPicker(void)
{
AllocateWindowDesc(&_build_airport_desc);
}
void InitializeAirportGui(void)
{
_selected_airport_type = AT_SMALL;
}

794
airport_movement.h Normal file
View File

@@ -0,0 +1,794 @@
/* $Id$ */
#ifndef AIRPORT_MOVEMENT_H
#define AIRPORT_MOVEMENT_H
// state machine input struct (from external file, etc.)
// Finite sTate mAchine --> FTA
typedef struct AirportFTAbuildup {
byte position; // the position that an airplane is at
byte heading; // the current orders (eg. TAKEOFF, HANGAR, ENDLANDING, etc.)
uint32 block; // the block this position is on on the airport (st->airport_flags)
byte next; // next position from this position
} AirportFTAbuildup;
///////////////////////////////////////////////////////////////////////
/////*********Movement Positions on Airports********************///////
// Country Airfield (small) 4x3
static const AirportMovingData _airport_moving_data_country[22] = {
{ 53, 3, AMED_EXACTPOS, 3 }, // 00 In Hangar
{ 53, 27, 0, 0 }, // 01 Taxi to right outside depot
{ 32, 23, AMED_EXACTPOS, 7 }, // 02 Terminal 1
{ 10, 23, AMED_EXACTPOS, 7 }, // 03 Terminal 2
{ 43, 37, 0, 0 }, // 04 Going towards terminal 2
{ 24, 37, 0, 0 }, // 05 Going towards terminal 2
{ 53, 37, 0, 0 }, // 06 Going for takeoff
{ 61, 40, AMED_EXACTPOS, 1 }, // 07 Taxi to start of runway (takeoff)
{ 3, 40, AMED_NOSPDCLAMP, 0 }, // 08 Accelerate to end of runway
{ -79, 40, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 09 Take off
{ 177, 40, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 10 Fly to landing position in air
{ 56, 40, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 11 Going down for land
{ 3, 40, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 12 Just landed, brake until end of runway
{ 7, 40, 0, 0 }, // 13 Just landed, turn around and taxi 1 square
{ 53, 40, 0, 0 }, // 14 Taxi from runway to crossing
{ -31, 193, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 15 Fly around waiting for a landing spot (north-east)
{ 1, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 16 Fly around waiting for a landing spot (north-west)
{ 257, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 17 Fly around waiting for a landing spot (south-west)
{ 273, 49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 18 Fly around waiting for a landing spot (south)
{ 44, 37, AMED_HELI_RAISE, 0 }, // 19 Helicopter takeoff
{ 44, 40, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 20 In position above landing spot helicopter
{ 44, 40, AMED_HELI_LOWER, 0 }, // 21 Helicopter landing
};
// Commuter Airfield (small) 5x4
static const AirportMovingData _airport_moving_data_commuter[37] = {
{ 69, 3, AMED_EXACTPOS, 3 }, // 00 In Hangar
{ 72, 22, 0, 0 }, // 01 Taxi to right outside depot
{ 8, 22, AMED_EXACTPOS, 5 }, // 01 Taxi to right outside depot
{ 24, 36, AMED_EXACTPOS, 3 }, // 03 Terminal 1
{ 40, 36, AMED_EXACTPOS, 3 }, // 04 Terminal 2
{ 56, 36, AMED_EXACTPOS, 3 }, // 05 Terminal 3
{ 40, 8, AMED_EXACTPOS, 1 }, // 06 Helipad 1
{ 56, 8, AMED_EXACTPOS, 1 }, // 07 Helipad 2
{ 24, 22, 0, 5 }, // 08 Taxiing
{ 40, 22, 0, 5 }, // 09 Taxiing
{ 56, 22, 0, 5 }, // 10 Taxiing
{ 72, 40, 0, 3 }, // 11 Airport OUTWAY
{ 72, 54, AMED_EXACTPOS, 1 }, // 12 Accelerate to end of runway
{ 7, 54, AMED_NOSPDCLAMP, 0 }, // 13 Release control of runway, for smoother movement
{ 5, 54, AMED_NOSPDCLAMP, 0 }, // 14 End of runway
{ -79, 54, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 15 Take off
{ 145, 54, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 16 Fly to landing position in air
{ 73, 54, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 17 Going down for land
{ 3, 54, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 18 Just landed, brake until end of runway
{ 12, 54, 0, 7 }, // 19 Just landed, turn around and taxi
{ 8, 32, 0, 7 }, // 20 Taxi from runway to crossing
{ -31, 149, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 21 Fly around waiting for a landing spot (north-east)
{ 1, 6, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 22 Fly around waiting for a landing spot (north-west)
{ 193, 6, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 23 Fly around waiting for a landing spot (south-west)
{ 225, 81, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 24 Fly around waiting for a landing spot (south)
// Helicopter
{ 80, 0, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 25 Bufferspace before helipad
{ 80, 0, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 26 Bufferspace before helipad
{ 32, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 27 Get in position for Helipad1
{ 48, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 28 Get in position for Helipad2
{ 32, 8, AMED_HELI_LOWER, 0 }, // 29 Land at Helipad1
{ 48, 8, AMED_HELI_LOWER, 0 }, // 30 Land at Helipad2
{ 32, 8, AMED_HELI_RAISE, 0 }, // 31 Takeoff Helipad1
{ 48, 8, AMED_HELI_RAISE, 0 }, // 32 Takeoff Helipad2
{ 64, 22, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 33 Go to position for Hangarentrance in air
{ 64, 22, AMED_HELI_LOWER, 0 }, // 34 Land in front of hangar
{ 40, 8, AMED_EXACTPOS, 0 }, // pre-helitakeoff helipad 1
{ 56, 8, AMED_EXACTPOS, 0 }, // pre-helitakeoff helipad 2
};
// City Airport (large) 6x6
static const AirportMovingData _airport_moving_data_town[25] = {
{ 85, 3, AMED_EXACTPOS, 3 }, // 00 In Hangar
{ 85, 27, 0, 0 }, // 01 Taxi to right outside depot
{ 26, 41, AMED_EXACTPOS, 5 }, // 02 Terminal 1
{ 56, 20, AMED_EXACTPOS, 3 }, // 03 Terminal 2
{ 38, 8, AMED_EXACTPOS, 5 }, // 04 Terminal 3
{ 65, 6, 0, 0 }, // 05 Taxi to right in infront of terminal 2/3
{ 80, 27, 0, 0 }, // 06 Taxiway terminals 2-3
{ 44, 63, 0, 0 }, // 07 Taxi to Airport center
{ 58, 71, 0, 0 }, // 08 Towards takeoff
{ 72, 85, 0, 0 }, // 09 Taxi to runway (takeoff)
{ 89, 85, AMED_EXACTPOS, 1 }, // 10 Taxi to start of runway (takeoff)
{ 3, 85, AMED_NOSPDCLAMP, 0 }, // 11 Accelerate to end of runway
{ -79, 85, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 12 Take off
{ 177, 85, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 13 Fly to landing position in air
{ 89, 85, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 14 Going down for land
{ 3, 85, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 15 Just landed, brake until end of runway
{ 20, 87, 0, 0 }, // 16 Just landed, turn around and taxi 1 square
{ 36, 71, 0, 0 }, // 17 Taxi from runway to crossing
{ -31, 193, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 18 Fly around waiting for a landing spot (north-east)
{ 1, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 19 Fly around waiting for a landing spot (north-west)
{ 257, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 20 Fly around waiting for a landing spot (south-west)
{ 273, 49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 21 Fly around waiting for a landing spot (south)
{ 44, 63, AMED_HELI_RAISE, 0 }, // 22 Helicopter takeoff
{ 28, 74, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 23 In position above landing spot helicopter
{ 28, 74, AMED_HELI_LOWER, 0 }, // 24 Helicopter landing
};
// Metropolitan Airport (metropolitan) - 2 runways
static const AirportMovingData _airport_moving_data_metropolitan[27] = {
{ 85, 3, AMED_EXACTPOS, 3 }, // 00 In Hangar
{ 85, 27, 0, 0 }, // 01 Taxi to right outside depot
{ 26, 41, AMED_EXACTPOS, 5 }, // 02 Terminal 1
{ 56, 20, AMED_EXACTPOS, 3 }, // 03 Terminal 2
{ 38, 8, AMED_EXACTPOS, 5 }, // 04 Terminal 3
{ 65, 6, 0, 0 }, // 05 Taxi to right in infront of terminal 2/3
{ 70, 33, 0, 0 }, // 06 Taxiway terminals 2-3
{ 44, 58, 0, 0 }, // 07 Taxi to Airport center
{ 72, 58, 0, 0 }, // 08 Towards takeoff
{ 72, 69, 0, 0 }, // 09 Taxi to runway (takeoff)
{ 89, 69, AMED_EXACTPOS, 1 }, // 10 Taxi to start of runway (takeoff)
{ 3, 69, AMED_NOSPDCLAMP, 0 }, // 11 Accelerate to end of runway
{ -79, 69, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 12 Take off
{ 177, 85, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 13 Fly to landing position in air
{ 89, 85, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 14 Going down for land
{ 3, 85, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 15 Just landed, brake until end of runway
{ 21, 85, 0, 0 }, // 16 Just landed, turn around and taxi 1 square
{ 21, 69, 0, 0 }, // 17 On Runway-out taxiing to In-Way
{ 21, 54, AMED_EXACTPOS, 5 }, // 18 Taxi from runway to crossing
{ -31, 193, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 19 Fly around waiting for a landing spot (north-east)
{ 1, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 20 Fly around waiting for a landing spot (north-west)
{ 257, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 21 Fly around waiting for a landing spot (south-west)
{ 273, 49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 22 Fly around waiting for a landing spot (south)
{ 44, 58, 0, 0 }, // 23 Helicopter takeoff spot on ground (to clear airport sooner)
{ 44, 63, AMED_HELI_RAISE, 0 }, // 24 Helicopter takeoff
{ 15, 54, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 25 Get in position above landing spot helicopter
{ 15, 54, AMED_HELI_LOWER, 0 }, // 26 Helicopter landing
};
// International Airport (international) - 2 runways, 6 terminals, dedicated helipod
static const AirportMovingData _airport_moving_data_international[51] = {
{ 7, 55, AMED_EXACTPOS, 3 }, // 00 In Hangar 1
{ 100, 21, AMED_EXACTPOS, 3 }, // 01 In Hangar 2
{ 7, 70, 0, 0 }, // 02 Taxi to right outside depot
{ 100, 36, 0, 0 }, // 03 Taxi to right outside depot
{ 38, 70, AMED_EXACTPOS, 5 }, // 04 Terminal 1
{ 38, 54, AMED_EXACTPOS, 5 }, // 05 Terminal 2
{ 38, 38, AMED_EXACTPOS, 5 }, // 06 Terminal 3
{ 70, 70, AMED_EXACTPOS, 1 }, // 07 Terminal 4
{ 70, 54, AMED_EXACTPOS, 1 }, // 08 Terminal 5
{ 70, 38, AMED_EXACTPOS, 1 }, // 09 Terminal 6
{ 104, 71, AMED_EXACTPOS, 1 }, // 10 Helipad 1
{ 104, 55, AMED_EXACTPOS, 1 }, // 11 Helipad 2
{ 22, 87, 0, 0 }, // 12 Towards Terminals 4/5/6, Helipad 1/2
{ 60, 87, 0, 0 }, // 13 Towards Terminals 4/5/6, Helipad 1/2
{ 66, 87, 0, 0 }, // 14 Towards Terminals 4/5/6, Helipad 1/2
{ 86, 87, AMED_EXACTPOS, 7 }, // 15 Towards Terminals 4/5/6, Helipad 1/2
{ 86, 70, 0, 0 }, // 16 In Front of Terminal 4 / Helipad 1
{ 86, 54, 0, 0 }, // 17 In Front of Terminal 5 / Helipad 2
{ 86, 38, 0, 0 }, // 18 In Front of Terminal 6
{ 86, 22, 0, 0 }, // 19 Towards Terminals Takeoff (Taxiway)
{ 66, 22, 0, 0 }, // 20 Towards Terminals Takeoff (Taxiway)
{ 60, 22, 0, 0 }, // 21 Towards Terminals Takeoff (Taxiway)
{ 38, 22, 0, 0 }, // 22 Towards Terminals Takeoff (Taxiway)
{ 22, 70, 0, 0 }, // 23 In Front of Terminal 1
{ 22, 58, 0, 0 }, // 24 In Front of Terminal 2
{ 22, 38, 0, 0 }, // 25 In Front of Terminal 3
{ 22, 22, AMED_EXACTPOS, 7 }, // 26 Going for Takeoff
{ 22, 6, 0, 0 }, // 27 On Runway-out, prepare for takeoff
{ 3, 6, AMED_EXACTPOS, 5 }, // 28 Accelerate to end of runway
{ 60, 6, AMED_NOSPDCLAMP, 0 }, // 29 Release control of runway, for smoother movement
{ 105, 6, AMED_NOSPDCLAMP, 0 }, // 30 End of runway
{ 190, 6, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 31 Take off
{ 193, 104, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 32 Fly to landing position in air
{ 105, 104, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 33 Going down for land
{ 3, 104, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 34 Just landed, brake until end of runway
{ 12, 104, 0, 0 }, // 35 Just landed, turn around and taxi 1 square
{ 7, 84, 0, 0 }, // 36 Taxi from runway to crossing
{ -31, 209, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 37 Fly around waiting for a landing spot (north-east)
{ 1, 6, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 38 Fly around waiting for a landing spot (north-west)
{ 273, 6, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 39 Fly around waiting for a landing spot (south-west)
{ 305, 81, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 40 Fly around waiting for a landing spot (south)
// Helicopter
{ 128, 80, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 41 Bufferspace before helipad
{ 128, 80, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 42 Bufferspace before helipad
{ 96, 71, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 43 Get in position for Helipad1
{ 96, 55, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 44 Get in position for Helipad2
{ 96, 71, AMED_HELI_LOWER, 0 }, // 45 Land at Helipad1
{ 96, 55, AMED_HELI_LOWER, 0 }, // 46 Land at Helipad2
{ 104, 71, AMED_HELI_RAISE, 0 }, // 47 Takeoff Helipad1
{ 104, 55, AMED_HELI_RAISE, 0 }, // 48 Takeoff Helipad2
{ 104, 32, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 49 Go to position for Hangarentrance in air
{ 104, 32, AMED_HELI_LOWER, 0} // 50 Land in HANGAR2_AREA to go to hangar
};
// Intercontinental Airport - 4 runways, 8 terminals, 2 dedicated helipads
static const AirportMovingData _airport_moving_data_intercontinental[77] = {
{ 7, 87, AMED_EXACTPOS, 3 }, // 00 In Hangar 1
{ 135, 72, AMED_EXACTPOS, 3 }, // 01 In Hangar 2
{ 7, 104, 0, 0 }, // 02 Taxi to right outside depot 1
{ 135, 88, 0, 0 }, // 03 Taxi to right outside depot 2
{ 56, 120, AMED_EXACTPOS, 6 }, // 04 Terminal 1
{ 56, 104, AMED_EXACTPOS, 5 }, // 05 Terminal 2
{ 56, 88, AMED_EXACTPOS, 5 }, // 06 Terminal 3
{ 56, 72, AMED_EXACTPOS, 5 }, // 07 Terminal 4
{ 88, 120, AMED_EXACTPOS, 0 }, // 08 Terminal 5
{ 88, 104, AMED_EXACTPOS, 1 }, // 09 Terminal 6
{ 88, 88, AMED_EXACTPOS, 1 }, // 10 Terminal 7
{ 88, 72, AMED_EXACTPOS, 1 }, // 11 Terminal 8
{ 88, 56, AMED_EXACTPOS, 3 }, // 12 Helipad 1
{ 72, 56, AMED_EXACTPOS, 1 }, // 13 Helipad 2
{ 40, 136, 0, 0 }, // 14 Term group 2 enter 1 a
{ 56, 136, 0, 0 }, // 15 Term group 2 enter 1 b
{ 88, 136, 0, 0 }, // 16 Term group 2 enter 2 a
{ 104, 136, 0, 0 }, // 17 Term group 2 enter 2 b
{ 104, 120, 0, 0 }, // 18 Term group 2 - opp term 5
{ 104, 104, 0, 0 }, // 19 Term group 2 - opp term 6 & exit2
{ 104, 88, 0, 0 }, // 20 Term group 2 - opp term 7 & hangar area 2
{ 104, 72, 0, 0 }, // 21 Term group 2 - opp term 8
{ 104, 56, 0, 0 }, // 22 Taxi Term group 2 exit a
{ 104, 40, 0, 0 }, // 23 Taxi Term group 2 exit b
{ 56, 40, 0, 0 }, // 24 Term group 2 exit 2a
{ 40, 40, 0, 0 }, // 25 Term group 2 exit 2b
{ 40, 120, 0, 0 }, // 26 Term group 1 - opp term 1
{ 40, 104, 0, 0 }, // 27 Term group 1 - opp term 2 & hangar area 1
{ 40, 88, 0, 0 }, // 28 Term group 1 - opp term 3
{ 40, 72, 0, 0 }, // 29 Term group 1 - opp term 4
{ 18, 72, 0, 7 }, // 30 Outway 1
{ 8, 40, 0, 7 }, // 31 Airport OUTWAY
{ 8, 24, AMED_EXACTPOS, 5 }, // 32 Accelerate to end of runway
{ 119, 24, AMED_NOSPDCLAMP, 0 }, // 33 Release control of runway, for smoother movement
{ 117, 24, AMED_NOSPDCLAMP, 0 }, // 34 End of runway
{ 197, 24, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 35 Take off
{ 254, 84, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 36 Flying to landing position in air
{ 117, 168, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 37 Going down for land
{ 3, 168, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 38 Just landed, brake until end of runway
{ 8, 168, 0, 0 }, // 39 Just landed, turn around and taxi
{ 8, 144, 0, 7 }, // 40 Taxi from runway
{ 8, 128, 0, 7 }, // 41 Taxi from runway
{ 8, 120, AMED_EXACTPOS, 5 }, // 42 Airport entrance
{ 56, 344, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 43 Fly around waiting for a landing spot (north-east)
{ -200, 88, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 44 Fly around waiting for a landing spot (north-west)
{ 56, -168, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 45 Fly around waiting for a landing spot (south-west)
{ 312, 88, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 46 Fly around waiting for a landing spot (south)
// Helicopter
{ 96, 40, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 47 Bufferspace before helipad
{ 96, 40, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 48 Bufferspace before helipad
{ 82, 54, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 49 Get in position for Helipad1
{ 64, 56, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 50 Get in position for Helipad2
{ 81, 55, AMED_HELI_LOWER, 0 }, // 51 Land at Helipad1
{ 64, 56, AMED_HELI_LOWER, 0 }, // 52 Land at Helipad2
{ 80, 56, AMED_HELI_RAISE, 0 }, // 53 Takeoff Helipad1
{ 64, 56, AMED_HELI_RAISE, 0 }, // 54 Takeoff Helipad2
{ 136, 96, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 55 Go to position for Hangarentrance in air
{ 136, 96, AMED_HELI_LOWER, 0 }, // 56 Land in front of hangar2
{ 126, 104, 0, 3 }, // 57 Outway 2
{ 136, 136, 0, 1 }, // 58 Airport OUTWAY 2
{ 136, 152, AMED_EXACTPOS, 1 }, // 59 Accelerate to end of runway2
{ 16, 152, AMED_NOSPDCLAMP, 0 }, // 60 Release control of runway2, for smoother movement
{ 20, 152, AMED_NOSPDCLAMP, 0 }, // 61 End of runway2
{ -56, 152, AMED_NOSPDCLAMP | AMED_TAKEOFF, 0 }, // 62 Take off2
{ 24, 8, AMED_NOSPDCLAMP | AMED_LAND, 0 }, // 63 Going down for land2
{ 136, 8, AMED_NOSPDCLAMP | AMED_BRAKE, 0 }, // 64 Just landed, brake until end of runway2in
{ 136, 8, 0, 0 }, // 65 Just landed, turn around and taxi
{ 136, 24, 0, 3 }, // 66 Taxi from runway 2in
{ 136, 40, 0, 3 }, // 67 Taxi from runway 2in
{ 136, 56, AMED_EXACTPOS, 1 }, // 68 Airport entrance2
{ -56, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 69 Fly to landing position in air2
{ 88, 40, 0, 0 }, // 70 Taxi Term group 2 exit - opp heli1
{ 72, 40, 0, 0 }, // 71 Taxi Term group 2 exit - opp heli2
{ 88, 57, AMED_EXACTPOS, 3 }, // 72 pre-helitakeoff helipad 1
{ 71, 56, AMED_EXACTPOS, 1 }, // 73 pre-helitakeoff helipad 2
{ 8, 120, AMED_HELI_RAISE, 0 }, // 74 Helitakeoff outside depot 1
{ 136, 104, AMED_HELI_RAISE, 0 }, // 75 Helitakeoff outside depot 2
{ 197, 168, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0} // 76 Fly to landing position in air1
};
// Heliport (heliport)
static const AirportMovingData _airport_moving_data_heliport[9] = {
{ 5, 9, AMED_EXACTPOS, 1 }, // 0 - At heliport terminal
{ 2, 9, AMED_HELI_RAISE, 0 }, // 1 - Take off (play sound)
{ -3, 9, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 2 - In position above landing spot helicopter
{ -3, 9, AMED_HELI_LOWER, 0 }, // 3 - Land
{ 2, 9, 0, 0 }, // 4 - Goto terminal on ground
{ -31, 59, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 5 - Circle #1 (north-east)
{ -31, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 6 - Circle #2 (north-west)
{ 49, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 7 - Circle #3 (south-west)
{ 70, 9, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 8 - Circle #4 (south)
};
// HeliDepot 2x2 (heliport)
static const AirportMovingData _airport_moving_data_helidepot[18] = {
{ 24, 4, AMED_EXACTPOS, 1 }, // 0 - At depot
{ 24, 28, 0, 0 }, // 1 Taxi to right outside depot
{ 5, 38, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 2 Flying
{ -15, -15, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 3 - Circle #1 (north-east)
{ -15, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 4 - Circle #2 (north-west)
{ 49, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 5 - Circle #3 (south-west)
{ 49, -15, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 6 - Circle #4 (south-east)
{ 8, 32, AMED_NOSPDCLAMP | AMED_SLOWTURN, 7 }, // 7 - PreHelipad
{ 8, 32, AMED_NOSPDCLAMP | AMED_SLOWTURN, 7 }, // 8 - Helipad
{ 8, 16, AMED_NOSPDCLAMP | AMED_SLOWTURN, 7 }, // 9 - Land
{ 8, 16, AMED_HELI_LOWER, 7 }, // 10 - Land
{ 8, 24, AMED_HELI_RAISE, 0 }, // 11 - Take off (play sound)
{ 32, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 7 }, // 12 Air to above hangar area
{ 32, 24, AMED_HELI_LOWER, 7 }, // 13 Taxi to right outside depot
{ 8, 24, AMED_EXACTPOS, 7 }, // 14 - on helipad1
{ 24, 28, AMED_HELI_RAISE, 0 }, // 15 Takeoff right outside depot
{ 8, 24, AMED_HELI_RAISE, 5 }, // 16 - Take off (play sound)
{ 8, 24, AMED_SLOWTURN | AMED_EXACTPOS, 2 }, // 17 - turn on helipad1 for takeoff
};
// HeliDepot 2x2 (heliport)
static const AirportMovingData _airport_moving_data_helistation[33] = {
{ 8, 3, AMED_EXACTPOS, 3 }, // 00 In Hangar2
{ 8, 22, 0, 0 }, // 01 outside hangar 2
{ 116, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 02 Fly to landing position in air
{ 14, 22, AMED_HELI_RAISE, 0 }, // 03 Helitakeoff outside hangar1(play sound)
{ 24, 22, 0, 0 }, // 04 taxiing
{ 40, 22, 0, 0 }, // 05 taxiing
{ 40, 8, AMED_EXACTPOS, 1 }, // 06 Helipad 1
{ 56, 8, AMED_EXACTPOS, 1 }, // 07 Helipad 2
{ 56, 24, AMED_EXACTPOS, 1 }, // 08 Helipad 3
{ 40, 8, AMED_EXACTPOS, 0 }, // 09 pre-helitakeoff helipad 1
{ 56, 8, AMED_EXACTPOS, 0 }, // 10 pre-helitakeoff helipad 2
{ 56, 24, AMED_EXACTPOS, 0 }, // 11 pre-helitakeoff helipad 3
{ 32, 8, AMED_HELI_RAISE, 0 }, // 12 Takeoff Helipad1
{ 48, 8, AMED_HELI_RAISE, 0 }, // 13 Takeoff Helipad2
{ 48, 24, AMED_HELI_RAISE, 0 }, // 14 Takeoff Helipad3
{ 84, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 15 Bufferspace before helipad
{ 68, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 16 Bufferspace before helipad
{ 32, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 17 Get in position for Helipad1
{ 48, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 18 Get in position for Helipad2
{ 48, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 1 }, // 19 Get in position for Helipad3
{ 40, 8, AMED_HELI_LOWER, 0 }, // 20 Land at Helipad1
{ 48, 8, AMED_HELI_LOWER, 0 }, // 21 Land at Helipad2
{ 48, 24, AMED_HELI_LOWER, 0 }, // 22 Land at Helipad3
{ 0, 22, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 23 Go to position for Hangarentrance in air
{ 0, 22, AMED_HELI_LOWER, 0 }, // 24 Land in front of hangar
{ 148, -8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 25 Fly around waiting for a landing spot (south-east)
{ 148, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 26 Fly around waiting for a landing spot (south-west)
{ 132, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 27 Fly around waiting for a landing spot (south-west)
{ 100, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 28 Fly around waiting for a landing spot (north-east)
{ 84, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 29 Fly around waiting for a landing spot (south-east)
{ 84, -8, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 30 Fly around waiting for a landing spot (south-west)
{ 100, -24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 31 Fly around waiting for a landing spot (north-west)
{ 132, -24, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 32 Fly around waiting for a landing spot (north-east)
};
// Oilrig
static const AirportMovingData _airport_moving_data_oilrig[9] = {
{ 31, 9, AMED_EXACTPOS, 1 }, // 0 - At oilrig terminal
{ 28, 9, AMED_HELI_RAISE, 0 }, // 1 - Take off (play sound)
{ 23, 9, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 2 - In position above landing spot helicopter
{ 23, 9, AMED_HELI_LOWER, 0 }, // 3 - Land
{ 28, 9, 0, 0 }, // 4 - Goto terminal on ground
{ -31, 69, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 5 - circle #1 (north-east)
{ -31, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 6 - circle #2 (north-west)
{ 69, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 7 - circle #3 (south-west)
{ 70, 9, AMED_NOSPDCLAMP | AMED_SLOWTURN, 0 }, // 8 - circle #4 (south)
};
///////////////////////////////////////////////////////////////////////
/////**********Movement Machine on Airports*********************///////
/* First element of terminals array tells us how many depots there are (to know size of array)
* this may be changed later when airports are moved to external file */
static const TileIndexDiffC _airport_depots_country[] = {{3, 0}};
static const byte _airport_terminal_country[] = {1, 2};
static const AirportFTAbuildup _airport_fta_country[] = {
{ 0, HANGAR, NOTHING_block, 1 },
{ 1, 255, AIRPORT_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM1, TERM1_block, 2 }, { 1, TERM2, 0, 4 }, { 1, HELITAKEOFF, 0, 19 }, { 1, 0, 0, 6 },
{ 2, TERM1, TERM1_block, 1 },
{ 3, TERM2, TERM2_block, 5 },
{ 4, 255, AIRPORT_BUSY_block, 0 }, { 4, TERM2, 0, 5 }, { 4, HANGAR, 0, 1 }, { 4, TAKEOFF, 0, 6 }, { 4, HELITAKEOFF, 0, 1 },
{ 5, 255, AIRPORT_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, 0, 0, 4 },
{ 6, 0, AIRPORT_BUSY_block, 7 },
// takeoff
{ 7, TAKEOFF, AIRPORT_BUSY_block, 8 },
{ 8, STARTTAKEOFF, NOTHING_block, 9 },
{ 9, ENDTAKEOFF, NOTHING_block, 0 },
// landing
{ 10, FLYING, NOTHING_block, 15 }, { 10, LANDING, 0, 11 }, { 10, HELILANDING, 0, 20 },
{ 11, LANDING, AIRPORT_BUSY_block, 12 },
{ 12, 0, AIRPORT_BUSY_block, 13 },
{ 13, ENDLANDING, AIRPORT_BUSY_block, 14 }, { 13, TERM2, 0, 5 }, { 13, 0, 0, 14 },
{ 14, 0, AIRPORT_BUSY_block, 1 },
// In air
{ 15, 0, NOTHING_block, 16 },
{ 16, 0, NOTHING_block, 17 },
{ 17, 0, NOTHING_block, 18 },
{ 18, 0, NOTHING_block, 10 },
{ 19, HELITAKEOFF, NOTHING_block, 0 },
{ 20, HELILANDING, AIRPORT_BUSY_block, 21 },
{ 21, HELIENDLANDING, AIRPORT_BUSY_block, 1 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
static const TileIndexDiffC _airport_depots_commuter[] = { { 4, 0 } };
static const byte _airport_terminal_commuter[] = { 1, 3 };
static const byte _airport_helipad_commuter[] = { 1, 2 };
static const AirportFTAbuildup _airport_fta_commuter[] = {
{ 0, HANGAR, NOTHING_block, 1 }, { 0, HELITAKEOFF, HELIPAD2_block, 1 }, { 0, 0, 0, 1 },
{ 1, 255, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TAKEOFF, 0, 11 }, { 1, TERM1, TAXIWAY_BUSY_block, 10 }, { 1, TERM2, TAXIWAY_BUSY_block, 10 }, { 1, TERM3, TAXIWAY_BUSY_block, 10 }, { 1, HELIPAD1, TAXIWAY_BUSY_block, 10 }, { 1, HELIPAD2, TAXIWAY_BUSY_block, 10 }, { 1, HELITAKEOFF, TAXIWAY_BUSY_block, 10 }, { 1, 0, 0, 0 },
{ 2, 255, AIRPORT_ENTRANCE_block, 2 }, { 2, HANGAR, 0, 8 }, { 2, TERM1, 0, 8 }, { 2, TERM2, 0, 8 }, { 2, TERM3, 0, 8 }, { 2, HELIPAD1, 0, 8 }, { 2, HELIPAD2, 0, 8 }, { 2, HELITAKEOFF, 0, 8 }, { 2, 0, 0, 2 },
{ 3, TERM1, TERM1_block, 8 }, { 3, HANGAR, 0, 8 }, { 3, TAKEOFF, 0, 8 }, { 3, 0, 0, 3 },
{ 4, TERM2, TERM2_block, 9 }, { 4, HANGAR, 0, 9 }, { 4, TAKEOFF, 0, 9 }, { 4, 0, 0, 4 },
{ 5, TERM3, TERM3_block, 10 }, { 5, HANGAR, 0, 10 }, { 5, TAKEOFF, 0, 10 }, { 5, 0, 0, 5 },
{ 6, HELIPAD1, HELIPAD1_block, 6 }, { 6, HANGAR, TAXIWAY_BUSY_block, 9 }, { 6, HELITAKEOFF, 0, 35 },
{ 7, HELIPAD2, HELIPAD2_block, 7 }, { 7, HANGAR, TAXIWAY_BUSY_block, 10 }, { 7, HELITAKEOFF, 0, 36 },
{ 8, 255, TAXIWAY_BUSY_block, 8 }, { 8, TAKEOFF, TAXIWAY_BUSY_block, 9 }, { 8, HANGAR, TAXIWAY_BUSY_block, 9 }, { 8, TERM1, TERM1_block, 3 }, { 8, 0, TAXIWAY_BUSY_block, 9 },
{ 9, 255, TAXIWAY_BUSY_block, 9 }, { 9, TAKEOFF, TAXIWAY_BUSY_block, 10 }, { 9, HANGAR, TAXIWAY_BUSY_block, 10 }, { 9, TERM2, TERM2_block, 4 }, { 9, HELIPAD1, HELIPAD1_block, 6 }, { 9, HELITAKEOFF, HELIPAD1_block, 6 }, { 9, TERM1, TAXIWAY_BUSY_block, 8 }, { 9, 0, TAXIWAY_BUSY_block, 10 },
{ 10, 255, TAXIWAY_BUSY_block, 10 }, { 10, TERM3, TERM3_block, 5 }, { 10, HELIPAD1, 0, 9 }, { 10, HELIPAD2, HELIPAD2_block, 7 }, { 10, HELITAKEOFF, HELIPAD2_block, 7 }, { 10, TAKEOFF, TAXIWAY_BUSY_block, 1 }, { 10, HANGAR, TAXIWAY_BUSY_block, 1 }, { 10, 0, TAXIWAY_BUSY_block, 9 },
{ 11, 0, OUT_WAY_block, 12 },
// takeoff
{ 12, TAKEOFF, RUNWAY_IN_OUT_block, 13 },
{ 13, 0, RUNWAY_IN_OUT_block, 14 },
{ 14, STARTTAKEOFF, RUNWAY_IN_OUT_block, 15 },
{ 15, ENDTAKEOFF, NOTHING_block, 0 },
// landing
{ 16, FLYING, NOTHING_block, 21 }, { 16, LANDING, IN_WAY_block, 17 }, { 16, HELILANDING, 0, 25 },
{ 17, LANDING, RUNWAY_IN_OUT_block, 18 },
{ 18, 0, RUNWAY_IN_OUT_block, 19 },
{ 19, 0, RUNWAY_IN_OUT_block, 20 },
{ 20, ENDLANDING, IN_WAY_block, 2 },
// In Air
{ 21, 0, NOTHING_block, 22 },
{ 22, 0, NOTHING_block, 23 },
{ 23, 0, NOTHING_block, 24 },
{ 24, 0, NOTHING_block, 16 },
// Helicopter -- stay in air in special place as a buffer to choose from helipads
{ 25, HELILANDING, PRE_HELIPAD_block, 26 },
{ 26, HELIENDLANDING, PRE_HELIPAD_block, 26 }, { 26, HELIPAD1, 0, 27 }, { 26, HELIPAD2, 0, 28 }, { 26, HANGAR, 0, 33 },
{ 27, 0, NOTHING_block, 29 }, //helipad1 approach
{ 28, 0, NOTHING_block, 30 },
// landing
{ 29, 255, NOTHING_block, 0 }, { 29, HELIPAD1, HELIPAD1_block, 6 },
{ 30, 255, NOTHING_block, 0 }, { 30, HELIPAD2, HELIPAD2_block, 7 },
// Helicopter -- takeoff
{ 31, HELITAKEOFF, NOTHING_block, 0 },
{ 32, HELITAKEOFF, NOTHING_block, 0 },
{ 33, 0, TAXIWAY_BUSY_block, 34 }, // need to go to hangar when waiting in air
{ 34, 0, TAXIWAY_BUSY_block, 1 },
{ 35, 0, HELIPAD1_block, 31 },
{ 36, 0, HELIPAD2_block, 32 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
static const TileIndexDiffC _airport_depots_city[] = { { 5, 0 } };
static const byte _airport_terminal_city[] = { 1, 3 };
static const AirportFTAbuildup _airport_fta_city[] = {
{ 0, HANGAR, NOTHING_block, 1 }, { 0, TAKEOFF, OUT_WAY_block, 1 }, { 0, 0, 0, 1 },
{ 1, 255, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM2, 0, 6 }, { 1, TERM3, 0, 6 }, { 1, 0, 0, 7 }, // for all else, go to 7
{ 2, TERM1, TERM1_block, 7 }, { 2, TAKEOFF, OUT_WAY_block, 7 }, { 2, 0, 0, 7 },
{ 3, TERM2, TERM2_block, 5 }, { 3, TAKEOFF, OUT_WAY_block, 5 }, { 3, 0, 0, 5 },
{ 4, TERM3, TERM3_block, 5 }, { 4, TAKEOFF, OUT_WAY_block, 5 }, { 4, 0, 0, 5 },
{ 5, 255, TAXIWAY_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, TERM3, TERM3_block, 4 }, { 5, 0, 0, 6 },
{ 6, 255, TAXIWAY_BUSY_block, 0 }, { 6, TERM2, 0, 5 }, { 6, TERM3, 0, 5 }, { 6, HANGAR, 0, 1 }, { 6, 0, 0, 7 },
{ 7, 255, TAXIWAY_BUSY_block, 0 }, { 7, TERM1, TERM1_block, 2 }, { 7, TAKEOFF, OUT_WAY_block, 8 }, { 7, HELITAKEOFF, 0, 22 }, { 7, HANGAR, 0, 1 }, { 7, 0, 0, 6 },
{ 8, 0, OUT_WAY_block, 9 },
{ 9, 0, RUNWAY_IN_OUT_block, 10 },
// takeoff
{ 10, TAKEOFF, RUNWAY_IN_OUT_block, 11 },
{ 11, STARTTAKEOFF, NOTHING_block, 12 },
{ 12, ENDTAKEOFF, NOTHING_block, 0 },
// landing
{ 13, FLYING, NOTHING_block, 18 }, { 13, LANDING, 0, 14 }, { 13, HELILANDING, 0, 23 },
{ 14, LANDING, RUNWAY_IN_OUT_block, 15 },
{ 15, 0, RUNWAY_IN_OUT_block, 16 },
{ 16, 0, RUNWAY_IN_OUT_block, 17 },
{ 17, ENDLANDING, IN_WAY_block, 7 },
// In Air
{ 18, 0, NOTHING_block, 19 },
{ 19, 0, NOTHING_block, 20 },
{ 20, 0, NOTHING_block, 21 },
{ 21, 0, NOTHING_block, 13 },
// helicopter
{ 22, HELITAKEOFF, NOTHING_block, 0 },
{ 23, HELILANDING, IN_WAY_block, 24 },
{ 24, HELIENDLANDING, IN_WAY_block, 17 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
static const TileIndexDiffC _airport_depots_metropolitan[] = { { 5, 0 } };
static const byte _airport_terminal_metropolitan[] = { 1, 3 };
static const AirportFTAbuildup _airport_fta_metropolitan[] = {
{ 0, HANGAR, NOTHING_block, 1 },
{ 1, 255, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM2, 0, 6 }, { 1, TERM3, 0, 6 }, { 1, 0, 0, 7 }, // for all else, go to 7
{ 2, TERM1, TERM1_block, 7 },
{ 3, TERM2, TERM2_block, 5 },
{ 4, TERM3, TERM3_block, 5 },
{ 5, 255, TAXIWAY_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, TERM3, TERM3_block, 4 }, { 5, 0, 0, 6 },
{ 6, 255, TAXIWAY_BUSY_block, 0 }, { 6, TERM2, 0, 5 }, { 6, TERM3, 0, 5 }, { 6, HANGAR, 0, 1 }, { 6, 0, 0, 7 },
{ 7, 255, TAXIWAY_BUSY_block, 0 }, { 7, TERM1, TERM1_block, 2 }, { 7, TAKEOFF, 0, 8 }, { 7, HELITAKEOFF, 0, 23 }, { 7, HANGAR, 0, 1 }, { 7, 0, 0, 6 },
{ 8, 0, OUT_WAY_block, 9 },
{ 9, 0, RUNWAY_OUT_block, 10 },
// takeoff
{ 10, TAKEOFF, RUNWAY_OUT_block, 11 },
{ 11, STARTTAKEOFF, NOTHING_block, 12 },
{ 12, ENDTAKEOFF, NOTHING_block, 0 },
// landing
{ 13, FLYING, NOTHING_block, 19 }, { 13, LANDING, 0, 14 }, { 13, HELILANDING, 0, 25 },
{ 14, LANDING, RUNWAY_IN_block, 15 },
{ 15, 0, RUNWAY_IN_block, 16 },
{ 16, 255, RUNWAY_IN_block, 0 }, { 16, ENDLANDING, IN_WAY_block, 17 },
{ 17, 255, RUNWAY_OUT_block, 0 }, { 17, ENDLANDING, IN_WAY_block, 18 },
{ 18, ENDLANDING, IN_WAY_block, 7 },
// In Air
{ 19, 0, NOTHING_block, 20 },
{ 20, 0, NOTHING_block, 21 },
{ 21, 0, NOTHING_block, 22 },
{ 22, 0, NOTHING_block, 13 },
// helicopter
{ 23, 0, NOTHING_block, 24 },
{ 24, HELITAKEOFF, NOTHING_block, 0 },
{ 25, HELILANDING, IN_WAY_block, 26 },
{ 26, HELIENDLANDING, IN_WAY_block, 18 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
static const TileIndexDiffC _airport_depots_international[] = { { 0, 3 }, { 6, 1 } };
static const byte _airport_terminal_international[] = { 2, 3, 3 };
static const byte _airport_helipad_international[] = { 1, 2 };
static const AirportFTAbuildup _airport_fta_international[] = {
{ 0, HANGAR, NOTHING_block, 2 }, { 0, 255, TERM_GROUP1_block, 0 }, { 0, 255, TERM_GROUP2_ENTER1_block, 1 }, { 0, HELITAKEOFF, HELIPAD1_block, 2 }, { 0, 0, 0, 2 },
{ 1, HANGAR, NOTHING_block, 3 }, { 1, 255, HANGAR2_AREA_block, 1 }, { 1, HELITAKEOFF, HELIPAD2_block, 3 }, { 1, 0, 0, 3 },
{ 2, 255, AIRPORT_ENTRANCE_block, 0 }, { 2, HANGAR, 0, 0 }, { 2, TERM4, 0, 12 }, { 2, TERM5, 0, 12 }, { 2, TERM6, 0, 12 }, { 2, HELIPAD1, 0, 12 }, { 2, HELIPAD2, 0, 12 }, { 2, HELITAKEOFF, 0, 12 }, { 2, 0, 0, 23 },
{ 3, 255, HANGAR2_AREA_block, 0 }, { 3, HANGAR, 0, 1 }, { 3, 0, 0, 18 },
{ 4, TERM1, TERM1_block, 23 }, { 4, HANGAR, AIRPORT_ENTRANCE_block, 23 }, { 4, 0, 0, 23 },
{ 5, TERM2, TERM2_block, 24 }, { 5, HANGAR, AIRPORT_ENTRANCE_block, 24 }, { 5, 0, 0, 24 },
{ 6, TERM3, TERM3_block, 25 }, { 6, HANGAR, AIRPORT_ENTRANCE_block, 25 }, { 6, 0, 0, 25 },
{ 7, TERM4, TERM4_block, 16 }, { 7, HANGAR, HANGAR2_AREA_block, 16 }, { 7, 0, 0, 16 },
{ 8, TERM5, TERM5_block, 17 }, { 8, HANGAR, HANGAR2_AREA_block, 17 }, { 8, 0, 0, 17 },
{ 9, TERM6, TERM6_block, 18 }, { 9, HANGAR, HANGAR2_AREA_block, 18 }, { 9, 0, 0, 18 },
{ 10, HELIPAD1, HELIPAD1_block, 10 }, { 10, HANGAR, HANGAR2_AREA_block, 16 }, { 10, HELITAKEOFF, 0, 47 },
{ 11, HELIPAD2, HELIPAD2_block, 11 }, { 11, HANGAR, HANGAR2_AREA_block, 17 }, { 11, HELITAKEOFF, 0, 48 },
{ 12, 0, TERM_GROUP2_ENTER1_block, 13 },
{ 13, 0, TERM_GROUP2_ENTER1_block, 14 },
{ 14, 0, TERM_GROUP2_ENTER2_block, 15 },
{ 15, 0, TERM_GROUP2_ENTER2_block, 16 },
{ 16, 255, TERM_GROUP2_block, 0 }, { 16, TERM4, TERM4_block, 7 }, { 16, HELIPAD1, HELIPAD1_block, 10 }, { 16, HELITAKEOFF, HELIPAD1_block, 10 }, { 16, 0, 0, 17 },
{ 17, 255, TERM_GROUP2_block, 0 }, { 17, TERM5, TERM5_block, 8 }, { 17, TERM4, 0, 16 }, { 17, HELIPAD1, 0, 16 }, { 17, HELIPAD2, HELIPAD2_block, 11 }, { 17, HELITAKEOFF, HELIPAD2_block, 11 }, { 17, 0, 0, 18 },
{ 18, 255, TERM_GROUP2_block, 0 }, { 18, TERM6, TERM6_block, 9 }, { 18, TAKEOFF, 0, 19 }, { 18, HANGAR, HANGAR2_AREA_block, 3 }, { 18, 0, 0, 17 },
{ 19, 0, TERM_GROUP2_EXIT1_block, 20 },
{ 20, 0, TERM_GROUP2_EXIT1_block, 21 },
{ 21, 0, TERM_GROUP2_EXIT2_block, 22 },
{ 22, 0, TERM_GROUP2_EXIT2_block, 26 },
{ 23, 255, TERM_GROUP1_block, 0 }, { 23, TERM1, TERM1_block, 4 }, { 23, HANGAR, AIRPORT_ENTRANCE_block, 2 }, { 23, 0, 0, 24 },
{ 24, 255, TERM_GROUP1_block, 0 }, { 24, TERM2, TERM2_block, 5 }, { 24, TERM1, 0, 23 }, { 24, HANGAR, 0, 23 }, { 24, 0, 0, 25 },
{ 25, 255, TERM_GROUP1_block, 0 }, { 25, TERM3, TERM3_block, 6 }, { 25, TAKEOFF, 0, 26 }, { 25, 0, 0, 24 },
{ 26, 255, TAXIWAY_BUSY_block, 0 }, { 26, TAKEOFF, 0, 27 }, { 26, 0, 0, 25 },
{ 27, 0, OUT_WAY_block, 28 },
// takeoff
{ 28, TAKEOFF, OUT_WAY_block, 29 },
{ 29, 0, RUNWAY_OUT_block, 30 },
{ 30, STARTTAKEOFF, NOTHING_block, 31 },
{ 31, ENDTAKEOFF, NOTHING_block, 0 },
// landing
{ 32, FLYING, NOTHING_block, 37 }, { 32, LANDING, 0, 33 }, { 32, HELILANDING, 0, 41 },
{ 33, LANDING, RUNWAY_IN_block, 34 },
{ 34, 0, RUNWAY_IN_block, 35 },
{ 35, 0, RUNWAY_IN_block, 36 },
{ 36, ENDLANDING, IN_WAY_block, 36 }, { 36, 255, TERM_GROUP1_block, 0 }, { 36, 255, TERM_GROUP2_ENTER1_block, 1 }, { 36, TERM4, 0, 12 }, { 36, TERM5, 0, 12 }, { 36, TERM6, 0, 12 }, { 36, 0, 0, 2 },
// In Air
{ 37, 0, NOTHING_block, 38 },
{ 38, 0, NOTHING_block, 39 },
{ 39, 0, NOTHING_block, 40 },
{ 40, 0, NOTHING_block, 32 },
// Helicopter -- stay in air in special place as a buffer to choose from helipads
{ 41, HELILANDING, PRE_HELIPAD_block, 42 },
{ 42, HELIENDLANDING, PRE_HELIPAD_block, 42 }, { 42, HELIPAD1, 0, 43 }, { 42, HELIPAD2, 0, 44 }, { 42, HANGAR, 0, 49 },
{ 43, 0, NOTHING_block, 45 },
{ 44, 0, NOTHING_block, 46 },
// landing
{ 45, 255, NOTHING_block, 0 }, { 45, HELIPAD1, HELIPAD1_block, 10 },
{ 46, 255, NOTHING_block, 0 }, { 46, HELIPAD2, HELIPAD2_block, 11 },
// Helicopter -- takeoff
{ 47, HELITAKEOFF, NOTHING_block, 0 },
{ 48, HELITAKEOFF, NOTHING_block, 0 },
{ 49, 0, HANGAR2_AREA_block, 50 }, // need to go to hangar when waiting in air
{ 50, 0, HANGAR2_AREA_block, 3 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
// intercontinental
static const TileIndexDiffC _airport_depots_intercontinental[] = { { 0, 5 }, { 8, 4 } };
static const byte _airport_terminal_intercontinental[] = { 2, 4, 4 };
static const byte _airport_helipad_intercontinental[] = { 1, 2 };
static const AirportFTAbuildup _airport_fta_intercontinental[] = {
{ 0, HANGAR, NOTHING_block, 2 }, { 0, 255, HANGAR1_AREA_block | TERM_GROUP1_block, 0 }, { 0, 255, HANGAR1_AREA_block | TERM_GROUP1_block, 1 }, { 0, TAKEOFF, HANGAR1_AREA_block | TERM_GROUP1_block, 2 }, { 0, 0, 0, 2 },
{ 1, HANGAR, NOTHING_block, 3 }, { 1, 255, HANGAR2_AREA_block, 1 }, { 1, 255, HANGAR2_AREA_block, 0 }, { 1, 0, 0, 3 },
{ 2, 255, HANGAR1_AREA_block, 0 }, { 2, 255, TERM_GROUP1_block, 0 }, { 2, 255, TERM_GROUP1_block, 1 }, { 2, HANGAR, 0, 0 }, { 2, TAKEOFF, TERM_GROUP1_block, 27 }, { 2, TERM5, 0, 26 }, { 2, TERM6, 0, 26 }, { 2, TERM7, 0, 26 }, { 2, TERM8, 0, 26 }, { 2, HELIPAD1, 0, 26 }, { 2, HELIPAD2, 0, 26 }, { 2, HELITAKEOFF, 0, 74 }, { 2, 0, 0, 27 },
{ 3, 255, HANGAR2_AREA_block, 0 }, { 3, HANGAR, 0, 1 }, { 3, HELITAKEOFF, 0, 75 }, { 3, 0, 0, 20 },
{ 4, TERM1, TERM1_block, 26 }, { 4, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 26 }, { 4, 0, 0, 26 },
{ 5, TERM2, TERM2_block, 27 }, { 5, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 27 }, { 5, 0, 0, 27 },
{ 6, TERM3, TERM3_block, 28 }, { 6, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 28 }, { 6, 0, 0, 28 },
{ 7, TERM4, TERM4_block, 29 }, { 7, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 29 }, { 7, 0, 0, 29 },
{ 8, TERM5, TERM5_block, 18 }, { 8, HANGAR, HANGAR2_AREA_block, 18 }, { 8, 0, 0, 18 },
{ 9, TERM6, TERM6_block, 19 }, { 9, HANGAR, HANGAR2_AREA_block, 19 }, { 9, 0, 0, 19 },
{ 10, TERM7, TERM7_block, 20 }, { 10, HANGAR, HANGAR2_AREA_block, 20 }, { 10, 0, 0, 20 },
{ 11, TERM8, TERM8_block, 21 }, { 11, HANGAR, HANGAR2_AREA_block, 21 }, { 11, 0, 0, 21 },
{ 12, HELIPAD1, HELIPAD1_block, 12 }, { 12, HANGAR, 0, 70 }, { 12, HELITAKEOFF, 0, 72 },
{ 13, HELIPAD2, HELIPAD2_block, 13 }, { 13, HANGAR, 0, 71 }, { 13, HELITAKEOFF, 0, 73 },
{ 14, 0, TERM_GROUP2_ENTER1_block, 15 },
{ 15, 0, TERM_GROUP2_ENTER1_block, 16 },
{ 16, 0, TERM_GROUP2_ENTER2_block, 17 },
{ 17, 0, TERM_GROUP2_ENTER2_block, 18 },
{ 18, 255, TERM_GROUP2_block, 0 }, { 18, TERM5, TERM5_block, 8 }, { 18, TAKEOFF, 0, 19 }, { 18, HELITAKEOFF, HELIPAD1_block, 19 }, { 18, 0, TERM_GROUP2_EXIT1_block, 19 },
{ 19, 255, TERM_GROUP2_block, 0 }, { 19, TERM6, TERM6_block, 9 }, { 19, TERM5, 0, 18 }, { 19, TAKEOFF, 0, 57 }, { 19, HELITAKEOFF, HELIPAD1_block, 20 }, { 19, 0, TERM_GROUP2_EXIT1_block, 20 }, // add exit to runway out 2
{ 20, 255, TERM_GROUP2_block, 0 }, { 20, TERM7, TERM7_block, 10 }, { 20, TERM5, 0, 19 }, { 20, TERM6, 0, 19 }, { 20, HANGAR, HANGAR2_AREA_block, 3 }, { 20, TAKEOFF, 0, 19 }, { 20, 0, TERM_GROUP2_EXIT1_block, 21 },
{ 21, 255, TERM_GROUP2_block, 0 }, { 21, TERM8, TERM8_block, 11 }, { 21, HANGAR, HANGAR2_AREA_block, 20 }, { 21, TERM5, 0, 20 }, { 21, TERM6, 0, 20 }, { 21, TERM7, 0, 20 }, { 21, TAKEOFF, 0, 20 }, { 21, 0, TERM_GROUP2_EXIT1_block, 22 },
{ 22, 255, TERM_GROUP2_block, 0 }, { 22, HANGAR, 0, 21 }, { 22, TERM5, 0, 21 }, { 22, TERM6, 0, 21 }, { 22, TERM7, 0, 21 }, { 22, TERM8, 0, 21 }, { 22, TAKEOFF, 0, 21 }, { 22, 0, 0, 23 },
{ 23, 0, TERM_GROUP2_EXIT1_block, 70 },
{ 24, 0, TERM_GROUP2_EXIT2_block, 25 },
{ 25, 255, TERM_GROUP2_EXIT2_block, 0 }, { 25, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 29 }, { 25, 0, 0, 29 },
{ 26, 255, TERM_GROUP1_block, 0 }, { 26, TERM1, TERM1_block, 4 }, { 26, HANGAR, HANGAR1_AREA_block, 27 }, { 26, TERM5, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM6, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM7, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM8, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELIPAD1, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELIPAD2, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELITAKEOFF, TERM_GROUP2_ENTER1_block, 14 }, { 26, 0, 0, 27 },
{ 27, 255, TERM_GROUP1_block, 0 }, { 27, TERM2, TERM2_block, 5 }, { 27, HANGAR, HANGAR1_AREA_block, 2 }, { 27, TERM1, 0, 26 }, { 27, TERM5, 0, 26 }, { 27, TERM6, 0, 26 }, { 27, TERM7, 0, 26 }, { 27, TERM8, 0, 26 }, { 27, HELIPAD1, 0, 14 }, { 27, HELIPAD2, 0, 14 }, { 27, 0, 0, 28 },
{ 28, 255, TERM_GROUP1_block, 0 }, { 28, TERM3, TERM3_block, 6 }, { 28, HANGAR, HANGAR1_AREA_block, 27 }, { 28, TERM1, 0, 27 }, { 28, TERM2, 0, 27 }, { 28, TERM4, 0, 29 }, { 28, TERM5, 0, 14 }, { 28, TERM6, 0, 14 }, { 28, TERM7, 0, 14 }, { 28, TERM8, 0, 14 }, { 28, HELIPAD1, 0, 14 }, { 28, HELIPAD2, 0, 14 }, { 28, 0, 0, 29 },
{ 29, 255, TERM_GROUP1_block, 0 }, { 29, TERM4, TERM4_block, 7 }, { 29, HANGAR, HANGAR1_AREA_block, 27 }, { 29, TAKEOFF, 0, 30 }, { 29, 0, 0, 28 },
{ 30, 0, OUT_WAY_block2, 31 },
{ 31, 0, OUT_WAY_block, 32 },
// takeoff
{ 32, TAKEOFF, RUNWAY_OUT_block, 33 },
{ 33, 0, RUNWAY_OUT_block, 34 },
{ 34, STARTTAKEOFF, NOTHING_block, 35 },
{ 35, ENDTAKEOFF, NOTHING_block, 0 },
// landing
{ 36, 0, 0, 0 },
{ 37, LANDING, RUNWAY_IN_block, 38 },
{ 38, 0, RUNWAY_IN_block, 39 },
{ 39, 0, RUNWAY_IN_block, 40 },
{ 40, ENDLANDING, RUNWAY_IN_block, 41 },
{ 41, 0, IN_WAY_block, 42 },
{ 42, 255, IN_WAY_block, 0 }, { 42, 255, TERM_GROUP1_block, 0 }, { 42, 255, TERM_GROUP1_block, 1 }, { 42, HANGAR, 0, 2 }, { 42, 0, 0, 26 },
// In Air
{ 43, 0, 0, 44 },
{ 44, FLYING, 0, 45 }, { 44, HELILANDING, 0, 47 }, { 44, LANDING, 0, 69 }, { 44, 0, 0, 45 },
{ 45, 0, 0, 46 },
{ 46, FLYING, 0, 43 }, { 46, LANDING, 0, 76 }, { 46, 0, 0, 43 },
// Helicopter -- stay in air in special place as a buffer to choose from helipads
{ 47, HELILANDING, PRE_HELIPAD_block, 48 },
{ 48, HELIENDLANDING, PRE_HELIPAD_block, 48 }, { 48, HELIPAD1, 0, 49 }, { 48, HELIPAD2, 0, 50 }, { 48, HANGAR, 0, 55 },
{ 49, 0, NOTHING_block, 51 },
{ 50, 0, NOTHING_block, 52 },
// landing
{ 51, 255, NOTHING_block, 0 }, { 51, HELIPAD1, HELIPAD1_block, 12 }, { 51, HANGAR, 0, 55 }, { 51, 0, 0, 12 },
{ 52, 255, NOTHING_block, 0 }, { 52, HELIPAD2, HELIPAD2_block, 13 }, { 52, HANGAR, 0, 55 }, { 52, 0, 0, 13 },
// Helicopter -- takeoff
{ 53, HELITAKEOFF, NOTHING_block, 0 },
{ 54, HELITAKEOFF, NOTHING_block, 0 },
{ 55, 0, HANGAR2_AREA_block, 56 }, // need to go to hangar when waiting in air
{ 56, 0, HANGAR2_AREA_block, 3 },
// runway 2 out support
{ 57, 255, OUT_WAY2_block, 0 }, { 57, TAKEOFF, 0, 58 }, { 57, 0, 0, 58 },
{ 58, 0, OUT_WAY2_block, 59 },
{ 59, TAKEOFF, RUNWAY_OUT2_block, 60 }, // takeoff
{ 60, 0, RUNWAY_OUT2_block, 61 },
{ 61, STARTTAKEOFF, NOTHING_block, 62 },
{ 62, ENDTAKEOFF, NOTHING_block, 0 },
// runway 2 in support
{ 63, LANDING, RUNWAY_IN2_block, 64 },
{ 64, 0, RUNWAY_IN2_block, 65 },
{ 65, 0, RUNWAY_IN2_block, 66 },
{ 66, ENDLANDING, RUNWAY_IN2_block, 0 }, { 66, 255, 0, 1 }, { 66, 255, 0, 0 }, { 66, 0, 0, 67 },
{ 67, 0, IN_WAY2_block, 68 },
{ 68, 255, IN_WAY2_block, 0 }, { 68, 255, TERM_GROUP2_block, 1 }, { 68, 255, TERM_GROUP1_block, 0 }, { 68, HANGAR, HANGAR2_AREA_block, 22 }, { 68, 0, 0, 22 },
{ 69, 255, RUNWAY_IN2_block, 0 }, { 69, 0, RUNWAY_IN2_block, 63 },
{ 70, 255, TERM_GROUP2_EXIT1_block, 0 }, { 70, HELIPAD1, HELIPAD1_block, 12 }, { 70, HELITAKEOFF, HELIPAD1_block, 12 }, { 70, 0, 0, 71 },
{ 71, 255, TERM_GROUP2_EXIT1_block, 0 }, { 71, HELIPAD2, HELIPAD2_block, 13 }, { 71, HELITAKEOFF, HELIPAD1_block, 12 }, { 71, 0, 0, 24 },
{ 72, 0, HELIPAD1_block, 53 },
{ 73, 0, HELIPAD2_block, 54 },
{ 74, HELITAKEOFF, NOTHING_block, 0 },
{ 75, HELITAKEOFF, NOTHING_block, 0 },
{ 76, 255, RUNWAY_IN_block, 0 }, { 76, 0, RUNWAY_IN_block, 37 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
// heliports, oilrigs don't have depots
static const byte _airport_helipad_heliport_oilrig[] = { 1, 1 };
static const AirportFTAbuildup _airport_fta_heliport_oilrig[] = {
{ 0, HELIPAD1, HELIPAD1_block, 1 },
{ 1, HELITAKEOFF, NOTHING_block, 0 }, // takeoff
{ 2, 255, AIRPORT_BUSY_block, 0 }, { 2, HELILANDING, 0, 3 }, { 2, HELITAKEOFF, 0, 1 },
{ 3, HELILANDING, AIRPORT_BUSY_block, 4 },
{ 4, HELIENDLANDING, AIRPORT_BUSY_block, 4 }, { 4, HELIPAD1, HELIPAD1_block, 0 }, { 4, HELITAKEOFF, 0, 2 },
// In Air
{ 5, 0, NOTHING_block, 6 },
{ 6, 0, NOTHING_block, 7 },
{ 7, 0, NOTHING_block, 8 },
{ 8, FLYING, NOTHING_block, 5 }, { 8, HELILANDING, HELIPAD1_block, 2 }, // landing
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
// helidepots
static const TileIndexDiffC _airport_depots_helidepot[] = { { 1, 0 } };
static const byte _airport_helipad_helidepot[] = { 1, 1 };
static const AirportFTAbuildup _airport_fta_helidepot[] = {
{ 0, HANGAR, NOTHING_block, 1 },
{ 1, 255, HANGAR2_AREA_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, HELIPAD1, HELIPAD1_block, 14 }, { 1, HELITAKEOFF, 0, 15 }, { 1, 0, 0, 0 },
{ 2, FLYING, NOTHING_block, 3 }, { 2, HELILANDING, PRE_HELIPAD_block, 7 }, { 2, HANGAR, 0, 12 }, { 2, HELITAKEOFF, NOTHING_block, 16 },
// In Air
{ 3, 0, NOTHING_block, 4 },
{ 4, 0, NOTHING_block, 5 },
{ 5, 0, NOTHING_block, 6 },
{ 6, 0, NOTHING_block, 2 },
// Helicopter -- stay in air in special place as a buffer to choose from helipads
{ 7, HELILANDING, PRE_HELIPAD_block, 8 },
{ 8, HELIENDLANDING, PRE_HELIPAD_block, 8 }, { 8, HELIPAD1, 0, 9 }, { 8, HANGAR, 0, 12 }, { 8, 0, 0, 2 },
{ 9, 0, NOTHING_block, 10 },
// landing
{ 10, 255, NOTHING_block, 10 }, { 10, HELIPAD1, HELIPAD1_block, 14 }, { 10, HANGAR, 0, 1 }, { 10, 0, 0, 14 },
// Helicopter -- takeoff
{ 11, HELITAKEOFF, NOTHING_block, 0 },
{ 12, 0, HANGAR2_AREA_block, 13 }, // need to go to hangar when waiting in air
{ 13, 0, HANGAR2_AREA_block, 1 },
{ 14, HELIPAD1, HELIPAD1_block, 14 }, { 14, HANGAR, 0, 1 }, { 14, HELITAKEOFF, 0, 17 },
{ 15, HELITAKEOFF, NOTHING_block, 0 }, // takeoff outside depot
{ 16, HELITAKEOFF, 0, 14 },
{ 17, 0, NOTHING_block, 11 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
// helistation
static const TileIndexDiffC _airport_depots_helistation[] = { { 0, 0 } };
static const byte _airport_helipad_helistation[] = { 1, 3 };
static const AirportFTAbuildup _airport_fta_helistation[] = {
{ 0, HANGAR, NOTHING_block, 8 }, { 0, HELIPAD1, 0, 1 }, { 0, HELIPAD2, 0, 1 }, { 0, HELIPAD3, 0, 1 }, { 0, HELITAKEOFF, 0, 1 }, { 0, 0, 0, 0 },
{ 1, 255, HANGAR2_AREA_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, HELITAKEOFF, 0, 3 }, { 1, 0, 0, 4 },
// landing
{ 2, FLYING, NOTHING_block, 28 }, { 2, HELILANDING, 0, 15 }, { 2, 0, 0, 28 },
// helicopter side
{ 3, HELITAKEOFF, NOTHING_block, 0 }, // helitakeoff outside hangar2
{ 4, 255, TAXIWAY_BUSY_block, 0 }, { 4, HANGAR, HANGAR2_AREA_block, 1 }, { 4, HELITAKEOFF, 0, 1 }, { 4, 0, 0, 5 },
{ 5, 255, TAXIWAY_BUSY_block, 0 }, { 5, HELIPAD1, HELIPAD1_block, 6 }, { 5, HELIPAD2, HELIPAD2_block, 7 }, { 5, HELIPAD3, HELIPAD3_block, 8 }, { 5, 0, 0, 4 },
{ 6, HELIPAD1, HELIPAD1_block, 5 }, { 6, HANGAR, HANGAR2_AREA_block, 5 }, { 6, HELITAKEOFF, 0, 9 }, { 6, 0, 0, 6 },
{ 7, HELIPAD2, HELIPAD2_block, 5 }, { 7, HANGAR, HANGAR2_AREA_block, 5 }, { 7, HELITAKEOFF, 0, 10 }, { 7, 0, 0, 7 },
{ 8, HELIPAD3, HELIPAD3_block, 5 }, { 8, HANGAR, HANGAR2_AREA_block, 5 }, { 8, HELITAKEOFF, 0, 11 }, { 8, 0, 0, 8 },
{ 9, 0, HELIPAD1_block, 12 },
{ 10, 0, HELIPAD2_block, 13 },
{ 11, 0, HELIPAD3_block, 14 },
{ 12, HELITAKEOFF, NOTHING_block, 0 },
{ 13, HELITAKEOFF, NOTHING_block, 0 },
{ 14, HELITAKEOFF, NOTHING_block, 0 },
// heli - in flight moves
{ 15, HELILANDING, PRE_HELIPAD_block, 16 },
{ 16, HELIENDLANDING, PRE_HELIPAD_block, 16 }, { 16, HELIPAD1, 0, 17 }, { 16, HELIPAD2, 0, 18 }, { 16, HELIPAD3, 0, 19 }, { 16, HANGAR, 0, 23 },
{ 17, 0, NOTHING_block, 20 },
{ 18, 0, NOTHING_block, 21 },
{ 19, 0, NOTHING_block, 22 },
// heli landing
{ 20, 255, NOTHING_block, 0 }, { 20, HELIPAD1, HELIPAD1_block, 6 }, { 20, HANGAR, 0, 23 }, { 20, 0, 0, 6 },
{ 21, 255, NOTHING_block, 0 }, { 21, HELIPAD2, HELIPAD2_block, 7 }, { 21, HANGAR, 0, 23 }, { 21, 0, 0, 7 },
{ 22, 255, NOTHING_block, 0 }, { 22, HELIPAD3, HELIPAD3_block, 8 }, { 22, HANGAR, 0, 23 }, { 22, 0, 0, 8 },
{ 23, 0, HANGAR2_AREA_block, 24 }, // need to go to helihangar when waiting in air
{ 24, 0, HANGAR2_AREA_block, 1 },
{ 25, 0, NOTHING_block, 26 },
{ 26, 0, NOTHING_block, 27 },
{ 27, 0, NOTHING_block, 2 },
{ 28, 0, NOTHING_block, 29 },
{ 29, 0, NOTHING_block, 30 },
{ 30, 0, NOTHING_block, 31 },
{ 31, 0, NOTHING_block, 32 },
{ 32, 0, NOTHING_block, 25 },
{ MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE
};
static const AirportMovingData * const _airport_moving_datas[] = {
_airport_moving_data_country, // Country Airfield (small) 4x3
_airport_moving_data_town, // City Airport (large) 6x6
_airport_moving_data_heliport, // Heliport
_airport_moving_data_metropolitan, // Metropolitain Airport (large) - 2 runways
_airport_moving_data_international, // International Airport (xlarge) - 2 runways
_airport_moving_data_commuter, // Commuter Airfield (small) 5x4
_airport_moving_data_helidepot, // Helidepot
_airport_moving_data_intercontinental, // Intercontinental Airport (xxlarge) - 4 runways
_airport_moving_data_helistation, // Helistation
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
_airport_moving_data_oilrig // Oilrig
};
#endif /* AIRPORT_MOVEMENT_H */

296
aystar.c Normal file
View File

@@ -0,0 +1,296 @@
/* $Id$ */
/*
* This file has the core function for AyStar
* AyStar is a fast pathfinding routine and is used for things like
* AI_pathfinding and Train_pathfinding.
* For more information about AyStar (A* Algorithm), you can look at
* http://en.wikipedia.org/wiki/A-star_search_algorithm
*/
/*
* Friendly reminder:
* Call (AyStar).free() when you are done with Aystar. It reserves a lot of memory
* And when not free'd, it can cause system-crashes.
* Also remember that when you stop an algorithm before it is finished, your
* should call clear() yourself!
*/
#include "stdafx.h"
#include "openttd.h"
#include "aystar.h"
int _aystar_stats_open_size;
int _aystar_stats_closed_size;
// This looks in the Hash if a node exists in ClosedList
// If so, it returns the PathNode, else NULL
static PathNode* AyStarMain_ClosedList_IsInList(AyStar *aystar, const AyStarNode *node)
{
return (PathNode*)Hash_Get(&aystar->ClosedListHash, node->tile, node->direction);
}
// This adds a node to the ClosedList
// It makes a copy of the data
static void AyStarMain_ClosedList_Add(AyStar *aystar, const PathNode *node)
{
// Add a node to the ClosedList
PathNode *new_node = malloc(sizeof(*new_node));
*new_node = *node;
Hash_Set(&aystar->ClosedListHash, node->node.tile, node->node.direction, new_node);
}
// Checks if a node is in the OpenList
// If so, it returns the OpenListNode, else NULL
static OpenListNode *AyStarMain_OpenList_IsInList(AyStar *aystar, const AyStarNode *node)
{
return (OpenListNode*)Hash_Get(&aystar->OpenListHash, node->tile, node->direction);
}
// Gets the best node from OpenList
// returns the best node, or NULL of none is found
// Also it deletes the node from the OpenList
static OpenListNode *AyStarMain_OpenList_Pop(AyStar *aystar)
{
// Return the item the Queue returns.. the best next OpenList item.
OpenListNode *res = (OpenListNode*)aystar->OpenListQueue.pop(&aystar->OpenListQueue);
if (res != NULL) {
Hash_Delete(&aystar->OpenListHash, res->path.node.tile, res->path.node.direction);
}
return res;
}
// Adds a node to the OpenList
// It makes a copy of node, and puts the pointer of parent in the struct
static void AyStarMain_OpenList_Add(AyStar *aystar, PathNode *parent, const AyStarNode *node, int f, int g)
{
// Add a new Node to the OpenList
OpenListNode *new_node = malloc(sizeof(*new_node));
new_node->g = g;
new_node->path.parent = parent;
new_node->path.node = *node;
Hash_Set(&aystar->OpenListHash, node->tile, node->direction, new_node);
// Add it to the queue
aystar->OpenListQueue.push(&aystar->OpenListQueue, new_node, f);
}
/*
* Checks one tile and calculate his f-value
* return values:
* AYSTAR_DONE : indicates we are done
*/
int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
{
int new_f, new_g, new_h;
PathNode *closedlist_parent;
OpenListNode *check;
// Check the new node against the ClosedList
if (AyStarMain_ClosedList_IsInList(aystar, current) != NULL) return AYSTAR_DONE;
// Calculate the G-value for this node
new_g = aystar->CalculateG(aystar, current, parent);
// If the value was INVALID_NODE, we don't do anything with this node
if (new_g == AYSTAR_INVALID_NODE) return AYSTAR_DONE;
// There should not be given any other error-code..
assert(new_g >= 0);
// Add the parent g-value to the new g-value
new_g += parent->g;
if (aystar->max_path_cost != 0 && (uint)new_g > aystar->max_path_cost) return AYSTAR_DONE;
// Calculate the h-value
new_h = aystar->CalculateH(aystar, current, parent);
// There should not be given any error-code..
assert(new_h >= 0);
// The f-value if g + h
new_f = new_g + new_h;
// Get the pointer to the parent in the ClosedList (the currentone is to a copy of the one in the OpenList)
closedlist_parent = AyStarMain_ClosedList_IsInList(aystar, &parent->path.node);
// Check if this item is already in the OpenList
check = AyStarMain_OpenList_IsInList(aystar, current);
if (check != NULL) {
uint i;
// Yes, check if this g value is lower..
if (new_g > check->g) return AYSTAR_DONE;
aystar->OpenListQueue.del(&aystar->OpenListQueue, check, 0);
// It is lower, so change it to this item
check->g = new_g;
check->path.parent = closedlist_parent;
/* Copy user data, will probably have changed */
for (i = 0; i < lengthof(current->user_data); i++) {
check->path.node.user_data[i] = current->user_data[i];
}
// Readd him in the OpenListQueue
aystar->OpenListQueue.push(&aystar->OpenListQueue, check, new_f);
} else {
// A new node, add him to the OpenList
AyStarMain_OpenList_Add(aystar, closedlist_parent, current, new_f, new_g);
}
return AYSTAR_DONE;
}
/*
* This function is the core of AyStar. It handles one item and checks
* his neighbour items. If they are valid, they are added to be checked too.
* return values:
* AYSTAR_EMPTY_OPENLIST : indicates all items are tested, and no path
* has been found.
* AYSTAR_LIMIT_REACHED : Indicates that the max_nodes limit has been
* reached.
* AYSTAR_FOUND_END_NODE : indicates we found the end. Path_found now is true, and in path is the path found.
* AYSTAR_STILL_BUSY : indicates we have done this tile, did not found the path yet, and have items left to try.
*/
int AyStarMain_Loop(AyStar *aystar)
{
int i, r;
// Get the best node from OpenList
OpenListNode *current = AyStarMain_OpenList_Pop(aystar);
// If empty, drop an error
if (current == NULL) return AYSTAR_EMPTY_OPENLIST;
// Check for end node and if found, return that code
if (aystar->EndNodeCheck(aystar, current) == AYSTAR_FOUND_END_NODE) {
if (aystar->FoundEndNode != NULL)
aystar->FoundEndNode(aystar, current);
free(current);
return AYSTAR_FOUND_END_NODE;
}
// Add the node to the ClosedList
AyStarMain_ClosedList_Add(aystar, &current->path);
// Load the neighbours
aystar->GetNeighbours(aystar, current);
// Go through all neighbours
for (i = 0; i < aystar->num_neighbours; i++) {
// Check and add them to the OpenList if needed
r = aystar->checktile(aystar, &aystar->neighbours[i], current);
}
// Free the node
free(current);
if (aystar->max_search_nodes != 0 && Hash_Size(&aystar->ClosedListHash) >= aystar->max_search_nodes) {
/* We've expanded enough nodes */
return AYSTAR_LIMIT_REACHED;
} else {
// Return that we are still busy
return AYSTAR_STILL_BUSY;
}
}
/*
* This function frees the memory it allocated
*/
void AyStarMain_Free(AyStar *aystar)
{
aystar->OpenListQueue.free(&aystar->OpenListQueue, false);
/* 2nd argument above is false, below is true, to free the values only
* once */
delete_Hash(&aystar->OpenListHash, true);
delete_Hash(&aystar->ClosedListHash, true);
#ifdef AYSTAR_DEBUG
printf("[AyStar] Memory free'd\n");
#endif
}
/*
* This function make the memory go back to zero
* This function should be called when you are using the same instance again.
*/
void AyStarMain_Clear(AyStar *aystar)
{
// Clean the Queue, but not the elements within. That will be done by
// the hash.
aystar->OpenListQueue.clear(&aystar->OpenListQueue, false);
// Clean the hashes
clear_Hash(&aystar->OpenListHash, true);
clear_Hash(&aystar->ClosedListHash, true);
#ifdef AYSTAR_DEBUG
printf("[AyStar] Cleared AyStar\n");
#endif
}
/*
* This is the function you call to run AyStar.
* return values:
* AYSTAR_FOUND_END_NODE : indicates we found an end node.
* AYSTAR_NO_PATH : indicates that there was no path found.
* AYSTAR_STILL_BUSY : indicates we have done some checked, that we did not found the path yet, and that we still have items left to try.
* When the algorithm is done (when the return value is not AYSTAR_STILL_BUSY)
* aystar->clear() is called. Note that when you stop the algorithm halfway,
* you should still call clear() yourself!
*/
int AyStarMain_Main(AyStar *aystar) {
int r, i = 0;
// Loop through the OpenList
// Quit if result is no AYSTAR_STILL_BUSY or is more than loops_per_tick
while ((r = aystar->loop(aystar)) == AYSTAR_STILL_BUSY && (aystar->loops_per_tick == 0 || ++i < aystar->loops_per_tick)) { }
#ifdef AYSTAR_DEBUG
switch (r) {
case AYSTAR_FOUND_END_NODE: printf("[AyStar] Found path!\n"); break;
case AYSTAR_EMPTY_OPENLIST: printf("[AyStar] OpenList run dry, no path found\n"); break;
case AYSTAR_LIMIT_REACHED: printf("[AyStar] Exceeded search_nodes, no path found\n"); break;
default: break;
}
#endif
if (r != AYSTAR_STILL_BUSY) {
/* We're done, clean up */
_aystar_stats_open_size = aystar->OpenListHash.size;
_aystar_stats_closed_size = aystar->ClosedListHash.size;
aystar->clear(aystar);
}
switch (r) {
case AYSTAR_FOUND_END_NODE: return AYSTAR_FOUND_END_NODE;
case AYSTAR_EMPTY_OPENLIST:
case AYSTAR_LIMIT_REACHED: return AYSTAR_NO_PATH;
default: return AYSTAR_STILL_BUSY;
}
}
/*
* Adds a node from where to start an algorithm. Multiple nodes can be added
* if wanted. You should make sure that clear() is called before adding nodes
* if the AyStar has been used before (though the normal main loop calls
* clear() automatically when the algorithm finishes
* g is the cost for starting with this node.
*/
void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g)
{
#ifdef AYSTAR_DEBUG
printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n",
TileX(start_node->tile), TileY(start_node->tile), start_node->direction);
#endif
AyStarMain_OpenList_Add(aystar, NULL, start_node, 0, g);
}
void init_AyStar(AyStar *aystar, Hash_HashProc hash, uint num_buckets)
{
// Allocated the Hash for the OpenList and ClosedList
init_Hash(&aystar->OpenListHash, hash, num_buckets);
init_Hash(&aystar->ClosedListHash, hash, num_buckets);
// Set up our sorting queue
// BinaryHeap allocates a block of 1024 nodes
// When thatone gets full it reserves an otherone, till this number
// That is why it can stay this high
init_BinaryHeap(&aystar->OpenListQueue, 102400);
aystar->addstart = AyStarMain_AddStartNode;
aystar->main = AyStarMain_Main;
aystar->loop = AyStarMain_Loop;
aystar->free = AyStarMain_Free;
aystar->clear = AyStarMain_Clear;
aystar->checktile = AyStarMain_CheckTile;
}

179
aystar.h Normal file
View File

@@ -0,0 +1,179 @@
/* $Id$ */
/*
* This file has the header for AyStar
* AyStar is a fast pathfinding routine and is used for things like
* AI_pathfinding and Train_pathfinding.
* For more information about AyStar (A* Algorithm), you can look at
* http://en.wikipedia.org/wiki/A-star_search_algorithm
*/
#ifndef AYSTAR_H
#define AYSTAR_H
#include "queue.h"
//#define AYSTAR_DEBUG
enum {
AYSTAR_FOUND_END_NODE,
AYSTAR_EMPTY_OPENLIST,
AYSTAR_STILL_BUSY,
AYSTAR_NO_PATH,
AYSTAR_LIMIT_REACHED,
AYSTAR_DONE
};
enum{
AYSTAR_INVALID_NODE = -1,
};
typedef struct AyStarNode AyStarNode;
struct AyStarNode {
TileIndex tile;
uint direction;
uint user_data[2];
};
// The resulting path has nodes looking like this.
typedef struct PathNode PathNode;
struct PathNode {
AyStarNode node;
// The parent of this item
PathNode *parent;
};
// For internal use only
// We do not save the h-value, because it is only needed to calculate the f-value.
// h-value should _always_ be the distance left to the end-tile.
typedef struct OpenListNode OpenListNode;
struct OpenListNode {
int g;
PathNode path;
};
typedef struct AyStar AyStar;
/*
* This function is called to check if the end-tile is found
* return values can be:
* AYSTAR_FOUND_END_NODE : indicates this is the end tile
* AYSTAR_DONE : indicates this is not the end tile (or direction was wrong)
*/
/*
* The 2nd parameter should be OpenListNode, and NOT AyStarNode. AyStarNode is
* part of OpenListNode and so it could be accessed without any problems.
* The good part about OpenListNode is, and how AIs use it, that you can
* access the parent of the current node, and so check if you, for example
* don't try to enter the file tile with a 90-degree curve. So please, leave
* this an OpenListNode, it works just fine -- TrueLight
*/
typedef int32 AyStar_EndNodeCheck(AyStar *aystar, OpenListNode *current);
/*
* This function is called to calculate the G-value for AyStar Algorithm.
* return values can be:
* AYSTAR_INVALID_NODE : indicates an item is not valid (e.g.: unwalkable)
* Any value >= 0 : the g-value for this tile
*/
typedef int32 AyStar_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
/*
* This function is called to calculate the H-value for AyStar Algorithm.
* Mostly, this must result the distance (Manhattan way) between the
* current point and the end point
* return values can be:
* Any value >= 0 : the h-value for this tile
*/
typedef int32 AyStar_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
/*
* This function request the tiles around the current tile and put them in tiles_around
* tiles_around is never resetted, so if you are not using directions, just leave it alone.
* Warning: never add more tiles_around than memory allocated for it.
*/
typedef void AyStar_GetNeighbours(AyStar *aystar, OpenListNode *current);
/*
* If the End Node is found, this function is called.
* It can do, for example, calculate the route and put that in an array
*/
typedef void AyStar_FoundEndNode(AyStar *aystar, OpenListNode *current);
// For internal use, see aystar.c
typedef void AyStar_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g);
typedef int AyStar_Main(AyStar *aystar);
typedef int AyStar_Loop(AyStar *aystar);
typedef int AyStar_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
typedef void AyStar_Free(AyStar *aystar);
typedef void AyStar_Clear(AyStar *aystar);
struct AyStar {
/* These fields should be filled before initting the AyStar, but not changed
* afterwards (except for user_data and user_path)! (free and init again to change them) */
/* These should point to the application specific routines that do the
* actual work */
AyStar_CalculateG *CalculateG;
AyStar_CalculateH *CalculateH;
AyStar_GetNeighbours *GetNeighbours;
AyStar_EndNodeCheck *EndNodeCheck;
AyStar_FoundEndNode *FoundEndNode;
/* These are completely untouched by AyStar, they can be accesed by
* the application specific routines to input and output data.
* user_path should typically contain data about the resulting path
* afterwards, user_target should typically contain information about
* what where looking for, and user_data can contain just about
* everything */
void *user_path;
void *user_target;
uint user_data[10];
/* How many loops are there called before AyStarMain_Main gives
* control back to the caller. 0 = until done */
byte loops_per_tick;
/* If the g-value goes over this number, it stops searching
* 0 = infinite */
uint max_path_cost;
/* The maximum amount of nodes that will be expanded, 0 = infinite */
uint max_search_nodes;
/* These should be filled with the neighbours of a tile by
* GetNeighbours */
AyStarNode neighbours[12];
byte num_neighbours;
/* These will contain the methods for manipulating the AyStar. Only
* main() should be called externally */
AyStar_AddStartNode *addstart;
AyStar_Main *main;
AyStar_Loop *loop;
AyStar_Free *free;
AyStar_Clear *clear;
AyStar_CheckTile *checktile;
/* These will contain the open and closed lists */
/* The actual closed list */
Hash ClosedListHash;
/* The open queue */
Queue OpenListQueue;
/* An extra hash to speed up the process of looking up an element in
* the open list */
Hash OpenListHash;
};
void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g);
int AyStarMain_Main(AyStar *aystar);
int AyStarMain_Loop(AyStar *aystar);
int AyStarMain_CheckTile(AyStar *aystar, AyStarNode *current, OpenListNode *parent);
void AyStarMain_Free(AyStar *aystar);
void AyStarMain_Clear(AyStar *aystar);
/* Initialize an AyStar. You should fill all appropriate fields before
* callling init_AyStar (see the declaration of AyStar for which fields are
* internal */
void init_AyStar(AyStar *aystar, Hash_HashProc hash, uint num_buckets);
#endif /* AYSTAR_H */

View File

@@ -1,2 +0,0 @@
add_subdirectory(ai)
add_subdirectory(game)

View File

@@ -1,41 +0,0 @@
set(AI_COMPAT_SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/compat_0.7.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.0.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.1.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.2.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.3.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.4.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.5.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.6.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.7.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.8.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.9.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.10.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.11.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_12.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_13.nut
)
foreach(AI_COMPAT_SOURCE_FILE IN LISTS AI_COMPAT_SOURCE_FILES)
string(REPLACE "${CMAKE_SOURCE_DIR}/bin/" "" AI_COMPAT_SOURCE_FILE_NAME "${AI_COMPAT_SOURCE_FILE}")
string(CONCAT AI_COMPAT_BINARY_FILE "${CMAKE_BINARY_DIR}/" "${AI_COMPAT_SOURCE_FILE_NAME}")
add_custom_command(OUTPUT ${AI_COMPAT_BINARY_FILE}
COMMAND ${CMAKE_COMMAND} -E copy
${AI_COMPAT_SOURCE_FILE}
${AI_COMPAT_BINARY_FILE}
MAIN_DEPENDENCY ${AI_COMPAT_SOURCE_FILE}
COMMENT "Copying ${AI_COMPAT_SOURCE_FILE_NAME}"
)
list(APPEND AI_COMPAT_BINARY_FILES ${AI_COMPAT_BINARY_FILE})
endforeach()
# Create a new target which copies all compat files
add_custom_target(ai_compat_files
DEPENDS ${AI_COMPAT_BINARY_FILES}
)
add_dependencies(openttd
ai_compat_files
)

View File

@@ -1,394 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("0.7 API compatibility in effect:");
AILog.Info(" - AITown::GetLastMonthProduction's behaviour has slightly changed.");
AILog.Info(" - AISubsidy::GetDestination returns STATION_INVALID for awarded subsidies.");
AILog.Info(" - AISubsidy::GetSource returns STATION_INVALID for awarded subsidies.");
AISign.GetMaxSignID <- function()
{
local list = AISignList();
local max_id = 0;
foreach (id, d in list) {
if (id > max_id) max_id = id;
}
return max_id;
}
AITile.GetHeight <- function(tile)
{
if (!AIMap.IsValidTile(tile)) return -1;
return AITile.GetCornerHeight(tile, AITile.CORNER_N);
}
AIOrder.ChangeOrder <- function(vehicle_id, order_position, order_flags)
{
return AIOrder.SetOrderFlags(vehicle_id, order_position, order_flags);
}
AIWaypoint.WAYPOINT_INVALID <- 0xFFFF;
AISubsidy.SourceIsTown <- function(subsidy_id)
{
if (!AISubsidy.IsValidSubsidy(subsidy_id) || AISubsidy.IsAwarded(subsidy_id)) return false;
return AISubsidy.GetSourceType(subsidy_id) == AISubsidy.SPT_TOWN;
}
AISubsidy.GetSource <- function(subsidy_id)
{
if (!AISubsidy.IsValidSubsidy(subsidy_id)) return AIBaseStation.STATION_INVALID;
if (AISubsidy.IsAwarded(subsidy_id)) {
return AIBaseStation.STATION_INVALID;
}
return AISubsidy.GetSourceIndex(subsidy_id);
}
AISubsidy.DestinationIsTown <- function(subsidy_id)
{
if (!AISubsidy.IsValidSubsidy(subsidy_id) || AISubsidy.IsAwarded(subsidy_id)) return false;
return AISubsidy.GetDestinationType(subsidy_id) == AISubsidy.SPT_TOWN;
}
AISubsidy.GetDestination <- function(subsidy_id)
{
if (!AISubsidy.IsValidSubsidy(subsidy_id)) return AIBaseStation.STATION_INVALID;
if (AISubsidy.IsAwarded(subsidy_id)) {
return AIBaseStation.STATION_INVALID;
}
return AISubsidy.GetDestinationIndex(subsidy_id);
}
AITown.GetMaxProduction <- function(town_id, cargo_id)
{
return AITown.GetLastMonthProduction(town_id, cargo_id);
}
AIRail.RemoveRailWaypoint <- function(tile)
{
return AIRail.RemoveRailWaypointTileRect(tile, tile, true);
}
AIRail.RemoveRailStationTileRect <- function(tile, tile2)
{
return AIRail.RemoveRailStationTileRectangle(tile, tile2, false);
}
AIVehicle.SkipToVehicleOrder <- function(vehicle_id, order_position)
{
return AIOrder.SkipToOrder(vehicle_id, order_position);
}
AIEngine.IsValidEngine <- function(engine_id)
{
return AIEngine.IsBuildable(engine_id);
}
AIEngine._GetName <- AIEngine.GetName;
AIEngine.GetName <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return null;
return AIEngine._GetName(engine_id);
}
AIEngine._GetCargoType <- AIEngine.GetCargoType;
AIEngine.GetCargoType <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return 255;
return AIEngine._GetCargoType(engine_id);
}
AIEngine._CanRefitCargo <- AIEngine.CanRefitCargo;
AIEngine.CanRefitCargo <- function(engine_id, cargo_id)
{
if (!AIEngine.IsBuildable(engine_id)) return false;
return AIEngine._CanRefitCargo(engine_id, cargo_id);
}
AIEngine._CanPullCargo <- AIEngine.CanPullCargo;
AIEngine.CanPullCargo <- function(engine_id, cargo_id)
{
if (!AIEngine.IsBuildable(engine_id)) return false;
return AIEngine._CanPullCargo(engine_id, cargo_id);
}
AIEngine._GetCapacity <- AIEngine.GetCapacity;
AIEngine.GetCapacity <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return -1;
return AIEngine._GetCapacity(engine_id);
}
AIEngine._GetReliability <- AIEngine.GetReliability;
AIEngine.GetReliability <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return -1;
return AIEngine._GetReliability(engine_id);
}
AIEngine._GetMaxSpeed <- AIEngine.GetMaxSpeed;
AIEngine.GetMaxSpeed <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return -1;
return AIEngine._GetMaxSpeed(engine_id);
}
AIEngine._GetPrice <- AIEngine.GetPrice;
AIEngine.GetPrice <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return -1;
return AIEngine._GetPrice(engine_id);
}
AIEngine._GetMaxAge <- AIEngine.GetMaxAge;
AIEngine.GetMaxAge <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return -1;
return AIEngine._GetMaxAge(engine_id);
}
AIEngine._GetRunningCost <- AIEngine.GetRunningCost;
AIEngine.GetRunningCost <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return -1;
return AIEngine._GetRunningCost(engine_id);
}
AIEngine._GetPower <- AIEngine.GetPower;
AIEngine.GetPower <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return -1;
return AIEngine._GetPower(engine_id);
}
AIEngine._GetWeight <- AIEngine.GetWeight;
AIEngine.GetWeight <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return -1;
return AIEngine._GetWeight(engine_id);
}
AIEngine._GetMaxTractiveEffort <- AIEngine.GetMaxTractiveEffort;
AIEngine.GetMaxTractiveEffort <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return -1;
return AIEngine._GetMaxTractiveEffort(engine_id);
}
AIEngine._GetDesignDate <- AIEngine.GetDesignDate;
AIEngine.GetDesignDate <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return -1;
return AIEngine._GetDesignDate(engine_id);
}
AIEngine._GetVehicleType <- AIEngine.GetVehicleType;
AIEngine.GetVehicleType <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return AIVehicle.VT_INVALID;
return AIEngine._GetVehicleType(engine_id);
}
AIEngine._IsWagon <- AIEngine.IsWagon;
AIEngine.IsWagon <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return false;
return AIEngine._IsWagon(engine_id);
}
AIEngine._CanRunOnRail <- AIEngine.CanRunOnRail;
AIEngine.CanRunOnRail <- function(engine_id, track_rail_type)
{
if (!AIEngine.IsBuildable(engine_id)) return false;
return AIEngine._CanRunOnRail(engine_id, track_rail_type);
}
AIEngine._HasPowerOnRail <- AIEngine.HasPowerOnRail;
AIEngine.HasPowerOnRail <- function(engine_id, track_rail_type)
{
if (!AIEngine.IsBuildable(engine_id)) return false;
return AIEngine._HasPowerOnRail(engine_id, track_rail_type);
}
AIEngine._GetRoadType <- AIEngine.GetRoadType;
AIEngine.GetRoadType <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return AIRoad.ROADTYPE_INVALID;
return AIEngine._GetRoadType(engine_id);
}
AIEngine._GetRailType <- AIEngine.GetRailType;
AIEngine.GetRailType <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return AIRail.RAILTYPE_INVALID;
return AIEngine._GetRailType(engine_id);
}
AIEngine._IsArticulated <- AIEngine.IsArticulated;
AIEngine.IsArticulated <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return false;
return AIEngine._IsArticulated(engine_id);
}
AIEngine._GetPlaneType <- AIEngine.GetPlaneType;
AIEngine.GetPlaneType <- function(engine_id)
{
if (!AIEngine.IsBuildable(engine_id)) return -1;
return AIEngine._GetPlaneType(engine_id);
}
_AIWaypointList <- AIWaypointList;
class AIWaypointList extends _AIWaypointList {
constructor()
{
::_AIWaypointList.constructor(AIWaypoint.WAYPOINT_RAIL);
}
}
AIRoad._BuildRoadStation <- AIRoad.BuildRoadStation;
AIRoad.BuildRoadStation <- function(tile, front, road_veh_type, station_id)
{
if (AIRoad.IsRoadStationTile(tile) && AICompany.IsMine(AITile.GetOwner(tile))) return false;
return AIRoad._BuildRoadStation(tile, front, road_veh_type, station_id);
}
AIRoad._BuildDriveThroughRoadStation <- AIRoad.BuildDriveThroughRoadStation;
AIRoad.BuildDriveThroughRoadStation <- function(tile, front, road_veh_type, station_id)
{
if (AIRoad.IsRoadStationTile(tile) && AICompany.IsMine(AITile.GetOwner(tile))) return false;
return AIRoad._BuildDriveThroughRoadStation(tile, front, road_veh_type, station_id);
}
AIBridgeList.HasNext <-
AIBridgeList_Length.HasNext <-
AICargoList.HasNext <-
AICargoList_IndustryAccepting.HasNext <-
AICargoList_IndustryProducing.HasNext <-
AIDepotList.HasNext <-
AIEngineList.HasNext <-
AIGroupList.HasNext <-
AIIndustryList.HasNext <-
AIIndustryList_CargoAccepting.HasNext <-
AIIndustryList_CargoProducing.HasNext <-
AIIndustryTypeList.HasNext <-
AIList.HasNext <-
AIRailTypeList.HasNext <-
AISignList.HasNext <-
AIStationList.HasNext <-
AIStationList_Vehicle.HasNext <-
AISubsidyList.HasNext <-
AITileList.HasNext <-
AITileList_IndustryAccepting.HasNext <-
AITileList_IndustryProducing.HasNext <-
AITileList_StationType.HasNext <-
AITownList.HasNext <-
AIVehicleList.HasNext <-
AIVehicleList_DefaultGroup.HasNext <-
AIVehicleList_Group.HasNext <-
AIVehicleList_SharedOrders.HasNext <-
AIVehicleList_Station.HasNext <-
AIWaypointList.HasNext <-
AIWaypointList_Vehicle.HasNext <-
function()
{
return !this.IsEnd();
}
AIIndustry._IsCargoAccepted <- AIIndustry.IsCargoAccepted;
AIIndustry.IsCargoAccepted <- function(industry_id, cargo_id)
{
return AIIndustry._IsCargoAccepted(industry_id, cargo_id) != AIIndustry.CAS_NOT_ACCEPTED;
}
AIAbstractList <- AIList;
AIList.ChangeItem <- AIList.SetValue;
AIRail.ERR_NONUNIFORM_STATIONS_DISABLED <- 0xFFFF;
AICompany.GetCompanyValue <- function(company)
{
return AICompany.GetQuarterlyCompanyValue(company, AICompany.CURRENT_QUARTER);
}
AITown.GetLastMonthTransported <- AITown.GetLastMonthSupplied;
AIEvent.AI_ET_INVALID <- AIEvent.ET_INVALID;
AIEvent.AI_ET_TEST <- AIEvent.ET_TEST;
AIEvent.AI_ET_SUBSIDY_OFFER <- AIEvent.ET_SUBSIDY_OFFER;
AIEvent.AI_ET_SUBSIDY_OFFER_EXPIRED <- AIEvent.ET_SUBSIDY_OFFER_EXPIRED;
AIEvent.AI_ET_SUBSIDY_AWARDED <- AIEvent.ET_SUBSIDY_AWARDED;
AIEvent.AI_ET_SUBSIDY_EXPIRED <- AIEvent.ET_SUBSIDY_EXPIRED;
AIEvent.AI_ET_ENGINE_PREVIEW <- AIEvent.ET_ENGINE_PREVIEW;
AIEvent.AI_ET_COMPANY_NEW <- AIEvent.ET_COMPANY_NEW;
AIEvent.AI_ET_COMPANY_IN_TROUBLE <- AIEvent.ET_COMPANY_IN_TROUBLE;
AIEvent.AI_ET_COMPANY_MERGER <- AIEvent.ET_COMPANY_MERGER;
AIEvent.AI_ET_COMPANY_BANKRUPT <- AIEvent.ET_COMPANY_BANKRUPT;
AIEvent.AI_ET_VEHICLE_CRASHED <- AIEvent.ET_VEHICLE_CRASHED;
AIEvent.AI_ET_VEHICLE_LOST <- AIEvent.ET_VEHICLE_LOST;
AIEvent.AI_ET_VEHICLE_WAITING_IN_DEPOT <- AIEvent.ET_VEHICLE_WAITING_IN_DEPOT;
AIEvent.AI_ET_VEHICLE_UNPROFITABLE <- AIEvent.ET_VEHICLE_UNPROFITABLE;
AIEvent.AI_ET_INDUSTRY_OPEN <- AIEvent.ET_INDUSTRY_OPEN;
AIEvent.AI_ET_INDUSTRY_CLOSE <- AIEvent.ET_INDUSTRY_CLOSE;
AIEvent.AI_ET_ENGINE_AVAILABLE <- AIEvent.ET_ENGINE_AVAILABLE;
AIEvent.AI_ET_STATION_FIRST_VEHICLE <- AIEvent.ET_STATION_FIRST_VEHICLE;
AIEvent.AI_ET_DISASTER_ZEPPELINER_CRASHED <- AIEvent.ET_DISASTER_ZEPPELINER_CRASHED;
AIEvent.AI_ET_DISASTER_ZEPPELINER_CLEARED <- AIEvent.ET_DISASTER_ZEPPELINER_CLEARED;
AIOrder.AIOF_NONE <- AIOrder.OF_NONE
AIOrder.AIOF_NON_STOP_INTERMEDIATE <- AIOrder.OF_NON_STOP_INTERMEDIATE
AIOrder.AIOF_NON_STOP_DESTINATION <- AIOrder.OF_NON_STOP_DESTINATION
AIOrder.AIOF_UNLOAD <- AIOrder.OF_UNLOAD
AIOrder.AIOF_TRANSFER <- AIOrder.OF_TRANSFER
AIOrder.AIOF_NO_UNLOAD <- AIOrder.OF_NO_UNLOAD
AIOrder.AIOF_FULL_LOAD <- AIOrder.OF_FULL_LOAD
AIOrder.AIOF_FULL_LOAD_ANY <- AIOrder.OF_FULL_LOAD_ANY
AIOrder.AIOF_NO_LOAD <- AIOrder.OF_NO_LOAD
AIOrder.AIOF_SERVICE_IF_NEEDED <- AIOrder.OF_SERVICE_IF_NEEDED
AIOrder.AIOF_STOP_IN_DEPOT <- AIOrder.OF_STOP_IN_DEPOT
AIOrder.AIOF_GOTO_NEAREST_DEPOT <- AIOrder.OF_GOTO_NEAREST_DEPOT
AIOrder.AIOF_NON_STOP_FLAGS <- AIOrder.OF_NON_STOP_FLAGS
AIOrder.AIOF_UNLOAD_FLAGS <- AIOrder.OF_UNLOAD_FLAGS
AIOrder.AIOF_LOAD_FLAGS <- AIOrder.OF_LOAD_FLAGS
AIOrder.AIOF_DEPOT_FLAGS <- AIOrder.OF_DEPOT_FLAGS
AIOrder.AIOF_INVALID <- AIOrder.OF_INVALID
/* 1.9 adds a vehicle type parameter. */
AIBridge._GetName <- AIBridge.GetName;
AIBridge.GetName <- function(bridge_id)
{
return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL);
}
/* 1.9 adds parent_group_id to CreateGroup function */
AIGroup._CreateGroup <- AIGroup.CreateGroup;
AIGroup.CreateGroup <- function(vehicle_type)
{
return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID);
}
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,146 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("1.0 API compatibility in effect.");
AIRoad._BuildRoadStation <- AIRoad.BuildRoadStation;
AIRoad.BuildRoadStation <- function(tile, front, road_veh_type, station_id)
{
if (AIRoad.IsRoadStationTile(tile) && AICompany.IsMine(AITile.GetOwner(tile))) return false;
return AIRoad._BuildRoadStation(tile, front, road_veh_type, station_id);
}
AIRoad._BuildDriveThroughRoadStation <- AIRoad.BuildDriveThroughRoadStation;
AIRoad.BuildDriveThroughRoadStation <- function(tile, front, road_veh_type, station_id)
{
if (AIRoad.IsRoadStationTile(tile) && AICompany.IsMine(AITile.GetOwner(tile))) return false;
return AIRoad._BuildDriveThroughRoadStation(tile, front, road_veh_type, station_id);
}
AIBridgeList.HasNext <-
AIBridgeList_Length.HasNext <-
AICargoList.HasNext <-
AICargoList_IndustryAccepting.HasNext <-
AICargoList_IndustryProducing.HasNext <-
AIDepotList.HasNext <-
AIEngineList.HasNext <-
AIGroupList.HasNext <-
AIIndustryList.HasNext <-
AIIndustryList_CargoAccepting.HasNext <-
AIIndustryList_CargoProducing.HasNext <-
AIIndustryTypeList.HasNext <-
AIList.HasNext <-
AIRailTypeList.HasNext <-
AISignList.HasNext <-
AIStationList.HasNext <-
AIStationList_Vehicle.HasNext <-
AISubsidyList.HasNext <-
AITileList.HasNext <-
AITileList_IndustryAccepting.HasNext <-
AITileList_IndustryProducing.HasNext <-
AITileList_StationType.HasNext <-
AITownList.HasNext <-
AIVehicleList.HasNext <-
AIVehicleList_DefaultGroup.HasNext <-
AIVehicleList_Depot.HasNext <-
AIVehicleList_Group.HasNext <-
AIVehicleList_SharedOrders.HasNext <-
AIVehicleList_Station.HasNext <-
AIWaypointList.HasNext <-
AIWaypointList_Vehicle.HasNext <-
function()
{
return !this.IsEnd();
}
AIIndustry._IsCargoAccepted <- AIIndustry.IsCargoAccepted;
AIIndustry.IsCargoAccepted <- function(industry_id, cargo_id)
{
return AIIndustry._IsCargoAccepted(industry_id, cargo_id) != AIIndustry.CAS_NOT_ACCEPTED;
}
AIAbstractList <- AIList;
AIList.ChangeItem <- AIList.SetValue;
AIRail.ERR_NONUNIFORM_STATIONS_DISABLED <- 0xFFFF;
AICompany.GetCompanyValue <- function(company)
{
return AICompany.GetQuarterlyCompanyValue(company, AICompany.CURRENT_QUARTER);
}
AITown.GetLastMonthTransported <- AITown.GetLastMonthSupplied;
AIEvent.AI_ET_INVALID <- AIEvent.ET_INVALID;
AIEvent.AI_ET_TEST <- AIEvent.ET_TEST;
AIEvent.AI_ET_SUBSIDY_OFFER <- AIEvent.ET_SUBSIDY_OFFER;
AIEvent.AI_ET_SUBSIDY_OFFER_EXPIRED <- AIEvent.ET_SUBSIDY_OFFER_EXPIRED;
AIEvent.AI_ET_SUBSIDY_AWARDED <- AIEvent.ET_SUBSIDY_AWARDED;
AIEvent.AI_ET_SUBSIDY_EXPIRED <- AIEvent.ET_SUBSIDY_EXPIRED;
AIEvent.AI_ET_ENGINE_PREVIEW <- AIEvent.ET_ENGINE_PREVIEW;
AIEvent.AI_ET_COMPANY_NEW <- AIEvent.ET_COMPANY_NEW;
AIEvent.AI_ET_COMPANY_IN_TROUBLE <- AIEvent.ET_COMPANY_IN_TROUBLE;
AIEvent.AI_ET_COMPANY_ASK_MERGER <- AIEvent.ET_COMPANY_ASK_MERGER;
AIEvent.AI_ET_COMPANY_MERGER <- AIEvent.ET_COMPANY_MERGER;
AIEvent.AI_ET_COMPANY_BANKRUPT <- AIEvent.ET_COMPANY_BANKRUPT;
AIEvent.AI_ET_VEHICLE_CRASHED <- AIEvent.ET_VEHICLE_CRASHED;
AIEvent.AI_ET_VEHICLE_LOST <- AIEvent.ET_VEHICLE_LOST;
AIEvent.AI_ET_VEHICLE_WAITING_IN_DEPOT <- AIEvent.ET_VEHICLE_WAITING_IN_DEPOT;
AIEvent.AI_ET_VEHICLE_UNPROFITABLE <- AIEvent.ET_VEHICLE_UNPROFITABLE;
AIEvent.AI_ET_INDUSTRY_OPEN <- AIEvent.ET_INDUSTRY_OPEN;
AIEvent.AI_ET_INDUSTRY_CLOSE <- AIEvent.ET_INDUSTRY_CLOSE;
AIEvent.AI_ET_ENGINE_AVAILABLE <- AIEvent.ET_ENGINE_AVAILABLE;
AIEvent.AI_ET_STATION_FIRST_VEHICLE <- AIEvent.ET_STATION_FIRST_VEHICLE;
AIEvent.AI_ET_DISASTER_ZEPPELINER_CRASHED <- AIEvent.ET_DISASTER_ZEPPELINER_CRASHED;
AIEvent.AI_ET_DISASTER_ZEPPELINER_CLEARED <- AIEvent.ET_DISASTER_ZEPPELINER_CLEARED;
AIOrder.AIOF_NONE <- AIOrder.OF_NONE
AIOrder.AIOF_NON_STOP_INTERMEDIATE <- AIOrder.OF_NON_STOP_INTERMEDIATE
AIOrder.AIOF_NON_STOP_DESTINATION <- AIOrder.OF_NON_STOP_DESTINATION
AIOrder.AIOF_UNLOAD <- AIOrder.OF_UNLOAD
AIOrder.AIOF_TRANSFER <- AIOrder.OF_TRANSFER
AIOrder.AIOF_NO_UNLOAD <- AIOrder.OF_NO_UNLOAD
AIOrder.AIOF_FULL_LOAD <- AIOrder.OF_FULL_LOAD
AIOrder.AIOF_FULL_LOAD_ANY <- AIOrder.OF_FULL_LOAD_ANY
AIOrder.AIOF_NO_LOAD <- AIOrder.OF_NO_LOAD
AIOrder.AIOF_SERVICE_IF_NEEDED <- AIOrder.OF_SERVICE_IF_NEEDED
AIOrder.AIOF_STOP_IN_DEPOT <- AIOrder.OF_STOP_IN_DEPOT
AIOrder.AIOF_GOTO_NEAREST_DEPOT <- AIOrder.OF_GOTO_NEAREST_DEPOT
AIOrder.AIOF_NON_STOP_FLAGS <- AIOrder.OF_NON_STOP_FLAGS
AIOrder.AIOF_UNLOAD_FLAGS <- AIOrder.OF_UNLOAD_FLAGS
AIOrder.AIOF_LOAD_FLAGS <- AIOrder.OF_LOAD_FLAGS
AIOrder.AIOF_DEPOT_FLAGS <- AIOrder.OF_DEPOT_FLAGS
AIOrder.AIOF_INVALID <- AIOrder.OF_INVALID
/* 1.9 adds a vehicle type parameter. */
AIBridge._GetName <- AIBridge.GetName;
AIBridge.GetName <- function(bridge_id)
{
return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL);
}
/* 1.9 adds parent_group_id to CreateGroup function */
AIGroup._CreateGroup <- AIGroup.CreateGroup;
AIGroup.CreateGroup <- function(vehicle_type)
{
return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID);
}
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,83 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("1.1 API compatibility in effect.");
AICompany.GetCompanyValue <- function(company)
{
return AICompany.GetQuarterlyCompanyValue(company, AICompany.CURRENT_QUARTER);
}
AITown.GetLastMonthTransported <- AITown.GetLastMonthSupplied;
AIEvent.AI_ET_INVALID <- AIEvent.ET_INVALID;
AIEvent.AI_ET_TEST <- AIEvent.ET_TEST;
AIEvent.AI_ET_SUBSIDY_OFFER <- AIEvent.ET_SUBSIDY_OFFER;
AIEvent.AI_ET_SUBSIDY_OFFER_EXPIRED <- AIEvent.ET_SUBSIDY_OFFER_EXPIRED;
AIEvent.AI_ET_SUBSIDY_AWARDED <- AIEvent.ET_SUBSIDY_AWARDED;
AIEvent.AI_ET_SUBSIDY_EXPIRED <- AIEvent.ET_SUBSIDY_EXPIRED;
AIEvent.AI_ET_ENGINE_PREVIEW <- AIEvent.ET_ENGINE_PREVIEW;
AIEvent.AI_ET_COMPANY_NEW <- AIEvent.ET_COMPANY_NEW;
AIEvent.AI_ET_COMPANY_IN_TROUBLE <- AIEvent.ET_COMPANY_IN_TROUBLE;
AIEvent.AI_ET_COMPANY_ASK_MERGER <- AIEvent.ET_COMPANY_ASK_MERGER;
AIEvent.AI_ET_COMPANY_MERGER <- AIEvent.ET_COMPANY_MERGER;
AIEvent.AI_ET_COMPANY_BANKRUPT <- AIEvent.ET_COMPANY_BANKRUPT;
AIEvent.AI_ET_VEHICLE_CRASHED <- AIEvent.ET_VEHICLE_CRASHED;
AIEvent.AI_ET_VEHICLE_LOST <- AIEvent.ET_VEHICLE_LOST;
AIEvent.AI_ET_VEHICLE_WAITING_IN_DEPOT <- AIEvent.ET_VEHICLE_WAITING_IN_DEPOT;
AIEvent.AI_ET_VEHICLE_UNPROFITABLE <- AIEvent.ET_VEHICLE_UNPROFITABLE;
AIEvent.AI_ET_INDUSTRY_OPEN <- AIEvent.ET_INDUSTRY_OPEN;
AIEvent.AI_ET_INDUSTRY_CLOSE <- AIEvent.ET_INDUSTRY_CLOSE;
AIEvent.AI_ET_ENGINE_AVAILABLE <- AIEvent.ET_ENGINE_AVAILABLE;
AIEvent.AI_ET_STATION_FIRST_VEHICLE <- AIEvent.ET_STATION_FIRST_VEHICLE;
AIEvent.AI_ET_DISASTER_ZEPPELINER_CRASHED <- AIEvent.ET_DISASTER_ZEPPELINER_CRASHED;
AIEvent.AI_ET_DISASTER_ZEPPELINER_CLEARED <- AIEvent.ET_DISASTER_ZEPPELINER_CLEARED;
AIEvent.AI_ET_TOWN_FOUNDED <- AIEvent.ET_TOWN_FOUNDED;
AIOrder.AIOF_NONE <- AIOrder.OF_NONE
AIOrder.AIOF_NON_STOP_INTERMEDIATE <- AIOrder.OF_NON_STOP_INTERMEDIATE
AIOrder.AIOF_NON_STOP_DESTINATION <- AIOrder.OF_NON_STOP_DESTINATION
AIOrder.AIOF_UNLOAD <- AIOrder.OF_UNLOAD
AIOrder.AIOF_TRANSFER <- AIOrder.OF_TRANSFER
AIOrder.AIOF_NO_UNLOAD <- AIOrder.OF_NO_UNLOAD
AIOrder.AIOF_FULL_LOAD <- AIOrder.OF_FULL_LOAD
AIOrder.AIOF_FULL_LOAD_ANY <- AIOrder.OF_FULL_LOAD_ANY
AIOrder.AIOF_NO_LOAD <- AIOrder.OF_NO_LOAD
AIOrder.AIOF_SERVICE_IF_NEEDED <- AIOrder.OF_SERVICE_IF_NEEDED
AIOrder.AIOF_STOP_IN_DEPOT <- AIOrder.OF_STOP_IN_DEPOT
AIOrder.AIOF_GOTO_NEAREST_DEPOT <- AIOrder.OF_GOTO_NEAREST_DEPOT
AIOrder.AIOF_NON_STOP_FLAGS <- AIOrder.OF_NON_STOP_FLAGS
AIOrder.AIOF_UNLOAD_FLAGS <- AIOrder.OF_UNLOAD_FLAGS
AIOrder.AIOF_LOAD_FLAGS <- AIOrder.OF_LOAD_FLAGS
AIOrder.AIOF_DEPOT_FLAGS <- AIOrder.OF_DEPOT_FLAGS
AIOrder.AIOF_INVALID <- AIOrder.OF_INVALID
/* 1.9 adds a vehicle type parameter. */
AIBridge._GetName <- AIBridge.GetName;
AIBridge.GetName <- function(bridge_id)
{
return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL);
}
/* 1.9 adds parent_group_id to CreateGroup function */
AIGroup._CreateGroup <- AIGroup.CreateGroup;
AIGroup.CreateGroup <- function(vehicle_type)
{
return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID);
}
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,21 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("1.10 API compatibility in effect.");
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,21 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("1.11 API compatibility in effect.");
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,35 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("1.2 API compatibility in effect.");
/* 1.9 adds a vehicle type parameter. */
AIBridge._GetName <- AIBridge.GetName;
AIBridge.GetName <- function(bridge_id)
{
return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL);
}
/* 1.9 adds parent_group_id to CreateGroup function */
AIGroup._CreateGroup <- AIGroup.CreateGroup;
AIGroup.CreateGroup <- function(vehicle_type)
{
return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID);
}
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,35 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("1.3 API compatibility in effect.");
/* 1.9 adds a vehicle type parameter. */
AIBridge._GetName <- AIBridge.GetName;
AIBridge.GetName <- function(bridge_id)
{
return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL);
}
/* 1.9 adds parent_group_id to CreateGroup function */
AIGroup._CreateGroup <- AIGroup.CreateGroup;
AIGroup.CreateGroup <- function(vehicle_type)
{
return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID);
}
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,35 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("1.4 API compatibility in effect.");
/* 1.9 adds a vehicle type parameter. */
AIBridge._GetName <- AIBridge.GetName;
AIBridge.GetName <- function(bridge_id)
{
return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL);
}
/* 1.9 adds parent_group_id to CreateGroup function */
AIGroup._CreateGroup <- AIGroup.CreateGroup;
AIGroup.CreateGroup <- function(vehicle_type)
{
return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID);
}
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,35 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("1.5 API compatibility in effect.");
/* 1.9 adds a vehicle type parameter. */
AIBridge._GetName <- AIBridge.GetName;
AIBridge.GetName <- function(bridge_id)
{
return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL);
}
/* 1.9 adds parent_group_id to CreateGroup function */
AIGroup._CreateGroup <- AIGroup.CreateGroup;
AIGroup.CreateGroup <- function(vehicle_type)
{
return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID);
}
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,35 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("1.6 API compatibility in effect.");
/* 1.9 adds a vehicle type parameter. */
AIBridge._GetName <- AIBridge.GetName;
AIBridge.GetName <- function(bridge_id)
{
return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL);
}
/* 1.9 adds parent_group_id to CreateGroup function */
AIGroup._CreateGroup <- AIGroup.CreateGroup;
AIGroup.CreateGroup <- function(vehicle_type)
{
return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID);
}
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,35 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("1.7 API compatibility in effect.");
/* 1.9 adds a vehicle type parameter. */
AIBridge._GetName <- AIBridge.GetName;
AIBridge.GetName <- function(bridge_id)
{
return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL);
}
/* 1.9 adds parent_group_id to CreateGroup function */
AIGroup._CreateGroup <- AIGroup.CreateGroup;
AIGroup.CreateGroup <- function(vehicle_type)
{
return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID);
}
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,35 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("1.8 API compatibility in effect.");
/* 1.9 adds a vehicle type parameter. */
AIBridge._GetName <- AIBridge.GetName;
AIBridge.GetName <- function(bridge_id)
{
return AIBridge._GetName(bridge_id, AIVehicle.VT_RAIL);
}
/* 1.9 adds parent_group_id to CreateGroup function */
AIGroup._CreateGroup <- AIGroup.CreateGroup;
AIGroup.CreateGroup <- function(vehicle_type)
{
return AIGroup._CreateGroup(vehicle_type, AIGroup.GROUP_INVALID);
}
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,21 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("1.9 API compatibility in effect.");
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,21 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
AILog.Info("12 API compatibility in effect.");
/* 13 really checks RoadType against RoadType */
AIRoad._HasRoadType <- AIRoad.HasRoadType;
AIRoad.HasRoadType <- function(tile, road_type)
{
local list = AIRoadTypeList(AIRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (AIRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,6 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/

View File

@@ -1,38 +0,0 @@
set(GS_COMPAT_SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.2.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.3.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.4.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.5.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.6.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.7.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.8.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.9.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.10.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_1.11.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_12.nut
${CMAKE_CURRENT_SOURCE_DIR}/compat_13.nut
)
foreach(GS_COMPAT_SOURCE_FILE IN LISTS GS_COMPAT_SOURCE_FILES)
string(REPLACE "${CMAKE_SOURCE_DIR}/bin/" "" GS_COMPAT_SOURCE_FILE_NAME "${GS_COMPAT_SOURCE_FILE}")
string(CONCAT GS_COMPAT_BINARY_FILE "${CMAKE_BINARY_DIR}/" "${GS_COMPAT_SOURCE_FILE_NAME}")
add_custom_command(OUTPUT ${GS_COMPAT_BINARY_FILE}
COMMAND ${CMAKE_COMMAND} -E copy
${GS_COMPAT_SOURCE_FILE}
${GS_COMPAT_BINARY_FILE}
MAIN_DEPENDENCY ${GS_COMPAT_SOURCE_FILE}
COMMENT "Copying ${GS_COMPAT_SOURCE_FILE_NAME}"
)
list(APPEND GS_COMPAT_BINARY_FILES ${GS_COMPAT_BINARY_FILE})
endforeach()
# Create a new target which copies all compat files
add_custom_target(gs_compat_files
DEPENDS ${GS_COMPAT_BINARY_FILES}
)
add_dependencies(openttd
gs_compat_files
)

View File

@@ -1,28 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
GSLog.Info("1.10 API compatibility in effect.");
/* 1.11 adds a tile parameter. */
GSCompany._ChangeBankBalance <- GSCompany.ChangeBankBalance;
GSCompany.ChangeBankBalance <- function(company, delta, expenses_type)
{
return GSCompany._ChangeBankBalance(company, delta, expenses_type, GSMap.TILE_INVALID);
}
/* 13 really checks RoadType against RoadType */
GSRoad._HasRoadType <- GSRoad.HasRoadType;
GSRoad.HasRoadType <- function(tile, road_type)
{
local list = GSRoadTypeList(GSRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (GSRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,21 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
GSLog.Info("1.11 API compatibility in effect.");
/* 13 really checks RoadType against RoadType */
GSRoad._HasRoadType <- GSRoad.HasRoadType;
GSRoad.HasRoadType <- function(tile, road_type)
{
local list = GSRoadTypeList(GSRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (GSRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,50 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
GSLog.Info("1.2 API compatibility in effect.");
GSTown._SetGrowthRate <- GSTown.SetGrowthRate;
GSTown.SetGrowthRate <- function(town_id, days_between_town_growth)
{
/* Growth rate 0 caused resetting the custom growth rate. While this was undocumented, it was used nevertheless (ofc). */
if (days_between_town_growth == 0) days_between_town_growth = GSTown.TOWN_GROWTH_NORMAL;
return GSTown._SetGrowthRate(town_id, days_between_town_growth);
}
/* 1.5 adds a game element reference to the news. */
GSNews._Create <- GSNews.Create;
GSNews.Create <- function(type, text, company)
{
return GSNews._Create(type, text, company, GSNews.NR_NONE, 0);
}
/* 1.9 adds a vehicle type parameter. */
GSBridge._GetName <- GSBridge.GetName;
GSBridge.GetName <- function(bridge_id)
{
return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL);
}
/* 1.11 adds a tile parameter. */
GSCompany._ChangeBankBalance <- GSCompany.ChangeBankBalance;
GSCompany.ChangeBankBalance <- function(company, delta, expenses_type)
{
return GSCompany._ChangeBankBalance(company, delta, expenses_type, GSMap.TILE_INVALID);
}
/* 13 really checks RoadType against RoadType */
GSRoad._HasRoadType <- GSRoad.HasRoadType;
GSRoad.HasRoadType <- function(tile, road_type)
{
local list = GSRoadTypeList(GSRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (GSRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,50 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
GSLog.Info("1.3 API compatibility in effect.");
GSTown._SetGrowthRate <- GSTown.SetGrowthRate;
GSTown.SetGrowthRate <- function(town_id, days_between_town_growth)
{
/* Growth rate 0 caused resetting the custom growth rate. While this was undocumented, it was used nevertheless (ofc). */
if (days_between_town_growth == 0) days_between_town_growth = GSTown.TOWN_GROWTH_NORMAL;
return GSTown._SetGrowthRate(town_id, days_between_town_growth);
}
/* 1.5 adds a game element reference to the news. */
GSNews._Create <- GSNews.Create;
GSNews.Create <- function(type, text, company)
{
return GSNews._Create(type, text, company, GSNews.NR_NONE, 0);
}
/* 1.9 adds a vehicle type parameter. */
GSBridge._GetName <- GSBridge.GetName;
GSBridge.GetName <- function(bridge_id)
{
return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL);
}
/* 1.11 adds a tile parameter. */
GSCompany._ChangeBankBalance <- GSCompany.ChangeBankBalance;
GSCompany.ChangeBankBalance <- function(company, delta, expenses_type)
{
return GSCompany._ChangeBankBalance(company, delta, expenses_type, GSMap.TILE_INVALID);
}
/* 13 really checks RoadType against RoadType */
GSRoad._HasRoadType <- GSRoad.HasRoadType;
GSRoad.HasRoadType <- function(tile, road_type)
{
local list = GSRoadTypeList(GSRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (GSRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,42 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
GSLog.Info("1.4 API compatibility in effect.");
/* 1.5 adds a game element reference to the news. */
GSNews._Create <- GSNews.Create;
GSNews.Create <- function(type, text, company)
{
return GSNews._Create(type, text, company, GSNews.NR_NONE, 0);
}
/* 1.9 adds a vehicle type parameter. */
GSBridge._GetName <- GSBridge.GetName;
GSBridge.GetName <- function(bridge_id)
{
return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL);
}
/* 1.11 adds a tile parameter. */
GSCompany._ChangeBankBalance <- GSCompany.ChangeBankBalance;
GSCompany.ChangeBankBalance <- function(company, delta, expenses_type)
{
return GSCompany._ChangeBankBalance(company, delta, expenses_type, GSMap.TILE_INVALID);
}
/* 13 really checks RoadType against RoadType */
GSRoad._HasRoadType <- GSRoad.HasRoadType;
GSRoad.HasRoadType <- function(tile, road_type)
{
local list = GSRoadTypeList(GSRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (GSRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,35 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
GSLog.Info("1.5 API compatibility in effect.");
/* 1.9 adds a vehicle type parameter. */
GSBridge._GetName <- GSBridge.GetName;
GSBridge.GetName <- function(bridge_id)
{
return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL);
}
/* 1.11 adds a tile parameter. */
GSCompany._ChangeBankBalance <- GSCompany.ChangeBankBalance;
GSCompany.ChangeBankBalance <- function(company, delta, expenses_type)
{
return GSCompany._ChangeBankBalance(company, delta, expenses_type, GSMap.TILE_INVALID);
}
/* 13 really checks RoadType against RoadType */
GSRoad._HasRoadType <- GSRoad.HasRoadType;
GSRoad.HasRoadType <- function(tile, road_type)
{
local list = GSRoadTypeList(GSRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (GSRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,35 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
GSLog.Info("1.6 API compatibility in effect.");
/* 1.9 adds a vehicle type parameter. */
GSBridge._GetName <- GSBridge.GetName;
GSBridge.GetName <- function(bridge_id)
{
return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL);
}
/* 1.11 adds a tile parameter. */
GSCompany._ChangeBankBalance <- GSCompany.ChangeBankBalance;
GSCompany.ChangeBankBalance <- function(company, delta, expenses_type)
{
return GSCompany._ChangeBankBalance(company, delta, expenses_type, GSMap.TILE_INVALID);
}
/* 13 really checks RoadType against RoadType */
GSRoad._HasRoadType <- GSRoad.HasRoadType;
GSRoad.HasRoadType <- function(tile, road_type)
{
local list = GSRoadTypeList(GSRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (GSRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,35 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
GSLog.Info("1.7 API compatibility in effect.");
/* 1.9 adds a vehicle type parameter. */
GSBridge._GetName <- GSBridge.GetName;
GSBridge.GetName <- function(bridge_id)
{
return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL);
}
/* 1.11 adds a tile parameter. */
GSCompany._ChangeBankBalance <- GSCompany.ChangeBankBalance;
GSCompany.ChangeBankBalance <- function(company, delta, expenses_type)
{
return GSCompany._ChangeBankBalance(company, delta, expenses_type, GSMap.TILE_INVALID);
}
/* 13 really checks RoadType against RoadType */
GSRoad._HasRoadType <- GSRoad.HasRoadType;
GSRoad.HasRoadType <- function(tile, road_type)
{
local list = GSRoadTypeList(GSRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (GSRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,35 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
GSLog.Info("1.8 API compatibility in effect.");
/* 1.9 adds a vehicle type parameter. */
GSBridge._GetName <- GSBridge.GetName;
GSBridge.GetName <- function(bridge_id)
{
return GSBridge._GetName(bridge_id, GSVehicle.VT_RAIL);
}
/* 1.11 adds a tile parameter. */
GSCompany._ChangeBankBalance <- GSCompany.ChangeBankBalance;
GSCompany.ChangeBankBalance <- function(company, delta, expenses_type)
{
return GSCompany._ChangeBankBalance(company, delta, expenses_type, GSMap.TILE_INVALID);
}
/* 13 really checks RoadType against RoadType */
GSRoad._HasRoadType <- GSRoad.HasRoadType;
GSRoad.HasRoadType <- function(tile, road_type)
{
local list = GSRoadTypeList(GSRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (GSRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,28 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
GSLog.Info("1.9 API compatibility in effect.");
/* 1.11 adds a tile parameter. */
GSCompany._ChangeBankBalance <- GSCompany.ChangeBankBalance;
GSCompany.ChangeBankBalance <- function(company, delta, expenses_type)
{
return GSCompany._ChangeBankBalance(company, delta, expenses_type, GSMap.TILE_INVALID);
}
/* 13 really checks RoadType against RoadType */
GSRoad._HasRoadType <- GSRoad.HasRoadType;
GSRoad.HasRoadType <- function(tile, road_type)
{
local list = GSRoadTypeList(GSRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (GSRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,21 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
GSLog.Info("12 API compatibility in effect.");
/* 13 really checks RoadType against RoadType */
GSRoad._HasRoadType <- GSRoad.HasRoadType;
GSRoad.HasRoadType <- function(tile, road_type)
{
local list = GSRoadTypeList(GSRoad.GetRoadTramType(road_type));
foreach (rt, _ in list) {
if (GSRoad._HasRoadType(tile, rt)) {
return true;
}
}
return false;
}

View File

@@ -1,6 +0,0 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/

View File

@@ -1,2 +0,0 @@
start_ai MyAI

View File

@@ -1,2 +0,0 @@
# Show a MOTD
say "Welcome..."

View File

@@ -1,22 +1,12 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file bmp.cpp Read and write support for bmps. */
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "gfx.h"
#include "bmp.h"
#include "core/bitmath_func.hpp"
#include "core/alloc_func.hpp"
#include "core/mem_func.hpp"
#include "macros.h"
#include "safeguards.h"
void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file)
{
void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file) {
buffer->pos = -1;
buffer->file = file;
buffer->read = 0;
@@ -25,24 +15,18 @@ void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file)
static inline void AdvanceBuffer(BmpBuffer *buffer)
{
if (buffer->read < 0) return;
buffer->read = (int)fread(buffer->data, 1, BMP_BUFFER_SIZE, buffer->file);
buffer->pos = 0;
}
static inline bool EndOfBuffer(BmpBuffer *buffer)
{
if (buffer->read < 0) return false;
if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
return buffer->pos == buffer->read;
}
static inline byte ReadByte(BmpBuffer *buffer)
{
if (buffer->read < 0) return 0;
if (buffer->pos == buffer->read || buffer->pos < 0) AdvanceBuffer(buffer);
buffer->real_pos++;
return buffer->data[buffer->pos++];
@@ -68,9 +52,7 @@ static inline void SkipBytes(BmpBuffer *buffer, int bytes)
static inline void SetStreamOffset(BmpBuffer *buffer, int offset)
{
if (fseek(buffer->file, offset, SEEK_SET) < 0) {
buffer->read = -1;
}
fseek(buffer->file, offset, SEEK_SET);
buffer->pos = -1;
buffer->real_pos = offset;
AdvanceBuffer(buffer);
@@ -138,63 +120,53 @@ static inline bool BmpRead4(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
*/
static inline bool BmpRead4Rle(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
{
uint i;
uint x = 0;
uint y = info->height - 1;
byte n, c, b;
byte *pixel = &data->bitmap[y * info->width];
while (y != 0 || x < info->width) {
if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
byte n = ReadByte(buffer);
byte c = ReadByte(buffer);
n = ReadByte(buffer);
c = ReadByte(buffer);
if (n == 0) {
switch (c) {
case 0: // end of line
x = 0;
if (y == 0) return false;
pixel = &data->bitmap[--y * info->width];
break;
case 1: // end of bitmap
return true;
case 2: { // delta
if (EndOfBuffer(buffer)) return false;
byte dx = ReadByte(buffer);
byte dy = ReadByte(buffer);
/* Check for over- and underflow. */
if (x + dx >= info->width || x + dx < x || dy > y) return false;
x += dx;
y -= dy;
pixel = &data->bitmap[y * info->width + x];
break;
}
default: { // uncompressed
uint i = 0;
while (i++ < c) {
if (EndOfBuffer(buffer) || x >= info->width) return false;
byte b = ReadByte(buffer);
*pixel++ = GB(b, 4, 4);
case 0: // end of line
x = 0;
pixel = &data->bitmap[--y * info->width];
break;
case 1: // end of bitmap
x = info->width;
y = 0;
pixel = NULL;
break;
case 2: // delta
x += ReadByte(buffer);
i = ReadByte(buffer);
if (x >= info->width || (y == 0 && i > 0)) return false;
y -= i;
pixel = &data->bitmap[y * info->width + x];
break;
default: // uncompressed
i = 0;
while (i++ < c) {
if (EndOfBuffer(buffer) || x >= info->width) return false;
b = ReadByte(buffer);
*pixel++ = GB(b, 4, 4);
x++;
if (x < info->width && i++ < c) {
*pixel++ = GB(b, 0, 4);
x++;
if (i++ < c) {
if (x >= info->width) return false;
*pixel++ = GB(b, 0, 4);
x++;
}
}
/* Padding for 16 bit align */
SkipBytes(buffer, ((c + 1) / 2) % 2);
break;
}
/* Padding for 16 bit align */
SkipBytes(buffer, ((c + 1) / 2) % 2);
break;
}
} else {
/* Apparently it is common to encounter BMPs where the count of
* pixels to be written is higher than the remaining line width.
* Ignore the superfluous pixels instead of reporting an error. */
uint i = 0;
while (x < info->width && i++ < n) {
i = 0;
while (i++ < n) {
if (EndOfBuffer(buffer) || x >= info->width) return false;
*pixel++ = GB(c, 4, 4);
x++;
if (x < info->width && i++ < n) {
@@ -231,55 +203,43 @@ static inline bool BmpRead8(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
*/
static inline bool BmpRead8Rle(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
{
uint i;
uint x = 0;
uint y = info->height - 1;
byte n, c;
byte *pixel = &data->bitmap[y * info->width];
while (y != 0 || x < info->width) {
if (EndOfBuffer(buffer)) return false; // the file is shorter than expected
byte n = ReadByte(buffer);
byte c = ReadByte(buffer);
n = ReadByte(buffer);
c = ReadByte(buffer);
if (n == 0) {
switch (c) {
case 0: // end of line
x = 0;
if (y == 0) return false;
pixel = &data->bitmap[--y * info->width];
break;
case 1: // end of bitmap
return true;
case 2: { // delta
if (EndOfBuffer(buffer)) return false;
byte dx = ReadByte(buffer);
byte dy = ReadByte(buffer);
/* Check for over- and underflow. */
if (x + dx >= info->width || x + dx < x || dy > y) return false;
x += dx;
y -= dy;
pixel = &data->bitmap[y * info->width + x];
break;
}
default: { // uncompressed
for (uint i = 0; i < c; i++) {
if (EndOfBuffer(buffer) || x >= info->width) return false;
*pixel++ = ReadByte(buffer);
x++;
}
/* Padding for 16 bit align */
SkipBytes(buffer, c % 2);
break;
}
case 0: // end of line
x = 0;
pixel = &data->bitmap[--y * info->width];
break;
case 1: // end of bitmap
x = info->width;
y = 0;
pixel = NULL;
break;
case 2: // delta
x += ReadByte(buffer);
i = ReadByte(buffer);
if (x >= info->width || (y == 0 && i > 0)) return false;
y -= i;
pixel = &data->bitmap[y * info->width + x];
break;
default: // uncompressed
if ((x += c) > info->width) return false;
for (i = 0; i < c; i++) *pixel++ = ReadByte(buffer);
/* Padding for 16 bit align */
SkipBytes(buffer, c % 2);
break;
}
} else {
/* Apparently it is common to encounter BMPs where the count of
* pixels to be written is higher than the remaining line width.
* Ignore the superfluous pixels instead of reporting an error. */
for (uint i = 0; x < info->width && i < n; i++) {
for (i = 0; i < n; i++) {
if (x >= info->width) return false;
*pixel++ = c;
x++;
}
@@ -317,8 +277,7 @@ static inline bool BmpRead24(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
{
uint32 header_size;
assert(info != nullptr);
MemSetT(info, 0);
assert(info != NULL);
/* Reading BMP header */
if (ReadWord(buffer) != 0x4D42) return false; // signature should be 'BM'
@@ -361,20 +320,16 @@ bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
if (info->bpp <= 8) {
uint i;
/* Reads number of colours if available in info header */
/* Reads number of colors if available in info header */
if (header_size >= 16) {
SkipBytes(buffer, 12); // skip image size and resolution
info->palette_size = ReadDword(buffer); // number of colours in palette
info->palette_size = ReadDword(buffer); // number of colors in palette
SkipBytes(buffer, header_size - 16); // skip the end of info header
}
if (info->palette_size == 0) info->palette_size = 1 << info->bpp;
uint maximum_palette_size = 1U << info->bpp;
if (info->palette_size == 0) info->palette_size = maximum_palette_size;
/* More palette colours than palette indices is not supported. */
if (info->palette_size > maximum_palette_size) return false;
data->palette = CallocT<Colour>(info->palette_size);
data->palette = calloc(info->palette_size, sizeof(*(data->palette)));
if (data->palette == NULL) return false;
for (i = 0; i < info->palette_size; i++) {
data->palette[i].b = ReadByte(buffer);
@@ -393,9 +348,10 @@ bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
*/
bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
{
assert(info != nullptr && data != nullptr);
assert(info != NULL && data != NULL);
data->bitmap = CallocT<byte>(info->width * info->height * ((info->bpp == 24) ? 3 : 1));
data->bitmap = calloc(info->width * info->height, ((info->bpp == 24) ? 3 : 1) * sizeof(byte));
if (data->bitmap == NULL) return false;
/* Load image */
SetStreamOffset(buffer, info->offset);
@@ -406,17 +362,17 @@ bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data)
case 4: return BmpRead4(buffer, info, data);
case 8: return BmpRead8(buffer, info, data);
case 24: return BmpRead24(buffer, info, data);
default: NOT_REACHED();
default: NOT_REACHED(); return false;
}
case 1: return BmpRead8Rle(buffer, info, data); // 8-bit RLE compression
case 2: return BmpRead4Rle(buffer, info, data); // 4-bit RLE compression
default: NOT_REACHED();
default: NOT_REACHED(); return false;
}
}
void BmpDestroyData(BmpData *data)
{
assert(data != nullptr);
assert(data != NULL);
free(data->palette);
free(data->bitmap);
}

36
bmp.h Normal file
View File

@@ -0,0 +1,36 @@
/* $Id$ */
#ifndef BMP_H
#define BMP_H
typedef struct {
uint32 offset; ///< offset of bitmap data from .bmp file begining
uint32 width; ///< bitmap width
uint32 height; ///< bitmap height
bool os2_bmp; ///< true if OS/2 1.x or windows 2.x bitmap
uint16 bpp; ///< bits per pixel
uint32 compression; ///< compression method (0 = none, 1 = 8-bit RLE, 2 = 4-bit RLE)
uint32 palette_size; ///< number of colors in palette
} BmpInfo;
typedef struct {
Colour *palette;
byte *bitmap;
} BmpData;
#define BMP_BUFFER_SIZE 1024
typedef struct {
byte data[BMP_BUFFER_SIZE];
int pos;
int read;
FILE *file;
uint real_pos;
} BmpBuffer;
void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file);
bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data);
bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data);
void BmpDestroyData(BmpData *data);
#endif /* BMP_H */

32
bridge.h Normal file
View File

@@ -0,0 +1,32 @@
/* $Id$ */
/** @file bridge.h Header file for bridges */
#ifndef BRIDGE_H
#define BRIDGE_H
enum {
MAX_BRIDGES = 13
};
/** Struct containing information about a single bridge type
*/
typedef struct Bridge {
Year avail_year; ///< the year in which the bridge becomes available
byte min_length; ///< the minimum length of the bridge (not counting start and end tile)
byte max_length; ///< the maximum length of the bridge (not counting start and end tile)
uint16 price; ///< the relative price of the bridge
uint16 speed; ///< maximum travel speed
PalSpriteID sprite; ///< the sprite which is used in the GUI (possibly with a recolor sprite)
StringID material; ///< the string that contains the bridge description
PalSpriteID **sprite_table; ///< table of sprites for drawing the bridge
byte flags; ///< bit 0 set: disable drawing of far pillars.
} Bridge;
extern const Bridge orig_bridge[MAX_BRIDGES];
extern Bridge _bridge[MAX_BRIDGES];
uint GetBridgeFoundation(Slope tileh, Axis axis);
uint GetBridgeHeightRamp(TileIndex t);
#endif /* BRIDGE_H */

167
bridge_gui.c Normal file
View File

@@ -0,0 +1,167 @@
/* $Id$ */
/** @file bridge_gui.c Graphical user interface for bridge construction*/
#include "stdafx.h"
#include "openttd.h"
#include "table/strings.h"
#include "functions.h"
#include "map.h"
#include "window.h"
#include "gui.h"
#include "viewport.h"
#include "gfx.h"
#include "command.h"
#include "sound.h"
#include "variables.h"
#include "bridge.h"
static struct BridgeData {
uint count;
TileIndex start_tile;
TileIndex end_tile;
byte type;
byte indexes[MAX_BRIDGES];
int32 costs[MAX_BRIDGES];
} _bridgedata;
void CcBuildBridge(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
if (success) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, tile);
}
static void BuildBridge(Window *w, int i)
{
DeleteWindow(w);
DoCommandP(_bridgedata.end_tile, _bridgedata.start_tile,
_bridgedata.indexes[i] | (_bridgedata.type << 8), CcBuildBridge,
CMD_BUILD_BRIDGE | CMD_AUTO | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE));
}
static void BuildBridgeWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_PAINT: {
uint i;
DrawWindowWidgets(w);
for (i = 0; i < 4 && i + w->vscroll.pos < _bridgedata.count; i++) {
const Bridge *b = &_bridge[_bridgedata.indexes[i + w->vscroll.pos]];
SetDParam(2, _bridgedata.costs[i + w->vscroll.pos]);
SetDParam(1, b->speed);
SetDParam(0, b->material);
DrawSprite(b->sprite, 3, 15 + i * 22);
DrawString(44, 15 + i * 22 , STR_500D, 0);
}
} break;
case WE_KEYPRESS: {
uint i = e->we.keypress.keycode - '1';
if (i < 9 && i < _bridgedata.count) {
e->we.keypress.cont = false;
BuildBridge(w, i);
}
break;
}
case WE_CLICK:
if (e->we.click.widget == 2) {
uint ind = ((int)e->we.click.pt.y - 14) / 22;
if (ind < 4 && (ind += w->vscroll.pos) < _bridgedata.count)
BuildBridge(w, ind);
}
break;
}
}
static const Widget _build_bridge_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 199, 0, 13, STR_100D_SELECT_RAIL_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_MATRIX, RESIZE_NONE, 7, 0, 187, 14, 101, 0x401, STR_101F_BRIDGE_SELECTION_CLICK},
{ WWT_SCROLLBAR, RESIZE_NONE, 7, 188, 199, 14, 101, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WIDGETS_END},
};
static const WindowDesc _build_bridge_desc = {
WDP_AUTO, WDP_AUTO, 200, 102,
WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_bridge_widgets,
BuildBridgeWndProc
};
static const Widget _build_road_bridge_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 199, 0, 13, STR_1803_SELECT_ROAD_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_MATRIX, RESIZE_NONE, 7, 0, 187, 14, 101, 0x401, STR_101F_BRIDGE_SELECTION_CLICK},
{ WWT_SCROLLBAR, RESIZE_NONE, 7, 188, 199, 14, 101, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WIDGETS_END},
};
static const WindowDesc _build_road_bridge_desc = {
WDP_AUTO, WDP_AUTO, 200, 102,
WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_road_bridge_widgets,
BuildBridgeWndProc
};
void ShowBuildBridgeWindow(TileIndex start, TileIndex end, byte bridge_type)
{
uint j = 0;
int32 ret;
StringID errmsg;
DeleteWindowById(WC_BUILD_BRIDGE, 0);
_bridgedata.type = bridge_type;
_bridgedata.start_tile = start;
_bridgedata.end_tile = end;
errmsg = INVALID_STRING_ID;
// only query bridge building possibility once, result is the same for all bridges!
// returns CMD_ERROR on failure, and price on success
ret = DoCommand(end, start, (bridge_type << 8), DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE);
if (CmdFailed(ret)) {
errmsg = _error_message;
} else {
// check which bridges can be built
int bridge_len; // length of the middle parts of the bridge
int tot_bridgedata_len; // total length of bridge
// get absolute bridge length
bridge_len = GetBridgeLength(start, end);
tot_bridgedata_len = bridge_len + 2;
tot_bridgedata_len = CalcBridgeLenCostFactor(tot_bridgedata_len);
for (bridge_type = 0; bridge_type != MAX_BRIDGES; bridge_type++) { // loop for all bridgetypes
if (CheckBridge_Stuff(bridge_type, bridge_len)) {
const Bridge *b = &_bridge[bridge_type];
// bridge is accepted, add to list
// add to terraforming & bulldozing costs the cost of the bridge itself (not computed with DC_QUERY_COST)
_bridgedata.costs[j] = ret + (((int64)tot_bridgedata_len * _price.build_bridge * b->price) >> 8);
_bridgedata.indexes[j] = bridge_type;
j++;
}
}
}
_bridgedata.count = j;
if (j != 0) {
Window *w = AllocateWindowDesc((_bridgedata.type & 0x80) ? &_build_road_bridge_desc : &_build_bridge_desc);
w->vscroll.cap = 4;
w->vscroll.count = (byte)j;
} else {
ShowErrorMessage(errmsg, STR_5015_CAN_T_BUILD_BRIDGE_HERE, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE);
}
}

37
bridge_map.c Normal file
View File

@@ -0,0 +1,37 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "bridge_map.h"
TileIndex GetBridgeEnd(TileIndex tile, DiagDirection dir)
{
TileIndexDiff delta = TileOffsByDiagDir(dir);
assert(DiagDirToAxis(dir) == GetBridgeAxis(tile));
do {
tile += delta;
} while (!IsBridgeRamp(tile));
return tile;
}
TileIndex GetSouthernBridgeEnd(TileIndex t)
{
return GetBridgeEnd(t, AxisToDiagDir(GetBridgeAxis(t)));
}
TileIndex GetOtherBridgeEnd(TileIndex tile)
{
TileIndexDiff delta = TileOffsByDiagDir(GetBridgeRampDirection(tile));
do {
tile += delta;
} while (!IsBridgeRamp(tile));
return tile;
}

235
bridge_map.h Normal file
View File

@@ -0,0 +1,235 @@
/* $Id$ */
#ifndef BRIDGE_MAP_H
#define BRIDGE_MAP_H
#include "direction.h"
#include "macros.h"
#include "map.h"
#include "rail.h"
#include "road_map.h"
#include "tile.h"
static inline bool IsBridge(TileIndex t)
{
assert(IsTileType(t, MP_TUNNELBRIDGE));
return HASBIT(_m[t].m5, 7);
}
static inline bool IsBridgeTile(TileIndex t)
{
return IsTileType(t, MP_TUNNELBRIDGE) && IsBridge(t);
}
static inline bool IsBridgeRamp(TileIndex t)
{
assert(IsBridgeTile(t));
return !HASBIT(_m[t].m5, 6);
}
static inline bool IsBridgeMiddle(TileIndex t)
{
assert(IsBridgeTile(t));
return HASBIT(_m[t].m5, 6);
}
/**
* Determines which piece of a bridge is contained in the current tile
* @param tile The tile to analyze
* @return the piece
*/
static inline uint GetBridgePiece(TileIndex t)
{
assert(IsBridgeMiddle(t));
return GB(_m[t].m2, 0, 4);
}
/**
* Determines the type of bridge on a tile
* @param tile The tile to analyze
* @return The bridge type
*/
static inline uint GetBridgeType(TileIndex t)
{
assert(IsBridgeTile(t));
return GB(_m[t].m2, 4, 4);
}
/**
* Get the direction pointing onto the bridge
*/
static inline DiagDirection GetBridgeRampDirection(TileIndex t)
{
assert(IsBridgeRamp(t));
return ReverseDiagDir(XYNSToDiagDir((Axis)GB(_m[t].m5, 0, 1), GB(_m[t].m5, 5, 1)));
}
static inline Axis GetBridgeAxis(TileIndex t)
{
assert(IsBridgeMiddle(t));
return (Axis)GB(_m[t].m5, 0, 1);
}
static inline TransportType GetBridgeTransportType(TileIndex t)
{
assert(IsBridgeTile(t));
return (TransportType)GB(_m[t].m5, 1, 2);
}
static inline bool IsClearUnderBridge(TileIndex t)
{
assert(IsBridgeMiddle(t));
return GB(_m[t].m5, 3, 3) == 0;
}
static inline bool IsWaterUnderBridge(TileIndex t)
{
assert(IsBridgeMiddle(t));
return GB(_m[t].m5, 3, 3) == 1;
}
static inline bool IsTransportUnderBridge(TileIndex t)
{
assert(IsBridgeMiddle(t));
return HASBIT(_m[t].m5, 5);
}
static inline TransportType GetTransportTypeUnderBridge(TileIndex t)
{
assert(IsTransportUnderBridge(t));
return (TransportType)GB(_m[t].m5, 3, 2);
}
static inline RoadBits GetRoadBitsUnderBridge(TileIndex t)
{
assert(GetTransportTypeUnderBridge(t) == TRANSPORT_ROAD);
return GetBridgeAxis(t) == AXIS_X ? ROAD_Y : ROAD_X;
}
static inline Track GetRailUnderBridge(TileIndex t)
{
assert(GetTransportTypeUnderBridge(t) == TRANSPORT_RAIL);
return AxisToTrack(OtherAxis(GetBridgeAxis(t)));
}
static inline TrackBits GetRailBitsUnderBridge(TileIndex t)
{
return TrackToTrackBits(GetRailUnderBridge(t));
}
/**
* Finds the end of a bridge in the specified direction starting at a middle tile
*/
TileIndex GetBridgeEnd(TileIndex, DiagDirection);
/**
* Finds the southern end of a bridge starting at a middle tile
*/
TileIndex GetSouthernBridgeEnd(TileIndex t);
/**
* Starting at one bridge end finds the other bridge end
*/
TileIndex GetOtherBridgeEnd(TileIndex);
uint GetBridgeHeight(TileIndex t);
static inline void SetClearUnderBridge(TileIndex t)
{
assert(IsBridgeMiddle(t));
SetTileOwner(t, OWNER_NONE);
SB(_m[t].m5, 3, 3, 0 << 2 | 0);
SB(_m[t].m3, 0, 4, 0);
}
static inline void SetWaterUnderBridge(TileIndex t)
{
assert(IsBridgeMiddle(t));
SetTileOwner(t, OWNER_WATER);
SB(_m[t].m5, 3, 3, 0 << 2 | 1);
SB(_m[t].m3, 0, 4, 0);
}
static inline void SetCanalUnderBridge(TileIndex t, Owner o)
{
assert(IsBridgeMiddle(t));
SetTileOwner(t, o);
SB(_m[t].m5, 3, 3, 0 << 2 | 1);
SB(_m[t].m3, 0, 4, 0);
}
static inline void SetRailUnderBridge(TileIndex t, Owner o, RailType r)
{
assert(IsBridgeMiddle(t));
SetTileOwner(t, o);
SB(_m[t].m5, 3, 3, 1 << 2 | TRANSPORT_RAIL);
SB(_m[t].m3, 0, 4, r);
}
static inline void SetRoadUnderBridge(TileIndex t, Owner o)
{
assert(IsBridgeMiddle(t));
SetTileOwner(t, o);
SB(_m[t].m5, 3, 3, 1 << 2 | TRANSPORT_ROAD);
SB(_m[t].m3, 0, 4, 0);
}
static inline void MakeBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d, TransportType tt)
{
uint northsouth = (d == DIAGDIR_NE || d == DIAGDIR_NW);
SetTileType(t, MP_TUNNELBRIDGE);
SetTileOwner(t, o);
_m[t].m2 = bridgetype << 4;
_m[t].m4 = 0;
_m[t].m5 = 1 << 7 | 0 << 6 | northsouth << 5 | tt << 1 | DiagDirToAxis(d);
}
static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d)
{
MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_ROAD);
_m[t].m3 = 0;
}
static inline void MakeRailBridgeRamp(TileIndex t, Owner o, uint bridgetype, DiagDirection d, RailType r)
{
MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL);
_m[t].m3 = r;
}
static inline void MakeBridgeMiddle(TileIndex t, uint bridgetype, uint piece, Axis a, TransportType tt)
{
SetTileType(t, MP_TUNNELBRIDGE);
SetTileOwner(t, OWNER_NONE);
_m[t].m2 = bridgetype << 4 | piece;
_m[t].m3 = 0;
_m[t].m4 = 0;
_m[t].m5 = 1 << 7 | 1 << 6 | 0 << 5 | 0 << 3 | tt << 1 | a;
}
static inline void MakeRoadBridgeMiddle(TileIndex t, uint bridgetype, uint piece, Axis a)
{
MakeBridgeMiddle(t, bridgetype, piece, a, TRANSPORT_ROAD);
}
static inline void MakeRailBridgeMiddle(TileIndex t, uint bridgetype, uint piece, Axis a, RailType r)
{
MakeBridgeMiddle(t, bridgetype, piece, a, TRANSPORT_RAIL);
SB(_m[t].m3, 4, 4, r);
}
#endif /* BRIDGE_MAP_H */

492
build_vehicle_gui.c Normal file
View File

@@ -0,0 +1,492 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "aircraft.h"
#include "debug.h"
#include "functions.h"
#include "table/sprites.h"
#include "table/strings.h"
#include "window.h"
#include "gui.h"
#include "vehicle.h"
#include "gfx.h"
#include "station.h"
#include "command.h"
#include "engine.h"
#include "player.h"
#include "depot.h"
#include "airport.h"
#include "vehicle_gui.h"
#include "newgrf_engine.h"
#include "date.h"
#include "strings.h"
enum BuildVehicleWidgets {
BUILD_VEHICLE_WIDGET_CLOSEBOX = 0,
BUILD_VEHICLE_WIDGET_CAPTION,
BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING,
BUILD_VEHICLE_WIDGET_SORT_TEXT,
BUILD_VEHICLE_WIDGET_SORT_DROPDOWN,
BUILD_VEHICLE_WIDGET_LIST,
BUILD_VEHICLE_WIDGET_SCROLLBAR,
BUILD_VEHICLE_WIDGET_PANEL,
BUILD_VEHICLE_WIDGET_BUILD,
BUILD_VEHICLE_WIDGET_RENAME,
BUILD_VEHICLE_WIDGET_RESIZE,
};
static const Widget _build_vehicle_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 239, 0, 13, STR_A005_NEW_AIRCRAFT, STR_018C_WINDOW_TITLE_DRAG_THIS },
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 80, 14, 25, STR_SORT_BY, STR_SORT_ORDER_TIP},
{ WWT_PANEL, RESIZE_NONE, 14, 81, 227, 14, 25, 0x0, STR_SORT_CRITERIA_TIP},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 228, 239, 14, 25, STR_0225, STR_SORT_CRITERIA_TIP},
{ WWT_MATRIX, RESIZE_BOTTOM, 14, 0, 227, 26, 121, 0x401, STR_A025_AIRCRAFT_SELECTION_LIST },
{ WWT_SCROLLBAR, RESIZE_BOTTOM, 14, 228, 239, 26, 121, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST },
{ WWT_PANEL, RESIZE_TB, 14, 0, 239, 122, 213, 0x0, STR_NULL },
{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 114, 214, 225, STR_A006_BUILD_AIRCRAFT, STR_A026_BUILD_THE_HIGHLIGHTED_AIRCRAFT },
{ WWT_PUSHTXTBTN, RESIZE_TB, 14, 115, 227, 214, 225, STR_A037_RENAME, STR_A038_RENAME_AIRCRAFT_TYPE },
{ WWT_RESIZEBOX, RESIZE_TB, 14, 228, 239, 214, 225, 0x0, STR_RESIZE_BUTTON },
{ WIDGETS_END},
};
static bool _internal_sort_order; // descending/ascending
static byte _last_sort_criteria = 0;
static bool _last_sort_order = false;
static int CDECL EngineNumberSorter(const void *a, const void *b)
{
const EngineID va = *(const EngineID*)a;
const EngineID vb = *(const EngineID*)b;
int r = va - vb;
return _internal_sort_order ? -r : r;
}
static int CDECL EngineIntroDateSorter(const void *a, const void *b)
{
const int va = GetEngine(*(const EngineID*)a)->intro_date;
const int vb = GetEngine(*(const EngineID*)b)->intro_date;
const int r = va - vb;
if (r == 0) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter(a, b);
}
return _internal_sort_order ? -r : r;
}
static int CDECL EngineNameSorter(const void *a, const void *b)
{
static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE };
static char last_name[2][64] = { "\0", "\0" };
const EngineID va = *(const EngineID*)a;
const EngineID vb = *(const EngineID*)b;
int r;
if (va != last_engine[0]) {
last_engine[0] = va;
GetString(last_name[0], GetCustomEngineName(va), lastof(last_name[0]));
}
if (vb != last_engine[1]) {
last_engine[1] = vb;
GetString(last_name[1], GetCustomEngineName(vb), lastof(last_name[1]));
}
r = strcmp(last_name[0], last_name[1]); // sort by name
if (r == 0) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter(a, b);
}
return _internal_sort_order ? -r : r;
}
static int CDECL EngineReliabilitySorter(const void *a, const void *b)
{
const int va = GetEngine(*(const EngineID*)a)->reliability;
const int vb = GetEngine(*(const EngineID*)b)->reliability;
const int r = va - vb;
if (r == 0) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter(a, b);
}
return _internal_sort_order ? -r : r;
}
/* Aircraft sorting functions */
static int CDECL AircraftEngineCostSorter(const void *a, const void *b)
{
const int va = AircraftVehInfo(*(const EngineID*)a)->base_cost;
const int vb = AircraftVehInfo(*(const EngineID*)b)->base_cost;
int r = va - vb;
return _internal_sort_order ? -r : r;
}
static int CDECL AircraftEngineSpeedSorter(const void *a, const void *b)
{
const int va = AircraftVehInfo(*(const EngineID*)a)->max_speed;
const int vb = AircraftVehInfo(*(const EngineID*)b)->max_speed;
const int r = va - vb;
if (r == 0) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter(a, b);
}
return _internal_sort_order ? -r : r;
}
static int CDECL AircraftEngineRunningCostSorter(const void *a, const void *b)
{
const int va = AircraftVehInfo(*(const EngineID*)a)->running_cost;
const int vb = AircraftVehInfo(*(const EngineID*)b)->running_cost;
const int r = va - vb;
if (r == 0) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter(a, b);
}
return _internal_sort_order ? -r : r;
}
static int CDECL AircraftEngineCargoSorter(const void *a, const void *b)
{
const int va = AircraftVehInfo(*(const EngineID*)a)->passenger_capacity;
const int vb = AircraftVehInfo(*(const EngineID*)b)->passenger_capacity;
const int r = va - vb;
if (r == 0) {
/* Use EngineID to sort instead since we want consistent sorting */
return EngineNumberSorter(a, b);
}
return _internal_sort_order ? -r : r;
}
static EngList_SortTypeFunction * const _aircraft_sorter[] = {
&EngineNumberSorter,
&AircraftEngineCostSorter,
&AircraftEngineSpeedSorter,
&EngineIntroDateSorter,
&EngineNameSorter,
&AircraftEngineRunningCostSorter,
&EngineReliabilitySorter,
&AircraftEngineCargoSorter,
};
static const StringID _aircraft_sort_listing[] = {
STR_ENGINE_SORT_ENGINE_ID,
STR_ENGINE_SORT_COST,
STR_SORT_BY_MAX_SPEED,
STR_ENGINE_SORT_INTRO_DATE,
STR_SORT_BY_DROPDOWN_NAME,
STR_ENGINE_SORT_RUNNING_COST,
STR_SORT_BY_RELIABILITY,
STR_ENGINE_SORT_CARGO_CAPACITY,
INVALID_STRING_ID
};
/**
* Draw the purchase info details of an aircraft at a given location.
* @param x,y location where to draw the info
* @param engine_number the engine of which to draw the info of
*/
void DrawAircraftPurchaseInfo(int x, int y, uint w, EngineID engine_number)
{
const AircraftVehicleInfo *avi = AircraftVehInfo(engine_number);
const Engine *e = GetEngine(engine_number);
CargoID cargo;
YearMonthDay ymd;
ConvertDateToYMD(e->intro_date, &ymd);
/* Purchase cost - Max speed */
SetDParam(0, avi->base_cost * (_price.aircraft_base>>3)>>5);
SetDParam(1, avi->max_speed * 128 / 10);
DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, 0);
y += 10;
/* Cargo capacity */
cargo = FindFirstRefittableCargo(engine_number);
if (cargo == CT_INVALID || cargo == CT_PASSENGERS) {
SetDParam(0, avi->passenger_capacity);
SetDParam(1, avi->mail_capacity);
DrawString(x, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY, 0);
} else {
/* Note, if the default capacity is selected by the refit capacity
* callback, then the capacity shown is likely to be incorrect. */
SetDParam(0, cargo);
SetDParam(1, AircraftDefaultCargoCapacity(cargo, engine_number));
SetDParam(2, STR_9842_REFITTABLE);
DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, 0);
}
y += 10;
/* Running cost */
SetDParam(0, avi->running_cost * _price.aircraft_running >> 8);
DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, 0);
y += 10;
/* Design date - Life length */
SetDParam(0, ymd.year);
SetDParam(1, e->lifelength);
DrawString(x, y, STR_PURCHASE_INFO_DESIGNED_LIFE, 0);
y += 10;
/* Reliability */
SetDParam(0, e->reliability * 100 >> 16);
DrawString(x, y, STR_PURCHASE_INFO_RELIABILITY, 0);
y += 10;
/* Additional text from NewGRF */
y += ShowAdditionalText(x, y, w, engine_number);
y += ShowRefitOptionsList(x, y, w, engine_number);
}
void DrawAircraftImage(const Vehicle *v, int x, int y, VehicleID selection)
{
PalSpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
DrawSprite(GetAircraftImage(v, DIR_W) | pal, x + 25, y + 10);
if (v->subtype == 0) {
SpriteID rotor_sprite = GetCustomRotorSprite(v, true);
if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED;
DrawSprite(rotor_sprite, x + 25, y + 5);
}
if (v->index == selection) {
DrawFrameRect(x - 1, y - 1, x + 58, y + 21, 0xF, FR_BORDERONLY);
}
}
void CcBuildAircraft(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
if (success) {
const Vehicle *v = GetVehicle(_new_vehicle_id);
if (v->tile == _backup_orders_tile) {
_backup_orders_tile = 0;
RestoreVehicleOrders(v, _backup_orders_data);
}
ShowAircraftViewWindow(v);
}
}
static void GenerateBuildAircraftList(Window *w)
{
EngineID eid, sel_id;
buildvehicle_d *bv = &WP(w, buildvehicle_d);
EngList_RemoveAll(&bv->eng_list);
/* Make list of all available planes.
* Also check to see if the previously selected plane is still available,
* and if not, reset selection to INVALID_ENGINE. This could be the case
* when planes become obsolete and are removed */
sel_id = INVALID_ENGINE;
for (eid = AIRCRAFT_ENGINES_INDEX; eid < AIRCRAFT_ENGINES_INDEX + NUM_AIRCRAFT_ENGINES; eid++) {
if (IsEngineBuildable(eid, VEH_Aircraft, _local_player)) {
const AircraftVehicleInfo *avi = AircraftVehInfo(eid);
switch (bv->filter.acc_planes) {
case HELICOPTERS_ONLY:
if (avi->subtype != 0) continue; // if not helicopter
break;
case AIRCRAFT_ONLY:
if (avi->subtype == 0) continue; // if helicopter
break;
case ALL: break;
}
EngList_Add(&bv->eng_list, eid);
if (eid == bv->sel_engine) sel_id = eid;
}
}
bv->sel_engine = sel_id;
}
static void GenerateBuildList(Window *w)
{
buildvehicle_d *bv = &WP(w, buildvehicle_d);
switch (bv->vehicle_type) {
case VEH_Aircraft:
GenerateBuildAircraftList(w);
_internal_sort_order = bv->descending_sort_order;
EngList_Sort(&bv->eng_list, _aircraft_sorter[bv->sort_criteria]);
break;
default: NOT_REACHED();
}
}
static void DrawBuildAircraftWindow(Window *w)
{
const buildvehicle_d *bv = &WP(w, buildvehicle_d);
SetWindowWidgetDisabledState(w, BUILD_VEHICLE_WIDGET_BUILD, w->window_number == 0);
SetVScrollCount(w, EngList_Count(&bv->eng_list));
DrawWindowWidgets(w);
{
int x = 2;
int y = 27;
EngineID selected_id = bv->sel_engine;
EngineID eid = w->vscroll.pos;
uint16 max = min(w->vscroll.pos + w->vscroll.cap, EngList_Count(&bv->eng_list));
for (; eid < max; eid++) {
const EngineID engine = bv->eng_list[eid];
DrawString(x + 62, y + 7, GetCustomEngineName(engine), engine == selected_id ? 0xC : 0x10);
DrawAircraftEngine(x + 29, y + 10, engine, GetEnginePalette(engine, _local_player));
y += 24;
}
if (selected_id != INVALID_ENGINE) {
const Widget *wi = &w->widget[BUILD_VEHICLE_WIDGET_PANEL];
DrawAircraftPurchaseInfo(x, wi->top + 1, wi->right - wi->left - 2, selected_id);
}
}
DrawString(85, 15, _aircraft_sort_listing[bv->sort_criteria], 0x10);
DoDrawString(bv->descending_sort_order ? DOWNARROW : UPARROW, 69, 15, 0x10);
}
static void BuildAircraftClickEvent(Window *w, WindowEvent *e)
{
buildvehicle_d *bv = &WP(w, buildvehicle_d);
switch (e->we.click.widget) {
case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING:
bv->descending_sort_order ^= true;
_last_sort_order = bv->descending_sort_order;
GenerateBuildList(w);
SetWindowDirty(w);
break;
case BUILD_VEHICLE_WIDGET_LIST: {
uint i = (e->we.click.pt.y - 26) / 24 + w->vscroll.pos;
uint num_items = EngList_Count(&bv->eng_list);
bv->sel_engine = (i < num_items) ? bv->eng_list[i] : INVALID_ENGINE;
SetWindowDirty(w);
break;
}
case BUILD_VEHICLE_WIDGET_SORT_TEXT: case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN:/* Select sorting criteria dropdown menu */
ShowDropDownMenu(w, _aircraft_sort_listing, bv->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0);
return;
case BUILD_VEHICLE_WIDGET_BUILD: {
EngineID sel_eng = bv->sel_engine;
if (sel_eng != INVALID_ENGINE) {
DoCommandP(w->window_number, sel_eng, 0, CcBuildAircraft, CMD_BUILD_AIRCRAFT | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
}
break;
}
case BUILD_VEHICLE_WIDGET_RENAME: {
EngineID sel_eng = bv->sel_engine;
if (sel_eng != INVALID_ENGINE) {
bv->rename_engine = sel_eng;
ShowQueryString(GetCustomEngineName(sel_eng), STR_A039_RENAME_AIRCRAFT_TYPE, 31, 160, w->window_class, w->window_number, CS_ALPHANUMERAL);
}
break;
}
}
}
static void NewAircraftWndProc(Window *w, WindowEvent *e)
{
buildvehicle_d *bv = &WP(w, buildvehicle_d);
switch (e->event) {
case WE_INVALIDATE_DATA:
GenerateBuildList(w);
break;
case WE_DESTROY:
EngList_Destroy(&bv->eng_list);
break;
case WE_PAINT:
DrawBuildAircraftWindow(w);
break;
case WE_CLICK:
BuildAircraftClickEvent(w, e);
break;
case WE_ON_EDIT_TEXT: {
if (e->we.edittext.str[0] != '\0') {
_cmd_text = e->we.edittext.str;
DoCommandP(0, bv->rename_engine, 0, NULL, CMD_RENAME_ENGINE | CMD_MSG(STR_A03A_CAN_T_RENAME_AIRCRAFT_TYPE));
}
break;
}
case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
if (bv->sort_criteria != e->we.dropdown.index) {
bv->sort_criteria = _last_sort_criteria = e->we.dropdown.index;
GenerateBuildList(w);
}
SetWindowDirty(w);
break;
case WE_RESIZE:
w->vscroll.cap += e->we.sizing.diff.y / 24;
w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
break;
}
}
static const WindowDesc _build_vehicle_desc = {
WDP_AUTO, WDP_AUTO, 240, 226,
WC_BUILD_VEHICLE,0,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
_build_vehicle_widgets,
NewAircraftWndProc
};
void ShowBuildVehicleWindow(TileIndex tile, byte type)
{
buildvehicle_d *bv;
Window *w;
DeleteWindowById(WC_BUILD_VEHICLE, tile);
w = AllocateWindowDescFront(&_build_vehicle_desc, tile);
if (w == NULL) return;
w->caption_color = (tile != 0) ? GetTileOwner(tile) : _local_player;
w->resize.step_height = GetVehicleListHeight(type);
w->vscroll.cap = 4;
w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
bv = &WP(w, buildvehicle_d);
EngList_Create(&bv->eng_list);
bv->sel_engine = INVALID_ENGINE;
bv->sort_criteria = _last_sort_criteria;
bv->descending_sort_order = _last_sort_order;
bv->vehicle_type = type;
switch (type) {
case VEH_Aircraft: {
byte acc_planes = (tile == 0) ? ALL : GetAirport(GetStationByTile(tile)->airport_type)->acc_planes;
bv->filter.acc_planes = acc_planes;
break;
}
default: NOT_REACHED();
}
GenerateBuildList(w);
/* Select the first plane in the list as default when opening the window */
if (EngList_Count(&bv->eng_list) > 0) bv->sel_engine = bv->eng_list[0];
}

91
callback_table.c Normal file
View File

@@ -0,0 +1,91 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "callback_table.h"
#include "functions.h"
// If you add a callback for DoCommandP, also add the callback in here
// see below for the full list!
// If you don't do it, it won't work across the network!!
/* aircraft_gui.c */
CommandCallback CcBuildAircraft;
CommandCallback CcCloneAircraft;
/* airport_gui.c */
CommandCallback CcBuildAirport;
/* bridge_gui.c */
CommandCallback CcBuildBridge;
/* dock_gui.c */
CommandCallback CcBuildDocks;
CommandCallback CcBuildCanal;
/* depot_gui.c */
CommandCallback CcCloneVehicle;
/* main_gui.c */
CommandCallback CcPlaySound10;
CommandCallback CcPlaceSign;
CommandCallback CcTerraform;
CommandCallback CcBuildTown;
/* rail_gui.c */
CommandCallback CcPlaySound1E;
CommandCallback CcRailDepot;
CommandCallback CcStation;
CommandCallback CcBuildRailTunnel;
/* road_gui.c */
CommandCallback CcPlaySound1D;
CommandCallback CcBuildRoadTunnel;
CommandCallback CcRoadDepot;
/* roadveh_gui.c */
CommandCallback CcBuildRoadVeh;
CommandCallback CcCloneRoadVeh;
/* ship_gui.c */
CommandCallback CcBuildShip;
CommandCallback CcCloneShip;
/* train_gui.c */
CommandCallback CcBuildWagon;
CommandCallback CcBuildLoco;
CommandCallback CcCloneTrain;
CommandCallback CcAI;
CommandCallback *_callback_table[] = {
/* 0x00 */ NULL,
/* 0x01 */ CcBuildAircraft,
/* 0x02 */ CcBuildAirport,
/* 0x03 */ CcBuildBridge,
/* 0x04 */ CcBuildCanal,
/* 0x05 */ CcBuildDocks,
/* 0x06 */ CcBuildLoco,
/* 0x07 */ CcBuildRoadVeh,
/* 0x08 */ CcBuildShip,
/* 0x09 */ CcBuildTown,
/* 0x0A */ CcBuildRoadTunnel,
/* 0x0B */ CcBuildRailTunnel,
/* 0x0C */ CcBuildWagon,
/* 0x0D */ CcRoadDepot,
/* 0x0E */ CcRailDepot,
/* 0x0F */ CcPlaceSign,
/* 0x10 */ CcPlaySound10,
/* 0x11 */ CcPlaySound1D,
/* 0x12 */ CcPlaySound1E,
/* 0x13 */ CcStation,
/* 0x14 */ CcTerraform,
/* 0x15 */ CcCloneAircraft,
/* 0x16 */ CcCloneRoadVeh,
/* 0x17 */ CcCloneShip,
/* 0x18 */ CcCloneTrain,
/* 0x19 */ CcAI,
/* 0x1A */ CcCloneVehicle
};
const int _callback_table_count = lengthof(_callback_table);

11
callback_table.h Normal file
View File

@@ -0,0 +1,11 @@
/* $Id$ */
#ifndef CALLBACK_TABLE_H
#define CALLBACK_TABLE_H
#include "command.h"
extern CommandCallback *_callback_table[];
extern const int _callback_table_count;
#endif /* CALLBACK_TABLE_H */

File diff suppressed because it is too large Load Diff

794
clear_cmd.c Normal file
View File

@@ -0,0 +1,794 @@
/* $Id$ */
#include "stdafx.h"
#include "openttd.h"
#include "clear_map.h"
#include "rail_map.h"
#include "table/strings.h"
#include "functions.h"
#include "map.h"
#include "player.h"
#include "tile.h"
#include "viewport.h"
#include "command.h"
#include "tunnel_map.h"
#include "variables.h"
#include "table/sprites.h"
#include "unmovable_map.h"
#include "genworld.h"
#include "industry.h"
typedef struct TerraformerHeightMod {
TileIndex tile;
byte height;
} TerraformerHeightMod;
typedef struct TerraformerState {
int height[4];
uint32 flags;
int direction;
int modheight_count;
int tile_table_count;
int32 cost;
TileIndex *tile_table;
TerraformerHeightMod *modheight;
} TerraformerState;
static int TerraformAllowTileProcess(TerraformerState *ts, TileIndex tile)
{
TileIndex *t;
int count;
if (TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY()) return -1;
t = ts->tile_table;
for (count = ts->tile_table_count; count != 0; count--, t++) {
if (*t == tile) return 0;
}
return 1;
}
static int TerraformGetHeightOfTile(TerraformerState *ts, TileIndex tile)
{
TerraformerHeightMod *mod = ts->modheight;
int count;
for (count = ts->modheight_count; count != 0; count--, mod++) {
if (mod->tile == tile) return mod->height;
}
return TileHeight(tile);
}
static void TerraformAddDirtyTile(TerraformerState *ts, TileIndex tile)
{
int count;
TileIndex *t;
count = ts->tile_table_count;
if (count >= 625) return;
for (t = ts->tile_table; count != 0; count--,t++) {
if (*t == tile) return;
}
ts->tile_table[ts->tile_table_count++] = tile;
}
static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile)
{
TerraformAddDirtyTile(ts, tile + TileDiffXY( 0, -1));
TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, -1));
TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, 0));
TerraformAddDirtyTile(ts, tile);
}
static int TerraformProc(TerraformerState *ts, TileIndex tile, int mode)
{
int r;
int32 ret;
assert(tile < MapSize());
r = TerraformAllowTileProcess(ts, tile);
if (r <= 0) return r;
if (IsTileType(tile, MP_RAILWAY)) {
static const TrackBits safe_track[] = { TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER, TRACK_BIT_RIGHT };
static const Slope unsafe_slope[] = { SLOPE_S, SLOPE_W, SLOPE_N, SLOPE_E };
Slope tileh;
uint z;
// Nothing could be built at the steep slope - this avoids a bug
// when you have a single diagonal track in one corner on a
// basement and then you raise/lower the other corner.
tileh = GetTileSlope(tile, &z);
if (tileh == unsafe_slope[mode] ||
tileh == ComplementSlope(unsafe_slope[mode])) {
_terraform_err_tile = tile;
_error_message = STR_1008_MUST_REMOVE_RAILROAD_TRACK;
return -1;
}
// If we have a single diagonal track there, the other side of
// tile can be terraformed.
if (IsPlainRailTile(tile) && GetTrackBits(tile) == safe_track[mode]) {
/* If terraforming downwards prevent damaging a potential tunnel below.
* This check is only necessary for flat tiles, because if the tile is
* non-flat, then the corner opposing the rail is raised. Only this corner
* can be lowered and this is a safe action
*/
if (tileh == SLOPE_FLAT &&
ts->direction == -1 &&
IsTunnelInWay(tile, z - TILE_HEIGHT)) {
_terraform_err_tile = tile;
_error_message = STR_1002_EXCAVATION_WOULD_DAMAGE;
return -1;
}
return 0;
}
}
ret = DoCommand(tile, 0,0, ts->flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
if (CmdFailed(ret)) {
_terraform_err_tile = tile;
return -1;
}
ts->cost += ret;
if (ts->tile_table_count >= 625) return -1;
ts->tile_table[ts->tile_table_count++] = tile;
return 0;
}
static bool TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height)
{
int nh;
TerraformerHeightMod *mod;
int count;
assert(tile < MapSize());
if (height < 0) {
_error_message = STR_1003_ALREADY_AT_SEA_LEVEL;
return false;
}
_error_message = STR_1004_TOO_HIGH;
if (height > 15) return false;
nh = TerraformGetHeightOfTile(ts, tile);
if (nh < 0 || height == nh) return false;
if (TerraformProc(ts, tile, 0) < 0) return false;
if (TerraformProc(ts, tile + TileDiffXY( 0, -1), 1) < 0) return false;
if (TerraformProc(ts, tile + TileDiffXY(-1, -1), 2) < 0) return false;
if (TerraformProc(ts, tile + TileDiffXY(-1, 0), 3) < 0) return false;
mod = ts->modheight;
count = ts->modheight_count;
for (;;) {
if (count == 0) {
if (ts->modheight_count >= 576) return false;
ts->modheight_count++;
break;
}
if (mod->tile == tile) break;
mod++;
count--;
}
mod->tile = tile;
mod->height = (byte)height;
ts->cost += _price.terraform;
{
int direction = ts->direction, r;
const TileIndexDiffC *ttm;
static const TileIndexDiffC _terraform_tilepos[] = {
{ 1, 0},
{-2, 0},
{ 1, 1},
{ 0, -2}
};
for (ttm = _terraform_tilepos; ttm != endof(_terraform_tilepos); ttm++) {
tile += ToTileIndexDiff(*ttm);
r = TerraformGetHeightOfTile(ts, tile);
if (r != height && r-direction != height && r+direction != height) {
if (!TerraformTileHeight(ts, tile, r+direction))
return false;
}
}
}
return true;
}
/** Terraform land
* @param tile tile to terraform
* @param p1 corners to terraform.
* @param p2 direction; eg up or down
*/
int32 CmdTerraformLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
TerraformerState ts;
TileIndex t;
int direction;
TerraformerHeightMod modheight_data[576];
TileIndex tile_table_data[625];
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
_terraform_err_tile = 0;
ts.direction = direction = p2 ? 1 : -1;
ts.flags = flags;
ts.modheight_count = ts.tile_table_count = 0;
ts.cost = 0;
ts.modheight = modheight_data;
ts.tile_table = tile_table_data;
/* Make an extra check for map-bounds cause we add tiles to the originating tile */
if (tile + TileDiffXY(1, 1) >= MapSize()) return CMD_ERROR;
if (p1 & 1) {
t = tile + TileDiffXY(1, 0);
if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
return CMD_ERROR;
}
}
if (p1 & 2) {
t = tile + TileDiffXY(1, 1);
if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
return CMD_ERROR;
}
}
if (p1 & 4) {
t = tile + TileDiffXY(0, 1);
if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
return CMD_ERROR;
}
}
if (p1 & 8) {
t = tile + TileDiffXY(0, 0);
if (!TerraformTileHeight(&ts, t, TileHeight(t) + direction)) {
return CMD_ERROR;
}
}
if (direction == -1) {
/* Check if tunnel would take damage */
int count;
TileIndex *ti = ts.tile_table;
for (count = ts.tile_table_count; count != 0; count--, ti++) {
uint z, t;
TileIndex tile = *ti;
z = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0));
t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0));
if (t <= z) z = t;
t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1));
if (t <= z) z = t;
t = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1));
if (t <= z) z = t;
if (IsTunnelInWay(tile, z * TILE_HEIGHT)) {
return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
}
}
}
if (flags & DC_EXEC) {
/* Clear the landscape at the tiles */
{
int count;
TileIndex *ti = ts.tile_table;
for (count = ts.tile_table_count; count != 0; count--, ti++) {
DoCommand(*ti, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
}
}
/* change the height */
{
int count;
TerraformerHeightMod *mod;
mod = ts.modheight;
for (count = ts.modheight_count; count != 0; count--, mod++) {
TileIndex til = mod->tile;
SetTileHeight(til, mod->height);
TerraformAddDirtyTileAround(&ts, til);
}
}
/* finally mark the dirty tiles dirty */
{
int count;
TileIndex *ti = ts.tile_table;
for (count = ts.tile_table_count; count != 0; count--, ti++) {
MarkTileDirtyByTile(*ti);
}
}
}
return ts.cost;
}
/** Levels a selected (rectangle) area of land
* @param tile end tile of area-drag
* @param p1 start tile of area drag
* @param p2 unused
*/
int32 CmdLevelLand(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
int size_x, size_y;
int ex;
int ey;
int sx, sy;
uint h, curh;
int32 ret, cost, money;
if (p1 >= MapSize()) return CMD_ERROR;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
// remember level height
h = TileHeight(p1);
// make sure sx,sy are smaller than ex,ey
ex = TileX(tile);
ey = TileY(tile);
sx = TileX(p1);
sy = TileY(p1);
if (ex < sx) intswap(ex, sx);
if (ey < sy) intswap(ey, sy);
tile = TileXY(sx, sy);
size_x = ex-sx+1;
size_y = ey-sy+1;
money = GetAvailableMoneyForCommand();
cost = 0;
BEGIN_TILE_LOOP(tile2, size_x, size_y, tile) {
curh = TileHeight(tile2);
while (curh != h) {
ret = DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND);
if (CmdFailed(ret)) break;
cost += ret;
if (flags & DC_EXEC) {
if ((money -= ret) < 0) {
_additional_cash_required = ret;
return cost - ret;
}
DoCommand(tile2, 8, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND);
}
curh += (curh > h) ? -1 : 1;
}
} END_TILE_LOOP(tile2, size_x, size_y, tile)
return (cost == 0) ? CMD_ERROR : cost;
}
/** Purchase a land area. Actually you only purchase one tile, so
* the name is a bit confusing ;p
* @param tile the tile the player is purchasing
* @param p1 unused
* @param p2 unused
*/
int32 CmdPurchaseLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
int32 cost;
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
if (!EnsureNoVehicle(tile)) return CMD_ERROR;
if (IsOwnedLandTile(tile) && IsTileOwner(tile, _current_player)) {
return_cmd_error(STR_5807_YOU_ALREADY_OWN_IT);
}
cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (CmdFailed(cost)) return CMD_ERROR;
if (flags & DC_EXEC) {
MakeOwnedLand(tile, _current_player);
MarkTileDirtyByTile(tile);
}
return cost + _price.purchase_land * 10;
}
static int32 ClearTile_Clear(TileIndex tile, byte flags)
{
static const int32* clear_price_table[] = {
&_price.clear_1,
&_price.purchase_land,
&_price.clear_2,
&_price.clear_3,
&_price.purchase_land,
&_price.purchase_land,
&_price.clear_2, // XXX unused?
};
int32 price;
if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
price = 0;
} else {
price = *clear_price_table[GetClearGround(tile)];
}
if (flags & DC_EXEC) DoClearSquare(tile);
return price;
}
/** Sell a land area. Actually you only sell one tile, so
* the name is a bit confusing ;p
* @param tile the tile the player is selling
* @param p1 unused
* @param p2 unused
*/
int32 CmdSellLandArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
if (!IsOwnedLandTile(tile)) return CMD_ERROR;
if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER) return CMD_ERROR;
if (!EnsureNoVehicle(tile)) return CMD_ERROR;
if (flags & DC_EXEC) DoClearSquare(tile);
return - _price.purchase_land * 2;
}
#include "table/clear_land.h"
void DrawClearLandTile(const TileInfo *ti, byte set)
{
DrawGroundSprite(SPR_FLAT_BARE_LAND + _tileh_to_sprite[ti->tileh] + set * 19);
}
void DrawHillyLandTile(const TileInfo *ti)
{
if (ti->tileh != SLOPE_FLAT) {
DrawGroundSprite(SPR_FLAT_ROUGH_LAND + _tileh_to_sprite[ti->tileh]);
} else {
DrawGroundSprite(_landscape_clear_sprites[GB(ti->x ^ ti->y, 4, 3)]);
}
}
void DrawClearLandFence(const TileInfo *ti)
{
byte z = ti->z;
if (ti->tileh & SLOPE_S) {
z += TILE_HEIGHT;
if (ti->tileh == SLOPE_STEEP_S) z += TILE_HEIGHT;
}
if (GetFenceSW(ti->tile) != 0) {
DrawGroundSpriteAt(_clear_land_fence_sprites_1[GetFenceSW(ti->tile) - 1] + _fence_mod_by_tileh[ti->tileh], ti->x, ti->y, z);
}
if (GetFenceSE(ti->tile) != 0) {
DrawGroundSpriteAt(_clear_land_fence_sprites_1[GetFenceSE(ti->tile) - 1] + _fence_mod_by_tileh_2[ti->tileh], ti->x, ti->y, z);
}
}
static void DrawTile_Clear(TileInfo *ti)
{
switch (GetClearGround(ti->tile)) {
case CLEAR_GRASS:
DrawClearLandTile(ti, GetClearDensity(ti->tile));
break;
case CLEAR_ROUGH:
DrawHillyLandTile(ti);
break;
case CLEAR_ROCKS:
DrawGroundSprite(SPR_FLAT_ROCKY_LAND_1 + _tileh_to_sprite[ti->tileh]);
break;
case CLEAR_FIELDS:
DrawGroundSprite(_clear_land_sprites_1[GetFieldType(ti->tile)] + _tileh_to_sprite[ti->tileh]);
break;
case CLEAR_SNOW:
DrawGroundSprite(_clear_land_sprites_2[GetClearDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]);
break;
case CLEAR_DESERT:
DrawGroundSprite(_clear_land_sprites_3[GetClearDensity(ti->tile)] + _tileh_to_sprite[ti->tileh]);
break;
}
DrawClearLandFence(ti);
}
static uint GetSlopeZ_Clear(TileIndex tile, uint x, uint y)
{
uint z;
uint tileh = GetTileSlope(tile, &z);
return z + GetPartialZ(x & 0xF, y & 0xF, tileh);
}
static Slope GetSlopeTileh_Clear(TileIndex tile, Slope tileh)
{
return tileh;
}
static void GetAcceptedCargo_Clear(TileIndex tile, AcceptedCargo ac)
{
/* unused */
}
static void AnimateTile_Clear(TileIndex tile)
{
/* unused */
}
void TileLoopClearHelper(TileIndex tile)
{
byte self;
byte neighbour;
TileIndex dirty = INVALID_TILE;
self = (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS));
neighbour = (IsTileType(TILE_ADDXY(tile, 1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 1, 0), CLEAR_FIELDS));
if (GetFenceSW(tile) == 0) {
if (self != neighbour) {
SetFenceSW(tile, 3);
dirty = tile;
}
} else {
if (self == 0 && neighbour == 0) {
SetFenceSW(tile, 0);
dirty = tile;
}
}
neighbour = (IsTileType(TILE_ADDXY(tile, 0, 1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, 1), CLEAR_FIELDS));
if (GetFenceSE(tile) == 0) {
if (self != neighbour) {
SetFenceSE(tile, 3);
dirty = tile;
}
} else {
if (self == 0 && neighbour == 0) {
SetFenceSE(tile, 0);
dirty = tile;
}
}
if (dirty != INVALID_TILE) MarkTileDirtyByTile(dirty);
}
/* convert into snowy tiles */
static void TileLoopClearAlps(TileIndex tile)
{
int k = GetTileZ(tile) - _opt.snow_line + TILE_HEIGHT;
if (k < 0) { // well below the snow line
if (!IsClearGround(tile, CLEAR_SNOW)) return;
if (GetClearDensity(tile) == 0) SetClearGroundDensity(tile, CLEAR_GRASS, 3);
} else {
if (!IsClearGround(tile, CLEAR_SNOW)) {
SetClearGroundDensity(tile, CLEAR_SNOW, 0);
} else {
uint density = min((uint)k / TILE_HEIGHT, 3);
if (GetClearDensity(tile) < density) {
AddClearDensity(tile, 1);
} else if (GetClearDensity(tile) > density) {
AddClearDensity(tile, -1);
} else {
return;
}
}
}
MarkTileDirtyByTile(tile);
}
static void TileLoopClearDesert(TileIndex tile)
{
if (IsClearGround(tile, CLEAR_DESERT)) return;
if (GetTropicZone(tile) == TROPICZONE_DESERT) {
SetClearGroundDensity(tile, CLEAR_DESERT, 3);
} else {
if (GetTropicZone(tile + TileDiffXY( 1, 0)) != TROPICZONE_DESERT &&
GetTropicZone(tile + TileDiffXY(-1, 0)) != TROPICZONE_DESERT &&
GetTropicZone(tile + TileDiffXY( 0, 1)) != TROPICZONE_DESERT &&
GetTropicZone(tile + TileDiffXY( 0, -1)) != TROPICZONE_DESERT)
return;
SetClearGroundDensity(tile, CLEAR_DESERT, 1);
}
MarkTileDirtyByTile(tile);
}
static void TileLoop_Clear(TileIndex tile)
{
TileLoopClearHelper(tile);
switch (_opt.landscape) {
case LT_DESERT: TileLoopClearDesert(tile); break;
case LT_HILLY: TileLoopClearAlps(tile); break;
}
switch (GetClearGround(tile)) {
case CLEAR_GRASS:
if (GetClearDensity(tile) == 3) return;
if (_game_mode != GM_EDITOR) {
if (GetClearCounter(tile) < 7) {
AddClearCounter(tile, 1);
return;
} else {
SetClearCounter(tile, 0);
AddClearDensity(tile, 1);
}
} else {
SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS : CLEAR_ROUGH, 3);
}
break;
case CLEAR_FIELDS: {
uint field_type;
if (_game_mode == GM_EDITOR) return;
if (GetClearCounter(tile) < 7) {
AddClearCounter(tile, 1);
return;
} else {
SetClearCounter(tile, 0);
}
if (GetIndustryIndexOfField(tile) == INVALID_INDUSTRY && GetFieldType(tile) >= 7) {
/* This farmfield is no longer farmfield, so make it grass again */
MakeClear(tile, CLEAR_GRASS, 2);
} else {
field_type = GetFieldType(tile);
field_type = (field_type < 8) ? field_type + 1 : 0;
SetFieldType(tile, field_type);
}
break;
}
default:
return;
}
MarkTileDirtyByTile(tile);
}
void GenerateClearTile(void)
{
uint i, gi;
TileIndex tile;
/* add rough tiles */
i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400);
gi = ScaleByMapSize(GB(Random(), 0, 7) + 0x80);
SetGeneratingWorldProgress(GWP_ROUGH_ROCKY, gi + i);
do {
IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
tile = RandomTile();
if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) SetClearGroundDensity(tile, CLEAR_ROUGH, 3);
} while (--i);
/* add rocky tiles */
i = gi;
do {
uint32 r = Random();
tile = RandomTileSeed(r);
IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY);
if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) {
uint j = GB(r, 16, 4) + 5;
for (;;) {
TileIndex tile_new;
SetClearGroundDensity(tile, CLEAR_ROCKS, 3);
do {
if (--j == 0) goto get_out;
tile_new = tile + TileOffsByDiagDir(GB(Random(), 0, 2));
} while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT));
tile = tile_new;
}
get_out:;
}
} while (--i);
}
static void ClickTile_Clear(TileIndex tile)
{
/* not used */
}
static uint32 GetTileTrackStatus_Clear(TileIndex tile, TransportType mode)
{
return 0;
}
static const StringID _clear_land_str[] = {
STR_080D_GRASS,
STR_080B_ROUGH_LAND,
STR_080A_ROCKS,
STR_080E_FIELDS,
STR_080F_SNOW_COVERED_LAND,
STR_0810_DESERT
};
static void GetTileDesc_Clear(TileIndex tile, TileDesc *td)
{
if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) {
td->str = STR_080C_BARE_LAND;
} else {
td->str = _clear_land_str[GetClearGround(tile)];
}
td->owner = GetTileOwner(tile);
}
static void ChangeTileOwner_Clear(TileIndex tile, PlayerID old_player, PlayerID new_player)
{
return;
}
void InitializeClearLand(void)
{
_opt.snow_line = _patches.snow_line_height * TILE_HEIGHT;
}
const TileTypeProcs _tile_type_clear_procs = {
DrawTile_Clear, /* draw_tile_proc */
GetSlopeZ_Clear, /* get_slope_z_proc */
ClearTile_Clear, /* clear_tile_proc */
GetAcceptedCargo_Clear, /* get_accepted_cargo_proc */
GetTileDesc_Clear, /* get_tile_desc_proc */
GetTileTrackStatus_Clear, /* get_tile_track_status_proc */
ClickTile_Clear, /* click_tile_proc */
AnimateTile_Clear, /* animate_tile_proc */
TileLoop_Clear, /* tile_loop_clear */
ChangeTileOwner_Clear, /* change_tile_owner_clear */
NULL, /* get_produced_cargo_proc */
NULL, /* vehicle_enter_tile_proc */
GetSlopeTileh_Clear, /* get_slope_tileh_proc */
};

145
clear_map.h Normal file
View File

@@ -0,0 +1,145 @@
/* $Id$ */
#ifndef CLEAR_MAP_H
#define CLEAR_MAP_H
#include "macros.h"
#include "tile.h"
/* ground type, m5 bits 2...4
* valid densities (bits 0...1) in comments after the enum
*/
typedef enum ClearGround {
CLEAR_GRASS = 0, // 0-3
CLEAR_ROUGH = 1, // 3
CLEAR_ROCKS = 2, // 3
CLEAR_FIELDS = 3, // 3
CLEAR_SNOW = 4, // 0-3
CLEAR_DESERT = 5 // 1,3
} ClearGround;
static inline ClearGround GetClearGround(TileIndex t)
{
assert(IsTileType(t, MP_CLEAR));
return GB(_m[t].m5, 2, 3);
}
static inline bool IsClearGround(TileIndex t, ClearGround ct)
{
return GetClearGround(t) == ct;
}
static inline uint GetClearDensity(TileIndex t)
{
assert(IsTileType(t, MP_CLEAR));
return GB(_m[t].m5, 0, 2);
}
static inline void AddClearDensity(TileIndex t, int d)
{
assert(IsTileType(t, MP_CLEAR)); // XXX incomplete
_m[t].m5 += d;
}
static inline uint GetClearCounter(TileIndex t)
{
assert(IsTileType(t, MP_CLEAR));
return GB(_m[t].m5, 5, 3);
}
static inline void AddClearCounter(TileIndex t, int c)
{
assert(IsTileType(t, MP_CLEAR)); // XXX incomplete
_m[t].m5 += c << 5;
}
static inline void SetClearCounter(TileIndex t, uint c)
{
assert(IsTileType(t, MP_CLEAR)); // XXX incomplete
SB(_m[t].m5, 5, 3, c);
}
/* Sets type and density in one go, also sets the counter to 0 */
static inline void SetClearGroundDensity(TileIndex t, ClearGround type, uint density)
{
assert(IsTileType(t, MP_CLEAR)); // XXX incomplete
_m[t].m5 = 0 << 5 | type << 2 | density;
}
static inline uint GetFieldType(TileIndex t)
{
assert(GetClearGround(t) == CLEAR_FIELDS);
return GB(_m[t].m3, 0, 4);
}
static inline void SetFieldType(TileIndex t, uint f)
{
assert(GetClearGround(t) == CLEAR_FIELDS); // XXX incomplete
SB(_m[t].m3, 0, 4, f);
}
static inline uint16 GetIndustryIndexOfField(TileIndex t)
{
assert(GetClearGround(t) == CLEAR_FIELDS);
return _m[t].m2;
}
static inline void SetIndustryIndexOfField(TileIndex t, uint16 i)
{
assert(GetClearGround(t) == CLEAR_FIELDS);
_m[t].m2 = i;
}
/* Is used by tree tiles, too */
static inline uint GetFenceSE(TileIndex t)
{
assert(IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES));
return GB(_m[t].m4, 2, 3);
}
static inline void SetFenceSE(TileIndex t, uint h)
{
assert(IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES)); // XXX incomplete
SB(_m[t].m4, 2, 3, h);
}
static inline uint GetFenceSW(TileIndex t)
{
assert(IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES));
return GB(_m[t].m4, 5, 3);
}
static inline void SetFenceSW(TileIndex t, uint h)
{
assert(IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES)); // XXX incomplete
SB(_m[t].m4, 5, 3, h);
}
static inline void MakeClear(TileIndex t, ClearGround g, uint density)
{
SetTileType(t, MP_CLEAR);
SetTileOwner(t, OWNER_NONE);
_m[t].m2 = 0;
_m[t].m3 = 0;
_m[t].m4 = 0 << 5 | 0 << 2;
SetClearGroundDensity(t, g, density);
}
static inline void MakeField(TileIndex t, uint field_type, uint16 industry)
{
SetTileType(t, MP_CLEAR);
SetTileOwner(t, OWNER_NONE);
_m[t].m2 = industry;
_m[t].m3 = field_type;
_m[t].m4 = 0 << 5 | 0 << 2;
SetClearGroundDensity(t, CLEAR_FIELDS, 3);
}
#endif /* CLEAR_MAP_H */

View File

@@ -1,145 +0,0 @@
macro(_parse_arguments_with_multi_hack ORIGINAL_COMMAND_LINE)
# cmake_parse_arguments() put all the MULTIS in a single variable; you
# lose the ability to see for example multiple COMMANDs. To be able to
# passthrough multiple MULTIS, we add a marker after every MULTI. This
# allows us to reassemble the correct amount again before giving it to
# the wrapped command with _reassemble_command_line().
set(COMMAND_LINE "${ORIGINAL_COMMAND_LINE}")
foreach(MULTI IN LISTS MULTIS)
string(REPLACE "${MULTI}" "${MULTI};:::" COMMAND_LINE "${COMMAND_LINE}")
endforeach()
cmake_parse_arguments(PARAM "${OPTIONS}" "${SINGLES}" "${MULTIS}" ${COMMAND_LINE})
endmacro()
macro(_reassemble_command_line)
# Reassemble the command line as we original got it.
set(NEW_COMMAND_LINE ${PARAM_UNPARSED_ARGUMENTS})
foreach(OPTION IN LISTS OPTIONS)
if(PARAM_${OPTION})
list(APPEND NEW_COMMAND_LINE "${OPTION}")
endif()
endforeach()
foreach(SINGLE IN LISTS SINGLES)
if(PARAM_${SINGLE})
list(APPEND NEW_COMMAND_LINE "${SINGLE}" "${PARAM_${SINGLE}}")
endif()
endforeach()
foreach(MULTI IN LISTS MULTIS)
if(PARAM_${MULTI})
# Replace our special marker with the name of the MULTI again. This
# restores for example multiple COMMANDs again.
string(REPLACE ":::" "${MULTI}" PARAM_${MULTI} "${PARAM_${MULTI}}")
list(APPEND NEW_COMMAND_LINE "${PARAM_${MULTI}}")
endif()
endforeach()
endmacro()
# Generated files can be older than their dependencies, causing useless
# regenerations. This function replaces each file in OUTPUT with a .timestamp
# file, adds a command to touch it and move the original file in BYPRODUCTS,
# before calling add_custom_command().
#
# Note: Any add_custom_target() depending on files in original OUTPUT must use
# add_custom_target_timestamp() instead to have the correct dependencies.
#
# add_custom_command_timestamp(OUTPUT output1 [output2 ...]
# COMMAND command1 [ARGS] [args1...]
# [COMMAND command2 [ARGS] [args2...] ...]
# [MAIN_DEPENDENCY depend]
# [DEPENDS [depends...]]
# [BYPRODUCTS [files...]]
# [IMPLICIT_DEPENDS <lang1> depend1
# [<lang2> depend2] ...]
# [WORKING_DIRECTORY dir]
# [COMMENT comment]
# [VERBATIM] [APPEND] [USES_TERMINAL])
function(add_custom_command_timestamp)
set(OPTIONS VERBATIM APPEND USES_TERMINAL)
set(SINGLES MAIN_DEPENDENCY WORKING_DIRECTORY COMMENT)
set(MULTIS OUTPUT COMMAND DEPENDS BYPRODUCTS IMPLICIT_DEPENDS)
_parse_arguments_with_multi_hack("${ARGN}")
# Create a list of all the OUTPUTs (by removing our magic marker)
string(REPLACE ":::;" "" OUTPUTS "${PARAM_OUTPUT}")
# Reset the OUTPUT and BYPRODUCTS as an empty list (if needed).
# Because they are MULTIS, we need to add our special marker here.
set(PARAM_OUTPUT ":::")
if(NOT PARAM_BYPRODUCTS)
set(PARAM_BYPRODUCTS ":::")
endif()
foreach(OUTPUT IN LISTS OUTPUTS)
# For every output, we add a 'cmake -E touch' entry to update the
# timestamp on each run.
get_filename_component(OUTPUT_FILENAME ${OUTPUT} NAME)
string(APPEND PARAM_COMMAND ";:::;${CMAKE_COMMAND};-E;touch;${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILENAME}.timestamp")
# We change the OUTPUT to a '.timestamp' variant, and make the real
# output a byproduct.
list(APPEND PARAM_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILENAME}.timestamp)
list(APPEND PARAM_BYPRODUCTS ${OUTPUT})
# Mark this file as being a byproduct; we use this again with
# add_custom_target_timestamp() to know if we should point to the
# '.timestamp' variant or not.
set_source_files_properties(${OUTPUT} PROPERTIES BYPRODUCT ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILENAME}.timestamp)
endforeach()
# Reassemble and call the wrapped command
_reassemble_command_line()
add_custom_command(${NEW_COMMAND_LINE})
endfunction()
# Generated files can be older than their dependencies, causing useless
# regenerations. This function adds a .timestamp file for each file in DEPENDS
# replaced by add_custom_command_timestamp(), before calling add_custom_target().
#
# add_custom_target_timestamp(Name [ALL] [command1 [args1...]]
# [COMMAND command2 [args2...] ...]
# [DEPENDS depend depend depend ... ]
# [BYPRODUCTS [files...]]
# [WORKING_DIRECTORY dir]
# [COMMENT comment]
# [VERBATIM] [USES_TERMINAL]
# [SOURCES src1 [src2...]])
function(add_custom_target_timestamp)
set(OPTIONS VERBATIM USES_TERMINAL)
set(SINGLES WORKING_DIRECTORY COMMENT)
set(MULTIS COMMAND DEPENDS BYPRODUCTS SOURCES)
# ALL is missing, as the order is important here. It will be picked up
# by ${PARAM_UNPARSED_ARGUMENTS} when reassembling the command line.
_parse_arguments_with_multi_hack("${ARGN}")
# Create a list of all the DEPENDs (by removing our magic marker)
string(REPLACE ":::;" "" DEPENDS "${PARAM_DEPENDS}")
# Reset the DEPEND as an empty list.
# Because it is a MULTI, we need to add our special marker here.
set(PARAM_DEPENDS ":::")
foreach(DEPEND IN LISTS DEPENDS)
# Check if the output is produced by add_custom_command_timestamp()
get_source_file_property(BYPRODUCT ${DEPEND} BYPRODUCT)
if(BYPRODUCT STREQUAL "NOTFOUND")
# If it is not, just keep it as DEPEND
list(APPEND PARAM_DEPENDS "${DEPEND}")
else()
# If it is, the BYPRODUCT property points to the timestamp we want to depend on
list(APPEND PARAM_DEPENDS "${BYPRODUCT}")
endif()
endforeach()
# Reassemble and call the wrapped command
_reassemble_command_line()
add_custom_target(${NEW_COMMAND_LINE})
endfunction()

Some files were not shown because too many files have changed in this diff Show More