diff --git a/res/gz/checkbox.png b/res/gz/checkbox.png index c694c324..c1e9a677 100644 Binary files a/res/gz/checkbox.png and b/res/gz/checkbox.png differ diff --git a/src/gz/gz_file.c b/src/gz/gz_file.c index 3c6e7547..470177d1 100644 --- a/src/gz/gz_file.c +++ b/src/gz/gz_file.c @@ -342,7 +342,7 @@ struct menu *gz_file_menu(void) /* create memfile controls */ menu_add_static(&menu, 0, 3, "memory file", 0xC0C0C0); - menu_add_watch(&menu, 19, 3, (uint32_t)&gz.memfile_slot, WATCH_TYPE_U8); + menu_add_watch(&menu, 19, 3, (uint32_t)&gz.memfile_slot, WATCH_TYPE_U8, 0, 0); menu_add_button(&menu, 17, 3, "-", memfile_dec_proc, NULL); menu_add_button(&menu, 21, 3, "+", memfile_inc_proc, NULL); diff --git a/src/gz/gz_macro.c b/src/gz/gz_macro.c index ebf2a496..90e60bdd 100644 --- a/src/gz/gz_macro.c +++ b/src/gz/gz_macro.c @@ -707,7 +707,7 @@ struct menu *gz_macro_menu(void) item = menu_add_intinput(&menu, 12, 4, 10, 6, movie_pos_proc, NULL); item->tooltip = "macro frame"; menu_add_watch(&menu, 19, 4, (uint32_t)&gz.movie_input.size, - WATCH_TYPE_U32); + WATCH_TYPE_U32, 0, 0); item = menu_add_button_icon(&menu, 0, 6, t_save, 0, 0xFFFFFF, import_macro_proc, NULL); item->tooltip = "import macro"; diff --git a/src/gz/gz_scene.c b/src/gz/gz_scene.c index ff0fb721..3902f8f2 100644 --- a/src/gz/gz_scene.c +++ b/src/gz/gz_scene.c @@ -389,18 +389,20 @@ struct menu *gz_scene_menu(void) /* teleport controls */ menu_add_static(&menu, 0, 10, "teleport slot", 0xC0C0C0); menu_add_watch(&menu, 18, 10, - (uint32_t)&settings->teleport_slot, WATCH_TYPE_U8); + (uint32_t)&settings->teleport_slot, WATCH_TYPE_U8, 0, 0); menu_add_button(&menu, 16, 10, "-", teleport_dec_proc, NULL); menu_add_button(&menu, 20, 10, "+", teleport_inc_proc, NULL); /* scene info watches */ menu_add_static(&menu, 0, 11, "current scene", 0xC0C0C0); menu_add_watch(&menu, 16, 11, - (uint32_t)&z64_game.scene_index, WATCH_TYPE_U16); + (uint32_t)&z64_game.scene_index, WATCH_TYPE_U16, 0, 0); menu_add_static(&menu, 0, 12, "current room", 0xC0C0C0); menu_add_watch(&menu, 16, 12, - (uint32_t)&z64_game.room_ctxt.rooms[0].index, WATCH_TYPE_U8); + (uint32_t)&z64_game.room_ctxt.rooms[0].index, WATCH_TYPE_U8, + 0, 0); menu_add_static(&menu, 0, 13, "no. rooms", 0xC0C0C0); - menu_add_watch(&menu, 16, 13, (uint32_t)&z64_game.n_rooms, WATCH_TYPE_U8); + menu_add_watch(&menu, 16, 13, (uint32_t)&z64_game.n_rooms, WATCH_TYPE_U8, + 0, 0); /* populate collision menu */ collision.selector = menu_add_submenu(&collision, 0, 0, NULL, "return"); diff --git a/src/gz/gz_settings.c b/src/gz/gz_settings.c index f39566c6..8d7c25b1 100644 --- a/src/gz/gz_settings.c +++ b/src/gz/gz_settings.c @@ -156,6 +156,23 @@ static int pause_display_proc(struct menu_item *item, return 0; } +static int pointer_watches_proc(struct menu_item *item, + enum menu_callback_reason reason, + void *data) +{ + if (reason == MENU_CALLBACK_SWITCH_ON) { + settings->bits.pointer_watches = 1; + watchlist_refresh(gz.menu_watchlist); + } + else if (reason == MENU_CALLBACK_SWITCH_OFF) { + settings->bits.pointer_watches = 0; + watchlist_refresh(gz.menu_watchlist); + } + else if (reason == MENU_CALLBACK_THINK) + menu_checkbox_set(item, settings->bits.pointer_watches); + return 0; +} + static int macro_input_proc(struct menu_item *item, enum menu_callback_reason reason, void *data) @@ -276,7 +293,7 @@ struct menu *gz_settings_menu(void) menu.selector = menu_add_submenu(&menu, 0, 0, NULL, "return"); /* profile select */ menu_add_static(&menu, 0, 1, "profile", 0xC0C0C0); - menu_add_watch(&menu, 18, 1, (uint32_t)&gz.profile, WATCH_TYPE_U8); + menu_add_watch(&menu, 18, 1, (uint32_t)&gz.profile, WATCH_TYPE_U8, 0, 0); menu_add_button(&menu, 16, 1, "-", profile_dec_proc, NULL); menu_add_button(&menu, 20, 1, "+", profile_inc_proc, NULL); /* appearance controls */ @@ -308,17 +325,19 @@ struct menu *gz_settings_menu(void) generic_position_proc, &settings->timer_x); menu_add_static(&menu, 0, 9, "pause display", 0xC0C0C0); menu_add_checkbox(&menu, 16, 9, pause_display_proc, NULL); + menu_add_static(&menu, 0, 10, "pointer watches", 0xC0C0C0); + menu_add_checkbox(&menu, 16, 10, pointer_watches_proc, NULL); /* behavior controls */ - menu_add_static(&menu, 0, 10, "macro input", 0xC0C0C0); - menu_add_checkbox(&menu, 16, 10, macro_input_proc, NULL); - menu_add_static(&menu, 0, 11, "break type", 0xC0C0C0); - menu_add_option(&menu, 16, 11, "normal\0""aggressive\0", + menu_add_static(&menu, 0, 11, "macro input", 0xC0C0C0); + menu_add_checkbox(&menu, 16, 11, macro_input_proc, NULL); + menu_add_static(&menu, 0, 12, "break type", 0xC0C0C0); + menu_add_option(&menu, 16, 12, "normal\0""aggressive\0", break_type_proc, NULL); - menu_add_submenu(&menu, 0, 12, &commands, "commands"); + menu_add_submenu(&menu, 0, 13, &commands, "commands"); /* settings commands */ - menu_add_button(&menu, 0, 13, "save settings", save_settings_proc, NULL); - menu_add_button(&menu, 0, 14, "load settings", load_settings_proc, NULL); - menu_add_button(&menu, 0, 15, "restore defaults", + menu_add_button(&menu, 0, 14, "save settings", save_settings_proc, NULL); + menu_add_button(&menu, 0, 15, "load settings", load_settings_proc, NULL); + menu_add_button(&menu, 0, 16, "restore defaults", restore_settings_proc, NULL); /* populate commands menu */ diff --git a/src/gz/menu.h b/src/gz/menu.h index 10b25c38..54eac2f6 100644 --- a/src/gz/menu.h +++ b/src/gz/menu.h @@ -41,6 +41,12 @@ enum menu_switch_reason MENU_SWITCH_HIDE, }; +enum menu_checkbox_type +{ + MENU_CHECKBOX_CHECK, + MENU_CHECKBOX_POINTER +}; + struct menu_draw_params { int x; @@ -227,18 +233,27 @@ void menu_prompt(struct menu *menu, const char *prompt, menu_prompt_callback callback_proc, void *callback_data); struct menu_item *menu_add_watch(struct menu *menu, int x, int y, - uint32_t address, enum watch_type type); + uint32_t address, enum watch_type type, + _Bool pointer, int offset); uint32_t menu_watch_get_address(struct menu_item *item); void menu_watch_set_address(struct menu_item *item, uint32_t address); +int menu_watch_get_offset(struct menu_item *item); +void menu_watch_set_offset(struct menu_item *item, + int offset); +_Bool menu_watch_get_pointer(struct menu_item *item); +void menu_watch_set_pointer(struct menu_item *item, + _Bool pointer); enum watch_type menu_watch_get_type(struct menu_item *item); void menu_watch_set_type(struct menu_item *item, enum watch_type type); struct menu_item *menu_add_userwatch(struct menu *menu, int x, int y, - uint32_t address, enum watch_type type); + uint32_t address, enum watch_type type, + _Bool pointer, int offset); struct menu_item *menu_userwatch_address(struct menu_item *item); struct menu_item *menu_userwatch_type(struct menu_item *item); struct menu_item *menu_userwatch_watch(struct menu_item *item); +struct menu_item *menu_userwatch_pointer(struct menu_item *item); struct menu_item *menu_add_submenu(struct menu *menu, int x, int y, struct menu *submenu, const char *name); struct menu_item *menu_add_switch(struct menu *menu, int x, int y, @@ -270,6 +285,8 @@ struct menu_item *menu_add_positioning(struct menu *menu, int x, int y, struct menu_item *menu_add_checkbox(struct menu *menu, int x, int y, menu_generic_callback callback_proc, void *callback_data); +void menu_checkbox_set_type(struct menu_item *item, + enum menu_checkbox_type type); _Bool menu_checkbox_get(struct menu_item *item); void menu_checkbox_set(struct menu_item *item, _Bool state); diff --git a/src/gz/menu_checkbox.c b/src/gz/menu_checkbox.c index 4617566e..4f9bf574 100644 --- a/src/gz/menu_checkbox.c +++ b/src/gz/menu_checkbox.c @@ -5,10 +5,11 @@ struct item_data { - menu_generic_callback callback_proc; - void *callback_data; - _Bool state; - int anim_state; + menu_generic_callback callback_proc; + void *callback_data; + _Bool state; + int anim_state; + enum menu_checkbox_type type; }; static int enter_proc(struct menu_item *item, enum menu_switch_reason reason) @@ -50,7 +51,12 @@ static int draw_proc(struct menu_item *item, if ((data->anim_state > 0) != data->state) { gfx_mode_set(GFX_MODE_COLOR, GPACK_RGBA8888(0xFF, 0xFF, 0xFF, draw_params->alpha)); - sprite.texture_tile = 2; + switch(data->type) + { + case MENU_CHECKBOX_POINTER: sprite.texture_tile = 3; break; + case MENU_CHECKBOX_CHECK: + default: sprite.texture_tile = 2; break; + } gfx_sprite_draw(&sprite); } if (data->anim_state > 0) @@ -81,6 +87,7 @@ struct menu_item *menu_add_checkbox(struct menu *menu, int x, int y, data->callback_proc = callback_proc; data->callback_data = callback_data; data->anim_state = 0; + data->type = MENU_CHECKBOX_CHECK; struct menu_item *item = menu_item_add(menu, x, y, NULL, 0xFFFFFF); item->data = data; item->enter_proc = enter_proc; @@ -90,6 +97,13 @@ struct menu_item *menu_add_checkbox(struct menu *menu, int x, int y, return item; } +void menu_checkbox_set_type(struct menu_item *item, + enum menu_checkbox_type type) +{ + struct item_data *data = item->data; + data->type = type; +} + _Bool menu_checkbox_get(struct menu_item *item) { struct item_data *data = item->data; diff --git a/src/gz/menu_userwatch.c b/src/gz/menu_userwatch.c index 8ad09d40..f5211a50 100644 --- a/src/gz/menu_userwatch.c +++ b/src/gz/menu_userwatch.c @@ -3,12 +3,16 @@ #include #include #include "menu.h" +#include "input.h" +#include "settings.h" struct item_data { struct menu_item *address; struct menu_item *type; struct menu_item *watch; + struct menu_item *pointer; + _Bool edit_offset; }; static int address_proc(struct menu_item *item, @@ -16,8 +20,13 @@ static int address_proc(struct menu_item *item, void *data) { struct item_data *item_data = data; - if (reason == MENU_CALLBACK_CHANGED) - menu_watch_set_address(item_data->watch, menu_intinput_get(item)); + if (reason == MENU_CALLBACK_CHANGED) { + if (!item_data->edit_offset) { + menu_watch_set_address(item_data->watch, menu_intinput_get(item)); + } else { + menu_watch_set_offset(item_data->watch, menu_intinput_get(item)); + } + } return 0; } @@ -31,22 +40,71 @@ static int type_proc(struct menu_item *item, return 0; } +static int pointer_proc(struct menu_item *item, + enum menu_callback_reason reason, + void *data) +{ + struct item_data *item_data = data; + if (reason == MENU_CALLBACK_SWITCH_OFF) { + if (input_pad() & BUTTON_Z) { + if (!item_data->edit_offset) { + menu_intinput_set(item_data->address, + menu_watch_get_offset(item_data->watch)); + item_data->edit_offset = 1; + } else { + menu_intinput_set(item_data->address, + menu_watch_get_address(item_data->watch)); + item_data->edit_offset = 0; + } + return 1; + } else { + menu_watch_set_pointer(item_data->watch, 0); + menu_intinput_set(item_data->address, + menu_watch_get_address(item_data->watch)); + item_data->edit_offset = 0; + } + } + else if (reason == MENU_CALLBACK_SWITCH_ON) { + menu_watch_set_pointer(item_data->watch, 1); + } + return 0; +} + struct menu_item *menu_add_userwatch(struct menu *menu, int x, int y, - uint32_t address, enum watch_type type) + uint32_t address, enum watch_type type, + _Bool pointer, int offset) { struct menu *imenu; struct menu_item *item = menu_add_imenu(menu, x, y, &imenu); struct item_data *data = malloc(sizeof(*data)); - data->address = menu_add_intinput(imenu, 0, 0, 16, 8, address_proc, data); - menu_intinput_set(data->address, address); - data->type = menu_add_option(imenu, 9, 0, - "u8\0""s8\0""x8\0" - "u16\0""s16\0""x16\0" - "u32\0""s32\0""x32\0" - "f32\0", - type_proc, data); - menu_option_set(data->type, type); - data->watch = menu_add_watch(imenu, 13, 0, address, type); + if (settings->bits.pointer_watches) { + data->pointer = menu_add_checkbox(imenu, 0, 0, pointer_proc, data); + data->edit_offset = 0; + menu_checkbox_set(data->pointer, pointer); + menu_checkbox_set_type(data->pointer, MENU_CHECKBOX_POINTER); + data->address = menu_add_intinput(imenu, 2, 0, 16, 8, address_proc, data); + menu_intinput_set(data->address, address); + data->type = menu_add_option(imenu, 11, 0, + "u8\0""s8\0""x8\0" + "u16\0""s16\0""x16\0" + "u32\0""s32\0""x32\0" + "f32\0", + type_proc, data); + menu_option_set(data->type, type); + data->watch = menu_add_watch(imenu, 15, 0, address, type, pointer, offset); + } else { + data->edit_offset = 0; + data->address = menu_add_intinput(imenu, 0, 0, 16, 8, address_proc, data); + menu_intinput_set(data->address, address); + data->type = menu_add_option(imenu, 9, 0, + "u8\0""s8\0""x8\0" + "u16\0""s16\0""x16\0" + "u32\0""s32\0""x32\0" + "f32\0", + type_proc, data); + menu_option_set(data->type, type); + data->watch = menu_add_watch(imenu, 13, 0, address, type, pointer, offset); + } item->data = data; return item; } @@ -68,3 +126,9 @@ struct menu_item *menu_userwatch_watch(struct menu_item *item) struct item_data *data = item->data; return data->watch; } + +struct menu_item *menu_userwatch_pointer(struct menu_item *item) +{ + struct item_data *data = item->data; + return data->pointer; +} \ No newline at end of file diff --git a/src/gz/menu_watch.c b/src/gz/menu_watch.c index d1c3c522..008542c8 100644 --- a/src/gz/menu_watch.c +++ b/src/gz/menu_watch.c @@ -7,10 +7,13 @@ #include #include "menu.h" #include "util.h" +#include "settings.h" struct item_data { uint32_t address; + _Bool pointer; + int offset; enum watch_type type; }; @@ -30,6 +33,13 @@ static int draw_proc(struct menu_item *item, if (address < 0x80000000 || address >= 0x80800000 || data->type < 0 || data->type >= WATCH_TYPE_MAX) return 1; + if (data->pointer && settings->bits.pointer_watches) { + address -= address % 4; + address = *(uint32_t*)address; + address = address + data->offset; + if (address < 0x80000000 || address >= 0x80800000) + return 1; + } address -= address % watch_type_size[data->type]; switch (data->type) { case WATCH_TYPE_U8: @@ -72,11 +82,14 @@ static int draw_proc(struct menu_item *item, } struct menu_item *menu_add_watch(struct menu *menu, int x, int y, - uint32_t address, enum watch_type type) + uint32_t address, enum watch_type type, + _Bool pointer, int offset) { struct item_data *data = malloc(sizeof(*data)); data->address = address; data->type = type; + data->pointer = pointer; + data->offset = offset; struct menu_item *item = menu_item_add(menu, x, y, NULL, 0xC0C0C0); item->text = malloc(17); item->selectable = 0; @@ -97,6 +110,30 @@ void menu_watch_set_address(struct menu_item *item, uint32_t address) data->address = address; } +int menu_watch_get_offset(struct menu_item *item) +{ + struct item_data *data = item->data; + return data->offset; +} + +void menu_watch_set_offset(struct menu_item *item, int offset) +{ + struct item_data *data = item->data; + data->offset = offset; +} + +_Bool menu_watch_get_pointer(struct menu_item *item) +{ + struct item_data *data = item->data; + return data->pointer; +} + +void menu_watch_set_pointer(struct menu_item *item, _Bool pointer) +{ + struct item_data *data = item->data; + data->pointer = pointer; +} + enum watch_type menu_watch_get_type(struct menu_item *item) { struct item_data *data = item->data; diff --git a/src/gz/settings.c b/src/gz/settings.c index d196d649..35461438 100644 --- a/src/gz/settings.c +++ b/src/gz/settings.c @@ -42,6 +42,7 @@ void settings_load_default(void) d->bits.lag_unit = SETTINGS_LAG_FRAMES; d->bits.timer = 0; d->bits.pause_display = 1; + d->bits.pointer_watches = 0; d->bits.macro_input = 0; d->bits.hack_oca_input = 1; d->bits.hack_oca_sync = 1; diff --git a/src/gz/settings.h b/src/gz/settings.h index 5b2eddfd..38557427 100644 --- a/src/gz/settings.h +++ b/src/gz/settings.h @@ -102,9 +102,10 @@ enum commands struct watch_info { - uint8_t type : 4; - uint8_t anchored : 1; - uint8_t position_set : 1; + uint8_t type : 4; + uint8_t anchored : 1; + uint8_t position_set : 1; + uint8_t pointer : 1; }; struct settings_bits @@ -117,6 +118,7 @@ struct settings_bits uint32_t lag_unit : 1; uint32_t timer : 1; uint32_t pause_display : 1; + uint32_t pointer_watches : 1; uint32_t macro_input : 1; uint32_t hack_oca_input : 1; uint32_t hack_oca_sync : 1; @@ -143,6 +145,7 @@ struct settings_data /* order elements by size for space-efficient packing */ z64_xyzf_t teleport_pos[SETTINGS_TELEPORT_MAX]; uint32_t watch_address[SETTINGS_WATCHES_MAX]; + uint32_t watch_offset[SETTINGS_WATCHES_MAX]; uint32_t cheats; z64_angle_t teleport_rot[SETTINGS_TELEPORT_MAX]; struct settings_bits bits; diff --git a/src/gz/watchlist.c b/src/gz/watchlist.c index c7bed262..83db0c43 100644 --- a/src/gz/watchlist.c +++ b/src/gz/watchlist.c @@ -68,7 +68,7 @@ static void anchor_member(struct member_data *member_data) member_data->anchored = 1; menu_item_disable(member_data->positioning); struct menu_item *watch = menu_userwatch_watch(member_data->userwatch); - watch->x = 13; + watch->x = settings->bits.pointer_watches ? 15 : 13; watch->y = 0; watch->pxoffset = 0; watch->pyoffset = 0; @@ -156,7 +156,8 @@ static int position_proc(struct menu_item *item, static void remove_button_proc(struct menu_item *item, void *data); static int add_member(struct item_data *data, uint32_t address, enum watch_type type, int position, - _Bool anchored, int x, int y, _Bool position_set) + _Bool anchored, _Bool pointer, int offset, int x, int y, + _Bool position_set) { if (data->members.size >= SETTINGS_WATCHES_MAX || position < 0 || position > data->members.size) @@ -180,7 +181,8 @@ static int add_member(struct item_data *data, member_data->anchor_button->data = member_data; member_data->positioning = menu_add_positioning(imenu, 4, 0, position_proc, member_data); - member_data->userwatch = menu_add_userwatch(imenu, 6, 0, address, type); + member_data->userwatch = menu_add_userwatch(imenu, 6, 0, address, type, + pointer, offset); member_data->anchored = 1; member_data->anchor_anim_state = 0; member_data->x = x; @@ -230,14 +232,19 @@ static void add_button_proc(struct menu_item *item, void *data) struct item_data *item_data = data; uint32_t address = 0x80000000; enum watch_type type = WATCH_TYPE_U8; + _Bool pointer = 0; + int offset = 0; if (item_data->members.size > 0) { struct member_data *member_data = get_member(item_data, item_data->members.size - 1); struct menu_item *last_watch = menu_userwatch_watch(member_data->userwatch); address = menu_watch_get_address(last_watch); type = menu_watch_get_type(last_watch); + pointer = menu_watch_get_pointer(last_watch); + offset = menu_watch_get_offset(last_watch); } - add_member(item_data, address, type, item_data->members.size, 1, 0, 0, 0); + add_member(item_data, address, type, item_data->members.size, 1, pointer, + offset, 0, 0, 0); } static int import_callback(const char *path, void *data); @@ -336,14 +343,36 @@ void watchlist_store(struct menu_item *item) struct member_data *member_data = get_member(data, i); struct menu_item *watch = menu_userwatch_watch(member_data->userwatch); settings->watch_address[i] = menu_watch_get_address(watch); + settings->watch_offset[i] = menu_watch_get_offset(watch); settings->watch_x[i] = member_data->x; settings->watch_y[i] = member_data->y; settings->watch_info[i].type = menu_watch_get_type(watch); settings->watch_info[i].anchored = member_data->anchored; + settings->watch_info[i].pointer = menu_watch_get_pointer(watch); settings->watch_info[i].position_set = member_data->position_set; } } +void watchlist_refresh(struct menu_item *item) +{ + struct item_data *data = item->data; + for (int i = 0; i < data->members.size; ++i) { + struct member_data *member_data = get_member(data, 0); + struct menu_item *watch = menu_userwatch_watch(member_data->userwatch); + int address = menu_watch_get_address(watch); + int offset = menu_watch_get_offset(watch); + int16_t x = member_data->x; + int16_t y = member_data->y; + enum watch_type type = menu_watch_get_type(watch); + _Bool anchored = member_data->anchored; + _Bool pointer = menu_watch_get_pointer(watch); + _Bool position_set = member_data->position_set; + remove_member(data, 0); + add_member(data, address, type, data->members.size, anchored, + pointer, offset, x, y, position_set); + } +} + void watchlist_fetch(struct menu_item *item) { struct item_data *data = item->data; @@ -351,7 +380,8 @@ void watchlist_fetch(struct menu_item *item) remove_member(data, i); for (int i = 0; i < settings->n_watches; ++i) add_member(data, settings->watch_address[i], settings->watch_info[i].type, - i, settings->watch_info[i].anchored, + i, settings->watch_info[i].anchored, + settings->watch_info[i].pointer, settings->watch_offset[i], settings->watch_x[i], settings->watch_y[i], settings->watch_info[i].position_set); } @@ -460,7 +490,7 @@ static int entry_activate_proc(struct menu_item *item) } else { add_member(watchfile_list_data, address, entry->type, - watchfile_list_data->members.size, 1, 0, 0, 0); + watchfile_list_data->members.size, 1, 0, 0, 0, 0, 0); } return 1; } diff --git a/src/gz/watchlist.h b/src/gz/watchlist.h index 6caadd78..1aca6e66 100644 --- a/src/gz/watchlist.h +++ b/src/gz/watchlist.h @@ -6,6 +6,7 @@ struct menu_item *watchlist_create(struct menu *menu, struct menu *menu_release, int x, int y); void watchlist_store(struct menu_item *item); +void watchlist_refresh(struct menu_item *item); void watchlist_fetch(struct menu_item *item); void watchlist_show(struct menu_item *item); void watchlist_hide(struct menu_item *item);