mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #1142 from trigger-death/in-game-object-selection
Added in-game object selection
This commit is contained in:
commit
ad4436ea4f
|
@ -5,6 +5,7 @@
|
|||
#include "../localisation/localisation.h"
|
||||
#include "../platform/platform.h"
|
||||
#include "../world/park.h"
|
||||
#include "../util/sawyercoding.h"
|
||||
#include "../config.h"
|
||||
#include "../cursors.h"
|
||||
#include "../game.h"
|
||||
|
@ -12,6 +13,8 @@
|
|||
#include "../object.h"
|
||||
#include "console.h"
|
||||
#include "window.h"
|
||||
#include "../world/scenery.h"
|
||||
#include "../management/research.h"
|
||||
|
||||
#define CONSOLE_BUFFER_SIZE 8192
|
||||
#define CONSOLE_BUFFER_2_SIZE 256
|
||||
|
@ -47,6 +50,7 @@ static int console_parse_int(const char *src, bool *valid);
|
|||
static double console_parse_double(const char *src, bool *valid);
|
||||
|
||||
static int cc_variables(const char **argv, int argc);
|
||||
static int cc_windows(const char **argv, int argc);
|
||||
static int cc_help(const char **argv, int argc);
|
||||
|
||||
#define SET_FLAG(variable, flag, value) {if (value) variable |= flag; else variable &= ~flag;}
|
||||
|
@ -631,6 +635,147 @@ static int cc_set(const char **argv, int argc)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
static void editor_load_selected_objects_console()
|
||||
{
|
||||
uint8 *selection_flags = RCT2_GLOBAL(RCT2_ADDRESS_EDITOR_OBJECT_FLAGS_LIST, uint8*);
|
||||
rct_object_entry *installed_entry = RCT2_GLOBAL(RCT2_ADDRESS_INSTALLED_OBJECT_LIST, rct_object_entry*);
|
||||
|
||||
if (RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32) == 0)
|
||||
return;
|
||||
|
||||
for (int i = RCT2_GLOBAL(RCT2_ADDRESS_OBJECT_LIST_NO_ITEMS, uint32); i != 0; i--, selection_flags++) {
|
||||
if (*selection_flags & 1) {
|
||||
uint8 entry_index, entry_type;
|
||||
if (!find_object_in_entry_group(installed_entry, &entry_type, &entry_index)){
|
||||
int chunk_size;
|
||||
if (!object_load(-1, installed_entry, &chunk_size)) {
|
||||
log_error("Failed to load entry %.8s", installed_entry->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
installed_entry = object_get_next(installed_entry);
|
||||
}
|
||||
}
|
||||
|
||||
static int cc_load_object(const char **argv, int argc) {
|
||||
if (argc > 0) {
|
||||
char path[260];
|
||||
|
||||
subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), argv[0]);
|
||||
// Require pointer to start of filename
|
||||
char* last_char = path + strlen(path);
|
||||
strcat(path, ".DAT\0");
|
||||
|
||||
rct_object_entry entry;
|
||||
if (object_load_entry(path, &entry)) {
|
||||
uint8 type = entry.flags & 0xF;
|
||||
uint8 index;
|
||||
|
||||
if (check_object_entry(&entry)) {
|
||||
if (!find_object_in_entry_group(&entry, &type, &index)){
|
||||
|
||||
int entryGroupIndex = 0;
|
||||
for (; entryGroupIndex < object_entry_group_counts[type]; entryGroupIndex++){
|
||||
if (object_entry_groups[type].chunks[entryGroupIndex] == (uint8*)-1){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entryGroupIndex >= object_entry_group_counts[type]) {
|
||||
console_writeline_error("Too many objects of that type.");
|
||||
}
|
||||
else {
|
||||
// Load the obect
|
||||
if (!object_load(entryGroupIndex, &entry, NULL)) {
|
||||
console_writeline_error("Could not load object file.");
|
||||
}
|
||||
else {
|
||||
reset_loaded_objects();
|
||||
if (type == OBJECT_TYPE_RIDE) {
|
||||
// Automatically research the ride so it's supported by the game.
|
||||
|
||||
rct_ride_type *rideEntry;
|
||||
int rideType;
|
||||
|
||||
rideEntry = GET_RIDE_ENTRY(entryGroupIndex);
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
rideType = rideEntry->ride_type[j];
|
||||
if (rideType != 255)
|
||||
research_insert(true, 0x10000 | (rideType << 8) | entryGroupIndex, rideEntry->category[0]);
|
||||
}
|
||||
|
||||
gSilentResearch = true;
|
||||
sub_684AC3();
|
||||
gSilentResearch = false;
|
||||
}
|
||||
else if (type == OBJECT_TYPE_SCENERY_SETS) {
|
||||
rct_scenery_set_entry *scenerySetEntry;
|
||||
|
||||
scenerySetEntry = g_scenerySetEntries[entryGroupIndex];
|
||||
|
||||
research_insert(true, entryGroupIndex, RESEARCH_CATEGORY_SCENERYSET);
|
||||
|
||||
gSilentResearch = true;
|
||||
sub_684AC3();
|
||||
gSilentResearch = false;
|
||||
}
|
||||
scenery_set_default_placement_configuration();
|
||||
window_new_ride_init_vars();
|
||||
|
||||
RCT2_GLOBAL(0x009DEB7C, uint16) = 0;
|
||||
gfx_invalidate_screen();
|
||||
console_writeline("Object file loaded.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
console_writeline_error("Object is already in scenario.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
console_writeline_error("The object file was invalid.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
console_writeline_error("Could not find the object file.");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int cc_object_count(const char **argv, int argc) {
|
||||
const char* object_type_names[] = { "Rides", "Small scenery", "Large scenery", "Walls", "Banners", "Paths", "Path Additions", "Scenery groups", "Park entrances", "Water" };
|
||||
for (int i = 0; i < 10; i++) {
|
||||
|
||||
int entryGroupIndex = 0;
|
||||
for (; entryGroupIndex < object_entry_group_counts[i]; entryGroupIndex++){
|
||||
if (object_entry_groups[i].chunks[entryGroupIndex] == (uint8*)-1){
|
||||
break;
|
||||
}
|
||||
}
|
||||
console_printf("%s: %d/%d", object_type_names[i], entryGroupIndex, object_entry_group_counts[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int cc_open(const char **argv, int argc) {
|
||||
if (argc > 0) {
|
||||
if (strcmp(argv[0], "object_selection") == 0) {
|
||||
// Only this window should be open for safety reasons
|
||||
window_close_all();
|
||||
window_editor_object_selection_open();
|
||||
} else if (strcmp(argv[0], "inventions_list") == 0) {
|
||||
window_editor_inventions_list_open();
|
||||
} else if (strcmp(argv[0], "options") == 0) {
|
||||
window_options_open();
|
||||
} else {
|
||||
console_writeline_error("Invalid window.");
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
typedef int (*console_command_func)(const char **argv, int argc);
|
||||
|
@ -638,6 +783,7 @@ typedef struct {
|
|||
char *command;
|
||||
console_command_func func;
|
||||
char *help;
|
||||
char *usage;
|
||||
} console_command;
|
||||
|
||||
char* console_variable_table[] = {
|
||||
|
@ -668,16 +814,33 @@ char* console_variable_table[] = {
|
|||
"test_unfinished_tracks",
|
||||
"no_test_crashes"
|
||||
};
|
||||
|
||||
console_command console_command_table[] = {
|
||||
{ "clear", cc_clear, "Clears the console." },
|
||||
{ "echo", cc_echo, "Echos the text to the console.\necho text" },
|
||||
{ "help", cc_help, "Lists commands or info about a command.\nhelp [command]" },
|
||||
{ "get", cc_get, "Gets the value of the specified variable.\nget variable" },
|
||||
{ "set", cc_set, "Sets the variable to the specified value.\nset variable value" },
|
||||
{ "variables", cc_variables, "Lists all the variables that can be used with get and sometimes set." }
|
||||
char* console_window_table[] = {
|
||||
"object_selection",
|
||||
"inventions_list",
|
||||
"options"
|
||||
};
|
||||
|
||||
console_command console_command_table[] = {
|
||||
{ "clear", cc_clear, "Clears the console." "clear"},
|
||||
{ "echo", cc_echo, "Echos the text to the console.", "echo <text>" },
|
||||
{ "help", cc_help, "Lists commands or info about a command.", "help [command]" },
|
||||
{ "get", cc_get, "Gets the value of the specified variable.", "get <variable>" },
|
||||
{ "set", cc_set, "Sets the variable to the specified value.", "set <variable> <value>" },
|
||||
{ "open", cc_open, "Opens the window with the give name.", "open <window>." },
|
||||
{ "variables", cc_variables, "Lists all the variables that can be used with get and sometimes set.", "variables" },
|
||||
{ "windows", cc_windows, "Lists all the windows that can be opened.", "windows" },
|
||||
{ "load_object", cc_load_object, "Loads the object file into the scenario.\n"
|
||||
"Loading a scenery group will not load its associated objects.\n"
|
||||
"This is a safer method opposed to \"open object_selection\".",
|
||||
"load_object <objectfilenodat>" },
|
||||
{ "object_count", cc_object_count, "Shows the number of objects of each type in the scenario.", "object_count" }
|
||||
};
|
||||
|
||||
static int cc_windows(const char **argv, int argc) {
|
||||
for (int i = 0; i < countof(console_window_table); i++)
|
||||
console_writeline(console_window_table[i]);
|
||||
return 0;
|
||||
}
|
||||
static int cc_variables(const char **argv, int argc)
|
||||
{
|
||||
for (int i = 0; i < countof(console_variable_table); i++)
|
||||
|
@ -689,8 +852,10 @@ static int cc_help(const char **argv, int argc)
|
|||
{
|
||||
if (argc > 0) {
|
||||
for (int i = 0; i < countof(console_command_table); i++) {
|
||||
if (strcmp(console_command_table[i].command, argv[0]) == 0)
|
||||
if (strcmp(console_command_table[i].command, argv[0]) == 0) {
|
||||
console_writeline(console_command_table[i].help);
|
||||
console_printf("\nUsage: %s", console_command_table[i].usage);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -602,6 +602,19 @@ void window_close_all() {
|
|||
}
|
||||
}
|
||||
|
||||
void window_close_all_except_class(rct_windowclass cls) {
|
||||
rct_window* w;
|
||||
|
||||
window_close_by_class(WC_DROPDOWN);
|
||||
|
||||
for (w = g_window_list; w < RCT2_LAST_WINDOW; w++){
|
||||
if (w->classification != cls && !(w->flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT))) {
|
||||
window_close(w);
|
||||
w = g_window_list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006EA845
|
||||
|
|
|
@ -449,6 +449,7 @@ void window_close_by_class(rct_windowclass cls);
|
|||
void window_close_by_number(rct_windowclass cls, rct_windownumber number);
|
||||
void window_close_top();
|
||||
void window_close_all();
|
||||
void window_close_all_except_class(rct_windowclass cls);
|
||||
rct_window *window_find_by_class(rct_windowclass cls);
|
||||
rct_window *window_find_by_number(rct_windowclass cls, rct_windownumber number);
|
||||
rct_window *window_find_from_point(int x, int y);
|
||||
|
|
|
@ -36,6 +36,8 @@ rct_research_item *gResearchItems = (rct_research_item*)RCT2_RESEARCH_ITEMS;
|
|||
// 0x00EE787C
|
||||
uint8 gResearchUncompletedCategories;
|
||||
|
||||
bool gSilentResearch = false;
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006671AD, part of 0x00667132
|
||||
|
@ -198,6 +200,7 @@ void research_finish_item(sint32 entryIndex)
|
|||
if (RCT2_GLOBAL(0x009AC06C, uint8) == 0) {
|
||||
RCT2_GLOBAL(0x013CE952, rct_string_id) = rideEntry->var_008 & 0x1000 ?
|
||||
rideEntry->name : ecx + 2;
|
||||
if (!gSilentResearch)
|
||||
news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2249, entryIndex);
|
||||
}
|
||||
|
||||
|
@ -213,6 +216,7 @@ void research_finish_item(sint32 entryIndex)
|
|||
// I don't think 0x009AC06C is ever not 0, so probably redundant
|
||||
if (RCT2_GLOBAL(0x009AC06C, uint8) == 0) {
|
||||
RCT2_GLOBAL(0x013CE952, rct_string_id) = scenerySetEntry->name;
|
||||
if (!gSilentResearch)
|
||||
news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2250, entryIndex);
|
||||
}
|
||||
|
||||
|
@ -426,7 +430,7 @@ static void research_insert_researched(int entryIndex, int category)
|
|||
} while (entryIndex != (researchItem++)->entryIndex);
|
||||
}
|
||||
|
||||
static void research_insert(int researched, int entryIndex, int category)
|
||||
void research_insert(int researched, int entryIndex, int category)
|
||||
{
|
||||
if (researched)
|
||||
research_insert_researched(entryIndex, category);
|
||||
|
@ -469,6 +473,35 @@ void research_populate_list_random()
|
|||
}
|
||||
}
|
||||
|
||||
void research_populate_list_researched()
|
||||
{
|
||||
rct_ride_type *rideEntry;
|
||||
rct_scenery_set_entry *scenerySetEntry;
|
||||
int rideType;
|
||||
|
||||
// Rides
|
||||
for (int i = 0; i < 128; i++) {
|
||||
rideEntry = GET_RIDE_ENTRY(i);
|
||||
if (rideEntry == (rct_ride_type*)-1)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < 3; j++) {
|
||||
rideType = rideEntry->ride_type[j];
|
||||
if (rideType != 255)
|
||||
research_insert(true, 0x10000 | (rideType << 8) | i, rideEntry->category[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Scenery
|
||||
for (int i = 0; i < 19; i++) {
|
||||
scenerySetEntry = g_scenerySetEntries[i];
|
||||
if (scenerySetEntry == (rct_scenery_set_entry*)-1)
|
||||
continue;
|
||||
|
||||
research_insert(true, i, RESEARCH_CATEGORY_SCENERYSET);
|
||||
}
|
||||
}
|
||||
|
||||
void research_set_funding(int amount)
|
||||
{
|
||||
game_do_command(0, GAME_COMMAND_FLAG_APPLY, 0, amount, GAME_COMMAND_SET_RESEARCH_FUNDING, 0, 0);
|
||||
|
|
|
@ -60,6 +60,7 @@ enum {
|
|||
|
||||
extern rct_research_item *gResearchItems;
|
||||
extern uint8 gResearchUncompletedCategories;
|
||||
extern bool gSilentResearch;
|
||||
|
||||
void research_reset_items();
|
||||
void research_update_uncompleted_types();
|
||||
|
@ -67,9 +68,12 @@ void research_update();
|
|||
void sub_684AC3();
|
||||
void research_remove_non_separate_vehicle_types();
|
||||
void research_populate_list_random();
|
||||
void research_populate_list_researched();
|
||||
|
||||
void research_set_funding(int amount);
|
||||
void research_set_priority(int activeCategories);
|
||||
void game_command_set_research_funding(int* eax, int* ebx, int* ecx, int* edx, int* esi, int* edi, int* ebp);
|
||||
void research_finish_item(sint32 entryIndex);
|
||||
void research_insert(int researched, int entryIndex, int category);
|
||||
|
||||
#endif
|
|
@ -76,6 +76,7 @@ int object_read_and_load_entries(FILE *file);
|
|||
int object_load_packed(FILE *file);
|
||||
void object_unload_all();
|
||||
|
||||
int check_object_entry(rct_object_entry *entry);
|
||||
int object_load(int groupIndex, rct_object_entry *entry, int* chunk_size);
|
||||
int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSize, const rct_object_entry *installedObject);
|
||||
void object_unload(int groupIndex, rct_object_entry_extended *entry);
|
||||
|
|
|
@ -385,7 +385,7 @@ static int object_list_cache_save(int fileCount, uint64 totalFileSize, int fileD
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int check_object_entry(rct_object_entry *entry)
|
||||
int check_object_entry(rct_object_entry *entry)
|
||||
{
|
||||
uint32 *dwords = (uint32*)entry;
|
||||
return (0xFFFFFFFF & dwords[0] & dwords[1] & dwords[2] & dwords[3]) + 1 != 0;
|
||||
|
|
|
@ -245,19 +245,26 @@ static void window_editor_object_selection_close()
|
|||
rct_window* w;
|
||||
window_get_register(w);
|
||||
|
||||
if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) &
|
||||
(SCREEN_FLAGS_SCENARIO_EDITOR |
|
||||
SCREEN_FLAGS_TRACK_DESIGNER |
|
||||
SCREEN_FLAGS_TRACK_MANAGER))
|
||||
)return;
|
||||
//if (!(RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_EDITOR))
|
||||
// return;
|
||||
|
||||
RCT2_CALLPROC_EBPSAFE(0x6ABB66);
|
||||
editor_load_selected_objects();
|
||||
reset_loaded_objects();
|
||||
object_free_scenario_text();
|
||||
RCT2_CALLPROC_EBPSAFE(0x6AB316);
|
||||
if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_EDITOR) {
|
||||
research_populate_list_random();
|
||||
research_remove_non_separate_vehicle_types();
|
||||
}
|
||||
else {
|
||||
// Used for in-game object selection cheat
|
||||
research_reset_items();
|
||||
research_populate_list_researched();
|
||||
gSilentResearch = true;
|
||||
sub_684AC3();
|
||||
gSilentResearch = false;
|
||||
}
|
||||
window_new_ride_init_vars();
|
||||
}
|
||||
|
||||
|
@ -274,7 +281,13 @@ static void window_editor_object_selection_mouseup()
|
|||
|
||||
switch (widgetIndex) {
|
||||
case WIDX_CLOSE:
|
||||
if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_EDITOR) {
|
||||
game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0);
|
||||
}
|
||||
else {
|
||||
// Used for in-game object selection cheat
|
||||
window_close(w);
|
||||
}
|
||||
break;
|
||||
|
||||
case WIDX_TAB_1:
|
||||
|
@ -340,6 +353,10 @@ static void window_editor_object_selection_scroll_mousedown()
|
|||
|
||||
window_scrollmouse_get_registers(w, scrollIndex, x, y);
|
||||
|
||||
// Used for in-game object selection cheat to prevent crashing the game
|
||||
// when windows attempt to draw objects that don't exist any more
|
||||
window_close_all_except_class(WC_EDITOR_OBJECT_SELECTION);
|
||||
|
||||
uint8 object_selection_flags;
|
||||
rct_object_entry* installed_entry;
|
||||
int selected_object = get_object_from_object_selection((w->selected_tab & 0xFF), y, &object_selection_flags, &installed_entry);
|
||||
|
@ -350,6 +367,7 @@ static void window_editor_object_selection_scroll_mousedown()
|
|||
|
||||
sound_play_panned(SOUND_CLICK_1, RCT2_GLOBAL(0x142406C,uint32), 0, 0, 0);
|
||||
|
||||
|
||||
if (RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) & SCREEN_FLAGS_TRACK_MANAGER) {
|
||||
if (!window_editor_object_selection_select_object(1, installed_entry))
|
||||
return;
|
||||
|
|
|
@ -176,5 +176,6 @@ void scenery_update_tile(int x, int y);
|
|||
void scenery_update_age(int x, int y, rct_map_element *mapElement);
|
||||
void scenery_set_default_placement_configuration();
|
||||
void scenery_remove_ghost_tool_placement();
|
||||
void scenery_set_default_placement_configuration();
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue