1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-22 14:24:33 +01:00

Merge branch 'develop' into vehicle-update

Conflicts:
 openrct2.vcxproj
This commit is contained in:
duncanspumpkin
2016-01-10 08:57:41 +00:00
36 changed files with 802 additions and 1036 deletions

324
src/argparse/argparse.c Normal file
View File

@@ -0,0 +1,324 @@
#include "argparse.h"
#define OPT_UNSET 1
static const char *
prefix_skip(const char *str, const char *prefix)
{
size_t len = strlen(prefix);
return strncmp(str, prefix, len) ? NULL : str + len;
}
int
prefix_cmp(const char *str, const char *prefix)
{
for (;; str++, prefix++)
if (!*prefix)
return 0;
else if (*str != *prefix)
return (unsigned char)*prefix - (unsigned char)*str;
}
static void
argparse_error(struct argparse *this, const struct argparse_option *opt,
const char *reason)
{
if (!strncmp(this->argv[0], "--", 2)) {
fprintf(stderr, "error: option `%s` %s\n", opt->long_name, reason);
exit(1);
} else {
fprintf(stderr, "error: option `%c` %s\n", opt->short_name, reason);
exit(1);
}
}
static int
argparse_getvalue(struct argparse *this, const struct argparse_option *opt,
int flags)
{
const char *s = NULL;
if (!opt->value)
goto skipped;
switch (opt->type) {
case ARGPARSE_OPT_BOOLEAN:
if (flags & OPT_UNSET) {
*(int *)opt->value = *(int *)opt->value - 1;
} else {
*(int *)opt->value = *(int *)opt->value + 1;
}
if (*(int *)opt->value < 0) {
*(int *)opt->value = 0;
}
break;
case ARGPARSE_OPT_BIT:
if (flags & OPT_UNSET) {
*(int *)opt->value &= ~opt->data;
} else {
*(int *)opt->value |= opt->data;
}
break;
case ARGPARSE_OPT_STRING:
if (this->optvalue) {
*(const char **)opt->value = this->optvalue;
this->optvalue = NULL;
} else if (this->argc > 1) {
this->argc--;
*(const char **)opt->value = *++this->argv;
} else {
argparse_error(this, opt, "requires a value");
}
break;
case ARGPARSE_OPT_INTEGER:
if (this->optvalue) {
*(int *)opt->value = strtol(this->optvalue, (char **)&s, 0);
this->optvalue = NULL;
} else if (this->argc > 1) {
this->argc--;
*(int *)opt->value = strtol(*++this->argv, (char **)&s, 0);
} else {
argparse_error(this, opt, "requires a value");
}
if (s[0] != '\0')
argparse_error(this, opt, "expects a numerical value");
break;
default:
assert(0);
}
skipped:
if (opt->callback) {
return opt->callback(this, opt);
}
return 0;
}
static void
argparse_options_check(const struct argparse_option *options)
{
for (; options->type != ARGPARSE_OPT_END; options++) {
switch (options->type) {
case ARGPARSE_OPT_END:
case ARGPARSE_OPT_BOOLEAN:
case ARGPARSE_OPT_BIT:
case ARGPARSE_OPT_INTEGER:
case ARGPARSE_OPT_STRING:
case ARGPARSE_OPT_GROUP:
continue;
default:
fprintf(stderr, "wrong option type: %d", options->type);
break;
}
}
}
static int
argparse_short_opt(struct argparse *this, const struct argparse_option *options)
{
for (; options->type != ARGPARSE_OPT_END; options++) {
if (options->short_name == *this->optvalue) {
this->optvalue = this->optvalue[1] ? this->optvalue + 1 : NULL;
return argparse_getvalue(this, options, 0);
}
}
return -2;
}
static int
argparse_long_opt(struct argparse *this, const struct argparse_option *options)
{
for (; options->type != ARGPARSE_OPT_END; options++) {
const char *rest;
int opt_flags = 0;
if (!options->long_name)
continue;
rest = prefix_skip(this->argv[0] + 2, options->long_name);
if (!rest) {
// Negation allowed?
if (options->flags & OPT_NONEG) {
continue;
}
// Only boolean/bit allow negation.
if (options->type != ARGPARSE_OPT_BOOLEAN && options->type != ARGPARSE_OPT_BIT) {
continue;
}
if (!prefix_cmp(this->argv[0] + 2, "no-")) {
rest = prefix_skip(this->argv[0] + 2 + 3, options->long_name);
if (!rest)
continue;
opt_flags |= OPT_UNSET;
} else {
continue;
}
}
if (*rest) {
if (*rest != '=')
continue;
this->optvalue = rest + 1;
}
return argparse_getvalue(this, options, opt_flags);
}
return -2;
}
int
argparse_init(struct argparse *this, struct argparse_option *options,
const char *const *usage, int flags)
{
memset(this, 0, sizeof(*this));
this->options = options;
this->usage = usage;
this->flags = flags;
return 0;
}
int
argparse_parse(struct argparse *this, int argc, const char **argv)
{
this->argc = argc - 1;
this->argv = argv + 1;
this->out = argv;
argparse_options_check(this->options);
for (; this->argc; this->argc--, this->argv++) {
const char *arg = this->argv[0];
if (arg[0] != '-' || !arg[1]) {
if (this->flags & ARGPARSE_STOP_AT_NON_OPTION) {
goto end;
}
// if it's not option or is a single char '-', copy verbatimly
this->out[this->cpidx++] = this->argv[0];
continue;
}
// short option
if (arg[1] != '-') {
this->optvalue = arg + 1;
switch (argparse_short_opt(this, this->options)) {
case -1:
break;
case -2:
goto unknown;
}
while (this->optvalue) {
switch (argparse_short_opt(this, this->options)) {
case -1:
break;
case -2:
goto unknown;
}
}
continue;
}
// if '--' presents
if (!arg[2]) {
this->argc--;
this->argv++;
break;
}
// long option
switch (argparse_long_opt(this, this->options)) {
case -1:
break;
case -2:
goto unknown;
}
continue;
unknown:
fprintf(stderr, "error: unknown option `%s`\n", this->argv[0]);
argparse_usage(this);
exit(1);
}
end:
memmove((void*)(this->out + this->cpidx),
this->argv,
this->argc * sizeof(*this->out));
this->out[this->cpidx + this->argc] = NULL;
return this->cpidx + this->argc;
}
void
argparse_usage(struct argparse *this)
{
fprintf(stdout, "Usage: %s\n", *this->usage++);
while (*this->usage && **this->usage)
fprintf(stdout, " or: %s\n", *this->usage++);
fputc('\n', stdout);
const struct argparse_option *options;
// figure out best width
size_t usage_opts_width = 0;
size_t len;
options = this->options;
for (; options->type != ARGPARSE_OPT_END; options++) {
len = 0;
if ((options)->short_name) {
len += 2;
}
if ((options)->short_name && (options)->long_name) {
len += 2; // separator ", "
}
if ((options)->long_name) {
len += strlen((options)->long_name) + 2;
}
if (options->type == ARGPARSE_OPT_INTEGER) {
len += strlen("=<int>");
} else if (options->type == ARGPARSE_OPT_STRING) {
len += strlen("=<str>");
}
len = ((len + 3) / 4) * 4;
if (usage_opts_width < len) {
usage_opts_width = len;
}
}
usage_opts_width += 4; // 4 spaces prefix
options = this->options;
for (; options->type != ARGPARSE_OPT_END; options++) {
size_t pos = 0;
int pad = 0;
if (options->type == ARGPARSE_OPT_GROUP) {
fputc('\n', stdout);
pos += fprintf(stdout, "%s", options->help);
fputc('\n', stdout);
continue;
}
pos = fprintf(stdout, " ");
if (options->short_name) {
pos += fprintf(stdout, "-%c", options->short_name);
}
if (options->long_name && options->short_name) {
pos += fprintf(stdout, ", ");
}
if (options->long_name) {
pos += fprintf(stdout, "--%s", options->long_name);
}
if (options->type == ARGPARSE_OPT_INTEGER) {
pos += fprintf(stdout, "=<int>");
} else if (options->type == ARGPARSE_OPT_STRING) {
pos += fprintf(stdout, "=<str>");
}
if (pos <= usage_opts_width) {
pad = usage_opts_width - pos;
} else {
fputc('\n', stdout);
pad = usage_opts_width;
}
fprintf(stdout, "%*s%s\n", pad + 2, "", options->help);
}
}
int
argparse_help_cb(struct argparse *this, const struct argparse_option *option)
{
(void)option;
argparse_usage(this);
exit(0);
return 0;
}

