mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-06 06:32:56 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
51
readme.md
51
readme.md
@@ -1,5 +1,5 @@
|
||||
# OpenRCT2
|
||||
An open source clone of Roller Coaster Tycoon 2 built by decompiling the original game one bit at a time.
|
||||
An open source clone of RollerCoaster Tycoon 2 built by decompiling the original game one bit at a time.
|
||||
- [Screenshot 1, cheats window](http://dev.intelorca.co.uk/2014/openrct2/cheats.png)
|
||||
- [Screenshot 2, large land tool area](http://i.imgur.com/kTkK5Gw.png)
|
||||
- [Screenshot 3, high resolution](http://i.imgur.com/yFzNyVu.jpg)
|
||||
@@ -24,18 +24,28 @@ An open source clone of Roller Coaster Tycoon 2 built by decompiling the origina
|
||||
# 1 Introduction
|
||||
|
||||
## 1.1 Background
|
||||
**OpenRCT2** is an attempt to decompile RollerCoaster Tycoon 2 into C. RollerCoaster Tycoon 2 was originally written in MASM and Visual C++ where functions related to interfacing with the operating system were written in C (supposedly 1%) and the rest of the game in pure x86 assembly. OpenTTD went through the same treatment where Transport Tycoon Deluxe was decompiled into C and then have thousands of more features added to the game. RollerCoaster Tycoon 2 uses the third version of Chris Sawyer's engine. It still shares some code seen in Transport Tycoon and this is reflected in OpenTTD 0.1 such as the window system and graphics rendering. Chris Sawyer's Locomotion is a more up to date version, however OpenRCT2 will only use RollerCoaster Tycoon 2's engine code for now.
|
||||
**OpenRCT2** is an attempt to decompile RollerCoaster Tycoon 2 into C. RollerCoaster Tycoon 2 was originally written in MASM and Visual C++ where functions related to interfacing with the operating system were written in C (supposedly 1%), with the rest of the game being written in pure x86 assembly. For an example of this method, OpenTTD was formed through a similar procedure; the original game, Transport Tycoon Deluxe, was decompiled into C which allowed for the addition of thousands of features to the game. RollerCoaster Tycoon 2 uses the third version of Chris Sawyer's engine, which shares some code with Transport Tycoon. This is reflected in the usage of OpenTTD 0.1 code such as the windowing system and graphics rendering. While the version of the engine used in Chris Sawyer's Locomotion is newer, OpenRCT2 is currently targeting the RollerCoaster Tycoon 2 engine to ease the decompilation process.
|
||||
|
||||
## 1.2 Decompiling the game
|
||||
In order to decompile the game gradually and successfully, each procedure in RollerCoaster Tycoon 2 is to be re-written in C one by one. To help test the accuracy of the re-written procedures, the decompiled C procedures are compiled into a DLL (*openrct2.dll*) which exports an entry procedure mimicking the WinMain function in RollerCoaster Tycoon 2. The original executable *rct2.exe* has been patched so that *openrct2.dll* and WinMain are in the DLL import table and the WinMain export procedure in *openrct2.dll* is called at the start of the WinMain procedure in *rct2.exe* before returning. This way, starting rct2.exe now simply calls the new DLL which can then run all the decompiled code whilst still able to read / write to the *rct2.exe* memory model and run *rct2.exe* procedures.
|
||||
In order to decompile the game gradually without introducing new bugs, each procedure in RollerCoaster Tycoon 2 is to be re-written in C on an individual basis. To test the accuracy of the re-written procedures, the decompiled C procedures are compiled into a DLL (*openrct2.dll*) which exports an entry procedure mimicking the WinMain function in RollerCoaster Tycoon 2. The original executable *rct2.exe* has been patched so that *openrct2.dll* and WinMain are in the DLL import table and the WinMain export procedure in *openrct2.dll* is called at the start of the WinMain procedure in *rct2.exe* before returning. With this system implemented, starting rct2.exe calls the new DLL as part of its initialization; the DLL can then run all the decompiled code whilst still being able to read / write to the *rct2.exe* memory model and run *rct2.exe* procedures.
|
||||
|
||||
The project therefore acts as a patch to RollerCoaster Tycoon 2 which can gradually implement each procedure whilst also adding new features where possible. Until all procedures of the original game are re-written in C, the project must remain a DLL which is called from the patched *rct2.exe*.
|
||||
The project therefore acts as a patch to RollerCoaster Tycoon 2, allowing each procedure to be gradually implemented while simultaneously adding new features where possible. Until all procedures of the original game are re-written in C, the project must remain a DLL which is called from the patched *rct2.exe*.
|
||||
|
||||
## 1.3 Progress
|
||||
Currently the window system, graphics rendering and basic game loop are gradually being decompiled. Decompiling the all the game windows is a convenient way of identifying the game's memory structure. SDL2 has been used to replace the operating system calls so that game is cross-platform after the original game is no longer required.
|
||||
Currently, the windowing system, graphics rendering and basic game loop are being decompiled. Decompiling all of the game's procedures is a convenient way of identifying the game's memory structure. SDL2 has been used as a replacement for the operating system calls, allowing for cross-platform support after the dependency on the original game's executable has been removed.
|
||||
|
||||
## 1.4 Aim
|
||||
The aim is to decompile RollerCoaster Tycoon 2 fully into C so that it can remain a cross platform game which runs on the latest operating systems with new features introduced and game play experience to be improved just like OpenTTD. Allowing the game to run in a resizeable window has already been accomplished using SDL2. Once the game has been fully decompiled, game logic such as peep path-finding, window / ride / object / map / construction limits increased, more sandbox friendly, editing available objects during a game, improved title sequence, mechanics only found in RCT1 (e.g. Shuttle Loop compatibility, pay for rides and park, have fun objective, finish five coasters objective, mountain tool during game) and lots more.
|
||||
The aim is to completely decompile RollerCoaster Tycoon 2 into C so that cross-platform support, new features, and new gameplay can be added in a similar fashion to OpenTTD. With the addition of SDL2, the game can already be run in a resizeable window (which was not possible originally). Once the game has been fully decompiled, additional gameplay features, gameplay tweaks, and improvements can be introduced. The following is only a brief, non-exhaustive list of the possibilities - there is much more possible:
|
||||
- Improved peep path-finding
|
||||
- Increased window / ride / object / map / construction limits
|
||||
- More sandbox-friendly gameplay
|
||||
- Editing available objects
|
||||
- Improved title sequence
|
||||
- Re-introduction of RollerCoaster Tycoon 1 mechanics
|
||||
- Shuttle Loop compatibility
|
||||
- Have Fun! objective
|
||||
- Finish building five coasters objective
|
||||
- Using the mountain tool during the game
|
||||
|
||||
# 2 Building the source code
|
||||
|
||||
@@ -46,27 +56,36 @@ The aim is to decompile RollerCoaster Tycoon 2 fully into C so that it can remai
|
||||
- [SDL2 development library for Visual C++](http://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip).
|
||||
|
||||
## 2.2 Compiling and running
|
||||
1. Checkout the repository. This can be done using [GitHub Windows](https://windows.github.com/) or [other tools](https://help.github.com/articles/which-remote-url-should-i-use).
|
||||
2. Download [SDL2 development library for Visual C++]((http://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip)) and copy it to a new directory called "sdl" in the repository. This directory should contain "include". The path should be something like ```\GitHub\OpenRCT2\sdl\include\```.
|
||||
1. Check out the repository. This can be done using [GitHub Windows](https://windows.github.com/) or [other tools](https://help.github.com/articles/which-remote-url-should-i-use).
|
||||
2. Download the [SDL2 development library for Visual C++]((http://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip)) and copy it to a new directory called "sdl" in the repository. This directory should contain "include". The path should resemble ```\OpenRCT2\sdl\include\```.
|
||||
3. Open the solution in the projects directory (**openrct2.vcxproj**) with Visual C++.
|
||||
4. In *rct2.c*, ```GAME_PATH``` **must** be edited to reflect your RollerCoaster Tycoon 2 installation. Each slash needs to be marked twice, like this: ```C:\\Program Files (x86)\\GOGcom\\RollerCoaster Tycoon 2\\RollerCoaster Tycoon 2 Triple Thrill Pack```. Existing registry keys and the original RCT2 executable are not required.
|
||||
5. [Select the 'Release' configuration](http://msdn.microsoft.com/en-us/library/wx0123s5.aspx) and click Build -> Rebuild Solution. The dropdown menu to enable the 'release' configuration is towards the top of the VS Express window, near the "TEST" menu.
|
||||
6. Start debugging. Press the "Local Windows Debugger" button with a green "play" icon next to it. If warned about *openrct2.exe* not having debug information, just continue.
|
||||
7. If the game crashes, you may need to press the red, square button along the top of VS Express (for "stop") to stop the program.
|
||||
4. [Select the 'Release' configuration](http://msdn.microsoft.com/en-us/library/wx0123s5.aspx) and click Build -> Rebuild Solution. The dropdown menu to enable the 'release' configuration is towards the top of the VS Express window, near the "TEST" menu.
|
||||
5. Start debugging. Press the "Local Windows Debugger" button with a green "play" icon next to it. If Visual Studio shows a warning about *openrct2.exe* not having debug information, press Continue.
|
||||
6. When OpenRCT2 is run for the first time, it creates a settings file in `My Documents/OpenRCT2`. If it can't find the original installation of RCT2, you will need to edit `config.ini` in that folder and change the value of `game_path` to where RCT2 is installed.
|
||||
7. If the game crashes, you may need to press the red, square Stop button along the top of VS Express to stop the program.
|
||||
|
||||
# 3 Contributing
|
||||
|
||||
## 3.1 Decompiling
|
||||
Experience with reverse engineering and x86 assembly is neccessary to decompile the original game. The game is currently being decompiled using IDA. Feel free to to take a procedure that hasn't currently been decompiled and decompile it. Contact IntelOrca for more information and for the lastest IDA database.
|
||||
Experience with reverse engineering and x86 assembly is necessary to decompile the original game. [IDA 5.0](https://www.hex-rays.com/products/ida/support/download_freeware.shtml) is currently being used to disassemble and analyze the game. You are welcome to contribute to the process by taking an undecompiled procedure, disassembling it, and rewriting it in C. For more information and the latest IDA database, contact IntelOrca.
|
||||
|
||||
## 3.2 Naming of procedures and variables
|
||||
Many variables and procedures are referenced in OpenRCT2 only by address. This may be because their function has not yet been identified. These can often be identified by removing their call and checking how they affect the game or reverse engineering the original game assembly to see where it is called / used.
|
||||
During the development phase, many variables and procedures are referenced by their memory address in OpenRCT2. This is a result of ongoing reverse engineering efforts; the functionality and use of these values has yet to be determined. To help with identification, there are multiple methods you can use.
|
||||
For variables:
|
||||
- Modify the variable and see how the game is affected
|
||||
- Reverse-engineer RCT2 and find where the variable is used or modified
|
||||
|
||||
For procedures:
|
||||
- Remove the call to the procedure in OpenRCT2 and observe the effects
|
||||
- Reverse-engineer RCT2 and find where the procedure is called
|
||||
|
||||
## 3.3 Cleaning and documenting the source code
|
||||
A lot of the source code is undocumented and messy. Whilst the structure of the code should be kept the same so that it closely resembles the original game. Various blocks of code can be moved into smaller functions and macros can be created for common operations.
|
||||
As the source code is formed from decompilation, it is unorganized and undocumented. Efforts towards cleaning up and documenting code are appreciated; for example, blocks of code can be moved into their own functions, and macros can be created for operations that occur frequently. However, be aware that the overall structure of the code should remain the same to ensure that OpenRCT2 is kept in sync with the original game to ease the integration of additional decompiled code.
|
||||
|
||||
In general, small changes that improve code quality and make it easier to reason about the logic are appreciated. More significant changes, such as changing the game's architecture, are to be avoided during the ongoing decompilation of the original game.
|
||||
|
||||
## 3.4 Implementing new features / fixing bugs
|
||||
If enough of the game has been decompiled to implement a certain feature or fix a certain bug. This can be written. Comments should be added to clearly identify where code has been changed on purpose causing it to differ from the original game assembly.
|
||||
While decompilation is an ongoing process, this does not prohibit changes being made to the game. New features or bugfixes can be added, with caution, if the underlying code has been decompiled. When implementing these changes, ensure that comments are added to clearly identify where code has been intentionally changed so that it functions differently to the original game; this is essential to ensuring all research from reverse-engineering can still be applied.
|
||||
|
||||
# 4 License
|
||||
**OpenRCT2** is licensed under the GNU General Public License version 3.
|
||||
|
||||
10
src/config.c
10
src/config.c
@@ -227,7 +227,7 @@ static void config_create_default(char *path)
|
||||
fp = fopen(path, "w");
|
||||
fprintf(fp, "[general]\n");
|
||||
fprintf(fp, "game_path = %s\n", gConfig.game_path);
|
||||
fprintf(fp, "screenshot_format = 1\n");
|
||||
fprintf(fp, "screenshot_format = PNG\n");
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
@@ -253,10 +253,12 @@ static void config_parse_settings(FILE *fp)
|
||||
if (strcmp(setting, "game_path") == 0){
|
||||
strcpy(gConfig.game_path, value);
|
||||
} else if(strcmp(setting, "screenshot_format") == 0) {
|
||||
if (strcmp(value, "1") == 0) {
|
||||
gConfig.screenshot_format = 1;
|
||||
if (strcmp(value, "png") == 0 || strcmp(value, "PNG") == 0) {
|
||||
gConfig.screenshot_format = SCREENSHOT_FORMAT_PNG;
|
||||
} else if (strcmp(value, "1") == 0) { // Maybe remove that? WARNING: Breaks existing config files
|
||||
gConfig.screenshot_format = SCREENSHOT_FORMAT_PNG;
|
||||
} else {
|
||||
gConfig.screenshot_format = 0;
|
||||
gConfig.screenshot_format = SCREENSHOT_FORMAT_BMP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,11 @@ enum {
|
||||
SHORTCUT_COUNT
|
||||
};
|
||||
|
||||
enum {
|
||||
SCREENSHOT_FORMAT_BMP,
|
||||
SCREENSHOT_FORMAT_PNG
|
||||
};
|
||||
|
||||
extern uint16 gShortcutKeys[SHORTCUT_COUNT];
|
||||
|
||||
void config_reset_shortcut_keys();
|
||||
|
||||
10
src/game.c
10
src/game.c
@@ -1190,10 +1190,10 @@ static void load_landscape()
|
||||
RCT2_CALLPROC_EBPSAFE(0x006758C0); // landscape_load
|
||||
if (1) {
|
||||
gfx_invalidate_screen();
|
||||
// game_loop_iteration
|
||||
rct2_endupdate();
|
||||
} else {
|
||||
RCT2_GLOBAL(0x009DEA66, uint16) = 0;
|
||||
// game_loop_iteration
|
||||
rct2_endupdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1223,10 +1223,10 @@ static void load_game()
|
||||
RCT2_CALLPROC_EBPSAFE(0x00675E1B); // game_load
|
||||
if (1) {
|
||||
gfx_invalidate_screen();
|
||||
// game_loop_iteration
|
||||
rct2_endupdate();
|
||||
} else {
|
||||
RCT2_GLOBAL(0x009DEA66, uint16) = 0;
|
||||
// game_loop_iteration
|
||||
rct2_endupdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1260,7 +1260,7 @@ void game_load_or_quit_no_save_prompt()
|
||||
RCT2_GLOBAL(0x009DE518, uint32) &= ~(1 << 5);
|
||||
}
|
||||
title_load();
|
||||
// game_loop_iteration
|
||||
rct2_endupdate();
|
||||
} else {
|
||||
rct2_exit();
|
||||
}
|
||||
|
||||
27
src/map.c
27
src/map.c
@@ -54,6 +54,23 @@ void map_element_set_terrain_edge(rct_map_element *element, int terrain)
|
||||
element->properties.surface.slope = (terrain & 7) << 5;
|
||||
}
|
||||
|
||||
rct_map_element *map_get_surface_element_at(int x, int y)
|
||||
{
|
||||
// Get first element of the tile
|
||||
rct_map_element *mapElement = TILE_MAP_ELEMENT_POINTER(y * 256 + x);
|
||||
|
||||
// Find the first surface element
|
||||
while ((mapElement->type & MAP_ELEMENT_TYPE_MASK) != MAP_ELEMENT_TYPE_SURFACE) {
|
||||
// Check if last element on tile
|
||||
if (mapElement->flags & MAP_ELEMENT_FLAG_LAST_TILE)
|
||||
return NULL;
|
||||
|
||||
mapElement++;
|
||||
}
|
||||
|
||||
return mapElement;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x0068AB4C
|
||||
@@ -136,16 +153,12 @@ int map_element_height(int x, int y)
|
||||
if (x >= 8192 || y >= 8192)
|
||||
return 16;
|
||||
|
||||
// Find the tile the element is on
|
||||
// Truncate subtile coordinates
|
||||
int x_tile = x & 0xFFFFFFE0;
|
||||
int y_tile = y & 0xFFFFFFE0;
|
||||
|
||||
i = ((y_tile * 256) + x_tile) / 32;
|
||||
|
||||
mapElement = TILE_MAP_ELEMENT_POINTER(i);
|
||||
while (mapElement->type & MAP_ELEMENT_TYPE_MASK) {
|
||||
mapElement++;
|
||||
}
|
||||
// Get the surface element for the tile
|
||||
mapElement = map_get_surface_element_at(x_tile / 32, y_tile / 32);
|
||||
|
||||
uint32 height =
|
||||
((mapElement->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK) << 20) |
|
||||
|
||||
@@ -110,7 +110,7 @@ int calculate_park_rating()
|
||||
continue;
|
||||
if (peep->happiness > 128)
|
||||
num_happy_peeps++;
|
||||
if (!(peep->var_C8 & 0x01))
|
||||
if (!(peep->flags & PEEP_FLAGS_LEAVING_PARK))
|
||||
continue;
|
||||
if (peep->var_C6 <= 89)
|
||||
_bp++;
|
||||
|
||||
33
src/peep.h
33
src/peep.h
@@ -37,16 +37,11 @@ enum STAFF_TYPE {
|
||||
STAFF_TYPE_ENTERTAINER
|
||||
};
|
||||
|
||||
enum {
|
||||
PEEP_FLAGS_TRACKING = 8
|
||||
};
|
||||
|
||||
enum PEEP_THOUGHT_TYPE {
|
||||
PEEP_THOUGHT_TYPE_NONE = 255
|
||||
};
|
||||
|
||||
enum PEEP_STATE {
|
||||
|
||||
PEEP_STATE_QUEUING_FRONT = 2,
|
||||
PEEP_STATE_ON_RIDE = 3,
|
||||
PEEP_STATE_LEAVING_RIDE = 4,
|
||||
@@ -71,6 +66,32 @@ enum PEEP_STATE {
|
||||
PEEP_STATE_INSPECTING = 23
|
||||
};
|
||||
|
||||
enum PEEP_FLAGS {
|
||||
PEEP_FLAGS_LEAVING_PARK = (1 << 0),
|
||||
PEEP_FLAGS_SLOW_WALK = (1 << 1),
|
||||
|
||||
PEEP_FLAGS_TRACKING = (1 << 3),
|
||||
PEEP_FLAGS_WAVING = (1 << 4), // Makes the peep wave
|
||||
|
||||
PEEP_FLAGS_PHOTO = (1 << 6), // Makes the peep take a picture
|
||||
PEEP_FLAGS_PAINTING = (1 << 7),
|
||||
|
||||
PEEP_FLAGS_LITTER = (1 << 9), // Makes the peep throw litter
|
||||
PEEP_FLAGS_LOST = (1 << 10), // Makes the peep feel lost (animation trigerred)
|
||||
PEEP_FLAGS_HUNGER = (1 << 11), // Makes the peep become hungry quicker
|
||||
PEEP_FLAGS_BATHROOM = (1 << 12), // Makes the peep want to go to the bathroom
|
||||
PEEP_FLAGS_CROWDED = (1 << 13), // The peep will start feeling crowded
|
||||
|
||||
PEEP_FLAGS_NAUSEA = (1 << 15), // Makes the peep feel sick (e.g. after an extreme ride)
|
||||
|
||||
PEEP_FLAGS_EATING = (1 << 17), // Reduces hunger
|
||||
PEEP_FLAGS_EXPLODE = (1 << 18),
|
||||
|
||||
PEEP_FLAGS_JOY = (1 << 23), // Makes the peep jump in joy
|
||||
PEEP_FLAGS_ANGRY = (1 << 24),
|
||||
PEEP_FLAGS_ICE_CREAM = (1 << 25) // Unconfirmed
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8 type;
|
||||
uint8 item;
|
||||
@@ -132,7 +153,7 @@ typedef struct {
|
||||
uint16 pad_C4;
|
||||
uint8 var_C6;
|
||||
uint8 pad_C7;
|
||||
uint32 var_C8; // Bit 25 Ice Cream, Bit 24 mad, Bit 3 tracking, Bit 0 leaving the park
|
||||
uint32 flags; // 0xC8
|
||||
uint8 var_CC;
|
||||
uint8 pad_CD[0x17];
|
||||
uint16 paid_to_enter; // 0xE4
|
||||
|
||||
@@ -29,10 +29,6 @@
|
||||
#include "strings.h"
|
||||
#include "window_error.h"
|
||||
|
||||
enum {
|
||||
SCREENSHOT_FORMAT_BMP,
|
||||
SCREENSHOT_FORMAT_PNG
|
||||
};
|
||||
|
||||
static int screenshot_dump_bmp();
|
||||
static int screenshot_dump_png();
|
||||
|
||||
Reference in New Issue
Block a user