Merge remote-tracking branch 'upstream/master' into hire-staff-command

This commit is contained in:
qcz 2014-08-19 09:46:25 +02:00
commit 2bbba4672b
35 changed files with 12365 additions and 596 deletions

3447
data/language/dutch.txt Normal file

File diff suppressed because it is too large Load Diff

3452
data/language/english_uk.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,6 @@
# STR_XXXX part is read and XXXX becomes the string id number.
# Everything after the colon and before the new line will be saved as the string.
# Use # at the beginning of a line to leave a comment.
STR_0000 :
STR_0001 :{STRINGID} {COMMA16}
STR_0002 :Ride
@ -1448,7 +1451,7 @@ STR_1446 :Looking at scenery
STR_1447 :Leaving the park
STR_1448 :Watching new ride being constructed
STR_1449 :{SPRITE} {STRINGID}{NEWLINE}({STRINGID})
STR_1450 :{INLINE_SPRITE}{MEDIUMFONT}{20}
STR_1450 :{INLINE_SPRITE}{09}{20}{00}{00}{SPRITE} {STRINGID}{NEWLINE}({STRINGID})
STR_1451 :{STRINGID}{NEWLINE}({STRINGID})
STR_1452 :Guest's name
STR_1453 :Enter name for this guest:-
@ -1710,10 +1713,10 @@ STR_1708 :{SMALLFONT}{BLACK}Set patrol area for this staff member
STR_1709 :Sack staff
STR_1710 :Yes
STR_1711 :{WINDOW_COLOUR_1}Are you sure you want to sack {STRINGID}?
STR_1712 :{INLINE_SPRITE}{247}{19}
STR_1713 :{INLINE_SPRITE}{248}{19}
STR_1714 :{INLINE_SPRITE}{249}{19}
STR_1715 :{INLINE_SPRITE}{250}{19}
STR_1712 :{INLINE_SPRITE}{247}{19}{00}{00}{WINDOW_COLOUR_2}Sweep footpaths
STR_1713 :{INLINE_SPRITE}{248}{19}{00}{00}{WINDOW_COLOUR_2}Water gardens
STR_1714 :{INLINE_SPRITE}{249}{19}{00}{00}{WINDOW_COLOUR_2}Empty litter bins
STR_1715 :{INLINE_SPRITE}{250}{19}{00}{00}{WINDOW_COLOUR_2}Mow grass
STR_1716 :Invalid name for park
STR_1717 :Can't rename park...
STR_1718 :Park Name
@ -1777,17 +1780,17 @@ STR_1775 :Off
STR_1776 :On
STR_1777 :{WINDOW_COLOUR_2}Music:
STR_1778 :{STRINGID} - -
STR_1779 :{INLINE_SPRITE}{254}{19}
STR_1780 :{INLINE_SPRITE}{255}{19}
STR_1781 :{INLINE_SPRITE}
STR_1782 :{INLINE_SPRITE}{MOVE_X}{20}
STR_1783 :{INLINE_SPRITE}{ADJUST_PALETTE}{20}
STR_1784 :{INLINE_SPRITE}{3}{20}
STR_1785 :{INLINE_SPRITE}{4}{20}
STR_1786 :{INLINE_SPRITE}{NEWLINE}{20}
STR_1787 :{INLINE_SPRITE}{NEWLINE_SMALLER}{20}
STR_1788 :{INLINE_SPRITE}{TINYFONT}{20}
STR_1789 :{INLINE_SPRITE}{BIGFONT}{20}
STR_1779 :{INLINE_SPRITE}{254}{19}{00}{00} Panda costume
STR_1780 :{INLINE_SPRITE}{255}{19}{00}{00} Tigre costume
STR_1781 :{INLINE_SPRITE}{00}{20}{00}{00} Elephant costume
STR_1782 :{INLINE_SPRITE}{01}{20}{00}{00} Roman costume
STR_1783 :{INLINE_SPRITE}{02}{20}{00}{00} Gorilla costume
STR_1784 :{INLINE_SPRITE}{03}{20}{00}{00} Snowman costume
STR_1785 :{INLINE_SPRITE}{04}{20}{00}{00} Knight costume
STR_1786 :{INLINE_SPRITE}{05}{20}{00}{00} Astronaut costume
STR_1787 :{INLINE_SPRITE}{06}{20}{00}{00} Bandit costume
STR_1788 :{INLINE_SPRITE}{07}{20}{00}{00} Sheriff costume
STR_1789 :{INLINE_SPRITE}{08}{20}{00}{00} Pirate costume
STR_1790 :{SMALLFONT}{BLACK}Select uniform color for this type of staff
STR_1791 :{WINDOW_COLOUR_2}Uniform color:
STR_1792 :Responding to {STRINGID} breakdown call
@ -1845,8 +1848,8 @@ STR_1843 :Favorite of: {COMMA16} guests
STR_1844 :{SMALLFONT}{BLACK}Select information type to show in ride/attraction list
STR_1845 :{MONTHYEAR}
STR_1846 :{COMMA16} guests
STR_1847 :{INLINE_SPRITE}{OUTLINE}{20}
STR_1848 :{INLINE_SPRITE}{SMALLFONT}{20}
STR_1847 :{INLINE_SPRITE}{11}{20}{00}{00}{COMMA16} guests
STR_1848 :{INLINE_SPRITE}{10}{20}{00}{00}{COMMA16} guests
STR_1849 :{WINDOW_COLOUR_2}Play music
STR_1850 :{SMALLFONT}{BLACK}Select whether music should be played for this ride
STR_1851 :{WINDOW_COLOUR_2}Running cost: {BLACK}{CURRENCY2DP} per hour
@ -1874,8 +1877,8 @@ STR_1872 :{COMMA16}
STR_1873 :{WINDOW_COLOUR_2}Income: {BLACK}{CURRENCY} per hour
STR_1874 :{WINDOW_COLOUR_2}Profit: {BLACK}{CURRENCY} per hour
STR_1875 :{BLACK} {SPRITE}{BLACK} {STRINGID}
STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{251}{19}
STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{252}{19}
STR_1876 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{251}{19}{00}{00}Inspect Rides
STR_1877 :{WINDOW_COLOUR_2}{INLINE_SPRITE}{252}{19}{00}{00}Fix Rides
STR_1878 :{WINDOW_COLOUR_2}Inspection:
STR_1879 :Every 10 minutes
STR_1880 :Every 20 minutes
@ -2758,25 +2761,27 @@ STR_2756 :???
STR_2757 :???
STR_2758 :???
STR_2759 :???
# New strings used in the cheats window previously these were ???
STR_2760 :+5K Money
STR_2761 :???
STR_2762 :???
STR_2761 :Pay For Entrance
STR_2762 :Pay For Rides
STR_2763 :???
STR_2764 :???
STR_2765 :???
STR_2764 :Happy Guests
STR_2765 :Large Tram
STR_2766 :???
STR_2767 :???
STR_2768 :???
STR_2769 :???
STR_2770 :???
STR_2771 :???
STR_2772 :???
STR_2773 :???
STR_2774 :???
STR_2775 :???
STR_2776 :???
STR_2777 :???
STR_2778 :???
STR_2767 :Freeze Climate
STR_2768 :Unfreeze Climate
STR_2769 :Open Park
STR_2770 :Close Park
STR_2771 :Slower Gamespeed
STR_2772 :Faster Gamespeed
STR_2773 :Windowed
STR_2774 :Fullscreen
STR_2775 :Fullscreen (desktop)
STR_2776 :Language
STR_2777 :{MOVE_X}{SMALLFONT}{STRING}
STR_2778 :{RIGHTGUILLEMET}{MOVE_X}{SMALLFONT}{STRING}
# End of new strings
STR_2779 :???
STR_2780 :???
STR_2781 :{STRINGID}:{MOVE_X}{195}{STRINGID}{STRINGID}

3452
data/language/french.txt Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,5 @@
#!/bin/bash
set -e
SDL2_PV=2.0.3
cachedir=.cache
@ -11,13 +9,44 @@ echo `uname`
if [[ `uname` == "Darwin" ]]; then
echo "Installation of OpenRCT2 assumes you have homebrew and use it to install packages."
echo "Check if brew is installed"
package_command="brew"
which -s brew
if [ $? -eq 1 ]; then
echo "brew is not installed, or is not in your \$PATH"
echo "Check if MacPorts is installed"
which -s port
if [ $? -eq 1 ]; then
echo "MacPorts not found either, abort"
exit
else
echo "MacPorts found"
package_command="sudo port"
fi
else
echo "brew was found"
fi
echo "Check if wget is installed"
which -s wget
if [ $? -eq 1 ]; then
echo "wget is not installed, installing wget.."
eval "$package_command install wget"
fi
# Install packages with whatever command was found.
# Very possible I'm missing some dependencies here.
brew install cmake wine
eval "$package_command install cmake wine"
if [[ ! -d /usr/include/wine ]]; then
# This will almost certainly break as brew changes. Better ideas
# welcome.
sudo ln -s /usr/local/Cellar/wine/1.6.2/include/wine /usr/include
wine_path="/usr/local/Cellar/wine/1.6.2/include/wine"
if [ $package_command == "sudo port" ]; then
wine_path="/opt/local/include/wine"
fi
sudo ln -s $wine_path /usr/include
fi
mingw_dmg=gcc-4.8.0-qt-4.8.4-for-mingw32.dmg
@ -68,7 +97,7 @@ if [[ ! -f $cachedir/i686-w64-mingw32-pkg-config ]]; then
# If this fails to work because of newlines, be sure you are running this
# script with Bash, and not sh. We should really move this to a separate
# file.
echo -e "#! /bin/sh\nexport PKG_CONFIG_LIBDIR=/usr/local/cross-tools/i686-w64-mingw32/lib/pkgconfig\npkg-config \$@" > $cachedir/i686-w64-mingw32-pkg-config;
echo -e "#!/bin/sh\nexport PKG_CONFIG_LIBDIR=/usr/local/cross-tools/i686-w64-mingw32/lib/pkgconfig\npkg-config \$@" > $cachedir/i686-w64-mingw32-pkg-config;
fi
chmod +x $cachedir/i686-w64-mingw32-pkg-config

View File

@ -29,6 +29,7 @@
<ClInclude Include="..\src\gfx.h" />
<ClInclude Include="..\src\graph.h" />
<ClInclude Include="..\src\intro.h" />
<ClInclude Include="..\src\language.h" />
<ClInclude Include="..\src\map.h" />
<ClInclude Include="..\src\marketing.h" />
<ClInclude Include="..\src\news_item.h" />
@ -73,6 +74,7 @@
<ClCompile Include="..\src\gfx.c" />
<ClCompile Include="..\src\graph.c" />
<ClCompile Include="..\src\intro.c" />
<ClCompile Include="..\src\language.c" />
<ClCompile Include="..\src\map.c" />
<ClCompile Include="..\src\marketing.c" />
<ClCompile Include="..\src\news_item.c" />
@ -117,9 +119,11 @@
<ClCompile Include="..\src\window_new_ride.c" />
<ClCompile Include="..\src\window_options.c" />
<ClCompile Include="..\src\window_peep.c" />
<ClCompile Include="..\src\window_research.c" />
<ClCompile Include="..\src\window_ride_list.c" />
<ClCompile Include="..\src\window_save_prompt.c" />
<ClCompile Include="..\src\window_staff.c" />
<ClCompile Include="..\src\window_staff_peep.c" />
<ClCompile Include="..\src\window_title_exit.c" />
<ClCompile Include="..\src\window_title_logo.c" />
<ClCompile Include="..\src\window_main.c" />
@ -133,10 +137,10 @@
<None Include="..\openrct2.exe" />
</ItemGroup>
<ItemGroup>
<Text Include="..\data\language\english.txt">
<DeploymentContent Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</DeploymentContent>
</Text>
<Text Include="..\data\language\dutch.txt" />
<Text Include="..\data\language\english_uk.txt" />
<Text Include="..\data\language\english_us.txt" />
<Text Include="..\data\language\french.txt" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D24D94F6-2A74-480C-B512-629C306CE92F}</ProjectGuid>

View File

@ -153,6 +153,9 @@
<ClInclude Include="..\src\graph.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\language.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\game.c">
@ -359,6 +362,15 @@
<ClCompile Include="..\src\window_new_campaign.c">
<Filter>Windows</Filter>
</ClCompile>
<ClCompile Include="..\src\language.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\window_research.c">
<Filter>Windows</Filter>
</ClCompile>
<ClCompile Include="..\src\window_staff_peep.c">
<Filter>Windows</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\openrct2.exe">
@ -366,7 +378,16 @@
</None>
</ItemGroup>
<ItemGroup>
<Text Include="..\data\language\english.txt">
<Text Include="..\data\language\dutch.txt">
<Filter>Data\Language</Filter>
</Text>
<Text Include="..\data\language\english_uk.txt">
<Filter>Data\Language</Filter>
</Text>
<Text Include="..\data\language\english_us.txt">
<Filter>Data\Language</Filter>
</Text>
<Text Include="..\data\language\french.txt">
<Filter>Data\Language</Filter>
</Text>
</ItemGroup>

View File