132
src/argparse/argparse.h Normal file
View File

@@ -0,0 +1,132 @@
#ifndef ARGPARSE_H
#define ARGPARSE_H
/**
* Command-line arguments parsing library.
*
* This module is inspired by parse-options.c (git) and python's argparse
* module.
*
* Arguments parsing is common task in cli program, but traditional `getopt`
* libraries are not easy to use. This library provides high-level arguments
* parsing solutions.
*
* The program defines what arguments it requires, and `argparse` will figure
* out how to parse those out of `argc` and `argv`, it also automatically
* generates help and usage messages and issues errors when users give the
* program invalid arguments.
*
* Reserved namespaces:
* argparse
* OPT
* Author: Yecheng Fu <cofyc.jackson@gmail.com>
*/
#include <assert.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct argparse;
struct argparse_option;
typedef int argparse_callback(struct argparse *this,
const struct argparse_option *option);
enum argparse_flag {
ARGPARSE_STOP_AT_NON_OPTION = 1,
};
enum argparse_option_type {
/* special */
ARGPARSE_OPT_END,
ARGPARSE_OPT_GROUP,
/* options with no arguments */
ARGPARSE_OPT_BOOLEAN,
ARGPARSE_OPT_BIT,
/* options with arguments (optional or required) */
ARGPARSE_OPT_INTEGER,
ARGPARSE_OPT_STRING,
};
enum argparse_option_flags {
OPT_NONEG = 1, /* Negation disabled. */
};
/*
* Argparse option struct.
*
* `type`:
* holds the type of the option, you must have an ARGPARSE_OPT_END last in your
* array.
*
* `short_name`:
* the character to use as a short option name, '\0' if none.
*
* `long_name`:
* the long option name, without the leading dash, NULL if none.
*
* `value`:
* stores pointer to the value to be filled.
*
* `help`:
* the short help message associated to what the option does.
* Must never be NULL (except for ARGPARSE_OPT_END).
*
* `callback`:
* function is called when corresponding argument is parsed.
*
* `data`:
* associated data. Callbacks can use it like they want.
*
* `flags`:
* option flags.
*
*/
struct argparse_option {
enum argparse_option_type type;
const char short_name;
const char *long_name;
void *value;
const char *help;
argparse_callback *callback;
intptr_t data;
int flags;
};
/*
* argpparse
*/
struct argparse {
// user supplied
const struct argparse_option *options;
const char *const *usage;
int flags;
// internal context
int argc;
const char **argv;
const char **out;
int cpidx;
const char *optvalue; // current option value
};
// builtin callbacks
int argparse_help_cb(struct argparse *this,
const struct argparse_option *option);
// builtin option macros
#define OPT_END() { ARGPARSE_OPT_END }
#define OPT_BOOLEAN(...) { ARGPARSE_OPT_BOOLEAN, __VA_ARGS__ }
#define OPT_BIT(...) { ARGPARSE_OPT_BIT, __VA_ARGS__ }
#define OPT_INTEGER(...) { ARGPARSE_OPT_INTEGER, __VA_ARGS__ }
#define OPT_STRING(...) { ARGPARSE_OPT_STRING, __VA_ARGS__ }
#define OPT_GROUP(h) { ARGPARSE_OPT_GROUP, 0, NULL, NULL, h, NULL }
#define OPT_HELP() OPT_BOOLEAN('h', "help", NULL, "show this help message and exit", argparse_help_cb)
int argparse_init(struct argparse *this, struct argparse_option *options,
const char *const *usage, int flags);
int argparse_parse(struct argparse *this, int argc, const char **argv);
void argparse_usage(struct argparse *this);
#endif

