2016-05-04 19:24:41 +02:00
# pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
2014-04-02 01:31:55 +02:00
/*****************************************************************************
* OpenRCT2 , an open source clone of Roller Coaster Tycoon 2.
2015-10-09 18:22:37 +02:00
*
2016-05-04 19:24:41 +02:00
* OpenRCT2 is the work of many authors , a full list can be found in contributors . md
* For more information , visit https : //github.com/OpenRCT2/OpenRCT2
2015-10-09 18:22:37 +02:00
*
2014-04-02 01:31:55 +02:00
* 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 .
2016-05-04 19:24:41 +02:00
*
* A full copy of the GNU General Public License can be found in licence . txt
2014-04-02 01:31:55 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-05-04 19:24:41 +02:00
# pragma endregion
2015-10-09 18:22:37 +02:00
2014-10-06 18:36:58 +02:00
# include "audio/audio.h"
2016-02-02 01:04:39 +01:00
# include "cheats.h"
2014-04-24 22:29:57 +02:00
# include "config.h"
2014-04-02 01:31:55 +02:00
# include "game.h"
2014-11-23 17:28:23 +01:00
# include "editor.h"
2015-01-15 00:38:48 +01:00
# include "world/footpath.h"
2014-08-24 19:45:47 +02:00
# include "input.h"
2014-10-06 18:36:58 +02:00
# include "localisation/localisation.h"
# include "interface/screenshot.h"
# include "interface/viewport.h"
# include "interface/widget.h"
# include "interface/window.h"
# include "management/finance.h"
2015-01-24 19:22:06 +01:00
# include "management/marketing.h"
2014-10-06 18:36:58 +02:00
# include "management/news_item.h"
2014-10-07 20:10:16 +02:00
# include "management/research.h"
2015-02-12 12:30:57 +01:00
# include "network/network.h"
2014-05-04 17:21:15 +02:00
# include "object.h"
2015-05-21 04:11:53 +02:00
# include "openrct2.h"
2014-10-06 20:41:43 +02:00
# include "peep/peep.h"
# include "peep/staff.h"
2015-02-12 21:51:40 +01:00
# include "platform/platform.h"
2016-04-25 15:38:44 +02:00
# include "rct1.h"
2014-10-06 18:36:58 +02:00
# include "ride/ride.h"
2014-10-09 21:31:58 +02:00
# include "ride/ride_ratings.h"
2014-10-06 18:36:58 +02:00
# include "ride/vehicle.h"
2015-04-29 20:49:49 +02:00
# include "ride/track.h"
2016-04-28 22:46:39 +02:00
# include "ride/track_design.h"
2014-05-01 19:15:02 +02:00
# include "scenario.h"
2014-05-02 23:21:08 +02:00
# include "title.h"
2014-10-06 18:36:58 +02:00
# include "util/sawyercoding.h"
2014-11-25 03:05:48 +01:00
# include "util/util.h"
2014-10-06 18:36:58 +02:00
# include "windows/error.h"
# include "windows/tooltip.h"
# include "world/climate.h"
2015-03-18 20:52:27 +01:00
# include "world/map_animation.h"
2014-10-06 18:36:58 +02:00
# include "world/park.h"
2015-03-29 03:29:07 +02:00
# include "world/scenery.h"
2014-10-06 18:36:58 +02:00
# include "world/sprite.h"
2015-03-01 22:06:51 +01:00
# include "world/water.h"
2016-01-04 16:22:15 +01:00
# define NUMBER_OF_AUTOSAVES_TO_KEEP 9
2014-07-16 04:41:12 +02:00
2016-05-20 23:56:45 +02:00
uint16 gTicksSinceLastUpdate ;
uint32 gLastTickCount ;
2016-04-23 14:34:55 +02:00
uint8 gGamePaused = 0 ;
2014-08-24 19:45:47 +02:00
int gGameSpeed = 1 ;
2015-07-24 23:58:41 +02:00
float gDayNightCycle = 0 ;
2015-11-07 18:56:03 +01:00
bool gInUpdateCode = false ;
2016-05-17 22:47:14 +02:00
int gGameCommandNestLevel ;
2016-05-30 13:39:09 +02:00
bool gGameCommandIsNetworked ;
2014-07-26 11:30:55 +02:00
2016-09-10 15:46:53 +02:00
uint8 gUnk13CA740 ;
uint8 gUnk141F568 ;
2016-09-03 22:25:19 +02:00
# ifdef NO_RCT2
uint32 gCurrentTicks ;
# endif
2015-07-24 01:22:03 +02:00
GAME_COMMAND_CALLBACK_POINTER * game_command_callback = 0 ;
GAME_COMMAND_CALLBACK_POINTER * game_command_callback_table [ ] = {
0 ,
game_command_callback_ride_construct_new ,
2015-09-21 12:01:01 +02:00
game_command_callback_ride_construct_placed_front ,
game_command_callback_ride_construct_placed_back ,
2015-11-03 21:38:42 +01:00
game_command_callback_ride_remove_track_piece ,
2016-01-24 01:33:08 +01:00
game_command_callback_place_banner ,
2016-03-05 14:11:06 +01:00
game_command_callback_place_ride_entrance_or_exit ,
2016-10-13 23:02:10 +02:00
game_command_callback_hire_new_staff_member ,
2015-07-24 01:22:03 +02:00
} ;
2016-01-23 00:57:00 +01:00
int game_command_playerid = - 1 ;
2015-07-24 01:22:03 +02:00
2016-04-15 18:54:46 +02:00
rct_string_id gGameCommandErrorTitle ;
rct_string_id gGameCommandErrorText ;
2016-05-02 22:23:28 +02:00
uint8 gErrorType ;
2016-07-14 14:07:49 +02:00
rct_string_id gErrorStringId ;
2016-04-15 18:54:46 +02:00
2015-07-24 01:22:03 +02:00
int game_command_callback_get_index ( GAME_COMMAND_CALLBACK_POINTER * callback )
{
for ( int i = 0 ; i < countof ( game_command_callback_table ) ; i + + ) {
if ( game_command_callback_table [ i ] = = callback ) {
return i ;
}
}
return 0 ;
}
GAME_COMMAND_CALLBACK_POINTER * game_command_callback_get_callback ( int index )
{
if ( index < countof ( game_command_callback_table ) ) {
return game_command_callback_table [ index ] ;
}
return 0 ;
}
2014-11-05 19:50:51 +01:00
void game_increase_game_speed ( )
{
2015-05-19 00:15:43 +02:00
gGameSpeed = min ( gConfigGeneral . debugging_tools ? 5 : 4 , gGameSpeed + 1 ) ;
if ( gGameSpeed = = 5 )
gGameSpeed = 8 ;
window_invalidate_by_class ( WC_TOP_TOOLBAR ) ;
2014-11-05 19:50:51 +01:00
}
void game_reduce_game_speed ( )
{
gGameSpeed = max ( 1 , gGameSpeed - 1 ) ;
2015-05-19 00:15:43 +02:00
if ( gGameSpeed = = 7 )
gGameSpeed = 4 ;
window_invalidate_by_class ( WC_TOP_TOOLBAR ) ;
2014-11-05 19:50:51 +01:00
}
2014-04-11 03:42:39 +02:00
/**
2015-10-09 18:22:37 +02:00
*
2014-04-11 03:42:39 +02:00
* rct2 : 0x0066B5C0 ( part of 0x0066B3E8 )
*/
void game_create_windows ( )
{
window_main_open ( ) ;
2015-02-09 19:32:58 +01:00
window_top_toolbar_open ( ) ;
2014-04-11 04:58:17 +02:00
window_game_bottom_toolbar_open ( ) ;
2016-04-24 01:36:39 +02:00
window_resize_gui ( gScreenWidth , gScreenHeight ) ;
2014-04-11 03:42:39 +02:00
}
2014-07-18 05:29:39 +02:00
/**
*
2014-09-23 21:33:55 +02:00
* rct2 : 0x006838BD
2014-07-18 05:29:39 +02:00
*/
2014-09-23 21:33:55 +02:00
void update_palette_effects ( )
2014-07-18 05:29:39 +02:00
{
2015-03-01 22:06:51 +01:00
rct_water_type * water_type = ( rct_water_type * ) object_entry_groups [ OBJECT_TYPE_WATER ] . chunks [ 0 ] ;
2016-04-24 22:49:09 +02:00
if ( gClimateLightningFlash = = 1 ) {
2016-02-28 20:32:02 +01:00
// change palette to lighter colour during lightning
2014-09-23 21:33:55 +02:00
int palette = 1532 ;
2015-03-01 22:06:51 +01:00
2016-07-30 14:13:04 +02:00
if ( ( intptr_t ) water_type ! = - 1 ) {
2015-03-01 22:06:51 +01:00
palette = water_type - > image_id ;
2014-07-20 08:46:29 +02:00
}
2015-05-28 01:16:51 +02:00
rct_g1_element g1_element = g1Elements [ palette ] ;
2014-09-23 21:33:55 +02:00
int xoffset = g1_element . x_offset ;
xoffset = xoffset * 4 ;
2016-04-24 03:02:56 +02:00
uint8 * paletteOffset = gGamePalette + xoffset ;
2014-09-23 21:33:55 +02:00
for ( int i = 0 ; i < g1_element . width ; i + + ) {
2016-04-24 03:02:56 +02:00
paletteOffset [ ( i * 4 ) + 0 ] = - ( ( 0xFF - g1_element . offset [ ( i * 3 ) + 0 ] ) / 2 ) - 1 ;
paletteOffset [ ( i * 4 ) + 1 ] = - ( ( 0xFF - g1_element . offset [ ( i * 3 ) + 1 ] ) / 2 ) - 1 ;
paletteOffset [ ( i * 4 ) + 2 ] = - ( ( 0xFF - g1_element . offset [ ( i * 3 ) + 2 ] ) / 2 ) - 1 ;
2014-07-20 08:46:29 +02:00
}
2016-04-24 03:02:56 +02:00
platform_update_palette ( gGamePalette , 10 , 236 ) ;
2016-04-24 22:49:09 +02:00
gClimateLightningFlash + + ;
2014-09-23 21:33:55 +02:00
} else {
2016-04-24 22:49:09 +02:00
if ( gClimateLightningFlash = = 2 ) {
2014-09-23 21:33:55 +02:00
// change palette back to normal after lightning
int palette = 1532 ;
2015-03-01 22:06:51 +01:00
2016-07-30 14:13:04 +02:00
if ( ( intptr_t ) water_type ! = - 1 ) {
2015-03-01 22:06:51 +01:00
palette = water_type - > image_id ;
2014-09-23 21:33:55 +02:00
}
2015-03-01 22:06:51 +01:00
2015-05-28 01:16:51 +02:00
rct_g1_element g1_element = g1Elements [ palette ] ;
2014-09-23 21:33:55 +02:00
int xoffset = g1_element . x_offset ;
xoffset = xoffset * 4 ;
2016-04-24 03:02:56 +02:00
uint8 * paletteOffset = gGamePalette + xoffset ;
2014-09-23 21:33:55 +02:00
for ( int i = 0 ; i < g1_element . width ; i + + ) {
2016-04-24 03:02:56 +02:00
paletteOffset [ ( i * 4 ) + 0 ] = g1_element . offset [ ( i * 3 ) + 0 ] ;
paletteOffset [ ( i * 4 ) + 1 ] = g1_element . offset [ ( i * 3 ) + 1 ] ;
paletteOffset [ ( i * 4 ) + 2 ] = g1_element . offset [ ( i * 3 ) + 2 ] ;
2014-09-23 21:33:55 +02:00
}
2014-07-20 08:46:29 +02:00
}
2014-07-18 05:29:39 +02:00
2014-09-23 21:33:55 +02:00
// animate the water/lava/chain movement palette
int q = 0 ;
2016-08-09 23:40:21 +02:00
extern const sint32 WeatherColours [ 4 ] ;
int weather_colour = WeatherColours [ gClimateCurrentWeatherGloom ] ;
2016-08-17 00:23:16 +02:00
if ( weather_colour ! = - 1 & & gConfigGeneral . render_weather_gloom ) {
2014-09-23 21:33:55 +02:00
q = 1 ;
if ( weather_colour ! = 0x2000031 ) {
q = 2 ;
}
}
2016-04-24 03:02:56 +02:00
uint32 j = gPaletteEffectFrame ;
2014-09-23 21:33:55 +02:00
j = ( ( ( uint16 ) ( ( ~ j / 2 ) * 128 ) * 15 ) > > 16 ) ;
int p = 1533 ;
2016-07-30 14:13:04 +02:00
if ( ( intptr_t ) water_type ! = - 1 ) {
2015-03-01 22:06:51 +01:00
p = water_type - > var_06 ;
2014-09-23 21:33:55 +02:00
}
2015-05-28 01:16:51 +02:00
rct_g1_element g1_element = g1Elements [ q + p ] ;
2014-09-23 21:33:55 +02:00
uint8 * vs = & g1_element . offset [ j * 3 ] ;
2016-04-24 03:02:56 +02:00
uint8 * vd = & gGamePalette [ 230 * 4 ] ;
2014-09-23 21:33:55 +02:00
int n = 5 ;
for ( int i = 0 ; i < n ; i + + ) {
vd [ 0 ] = vs [ 0 ] ;
vd [ 1 ] = vs [ 1 ] ;
vd [ 2 ] = vs [ 2 ] ;
vs + = 9 ;
if ( vs > = & g1_element . offset [ 9 * n ] ) {
vs - = 9 * n ;
}
vd + = 4 ;
2014-07-20 08:46:29 +02:00
}
2014-09-23 21:33:55 +02:00
p = 1536 ;
2016-07-30 14:13:04 +02:00
if ( ( intptr_t ) water_type ! = - 1 ) {
2015-03-01 22:06:51 +01:00
p = water_type - > var_0A ;
2014-09-23 21:33:55 +02:00
}
2015-05-28 01:16:51 +02:00
g1_element = g1Elements [ q + p ] ;
2014-09-23 21:33:55 +02:00
vs = & g1_element . offset [ j * 3 ] ;
n = 5 ;
for ( int i = 0 ; i < n ; i + + ) {
vd [ 0 ] = vs [ 0 ] ;
vd [ 1 ] = vs [ 1 ] ;
vd [ 2 ] = vs [ 2 ] ;
vs + = 9 ;
if ( vs > = & g1_element . offset [ 9 * n ] ) {
vs - = 9 * n ;
}
vd + = 4 ;
}
2014-07-20 08:46:29 +02:00
2016-04-24 03:02:56 +02:00
j = ( ( uint16 ) ( gPaletteEffectFrame * - 960 ) * 3 ) > > 16 ;
2014-09-23 21:33:55 +02:00
p = 1539 ;
2015-05-28 01:16:51 +02:00
g1_element = g1Elements [ q + p ] ;
2014-09-23 21:33:55 +02:00
vs = & g1_element . offset [ j * 3 ] ;
vd + = 12 ;
n = 3 ;
for ( int i = 0 ; i < n ; i + + ) {
vd [ 0 ] = vs [ 0 ] ;
vd [ 1 ] = vs [ 1 ] ;
vd [ 2 ] = vs [ 2 ] ;
vs + = 3 ;
if ( vs > = & g1_element . offset [ 3 * n ] ) {
vs - = 3 * n ;
}
vd + = 4 ;
}
2014-07-20 08:46:29 +02:00
2016-04-24 03:02:56 +02:00
platform_update_palette ( gGamePalette , 230 , 16 ) ;
2016-04-24 22:49:09 +02:00
if ( gClimateLightningFlash = = 2 ) {
2016-04-24 03:02:56 +02:00
platform_update_palette ( gGamePalette , 10 , 236 ) ;
2016-04-24 22:49:09 +02:00
gClimateLightningFlash = 0 ;
2014-09-23 21:33:55 +02:00
}
2014-07-20 08:46:29 +02:00
}
2014-07-18 05:29:39 +02:00
}
2014-04-02 01:31:55 +02:00
void game_update ( )
{
2015-02-16 14:27:31 +01:00
int i , numUpdates ;
2014-04-02 01:31:55 +02:00
// 0x006E3AEC // screen_game_process_mouse_input();
2014-04-25 19:25:34 +02:00
screenshot_check ( ) ;
game_handle_keyboard_input ( ) ;
2014-04-02 01:31:55 +02:00
2014-10-15 23:59:26 +02:00
// Determine how many times we need to update the game
if ( gGameSpeed > 1 ) {
numUpdates = 1 < < ( gGameSpeed - 1 ) ;
} else {
2016-05-20 23:56:45 +02:00
numUpdates = gTicksSinceLastUpdate / 31 ;
2014-10-15 23:59:26 +02:00
numUpdates = clamp ( 1 , numUpdates , 4 ) ;
}
2014-04-02 01:31:55 +02:00
2015-11-04 00:31:09 +01:00
if ( network_get_mode ( ) = = NETWORK_MODE_CLIENT & & network_get_status ( ) = = NETWORK_STATUS_CONNECTED & & network_get_authstatus ( ) = = NETWORK_AUTH_OK ) {
2016-04-23 03:49:24 +02:00
if ( network_get_server_tick ( ) - gCurrentTicks > = 10 ) {
2015-07-05 17:19:01 +02:00
// make sure client doesn't fall behind the server too much
numUpdates + = 10 ;
}
2016-07-25 18:36:58 +02:00
}
if ( game_is_paused ( ) ) {
numUpdates = 0 ;
// Update the animation list. Note this does not
// increment the map animation.
map_animation_invalidate_all ( ) ;
2015-07-05 17:19:01 +02:00
}
2014-10-15 23:59:26 +02:00
// Update the game one or more times
2015-08-16 00:19:15 +02:00
for ( i = 0 ; i < numUpdates ; i + + ) {
game_logic_update ( ) ;
if ( gGameSpeed > 1 )
continue ;
2016-09-10 16:22:14 +02:00
if ( gInputState = = INPUT_STATE_RESET | |
gInputState = = INPUT_STATE_NORMAL
) {
if ( gInputFlags & INPUT_FLAG_VIEWPORT_SCROLLING ) {
gInputFlags & = ~ INPUT_FLAG_VIEWPORT_SCROLLING ;
2015-08-16 00:19:15 +02:00
break ;
2014-04-02 01:31:55 +02:00
}
2016-09-10 16:22:14 +02:00
} else {
break ;
2014-04-02 01:31:55 +02:00
}
}
2015-10-03 14:18:43 +02:00
// Always perform autosave check, even when paused
scenario_autosave_check ( ) ;
2015-08-20 04:34:52 +02:00
network_update ( ) ;
2015-05-19 00:15:43 +02:00
window_dispatch_update_all ( ) ;
2016-05-17 22:47:14 +02:00
gGameCommandNestLevel = 0 ;
2014-04-02 01:31:55 +02:00
2016-01-04 23:53:03 +01:00
gInputFlags & = ~ INPUT_FLAG_VIEWPORT_SCROLLING ;
2015-02-16 14:27:31 +01:00
2015-02-16 22:19:19 +01:00
// the flickering frequency is reduced by 4, compared to the original
// it was done due to inability to reproduce original frequency
// and decision that the original one looks too fast
2016-04-23 03:49:24 +02:00
if ( gCurrentTicks % 4 = = 0 )
2016-05-13 23:51:16 +02:00
gWindowMapFlashingFlags ^ = ( 1 < < 15 ) ;
2015-02-16 14:27:31 +01:00
// Handle guest map flashing
2016-05-13 23:51:16 +02:00
gWindowMapFlashingFlags & = ~ ( 1 < < 1 ) ;
if ( gWindowMapFlashingFlags & ( 1 < < 0 ) )
gWindowMapFlashingFlags | = ( 1 < < 1 ) ;
gWindowMapFlashingFlags & = ~ ( 1 < < 0 ) ;
2015-02-16 14:27:31 +01:00
// Handle staff map flashing
2016-05-13 23:51:16 +02:00
gWindowMapFlashingFlags & = ~ ( 1 < < 3 ) ;
if ( gWindowMapFlashingFlags & ( 1 < < 2 ) )
gWindowMapFlashingFlags | = ( 1 < < 3 ) ;
gWindowMapFlashingFlags & = ~ ( 1 < < 2 ) ;
2014-04-02 01:31:55 +02:00
2014-10-17 03:01:58 +02:00
window_map_tooltip_update_visibility ( ) ;
2014-04-02 01:31:55 +02:00
// Input
2016-09-10 15:46:53 +02:00
gUnk141F568 = gUnk13CA740 ;
2014-04-14 04:09:51 +02:00
game_handle_input ( ) ;
2014-04-02 01:31:55 +02:00
}
2014-04-11 03:42:39 +02:00
2014-04-02 01:31:55 +02:00
void game_logic_update ( )
{
2015-11-07 18:56:03 +01:00
///////////////////////////
gInUpdateCode = true ;
///////////////////////////
2015-08-20 04:34:52 +02:00
network_update ( ) ;
2015-11-04 00:31:09 +01:00
if ( network_get_mode ( ) = = NETWORK_MODE_CLIENT & & network_get_status ( ) = = NETWORK_STATUS_CONNECTED & & network_get_authstatus ( ) = = NETWORK_AUTH_OK ) {
2016-04-23 03:49:24 +02:00
if ( gCurrentTicks > = network_get_server_tick ( ) ) {
2016-05-26 09:49:19 +02:00
// don't run past the server
2015-08-20 03:07:11 +02:00
return ;
}
}
2016-04-23 03:49:24 +02:00
gCurrentTicks + + ;
2016-05-09 00:20:42 +02:00
gScenarioTicks + + ;
2016-04-23 12:16:46 +02:00
gScreenAge + + ;
if ( gScreenAge = = 0 )
gScreenAge - - ;
2014-04-02 01:31:55 +02:00
2014-05-04 19:51:36 +02:00
sub_68B089 ( ) ;
2014-05-01 19:15:02 +02:00
scenario_update ( ) ;
2014-04-29 13:18:50 +02:00
climate_update ( ) ;
2015-03-22 18:04:30 +01:00
map_update_tiles ( ) ;
2016-09-20 22:22:55 +02:00
// Temporarily remove provisional paths to prevent peep from interacting with them
map_remove_provisional_elements ( ) ;
2015-11-14 01:08:31 +01:00
map_update_path_wide_flags ( ) ;
2014-04-03 01:22:33 +02:00
peep_update_all ( ) ;
2016-09-20 22:22:55 +02:00
map_restore_provisional_elements ( ) ;
2014-05-25 19:40:11 +02:00
vehicle_update_all ( ) ;
2015-03-23 11:39:47 +01:00
sprite_misc_update_all ( ) ;
2014-10-09 21:31:58 +02:00
ride_update_all ( ) ;
2014-05-25 14:59:31 +02:00
park_update ( ) ;
2014-10-05 16:23:52 +02:00
research_update ( ) ;
2014-10-09 21:31:58 +02:00
ride_ratings_update_all ( ) ;
2014-09-21 14:50:35 +02:00
ride_measurements_update ( ) ;
2016-10-02 02:49:58 +02:00
news_item_update_current ( ) ;
2015-11-07 18:56:03 +01:00
///////////////////////////
gInUpdateCode = false ;
///////////////////////////
2015-03-18 20:52:27 +01:00
map_animation_invalidate_all ( ) ;
2014-10-09 21:31:58 +02:00
vehicle_sounds_update ( ) ;
2014-05-25 02:08:08 +02:00
peep_update_crowd_noise ( ) ;
2014-05-28 23:53:28 +02:00
climate_update_sound ( ) ;
2014-11-23 17:28:23 +01:00
editor_open_windows_for_current_step ( ) ;
2014-04-02 01:31:55 +02:00
2016-09-04 16:01:49 +02:00
gSavedAge + + ;
2015-07-30 16:09:39 +02:00
2014-04-02 01:31:55 +02:00
// Update windows
2015-05-19 00:15:43 +02:00
//window_dispatch_update_all();
2014-04-02 01:31:55 +02:00
2016-05-02 22:23:28 +02:00
if ( gErrorType ! = ERROR_TYPE_NONE ) {
2015-03-07 13:45:13 +01:00
rct_string_id title_text = STR_UNABLE_TO_LOAD_FILE ;
2016-05-02 22:23:28 +02:00
rct_string_id body_text = gErrorStringId ;
if ( gErrorType = = ERROR_TYPE_GENERIC ) {
title_text = gErrorStringId ;
2015-03-07 13:45:13 +01:00
body_text = 0xFFFF ;
2014-04-02 01:31:55 +02:00
}
2016-05-02 22:23:28 +02:00
gErrorType = ERROR_TYPE_NONE ;
2014-04-02 01:31:55 +02:00
2015-03-07 13:45:13 +01:00
window_error_open ( title_text , body_text ) ;
2014-04-02 01:31:55 +02:00
}
2014-04-14 04:09:51 +02:00
}
2014-05-02 03:12:14 +02:00
/**
2015-10-09 18:22:37 +02:00
*
2014-07-14 20:46:45 +02:00
* rct2 : 0x0069C62C
2014-05-02 03:12:14 +02:00
*
* @ param cost ( ebp )
*/
static int game_check_affordability ( int cost )
{
2014-07-14 20:46:45 +02:00
if ( cost < = 0 ) return cost ;
2016-09-10 15:46:53 +02:00
if ( gUnk141F568 & 0xF0 ) return cost ;
2016-04-23 02:58:54 +02:00
if ( cost < = ( sint32 ) ( DECRYPT_MONEY ( gCashEncrypted ) ) ) return cost ;
2015-08-16 19:05:49 +02:00
2016-05-15 23:03:53 +02:00
set_format_arg ( 0 , uint32 , cost ) ;
2015-08-16 19:05:49 +02:00
2016-05-02 21:06:14 +02:00
gGameCommandErrorText = STR_NOT_ENOUGH_CASH_REQUIRES ;
2015-04-16 01:30:18 +02:00
return MONEY32_UNDEFINED ;
2014-05-02 03:12:14 +02:00
}
/**
2015-10-09 18:22:37 +02:00
*
2014-05-02 03:12:14 +02:00
* rct2 : 0x006677F2
*
* @ param flags ( ebx )
* @ param command ( esi )
*/
int game_do_command ( int eax , int ebx , int ecx , int edx , int esi , int edi , int ebp )
{
2014-08-09 15:47:58 +02:00
return game_do_command_p ( esi , & eax , & ebx , & ecx , & edx , & esi , & edi , & ebp ) ;
2014-05-02 23:21:08 +02:00
}
2014-08-05 19:15:28 +02:00
/**
*
* rct2 : 0x006677F2 with pointers as arguments
*
* @ param flags ( ebx )
* @ param command ( esi )
*/
2014-08-06 21:06:51 +02:00
int game_do_command_p ( int command , int * eax , int * ebx , int * ecx , int * edx , int * esi , int * edi , int * ebp )
2014-08-05 19:15:28 +02:00
{
int cost , flags , insufficientFunds ;
int original_ebx , original_edx , original_esi , original_edi , original_ebp ;
2014-08-06 21:06:51 +02:00
* esi = command ;
2014-08-05 19:15:28 +02:00
original_ebx = * ebx ;
original_edx = * edx ;
original_esi = * esi ;
original_edi = * edi ;
original_ebp = * ebp ;
2016-01-20 23:45:09 +01:00
if ( command > = countof ( new_game_command_table ) ) {
return MONEY32_UNDEFINED ;
}
2014-08-05 19:15:28 +02:00
flags = * ebx ;
2016-05-30 13:39:09 +02:00
if ( gGameCommandNestLevel = = 0 ) {
2016-10-02 13:49:30 +02:00
gGameCommandErrorText = STR_NONE ;
2016-05-30 13:39:09 +02:00
gGameCommandIsNetworked = ( flags & GAME_COMMAND_FLAG_NETWORKED ) ! = 0 ;
}
2014-08-05 19:15:28 +02:00
// Increment nest count
2016-05-17 22:47:14 +02:00
gGameCommandNestLevel + + ;
2014-08-05 19:15:28 +02:00
2015-07-18 18:49:08 +02:00
// Remove ghost scenery so it doesn't interfere with incoming network command
2015-07-24 01:22:03 +02:00
if ( ( flags & GAME_COMMAND_FLAG_NETWORKED ) & & ! ( flags & GAME_COMMAND_FLAG_GHOST ) & &
2015-07-18 18:49:08 +02:00
( command = = GAME_COMMAND_PLACE_FENCE | |
command = = GAME_COMMAND_PLACE_SCENERY | |
command = = GAME_COMMAND_PLACE_LARGE_SCENERY | |
2015-10-09 18:22:37 +02:00
command = = GAME_COMMAND_PLACE_BANNER | |
2015-07-18 18:49:08 +02:00
command = = GAME_COMMAND_PLACE_PATH ) ) {
scenery_remove_ghost_tool_placement ( ) ;
}
2016-01-23 00:57:00 +01:00
if ( game_command_playerid = = - 1 ) {
2016-01-22 07:32:40 +01:00
game_command_playerid = network_get_current_player_id ( ) ;
}
2015-01-15 00:38:48 +01:00
* ebx & = ~ GAME_COMMAND_FLAG_APPLY ;
2015-10-09 18:22:37 +02:00
2015-10-10 21:26:17 +02:00
// First call for validity and price check
new_game_command_table [ command ] ( eax , ebx , ecx , edx , esi , edi , ebp ) ;
2014-08-05 19:15:28 +02:00
cost = * ebx ;
2015-04-16 01:30:18 +02:00
if ( cost ! = MONEY32_UNDEFINED ) {
2014-08-05 19:15:28 +02:00
// Check funds
insufficientFunds = 0 ;
2016-05-17 22:47:14 +02:00
if ( gGameCommandNestLevel = = 1 & & ! ( flags & GAME_COMMAND_FLAG_2 ) & & ! ( flags & GAME_COMMAND_FLAG_5 ) & & cost ! = 0 )
2014-08-05 19:15:28 +02:00
insufficientFunds = game_check_affordability ( cost ) ;
2015-04-16 01:30:18 +02:00
if ( insufficientFunds ! = MONEY32_UNDEFINED ) {
2014-08-05 19:15:28 +02:00
* ebx = original_ebx ;
* edx = original_edx ;
* esi = original_esi ;
* edi = original_edi ;
* ebp = original_ebp ;
2015-07-09 04:19:12 +02:00
if ( ! ( flags & GAME_COMMAND_FLAG_APPLY ) ) {
2014-08-05 19:15:28 +02:00
// Decrement nest count
2016-05-17 22:47:14 +02:00
gGameCommandNestLevel - - ;
2014-08-05 19:15:28 +02:00
return cost ;
}
2016-05-17 22:47:14 +02:00
if ( network_get_mode ( ) ! = NETWORK_MODE_NONE & & ! ( flags & GAME_COMMAND_FLAG_NETWORKED ) & & ! ( flags & GAME_COMMAND_FLAG_GHOST ) & & ! ( flags & GAME_COMMAND_FLAG_5 ) & & gGameCommandNestLevel = = 1 /* Send only top-level commands */ ) {
2015-08-20 04:34:52 +02:00
if ( command ! = GAME_COMMAND_LOAD_OR_QUIT ) { // Disable these commands over the network
network_send_gamecmd ( * eax , * ebx , * ecx , * edx , * esi , * edi , * ebp , game_command_callback_get_index ( game_command_callback ) ) ;
if ( network_get_mode ( ) = = NETWORK_MODE_CLIENT ) { // Client sent the command to the server, do not run it locally, just return. It will run when server sends it
game_command_callback = 0 ;
// Decrement nest count
2016-05-17 22:47:14 +02:00
gGameCommandNestLevel - - ;
2015-08-20 04:34:52 +02:00
return cost ;
}
2015-07-09 04:19:12 +02:00
}
}
2015-10-10 21:26:17 +02:00
// Second call to actually perform the operation
new_game_command_table [ command ] ( eax , ebx , ecx , edx , esi , edi , ebp ) ;
2015-07-24 01:22:03 +02:00
2016-03-05 14:11:06 +01:00
// Do the callback (required for multiplayer to work correctly), but only for top level commands
2016-05-17 22:47:14 +02:00
if ( gGameCommandNestLevel = = 1 ) {
2016-03-05 14:11:06 +01:00
if ( game_command_callback & & ! ( flags & GAME_COMMAND_FLAG_GHOST ) ) {
game_command_callback ( * eax , * ebx , * ecx , * edx , * esi , * edi , * ebp ) ;
game_command_callback = 0 ;
}
2015-07-24 01:22:03 +02:00
}
2016-01-24 01:33:08 +01:00
game_command_playerid = - 1 ;
2014-08-05 19:15:28 +02:00
* edx = * ebx ;
2015-04-16 01:30:18 +02:00
if ( * edx ! = MONEY32_UNDEFINED & & * edx < cost )
2014-08-05 19:15:28 +02:00
cost = * edx ;
// Decrement nest count
2016-05-17 22:47:14 +02:00
gGameCommandNestLevel - - ;
if ( gGameCommandNestLevel ! = 0 )
2014-08-05 19:15:28 +02:00
return cost ;
2015-10-09 18:22:37 +02:00
//
2014-08-05 19:15:28 +02:00
if ( ! ( flags & 0x20 ) ) {
// Update money balance
2016-04-24 18:53:39 +02:00
finance_payment ( cost , gCommandExpenditureType ) ;
2016-09-10 15:46:53 +02:00
if ( gUnk141F568 = = gUnk13CA740 ) {
2014-08-05 19:15:28 +02:00
// Create a +/- money text effect
if ( cost ! = 0 )
2015-03-31 04:23:40 +02:00
money_effect_create ( cost ) ;
2014-08-05 19:15:28 +02:00
}
}
2016-01-23 01:08:06 +01:00
if ( network_get_mode ( ) = = NETWORK_MODE_SERVER & & ! ( flags & GAME_COMMAND_FLAG_NETWORKED ) & & ! ( flags & GAME_COMMAND_FLAG_GHOST ) ) {
2016-01-23 20:32:02 +01:00
network_set_player_last_action ( network_get_player_index ( network_get_current_player_id ( ) ) , command ) ;
2016-01-20 23:45:09 +01:00
network_add_player_money_spent ( network_get_current_player_id ( ) , cost ) ;
}
2014-08-05 19:15:28 +02:00
return cost ;
}
}
2016-05-26 09:49:19 +02:00
// Error occurred
2014-08-05 19:15:28 +02:00
// Decrement nest count
2016-05-17 22:47:14 +02:00
gGameCommandNestLevel - - ;
2016-03-13 19:40:50 +01:00
// Clear the game command callback to prevent the next command triggering it
game_command_callback = 0 ;
2014-08-05 19:15:28 +02:00
// Show error window
2016-09-10 15:46:53 +02:00
if ( gGameCommandNestLevel = = 0 & & ( flags & GAME_COMMAND_FLAG_APPLY ) & & gUnk141F568 = = gUnk13CA740 & & ! ( flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED ) & & ! ( flags & GAME_COMMAND_FLAG_NETWORKED ) )
2016-04-15 18:54:46 +02:00
window_error_open ( gGameCommandErrorTitle , gGameCommandErrorText ) ;
2014-08-05 19:15:28 +02:00
2015-04-16 01:30:18 +02:00
return MONEY32_UNDEFINED ;
2014-08-05 19:15:28 +02:00
}
2015-03-31 03:21:30 +02:00
void pause_toggle ( )
{
2016-04-23 14:34:55 +02:00
gGamePaused ^ = GAME_PAUSED_NORMAL ;
2015-03-31 03:21:30 +02:00
window_invalidate_by_class ( WC_TOP_TOOLBAR ) ;
2016-04-23 14:34:55 +02:00
if ( gGamePaused & GAME_PAUSED_NORMAL ) {
2015-11-16 23:39:40 +01:00
audio_pause_sounds ( ) ;
audio_unpause_sounds ( ) ;
2015-10-16 10:25:56 +02:00
} else {
2015-11-16 23:39:40 +01:00
audio_unpause_sounds ( ) ;
2015-10-16 10:25:56 +02:00
}
2015-03-31 03:21:30 +02:00
}
2014-08-05 19:15:28 +02:00
2016-04-23 14:34:55 +02:00
bool game_is_paused ( )
{
return gGamePaused ! = 0 ;
}
bool game_is_not_paused ( )
{
return gGamePaused = = 0 ;
}
2014-05-03 10:00:49 +02:00
/**
2015-10-09 18:22:37 +02:00
*
2014-05-03 10:00:49 +02:00
* rct2 : 0x00667C15
*/
2015-02-08 16:37:33 +01:00
void game_pause_toggle ( int * eax , int * ebx , int * ecx , int * edx , int * esi , int * edi , int * ebp )
2014-05-03 10:00:49 +02:00
{
2015-03-31 03:21:30 +02:00
if ( * ebx & GAME_COMMAND_FLAG_APPLY )
pause_toggle ( ) ;
2015-02-08 16:37:33 +01:00
* ebx = 0 ;
2014-05-03 10:00:49 +02:00
}
2014-05-02 23:21:08 +02:00
/**
2015-10-09 18:22:37 +02:00
*
2014-05-02 23:21:08 +02:00
* rct2 : 0x0066DB5F
*/
2015-02-08 16:37:33 +01:00
static void game_load_or_quit ( int * eax , int * ebx , int * ecx , int * edx , int * esi , int * edi , int * ebp )
2014-05-02 23:21:08 +02:00
{
2015-02-08 16:37:33 +01:00
if ( * ebx & GAME_COMMAND_FLAG_APPLY ) {
switch ( * edx & 0xFF ) {
case 0 :
2016-04-23 12:16:46 +02:00
gSavePromptMode = * edi & 0xFF ;
2015-02-08 16:37:33 +01:00
window_save_prompt_open ( ) ;
break ;
case 1 :
window_close_by_class ( WC_SAVE_PROMPT ) ;
break ;
default :
game_load_or_quit_no_save_prompt ( ) ;
break ;
}
2014-05-02 23:21:08 +02:00
}
2015-02-08 16:37:33 +01:00
* ebx = 0 ;
2014-05-02 23:21:08 +02:00
}
/**
2014-11-20 19:40:10 +01:00
*
2014-05-02 23:21:08 +02:00
* rct2 : 0x0066DC0F
*/
static void load_landscape ( )
{
2015-06-08 00:12:17 +02:00
window_loadsave_open ( LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE , NULL ) ;
2014-05-02 23:21:08 +02:00
}
2016-03-13 16:33:38 +01:00
static void utf8_to_rct2_self ( char * buffer , size_t length )
{
char tempBuffer [ 512 ] ;
utf8_to_rct2 ( tempBuffer , buffer ) ;
2016-03-19 12:16:11 +01:00
size_t i = 0 ;
const char * src = tempBuffer ;
char * dst = buffer ;
while ( * src ! = 0 & & i < length - 1 ) {
if ( * src = = ( char ) 0xFF ) {
if ( i < length - 3 ) {
* dst + + = * src + + ;
* dst + + = * src + + ;
* dst + + = * src + + ;
} else {
break ;
}
2016-03-19 14:55:14 +01:00
i + = 3 ;
2016-03-19 12:16:11 +01:00
} else {
* dst + + = * src + + ;
i + + ;
}
}
do {
* dst + + = ' \0 ' ;
i + + ;
} while ( i < length ) ;
2016-03-13 16:33:38 +01:00
}
static void rct2_to_utf8_self ( char * buffer , size_t length )
{
char tempBuffer [ 512 ] ;
2016-03-19 12:16:11 +01:00
if ( length > 0 ) {
rct2_to_utf8 ( tempBuffer , buffer ) ;
2016-09-26 04:24:29 +02:00
safe_strcpy ( buffer , tempBuffer , length ) ;
2016-03-19 12:16:11 +01:00
}
2016-03-13 16:33:38 +01:00
}
2015-07-30 00:57:43 +02:00
/**
* Converts all the user strings and news item strings to UTF - 8.
*/
void game_convert_strings_to_utf8 ( )
{
2016-03-13 16:33:38 +01:00
// Scenario details
2016-04-23 19:07:07 +02:00
rct2_to_utf8_self ( gScenarioCompletedBy , 32 ) ;
2016-04-23 18:53:25 +02:00
rct2_to_utf8_self ( gScenarioName , 64 ) ;
rct2_to_utf8_self ( gScenarioDetails , 256 ) ;
2015-07-30 00:57:43 +02:00
// User strings
for ( int i = 0 ; i < MAX_USER_STRINGS ; i + + ) {
utf8 * userString = & gUserStrings [ i * USER_STRING_MAX_LENGTH ] ;
if ( ! str_is_null_or_empty ( userString ) ) {
2016-03-13 16:33:38 +01:00
rct2_to_utf8_self ( userString , 32 ) ;
2016-06-09 13:30:32 +02:00
utf8_remove_formatting ( userString , true ) ;
2015-07-30 00:57:43 +02:00
}
}
// News items
for ( int i = 0 ; i < MAX_NEWS_ITEMS ; i + + ) {
rct_news_item * newsItem = news_item_get ( i ) ;
if ( ! str_is_null_or_empty ( newsItem - > text ) ) {
2016-03-13 16:33:38 +01:00
rct2_to_utf8_self ( newsItem - > text , 256 ) ;
2015-07-30 00:57:43 +02:00
}
}
}
/**
* Converts all the user strings and news item strings to RCT2 encoding .
*/
void game_convert_strings_to_rct2 ( rct_s6_data * s6 )
{
2016-03-13 16:33:38 +01:00
// Scenario details
utf8_to_rct2_self ( s6 - > scenario_completed_name , sizeof ( s6 - > scenario_completed_name ) ) ;
utf8_to_rct2_self ( s6 - > scenario_name , sizeof ( s6 - > scenario_name ) ) ;
utf8_to_rct2_self ( s6 - > scenario_description , sizeof ( s6 - > scenario_description ) ) ;
2015-07-30 00:57:43 +02:00
// User strings
for ( int i = 0 ; i < MAX_USER_STRINGS ; i + + ) {
char * userString = & s6 - > custom_strings [ i * USER_STRING_MAX_LENGTH ] ;
if ( ! str_is_null_or_empty ( userString ) ) {
2016-03-13 16:33:38 +01:00
utf8_to_rct2_self ( userString , 32 ) ;
2015-07-30 00:57:43 +02:00
}
}
// News items
for ( int i = 0 ; i < MAX_NEWS_ITEMS ; i + + ) {
rct_news_item * newsItem = & s6 - > news_items [ i ] ;
if ( ! str_is_null_or_empty ( newsItem - > text ) ) {
2016-03-13 16:33:38 +01:00
utf8_to_rct2_self ( newsItem - > text , 256 ) ;
2015-07-30 00:57:43 +02:00
}
}
}
2015-10-07 20:53:55 +02:00
// OpenRCT2 workaround to recalculate some values which are saved redundantly in the save to fix corrupted files.
// For example recalculate guest count by looking at all the guests instead of trusting the value in the file.
void game_fix_save_vars ( ) {
// Recalculates peep count after loading a save to fix corrupted files
rct_peep * peep ;
uint16 spriteIndex ;
uint16 peepCount = 0 ;
FOR_ALL_GUESTS ( spriteIndex , peep ) {
if ( ! peep - > outside_of_park )
peepCount + + ;
}
2016-04-23 02:00:00 +02:00
gNumGuestsInPark = peepCount ;
2015-10-30 12:44:19 +01:00
2016-05-15 18:47:04 +02:00
peep_sort ( ) ;
2016-05-08 01:39:59 +02:00
2015-10-30 12:44:19 +01:00
// Fixes broken saves where a surface element could be null
for ( int y = 0 ; y < 256 ; y + + ) {
for ( int x = 0 ; x < 256 ; x + + ) {
rct_map_element * mapElement = map_get_surface_element_at ( x , y ) ;
if ( mapElement = = NULL )
{
log_error ( " Null map element at x = %d and y = %d. Fixing... " , x , y ) ;
2016-02-26 20:49:01 +01:00
mapElement = map_element_insert ( x , y , 14 , 0 ) ;
2016-04-20 00:14:02 +02:00
if ( mapElement = = NULL ) {
log_error ( " Unable to fix: Map element limit reached. " ) ;
return ;
}
2015-10-30 12:44:19 +01:00
}
}
}
2016-10-01 15:56:44 +02:00
// Fix invalid research items
for ( int i = 0 ; i < 500 ; i + + ) {
rct_research_item * researchItem = & gResearchItems [ i ] ;
if ( researchItem - > entryIndex = = RESEARCHED_ITEMS_SEPARATOR ) continue ;
if ( researchItem - > entryIndex = = RESEARCHED_ITEMS_END ) continue ;
if ( researchItem - > entryIndex = = RESEARCHED_ITEMS_END_2 ) break ;
if ( researchItem - > entryIndex & 0x10000 ) {
uint8 entryIndex = researchItem - > entryIndex & 0xFF ;
rct_ride_entry * rideEntry = get_ride_entry ( entryIndex ) ;
if ( rideEntry = = NULL | | rideEntry = = ( rct_ride_entry * ) - 1 ) {
research_remove ( researchItem - > entryIndex ) ;
i - - ;
}
} else {
uint8 entryIndex = researchItem - > entryIndex ;
rct_scenery_set_entry * sceneryGroupEntry = get_scenery_group_entry ( entryIndex ) ;
if ( sceneryGroupEntry = = NULL | | sceneryGroupEntry = = ( rct_scenery_set_entry * ) - 1 ) {
research_remove ( researchItem - > entryIndex ) ;
i - - ;
}
}
}
2015-10-07 20:53:55 +02:00
}
2015-06-14 22:01:48 +02:00
/**
2015-10-09 18:22:37 +02:00
*
2015-06-14 22:01:48 +02:00
* rct2 : 0x00675E1B
*/
2016-01-09 01:25:09 +01:00
bool game_load_save ( const utf8 * path )
2015-06-14 22:01:48 +02:00
{
2015-07-05 06:36:25 +02:00
log_verbose ( " loading saved game, %s " , path ) ;
2016-06-19 23:47:06 +02:00
safe_strcpy ( ( char * ) gRCT2AddressSavedGamesPath2 , path , MAX_PATH ) ;
2015-07-05 06:36:25 +02:00
2016-01-18 20:49:52 +01:00
safe_strcpy ( gScenarioSavePath , path , MAX_PATH ) ;
2015-07-05 06:36:25 +02:00
2015-08-29 14:12:52 +02:00
SDL_RWops * rw = SDL_RWFromFile ( path , " rb " ) ;
2015-07-05 06:36:25 +02:00
if ( rw = = NULL ) {
log_error ( " unable to open %s " , path ) ;
2016-05-02 22:23:28 +02:00
gErrorType = ERROR_TYPE_FILE_LOAD ;
2016-04-15 18:54:46 +02:00
gGameCommandErrorTitle = STR_FILE_CONTAINS_INVALID_DATA ;
2016-01-09 01:25:09 +01:00
return false ;
2015-07-05 06:36:25 +02:00
}
2016-04-25 19:11:51 +02:00
uint32 extension_type = get_file_extension_type ( path ) ;
2016-04-25 15:38:44 +02:00
bool result = false ;
2016-04-25 19:11:51 +02:00
if ( extension_type = = FILE_EXTENSION_SV6 ) {
2016-04-25 15:38:44 +02:00
result = game_load_sv6 ( rw ) ;
2016-04-25 19:11:51 +02:00
} else if ( extension_type = = FILE_EXTENSION_SV4 ) {
2016-04-25 15:38:44 +02:00
result = rct1_load_saved_game ( path ) ;
2016-04-25 19:16:58 +02:00
if ( result )
gFirstTimeSave = 1 ;
2016-04-25 15:38:44 +02:00
}
2015-07-05 06:36:25 +02:00
SDL_RWclose ( rw ) ;
2015-06-14 22:01:48 +02:00
2016-01-09 01:25:09 +01:00
if ( result ) {
2016-08-05 23:46:19 +02:00
if ( network_get_mode ( ) = = NETWORK_MODE_CLIENT ) {
network_close ( ) ;
}
2016-01-09 01:25:09 +01:00
game_load_init ( ) ;
if ( network_get_mode ( ) = = NETWORK_MODE_SERVER ) {
network_send_map ( ) ;
}
return true ;
} else {
2016-04-25 19:11:51 +02:00
// If loading the SV6 or SV4 failed, the current park state will be corrupted
2016-01-09 01:25:09 +01:00
// so just go back to the title screen.
title_load ( ) ;
return false ;
2015-07-30 00:30:05 +02:00
}
2015-07-05 17:19:01 +02:00
}
void game_load_init ( )
{
rct_window * mainWindow ;
2016-04-23 12:16:46 +02:00
gScreenFlags = SCREEN_FLAGS_PLAYING ;
2016-10-03 19:14:34 +02:00
audio_stop_all_music_and_sounds ( ) ;
2014-05-04 17:21:15 +02:00
viewport_init_all ( ) ;
game_create_windows ( ) ;
mainWindow = window_get_main ( ) ;
2014-07-23 19:07:38 +02:00
mainWindow - > viewport_target_sprite = - 1 ;
2016-04-25 22:37:48 +02:00
mainWindow - > saved_view_x = gSavedViewX ;
mainWindow - > saved_view_y = gSavedViewY ;
uint8 zoomDifference = gSavedViewZoom - mainWindow - > viewport - > zoom ;
mainWindow - > viewport - > zoom = gSavedViewZoom ;
gCurrentRotation = gSavedViewRotation ;
if ( zoomDifference ! = 0 ) {
if ( zoomDifference < 0 ) {
zoomDifference = - zoomDifference ;
mainWindow - > viewport - > view_width > > = zoomDifference ;
mainWindow - > viewport - > view_height > > = zoomDifference ;
2014-05-04 17:21:15 +02:00
} else {
2016-04-25 22:37:48 +02:00
mainWindow - > viewport - > view_width < < = zoomDifference ;
mainWindow - > viewport - > view_height < < = zoomDifference ;
2014-05-04 17:21:15 +02:00
}
}
mainWindow - > saved_view_x - = mainWindow - > viewport - > view_width > > 1 ;
mainWindow - > saved_view_y - = mainWindow - > viewport - > view_height > > 1 ;
window_invalidate ( mainWindow ) ;
2016-08-05 23:46:19 +02:00
if ( network_get_mode ( ) ! = NETWORK_MODE_CLIENT )
{
reset_sprite_spatial_index ( ) ;
}
2015-05-30 11:15:29 +02:00
reset_all_sprite_quadrant_placements ( ) ;
2015-03-29 03:29:07 +02:00
scenery_set_default_placement_configuration ( ) ;
2014-05-10 00:11:51 +02:00
window_new_ride_init_vars ( ) ;
2016-08-06 02:35:46 +02:00
gWindowUpdateTicks = 0 ;
2014-05-04 17:21:15 +02:00
2015-02-07 18:40:20 +01:00
load_palette ( ) ;
2014-05-04 17:21:15 +02:00
gfx_invalidate_screen ( ) ;
2015-07-30 00:30:05 +02:00
window_update_all ( ) ;
2015-02-22 19:24:19 +01:00
2015-06-25 17:19:23 +02:00
gGameSpeed = 1 ;
2014-05-04 17:21:15 +02:00
}
2015-12-11 16:38:37 +01:00
/**
2014-06-21 16:50:13 +02:00
*
2015-12-11 16:38:37 +01:00
* rct2 : 0x0069E9A7
2015-05-30 11:15:29 +02:00
* Call after a rotation or loading of a save to reset sprite quadrants
2014-06-21 16:50:13 +02:00
*/
2015-05-30 11:15:29 +02:00
void reset_all_sprite_quadrant_placements ( )
2014-11-24 00:03:45 +01:00
{
2016-05-09 01:08:03 +02:00
for ( size_t i = 0 ; i < MAX_SPRITES ; i + + ) {
2016-07-17 22:14:44 +02:00
rct_sprite * spr = get_sprite ( i ) ;
2016-05-09 01:08:03 +02:00
if ( spr - > unknown . sprite_identifier ! = SPRITE_IDENTIFIER_NULL ) {
2014-11-12 18:45:39 +01:00
sprite_move ( spr - > unknown . x , spr - > unknown . y , spr - > unknown . z , spr ) ;
2016-05-09 01:08:03 +02:00
}
}
2014-06-21 16:50:13 +02:00
}
2015-08-22 12:56:32 +02:00
void save_game ( )
2014-05-27 23:33:16 +02:00
{
2015-08-19 21:54:25 +02:00
if ( ! gFirstTimeSave ) {
2015-11-11 22:37:26 +01:00
log_verbose ( " Saving to %s " , gScenarioSavePath ) ;
2015-02-14 03:16:03 +01:00
2015-11-11 22:37:26 +01:00
SDL_RWops * rw = SDL_RWFromFile ( gScenarioSavePath , " wb+ " ) ;
2015-08-19 21:54:25 +02:00
if ( rw ! = NULL ) {
2016-04-15 22:22:23 +02:00
scenario_save ( rw , 0x80000000 | ( gConfigGeneral . save_plugin_data ? 1 : 0 ) ) ;
2015-11-11 22:37:26 +01:00
log_verbose ( " Saved to %s " , gScenarioSavePath ) ;
2015-08-19 21:54:25 +02:00
SDL_RWclose ( rw ) ;
2015-11-28 14:34:22 +01:00
// Setting screen age to zero, so no prompt will pop up when closing the
// game shortly after saving.
2016-04-23 12:16:46 +02:00
gScreenAge = 0 ;
2015-07-05 06:36:25 +02:00
}
2015-08-22 12:56:32 +02:00
} else {
2015-08-19 21:54:25 +02:00
save_game_as ( ) ;
}
}
2015-08-22 12:56:32 +02:00
void save_game_as ( )
2015-08-19 21:54:25 +02:00
{
2016-01-04 23:41:18 +01:00
char name [ MAX_PATH ] ;
2016-01-18 20:49:52 +01:00
safe_strcpy ( name , path_get_filename ( gScenarioSavePath ) , MAX_PATH ) ;
2016-01-04 23:41:18 +01:00
path_remove_extension ( name ) ;
window_loadsave_open ( LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME , name ) ;
2014-05-27 23:33:16 +02:00
}
2016-07-13 00:46:51 +02:00
static int compare_autosave_file_paths ( const void * a , const void * b ) {
2016-01-04 16:22:15 +01:00
return strcmp ( * ( char * * ) a , * ( char * * ) b ) ;
}
2016-07-13 00:46:51 +02:00
static void limit_autosave_count ( const size_t numberOfFilesToKeep )
2016-01-04 16:22:15 +01:00
{
int fileEnumHandle = 0 ;
size_t autosavesCount = 0 ;
size_t numAutosavesToDelete = 0 ;
file_info fileInfo ;
utf8 filter [ MAX_PATH ] ;
utf8 * * autosaveFiles = NULL ;
size_t i = 0 ;
2016-09-26 04:24:29 +02:00
platform_get_user_directory ( filter , " save " , sizeof ( filter ) ) ;
safe_strcat_path ( filter , " autosave_*.sv6 " , sizeof ( filter ) ) ;
2016-01-04 16:22:15 +01:00
// At first, count how many autosaves there are
fileEnumHandle = platform_enumerate_files_begin ( filter ) ;
while ( platform_enumerate_files_next ( fileEnumHandle , & fileInfo ) ) {
autosavesCount + + ;
}
platform_enumerate_files_end ( fileEnumHandle ) ;
// If there are fewer autosaves than the number of files to keep we don't need to delete anything
if ( autosavesCount < = numberOfFilesToKeep ) {
return ;
}
autosaveFiles = ( utf8 * * ) malloc ( sizeof ( utf8 * ) * autosavesCount ) ;
fileEnumHandle = platform_enumerate_files_begin ( filter ) ;
for ( i = 0 ; i < autosavesCount ; i + + ) {
autosaveFiles [ i ] = ( utf8 * ) malloc ( sizeof ( utf8 ) * MAX_PATH ) ;
memset ( autosaveFiles [ i ] , 0 , sizeof ( utf8 ) * MAX_PATH ) ;
if ( platform_enumerate_files_next ( fileEnumHandle , & fileInfo ) ) {
2016-09-26 04:24:29 +02:00
platform_get_user_directory ( autosaveFiles [ i ] , " save " , sizeof ( utf8 ) * MAX_PATH ) ;
safe_strcat_path ( autosaveFiles [ i ] , fileInfo . path , sizeof ( utf8 ) * MAX_PATH ) ;
2016-01-04 16:22:15 +01:00
}
}
platform_enumerate_files_end ( fileEnumHandle ) ;
qsort ( autosaveFiles , autosavesCount , sizeof ( char * ) , compare_autosave_file_paths ) ;
// calculate how many saves we need to delete.
numAutosavesToDelete = autosavesCount - numberOfFilesToKeep ;
i = 0 ;
while ( numAutosavesToDelete > 0 ) {
platform_file_delete ( autosaveFiles [ i ] ) ;
i + + ;
numAutosavesToDelete - - ;
}
for ( i = 0 ; i < autosavesCount ; i + + ) {
free ( autosaveFiles [ i ] ) ;
}
free ( autosaveFiles ) ;
}
2015-08-19 21:54:25 +02:00
2015-02-21 12:05:15 +01:00
void game_autosave ( )
{
2015-08-04 22:41:45 +02:00
utf8 path [ MAX_PATH ] ;
utf8 backupPath [ MAX_PATH ] ;
2016-09-26 04:24:29 +02:00
utf8 timeName [ 34 ] ;
2016-07-23 23:25:13 +02:00
// retrieve current time
rct2_date currentDate ;
platform_get_date_local ( & currentDate ) ;
rct2_time currentTime ;
platform_get_time_local ( & currentTime ) ;
2016-09-26 04:24:29 +02:00
snprintf ( timeName , 34 , " autosave_%d-%02d-%02d_%02d-%02d-%02d.sv6 " , currentDate . year , currentDate . month , currentDate . day , currentTime . hour , currentTime . minute , currentTime . second ) ;
2016-01-04 16:22:15 +01:00
limit_autosave_count ( NUMBER_OF_AUTOSAVES_TO_KEEP ) ;
2016-07-23 23:25:13 +02:00
2016-09-26 04:24:29 +02:00
platform_get_user_directory ( path , " save " , sizeof ( path ) ) ;
safe_strcpy ( backupPath , path , sizeof ( backupPath ) ) ;
2015-08-04 22:41:45 +02:00
2016-09-26 04:24:29 +02:00
safe_strcat_path ( path , timeName , sizeof ( path ) ) ;
safe_strcat_path ( backupPath , " autosave.sv6.bak " , sizeof ( backupPath ) ) ;
2015-08-04 22:41:45 +02:00
if ( platform_file_exists ( path ) ) {
platform_file_copy ( path , backupPath , true ) ;
}
2015-02-21 12:05:15 +01:00
2015-08-29 14:12:52 +02:00
SDL_RWops * rw = SDL_RWFromFile ( path , " wb+ " ) ;
2015-07-05 06:36:25 +02:00
if ( rw ! = NULL ) {
scenario_save ( rw , 0x80000000 ) ;
SDL_RWclose ( rw ) ;
}
2015-02-21 12:05:15 +01:00
}
2015-03-07 12:13:10 +01:00
/**
*
* rct2 : 0x006E3838
*/
void rct2_exit_reason ( rct_string_id title , rct_string_id body ) {
// Before this would set a quit message
char exit_title [ 255 ] ;
2016-09-26 04:24:29 +02:00
format_string ( exit_title , 256 , title , 0 ) ;
2015-03-07 12:13:10 +01:00
char exit_body [ 255 ] ;
2016-09-26 04:24:29 +02:00
format_string ( exit_body , 256 , body , 0 ) ;
2015-03-07 12:13:10 +01:00
log_error ( exit_title ) ;
log_error ( exit_body ) ;
rct2_exit ( ) ;
}
2014-05-02 23:21:08 +02:00
/**
2015-10-09 18:22:37 +02:00
*
2014-05-02 23:21:08 +02:00
* rct2 : 0x006E3879
*/
2014-07-16 22:39:39 +02:00
void rct2_exit ( )
2014-05-02 23:21:08 +02:00
{
2015-05-21 04:11:53 +02:00
openrct2_finish ( ) ;
2014-05-02 23:21:08 +02:00
}
/**
2015-10-09 18:22:37 +02:00
*
2014-05-02 23:21:08 +02:00
* rct2 : 0x0066DB79
*/
void game_load_or_quit_no_save_prompt ( )
{
2016-04-23 12:16:46 +02:00
switch ( gSavePromptMode ) {
case PM_SAVE_BEFORE_LOAD :
2014-08-06 21:06:51 +02:00
game_do_command ( 0 , 1 , 0 , 1 , GAME_COMMAND_LOAD_OR_QUIT , 0 , 0 ) ;
2014-05-02 23:38:16 +02:00
tool_cancel ( ) ;
2016-04-23 12:16:46 +02:00
if ( gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR ) {
2014-05-02 23:21:08 +02:00
load_landscape ( ) ;
2016-01-09 01:25:09 +01:00
} else {
window_loadsave_open ( LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME , NULL ) ;
}
2016-04-23 12:16:46 +02:00
break ;
case PM_SAVE_BEFORE_QUIT :
2014-08-06 21:06:51 +02:00
game_do_command ( 0 , 1 , 0 , 1 , GAME_COMMAND_LOAD_OR_QUIT , 0 , 0 ) ;
2015-05-20 20:18:54 +02:00
tool_cancel ( ) ;
2016-01-04 23:53:03 +01:00
if ( gInputFlags & INPUT_FLAG_5 ) {
gInputFlags & = ~ INPUT_FLAG_5 ;
2014-05-02 23:21:08 +02:00
}
2015-05-19 00:15:43 +02:00
gGameSpeed = 1 ;
2016-09-14 00:53:46 +02:00
gFirstTimeSave = 1 ;
2014-05-02 23:21:08 +02:00
title_load ( ) ;
2016-04-23 12:16:46 +02:00
break ;
default :
2014-05-02 23:21:08 +02:00
rct2_exit ( ) ;
2016-04-23 12:16:46 +02:00
break ;
2014-05-02 23:21:08 +02:00
}
}
2016-05-31 09:06:07 +02:00
GAME_COMMAND_POINTER * new_game_command_table [ 68 ] = {
2015-04-16 18:47:05 +02:00
game_command_set_ride_appearance ,
2015-07-12 02:46:52 +02:00
game_command_set_land_height ,
2015-02-08 16:37:33 +01:00
game_pause_toggle ,
2015-06-27 18:53:28 +02:00
game_command_place_track ,
game_command_remove_track ,
2015-02-08 16:37:33 +01:00
game_load_or_quit ,
2015-07-16 02:38:18 +02:00
game_command_create_ride ,
2015-04-11 08:31:09 +02:00
game_command_demolish_ride ,
2015-01-29 01:16:34 +01:00
game_command_set_ride_status ,
2015-06-29 17:14:56 +02:00
game_command_set_ride_vehicles ,
2015-10-10 21:26:17 +02:00
game_command_set_ride_name ,
2015-03-20 23:33:06 +01:00
game_command_set_ride_setting ,
2015-07-08 21:12:17 +02:00
game_command_place_ride_entrance_or_exit ,
2015-07-08 21:47:27 +02:00
game_command_remove_ride_entrance_or_exit ,
2015-04-16 04:02:47 +02:00
game_command_remove_scenery ,
2015-05-12 21:08:36 +02:00
game_command_place_scenery ,
2015-06-29 19:39:10 +02:00
game_command_set_water_height ,
2014-12-18 23:31:05 +01:00
game_command_place_footpath ,
2015-09-30 00:07:07 +02:00
game_command_place_footpath_from_track ,
2014-12-18 23:31:05 +01:00
game_command_remove_footpath ,
2015-10-10 21:26:17 +02:00
game_command_change_surface_style ,
2015-06-09 03:28:07 +02:00
game_command_set_ride_price ,
2016-04-28 20:09:05 +02:00
game_command_set_guest_name ,
2016-04-23 06:35:57 +02:00
game_command_set_staff_name ,
2015-04-14 23:17:19 +02:00
game_command_raise_land ,
game_command_lower_land ,
2015-10-10 21:26:17 +02:00
game_command_smooth_land ,
2015-04-15 21:19:02 +02:00
game_command_raise_water ,
game_command_lower_water ,
2015-06-28 12:44:34 +02:00
game_command_set_brakes_speed ,
2015-10-10 21:26:17 +02:00
game_command_hire_new_staff_member ,
game_command_set_staff_patrol ,
2015-04-12 22:24:43 +02:00
game_command_fire_staff_member ,
2015-04-12 20:27:39 +02:00
game_command_set_staff_order ,
2015-01-27 22:18:30 +01:00
game_command_set_park_name ,
2015-01-25 01:20:53 +01:00
game_command_set_park_open ,
2015-10-10 21:26:17 +02:00
game_command_buy_land_rights ,
2015-10-01 22:24:24 +02:00
game_command_place_park_entrance ,
2015-01-27 22:18:30 +01:00
game_command_remove_park_entrance ,
2015-10-10 21:26:17 +02:00
game_command_set_maze_track ,
2015-02-08 15:31:37 +01:00
game_command_set_park_entrance_fee ,
2015-10-10 21:26:17 +02:00
game_command_update_staff_colour ,
2015-06-20 01:05:30 +02:00
game_command_place_fence ,
2015-04-16 01:17:43 +02:00
game_command_remove_fence ,
2015-06-14 13:56:12 +02:00
game_command_place_large_scenery ,
2015-04-17 08:47:23 +02:00
game_command_remove_large_scenery ,
2015-01-24 20:07:35 +01:00
game_command_set_current_loan ,
2015-01-24 19:41:55 +01:00
game_command_set_research_funding ,
2015-06-27 18:53:28 +02:00
game_command_place_track_design ,
2015-01-24 19:22:06 +01:00
game_command_start_campaign ,
2015-10-10 21:26:17 +02:00
game_command_place_maze_design ,
game_command_place_banner ,
2015-04-22 09:46:44 +02:00
game_command_remove_banner ,
2015-04-17 22:56:19 +02:00
game_command_set_scenery_colour ,
2015-04-18 07:01:50 +02:00
game_command_set_fence_colour ,
2015-04-18 21:03:18 +02:00
game_command_set_large_scenery_colour ,
2015-04-18 23:48:17 +02:00
game_command_set_banner_colour ,
2015-10-04 01:07:22 +02:00
game_command_set_land_ownership ,
2015-10-31 09:25:43 +01:00
game_command_clear_scenery ,
game_command_set_banner_name ,
game_command_set_sign_name ,
game_command_set_banner_style ,
2016-01-20 23:45:09 +01:00
game_command_set_sign_style ,
2016-01-22 04:32:51 +01:00
game_command_set_player_group ,
2016-01-22 07:32:40 +01:00
game_command_modify_groups ,
2016-02-02 01:04:39 +01:00
game_command_kick_player ,
2016-05-31 09:06:07 +02:00
game_command_cheat ,
2014-08-10 14:31:41 +02:00
} ;