2014-04-02 01:31:55 +02:00
/*****************************************************************************
2014-05-09 09:47:20 +02:00
* Copyright ( c ) 2014 Ted John , Peter Hill
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
*
2014-04-02 01:31:55 +02:00
* This file is part of 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 .
* 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/>.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2015-10-09 18:22:37 +02:00
2014-04-02 01:31:55 +02:00
# include "addresses.h"
2014-10-06 18:36:58 +02:00
# include "audio/audio.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"
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"
2014-05-01 19:15:02 +02:00
# include "scenario.h"
2014-05-02 23:21:08 +02:00
# include "title.h"
2014-04-26 02:16:32 +02:00
# include "tutorial.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"
2014-07-16 04:41:12 +02:00
2014-08-24 19:45:47 +02:00
int gGameSpeed = 1 ;
2015-07-24 23:58:41 +02:00
float gDayNightCycle = 0 ;
2014-07-26 11:30:55 +02:00
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 ,
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 ( ) ;
2015-06-09 19:29:02 +02:00
window_resize_gui ( RCT2_GLOBAL ( RCT2_ADDRESS_SCREEN_WIDTH , uint16 ) , RCT2_GLOBAL ( RCT2_ADDRESS_SCREEN_HEIGHT , uint16 ) ) ;
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 ] ;
2014-09-23 21:33:55 +02:00
if ( RCT2_GLOBAL ( RCT2_ADDRESS_LIGHTNING_ACTIVE , uint8 ) = = 1 ) {
// change palette to lighter color during lightning
int palette = 1532 ;
2015-03-01 22:06:51 +01:00
if ( ( sint32 ) water_type ! = - 1 ) {
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 ;
for ( int i = 0 ; i < g1_element . width ; i + + ) {
2015-10-09 18:22:37 +02:00
RCT2_ADDRESS ( RCT2_ADDRESS_PALETTE + xoffset , uint8 ) [ ( i * 4 ) + 0 ] = - ( ( 0xFF - g1_element . offset [ ( i * 3 ) + 0 ] ) / 2 ) - 1 ;
RCT2_ADDRESS ( RCT2_ADDRESS_PALETTE + xoffset , uint8 ) [ ( i * 4 ) + 1 ] = - ( ( 0xFF - g1_element . offset [ ( i * 3 ) + 1 ] ) / 2 ) - 1 ;
RCT2_ADDRESS ( RCT2_ADDRESS_PALETTE + xoffset , uint8 ) [ ( i * 4 ) + 2 ] = - ( ( 0xFF - g1_element . offset [ ( i * 3 ) + 2 ] ) / 2 ) - 1 ;
2014-07-20 08:46:29 +02:00
}
2014-09-23 21:33:55 +02:00
RCT2_GLOBAL ( 0x014241BC , uint32 ) = 2 ;
2015-10-09 18:22:37 +02:00
platform_update_palette ( RCT2_ADDRESS ( RCT2_ADDRESS_PALETTE , uint8 ) , 10 , 236 ) ;
2014-09-23 21:33:55 +02:00
RCT2_GLOBAL ( 0x014241BC , uint32 ) = 0 ;
RCT2_GLOBAL ( RCT2_ADDRESS_LIGHTNING_ACTIVE , uint8 ) + + ;
} else {
if ( RCT2_GLOBAL ( RCT2_ADDRESS_LIGHTNING_ACTIVE , uint8 ) = = 2 ) {
// change palette back to normal after lightning
int palette = 1532 ;
2015-03-01 22:06:51 +01:00
if ( ( sint32 ) water_type ! = - 1 ) {
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 ;
for ( int i = 0 ; i < g1_element . width ; i + + ) {
2015-10-09 18:22:37 +02:00
RCT2_ADDRESS ( RCT2_ADDRESS_PALETTE + xoffset , uint8 ) [ ( i * 4 ) + 0 ] = g1_element . offset [ ( i * 3 ) + 0 ] ;
RCT2_ADDRESS ( RCT2_ADDRESS_PALETTE + xoffset , uint8 ) [ ( i * 4 ) + 1 ] = g1_element . offset [ ( i * 3 ) + 1 ] ;
RCT2_ADDRESS ( RCT2_ADDRESS_PALETTE + xoffset , uint8 ) [ ( 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 ;
int weather_colour = RCT2_ADDRESS ( 0x98195C , uint32 ) [ RCT2_GLOBAL ( RCT2_ADDRESS_CURRENT_WEATHER_GLOOM , uint8 ) ] ;
if ( weather_colour ! = - 1 ) {
q = 1 ;
if ( weather_colour ! = 0x2000031 ) {
q = 2 ;
}
}
2015-02-07 18:40:20 +01:00
uint32 j = RCT2_GLOBAL ( RCT2_ADDRESS_PALETTE_EFFECT_FRAME_NO , uint32 ) ;
2014-09-23 21:33:55 +02:00
j = ( ( ( uint16 ) ( ( ~ j / 2 ) * 128 ) * 15 ) > > 16 ) ;
int p = 1533 ;
2015-03-01 22:06:51 +01:00
if ( ( sint32 ) water_type ! = - 1 ) {
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 ] ;
uint8 * vd = RCT2_ADDRESS ( 0x01424A18 , uint8 ) ;
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 ;
2015-03-01 22:06:51 +01:00
if ( ( sint32 ) water_type ! = - 1 ) {
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
2015-02-07 18:40:20 +01:00
j = ( ( uint16 ) ( RCT2_GLOBAL ( RCT2_ADDRESS_PALETTE_EFFECT_FRAME_NO , uint32 ) * - 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
2014-09-23 21:33:55 +02:00
RCT2_GLOBAL ( 0x014241BC , uint32 ) = 2 ;
2015-10-09 18:22:37 +02:00
platform_update_palette ( RCT2_ADDRESS ( RCT2_ADDRESS_PALETTE , uint8 ) , 230 , 16 ) ;
2014-09-23 21:33:55 +02:00
RCT2_GLOBAL ( 0x014241BC , uint32 ) = 0 ;
if ( RCT2_GLOBAL ( RCT2_ADDRESS_LIGHTNING_ACTIVE , uint8 ) = = 2 ) {
RCT2_GLOBAL ( 0x014241BC , uint32 ) = 2 ;
2015-10-09 18:22:37 +02:00
platform_update_palette ( RCT2_ADDRESS ( RCT2_ADDRESS_PALETTE , uint8 ) , 10 , 236 ) ;
2014-09-23 21:33:55 +02:00
RCT2_GLOBAL ( 0x014241BC , uint32 ) = 0 ;
RCT2_GLOBAL ( RCT2_ADDRESS_LIGHTNING_ACTIVE , uint8 ) = 0 ;
}
2014-07-20 08:46:29 +02:00
}
2014-09-23 21:33:55 +02:00
if ( RCT2_GLOBAL ( 0x009E2C4C , uint32 ) = = 2 | | RCT2_GLOBAL ( 0x009E2C4C , uint32 ) = = 1 ) {
if ( RCT2_GLOBAL ( RCT2_ADDRESS_SCREEN_CAP_BPP , uint32 ) ! = 8 ) {
RCT2_GLOBAL ( 0x009E2C78 , int ) = 1 ;
}
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 {
2015-10-03 20:00:29 +02:00
numUpdates = RCT2_GLOBAL ( RCT2_ADDRESS_TICKS_SINCE_LAST_UPDATE , uint16 ) / 31 ;
2014-10-15 23:59:26 +02:00
numUpdates = clamp ( 1 , numUpdates , 4 ) ;
}
2014-04-02 01:31:55 +02:00
2015-10-27 04:43:33 +01:00
if ( network_get_mode ( ) = = NETWORK_MODE_CLIENT & & network_get_status ( ) = = NETWORK_STATUS_CONNECTED ) {
2015-07-10 21:53:41 +02:00
if ( network_get_server_tick ( ) - RCT2_GLOBAL ( RCT2_ADDRESS_CURRENT_TICKS , uint32 ) > = 10 ) {
2015-07-05 17:19:01 +02:00
// make sure client doesn't fall behind the server too much
numUpdates + = 10 ;
}
2015-08-16 00:19:15 +02:00
} else {
if ( RCT2_GLOBAL ( RCT2_ADDRESS_GAME_PAUSED , uint8 ) ! = 0 ) {
numUpdates = 0 ;
}
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 ( ) ;
start_title_music ( ) ;
if ( gGameSpeed > 1 )
continue ;
// Possibly smooths viewport scrolling, I don't see a difference though
if ( RCT2_GLOBAL ( 0x009E2D74 , uint32 ) = = 1 ) {
RCT2_GLOBAL ( 0x009E2D74 , uint32 ) = 0 ;
break ;
} else {
if ( RCT2_GLOBAL ( RCT2_ADDRESS_INPUT_STATE , uint8 ) = = INPUT_STATE_RESET | |
RCT2_GLOBAL ( RCT2_ADDRESS_INPUT_STATE , uint8 ) = = INPUT_STATE_NORMAL
) {
if ( RCT2_GLOBAL ( RCT2_ADDRESS_INPUT_FLAGS , uint32 ) & INPUT_FLAG_VIEWPORT_SCROLLING ) {
RCT2_GLOBAL ( RCT2_ADDRESS_INPUT_FLAGS , uint32 ) & = ~ INPUT_FLAG_VIEWPORT_SCROLLING ;
2014-10-15 23:59:26 +02:00
break ;
}
2015-08-16 00:19:15 +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
news_item_update_current ( ) ;
window_dispatch_update_all ( ) ;
2014-11-18 21:33:21 +01:00
RCT2_GLOBAL ( 0x009A8C28 , uint8 ) = 0 ;
2014-04-02 01:31:55 +02:00
2014-10-15 23:59:26 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_INPUT_FLAGS , uint32 ) & = ~ 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
2015-07-05 17:19:01 +02:00
if ( RCT2_GLOBAL ( RCT2_ADDRESS_CURRENT_TICKS , uint32 ) % 4 = = 0 )
2015-02-16 22:19:19 +01:00
RCT2_GLOBAL ( RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS , uint16 ) ^ = ( 1 < < 15 ) ;
2015-02-16 14:27:31 +01:00
// Handle guest map flashing
RCT2_GLOBAL ( RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS , uint16 ) & = ~ ( 1 < < 1 ) ;
if ( RCT2_GLOBAL ( RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS , uint16 ) & ( 1 < < 0 ) )
RCT2_GLOBAL ( RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS , uint16 ) | = ( 1 < < 1 ) ;
RCT2_GLOBAL ( RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS , uint16 ) & = ~ ( 1 < < 0 ) ;
// Handle staff map flashing
RCT2_GLOBAL ( RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS , uint16 ) & = ~ ( 1 < < 3 ) ;
if ( RCT2_GLOBAL ( RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS , uint16 ) & ( 1 < < 2 ) )
RCT2_GLOBAL ( RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS , uint16 ) | = ( 1 < < 3 ) ;
RCT2_GLOBAL ( RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS , uint16 ) & = ~ ( 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
2014-04-13 23:23:56 +02:00
RCT2_GLOBAL ( 0x0141F568 , uint8 ) = RCT2_GLOBAL ( 0x0013CA740 , uint8 ) ;
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-08-20 04:34:52 +02:00
network_update ( ) ;
2015-10-27 04:43:33 +01:00
if ( network_get_mode ( ) = = NETWORK_MODE_CLIENT & & network_get_status ( ) = = NETWORK_STATUS_CONNECTED ) {
2015-08-20 03:07:11 +02:00
if ( RCT2_GLOBAL ( RCT2_ADDRESS_CURRENT_TICKS , uint32 ) > = network_get_server_tick ( ) ) {
// dont run past the server
return ;
}
}
2015-07-05 17:19:01 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_CURRENT_TICKS , uint32 ) + + ;
RCT2_GLOBAL ( RCT2_ADDRESS_SCENARIO_TICKS , uint32 ) + + ;
2015-08-16 19:05:49 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_SCREEN_AGE , sint16 ) + + ;
if ( RCT2_GLOBAL ( RCT2_ADDRESS_SCREEN_AGE , sint16 ) = = 0 )
RCT2_GLOBAL ( RCT2_ADDRESS_SCREEN_AGE , sint16 ) - - ;
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 ( ) ;
2014-10-09 21:31:58 +02:00
sub_6A876D ( ) ;
2014-04-03 01:22:33 +02:00
peep_update_all ( ) ;
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 ( ) ;
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
2015-08-16 19:05:49 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_SAVED_AGE , uint16 ) + + ;
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
2015-03-07 13:45:13 +01:00
if ( RCT2_GLOBAL ( RCT2_ADDRESS_ERROR_TYPE , uint8 ) ! = 0 ) {
rct_string_id title_text = STR_UNABLE_TO_LOAD_FILE ;
rct_string_id body_text = RCT2_GLOBAL ( RCT2_ADDRESS_ERROR_STRING_ID , uint16 ) ;
if ( RCT2_GLOBAL ( RCT2_ADDRESS_ERROR_TYPE , uint8 ) = = 254 ) {
title_text = RCT2_GLOBAL ( RCT2_ADDRESS_ERROR_STRING_ID , uint16 ) ;
body_text = 0xFFFF ;
2014-04-02 01:31:55 +02:00
}
2015-03-07 13:45:13 +01:00
RCT2_GLOBAL ( RCT2_ADDRESS_ERROR_TYPE , uint8 ) = 0 ;
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 ;
if ( RCT2_GLOBAL ( 0x141F568 , uint8 ) & 0xF0 ) return cost ;
2015-08-16 19:05:49 +02:00
2014-07-14 20:46:45 +02:00
if ( ! ( RCT2_GLOBAL ( RCT2_ADDRESS_PARK_FLAGS , uint32 ) & ( 1 < < 8 ) ) ) {
if ( cost < = ( sint32 ) ( DECRYPT_MONEY ( RCT2_GLOBAL ( RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED , sint32 ) ) ) ) return cost ;
}
2015-08-16 19:05:49 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_COMMON_FORMAT_ARGS , uint32 ) = cost ;
2014-07-14 20:46:45 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT , uint16 ) = 827 ;
2015-04-16 01:30:18 +02:00
return MONEY32_UNDEFINED ;
2014-05-02 03:12:14 +02:00
}
2015-10-31 09:25:43 +01:00
static GAME_COMMAND_POINTER * new_game_command_table [ 62 ] ;
2014-05-02 23:21:08 +02:00
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 ;
flags = * ebx ;
RCT2_GLOBAL ( RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT , uint16 ) = 0xFFFF ;
// Increment nest count
RCT2_GLOBAL ( 0x009A8C28 , uint8 ) + + ;
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 ( ) ;
}
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 ;
2015-07-24 01:22:03 +02:00
if ( RCT2_GLOBAL ( 0x009A8C28 , uint8 ) = = 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
RCT2_GLOBAL ( 0x009A8C28 , uint8 ) - - ;
return cost ;
}
2015-08-20 04:34:52 +02:00
if ( network_get_mode ( ) ! = NETWORK_MODE_NONE & & ! ( flags & GAME_COMMAND_FLAG_NETWORKED ) & & ! ( flags & GAME_COMMAND_FLAG_GHOST ) & & ! ( flags & GAME_COMMAND_FLAG_5 ) & & RCT2_GLOBAL ( 0x009A8C28 , uint8 ) = = 1 /* Send only top-level commands */ ) {
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
RCT2_GLOBAL ( 0x009A8C28 , uint8 ) - - ;
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
if ( game_command_callback ) {
game_command_callback ( * eax , * ebx , * ecx , * edx , * esi , * edi , * ebp ) ;
game_command_callback = 0 ;
}
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
RCT2_GLOBAL ( 0x009A8C28 , uint8 ) - - ;
if ( RCT2_GLOBAL ( 0x009A8C28 , uint8 ) ! = 0 )
return cost ;
2015-10-09 18:22:37 +02:00
//
2014-08-05 19:15:28 +02:00
if ( ! ( flags & 0x20 ) ) {
// Update money balance
2015-02-08 15:31:37 +01:00
finance_payment ( cost , RCT2_GLOBAL ( RCT2_ADDRESS_NEXT_EXPENDITURE_TYPE , uint8 ) / 4 ) ;
2014-08-05 19:15:28 +02:00
if ( RCT2_GLOBAL ( 0x0141F568 , uint8 ) = = RCT2_GLOBAL ( 0x013CA740 , uint8 ) ) {
// 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
}
}
return cost ;
}
}
// Error occured
// Decrement nest count
RCT2_GLOBAL ( 0x009A8C28 , uint8 ) - - ;
// Show error window
2015-07-27 04:15:02 +02:00
if ( RCT2_GLOBAL ( 0x009A8C28 , uint8 ) = = 0 & & ( flags & GAME_COMMAND_FLAG_APPLY ) & & RCT2_GLOBAL ( 0x0141F568 , uint8 ) = = RCT2_GLOBAL ( 0x013CA740 , uint8 ) & & ! ( flags & GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED ) )
2014-08-05 19:15:28 +02:00
window_error_open ( RCT2_GLOBAL ( RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE , uint16 ) , RCT2_GLOBAL ( RCT2_ADDRESS_GAME_COMMAND_ERROR_TEXT , uint16 ) ) ;
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 ( )
{
RCT2_GLOBAL ( RCT2_ADDRESS_GAME_PAUSED , uint32 ) ^ = 1 ;
window_invalidate_by_class ( WC_TOP_TOOLBAR ) ;
2015-10-16 10:25:56 +02:00
if ( RCT2_GLOBAL ( RCT2_ADDRESS_GAME_PAUSED , uint32 ) & 1 ) {
2015-03-31 03:21:30 +02:00
pause_sounds ( ) ;
unpause_sounds ( ) ;
2015-10-16 10:25:56 +02:00
} else {
unpause_sounds ( ) ;
}
2015-03-31 03:21:30 +02:00
}
2014-08-05 19:15:28 +02:00
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 :
RCT2_GLOBAL ( RCT2_ADDRESS_SAVE_PROMPT_MODE , uint16 ) = * edi & 0xFF ;
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 : 0x00674F40
*/
static int open_landscape_file_dialog ( )
{
2014-05-12 03:18:08 +02:00
int result ;
2014-07-18 22:03:33 +02:00
format_string ( ( char * ) RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER , STR_LOAD_LANDSCAPE_DIALOG_TITLE , 0 ) ;
2015-10-30 15:18:29 +01:00
safe_strncpy ( ( char * ) 0x0141EF68 , ( char * ) RCT2_ADDRESS_LANDSCAPES_PATH , MAX_PATH ) ;
2014-05-12 02:45:45 +02:00
format_string ( ( char * ) 0x0141EE68 , STR_RCT2_LANDSCAPE_FILE , 0 ) ;
2014-05-06 23:04:09 +02:00
pause_sounds ( ) ;
2015-02-12 21:51:40 +01:00
result = platform_open_common_file_dialog ( 1 , ( char * ) RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER , ( char * ) 0x0141EF68 , " *.SV6;*.SV4;*.SC6 " , ( char * ) 0x0141EE68 ) ;
2014-05-06 23:04:09 +02:00
unpause_sounds ( ) ;
2014-05-03 11:27:48 +02:00
// window_proc
2014-05-12 03:18:08 +02:00
return result ;
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 : 0x00674EB6
*/
static int open_load_game_dialog ( )
{
2014-05-07 23:11:23 +02:00
int result ;
2014-07-18 22:03:33 +02:00
format_string ( ( char * ) RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER , STR_LOAD_GAME_DIALOG_TITLE , 0 ) ;
2015-10-30 15:18:29 +01:00
safe_strncpy ( ( char * ) 0x0141EF68 , ( char * ) RCT2_ADDRESS_SAVED_GAMES_PATH , MAX_PATH ) ;
2014-05-12 02:45:45 +02:00
format_string ( ( char * ) 0x0141EE68 , STR_RCT2_SAVED_GAME , 0 ) ;
2014-05-06 23:04:09 +02:00
pause_sounds ( ) ;
2015-02-12 21:51:40 +01:00
result = platform_open_common_file_dialog ( 1 , ( char * ) RCT2_ADDRESS_COMMON_STRING_FORMAT_BUFFER , ( char * ) 0x0141EF68 , " *.SV6 " , ( char * ) 0x0141EE68 ) ;
2014-05-06 23:04:09 +02:00
unpause_sounds ( ) ;
2014-05-03 11:27:48 +02:00
// window_proc
2014-05-07 23:11:23 +02:00
return result ;
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 ) ;
2015-02-14 03:16:03 +01:00
return ;
2014-05-02 23:21:08 +02:00
if ( open_landscape_file_dialog ( ) = = 0 ) {
gfx_invalidate_screen ( ) ;
2014-11-24 03:58:48 +01:00
} else {
2014-05-03 03:33:01 +02:00
// Set default filename
2014-05-12 02:45:45 +02:00
char * esi = ( char * ) 0x0141EF67 ;
2014-05-03 03:33:01 +02:00
while ( 1 ) {
esi + + ;
if ( * esi = = ' . ' )
break ;
if ( * esi ! = 0 )
continue ;
strcpy ( esi , " .SC6 " ) ;
break ;
}
2015-10-30 15:18:29 +01:00
safe_strncpy ( ( char * ) RCT2_ADDRESS_SAVED_GAMES_PATH_2 , ( char * ) 0x0141EF68 , MAX_PATH ) ;
2014-05-02 23:21:08 +02:00
2014-11-24 03:58:48 +01:00
editor_load_landscape ( ( char * ) 0x0141EF68 ) ;
2014-05-02 23:21:08 +02:00
if ( 1 ) {
gfx_invalidate_screen ( ) ;
2014-05-03 21:39:34 +02:00
rct2_endupdate ( ) ;
2014-11-24 03:58:48 +01:00
} else {
2015-08-16 19:05:49 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_SCREEN_AGE , uint16 ) = 0 ;
2014-05-03 21:39:34 +02:00
rct2_endupdate ( ) ;
2014-05-02 23:21:08 +02: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 ( )
{
utf8 buffer [ 512 ] ;
// 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 ) ) {
rct2_to_utf8 ( buffer , userString ) ;
memcpy ( userString , buffer , 31 ) ;
userString [ 31 ] = 0 ;
}
}
// 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 ) ) {
rct2_to_utf8 ( buffer , newsItem - > text ) ;
memcpy ( newsItem - > text , buffer , 255 ) ;
newsItem - > text [ 255 ] = 0 ;
}
}
}
/**
* Converts all the user strings and news item strings to RCT2 encoding .
*/
void game_convert_strings_to_rct2 ( rct_s6_data * s6 )
{
char buffer [ 512 ] ;
// 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 ) ) {
utf8_to_rct2 ( buffer , userString ) ;
memcpy ( userString , buffer , 31 ) ;
userString [ 31 ] = 0 ;
}
}
// 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 ) ) {
utf8_to_rct2 ( buffer , newsItem - > text ) ;
memcpy ( newsItem - > text , buffer , 255 ) ;
newsItem - > text [ 255 ] = 0 ;
}
}
}
2014-05-04 17:21:15 +02:00
/**
2015-10-09 18:22:37 +02:00
*
2014-05-04 17:21:15 +02:00
* rct2 : 0x00675E1B
*/
2015-07-05 06:36:25 +02:00
int game_load_sv6 ( SDL_RWops * rw )
2014-05-04 17:21:15 +02:00
{
int i , j ;
2015-07-05 06:36:25 +02:00
if ( ! sawyercoding_validate_checksum ( rw ) ) {
log_error ( " invalid checksum " ) ;
2014-11-26 01:51:26 +01:00
2015-03-07 13:45:13 +01:00
RCT2_GLOBAL ( RCT2_ADDRESS_ERROR_TYPE , uint8 ) = 255 ;
2015-08-27 16:44:18 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE , uint16 ) = STR_FILE_CONTAINS_INVALID_DATA ;
2014-05-04 18:34:13 +02:00
return 0 ;
}
2014-05-04 17:21:15 +02:00
2014-05-12 02:45:45 +02:00
rct_s6_header * s6Header = ( rct_s6_header * ) 0x009E34E4 ;
rct_s6_info * s6Info = ( rct_s6_info * ) 0x0141F570 ;
2014-05-04 17:21:15 +02:00
// Read first chunk
2015-07-05 06:36:25 +02:00
sawyercoding_read_chunk ( rw , ( uint8 * ) s6Header ) ;
2014-05-04 17:21:15 +02:00
if ( s6Header - > type = = S6_TYPE_SAVEDGAME ) {
// Read packed objects
if ( s6Header - > num_packed_objects > 0 ) {
j = 0 ;
for ( i = 0 ; i < s6Header - > num_packed_objects ; i + + )
2015-07-05 06:36:25 +02:00
j + = object_load_packed ( rw ) ;
2014-05-04 17:21:15 +02:00
if ( j > 0 )
2014-05-24 02:34:17 +02:00
object_list_load ( ) ;
2014-05-04 17:21:15 +02:00
}
}
2015-07-05 06:36:25 +02:00
uint8 load_success = object_read_and_load_entries ( rw ) ;
2014-05-04 17:21:15 +02:00
// Read flags (16 bytes)
2015-07-05 06:36:25 +02:00
sawyercoding_read_chunk ( rw , ( uint8 * ) RCT2_ADDRESS_CURRENT_MONTH_YEAR ) ;
2014-05-04 17:21:15 +02:00
// Read map elements
2014-05-12 02:45:45 +02:00
memset ( ( void * ) RCT2_ADDRESS_MAP_ELEMENTS , 0 , MAX_MAP_ELEMENTS * sizeof ( rct_map_element ) ) ;
2015-07-05 06:36:25 +02:00
sawyercoding_read_chunk ( rw , ( uint8 * ) RCT2_ADDRESS_MAP_ELEMENTS ) ;
2014-05-04 17:21:15 +02:00
// Read game data, including sprites
2015-07-05 06:36:25 +02:00
sawyercoding_read_chunk ( rw , ( uint8 * ) 0x010E63B8 ) ;
2014-05-04 17:21:15 +02:00
2014-11-19 22:46:32 +01:00
if ( ! load_success ) {
2014-11-20 19:40:10 +01:00
set_load_objects_fail_reason ( ) ;
2015-05-07 20:31:11 +02:00
if ( RCT2_GLOBAL ( RCT2_ADDRESS_INPUT_FLAGS , uint32 ) & INPUT_FLAG_5 ) {
2014-11-20 13:52:42 +01:00
//call 0x0040705E Sets cursor position and something else. Calls maybe wind func 8 probably pointless
RCT2_GLOBAL ( 0x14241BC , uint32 ) = 0 ;
2015-05-07 20:31:11 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_INPUT_FLAGS , uint32 ) & = ~ INPUT_FLAG_5 ;
2014-11-20 13:52:42 +01:00
}
2015-06-14 22:01:48 +02:00
2014-11-20 20:02:27 +01:00
return 0 ; //This never gets called
2014-11-19 22:46:32 +01:00
}
2015-10-07 20:53:55 +02:00
// The rest is the same as in scenario_load
2015-03-07 12:13:10 +01:00
reset_loaded_objects ( ) ;
2014-05-04 17:21:15 +02:00
map_update_tile_pointers ( ) ;
2015-03-31 04:23:40 +02:00
reset_0x69EBE4 ( ) ;
2015-07-06 23:21:25 +02:00
openrct2_reset_object_tween_locations ( ) ;
2015-07-30 00:57:43 +02:00
game_convert_strings_to_utf8 ( ) ;
2015-10-07 20:53:55 +02:00
game_fix_save_vars ( ) ; // OpenRCT2 fix broken save games
2015-06-14 22:01:48 +02:00
return 1 ;
}
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 + + ;
}
RCT2_GLOBAL ( RCT2_ADDRESS_GUESTS_IN_PARK , uint16 ) = peepCount ;
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 ) ;
map_element_insert ( x , y , 14 , 0 ) ;
}
}
}
2015-10-07 20:53:55 +02:00
}
2015-07-31 16:14:44 +02:00
// Load game state for multiplayer
int game_load_network ( SDL_RWops * rw )
{
int i , j ;
rct_s6_header * s6Header = ( rct_s6_header * ) 0x009E34E4 ;
rct_s6_info * s6Info = ( rct_s6_info * ) 0x0141F570 ;
// Read first chunk
sawyercoding_read_chunk ( rw , ( uint8 * ) s6Header ) ;
if ( s6Header - > type = = S6_TYPE_SAVEDGAME ) {
// Read packed objects
if ( s6Header - > num_packed_objects > 0 ) {
j = 0 ;
for ( i = 0 ; i < s6Header - > num_packed_objects ; i + + )
j + = object_load_packed ( rw ) ;
if ( j > 0 )
object_list_load ( ) ;
}
}
uint8 load_success = object_read_and_load_entries ( rw ) ;
// Read flags (16 bytes)
sawyercoding_read_chunk ( rw , ( uint8 * ) RCT2_ADDRESS_CURRENT_MONTH_YEAR ) ;
// Read map elements
memset ( ( void * ) RCT2_ADDRESS_MAP_ELEMENTS , 0 , MAX_MAP_ELEMENTS * sizeof ( rct_map_element ) ) ;
sawyercoding_read_chunk ( rw , ( uint8 * ) RCT2_ADDRESS_MAP_ELEMENTS ) ;
// Read game data, including sprites
sawyercoding_read_chunk ( rw , ( uint8 * ) 0x010E63B8 ) ;
// Read checksum
uint32 checksum ;
SDL_RWread ( rw , & checksum , sizeof ( uint32 ) , 1 ) ;
2015-08-20 04:34:52 +02:00
// Read other data not in normal save files
RCT2_GLOBAL ( RCT2_ADDRESS_GAME_PAUSED , uint32 ) = SDL_ReadLE32 ( rw ) ;
2015-07-31 16:14:44 +02:00
if ( ! load_success ) {
set_load_objects_fail_reason ( ) ;
if ( RCT2_GLOBAL ( RCT2_ADDRESS_INPUT_FLAGS , uint32 ) & INPUT_FLAG_5 ) {
//call 0x0040705E Sets cursor position and something else. Calls maybe wind func 8 probably pointless
RCT2_GLOBAL ( 0x14241BC , uint32 ) = 0 ;
RCT2_GLOBAL ( RCT2_ADDRESS_INPUT_FLAGS , uint32 ) & = ~ INPUT_FLAG_5 ;
}
return 0 ; //This never gets called
}
// The rest is the same as in scenario load and play
reset_loaded_objects ( ) ;
map_update_tile_pointers ( ) ;
reset_0x69EBE4 ( ) ;
openrct2_reset_object_tween_locations ( ) ;
return 1 ;
}
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
*/
int game_load_save ( const char * path )
{
2015-07-05 06:36:25 +02:00
log_verbose ( " loading saved game, %s " , path ) ;
2015-10-30 15:18:29 +01:00
safe_strncpy ( ( char * ) 0x0141EF68 , path , MAX_PATH ) ;
safe_strncpy ( ( char * ) RCT2_ADDRESS_SAVED_GAMES_PATH_2 , path , MAX_PATH ) ;
2015-07-05 06:36:25 +02:00
2015-10-30 15:18:29 +01:00
safe_strncpy ( gScenarioSaveName , path_get_filename ( path ) , MAX_PATH ) ;
2015-07-05 06:36:25 +02:00
path_remove_extension ( gScenarioSaveName ) ;
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 ) ;
RCT2_GLOBAL ( RCT2_ADDRESS_ERROR_TYPE , uint8 ) = 255 ;
2015-08-27 16:44:18 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_GAME_COMMAND_ERROR_TITLE , uint16 ) = STR_FILE_CONTAINS_INVALID_DATA ;
2015-07-05 06:36:25 +02:00
return 0 ;
}
if ( ! game_load_sv6 ( rw ) ) {
2015-06-14 22:01:48 +02:00
title_load ( ) ;
rct2_endupdate ( ) ;
2015-07-05 06:36:25 +02:00
SDL_RWclose ( rw ) ;
2015-06-14 22:01:48 +02:00
return 0 ;
}
2015-07-05 06:36:25 +02:00
SDL_RWclose ( rw ) ;
2015-06-14 22:01:48 +02:00
2015-07-05 17:19:01 +02:00
game_load_init ( ) ;
2015-07-30 00:30:05 +02:00
if ( network_get_mode ( ) = = NETWORK_MODE_SERVER ) {
network_send_map ( ) ;
}
2015-07-05 17:19:01 +02:00
return 1 ;
}
void game_load_init ( )
{
rct_window * mainWindow ;
2014-05-04 17:21:15 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_SCREEN_FLAGS , uint8 ) = SCREEN_FLAGS_PLAYING ;
viewport_init_all ( ) ;
game_create_windows ( ) ;
mainWindow = window_get_main ( ) ;
2014-07-23 19:07:38 +02:00
mainWindow - > viewport_target_sprite = - 1 ;
2014-05-04 17:21:15 +02:00
mainWindow - > saved_view_x = RCT2_GLOBAL ( RCT2_ADDRESS_SAVED_VIEW_X , sint16 ) ;
mainWindow - > saved_view_y = RCT2_GLOBAL ( RCT2_ADDRESS_SAVED_VIEW_Y , sint16 ) ;
2015-10-28 11:44:08 +01:00
uint8 _cl = ( RCT2_GLOBAL ( RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION , sint16 ) & 0xFF ) - mainWindow - > viewport - > zoom ;
mainWindow - > viewport - > zoom = RCT2_GLOBAL ( RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION , sint16 ) & 0xFF ;
* ( ( char * ) ( & RCT2_GLOBAL ( RCT2_ADDRESS_CURRENT_ROTATION , sint32 ) ) ) = RCT2_GLOBAL ( RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION , sint16 ) > > 8 ;
2014-05-04 17:21:15 +02:00
if ( _cl ! = 0 ) {
if ( _cl < 0 ) {
_cl = - _cl ;
mainWindow - > viewport - > view_width > > = _cl ;
mainWindow - > viewport - > view_height > > = _cl ;
} else {
mainWindow - > viewport - > view_width < < = _cl ;
mainWindow - > viewport - > view_height < < = _cl ;
}
}
mainWindow - > saved_view_x - = mainWindow - > viewport - > view_width > > 1 ;
mainWindow - > saved_view_y - = mainWindow - > viewport - > view_height > > 1 ;
window_invalidate ( mainWindow ) ;
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 ( ) ;
2015-10-03 20:00:29 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_WINDOW_UPDATE_TICKS , uint16 ) = 0 ;
2014-05-04 17:21:15 +02:00
if ( RCT2_GLOBAL ( 0x0013587C4 , uint32 ) = = 0 ) // this check is not in scenario play
2015-08-13 09:00:49 +02:00
finance_update_loan_hash ( ) ;
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 ;
2015-02-22 19:24:19 +01:00
scenario_set_filename ( ( char * ) 0x0135936C ) ;
2014-05-04 17:21:15 +02:00
}
2014-06-21 16:50:13 +02: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
{
for ( rct_sprite * spr = g_sprite_list ; spr < ( rct_sprite * ) RCT2_ADDRESS_SPRITES_NEXT_INDEX ; spr + + )
if ( spr - > unknown . sprite_identifier ! = 0xFF )
2014-11-12 18:45:39 +01:00
sprite_move ( spr - > unknown . x , spr - > unknown . y , spr - > unknown . z , spr ) ;
2014-06-21 16:50:13 +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 : 0x0066DBB7
*/
static void load_game ( )
{
2015-06-08 00:12:17 +02:00
window_loadsave_open ( LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME , NULL ) ;
2015-02-14 03:16:03 +01:00
return ;
2014-05-02 23:21:08 +02:00
if ( open_load_game_dialog ( ) = = 0 ) {
gfx_invalidate_screen ( ) ;
} else {
2014-05-03 03:33:01 +02:00
// Set default filename
2014-05-12 02:45:45 +02:00
char * esi = ( char * ) 0x0141EF67 ;
2014-05-03 03:33:01 +02:00
while ( 1 ) {
esi + + ;
if ( * esi = = ' . ' )
break ;
if ( * esi ! = 0 )
continue ;
strcpy ( esi , " .SV6 " ) ;
break ;
}
2015-10-30 15:18:29 +01:00
safe_strncpy ( ( char * ) RCT2_ADDRESS_SAVED_GAMES_PATH_2 , ( char * ) 0x0141EF68 , MAX_PATH ) ;
2014-05-02 23:21:08 +02:00
2014-09-10 20:36:11 +02:00
if ( game_load_save ( ( char * ) 0x0141EF68 ) ) {
2014-05-02 23:21:08 +02:00
gfx_invalidate_screen ( ) ;
2014-05-03 21:39:34 +02:00
rct2_endupdate ( ) ;
2014-05-02 23:21:08 +02:00
} else {
2015-08-16 19:05:49 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_SCREEN_AGE , uint16 ) = 0 ;
2014-05-03 21:39:34 +02:00
rct2_endupdate ( ) ;
2014-05-02 23:21:08 +02:00
}
}
}
2014-11-25 03:05:48 +01:00
/**
*
* rct2 : 0x006750E9
*/
static int show_save_game_dialog ( char * resultPath )
{
rct_s6_info * s6Info = ( rct_s6_info * ) 0x0141F570 ;
int result ;
char title [ 256 ] ;
char filename [ MAX_PATH ] ;
char filterName [ 256 ] ;
format_string ( title , STR_SAVE_GAME_1040 , NULL ) ;
2015-10-30 15:18:29 +01:00
safe_strncpy ( filename , RCT2_ADDRESS ( RCT2_ADDRESS_SAVED_GAMES_PATH_2 , char ) , MAX_PATH ) ;
2014-11-25 03:05:48 +01:00
format_string ( filterName , STR_RCT2_SAVED_GAME , NULL ) ;
pause_sounds ( ) ;
2015-02-12 21:51:40 +01:00
result = platform_open_common_file_dialog ( 0 , title , filename , " *.SV6 " , filterName ) ;
2014-11-25 03:05:48 +01:00
unpause_sounds ( ) ;
if ( result )
2015-10-30 15:18:29 +01:00
safe_strncpy ( resultPath , filename , MAX_PATH ) ;
2014-11-25 03:05:48 +01:00
return result ;
}
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 ) {
utf8 path [ MAX_PATH ] ;
2015-02-14 03:16:03 +01:00
2015-08-19 23:09:54 +02:00
log_verbose ( " Saving to %s " , gScenarioSaveName ) ;
2014-11-25 03:05:48 +01:00
2015-08-19 21:54:25 +02:00
platform_get_user_directory ( path , " save " ) ;
2014-05-27 23:33:16 +02:00
2015-08-19 21:54:25 +02:00
strcat ( path , gScenarioSaveName ) ;
strcat ( path , " .sv6 " ) ;
2015-08-29 14:12:52 +02:00
SDL_RWops * rw = SDL_RWFromFile ( path , " wb+ " ) ;
2015-08-19 21:54:25 +02:00
if ( rw ! = NULL ) {
scenario_save ( rw , 0x80000000 ) ;
2015-08-19 23:09:54 +02:00
log_verbose ( " Saved to %s " , gScenarioSaveName ) ;
2015-08-19 21:54:25 +02:00
SDL_RWclose ( rw ) ;
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
{
window_loadsave_open ( LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME , gScenarioSaveName ) ;
2014-05-27 23:33:16 +02:00
}
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 ] ;
2015-02-21 12:05:15 +01:00
platform_get_user_directory ( path , " save " ) ;
2015-10-30 15:18:29 +01:00
safe_strncpy ( backupPath , path , MAX_PATH ) ;
2015-08-04 22:41:45 +02:00
2015-02-21 12:05:15 +01:00
strcat ( path , " autosave.sv6 " ) ;
2015-08-04 22:41:45 +02:00
strcat ( backupPath , " autosave.sv6.bak " ) ;
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 ] ;
format_string ( exit_title , title , 0 ) ;
char exit_body [ 255 ] ;
format_string ( exit_body , body , 0 ) ;
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-09-23 10:39:45 +02:00
//audio_close();
2014-07-17 18:59:49 +02:00
//Post quit message does not work in 0x6e3879 as its windows only.
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 ( )
{
2014-05-23 11:30:19 +02:00
if ( RCT2_GLOBAL ( RCT2_ADDRESS_SAVE_PROMPT_MODE , uint16 ) < 1 ) {
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 ( ) ;
2014-05-02 23:21:08 +02:00
if ( RCT2_GLOBAL ( RCT2_ADDRESS_SCREEN_FLAGS , uint8 ) & 2 )
load_landscape ( ) ;
else
load_game ( ) ;
2014-05-23 11:30:19 +02:00
} else if ( RCT2_GLOBAL ( RCT2_ADDRESS_SAVE_PROMPT_MODE , uint16 ) = = 1 ) {
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 ( ) ;
2014-10-15 23:59:26 +02:00
if ( RCT2_GLOBAL ( RCT2_ADDRESS_INPUT_FLAGS , uint32 ) & INPUT_FLAG_5 ) {
2015-06-28 14:31:46 +02:00
// RCT2_CALLPROC_EBPSAFE(0x0040705E); Function not required resets cursor position.
2014-10-15 23:59:26 +02:00
RCT2_GLOBAL ( RCT2_ADDRESS_INPUT_FLAGS , uint32 ) & = ~ INPUT_FLAG_5 ;
2014-05-02 23:21:08 +02:00
}
2015-05-19 00:15:43 +02:00
gGameSpeed = 1 ;
2014-05-02 23:21:08 +02:00
title_load ( ) ;
2014-05-03 21:39:34 +02:00
rct2_endupdate ( ) ;
2014-05-02 23:21:08 +02:00
} else {
rct2_exit ( ) ;
}
}
2015-10-31 09:25:43 +01:00
static GAME_COMMAND_POINTER * new_game_command_table [ 62 ] = {
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 ,
2015-09-30 22:55:36 +02:00
game_command_set_peep_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 ,
game_command_set_sign_style
2014-08-10 14:31:41 +02:00
} ;