View File

@@ -19,7 +19,7 @@
*****************************************************************************/
#include <time.h>
#include <argparse/argparse.h>
#include "argparse/argparse.h"
#include "addresses.h"
#include "cmdline.h"
#include "interface/screenshot.h"
@@ -108,7 +108,7 @@ int cmdline_run(const char **argv, int argc)
*/
int k=0;
for (int i=0; i < argc; ++i)
if (strcmp(argv[k], "-NSDocumentRevisionsDebugMode") != 0)
if (strcmp(argv[k], "-NSDocumentRevisionsDebugMode") != 0 && strncmp(argv[k], "-psn_", 5) != 0)
mutableArgv[k++] = (char *) argv[i];
argc = k;
#else

View File

@@ -331,6 +331,11 @@ static void rwopswritec(SDL_RWops *file, char c)
SDL_RWwrite(file, &c, 1, 1);
}
static void rwopswritestr(SDL_RWops *file, const char *str)
{
SDL_RWwrite(file, str, strlen(str), 1);
}
static void rwopsprintf(SDL_RWops *file, const char *format, ...)
{
va_list args;
@@ -344,6 +349,11 @@ static void rwopsprintf(SDL_RWops *file, const char *format, ...)
va_end(args);
}
static void rwopswritenewline(SDL_RWops *file)
{
rwopswritestr(file, platform_get_new_line());
}
void config_set_defaults()
{
int i, j;
@@ -478,24 +488,24 @@ bool config_save(const utf8string path)
config_section_definition *section = &_sectionDefinitions[i];
rwopswritec(file, '[');
SDL_RWwrite(file, section->section_name, strlen(section->section_name), 1);
rwopswritestr(file, section->section_name);
rwopswritec(file, ']');
rwopswritec(file, '\n');
rwopswritenewline(file);
for (j = 0; j < section->property_definitions_count; j++) {
config_property_definition *property = &section->property_definitions[j];
SDL_RWwrite(file, property->property_name, strlen(property->property_name), 1);
SDL_RWwrite(file, " = ", 3, 1);
rwopswritestr(file, property->property_name);
rwopswritestr(file, " = ");
value = (value_union*)((size_t)section->base_address + (size_t)property->offset);
if (property->enum_definitions != NULL)
config_write_enum(file, property->type, value, property->enum_definitions);
else
config_save_property_value(file, property->type, value);
rwopswritec(file, '\n');
rwopswritenewline(file);
}
rwopswritec(file, '\n');
rwopswritenewline(file);
}
SDL_RWclose(file);
@@ -506,8 +516,8 @@ static void config_save_property_value(SDL_RWops *file, uint8 type, value_union
{
switch (type) {
case CONFIG_VALUE_TYPE_BOOLEAN:
if (value->value_boolean) SDL_RWwrite(file, "true", 4, 1);
else SDL_RWwrite(file, "false", 5, 1);
if (value->value_boolean) rwopswritestr(file, "true");
else rwopswritestr(file, "false");
break;
case CONFIG_VALUE_TYPE_UINT8:
rwopsprintf(file, "%u", value->value_uint8);
@@ -535,8 +545,9 @@ static void config_save_property_value(SDL_RWops *file, uint8 type, value_union
break;
case CONFIG_VALUE_TYPE_STRING:
rwopswritec(file, '"');
if (value->value_string != NULL)
SDL_RWwrite(file, value->value_string, strlen(value->value_string), 1);
if (value->value_string != NULL) {
rwopswritestr(file, value->value_string);
}
rwopswritec(file, '"');
break;
}
@@ -728,7 +739,7 @@ static void config_write_enum(SDL_RWops *file, uint8 type, value_union *value, c
uint32 enumValue = (value->value_uint32) & ((1 << (_configValueTypeSize[type] * 8)) - 1);
while (enumDefinitions->key != NULL) {
if (enumDefinitions->value.value_uint32 == enumValue) {
SDL_RWwrite(file, enumDefinitions->key, strlen(enumDefinitions->key), 1);
rwopswritestr(file, enumDefinitions->key);
return;
}
enumDefinitions++;
@@ -1231,15 +1242,15 @@ static bool themes_save(const_utf8string path, int preset)
theme_section_definition *section = &_themeSectionDefinitions[i];
rwopswritec(file, '[');
SDL_RWwrite(file, section->section_name, strlen(section->section_name), 1);
rwopswritestr(file, section->section_name);
rwopswritec(file, ']');
rwopswritec(file, '\n');
rwopswritenewline(file);
for (j = 0; j < section->property_definitions_count; j++) {
theme_property_definition *property = &section->property_definitions[j];
SDL_RWwrite(file, property->property_name, strlen(property->property_name), 1);
SDL_RWwrite(file, " = ", 3, 1);
rwopswritestr(file, property->property_name);
rwopswritestr(file, " = ");
value = (value_union*)((size_t)&gConfigThemes.presets[preset] + (size_t)section->offset + (size_t)property->offset);
@@ -1247,24 +1258,24 @@ static bool themes_save(const_utf8string path, int preset)
config_write_enum(file, property->type, value, property->enum_definitions);
else
config_save_property_value(file, property->type, value);
rwopswritec(file, '\n');
rwopswritenewline(file);
}
rwopswritec(file, '\n');
rwopswritenewline(file);
}
for (i = 0; i < (int)gNumThemeWindows; i++) {
theme_section_definition *section = &_themeSectionDefinitions[0];
rwopswritec(file, '[');
SDL_RWwrite(file, gThemeWindowDefinitions[i].section_name, strlen(gThemeWindowDefinitions[i].section_name), 1);
rwopswritestr(file, gThemeWindowDefinitions[i].section_name);
rwopswritec(file, ']');
rwopswritec(file, '\n');
rwopswritenewline(file);
for (j = 0; j < section->property_definitions_count; j++) {
theme_property_definition *property = &section->property_definitions[j];
SDL_RWwrite(file, property->property_name, strlen(property->property_name), 1);
SDL_RWwrite(file, " = ", 3, 1);
rwopswritestr(file, property->property_name);
rwopswritestr(file, " = ");
value = (value_union*)((size_t)gConfigThemes.presets[preset].windows + (size_t)(sizeof(theme_window) * i) + (size_t)property->offset);
@@ -1272,7 +1283,7 @@ static bool themes_save(const_utf8string path, int preset)
config_write_enum(file, property->type, value, property->enum_definitions);
else
config_save_property_value(file, property->type, value);
rwopswritec(file, '\n');
rwopswritenewline(file);
}
}
@@ -1627,33 +1638,34 @@ void title_sequence_save_preset_script(int preset)
switch (command->command) {
case TITLE_SCRIPT_LOAD:
if (command->saveIndex == 0xFF)
rwopsprintf(file, "LOAD <No save file>\r\n");
rwopsprintf(file, "LOAD <No save file>");
else
rwopsprintf(file, "LOAD %s\r\n", gConfigTitleSequences.presets[preset].saves[command->saveIndex]);
rwopsprintf(file, "LOAD %s", gConfigTitleSequences.presets[preset].saves[command->saveIndex]);
break;
case TITLE_SCRIPT_LOCATION:
rwopsprintf(file, "LOCATION %i %i\r\n", command->x, command->y);
rwopsprintf(file, "LOCATION %i %i", command->x, command->y);
break;
case TITLE_SCRIPT_ROTATE:
rwopsprintf(file, "ROTATE %i\r\n", command->rotations);
rwopsprintf(file, "ROTATE %i", command->rotations);
break;
case TITLE_SCRIPT_ZOOM:
rwopsprintf(file, "ZOOM %i\r\n", command->zoom);
rwopsprintf(file, "ZOOM %i", command->zoom);
break;
case TITLE_SCRIPT_SPEED:
rwopsprintf(file, "SPEED %i\r\n", command->speed);
rwopsprintf(file, "SPEED %i", command->speed);
break;
case TITLE_SCRIPT_WAIT:
rwopsprintf(file, "WAIT %i\r\n\r\n", command->seconds);
rwopsprintf(file, "WAIT %i", command->seconds);
rwopswritenewline(file);
break;
case TITLE_SCRIPT_RESTART:
rwopsprintf(file, "RESTART\r\n");
rwopsprintf(file, "RESTART");
break;
case TITLE_SCRIPT_END:
rwopsprintf(file, "END\r\n");
rwopsprintf(file, "END");
break;
}
rwopswritenewline(file);
}
SDL_RWclose(file);

View File

@@ -1835,6 +1835,10 @@ enum {
STR_OBJECTIVE = 3322,
STR_MISSING_OBJECT_DATA_ID = 3323,
STR_REQUIRES_THE_FOLLOWING_ADDON_PACK = 3324,
STR_REQUIRES_AN_ADDON_PACK = 3325,
STR_PEEP_SPAWNS_NOT_SET = 3327,
STR_CANT_ADVANCE_TO_NEXT_EDITOR_STAGE = 3328,
STR_NO_PARK_ENTRANCES = 3329,

View File

@@ -484,16 +484,20 @@ void object_create_identifier_name(char* string_buffer, const rct_object_entry*
*
* rct2: 0x675827
*/
void set_load_objects_fail_reason(){
void set_load_objects_fail_reason()
{
rct_string_id expansionNameId;
rct_object_entry* object = RCT2_ADDRESS(0x13CE952, rct_object_entry);
int expansion = (object->flags & 0xFF) >> 4;
if (expansion == 0
|| expansion == 8
|| RCT2_GLOBAL(0x9AB4C0, uint16) & (1 << expansion)){
char* string_buffer = RCT2_ADDRESS(0x9BC677, char);
format_string(string_buffer, 3323, 0); //Missing object data, ID:
format_string(string_buffer, STR_MISSING_OBJECT_DATA_ID, 0);
object_create_identifier_name(string_buffer, object);
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 0xFF;
@@ -501,17 +505,23 @@ void set_load_objects_fail_reason(){
return;
}
char* exapansion_name = &RCT2_ADDRESS(RCT2_ADDRESS_EXPANSION_NAMES, char)[128 * expansion];
if (*exapansion_name == '\0'){
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 0xFF;
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = 3325;
return;
switch(expansion) {
case 1: // Wacky Worlds
expansionNameId = STR_OBJECT_FILTER_WW;
break;
case 2: // Time Twister
expansionNameId = STR_OBJECT_FILTER_TT;
break;
default:
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 0xFF;
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = STR_REQUIRES_AN_ADDON_PACK;
return;
}
char* string_buffer = RCT2_ADDRESS(0x9BC677, char);
format_string(string_buffer, 3324, 0); // Requires expansion pack
strcat(string_buffer, exapansion_name);
format_string(string_buffer, STR_REQUIRES_THE_FOLLOWING_ADDON_PACK, &expansionNameId);
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 0xFF;
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = 3165;
}

View File

@@ -125,6 +125,7 @@ void platform_get_time(rct2_time *out_time);
// Platform specific definitions
void platform_get_exe_path(utf8 *outPath);
const char *platform_get_new_line();
char platform_get_path_separator();
bool platform_file_exists(const utf8 *path);
bool platform_directory_exists(const utf8 *path);

View File

@@ -91,6 +91,11 @@ char platform_get_path_separator()
return '/';
}
const char *platform_get_new_line()
{
return "\n";
}
bool platform_file_exists(const utf8 *path)
{
wchar_t *wPath = utf8_to_widechar(path);

View File

@@ -148,6 +148,11 @@ char platform_get_path_separator()
return '\\';
}
const char *platform_get_new_line()
{
return "\r\n";
}
bool platform_file_exists(const utf8 *path)
{
wchar_t *wPath = utf8_to_widechar(path);

View File

@@ -5766,95 +5766,115 @@ void game_command_demolish_ride(int *eax, int *ebx, int *ecx, int *edx, int *esi
*/
void game_command_set_ride_appearance(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp)
{
if(*ebx & GAME_COMMAND_FLAG_APPLY){
uint8 ride_id = *edx;
uint8 type = *ebx >> 8;
uint8 value = *edx >> 8;
int index = *edi;
if (index < 0) {
bool apply = (*ebx & GAME_COMMAND_FLAG_APPLY);
uint8 ride_id = *edx;
uint8 type = *ebx >> 8;
uint8 value = *edx >> 8;
int index = *edi;
if (index < 0) {
log_warning("Invalid game command, index %d out of bounds", index);
*ebx = MONEY32_UNDEFINED;
return;
}
rct_ride *ride = GET_RIDE(ride_id);
if (ride->type == RIDE_TYPE_NULL) {
log_warning("Invalid game command, ride_id = %u", ride_id);
*ebx = MONEY32_UNDEFINED;
return;
}
*ebx = 0;
switch(type) {
case 0:
if (index >= countof(ride->track_colour_main)) {
log_warning("Invalid game command, index %d out of bounds", index);
*ebx = MONEY32_UNDEFINED;
return;
}
rct_ride *ride = GET_RIDE(ride_id);
if (ride->type == RIDE_TYPE_NULL) {
log_warning("Invalid game command, ride_id = %u", ride_id);
if (apply) {
ride->track_colour_main[index] = value;
gfx_invalidate_screen();
}
break;
case 1:
if (index >= countof(ride->track_colour_additional)) {
log_warning("Invalid game command, index %d out of bounds", index);
*ebx = MONEY32_UNDEFINED;
return;
}
*ebx = 0;
switch(type){
case 0:
if (index >= countof(ride->track_colour_main)) {
log_warning("Invalid game command, index %d out of bounds", index);
*ebx = MONEY32_UNDEFINED;
break;
}
ride->track_colour_main[index] = value;
gfx_invalidate_screen();
break;
case 1:
if (index >= countof(ride->track_colour_additional)) {
log_warning("Invalid game command, index %d out of bounds", index);
*ebx = MONEY32_UNDEFINED;
break;
}
ride->track_colour_additional[index] = value;
gfx_invalidate_screen();
break;
case 2:
if (index >= countof(ride->vehicle_colours)) {
log_warning("Invalid game command, index %d out of bounds", index);
*ebx = MONEY32_UNDEFINED;
break;
}
*((uint8*)(&ride->vehicle_colours[index])) = value;
ride_update_vehicle_colours(ride_id);
break;
case 3:
if (index >= countof(ride->vehicle_colours)) {
log_warning("Invalid game command, index %d out of bounds", index);
*ebx = MONEY32_UNDEFINED;
break;
}
*((uint8*)(&ride->vehicle_colours[index]) + 1) = value;
ride_update_vehicle_colours(ride_id);
break;
case 4:
if (index >= countof(ride->track_colour_supports)) {
log_warning("Invalid game command, index %d out of bounds", index);
*ebx = MONEY32_UNDEFINED;
break;
}
ride->track_colour_supports[index] = value;
gfx_invalidate_screen();
break;
case 5:
ride->colour_scheme_type &= ~(RIDE_COLOUR_SCHEME_DIFFERENT_PER_TRAIN | RIDE_COLOUR_SCHEME_DIFFERENT_PER_CAR);
ride->colour_scheme_type |= value;
for(int i = 1; i < countof(ride->vehicle_colours); i++){
ride->vehicle_colours[i] = ride->vehicle_colours[0];
ride->vehicle_colours_extended[i] = ride->vehicle_colours_extended[0];
}
ride_update_vehicle_colours(ride_id);
break;
case 6:
ride->entrance_style = value;
RCT2_GLOBAL(0x01358840, uint8) = value;
gfx_invalidate_screen();
break;
case 7:
if (index >= countof(ride->vehicle_colours_extended)) {
log_warning("Invalid game command, index %d out of bounds", index);
*ebx = MONEY32_UNDEFINED;
break;
}
if (apply) {
ride->track_colour_additional[index] = value;
gfx_invalidate_screen();
}
break;
case 2:
if (index >= countof(ride->vehicle_colours)) {
log_warning("Invalid game command, index %d out of bounds", index);
*ebx = MONEY32_UNDEFINED;
return;
}
if (apply) {
*((uint8*)(&ride->vehicle_colours[index])) = value;
ride_update_vehicle_colours(ride_id);
}
break;
case 3:
if (index >= countof(ride->vehicle_colours)) {
log_warning("Invalid game command, index %d out of bounds", index);
*ebx = MONEY32_UNDEFINED;
return;
}
if (apply) {
*((uint8*)(&ride->vehicle_colours[index]) + 1) = value;
ride_update_vehicle_colours(ride_id);
}
break;
case 4:
if (index >= countof(ride->track_colour_supports)) {
log_warning("Invalid game command, index %d out of bounds", index);
*ebx = MONEY32_UNDEFINED;
return;
}
if (apply) {
ride->track_colour_supports[index] = value;
gfx_invalidate_screen();
}
break;
case 5:
if (apply) {
ride->colour_scheme_type &= ~(RIDE_COLOUR_SCHEME_DIFFERENT_PER_TRAIN | RIDE_COLOUR_SCHEME_DIFFERENT_PER_CAR);
ride->colour_scheme_type |= value;
for (int i = 1; i < countof(ride->vehicle_colours); i++) {
ride->vehicle_colours[i] = ride->vehicle_colours[0];
ride->vehicle_colours_extended[i] = ride->vehicle_colours_extended[0];
}
ride_update_vehicle_colours(ride_id);
}
break;
case 6:
if (apply) {
ride->entrance_style = value;
RCT2_GLOBAL(0x01358840, uint8) = value;
gfx_invalidate_screen();
}
break;
case 7:
if (index >= countof(ride->vehicle_colours_extended)) {
log_warning("Invalid game command, index %d out of bounds", index);
*ebx = MONEY32_UNDEFINED;
return;
} else {
if (apply) {
ride->vehicle_colours_extended[index] = value;
ride_update_vehicle_colours(ride_id);
break;
}
}
window_invalidate_by_number(WC_RIDE, ride_id);
break;
}
window_invalidate_by_number(WC_RIDE, ride_id);
}
/**

View File

@@ -572,10 +572,11 @@ static void window_guest_list_invalidate(rct_window *w)
window_guest_list_widgets[WIDX_TITLE].right = w->width - 2;
window_guest_list_widgets[WIDX_CLOSE].left = w->width - 13;
window_guest_list_widgets[WIDX_CLOSE].right = w->width - 3;
window_guest_list_widgets[WIDX_GUEST_LIST].right = w->width - 4;
window_guest_list_widgets[WIDX_GUEST_LIST].bottom = w->height - 15;
window_guest_list_widgets[WIDX_PAGE_DROPDOWN].image = _window_guest_list_selected_page + 3440;
window_guest_list_widgets[WIDX_TRACKING].left = 321 - 350 + w->width;
window_guest_list_widgets[WIDX_TRACKING].right = 344 - 350 + w->width;
}
/**

View File

@@ -104,26 +104,31 @@ enum WINDOW_STAFF_LIST_WIDGET_IDX {
WIDX_STAFF_LIST_LIST,
WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER,
WIDX_STAFF_LIST_HIRE_BUTTON,
WIDX_STAFF_LIST_QUICK_FIRE,
WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON,
WIDX_STAFF_LIST_MAP,
WIDX_STAFF_LIST_QUICK_FIRE,
};
#define WW 320
#define WH 270
#define MAX_WW 500
#define MAX_WH 450
static rct_widget window_staff_list_widgets[] = {
{ WWT_FRAME, 0, 0, 319, 0, 269, 0x0FFFFFFFF, STR_NONE }, // panel / background
{ WWT_CAPTION, 0, 1, 318, 1, 14, STR_STAFF, STR_WINDOW_TITLE_TIP }, // title bar
{ WWT_CLOSEBOX, 0, 307, 317, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close button
{ WWT_RESIZE, 1, 0, 319, 43, 269, 0x0FFFFFFFF, STR_NONE }, // tab content panel
{ WWT_TAB, 1, 3, 33, 17, 43, 0x02000144E, STR_STAFF_HANDYMEN_TAB_TIP }, // handymen tab
{ WWT_TAB, 1, 34, 64, 17, 43, 0x02000144E, STR_STAFF_MECHANICS_TAB_TIP }, // mechanics tab
{ WWT_TAB, 1, 65, 95, 17, 43, 0x02000144E, STR_STAFF_SECURITY_TAB_TIP }, // security guards tab
{ WWT_TAB, 1, 96, 126, 17, 43, 0x02000144E, STR_STAFF_ENTERTAINERS_TAB_TIP }, // entertainers tab
{ WWT_SCROLL, 1, 3, 316, 72, 266, 3, STR_NONE }, // staff list
{ WWT_COLORBTN, 1, 130, 141, 58, 69, STR_NONE, STR_UNIFORM_COLOUR_TIP }, // uniform color picker
{ WWT_DROPDOWN_BUTTON, 0, 165, 309, 17, 29, STR_NONE, STR_HIRE_STAFF_TIP }, // hire button
{ WWT_FLATBTN, 1, 267, 290, 46, 69, 5175, STR_SHOW_PATROL_AREA_TIP }, // show staff patrol area tool
{ WWT_FLATBTN, 1, 291, 314, 46, 69, 5192, STR_SHOW_STAFF_ON_MAP_TIP }, // show staff on map button
{ WWT_FLATBTN, 1, 243, 266, 46, 69, SPR_DEMOLISH, 5300 }, // quick fire staff
{ WWT_FRAME, 0, 0, 319, 0, 269, 0x0FFFFFFFF, STR_NONE }, // panel / background
{ WWT_CAPTION, 0, 1, 318, 1, 14, STR_STAFF, STR_WINDOW_TITLE_TIP }, // title bar
{ WWT_CLOSEBOX, 0, 307, 317, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close button
{ WWT_RESIZE, 1, 0, 319, 43, 269, 0x0FFFFFFFF, STR_NONE }, // tab content panel
{ WWT_TAB, 1, 3, 33, 17, 43, 0x02000144E, STR_STAFF_HANDYMEN_TAB_TIP }, // handymen tab
{ WWT_TAB, 1, 34, 64, 17, 43, 0x02000144E, STR_STAFF_MECHANICS_TAB_TIP }, // mechanics tab
{ WWT_TAB, 1, 65, 95, 17, 43, 0x02000144E, STR_STAFF_SECURITY_TAB_TIP }, // security guards tab
{ WWT_TAB, 1, 96, 126, 17, 43, 0x02000144E, STR_STAFF_ENTERTAINERS_TAB_TIP }, // entertainers tab
{ WWT_SCROLL, 1, 3, 316, 72, 266, 3, STR_NONE }, // staff list
{ WWT_COLORBTN, 1, 130, 141, 58, 69, STR_NONE, STR_UNIFORM_COLOUR_TIP }, // uniform color picker
{ WWT_DROPDOWN_BUTTON, 0, WW - 155, WW - 11, 17, 29, STR_NONE, STR_HIRE_STAFF_TIP }, // hire button
{ WWT_FLATBTN, 1, WW - 77, WW - 54, 46, 69, SPR_DEMOLISH, 5300 }, // quick fire staff
{ WWT_FLATBTN, 1, WW - 53, WW - 30, 46, 69, 5175, STR_SHOW_PATROL_AREA_TIP }, // show staff patrol area tool
{ WWT_FLATBTN, 1, WW - 29, WW - 6, 46, 69, 5192, STR_SHOW_STAFF_ON_MAP_TIP }, // show staff on map button
{ WIDGETS_END },
};
@@ -152,7 +157,7 @@ void window_staff_list_open()
if (window != NULL)
return;
window = window_create_auto_pos(320, 270, &window_staff_list_events, WC_STAFF_LIST, WF_10 | WF_RESIZABLE);
window = window_create_auto_pos(WW, WH, &window_staff_list_events, WC_STAFF_LIST, WF_10 | WF_RESIZABLE);
window->widgets = window_staff_list_widgets;
window->enabled_widgets =
(1 << WIDX_STAFF_LIST_CLOSE) |
@@ -171,10 +176,10 @@ void window_staff_list_open()
window->list_information_type = 0;
window_staff_list_widgets[WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER].type = WWT_EMPTY;
window->min_width = 320;
window->min_height = 270;
window->max_width = 500;
window->max_height = 450;
window->min_width = WW;
window->min_height = WH;
window->max_width = MAX_WW;
window->max_height = MAX_WH;
_quick_fire_mode = false;
}
@@ -240,8 +245,8 @@ static void window_staff_list_mouseup(rct_window *w, int widgetIndex)
*/
static void window_staff_list_resize(rct_window *w)
{
w->min_width = 320;
w->min_height = 270;
w->min_width = WW;
w->min_height = WH;
if (w->width < w->min_width) {
w->width = w->min_width;
window_invalidate(w);
@@ -308,13 +313,11 @@ void window_staff_list_update(rct_window *w)
} else {
widget_invalidate(w, WIDX_STAFF_LIST_HANDYMEN_TAB + RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8));
RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_MAP_FLASHING_FLAGS, uint16) |= (1 << 2);
FOR_ALL_PEEPS(spriteIndex, peep) {
if (peep->type == PEEP_TYPE_STAFF) {
peep->list_flags &= ~(PEEP_LIST_FLAGS_FLASHING);
FOR_ALL_STAFF(spriteIndex, peep) {
peep->list_flags &= ~(PEEP_LIST_FLAGS_FLASHING);
if (peep->staff_type == RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8)) {
peep->list_flags |= PEEP_LIST_FLAGS_FLASHING;
}
if (peep->staff_type == RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8)) {
peep->list_flags |= PEEP_LIST_FLAGS_FLASHING;
}
}
}
@@ -401,8 +404,8 @@ void window_staff_list_scrollgetsize(rct_window *w, int scrollIndex, int *width,
rct_peep *peep;
uint16 staffCount = 0;
FOR_ALL_PEEPS(spriteIndex, peep) {
if (peep->type == PEEP_TYPE_STAFF && peep->staff_type == RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8))
FOR_ALL_STAFF(spriteIndex, peep) {
if (peep->staff_type == RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8))
staffCount++;
}
@@ -435,10 +438,7 @@ void window_staff_list_scrollmousedown(rct_window *w, int scrollIndex, int x, in
rct_peep *peep;
i = y / 10;
FOR_ALL_PEEPS(spriteIndex, peep) {
if (peep->type != PEEP_TYPE_STAFF)
continue;
FOR_ALL_STAFF(spriteIndex, peep) {
if (peep->staff_type != RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8))
continue;
@@ -490,7 +490,7 @@ void window_staff_list_invalidate(rct_window *w)
uint8 tabIndex = RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8);
uint8 widgetIndex = tabIndex + 4;
w->pressed_widgets = pressed_widgets | (1 << widgetIndex);
w->pressed_widgets = pressed_widgets | (1ULL << widgetIndex);
window_staff_list_widgets[WIDX_STAFF_LIST_HIRE_BUTTON].image = STR_HIRE_HANDYMAN + tabIndex;
window_staff_list_widgets[WIDX_STAFF_LIST_UNIFORM_COLOR_PICKER].type = WWT_EMPTY;
@@ -501,9 +501,9 @@ void window_staff_list_invalidate(rct_window *w)
0x600013C3;
}
if (_quick_fire_mode)
w->pressed_widgets |= (1 << WIDX_STAFF_LIST_QUICK_FIRE);
w->pressed_widgets |= (1ULL << WIDX_STAFF_LIST_QUICK_FIRE);
else
w->pressed_widgets &= ~(1 << WIDX_STAFF_LIST_QUICK_FIRE);
w->pressed_widgets &= ~(1ULL << WIDX_STAFF_LIST_QUICK_FIRE);
window_staff_list_widgets[WIDX_STAFF_LIST_BACKGROUND].right = w->width - 1;
window_staff_list_widgets[WIDX_STAFF_LIST_BACKGROUND].bottom = w->height - 1;
@@ -514,6 +514,14 @@ void window_staff_list_invalidate(rct_window *w)
window_staff_list_widgets[WIDX_STAFF_LIST_CLOSE].right = w->width - 2 - 0x0B + 0x0A;
window_staff_list_widgets[WIDX_STAFF_LIST_LIST].right = w->width - 4;
window_staff_list_widgets[WIDX_STAFF_LIST_LIST].bottom = w->height - 0x0F;
window_staff_list_widgets[WIDX_STAFF_LIST_QUICK_FIRE].left = w->width - 77;
window_staff_list_widgets[WIDX_STAFF_LIST_QUICK_FIRE].right = w->width - 54;
window_staff_list_widgets[WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON].left = w->width - 53;
window_staff_list_widgets[WIDX_STAFF_LIST_SHOW_PATROL_AREA_BUTTON].right = w->width - 30;
window_staff_list_widgets[WIDX_STAFF_LIST_MAP].left = w->width - 29;
window_staff_list_widgets[WIDX_STAFF_LIST_MAP].right = w->width - 6;
window_staff_list_widgets[WIDX_STAFF_LIST_HIRE_BUTTON].left = w->width - 155;
window_staff_list_widgets[WIDX_STAFF_LIST_HIRE_BUTTON].right = w->width - 11;
}
/**
@@ -591,7 +599,7 @@ void window_staff_list_paint(rct_window *w, rct_drawpixelinfo *dpi)
if (!(RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) & PARK_FLAGS_NO_MONEY)) {
RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS, uint32) = RCT2_ADDRESS(0x00992A00, uint16)[selectedTab];
gfx_draw_string_left(dpi, 1858, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, 0, w->x + 0xA5, w->y + 0x20);
gfx_draw_string_left(dpi, 1858, (void*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, 0, w->x + w->width - 155, w->y + 0x20);
}
if (selectedTab < 3) {
@@ -626,8 +634,8 @@ void window_staff_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int sc
y = 0;
i = 0;
selectedTab = RCT2_GLOBAL(RCT2_ADDRESS_WINDOW_STAFF_LIST_SELECTED_TAB, uint8);
FOR_ALL_PEEPS(spriteIndex, peep) {
if (peep->type == PEEP_TYPE_STAFF && peep->staff_type == selectedTab) {
FOR_ALL_STAFF(spriteIndex, peep) {
if (peep->staff_type == selectedTab) {
if (y > dpi->y + dpi->height) {
break;
}

View File

@@ -1601,7 +1601,8 @@ static money32 map_set_land_height(int flags, int x, int y, int height, int styl
if(flags & GAME_COMMAND_FLAG_APPLY)
{
footpath_remove_litter(x, y, map_element_height(x, y));
map_remove_walls_at(x, y, height * 8 - 16, height * 8 + 32);
if(!gCheatsDisableClearanceChecks)
map_remove_walls_at(x, y, height * 8 - 16, height * 8 + 32);
}
RCT2_GLOBAL(0x9E2E18, money32) += MONEY(20, 0);
@@ -2498,7 +2499,8 @@ void game_command_set_water_height(int* eax, int* ebx, int* ecx, int* edx, int*
if(*ebx & GAME_COMMAND_FLAG_APPLY){
int element_height = map_element_height(x, y);
footpath_remove_litter(x, y, element_height);
map_remove_walls_at_z(x, y, element_height);
if(!gCheatsDisableClearanceChecks)
map_remove_walls_at_z(x, y, element_height);
}
rct_map_element* map_element = map_get_surface_element_at(x / 32, y / 32);