@ -5,6 +5,8 @@ An open source clone of RollerCoaster Tycoon 2 built by decompiling the original
- [Screenshot 3, high resolution](http://i.imgur.com/yFzNyVu.jpg)
- [Screenshot 4, resizable window](http://imgur.com/a/3GDuT)
[![Build Status](https://travis-ci.org/IntelOrca/OpenRCT2.svg)](https://travis-ci.org/IntelOrca/OpenRCT2)
# Contents
- 1 - [Introduction](#1-introduction)
- 1.1 - [Background](#11-background)
@ -34,6 +36,8 @@ The project therefore acts as a patch to RollerCoaster Tycoon 2, allowing each p
## 1.3 Progress
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.
As of 16th August 2014, various UI improvements have already been made, settings are now stored in a local INI file. More drawing functions have now been decompiled but still remain cryptic C, much of the game management have been decompiled (e.g. peep generation, awards, cash out) and almost half of the windows. A rough estimate based on number of functions in the original game and number of functions now in C tells us that the project is approximately 25% complete of its target goal of having the game run on 100% C code. More information can be found in [changes to original game](https://github.com/IntelOrca/OpenRCT2/wiki/Changes-to-original-game) and [window progress](https://github.com/IntelOrca/OpenRCT2/wiki/Window-progress).
## 1.4 Aim
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
@ -56,9 +60,13 @@ The aim is to completely decompile RollerCoaster Tycoon 2 into C so that cross-p
- Visual Studio 2013 (paid) / [Visual Studio Express 2013](http://www.visualstudio.com/downloads/download-visual-studio-vs#d-express-windows-desktop) (free)
- [SDL2 development library for Visual C++](http://www.libsdl.org/release/SDL2-devel-2.0.3-VC.zip).
### Linux:
### Max OS X:
- [Homebrew](http://brew.sh)
- RollerCoaster Tycoon 2
### Mac OS X / Linux:
- [MinGW-w64](mingw-w64.sourceforge.net)
- [Wine](http://www.winehq.org/)
- [Wine](http://www.winehq.org)
- RollerCoaster Tycoon 2
- libsdl2 compiled with MinGW-w64
@ -72,6 +80,14 @@ The aim is to completely decompile RollerCoaster Tycoon 2 into C so that cross-p
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.
### Mac OS X:
Providing Homebrew is installed, OpenRCT2's dependencies and Wine can be installed automatically through `install.sh`.
```
bash install.sh
bash build.sh
wine openrct2.exe
```
### Linux:
As the easiest approach depends on your distribution, please take a look at the [wiki](https://github.com/IntelOrca/OpenRCT2/wiki).

View File

@ -215,6 +215,7 @@
#define RCT2_ADDRESS_CURRENT_PARK_RATING 0x01357CB0
#define RCT2_ADDRESS_PARK_RATING_HISTORY 0x01357CB2
#define RCT2_ADDRESS_GUESTS_IN_PARK_HISTORY 0x01357CD2
#define RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT 0x01357CF4
#define RCT2_ADDRESS_OBJECTIVE_TYPE 0x013580F8
#define RCT2_ADDRESS_OBJECTIVE_YEAR 0x013580F9
#define RCT2_ADDRESS_OBJECTIVE_CURRENCY 0x013580FC
@ -250,6 +251,8 @@
#define RCT2_ADDRESS_SECURITY_COLOUR 0x01357BCF
#define RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES 0x01357CF2
#define RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY 0x013580E7
#define RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_MONTH 0x013580E8
#define RCT2_ADDRESS_MAP_SIZE 0x01358834
#define RCT2_ADDRESS_PARK_SIZE 0x013580EA

View File

@ -23,6 +23,7 @@
#include <ctype.h>
#include "addresses.h"
#include "config.h"
#include "language.h"
#include "rct2.h"
@ -90,6 +91,7 @@ general_configuration_t gGeneral_config_default = {
0, // show_height_as_units
1, // save_plugin_data
0, // fullscreen mode (default: windowed)
LANGUAGE_ENGLISH_UK
};
sound_configuration_t gSound_config;
@ -381,6 +383,8 @@ void config_write_ini_general(FILE *fp)
fprintf(fp, "fullscreen_mode = fullscreen\n");
else
fprintf(fp, "fullscreen_mode = borderless_fullscreen\n");
fprintf(fp, "language = %d\n", gGeneral_config.language);
}
/**
@ -621,6 +625,9 @@ static void config_general(char *setting, char *value){
else
gGeneral_config.fullscreen_mode = 2;
}
else if (strcmp(setting, "language") == 0) {
gGeneral_config.language = atoi(value);
}
}
/**

View File

@ -130,6 +130,7 @@ typedef struct general_configuration {
//new
uint8 fullscreen_mode;
uint16 language;
} general_configuration_t;
static const struct { char *key; int value; } _currencyLookupTable[] = {

View File

@ -130,7 +130,7 @@ void finance_pay_ride_upkeep()
if (ride->status != RIDE_STATUS_CLOSED && !(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & 0x800)) {
sint16 upkeep = ride->upkeep_cost;
if (upkeep != -1) {
ride->var_158 -= upkeep;
ride->var_154 -= upkeep;
ride->var_14D |= 2;
finance_payment(upkeep, RCT2_EXPENDITURE_TYPE_RIDE_UPKEEP);
}

View File

@ -824,7 +824,7 @@ static void game_handle_input_mouse(int x, int y, int state)
switch (ebx & 0xFF) {
case 2:
if (*((uint8*)edx) == 0)
RCT2_CALLPROC_X(0x006B4857, eax, 0, ecx, 0, 0, 0, 0);
RCT2_CALLPROC_X(0x006B4857, eax, 0, ecx, edx, 0, 0, 0);
break;
case 3:
RCT2_CALLPROC_X(0x006CC056, eax, 0, ecx, edx, 0, 0, 0);
@ -867,7 +867,78 @@ static void game_handle_input_mouse(int x, int y, int state)
RCT2_CALLPROC_X(0x006E8DA7, x, y, state, widgetIndex, (int)w, (int)widget, 0);
break;
case INPUT_STATE_VIEWPORT_LEFT:
RCT2_CALLPROC_X(0x006E87B4, x, y, state, widgetIndex, (int)w, (int)widget, 0);
//RCT2_CALLPROC_X(0x006E87B4, x, y, state, widgetIndex, (int)w, (int)widget, 0);
w = window_find_by_id(RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber));
if (!w){
RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 0;
break;
}
if (state == 0){
if (!w->viewport){
RCT2_GLOBAL(RCT2_ADDRESS_INPUT_STATE, uint8) = 0;
break;
}
if (w->classification != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWCLASS, rct_windowclass) ||
w->number != RCT2_GLOBAL(RCT2_ADDRESS_CURSOR_DRAG_WINDOWNUMBER, rct_windownumber) ||
!(RCT2_GLOBAL(0x9DE518, uint32)&(1 << 3)))break;
w = window_find_by_id(RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber));
if (!w)break;
RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_DRAG], x, y, 0, (int)RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16), (int)w, 0, 0);
}
else if (state == 2){
RCT2_GLOBAL(0x9DE51D, uint8) = 0;
if (RCT2_GLOBAL(0x9DE52E, rct_windownumber) != w->number)break;
if ((RCT2_GLOBAL(0x9DE518, uint32)&(1 << 3))){
w = window_find_by_id(RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWCLASS, rct_windowclass), RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WINDOWNUMBER, rct_windownumber));
if (!w)break;
RCT2_CALLPROC_X(w->event_handlers[WE_TOOL_UP], x, y, 0, (int)RCT2_GLOBAL(RCT2_ADDRESS_TOOL_WIDGETINDEX, uint16), (int)w, 0, 0);
}
else{
if ((RCT2_GLOBAL(0x9DE518, uint32)&(1 << 4)))break;
rct_sprite* spr;
int eax = x, ebx = y, ecx = state, esi = (int)w, edi = (int)widget, ebp = 0;
RCT2_CALLFUNC_X(0X6ED9D0, &eax, &ebx, &ecx, (int*)&spr, &esi, &edi, &ebp);
if ((ebx & 0xFF) == 2){
if (spr->unknown.sprite_identifier == SPRITE_IDENTIFIER_VEHICLE){
//Open ride window
RCT2_CALLPROC_X(0x6ACAC2, eax, ebx, ecx, (int)spr, esi, edi, ebp);
}
else if (spr->unknown.sprite_identifier == SPRITE_IDENTIFIER_PEEP){
window_peep_open(&spr->peep);
}
else if (spr->unknown.sprite_identifier == SPRITE_IDENTIFIER_FLOATING_TEXT){
//Unknown for now
RCT2_CALLPROC_X(0x6E88D7, eax, ebx, ecx, (int)spr, esi, edi, ebp);
}
}
else if ((ebx & 0xFF) == 3){
//Don't think it is a map element.
rct_map_element_properties* map_element = (rct_map_element_properties*)spr;
uint32 edx = (uint32)spr;
if (!((map_element->track.type & 0x3C) == 16)){
eax = RCT2_ADDRESS(0x0099BA64, uint8)[16 * (*(uint8*)(edx + 4))];
if (!(eax & 0x10)){
eax = *((uint8*)(edx + 7));
RCT2_CALLPROC_X(0x6ACC28, eax, ebx, ecx, edx, esi, edi, ebp);
break;
}
}
//Open ride window
RCT2_CALLPROC_X(0x6ACCCE, *(uint8*)(edx + 7), ((*(uint8*)(edx + 5)) & 0x70) >> 4, ecx, edx, esi, edi, ebp);
}
else if ((ebx & 0xFF) == 8){
window_park_entrance_open();
}
}
}
break;
case INPUT_STATE_SCROLL_LEFT://0x006E8676
//RCT2_CALLPROC_X(0x006E8676, x, y, state, widgetIndex, (int)w, (int)widget, 0);

113
src/gfx.c
View File

@ -690,6 +690,7 @@ void gfx_fill_rect_inset(rct_drawpixelinfo* dpi, short left, short top, short ri
*/
void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, uint8* source_pointer, uint8* dest_pointer, rct_g1_element* source_image, rct_drawpixelinfo *dest_dpi, int height, int width, int image_type){
uint8 zoom_level = dest_dpi->zoom_level;
uint8 zoom_amount = 1 << zoom_level;
//Requires use of palette?
if (image_type & IMAGE_TYPE_USE_PALETTE){
@ -697,12 +698,12 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui
if (unknown_pointer!= NULL){ //Not tested. I can't actually work out when this code runs.
unknown_pointer += source_pointer - source_image->offset;// RCT2_GLOBAL(0x9E3CE0, uint32);
for (; height > 0; height -= (1<<zoom_level)){
uint8* next_source_pointer = source_pointer + (uint32)(source_image->width << zoom_level);
uint8* next_unknown_pointer = unknown_pointer + (uint32)(source_image->width << zoom_level);
uint8* next_dest_pointer = dest_pointer + (dest_dpi->width >> zoom_level) + dest_dpi->pitch;
for (; height > 0; height -= zoom_amount){
uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount);
uint8* next_unknown_pointer = unknown_pointer + (uint32)(source_image->width * zoom_amount);
uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch;
for (int no_pixels = width; no_pixels > 0; no_pixels -= (1<<zoom_level), source_pointer+=(1<<zoom_level), unknown_pointer+=(1<<zoom_level), dest_pointer++){
for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, unknown_pointer += zoom_amount, dest_pointer++){
uint8 pixel = *source_pointer;
pixel = palette_pointer[pixel];
pixel &= *unknown_pointer;
@ -718,10 +719,10 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui
}
//image colour adjusted?
for (; height > 0; height -= (1<<zoom_level)){
uint8* next_source_pointer = source_pointer + (uint32)(source_image->width<<zoom_level);
uint8* next_dest_pointer = dest_pointer + (dest_dpi->width >> zoom_level) + dest_dpi->pitch;
for (int no_pixels = width; no_pixels > 0; no_pixels -= (1<<zoom_level), source_pointer+= (1<<zoom_level), dest_pointer++){
for (; height > 0; height -= zoom_amount){
uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount);
uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch;
for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){
uint8 pixel = *source_pointer;
pixel = palette_pointer[pixel];
if (pixel){
@ -738,11 +739,11 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui
//Mix with background. It only uses source pointer for
//telling if it needs to be drawn not for colour.
if (image_type & IMAGE_TYPE_MIX_BACKGROUND){//Not tested
for (; height > 0; height -= (1<<zoom_level)){
uint8* next_source_pointer = source_pointer + (uint32)(source_image->width << zoom_level);
uint8* next_dest_pointer = dest_pointer + (dest_dpi->width >> zoom_level) + dest_dpi->pitch;
for (; height > 0; height -= zoom_amount){
uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount);
uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch;
for (int no_pixels = width; no_pixels > 0; no_pixels -= (1<<zoom_level), source_pointer += (1<<zoom_level), dest_pointer++){
for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){
uint8 pixel = *source_pointer;
if (pixel){
pixel = *dest_pointer;
@ -759,11 +760,11 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui
//Basic bitmap no fancy stuff
if (!(source_image->flags & G1_FLAG_BMP)){//Not tested
for (; height > 0; height-=(1<<zoom_level)){
uint8* next_source_pointer = source_pointer + (uint32)(source_image->width << zoom_level);
uint8* next_dest_pointer = dest_pointer + (dest_dpi->width >> zoom_level) + dest_dpi->pitch;
for (; height > 0; height -= zoom_amount){
uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount);
uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch;
for (int no_pixels = width; no_pixels > 0; no_pixels -= (1<<zoom_level), dest_pointer++, source_pointer += (1<<zoom_level)){
for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount){
*dest_pointer = *source_pointer;
}
@ -776,12 +777,12 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui
if (RCT2_GLOBAL(0x9E3CDC, uint32) != 0){//Not tested. I can't actually work out when this code runs.
unknown_pointer += source_pointer - source_image->offset;
for (; height > 0; height -= (1<<zoom_level)){
uint8* next_source_pointer = source_pointer + (uint32)(source_image->width << zoom_level);
uint8* next_unknown_pointer = unknown_pointer + (uint32)(source_image->width << zoom_level);
uint8* next_dest_pointer = dest_pointer + (dest_dpi->width >> zoom_level) + dest_dpi->pitch;
for (; height > 0; height -= zoom_amount){
uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount);
uint8* next_unknown_pointer = unknown_pointer + (uint32)(source_image->width * zoom_amount);
uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch;
for (int no_pixels = width; no_pixels > 0; no_pixels -= (1<<zoom_level), dest_pointer++, source_pointer += (1<<zoom_level), unknown_pointer += (1<<zoom_level)){
for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount, unknown_pointer += zoom_amount){
uint8 pixel = *source_pointer;
pixel &= *unknown_pointer;
if (pixel){
@ -795,11 +796,11 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui
}
//Basic bitmap with no draw pixels
for (; height > 0; height -= (1<<zoom_level)){
uint8* next_source_pointer = source_pointer + (uint32)(source_image->width << zoom_level);
uint8* next_dest_pointer = dest_pointer + (dest_dpi->width >> zoom_level) + dest_dpi->pitch;
for (; height > 0; height -= zoom_amount){
uint8* next_source_pointer = source_pointer + (uint32)(source_image->width * zoom_amount);
uint8* next_dest_pointer = dest_pointer + (dest_dpi->width / zoom_amount) + dest_dpi->pitch;
for (int no_pixels = width; no_pixels > 0; no_pixels -= (1<<zoom_level), dest_pointer++, source_pointer += (1<<zoom_level)){
for (int no_pixels = width; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++, source_pointer += zoom_amount){
uint8 pixel = *source_pointer;
if (pixel){
*dest_pointer = pixel;
@ -818,11 +819,12 @@ void gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unknown_pointer, ui
*/
void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_pointer, uint8* palette_pointer, rct_drawpixelinfo *dpi, int image_type, int source_y_start, int height, int source_x_start, int width){
int zoom_level = dpi->zoom_level;
int zoom_amount = 1 << zoom_level;
uint8* next_source_pointer;
uint8* next_dest_pointer = dest_bits_pointer;
//For every line in the image
for (int y = source_y_start; y < (height + source_y_start); y += (1<<zoom_level)){
for (int y = source_y_start; y < (height + source_y_start); y += zoom_amount){
//The first part of the source pointer is a list of offsets to different lines
//This will move the pointer to the correct source line.
@ -852,7 +854,7 @@ void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_point
if (x_start > 0){
//Since the start is positive
//We need to move the drawing surface to the correct position
dest_pointer += x_start >> zoom_level;
dest_pointer += x_start / zoom_amount;
}
else{
//If the start is negative we require to remove part of the image.
@ -879,7 +881,7 @@ void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_point
//Finally after all those checks, copy the image onto the drawing surface
//If the image type is not a basic one we require to mix the pixels
if (image_type & IMAGE_TYPE_USE_PALETTE){//In the .exe these are all unraveled loops
for (; no_pixels > 0; no_pixels -= (1<<zoom_level), source_pointer += (1<<zoom_level), dest_pointer++){
for (; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){
uint8 al = *source_pointer;
uint8 ah = *dest_pointer;
if (image_type & IMAGE_TYPE_MIX_BACKGROUND)
@ -893,7 +895,7 @@ void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_point
//Doesnt use source pointer ??? mix with background only?
//Not Tested
for (; no_pixels > 0; no_pixels -= (1<<zoom_level), dest_pointer++){
for (; no_pixels > 0; no_pixels -= zoom_amount, dest_pointer++){
uint8 pixel = *dest_pointer;
pixel = palette_pointer[pixel];
*dest_pointer = pixel;
@ -901,14 +903,14 @@ void gfx_rle_sprite_to_buffer(uint8* source_bits_pointer, uint8* dest_bits_point
}
else
{
for (; no_pixels > 0; no_pixels -= (1<<zoom_level), source_pointer += (1<<zoom_level), dest_pointer++){
for (; no_pixels > 0; no_pixels -= zoom_amount, source_pointer += zoom_amount, dest_pointer++){
*dest_pointer = *source_pointer;
}
}
}
//Add a line to the drawing surface pointer
next_dest_pointer += (int)(dpi->width >> zoom_level) + (int)dpi->pitch;
next_dest_pointer += dpi->width / zoom_amount + dpi->pitch;
}
}
@ -946,7 +948,7 @@ void gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32
if (image_type && !(image_type & IMAGE_TYPE_UNKNOWN)) {
uint8 palette_ref = (image_id >> 19) & 0xFF;
if (!(image_type & IMAGE_TYPE_MIX_BACKGROUND)){
if (image_type & IMAGE_TYPE_MIX_BACKGROUND){
unknown_pointer = NULL;
RCT2_GLOBAL(0x009E3CDC, uint32) = 0;
}
@ -1022,7 +1024,7 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in
rct_g1_element* g1_source = &(RCT2_ADDRESS(RCT2_ADDRESS_G1_ELEMENTS, rct_g1_element)[image_element]);
//Zooming code has been integrated into main code but is not working.
//Zooming code has been integrated into main code.
//if (dpi->zoom_level >= 1){ //These have not been tested
// //something to do with zooming
// if (dpi->zoom_level == 1){
@ -1053,17 +1055,19 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in
if ( dpi->zoom_level && (g1_source->flags & (1<<5)) ){
return;
}
//Its used super often so we will define it to a seperate variable.
int zoom_level = dpi->zoom_level;
uint16 zoom_mask = 0xFFFF << zoom_level;
int zoom_amount = 1 << zoom_level;
int zoom_mask = 0xFFFFFFFF << zoom_level;
//This will be the height of the drawn image
int height = g1_source->height >> zoom_level;
int height = g1_source->height;
//This is the start y coordinate on the destination
sint16 dest_start_y = ((sint16)y + g1_source->y_offset - dpi->y) >> zoom_level;
sint16 dest_start_y = ((y + g1_source->y_offset)&zoom_mask) - dpi->y;
//This is the start y coordinate on the source
int source_start_y = 0;
if (dest_start_y < 0){
//If the destination y is negative reduce the height of the
//image as we will cut off the bottom
@ -1073,29 +1077,31 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in
return;
}
//The source image will start a further up the image
source_start_y -= dest_start_y<<zoom_level;
source_start_y -= dest_start_y;
//The destination start is now reset to 0
dest_start_y = 0;
}
int dest_end_y = dest_start_y + height;
if (dest_end_y > (dpi->height >> zoom_level)){
if (dest_end_y > dpi->height){
//If the destination y is outside of the drawing
//image reduce the height of the image
height -= dest_end_y - (dpi->height >> zoom_level);
height -= dest_end_y - dpi->height;
}
//If the image no longer has anything to draw
if (height <= 0)return;
dest_start_y /= zoom_amount;
dest_end_y /= zoom_amount;
//This will be the width of the drawn image
int width = g1_source->width >> zoom_level;
int width = g1_source->width;
//This is the source start x coordinate
int source_start_x = 0;
//This is the destination start x coordinate
sint16 dest_start_x = ((sint16)x + g1_source->x_offset - dpi->x) >> zoom_level;
sint16 dest_start_x = ((x + g1_source->x_offset) & zoom_mask) - dpi->x;
if (dest_start_x < 0){
//If the destination is negative reduce the width
//image will cut off the side
@ -1105,29 +1111,28 @@ void gfx_draw_sprite_palette_set(rct_drawpixelinfo *dpi, int image_id, int x, in
return;
}
//The source start will also need to cut off the side
source_start_x -= dest_start_x<<zoom_level;
source_start_x -= dest_start_x;
//Reset the destination to 0
dest_start_x = 0;
}
int dest_end_x = dest_start_x + width;
if (dest_end_x > (dpi->width>>zoom_level)){
if (dest_end_x > dpi->width){
//If the destination x is outside of the drawing area
//reduce the image width.
width -= dest_end_x - (dpi->width >> zoom_level);
width -= dest_end_x - dpi->width;
//If there is no image to draw.
if (width <= 0)return;
}
dest_start_x /= zoom_amount;
dest_end_x /= zoom_amount;
uint8* dest_pointer = (uint8*)dpi->bits;
//Move the pointer to the start point of the destination
dest_pointer += ((dpi->width >> zoom_level) + dpi->pitch)*dest_start_y + dest_start_x;
height <<= zoom_level;
width <<= zoom_level;
dest_pointer += ((dpi->width / zoom_amount) + dpi->pitch)*dest_start_y + dest_start_x;
if (g1_source->flags & G1_FLAG_RLE_COMPRESSION){
//We have to use a different method to move the source pointer for
//rle encoded sprites so that will be handled within this function

View File

@ -54,7 +54,7 @@ static void graph_draw_line_a_uint8(rct_drawpixelinfo *dpi, uint8 *history, int
x = baseX;
for (i = count - 1; i >= 0; i--) {
if (history[i] != 0 && history[i] != 255) {
y = baseY + (history[i] * 100) / 256;
y = baseY + ((255 - history[i]) * 100) / 256;
if (lastX != -1) {
gfx_draw_line(dpi, lastX + 1, lastY + 1, x + 1, y + 1, 10);
@ -78,7 +78,7 @@ static void graph_draw_line_b_uint8(rct_drawpixelinfo *dpi, uint8 *history, int
x = baseX;
for (i = count - 1; i >= 0; i--) {
if (history[i] != 0 && history[i] != 255) {
y = baseY + (history[i] * 100) / 256;
y = baseY + ((255 - history[i]) * 100) / 256;
if (lastX != -1)
gfx_draw_line(dpi, lastX, lastY, x, y, 21);

209
src/language.c Normal file
View File

@ -0,0 +1,209 @@
/*****************************************************************************
* 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 <stdio.h>
#include <string.h>
#include "addresses.h"
#include "language.h"
#include "string_ids.h"
const char *language_names[LANGUAGE_COUNT] = {
"", // LANGUAGE_UNDEFINED
"English (UK)", // LANGUAGE_ENGLISH_UK
"English (US)", // LANGUAGE_ENGLISH_US
"Nederlands", // LANGUAGE_DUTCH
"Fran\u00e7ais" // LANGUAGE_FRENCH
};
const char *language_filenames[LANGUAGE_COUNT] = {
"", // LANGUAGE_UNDEFINED
"english_uk", // LANGUAGE_ENGLISH_UK
"english_us", // LANGUAGE_ENGLISH_US
"dutch", // LANGUAGE_DUTCH
"french" // LANGUAGE_FRENCH
};
int gCurrentLanguage = LANGUAGE_UNDEFINED;
// Buffer storing all the string data
long language_buffer_size = 0;
char *language_buffer = NULL;
// List of string pointers into the string data
int language_num_strings = 0;
char **language_strings = NULL;
static int language_open_file(const char *filename);
static int utf8_get_next(char *char_ptr, char **nextchar_ptr)
{
int result;
int numBytes;
if (!(char_ptr[0] & 0x80)) {
result = char_ptr[0];
numBytes = 1;
} else if (!(char_ptr[0] & 0x20)) {
result = ((char_ptr[0] & 0x1F) << 6) | (char_ptr[1] & 0x3F);
numBytes = 2;
}
if (nextchar_ptr != NULL)
*nextchar_ptr = char_ptr + numBytes;
return result;
}
const char *language_get_string(rct_string_id id)
{
const char *rct = RCT2_ADDRESS(0x009BF2D4, const char*)[id];
const char *openrct = language_strings == NULL ? NULL : language_strings[id];
const char *str = (openrct == NULL || strlen(openrct) == 0 ? rct : openrct);
return str == NULL ? "" : str;
}
int language_open(int id)
{
char filename[_MAX_PATH];
language_close();
if (id == LANGUAGE_UNDEFINED)
return 1;
sprintf(filename, "data/language/%s.txt", language_filenames[id]);
if (language_open_file(filename)) {
gCurrentLanguage = id;
return 1;
}
return 0;
}
/**
* Partial support to open a uncompiled language file which parses tokens and converts them to the corresponding character
* code. Due to resource strings (strings in scenarios and objects) being written to the original game's string table,
* get_string will use those if the same entry in the loaded language is empty.
*
* Unsure at how the original game decides which entries to write resource strings to, but this could affect adding new
* strings for the time being. Further investigation is required.
*
* Also note that all strings are currently still ASCII. It probably can't be converted to UTF-8 until all game functions that
* read / write strings in some way is decompiled. The original game used a DIY extended 8-bit extended ASCII set for special
* characters, format codes and accents.
*
* In terms of reading the language files, the STR_XXXX part is read and XXXX becomes the string id number. Everything after the
* colon and before the new line will be saved as the string. Tokens are written with inside curly braces {TOKEN}.
* Use # at the beginning of a line to leave a comment.
*/
static int language_open_file(const char *filename)
{
FILE *f = fopen(filename, "rb");
if (f == NULL)
return 0;
fseek(f, 0, SEEK_END);
language_buffer_size = ftell(f);
language_buffer = calloc(1, language_buffer_size);
fseek(f, 0, SEEK_SET);
fread(language_buffer, language_buffer_size, 1, f);
fclose(f);
language_strings = calloc(STR_COUNT, sizeof(char*));
char *dst, *token;
char tokenBuffer[64];
int i, stringIndex = 0, mode = 0, string_no;
for (i = 0; i < language_buffer_size; i++) {
char *src = &language_buffer[i];
// Handle UTF-8
char *srcNext;
int utf8Char = utf8_get_next(src, &srcNext);
i += srcNext - src - 1;
if (utf8Char > 0xFF)
utf8Char = '?';
else if (utf8Char > 0x7F)
utf8Char &= 0xFF;
switch (mode) {
case 0:
// Search for a comment
if (utf8Char == '#') {
mode = 3;
} else if (utf8Char == ':' && string_no != -1) {
// Search for colon
dst = src + 1;
language_strings[string_no] = dst;
stringIndex++;
mode = 1;
} else if (!strncmp(src, "STR_", 4)){
// Copy in the string number, 4 characters only
if (sscanf(src, "STR_%4d", &string_no) != 1) {
string_no = -1;
}
}
break;
case 1:
// Copy string over, stop at line break
if (utf8Char == '{') {
token = src + 1;
mode = 2;
} else if (utf8Char == '\n' || *src == '\r') {
*dst = 0;
mode = 0;
} else {
*dst++ = utf8Char;
}
break;
case 2:
// Read token, convert to code
if (utf8Char == '}') {
int tokenLength = min(src - token, sizeof(tokenBuffer) - 1);
memcpy(tokenBuffer, token, tokenLength);
tokenBuffer[tokenLength] = 0;
char code = format_get_code(tokenBuffer);
if (code == 0)
code = atoi(tokenBuffer);
*dst++ = code;
mode = 1;
}
break;
case 3:
if (utf8Char == '\n' || utf8Char == '\r') {
mode = 0;
}
}
}
language_num_strings = stringIndex;
return 1;
}
void language_close()
{
if (language_buffer != NULL)
free(language_buffer);
language_buffer_size = 0;
if (language_strings != NULL)
free(language_strings);
language_num_strings = 0;
gCurrentLanguage = LANGUAGE_UNDEFINED;
}

43
src/language.h Normal file
View File

@ -0,0 +1,43 @@
/*****************************************************************************
* 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/>.
*****************************************************************************/
#ifndef _LANGUAGE_H_
#define _LANGUAGE_H_
#include "rct2.h"
#include "string_ids.h"
enum {
LANGUAGE_UNDEFINED,
LANGUAGE_ENGLISH_UK,
LANGUAGE_ENGLISH_US,
LANGUAGE_DUTCH,
LANGUAGE_FRENCH,
LANGUAGE_COUNT
};
extern const char *language_names[LANGUAGE_COUNT];
extern int gCurrentLanguage;
const char *language_get_string(rct_string_id id);
int language_open(int id);
void language_close();
#endif

View File

@ -94,8 +94,34 @@ static int object_calculate_checksum(rct_object_entry *entry, char *data, int da
return checksum;
}
/**
* rct2: 0x66B355 part
* If al is 0
* chunk : esi
*/
int object_scenario_load_custom_text(char* chunk){
int ebp = (int)(&((uint32*)chunk)[2]);
int edx = 0;
int eax, ebx, ecx, edi;
RCT2_CALLFUNC_X(0x6A9E24, &eax, &ebx, &ecx, &edx, (int*)&chunk, &edi, &ebp);
*((uint16*)chunk) = eax;
edx++;
RCT2_CALLFUNC_X(0x6A9E24, &eax, &ebx, &ecx, &edx, (int*)&chunk, &edi, &ebp);
*((uint16*)chunk + 1) = eax;
edx++;
RCT2_CALLFUNC_X(0x6A9E24, &eax, &ebx, &ecx, &edx, (int*)&chunk, &edi, &ebp);
*((uint16*)chunk + 2) = eax;
if (RCT2_GLOBAL(0x9ADAF4, int) == -1)return 0;
else *(RCT2_GLOBAL(0x9ADAF4, uint32*)) = 0;
return 1;
}
int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp)
{
if (type == 10){
if (eax == 0) return object_scenario_load_custom_text((char*)esi);
}
RCT2_CALLPROC_X(RCT2_ADDRESS(0x0098D9D4, uint32)[type], eax, ebx, ecx, edx, esi, edi, ebp);
#ifdef _MSC_VER
__asm jb success

View File

@ -71,7 +71,7 @@ void park_init()
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PARK_RATING, uint16) = 0;
_guestGenerationProbability = 0;
RCT2_GLOBAL(RCT2_TOTAL_RIDE_VALUE, uint16) = 0;
RCT2_GLOBAL(0x01357CF4, sint32) = -1;
RCT2_GLOBAL(RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT, sint32) = -1;
for (i = 0; i < 20; i++)
RCT2_ADDRESS(0x01358102, uint8)[i] = 0;

View File

@ -37,6 +37,7 @@
#include "game.h"
#include "gfx.h"
#include "intro.h"
#include "language.h"
#include "map.h"
#include "news_item.h"
#include "object.h"
@ -76,9 +77,6 @@ __declspec(dllexport) int StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInsta
{
print_launch_information();
// OpenRCT2 initialisation
language_open("data/language/english.txt");
// Begin RCT2
RCT2_GLOBAL(RCT2_ADDRESS_HINSTANCE, HINSTANCE) = hInstance;
RCT2_GLOBAL(RCT2_ADDRESS_CMDLINE, LPSTR) = lpCmdLine;
@ -88,6 +86,7 @@ __declspec(dllexport) int StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInsta
audio_get_devices();
RCT2_CALLPROC(0x0040502E); // get_dsound_devices()
config_init();
language_open(gGeneral_config.language);
rct2_init();
rct2_loop();
osinterface_free();

View File

@ -42,6 +42,12 @@ typedef unsigned long long uint64;
#define ror32(x, shift) (((uint32)(x) >> (shift)) | ((uint32)(x) << (32 - (shift))))
#define rol64(x, shift) (((uint64)(x) << (shift)) | ((uint32)(x) >> (64 - (shift))))
#define ror64(x, shift) (((uint64)(x) >> (shift)) | ((uint32)(x) << (64 - (shift))))
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#define sgn(x) ((x > 0) ? 1 : ((x < 0) ? -1 : 0))
#define clamp(l, x, h) (min(h, max(l, x)))

View File

@ -100,7 +100,8 @@ typedef struct {
uint16 var_14A;
uint8 pad_14C;
uint8 var_14D;
uint8 pad_14E[0x0A];
uint8 pad_14E[0x06];
uint32 var_154;
uint16 var_158;
uint8 pad_15A[0x26];
uint16 build_date;

View File

@ -25,6 +25,7 @@
#include "currency.h"
#include "game.h"
#include "date.h"
#include "language.h"
#include "rct2.h"
#include "string_ids.h"
#include "util.h"
@ -1471,7 +1472,7 @@ void format_string_code(unsigned char format_code, char **dest, char **args)
value = *((uint16*)*args);
*args += 2;
strcpy(*dest, get_string(STR_MONTH_MARCH + date_get_month(value)));
strcpy(*dest, language_get_string(STR_MONTH_MARCH + date_get_month(value)));
*dest += strlen(*dest);
break;
case FORMAT_VELOCITY:
@ -1591,7 +1592,7 @@ void format_string_part(char **dest, rct_string_id format, char **args)
{
if (format < 0x8000) {
// Language string
format_string_part_from_raw(dest, get_string(format), args);
format_string_part_from_raw(dest, language_get_string(format), args);
} else if (format < 0x9000) {
// Custom string
format -= 0x8000;
@ -1690,108 +1691,4 @@ void reset_saved_strings() {
for (int i = 0; i < 1024; i++) {
RCT2_ADDRESS(0x135A8F4, uint8)[i * 32] = 0;
}
}
// Buffer storing all the string data
long language_buffer_size = 0;
char *language_buffer = NULL;
// List of string pointers into the string data
int language_num_strings = 0;
char **language_strings = NULL;
const char *get_string(rct_string_id id)
{
const char *rct = RCT2_ADDRESS(0x009BF2D4, const char*)[id];
const char *openrct = language_strings == NULL ? NULL : language_strings[id];
const char *str = (openrct == NULL || strlen(openrct) == 0 ? rct : openrct);
return str == NULL ? "" : str;
}
/**
* Partial support to open a uncompiled language file which parses tokens and converts them to the corresponding character
* code. Due to resource strings (strings in scenarios and objects) being written to the original game's string table,
* get_string will use those if the same entry in the loaded language is empty.
*
* Unsure at how the original game decides which entries to write resource strings to, but this could affect adding new
* strings for the time being. Further investigation is required.
*
* Also note that all strings are currently still ASCII. It probably can't be converted to UTF-8 until all game functions that
* read / write strings in some way is decompiled. The original game used a DIY extended 8-bit extended ASCII set for special
* characters, format codes and accents.
*
* In terms of reading the language files, the STR_XXXX part is completely ignored at the moment. It just parses each line from
* the colon and thus not allowing gaps in the string indices.
*/
int language_open(const char *filename)
{
FILE *f = fopen(filename, "rb");
if (f == NULL)
return 0;
fseek(f, 0, SEEK_END);
language_buffer_size = ftell(f);
language_buffer = calloc(1, language_buffer_size);
fseek(f, 0, SEEK_SET);
fread(language_buffer, language_buffer_size, 1, f);
fclose(f);
language_strings = calloc(STR_COUNT, sizeof(char*));
char *dst, *token;
char tokenBuffer[64];
int i, stringIndex = 0, mode = 0;
for (i = 0; i < language_buffer_size; i++) {
char *src = &language_buffer[i];
switch (mode) {
case 0:
// Search for colon
if (*src == ':') {
dst = src + 1;
language_strings[stringIndex++] = dst;
mode = 1;
}
break;
case 1:
// Copy string over, stop at line break
if (*src == '{') {
token = src + 1;
mode = 2;
} else if (*src == '\n' || *src == '\r') {
*dst = 0;
mode = 0;
} else {
*dst++ = *src;
}
break;
case 2:
// Read token, convert to code
if (*src == '}') {
int tokenLength = min(src - token, sizeof(tokenBuffer) - 1);
memcpy(tokenBuffer, token, tokenLength);
tokenBuffer[tokenLength] = 0;
char code = format_get_code(tokenBuffer);
if (code == 0)
code = atoi(tokenBuffer);
*dst++ = code;
mode = 1;
}
break;
}
}
language_num_strings = stringIndex;
return 1;
}
void language_close()
{
if (language_buffer != NULL)
free(language_buffer);
language_buffer_size = 0;
if (language_strings != NULL)
free(language_strings);
language_num_strings = 0;
}

View File

@ -28,9 +28,8 @@ void generate_string_file();
void reset_saved_strings();
void error_string_quit(int error, rct_string_id format);
const char *get_string(rct_string_id id);
int language_open(const char *filename);
void language_close();
char format_get_code(const char *token);
const char *format_get_token(char code);
enum {
// Font format codes
@ -238,6 +237,7 @@ enum {
STR_SHOPS_AND_STALLS = 975,
STR_RESTROOMS_AND_INFORMATION_KIOSKS = 976,
STR_RESEARCH_AND_DEVELOPMENT = 983,
STR_RAISE_COST_AMOUNT = 984,
STR_LOWER_COST_AMOUNT = 985,
STR_COST_AMOUNT = 986,
@ -515,7 +515,29 @@ enum {
STR_RESEARCH_COST_PER_MONTH = 2265,
STR_RESEARCH_PRIORITIES = 2266,
STR_RESEARCH_TYPE_LABEL = 2269,
STR_RESEARCH_PROGRESS_LABEL = 2270,
STR_RESEARCH_EXPECTED_LABEL = 2271,
STR_RESEARCH_RIDE_LABEL = 2272,
STR_RESEARCH_SCENERY_LABEL = 2273,
STR_RESEARCH_SHOW_DETAILS_TIP = 2274,
STR_FINANCES_RESEARCH = 2275,
STR_RESEARCH_AND_DEVELOPMENT_TIP = 2276,
STR_RESEARCH_UNKNOWN = 2277,
STR_TRANSPORT_RIDE = 2278,
STR_GENTLE_RIDE = 2279,
STR_ROLLER_COASTER = 2280,
STR_THRILL_RIDE = 2281,
STR_WATER_RIDE = 2282,
STR_SHOP_STALL = 2283,
STR_SCENERY_THEMEING = 2284,
STR_INITIAL_RESEARCH = 2285,
STR_DESIGNING = 2286,
STR_COMPLETING_DESIGN = 2287,
STR_UNKNOWN = 2288,
STR_SELECT_SCENARIO = 2291,

View File

@ -318,11 +318,11 @@ static void widget_tab_draw(rct_drawpixelinfo *dpi, rct_window *w, int widgetInd
b = w->y + widget->bottom;
// Get the colour and image
colour = w->colours[widget->colour] << 19;
colour = w->colours[widget->colour];
image = widget->image + 2;
// Draw coloured image
gfx_draw_sprite(dpi, image | colour, l, t, 0);
gfx_draw_sprite(dpi, image | (colour << 19), l, t, 0);
}
/**

View File

@ -642,7 +642,7 @@ int window_find_widget_from_point(rct_window *w, int x, int y)
/**
* Invalidates the specified window.
* rct2: 0x006EB31A
* rct2: 0x006EB13A
*
* @param window The window to invalidate (esi).
*/
@ -924,7 +924,7 @@ void window_zoom_in(rct_window *w)
w->saved_view_x += v->view_width >> 1;
w->saved_view_y += v->view_height >> 1;
RCT2_CALLPROC_X(0x006EB13A, 0, 0, 0, 0, (int)w, 0, 0);
window_invalidate(w);
}
/**
@ -951,7 +951,7 @@ void window_zoom_out(rct_window *w)
w->saved_view_x -= width / 2;
w->saved_view_y -= height >> 1;
RCT2_CALLPROC_X(0x006EB13A, 0, 0, 0, 0, (int)w, 0, 0);
window_invalidate(w);
}
/**

View File

@ -287,6 +287,7 @@ enum {
WC_CLEAR_SCENERY = 50,
WC_MANAGE_TRACK_DESIGN = 89,
WC_CHEATS = 110,
WC_RESEARCH = 111
} WINDOW_CLASS;
enum PROMPT_MODE {
@ -374,8 +375,10 @@ void window_park_rating_open();
void window_finances_open();
void window_new_campaign_open(int campaignType);
void window_ride_list_open();
void window_new_ride_open();
void window_banner_open();
void window_cheats_open();
void window_research_open();
void window_guest_list_init_vars_a();
void window_guest_list_init_vars_b();

View File

@ -89,8 +89,8 @@ static rct_widget window_cheats_money_widgets[] = {
{ WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 2462}, // tab 1
{ WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 2462}, // tab 2
{ WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 2462}, // tab 3
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), 2760, STR_VERY_HIGH}, // high money
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(3), HPL(3), STR_FREE, STR_FREE}, //Park Entrance Fee Toggle
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), 2760, STR_NONE}, // high money
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(3), HPL(3), 2761, STR_NONE}, //Park Entrance Fee Toggle
{ WIDGETS_END },
};
@ -102,8 +102,8 @@ static rct_widget window_cheats_guests_widgets[] = {
{ WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 2462 }, // tab 1
{ WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 2462 }, // tab 2
{ WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 2462 }, // tab 3
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), STR_EXTREME, STR_EXTREME}, // happy guests
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(3), HPL(3), STR_NONE, STR_NONE}, // happy guests
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), 2764, STR_NONE}, // happy guests
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(3), HPL(3), 2765, STR_NONE}, // happy guests
{ WIDGETS_END },
};
@ -116,10 +116,10 @@ static rct_widget window_cheats_misc_widgets[] = {
{ WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 2462 }, // tab 1
{ WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 2462 }, // tab 2
{ WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 2462}, // tab 3
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(0), HPL(0), STR_NONE, STR_NONE}, // Freeze climate
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), STR_NONE, STR_NONE}, // open / close park
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(2), HPL(2), STR_NONE, STR_NONE}, // decrease game speed
{ WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(2), HPL(2), STR_NONE, STR_NONE}, // increase game speed
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(0), HPL(0), 2767, STR_NONE}, // Freeze climate
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(1), HPL(1), 2769, STR_NONE}, // open / close park
{ WWT_CLOSEBOX, 1, XPL(0), WPL(0), YPL(2), HPL(2), 2771, STR_NONE}, // decrease game speed
{ WWT_CLOSEBOX, 1, XPL(1), WPL(1), YPL(2), HPL(2), 2772, STR_NONE}, // increase game speed
{ WIDGETS_END },
};
@ -306,8 +306,8 @@ static void window_cheats_money_mouseup()
break;
case WIDX_PARK_ENTRANCE_FEE:
RCT2_GLOBAL(0x13573E5, uint32) ^= 0x020;
if (!(RCT2_GLOBAL(0x13573E5, uint32) & 0x020) ) w->widgets[widgetIndex].image = 2010;
else w->widgets[widgetIndex].image = STR_FREE;
if (!(RCT2_GLOBAL(0x13573E5, uint32) & 0x020) ) w->widgets[widgetIndex].image = 2762;
else w->widgets[widgetIndex].image = 2761;
window_invalidate_by_id(0x40 | WC_PARK_INFORMATION, 0);
break;
}
@ -384,10 +384,12 @@ static void window_cheats_misc_mouseup()
break;
case WIDX_FREEZE_CLIMATE:
toggle_climate_lock();
w->widgets[widgetIndex].image = w->widgets[widgetIndex].image == 2767 ? 2768 : 2767;
window_invalidate_by_id(0x40 | WC_BOTTOM_TOOLBAR, 0);
break;
case WIDX_OPEN_CLOSE_PARK:
game_do_command(0, 1, 0, park_is_open() ? 0 : 0x101, GAME_COMMAND_SET_PARK_OPEN, 0, 0);
w->widgets[widgetIndex].image = w->widgets[widgetIndex].image == 2769 ? 2770 : 2769;
window_invalidate_by_id(0x40 | WC_BOTTOM_TOOLBAR, 0);
break;
case WIDX_DECREASE_GAME_SPEED:
@ -478,23 +480,10 @@ static void window_cheats_paint()
// Format text
sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_BLACK, "Increases every peeps happiness to max.");
// Draw shadow
gfx_draw_string(dpi, buffer, 0, w->x + 4, w->y + 50);
gfx_draw_string(dpi, buffer, 0, w->x + XPL(0) + TXTO, w->y + YPL(0) + TXTO);
sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_BLACK, "Large group of peeps arrive");
gfx_draw_string(dpi, buffer, 0, w->x + XPL(0) + TXTO, w->y + YPL(2) + TXTO);
sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_WINDOW_COLOUR_2, "Large Tram");
gfx_draw_string(dpi, buffer, 0, w->x + XPL(0) + TXTO, w->y + YPL(3) + TXTO);
}
else if (w->page == WINDOW_CHEATS_PAGE_MISC){
char buffer[256];
sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_WINDOW_COLOUR_2, "Freeze climate");
gfx_draw_string(dpi, buffer, 0, w->x + XPL(0) + TXTO, w->y + YPL(0) + TXTO);
sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_WINDOW_COLOUR_2, "Open/Close Park");
gfx_draw_string(dpi, buffer, 0, w->x + XPL(0) + TXTO, w->y + YPL(1) + TXTO);
sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_WINDOW_COLOUR_2, "Slower Gamespeed");
gfx_draw_string(dpi, buffer, 0, w->x + XPL(0) + TXTO, w->y + YPL(2) + TXTO);
sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_WINDOW_COLOUR_2, "Faster Gamespeed");
gfx_draw_string(dpi, buffer, 0, w->x + XPL(1) + TXTO, w->y + YPL(2) + TXTO);
}
}

View File

@ -48,7 +48,8 @@ enum {
WIDX_GUESTS,
WIDX_CLEAR_SCENERY,
WIDX_FASTFORWARD
WIDX_FASTFORWARD,
WIDX_RESEARCH
};
typedef enum {
@ -93,8 +94,8 @@ static rct_widget window_game_top_toolbar_widgets[] = {
{ WWT_TRNBTN, 3, 0x0230, 0x024D, 0, 27, 0x20000000 | SPR_TOOLBAR_GUESTS, STR_GUESTS_TIP }, // Guests
{ WWT_TRNBTN, 2, 0x0230, 0x024D, 0, 27, 0x20000000 | SPR_TOOLBAR_CLEAR_SCENERY, STR_CLEAR_SCENERY_TIP }, // Clear scenery
{ WWT_TRNBTN, 0, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, STR_NONE }, // Fast forward
{ WWT_TRNBTN, 0, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, STR_NONE }, // Fast forward
{ WWT_TRNBTN, 3, 0x001E, 0x003B, 0, 27, 0x20000000 | 0x15F9, 2275 }, // Research
{ WIDGETS_END },
};
@ -152,8 +153,27 @@ void window_game_top_toolbar_open()
WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_5
);
window->widgets = window_game_top_toolbar_widgets;
window->enabled_widgets |= (1 | 2 | 4 | 8 | 0x10 | 0x20 | 0x40 | 0x80 | 0x100 | 0x200 | 0x400 | 0x800 |
0x1000 | 0x2000 | 0x4000 | 0x8000 | 0x10000 | 0x20000);
window->enabled_widgets |=
(1 << WIDX_PAUSE) |
(1 << WIDX_FILE_MENU) |
(1 << WIDX_ZOOM_OUT) |
(1 << WIDX_ZOOM_IN) |
(1 << WIDX_ROTATE) |
(1 << WIDX_VIEW_MENU) |
(1 << WIDX_MAP) |
(1 << WIDX_LAND) |
(1 << WIDX_WATER) |
(1 << WIDX_SCENERY) |
(1 << WIDX_PATH) |
(1 << WIDX_CONSTRUCT_RIDE) |
(1 << WIDX_RIDES) |
(1 << WIDX_PARK) |
(1 << WIDX_STAFF) |
(1 << WIDX_CLEAR_SCENERY) |
(1ULL << WIDX_FASTFORWARD) |
(1ULL << WIDX_RESEARCH);
window_init_scroll_widgets(window);
window->colours[0] = 7;
window->colours[1] = 12;
@ -170,22 +190,13 @@ static void window_game_top_toolbar_mouseup()
short widgetIndex;
rct_window *w, *mainWindow;
#ifdef _MSC_VER
__asm mov widgetIndex, dx
#else
__asm__ ( "mov %[widgetIndex], dx " : [widgetIndex] "+m" (widgetIndex) );
#endif
#ifdef _MSC_VER
__asm mov w, esi
#else
__asm__ ( "mov %[w], esi " : [w] "+m" (w) );
#endif
window_mouse_up_get_registers(w, widgetIndex);
switch (widgetIndex) {
case WIDX_PAUSE:
game_do_command(0, 1, 0, 0, GAME_COMMAND_TOGGLE_PAUSE, 0, 0);
// Not sure where this was done in the original code
w->pressed_widgets ^= (1 << WIDX_PAUSE);
break;
case WIDX_FASTFORWARD:
// This is an excellent place to add in debugging statements and
@ -209,7 +220,6 @@ static void window_game_top_toolbar_mouseup()
window_rotate_camera(mainWindow);
break;
case WIDX_MAP:
//RCT2_CALLPROC_EBPSAFE(0x0068C88A);
window_map_open();
break;
case WIDX_CLEAR_SCENERY:
@ -260,7 +270,7 @@ static void window_game_top_toolbar_mouseup()
}
break;
case WIDX_CONSTRUCT_RIDE:
RCT2_CALLPROC_EBPSAFE(0x006B3CFF);
window_new_ride_open();
break;
case WIDX_RIDES:
window_ride_list_open();
@ -270,11 +280,13 @@ static void window_game_top_toolbar_mouseup()
break;
case WIDX_STAFF:
window_staff_open();
//RCT2_CALLPROC_EBPSAFE(0x006BD3CC);
break;
case WIDX_GUESTS:
window_guest_list_open();
break;
case WIDX_RESEARCH:
window_research_open();
break;
}
}
@ -447,7 +459,7 @@ static void window_game_top_toolbar_dropdown()
default:
return;
}
RCT2_CALLPROC_X(0x6EB13A, 0, 0, 0, 0, (int)w, 0, 0);
window_invalidate(w);
}
}
}
@ -488,6 +500,10 @@ static void window_game_top_toolbar_invalidate()
window_game_top_toolbar_widgets[WIDX_RIDES].right = x;
x -= 29;
window_game_top_toolbar_widgets[WIDX_RIDES].left = x;
x -= 1;
window_game_top_toolbar_widgets[WIDX_RESEARCH].right = x;
x -= 29;
window_game_top_toolbar_widgets[WIDX_RESEARCH].left = x;
x -= 11;
window_game_top_toolbar_widgets[WIDX_CONSTRUCT_RIDE].right = x;
x -= 29;
@ -524,6 +540,18 @@ static void window_game_top_toolbar_invalidate()
w->pressed_widgets |= (1 << WIDX_FASTFORWARD);
else
w->pressed_widgets &= ~(1 << WIDX_FASTFORWARD);
// Zoomed out/in disable. Not sure where this code is in the original.
if (window_get_main()->viewport->zoom == 0){
w->disabled_widgets |= (1 << WIDX_ZOOM_IN);
}
else if (window_get_main()->viewport->zoom == 3){
w->disabled_widgets |= (1 << WIDX_ZOOM_OUT);
}
else
{
w->disabled_widgets &= ~((1 << WIDX_ZOOM_IN) | (1 << WIDX_ZOOM_OUT));
}
}
/**
@ -559,4 +587,10 @@ static void window_game_top_toolbar_paint()
imgId++;
imgId |= (RCT2_GLOBAL(RCT2_ADDRESS_HANDYMAN_COLOUR, uint8) << 19) | 0xA0000000 | (RCT2_GLOBAL(RCT2_ADDRESS_MECHANIC_COLOUR, uint8) << 24);
gfx_draw_sprite(dpi, imgId, x, y, 0);
// Draw research button
x = w->x + window_game_top_toolbar_widgets[WIDX_RESEARCH].left - 1;
y = w->y + window_game_top_toolbar_widgets[WIDX_RESEARCH].top - 1;
imgId = SPR_TAB_FINANCES_RESEARCH_0;
gfx_draw_sprite(dpi, imgId, x, y, 0);
}

View File

@ -33,6 +33,24 @@ enum {
WINDOW_NEW_RIDE_TAB_RESEARCH
} WINDOW_RIDE_CONSTRUCTION_TAB;
enum {
WIDX_BACKGROUND,
WIDX_TITLE,
WIDX_CLOSE,
WIDX_PAGE_BACKGROUND,
WIDX_TAB_1,
WIDX_TAB_2,
WIDX_TAB_3,
WIDX_TAB_4,
WIDX_TAB_5,
WIDX_TAB_6,
WIDX_TAB_7,
WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP,
WIDX_LAST_DEVELOPMENT_GROUP,
WIDX_LAST_DEVELOPMENT_BUTTON
};
/**
*
* rct2: 0x006ACA58
@ -55,4 +73,54 @@ void window_new_ride_init_vars() {
}
RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_RIDE_LIST_INFORMATION_TYPE, uint8) = 0;
}
/**
*
* rct2: 0x006B3CFF
*/
void window_new_ride_open()
{
rct_window *w;
w = window_bring_to_front_by_id(WC_CONSTRUCT_RIDE, 0);
if (w != NULL)
return;
// Not sure what these windows are
window_close_by_id(161, 0);
window_close_by_id(162, 0);
w = window_create_auto_pos(601, 370, (uint32*)0x0098E354, WC_CONSTRUCT_RIDE, 0x400);
w->widgets = (rct_widget*)0x009AEBF4;
w->enabled_widgets =
(1 << WIDX_CLOSE) |
(1 << WIDX_TAB_1) |
(1 << WIDX_TAB_2) |
(1 << WIDX_TAB_3) |
(1 << WIDX_TAB_4) |
(1 << WIDX_TAB_5) |
(1 << WIDX_TAB_6) |
(1 << WIDX_TAB_7) |
(1 << 14) |
(1 << 15);
window_init_scroll_widgets(w);
w->frame_no = 0;
w->colours[0] = 24;
w->colours[1] = 26;
w->colours[2] = 26;
w->var_480 = -1;
w->var_482 = -1;
RCT2_GLOBAL(0x00F43866, sint16) = -1;
RCT2_CALLPROC_EBPSAFE(0x006B6F3E);
w->var_482 = RCT2_ADDRESS(0x00F43825, sint16)[RCT2_GLOBAL(0x00F43824, uint8)];
if (w->var_482 == -1)
w->var_482 = RCT2_GLOBAL(0x00F43523, sint16);
w->width = 1;
RCT2_CALLPROC_EBPSAFE(0x006B3DF1); // initialise window size and widgets
RCT2_CALLPROC_EBPSAFE(0x006B7220);
}

View File

@ -129,18 +129,7 @@ static void window_news_mouseup()
short widgetIndex;
rct_window *w;
#ifdef _MSC_VER
__asm mov widgetIndex, dx
#else
__asm__ ( "mov %[widgetIndex], dx " : [widgetIndex] "+m" (widgetIndex) );
#endif
#ifdef _MSC_VER
__asm mov w, esi
#else
__asm__ ( "mov %[w], esi " : [w] "+m" (w) );
#endif
window_mouse_up_get_registers(w, widgetIndex);
if (widgetIndex == WIDX_CLOSE)
window_close(w);
@ -304,18 +293,7 @@ static void window_news_paint()
rct_window *w;
rct_drawpixelinfo *dpi;
#ifdef _MSC_VER
__asm mov w, esi
#else
__asm__ ( "mov %[w], esi " : [w] "+m" (w) );
#endif
#ifdef _MSC_VER
__asm mov dpi, edi
#else
__asm__ ( "mov %[dpi], edi " : [dpi] "+m" (dpi) );
#endif
window_paint_get_registers(w, dpi);
window_draw_widgets(w, dpi);
}
@ -331,18 +309,7 @@ static void window_news_scrollpaint()
rct_drawpixelinfo *dpi;
rct_news_item *newsItems, *newsItem, *newsItem2;
#ifdef _MSC_VER
__asm mov w, esi
#else
__asm__ ( "mov %[w], esi " : [w] "+m" (w) );
#endif
#ifdef _MSC_VER
__asm mov dpi, edi
#else
__asm__ ( "mov %[dpi], edi " : [dpi] "+m" (dpi) );
#endif
window_paint_get_registers(w, dpi);
y = 0;
newsItems = RCT2_ADDRESS(RCT2_ADDRESS_NEWS_ITEM_LIST, rct_news_item);
@ -366,9 +333,9 @@ static void window_news_scrollpaint()
gfx_draw_string_left(dpi, 2235, (void*)0x013CE952, 2, 4, y);
// Item text
RCT2_GLOBAL(0x009B5F2C, uint8) = newsItem->colour;
strcpy((char*)0x009B5F2D, newsItem->text);
gfx_draw_string_left_wrapped(dpi, 0, 2, y + 10, 325, 1926, 14);
char *sz = (char*)0x013CE952;
sprintf(sz, "%c%c%s", newsItem->colour, FORMAT_SMALLFONT, newsItem->text);
gfx_draw_string_left_wrapped(dpi, &sz, 2, y + 10, 325, 1170, 14);
// Subject button
if ((RCT2_ADDRESS(0x0097BE7C, uint8)[newsItem->type] & 2) && !(newsItem->flags & 1)) {

View File

@ -18,42 +18,49 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
/**
* To better group the options together and allow the window to be scalable with additional OpenRCT2 options, the window has
* been changed to a tab interface similar to the options window seen in Locomotion.
*
* TODO Some parts, particularly the string handling and order of widgets needs reorganising.
* Padding between the widgets and the window needs reducing, an artifact from originally being inside group boxes.
*/
#include <stdint.h>
#include "addresses.h"
#include "audio.h"
#include "config.h"
#include "gfx.h"
#include "language.h"
#include "osinterface.h"
#include "sprites.h"
#include "string_ids.h"
#include "viewport.h"
#include "widget.h"
#include "window.h"
#include "window_dropdown.h"
#include <stdint.h>
enum {
WINDOW_OPTIONS_PAGE_DISPLAY,
WINDOW_OPTIONS_PAGE_CULTURE,
WINDOW_OPTIONS_PAGE_AUDIO,
WINDOW_OPTIONS_PAGE_INPUT,
WINDOW_OPTIONS_PAGE_MISC,
WINDOW_OPTIONS_PAGE_COUNT
};
enum WINDOW_OPTIONS_WIDGET_IDX {
WIDX_BACKGROUND,
WIDX_TITLE,
WIDX_CLOSE,
WIDX_SOUND_GROUP,
WIDX_SOUND,
WIDX_SOUND_DROPDOWN,
WIDX_MUSIC,
WIDX_MUSIC_DROPDOWN,
WIDX_SOUND_QUALITY,
WIDX_SOUND_QUALITY_DROPDOWN,
WIDX_SOUND_SW_BUFFER_CHECKBOX,
WIDX_SOUND_PAUSED_CHECKBOX,
WIDX_UNITS_GROUP,
WIDX_CURRENCY,
WIDX_CURRENCY_DROPDOWN,
WIDX_DISTANCE,
WIDX_DISTANCE_DROPDOWN,
WIDX_TEMPERATURE,
WIDX_TEMPERATURE_DROPDOWN,
WIDX_HEIGHT_LABELS,
WIDX_HEIGHT_LABELS_DROPDOWN,
WIDX_DISPLAY_GROUP,
WIDX_PAGE_BACKGROUND,
WIDX_TAB_1,
WIDX_TAB_2,
WIDX_TAB_3,
WIDX_TAB_4,
WIDX_TAB_5,
WIDX_RESOLUTION,
WIDX_RESOLUTION_DROPDOWN,
WIDX_FULLSCREEN,
@ -62,64 +69,106 @@ enum WINDOW_OPTIONS_WIDGET_IDX {
WIDX_GRIDLINES_CHECKBOX,
WIDX_CONSTRUCTION_MARKER,
WIDX_CONSTRUCTION_MARKER_DROPDOWN,
WIDX_CONTROLS_GROUP,
WIDX_LANGUAGE,
WIDX_LANGUAGE_DROPDOWN,
WIDX_CURRENCY,
WIDX_CURRENCY_DROPDOWN,
WIDX_DISTANCE,
WIDX_DISTANCE_DROPDOWN,
WIDX_TEMPERATURE,
WIDX_TEMPERATURE_DROPDOWN,
WIDX_HEIGHT_LABELS,
WIDX_HEIGHT_LABELS_DROPDOWN,
WIDX_SOUND,
WIDX_SOUND_DROPDOWN,
WIDX_MUSIC,
WIDX_MUSIC_DROPDOWN,
WIDX_SOUND_QUALITY,
WIDX_SOUND_QUALITY_DROPDOWN,
WIDX_SOUND_SW_BUFFER_CHECKBOX,
WIDX_SOUND_PAUSED_CHECKBOX,
WIDX_SCREEN_EDGE_SCROLLING,
WIDX_HOTKEY_DROPDOWN,
WIDX_GENERAL_GROUP,
WIDX_REAL_NAME_CHECKBOX,
WIDX_SAVE_PLUGIN_DATA_CHECKBOX
WIDX_SAVE_PLUGIN_DATA_CHECKBOX,
};
#define WW 310
#define WH 399
#define WH 135
static rct_widget window_options_widgets[] = {
{ WWT_FRAME, 0, 0, WW - 1, 0, WH - 1, STR_NONE, STR_NONE },
{ WWT_CAPTION, 0, 1, WW - 2, 1, 14, STR_OPTIONS, STR_WINDOW_TITLE_TIP },
{ WWT_CLOSEBOX, 0, WW-13, WW - 3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP },
{ WWT_GROUPBOX, 0, 3, 306, 17, 105, STR_SOUND, STR_NONE },
{ WWT_DROPDOWN, 0, 10, 299, 31, 42, 0x361, STR_NONE }, // sound
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 32, 41, 0x36C, STR_NONE },
{ WWT_DROPDOWN, 0, 155, 299, 46, 57, 0x365, STR_NONE }, // music
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 47, 56, 0x36C, STR_NONE },
{ WWT_DROPDOWN, 0, 155, 299, 61, 72, 0x366, STR_NONE }, // sound quality
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 62, 71, 0x36C, STR_NONE },
{ WWT_CHECKBOX, 0, 10, 299, 76, 87, STR_SOUND_FORCED_SOFTWARE_BUFFER_MIXING, STR_SOUND_FORCED_SOFTWARE_BUFFER_MIXING_TIP },
{ WWT_CHECKBOX, 0, 10, 229, 88, 99, STR_SOUND, STR_NONE }, // enable/disable sound
{ WWT_GROUPBOX, 0, 3, 306, 112, 188, STR_UNITS, STR_NONE },
{ WWT_DROPDOWN, 0, 155, 299, 126, 137, 0x367, STR_NONE }, // currency
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 127, 136, 0x36C, STR_NONE },//
{ WWT_DROPDOWN, 0, 155, 299, 141, 152, 0x368, STR_NONE }, // distance
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 142, 151, 0x36C, STR_NONE },
{ WWT_DROPDOWN, 0, 155, 299, 156, 168, 0x36B, STR_NONE }, // temperature
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 157, 166, 0x36C, STR_NONE }, //jjj
{ WWT_DROPDOWN, 0, 155, 299, 171, 182, 0x364, STR_NONE }, // height labels
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 172, 181, 0x36C, STR_NONE },
{ WWT_GROUPBOX, 0, 3, 306, 194, 285, STR_DISPLAY, STR_NONE },//
{ WWT_DROPDOWN, 0, 155, 299, 208, 219, 0x348, STR_NONE }, // resolution
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 209, 218, 0x36C, STR_NONE },
{ WWT_DROPDOWN, 0, 155, 299, 223, 234, 0x348, STR_NONE }, // fullscreen
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 224, 233, 0x36C, STR_NONE },
{ WWT_CHECKBOX, 0, 10, 299, 239, 250, STR_TILE_SMOOTHING, STR_TILE_SMOOTHING_TIP },
{ WWT_CHECKBOX, 0, 10, 299, 254, 265, STR_GRIDLINES, STR_GRIDLINES_TIP },
{ WWT_DROPDOWN, 0, 155, 299, 268, 279, STR_NONE, STR_NONE }, // construction marker
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 269, 278, 0x36C, STR_NONE },
{ WWT_GROUPBOX, 0, 3, 306, 291, 337, STR_CONTROLS, STR_NONE },
{ WWT_CHECKBOX, 2, 10, 299, 306, 317, STR_SCREEN_EDGE_SCROLLING, STR_SCREEN_EDGE_SCROLLING_TIP },
{ WWT_DROPDOWN_BUTTON, 0, 26, 185, 321, 331, STR_HOTKEY, STR_HOTKEY_TIP },
{ WWT_GROUPBOX, 0, 3, 306, 344, 392, STR_GENERAL, STR_NONE },
{ WWT_CHECKBOX, 2, 10, 299, 358, 369, STR_REAL_NAME, STR_REAL_NAME_TIP },
{ WWT_CHECKBOX, 2, 10, 299, 372, 384, STR_SAVE_PLUGIN_DATA, STR_SAVE_PLUGIN_DATA_TIP },
{ WWT_RESIZE, 1, 0, WW - 1, 43, WH - 1, 0xFFFFFFFF, STR_NONE },
{ WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_NONE },
{ WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_NONE },
{ WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, STR_NONE },
{ WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_NONE },
{ WWT_TAB, 1, 127, 157, 17, 43, 0x2000144E, STR_NONE },
// Display tab
{ WWT_DROPDOWN, 0, 155, 299, 53, 64, 840, STR_NONE }, // resolution
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 54, 63, 876, STR_NONE },
{ WWT_DROPDOWN, 0, 155, 299, 68, 79, 871, STR_NONE }, // fullscreen
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 69, 78, 876, STR_NONE },
{ WWT_CHECKBOX, 0, 10, 299, 84, 95, STR_TILE_SMOOTHING, STR_TILE_SMOOTHING_TIP },
{ WWT_CHECKBOX, 0, 10, 299, 99, 110, STR_GRIDLINES, STR_GRIDLINES_TIP },
{ WWT_DROPDOWN, 0, 155, 299, 113, 124, STR_NONE, STR_NONE }, // construction marker
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 114, 123, 876, STR_NONE },
// Culture / units tab
{ WWT_DROPDOWN, 0, 155, 299, 53, 64, STR_NONE, STR_NONE }, // language
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 54, 63, 876, STR_NONE },
{ WWT_DROPDOWN, 0, 155, 299, 68, 79, 871, STR_NONE }, // currency
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 69, 78, 876, STR_NONE }, //
{ WWT_DROPDOWN, 0, 155, 299, 83, 94, 872, STR_NONE }, // distance
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 84, 93, 876, STR_NONE },
{ WWT_DROPDOWN, 0, 155, 299, 98, 110, 875, STR_NONE }, // temperature
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 99, 108, 876, STR_NONE }, //jjj
{ WWT_DROPDOWN, 0, 155, 299, 113, 124, 868, STR_NONE }, // height labels
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 114, 123, 876, STR_NONE },
// Audio tab
{ WWT_DROPDOWN, 0, 10, 299, 53, 64, 865, STR_NONE }, // sound
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 54, 63, 876, STR_NONE },
{ WWT_DROPDOWN, 0, 155, 299, 68, 79, 869, STR_NONE }, // music
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 69, 78, 876, STR_NONE },
{ WWT_DROPDOWN, 0, 155, 299, 83, 94, 870, STR_NONE }, // sound quality
{ WWT_DROPDOWN_BUTTON, 0, 288, 298, 84, 93, 876, STR_NONE },
{ WWT_CHECKBOX, 0, 10, 299, 99, 110, STR_SOUND_FORCED_SOFTWARE_BUFFER_MIXING, STR_SOUND_FORCED_SOFTWARE_BUFFER_MIXING_TIP },
{ WWT_CHECKBOX, 0, 10, 229, 114, 125, STR_SOUND, STR_NONE }, // enable/disable sound
// Controls tab
{ WWT_CHECKBOX, 2, 10, 299, 53, 64, STR_SCREEN_EDGE_SCROLLING, STR_SCREEN_EDGE_SCROLLING_TIP },
{ WWT_DROPDOWN_BUTTON, 0, 26, 185, 68, 78, STR_HOTKEY, STR_HOTKEY_TIP },
// Misc
{ WWT_CHECKBOX, 2, 10, 299, 53, 64, STR_REAL_NAME, STR_REAL_NAME_TIP },
{ WWT_CHECKBOX, 2, 10, 299, 68, 79, STR_SAVE_PLUGIN_DATA, STR_SAVE_PLUGIN_DATA_TIP },
{ WIDGETS_END },
};
const int window_options_tab_animation_divisor[] = { 4, 8, 2, 2, 2 };
const int window_options_tab_animation_frames[] = { 16, 8, 16, 4, 16 };
static void window_options_set_page(rct_window *w, int page);
static void window_options_set_pressed_tab(rct_window *w);
static void window_options_draw_tab_image(rct_drawpixelinfo *dpi, rct_window *w, int page, int spriteIndex);
static void window_options_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w);
static void window_options_emptysub() { }
static void window_options_mouseup();
static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* widget);
static void window_options_dropdown();
static void window_options_update(rct_window *w);
static void window_options_invalidate();
static void window_options_paint();
static void window_options_draw_dropdown_box(rct_window *w, rct_widget *widget, int num_items);
static void window_options_show_dropdown(rct_window *w, rct_widget *widget, int num_items);
static void window_options_update_height_markers();
static void* window_options_events[] = {
@ -129,7 +178,7 @@ static void* window_options_events[] = {
window_options_mousedown,
window_options_dropdown,
window_options_emptysub,
window_options_emptysub,
window_options_update,
window_options_emptysub,
window_options_emptysub,
window_options_emptysub,
@ -169,36 +218,42 @@ void window_options_open()
w = window_create_auto_pos(WW, WH, (uint32*)window_options_events, WC_OPTIONS, 0);
w->widgets = window_options_widgets;
w->enabled_widgets =
(1 << WIDX_CLOSE) |
(1 << WIDX_SOUND) |
(1 << WIDX_SOUND_DROPDOWN) |
(1 << WIDX_MUSIC) |
(1 << WIDX_MUSIC_DROPDOWN) |
(1 << WIDX_SOUND_QUALITY) |
(1 << WIDX_SOUND_QUALITY_DROPDOWN) |
(1 << WIDX_CURRENCY) |
(1 << WIDX_CURRENCY_DROPDOWN) |
(1 << WIDX_DISTANCE) |
(1 << WIDX_DISTANCE_DROPDOWN) |
(1 << WIDX_RESOLUTION) |
(1 << WIDX_RESOLUTION_DROPDOWN) |
(1 << WIDX_FULLSCREEN) |
(1 << WIDX_FULLSCREEN_DROPDOWN) |
(1 << WIDX_TEMPERATURE) |
(1 << WIDX_TEMPERATURE_DROPDOWN) |
(1ULL << WIDX_CLOSE) |
(1ULL << WIDX_TAB_1) |
(1ULL << WIDX_TAB_2) |
(1ULL << WIDX_TAB_3) |
(1ULL << WIDX_TAB_4) |
(1ULL << WIDX_TAB_5) |
(1ULL << WIDX_SOUND) |
(1ULL << WIDX_SOUND_DROPDOWN) |
(1ULL << WIDX_MUSIC) |
(1ULL << WIDX_MUSIC_DROPDOWN) |
(1ULL << WIDX_SOUND_QUALITY) |
(1ULL << WIDX_SOUND_QUALITY_DROPDOWN) |
(1ULL << WIDX_CURRENCY) |
(1ULL << WIDX_CURRENCY_DROPDOWN) |
(1ULL << WIDX_DISTANCE) |
(1ULL << WIDX_DISTANCE_DROPDOWN) |
(1ULL << WIDX_RESOLUTION) |
(1ULL << WIDX_RESOLUTION_DROPDOWN) |
(1ULL << WIDX_FULLSCREEN) |
(1ULL << WIDX_FULLSCREEN_DROPDOWN) |
(1ULL << WIDX_TEMPERATURE) |
(1ULL << WIDX_TEMPERATURE_DROPDOWN) |
(1ULL << WIDX_HOTKEY_DROPDOWN) |
(1ULL << WIDX_SCREEN_EDGE_SCROLLING) |
(1ULL << WIDX_REAL_NAME_CHECKBOX) |
(1 << WIDX_CONSTRUCTION_MARKER) |
(1 << WIDX_CONSTRUCTION_MARKER_DROPDOWN) |
(1 << WIDX_HEIGHT_LABELS) |
(1 << WIDX_HEIGHT_LABELS_DROPDOWN) |
(1 << WIDX_TILE_SMOOTHING_CHECKBOX) |
(1 << WIDX_GRIDLINES_CHECKBOX) |
(1 << WIDX_SOUND_SW_BUFFER_CHECKBOX) |
(1 << WIDX_SOUND_PAUSED_CHECKBOX) |
(1ULL << WIDX_CONSTRUCTION_MARKER) |
(1ULL << WIDX_CONSTRUCTION_MARKER_DROPDOWN) |
(1ULL << WIDX_HEIGHT_LABELS) |
(1ULL << WIDX_HEIGHT_LABELS_DROPDOWN) |
(1ULL << WIDX_TILE_SMOOTHING_CHECKBOX) |
(1ULL << WIDX_GRIDLINES_CHECKBOX) |
(1ULL << WIDX_SOUND_SW_BUFFER_CHECKBOX) |
(1ULL << WIDX_SOUND_PAUSED_CHECKBOX) |
(1ULL << WIDX_SAVE_PLUGIN_DATA_CHECKBOX); // doesn't seem to work?
w->page = WINDOW_OPTIONS_PAGE_DISPLAY;
window_init_scroll_widgets(w);
w->colours[0] = 7;
w->colours[1] = 7;
@ -214,23 +269,19 @@ static void window_options_mouseup()
short widgetIndex;
rct_window *w;
#ifdef _MSC_VER
__asm mov widgetIndex, dx
#else
__asm__ ( "mov %[widgetIndex], dx " : [widgetIndex] "+m" (widgetIndex) );
#endif
#ifdef _MSC_VER
__asm mov w, esi
#else
__asm__ ( "mov %[w], esi " : [w] "+m" (w) );
#endif
window_mouse_up_get_registers(w, widgetIndex);
switch (widgetIndex) {
case WIDX_CLOSE:
window_close(w);
break;
case WIDX_TAB_1:
case WIDX_TAB_2:
case WIDX_TAB_3:
case WIDX_TAB_4:
case WIDX_TAB_5:
window_options_set_page(w, widgetIndex - WIDX_TAB_1);
break;
case WIDX_HOTKEY_DROPDOWN:
RCT2_CALLPROC_EBPSAFE(0x006E3884);
break;
@ -326,7 +377,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
gDropdownItemsArgs[i] = 1170 | ((uint64)(intptr_t)gAudioDevices[i].name << 16);
}
window_options_draw_dropdown_box(w, widget, gAudioDeviceCount);
window_options_show_dropdown(w, widget, gAudioDeviceCount);
gDropdownItemsChecked |= (1 << RCT2_GLOBAL(0x9AF280, uint32));
break;
@ -336,7 +387,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
gDropdownItemsArgs[0] = STR_UNITS;
gDropdownItemsArgs[1] = STR_REAL_VALUES;
window_options_draw_dropdown_box(w, widget, 2);
window_options_show_dropdown(w, widget, 2);
gDropdownItemsChecked =
(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) &
@ -348,7 +399,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
gDropdownItemsArgs[0] = STR_OFF;
gDropdownItemsArgs[1] = STR_ON;
window_options_draw_dropdown_box(w, widget, 2);
window_options_show_dropdown(w, widget, 2);
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8);
break;
@ -360,7 +411,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
gDropdownItemsArgs[i] = STR_SOUND_LOW + i; // low, medium, high
}
window_options_draw_dropdown_box(w, widget, num_items);
window_options_show_dropdown(w, widget, num_items);
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, uint8);
break;
@ -372,7 +423,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
gDropdownItemsArgs[i] = STR_POUNDS + i; // all different currencies
}
window_options_draw_dropdown_box(w, widget, num_items);
window_options_show_dropdown(w, widget, num_items);
gDropdownItemsChecked = 1 << (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CURRENCY, uint8) & 0x3F);
break;
@ -382,7 +433,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
gDropdownItemsArgs[0] = STR_IMPERIAL;
gDropdownItemsArgs[1] = STR_METRIC;
window_options_draw_dropdown_box(w, widget, 2);
window_options_show_dropdown(w, widget, 2);
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, uint8);
break;
@ -393,11 +444,11 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
gDropdownItemsFormat[0] = 1142;
gDropdownItemsFormat[1] = 1142;
gDropdownItemsFormat[2] = 1142;
gDropdownItemsArgs[0] = STR_CELSIUS;
gDropdownItemsArgs[1] = STR_FAHRENHEIT;
gDropdownItemsArgs[2] = STR_METRIC;
gDropdownItemsArgs[0] = 2773;
gDropdownItemsArgs[1] = 2774;
gDropdownItemsArgs[2] = 2775;
window_options_draw_dropdown_box(w, widget, 3);
window_options_show_dropdown(w, widget, 3);
gDropdownItemsChecked = 1 << gGeneral_config.fullscreen_mode;
break;
@ -407,7 +458,7 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
gDropdownItemsArgs[0] = STR_CELSIUS;
gDropdownItemsArgs[1] = STR_FAHRENHEIT;
window_options_draw_dropdown_box(w, widget, 2);
window_options_show_dropdown(w, widget, 2);
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_TEMPERATURE, uint8);
break;
@ -417,10 +468,18 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget*
gDropdownItemsArgs[0] = STR_WHITE;
gDropdownItemsArgs[1] = STR_TRANSLUCENT;
window_options_draw_dropdown_box(w, widget, 2);
window_options_show_dropdown(w, widget, 2);
gDropdownItemsChecked = 1 << RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CONSTRUCTION_MARKER, uint8);
break;
case WIDX_LANGUAGE_DROPDOWN:
for (i = 1; i < LANGUAGE_COUNT; i++) {
gDropdownItemsFormat[i - 1] = 2777;
gDropdownItemsArgs[i - 1] = (sint64)language_names[i];
}
window_options_show_dropdown(w, widget, LANGUAGE_COUNT - 1);
gDropdownItemsChecked = 1 << (gCurrentLanguage - 1);
break;
}
}
@ -434,24 +493,7 @@ static void window_options_dropdown()
short widgetIndex;
rct_window *w;
#ifdef _MSC_VER
__asm mov dropdownIndex, ax
#else
__asm__ ( "mov %[dropdownIndex], ax " : [dropdownIndex] "+m" (dropdownIndex) );
#endif
#ifdef _MSC_VER
__asm mov widgetIndex, dx
#else
__asm__ ( "mov %[widgetIndex], dx " : [widgetIndex] "+m" (widgetIndex) );
#endif
#ifdef _MSC_VER
__asm mov w, esi
#else
__asm__ ( "mov %[w], esi " : [w] "+m" (w) );
#endif
window_dropdown_get_registers(w, widgetIndex, dropdownIndex);
if (dropdownIndex == -1)
return;
@ -521,8 +563,7 @@ static void window_options_dropdown()
if (dropdownIndex == 2){
w->disabled_widgets |= (1 << WIDX_RESOLUTION_DROPDOWN);
w->disabled_widgets |= (1 << WIDX_RESOLUTION);
}
else {
} else {
w->disabled_widgets &= ~(1 << WIDX_RESOLUTION_DROPDOWN);
w->disabled_widgets &= ~(1 << WIDX_RESOLUTION);
}
@ -544,6 +585,14 @@ static void window_options_dropdown()
gfx_invalidate_screen();
}
break;
case WIDX_LANGUAGE_DROPDOWN:
if (dropdownIndex != gCurrentLanguage - 1) {
language_open(dropdownIndex + 1);
gGeneral_config.language = dropdownIndex + 1;
config_save();
gfx_invalidate_screen();
}
break;
}
}
@ -554,107 +603,154 @@ static void window_options_dropdown()
static void window_options_invalidate()
{
rct_window *w;
#ifdef _MSC_VER
__asm mov w, esi
#else
__asm__ ( "mov %[w], esi " : [w] "+m" (w) );
#endif
int i;
sint32 currentSoundDevice;
sint32 currentSoundDevice = RCT2_GLOBAL(0x009AF280, sint32);
window_get_register(w);
// sound devices
if (currentSoundDevice == -1 || gAudioDeviceCount == 0) {
RCT2_GLOBAL(0x013CE952, uint16) = STR_SOUND_NONE;
} else {
RCT2_GLOBAL(0x013CE952, uint16) = 1170;
RCT2_GLOBAL(0x013CE952 + 2, uint32) = (uint32)gAudioDevices[currentSoundDevice].name;
window_options_set_pressed_tab(w);
for (i = WIDX_RESOLUTION; i <= WIDX_SAVE_PLUGIN_DATA_CHECKBOX; i++) {
window_options_widgets[i].type = WWT_EMPTY;
}
// height: units/real values
RCT2_GLOBAL(0x013CE952 + 6, uint16) = ((RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS)) ?
STR_UNITS : STR_REAL_VALUES;
// music: on/off
RCT2_GLOBAL(0x013CE952 + 8, uint16) = STR_OFF +
RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8);
// sound quality: low/medium/high
RCT2_GLOBAL(0x013CE952 + 10, uint16) = STR_SOUND_LOW +
RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, uint8);
// currency: pounds, dollars, etc. (10 total)
RCT2_GLOBAL(0x013CE952 + 12, uint16) = STR_POUNDS +
(RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CURRENCY, uint8) & 0x3F);
switch (w->page) {
case WINDOW_OPTIONS_PAGE_DISPLAY:
// resolution
RCT2_GLOBAL(0x013CE952 + 16, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_RESOLUTION_WIDTH, uint16);
RCT2_GLOBAL(0x013CE952 + 18, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_RESOLUTION_HEIGHT, uint16);
RCT2_GLOBAL(0x013CE952 + 12, uint16) = 2773 + gGeneral_config.fullscreen_mode;
// distance: metric/imperial
RCT2_GLOBAL(0x013CE952 + 14, uint16) = STR_IMPERIAL +
RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, uint8);
// landscape tile smoothing checkbox
if ((RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_DISABLE_SMOOTH_LANDSCAPE))
w->pressed_widgets &= ~(1ULL << WIDX_TILE_SMOOTHING_CHECKBOX);
else
w->pressed_widgets |= (1ULL << WIDX_TILE_SMOOTHING_CHECKBOX);
// resolution
RCT2_GLOBAL(0x013CE952 + 16, uint16) =
RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_RESOLUTION_WIDTH, uint16);
RCT2_GLOBAL(0x013CE952 + 18, uint16) =
RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_RESOLUTION_HEIGHT, uint16);
// show gridlines checkbox
if ((RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES))
w->pressed_widgets |= (1ULL << WIDX_GRIDLINES_CHECKBOX);
else
w->pressed_widgets &= ~(1ULL << WIDX_GRIDLINES_CHECKBOX);
// temperature: celsius/fahrenheit
RCT2_GLOBAL(0x013CE952 + 20, uint16) = STR_CELSIUS +
RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_TEMPERATURE, uint8);
// construction marker: celsius/fahrenheit
window_options_widgets[WIDX_CONSTRUCTION_MARKER].image = STR_WHITE + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CONSTRUCTION_MARKER, uint8);
// construction marker: celsius/fahrenheit
window_options_widgets[WIDX_CONSTRUCTION_MARKER].image = STR_WHITE +
RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CONSTRUCTION_MARKER, uint8);
//Sound pause checkbox
if (!g_sounds_disabled)
w->pressed_widgets |= (1 << WIDX_SOUND_PAUSED_CHECKBOX);
else
w->pressed_widgets &= ~(1 << WIDX_SOUND_PAUSED_CHECKBOX);
window_options_widgets[WIDX_RESOLUTION].type = WWT_DROPDOWN;
window_options_widgets[WIDX_RESOLUTION_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
window_options_widgets[WIDX_FULLSCREEN].type = WWT_DROPDOWN;
window_options_widgets[WIDX_FULLSCREEN_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
window_options_widgets[WIDX_TILE_SMOOTHING_CHECKBOX].type = WWT_CHECKBOX;
window_options_widgets[WIDX_GRIDLINES_CHECKBOX].type = WWT_CHECKBOX;
window_options_widgets[WIDX_CONSTRUCTION_MARKER].type = WWT_DROPDOWN;
window_options_widgets[WIDX_CONSTRUCTION_MARKER_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
break;
case WINDOW_OPTIONS_PAGE_CULTURE:
// currency: pounds, dollars, etc. (10 total)
RCT2_GLOBAL(0x013CE952 + 12, uint16) = STR_POUNDS + (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_CURRENCY, uint8) & 0x3F);
// distance: metric/imperial
RCT2_GLOBAL(0x013CE952 + 14, uint16) = STR_IMPERIAL + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_METRIC, uint8);
// temperature: celsius/fahrenheit
RCT2_GLOBAL(0x013CE952 + 20, uint16) = STR_CELSIUS + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_TEMPERATURE, uint8);
// height: units/real values
RCT2_GLOBAL(0x013CE952 + 6, uint16) =
((RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_SHOW_HEIGHT_AS_UNITS)) ? STR_UNITS : STR_REAL_VALUES;
window_options_widgets[WIDX_LANGUAGE].type = WWT_DROPDOWN;
window_options_widgets[WIDX_LANGUAGE_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
window_options_widgets[WIDX_CURRENCY].type = WWT_DROPDOWN;
window_options_widgets[WIDX_CURRENCY_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
window_options_widgets[WIDX_DISTANCE].type = WWT_DROPDOWN;
window_options_widgets[WIDX_DISTANCE_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
window_options_widgets[WIDX_TEMPERATURE].type = WWT_DROPDOWN;
window_options_widgets[WIDX_TEMPERATURE_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
window_options_widgets[WIDX_HEIGHT_LABELS].type = WWT_DROPDOWN;
window_options_widgets[WIDX_HEIGHT_LABELS_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
break;
case WINDOW_OPTIONS_PAGE_AUDIO:
currentSoundDevice = RCT2_GLOBAL(0x009AF280, sint32);
// sound devices
if (currentSoundDevice == -1 || gAudioDeviceCount == 0) {
RCT2_GLOBAL(0x013CE952, uint16) = STR_SOUND_NONE;
} else {
RCT2_GLOBAL(0x013CE952, uint16) = 1170;
RCT2_GLOBAL(0x013CE952 + 2, uint32) = (uint32)gAudioDevices[currentSoundDevice].name;
}
// music: on/off
RCT2_GLOBAL(0x013CE952 + 8, uint16) = STR_OFF + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_MUSIC, uint8);
// sound quality: low/medium/high
RCT2_GLOBAL(0x013CE952 + 10, uint16) = STR_SOUND_LOW + RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_QUALITY, uint8);
//Sound pause checkbox
if (!g_sounds_disabled)
w->pressed_widgets |= (1ULL << WIDX_SOUND_PAUSED_CHECKBOX);
else
w->pressed_widgets &= ~(1ULL << WIDX_SOUND_PAUSED_CHECKBOX);
// sound software mixing buffer checkbox
if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, uint8))
w->pressed_widgets |= (1 << WIDX_SOUND_SW_BUFFER_CHECKBOX);
else
w->pressed_widgets &= ~(1 << WIDX_SOUND_SW_BUFFER_CHECKBOX);
// sound software mixing buffer checkbox
if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_SOUND_SW_BUFFER, uint8))
w->pressed_widgets |= (1ULL << WIDX_SOUND_SW_BUFFER_CHECKBOX);
else
w->pressed_widgets &= ~(1ULL << WIDX_SOUND_SW_BUFFER_CHECKBOX);
// screen edge scrolling checkbox
if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_EDGE_SCROLLING, uint8))
w->pressed_widgets |= (1ULL << WIDX_SCREEN_EDGE_SCROLLING);
else
w->pressed_widgets &= ~(1ULL << WIDX_SCREEN_EDGE_SCROLLING);
window_options_widgets[WIDX_SOUND].type = WWT_DROPDOWN;
window_options_widgets[WIDX_SOUND_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
window_options_widgets[WIDX_MUSIC].type = WWT_DROPDOWN;
window_options_widgets[WIDX_MUSIC_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
window_options_widgets[WIDX_SOUND_QUALITY].type = WWT_DROPDOWN;
window_options_widgets[WIDX_SOUND_QUALITY_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
window_options_widgets[WIDX_SOUND_SW_BUFFER_CHECKBOX].type = WWT_CHECKBOX;
window_options_widgets[WIDX_SOUND_PAUSED_CHECKBOX].type = WWT_CHECKBOX;
break;
case WINDOW_OPTIONS_PAGE_INPUT:
// screen edge scrolling checkbox
if (RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_EDGE_SCROLLING, uint8))
w->pressed_widgets |= (1ULL << WIDX_SCREEN_EDGE_SCROLLING);
else
w->pressed_widgets &= ~(1ULL << WIDX_SCREEN_EDGE_SCROLLING);
// real name checkbox
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_SHOW_REAL_GUEST_NAMES)
w->pressed_widgets |= (1ULL << WIDX_REAL_NAME_CHECKBOX);
else
w->pressed_widgets &= ~(1ULL << WIDX_REAL_NAME_CHECKBOX);
// landscape tile smoothing checkbox
if ((RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_DISABLE_SMOOTH_LANDSCAPE))
w->pressed_widgets &= ~(1 << WIDX_TILE_SMOOTHING_CHECKBOX);
else
w->pressed_widgets |= (1 << WIDX_TILE_SMOOTHING_CHECKBOX);
window_options_widgets[WIDX_SCREEN_EDGE_SCROLLING].type = WWT_CHECKBOX;
window_options_widgets[WIDX_HOTKEY_DROPDOWN].type = WWT_DROPDOWN_BUTTON;
break;
case WINDOW_OPTIONS_PAGE_MISC:
// real name checkbox
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_SHOW_REAL_GUEST_NAMES)
w->pressed_widgets |= (1ULL << WIDX_REAL_NAME_CHECKBOX);
else
w->pressed_widgets &= ~(1ULL << WIDX_REAL_NAME_CHECKBOX);
// show gridlines checkbox
if ((RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_ALWAYS_SHOW_GRIDLINES))
w->pressed_widgets |= (1 << WIDX_GRIDLINES_CHECKBOX);
else
w->pressed_widgets &= ~(1 << WIDX_GRIDLINES_CHECKBOX);
// save plugin data checkbox
if ((RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_SAVE_PLUGIN_DATA))
w->pressed_widgets |= (1ULL << WIDX_SAVE_PLUGIN_DATA_CHECKBOX);
else
w->pressed_widgets &= ~(1ULL << WIDX_SAVE_PLUGIN_DATA_CHECKBOX);
// save plugin data checkbox
if ((RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_FLAGS, uint8) & CONFIG_FLAG_SAVE_PLUGIN_DATA))
w->pressed_widgets |= (1ULL << WIDX_SAVE_PLUGIN_DATA_CHECKBOX);
else
w->pressed_widgets &= ~(1ULL << WIDX_SAVE_PLUGIN_DATA_CHECKBOX);
// unknown park flag can disable real name checkbox
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & 0x8000)
w->disabled_widgets |= (1ULL << WIDX_REAL_NAME_CHECKBOX);
// unknown park flag can disable real name checkbox
if (RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & 0x8000)
w->disabled_widgets |= (1ULL << WIDX_REAL_NAME_CHECKBOX);
// save plugin data checkbox: visible or not
if (RCT2_GLOBAL(0x00F42BDA, uint8) == 1)
window_options_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_EMPTY;
else
window_options_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_CHECKBOX;
// save plugin data checkbox: visible or not
if (RCT2_GLOBAL(0x00F42BDA, uint8) == 1)
window_options_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_EMPTY;
else
window_options_widgets[WIDX_REAL_NAME_CHECKBOX].type = WWT_CHECKBOX;
window_options_widgets[WIDX_SAVE_PLUGIN_DATA_CHECKBOX].type = WWT_CHECKBOX;
break;
}
}
static void window_options_update(rct_window *w)
{
// Tab animation
w->frame_no++;
widget_invalidate(w->classification, w->number, WIDX_TAB_1 + w->page);
}
/**
@ -665,53 +761,46 @@ static void window_options_paint()
{
rct_window *w;
rct_drawpixelinfo *dpi;
char buffer[256];
#ifdef _MSC_VER
__asm mov w, esi
#else
__asm__ ( "mov %[w], esi " : [w] "+m" (w) );
#endif
#ifdef _MSC_VER
__asm mov dpi, edi
#else
__asm__ ( "mov %[dpi], edi " : [dpi] "+m" (dpi) );
#endif
window_paint_get_registers(w, dpi);
window_draw_widgets(w, dpi);
window_options_draw_tab_images(dpi, w);
// units
gfx_draw_string_left(dpi, STR_CURRENCY, w, 0, w->x + 10,
w->y + window_options_widgets[WIDX_CURRENCY].top + 1);
gfx_draw_string_left(dpi, STR_DISTANCE_AND_SPEED, w, 0, w->x + 10,
w->y + window_options_widgets[WIDX_DISTANCE].top + 1);
gfx_draw_string_left(dpi, STR_TEMPERATURE, w, 0, w->x + 10,
w->y + window_options_widgets[WIDX_TEMPERATURE].top + 1);
gfx_draw_string_left(dpi, STR_HEIGHT_LABELS, w, 0, w->x + 10,
w->y + window_options_widgets[WIDX_HEIGHT_LABELS].top + 1);
switch (w->page) {
case WINDOW_OPTIONS_PAGE_DISPLAY:
gfx_draw_string_left(dpi, STR_DISPLAY_RESOLUTION, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_RESOLUTION].top + 1);
// display
gfx_draw_string_left(dpi, STR_DISPLAY_RESOLUTION, w, 0, w->x + 10,
w->y + window_options_widgets[WIDX_RESOLUTION].top + 1);
sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_WINDOW_COLOUR_2, "Fullscreen mode:");
gfx_draw_string(dpi, buffer, 0, w->x + 10, w->y + window_options_widgets[WIDX_FULLSCREEN].top + 1);
char buffer[256];
sprintf(buffer, "%c%c%s", FORMAT_MEDIUMFONT, FORMAT_WINDOW_COLOUR_2, "Fullscreen mode:");
gfx_draw_string(dpi, buffer, 0, w->x + 10,
w->y + window_options_widgets[WIDX_FULLSCREEN].top + 1);
gfx_draw_string_left(dpi, STR_CONSTRUCTION_MARKER, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_CONSTRUCTION_MARKER].top + 1);
break;
case WINDOW_OPTIONS_PAGE_CULTURE:
gfx_draw_string_left(dpi, 2776, w, 12, w->x + 10, w->y + window_options_widgets[WIDX_LANGUAGE].top + 1);
gfx_draw_string(
dpi,
(char*)language_names[gCurrentLanguage],
12,
w->x + window_options_widgets[WIDX_LANGUAGE].left + 1,
w->y + window_options_widgets[WIDX_LANGUAGE].top
);
gfx_draw_string_left(dpi, STR_CONSTRUCTION_MARKER, w, 0, w->x + 10,
w->y + window_options_widgets[WIDX_CONSTRUCTION_MARKER].top + 1);
// sound
gfx_draw_string_left(dpi, STR_MUSIC, w, 0, w->x + 10,
w->y + window_options_widgets[WIDX_MUSIC].top + 1);
gfx_draw_string_left(dpi, STR_SOUND_QUALITY, w, 0, w->x + 10,
w->y + window_options_widgets[WIDX_SOUND_QUALITY].top + 1);
gfx_draw_string_left(dpi, STR_CURRENCY, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_CURRENCY].top + 1);
gfx_draw_string_left(dpi, STR_DISTANCE_AND_SPEED, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_DISTANCE].top + 1);
gfx_draw_string_left(dpi, STR_TEMPERATURE, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_TEMPERATURE].top + 1);
gfx_draw_string_left(dpi, STR_HEIGHT_LABELS, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_HEIGHT_LABELS].top + 1);
break;
case WINDOW_OPTIONS_PAGE_AUDIO:
gfx_draw_string_left(dpi, STR_MUSIC, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_MUSIC].top + 1);
gfx_draw_string_left(dpi, STR_SOUND_QUALITY, w, 0, w->x + 10, w->y + window_options_widgets[WIDX_SOUND_QUALITY].top + 1);
break;
}
}
// helper function, all dropdown boxes have similar properties
static void window_options_draw_dropdown_box(rct_window *w, rct_widget *widget, int num_items)
static void window_options_show_dropdown(rct_window *w, rct_widget *widget, int num_items)
{
window_dropdown_show_text_custom_width(
w->x + widget->left,
@ -721,7 +810,7 @@ static void window_options_draw_dropdown_box(rct_window *w, rct_widget *widget,
0x80,
num_items,
widget->right - widget->left - 3
);
);
}
static void window_options_update_height_markers()
@ -736,3 +825,52 @@ static void window_options_update_height_markers()
config_save();
gfx_invalidate_screen();
}
#pragma region Common
static void window_options_set_page(rct_window *w, int page)
{
w->page = page;
w->frame_no = 0;
window_invalidate(w);
RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0);
RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0);
window_init_scroll_widgets(w);
window_invalidate(w);
}
static void window_options_set_pressed_tab(rct_window *w)
{
int i;
for (i = 0; i < WINDOW_OPTIONS_PAGE_COUNT; i++)
w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i));
w->pressed_widgets |= 1LL << (WIDX_TAB_1 + w->page);
}
static void window_options_draw_tab_image(rct_drawpixelinfo *dpi, rct_window *w, int page, int spriteIndex)
{
int widgetIndex = WIDX_TAB_1 + page;
if (!(w->disabled_widgets & (1LL << widgetIndex))) {
if (w->page == page) {
int frame = w->frame_no / window_options_tab_animation_divisor[w->page];
spriteIndex += (frame % window_options_tab_animation_frames[w->page]);
}
gfx_draw_sprite(dpi, spriteIndex, w->x + w->widgets[widgetIndex].left, w->y + w->widgets[widgetIndex].top, 0);
}
}
static void window_options_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w)
{
window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_DISPLAY, 5442);
window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_CULTURE, 5229);
window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_AUDIO, 5335);
window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_INPUT, 5201);
window_options_draw_tab_image(dpi, w, WINDOW_OPTIONS_PAGE_MISC, 5205);
}
#pragma endregion

View File

@ -129,7 +129,8 @@ uint32 window_peep_page_enabled_widgets[] = {
void window_peep_open(rct_peep* peep){
if (peep->type == PEEP_TYPE_STAFF){
RCT2_CALLPROC_X(0x006989E9, 0, 0, 0, (int)peep, 0, 0, 0);
window_staff_peep_open(peep);
return;
}
rct_window* window;
@ -151,7 +152,7 @@ void window_peep_open(rct_peep* peep){
window->min_height = 157;
window->max_width = 500;
window->max_height = 450;
window->flags = 8;
window->flags = 1 << 8;
window->no_list_items = 0;
window->selected_list_item = -1;
window->colours[0] = 1;
@ -161,7 +162,7 @@ void window_peep_open(rct_peep* peep){
}
window->page = 0;
RCT2_CALLPROC_X(0x006EB13A, 0, 0, 0, 0, (int)window, 0, 0);
window_invalidate(window);
window->widgets = RCT2_GLOBAL(0x981D0C, rct_widget*);
window->enabled_widgets = RCT2_GLOBAL(0x981D3C,uint32);
@ -173,35 +174,3 @@ void window_peep_open(rct_peep* peep){
window_init_scroll_widgets(window);
RCT2_CALLPROC_X(0x0069883C, 0, 0, 0, 0, (int)window, 0, 0);
}
/**
*
* rct2: 0x006BEE98
*/
void window_staff_peep_open(rct_peep* peep)
{
rct_window* w = window_bring_to_front_by_id(WC_PEEP, peep->sprite_index);
if (!w) {
int eax, ebx, ecx, edx, esi, edi;
eax = peep->sprite_index;
ecx = WC_PEEP;
edx = peep->sprite_index;
RCT2_CALLFUNC_X(0x006BEF1B, &eax, &ebx, &ecx, &edx, &esi, &edi, (int*)peep);
w = (rct_window*)esi;
}
int PEEP_BACKGROUND_IDX = 0;
w->widgets = RCT2_GLOBAL(0x992998, rct_widget*);
w->enabled_widgets = RCT2_GLOBAL(0x9929B0, uint32);
w->var_020 = RCT2_GLOBAL(0x9929BC, uint32);
w->event_handlers = (uint32*)RCT2_GLOBAL(0x9929A4, uint32);
w->pressed_widgets = 0;
RCT2_CALLPROC_X(0x006BED21, 0, 0, 0, 0, (int)w, 0, 0);
window_init_scroll_widgets(w);
RCT2_CALLPROC_X(0x006BEDA3, 0, 0, 0, 0, (int)w, 0, 0);
if (g_sprite_list[w->number].peep.state == PEEP_STATE_PICKED) {
RCT2_CALLPROC_X(w->event_handlers[1], 0, 0, 0, 10, (int)w, 0, 0);
}
}

641
src/window_research.c Normal file
View File

@ -0,0 +1,641 @@
/*****************************************************************************
* 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 "addresses.h"
#include "finance.h"
#include "game.h"
#include "news_item.h"
#include "string_ids.h"
#include "sprites.h"
#include "widget.h"
#include "window.h"
#include "window_dropdown.h"
enum {
WINDOW_RESEARCH_PAGE_DEVELOPMENT,
WINDOW_RESEARCH_PAGE_FUNDING,
WINDOW_RESEARCH_PAGE_COUNT
};
enum {
WIDX_BACKGROUND,
WIDX_TITLE,
WIDX_CLOSE,
WIDX_PAGE_BACKGROUND,
WIDX_TAB_1,
WIDX_TAB_2,
WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP,
WIDX_LAST_DEVELOPMENT_GROUP,
WIDX_LAST_DEVELOPMENT_BUTTON,
WIDX_FUNDING_GROUP = 6,
WIDX_RESEARCH_FUNDING,
WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON,
WIDX_PRIORITIES_GROUP,
WIDX_TRANSPORT_RIDES,
WIDX_GENTLE_RIDES,
WIDX_ROLLER_COASTERS,
WIDX_THRILL_RIDES,
WIDX_WATER_RIDES,
WIDX_SHOPS_AND_STALLS,
WIDX_SCENERY_AND_THEMING,
};
#pragma region Widgets
static rct_widget window_research_development_widgets[] = {
{ WWT_FRAME, 0, 0, 299, 0, 195, 0xFFFFFFFF, STR_NONE },
{ WWT_CAPTION, 0, 1, 298, 1, 14, STR_RESEARCH_AND_DEVELOPMENT, STR_WINDOW_TITLE_TIP },
{ WWT_CLOSEBOX, 0, 287, 297, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP },
{ WWT_RESIZE, 1, 0, 299, 43, 195, 0xFFFFFFFF, STR_NONE },
{ WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_RESEARCH_AND_DEVELOPMENT_TIP },
{ WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH },
{ WWT_GROUPBOX, 2, 3, 292, 47, 116, 2267, STR_NONE },
{ WWT_GROUPBOX, 2, 3, 292, 124, 188, 2268, STR_NONE },
{ WWT_FLATBTN, 2, 265, 288, 161, 184, 0xFFFFFFFF, STR_RESEARCH_SHOW_DETAILS_TIP },
{ WIDGETS_END },
};
static rct_widget window_research_funding_widgets[] = {
{ WWT_FRAME, 0, 0, 319, 0, 206, 0xFFFFFFFF, STR_NONE },
{ WWT_CAPTION, 0, 1, 318, 1, 14, STR_RESEARCH_FUNDING, STR_WINDOW_TITLE_TIP },
{ WWT_CLOSEBOX, 0, 307, 317, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP },
{ WWT_RESIZE, 1, 0, 319, 43, 206, 0xFFFFFFFF, STR_NONE },
{ WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, STR_RESEARCH_AND_DEVELOPMENT_TIP },
{ WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, STR_FINANCES_RESEARCH },
{ WWT_GROUPBOX, 2, 3, 316, 47, 91, STR_RESEARCH_FUNDING_, STR_NONE },
{ WWT_DROPDOWN, 2, 8, 167, 59, 70, 0xFFFFFFFF, STR_SELECT_LEVEL_OF_RESEARCH_AND_DEVELOPMENT },
{ WWT_DROPDOWN_BUTTON, 2, 156, 166, 60, 69, 876, STR_SELECT_LEVEL_OF_RESEARCH_AND_DEVELOPMENT },
{ WWT_GROUPBOX, 2, 3, 316, 96, 202, STR_RESEARCH_PRIORITIES, STR_NONE },
{ WWT_CHECKBOX, 2, 8, 311, 108, 119, STR_RESEARCH_TRANSPORT_RIDES, STR_RESEARCH_NEW_TRANSPORT_RIDES },
{ WWT_CHECKBOX, 2, 8, 311, 121, 132, STR_RESEARCH_GENTLE_RIDES, STR_RESEARCH_NEW_GENTLE_RIDES },
{ WWT_CHECKBOX, 2, 8, 311, 134, 145, STR_RESEARCH_ROLLER_COASTERS, STR_RESEARCH_NEW_ROLLER_COASTERS },
{ WWT_CHECKBOX, 2, 8, 311, 147, 158, STR_RESEARCH_THRILL_RIDES, STR_RESEARCH_NEW_THRILL_RIDES },
{ WWT_CHECKBOX, 2, 8, 311, 160, 171, STR_RESEARCH_WATER_RIDES, STR_RESEARCH_NEW_WATER_RIDES },
{ WWT_CHECKBOX, 2, 8, 311, 173, 184, STR_RESEARCH_SHOPS_AND_STALLS, STR_RESEARCH_NEW_SHOPS_AND_STALLS },
{ WWT_CHECKBOX, 2, 8, 311, 186, 197, STR_RESEARCH_SCENERY_AND_THEMING, STR_RESEARCH_NEW_SCENERY_AND_THEMING },
{ WIDGETS_END },
};
static rct_widget *window_research_page_widgets[] = {
window_research_development_widgets,
window_research_funding_widgets
};
#pragma endregion
#pragma region Events
static void window_research_emptysub() { }
static void window_research_development_mouseup();
static void window_research_development_update(rct_window *w);
static void window_research_development_invalidate();
static void window_research_development_paint();
static void window_research_funding_mouseup();
static void window_research_funding_mousedown(int widgetIndex, rct_window*w, rct_widget* widget);
static void window_research_funding_dropdown();
static void window_research_funding_update(rct_window *w);
static void window_research_funding_invalidate();
static void window_research_funding_paint();
//
static void* window_research_development_events[] = {
window_research_emptysub,
window_research_development_mouseup,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_development_update,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_development_invalidate,
window_research_development_paint,
window_research_emptysub
};
// 0x009890E8
static void* window_research_funding_events[] = {
window_research_emptysub,
window_research_funding_mouseup,
window_research_emptysub,
window_research_funding_mousedown,
window_research_funding_dropdown,
window_research_emptysub,
window_research_funding_update,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_emptysub,
window_research_funding_invalidate,
window_research_funding_paint,
window_research_emptysub
};
static void* window_research_page_events[] = {
window_research_development_events,
window_research_funding_events
};
#pragma endregion
#pragma region Enabled widgets
static uint32 window_research_page_enabled_widgets[] = {
(1 << WIDX_CLOSE) |
(1 << WIDX_TAB_1) |
(1 << WIDX_TAB_2),
(1 << WIDX_CLOSE) |
(1 << WIDX_TAB_1) |
(1 << WIDX_TAB_2) |
(1 << WIDX_RESEARCH_FUNDING) |
(1 << WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON) |
(1 << WIDX_TRANSPORT_RIDES) |
(1 << WIDX_GENTLE_RIDES) |
(1 << WIDX_ROLLER_COASTERS) |
(1 << WIDX_THRILL_RIDES) |
(1 << WIDX_WATER_RIDES) |
(1 << WIDX_SHOPS_AND_STALLS) |
(1 << WIDX_SCENERY_AND_THEMING)
};
#pragma endregion
const int window_research_tab_animation_loops[] = { 16, 16 };
static void window_research_set_page(rct_window *w, int page);
static void window_research_set_pressed_tab(rct_window *w);
static void window_research_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w);
void window_research_open()
{
rct_window *w;
w = window_bring_to_front_by_id(WC_RESEARCH, 0);
if (w == NULL) {
w = window_create_auto_pos(530, 257, window_research_page_events[0], WC_RESEARCH, WF_10);
w->widgets = window_research_page_widgets[0];
w->enabled_widgets = window_research_page_enabled_widgets[0];
w->number = 0;
w->page = 0;
w->frame_no = 0;
w->disabled_widgets = 0;
w->colours[0] = 1;
w->colours[1] = 19;
w->colours[2] = 19;
RCT2_CALLPROC_EBPSAFE(0x00684BAE);
}
w->page = 0;
window_invalidate(w);
w->width = 300;
w->height = 196;
window_invalidate(w);
w->widgets = window_research_page_widgets[0];
w->enabled_widgets = window_research_page_enabled_widgets[0];
w->var_020 = RCT2_GLOBAL(0x00988E3C, uint32);
w->event_handlers = window_research_page_events[0];
w->pressed_widgets = 0;
w->disabled_widgets = 0;
window_init_scroll_widgets(w);
}
#pragma region Development page
/**
*
* rct2: 0x006B6B38
*/
static void window_research_development_mouseup()
{
short widgetIndex;
rct_window *w;
window_mouse_up_get_registers(w, widgetIndex);
switch (widgetIndex) {
case WIDX_CLOSE:
window_close(w);
break;
case WIDX_TAB_1:
case WIDX_TAB_2:
window_research_set_page(w, widgetIndex - WIDX_TAB_1);
break;
case WIDX_LAST_DEVELOPMENT_BUTTON:
news_item_open_subject(NEWS_ITEM_RESEARCH, RCT2_GLOBAL(RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT, sint32));
break;
}
}
/**
*
* rct2: 0x0069CBA6
*/
static void window_research_development_update(rct_window *w)
{
// Tab animation
if (++w->frame_no >= window_research_tab_animation_loops[w->page])
w->frame_no = 0;
widget_invalidate(w->classification, w->number, WIDX_TAB_1);
}
/**
*
* rct2: 0x006B6819
*/
static void window_research_development_invalidate()
{
rct_window *w;
window_get_register(w);
if (w->widgets != window_research_page_widgets[WINDOW_RESEARCH_PAGE_DEVELOPMENT]) {
w->widgets = window_research_page_widgets[WINDOW_RESEARCH_PAGE_DEVELOPMENT];
window_init_scroll_widgets(w);
}
window_research_set_pressed_tab(w);
window_research_development_widgets[WIDX_LAST_DEVELOPMENT_BUTTON].type = WWT_EMPTY;
uint32 typeId = RCT2_GLOBAL(0x01357CF4, uint32);
if (typeId != 0xFFFFFFFF) {
window_research_development_widgets[WIDX_LAST_DEVELOPMENT_BUTTON].type = WWT_FLATBTN;
window_research_development_widgets[WIDX_LAST_DEVELOPMENT_BUTTON].image = typeId >= 0x10000 ? 5189 : 5191;
}
}
/**
*
* rct2: 0x006B689B
*/
static void window_research_development_paint()
{
rct_window *w;
rct_drawpixelinfo *dpi;
int x, y;
rct_string_id stringId;
window_paint_get_registers(w, dpi);
window_draw_widgets(w, dpi);
window_research_draw_tab_images(dpi, w);
x = w->x + 10;
y = w->y + window_research_development_widgets[WIDX_CURRENTLY_IN_DEVELOPMENT_GROUP].top + 12;
// Research type
stringId = STR_RESEARCH_UNKNOWN;
if (RCT2_GLOBAL(0x01357CF3, uint8) != 0) {
stringId = STR_TRANSPORT_RIDE + RCT2_GLOBAL(0x013580E6, uint8);
if (RCT2_GLOBAL(0x01357CF3, uint8) != 1) {
uint32 typeId = RCT2_GLOBAL(0x013580E0, uint32);
if (typeId >= 0x10000) {
uint8 *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, uint8*);
if (RCT2_GLOBAL(rideEntry + 8, uint32) & 0x1000)
stringId = RCT2_GLOBAL(rideEntry, uint16);
else
stringId = (typeId & 0xFF00) + 2;
} else {
uint8 *sceneryEntry = RCT2_GLOBAL(0x009ADA90 + (typeId & 0xFFFF) * 4, uint8*);
stringId = RCT2_GLOBAL(sceneryEntry, uint16);
}
}
}
gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_TYPE_LABEL, 0);
y += 25;
// Progress
stringId = 2285 + RCT2_GLOBAL(0x01357CF3, uint8);
gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 296, STR_RESEARCH_PROGRESS_LABEL, 0);
y += 15;
// Expected
RCT2_GLOBAL(0x013CE952, uint16) = STR_UNKNOWN;
if (RCT2_GLOBAL(0x01357CF3, uint8) != 0) {
uint16 expectedDay = RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_DAY, uint8);
if (expectedDay != 255) {
RCT2_GLOBAL(0x013CE952 + 2, uint16) = STR_DATE_DAY_1 + expectedDay;
RCT2_GLOBAL(0x013CE952 + 4, uint16) = STR_MONTH_MARCH + RCT2_GLOBAL(RCT2_ADDRESS_NEXT_RESEARCH_EXPECTED_MONTH, uint8);
RCT2_GLOBAL(0x013CE952, uint16) = 2289;
}
}
gfx_draw_string_left(dpi, STR_RESEARCH_EXPECTED_LABEL, (void*)0x013CE952, 0, x, y);
// Last development
x = w->x + 10;
y = w->y + window_research_development_widgets[WIDX_LAST_DEVELOPMENT_GROUP].top + 12;
uint32 typeId = RCT2_GLOBAL(0x01357CF4, uint32);
if (typeId != 0xFFFFFFFF) {
if (typeId >= 0x10000) {
uint8 *rideEntry = RCT2_GLOBAL(0x009ACFA4 + (typeId & 0xFF) * 4, uint8*);
if (RCT2_GLOBAL(rideEntry + 8, uint32) & 0x1000)
stringId = RCT2_GLOBAL(rideEntry, uint16);
else
stringId = (typeId & 0xFF00) + 2;
} else {
uint8 *sceneryEntry = RCT2_GLOBAL(0x009ADA90 + (typeId & 0xFFFF) * 4, uint8*);
stringId = RCT2_GLOBAL(sceneryEntry, uint16);
}
gfx_draw_string_left_wrapped(dpi, &stringId, x, y, 266, STR_RESEARCH_RIDE_LABEL, 0);
}
}
#pragma endregion
#pragma region Funding page
/**
*
* rct2: 0x0069DB3F
*/
static void window_research_funding_mouseup()
{
rct_window * w;
short widgetIndex;
int activeResearchTypes;
window_mouse_up_get_registers(w, widgetIndex);
switch (widgetIndex) {
case WIDX_CLOSE:
window_close(w);
break;
case WIDX_TAB_1:
case WIDX_TAB_2:
window_research_set_page(w, widgetIndex - WIDX_TAB_1);
break;
case WIDX_TRANSPORT_RIDES:
case WIDX_GENTLE_RIDES:
case WIDX_ROLLER_COASTERS:
case WIDX_THRILL_RIDES:
case WIDX_WATER_RIDES:
case WIDX_SHOPS_AND_STALLS:
case WIDX_SCENERY_AND_THEMING:
activeResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES, uint16);
activeResearchTypes ^= 1 << (widgetIndex - WIDX_TRANSPORT_RIDES);
game_do_command(0, (1 << 8) | 1, 0, activeResearchTypes, GAME_COMMAND_SET_RESEARCH_FUNDING, 0, 0);
break;
}
}
/**
*
* rct2: 0x0069DB66
*/
static void window_research_funding_mousedown(int widgetIndex, rct_window *w, rct_widget* widget)
{
rct_widget *dropdownWidget;
int i;
if (widgetIndex != WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON)
return;
dropdownWidget = widget - 1;
for (i = 0; i < 4; i++) {
gDropdownItemsFormat[i] = 1142;
gDropdownItemsArgs[i] = STR_NO_FUNDING + i;
}
window_dropdown_show_text_custom_width(
w->x + dropdownWidget->left,
w->y + dropdownWidget->top,
dropdownWidget->bottom - dropdownWidget->top + 1,
w->colours[1],
0x80,
4,
dropdownWidget->right - dropdownWidget->left - 3
);
int currentResearchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8);
gDropdownItemsChecked = (1 << currentResearchLevel);
}
/**
*
* rct2: 0x0069DB6D
*/
static void window_research_funding_dropdown()
{
rct_window *w;
short widgetIndex;
short dropdownIndex;
window_dropdown_get_registers(w, widgetIndex, dropdownIndex);
if (widgetIndex != WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON || dropdownIndex == -1)
return;
game_do_command(0, 1, 0, dropdownIndex, GAME_COMMAND_SET_RESEARCH_FUNDING, 0, 0);
window_invalidate(w);
}
/**
*
* rct2: 0x0069DC23
*/
static void window_research_funding_update(rct_window *w)
{
// Tab animation
if (++w->frame_no >= window_research_tab_animation_loops[w->page])
w->frame_no = 0;
widget_invalidate(w->classification, w->number, WIDX_TAB_2);
}
/**
*
* rct2: 0x0069DA64
*/
static void window_research_funding_invalidate()
{
rct_window *w;
window_get_register(w);
if (w->widgets != window_research_page_widgets[WINDOW_RESEARCH_PAGE_FUNDING]) {
w->widgets = window_research_page_widgets[WINDOW_RESEARCH_PAGE_FUNDING];
window_init_scroll_widgets(w);
}
window_research_set_pressed_tab(w);
if ((RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) {
window_research_funding_widgets[WIDX_FUNDING_GROUP].type = WWT_EMPTY;
window_research_funding_widgets[WIDX_RESEARCH_FUNDING].type = WWT_EMPTY;
window_research_funding_widgets[WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON].type = WWT_EMPTY;
} else {
window_research_funding_widgets[WIDX_FUNDING_GROUP].type = WWT_GROUPBOX;
window_research_funding_widgets[WIDX_RESEARCH_FUNDING].type = WWT_DROPDOWN;
window_research_funding_widgets[WIDX_RESEARCH_FUNDING_DROPDOWN_BUTTON].type = WWT_DROPDOWN_BUTTON;
// Current funding
int currentResearchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8);
window_research_funding_widgets[WIDX_RESEARCH_FUNDING].image = STR_NO_FUNDING + currentResearchLevel;
}
// Checkboxes
int activeResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES, uint16);
int uncompletedResearchTypes = RCT2_GLOBAL(RCT2_ADDRESS_UNCOMPLETED_RESEARCH_TYPES, uint16);
for (int i = 0; i < 7; i++) {
int mask = 1 << i;
int widgetMask = 1 << (i + WIDX_TRANSPORT_RIDES);
// Set checkbox disabled if research type is complete
if (uncompletedResearchTypes & mask) {
w->disabled_widgets &= ~widgetMask;
// Set checkbox ticked if research type is active
if (activeResearchTypes & mask)
w->pressed_widgets |= widgetMask;
else
w->pressed_widgets &= ~widgetMask;
} else {
w->disabled_widgets |= widgetMask;
w->pressed_widgets &= ~widgetMask;
}
}
}
/**
*
* rct2: 0x0069DAF0
*/
static void window_research_funding_paint()
{
rct_window *w;
rct_drawpixelinfo *dpi;
window_paint_get_registers(w, dpi);
window_draw_widgets(w, dpi);
window_research_draw_tab_images(dpi, w);
if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) {
int currentResearchLevel = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_RESEARCH_LEVEL, uint8);
money32 currentResearchCostPerWeek = research_cost_table[currentResearchLevel];
gfx_draw_string_left(dpi, STR_RESEARCH_COST_PER_MONTH, &currentResearchCostPerWeek, 0, w->x + 10, w->y + 77);
}
}
#pragma endregion
#pragma region Common
/**
*
* rct2: 0x0069CAC5
*/
static void window_research_set_page(rct_window *w, int page)
{
w->page = page;
w->frame_no = 0;
if (w->viewport != NULL) {
w->viewport->width = 0;
w->viewport = NULL;
}
w->enabled_widgets = window_research_page_enabled_widgets[page];
w->var_020 = RCT2_ADDRESS(0x00988E3C, uint32)[page];
w->event_handlers = window_research_page_events[page];
w->widgets = window_research_page_widgets[page];
w->disabled_widgets = 0;
w->pressed_widgets = 0;
window_invalidate(w);
if (w->page == WINDOW_RESEARCH_PAGE_DEVELOPMENT) {
w->width = 300;
w->height = 196;
} else {
w->width = 320;
w->height = 207;
}
RCT2_CALLPROC_X(w->event_handlers[WE_RESIZE], 0, 0, 0, 0, (int)w, 0, 0);
RCT2_CALLPROC_X(w->event_handlers[WE_INVALIDATE], 0, 0, 0, 0, (int)w, 0, 0);
window_init_scroll_widgets(w);
window_invalidate(w);
}
static void window_research_set_pressed_tab(rct_window *w)
{
int i;
for (i = 0; i < WINDOW_RESEARCH_PAGE_COUNT; i++)
w->pressed_widgets &= ~(1 << (WIDX_TAB_1 + i));
w->pressed_widgets |= 1LL << (WIDX_TAB_1 + w->page);
}
static void window_research_draw_tab_image(rct_drawpixelinfo *dpi, rct_window *w, int page, int spriteIndex)
{
int widgetIndex = WIDX_TAB_1 + page;
if (!(w->disabled_widgets & (1LL << widgetIndex))) {
if (w->page == page) {
int frame = w->frame_no / 2;
if (page == WINDOW_RESEARCH_PAGE_DEVELOPMENT)
frame %= 8;
spriteIndex += frame;
}
gfx_draw_sprite(dpi, spriteIndex, w->x + w->widgets[widgetIndex].left, w->y + w->widgets[widgetIndex].top, 0);
}
}
static void window_research_draw_tab_images(rct_drawpixelinfo *dpi, rct_window *w)
{
window_research_draw_tab_image(dpi, w, WINDOW_RESEARCH_PAGE_DEVELOPMENT, SPR_TAB_FINANCES_RESEARCH_0);
window_research_draw_tab_image(dpi, w, WINDOW_RESEARCH_PAGE_FUNDING, SPR_TAB_FINANCES_SUMMARY_0);
}
#pragma endregion

