1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-18 04:23:20 +01:00

fix track design preview, place and refactor

This commit is contained in:
Ted John
2016-04-30 13:27:12 +01:00
parent 3c95562efd
commit f00d7daef5
6 changed files with 312 additions and 573 deletions

View File

@@ -627,7 +627,7 @@ void ride_construction_toolupdate_construct(int screenX, int screenY);
void ride_construction_tooldown_construct(int screenX, int screenY);
void window_maze_construction_update_pressed_widgets();
void window_track_place_open();
void window_track_place_open(utf8 *tdPath);
rct_window *window_new_ride_open();
rct_window *window_new_ride_open_research();
void window_install_track_open(const char* path);

View File

@@ -274,159 +274,12 @@ void track_update_max_min_coordinates(sint16 x, sint16 y, sint16 z)
}
}
#ifdef ADSIASD
void track_list_populate(ride_list_item item, uint8* track_list_cache){
uint8* track_pointer = track_list_cache;
int cur_track_entry_index = 0;
for (uint8 track_type = *track_pointer++; track_type != 0xFE;
track_pointer += strlen((const char *)track_pointer) + 1,
track_type = *track_pointer++){
rct_object_entry* track_object = (rct_object_entry*)track_pointer;
track_pointer += sizeof(rct_object_entry);
if (track_type != item.type){
continue;
}
uint8 entry_type, entry_index;
if (item.entry_index != 0xFF){
if (!find_object_in_entry_group(track_object, &entry_type, &entry_index))continue;
if (item.entry_index != entry_index)continue;
}
else{
if (find_object_in_entry_group(track_object, &entry_type, &entry_index)){
if ((get_ride_entry(entry_index)->flags & (RIDE_ENTRY_FLAG_SEPARATE_RIDE_NAME | RIDE_ENTRY_FLAG_SEPARATE_RIDE)) &&
!rideTypeShouldLoseSeparateFlag(get_ride_entry(entry_index)))
continue;
}
else{
uint32* esi = sub_6AB49A(track_object);
if (esi == NULL) continue;
if (*esi & 0x1000000)continue;
}
}
// If cur_track_entry_index is greater than max number of tracks
if (cur_track_entry_index >= 1000){
RCT2_GLOBAL(0xF635ED, uint8) |= 1;
break;
}
int track_entry_index = 0;
uint8 isBelow = 0;
for (; track_entry_index != cur_track_entry_index; track_entry_index++){
if (strcicmp((const char *)track_pointer, &RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, const char)[track_entry_index * 128]) < 0){
isBelow = 1;
break;
}
}
if (isBelow == 1){
memmove(
&RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[track_entry_index * 128 + 128],
&RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[track_entry_index * 128],
(cur_track_entry_index - track_entry_index) * 128);
}
strcpy(&RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, char)[track_entry_index * 128], (const char *)track_pointer);
cur_track_entry_index++;
}
RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8)[cur_track_entry_index * 128] = '\0';
}
/**
*
* rct2: 0x006CED50
*/
void track_load_list(ride_list_item item)
{
RCT2_GLOBAL(0xF635ED, uint8) = 0;
if (item.type < 0x80){
rct_ride_entry* ride_type = get_ride_entry(item.entry_index);
if (!(ride_type->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) || rideTypeShouldLoseSeparateFlag(ride_type)){
item.entry_index = 0xFF;
}
}
int totalFiles;
track_list_query_directory(&totalFiles);
uint8* track_list_cache;
if (item.type == 0xFC || !(track_list_cache = track_list_cache_load(totalFiles))){
uint8* new_track_file;
new_track_file = malloc(0x40000);
uint8* new_file_pointer = new_track_file;
file_info enumFileInfo;
int enumFileHandle = platform_enumerate_files_begin(RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char));
if (enumFileHandle == INVALID_HANDLE)
{
free(new_file_pointer);
return;
}
while (platform_enumerate_files_next(enumFileHandle, &enumFileInfo)) {
if (new_file_pointer > new_track_file + 0x3FF00)break;
char path[MAX_PATH];
substitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_TRACKS_PATH, char), enumFileInfo.path);
rct_track_td6* loaded_track = load_track_design(path);
if (loaded_track){
*new_file_pointer++ = loaded_track->type;
}
else{
*new_file_pointer++ = 0xFF;
// Garbage object
new_file_pointer += sizeof(rct_object_entry);
// Empty string
*new_file_pointer++ = '\0';
// Unsure why it previously didn't continue on load fail??
continue;
}
memcpy(new_file_pointer, &loaded_track->vehicle_object, sizeof(rct_object_entry));
new_file_pointer += sizeof(rct_object_entry);
int file_name_length = strlen(enumFileInfo.path);
strcpy((char *)new_file_pointer, enumFileInfo.path);
new_file_pointer += file_name_length + 1;
}
platform_enumerate_files_end(enumFileHandle);
if (!track_list_cache_save(totalFiles, new_track_file, new_file_pointer - new_track_file)){
log_error("Track list failed to save.");
return;
}
free(new_track_file);
track_list_cache = track_list_cache_load(totalFiles);
if (!track_list_cache){
log_error("Track list failed to load after new save");
return;
}
}
track_list_populate(item, track_list_cache);
free(track_list_cache);
}
#endif
/**
*
* rct2: 0x006ABDB0
*/
void load_track_scenery_objects(){
void load_track_scenery_objects()
{
uint8 entry_index = RCT2_GLOBAL(0xF44157, uint8);
rct_object_entry_extended* object_entry = &object_entry_groups[0].entries[entry_index];
@@ -439,8 +292,8 @@ void load_track_scenery_objects(){
find_object_in_entry_group(copied_entry, &entry_type, &entry_index);
RCT2_GLOBAL(0xF44157, uint8) = entry_index;
rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6);
uint8* track_elements = RCT2_ADDRESS(0x9D821B, uint8);
rct_track_td6 *track_design = gActiveTrackDesign;
uint8 *track_elements = gActiveTrackDesign->elements;
if (track_design->type == RIDE_TYPE_MAZE){
// Skip all of the maze track elements
@@ -616,19 +469,14 @@ void track_mirror_maze(uint8** track_elements){
*
* rct2: 0x006D2436
*/
void track_mirror(){
uint8* track_elements = RCT2_ADDRESS(0x009D821B, uint8);
rct_track_td6* track_design = RCT2_ADDRESS(0x009D8178, rct_track_td6);
if (track_design->type == RIDE_TYPE_MAZE){
track_mirror_maze(&track_elements);
void track_mirror()
{
if (gActiveTrackDesign->type == RIDE_TYPE_MAZE) {
track_mirror_maze(gActiveTrackDesign->elements);
} else {
track_mirror_ride(gActiveTrackDesign->elements);
}
else{
track_mirror_ride(&track_elements);
}
track_mirror_scenery(&track_elements);
track_mirror_scenery(gActiveTrackDesign->elements);
}
static void track_add_selection_tile(sint16 x, sint16 y)
@@ -1468,7 +1316,7 @@ int sub_6D01B3(rct_track_td6 *td6, uint8 bl, uint8 rideIndex, int x, int y, int
RCT2_GLOBAL(RCT2_ADDRESS_TRACK_PREVIEW_Z_MAX, sint16) = z;
RCT2_GLOBAL(0x00F44129, uint16) = 0;
uint8* track_elements = RCT2_ADDRESS(0x009D821B, uint8);
uint8* track_elements = td6->elements;
uint8 track_place_success = 0;
@@ -1722,72 +1570,6 @@ void draw_track_preview(rct_track_td6 *td6, uint8** preview)
track_design_preview_restore_map();
}
#ifdef fsdfds
/**
*
* I don't think preview is a necessary output argument. It can be obtained easily using the track design structure.
* rct2: 0x006D1DEC
*/
rct_track_design *track_get_info(int index, uint8** preview)
{
rct_track_design *trackDesign;
uint8 *trackDesignList = RCT2_ADDRESS(RCT2_ADDRESS_TRACK_LIST, uint8);
int i;
trackDesign = NULL;
// Check if track design has already been loaded
for (i = 0; i < 4; i++) {
if (index == RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i]) {
trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, rct_track_design*)[i];
break;
}
}
if (trackDesign == NULL) {
// Load track design
i = RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32)++;
if (RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32) >= 4)
RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_NEXT_INDEX_CACHE, uint32) = 0;
RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i] = index;
char track_path[MAX_PATH] = { 0 };
substitute_path(track_path, (char*)RCT2_ADDRESS_TRACKS_PATH, (char *)trackDesignList + (index * 128));
rct_track_td6* loaded_track = NULL;
log_verbose("Loading track: %s", trackDesignList + (index * 128));
if (!(loaded_track = load_track_design(track_path))) {
if (preview != NULL) *preview = NULL;
// Mark cache as empty.
RCT2_ADDRESS(RCT2_ADDRESS_TRACK_DESIGN_INDEX_CACHE, uint32)[i] = 0;
log_error("Failed to load track: %s", trackDesignList + (index * 128));
return NULL;
}
trackDesign = &RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, rct_track_design*)[i];
// Copy the track design apart from the preview image
memcpy(&trackDesign->track_td6, loaded_track, sizeof(rct_track_td6));
// Load in a new preview image, calculate cost variable, calculate var_06
draw_track_preview(&trackDesign->track_td6, (uint8**)trackDesign->preview);
trackDesign->track_td6.cost = gTrackDesignCost;
trackDesign->track_td6.track_flags = RCT2_GLOBAL(0x00F44151, uint8) & 7;
}
// Set preview to correct preview image based on rotation
if (preview != NULL)
*preview = trackDesign->preview[_currentTrackPieceDirection];
return trackDesign;
}
#endif
/**
*
* rct2: 0x006D3664

View File

@@ -785,7 +785,7 @@ static bool track_design_save_to_td6(rct_track_td6 *td6, uint8 rideIndex)
td6->flags = 0;
td6->flags2 = 0;
uint8 *trackElements = RCT2_ADDRESS(0x9D821B, uint8);
uint8 *trackElements = td6->elements;
memset(trackElements, 0, 8000);
if (td6->type == RIDE_TYPE_MAZE) {

View File

@@ -198,7 +198,7 @@ static void window_install_track_select(rct_window *w, int index)
// window_error_open(STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE, -1);
window_close(w);
window_track_place_open();
window_track_place_open(NULL);
}
/**

View File

@@ -100,40 +100,24 @@ static uint16 _loadedTrackDesignIndex;
static rct_track_td6 _loadedTrackDesign;
static uint8 _loadedTrackDesignPreview[4][TRACK_PREVIEW_IMAGE_SIZE];
static void track_list_load_designs(ride_list_item item);
static bool track_list_load_design_for_preview(utf8 *path);
/**
*
* rct2: 0x006CF1A2
*/
void window_track_list_open(ride_list_item item)
{
rct_window *w;
int x, y;
void *mem;
window_close_construction_windows();
_window_track_list_item = item;
track_list_load_designs(item);
char entry[9];
const char *entryPtr = NULL;
if (item.type < 0x80) {
rct_ride_entry *rideEntry = get_ride_entry(item.entry_index);
if ((rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) && !rideTypeShouldLoseSeparateFlag(rideEntry)) {
get_ride_entry_name(entry, item.entry_index);
entryPtr = entry;
}
}
_trackDesignsCount = track_design_index_get_for_ride(&_trackDesigns, item.type, entryPtr);
if (RCT2_GLOBAL(0x00F635ED, uint8) & 1)
if (RCT2_GLOBAL(0x00F635ED, uint8) & 1) {
window_error_open(STR_WARNING, STR_TOO_MANY_TRACK_DESIGNS_OF_THIS_TYPE);
}
mem = malloc(1285292);
if (mem == NULL)
return;
RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, void*) = mem;
// reset_track_list_cache();
int x, y;
if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER) {
x = gScreenWidth / 2 - 300;
y = max(28, gScreenHeight / 2 - 200);
@@ -141,7 +125,7 @@ void window_track_list_open(ride_list_item item)
x = 0;
y = 29;
}
w = window_create(
rct_window *w = window_create(
x,
y,
600,
@@ -161,6 +145,24 @@ void window_track_list_open(ride_list_item item)
_currentTrackPieceDirection = 2;
}
/**
*
* rct2: 0x006CFD76
*/
static void window_track_list_close(rct_window *w)
{
// Dispose loaded track
SafeFree(_loadedTrackDesign.elements);
// Dispose track list
for (size_t i = 0; i < _trackDesignsCount; i++) {
free(_trackDesigns[i].name);
free(_trackDesigns[i].path);
}
SafeFree(_trackDesigns);
_trackDesignsCount = 0;
}
/**
*
* rct2: 0x006CFB82
@@ -200,21 +202,12 @@ static void window_track_list_select(rct_window *w, int index)
return;
}
// if (!load_track_design(tdRef->path)) {
// w->track_list.var_480 = 0xFFFF;
// window_invalidate(w);
// return;
// }
if (_loadedTrackDesignIndex != -1 && _loadedTrackDesign.track_flags & 4) {
window_error_open(STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE, STR_NONE);
}
// rct_track_design *trackDesign = track_get_info(index, NULL);
// if (trackDesign != NULL) {
// if (trackDesign->track_td6.track_flags & 4) {
// window_error_open(STR_THIS_DESIGN_WILL_BE_BUILT_WITH_AN_ALTERNATIVE_VEHICLE_TYPE, STR_NONE);
// }
//
// window_close(w);
// window_track_place_open();
// }
window_close(w);
window_track_place_open(tdRef->path);
}
static int window_track_list_get_list_item_index_from_position(int x, int y)
@@ -232,22 +225,6 @@ static int window_track_list_get_list_item_index_from_position(int x, int y)
return index;
}
/**
*
* rct2: 0x006CFD76
*/
static void window_track_list_close(rct_window *w)
{
for (size_t i = 0; i < _trackDesignsCount; i++) {
free(_trackDesigns[i].name);
free(_trackDesigns[i].path);
}
free(_trackDesigns);
_trackDesignsCount = 0;
free(RCT2_GLOBAL(RCT2_ADDRESS_TRACK_DESIGN_CACHE, void*));
}
/**
*
* rct2: 0x006CFA31
@@ -388,16 +365,9 @@ static void window_track_list_invalidate(rct_window *w)
*/
static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi)
{
rct_widget *widget;
uint8 *image;
uint16 holes, speed, drops, dropHeight, inversions;
fixed32_2dp rating;
int trackIndex, x, y, colour, gForces, airTime;
rct_g1_element tmpElement, *substituteElement;
window_draw_widgets(w, dpi);
trackIndex = w->track_list.var_482;
int trackIndex = w->track_list.var_482;
if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER) {
if (_trackDesignsCount == 0 || trackIndex == -1) {
return;
@@ -407,36 +377,32 @@ static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi)
}
// Track preview
widget = &window_track_list_widgets[WIDX_TRACK_PREVIEW];
int x, y, colour;
rct_widget *widget = &window_track_list_widgets[WIDX_TRACK_PREVIEW];
x = w->x + widget->left + 1;
y = w->y + widget->top + 1;
colour = ColourMapA[w->colours[0]].darkest;
gfx_fill_rect(dpi, x, y, x + 369, y + 216, colour);
rct_track_td6 *td6 = &_loadedTrackDesign;
gActiveTrackDesign = td6;
if (_loadedTrackDesignIndex != trackIndex) {
if (!track_design_open(td6, _trackDesigns[trackIndex].path)) {
uint8 *path = _trackDesigns[trackIndex].path;
if (track_list_load_design_for_preview(path)) {
_loadedTrackDesignIndex = trackIndex;
} else {
_loadedTrackDesignIndex = -1;
return;
}
// Load in a new preview image, calculate cost variable, calculate var_06
draw_track_preview(td6, (uint8**)_loadedTrackDesignPreview);
td6->cost = gTrackDesignCost;
td6->track_flags = RCT2_GLOBAL(0x00F44151, uint8) & 7;
_loadedTrackDesignIndex = trackIndex;
}
image = _loadedTrackDesignPreview[_currentTrackPieceDirection];
uint8 *image = _loadedTrackDesignPreview[_currentTrackPieceDirection];
// trackDesign = track_get_info(trackIndex, &image);
// if (trackDesign == NULL) {
// return;
// }
substituteElement = &g1Elements[0];
tmpElement = *substituteElement;
rct_g1_element *substituteElement = &g1Elements[0];
rct_g1_element tmpElement = *substituteElement;
substituteElement->offset = image;
substituteElement->width = 370;
substituteElement->height = 217;
@@ -475,7 +441,7 @@ static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi)
y = w->y + widget->bottom + 2;
// Stats
rating = td6->excitement * 10;
fixed32_2dp rating = td6->excitement * 10;
gfx_draw_string_left(dpi, STR_TRACK_LIST_EXCITEMENT_RATING, &rating, 0, x, y);
y += 10;
@@ -490,12 +456,12 @@ static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi)
if (td6->type != RIDE_TYPE_MAZE) {
if (td6->type == RIDE_TYPE_MINI_GOLF) {
// Holes
holes = td6->holes & 0x1F;
uint16 holes = td6->holes & 0x1F;
gfx_draw_string_left(dpi, STR_HOLES, &holes, 0, x, y);
y += 10;
} else {
// Maximum speed
speed = ((td6->max_speed << 16) * 9) >> 18;
uint16 speed = ((td6->max_speed << 16) * 9) >> 18;
gfx_draw_string_left(dpi, STR_MAX_SPEED, &speed, 0, x, y);
y += 10;
@@ -514,7 +480,7 @@ static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi)
if (ride_type_has_flag(td6->type, RIDE_TYPE_FLAG_HAS_G_FORCES)) {
// Maximum positive vertical Gs
gForces = td6->max_positive_vertical_g * 32;
int gForces = td6->max_positive_vertical_g * 32;
gfx_draw_string_left(dpi, STR_MAX_POSITIVE_VERTICAL_G, &gForces, 0, x, y);
y += 10;
@@ -532,7 +498,7 @@ static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi)
if (td6->version_and_colour_scheme / 4 >= 2) {
if (td6->total_air_time != 0) {
// Total air time
airTime = td6->total_air_time * 25;
int airTime = td6->total_air_time * 25;
gfx_draw_string_left(dpi, STR_TOTAL_AIR_TIME, &airTime, 0, x, y);
y += 10;
}
@@ -541,18 +507,18 @@ static void window_track_list_paint(rct_window *w, rct_drawpixelinfo *dpi)
if (ride_type_has_flag(td6->type, RIDE_TYPE_FLAG_HAS_DROPS)) {
// Drops
drops = td6->drops & 0x3F;
uint16 drops = td6->drops & 0x3F;
gfx_draw_string_left(dpi, STR_DROPS, &drops, 0, x, y);
y += 10;
// Drop height is multiplied by 0.75
dropHeight = (td6->highest_drop_height + (td6->highest_drop_height / 2)) / 2;
uint16 dropHeight = (td6->highest_drop_height + (td6->highest_drop_height / 2)) / 2;
gfx_draw_string_left(dpi, STR_HIGHEST_DROP_HEIGHT, &drops, 0, x, y);
y += 10;
}
if (td6->type != RIDE_TYPE_MINI_GOLF) {
inversions = td6->inversions & 0x1F;
uint16 inversions = td6->inversions & 0x1F;
if (inversions != 0) {
// Inversions
gfx_draw_string_left(dpi, STR_INVERSIONS, &inversions, 0, x, y);
@@ -633,3 +599,34 @@ static void window_track_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi,
y += 10;
}
}
static void track_list_load_designs(ride_list_item item)
{
char entry[9];
const char *entryPtr = NULL;
if (item.type < 0x80) {
rct_ride_entry *rideEntry = get_ride_entry(item.entry_index);
if ((rideEntry->flags & RIDE_ENTRY_FLAG_SEPARATE_RIDE) && !rideTypeShouldLoseSeparateFlag(rideEntry)) {
get_ride_entry_name(entry, item.entry_index);
entryPtr = entry;
}
}
_trackDesignsCount = track_design_index_get_for_ride(&_trackDesigns, item.type, entryPtr);
}
static bool track_list_load_design_for_preview(utf8 *path)
{
// Dispose currently loaded track
SafeFree(_loadedTrackDesign.elements);
if (track_design_open(&_loadedTrackDesign, path)) {
// Load in a new preview image, calculate cost variable, calculate var_06
gActiveTrackDesign = &_loadedTrackDesign;
draw_track_preview(&_loadedTrackDesign, (uint8**)_loadedTrackDesignPreview);
_loadedTrackDesign.cost = gTrackDesignCost;
_loadedTrackDesign.track_flags = RCT2_GLOBAL(0x00F44151, uint8) & 7;
return true;
}
return false;
}

View File

@@ -105,6 +105,15 @@ static sint16 _window_track_place_last_valid_y;
static sint16 _window_track_place_last_valid_z;
static money32 _window_track_place_last_cost;
static void window_track_place_clear_provisional();
static int window_track_place_get_base_z(int x, int y);
static void window_track_place_attempt_placement(int x, int y, int z, int bl, money32 *cost, uint8 *rideIndex);
static void window_track_place_clear_mini_preview();
static void window_track_place_draw_mini_preview();
static void window_track_place_draw_mini_preview_track(int pass, rct_xy16 origin, rct_xy16 *min, rct_xy16 *max);
static void window_track_place_draw_mini_preview_maze(int pass, rct_xy16 origin, rct_xy16 *min, rct_xy16 *max);
/**
*
* rct2: 0x006D182E
@@ -116,262 +125,22 @@ static void window_track_place_clear_mini_preview()
#define swap(x, y) x = x ^ y; y = x ^ y; x = x ^ y;
/**
*
* rct2: 0x006D1845
*/
static void window_track_place_draw_mini_preview()
{
rct_track_td6 *track = RCT2_ADDRESS(0x009D8178, rct_track_td6);
uint8 *pixel, colour, bits;
int i, rotation, pass, x, y, pixelX, pixelY, originX, originY, minX, minY, maxX, maxY;
rct_maze_element *mazeElement;
rct_track_element *trackElement;
const rct_preview_track *trackBlock;
window_track_place_clear_mini_preview();
minX = 0;
minY = 0;
maxX = 0;
maxY = 0;
// First pass is used to determine the width and height of the image so it can centre it
for (pass = 0; pass < 2; pass++) {
originX = 0;
originY = 0;
if (pass == 1) {
originX -= ((maxX + minX) >> 6) << 5;
originY -= ((maxY + minY) >> 6) << 5;
}
if (track->type != RIDE_TYPE_MAZE) {
#pragma region Track
rotation = _currentTrackPieceDirection + get_current_rotation();
trackElement = RCT2_ADDRESS(0x009D821B, rct_track_element);
while (trackElement->type != 255) {
int trackType = trackElement->type;
if (trackType == 101)
trackType = 255;
// Station track is a lighter colour
colour = RCT2_ADDRESS(0x0099BA64, uint8)[trackType * 16] & 0x10 ? 222 : 218;
// Follow a single track piece shape
trackBlock = TrackBlocks[trackType];
while (trackBlock->index != 255) {
x = originX;
y = originY;
switch (rotation & 3) {
case 0:
x += trackBlock->x;
y += trackBlock->y;
break;
case 1:
x += trackBlock->y;
y -= trackBlock->x;
break;
case 2:
x -= trackBlock->x;
y -= trackBlock->y;
break;
case 3:
x -= trackBlock->y;
y += trackBlock->x;
break;
}
if (pass == 0) {
minX = min(minX, x);
maxX = max(maxX, x);
minY = min(minY, y);
maxY = max(maxY, y);
} else {
pixelX = 80 + ((y / 32) - (x / 32)) * 4;
pixelY = 38 + ((y / 32) + (x / 32)) * 2;
if (pixelX >= 0 && pixelY >= 0 && pixelX <= 160 && pixelY <= 75) {
pixel = &_window_track_place_mini_preview[pixelY * TRACK_MINI_PREVIEW_WIDTH + pixelX];
bits = trackBlock->var_08 << (rotation & 3);
bits = (bits & 0x0F) | ((bits & 0xF0) >> 4);
for (i = 0; i < 4; i++) {
if (bits & 1) pixel[338 + i] = colour;
if (bits & 2) pixel[168 + i] = colour;
if (bits & 4) pixel[ 2 + i] = colour;
if (bits & 8) pixel[172 + i] = colour;
}
}
}
trackBlock++;
}
// Change rotation and next position based on track curvature
rotation &= 3;
const rct_track_coordinates* track_coordinate = &TrackCoordinates[trackType];
trackType *= 10;
switch (rotation) {
case 0:
originX += track_coordinate->x;
originY += track_coordinate->y;
break;
case 1:
originX += track_coordinate->y;
originY -= track_coordinate->x;
break;
case 2:
originX -= track_coordinate->x;
originY -= track_coordinate->y;
break;
case 3:
originX -= track_coordinate->y;
originY += track_coordinate->x;
break;
}
rotation += track_coordinate->rotation_end - track_coordinate->rotation_begin;
rotation &= 3;
if (track_coordinate->rotation_end & 4)
rotation |= 4;
if (!(rotation & 4)) {
originX += TileDirectionDelta[rotation].x;
originY += TileDirectionDelta[rotation].y;
}
trackElement++;
}
#pragma endregion
} else {
#pragma region Maze
rotation = (_currentTrackPieceDirection + get_current_rotation()) & 3;
mazeElement = RCT2_ADDRESS(0x009D821B, rct_maze_element);
while (mazeElement->all != 0) {
x = mazeElement->x * 32;
y = mazeElement->y * 32;
switch (rotation) {
case 1:
x = -x;
swap(x, y);
break;
case 2:
x = -x;
y = -y;
break;
case 3:
x = -x;
swap(x, y);
break;
}
x += originX;
y += originY;
// Entrance or exit is a lighter colour
colour = mazeElement->type == 8 || mazeElement->type == 128 ? 222 : 218;
if (pass == 0) {
minX = min(minX, x);
maxX = max(maxX, x);
minY = min(minY, y);
maxY = max(maxY, y);
} else {
pixelX = 80 + ((y / 32) - (x / 32)) * 4;
pixelY = 38 + ((y / 32) + (x / 32)) * 2;
if (pixelX <= 160 && pixelY <= 75) {
pixel = &_window_track_place_mini_preview[pixelY * TRACK_MINI_PREVIEW_WIDTH + pixelX];
for (i = 0; i < 4; i++) {
pixel[338 + i] = colour;
pixel[168 + i] = colour;
pixel[ 2 + i] = colour;
pixel[172 + i] = colour;
}
}
}
mazeElement++;
}
#pragma endregion
}
}
}
/**
*
* rct2: 0x006D017F
*/
static void window_track_place_clear_provisional()
{
if (_window_track_place_last_was_valid) {
sub_6D01B3(
gActiveTrackDesign,
PTD_OPERATION_CLEAR_OUTLINES,
RCT2_GLOBAL(0x00F440EB, uint8),
_window_track_place_last_valid_x,
_window_track_place_last_valid_y,
_window_track_place_last_valid_z
);
_window_track_place_last_was_valid = 0;
}
}
/**
*
* rct2: 0x006D17C6
*/
static int window_track_place_get_base_z(int x, int y)
{
rct_map_element *mapElement;
int z;
mapElement = map_get_surface_element_at(x >> 5, y >> 5);
z = mapElement->base_height * 8;
// Increase Z above slope
if (mapElement->properties.surface.slope & 0x0F) {
z += 16;
// Increase Z above double slope
if (mapElement->properties.surface.slope & 0x10)
z += 16;
}
// Increase Z above water
if (mapElement->properties.surface.terrain & 0x1F)
z = max(z, (mapElement->properties.surface.terrain & 0x1F) << 4);
return z + sub_6D01B3(gActiveTrackDesign, PTD_OPERATION_GET_PLACE_Z, 0, x, y, z);
}
static void window_track_place_attempt_placement(int x, int y, int z, int bl, money32 *cost, uint8 *rideIndex)
{
int eax, ebx, ecx, edx, esi, edi, ebp;
money32 result;
edx = esi = ebp = 0;
eax = x;
ebx = bl;
ecx = y;
edi = z;
result = game_do_command_p(GAME_COMMAND_PLACE_TRACK_DESIGN, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp);
if (cost != NULL) *cost = result;
if (rideIndex != NULL) *rideIndex = edi & 0xFF;
}
/**
*
* rct2: 0x006CFCA0
*/
void window_track_place_open()
void window_track_place_open(utf8 *tdPath)
{
rct_window *w;
window_close_construction_windows();
gActiveTrackDesign = malloc(sizeof(rct_track_td6));
if (!track_design_open(gActiveTrackDesign, tdPath)) {
SafeFree(gActiveTrackDesign);
return;
}
_window_track_place_mini_preview = malloc(TRACK_MINI_PREVIEW_SIZE);
window_track_place_clear_mini_preview();
@@ -408,7 +177,8 @@ static void window_track_place_close(rct_window *w)
map_invalidate_map_selection_tiles();
RCT2_GLOBAL(RCT2_ADDRESS_MAP_SELECTION_FLAGS, uint16) &= ~6;
hide_gridlines();
free(_window_track_place_mini_preview);
SafeFree(_window_track_place_mini_preview);
SafeFree(gActiveTrackDesign);
}
/**
@@ -588,21 +358,82 @@ static void window_track_place_invalidate(rct_window *w)
colour_scheme_update(w);
}
/**
*
* rct2: 0x006D017F
*/
static void window_track_place_clear_provisional()
{
if (_window_track_place_last_was_valid) {
sub_6D01B3(
gActiveTrackDesign,
PTD_OPERATION_CLEAR_OUTLINES,
RCT2_GLOBAL(0x00F440EB, uint8),
_window_track_place_last_valid_x,
_window_track_place_last_valid_y,
_window_track_place_last_valid_z
);
_window_track_place_last_was_valid = 0;
}
}
/**
*
* rct2: 0x006D17C6
*/
static int window_track_place_get_base_z(int x, int y)
{
rct_map_element *mapElement;
int z;
mapElement = map_get_surface_element_at(x >> 5, y >> 5);
z = mapElement->base_height * 8;
// Increase Z above slope
if (mapElement->properties.surface.slope & 0x0F) {
z += 16;
// Increase Z above double slope
if (mapElement->properties.surface.slope & 0x10)
z += 16;
}
// Increase Z above water
if (mapElement->properties.surface.terrain & 0x1F)
z = max(z, (mapElement->properties.surface.terrain & 0x1F) << 4);
return z + sub_6D01B3(gActiveTrackDesign, PTD_OPERATION_GET_PLACE_Z, 0, x, y, z);
}
static void window_track_place_attempt_placement(int x, int y, int z, int bl, money32 *cost, uint8 *rideIndex)
{
int eax, ebx, ecx, edx, esi, edi, ebp;
money32 result;
edx = esi = ebp = 0;
eax = x;
ebx = bl;
ecx = y;
edi = z;
result = game_do_command_p(GAME_COMMAND_PLACE_TRACK_DESIGN, &eax, &ebx, &ecx, &edx, &esi, &edi, &ebp);
if (cost != NULL) *cost = result;
if (rideIndex != NULL) *rideIndex = edi & 0xFF;
}
/**
*
* rct2: 0x006CFD9D
*/
static void window_track_place_paint(rct_window *w, rct_drawpixelinfo *dpi)
{
rct_drawpixelinfo clippedDpi;
rct_g1_element tmpElement, *substituteElement;
window_draw_widgets(w, dpi);
// Draw mini tile preview
rct_drawpixelinfo clippedDpi;
if (clip_drawpixelinfo(&clippedDpi, dpi, w->x + 4, w->y + 18, 168, 78)) {
substituteElement = &g1Elements[0];
tmpElement = *substituteElement;
rct_g1_element *substituteElement = &g1Elements[0];
rct_g1_element tmpElement = *substituteElement;
substituteElement->offset = _window_track_place_mini_preview;
substituteElement->width = TRACK_MINI_PREVIEW_WIDTH;
substituteElement->height = TRACK_MINI_PREVIEW_HEIGHT;
@@ -614,7 +445,136 @@ static void window_track_place_paint(rct_window *w, rct_drawpixelinfo *dpi)
}
// Price
if (_window_track_place_last_cost != MONEY32_UNDEFINED)
if (!(gParkFlags & PARK_FLAGS_NO_MONEY))
gfx_draw_string_centred(dpi, STR_COST_LABEL, w->x + 88, w->y + 94, 0, &_window_track_place_last_cost);
if (_window_track_place_last_cost != MONEY32_UNDEFINED && !(gParkFlags & PARK_FLAGS_NO_MONEY)) {
gfx_draw_string_centred(dpi, STR_COST_LABEL, w->x + 88, w->y + 94, 0, &_window_track_place_last_cost);
}
}
/**
*
* rct2: 0x006D1845
*/
static void window_track_place_draw_mini_preview()
{
window_track_place_clear_mini_preview();
bool isMaze = gActiveTrackDesign->type == RIDE_TYPE_MAZE;
// First pass is used to determine the width and height of the image so it can centre it
rct_xy16 min = { 0, 0 };
rct_xy16 max = { 0, 0 };
for (int pass = 0; pass < 2; pass++) {
rct_xy16 origin = { 0, 0 };
if (pass == 1) {
origin.x -= ((max.x + min.x) >> 6) << 5;
origin.y -= ((max.y + min.y) >> 6) << 5;
}
if (isMaze) {
window_track_place_draw_mini_preview_maze(pass, origin, &min, &max);
} else {
window_track_place_draw_mini_preview_track(pass, origin, &min, &max);
}
}
}
static void window_track_place_draw_mini_preview_track(int pass, rct_xy16 origin, rct_xy16 *min, rct_xy16 *max)
{
int rotation = _currentTrackPieceDirection + get_current_rotation();
rct_track_element *trackElement = (rct_track_element*)gActiveTrackDesign->elements;
while (trackElement->type != 255) {
int trackType = trackElement->type;
if (trackType == TRACK_ELEM_INVERTED_90_DEG_UP_TO_FLAT_QUARTER_LOOP) {
trackType = 255;
}
// Station track is a lighter colour
uint8 colour = RCT2_ADDRESS(0x0099BA64, uint8)[trackType * 16] & 0x10 ? 222 : 218;
// Follow a single track piece shape
const rct_preview_track *trackBlock = TrackBlocks[trackType];
while (trackBlock->index != 255) {
sint16 x = origin.x;
sint16 y = origin.y;
map_offset_with_rotation(&x, &y, trackBlock->x, trackBlock->y, rotation);
if (pass == 0) {
min->x = min(min->x, x);
max->x = max(max->x, x);
min->y = min(min->y, y);
max->y = max(max->y, y);
} else {
int pixelX = 80 + ((y / 32) - (x / 32)) * 4;
int pixelY = 38 + ((y / 32) + (x / 32)) * 2;
if (pixelX >= 0 && pixelY >= 0 && pixelX <= 160 && pixelY <= 75) {
uint8 *pixel = &_window_track_place_mini_preview[pixelY * TRACK_MINI_PREVIEW_WIDTH + pixelX];
uint8 bits = trackBlock->var_08 << (rotation & 3);
bits = (bits & 0x0F) | ((bits & 0xF0) >> 4);
for (int i = 0; i < 4; i++) {
if (bits & 1) pixel[338 + i] = colour;
if (bits & 2) pixel[168 + i] = colour;
if (bits & 4) pixel[ 2 + i] = colour;
if (bits & 8) pixel[172 + i] = colour;
}
}
}
trackBlock++;
}
// Change rotation and next position based on track curvature
rotation &= 3;
const rct_track_coordinates* track_coordinate = &TrackCoordinates[trackType];
trackType *= 10;
map_offset_with_rotation(&origin.x, &origin.y, track_coordinate->x, track_coordinate->y, rotation);
rotation += track_coordinate->rotation_end - track_coordinate->rotation_begin;
rotation &= 3;
if (track_coordinate->rotation_end & 4)
rotation |= 4;
if (!(rotation & 4)) {
origin.x += TileDirectionDelta[rotation].x;
origin.y += TileDirectionDelta[rotation].y;
}
trackElement++;
}
}
static void window_track_place_draw_mini_preview_maze(int pass, rct_xy16 origin, rct_xy16 *min, rct_xy16 *max)
{
int rotation = (_currentTrackPieceDirection + get_current_rotation()) & 3;
rct_maze_element *mazeElement = gActiveTrackDesign->elements;
while (mazeElement->all != 0) {
sint16 x = mazeElement->x * 32;
sint16 y = mazeElement->y * 32;
rotate_map_coordinates(&x, &y, rotation);
x += origin.x;
y += origin.y;
// Entrance or exit is a lighter colour
uint8 colour = mazeElement->type == 8 || mazeElement->type == 128 ? 222 : 218;
if (pass == 0) {
min->x = min(min->x, x);
max->x = max(max->x, x);
min->y = min(min->y, y);
max->y = max(max->y, y);
} else {
int pixelX = 80 + ((y / 32) - (x / 32)) * 4;
int pixelY = 38 + ((y / 32) + (x / 32)) * 2;
if (pixelX <= 160 && pixelY <= 75) {
uint8 *pixel = &_window_track_place_mini_preview[pixelY * TRACK_MINI_PREVIEW_WIDTH + pixelX];
for (int i = 0; i < 4; i++) {
pixel[338 + i] = colour;
pixel[168 + i] = colour;
pixel[ 2 + i] = colour;
pixel[172 + i] = colour;
}
}
}
mazeElement++;
}
}