add cheat window and compile manual

This commit is contained in:
IntelOrca 2014-04-15 00:50:20 +01:00
parent 3f59b7ad9e
commit 98aab20369
8 changed files with 290 additions and 4 deletions

View File

@ -70,6 +70,7 @@
<ClCompile Include="..\src\viewport.c" />
<ClCompile Include="..\src\widget.c" />
<ClCompile Include="..\src\window.c" />
<ClCompile Include="..\src\window_cheats.c" />
<ClCompile Include="..\src\window_game_bottom_toolbar.c" />
<ClCompile Include="..\src\window_dropdown.c" />
<ClCompile Include="..\src\window_land.c" />

View File

@ -212,6 +212,9 @@
<ClCompile Include="..\src\window_park.c">
<Filter>Windows</Filter>
</ClCompile>
<ClCompile Include="..\src\window_cheats.c">
<Filter>Windows</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\openrct2.exe">

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerCommand>$(TargetDir)\openrct2.exe</LocalDebuggerCommand>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommandArguments>
</LocalDebuggerCommandArguments>
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<PropertyGroup>
<ShowAllFiles>false</ShowAllFiles>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommand>$(TargetDir)\openrct2.exe</LocalDebuggerCommand>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
</PropertyGroup>
</Project>

View File

@ -1,3 +1,67 @@
OpenRCT2
=====================
An open source clone of Roller Coaster Tycoon 2 built by decompiling the original game one bit at a time.
# OpenRCT2
An open source clone of Roller Coaster Tycoon 2 built by decompiling the original game one bit at a time.
- [Screenshot 1](http://dev.intelorca.co.uk/2014/openrct2/cheats.png)
# Contents
- 1 Introduction
- 1.1 Background
- 1.2 Decompiling the game
- 1.3 Progress
- 2 Building the source code
- 2.1 Prerequisites
- 2.2 Compiling and running
- 3 Contributing
- 3.1 Decompiling
- 3.2 Naming of procedures and variables
- 3.3 Cleaning and documenting the source code
- 3.4 Implementing new featues / fixing bugs
- 4 Licence
# 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.
## 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.
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*.
## 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.
## 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.
# 2 Building the source code
## 2.1 Prerequisites
- Windows XP / Vista / 7 / 8
- RollerCoaster Tycoon 2
- Visual Studio 2013 / Visual Studio Express 2013
- SDL2 development library for Visual C++.
## 2.2 Compiling and running
1. Checkout the repository.
2. Download SDL2 development library for Visual C++ and copy it to a directory called "sdl" in the repository. This directory should contain "include".
3. Open the solution in projects directory.
4. In *rct2.c*, ```GAME_PATH``` can be edited to reflect your RollerCoaster Tycoon 2 installation. (Registry keys and original executable are not required)
5. Select the 'Release' configuration and click Build -> Rebuild Solution.
6. Start debugging. If warned about *openrct2.exe* not having debug information, just continue.
# 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.
## 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.
## 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.
## 3.4 Implementing new featues / 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.
# 4 License
**OpenRCT2** is licensed under the GNU General Public License version 3.

View File

@ -42,6 +42,8 @@
#include "title.h"
#include "viewport.h"
#define GAME_PATH "C:\\Program Files (x86)\\Infogrames\\RollerCoaster Tycoon 2"
void rct2_init_directories();
void rct2_startup_checks();
@ -143,7 +145,7 @@ void rct2_init()
// rct2: 0x00683499
void rct2_init_directories()
{
strcpy(RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char), "C:\\Program Files (x86)\\Infogrames\\RollerCoaster Tycoon 2");
strcpy(RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char), GAME_PATH);
strcpy(RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH_SLASH, char), RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH, char));
strcat(RCT2_ADDRESS(RCT2_ADDRESS_APP_PATH_SLASH, char), "\\");

View File

@ -305,5 +305,6 @@ void window_scenarioselect_open();
void window_land_open();
void window_water_open();
void window_park_objective_open();
void window_cheats_open();
#endif

196
src/window_cheats.c Normal file
View File