244
src/window_staff_peep.c Normal file
View File

@ -0,0 +1,244 @@
/*****************************************************************************
* Copyright (c) 2014 Ted John, Duncan Frost
* 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 "addresses.h"
#include "game.h"
#include "peep.h"
#include "string_ids.h"
#include "sprite.h"
#include "sprites.h"
#include "widget.h"
#include "window.h"
#include "window_dropdown.h"
enum WINDOW_STAFF_PEEP_PAGE {
WINDOW_STAFF_PEEP_OVERVIEW,
WINDOW_STAFF_PEEP_OPTIONS,
WINDOW_STAFF_PEEP_STATISTICS,
};
enum WINDOW_STAFF_PEEP_WIDGET_IDX {
WIDX_BACKGROUND,
WIDX_TITLE,
WIDX_CLOSE,
WIDX_RESIZE,
WIDX_TAB_1,
WIDX_TAB_2,
WIDX_TAB_3,
WIDX_TAB_4,
WIDX_VIEWPORT,
WIDX_BTM_LABEL,
WIDX_PATROL,
WIDX_RENAME,
WIDX_LOCATE,
WIDX_FIRE
};
void window_staff_peep_emptysub(){};
rct_widget window_staff_peep_overview_widgets[] = {
{ WWT_FRAME, 0, 0, 189, 0, 179, 0x0FFFFFFFF, STR_NONE }, // Panel / Background
{ WWT_CAPTION, 0, 1, 188, 1, 14, 0x361, STR_WINDOW_TITLE_TIP }, // Title
{ WWT_CLOSEBOX, 0, 177, 187, 2, 13, 0x338, STR_CLOSE_WINDOW_TIP }, // Close x button
{ WWT_RESIZE, 1, 0, 189, 43, 179, 0x0FFFFFFFF, STR_NONE }, // Resize
{ WWT_TAB, 1, 3, 33, 17, 43, 0x2000144E, 1939 }, // Tab 1
{ WWT_TAB, 1, 34, 64, 17, 43, 0x2000144E, 1945}, // Tab 2
{ WWT_TAB, 1, 65, 95, 17, 43, 0x2000144E, 2348}, // Tab 3
{ WWT_TAB, 1, 96, 126, 17, 43, 0x2000144E, STR_NONE}, // Tab 4
{ WWT_VIEWPORT, 1, 3, 164, 47, 166, 0x0FFFFFFFF, STR_NONE}, // Viewport
{ WWT_12, 1, 3, 164, 167, 177, 0x0FFFFFFFF, STR_NONE }, // Label at bottom of viewport
{ WWT_FLATBTN, 1, 165, 188, 45, 68, 0x1436, 1706}, // Pickup Button
{ WWT_FLATBTN, 1, 165, 188, 69, 92, 0x1437, 1708}, // Patrol Button
{ WWT_FLATBTN, 1, 165, 188, 93, 116, 0x1430, 1056}, // Rename Button
{ WWT_FLATBTN, 1, 165, 188, 117, 140, 0x142F, 1027}, // Locate Button
{ WWT_FLATBTN, 1, 165, 188, 141, 164, 0x142D, 1705}, // Fire Button
{ WIDGETS_END },
};
rct_widget *window_staff_peep_page_widgets[] = {
window_staff_peep_overview_widgets
};
// 0x992AEC
static void* window_staff_peep_overview_events[] = {
(void*)0x6BDFF8,
(void*)0x6BDF55,
(void*)0x6BE558,
(void*)0x6BDF98,
(void*)0x6BDFA3,
window_staff_peep_emptysub,
(void*)0x6BE602,
window_staff_peep_emptysub,
window_staff_peep_emptysub,
(void*)0x6BDFD8,
(void*)0x6BDFC3,
window_staff_peep_emptysub,
window_staff_peep_emptysub,
(void*)0x6BDFAE,
window_staff_peep_emptysub,
window_staff_peep_emptysub,
window_staff_peep_emptysub,
window_staff_peep_emptysub,
window_staff_peep_emptysub,
(void*)0x6BDFED,
(void*)0x6BE5FC,
window_staff_peep_emptysub,
window_staff_peep_emptysub,
window_staff_peep_emptysub,
window_staff_peep_emptysub,
(void*)0x6BDD91, //Invalidate
(void*)0x6BDEAF, //Paint
(void*)0x6BE62A
};
void* window_staff_peep_page_events[] = {
window_staff_peep_overview_events
};
uint32 window_staff_peep_page_enabled_widgets[] = {
(1 << WIDX_CLOSE) |
(1 << WIDX_TAB_1) |
(1 << WIDX_TAB_2) |
(1 << WIDX_TAB_3) |
(1 << WIDX_PATROL) |
(1 << WIDX_RENAME) |
(1 << WIDX_LOCATE) |
(1 << WIDX_FIRE) |
(1 << 14)
};
/**
* rct2: 0x006BED21
*
*/
void sub_6BED21(rct_window* w, rct_peep* peep)
{
int eax = 0 | 0x80;
if (peep->staff_type == 2) {
eax |= 0x20;
}
//RCT2_CALLFUNC_X(0x698827, 0, 0, 0, 0, 0, 0, 0);
// sub_698827
// This is here due to needing the Carry Flag.
int CF = 0;
int res = RCT2_GLOBAL(0x982004 + peep->state, uint8) & 1;
if (res == 0) {
CF = 1;
}
else {
eax = eax & eax;
}
// end sub_698827
int a = 0;
// pop esi
if (CF == 1 && w->page == 0) {
eax |= 0x400; //or eax, 400h
a = w->disabled_widgets & (1 << 0xA); //bt dword ptr[esi + 10h], 0Ah
}
if (a == 0) {
CF = w->disabled_widgets & (1 << 0xA); //bt dword ptr [esi+10h], 0Ah
if (CF == 1) {
window_invalidate(w);
}
}
w->disabled_widgets = eax;
}
/**
* Create the window for a specific peep.
*
* rct2: 0x006BEF1B
*/
rct_window* sub_6BEF1B(rct_peep* peep)
{
rct_window* w = window_create_auto_pos(190, 180, (uint32*)window_staff_peep_overview_events, WC_PEEP, (uint16)0x400);
w->widgets = RCT2_GLOBAL(0x9AF81C, rct_widget*);
w->enabled_widgets = RCT2_GLOBAL(0x9929B0, uint32);
w->number = peep->sprite_index;
w->page = 0;
w->var_482 = 0;
w->frame_no = 0;
RCT2_GLOBAL((int*)w + 0x496, uint16) = 0; // missing, var_494 should perhaps be uint16?
sub_6BED21(w, peep);
w->min_width = 190;
w->min_height = 180;
w->max_width = 500;
w->max_height = 450;
w->flags = 1 << 8;
w->colours[0] = 1;
w->colours[1] = 4;
w->colours[2] = 4;
return w;
}
/**
*
* rct2: 0x006BEE98
*/
void window_staff_peep_open(rct_peep* peep)
{
rct_window* w = window_bring_to_front_by_id(WC_PEEP, peep->sprite_index);
if (!w) {
//int eax, ebx, ecx, edx, esi, edi;
//eax = peep->sprite_index;
//ecx = WC_PEEP;
//edx = peep->sprite_index;
//RCT2_CALLFUNC_X(0x006BEF1B, &eax, &ebx, &ecx, &edx, &esi, &edi, (int*)peep);
//w = (rct_window*)esi;
w = sub_6BEF1B(peep);
}
w->page = 0;
window_invalidate(w);
w->widgets = window_staff_peep_overview_widgets;
w->enabled_widgets = window_staff_peep_page_enabled_widgets[0];
w->var_020 = RCT2_GLOBAL(0x9929BC, uint32);
w->event_handlers = window_staff_peep_page_events[0];
w->pressed_widgets = 0;
//RCT2_CALLPROC_X(0x006BED21, 0, 0, 0, 0, (int)w, 0, 0);
sub_6BED21(w, peep);
window_init_scroll_widgets(w);
RCT2_CALLPROC_X(0x006BEDA3, 0, 0, 0, 0, (int)w, 0, 0);
if (g_sprite_list[w->number].peep.state == PEEP_STATE_PICKED) {
RCT2_CALLPROC_X(w->event_handlers[WE_MOUSE_UP], 0, 0, 0, 10, (int)w, 0, 0);
}
}