1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 11:03:00 +01:00

improve scenario structures

This commit is contained in:
IntelOrca
2014-04-10 03:23:12 +01:00
parent 3ae8971340
commit ea83736d5a
7 changed files with 200 additions and 127 deletions

View File

@@ -32,6 +32,11 @@ int date_get_year(int months)
return months / MONTH_COUNT;
}
int date_get_total_months(int month, int year)
{
return (year - 1) * MONTH_COUNT + month;
}
/**
*
* rct2: 0x006C4494

View File

@@ -34,6 +34,7 @@ enum {
MONTH_COUNT
};
int date_get_total_months(int month, int year);
void date_reset();
#endif

View File

@@ -35,35 +35,31 @@ static void decode_chunk_rotate(char *buffer, int length);
int sawyercoding_read_chunk(HFILE hFile, uint8 *buffer)
{
DWORD numBytesRead;
int i, code;
sawyercoding_chunk_header chunkHeader;
uint8 encoding;
uint32 length;
// Read chunk encoding and length
ReadFile(hFile, &encoding, 1, &numBytesRead, NULL);
ReadFile(hFile, &length, 4, &numBytesRead, NULL);
// Read chunk header
ReadFile(hFile, &chunkHeader, sizeof(sawyercoding_chunk_header), &numBytesRead, NULL);
// Read chunk data
ReadFile(hFile, buffer, length, &numBytesRead, NULL);
ReadFile(hFile, buffer, chunkHeader.length, &numBytesRead, NULL);
// Decode chunk data
switch (encoding) {
switch (chunkHeader.encoding) {
case CHUNK_ENCODING_RLE:
length = decode_chunk_rle(buffer, length);
chunkHeader.length = decode_chunk_rle(buffer, chunkHeader.length);
break;
case CHUNK_ENCODING_RLECOMPRESSED:
length = decode_chunk_rle(buffer, length);
length = decode_chunk_repeat(buffer, length);
chunkHeader.length = decode_chunk_rle(buffer, chunkHeader.length);
chunkHeader.length = decode_chunk_repeat(buffer, chunkHeader.length);
break;
case CHUNK_ENCODING_ROTATE:
decode_chunk_rotate(buffer, length);
decode_chunk_rotate(buffer, chunkHeader.length);
break;
}
// Set length
RCT2_GLOBAL(0x009E3828, uint32) = length;
return length;
RCT2_GLOBAL(0x009E3828, uint32) = chunkHeader.length;
return chunkHeader.length;
}
/**

View File

@@ -22,6 +22,12 @@
#define _SAWYERCODING_H_
#include <windows.h>
#include "rct2.h"
typedef struct {
uint8 encoding;
uint32 length;
} sawyercoding_chunk_header;
enum {
CHUNK_ENCODING_NONE,

View File

@@ -33,6 +33,7 @@
#define RCT2_NUM_SCENARIOS RCT2_GLOBAL(RCT2_ADDRESS_NUM_SCENARIOS, sint32)
int _scenarioListSize;
static void scenario_list_add(char *path);
static void scenario_list_sort();
static int scenario_list_sort_compare(const void* a, const void* b);
static void scenario_scores_load();
@@ -63,99 +64,109 @@ static rct_scenario_basic *get_scenario_by_filename(char *filename)
*/
void scenario_load_list()
{
int i;
HANDLE hFindFile;
WIN32_FIND_DATAA findFileData;
int i;
// Load scores
scenario_scores_load();
// Unset flag 1 for each scenario
// Set all scenarios to be invisible
for (i = 0; i < RCT2_NUM_SCENARIOS; i++)
RCT2_SCENARIO_LIST[i].var_0268 &= ~0x01;
RCT2_SCENARIO_LIST[i].flags &= ~SCENARIO_FLAGS_VISIBLE;
// Enumerate through each scenario in the directory
hFindFile = FindFirstFile(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char), &findFileData);
if (hFindFile != INVALID_HANDLE_VALUE) {
do {
// Check if scenario already exists in list, likely if in scores
rct_scenario_basic *scenario = get_scenario_by_filename(findFileData.cFileName);
if (scenario != NULL) {
// Set 0141EF68 to the scenario path
subsitute_path(
RCT2_ADDRESS(0x0141EF68, char),
RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char),
findFileData.cFileName
);
// Load the basic scenario information
if (!scenario_load_basic(RCT2_ADDRESS(0x0141EF68, char)))
continue;
//
if (RCT2_GLOBAL(0x0141F570, sint8) != -1)
continue;
// Update the scenario information
scenario->var_0268 |= 0x01;
scenario->category = RCT2_GLOBAL(0x0141F571, uint8);
scenario->var_0120 = RCT2_GLOBAL(0x0141F572, sint8);
scenario->var_0121 = RCT2_GLOBAL(0x0141F573, sint8);
scenario->var_0122 = RCT2_GLOBAL(0x0141F574, sint32);
scenario->var_0126 = RCT2_GLOBAL(0x0141F578, sint16);
strcpy(scenario->name, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIO_NAME, char));
strcpy(scenario->details, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIO_DETAILS, char));
continue;
}
// Check if the scenario list buffer has room for another scenario
if ((RCT2_NUM_SCENARIOS + 1) * sizeof(rct_scenario_basic) > _scenarioListSize) {
// Allocate more room
_scenarioListSize += 16 * sizeof(rct_scenario_basic);
RCT2_SCENARIO_LIST = (rct_scenario_basic*)rct2_realloc(RCT2_SCENARIO_LIST, _scenarioListSize);
}
// Set 0141EF68 to the scenario path
subsitute_path(
RCT2_ADDRESS(0x0141EF68, char),
RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char),
findFileData.cFileName
);
// Load the scenario information
if (!scenario_load_basic(RCT2_ADDRESS(0x0141EF68, char)))
continue;
//
if (RCT2_GLOBAL(0x0141F570, sint8) != -1)
continue;
// Increment the number of scenarios
i = RCT2_NUM_SCENARIOS;
RCT2_NUM_SCENARIOS++;
// Add this new scenario to the list
strcpy(RCT2_SCENARIO_LIST[i].path, findFileData.cFileName);
RCT2_SCENARIO_LIST[i].var_0268 = 0x01;
if (RCT2_GLOBAL(0x009AA00C, uint8) & 1)
RCT2_SCENARIO_LIST[i].var_0268 |= 0x04;
RCT2_SCENARIO_LIST[i].category = RCT2_GLOBAL(0x0141F571, uint8);
RCT2_SCENARIO_LIST[i].var_0120 = RCT2_GLOBAL(0x0141F572, sint8);
RCT2_SCENARIO_LIST[i].var_0121 = RCT2_GLOBAL(0x0141F573, sint8);
RCT2_SCENARIO_LIST[i].var_0122 = RCT2_GLOBAL(0x0141F574, sint32);
RCT2_SCENARIO_LIST[i].var_0126 = RCT2_GLOBAL(0x0141F578, sint16);
strcpy(RCT2_SCENARIO_LIST[i].name, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIO_NAME, char));
strcpy(RCT2_SCENARIO_LIST[i].details, RCT2_ADDRESS(RCT2_ADDRESS_SCENARIO_DETAILS, char));
scenario_list_add(findFileData.cFileName);
} while (FindNextFile(hFindFile, &findFileData));
FindClose(hFindFile);
}
// Sort alphabetically
scenario_list_sort();
// Save the scores
scenario_scores_save();
}
static void scenario_list_add(char *path)
{
int i;
rct_scenario_basic *scenario;
rct_s6_info *s6Info = 0x0141F570;
// Check if scenario already exists in list, likely if in scores
scenario = get_scenario_by_filename(path);
if (scenario != NULL) {
// Set 0141EF68 to the scenario path
subsitute_path(
RCT2_ADDRESS(0x0141EF68, char),
RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char),
path
);
// Load the basic scenario information
if (!scenario_load_basic(RCT2_ADDRESS(0x0141EF68, char)))
return;
//
if (s6Info->var_000 != 255)
return;
// Update the scenario information
scenario->flags |= SCENARIO_FLAGS_VISIBLE;
scenario->category = s6Info->category;
scenario->objective_type = s6Info->objective_type;
scenario->objective_arg_1 = s6Info->objective_arg_1;
scenario->objective_arg_2 = s6Info->objective_arg_2;
scenario->objective_arg_3 = s6Info->objective_arg_3;
strcpy(scenario->name, s6Info->name);
strcpy(scenario->details, s6Info->details);
return;
}
// Check if the scenario list buffer has room for another scenario
if ((RCT2_NUM_SCENARIOS + 1) * sizeof(rct_scenario_basic) > _scenarioListSize) {
// Allocate more room
_scenarioListSize += 16 * sizeof(rct_scenario_basic);
RCT2_SCENARIO_LIST = (rct_scenario_basic*)rct2_realloc(RCT2_SCENARIO_LIST, _scenarioListSize);
}
// Set 0141EF68 to the scenario path
subsitute_path(
RCT2_ADDRESS(0x0141EF68, char),
RCT2_ADDRESS(RCT2_ADDRESS_SCENARIOS_PATH, char),
path
);
// Load the scenario information
if (!scenario_load_basic(RCT2_ADDRESS(0x0141EF68, char)))
return;
//
if (s6Info->var_000 != 255)
return;
// Increment the number of scenarios
scenario = &RCT2_SCENARIO_LIST[RCT2_NUM_SCENARIOS];
RCT2_NUM_SCENARIOS++;
// Add this new scenario to the list
strcpy(scenario->path, path);
scenario->flags = SCENARIO_FLAGS_VISIBLE;
if (RCT2_GLOBAL(0x009AA00C, uint8) & 1)
scenario->flags |= SCENARIO_FLAGS_SIXFLAGS;
scenario->category = s6Info->category;
scenario->objective_type = s6Info->objective_type;
scenario->objective_arg_1 = s6Info->objective_arg_1;
scenario->objective_arg_2 = s6Info->objective_arg_2;
scenario->objective_arg_3 = s6Info->objective_arg_3;
strcpy(scenario->name, s6Info->name);
strcpy(scenario->details, s6Info->details);
}
/**
* Sort the list of scenarios. This used to be an insertion sort which took
* place as each scenario loaded. It has now been changed to a quicksort which
@@ -248,17 +259,22 @@ static int scenario_load_basic(char *path)
{
HANDLE hFile;
int _eax;
rct_s6_header *s6Header = 0x009E34E4;
rct_s6_info *s6Info = 0x0141F570;
hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_FLAG_RANDOM_ACCESS | FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
RCT2_GLOBAL(0x009E382C, HANDLE*) = hFile;
sawyercoding_read_chunk(hFile, 0x009E34E4);
if (RCT2_GLOBAL(0x009E34E4, uint8) == 1) {
sawyercoding_read_chunk(hFile, 0x0141F570);
// Read first chunk
sawyercoding_read_chunk(hFile, s6Header);
if (s6Header->type == S6_TYPE_SCENARIO) {
// Read second chunk
sawyercoding_read_chunk(hFile, s6Info);
CloseHandle(hFile);
RCT2_GLOBAL(0x009AA00C, uint8) = 0;
if (RCT2_GLOBAL(0x0141F6F8, uint8) != 255) {
if (s6Info->flags != 255) {
__asm {
push ebp
mov ebp, 0141F6F8h
@@ -270,8 +286,8 @@ static int scenario_load_basic(char *path)
}
int ebp = RCT2_GLOBAL(0x009ADAF8, uint32);
format_string(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIO_NAME, char), RCT2_GLOBAL(ebp, sint16), NULL);
format_string(RCT2_ADDRESS(RCT2_ADDRESS_SCENARIO_DETAILS, char), RCT2_GLOBAL(ebp + 4, sint16), NULL);
format_string(s6Info->name, RCT2_GLOBAL(ebp, sint16), NULL);
format_string(s6Info->details, RCT2_GLOBAL(ebp + 4, sint16), NULL);
RCT2_GLOBAL(0x009AA00C, uint8) = RCT2_GLOBAL(ebp + 6, uint8);
RCT2_CALLPROC(0x006A982D);
__asm mov _eax, eax

View File

@@ -23,6 +23,37 @@
#include "rct2.h"
/**
* SV6/SC6 header chunk
* size: 0x20
*/
typedef struct {
uint16 type; // 0x00
uint16 num_packed_objects; // 0x02
uint32 version; // 0x04
uint32 magic_number; // 0x08
uint8 pad_0C[0x14];
} rct_s6_header;
/**
* SC6 information chunk
* size: 0x198
*/
typedef struct {
uint8 var_000;
uint8 category; // 0x01
uint8 objective_type; // 0x02
uint8 objective_arg_1; // 0x03
sint32 objective_arg_2; // 0x04
sint16 objective_arg_3; // 0x08
uint8 pad_00A[0x3E];
char name[64]; // 0x48
char details[256]; // 0x88
uint8 flags; // 0x188
uint8 pad_189[0x0F];
} rct_s6_info;
/**
* Scenario basic structure, mainly for scenario select
* size: 0x02B0
@@ -31,17 +62,36 @@ typedef struct {
char path[256]; // 0x0000
uint8 category; // 0x0100
uint8 pad_0101[0x1F];
sint8 var_0120;
sint8 var_0121;
sint32 var_0122;
sint16 var_0126;
sint8 objective_type; // 0x0120
sint8 objective_arg_1; // 0x0121
sint32 objective_arg_2; // 0x0122
sint16 objective_arg_3; // 0x0126
char name[64]; // 0x0128
char details[256]; // 0x0168
sint32 var_0268;
uint32 pad_026C;
sint8 var_0270[64];
sint32 flags; // 0x0268
uint32 company_value; // 0x026C
char completed_by[64]; // 0x0270
} rct_scenario_basic;
enum {
SCENARIO_FLAGS_VISIBLE = (1 << 0),
SCENARIO_FLAGS_COMPLETED = (1 << 1),
SCENARIO_FLAGS_SIXFLAGS = (1 << 2)
};
enum {
S6_TYPE_SAVEDGAME,
S6_TYPE_SCENARIO
};
enum {
SCENARIO_CATEGORY_BEGINNER,
SCENARIO_CATEGORY_CHALLENGING,
SCENARIO_CATEGORY_EXPERT,
SCENARIO_CATEGORY_REAL,
SCENARIO_CATEGORY_BUILDYOUROWN
};
enum {
OBJECTIVE_NONE,
OBJECTIVE_GUESTS_BY,

View File

@@ -20,6 +20,7 @@
#include "addresses.h"
#include "audio.h"
#include "date.h"
#include "scenario.h"
#include "strings.h"
#include "sprites.h"
@@ -147,10 +148,8 @@ static void window_scenarioselect_init_tabs()
show_pages = 0;
for (i = 0; i < RCT2_GLOBAL(RCT2_ADDRESS_NUM_SCENARIOS, sint32); i++) {
scenario = &(RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_LIST, rct_scenario_basic*)[i]);
if (!(scenario->var_0268 & 1))
continue;
show_pages |= 1 << scenario->category;
if (scenario->flags & SCENARIO_FLAGS_VISIBLE)
show_pages |= 1 << scenario->category;
}
x = 3;
@@ -212,10 +211,8 @@ static void window_scenarioselect_scrollgetsize()
scenario = &(RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_LIST, rct_scenario_basic*)[i]);
if (scenario->category != w->var_4AC)
continue;
if (!(scenario->var_0268 & 1))
continue;
height += 24;
if (scenario->flags & SCENARIO_FLAGS_VISIBLE)
height += 24;
}
__asm mov ecx, 0
@@ -237,7 +234,7 @@ static void window_scenarioselect_scrollmousedown()
scenario = &(RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_LIST, rct_scenario_basic*)[i]);
if (scenario->category != w->var_4AC)
continue;
if (!(scenario->var_0268 & 1))
if (!(scenario->flags & SCENARIO_FLAGS_VISIBLE))
continue;
y -= 24;
@@ -266,7 +263,7 @@ static void window_scenarioselect_scrollmouseover()
scenario = &(RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_LIST, rct_scenario_basic*)[i]);
if (scenario->category != w->var_4AC)
continue;
if (!(scenario->var_0268 & 1))
if (!(scenario->flags & SCENARIO_FLAGS_VISIBLE))
continue;
y -= 24;
@@ -298,6 +295,7 @@ static void window_scenarioselect_paint()
rct_window *w;
rct_drawpixelinfo *dpi;
rct_widget *widget;
rct_scenario_basic *scenario;
__asm mov w, esi
__asm mov dpi, edi
@@ -317,40 +315,41 @@ static void window_scenarioselect_paint()
}
// Return if no scenario highlighted
if (w->var_494 == NULL)
scenario = (rct_scenario_basic*)w->var_494;
if (scenario == NULL)
return;
// Draw SixFlags image
if (*((int*)(w->var_494 + 0x0268)) & 4)
if (scenario->flags & SCENARIO_FLAGS_SIXFLAGS)
gfx_draw_sprite(dpi, SPR_SIX_FLAGS, w->x + w->width - 55, w->y + w->height - 75);
// Scenario name
x = w->x + window_scenarioselect_widgets[WIDX_SCENARIOLIST].right + 4;
y = w->y + window_scenarioselect_widgets[WIDX_TABCONTENT].top + 5;
strcpy(0x009BC677, (char*)(w->var_494 + 0x0128));
strcpy(0x009BC677, scenario->name);
*((short*)(0x0013CE952 + 0)) = 3165;
gfx_draw_string_centred_clipped(dpi, 1193, (void*)0x013CE952, 0, x + 85, y, 170);
y += 15;
// Scenario description
strcpy(0x009BC677, (char*)(w->var_494 + 0x0168));
// Scenario details
strcpy(0x009BC677, scenario->details);
*((short*)(0x0013CE952 + 0)) = 3165;
y += gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x, y, 170, 1191, 0) + 5;
// Scenario objective
*((short*)(0x0013CE952 + 0)) = *((unsigned char*)(w->var_494 + 0x0120)) + STR_OBJECTIVE_NONE;
*((short*)(0x0013CE952 + 2)) = *((short*)(w->var_494 + 0x0126));
*((short*)(0x0013CE956 + 0)) = *((unsigned char*)(w->var_494 + 0x0121)) * 8 - 1;
*((int*)(0x0013CE956 + 2)) = *((int*)(w->var_494 + 0x0122));
*((short*)(0x0013CE952 + 0)) = scenario->objective_type + STR_OBJECTIVE_NONE;
*((short*)(0x0013CE952 + 2)) = scenario->objective_arg_3;
*((short*)(0x0013CE952 + 4)) = date_get_total_months(MONTH_OCTOBER, scenario->objective_arg_1);
*((int*)(0x0013CE952 + 6)) = scenario->objective_arg_2;
y += gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x, y, 170, STR_OBJECTIVE, 0) + 5;
// Scenario score
if (!(*((int*)(w->var_494 + 0x0268)) & 2))
return;
strcpy(0x009BC677, (char*)(w->var_494 + 0x0270));
*((short*)(0x0013CE952 + 0)) = 3165;
*((int*)(0x0013CE952 + 2)) = *((int*)(w->var_494 + 0x026C));
y += gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x, y, 170, STR_COMPLETED_BY_WITH_COMPANY_VALUE, 0);
if (scenario->flags & SCENARIO_FLAGS_COMPLETED) {
strcpy(0x009BC677, scenario->completed_by);
*((short*)(0x0013CE952 + 0)) = 3165;
*((int*)(0x0013CE952 + 2)) = scenario->company_value;
y += gfx_draw_string_left_wrapped(dpi, (void*)0x013CE952, x, y, 170, STR_COMPLETED_BY_WITH_COMPANY_VALUE, 0);
}
}
static void window_scenarioselect_scrollpaint()
@@ -372,7 +371,7 @@ static void window_scenarioselect_scrollpaint()
scenario = &(RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_LIST, rct_scenario_basic*)[i]);
if (scenario->category != w->var_4AC)
continue;
if (!(scenario->var_0268 & 1))
if (!(scenario->flags & SCENARIO_FLAGS_VISIBLE))
continue;
if (y > dpi->y + dpi->height)
@@ -390,12 +389,12 @@ static void window_scenarioselect_scrollpaint()
gfx_draw_string_centred(dpi, highlighted ? 1193 : 1191, 210, y + 1, 0, (void*)0x013CE952);
// Check if scenario is completed
if (scenario->var_0268 & 2) {
if (scenario->flags & SCENARIO_FLAGS_COMPLETED) {
// Draw completion tick
gfx_draw_sprite(dpi, 0x5A9F, 395, y + 1);
// Draw completion score
strcpy((char*)0x009BC677, scenario->var_0270);
strcpy((char*)0x009BC677, scenario->completed_by);
*((short*)0x013CE952) = 2793;
*((short*)0x013CE954) = 3165;
gfx_draw_string_centred(dpi, highlighted ? 1193 : 1191, 210, y + 11, 0, (void*)0x013CE952);