Merge pull request #880 from duncanspumpkin/track_save

Save Track Design
This commit is contained in:
Ted John 2015-02-27 14:24:00 +00:00
commit b8f81b2c29
3 changed files with 261 additions and 18 deletions

View File

@ -19,6 +19,7 @@
*****************************************************************************/
#include "../addresses.h"
#include "../audio/audio.h"
#include "../game.h"
#include "../interface/viewport.h"
#include "../localisation/localisation.h"
@ -27,6 +28,7 @@
#include "../util/sawyercoding.h"
#include "../util/util.h"
#include "../world/park.h"
#include "../windows/error.h"
#include "ride.h"
#include "track.h"
@ -713,12 +715,12 @@ void load_track_scenery_objects(){
if (track_design->type == RIDE_TYPE_MAZE){
// Skip all of the maze track elements
while (*(uint32*)track_elements != 0)track_elements += 4;
track_elements += 4;
while (*(uint32*)track_elements != 0)track_elements += sizeof(rct_maze_element);
track_elements += sizeof(rct_maze_element);
}
else{
// Skip track_elements
while (*track_elements != 255) track_elements += 2;
while (*track_elements != 255) track_elements += sizeof(rct_track_element);
track_elements++;
// Skip entrance exit elements
@ -727,11 +729,13 @@ void load_track_scenery_objects(){
}
while (*track_elements != 255){
if (!find_object_in_entry_group((rct_object_entry*)track_elements, &entry_type, &entry_index)){
object_load(-1, (rct_object_entry*)track_elements, 0);
rct_track_scenery* scenery_entry = (rct_track_scenery*)track_elements;
if (!find_object_in_entry_group(&scenery_entry->scenery_object, &entry_type, &entry_index)){
object_load(-1, &scenery_entry->scenery_object, 0);
}
// Skip object and location/direction/colour
track_elements += sizeof(rct_object_entry) + 6;
scenery_entry += sizeof(rct_track_scenery);
}
sub_6A9FC0();
@ -1166,3 +1170,182 @@ int track_is_connected_by_shape(rct_map_element *a, rct_map_element *b)
return aBank == bBank && aAngle == bAngle;
}
/* Based on rct2: 0x006D2897 */
int copy_scenery_to_track(uint8** track_pointer){
rct_track_scenery* track_scenery = (rct_track_scenery*)(*track_pointer - 1);
rct_track_scenery* scenery_source = RCT2_ADDRESS(0x009DA193, rct_track_scenery);
while (1){
int ebx = 0;
memcpy(track_scenery, scenery_source, sizeof(rct_track_scenery));
if ((track_scenery->scenery_object.flags & 0xFF) == 0xFF) break;
//0x00F4414D is direction of track?
if ((track_scenery->scenery_object.flags & 0xF) == OBJECT_TYPE_PATHS){
uint8 slope = (track_scenery->flags & 0x60) >> 5;
slope -= RCT2_GLOBAL(0x00F4414D, uint8);
track_scenery->flags &= 0x9F;
track_scenery->flags |= ((slope & 3) << 5);
// Direction of connection on path
uint8 direction = track_scenery->flags & 0xF;
// Rotate the direction by the track direction
direction = ((direction << 4) >> RCT2_GLOBAL(0x00F4414D, uint8));
track_scenery->flags &= 0xF0;
track_scenery->flags |= (direction & 0xF) | (direction >> 4);
}
else if ((track_scenery->scenery_object.flags & 0xF) == OBJECT_TYPE_WALLS){
uint8 direction = track_scenery->flags & 3;
direction -= RCT2_GLOBAL(0x00F4414D, uint8);
track_scenery->flags &= 0xFC;
track_scenery->flags |= (direction & 3);
}
else {
uint8 direction = track_scenery->flags & 3;
uint8 quadrant = (track_scenery->flags & 0xC) >> 2;
direction -= RCT2_GLOBAL(0x00F4414D, uint8);
quadrant -= RCT2_GLOBAL(0x00F4414D, uint8);
track_scenery->flags &= 0xF0;
track_scenery->flags |= (direction & 3) | ((quadrant & 3) << 2);
}
int x = track_scenery->x * 32 - RCT2_GLOBAL(0x00F44142, sint16);
int y = track_scenery->y * 32 - RCT2_GLOBAL(0x00F44144, sint16);
switch (RCT2_GLOBAL(0x00F4414D, uint8)){
case 0:
break;
case 1:
{
int temp_y = y;
y = x;
x = -y;
}
break;
case 2:
x = -x;
y = -y;
break;
case 3:
{
int temp_x = x;
x = y;
y = -x;
}
break;
}
x /= 32;
y /= 32;
if (x > 127 || y > 127 || x < -126 || y < -126){
window_error_open(3346, 3347);
return 0;
}
track_scenery->x = x;
track_scenery->y = y;
int z = track_scenery->z * 8 - RCT2_GLOBAL(0xF44146, sint16);
z /= 8;
if (z > 127 || z < -126){
window_error_open(3346, 3347);
return 0;
}
track_scenery->z = z;
track_scenery++;
scenery_source++;
}
*track_pointer = (uint8*)track_scenery;
//Skip end of scenery elements byte
(*track_pointer)++;
return 1;
}
/* rct2: 0x006D2804 & 0x006D264D */
int save_track_design(uint8 rideIndex){
rct_ride* ride = GET_RIDE(rideIndex);
if (!(ride->lifecycle_flags & RIDE_LIFECYCLE_TESTED)){
window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id));
return 0;
}
if (ride->ratings.excitement == 0xFFFF){
window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id));
return 0;
}
if (!(RCT2_ADDRESS(0x0097CF40, uint32)[ride->type] & 0x10000000)){
window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id));
return 0;
}
if (RCT2_CALLPROC_X(0x006CE44F, 0, 0, 0, rideIndex, 0, 0, 0) & 0x100){
window_error_open(3346, RCT2_GLOBAL(0x141E9AC, rct_string_id));
return 0;
}
uint8* track_pointer = RCT2_GLOBAL(0x00F44058, uint8*);
if (RCT2_GLOBAL(0x009DEA6F, uint8) & 1){
if (!copy_scenery_to_track(&track_pointer))
return 0;
}
while (track_pointer < RCT2_ADDRESS(0x009DE217, uint8))*track_pointer++ = 0;
char track_name[MAX_PATH];
// Get track name
format_string(track_name, ride->name, &ride->name_arguments);
char path[MAX_PATH];
subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), track_name);
strcat(path, ".TD6");
// Save track design
format_string(RCT2_ADDRESS(0x141ED68, char), 2306, NULL);
// Track design files
format_string(RCT2_ADDRESS(0x141EE68, char), 2305, NULL);
pause_sounds();
int result = platform_open_common_file_dialog(
0,
RCT2_ADDRESS(0x141ED68, char),
path,
"*.TD?",
RCT2_ADDRESS(0x141EE68, char));
unpause_sounds();
if (result == 0){
ride_list_item item = { .type = 0xFD, .entry_index = 0 };
track_load_list(item);
return 1;
}
// Until 0x006771DC is finished we required to copy the path name.
strcpy(RCT2_ADDRESS(0x141EF68, char), path);
// This is the function that actually saves the track to a file
RCT2_CALLPROC_EBPSAFE(0x006771DC);
ride_list_item item = { .type = 0xFC, .entry_index = 0 };
track_load_list(item);
gfx_invalidate_screen();
return 1;
}