@ -0,0 +1,196 @@
/*****************************************************************************
* Copyright (c) 2014 Ted John
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* This file is part of OpenRCT2.
*
* OpenRCT2 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, either version 3 of the License, or
* (at your option) any later version.
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include <string.h>
#include "addresses.h"
#include "park.h"
#include "strings.h"
#include "sprites.h"
#include "widget.h"
#include "window.h"
#define WW 200
#define WH 128
enum {
WINDOW_CHEATS_PAGE_MONEY,
WINDOW_CHEATS_PAGE_GUESTS
};
static enum WINDOW_CHEATS_WIDGET_IDX {
WIDX_BACKGROUND,
WIDX_TITLE,
WIDX_CLOSE,
WIDX_PAGE_BACKGROUND,
WIDX_TAB_1,
WIDX_TAB_2,
WIDX_HIGH_MONEY
};
static rct_widget window_cheats_widgets[] = {
{ WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, 0x0FFFFFFFF, 65535}, // panel / background
{ WWT_CAPTION, 0, 1, WW - 2, 1, 14, 3165, STR_WINDOW_TITLE_TIP}, // title bar
{ WWT_CLOSEBOX, 0, WW - 13, WW - 3, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP}, // close x button
{ WWT_IMGBTN, 1, 0, WW - 1, 43, WH - 1, 0x0FFFFFFFF, 65535}, // tab content panel
{ WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 2462}, // tab 1
{ WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 2462}, // tab 2
{ WWT_CLOSEBOX, 1, 4, 74, 47, 63, 2375, 2375 }, // high money
{ WIDGETS_END },
};
static void window_cheats_emptysub() { }
static void window_cheats_mouseup();
static void window_cheats_update();
static void window_cheats_invalidate();
static void window_cheats_paint();
static uint32 window_cheats_events[] = {
window_cheats_emptysub,
window_cheats_mouseup,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_update,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_emptysub,
window_cheats_invalidate,
window_cheats_paint,
window_cheats_emptysub
};
static void window_cheats_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w);
void window_cheats_open()
{
rct_window* window;
// Check if window is already open
window = window_bring_to_front_by_id(WC_CHEATS, 0);
if (window != NULL)
return;
window = window_create(32, 32, WW, WH, window_cheats_events, WC_CHEATS, 0);
window->widgets = window_cheats_widgets;
window->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_HIGH_MONEY);
window_init_scroll_widgets(window);
window->var_48A = WINDOW_CHEATS_PAGE_MONEY;
window->colours[0] = 1;
window->colours[1] = 19;
window->colours[2] = 19;
}
static void window_cheats_mouseup()
{
int i;
short widgetIndex;
rct_window *w;
__asm mov widgetIndex, dx
__asm mov w, esi
switch (widgetIndex) {
case WIDX_CLOSE:
window_close(w);
break;
case WIDX_HIGH_MONEY:
i = DECRYPT_MONEY(RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32));
i += 100000;
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED, sint32) = ENCRYPT_MONEY(i);
window_invalidate_by_id(0x40 | WC_BOTTOM_TOOLBAR, 0);
break;
}
}
static void window_cheats_update()
{
rct_window *w;
__asm mov w, esi
w->var_48E++;
widget_invalidate(w->classification, w->number, WIDX_TAB_1);
}
static void window_cheats_invalidate()
{
int i;
rct_window *w;
__asm mov w, esi
strcpy((char*)0x009BC677, "Cheats");
// Set correct active tab
for (i = 0; i < 7; i++)
w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i));
w->pressed_widgets |= 1 << (WIDX_TAB_1 + w->var_48A);
}
static void window_cheats_paint()
{
rct_window *w;
rct_drawpixelinfo *dpi;
__asm mov w, esi
__asm mov dpi, edi
window_draw_widgets(w, dpi);
window_cheats_draw_tab_images(dpi, w);
}
static void window_cheats_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w)
{
int sprite_idx;
// Money tab
if (!(w->disabled_widgets & (1 << WIDX_TAB_1))) {
sprite_idx = 5261;
if (w->var_48A == WINDOW_CHEATS_PAGE_MONEY)
sprite_idx += (w->var_48E / 2) % 8;
gfx_draw_sprite(dpi, sprite_idx, w->x + w->widgets[WIDX_TAB_1].left, w->y + w->widgets[WIDX_TAB_1].top);
}
// Guests tab
if (!(w->disabled_widgets & (1 << WIDX_TAB_2))) {
sprite_idx = 5568;
if (w->var_48A == WINDOW_CHEATS_PAGE_GUESTS)
sprite_idx += w->var_48E / 4;
gfx_draw_sprite(dpi, sprite_idx, w->x + w->widgets[WIDX_TAB_2].left, w->y + w->widgets[WIDX_TAB_2].top);
}
}

View File

@ -148,6 +148,7 @@ static void window_game_top_toolbar_mouseup()
RCT2_CALLPROC_X(0x006677F2, 0, 1, 0, 0, 2, 0, 0);
break;
case WIDX_FASTFORWARD:
window_cheats_open();
break;
case WIDX_ZOOM_OUT: