Added in-game object selection

New console commands:
- open (opens a window)
- windows (lists windows usable with open)
- load_object (loads the specified obj with the given filename)
- object_count (lists the number of objects in the scenary)
Console commands now have a usage variable.

Use: "open object_selection" for the object selection window.
Once the object selection window is closed, all objects will
automatically be researched whether or not they were already in the base
scenario.
The object selection window will close any other windows when selecting
an object to prevent a crash.
This commit is contained in:
Robert Jordan 2015-05-23 14:56:54 -04:00
parent d0a50c43f4
commit ab942236d7
9 changed files with 257 additions and 21 deletions

View File

@ -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;}
@ -615,6 +619,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);
@ -622,6 +767,7 @@ typedef struct {
char *command;
console_command_func func;
char *help;
char *usage;
} console_command;
char* console_variable_table[] = {
@ -650,16 +796,33 @@ char* console_variable_table[] = {
"game_speed",
"console_small_font"
};
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++)
@ -671,8 +834,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 {

View File

@ -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

View File

@ -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);

View File

@ -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,7 +200,8 @@ 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;
news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2249, entryIndex);
if (!gSilentResearch)
news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2249, entryIndex);
}
research_invalidate_related_windows();
@ -213,7 +216,8 @@ 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;
news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2250, entryIndex);
if (!gSilentResearch)
news_item_add_to_queue(NEWS_ITEM_RESEARCH, 2250, entryIndex);
}
research_invalidate_related_windows();
@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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);
research_populate_list_random();
research_remove_non_separate_vehicle_types();
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:
game_do_command(0, 1, 0, 0, GAME_COMMAND_LOAD_OR_QUIT, 1, 0);
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;

View File

@ -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