View File

@ -69,6 +69,17 @@ typedef struct{
uint8 flags;
}rct_track_element;
/* Track Scenery entry size: 0x16 */
typedef struct{
rct_object_entry scenery_object; // 0x00
uint8 x; // 0x10
uint8 y; // 0x11
uint8 z; // 0x12
uint8 flags; // 0x13 direction quadrant tertiary colour
uint8 primary_colour; // 0x14
uint8 secondary_colour; // 0x15
}rct_track_scenery;
enum{
TRACK_ELEMENT_FLAG_CHAIN_LIFT = (1<<7),
TRACK_ELEMENT_FLAG_INVERTED = (1<<6),
@ -216,5 +227,6 @@ int track_delete();
void reset_track_list_cache();
int track_is_connected_by_shape(rct_map_element *a, rct_map_element *b);
int sub_6D01B3(int bl, int x, int y, int z);
int save_track_design(uint8 rideIndex);
#endif

View File

@ -28,10 +28,12 @@
#include "../peep/staff.h"
#include "../ride/ride.h"
#include "../ride/ride_data.h"
#include "../ride/track.h"
#include "../sprites.h"
#include "../windows/error.h"
#include "../world/map.h"
#include "../world/sprite.h"
#include "../audio/audio.h"
#include "dropdown.h"
#define var_496(w) RCT2_GLOBAL((int)w + 0x496, uint16)
@ -4390,6 +4392,50 @@ static void window_ride_music_paint()
#pragma region Measurements
/* rct2: 0x006D2804 when al == 0*/
static void cancel_scenery_selection(){
RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) &= ~(1 << 2);
RCT2_GLOBAL(0x9DEA6F, uint8) &= ~(1 << 0);
unpause_sounds();
rct_window* main_w = window_get_main();
if (main_w){
main_w->viewport->flags &= ~(VIEWPORT_FLAG_HIDE_VERTICAL | VIEWPORT_FLAG_HIDE_BASE);
}
gfx_invalidate_screen();
tool_cancel();
}
/* rct2: 0x006D27A3 */
static void setup_scenery_selection(rct_window* w){
rct_ride* ride = GET_RIDE(w->number);
if (RCT2_GLOBAL(0x009DEA6F, uint8) & 1){
cancel_scenery_selection();
}
while (tool_set(w, 0, 12));
RCT2_GLOBAL(0x00F64DE8, uint8) = (uint8)w->number;
RCT2_GLOBAL(0x009DA193, uint8) = 0xFF;
RCT2_GLOBAL(0x00F63674, sint32) = -1;
RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) |= (1 << 2);
RCT2_GLOBAL(0x009DEA6F, uint8) |= 1;
pause_sounds();
rct_window* w_main = window_get_main();
if (w_main){
w_main->viewport->flags |= (VIEWPORT_FLAG_HIDE_VERTICAL | VIEWPORT_FLAG_HIDE_BASE);
}
gfx_invalidate_screen();
}
/**
*
* rct2: 0x006D3026
@ -4408,15 +4454,6 @@ static void window_ride_measurements_design_select_nearby_scenery()
RCT2_CALLPROC_EBPSAFE(0x006D303D);
}
/**
*
* rct2: 0x006AD4CD
*/
static void window_ride_measurements_design_save(rct_window *w)
{
RCT2_CALLPROC_X(0x006D2804, 1, 0, 0, 0, (int)w, 0, 0);
}
/**
*
* rct2: 0x006AD4DA
@ -4424,7 +4461,18 @@ static void window_ride_measurements_design_save(rct_window *w)
static void window_ride_measurements_design_cancel()
{
if (RCT2_GLOBAL(0x009DEA6F, uint8) & 1)
RCT2_CALLPROC_X(0x006D2804, 0, 0, 0, 0, 0, 0, 0);
cancel_scenery_selection();
}
/**
*
* rct2: 0x006AD4CD
*/
static void window_ride_measurements_design_save(rct_window *w)
{
if (save_track_design((uint8)w->number) == 0) return;
window_ride_measurements_design_cancel();
}
/**
@ -4536,9 +4584,9 @@ static void window_ride_measurements_dropdown()
dropdownIndex = RCT2_GLOBAL(0x009DEBA2, sint16);
if (dropdownIndex == 0)
RCT2_CALLPROC_X(0x006D264D, 0, 0, 0, 0, (int)w, 0, 0);
save_track_design((uint8)w->number);
else
RCT2_CALLPROC_X(0x006D27A3, 0, 0, 0, 0, (int)w, 0, 0);
setup_scenery_selection(w);
}
/**