Merge pull request #1142 from trigger-death/in-game-object-selection

Added in-game object selection
This commit is contained in:
Ted John 2015-05-24 03:52:53 +01:00
commit ad4436ea4f
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;}
@ -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 {

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