mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-28 23:45:45 -04:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7cc0c07ffb | |||
| a775418c66 | |||
| 48b5c2e8c1 | |||
| 705e7f058b | |||
| e30e0fe062 | |||
| c4f4712d0e | |||
| 2d70c24b37 | |||
| 72ccb14d35 | |||
| c53f3f774b | |||
| 5a8622c6b2 | |||
| 29b86f938f | |||
| e02638ac6d | |||
| 1db2a74192 | |||
| d281c34a65 | |||
| 788700daa6 | |||
| 3aa54ca170 | |||
| 81dfe701e9 | |||
| 16f2b954fa | |||
| 41d5148793 | |||
| 14f9b6c762 | |||
| 44e02a9d53 | |||
| 5f0f3d4ebe | |||
| 172d06f38d |
+45
-4
@@ -411,7 +411,47 @@ if (DUSK_ENABLE_CODE_MODS)
|
||||
setup_symbol_manifest(dusklight)
|
||||
endif ()
|
||||
|
||||
# Hook reliability: guaranteed patchable entries on the game ABI surface, and no identical-code folding.
|
||||
# Hook reliability: prevent auto-inlining, guarantee patchable function entries,
|
||||
# and disable identical-code folding for game functions.
|
||||
set(DUSK_GAME_ABI_INLINE_OPTIONS)
|
||||
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "GNU")
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
list(APPEND DUSK_GAME_ABI_INLINE_OPTIONS
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-finline-hint-functions>)
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
list(APPEND DUSK_GAME_ABI_INLINE_OPTIONS
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-flive-patching=inline-clone>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-inline-functions>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-inline-small-functions>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-inline-functions-called-once>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-early-inlining>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-ipa-cp>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-ipa-cp-clone>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-ipa-sra>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-partial-inlining>)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (DUSK_GAME_ABI_INLINE_OPTIONS)
|
||||
set(_game_abi_files ${GAME_BASE_FILES} ${GAME_DEBUG_FILES})
|
||||
list(FILTER _game_abi_files EXCLUDE REGEX "^src/dusk/")
|
||||
set_property(SOURCE ${_game_abi_files} APPEND PROPERTY
|
||||
COMPILE_OPTIONS ${DUSK_GAME_ABI_INLINE_OPTIONS})
|
||||
|
||||
foreach(jsystem_lib IN LISTS JSYSTEM_LIBRARIES)
|
||||
target_compile_options(${jsystem_lib} PRIVATE ${DUSK_GAME_ABI_INLINE_OPTIONS})
|
||||
endforeach()
|
||||
foreach(_sdk_lib aurora_card aurora_core aurora_dvd aurora_gd aurora_gx aurora_mtx
|
||||
aurora_os aurora_pad aurora_si aurora_vi)
|
||||
if (TARGET ${_sdk_lib})
|
||||
get_target_property(_sdk_lib_imported ${_sdk_lib} IMPORTED)
|
||||
if (NOT _sdk_lib_imported)
|
||||
target_compile_options(${_sdk_lib} PRIVATE ${DUSK_GAME_ABI_INLINE_OPTIONS})
|
||||
endif ()
|
||||
endif ()
|
||||
endforeach ()
|
||||
endif ()
|
||||
|
||||
if (MSVC)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(DUSK_PATCHABLE_ENTRY_FLAG $<$<COMPILE_LANGUAGE:C,CXX>:/hotpatch>)
|
||||
@@ -421,11 +461,11 @@ if (MSVC)
|
||||
else ()
|
||||
target_link_options(dusklight PRIVATE /FUNCTIONPADMIN /OPT:NOICF)
|
||||
endif ()
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "^(AppleClang|Clang)$")
|
||||
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" OR CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "^(AppleClang|Clang|GNU)$")
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)$" OR CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
|
||||
set(DUSK_PATCHABLE_ENTRY_FLAG $<$<COMPILE_LANGUAGE:C,CXX>:-fpatchable-function-entry=2,1>)
|
||||
else ()
|
||||
set(DUSK_PATCHABLE_ENTRY_FLAG $<$<COMPILE_LANGUAGE:C,CXX>:-fpatchable-function-entry=10,5>)
|
||||
set(DUSK_PATCHABLE_ENTRY_FLAG $<$<COMPILE_LANGUAGE:C,CXX>:-fpatchable-function-entry=10,4>)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
@@ -520,6 +560,7 @@ if (DUSK_ENABLE_CODE_MODS AND CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR
|
||||
add_subdirectory(mods/shadow_mod)
|
||||
add_subdirectory(mods/window_demo)
|
||||
add_subdirectory(mods/flow_demo)
|
||||
add_subdirectory(mods/basic_cosmetics_mod)
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
|
||||
@@ -2,7 +2,7 @@ include_guard(GLOBAL)
|
||||
|
||||
get_filename_component(_SYMBOL_MANIFEST_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
|
||||
|
||||
set(_SYMGEN_VERSION "1.3.2")
|
||||
set(_SYMGEN_VERSION "1.3.3")
|
||||
set(_SYMGEN_RELEASE_BASE_URL "https://github.com/encounter/symgen/releases/download/v${_SYMGEN_VERSION}")
|
||||
set(SYMGEN_PATH "" CACHE FILEPATH "Path to a symgen executable; empty downloads the pinned release")
|
||||
mark_as_advanced(SYMGEN_PATH)
|
||||
@@ -15,32 +15,32 @@ function(symgen_host_asset out_name out_hash)
|
||||
if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
|
||||
if (_host_processor MATCHES "^(arm64|aarch64)$")
|
||||
set(_asset "symgen-macos-arm64")
|
||||
set(_asset_hash "SHA256=0344838d1674df09c17c3eeddcf26eb89c333fdb85dfd78f68adc436070eccbe")
|
||||
set(_asset_hash "SHA256=e8420df1160242c83bd0e5197efeeb25ceb9fecc69dbc82bdc4927476381e948")
|
||||
elseif (_host_processor MATCHES "^(x86_64|amd64)$")
|
||||
set(_asset "symgen-macos-x86_64")
|
||||
set(_asset_hash "SHA256=ae0674f4a1e9d0dedfa02d35939ac28cdd229276b331c1f507df5df809cbec7e")
|
||||
set(_asset_hash "SHA256=e51d13bbf0e982d1519f56850ff3c7b5910ca5a7095dd5a82cd8e59750e2d013")
|
||||
endif ()
|
||||
elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
|
||||
if (_host_processor MATCHES "^(aarch64|arm64)$")
|
||||
set(_asset "symgen-linux-aarch64")
|
||||
set(_asset_hash "SHA256=af766de2bfaeb0a06f6d7bc17bb2510b4a9c40f44a56e49bc4a4b798a6223042")
|
||||
set(_asset_hash "SHA256=331190dd21ecee12a52e857b7f90a8b3e0a114608173813f7df74a31cf783f70")
|
||||
elseif (_host_processor MATCHES "^(x86_64|amd64)$")
|
||||
set(_asset "symgen-linux-x86_64")
|
||||
set(_asset_hash "SHA256=ebd62fb9623acc942b6295609e2306f85a73043b0a8a117f2072b761dd08e68f")
|
||||
set(_asset_hash "SHA256=d727e0ba43242f92a92865af1b69c47aa9d81a0242c4570ce53b90e1ecd15e84")
|
||||
elseif (_host_processor MATCHES "^(i[3-6]86|x86)$")
|
||||
set(_asset "symgen-linux-i686")
|
||||
set(_asset_hash "SHA256=07780a4513fd29726578efc4ff2d88736b22f407ed821b32a68e35ff1e9af5f4")
|
||||
set(_asset_hash "SHA256=0c9f94d36b7fa46d15a199c9d0f1a633b73eb7d9c02621a6a76a676b83a135c7")
|
||||
endif ()
|
||||
elseif (CMAKE_HOST_WIN32)
|
||||
if (_host_processor MATCHES "^(arm64|aarch64)$")
|
||||
set(_asset "symgen-windows-arm64.exe")
|
||||
set(_asset_hash "SHA256=5bb22b4a4a9b5ad45646af411bfb09b8321a732ff3a077eb4c9de1feaef27d2b")
|
||||
set(_asset_hash "SHA256=c699192957e2086ed68912ed39fa77858e1ae894476ab8b557711804cf2aa7cb")
|
||||
elseif (_host_processor MATCHES "^(x86_64|amd64)$")
|
||||
set(_asset "symgen-windows-x86_64.exe")
|
||||
set(_asset_hash "SHA256=1d1ac087f991a96932d108969e15998becfec643e88f3e7d182ca97ebfc6a46f")
|
||||
set(_asset_hash "SHA256=6d56a45617c75065ab7a3192d09ca52ff735baf5637b0899f446138d46acc310")
|
||||
elseif (_host_processor MATCHES "^(i[3-6]86|x86)$")
|
||||
set(_asset "symgen-windows-x86.exe")
|
||||
set(_asset_hash "SHA256=c113f4cd05f813efe2b1878dbfcf44d6302aee3974271736e0036430b0cced78")
|
||||
set(_asset_hash "SHA256=6cccc3a8d29e7525a4d1ade1dc4d89327b7c3002a604ab1c7decb43eea6fd4ab")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
+82
-9
@@ -474,8 +474,8 @@ per-window RCSS. A non-`MOD_OK` result from `build`/`update` fails your mod, as
|
||||
callback.
|
||||
|
||||
**Controls:** `pane_add_control` adds an input row described by a `UiControlDesc`: `UI_CONTROL_BUTTON`,
|
||||
`UI_CONTROL_TOGGLE`, `UI_CONTROL_NUMBER`, `UI_CONTROL_STRING`, or `UI_CONTROL_SELECT`. Values bind with callbacks or
|
||||
directly to a config var.
|
||||
`UI_CONTROL_GROUP`, `UI_CONTROL_TOGGLE`, `UI_CONTROL_NUMBER`, `UI_CONTROL_STRING`, `UI_CONTROL_SELECT`, or
|
||||
`UI_CONTROL_COLOR`. Values bind with callbacks or directly to a config var.
|
||||
|
||||
```cpp
|
||||
UiControlDesc control = UI_CONTROL_DESC_INIT;
|
||||
@@ -488,9 +488,56 @@ svc_ui->pane_add_control(mod_ctx, leftPane, &control, nullptr);
|
||||
```
|
||||
|
||||
`UI_BINDING_CONFIG_VAR` wires persistence, change notifications, and the modified indicator automatically. The var
|
||||
type must match the control: `TOGGLE` = bool, `NUMBER` and `SELECT` = int, `STRING` = string. Float vars are not
|
||||
bindable; use callbacks and convert. `help_rml` and `SELECT` option lists render in a help pane, so `SELECT` controls
|
||||
are only available inside window tabs.
|
||||
type must match the control: `TOGGLE` = bool, `NUMBER` and `SELECT` = int, `STRING` and `COLOR` = string. Float vars
|
||||
are not bindable; use callbacks and convert. `help_rml` and `SELECT` option lists render in a help pane, so `SELECT`
|
||||
controls are only available inside window tabs.
|
||||
|
||||
`pane_add_group` adds a category button to a window tab's left pane. Focusing the button clears the paired right pane
|
||||
and calls the group's build callback with that pane, which is useful for organizing related controls without adding
|
||||
more tabs.
|
||||
|
||||
**Lists:** `pane_add_list` adds a scrollable virtualized list of items that can be efficiently updated and filtered.
|
||||
Keys must be unique and remain stable across replacements.
|
||||
|
||||
```cpp
|
||||
UiListHandle locationList = 0;
|
||||
|
||||
void replace_locations(std::string_view query) {
|
||||
std::vector<UiListItem> items;
|
||||
for (uint64_t i = 0; i < locations.size(); ++i) {
|
||||
if (matches(locations[i], query)) {
|
||||
UiListItem item = UI_LIST_ITEM_INIT;
|
||||
item.key = i;
|
||||
item.label = locations[i].c_str();
|
||||
items.push_back(item);
|
||||
}
|
||||
}
|
||||
svc_ui->list_set_items(mod_ctx, locationList, items.data(), items.size());
|
||||
}
|
||||
|
||||
void set_filter(ModContext*, void*, const UiControlValue* value) {
|
||||
replace_locations(value->string_value);
|
||||
}
|
||||
|
||||
bool location_selected(ModContext*, UiListHandle, uint64_t key, void*) {
|
||||
return selected_locations.contains(key);
|
||||
}
|
||||
|
||||
UiControlDesc filter = UI_CONTROL_DESC_INIT;
|
||||
filter.kind = UI_CONTROL_STRING;
|
||||
filter.label = "Filter";
|
||||
filter.get = get_filter;
|
||||
filter.set = set_filter;
|
||||
filter.string_set_mode = UI_STRING_SET_ON_CHANGE; /* invoke `set` while typing */
|
||||
svc_ui->pane_add_control(mod_ctx, pane, &filter, nullptr);
|
||||
|
||||
UiListDesc list = UI_LIST_DESC_INIT;
|
||||
/* items may be passed as a part of list creation, or set afterwards */
|
||||
list.on_pressed = location_pressed;
|
||||
list.is_selected = location_selected;
|
||||
svc_ui->pane_add_list(mod_ctx, pane, &list, &locationList);
|
||||
replace_locations(""); /* calls `list_set_items` */
|
||||
```
|
||||
|
||||
**Windows:** `window_push` pushes a tabbed two-pane window onto the document stack and shows it. Each tab's `build`
|
||||
receives the window handle plus fresh left and right pane handles on every activation. The optional per-tab `update`
|
||||
@@ -512,10 +559,36 @@ svc_ui->window_push(mod_ctx, &desc, &window);
|
||||
```
|
||||
|
||||
**Dialogs:** `dialog_push` shows a modal dialog. `variant` picks the style, `icon` optionally overrides the variant's
|
||||
default icon, and actions become buttons. After an action's `on_pressed` returns, the dialog closes unless the action
|
||||
sets `keep_open`. A `keep_open` action can close it later (or immediately) with `dialog_close`. Cancel fires
|
||||
`on_dismiss` if present and always closes. `dialog_set_body`, `dialog_set_icon`, and `dialog_add_action` mutate a live
|
||||
dialog.
|
||||
default icon, and actions become buttons. The optional `build` callback allows you to add controls to a pane between
|
||||
the body and actions. It uses the same text, progress, and control builders as panels.
|
||||
|
||||
```cpp
|
||||
ModResult build_dialog(ModContext*, UiElementHandle pane, void*, ModError*) {
|
||||
UiControlDesc input = UI_CONTROL_DESC_INIT;
|
||||
input.kind = UI_CONTROL_STRING;
|
||||
input.label = "Name";
|
||||
input.get = get_name;
|
||||
input.set = set_name;
|
||||
return svc_ui->pane_add_control(mod_ctx, pane, &input, nullptr);
|
||||
}
|
||||
|
||||
UiDialogAction action = UI_DIALOG_ACTION_INIT;
|
||||
action.label = "Save";
|
||||
action.on_pressed = save;
|
||||
action.is_disabled = is_save_disabled;
|
||||
|
||||
UiDialogDesc dialog = UI_DIALOG_DESC_INIT;
|
||||
dialog.title = "New Preset";
|
||||
dialog.body_rml = "Choose a name for the preset.";
|
||||
dialog.actions = &action;
|
||||
dialog.action_count = 1;
|
||||
dialog.build = build_dialog;
|
||||
svc_ui->dialog_push(mod_ctx, &dialog, nullptr);
|
||||
```
|
||||
|
||||
After an action's `on_pressed`, the dialog closes unless the action sets `keep_open`. It can then be closed later
|
||||
(or immediately) with `dialog_close`. Cancel fires `on_dismiss` and always closes. `dialog_set_body` and
|
||||
`dialog_set_icon` mutate a live dialog.
|
||||
|
||||
**Toasts:** `push_toast` enqueues a notification. Titles and bodies accept RML. The optional `type` is applied as an
|
||||
RCSS class; `warning` uses the built-in warning appearance, and mods can define their own types. A duration of 0 uses
|
||||
|
||||
Vendored
+1
-1
Submodule extern/aurora updated: 0f15fb65d1...2c9c95cfed
+10
@@ -1525,6 +1525,8 @@ set(DUSK_FILES
|
||||
src/dusk/ui/bool_button.hpp
|
||||
src/dusk/ui/button.cpp
|
||||
src/dusk/ui/button.hpp
|
||||
src/dusk/ui/color_input.cpp
|
||||
src/dusk/ui/color_input.hpp
|
||||
src/dusk/ui/component.cpp
|
||||
src/dusk/ui/component.hpp
|
||||
src/dusk/ui/controller_config.cpp
|
||||
@@ -1538,12 +1540,16 @@ set(DUSK_FILES
|
||||
src/dusk/ui/event.hpp
|
||||
src/dusk/ui/graphics_tuner.cpp
|
||||
src/dusk/ui/graphics_tuner.hpp
|
||||
src/dusk/ui/group_button.cpp
|
||||
src/dusk/ui/group_button.hpp
|
||||
src/dusk/ui/icon_provider.cpp
|
||||
src/dusk/ui/icon_provider.hpp
|
||||
src/dusk/ui/input.cpp
|
||||
src/dusk/ui/input.hpp
|
||||
src/dusk/ui/logs_window.cpp
|
||||
src/dusk/ui/logs_window.hpp
|
||||
src/dusk/ui/list.cpp
|
||||
src/dusk/ui/list.hpp
|
||||
src/dusk/ui/menu_bar.cpp
|
||||
src/dusk/ui/menu_bar.hpp
|
||||
src/dusk/ui/mod_texture_provider.cpp
|
||||
@@ -1555,12 +1561,16 @@ set(DUSK_FILES
|
||||
src/dusk/ui/mods_window.cpp
|
||||
src/dusk/ui/mods_window.hpp
|
||||
src/dusk/ui/nav_types.hpp
|
||||
src/dusk/ui/nav_group.cpp
|
||||
src/dusk/ui/nav_group.hpp
|
||||
src/dusk/ui/number_button.cpp
|
||||
src/dusk/ui/number_button.hpp
|
||||
src/dusk/ui/overlay.cpp
|
||||
src/dusk/ui/overlay.hpp
|
||||
src/dusk/ui/pane.cpp
|
||||
src/dusk/ui/pane.hpp
|
||||
src/dusk/ui/popover.cpp
|
||||
src/dusk/ui/popover.hpp
|
||||
src/dusk/ui/prelaunch.cpp
|
||||
src/dusk/ui/prelaunch.hpp
|
||||
src/dusk/ui/preset.cpp
|
||||
|
||||
@@ -8449,8 +8449,10 @@ struct daAlink_cutHorseParamTbl {
|
||||
/* 0xA */ u8 m_cutType;
|
||||
}; // Size: 0xC
|
||||
|
||||
#if !TARGET_PC
|
||||
inline BOOL dComIfGs_isTransformLV(int i_no);
|
||||
inline BOOL dComIfGs_isEventBit(const u16);
|
||||
#endif
|
||||
|
||||
static fopAc_ac_c* daAlink_searchPortal(fopAc_ac_c* i_actor, void* i_data);
|
||||
static fopAc_ac_c* daAlink_searchCanoe(fopAc_ac_c* i_actor, void* i_data);
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
/* 0xDEC */ u8 field_0xdec[0xdf9 - 0xdec];
|
||||
/* 0xDF9 */ u8 field_0xdf9;
|
||||
#if TARGET_PC
|
||||
bool mItemCheckOverridden;
|
||||
bool mItemCheckHandled;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -32,6 +32,12 @@ struct daItemBase_data {
|
||||
class daItemBase_c : public fopAc_ac_c {
|
||||
public:
|
||||
u8 getItemNo();
|
||||
#if TARGET_PC
|
||||
u8 getDisplayItemNo() const {
|
||||
return mDisplayItemNo != 0xFF ? mDisplayItemNo : m_itemNo;
|
||||
}
|
||||
void setDisplayItemNo(u8 itemNo) { mDisplayItemNo = itemNo; }
|
||||
#endif
|
||||
void hide();
|
||||
void show();
|
||||
void changeDraw();
|
||||
@@ -79,6 +85,9 @@ public:
|
||||
/* 0x928 */ s16 m_get_timer;
|
||||
/* 0x92A */ u8 m_itemNo;
|
||||
/* 0x92B */ u8 field_0x92b;
|
||||
#if TARGET_PC
|
||||
u8 mDisplayItemNo = 0xFF;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* D_A_D_A_ITEMBASE_H */
|
||||
|
||||
@@ -423,7 +423,7 @@ public:
|
||||
static DUSK_GAME_DATA daMidna_texData_s const m_texDataTable[21];
|
||||
static DUSK_GAME_DATA daMidna_anmData_s const m_anmDataTable[53];
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x568 */ request_of_phase_process_class mPhase;
|
||||
/* 0x570 */ J3DModel* mpModel;
|
||||
/* 0x574 */ J3DModel* mpShadowModel;
|
||||
|
||||
@@ -92,6 +92,7 @@ private:
|
||||
u8 mOriginalItemNo;
|
||||
bool mItemOverridden;
|
||||
bool mOverrideHover;
|
||||
bool mGoldenWolfItem;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -311,9 +311,11 @@ private:
|
||||
class daMidna_c;
|
||||
class daSpinner_c;
|
||||
class daPy_py_c;
|
||||
#if !TARGET_PC
|
||||
inline daPy_py_c* dComIfGp_getLinkPlayer();
|
||||
inline BOOL dComIfGs_isEventBit(const u16);
|
||||
inline u32 dComIfGs_getLastSceneMode();
|
||||
#endif
|
||||
|
||||
class daPy_py_c : public fopAc_ac_c {
|
||||
public:
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
#ifndef D_A_D_A_ITEMBASE_STATIC_H
|
||||
#define D_A_D_A_ITEMBASE_STATIC_H
|
||||
|
||||
#include "dolphin/types.h"
|
||||
|
||||
class fopAc_ac_c;
|
||||
|
||||
int CheckFieldItemCreateHeap(fopAc_ac_c* actor);
|
||||
int CheckItemCreateHeap(fopAc_ac_c* i_this);
|
||||
|
||||
#if TARGET_PC
|
||||
const char* dItem_fieldModelArc(u8 itemNo);
|
||||
#endif
|
||||
|
||||
#endif /* D_A_D_A_ITEMBASE_STATIC_H */
|
||||
|
||||
+934
-78
File diff suppressed because it is too large
Load Diff
@@ -37,7 +37,7 @@ public:
|
||||
CPaneMgrAlpha* getNoDatBase() { return mNoDatBase; }
|
||||
void draw() { _draw(); }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x04 */ JKRArchive* mArchive;
|
||||
/* 0x08 */ dDlst_FileInfo_c mFileInfo;
|
||||
/* 0x1C */ u8 field_0x1c[4];
|
||||
|
||||
@@ -16,39 +16,6 @@
|
||||
class dFile_info_c;
|
||||
class J2DPicture;
|
||||
|
||||
#if TARGET_PC
|
||||
static PaneCache mSelDtPanes[] = {
|
||||
{MULTI_CHAR('tate_n0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('tate_n1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('ken_n0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('ken_n1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fuku_n0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fuku_n1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fuku_n2'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('gray_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('b_base'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('b_base1'), 0.0f, 0.0f, false},
|
||||
};
|
||||
|
||||
static PaneCache fileSelPanes[] = {
|
||||
{MULTI_CHAR('w_uzu00'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu01'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu02'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu03'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu04'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu05'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu06'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu07'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu08'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu09'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_er_msg'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_er_msE'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_er_msR'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('er_for0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('er_for1'), 0.0f, 0.0f, false},
|
||||
};
|
||||
#endif
|
||||
|
||||
class dDlst_FileSel_c : public dDlst_base_c {
|
||||
public:
|
||||
void draw();
|
||||
|
||||
@@ -142,7 +142,12 @@ enum {
|
||||
/* 0x2F */ dItemNo_WEAR_KOKIRI_e,
|
||||
/* 0x30 */ dItemNo_ARMOR_e,
|
||||
/* 0x31 */ dItemNo_WEAR_ZORA_e,
|
||||
#if TARGET_PC
|
||||
/* 0x32 */ dItemNo_MAGIC_LV1_e,
|
||||
dItemNo_SHADOW_CRYSTAL_e = dItemNo_MAGIC_LV1_e,
|
||||
#else
|
||||
/* 0x32 */ dItemNo_MAGIC_LV1_e,
|
||||
#endif
|
||||
/* 0x33 */ dItemNo_DUNGEON_EXIT_2_e,
|
||||
/* 0x34 */ dItemNo_WALLET_LV1_e,
|
||||
/* 0x35 */ dItemNo_WALLET_LV2_e,
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
|
||||
void drawSelf() { mpKanteraIcon->draw(); }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x04 */ dDlst_KanteraIcon_c* mpKanteraIcon;
|
||||
/* 0x08 */ CPaneMgr* mpParent;
|
||||
/* 0x0C */ CPaneMgr* mpGauge;
|
||||
|
||||
@@ -15,49 +15,6 @@ class dMenu_Fishing_c;
|
||||
class dMenu_Skill_c;
|
||||
class dMenu_Insect_c;
|
||||
class dSelect_cursor_c;
|
||||
|
||||
#if TARGET_PC
|
||||
struct PaneCache {
|
||||
u64 tag;
|
||||
f32 origTransX;
|
||||
f32 origTransY;
|
||||
bool cached;
|
||||
};
|
||||
|
||||
static PaneCache mpScreenPanes[] = {
|
||||
{MULTI_CHAR('sa_tex_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('op_tex_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('heart_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('wolf_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('item_0_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('item_1_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('item_2_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fish_3_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('lett_4_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('maki_5_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fuku_n0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fuku_n1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fuku_n2'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('tate_n0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('tate_n1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('ken_n0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('ken_n1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('kabu_6n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('t_t00'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('f_t00'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('itemn_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('infotxtn'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('sa_op_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('title_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('menu_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_er_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('center_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('info_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('lavel_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('modelbgn'), 0.0f, 0.0f, false},
|
||||
};
|
||||
#endif
|
||||
|
||||
class dMenu_Collect2D_c;
|
||||
class dMenu_Collect2DTop_c : public dDlst_base_c {
|
||||
public:
|
||||
@@ -172,7 +129,7 @@ public:
|
||||
J2DPicture* getBlackTex() { return mpBlackTex; }
|
||||
u8 getSubWindowOpenCheck() { return mSubWindowOpenCheck; }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x004 */ JKRExpHeap* mpHeap;
|
||||
/* 0x008 */ JKRExpHeap* mpSubHeap;
|
||||
/* 0x00C */ void* field_0xc;
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
|
||||
u8 getStatus() { return mStatus; }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x004 */ JKRExpHeap* mpHeap;
|
||||
/* 0x008 */ JKRArchive* mpArchive;
|
||||
/* 0x00C */ STControl* mpStick;
|
||||
|
||||
@@ -270,7 +270,7 @@ public:
|
||||
|
||||
static DUSK_GAME_DATA dMenu_Fmap_c* MyClass;
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x004 */ JKRExpHeap* mpHeap;
|
||||
/* 0x008 */ JKRExpHeap* mpTalkHeap;
|
||||
/* 0x00C */ STControl* mpStick;
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
|
||||
u8 getStatus() { return mStatus; }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x04 */ JKRExpHeap* mpHeap;
|
||||
/* 0x08 */ JKRArchive* mpArchive;
|
||||
/* 0x0C */ STControl* mpStick;
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
|
||||
u8 getStatus() { return mStatus; }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x004 */ JKRExpHeap* mpHeap;
|
||||
/* 0x008 */ JKRArchive* mpArchive;
|
||||
/* 0x00C */ STControl* mpStick;
|
||||
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
return ((u8)mUseFlag & (u8)i_flag) != 0 ? true : false;
|
||||
}
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x004 */ J2DScreen* mpBackScreen;
|
||||
/* 0x008 */ J2DScreen* mpScreen;
|
||||
/* 0x00C */ J2DScreen* mpClipScreen;
|
||||
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
void drawFlag0() { mDrawFlag = 0; }
|
||||
void setStatus(u8 i_status) { mStatus = i_status; }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x004 */ JKRExpHeap* mpHeap;
|
||||
/* 0x008 */ STControl* mpStick;
|
||||
/* 0x00C */ CSTControl* mpCStick;
|
||||
|
||||
@@ -278,7 +278,7 @@ public:
|
||||
u8 getEndStatus() { return mEndStatus; }
|
||||
void setUseType(u8 type) { mUseType = type; }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x0004 */ JKRArchive* mpArchive;
|
||||
/* 0x0008 */ mDoDvdThd_mountArchive_c* mpMount;
|
||||
/* 0x000C */ STControl* stick;
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
|
||||
u8 getStatus() { return mStatus; }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x004 */ JKRExpHeap* mpHeap;
|
||||
/* 0x008 */ JKRArchive* mpArchive;
|
||||
/* 0x00C */ STControl* mpStick;
|
||||
|
||||
@@ -154,7 +154,7 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x004 */ item_params mItemParams[4];
|
||||
/* 0x074 */ JKRExpHeap* heap;
|
||||
/* 0x078 */ J2DScreen* mpScreen;
|
||||
|
||||
@@ -328,6 +328,150 @@ void dMeter2Info_onWide2D();
|
||||
void dMeter2Info_offWide2D();
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
DUSK_NOINLINE void dMeter2Info_Initialize();
|
||||
DUSK_NOINLINE dMeterMap_c* dMeter2Info_getMeterMapClass();
|
||||
DUSK_NOINLINE dMw_c* dMeter2Info_getMenuWindowClass();
|
||||
DUSK_NOINLINE void dMeter2Info_setWindowStatus(u8 i_status);
|
||||
DUSK_NOINLINE CPaneMgr* dMeter2Info_getMeterItemPanePtr(s32 i_idx);
|
||||
DUSK_NOINLINE void dMeter2Info_getString(
|
||||
u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry);
|
||||
DUSK_NOINLINE void dMeter2Info_getStringKanji(
|
||||
u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry);
|
||||
DUSK_NOINLINE void dMeter2Info_getStringKana(
|
||||
u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry);
|
||||
DUSK_NOINLINE f32 dMeter2Info_getStringLength(
|
||||
JUTFont* i_font, f32 param_2, f32 param_3, char* i_string);
|
||||
DUSK_NOINLINE f32 dMeter2Info_getStringLength(J2DTextBox* i_textbox, char* i_string);
|
||||
DUSK_NOINLINE void dMeter2Info_setHotSpringTimer(u8 i_slotNo);
|
||||
DUSK_NOINLINE u16 dMeter2Info_getOilGaugeBackUp();
|
||||
DUSK_NOINLINE void dMeter2Info_setOilGaugeBackUp(u16 param_1);
|
||||
DUSK_NOINLINE void dMeter2Info_setSaveStageName(const char* i_stageName);
|
||||
DUSK_NOINLINE u8 dMeter2Info_getInsectSelectType();
|
||||
DUSK_NOINLINE void dMeter2Info_setInsectSelectType(u8 i_type);
|
||||
DUSK_NOINLINE u8 dMeter2Info_getWarpStatus();
|
||||
DUSK_NOINLINE void dMeter2Info_setWarpStatus(u8 i_status);
|
||||
DUSK_NOINLINE int dMeter2Info_readItemTexture(u8 i_itemNo, void* i_texBuf1, J2DPicture* i_pic1,
|
||||
void* i_texBuf2, J2DPicture* i_pic2, void* i_texBuf3, J2DPicture* i_pic3, void* i_texBuf4,
|
||||
J2DPicture* i_pic4, int param_9);
|
||||
DUSK_NOINLINE void dMeter2Info_setItemColor(
|
||||
u8 i_itemNo, J2DPicture* i_pic1, J2DPicture* i_pic2, J2DPicture* i_pic3, J2DPicture* i_pic4);
|
||||
DUSK_NOINLINE u8 dMeter2Info_getWarpRoomNo();
|
||||
DUSK_NOINLINE u8 dMeter2Info_getWarpPlayerNo();
|
||||
DUSK_NOINLINE cXyz& dMeter2Info_getWarpPos();
|
||||
DUSK_NOINLINE const char* dMeter2Info_getWarpStageName();
|
||||
DUSK_NOINLINE void dMeter2Info_setNowCount(u8 i_count);
|
||||
DUSK_NOINLINE void dMeter2Info_setMaxCount(u8 i_count);
|
||||
DUSK_NOINLINE BOOL dMeter2Info_isDirectUseItem(int param_0);
|
||||
DUSK_NOINLINE bool dMeter2Info_isUseButton(int i_buttonBit);
|
||||
DUSK_NOINLINE void dMeter2Info_setMeterMapClass(dMeterMap_c* i_map);
|
||||
DUSK_NOINLINE void dMeter2Info_decHotSpringTimer();
|
||||
DUSK_NOINLINE void dMeter2Info_allUseButton();
|
||||
DUSK_NOINLINE void dMeter2Info_offUseButton(int i_buttonBit);
|
||||
DUSK_NOINLINE void dMeter2Info_resetGameStatus();
|
||||
DUSK_NOINLINE void dMeter2Info_onGameStatus(int i_status);
|
||||
DUSK_NOINLINE void dMeter2Info_setMapStatus(u8 i_status);
|
||||
DUSK_NOINLINE u8 dMeter2Info_getMapStatus();
|
||||
DUSK_NOINLINE void dMeter2Info_setPauseStatus(u8 i_status);
|
||||
DUSK_NOINLINE void dMeter2Info_resetPauseStatus();
|
||||
DUSK_NOINLINE u8 dMeter2Info_getPauseStatus();
|
||||
DUSK_NOINLINE bool dMeter2Info_isGameStatus(int i_status);
|
||||
DUSK_NOINLINE bool dMeter2Info_isTouchKeyCheck(int i_status);
|
||||
DUSK_NOINLINE void dMeter2Info_setMapKeyDirection(u16 i_direction);
|
||||
DUSK_NOINLINE bool dMeter2Info_isSub2DStatus(int i_flag);
|
||||
DUSK_NOINLINE void dMeter2Info_offMenuInForce(int i_flag);
|
||||
DUSK_NOINLINE bool dMeter2Info_isMenuInForce(int i_flag);
|
||||
DUSK_NOINLINE void dMeter2Info_setMenuWindowClass(dMw_c* i_menu);
|
||||
DUSK_NOINLINE void dMeter2Info_resetWarpStatus();
|
||||
DUSK_NOINLINE u16 dMeter2Info_getMapKeyDirection();
|
||||
DUSK_NOINLINE u8 dMeter2Info_getWindowStatus();
|
||||
DUSK_NOINLINE void dMeter2Info_setMsgResource(void* i_res);
|
||||
DUSK_NOINLINE void dMeter2Info_setStageMsgResource(void* i_res);
|
||||
DUSK_NOINLINE void dMeter2Info_setMsgUnitResource(void* i_res);
|
||||
DUSK_NOINLINE void* dMeter2Info_getMsgResource();
|
||||
DUSK_NOINLINE void* dMeter2Info_getStageMsgResource();
|
||||
DUSK_NOINLINE void* dMeter2Info_getMsgUnitResource();
|
||||
DUSK_NOINLINE u8 dMeter2Info_getLightDropGetFlag(int i_no);
|
||||
DUSK_NOINLINE s32 dMeter2Info_getMeterStringType();
|
||||
DUSK_NOINLINE void dMeter2Info_setMeterClass(dMeter2_c* i_meter);
|
||||
DUSK_NOINLINE void dMeter2Info_onLifeGaugeSE();
|
||||
DUSK_NOINLINE void dMeter2Info_offLifeGaugeSE();
|
||||
DUSK_NOINLINE u8 dMeter2Info_getLifeGaugeSE();
|
||||
DUSK_NOINLINE const char* dMeter2Info_getSaveStageName();
|
||||
DUSK_NOINLINE void dMeter2Info_onShopTalkFlag();
|
||||
DUSK_NOINLINE void dMeter2Info_setLightDropGetFlag(int i_no, u8 i_flag);
|
||||
DUSK_NOINLINE u8 dMeter2Info_getRentalBombBag();
|
||||
DUSK_NOINLINE u8 dMeter2Info_getMiniGameItemSetFlag();
|
||||
DUSK_NOINLINE void dMeter2Info_setMiniGameItem(u8 i_minigameFlag);
|
||||
DUSK_NOINLINE void dMeter2Info_resetMiniGameItem(bool i_saveItem);
|
||||
DUSK_NOINLINE void dMeter2Info_setTableMapRegionNo(u8 i_regionNo);
|
||||
DUSK_NOINLINE void dMeter2Info_setGoldWolfMapType(u8 i_mapType);
|
||||
DUSK_NOINLINE void dMeter2Info_changeWater(u8 i_slotNo);
|
||||
DUSK_NOINLINE void dMeter2Info_warpInProc();
|
||||
DUSK_NOINLINE void dMeter2Info_warpOutProc();
|
||||
DUSK_NOINLINE dMeter2_c* dMeter2Info_getMeterClass();
|
||||
DUSK_NOINLINE s16 dMeter2Info_getMsgKeyWaitTimer();
|
||||
DUSK_NOINLINE void dMeter2Info_onDirectUseItem(int param_0);
|
||||
DUSK_NOINLINE void dMeter2Info_setFloatingFlow(u16 i_flowID, s16 i_msgTimer, bool i_wakuVisible);
|
||||
DUSK_NOINLINE u8 dMeter2Info_getGameOverType();
|
||||
DUSK_NOINLINE void dMeter2Info_setGameOverType(u8 i_gameoverType);
|
||||
DUSK_NOINLINE void dMeter2Info_setMsgKeyWaitTimer(s16 i_waitTimer);
|
||||
DUSK_NOINLINE s32 dMeter2Info_getMsgTimeMs();
|
||||
DUSK_NOINLINE s32 dMeter2Info_getTimeMs();
|
||||
DUSK_NOINLINE void dMeter2Info_setMsgTimeMs(s32 i_msgTime);
|
||||
DUSK_NOINLINE void dMeter2Info_setTimeMs(s32 i_time);
|
||||
DUSK_NOINLINE u8 dMeter2Info_getNowCount();
|
||||
DUSK_NOINLINE u8 dMeter2Info_getMaxCount();
|
||||
DUSK_NOINLINE void dMeter2Info_setScopeZoomPointer(u8 param_0);
|
||||
DUSK_NOINLINE void dMeter2Info_decMsgKeyWaitTimer();
|
||||
DUSK_NOINLINE bool dMeter2Info_isFloatingMessageVisible();
|
||||
DUSK_NOINLINE u8 dMeter2Info_getItemExplainWindowStatus();
|
||||
DUSK_NOINLINE void dMeter2Info_setItemExplainWindowStatus(u8 i_value);
|
||||
DUSK_NOINLINE void dMeter2Info_resetDirectUseItem();
|
||||
DUSK_NOINLINE u16 dMeter2Info_getFloatingFlowID();
|
||||
DUSK_NOINLINE u8 dMeter2Info_getCollectCursorPosX();
|
||||
DUSK_NOINLINE u8 dMeter2Info_getCollectCursorPosY();
|
||||
DUSK_NOINLINE void dMeter2Info_setCollectCursorPosXY(u8 x, u8 y);
|
||||
DUSK_NOINLINE void dMeter2Info_onBlinkButton(int i_flag);
|
||||
DUSK_NOINLINE bool dMeter2Info_isFloatingMessageWakuVisible();
|
||||
DUSK_NOINLINE bool dMeter2Info_isBlinkButton(int i_flag);
|
||||
DUSK_NOINLINE void dMeter2Info_resetBlinkButton();
|
||||
DUSK_NOINLINE void dMeter2Info_resetFloatingMessage();
|
||||
DUSK_NOINLINE s16 dMeter2Info_decFloatingMessageTimer();
|
||||
DUSK_NOINLINE s16 dMeter2Info_getFloatingMessageTimer();
|
||||
DUSK_NOINLINE u16 dMeter2Info_getFloatingMessageID();
|
||||
DUSK_NOINLINE s16 dMeter2Info_getHorseLifeCount();
|
||||
DUSK_NOINLINE void dMeter2Info_setMeterString(s32 i_string);
|
||||
DUSK_NOINLINE void dMeter2Info_resetMeterString();
|
||||
DUSK_NOINLINE void dMeter2Info_setMeterItemPanePtr(int i_no, CPaneMgr* i_pane);
|
||||
DUSK_NOINLINE bool dMeter2Info_isShopTalkFlag();
|
||||
DUSK_NOINLINE void dMeter2Info_setMapDrugFlag(bool i_flag);
|
||||
DUSK_NOINLINE bool dMeter2Info_isTempBit(int i_bit);
|
||||
DUSK_NOINLINE void dMeter2Info_offSub2DStatus(int i_bit);
|
||||
DUSK_NOINLINE void dMeter2Info_onSub2DStatus(int i_bit);
|
||||
DUSK_NOINLINE void dMeter2Info_set2DWidth(f32 i_width);
|
||||
DUSK_NOINLINE void dMeter2Info_set2DHeight(f32 i_height);
|
||||
DUSK_NOINLINE void dMeter2Info_set2DPosH(f32 i_posH);
|
||||
DUSK_NOINLINE void dMeter2Info_set2DPosV(f32 i_posV);
|
||||
DUSK_NOINLINE void dMeter2Info_offShopTalkFlag();
|
||||
DUSK_NOINLINE void dMeter2Info_onUseButton(int i_button);
|
||||
DUSK_NOINLINE f32 dMeter2Info_get2DWidth();
|
||||
DUSK_NOINLINE f32 dMeter2Info_get2DHeight();
|
||||
DUSK_NOINLINE void dMeter2Info_setWarpInfo(const char* i_stageName, const cXyz& i_position,
|
||||
s16 i_angle, u8 i_roomNo, u8 param_4, u8 i_warpPlayerNo);
|
||||
DUSK_NOINLINE u8 dMeter2Info_getTableMapRegionNo();
|
||||
DUSK_NOINLINE u8 dMeter2Info_getGoldWolfMapType();
|
||||
DUSK_NOINLINE bool dMeter2Info_isWindowAccept(int param_0);
|
||||
DUSK_NOINLINE void dMeter2Info_setHorseLifeCount(s16 i_count);
|
||||
DUSK_NOINLINE void dMeter2Info_offTempBit(int i_bit);
|
||||
DUSK_NOINLINE void dMeter2Info_onTempBit(int i_bit);
|
||||
DUSK_NOINLINE void dMeter2Info_setFloatingMessage(u16 i_msgID, s16 i_msgTimer, bool i_wakuVisible);
|
||||
DUSK_NOINLINE void dMeter2Info_setMiniGameCount(s8 i_count);
|
||||
DUSK_NOINLINE void dMeter2Info_onWindowAccept(int param_0);
|
||||
DUSK_NOINLINE void dMeter2Info_offWindowAccept(int param_0);
|
||||
DUSK_NOINLINE void dMeter2Info_onMenuInForce(int param_0);
|
||||
|
||||
#else
|
||||
inline void dMeter2Info_Initialize() {
|
||||
g_meter2_info.init();
|
||||
}
|
||||
@@ -865,4 +1009,6 @@ inline void dMeter2Info_onMenuInForce(int param_0) {
|
||||
g_meter2_info.onMenuInForce(param_0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* D_METER_D_METER2_INFO_H */
|
||||
|
||||
@@ -121,6 +121,25 @@ struct jmessage_tReference : public JMessage::TReference {
|
||||
void setDemoFrame(u32 i_frame) { mDemoFrame = i_frame; }
|
||||
void setTopColorType(u8 i_colorType) { mTopColorType = i_colorType; }
|
||||
void setNowColorType(u8 i_colorType) { mNowColorType = i_colorType; }
|
||||
#if TARGET_PC
|
||||
void resetColors() {
|
||||
mNowCCColor = 0xFFFFFFFF;
|
||||
mNowGCColor = 0xFFFFFFFF;
|
||||
mTopCCColor = 0xFFFFFFFF;
|
||||
mTopGCColor = 0xFFFFFFFF;
|
||||
mNowFullColor = false;
|
||||
mTopFullColor = false;
|
||||
}
|
||||
void setFullColor(u32 ccColor, u32 gcColor) {
|
||||
mNowCCColor = ccColor;
|
||||
mNowGCColor = gcColor;
|
||||
mNowFullColor = true;
|
||||
}
|
||||
void clearNowFullColor() { mNowFullColor = false; }
|
||||
bool hasTopFullColor() { return mTopFullColor; }
|
||||
u32 getTopCCColor() { return mTopCCColor; }
|
||||
u32 getTopGCColor() { return mTopGCColor; }
|
||||
#endif
|
||||
void setTopTagScale(u16 i_tagScale) { mTopTagScale = i_tagScale; }
|
||||
void setNowTagScale(u16 i_tagScale) { mNowTagScale = i_tagScale; }
|
||||
void setRevoMessageID(u32 i_msgID) { mRevoMessageID = i_msgID; }
|
||||
@@ -365,6 +384,14 @@ struct jmessage_tReference : public JMessage::TReference {
|
||||
/* 0x1274 */ bool mSelectSetCancelFlag;
|
||||
/* 0x1275 */ bool mBombNameUseFlag;
|
||||
/* 0x1276 */ u8 mBatchColorFlag;
|
||||
#if TARGET_PC
|
||||
u32 mNowCCColor;
|
||||
u32 mNowGCColor;
|
||||
u32 mTopCCColor;
|
||||
u32 mTopGCColor;
|
||||
bool mNowFullColor;
|
||||
bool mTopFullColor;
|
||||
#endif
|
||||
}; // Size: 0x1278
|
||||
|
||||
struct jmessage_tMeasureProcessor : public JMessage::TRenderingProcessor {
|
||||
@@ -462,6 +489,9 @@ struct jmessage_tRenderingProcessor : public JMessage::TRenderingProcessor {
|
||||
void do_selwidthcenter(int);
|
||||
void do_heightcenter();
|
||||
void do_color(u8);
|
||||
#if TARGET_PC
|
||||
void do_fullcolor(u32 ccColor, u32 gcColor);
|
||||
#endif
|
||||
void do_scale(f32);
|
||||
void do_linedown(s16);
|
||||
void do_transY(s16, bool);
|
||||
@@ -640,6 +670,9 @@ struct jmessage_string_tRenderingProcessor : public JMessage::TRenderingProcesso
|
||||
void do_rubystrcat(char*);
|
||||
void do_outfont(u8);
|
||||
void do_color(u8);
|
||||
#if TARGET_PC
|
||||
void do_fullcolor(u32 ccColor, u32 gcColor);
|
||||
#endif
|
||||
void do_scale(f32);
|
||||
void do_linedown(s16);
|
||||
void do_numset(s16);
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
void setTextBoxPtr(J2DTextBox* p_textBox) { mpTextBoxPtr = p_textBox; }
|
||||
void resetType() { mType = 0x47; }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x04 */ J2DTextBox* mpTextBoxPtr;
|
||||
/* 0x08 */ f32 mPosX;
|
||||
/* 0x0C */ f32 mPosY;
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
|
||||
void setRupeeColor(u8 color) { mRupeeColor = color; }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x004 */ COutFontSet_c* mpOfs[35];
|
||||
/* 0x090 */ J2DPicture* mpPane[70];
|
||||
/* 0x1A8 */ f32 mAlphaRatio;
|
||||
|
||||
@@ -12,34 +12,6 @@ class J2DTextBox;
|
||||
class JUTFont;
|
||||
class STControl;
|
||||
|
||||
#if TARGET_PC
|
||||
struct PaneCache {
|
||||
u64 tag;
|
||||
f32 origTransX;
|
||||
f32 origTransY;
|
||||
bool cached;
|
||||
};
|
||||
|
||||
static PaneCache l_tagName[] = {
|
||||
{MULTI_CHAR('m_00_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_00_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_00_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_00_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_00_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_01_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_01_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_01_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_01_3'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m_01_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_02_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_02_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_02_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_02_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_02_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m03_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m03_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m03_2'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m03_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m03_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_04_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_04_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_04_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_04_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_04_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_05_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_05_1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m_05_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_05_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_05_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_06_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_06_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_06_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_06_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_06_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_07_0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m_07_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_07_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_07_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_07_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_08_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_08_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_08_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_08_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_08_4'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m_09_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_09_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_09_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_09_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_09_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_10_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_10_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_10_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_10_3'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m_10_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_11_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_11_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_11_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_11_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_11_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m12_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m12_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m12_2'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m12_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m12_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('p_end_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('p_end_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('p_end_0'), 0.0f, 0.0f, false},
|
||||
};
|
||||
|
||||
static PaneCache l_nameTagName[] = {
|
||||
{MULTI_CHAR('name_00'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_01'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_02'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_03'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_04'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_05'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_06'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_07'), 0.0f, 0.0f, false},
|
||||
};
|
||||
|
||||
static PaneCache l_nameCurTagName[] = {
|
||||
{MULTI_CHAR('s__n_00'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_01'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_02'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_03'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_04'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_05'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_06'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_07'), 0.0f, 0.0f, false},
|
||||
};
|
||||
#endif
|
||||
|
||||
class dNm_HIO_c {
|
||||
public:
|
||||
dNm_HIO_c();
|
||||
|
||||
@@ -532,10 +532,12 @@ s32 fopAcM_delete(fpc_ProcID i_actorID);
|
||||
|
||||
fpc_ProcID fopAcM_create(s16 i_procName, u16 i_setId, u32 i_parameters, const cXyz* i_pos,
|
||||
int i_roomNo, const csXyz* i_angle, const cXyz* i_scale, s8 i_argument,
|
||||
createFunc i_createFunc IF_DUSK_ARG(u32 i_itemGiveTag = 0));
|
||||
createFunc i_createFunc IF_DUSK_ARG(u32 i_itemGiveTag = 0)
|
||||
IF_DUSK_ARG(u8 i_itemOriginalNo = 0xFF));
|
||||
|
||||
fpc_ProcID fopAcM_create(s16 i_procName, u32 i_parameters, const cXyz* i_pos, int i_roomNo,
|
||||
const csXyz* i_angle, const cXyz* i_scale, s8 i_argument IF_DUSK_ARG(u32 i_itemGiveTag = 0));
|
||||
const csXyz* i_angle, const cXyz* i_scale, s8 i_argument IF_DUSK_ARG(u32 i_itemGiveTag = 0)
|
||||
IF_DUSK_ARG(u8 i_itemOriginalNo = 0xFF));
|
||||
|
||||
inline fpc_ProcID fopAcM_Create(s16 i_procName, createFunc i_createFunc, void* params) {
|
||||
return fpcM_Create(i_procName, i_createFunc,params);
|
||||
|
||||
+15
-1
@@ -123,6 +123,14 @@ inline int __builtin_clz(unsigned int v) {
|
||||
#endif
|
||||
#define DUSK_GAME_EXTERN extern DUSK_GAME_DATA
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define DUSK_NOINLINE __declspec(noinline)
|
||||
#elif defined(__GNUC__)
|
||||
#define DUSK_NOINLINE __attribute__((noinline))
|
||||
#else
|
||||
#define DUSK_NOINLINE
|
||||
#endif
|
||||
|
||||
#define FAST_DIV(x, n) (x >> (n / 2))
|
||||
|
||||
#define SQUARE(x) ((x) * (x))
|
||||
@@ -259,13 +267,19 @@ using std::isnan;
|
||||
#if TARGET_PC && defined(DUSK_BUILDING_GAME)
|
||||
#include "dusk/mods/item.hpp"
|
||||
#define DUSK_ITEM_CHECK(name, item_no, giver) \
|
||||
(item_no) = ::dusk::mods::item_check(name, (item_no), giver)
|
||||
(item_no) = ::dusk::mods::item_check_commit(name, (item_no), giver).itemNo
|
||||
#define DUSK_ITEM_CHECK_EXPR(name, item_no, giver) \
|
||||
(::dusk::mods::item_check_commit(name, (item_no), giver).itemNo)
|
||||
#define DUSK_ITEM_CHECK_PREVIEW(name, item_no, giver) \
|
||||
(item_no) = ::dusk::mods::item_check(name, (item_no), giver)
|
||||
#define DUSK_ITEM_CHECK_PREVIEW_EXPR(name, item_no, giver) \
|
||||
(::dusk::mods::item_check(name, (item_no), giver))
|
||||
#define DUSK_GIVE_TAG(name) IF_DUSK_ARG(::dusk::mods::item_give_tag(name))
|
||||
#else
|
||||
#define DUSK_ITEM_CHECK(name, item_no, giver)
|
||||
#define DUSK_ITEM_CHECK_EXPR(name, item_no, giver) (item_no)
|
||||
#define DUSK_ITEM_CHECK_PREVIEW(name, item_no, giver)
|
||||
#define DUSK_ITEM_CHECK_PREVIEW_EXPR(name, item_no, giver) (item_no)
|
||||
#define DUSK_GIVE_TAG(name)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
JKRMemArchive* getArchive() const { return mArchive; }
|
||||
JKRHeap* getHeap() const { return mHeap; }
|
||||
|
||||
private:
|
||||
// private:
|
||||
/* 0x14 */ u8 mMountDirection;
|
||||
/* 0x18 */ s32 mEntryNumber;
|
||||
/* 0x1C */ JKRMemArchive* mArchive;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
class J3DModelData;
|
||||
class J3DMaterialTable;
|
||||
struct J3DModelHierarchy;
|
||||
class J3DVertexData;
|
||||
|
||||
#if TARGET_PC
|
||||
#define OFFSET_PTR_V0 BE(u32)
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
project(basic_cosmetics_mod CXX)
|
||||
|
||||
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
set(DUSK_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../.." CACHE PATH "Path to dusk source root")
|
||||
option(DUSK_MOD_USE_FULL_TREE "Use full build instead of the minimal mod SDK" OFF)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
if (DUSK_MOD_USE_FULL_TREE)
|
||||
add_subdirectory("${DUSK_DIR}" dusk EXCLUDE_FROM_ALL)
|
||||
else ()
|
||||
add_subdirectory("${DUSK_DIR}/sdk" dusk-sdk EXCLUDE_FROM_ALL)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
message(STATUS "basic_cosmetics_mod: Fetching xxhash")
|
||||
FetchContent_Declare(
|
||||
xxhash
|
||||
GIT_REPOSITORY https://github.com/Cyan4973/xxHash.git
|
||||
GIT_TAG v0.8.3
|
||||
)
|
||||
FetchContent_MakeAvailable(xxhash)
|
||||
|
||||
set(COSMETIC_SOURCES src/color_utils.cpp src/midna_hair_color.cpp src/texture_utils.cpp src/hooks.cpp)
|
||||
|
||||
add_mod(basic_cosmetics_mod
|
||||
FEATURES game fmt
|
||||
SOURCES src/mod.cpp ${COSMETIC_SOURCES}
|
||||
MOD_JSON mod.json
|
||||
RES_DIR res
|
||||
BUNDLE
|
||||
)
|
||||
|
||||
target_link_libraries(basic_cosmetics_mod PRIVATE xxHash::xxhash)
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"id": "dev.twilitrealm.basic_cosmetics",
|
||||
"name": "Basic Cosmetics",
|
||||
"version": "1.0.0",
|
||||
"author": "Twilit Realm",
|
||||
"description": "Change Basic Cosmetic Colors"
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "color_utils.hpp"
|
||||
|
||||
uint8_t desaturate_rgb_565(uint16_t rgb565Val) {
|
||||
const uint32_t r = (rgb565Val & 0xf800) >> 11;
|
||||
const uint32_t g = (rgb565Val & 0x7e0) >> 5;
|
||||
const uint32_t b = rgb565Val & 0x1f;
|
||||
|
||||
// Here we are doing a quicker (0.22 * r + 0.72 * g + 0.06 * b) which
|
||||
// uses multiplies and shifts rather than division.
|
||||
const uint32_t combined = 30480413 * r + 49085341 * g + 8312839 * b;
|
||||
uint8_t shifted = (combined >> 24) & 0xff;
|
||||
|
||||
// Check if should round up shifted value.
|
||||
if (shifted < 0xff && combined & 0x00800000) {
|
||||
shifted += 1;
|
||||
}
|
||||
|
||||
return shifted;
|
||||
}
|
||||
|
||||
uint16_t blend_overlay_rgb_565(uint8_t grayVal, GXColor color) {
|
||||
uint32_t rTimes255, gTimes255, bTimes255;
|
||||
|
||||
if (grayVal <= 0x7f) {
|
||||
const uint32_t grayTimesTwo = 2 * grayVal;
|
||||
|
||||
rTimes255 = grayTimesTwo * color.r;
|
||||
gTimes255 = grayTimesTwo * color.g;
|
||||
bTimes255 = grayTimesTwo * color.b;
|
||||
} else {
|
||||
const uint32_t multiplier = 2 * (255 - grayVal);
|
||||
|
||||
rTimes255 = 255 * 255 - multiplier * (255 - color.r);
|
||||
gTimes255 = 255 * 255 - multiplier * (255 - color.g);
|
||||
bTimes255 = 255 * 255 - multiplier * (255 - color.b);
|
||||
}
|
||||
|
||||
// Divide each by 255
|
||||
const uint32_t r = (rTimes255 + 1 + (rTimes255 >> 8)) >> 8;
|
||||
const uint32_t g = (gTimes255 + 1 + (gTimes255 >> 8)) >> 8;
|
||||
const uint32_t b = (bTimes255 + 1 + (bTimes255 >> 8)) >> 8;
|
||||
|
||||
return ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
|
||||
}
|
||||
|
||||
// Helper function to perform overlay blending on a single 8-bit color channel
|
||||
uint8_t blend_overlay_channel(uint8_t base, uint8_t blend) {
|
||||
if (base < 128) {
|
||||
return static_cast<uint8_t>((2 * base * blend) / 255);
|
||||
}
|
||||
|
||||
return static_cast<uint8_t>(255 - (2 * (255 - base) * (255 - blend)) / 255);
|
||||
}
|
||||
|
||||
bool is_valid_hex_color_str(std::string_view hexStr) {
|
||||
return hexStr.find_first_not_of("0123456789ABCDEFabcdef") == std::string_view::npos &&
|
||||
hexStr.length() == 6;
|
||||
}
|
||||
|
||||
GXColor hex_color_str_to_gx_color(const std::string& hexColorStr) {
|
||||
u8 r = std::stoi(hexColorStr.substr(0, 2), nullptr, 16);
|
||||
u8 g = std::stoi(hexColorStr.substr(2, 2), nullptr, 16);
|
||||
u8 b = std::stoi(hexColorStr.substr(4, 2), nullptr, 16);
|
||||
return GXColor{r, g, b};
|
||||
}
|
||||
|
||||
static f32 rainbowPhaseAngle = 0.f;
|
||||
|
||||
GXColor get_rainbow_rgb(f32 amplitude) {
|
||||
f32 phase_rad = rainbowPhaseAngle * M_PI / 180.0f;
|
||||
|
||||
u8 r_val = (u8)(amplitude * (sinf(phase_rad) + 1.0f) + 0.5f);
|
||||
u8 g_val = (u8)(amplitude * (sinf(phase_rad + 2.0f * M_PI / 3.0f) + 1.0f) + 0.5f);
|
||||
u8 b_val = (u8)(amplitude * (sinf(phase_rad + 4.0f * M_PI / 3.0f) + 1.0f));
|
||||
GXColor rgbColor;
|
||||
rgbColor.r = r_val;
|
||||
rgbColor.g = g_val;
|
||||
rgbColor.b = b_val;
|
||||
rgbColor.a = 0xff;
|
||||
return rgbColor;
|
||||
}
|
||||
|
||||
void update_rainbow_rgb(f32 increment) {
|
||||
rainbowPhaseAngle += increment;
|
||||
if (rainbowPhaseAngle >= 360.0f) {
|
||||
rainbowPhaseAngle -= 360.0f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* File originally copied from console TPR with permission from isaac
|
||||
* https://github.com/zsrtp/libtp_rel/blob/master/include/util/color_utils.h
|
||||
*/
|
||||
|
||||
#include <gx.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
// Desaturates an RGB565 color to a u8 gray value (0xFF being white and 0x00
|
||||
// being black).
|
||||
uint8_t desaturate_rgb_565(uint16_t rgb565Val);
|
||||
|
||||
// Performs an "Overlay" blend of a u8 gray value and a pointer to a u8
|
||||
// array of {r,g,b}. Returns the result as an RGB565.
|
||||
uint16_t blend_overlay_rgb_565(uint8_t grayVal, GXColor color);
|
||||
|
||||
// Perform overlay blending on a single 8-bit color channel
|
||||
uint8_t blend_overlay_channel(uint8_t base, uint8_t blend);
|
||||
|
||||
bool is_valid_hex_color_str(std::string_view hexStr);
|
||||
|
||||
GXColor hex_color_str_to_gx_color(const std::string& hexColorStr);
|
||||
|
||||
GXColor get_rainbow_rgb(f32 amplitude);
|
||||
|
||||
void update_rainbow_rgb(f32 increment);
|
||||
@@ -0,0 +1,731 @@
|
||||
#include "hooks.hpp"
|
||||
|
||||
#include "color_utils.hpp"
|
||||
#include "midna_hair_color.hpp"
|
||||
#include "mod.hpp"
|
||||
#include "types.h"
|
||||
|
||||
#include "mods/svc/hook.hpp"
|
||||
#include "mods/svc/log.hpp"
|
||||
|
||||
#include "SSystem/SComponent/c_phase.h"
|
||||
#include "d/actor/d_a_alink.h"
|
||||
#include "d/actor/d_a_midna.h"
|
||||
#include "d/d_a_item_static.h"
|
||||
#include "d/d_bright_check.h"
|
||||
#include "d/d_file_sel_info.h"
|
||||
#include "d/d_file_select.h"
|
||||
#include "d/d_kankyo.h"
|
||||
#include "d/d_kantera_icon_meter.h"
|
||||
#include "d/d_menu_collect.h"
|
||||
#include "d/d_menu_fishing.h"
|
||||
#include "d/d_menu_fmap2D.h"
|
||||
#include "d/d_menu_insect.h"
|
||||
#include "d/d_menu_letter.h"
|
||||
#include "d/d_menu_option.h"
|
||||
#include "d/d_menu_ring.h"
|
||||
#include "d/d_menu_save.h"
|
||||
#include "d/d_menu_skill.h"
|
||||
#include "d/d_meter2.h"
|
||||
#include "d/d_meter2_draw.h"
|
||||
#include "d/d_meter2_info.h"
|
||||
#include "d/d_meter_button.h"
|
||||
#include "d/d_meter_hakusha.h"
|
||||
#include "d/d_msg_object.h"
|
||||
#include "d/d_msg_out_font.h"
|
||||
#include "d/d_msg_scrn_base.h"
|
||||
#include "d/d_pane_class.h"
|
||||
|
||||
// Lantern ambience color
|
||||
DEFINE_HOOK(&dKy_WolfEyeLight_set, WolfEyeLightSet);
|
||||
void wolf_eye_light_set_post(ModContext*, void*, void*, void*) {
|
||||
auto maybeLanternColor = get_config_var_color(get_cvars().lanternGlowColor, true);
|
||||
if (maybeLanternColor.has_value()) {
|
||||
auto lanternColor = maybeLanternColor.value();
|
||||
|
||||
dScnKy_env_light_c* kankyo = dKy_getEnvlight();
|
||||
kankyo->field_0x0c18[0].mColor.r = lanternColor.r;
|
||||
kankyo->field_0x0c18[0].mColor.g = lanternColor.g;
|
||||
kankyo->field_0x0c18[0].mColor.b = lanternColor.b;
|
||||
}
|
||||
}
|
||||
|
||||
// Lantern Sphere color
|
||||
DEFINE_HOOK(&daAlink_c::preKandelaarDraw, PreKandelaarDraw);
|
||||
void pre_kandelaar_draw_post(ModContext*, void*, void*, void*) {
|
||||
auto maybeLanternColor = get_config_var_color(get_cvars().lanternGlowColor, true);
|
||||
if (maybeLanternColor.has_value()) {
|
||||
auto lanternColor = maybeLanternColor.value();
|
||||
|
||||
J3DMaterial* mat_p = daAlink_getAlinkActorClass()
|
||||
->mpKanteraGlowModel->getModelData()
|
||||
->getMaterialNodePointer(0);
|
||||
|
||||
J3DGXColorS10 color;
|
||||
color.r = lanternColor.r;
|
||||
color.g = lanternColor.g;
|
||||
color.b = lanternColor.b;
|
||||
color.a = 255;
|
||||
mat_p->setTevColor(1, &color);
|
||||
|
||||
color.r = lanternColor.r;
|
||||
color.g = lanternColor.g;
|
||||
color.b = lanternColor.b;
|
||||
mat_p->setTevColor(2, &color);
|
||||
}
|
||||
}
|
||||
|
||||
// Main Lantern Meter Color
|
||||
DEFINE_HOOK(&CPaneMgr::setBlackWhite, CPaneMgrSetBlackWhite);
|
||||
HookAction cpane_mgr_set_black_white_pre(ModContext*, void* args, void*, void*) {
|
||||
// Check for magic meter
|
||||
auto pane = mods::arg<CPaneMgr*>(args, 0);
|
||||
if (dMeter2Info_getMeterClass() == NULL ||
|
||||
pane != dMeter2Info_getMeterClass()->getMeterDrawPtr()->mpMagicMeter)
|
||||
{
|
||||
return HOOK_CONTINUE;
|
||||
}
|
||||
|
||||
// If magic meter, check to see we're setting lantern colors
|
||||
auto& black = mods::arg_ref<JUtility::TColor>(args, 1);
|
||||
auto& white = mods::arg_ref<JUtility::TColor>(args, 2);
|
||||
if (black != JUtility::TColor(255, 255, 140, 255) &&
|
||||
white != JUtility::TColor(230, 170, 0, 255))
|
||||
{
|
||||
return HOOK_CONTINUE;
|
||||
}
|
||||
|
||||
auto maybeLanternColor = get_config_var_color(get_cvars().lanternGlowColor, true);
|
||||
if (maybeLanternColor.has_value()) {
|
||||
auto lanternColor = maybeLanternColor.value();
|
||||
black = JUtility::TColor(lanternColor.r, lanternColor.g, lanternColor.b, 255);
|
||||
white = JUtility::TColor(lanternColor.r, lanternColor.g, lanternColor.b, 255);
|
||||
}
|
||||
|
||||
return HOOK_CONTINUE;
|
||||
}
|
||||
|
||||
// Lantern Icon Meter Color
|
||||
DEFINE_HOOK(&dKantera_icon_c::setNowGauge, KanteraIconSetNowGauge);
|
||||
void kantera_icon_set_now_gauge_post(ModContext*, void* args, void*, void*) {
|
||||
auto maybeLanternColor = get_config_var_color(get_cvars().lanternGlowColor, true);
|
||||
if (maybeLanternColor.has_value()) {
|
||||
auto lanternColor = maybeLanternColor.value();
|
||||
|
||||
auto kanteraIcon = mods::arg<dKantera_icon_c*>(args, 0);
|
||||
kanteraIcon->mpGauge->setBlackWhite(
|
||||
JUtility::TColor(lanternColor.r, lanternColor.g, lanternColor.b, 255),
|
||||
JUtility::TColor(lanternColor.r, lanternColor.g, lanternColor.b, 255));
|
||||
}
|
||||
}
|
||||
|
||||
// Light Sword Effect Color
|
||||
DEFINE_HOOK(&daAlink_c::setLightningSwordEffect, SetLightningSwordEffect);
|
||||
void set_lightning_sword_effect_post(ModContext*, void* args, void*, void*) {
|
||||
auto maybeGlowColor = get_config_var_color(get_cvars().lightSwordGlowColor, true);
|
||||
if (maybeGlowColor.has_value()) {
|
||||
auto glowColor = maybeGlowColor.value();
|
||||
|
||||
auto link = mods::arg<daAlink_c*>(args, 0);
|
||||
// Check copied from inside the hooked function
|
||||
if (link->mEquipItem == 0x103 && link->checkNoResetFlg3(daPy_py_c::FLG3_UNK_100000)) {
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
auto emitter = dComIfGp_particle_getEmitter(link->field_0x327c[i]);
|
||||
if (emitter != NULL) {
|
||||
emitter->setGlobalEnvColor(glowColor.r, glowColor.g, glowColor.b);
|
||||
emitter->setGlobalPrmColor(glowColor.r, glowColor.g, glowColor.b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void recolor_ui_button(ConfigVarHandle option, u64 tag, J2DScreen* screen) {
|
||||
auto buttonColorStr = get_str_option(option, "");
|
||||
if (is_valid_hex_color_str(buttonColorStr)) {
|
||||
auto color = hex_color_str_to_gx_color(buttonColorStr);
|
||||
auto element = static_cast<J2DPicture*>(screen->search(tag));
|
||||
if (element != nullptr) {
|
||||
element->setBlackWhite(
|
||||
JUtility::TColor(0, 0, 0, 0), JUtility::TColor(color.r, color.g, color.b, 0xFF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Main gameplay UI. Top left hearts and top right buttons
|
||||
DEFINE_HOOK(&dMeter2Draw_c::init, dMeter2Init);
|
||||
void d_meter_2_init_post(ModContext*, void* args, void*, void*) {
|
||||
auto dMeter2Draw = mods::arg<dMeter2Draw_c*>(args, 0);
|
||||
auto screen = dMeter2Draw->getMainScreenPtr();
|
||||
|
||||
// Heart tags on main UI
|
||||
static constexpr std::array kHeartTags = {MULTI_CHAR('hear_00'), MULTI_CHAR('hear_01'),
|
||||
MULTI_CHAR('hear_02'), MULTI_CHAR('hear_03'), MULTI_CHAR('hear_04'), MULTI_CHAR('hear_05'),
|
||||
MULTI_CHAR('hear_06'), MULTI_CHAR('hear_07'), MULTI_CHAR('hear_08'), MULTI_CHAR('hear_09'),
|
||||
MULTI_CHAR('hear_10'), MULTI_CHAR('hear_11'), MULTI_CHAR('hear_12'), MULTI_CHAR('hear_13'),
|
||||
MULTI_CHAR('hear_14'), MULTI_CHAR('hear_15'), MULTI_CHAR('hear_16'), MULTI_CHAR('hear_17'),
|
||||
MULTI_CHAR('hear_18'), MULTI_CHAR('hear_19'), MULTI_CHAR('bigh_00'), MULTI_CHAR('bigh_01'),
|
||||
MULTI_CHAR('bigh_02'), MULTI_CHAR('bigh_03')};
|
||||
|
||||
auto maybeHeartColor = get_config_var_color(get_cvars().heartColor);
|
||||
if (maybeHeartColor.has_value()) {
|
||||
auto heartColor = maybeHeartColor.value();
|
||||
for (auto tag : kHeartTags) {
|
||||
auto element = static_cast<J2DPicture*>(screen->search(tag));
|
||||
if (element != nullptr) {
|
||||
element->setBlackWhite(heartColor, JUtility::TColor(200, 200, 200, 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('a_btn'), screen);
|
||||
recolor_ui_button(get_cvars().bButtonColor, MULTI_CHAR('b_btn'), screen);
|
||||
recolor_ui_button(get_cvars().xButtonColor, MULTI_CHAR('x_btn'), screen);
|
||||
recolor_ui_button(get_cvars().yButtonColor, MULTI_CHAR('y_btn'), screen);
|
||||
recolor_ui_button(get_cvars().zButtonColor, MULTI_CHAR('zbtn'), screen);
|
||||
}
|
||||
|
||||
// Hearts on the file select screen
|
||||
DEFINE_HOOK(&dFile_info_c::setHeartCnt, FileInfoSetHeartCount);
|
||||
void file_info_set_heart_count_post(ModContext*, void* args, void*, void*) {
|
||||
auto fileInfo = mods::arg<dFile_info_c*>(args, 0);
|
||||
|
||||
// Heart tags on file select
|
||||
static constexpr std::array kFileSelectHeartTags{
|
||||
MULTI_CHAR('hear_20'),
|
||||
MULTI_CHAR('hear_21'),
|
||||
MULTI_CHAR('hear_22'),
|
||||
MULTI_CHAR('hear_23'),
|
||||
MULTI_CHAR('hear_24'),
|
||||
MULTI_CHAR('hear_25'),
|
||||
MULTI_CHAR('hear_26'),
|
||||
MULTI_CHAR('hear_27'),
|
||||
MULTI_CHAR('hear_28'),
|
||||
MULTI_CHAR('hear_29'),
|
||||
MULTI_CHAR('hear_30'),
|
||||
MULTI_CHAR('hear_31'),
|
||||
MULTI_CHAR('hear_32'),
|
||||
MULTI_CHAR('hear_33'),
|
||||
MULTI_CHAR('hear_34'),
|
||||
MULTI_CHAR('hear_35'),
|
||||
MULTI_CHAR('hear_36'),
|
||||
MULTI_CHAR('hear_37'),
|
||||
MULTI_CHAR('hear_38'),
|
||||
MULTI_CHAR('hear_39'),
|
||||
};
|
||||
|
||||
auto maybeHeartColor = get_config_var_color(get_cvars().heartColor);
|
||||
if (maybeHeartColor.has_value()) {
|
||||
auto heartColor = maybeHeartColor.value();
|
||||
for (auto tag : kFileSelectHeartTags) {
|
||||
auto element = static_cast<J2DPicture*>(fileInfo->mFileInfo.Scr->search(tag));
|
||||
if (element != nullptr) {
|
||||
element->setBlackWhite(heartColor, JUtility::TColor(200, 200, 200, 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Buttons that appear contextually at the bottom of the screen during gameplay
|
||||
// (Are X, Y ever used there?)
|
||||
DEFINE_HOOK(&dMeterButton_c::screenInitButton, ScreenInitButton);
|
||||
void screen_init_button_post(ModContext*, void* args, void*, void*) {
|
||||
auto meterButton = mods::arg<dMeterButton_c*>(args, 0);
|
||||
auto screen = meterButton->mpButtonScreen;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('a_btn1'), screen);
|
||||
recolor_ui_button(get_cvars().bButtonColor, MULTI_CHAR('b_btn'), screen);
|
||||
recolor_ui_button(get_cvars().xButtonColor, MULTI_CHAR('x_btn'), screen);
|
||||
recolor_ui_button(get_cvars().yButtonColor, MULTI_CHAR('y_btn'), screen);
|
||||
recolor_ui_button(get_cvars().zButtonColor, MULTI_CHAR('zbtn'), screen);
|
||||
}
|
||||
|
||||
// A and B buttons when saving a file
|
||||
DEFINE_HOOK(&dMenu_save_c::screenSet, MenuSaveScreenSet);
|
||||
void menu_save_screen_set_post(ModContext*, void* args, void*, void*) {
|
||||
auto menuSave = mods::arg<dMenu_save_c*>(args, 0);
|
||||
auto screen = menuSave->mSaveSel.Scr;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('wabtn'), screen);
|
||||
recolor_ui_button(get_cvars().bButtonColor, MULTI_CHAR('wbbtn'), screen);
|
||||
}
|
||||
|
||||
// A and B buttons when selecting a file
|
||||
DEFINE_HOOK(&dFile_select_c::screenSet, FileSelectScreenSet);
|
||||
void file_select_screen_set_post(ModContext*, void* args, void*, void*) {
|
||||
auto fileSelect = mods::arg<dFile_select_c*>(args, 0);
|
||||
auto screen = fileSelect->fileSel.Scr;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('wabtn'), screen);
|
||||
recolor_ui_button(get_cvars().bButtonColor, MULTI_CHAR('wbbtn'), screen);
|
||||
}
|
||||
|
||||
// A button on brightness check screen
|
||||
DEFINE_HOOK(&dBrightCheck_c::screenSet, BrightCheckScreenSet);
|
||||
void bright_check_screen_set_post(ModContext*, void* args, void*, void*) {
|
||||
auto brightCheck = mods::arg<dBrightCheck_c*>(args, 0);
|
||||
auto screen = brightCheck->mBrightCheck.Scr;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('a_btn1'), screen);
|
||||
}
|
||||
|
||||
// X and Y buttons on the item wheel screen
|
||||
DEFINE_HOOK(&dMenu_Ring_c::_create, MenuRingCreate);
|
||||
void menu_ring_create_post(ModContext*, void* args, void*, void*) {
|
||||
auto menuRing = mods::arg<dMenu_Ring_c*>(args, 0);
|
||||
auto screen = menuRing->mpScreen;
|
||||
|
||||
recolor_ui_button(get_cvars().xButtonColor, MULTI_CHAR('xbtn'), screen);
|
||||
recolor_ui_button(get_cvars().yButtonColor, MULTI_CHAR('ybtn'), screen);
|
||||
}
|
||||
|
||||
// A and B buttons on the main pause screen
|
||||
DEFINE_HOOK(&dMenu_Collect2D_c::_create, MenuCollect2DCreate);
|
||||
void menu_collect_2D_create_post(ModContext*, void* args, void*, void*) {
|
||||
auto menuCollect2D = mods::arg<dMenu_Collect2D_c*>(args, 0);
|
||||
auto screen = menuCollect2D->mpScreenIcon;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('a_btn'), screen);
|
||||
recolor_ui_button(get_cvars().bButtonColor, MULTI_CHAR('b_btn'), screen);
|
||||
}
|
||||
|
||||
// A and B buttons on the fishing journal screen
|
||||
DEFINE_HOOK(&dMenu_Fishing_c::screenSetDoIcon, MenuFishingScreenSetDoIcon);
|
||||
void menu_fishing_screen_set_do_icon_post(ModContext*, void* args, void*, void*) {
|
||||
auto menuFishing = mods::arg<dMenu_Fishing_c*>(args, 0);
|
||||
auto screen = menuFishing->mpIconScreen;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('a_btn'), screen);
|
||||
recolor_ui_button(get_cvars().bButtonColor, MULTI_CHAR('b_btn'), screen);
|
||||
}
|
||||
|
||||
// A and B buttons on the insect collection screen
|
||||
DEFINE_HOOK(&dMenu_Insect_c::screenSetDoIcon, MenuInsectScreenSetDoIcon);
|
||||
void menu_insect_screen_set_do_icon_post(ModContext*, void* args, void*, void*) {
|
||||
auto menuInsect = mods::arg<dMenu_Insect_c*>(args, 0);
|
||||
auto screen = menuInsect->mpIconScreen;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('a_btn'), screen);
|
||||
recolor_ui_button(get_cvars().bButtonColor, MULTI_CHAR('b_btn'), screen);
|
||||
}
|
||||
|
||||
// A and B buttons on the letters screen
|
||||
DEFINE_HOOK(&dMenu_Letter_c::screenSetDoIcon, MenuLetterScreenSetDoIcon);
|
||||
void menu_letter_screen_set_do_icon_post(ModContext*, void* args, void*, void*) {
|
||||
auto menuLetter = mods::arg<dMenu_Letter_c*>(args, 0);
|
||||
auto screen = menuLetter->mpIconScreen;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('a_btn'), screen);
|
||||
recolor_ui_button(get_cvars().bButtonColor, MULTI_CHAR('b_btn'), screen);
|
||||
}
|
||||
|
||||
// A, B, and Z buttons on option screen
|
||||
DEFINE_HOOK(&dMenu_Option_c::_create, MenuOptionCreate);
|
||||
void menu_option_create_post(ModContext*, void* args, void*, void*) {
|
||||
auto menuOption = mods::arg<dMenu_Option_c*>(args, 0);
|
||||
auto screen = menuOption->mpScreenIcon;
|
||||
auto backScreen = menuOption->mpBackScreen;
|
||||
auto tvScreen = menuOption->mpTVScreen;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('a_btn'), screen);
|
||||
recolor_ui_button(get_cvars().bButtonColor, MULTI_CHAR('b_btn'), screen);
|
||||
recolor_ui_button(get_cvars().zButtonColor, MULTI_CHAR('g_zbtn'), backScreen);
|
||||
|
||||
// A Button on option's brightness check screen
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('a_btn1'), tvScreen);
|
||||
}
|
||||
|
||||
// A and B buttons on the hidden skills screen
|
||||
DEFINE_HOOK(&dMenu_Skill_c::screenSetDoIcon, MenuSkillScreenSetDoIcon);
|
||||
void menu_skill_screen_set_do_icon_post(ModContext*, void* args, void*, void*) {
|
||||
auto menuSkill = mods::arg<dMenu_Skill_c*>(args, 0);
|
||||
auto screen = menuSkill->mpIconScreen;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('a_btn'), screen);
|
||||
recolor_ui_button(get_cvars().bButtonColor, MULTI_CHAR('b_btn'), screen);
|
||||
}
|
||||
|
||||
// A, B, and Z buttons on the map screen
|
||||
DEFINE_HOOK(&dMenu_Fmap_c::_create, MenuFMapCreate);
|
||||
void menu_fmap_create_post(ModContext*, void* args, void*, void*) {
|
||||
auto menuFMap = mods::arg<dMenu_Fmap_c*>(args, 0);
|
||||
auto screen = menuFMap->mpDraw2DTop->mpTitleScreen;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('a_btn'), screen);
|
||||
recolor_ui_button(get_cvars().bButtonColor, MULTI_CHAR('b_btn1'), screen);
|
||||
recolor_ui_button(get_cvars().zButtonColor, MULTI_CHAR('zbtn'), screen);
|
||||
}
|
||||
|
||||
// A button on the howling screen
|
||||
DEFINE_HOOK(&dMsgObject_c::talkStartInit, MsgObjectTalkStartInit);
|
||||
void msg_object_talk_start_init_post(ModContext*, void* args, void*, void*) {
|
||||
auto msgObject = mods::arg<dMsgObject_c*>(args, 0);
|
||||
|
||||
// If textbox kind is howling
|
||||
if (msgObject->mFukiKind == 17) {
|
||||
auto screen = msgObject->mpScrnDraw->mpScreen;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('abtn'), screen);
|
||||
}
|
||||
}
|
||||
|
||||
// A button when on Epona
|
||||
DEFINE_HOOK(&dMeterHakusha_c::_create, MeterHakushaCreate);
|
||||
void meter_hakusha_create_post(ModContext*, void* args, void*, void*) {
|
||||
auto meterHakusha = mods::arg<dMeterHakusha_c*>(args, 0);
|
||||
auto screen = meterHakusha->mpButtonScreen;
|
||||
|
||||
recolor_ui_button(get_cvars().aButtonColor, MULTI_CHAR('a_btn1'), screen);
|
||||
}
|
||||
|
||||
// A, B, X, and Y button icons in text
|
||||
DEFINE_HOOK(&COutFont_c::createPane, OutFontCreatePane);
|
||||
void out_font_create_pane_post(ModContext*, void* args, void*, void*) {
|
||||
auto outFont = mods::arg<COutFont_c*>(args, 0);
|
||||
auto paneArr = outFont->mpPane;
|
||||
|
||||
auto maybeAButtonColor = get_config_var_color(get_cvars().aButtonColor);
|
||||
if (maybeAButtonColor.has_value()) {
|
||||
auto aButtonColor = maybeAButtonColor.value();
|
||||
paneArr[0]->setBlackWhite(JUtility::TColor(255, 255, 255, 0),
|
||||
JUtility::TColor(aButtonColor.r, aButtonColor.g, aButtonColor.b, 255));
|
||||
}
|
||||
|
||||
auto maybeBButtonColor = get_config_var_color(get_cvars().bButtonColor);
|
||||
if (maybeBButtonColor.has_value()) {
|
||||
auto bButtonColor = maybeBButtonColor.value();
|
||||
paneArr[1]->setBlackWhite(JUtility::TColor(255, 255, 255, 0),
|
||||
JUtility::TColor(bButtonColor.r, bButtonColor.g, bButtonColor.b, 255));
|
||||
}
|
||||
|
||||
// Condition copied from hooked function
|
||||
auto xyBlack = JUtility::TColor(255, 255, 255, 0);
|
||||
if (outFont->field_0x242 == 1) {
|
||||
xyBlack = JUtility::TColor(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
auto maybeXButtonColor = get_config_var_color(get_cvars().xButtonColor);
|
||||
if (maybeXButtonColor.has_value()) {
|
||||
auto xButtonColor = maybeXButtonColor.value();
|
||||
paneArr[5]->setBlackWhite(
|
||||
xyBlack, JUtility::TColor(xButtonColor.r, xButtonColor.g, xButtonColor.b, 255));
|
||||
}
|
||||
|
||||
auto maybeYButtonColor = get_config_var_color(get_cvars().yButtonColor);
|
||||
if (maybeYButtonColor.has_value()) {
|
||||
auto yButtonColor = maybeYButtonColor.value();
|
||||
paneArr[6]->setBlackWhite(
|
||||
xyBlack, JUtility::TColor(yButtonColor.r, yButtonColor.g, yButtonColor.b, 255));
|
||||
}
|
||||
}
|
||||
|
||||
// Heart icon in text
|
||||
DEFINE_HOOK(&COutFontSet_c::drawFont, OutFontSetDrawFont);
|
||||
void out_font_set_draw_font_post(ModContext*, void* args, void*, void*) {
|
||||
auto outFontSet = mods::arg<COutFontSet_c*>(args, 0);
|
||||
|
||||
auto maybeHeartColor = get_config_var_color(get_cvars().heartColor);
|
||||
if (maybeHeartColor.has_value()) {
|
||||
auto heartColor = maybeHeartColor.value();
|
||||
u32 heartColor_u32 = heartColor.r << 24 | heartColor.g << 16 | heartColor.b << 8 | 0xFF;
|
||||
if (outFontSet->getType() == 0x1B) { // Heart icon type
|
||||
outFontSet->mColor = heartColor_u32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Heart Drop/Piece of Heart/Heart Container model color
|
||||
DEFINE_HOOK(&daItemBase_c::CreateItemHeap, ItemBaseCreateItemHeap);
|
||||
void item_base_create_item_heap_post(ModContext*, void* args, void*, void*) {
|
||||
auto itemBase = mods::arg<daItemBase_c*>(args, 0);
|
||||
if (itemBase == NULL) {
|
||||
return;
|
||||
}
|
||||
auto itemNo = itemBase->m_itemNo;
|
||||
if (itemNo == dItemNo_HEART_e || itemNo == dItemNo_UTAWA_HEART_e ||
|
||||
itemNo == dItemNo_KAKERA_HEART_e)
|
||||
{
|
||||
auto maybeHeartColor = get_config_var_color(get_cvars().heartColor);
|
||||
if (maybeHeartColor.has_value()) {
|
||||
auto heartColor = maybeHeartColor.value();
|
||||
auto heartColorS10 = GXColorS10(heartColor.r, heartColor.g, heartColor.b, heartColor.a);
|
||||
|
||||
// Edit inner heart material color for Piece of Heart / Heart Container
|
||||
if (itemNo == dItemNo_UTAWA_HEART_e || itemNo == dItemNo_KAKERA_HEART_e) {
|
||||
*itemBase->mpModel->getModelData()->getMaterialNodePointer(3)->getTevKColor(1) =
|
||||
heartColor;
|
||||
*itemBase->mpModel->getModelData()->getMaterialNodePointer(3)->getTevColor(1) =
|
||||
heartColorS10;
|
||||
}
|
||||
|
||||
const u8 heartColorRGB[3] = {heartColor.r, heartColor.g, heartColor.b};
|
||||
u8** cRegTable =
|
||||
reinterpret_cast<u8**>(&itemBase->mpBrkAnm->getBrkAnm()->mAnmCRegDataR);
|
||||
u8** kRegTable =
|
||||
reinterpret_cast<u8**>(&itemBase->mpBrkAnm->getBrkAnm()->mAnmKRegDataR);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
u8* cReg = cRegTable[i];
|
||||
u8* kReg = kRegTable[i];
|
||||
|
||||
auto curColor = heartColorRGB[i];
|
||||
|
||||
// Set heart drop inner heart color
|
||||
cReg[0x3] = curColor;
|
||||
cReg[0xB] = curColor;
|
||||
|
||||
// Set heart drop outer heart color
|
||||
kReg[0x3] = curColor;
|
||||
kReg[0xB] = curColor;
|
||||
|
||||
if (itemNo == dItemNo_KAKERA_HEART_e) {
|
||||
cReg[0x13] = curColor;
|
||||
cReg[0x1B] = curColor;
|
||||
kReg[0x13] = curColor;
|
||||
kReg[0x1B] = curColor;
|
||||
}
|
||||
if (itemNo == dItemNo_UTAWA_HEART_e) {
|
||||
cReg[0x13] = curColor;
|
||||
kReg[0x13] = curColor;
|
||||
kReg[0x1B] = curColor;
|
||||
kReg[0x23] = curColor;
|
||||
kReg[0x2B] = curColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Midna Hair Color
|
||||
DEFINE_HOOK(&daMidna_c::create, MidnaCreate);
|
||||
void midna_create_post(ModContext*, void* args, void* retval, void*) {
|
||||
auto step = reinterpret_cast<int*>(retval);
|
||||
// Don't set colors if midna isn't done loading
|
||||
if (*step != cPhs_COMPLEATE_e) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto midna = mods::arg<daMidna_c*>(args, 0);
|
||||
midna->field_0x6e0 = g_currentMidnaHairColors.normalColor;
|
||||
if (dKy_darkworld_check()) {
|
||||
midna->field_0x6e8 = g_currentMidnaHairColors.normalKColor;
|
||||
midna->field_0x6ec = g_currentMidnaHairColors.normalKColor2;
|
||||
} else {
|
||||
midna->field_0x6e8 = g_currentMidnaHairColors.lNormalKColor;
|
||||
midna->field_0x6ec = g_currentMidnaHairColors.lNormalKColor2;
|
||||
}
|
||||
}
|
||||
|
||||
// Override Midna Hair Color Part 2
|
||||
DEFINE_HOOK(&daMidna_c::setBodyPartMatrix, MidnaSetBodyPartMatrix);
|
||||
|
||||
static GXColorS10 midnaField0x6e0{};
|
||||
static GXColor midnaField0x6e8{};
|
||||
static GXColor midnaField0x6ec{};
|
||||
|
||||
// Copy the original values before setBodyPartMatrix runs
|
||||
HookAction midna_set_body_part_matrix_pre(ModContext*, void* args, void* retval, void* userdata) {
|
||||
auto midna = mods::arg<daMidna_c*>(args, 0);
|
||||
|
||||
midnaField0x6e0 = midna->field_0x6e0;
|
||||
midnaField0x6e8 = midna->field_0x6e8;
|
||||
midnaField0x6ec = midna->field_0x6ec;
|
||||
|
||||
return HOOK_CONTINUE;
|
||||
}
|
||||
|
||||
void midna_set_body_part_matrix_post(ModContext*, void* args, void* retval, void* userdata) {
|
||||
auto midna = mods::arg<daMidna_c*>(args, 0);
|
||||
if (midna->mpHairhandBmd != NULL) {
|
||||
// Restore the original values from before setBodyPartMatrix ran (this undoes the chase)
|
||||
midna->field_0x6e0 = midnaField0x6e0;
|
||||
midna->field_0x6e8 = midnaField0x6e8;
|
||||
midna->field_0x6ec = midnaField0x6ec;
|
||||
|
||||
// Statement copied from inside function to determine colors
|
||||
bool bigColors =
|
||||
midna->checkStateFlg0(daMidna_c::FLG0_UNK_10000000) ||
|
||||
midna->mBckHeap[2].getIdx() == daMidna_c::m_anmDataTable[daMidna_c::ANM_HAIR].mResID ||
|
||||
midna->mBckHeap[2].getIdx() ==
|
||||
daMidna_c::m_anmDataTable[daMidna_c::ANM_S_TAKES].mResID ||
|
||||
midna->mBckHeap[2].getIdx() ==
|
||||
daMidna_c::m_anmDataTable[daMidna_c::ANM_S_WAITS].mResID ||
|
||||
midna->mBckHeap[2].getIdx() ==
|
||||
daMidna_c::m_anmDataTable[daMidna_c::ANM_S_PACKAWAY].mResID ||
|
||||
midna->mBckHeap[2].getIdx() ==
|
||||
daMidna_c::m_anmDataTable[daMidna_c::ANM_GRABST].mResID ||
|
||||
midna->checkEndResetStateFlg0(daMidna_c::ERFLG0_UNK_40) ||
|
||||
dComIfGp_checkPlayerStatus1(0, 0x800000);
|
||||
|
||||
GXColorS10 color{};
|
||||
GXColor kcolor1{};
|
||||
GXColor kcolor2{};
|
||||
|
||||
// Set our own colors
|
||||
if (bigColors) {
|
||||
kcolor1 = g_currentMidnaHairColors.bigKColor;
|
||||
if (dKy_darkworld_check()) {
|
||||
color = g_currentMidnaHairColors.bigColor;
|
||||
kcolor2 = g_currentMidnaHairColors.normalKColor2;
|
||||
} else {
|
||||
color = g_currentMidnaHairColors.lBigColor;
|
||||
kcolor2 = g_currentMidnaHairColors.lBigKColor2;
|
||||
}
|
||||
} else {
|
||||
color = g_currentMidnaHairColors.normalColor;
|
||||
if (dKy_darkworld_check()) {
|
||||
kcolor1 = g_currentMidnaHairColors.normalKColor;
|
||||
kcolor2 = g_currentMidnaHairColors.normalKColor2;
|
||||
} else {
|
||||
kcolor1 = g_currentMidnaHairColors.lNormalKColor;
|
||||
kcolor2 = g_currentMidnaHairColors.lNormalKColor2;
|
||||
}
|
||||
}
|
||||
|
||||
// Reapply the chase that happens in the function
|
||||
cLib_chaseS(&midna->field_0x6e0.r, color.r, 10);
|
||||
cLib_chaseS(&midna->field_0x6e0.g, color.g, 10);
|
||||
cLib_chaseS(&midna->field_0x6e0.b, color.b, 10);
|
||||
cLib_chaseUC(&midna->field_0x6e8.r, kcolor1.r, 10);
|
||||
cLib_chaseUC(&midna->field_0x6e8.g, kcolor1.g, 10);
|
||||
cLib_chaseUC(&midna->field_0x6e8.b, kcolor1.b, 10);
|
||||
cLib_chaseUC(&midna->field_0x6ec.r, kcolor2.r, 10);
|
||||
cLib_chaseUC(&midna->field_0x6ec.g, kcolor2.g, 10);
|
||||
cLib_chaseUC(&midna->field_0x6ec.b, kcolor2.b, 10);
|
||||
}
|
||||
}
|
||||
|
||||
// Midna Charge Ring Color
|
||||
DEFINE_HOOK(&daAlink_c::setWolfLockDomeModel, SetWolfLockDomeModel);
|
||||
void wolf_lock_dome_model_post(ModContext*, void*, void*, void*) {
|
||||
auto domeRingColorStr = get_str_option(get_cvars().midnaChargeRingColor, "");
|
||||
if (is_valid_hex_color_str(domeRingColorStr)) {
|
||||
auto domeRingColor = hex_color_str_to_gx_color(domeRingColorStr);
|
||||
const u8 domeWave1RGBA[3] = {domeRingColor.r, domeRingColor.g, domeRingColor.b};
|
||||
const u8 domeWave2RGBA[3] = {domeRingColor.r, domeRingColor.g, domeRingColor.b};
|
||||
u8** chromaRegisterTable =
|
||||
reinterpret_cast<u8**>(&daAlink_getAlinkActorClass()->field_0x0724->mAnmCRegDataR);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
u8* currentTable = chromaRegisterTable[i];
|
||||
const u8 currentWave1Color = domeWave1RGBA[i];
|
||||
const u8 currentWave2Color = domeWave2RGBA[i];
|
||||
const u8 currentBaseColor = (currentWave1Color + currentWave2Color) / 2;
|
||||
|
||||
currentTable[0x3] = currentBaseColor; // Set Alpha for the ring base
|
||||
currentTable[0x13] = currentWave1Color; // Set Alpha for ring wave 1
|
||||
currentTable[0x23] = currentWave2Color; // Set Alpha for ring wave 2
|
||||
currentTable[0xB] = currentBaseColor; // Set Alpha for darkworld ring base
|
||||
currentTable[0x1B] = currentWave1Color; // Set Alpha for darkworld ring wave 1
|
||||
currentTable[0x2B] = currentWave2Color; // Set Alpha for darkworld ring wave 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define ADD_POST_HOOK(defined_hook, function, original) \
|
||||
result = mods::hook::add_post<defined_hook>(function); \
|
||||
if (result != MOD_OK) { \
|
||||
mods::log::debug( \
|
||||
"failed to add post hook to" #original ", Result {}", static_cast<int>(result)); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
#define ADD_PRE_HOOK(defined_hook, function, original) \
|
||||
result = mods::hook::add_pre<defined_hook>(function); \
|
||||
if (result != MOD_OK) { \
|
||||
mods::log::debug( \
|
||||
"failed to add pre hook to" #original ", Result {}", static_cast<int>(result)); \
|
||||
return result; \
|
||||
}
|
||||
|
||||
ModResult add_all_hooks() {
|
||||
ModResult result{};
|
||||
|
||||
// Hooks for lantern glow
|
||||
ADD_POST_HOOK(WolfEyeLightSet, wolf_eye_light_set_post, dKy_WolfEyeLight_set)
|
||||
ADD_POST_HOOK(PreKandelaarDraw, pre_kandelaar_draw_post, daAlink_c::preKandelaarDraw)
|
||||
|
||||
// Hooks for lantern meter color
|
||||
ADD_PRE_HOOK(CPaneMgrSetBlackWhite, cpane_mgr_set_black_white_pre, CPaneMgr::setBlackWhite)
|
||||
ADD_POST_HOOK(
|
||||
KanteraIconSetNowGauge, kantera_icon_set_now_gauge_post, dKantera_icon_c::setNowGauge)
|
||||
|
||||
// Hook for midna charge ring
|
||||
ADD_POST_HOOK(SetWolfLockDomeModel, wolf_lock_dome_model_post, daAlink_c::setWolfLockDomeModel)
|
||||
|
||||
// Hook for light sword glow
|
||||
ADD_POST_HOOK(SetLightningSwordEffect, set_lightning_sword_effect_post,
|
||||
daAlink_c::setLightningSwordEffect)
|
||||
|
||||
// Hooks for Midna Hair Color
|
||||
ADD_POST_HOOK(MidnaCreate, midna_create_post, daMidna_c::create)
|
||||
ADD_PRE_HOOK(
|
||||
MidnaSetBodyPartMatrix, midna_set_body_part_matrix_pre, daMidna_c::setBodyPartMatrix)
|
||||
ADD_POST_HOOK(
|
||||
MidnaSetBodyPartMatrix, midna_set_body_part_matrix_post, daMidna_c::setBodyPartMatrix)
|
||||
|
||||
// Hooks for UI colors
|
||||
ADD_POST_HOOK(dMeter2Init, d_meter_2_init_post, dMeter2Draw_c::init)
|
||||
ADD_POST_HOOK(FileInfoSetHeartCount, file_info_set_heart_count_post, dFile_info_c::setHeartCnt)
|
||||
ADD_POST_HOOK(ScreenInitButton, screen_init_button_post, dMeterButton_c::screenInitButton)
|
||||
ADD_POST_HOOK(MenuSaveScreenSet, menu_save_screen_set_post, dMenu_save_c::screenSet)
|
||||
ADD_POST_HOOK(FileSelectScreenSet, file_select_screen_set_post, dFile_select_c::screenSet)
|
||||
ADD_POST_HOOK(BrightCheckScreenSet, bright_check_screen_set_post, dBrightCheck_c::screenSet)
|
||||
ADD_POST_HOOK(MenuRingCreate, menu_ring_create_post, dMenu_Ring_c::_create)
|
||||
ADD_POST_HOOK(MenuCollect2DCreate, menu_collect_2D_create_post, dMenu_Collect2D_c::_create)
|
||||
ADD_POST_HOOK(MenuFishingScreenSetDoIcon, menu_fishing_screen_set_do_icon_post,
|
||||
dMenu_Fishing_c::screenSetDoIcon)
|
||||
ADD_POST_HOOK(MenuInsectScreenSetDoIcon, menu_insect_screen_set_do_icon_post,
|
||||
dMenu_Insect_c::screenSetDoIcon)
|
||||
ADD_POST_HOOK(MenuLetterScreenSetDoIcon, menu_letter_screen_set_do_icon_post,
|
||||
dMenu_Letter_c::screenSetDoIcon)
|
||||
ADD_POST_HOOK(MenuOptionCreate, menu_option_create_post, dMenu_Option_c::_create)
|
||||
ADD_POST_HOOK(MenuSkillScreenSetDoIcon, menu_skill_screen_set_do_icon_post,
|
||||
dMenu_Skill_c::screenSetDoIcon)
|
||||
ADD_POST_HOOK(OutFontCreatePane, out_font_create_pane_post, COutFont_c::createPane)
|
||||
ADD_POST_HOOK(OutFontSetDrawFont, out_font_set_draw_font_post, COutFontSet_c::drawFont)
|
||||
ADD_POST_HOOK(MenuFMapCreate, menu_fmap_create_post, dMenu_Fmap_c::_create)
|
||||
ADD_POST_HOOK(
|
||||
MsgObjectTalkStartInit, msg_object_talk_start_init_post, dMsgObject_c::talkStartInit)
|
||||
ADD_POST_HOOK(MeterHakushaCreate, meter_hakusha_create_post, dMeterHakusha_c::_create)
|
||||
|
||||
// Heart Model Color
|
||||
ADD_POST_HOOK(
|
||||
ItemBaseCreateItemHeap, item_base_create_item_heap_post, daItemBase_c::CreateItemHeap)
|
||||
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
#define UNINSTALL_HOOK(defined_hook) mods::hook::uninstall<defined_hook>(svc_hook);
|
||||
|
||||
ModResult remove_all_hooks() {
|
||||
UNINSTALL_HOOK(WolfEyeLightSet)
|
||||
UNINSTALL_HOOK(PreKandelaarDraw)
|
||||
UNINSTALL_HOOK(CPaneMgrSetBlackWhite)
|
||||
UNINSTALL_HOOK(KanteraIconSetNowGauge)
|
||||
UNINSTALL_HOOK(SetWolfLockDomeModel)
|
||||
UNINSTALL_HOOK(SetLightningSwordEffect)
|
||||
UNINSTALL_HOOK(MidnaCreate)
|
||||
UNINSTALL_HOOK(MidnaSetBodyPartMatrix)
|
||||
UNINSTALL_HOOK(MidnaSetBodyPartMatrix)
|
||||
UNINSTALL_HOOK(dMeter2Init)
|
||||
UNINSTALL_HOOK(FileInfoSetHeartCount)
|
||||
UNINSTALL_HOOK(ScreenInitButton)
|
||||
UNINSTALL_HOOK(MenuSaveScreenSet)
|
||||
UNINSTALL_HOOK(FileSelectScreenSet)
|
||||
UNINSTALL_HOOK(BrightCheckScreenSet)
|
||||
UNINSTALL_HOOK(MenuRingCreate)
|
||||
UNINSTALL_HOOK(MenuCollect2DCreate)
|
||||
UNINSTALL_HOOK(MenuFishingScreenSetDoIcon)
|
||||
UNINSTALL_HOOK(MenuInsectScreenSetDoIcon)
|
||||
UNINSTALL_HOOK(MenuLetterScreenSetDoIcon)
|
||||
UNINSTALL_HOOK(MenuOptionCreate)
|
||||
UNINSTALL_HOOK(MenuSkillScreenSetDoIcon)
|
||||
UNINSTALL_HOOK(OutFontCreatePane)
|
||||
UNINSTALL_HOOK(OutFontSetDrawFont)
|
||||
UNINSTALL_HOOK(MenuFMapCreate)
|
||||
UNINSTALL_HOOK(MsgObjectTalkStartInit)
|
||||
UNINSTALL_HOOK(MeterHakushaCreate)
|
||||
UNINSTALL_HOOK(ItemBaseCreateItemHeap)
|
||||
return MOD_OK;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "mods/service.hpp"
|
||||
|
||||
ModResult add_all_hooks();
|
||||
|
||||
ModResult remove_all_hooks();
|
||||
@@ -0,0 +1,115 @@
|
||||
#include "midna_hair_color.hpp"
|
||||
#include "mod.hpp"
|
||||
|
||||
#include "mods/svc/log.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace {
|
||||
constexpr std::array<std::array<GXColor, 9>, 10> kMidnaHairColors = {{
|
||||
// Default
|
||||
{{
|
||||
/*l_lNormalKColor*/ /*l_normalKColor*/ /*l_normalColor*/
|
||||
{0xFF, 0xDC, 0x00}, {0xB4, 0x87, 0x00}, {0x50, 0x00, 0x00},
|
||||
/*l_bigKColor*/ /*l_lBigColor*/ /*l_bigColor*/
|
||||
{0x1E, 0x00, 0x00}, {0xFF, 0x78, 0x00}, {0xFF, 0x64, 0x78},
|
||||
/*l_lNormalKColor2*//*l_normalKColor2*/ /*l_lBigKColor2*/
|
||||
{0x00, 0xC3, 0xEB}, {0x00, 0xC3, 0xC3}, {0xAA, 0xFF, 0xC3}
|
||||
}},
|
||||
// Pink
|
||||
{{
|
||||
{0xF5, 0xCF, 0xF3}, {0xAD, 0x7F, 0x7F}, {0x1B, 0x00, 0x20},
|
||||
{0x3C, 0x02, 0x58}, {0xE3, 0x72, 0xF2}, {0xE3, 0x5F, 0xF8},
|
||||
{0xDD, 0x00, 0xEB}, {0xDD, 0x00, 0xC3}, {0xF6, 0x4C, 0xFF}
|
||||
}},
|
||||
// Red
|
||||
{{
|
||||
{0xE4, 0x65, 0x41}, {0xA1, 0x3E, 0x22}, {0x21, 0x00, 0x00},
|
||||
{0x4F, 0x02, 0x01}, {0xF0, 0x3A, 0x25}, {0xF0, 0x30, 0x8C},
|
||||
{0xEB, 0x00, 0x00}, {0xEB, 0x00, 0x00}, {0xFF, 0x4F, 0x3A}
|
||||
}},
|
||||
// Yellow
|
||||
{{
|
||||
{0x91, 0x83, 0x0E}, {0x66, 0x50, 0x07}, {0x0E, 0x0B, 0x00},
|
||||
{0x24, 0x25, 0x02}, {0xCB, 0xB7, 0x00}, {0xCB, 0x99, 0x78},
|
||||
{0xEB, 0xDE, 0x00}, {0xEB, 0xDE, 0x00}, {0xFF, 0xF8, 0xBF}
|
||||
}},
|
||||
// Green
|
||||
{{
|
||||
{0x35, 0x79, 0x53}, {0x25, 0x4A, 0x2B}, {0x00, 0x0E, 0x05},
|
||||
{0x0A, 0x29, 0x10}, {0x00, 0xB6, 0x6F}, {0x00, 0x98, 0xB3},
|
||||
{0x1F, 0xEB, 0x00}, {0x1F, 0xEB, 0x00}, {0x9A, 0xFF, 0x81}
|
||||
}},
|
||||
// Blue
|
||||
{{
|
||||
{0x00, 0x72, 0xFF}, {0x00, 0x46, 0x85}, {0x00, 0x08, 0x28},
|
||||
{0x16, 0x1B, 0x5D}, {0x00, 0x60, 0xFF}, {0x00, 0x50, 0xFF},
|
||||
{0x00, 0x48, 0xEB}, {0x00, 0x48, 0xC3}, {0x3A, 0x66, 0xFF}
|
||||
}},
|
||||
// Purple
|
||||
{{
|
||||
{0x6F, 0x34, 0xFF}, {0x4E, 0x20, 0x85}, {0x0D, 0x00, 0x34},
|
||||
{0x15, 0x08, 0x79}, {0x62, 0x00, 0xFF}, {0x62, 0x00, 0xFF},
|
||||
{0x7B, 0x00, 0xEB}, {0x7B, 0x00, 0xC3}, {0x94, 0x3E, 0xFF}
|
||||
}},
|
||||
// Brown
|
||||
{{
|
||||
{0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x1A, 0x05, 0x00},
|
||||
{0x3C, 0x19, 0x0E}, {0x3F, 0x1D, 0x0B}, {0x3F, 0x18, 0x7E},
|
||||
{0x3F, 0x1D, 0x0B}, {0x3F, 0x1D, 0x09}, {0x59, 0x32, 0x1E}
|
||||
}},
|
||||
// White
|
||||
{{
|
||||
{0xF0, 0xF1, 0xF1}, {0xA9, 0x94, 0x7E}, {0x09, 0x0B, 0x0C},
|
||||
{0x22, 0x24, 0x24}, {0xFF, 0xFF, 0xFF}, {0xFF, 0xD5, 0xFF},
|
||||
{0xEA, 0xEA, 0xEA}, {0xEA, 0xEA, 0xC2}, {0xF3, 0xF3, 0xF3}
|
||||
}},
|
||||
// Black
|
||||
{{
|
||||
{0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x0B, 0x0B, 0x0B},
|
||||
{0x23, 0x23, 0x23}, {0x00, 0x00, 0x00}, {0x00, 0x00, 0x78},
|
||||
{0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}
|
||||
}}
|
||||
}};
|
||||
|
||||
size_t get_midna_hair_color_index(ConfigVarHandle handle) {
|
||||
const auto optionIndex = get_int_option(handle, 0);
|
||||
if (optionIndex < 0 || optionIndex >= static_cast<int64_t>(kMidnaHairColors.size())) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<size_t>(optionIndex);
|
||||
}
|
||||
}
|
||||
|
||||
MidnaHairColors g_currentMidnaHairColors = {
|
||||
.normalColor = {0x50, 0x00, 0x00, 0x00},
|
||||
.normalKColor = {0xB4, 0x87, 0x00, 0x00},
|
||||
.normalKColor2 = {0x00, 0xC3, 0xC3, 0x00},
|
||||
.bigColor = {0xFF, 0x64, 0x78, 0x00},
|
||||
.bigKColor = {0x1E, 0x00, 0x00, 0x00},
|
||||
.lNormalKColor = {0xFF, 0xDC, 0x00, 0x00},
|
||||
.lNormalKColor2 = {0x00, 0xC3, 0xEB, 0x00},
|
||||
.lBigColor = {0xFF, 0x78, 0x00, 0x00},
|
||||
.lBigKColor2 = {0xAA, 0xFF, 0xC3, 0x00},
|
||||
};
|
||||
|
||||
void set_all_midna_hair_colors() {
|
||||
auto& g_cvars = get_cvars();
|
||||
auto hairBaseColor = get_midna_hair_color_index(g_cvars.midnaHairBaseColor);
|
||||
auto hairTipsColor = get_midna_hair_color_index(g_cvars.midnaHairTipsColor);
|
||||
|
||||
// Colors we have to convert to GXColorS10
|
||||
auto& normalColor = kMidnaHairColors.at(hairBaseColor)[2];
|
||||
auto& bigColor = kMidnaHairColors.at(hairBaseColor)[5];
|
||||
auto& lBigColor = kMidnaHairColors.at(hairBaseColor)[4];
|
||||
|
||||
g_currentMidnaHairColors.normalColor = GXColorS10{normalColor.r, normalColor.g, normalColor.b};
|
||||
g_currentMidnaHairColors.normalKColor = kMidnaHairColors.at(hairBaseColor)[1];
|
||||
g_currentMidnaHairColors.normalKColor2 = kMidnaHairColors.at(hairTipsColor)[7];
|
||||
g_currentMidnaHairColors.bigColor = GXColorS10{bigColor.r, bigColor.g, bigColor.b};
|
||||
g_currentMidnaHairColors.bigKColor = kMidnaHairColors.at(hairBaseColor)[3];
|
||||
g_currentMidnaHairColors.lNormalKColor = kMidnaHairColors.at(hairBaseColor)[0];
|
||||
g_currentMidnaHairColors.lNormalKColor2 = kMidnaHairColors.at(hairTipsColor)[6];
|
||||
g_currentMidnaHairColors.lBigColor = GXColorS10{lBigColor.r, lBigColor.g, lBigColor.b};
|
||||
g_currentMidnaHairColors.lBigKColor2 = kMidnaHairColors.at(hairTipsColor)[8];
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <gx.h>
|
||||
|
||||
struct MidnaHairColors {
|
||||
GXColorS10 normalColor;
|
||||
GXColor normalKColor;
|
||||
GXColor normalKColor2;
|
||||
GXColorS10 bigColor;
|
||||
GXColor bigKColor;
|
||||
GXColor lNormalKColor;
|
||||
GXColor lNormalKColor2;
|
||||
GXColorS10 lBigColor;
|
||||
GXColor lBigKColor2;
|
||||
};
|
||||
|
||||
extern MidnaHairColors g_currentMidnaHairColors;
|
||||
|
||||
void set_all_midna_hair_colors();
|
||||
@@ -0,0 +1,653 @@
|
||||
#include "mod.hpp"
|
||||
#include "color_utils.hpp"
|
||||
#include "hooks.hpp"
|
||||
#include "midna_hair_color.hpp"
|
||||
#include "texture_utils.hpp"
|
||||
|
||||
#include "mods/service.hpp"
|
||||
#include "mods/svc/config.h"
|
||||
#include "mods/svc/hook.hpp"
|
||||
#include "mods/svc/log.h"
|
||||
#include "mods/svc/log.hpp"
|
||||
#include "mods/svc/ui.h"
|
||||
|
||||
#include "d/d_com_inf_game.h"
|
||||
|
||||
#include <xxhash.h>
|
||||
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
|
||||
DEFINE_MOD();
|
||||
IMPORT_SERVICE(LogService, svc_log);
|
||||
IMPORT_SERVICE(ConfigService, svc_config);
|
||||
IMPORT_SERVICE(HookService, svc_hook);
|
||||
IMPORT_SERVICE(TextureService, svc_texture);
|
||||
IMPORT_SERVICE(UiService, svc_ui);
|
||||
|
||||
static cvars g_cvars;
|
||||
|
||||
cvars& get_cvars() {
|
||||
return g_cvars;
|
||||
}
|
||||
|
||||
std::string get_str_option(ConfigVarHandle handle, const std::string& fallback) {
|
||||
std::string value{};
|
||||
size_t outLength{};
|
||||
svc_config->get_string(mod_ctx, handle, NULL, 0, &outLength);
|
||||
value.resize(outLength);
|
||||
if (handle == 0 || svc_config->get_string(
|
||||
mod_ctx, handle, value.data(), value.size() + 1, &outLength) != MOD_OK)
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
int64_t get_int_option(ConfigVarHandle handle, int64_t fallback) {
|
||||
int64_t value = fallback;
|
||||
if (handle == 0 || svc_config->get_int(mod_ctx, handle, &value) != MOD_OK) {
|
||||
return fallback;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Helper for getting configVar color
|
||||
std::optional<GXColor> get_config_var_color(ConfigVarHandle handle, bool allowRainbow) {
|
||||
auto colorStr = get_str_option(handle, "");
|
||||
// Convert to lowercase
|
||||
for (auto& c : colorStr) {
|
||||
c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
||||
}
|
||||
if (colorStr == "rainbow" && allowRainbow) {
|
||||
auto color = get_rainbow_rgb(127.5f);
|
||||
color.r /= 2;
|
||||
color.g /= 2;
|
||||
color.b /= 2;
|
||||
return color;
|
||||
}
|
||||
if (is_valid_hex_color_str(colorStr)) {
|
||||
return hex_color_str_to_gx_color(colorStr);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
namespace {
|
||||
UiWindowHandle g_cosmeticsWindow = 0;
|
||||
bool g_loadedAllBaseTextures = false;
|
||||
constexpr uint32_t kTextureLoadRetryFrames = 30;
|
||||
uint32_t g_textureLoadRetryCountdown = 0;
|
||||
|
||||
constexpr const char* kOverlayPresets[] = {
|
||||
"ab706e",
|
||||
"6382a0",
|
||||
"94749a",
|
||||
"ec8644",
|
||||
"b9ab00",
|
||||
"ec9fc8",
|
||||
"505154",
|
||||
"f8f7f4",
|
||||
"91723e",
|
||||
};
|
||||
|
||||
constexpr const char* kLightPresets[] = {
|
||||
"ff0000",
|
||||
"f68821",
|
||||
"f6f321",
|
||||
"00ff00",
|
||||
"0000ff",
|
||||
"8000ff",
|
||||
"a0a0a0",
|
||||
"30d0d0",
|
||||
};
|
||||
|
||||
constexpr const char* kRainbowLightPresets[] = {
|
||||
"rainbow",
|
||||
"ff0000",
|
||||
"f68821",
|
||||
"f6f321",
|
||||
"00ff00",
|
||||
"0000ff",
|
||||
"8000ff",
|
||||
"a0a0a0",
|
||||
};
|
||||
|
||||
constexpr const char* kAButtonPresets[] = {
|
||||
"ff0000",
|
||||
"ff5000",
|
||||
"ffaf00",
|
||||
"0080ff",
|
||||
"0000ff",
|
||||
"8000ff",
|
||||
"5555ff",
|
||||
"ff20ff",
|
||||
};
|
||||
|
||||
constexpr const char* kBButtonPresets[] = {
|
||||
"ffff40",
|
||||
"ffa0ff",
|
||||
"00e87b",
|
||||
"00aaff",
|
||||
"6078ff",
|
||||
"000000",
|
||||
"00f3ff",
|
||||
};
|
||||
|
||||
constexpr const char* kXyButtonPresets[] = {
|
||||
"ff0000",
|
||||
"ff8200",
|
||||
"f7df00",
|
||||
"70ff00",
|
||||
"00bd11",
|
||||
"0000ff",
|
||||
"800088",
|
||||
"000000",
|
||||
"ff00aa",
|
||||
"00ffff",
|
||||
};
|
||||
|
||||
constexpr const char* kZButtonPresets[] = {
|
||||
"ff0000",
|
||||
"ff8200",
|
||||
"f7df00",
|
||||
"70ff00",
|
||||
"00bd11",
|
||||
"800088",
|
||||
"000000",
|
||||
"00ffff",
|
||||
};
|
||||
|
||||
constexpr const char* kChargeRingPresets[] = {
|
||||
"ff9f9f",
|
||||
"ff0000",
|
||||
"ffff00",
|
||||
"00ff00",
|
||||
"0000ff",
|
||||
"ff00ff",
|
||||
"331900",
|
||||
"feffff",
|
||||
"000000",
|
||||
};
|
||||
|
||||
ModResult register_str_option(
|
||||
const char* name, const char* defaultValue, ConfigVarHandle& outHandle, ModError* error) {
|
||||
ConfigVarDesc cvarDesc = CONFIG_VAR_DESC_INIT;
|
||||
cvarDesc.name = name;
|
||||
cvarDesc.type = CONFIG_VAR_STRING;
|
||||
cvarDesc.default_string = defaultValue;
|
||||
if (svc_config->register_var(mod_ctx, &cvarDesc, &outHandle) != MOD_OK) {
|
||||
return mods::set_error(error, MOD_ERROR, "failed to register cosmetics option");
|
||||
}
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult register_int_option(
|
||||
const char* name, int64_t defaultValue, ConfigVarHandle& outHandle, ModError* error) {
|
||||
ConfigVarDesc cvarDesc = CONFIG_VAR_DESC_INIT;
|
||||
cvarDesc.name = name;
|
||||
cvarDesc.type = CONFIG_VAR_INT;
|
||||
cvarDesc.default_int = defaultValue;
|
||||
if (svc_config->register_var(mod_ctx, &cvarDesc, &outHandle) != MOD_OK) {
|
||||
return mods::set_error(error, MOD_ERROR, "failed to register cosmetics option");
|
||||
}
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
void add_control(UiElementHandle pane, const UiControlDesc& desc) {
|
||||
auto result = svc_ui->pane_add_control(mod_ctx, pane, &desc, nullptr);
|
||||
if (result != MOD_OK) {
|
||||
mods::log::debug("pane_add_control failed {}", static_cast<int>(result));
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
void add_cosmetic_option(
|
||||
UiElementHandle pane, ConfigVarHandle cvar, const char* name, const char* const (&presets)[N]) {
|
||||
UiControlDesc control = UI_CONTROL_DESC_INIT;
|
||||
control.kind = UI_CONTROL_COLOR;
|
||||
control.label = name;
|
||||
control.binding = UI_BINDING_CONFIG_VAR;
|
||||
control.config_var = cvar;
|
||||
control.color_presets = presets;
|
||||
control.color_preset_count = N;
|
||||
add_control(pane, control);
|
||||
}
|
||||
|
||||
void add_midna_hair_option(UiElementHandle left, ConfigVarHandle cvar, const std::string& name) {
|
||||
static const char* kMidnaHairOptions[] = {
|
||||
"Default", "Pink", "Red", "Yellow", "Green", "Blue", "Purple", "Brown", "White", "Black"};
|
||||
UiControlDesc control = UI_CONTROL_DESC_INIT;
|
||||
control.kind = UI_CONTROL_SELECT;
|
||||
control.label = name.c_str();
|
||||
control.help_rml = "Choose Midna's hair color.";
|
||||
control.binding = UI_BINDING_CONFIG_VAR;
|
||||
control.config_var = cvar;
|
||||
control.options = kMidnaHairOptions;
|
||||
control.option_count = 10;
|
||||
add_control(left, control);
|
||||
}
|
||||
|
||||
void add_group(
|
||||
UiElementHandle groups, UiElementHandle colors, const char* label, UiGroupBuildFn build) {
|
||||
UiGroupDesc group = UI_GROUP_DESC_INIT;
|
||||
group.label = label;
|
||||
group.build = build;
|
||||
const auto result = svc_ui->pane_add_group(mod_ctx, groups, colors, &group, nullptr);
|
||||
if (result != MOD_OK) {
|
||||
mods::log::debug("pane_add_group failed {}", static_cast<int>(result));
|
||||
}
|
||||
}
|
||||
|
||||
ModResult build_hero_tunic_colors(ModContext*, UiElementHandle pane, void*, ModError*) {
|
||||
svc_ui->pane_add_section(mod_ctx, pane, "Hero's Tunic");
|
||||
add_cosmetic_option(pane, g_cvars.herosTunicCapColor, "Cap", kOverlayPresets);
|
||||
add_cosmetic_option(pane, g_cvars.herosTunicTorsoColor, "Body", kOverlayPresets);
|
||||
add_cosmetic_option(pane, g_cvars.herosTunicSkirtColor, "Skirt", kOverlayPresets);
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult build_zora_armor_colors(ModContext*, UiElementHandle pane, void*, ModError*) {
|
||||
svc_ui->pane_add_section(mod_ctx, pane, "Zora Armor");
|
||||
add_cosmetic_option(pane, g_cvars.zoraArmorCapColor, "Cap", kOverlayPresets);
|
||||
add_cosmetic_option(pane, g_cvars.zoraArmorHelmetColor, "Helmet", kOverlayPresets);
|
||||
add_cosmetic_option(pane, g_cvars.zoraArmorTorsoColor, "Torso", kOverlayPresets);
|
||||
add_cosmetic_option(pane, g_cvars.zoraArmorScalesColor, "Scales", kOverlayPresets);
|
||||
add_cosmetic_option(pane, g_cvars.zoraArmorFlippersColor, "Flippers", kOverlayPresets);
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult build_sword_colors(ModContext*, UiElementHandle pane, void*, ModError*) {
|
||||
svc_ui->pane_add_section(mod_ctx, pane, "Swords");
|
||||
add_cosmetic_option(pane, g_cvars.woodenSwordColor, "Wooden Sword", kOverlayPresets);
|
||||
add_cosmetic_option(pane, g_cvars.ordonSwordBladeColor, "Ordon Blade", kLightPresets);
|
||||
add_cosmetic_option(pane, g_cvars.ordonSwordHandleColor, "Ordon Handle", kLightPresets);
|
||||
add_cosmetic_option(pane, g_cvars.msBladeColor, "Master Sword Blade", kLightPresets);
|
||||
add_cosmetic_option(pane, g_cvars.msHandleColor, "Master Sword Handle", kLightPresets);
|
||||
add_cosmetic_option(
|
||||
pane, g_cvars.lightSwordGlowColor, "Light Sword Glow", kRainbowLightPresets);
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult build_equipment_colors(ModContext*, UiElementHandle pane, void*, ModError*) {
|
||||
svc_ui->pane_add_section(mod_ctx, pane, "Equipment");
|
||||
add_cosmetic_option(pane, g_cvars.lanternGlowColor, "Lantern Glow", kRainbowLightPresets);
|
||||
add_cosmetic_option(pane, g_cvars.boomerangColor, "Gale Boomerang", kOverlayPresets);
|
||||
add_cosmetic_option(pane, g_cvars.ironBootsColor, "Iron Boots", kOverlayPresets);
|
||||
add_cosmetic_option(pane, g_cvars.spinnerColor, "Spinner", kOverlayPresets);
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult build_button_colors(ModContext*, UiElementHandle pane, void*, ModError*) {
|
||||
svc_ui->pane_add_section(mod_ctx, pane, "Buttons");
|
||||
add_cosmetic_option(pane, g_cvars.aButtonColor, "A Button", kAButtonPresets);
|
||||
add_cosmetic_option(pane, g_cvars.bButtonColor, "B Button", kBButtonPresets);
|
||||
add_cosmetic_option(pane, g_cvars.xButtonColor, "X Button", kXyButtonPresets);
|
||||
add_cosmetic_option(pane, g_cvars.yButtonColor, "Y Button", kXyButtonPresets);
|
||||
add_cosmetic_option(pane, g_cvars.zButtonColor, "Z Button", kZButtonPresets);
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult build_hud_colors(ModContext*, UiElementHandle pane, void*, ModError*) {
|
||||
svc_ui->pane_add_section(mod_ctx, pane, "HUD");
|
||||
add_cosmetic_option(pane, g_cvars.heartColor, "Hearts", kBButtonPresets);
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult build_link_colors(ModContext*, UiElementHandle pane, void*, ModError*) {
|
||||
svc_ui->pane_add_section(mod_ctx, pane, "Link");
|
||||
add_cosmetic_option(pane, g_cvars.linkHairColor, "Hair", kOverlayPresets);
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult build_midna_colors(ModContext*, UiElementHandle pane, void*, ModError*) {
|
||||
svc_ui->pane_add_section(mod_ctx, pane, "Midna");
|
||||
add_cosmetic_option(pane, g_cvars.midnaChargeRingColor, "Charge Ring", kChargeRingPresets);
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult build_companion_colors(ModContext*, UiElementHandle pane, void*, ModError*) {
|
||||
svc_ui->pane_add_section(mod_ctx, pane, "Companions");
|
||||
add_cosmetic_option(pane, g_cvars.wolfLinkColor, "Wolf Link", kOverlayPresets);
|
||||
add_cosmetic_option(pane, g_cvars.eponaColor, "Epona", kOverlayPresets);
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult build_equipment_colors_tab(
|
||||
ModContext*, UiWindowHandle, UiElementHandle left, UiElementHandle right, void*, ModError*) {
|
||||
svc_ui->pane_add_section(mod_ctx, left, "Color Groups");
|
||||
add_group(left, right, "Hero's Tunic", build_hero_tunic_colors);
|
||||
add_group(left, right, "Zora Armor", build_zora_armor_colors);
|
||||
add_group(left, right, "Swords", build_sword_colors);
|
||||
add_group(left, right, "Equipment", build_equipment_colors);
|
||||
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult build_ui_colors_tab(
|
||||
ModContext*, UiWindowHandle, UiElementHandle left, UiElementHandle right, void*, ModError*) {
|
||||
svc_ui->pane_add_section(mod_ctx, left, "Color Groups");
|
||||
add_group(left, right, "Buttons", build_button_colors);
|
||||
add_group(left, right, "HUD", build_hud_colors);
|
||||
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
ModResult build_misc_colors_tab(
|
||||
ModContext*, UiWindowHandle, UiElementHandle left, UiElementHandle right, void*, ModError*) {
|
||||
svc_ui->pane_add_section(mod_ctx, left, "Hair Presets");
|
||||
add_midna_hair_option(left, g_cvars.midnaHairBaseColor, "Midna's Hair Base Color");
|
||||
add_midna_hair_option(left, g_cvars.midnaHairTipsColor, "Midna's Hair Tips Color");
|
||||
svc_ui->pane_add_section(mod_ctx, left, "Color Groups");
|
||||
add_group(left, right, "Link", build_link_colors);
|
||||
add_group(left, right, "Midna", build_midna_colors);
|
||||
add_group(left, right, "Companions", build_companion_colors);
|
||||
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
void on_cosmetics_menu_window_closed(ModContext*, UiWindowHandle, void*) {
|
||||
g_cosmeticsWindow = 0;
|
||||
}
|
||||
|
||||
void on_open_cosmetics_menu(ModContext*, void*) {
|
||||
if (g_cosmeticsWindow != 0) {
|
||||
return;
|
||||
}
|
||||
UiTabDesc tabs[] = {UI_TAB_DESC_INIT, UI_TAB_DESC_INIT, UI_TAB_DESC_INIT};
|
||||
tabs[0].title = "Equipment";
|
||||
tabs[0].build = build_equipment_colors_tab;
|
||||
tabs[1].title = "Interface";
|
||||
tabs[1].build = build_ui_colors_tab;
|
||||
tabs[2].title = "Characters";
|
||||
tabs[2].build = build_misc_colors_tab;
|
||||
UiWindowDesc desc = UI_WINDOW_DESC_INIT;
|
||||
desc.tabs = tabs;
|
||||
desc.tab_count = ARRAY_SIZE(tabs);
|
||||
desc.on_closed = on_cosmetics_menu_window_closed;
|
||||
if (svc_ui->window_push(mod_ctx, &desc, &g_cosmeticsWindow) != MOD_OK) {
|
||||
svc_log->error(mod_ctx, "failed to open basic cosmetics window");
|
||||
}
|
||||
}
|
||||
|
||||
ModResult build_panel(ModContext*, UiElementHandle panel, void*, ModError*) {
|
||||
UiControlDesc control = UI_CONTROL_DESC_INIT;
|
||||
control.kind = UI_CONTROL_GROUP;
|
||||
control.label = "Open Cosmetics Menu";
|
||||
control.on_pressed = on_open_cosmetics_menu;
|
||||
add_control(panel, control);
|
||||
return MOD_OK;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void load_base_texture_data() {
|
||||
// Go through each texture we can recolor and attempt to load and store
|
||||
// the texture data for future recoloring
|
||||
for (auto& replacements : get_texture_replacements() | std::views::values) {
|
||||
for (auto& replacement : replacements) {
|
||||
// If we've already loaded the texture data, don't load it again
|
||||
if (replacement.loadedTextureData) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Avoid noisy resource lookups until the archive has finished loading.
|
||||
auto* resInfo = dComIfG_getObjectResInfo(replacement.arc);
|
||||
if (resInfo == nullptr || resInfo->getArchive() == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try to get the model this texture is part of. If we can't get it, try again later
|
||||
auto model = static_cast<J3DModelData*>(
|
||||
dComIfG_getObjectRes(replacement.arc, replacement.modelFileName));
|
||||
if (model == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
J3DTexture* tex = model->getTexture();
|
||||
JUTNameTab* nametable = model->getTextureName();
|
||||
if (tex != nullptr && nametable != nullptr) {
|
||||
for (u16 i = 0; i < tex->getNum(); i++) {
|
||||
const char* texName = nametable->getName(i);
|
||||
if (texName != nullptr && std::strcmp(texName, replacement.textureName) == 0) {
|
||||
// Once we've found the texture, set all our TextureKey and TextureData
|
||||
// fields that we can set right now.
|
||||
auto imageHeader = tex->getResTIMG(i);
|
||||
auto& key = replacement.key;
|
||||
auto& data = replacement.data;
|
||||
key.kind = TEXTURE_KEY_SOURCE;
|
||||
key.has_tlut = imageHeader->numColors > 0;
|
||||
key.width = imageHeader->width;
|
||||
key.height = imageHeader->height;
|
||||
key.gx_format = imageHeader->format;
|
||||
|
||||
// Currently, no replaced textures have a tlut
|
||||
key.tlut_hash = replacement.tlutHash;
|
||||
|
||||
// Calculate the size of the image data
|
||||
const uint32_t mipCount =
|
||||
imageHeader->mipmapEnabled ?
|
||||
std::max<uint32_t>(imageHeader->mipmapCount, 1) :
|
||||
1;
|
||||
auto size = get_image_data_size(
|
||||
imageHeader->format, imageHeader->width, imageHeader->height, mipCount);
|
||||
replacement.baseTextureData.resize(size);
|
||||
std::memcpy(
|
||||
replacement.baseTextureData.data(), tex->getImgDataPtr(i), size);
|
||||
|
||||
// Source texture keys hash only the base mip level.
|
||||
const auto baseMipSize = get_image_data_size(
|
||||
imageHeader->format, imageHeader->width, imageHeader->height, 1);
|
||||
auto textureHash =
|
||||
XXH64(replacement.baseTextureData.data(), baseMipSize, 0);
|
||||
replacement.key.texture_hash = textureHash;
|
||||
|
||||
mods::log::debug("Loaded base texture data for {}. size: {:X} hash: {:X}",
|
||||
replacement.textureName, size, textureHash);
|
||||
replacement.loadedTextureData = true;
|
||||
|
||||
data.width = imageHeader->width;
|
||||
data.height = imageHeader->height;
|
||||
data.mip_count = mipCount;
|
||||
data.size = size;
|
||||
data.gx_format = imageHeader->format;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we've loaded all base textures for recoloring, then we don't need to call this function
|
||||
// again
|
||||
g_loadedAllBaseTextures = std::ranges::all_of(
|
||||
get_texture_replacements() | std::views::values, [](auto& replacementList) {
|
||||
return std::ranges::all_of(
|
||||
replacementList, [](const TextureReplacementData& replacement) {
|
||||
return replacement.loadedTextureData;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ModResult check_and_set_recolored_textures() {
|
||||
for (auto& [configVar, replacements] : get_texture_replacements()) {
|
||||
// If the configvar hasn't been set, don't continue
|
||||
if (configVar == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto maybeColor = get_config_var_color(configVar);
|
||||
if (!maybeColor.has_value()) {
|
||||
// An empty or invalid option means the original texture should be restored.
|
||||
for (auto& replacement : replacements) {
|
||||
if (replacement.handle != 0) {
|
||||
auto result = svc_texture->unregister(mod_ctx, replacement.handle);
|
||||
if (result != MOD_OK) {
|
||||
mods::log::debug("Could not unregister replacement for {}. Result: {}",
|
||||
replacement.textureName, static_cast<int>(result));
|
||||
}
|
||||
replacement.handle = 0;
|
||||
}
|
||||
replacement.curColor.reset();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
auto color = maybeColor.value();
|
||||
for (auto& replacement : replacements) {
|
||||
// If we haven't loaded the base texture yet, don't try to recolor it
|
||||
if (!replacement.loadedTextureData) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If our color hasn't changed, don't try to recolor
|
||||
auto& curColor = replacement.curColor;
|
||||
if (curColor == std::nullopt || curColor.value().r != color.r ||
|
||||
curColor.value().g != color.g || curColor.value().b != color.b)
|
||||
{
|
||||
// Make a copy of the base texture data to recolor
|
||||
auto newTexture = replacement.baseTextureData;
|
||||
recolor_texture(replacement, color, newTexture);
|
||||
|
||||
TextureData newTextureData = replacement.data;
|
||||
newTextureData.data = newTexture.data();
|
||||
newTextureData.size = newTexture.size();
|
||||
|
||||
// Keep the current replacement active if registering the new one fails.
|
||||
TextureReplacementHandle newHandle{};
|
||||
auto result = svc_texture->register_data(
|
||||
mod_ctx, &replacement.key, &newTextureData, &newHandle);
|
||||
if (result != MOD_OK) {
|
||||
mods::log::debug("Could not register_data for {}. Result: {}",
|
||||
replacement.textureName, static_cast<int>(result));
|
||||
} else {
|
||||
mods::log::debug("Registered replacement for {}.", replacement.textureName,
|
||||
static_cast<int>(result));
|
||||
auto oldHandle = replacement.handle;
|
||||
replacement.handle = newHandle;
|
||||
curColor = color;
|
||||
|
||||
if (oldHandle != 0) {
|
||||
result = svc_texture->unregister(mod_ctx, oldHandle);
|
||||
if (result != MOD_OK) {
|
||||
mods::log::debug(
|
||||
"Could not unregister previous replacement for {}. Result: {}",
|
||||
replacement.textureName, static_cast<int>(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
void unregister_all_texture_handles() {
|
||||
for (auto& replacements : get_texture_replacements() | std::views::values) {
|
||||
for (auto& replacement : replacements) {
|
||||
if (replacement.handle != 0) {
|
||||
svc_texture->unregister(mod_ctx, replacement.handle);
|
||||
replacement.handle = 0;
|
||||
}
|
||||
replacement.curColor.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define REGISTER_COSMETIC_OPTION(option) \
|
||||
result = register_str_option(#option, NULL, g_cvars.option, error); \
|
||||
if (result != MOD_OK) { \
|
||||
return result; \
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
MOD_EXPORT ModResult mod_initialize(ModError* error) {
|
||||
svc_log->info(mod_ctx, "basic_cosmetics_mod initialized");
|
||||
|
||||
ModResult result{};
|
||||
|
||||
REGISTER_COSMETIC_OPTION(herosTunicCapColor)
|
||||
REGISTER_COSMETIC_OPTION(herosTunicTorsoColor)
|
||||
REGISTER_COSMETIC_OPTION(herosTunicSkirtColor)
|
||||
REGISTER_COSMETIC_OPTION(zoraArmorCapColor)
|
||||
REGISTER_COSMETIC_OPTION(zoraArmorHelmetColor)
|
||||
REGISTER_COSMETIC_OPTION(zoraArmorTorsoColor)
|
||||
REGISTER_COSMETIC_OPTION(zoraArmorScalesColor)
|
||||
REGISTER_COSMETIC_OPTION(zoraArmorFlippersColor)
|
||||
REGISTER_COSMETIC_OPTION(lanternGlowColor)
|
||||
REGISTER_COSMETIC_OPTION(woodenSwordColor)
|
||||
REGISTER_COSMETIC_OPTION(ordonSwordBladeColor)
|
||||
REGISTER_COSMETIC_OPTION(ordonSwordHandleColor)
|
||||
REGISTER_COSMETIC_OPTION(msBladeColor)
|
||||
REGISTER_COSMETIC_OPTION(msHandleColor)
|
||||
REGISTER_COSMETIC_OPTION(lightSwordGlowColor)
|
||||
REGISTER_COSMETIC_OPTION(boomerangColor)
|
||||
REGISTER_COSMETIC_OPTION(ironBootsColor)
|
||||
REGISTER_COSMETIC_OPTION(spinnerColor)
|
||||
REGISTER_COSMETIC_OPTION(aButtonColor)
|
||||
REGISTER_COSMETIC_OPTION(bButtonColor)
|
||||
REGISTER_COSMETIC_OPTION(xButtonColor)
|
||||
REGISTER_COSMETIC_OPTION(yButtonColor)
|
||||
REGISTER_COSMETIC_OPTION(zButtonColor)
|
||||
REGISTER_COSMETIC_OPTION(heartColor)
|
||||
|
||||
result = register_int_option("midnaHairBaseColor", 0, g_cvars.midnaHairBaseColor, error);
|
||||
if (result != MOD_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = register_int_option("midnaHairTipsColor", 0, g_cvars.midnaHairTipsColor, error);
|
||||
if (result != MOD_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
REGISTER_COSMETIC_OPTION(midnaChargeRingColor)
|
||||
REGISTER_COSMETIC_OPTION(linkHairColor)
|
||||
REGISTER_COSMETIC_OPTION(wolfLinkColor)
|
||||
REGISTER_COSMETIC_OPTION(eponaColor)
|
||||
|
||||
UiModsPanelDesc panelDesc = UI_MODS_PANEL_DESC_INIT;
|
||||
panelDesc.build = build_panel;
|
||||
svc_ui->register_mods_panel(mod_ctx, &panelDesc);
|
||||
|
||||
// Add all our hooks
|
||||
result = add_all_hooks();
|
||||
if (result != MOD_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
g_loadedAllBaseTextures = false;
|
||||
g_textureLoadRetryCountdown = 0;
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
MOD_EXPORT ModResult mod_update(ModError*) {
|
||||
update_rainbow_rgb(1.0f);
|
||||
set_all_midna_hair_colors();
|
||||
|
||||
if (!g_loadedAllBaseTextures) {
|
||||
if (g_textureLoadRetryCountdown == 0) {
|
||||
load_base_texture_data();
|
||||
g_textureLoadRetryCountdown = kTextureLoadRetryFrames;
|
||||
} else {
|
||||
--g_textureLoadRetryCountdown;
|
||||
}
|
||||
}
|
||||
|
||||
check_and_set_recolored_textures();
|
||||
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
MOD_EXPORT ModResult mod_shutdown(ModError*) {
|
||||
svc_log->info(mod_ctx, "basic_cosmetics_mod unloaded");
|
||||
g_cosmeticsWindow = 0;
|
||||
remove_all_hooks();
|
||||
unregister_all_texture_handles();
|
||||
get_texture_replacements().clear();
|
||||
g_loadedAllBaseTextures = false;
|
||||
g_textureLoadRetryCountdown = 0;
|
||||
return MOD_OK;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "mods/svc/config.h"
|
||||
#include "mods/svc/texture.h"
|
||||
|
||||
#include <gx.h>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct cvars {
|
||||
ConfigVarHandle herosTunicCapColor = 0;
|
||||
ConfigVarHandle herosTunicTorsoColor = 0;
|
||||
ConfigVarHandle herosTunicSkirtColor = 0;
|
||||
ConfigVarHandle zoraArmorCapColor = 0;
|
||||
ConfigVarHandle zoraArmorHelmetColor = 0;
|
||||
ConfigVarHandle zoraArmorTorsoColor = 0;
|
||||
ConfigVarHandle zoraArmorScalesColor = 0;
|
||||
ConfigVarHandle zoraArmorFlippersColor = 0;
|
||||
ConfigVarHandle lanternGlowColor = 0;
|
||||
ConfigVarHandle woodenSwordColor = 0;
|
||||
ConfigVarHandle ordonSwordBladeColor = 0;
|
||||
ConfigVarHandle ordonSwordHandleColor = 0;
|
||||
ConfigVarHandle msBladeColor = 0;
|
||||
ConfigVarHandle msHandleColor = 0;
|
||||
ConfigVarHandle lightSwordGlowColor = 0;
|
||||
ConfigVarHandle boomerangColor = 0;
|
||||
ConfigVarHandle ironBootsColor = 0;
|
||||
ConfigVarHandle spinnerColor = 0;
|
||||
ConfigVarHandle heartColor = 0;
|
||||
ConfigVarHandle aButtonColor = 0;
|
||||
ConfigVarHandle bButtonColor = 0;
|
||||
ConfigVarHandle xButtonColor = 0;
|
||||
ConfigVarHandle yButtonColor = 0;
|
||||
ConfigVarHandle zButtonColor = 0;
|
||||
ConfigVarHandle midnaHairBaseColor = 0;
|
||||
ConfigVarHandle midnaHairTipsColor = 0;
|
||||
ConfigVarHandle midnaChargeRingColor = 0;
|
||||
ConfigVarHandle linkHairColor = 0;
|
||||
ConfigVarHandle wolfLinkColor = 0;
|
||||
ConfigVarHandle eponaColor = 0;
|
||||
};
|
||||
|
||||
struct TextureReplacementData {
|
||||
const char* arc{};
|
||||
const char* modelFileName{};
|
||||
const char* textureName{};
|
||||
uint64_t textureHash{};
|
||||
uint64_t tlutHash{};
|
||||
TextureKey key = TEXTURE_KEY_INIT;
|
||||
TextureData data = TEXTURE_DATA_INIT;
|
||||
TextureReplacementHandle handle{};
|
||||
std::vector<u8> baseTextureData{};
|
||||
bool loadedTextureData = false;
|
||||
std::optional<GXColor> curColor{};
|
||||
};
|
||||
|
||||
cvars& get_cvars();
|
||||
|
||||
std::string get_str_option(ConfigVarHandle handle, const std::string& fallback);
|
||||
|
||||
int64_t get_int_option(ConfigVarHandle handle, int64_t fallback);
|
||||
|
||||
std::optional<GXColor> get_config_var_color(ConfigVarHandle handle, bool allowRainbow = false);
|
||||
@@ -0,0 +1,682 @@
|
||||
#include "texture_utils.hpp"
|
||||
#include "color_utils.hpp"
|
||||
#include "mod.hpp"
|
||||
|
||||
#include "mods/svc/config.h"
|
||||
#include "mods/svc/log.hpp"
|
||||
|
||||
#include "JSystem/J3DGraphLoader/J3DModelLoader.h"
|
||||
#include "JSystem/JSupport/JSupport.h"
|
||||
#include "JSystem/JUtility/JUTNameTab.h"
|
||||
#include "d/actor/d_a_alink.h"
|
||||
|
||||
static void get_gx_tile_info(uint8_t format, uint32_t& tileWidth, uint32_t& tileHeight, uint32_t& tileSize) {
|
||||
switch (format) {
|
||||
case GX_TF_I8:
|
||||
case GX_TF_IA4:
|
||||
case GX_TF_C8:
|
||||
tileWidth = 8; tileHeight = 4; tileSize = 32;
|
||||
break;
|
||||
case GX_TF_IA8:
|
||||
case GX_TF_RGB565:
|
||||
case GX_TF_RGB5A3:
|
||||
case GX_TF_C14X2:
|
||||
tileWidth = 4; tileHeight = 4; tileSize = 32;
|
||||
break;
|
||||
case GX_TF_RGBA8:
|
||||
tileWidth = 4; tileHeight = 4; tileSize = 64;
|
||||
break;
|
||||
case GX_TF_I4:
|
||||
case GX_TF_C4:
|
||||
case GX_TF_CMPR:
|
||||
default:
|
||||
tileWidth = 8; tileHeight = 8; tileSize = 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t get_image_data_size(uint32_t format, uint32_t width, uint32_t height, uint32_t mipmapCount) {
|
||||
|
||||
uint32_t tileWidth, tileHeight, tileSize;
|
||||
get_gx_tile_info(format, tileWidth, tileHeight, tileSize);
|
||||
|
||||
uint32_t totalSize = 0;
|
||||
|
||||
for (uint8_t i = 0; i < mipmapCount; ++i) {
|
||||
// Round dimensions up to nearest tile boundary
|
||||
uint32_t paddedWidth = (width + tileWidth - 1) & ~(tileWidth - 1);
|
||||
uint32_t paddedHeight = (height + tileHeight - 1) & ~(tileHeight - 1);
|
||||
|
||||
uint32_t tilesX = paddedWidth / tileWidth;
|
||||
uint32_t tilesY = paddedHeight / tileHeight;
|
||||
|
||||
totalSize += tilesX * tilesY * tileSize;
|
||||
|
||||
// Downscale dimensions for next mipmap level
|
||||
width = std::max(1u, width >> 1);
|
||||
height = std::max(1u, height >> 1);
|
||||
}
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
// When left is greater than right
|
||||
// 0b00 points to the left color
|
||||
// 0b01 points to the right color
|
||||
// 0b10 is closer to left color
|
||||
// 0b11 is closer to right color
|
||||
|
||||
// When left is not greater than right
|
||||
// 0b00 points to the left color
|
||||
// 0b01 points to the right color
|
||||
// 0b10 is midway between the colors
|
||||
// 0b11 is transparent
|
||||
|
||||
// That means when maintaining the relative order, if we have to swap the colors:
|
||||
|
||||
// in the case of left being greater than right:
|
||||
// 0b00 will swap to 0b01
|
||||
// 0b01 will swap to 0b00
|
||||
// 0b10 will swap to 0b11
|
||||
// 0b11 will swap to 0b10
|
||||
// So the left bit stays the same, and the right bit changes
|
||||
// Can do xor (^) like 0b01010101 or 0x55 for each u16
|
||||
|
||||
// in the case of left not being greater than right:
|
||||
// 0b00 will swap to 0b01
|
||||
// 0b01 will swap to 0b00
|
||||
// 0b10 will stay the same
|
||||
// 0b11 will stay the same
|
||||
// so if the left bit is a 0, the right bit will change
|
||||
uint32_t swap_index_bits(bool leftIsGreater, uint32_t bits) {
|
||||
if (leftIsGreater) {
|
||||
return bits ^ 0x55555555;
|
||||
}
|
||||
|
||||
const uint32_t mask = ((bits >> 1) & 0x55555555) ^ 0x55555555;
|
||||
return bits ^ mask;
|
||||
}
|
||||
|
||||
void recolor_cmpr_texture(const TextureReplacementData& replacementData, const GXColor color, std::vector<u8>& newTextureDataOut)
|
||||
{
|
||||
uint16_t recolors[0x100];
|
||||
for (int32_t i = 0; i < 0x100; i++) {
|
||||
recolors[i] = blend_overlay_rgb_565(i, color);
|
||||
}
|
||||
|
||||
const uint8_t mipCount = (replacementData.data.mip_count > 0) ? replacementData.data.mip_count : 1;
|
||||
uint32_t mipWidth = replacementData.key.width;
|
||||
uint32_t mipHeight = replacementData.key.height;
|
||||
|
||||
uint8_t* currentAddr = newTextureDataOut.data();
|
||||
|
||||
for (uint8_t mip = 0; mip < mipCount; ++mip) {
|
||||
// Round dimensions up to the nearest 8x8 tile boundary
|
||||
const uint32_t roundedWidth = (mipWidth + 7) & ~7;
|
||||
const uint32_t roundedHeight = (mipHeight + 7) & ~7;
|
||||
|
||||
const uint32_t numBlocks = (roundedWidth / 8) * (roundedHeight / 8);
|
||||
const uint32_t iterations = numBlocks * 4; // 4 CMPR sub-blocks per 8x8 tile
|
||||
|
||||
for (uint32_t i = 0; i < iterations; i++) {
|
||||
auto* rgb565Ptr = reinterpret_cast<BE<uint16_t>*>(currentAddr);
|
||||
|
||||
auto leftRgb565 = rgb565Ptr[0];
|
||||
auto rightRgb565 = rgb565Ptr[1];
|
||||
const bool leftIsGreater = leftRgb565 > rightRgb565;
|
||||
|
||||
const uint32_t leftGrayVal = desaturate_rgb_565(leftRgb565);
|
||||
const uint32_t rightGrayVal = desaturate_rgb_565(rightRgb565);
|
||||
|
||||
uint16_t leftNewRgb565 = recolors[leftGrayVal];
|
||||
uint16_t rightNewRgb565 = recolors[rightGrayVal];
|
||||
|
||||
bool needsBitSwap = false;
|
||||
|
||||
if (leftIsGreater) {
|
||||
if (leftNewRgb565 == rightNewRgb565) {
|
||||
// Need to make sure that subtracting 1 does not mess
|
||||
// everything up. For example, 0x1000 - 1 => 0x0fff which is
|
||||
// a completely different color.
|
||||
if ((leftNewRgb565 & 0x1f) == 0) {
|
||||
// If left value has 0 blue, we change its blue to 1.
|
||||
leftNewRgb565 += 1;
|
||||
}
|
||||
rightNewRgb565 = leftNewRgb565 - 1;
|
||||
}
|
||||
else if (leftNewRgb565 < rightNewRgb565) {
|
||||
needsBitSwap = true;
|
||||
}
|
||||
}
|
||||
else if (leftNewRgb565 > rightNewRgb565) {
|
||||
needsBitSwap = true;
|
||||
}
|
||||
|
||||
if (needsBitSwap) {
|
||||
// The left and right colors are swapping so that their values
|
||||
// are relative in the same way. We need to update the bits
|
||||
// referencing the palette entries to handle the swap.
|
||||
const uint16_t temp = leftNewRgb565;
|
||||
leftNewRgb565 = rightNewRgb565;
|
||||
rightNewRgb565 = temp;
|
||||
|
||||
auto wordPtr = reinterpret_cast<BE<uint32_t>*>(currentAddr);
|
||||
const uint32_t bits = wordPtr[1];
|
||||
|
||||
const uint32_t newBits = swap_index_bits(leftIsGreater, bits);
|
||||
wordPtr[1] = newBits;
|
||||
}
|
||||
|
||||
rgb565Ptr[0] = leftNewRgb565;
|
||||
rgb565Ptr[1] = rightNewRgb565;
|
||||
|
||||
currentAddr += 8;
|
||||
}
|
||||
|
||||
// Halve dimensions for the next mipmap level
|
||||
mipWidth = std::max(1u, mipWidth >> 1);
|
||||
mipHeight = std::max(1u, mipHeight >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
void recolor_rgb5a3_texture(const TextureReplacementData& replacementData, const GXColor color, std::vector<u8>& newTextureDataOut)
|
||||
{
|
||||
// Precompute lookup tables for both RGB555 (opaque) and RGB444 (translucent) modes
|
||||
uint16_t recolors_rgb555[0x100];
|
||||
uint16_t recolors_rgb444[0x100];
|
||||
|
||||
for (int32_t i = 0; i < 0x100; i++) {
|
||||
const uint8_t r = blend_overlay_channel(i, color.r);
|
||||
const uint8_t g = blend_overlay_channel(i, color.g);
|
||||
const uint8_t b = blend_overlay_channel(i, color.b);
|
||||
|
||||
// Pack as RGB555: Bit 15 set to 1 + 5 bits R, G, B
|
||||
recolors_rgb555[i] = 0x8000 | ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
|
||||
|
||||
// Pack as RGB444: 4 bits R, G, B (Bit 15 remains 0)
|
||||
recolors_rgb444[i] = ((r >> 4) << 8) | ((g >> 4) << 4) | (b >> 4);
|
||||
}
|
||||
|
||||
const uint8_t mipCount =
|
||||
replacementData.data.mip_count > 0 ? replacementData.data.mip_count : 1;
|
||||
uint32_t mipWidth = replacementData.key.width;
|
||||
uint32_t mipHeight = replacementData.key.height;
|
||||
auto* pixelPtr = reinterpret_cast<BE<uint16_t>*>(newTextureDataOut.data());
|
||||
|
||||
for (uint8_t mip = 0; mip < mipCount; ++mip) {
|
||||
const uint32_t roundedWidth = (mipWidth + 3) & ~3;
|
||||
const uint32_t roundedHeight = (mipHeight + 3) & ~3;
|
||||
const uint32_t totalPixels = roundedWidth * roundedHeight;
|
||||
|
||||
for (uint32_t i = 0; i < totalPixels; i++) {
|
||||
const uint16_t rawPixel = pixelPtr[i];
|
||||
|
||||
// MSB determines if pixel is opaque or translucent
|
||||
if (rawPixel & 0x8000) {
|
||||
// Pixel is opaque
|
||||
const uint8_t r5 = (rawPixel >> 10) & 0x1F;
|
||||
const uint8_t g5 = (rawPixel >> 5) & 0x1F;
|
||||
const uint8_t b5 = rawPixel & 0x1F;
|
||||
|
||||
// Expand 5-bit to 8-bit
|
||||
const uint8_t r8 = (r5 << 3) | (r5 >> 2);
|
||||
const uint8_t g8 = (g5 << 3) | (g5 >> 2);
|
||||
const uint8_t b8 = (b5 << 3) | (b5 >> 2);
|
||||
|
||||
const uint8_t grayVal = static_cast<uint8_t>((r8 * 77 + g8 * 150 + b8 * 29) >> 8);
|
||||
|
||||
pixelPtr[i] = recolors_rgb555[grayVal];
|
||||
} else {
|
||||
// Pixel is translucent
|
||||
const uint16_t alpha3 = rawPixel & 0x7000;
|
||||
|
||||
const uint8_t r4 = (rawPixel >> 8) & 0x0F;
|
||||
const uint8_t g4 = (rawPixel >> 4) & 0x0F;
|
||||
const uint8_t b4 = rawPixel & 0x0F;
|
||||
|
||||
// Expand 4-bit to 8-bit
|
||||
const uint8_t r8 = (r4 << 4) | r4;
|
||||
const uint8_t g8 = (g4 << 4) | g4;
|
||||
const uint8_t b8 = (b4 << 4) | b4;
|
||||
|
||||
const uint8_t grayVal = static_cast<uint8_t>((r8 * 77 + g8 * 150 + b8 * 29) >> 8);
|
||||
|
||||
// Combine original alpha with recolored RGB444
|
||||
pixelPtr[i] = alpha3 | recolors_rgb444[grayVal];
|
||||
}
|
||||
}
|
||||
|
||||
pixelPtr += totalPixels;
|
||||
mipWidth = std::max(1u, mipWidth >> 1);
|
||||
mipHeight = std::max(1u, mipHeight >> 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to encode a single 4x4 sub-block (16 pixels) into an 8-byte CMPR block
|
||||
static void encode_cmpr_sub_block(uint8_t* dst, const uint8_t pixels[16]) {
|
||||
uint8_t min_val = 255;
|
||||
uint8_t max_val = 0;
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (pixels[i] < min_val) min_val = pixels[i];
|
||||
if (pixels[i] > max_val) max_val = pixels[i];
|
||||
}
|
||||
|
||||
auto intensity_to_rgb565 = [](uint8_t val) -> uint16_t {
|
||||
uint16_t r5 = val >> 3;
|
||||
uint16_t g6 = val >> 2;
|
||||
uint16_t b5 = val >> 3;
|
||||
return static_cast<uint16_t>((r5 << 11) | (g6 << 5) | b5);
|
||||
};
|
||||
|
||||
uint16_t c0_565 = intensity_to_rgb565(max_val);
|
||||
uint16_t c1_565 = intensity_to_rgb565(min_val);
|
||||
uint32_t indices = 0;
|
||||
|
||||
if (max_val > min_val) {
|
||||
// Enforce c0_565 > c1_565 in unsigned 16-bit representation to use 4-color mode
|
||||
if (c0_565 == c1_565) {
|
||||
if ((c0_565 & 0x001F) < 0x001F) {
|
||||
c0_565 += 1;
|
||||
} else {
|
||||
c1_565 -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Interpolated 8-bit intensity values for quantization
|
||||
const int c0 = max_val;
|
||||
const int c1 = min_val;
|
||||
const int c2 = (2 * max_val + min_val) / 3;
|
||||
const int c3 = (max_val + 2 * min_val) / 3;
|
||||
|
||||
// Map each pixel to the nearest palette entry
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
const int p = pixels[i];
|
||||
const int d0 = std::abs(p - c0);
|
||||
const int d1 = std::abs(p - c1);
|
||||
const int d2 = std::abs(p - c2);
|
||||
const int d3 = std::abs(p - c3);
|
||||
|
||||
uint32_t best_idx = 0;
|
||||
int min_d = d0;
|
||||
|
||||
if (d1 < min_d) { min_d = d1; best_idx = 1; }
|
||||
if (d2 < min_d) { min_d = d2; best_idx = 2; }
|
||||
if (d3 < min_d) { min_d = d3; best_idx = 3; }
|
||||
|
||||
indices |= (best_idx << (30 - (2 * i)));
|
||||
}
|
||||
}
|
||||
|
||||
// Account for big endian data expectation
|
||||
dst[0] = static_cast<uint8_t>(c0_565 >> 8);
|
||||
dst[1] = static_cast<uint8_t>(c0_565 & 0xFF);
|
||||
dst[2] = static_cast<uint8_t>(c1_565 >> 8);
|
||||
dst[3] = static_cast<uint8_t>(c1_565 & 0xFF);
|
||||
dst[4] = static_cast<uint8_t>(indices >> 24);
|
||||
dst[5] = static_cast<uint8_t>((indices >> 16) & 0xFF);
|
||||
dst[6] = static_cast<uint8_t>((indices >> 8) & 0xFF);
|
||||
dst[7] = static_cast<uint8_t>(indices & 0xFF);
|
||||
}
|
||||
|
||||
bool convert_i8_to_cmpr(TextureReplacementData& replacementData, std::vector<u8>& cmprOut) {
|
||||
if (cmprOut.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t mipCount = (replacementData.data.mip_count > 0) ? replacementData.data.mip_count : 1;
|
||||
const auto expectedInputSize = get_image_data_size(
|
||||
GX_TF_I8, replacementData.key.width, replacementData.key.height, mipCount);
|
||||
if (cmprOut.size() < expectedInputSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto sourceData = cmprOut;
|
||||
std::vector<u8> convertedData(get_image_data_size(
|
||||
GX_TF_CMPR, replacementData.key.width, replacementData.key.height, mipCount));
|
||||
uint32_t mipWidth = replacementData.key.width;
|
||||
uint32_t mipHeight = replacementData.key.height;
|
||||
|
||||
const uint8_t* readPtr = sourceData.data();
|
||||
uint8_t* writePtr = convertedData.data();
|
||||
|
||||
for (uint8_t mip = 0; mip < mipCount; ++mip) {
|
||||
const uint32_t paddedWidthI8 = (mipWidth + 7) & ~7;
|
||||
const uint32_t paddedHeightI8 = (mipHeight + 3) & ~3;
|
||||
const uint32_t tilesX_I8 = paddedWidthI8 / 8;
|
||||
|
||||
const uint32_t paddedWidthCMPR = (mipWidth + 7) & ~7;
|
||||
const uint32_t paddedHeightCMPR = (mipHeight + 7) & ~7;
|
||||
const uint32_t blocksX_CMPR = paddedWidthCMPR / 8;
|
||||
const uint32_t blocksY_CMPR = paddedHeightCMPR / 8;
|
||||
|
||||
for (uint32_t by = 0; by < blocksY_CMPR; ++by) {
|
||||
for (uint32_t bx = 0; bx < blocksX_CMPR; ++bx) {
|
||||
uint8_t subBlockPixels[4][16]{};
|
||||
|
||||
for (uint32_t subBlockY = 0; subBlockY < 2; ++subBlockY) {
|
||||
for (uint32_t subBlockX = 0; subBlockX < 2; ++subBlockX) {
|
||||
const uint32_t subBlock = subBlockY * 2 + subBlockX;
|
||||
for (uint32_t row = 0; row < 4; ++row) {
|
||||
for (uint32_t col = 0; col < 4; ++col) {
|
||||
const uint32_t x = bx * 8 + subBlockX * 4 + col;
|
||||
const uint32_t y = by * 8 + subBlockY * 4 + row;
|
||||
if (x >= mipWidth || y >= mipHeight) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint32_t tile = (y / 4) * tilesX_I8 + (x / 8);
|
||||
const uint32_t tileOffset = (y % 4) * 8 + (x % 8);
|
||||
subBlockPixels[subBlock][row * 4 + col] =
|
||||
readPtr[tile * 32 + tileOffset];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& subBlockPixel : subBlockPixels) {
|
||||
encode_cmpr_sub_block(writePtr, subBlockPixel);
|
||||
writePtr += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t tilesY_I8 = paddedHeightI8 / 4;
|
||||
readPtr += tilesX_I8 * tilesY_I8 * 32;
|
||||
|
||||
mipWidth = std::max(1u, mipWidth >> 1);
|
||||
mipHeight = std::max(1u, mipHeight >> 1);
|
||||
}
|
||||
|
||||
cmprOut.swap(convertedData);
|
||||
|
||||
// Update format
|
||||
replacementData.data.gx_format = GX_TF_CMPR;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void recolor_texture(TextureReplacementData& replacementData, GXColor color, std::vector<u8>& newTextureDataOut) {
|
||||
|
||||
switch (replacementData.key.gx_format) {
|
||||
case GX_TF_CMPR:
|
||||
recolor_cmpr_texture(replacementData, color, newTextureDataOut);
|
||||
break;
|
||||
case GX_TF_RGB5A3:
|
||||
recolor_rgb5a3_texture(replacementData, color, newTextureDataOut);
|
||||
break;
|
||||
case GX_TF_I8:
|
||||
if (convert_i8_to_cmpr(replacementData, newTextureDataOut)) {
|
||||
recolor_cmpr_texture(replacementData, color, newTextureDataOut);
|
||||
} else {
|
||||
mods::log::debug("Could not convert {} from i8 to cmpr", replacementData.textureName);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<ConfigVarHandle, std::list<TextureReplacementData>>& get_texture_replacements() {
|
||||
static std::unordered_map<ConfigVarHandle, std::list<TextureReplacementData>> replacements{};
|
||||
|
||||
if (replacements.empty()) {
|
||||
replacements = {
|
||||
{get_cvars().herosTunicCapColor, {
|
||||
{
|
||||
.arc = "Kmdl",
|
||||
.modelFileName = "al_head.bmd",
|
||||
.textureName = "al_cap",
|
||||
}
|
||||
}},
|
||||
{get_cvars().herosTunicTorsoColor, {
|
||||
{
|
||||
.arc = "Kmdl",
|
||||
.modelFileName = "al.bmd",
|
||||
.textureName = "al_upbody",
|
||||
}
|
||||
}},
|
||||
{get_cvars().herosTunicSkirtColor, {
|
||||
{
|
||||
.arc = "Kmdl",
|
||||
.modelFileName = "al.bmd",
|
||||
.textureName = "al_lowbody",
|
||||
}
|
||||
}},
|
||||
{get_cvars().zoraArmorCapColor, {
|
||||
{
|
||||
.arc = "Zmdl",
|
||||
.modelFileName = "zl_head.bmd",
|
||||
.textureName = "zl_cap",
|
||||
}
|
||||
}},
|
||||
{get_cvars().zoraArmorHelmetColor, {
|
||||
{
|
||||
.arc = "Zmdl",
|
||||
.modelFileName = "zl_head.bmd",
|
||||
.textureName = "zl_helmet",
|
||||
}
|
||||
}},
|
||||
{get_cvars().zoraArmorTorsoColor, {
|
||||
{
|
||||
.arc = "Zmdl",
|
||||
.modelFileName = "zl.bmd",
|
||||
.textureName = "zl_armor",
|
||||
},
|
||||
{
|
||||
.arc = "Zmdl",
|
||||
.modelFileName = "zl.bmd",
|
||||
.textureName = "zl_armL",
|
||||
}
|
||||
}},
|
||||
{get_cvars().zoraArmorScalesColor, {
|
||||
{
|
||||
.arc = "Zmdl",
|
||||
.modelFileName = "zl.bmd",
|
||||
.textureName = "zl_body",
|
||||
}
|
||||
}},
|
||||
{get_cvars().zoraArmorFlippersColor, {
|
||||
{
|
||||
.arc = "Zmdl",
|
||||
.modelFileName = "zl.bmd",
|
||||
.textureName = "zl_boots",
|
||||
}
|
||||
}},
|
||||
{get_cvars().woodenSwordColor, {
|
||||
{
|
||||
.arc = "Bmdl", // Ordon Clothes Model
|
||||
.modelFileName = "al_swb.bmd",
|
||||
.textureName = "al_SWB",
|
||||
},
|
||||
{
|
||||
.arc = "Kmdl", // Hero's Tunic Model
|
||||
.modelFileName = "al_swb.bmd",
|
||||
.textureName = "al_SWB",
|
||||
},
|
||||
{
|
||||
.arc = "Zmdl", // Zora Armor Model
|
||||
.modelFileName = "al_swb.bmd",
|
||||
.textureName = "al_SWB",
|
||||
},
|
||||
{
|
||||
.arc = "Mmdl", // Magic Armor Model
|
||||
.modelFileName = "al_swb.bmd",
|
||||
.textureName = "al_SWB",
|
||||
},
|
||||
{
|
||||
.arc = "O_gD_SWB", // Get Item Model
|
||||
.modelFileName = "o_gd_al_swb.bmd",
|
||||
.textureName = "al_SWB",
|
||||
}
|
||||
}},
|
||||
{get_cvars().ordonSwordHandleColor, {
|
||||
{
|
||||
.arc = "Alink",
|
||||
.modelFileName = "al_swa.bmd",
|
||||
.textureName = "al_SWgripA",
|
||||
},
|
||||
{
|
||||
.arc = "O_gD_SWA", // Get Item Model
|
||||
.modelFileName = "o_gd_al_swa.bmd",
|
||||
.textureName = "al_SWgripA",
|
||||
}
|
||||
}},
|
||||
{get_cvars().ordonSwordBladeColor, {
|
||||
{
|
||||
.arc = "Alink",
|
||||
.modelFileName = "al_swa.bmd",
|
||||
.textureName = "al_SWA",
|
||||
}
|
||||
}},
|
||||
{get_cvars().msHandleColor, {
|
||||
{
|
||||
.arc = "Alink",
|
||||
.modelFileName = "al_swm.bmd",
|
||||
.textureName = "al_SWgripM",
|
||||
}
|
||||
}},
|
||||
{get_cvars().msBladeColor, {
|
||||
{
|
||||
.arc = "Alink",
|
||||
.modelFileName = "al_swm.bmd",
|
||||
.textureName = "al_SWM",
|
||||
}
|
||||
}},
|
||||
{get_cvars().boomerangColor, {
|
||||
{
|
||||
.arc = "Alink", // Boomerang in Link's hand
|
||||
.modelFileName = "al_boom.bmd",
|
||||
.textureName = "L_al_boom00",
|
||||
},
|
||||
{
|
||||
.arc = "E_mk", // Boomerang in Ook's hand
|
||||
.modelFileName = "bm.bmd",
|
||||
.textureName = "L_al_boom00",
|
||||
},
|
||||
{
|
||||
.arc = "E_mk", // Boomerang in Ook's hand
|
||||
.modelFileName = "bm.bmd",
|
||||
.textureName = "bm_boom",
|
||||
},
|
||||
{
|
||||
.arc = "O_gD_boom", // Get Item Model
|
||||
.modelFileName = "o_gd_boom.bmd",
|
||||
.textureName = "L_al_boom00",
|
||||
}
|
||||
}},
|
||||
{get_cvars().ironBootsColor, {
|
||||
{
|
||||
.arc = "Bmdl", // Ordon Clothes Model
|
||||
.modelFileName = "al_bootsh.bmd",
|
||||
.textureName = "al_bootsH",
|
||||
},
|
||||
{
|
||||
.arc = "Kmdl", // Hero's Tunic Model
|
||||
.modelFileName = "al_bootsh.bmd",
|
||||
.textureName = "al_bootsH",
|
||||
},
|
||||
{
|
||||
.arc = "Zmdl", // Zora Armor Model
|
||||
.modelFileName = "al_bootsh.bmd",
|
||||
.textureName = "al_bootsH",
|
||||
},
|
||||
{
|
||||
.arc = "Mmdl", // Magic Armor Model
|
||||
.modelFileName = "al_bootsh.bmd",
|
||||
.textureName = "al_bootsH",
|
||||
},
|
||||
{
|
||||
.arc = "O_gD_boot", // Get Item Model
|
||||
.modelFileName = "o_gd_al_bootsh.bmd",
|
||||
.textureName = "al_bootsH",
|
||||
}
|
||||
}},
|
||||
{get_cvars().spinnerColor, {
|
||||
{
|
||||
.arc = "Alink", // Spinner used by Link
|
||||
.modelFileName = "al_sp.bmd",
|
||||
.textureName = "al_SP",
|
||||
},
|
||||
{
|
||||
.arc = "O_gD_SP", // Get Item Model
|
||||
.modelFileName = "o_gd_al_sp.bmd",
|
||||
.textureName = "al_SP",
|
||||
}
|
||||
}},
|
||||
{get_cvars().linkHairColor, {
|
||||
{
|
||||
.arc = "Bmdl", // Ordon Clothes Model
|
||||
.modelFileName = "bl_head.bmd",
|
||||
.textureName = "bl_hair",
|
||||
},
|
||||
{
|
||||
.arc = "Kmdl", // Hero's Tunic Model
|
||||
.modelFileName = "al_head.bmd",
|
||||
.textureName = "al_hair",
|
||||
},
|
||||
{
|
||||
.arc = "Mmdl", // Magic Armor Model
|
||||
.modelFileName = "ml_head.bmd",
|
||||
.textureName = "al_hair",
|
||||
}
|
||||
}},
|
||||
{get_cvars().wolfLinkColor, {
|
||||
{
|
||||
.arc = "Wmdl",
|
||||
.modelFileName = "wl.bmd",
|
||||
.textureName = "wl_body",
|
||||
},
|
||||
{
|
||||
.arc = "Wmdl",
|
||||
.modelFileName = "wl.bmd",
|
||||
.textureName = "wl_eye.1",
|
||||
},
|
||||
{
|
||||
.arc = "Wmdl",
|
||||
.modelFileName = "wl.bmd",
|
||||
.textureName = "wl_eye.2",
|
||||
},
|
||||
{
|
||||
.arc = "Wmdl",
|
||||
.modelFileName = "wl.bmd",
|
||||
.textureName = "wl_eye.3",
|
||||
},
|
||||
{
|
||||
.arc = "Wmdl",
|
||||
.modelFileName = "wl.bmd",
|
||||
.textureName = "wl_eye.4",
|
||||
},
|
||||
{
|
||||
.arc = "Wmdl",
|
||||
.modelFileName = "wl.bmd",
|
||||
.textureName = "wl_eye.5",
|
||||
}
|
||||
}},
|
||||
{get_cvars().eponaColor, {
|
||||
{
|
||||
.arc = "Horse",
|
||||
.modelFileName = "hs.bmd",
|
||||
.textureName = "hs_body",
|
||||
},
|
||||
{
|
||||
.arc = "Horse",
|
||||
.modelFileName = "hs.bmd",
|
||||
.textureName = "hs_eye.1",
|
||||
},
|
||||
{
|
||||
.arc = "Horse",
|
||||
.modelFileName = "hs.bmd",
|
||||
.textureName = "hs_eye.2",
|
||||
},
|
||||
{
|
||||
.arc = "Horse",
|
||||
.modelFileName = "hs.bmd",
|
||||
.textureName = "hs_eye.3",
|
||||
},
|
||||
}},
|
||||
};
|
||||
}
|
||||
|
||||
return replacements;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* File originally copied from console TPR with permission from isaac
|
||||
* https://github.com/zsrtp/libtp_rel/blob/master/include/util/texture_utils.h
|
||||
*/
|
||||
|
||||
#include "mod.hpp"
|
||||
|
||||
#include <gx.h>
|
||||
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
|
||||
uint32_t get_image_data_size(
|
||||
uint32_t format, uint32_t width, uint32_t height, uint32_t mipmapCount);
|
||||
|
||||
void recolor_texture(
|
||||
TextureReplacementData& replacementData, GXColor color, std::vector<u8>& newTextureDataOut);
|
||||
|
||||
std::unordered_map<ConfigVarHandle, std::list<TextureReplacementData>>& get_texture_replacements();
|
||||
@@ -177,18 +177,20 @@ MOD_EXPORT ModResult mod_initialize(ModError* outError) {
|
||||
if (result == MOD_OK) {
|
||||
result = add_message(mods::flow::MessageBuilder{kResponseStyle}
|
||||
.text_color(MESSAGE_COLOR_DEFAULT)
|
||||
.text("Hello from ")
|
||||
.text_color(MESSAGE_COLOR_RED)
|
||||
.text("FlowService")
|
||||
.text("Custom ")
|
||||
.text_color(0xFF0000FF)
|
||||
.text("colors")
|
||||
.text_color(MESSAGE_COLOR_DEFAULT)
|
||||
.text(" and even ")
|
||||
.text_color(0x00FF00FF, 0x00FFFFFF)
|
||||
.text("gradients")
|
||||
.text_color(MESSAGE_COLOR_DEFAULT)
|
||||
.text(", ")
|
||||
.player_name()
|
||||
.text("!\n")
|
||||
.character_delay(3)
|
||||
.text("This text is slow. ")
|
||||
.character_delay(0)
|
||||
.pause(12)
|
||||
.text_scale(125)
|
||||
.text_scale(150)
|
||||
.text("Big")
|
||||
.text_scale(100)
|
||||
.text(" text too.")
|
||||
|
||||
@@ -17,5 +17,4 @@ add_mod(shadow_mod
|
||||
SOURCES src/mod.cpp
|
||||
MOD_JSON mod.json
|
||||
RES_DIR res
|
||||
BUNDLE
|
||||
)
|
||||
|
||||
@@ -16,5 +16,4 @@ add_mod(window_demo
|
||||
FEATURES fmt webgpu
|
||||
SOURCES src/logging.cpp src/mod.cpp
|
||||
MOD_JSON mod.json
|
||||
BUNDLE
|
||||
)
|
||||
|
||||
@@ -188,8 +188,6 @@ MOD_EXPORT ModResult mod_initialize(ModError* error) {
|
||||
g_stageHook = 0;
|
||||
return mods::set_error(error, MOD_ERROR, "failed to register mod panel");
|
||||
}
|
||||
|
||||
mods::log::info("auxiliary WebGPU window ready");
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
*, *:before, *:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
popover {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
font-family: "Fira Sans";
|
||||
font-size: 14dp;
|
||||
color: #E0DBC8;
|
||||
border-radius: 14dp;
|
||||
border: 2dp #92875B;
|
||||
background-color: rgba(21, 22, 16, 96%);
|
||||
backdrop-filter: blur(5dp);
|
||||
box-shadow: 0 6dp 24dp 2dp rgba(0, 0, 0, 55%);
|
||||
filter: opacity(0);
|
||||
transform: scale(0.95);
|
||||
transform-origin: center;
|
||||
transition: filter transform 0.15s cubic-in-out;
|
||||
focus: auto;
|
||||
}
|
||||
|
||||
popover[open] {
|
||||
filter: opacity(1);
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
popover.color-picker {
|
||||
width: 280dp;
|
||||
padding: 18dp;
|
||||
gap: 10dp;
|
||||
}
|
||||
|
||||
color-sv {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 240dp;
|
||||
height: 150dp;
|
||||
border-radius: 8dp;
|
||||
box-shadow: rgba(146, 135, 91, 50%) 0 0 0 1dp;
|
||||
drag: drag;
|
||||
focus: auto;
|
||||
}
|
||||
|
||||
color-hue,
|
||||
color-alpha {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: 240dp;
|
||||
height: 14dp;
|
||||
border-radius: 7dp;
|
||||
box-shadow: rgba(146, 135, 91, 50%) 0 0 0 1dp;
|
||||
drag: drag;
|
||||
focus: auto;
|
||||
}
|
||||
|
||||
color-sv:focus-visible,
|
||||
color-hue:focus-visible,
|
||||
color-alpha:focus-visible {
|
||||
box-shadow: #C2A42D 0 0 0 2dp;
|
||||
}
|
||||
|
||||
color-sv.adjusting,
|
||||
color-hue.adjusting,
|
||||
color-alpha.adjusting {
|
||||
box-shadow: #FFFFFF 0 0 0 3dp;
|
||||
}
|
||||
|
||||
color-hue {
|
||||
decorator: linear-gradient(90deg, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);
|
||||
}
|
||||
|
||||
color-cursor {
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 14dp;
|
||||
height: 14dp;
|
||||
border-radius: 7dp;
|
||||
border: 2dp #ffffff;
|
||||
box-shadow: 0 0 4dp 1dp rgba(0, 0, 0, 70%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
color-heading {
|
||||
display: block;
|
||||
margin-top: 2dp;
|
||||
font-family: "Fira Sans Condensed";
|
||||
font-weight: bold;
|
||||
font-size: 13dp;
|
||||
text-transform: uppercase;
|
||||
color: rgba(224, 219, 200, 55%);
|
||||
}
|
||||
|
||||
color-presets {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
gap: 5dp;
|
||||
}
|
||||
|
||||
color-history {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
gap: 5dp;
|
||||
}
|
||||
|
||||
button.color-swatch-button {
|
||||
width: 25dp;
|
||||
height: 25dp;
|
||||
padding: 0;
|
||||
border-radius: 7dp;
|
||||
}
|
||||
|
||||
color-chip {
|
||||
display: block;
|
||||
flex: 0 0 20dp;
|
||||
width: 20dp;
|
||||
height: 20dp;
|
||||
border-radius: 5dp;
|
||||
box-shadow: rgba(255, 255, 255, 45%) 0 0 0 1dp;
|
||||
}
|
||||
|
||||
button.color-swatch-button color-chip {
|
||||
width: 25dp;
|
||||
height: 25dp;
|
||||
border-radius: 7dp;
|
||||
}
|
||||
|
||||
color-chip.empty,
|
||||
color-swatch.empty {
|
||||
background-color: rgba(224, 219, 200, 12%);
|
||||
decorator: linear-gradient(135deg, rgba(224, 219, 200, 0) 45%,
|
||||
rgba(194, 164, 45, 70%) 48%, rgba(194, 164, 45, 70%) 52%,
|
||||
rgba(224, 219, 200, 0) 55%);
|
||||
}
|
||||
|
||||
color-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6dp;
|
||||
padding-top: 2dp;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: rgba(17, 16, 10, 35%);
|
||||
padding: 4dp 8dp;
|
||||
border-radius: 8dp;
|
||||
box-shadow: rgba(146, 135, 91, 30%) 0 0 0 1dp;
|
||||
color: #E0DBC8;
|
||||
cursor: pointer;
|
||||
focus: auto;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
button:focus-visible {
|
||||
background-color: rgba(204, 184, 119, 20%);
|
||||
box-shadow: #C2A42D 0 0 0 2dp;
|
||||
}
|
||||
|
||||
button:active {
|
||||
background-color: rgba(204, 184, 119, 40%);
|
||||
}
|
||||
|
||||
color-value {
|
||||
display: block;
|
||||
flex: 1 1 auto;
|
||||
text-align: right;
|
||||
font-family: "Noto Mono";
|
||||
font-size: 12dp;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
focus: auto;
|
||||
}
|
||||
|
||||
color-value:hover,
|
||||
color-value:focus-visible {
|
||||
color: #C2A42D;
|
||||
}
|
||||
+177
-12
@@ -48,6 +48,12 @@ window.modal {
|
||||
max-width: 640dp;
|
||||
}
|
||||
|
||||
@media (max-height: 896dp) {
|
||||
window.modal {
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
window[open] {
|
||||
filter: opacity(1);
|
||||
transform: scale(1);
|
||||
@@ -62,6 +68,16 @@ window[open] {
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768dp) {
|
||||
body {
|
||||
padding: 16dp;
|
||||
}
|
||||
window.modal {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
window tab-bar {
|
||||
flex: 0 0 64dp;
|
||||
height: 64dp;
|
||||
@@ -91,7 +107,6 @@ window content pane {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 24dp;
|
||||
padding-bottom: 0dp;
|
||||
gap: 8dp;
|
||||
overflow: hidden auto;
|
||||
font-size: 20dp;
|
||||
@@ -105,6 +120,76 @@ window content pane > * {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
ui-list {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
window content pane > ui-list,
|
||||
.modal-content pane > ui-list {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
ui-list-viewport {
|
||||
display: block;
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
overflow: hidden auto;
|
||||
}
|
||||
|
||||
ui-list-content {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 8dp;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
ui-list-content > button.ui-list-row {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
ui-list-empty {
|
||||
display: block;
|
||||
padding: 16dp;
|
||||
text-align: center;
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
window content pane > ui-list {
|
||||
margin-left: -24dp;
|
||||
margin-right: -24dp;
|
||||
}
|
||||
|
||||
window content pane > ui-list:first-child {
|
||||
margin-top: -24dp;
|
||||
}
|
||||
|
||||
window content pane > ui-list:last-child {
|
||||
margin-bottom: -24dp;
|
||||
}
|
||||
|
||||
window content pane > ui-list ui-list-content,
|
||||
window content pane > ui-list ui-list-empty {
|
||||
padding-left: 24dp;
|
||||
padding-right: 24dp;
|
||||
}
|
||||
|
||||
window content pane > ui-list:first-child ui-list-content,
|
||||
window content pane > ui-list:first-child ui-list-empty {
|
||||
padding-top: 24dp;
|
||||
}
|
||||
|
||||
window content pane > ui-list:last-child ui-list-content,
|
||||
window content pane > ui-list:last-child ui-list-empty {
|
||||
padding-bottom: 24dp;
|
||||
}
|
||||
|
||||
window content pane:last-of-type > div {
|
||||
line-height: 1.625;
|
||||
}
|
||||
@@ -115,14 +200,6 @@ window content pane:last-of-type > div {
|
||||
color: rgba(224, 219, 200, 65%);
|
||||
}
|
||||
|
||||
window content pane > spacer {
|
||||
display: block;
|
||||
/* Completes the 24dp bottom inset after the pane's 8dp gap. */
|
||||
flex: 0 0 16dp;
|
||||
height: 16dp;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
scrollbarvertical {
|
||||
width: 8dp;
|
||||
margin: 4dp 4dp 4dp 0;
|
||||
@@ -278,6 +355,40 @@ select-button input {
|
||||
font-size: 20dp;
|
||||
}
|
||||
|
||||
select-button.group-button icon {
|
||||
flex: 0 0 24dp;
|
||||
margin-left: auto;
|
||||
width: 24dp;
|
||||
height: 24dp;
|
||||
font-size: 24dp;
|
||||
color: inherit;
|
||||
decorator: text("" center center);
|
||||
}
|
||||
|
||||
select-button.group-button value {
|
||||
display: none;
|
||||
}
|
||||
|
||||
select-button.color-input value {
|
||||
min-width: 0;
|
||||
font-family: "Noto Mono";
|
||||
font-size: 15dp;
|
||||
}
|
||||
|
||||
select-button.color-input color-swatch {
|
||||
display: block;
|
||||
flex: 0 0 48dp;
|
||||
width: 48dp;
|
||||
height: 24dp;
|
||||
border-radius: 7dp;
|
||||
box-shadow: rgba(255, 255, 255, 45%) 0 0 0 1dp;
|
||||
}
|
||||
|
||||
select-button.color-input color-swatch.empty {
|
||||
background-color: rgba(224, 219, 200, 12%);
|
||||
decorator: linear-gradient(135deg, rgba(224, 219, 200, 0) 45%, rgba(194, 164, 45, 70%) 48%, rgba(194, 164, 45, 70%) 52%, rgba(224, 219, 200, 0) 55%);
|
||||
}
|
||||
|
||||
icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
@@ -385,14 +496,17 @@ progress {
|
||||
margin: 6dp 0 2dp 0;
|
||||
}
|
||||
|
||||
progress fill {
|
||||
background-color: rgba(194, 164, 45, 80%);
|
||||
border-radius: 3dp;
|
||||
}
|
||||
|
||||
progress.progress-done fill {
|
||||
background-color: #44aa22;
|
||||
border-radius: 3dp;
|
||||
}
|
||||
|
||||
progress.progress-ongoing fill {
|
||||
background-color: #2255bb;
|
||||
border-radius: 3dp;
|
||||
}
|
||||
|
||||
button.achievement-clear {
|
||||
@@ -432,7 +546,9 @@ button.achievement-clear {
|
||||
padding: 24dp;
|
||||
gap: 20dp;
|
||||
flex: 0 1 auto;
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@@ -473,7 +589,7 @@ window.modal.danger .modal-header icon {
|
||||
.modal-body {
|
||||
display: block;
|
||||
width: 100%;
|
||||
flex: 0 1 auto;
|
||||
flex: 0 0 auto;
|
||||
min-width: 0;
|
||||
font-size: 20dp;
|
||||
color: #FFFFFF;
|
||||
@@ -485,6 +601,33 @@ window.modal.danger .modal-header icon {
|
||||
color: #92875B;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
display: none;
|
||||
width: 100%;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modal-content.active {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.modal-content pane {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
gap: 8dp;
|
||||
overflow: hidden auto;
|
||||
}
|
||||
|
||||
.modal-content pane > * {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.verification-progress {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -529,3 +672,25 @@ progress.verification-progress-bar {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media (max-height: 640dp) {
|
||||
.modal-dialog {
|
||||
padding: 16dp;
|
||||
gap: 12dp;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
font-size: 17dp;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640dp) {
|
||||
.modal-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.modal-actions button.modal-btn {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* ItemService check names.
|
||||
*/
|
||||
|
||||
#define ITEM_CHECK_BOSS_PREFIX "boss:" /* <stage> */
|
||||
#define ITEM_CHECK_BUG_PREFIX "bug:" /* <insect_item> */
|
||||
#define ITEM_CHECK_CHEST_PREFIX "chest:" /* <stage>:<box> */
|
||||
#define ITEM_CHECK_FREESTANDING_PREFIX "freestanding:" /* <stage>:<bit> */
|
||||
#define ITEM_CHECK_GOLDEN_WOLF_PREFIX "golden_wolf:" /* <event_flag> */
|
||||
#define ITEM_CHECK_POE_PREFIX "poe:" /* <stage>:<switch> */
|
||||
#define ITEM_CHECK_SHOP_PREFIX "shop:" /* <stage>:<item> */
|
||||
#define ITEM_CHECK_SKY_PREFIX "sky:" /* <stage>:<room> */
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_PREFIX "dungeon_reward:" /* <stage> */
|
||||
|
||||
#define ITEM_CHECK_ARCHERY_REWARD "archery_reward:F_SP109"
|
||||
#define ITEM_CHECK_ASHEI_SKETCH "ashei_sketch"
|
||||
#define ITEM_CHECK_AURU_MEMO "auru_memo"
|
||||
#define ITEM_CHECK_BALL_AND_CHAIN "ball_and_chain:D_MN11"
|
||||
#define ITEM_CHECK_BULBLIN_KEY "bulblin_key:D_MN09"
|
||||
#define ITEM_CHECK_CORAL_EARRING "coral_earring"
|
||||
#define ITEM_CHECK_CORO_BOTTLE "coro_bottle"
|
||||
#define ITEM_CHECK_DUNGEON_MAP_SNOWPEAK "dungeon_map:D_MN11"
|
||||
#define ITEM_CHECK_FAIRY_REWARD "fairy_reward:D_SB01"
|
||||
#define ITEM_CHECK_FISHING_BOTTLE "fishing_bottle"
|
||||
#define ITEM_CHECK_FISHING_HEART_PIECE "fishing_heart_piece"
|
||||
#define ITEM_CHECK_GOATS_REWARD "goats_reward"
|
||||
#define ITEM_CHECK_GORON_REWARD "goron_reward:F_SP113"
|
||||
#define ITEM_CHECK_GORON_SPRINGWATER_RUSH "goron_springwater_rush"
|
||||
#define ITEM_CHECK_ILIA_CHARM "ilia_charm"
|
||||
#define ITEM_CHECK_ILIA_MEMORY "ilia_memory"
|
||||
#define ITEM_CHECK_IZA_REWARD_1 "iza_reward_1"
|
||||
#define ITEM_CHECK_IZA_REWARD_2 "iza_reward_2"
|
||||
#define ITEM_CHECK_JOVANI_REWARD_1 "jovani_reward_1"
|
||||
#define ITEM_CHECK_JOVANI_REWARD_2 "jovani_reward_2"
|
||||
#define ITEM_CHECK_KEY_SHARD_1 "key_shard_1:D_MN04"
|
||||
#define ITEM_CHECK_KEY_SHARD_2 "key_shard_2:D_MN04"
|
||||
#define ITEM_CHECK_KEY_SHARD_3 "key_shard_3:D_MN04"
|
||||
#define ITEM_CHECK_ORDON_SHIELD "ordon_shield"
|
||||
#define ITEM_CHECK_ORDON_SWORD "ordon_sword"
|
||||
#define ITEM_CHECK_PLUMM_REWARD "plumm_minigame_reward"
|
||||
#define ITEM_CHECK_PRAYER_REWARD "prayer_reward"
|
||||
#define ITEM_CHECK_RENADO_LETTER "renado_letter"
|
||||
#define ITEM_CHECK_SERA_REWARD "sera_reward"
|
||||
#define ITEM_CHECK_SHAD_DOMINION_ROD "shad_dominion_rod"
|
||||
#define ITEM_CHECK_SKYBOOK "skybook"
|
||||
#define ITEM_CHECK_SNOWBOARD_REWARD "snowboard_race_reward"
|
||||
#define ITEM_CHECK_STAR_REWARD_1 "star_reward_1"
|
||||
#define ITEM_CHECK_STAR_REWARD_2 "star_reward_2"
|
||||
#define ITEM_CHECK_TELMA_INVOICE "telma_invoice"
|
||||
#define ITEM_CHECK_ULI_CRADLE_REWARD "uli_cradle_reward"
|
||||
#define ITEM_CHECK_WOOD_STATUE "wood_statue"
|
||||
#define ITEM_CHECK_ZORA_ARMOR "zora_armor"
|
||||
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_FOREST "dungeon_reward:D_MN05"
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_GORON "dungeon_reward:D_MN04"
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_LAKEBED "dungeon_reward:D_MN01"
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_ARBITERS "dungeon_reward:D_MN10"
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_SNOWPEAK "dungeon_reward:D_MN11"
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_TIME "dungeon_reward:D_MN06"
|
||||
#define ITEM_CHECK_DUNGEON_REWARD_CITY "dungeon_reward:D_MN07"
|
||||
|
||||
#define ITEM_CHECK_MASTER_SWORD "master_sword"
|
||||
#define ITEM_CHECK_SHADOW_CRYSTAL "shadow_crystal"
|
||||
@@ -100,6 +100,7 @@ public:
|
||||
NodeRef next(uint16_t target) const;
|
||||
/* Set a branch node's result targets */
|
||||
NodeRef results(std::initializer_list<uint16_t> targets) const;
|
||||
NodeRef results(std::span<const uint16_t> targets) const;
|
||||
|
||||
uint16_t id() const { return mId; }
|
||||
operator uint16_t() const { return mId; }
|
||||
@@ -153,6 +154,35 @@ public:
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
GraphBuilder& patch_branch(uint16_t nodeIndex, FlowQueryId query, uint16_t parameter,
|
||||
std::span<const uint16_t> targets) {
|
||||
if (mResult != MOD_OK || targets.empty() || targets.size() > 0xff) {
|
||||
if (mResult == MOD_OK) {
|
||||
mResult = MOD_INVALID_ARGUMENT;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
uint16_t first = 0;
|
||||
mResult = svc_flow->add_edges(
|
||||
mod_ctx, mHandle, targets.data(), static_cast<uint16_t>(targets.size()), &first);
|
||||
if (mResult == MOD_OK) {
|
||||
patch_node(nodeIndex,
|
||||
branch(static_cast<uint8_t>(targets.size()), query, parameter, first));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
GraphBuilder& patch_event(uint16_t nodeIndex, FlowEventId eventId,
|
||||
std::array<uint8_t, 4> params, uint16_t target) {
|
||||
if (mResult != MOD_OK) {
|
||||
return *this;
|
||||
}
|
||||
uint16_t edge = 0;
|
||||
mResult = svc_flow->add_edges(mod_ctx, mHandle, &target, 1, &edge);
|
||||
if (mResult == MOD_OK) {
|
||||
patch_node(nodeIndex, event(eventId, edge, params));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Graph commit() {
|
||||
for (const auto& node : mNodes) {
|
||||
@@ -232,7 +262,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void set_results(uint16_t id, std::initializer_list<uint16_t> targets) {
|
||||
void set_results(uint16_t id, std::span<const uint16_t> targets) {
|
||||
if (mResult != MOD_OK) {
|
||||
return;
|
||||
}
|
||||
@@ -246,7 +276,7 @@ private:
|
||||
node->wired = true;
|
||||
uint16_t first = 0;
|
||||
mResult = svc_flow->add_edges(
|
||||
mod_ctx, mHandle, targets.begin(), static_cast<uint16_t>(targets.size()), &first);
|
||||
mod_ctx, mHandle, targets.data(), static_cast<uint16_t>(targets.size()), &first);
|
||||
if (mResult == MOD_OK) {
|
||||
node->data.bytes[1] = static_cast<uint8_t>(targets.size());
|
||||
write_bits(node->data.bytes + 6, first);
|
||||
@@ -266,6 +296,10 @@ inline NodeRef NodeRef::next(uint16_t target) const {
|
||||
}
|
||||
|
||||
inline NodeRef NodeRef::results(std::initializer_list<uint16_t> targets) const {
|
||||
return results(std::span{targets.begin(), targets.size()});
|
||||
}
|
||||
|
||||
inline NodeRef NodeRef::results(std::span<const uint16_t> targets) const {
|
||||
if (mBuilder != nullptr) {
|
||||
mBuilder->set_results(mId, targets);
|
||||
}
|
||||
@@ -368,6 +402,10 @@ public:
|
||||
[[nodiscard]] constexpr MessageStyle face_anim(uint8_t value) const {
|
||||
return set_u8(17, value);
|
||||
}
|
||||
/* INF1 bytes 18-19, normally 0x0400. */
|
||||
[[nodiscard]] constexpr MessageStyle trailing_data(uint16_t value) const {
|
||||
return set_u16(18, value);
|
||||
}
|
||||
[[nodiscard]] constexpr const MessageEntryData& data() const { return mData; }
|
||||
|
||||
private:
|
||||
@@ -432,6 +470,9 @@ public:
|
||||
MessageBuilder& camera_attr(uint8_t value) { return style(&MessageStyle::camera_attr, value); }
|
||||
MessageBuilder& talk_anim(uint8_t value) { return style(&MessageStyle::talk_anim, value); }
|
||||
MessageBuilder& face_anim(uint8_t value) { return style(&MessageStyle::face_anim, value); }
|
||||
MessageBuilder& trailing_data(uint16_t value) {
|
||||
return style(&MessageStyle::trailing_data, value);
|
||||
}
|
||||
|
||||
/* Content builder functions */
|
||||
MessageBuilder& text(std::string_view value) {
|
||||
@@ -459,7 +500,20 @@ public:
|
||||
}
|
||||
MessageBuilder& text_color(MessageTextColor color) {
|
||||
const auto index = static_cast<uint8_t>(color);
|
||||
return raw_tag(255, 0, {&index, 1});
|
||||
return raw_tag(0xFF, 0, {&index, 1});
|
||||
}
|
||||
/* Full 32-bit text color (Dusklight extension) */
|
||||
MessageBuilder& text_color(uint32_t rgba) {
|
||||
std::array<uint8_t, 4> arguments{};
|
||||
write_bits(arguments.data(), rgba);
|
||||
return raw_tag(0xFF, 0, arguments);
|
||||
}
|
||||
/* Full 32-bit text vertical gradient colors (Dusklight extension) */
|
||||
MessageBuilder& text_color(uint32_t upperRgba, uint32_t lowerRgba) {
|
||||
std::array<uint8_t, 8> arguments{};
|
||||
write_bits(arguments.data(), upperRgba);
|
||||
write_bits(arguments.data() + sizeof(upperRgba), lowerRgba);
|
||||
return raw_tag(0xFF, 0, arguments);
|
||||
}
|
||||
MessageBuilder& text_scale(uint16_t percent) { return timed_tag(255, 1, percent); }
|
||||
MessageBuilder& character_delay(uint16_t frames) { return timed_tag(0, 6, frames); }
|
||||
|
||||
+18
-10
@@ -8,7 +8,7 @@
|
||||
|
||||
#define ITEM_SERVICE_ID "dev.twilitrealm.dusklight.item"
|
||||
#define ITEM_SERVICE_MAJOR 2u
|
||||
#define ITEM_SERVICE_MINOR 0u
|
||||
#define ITEM_SERVICE_MINOR 1u
|
||||
|
||||
/* 0 is never a valid handle. */
|
||||
typedef uint64_t ItemCheckHandle;
|
||||
@@ -17,10 +17,12 @@ typedef uint64_t ItemGiveHandle;
|
||||
/*
|
||||
* Item check resolution and inventory grants.
|
||||
*
|
||||
* Check names are case-sensitive. Resolvers must be free of side effects because the game may
|
||||
* resolve a check more than once, including once for display and again when granting the item.
|
||||
* Registrations and pending grants are removed when the calling mod is detached. Callbacks run
|
||||
* on the game thread.
|
||||
* Check names are case-sensitive. Resolvers must be free of side effects because previews may be
|
||||
* resolved repeatedly. For checks representing a non-item side effect, vanilla_item is 0xFF:
|
||||
* resolving to 0xFF preserves that side effect, while resolving to another item replaces it.
|
||||
*
|
||||
* Registrations and pending grants are removed when the calling mod is detached. Callbacks run on
|
||||
* the game thread. Check names are listed in <mods/items.h>.
|
||||
*/
|
||||
|
||||
/* Host-owned callback data, valid only for the duration of the callback. */
|
||||
@@ -29,11 +31,17 @@ typedef struct ItemCheckInfo {
|
||||
const void* giver_actor; /* fopAc_ac_c*, or NULL when unavailable */
|
||||
uint8_t vanilla_item;
|
||||
uint8_t current_item;
|
||||
uint8_t current_display_item;
|
||||
} ItemCheckInfo;
|
||||
|
||||
/* Return true and write out_item to replace current_item, or false to leave it unchanged. */
|
||||
typedef struct ItemCheckResolution {
|
||||
uint8_t item;
|
||||
uint8_t display_item; /* leave unset (0xFF/NONE) to use the item */
|
||||
} ItemCheckResolution;
|
||||
|
||||
/* Return true and write out_result to replace the result, or false to leave it unchanged. */
|
||||
typedef bool (*ItemCheckResolveFn)(
|
||||
ModContext* ctx, const ItemCheckInfo* info, uint8_t* out_item, void* user_data);
|
||||
ModContext* ctx, const ItemCheckInfo* info, ItemCheckResolution* out_result, void* user_data);
|
||||
|
||||
typedef enum ItemGiveOrigin {
|
||||
ITEM_GIVE_ORIGIN_GAME = 0,
|
||||
@@ -72,14 +80,14 @@ typedef struct ItemService {
|
||||
|
||||
ModResult (*clear_check_resolver)(ModContext* ctx, ItemCheckHandle handle);
|
||||
|
||||
/* Resolve without granting an item or notifying give observers. */
|
||||
/* Resolve a live preview without granting an item or notifying give observers. */
|
||||
ModResult (*resolve_check)(
|
||||
ModContext* ctx, const char* name, uint8_t vanilla_item, uint8_t* out_item);
|
||||
|
||||
/*
|
||||
* Add a grant to the global FIFO. check_name may be NULL unless ITEM_GIVE_RESOLVE is set.
|
||||
* Returns MOD_UNAVAILABLE when the queue is full. Entries wait until gameplay is in a safe
|
||||
* state and are cleared when the active save slot changes.
|
||||
* Entries wait until gameplay is in a safe state and are cleared when the active save slot
|
||||
* changes.
|
||||
*/
|
||||
ModResult (*give_item)(
|
||||
ModContext* ctx, const char* check_name, uint8_t item_no, uint32_t flags);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#define MESSAGE_SERVICE_ID "dev.twilitrealm.dusklight.message"
|
||||
#define MESSAGE_SERVICE_MAJOR 1u
|
||||
#define MESSAGE_SERVICE_MINOR 0u
|
||||
#define MESSAGE_SERVICE_MINOR 1u
|
||||
|
||||
typedef uint16_t MessageId;
|
||||
typedef uint64_t MessageHandle;
|
||||
|
||||
+96
-24
@@ -8,8 +8,8 @@
|
||||
#endif
|
||||
|
||||
#define UI_SERVICE_ID "dev.twilitrealm.dusklight.ui"
|
||||
#define UI_SERVICE_MAJOR 1u
|
||||
#define UI_SERVICE_MINOR 2u
|
||||
#define UI_SERVICE_MAJOR 2u
|
||||
#define UI_SERVICE_MINOR 1u
|
||||
|
||||
/*
|
||||
* UI primitives: a panel inside the host Mods window, mod-owned windows, dialogs, toasts,
|
||||
@@ -51,6 +51,8 @@ typedef enum UiControlKind {
|
||||
UI_CONTROL_NUMBER = 2, /* integer stepper with min/max/step */
|
||||
UI_CONTROL_STRING = 3, /* text input */
|
||||
UI_CONTROL_SELECT = 4, /* one of `options`; the value is the option index */
|
||||
UI_CONTROL_COLOR = 5, /* RGB/RGBA color string with a picker */
|
||||
UI_CONTROL_GROUP = 6, /* navigation row (on_pressed) */
|
||||
} UiControlKind;
|
||||
|
||||
typedef enum UiControlBinding {
|
||||
@@ -60,14 +62,19 @@ typedef enum UiControlBinding {
|
||||
/* The control reads and writes `config_var` (a ConfigService handle owned by the calling mod)
|
||||
* directly: persistence, change notifications and the modified indicator (value != default) are
|
||||
* wired automatically. The var type must match the control kind: TOGGLE = bool, NUMBER and
|
||||
* SELECT = int, STRING = string. Float vars are not bindable; use callbacks. */
|
||||
* SELECT = int, STRING and COLOR = string. Float vars are not bindable; use callbacks. */
|
||||
UI_BINDING_CONFIG_VAR = 1,
|
||||
} UiControlBinding;
|
||||
|
||||
typedef enum UiStringSetMode {
|
||||
UI_STRING_SET_ON_COMMIT = 0, /* invokes `set` when input is committed */
|
||||
UI_STRING_SET_ON_CHANGE = 1, /* invokes `set` on every text change (e.g. while typing) */
|
||||
} UiStringSetMode;
|
||||
|
||||
/* Tagged by the control's kind: TOGGLE reads bool_value, NUMBER and SELECT read int_value, STRING
|
||||
* reads string_value. string_value passed to a setter is only valid during the call; a getter
|
||||
* should point it at storage owned by the mod (e.g. a static buffer) that stays valid until the
|
||||
* next call into the mod — the host copies it right after the getter returns. */
|
||||
* and COLOR read string_value. string_value passed to a setter is only valid during the call; a
|
||||
* getter should point it at storage owned by the mod (e.g. a static buffer) that stays valid until
|
||||
* the next call into the mod — the host copies it right after the getter returns. */
|
||||
typedef struct UiControlValue {
|
||||
uint32_t struct_size;
|
||||
bool bool_value;
|
||||
@@ -91,16 +98,16 @@ typedef struct UiControlDesc {
|
||||
/* Optional RML shown as contextual help when the control is focused or hovered. Only rendered
|
||||
* where a help pane exists (mod window tabs). */
|
||||
const char* help_rml;
|
||||
UiControlBinding binding; /* ignored for BUTTON */
|
||||
UiControlBinding binding; /* ignored for BUTTON and GROUP */
|
||||
ConfigVarHandle config_var; /* UI_BINDING_CONFIG_VAR */
|
||||
UiControlGetFn get; /* UI_BINDING_CALLBACKS (all kinds but BUTTON) */
|
||||
UiControlSetFn set; /* UI_BINDING_CALLBACKS (all kinds but BUTTON) */
|
||||
UiPressedFn on_pressed; /* BUTTON only. Required for BUTTON. */
|
||||
UiControlGetFn get; /* UI_BINDING_CALLBACKS (all kinds but BUTTON/GROUP) */
|
||||
UiControlSetFn set; /* UI_BINDING_CALLBACKS (all kinds but BUTTON/GROUP) */
|
||||
UiPressedFn on_pressed; /* BUTTON/GROUP only. Required for both. */
|
||||
UiPredicateFn is_disabled; /* optional */
|
||||
/* Optional override for the modified indicator. CONFIG_VAR controls derive it from value !=
|
||||
* default when this is NULL. */
|
||||
UiPredicateFn is_modified;
|
||||
/* Passed to every callback above. */
|
||||
/* Passed to every callback. */
|
||||
void* user_data;
|
||||
/* NUMBER: inclusive clamp range and step. min == max means the defaults (0 .. INT32_MAX); step
|
||||
* < 1 means 1. */
|
||||
@@ -115,17 +122,56 @@ typedef struct UiControlDesc {
|
||||
const char* const* options;
|
||||
size_t option_count;
|
||||
int32_t max_length; /* STRING: maximum input length; < 1 means unlimited */
|
||||
/* COLOR: optional RRGGBB/RRGGBBAA values for presets. "rainbow" is a special value. */
|
||||
const char* const* color_presets;
|
||||
size_t color_preset_count;
|
||||
bool color_alpha; /* COLOR: use RRGGBBAA values instead of RRGGBB */
|
||||
UiPredicateFn is_selected; /* BUTTON/GROUP: optional selected state */
|
||||
UiStringSetMode string_set_mode; /* STRING: when to invoke the setter */
|
||||
} UiControlDesc;
|
||||
|
||||
#define UI_CONTROL_DESC_INIT \
|
||||
{sizeof(UiControlDesc), UI_CONTROL_BUTTON, NULL, NULL, UI_BINDING_CALLBACKS, 0u, NULL, NULL, \
|
||||
NULL, NULL, NULL, NULL, 0, 0, 1, NULL, NULL, NULL, 0u, 0}
|
||||
NULL, NULL, NULL, NULL, 0, 0, 1, NULL, NULL, NULL, 0u, 0, NULL, 0u, false, NULL, \
|
||||
UI_STRING_SET_ON_COMMIT}
|
||||
|
||||
typedef uint64_t UiListHandle;
|
||||
|
||||
/* Must be initialized with UI_LIST_ITEM_INIT */
|
||||
typedef struct UiListItem {
|
||||
uint32_t struct_size;
|
||||
uint64_t key; /* required; unique, stable item key */
|
||||
const char* label; /* required; visible item text */
|
||||
} UiListItem;
|
||||
|
||||
#define UI_LIST_ITEM_INIT {sizeof(UiListItem), 0u, NULL}
|
||||
|
||||
typedef void (*UiListPressedFn)(
|
||||
ModContext* ctx, UiListHandle list, uint64_t item_key, void* user_data);
|
||||
typedef bool (*UiListPredicateFn)(
|
||||
ModContext* ctx, UiListHandle list, uint64_t item_key, void* user_data);
|
||||
|
||||
/* Must be initialized with UI_LIST_DESC_INIT */
|
||||
typedef struct UiListDesc {
|
||||
uint32_t struct_size;
|
||||
const UiListItem* items; /* optional; initial set of items */
|
||||
size_t item_count;
|
||||
UiListPressedFn on_pressed; /* required */
|
||||
UiListPredicateFn is_selected; /* optional; polled only for render-visible rows */
|
||||
UiListPredicateFn is_disabled; /* optional; polled only for render-visible rows */
|
||||
void* user_data;
|
||||
} UiListDesc;
|
||||
|
||||
#define UI_LIST_DESC_INIT {sizeof(UiListDesc), NULL, 0u, NULL, NULL, NULL, NULL}
|
||||
|
||||
/* Build pane contents. A non-MOD_OK result fails the mod. */
|
||||
typedef ModResult (*UiPaneBuildFn)(
|
||||
ModContext* ctx, UiElementHandle pane, void* user_data, ModError* out_error);
|
||||
|
||||
/* Build the panel contents. `panel` accepts the pane_add_* functions; it and
|
||||
* every element created in it are destroyed (handles invalidated) whenever the
|
||||
* panel is rebuilt, e.g. on tab switches. A non-MOD_OK result fails the mod. */
|
||||
typedef ModResult (*UiPanelBuildFn)(
|
||||
ModContext* ctx, UiElementHandle panel, void* user_data, ModError* out_error);
|
||||
typedef UiPaneBuildFn UiPanelBuildFn;
|
||||
/* Called every frame while the panel is the visible tab. */
|
||||
typedef ModResult (*UiPanelUpdateFn)(ModContext* ctx, void* user_data, ModError* out_error);
|
||||
|
||||
@@ -139,6 +185,19 @@ typedef struct UiModsPanelDesc {
|
||||
|
||||
#define UI_MODS_PANEL_DESC_INIT {sizeof(UiModsPanelDesc), NULL, NULL, NULL}
|
||||
|
||||
/* Builds the contents associated with a group button. The target pane is cleared immediately
|
||||
* before this callback and is valid only while its tab remains built. */
|
||||
typedef UiPaneBuildFn UiGroupBuildFn;
|
||||
|
||||
typedef struct UiGroupDesc {
|
||||
uint32_t struct_size;
|
||||
const char* label; /* required */
|
||||
UiGroupBuildFn build; /* required */
|
||||
void* user_data;
|
||||
} UiGroupDesc;
|
||||
|
||||
#define UI_GROUP_DESC_INIT {sizeof(UiGroupDesc), NULL, NULL, NULL}
|
||||
|
||||
/* Build one tab of a mod window. `left_pane` is the interactive column,
|
||||
* `right_pane` shows contextual help (controls' help_rml and SELECT options
|
||||
* render there). Rebuilt on every tab activation. */
|
||||
@@ -174,15 +233,17 @@ typedef struct UiWindowDesc {
|
||||
|
||||
typedef void (*UiDialogActionFn)(ModContext* ctx, UiDialogHandle dialog, void* user_data);
|
||||
|
||||
/* Note: array element without struct_size; a future change requires appending
|
||||
* a v2 desc struct rather than growing this one. */
|
||||
typedef struct UiDialogAction {
|
||||
uint32_t struct_size;
|
||||
const char* label; /* required */
|
||||
UiDialogActionFn on_pressed;
|
||||
void* user_data;
|
||||
bool keep_open; /* false = the dialog closes after on_pressed returns */
|
||||
bool keep_open; /* false = the dialog closes after on_pressed returns */
|
||||
UiPredicateFn is_disabled; /* optional; polled every frame while the dialog is visible */
|
||||
} UiDialogAction;
|
||||
|
||||
#define UI_DIALOG_ACTION_INIT {sizeof(UiDialogAction), NULL, NULL, NULL, false, NULL}
|
||||
|
||||
typedef struct UiDialogDesc {
|
||||
uint32_t struct_size;
|
||||
const char* title; /* plain text; required */
|
||||
@@ -196,11 +257,14 @@ typedef struct UiDialogDesc {
|
||||
/* Fired on cancel (B/Escape) before the dialog closes; the dialog always
|
||||
* closes on dismiss. */
|
||||
UiDialogActionFn on_dismiss;
|
||||
void* user_data; /* passed to on_dismiss */
|
||||
void* user_data; /* passed to build and on_dismiss */
|
||||
/* Optional content builder. The pane is rendered below body_rml and above the actions. Its
|
||||
* handle and all child element handles remain valid until the dialog closes. */
|
||||
UiPaneBuildFn build;
|
||||
} UiDialogDesc;
|
||||
|
||||
#define UI_DIALOG_DESC_INIT \
|
||||
{sizeof(UiDialogDesc), NULL, NULL, UI_DIALOG_NORMAL, NULL, NULL, 0u, NULL, NULL}
|
||||
{sizeof(UiDialogDesc), NULL, NULL, UI_DIALOG_NORMAL, NULL, NULL, 0u, NULL, NULL, NULL}
|
||||
|
||||
/* A tab added to the in-game menu bar. */
|
||||
typedef struct UiMenuTabDesc {
|
||||
@@ -242,6 +306,10 @@ typedef struct UiService {
|
||||
ModContext* ctx, UiElementHandle pane, float value, UiElementHandle* out_elem);
|
||||
ModResult (*pane_add_control)(ModContext* ctx, UiElementHandle pane, const UiControlDesc* desc,
|
||||
UiElementHandle* out_elem);
|
||||
/* Add a group button to one pane that builds controls in its paired pane.
|
||||
* The panes must be the left and right handles from the same UiTabBuildFn call. */
|
||||
ModResult (*pane_add_group)(ModContext* ctx, UiElementHandle group_pane,
|
||||
UiElementHandle target_pane, const UiGroupDesc* desc, UiElementHandle* out_elem);
|
||||
|
||||
/* Element updates. The handle kind must match the setter (text/rml on text
|
||||
* rows, progress on progress bars). */
|
||||
@@ -263,9 +331,6 @@ typedef struct UiService {
|
||||
ModResult (*dialog_set_body)(ModContext* ctx, UiDialogHandle dialog, const char* body_rml);
|
||||
/* Replace the dialog icon ("" removes it; names as in UiDialogDesc.icon). */
|
||||
ModResult (*dialog_set_icon)(ModContext* ctx, UiDialogHandle dialog, const char* icon);
|
||||
/* Append one action button (same callback rules as at push). */
|
||||
ModResult (*dialog_add_action)(
|
||||
ModContext* ctx, UiDialogHandle dialog, const UiDialogAction* action);
|
||||
|
||||
/* Whether any focus-stack document is currently visible (visible documents block gamepad
|
||||
* input). */
|
||||
@@ -292,9 +357,16 @@ typedef struct UiService {
|
||||
/* Enqueue a toast notification. */
|
||||
ModResult (*push_toast)(ModContext* ctx, const UiToastDesc* desc);
|
||||
|
||||
/* Minor version 2 */
|
||||
ModResult (*get_clipboard_text)(ModContext* ctx, char* buffer, size_t bufferSize, size_t* outLength);
|
||||
ModResult (*get_clipboard_text)(
|
||||
ModContext* ctx, char* buffer, size_t bufferSize, size_t* outLength);
|
||||
ModResult (*set_clipboard_text)(ModContext* ctx, const char* text);
|
||||
|
||||
/* A scrollable virtualized list of items. */
|
||||
ModResult (*pane_add_list)(
|
||||
ModContext* ctx, UiElementHandle pane, const UiListDesc* desc, UiListHandle* out_list);
|
||||
/* Replace all items in a list with a new set. */
|
||||
ModResult (*list_set_items)(
|
||||
ModContext* ctx, UiListHandle list, const UiListItem* items, size_t item_count);
|
||||
} UiService;
|
||||
|
||||
MOD_DECLARE_SERVICE(UiService, svc_ui, UI_SERVICE_ID, UI_SERVICE_MAJOR, UI_SERVICE_MINOR);
|
||||
|
||||
@@ -1027,6 +1027,9 @@ void daAlink_c::setGetItemFace(u16 i_itemNo) {
|
||||
|| i_itemNo == dItemNo_ANCIENT_DOCUMENT2_e
|
||||
|| i_itemNo == dItemNo_DROP_CONTAINER_e
|
||||
|| i_itemNo == dItemNo_DROP_CONTAINER02_e
|
||||
#if TARGET_PC
|
||||
|| i_itemNo == dItemNo_SHADOW_CRYSTAL_e
|
||||
#endif
|
||||
|| i_itemNo == dItemNo_DROP_CONTAINER03_e)
|
||||
{
|
||||
setFaceBasicBck(dRes_ID_ALANM_BCK_FI_e);
|
||||
@@ -2009,7 +2012,11 @@ void daAlink_c::setGetSubBgm(int i_itemNo) {
|
||||
/* dItemNo_WEAR_KOKIRI_e */ SETYPE_NONE,
|
||||
/* dItemNo_ARMOR_e */ SETYPE_ITEM_GET,
|
||||
/* dItemNo_WEAR_ZORA_e */ SETYPE_ITEM_GET,
|
||||
#if TARGET_PC
|
||||
/* dItemNo_SHADOW_CRYSTAL_e */ SETYPE_ITEM_GET,
|
||||
#else
|
||||
/* dItemNo_MAGIC_LV1_e */ SETYPE_NONE,
|
||||
#endif
|
||||
/* dItemNo_DUNGEON_EXIT_2_e */ SETYPE_ITEM_GET_MINI,
|
||||
/* dItemNo_WALLET_LV1_e */ SETYPE_NONE,
|
||||
/* dItemNo_WALLET_LV2_e */ SETYPE_ITEM_GET,
|
||||
@@ -2307,8 +2314,13 @@ int daAlink_c::procCoGetItemInit() {
|
||||
item_no = dComIfGp_event_getGtItm();
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
const u32 giveTag = mDemo.getParam0() != 0x100 && mDemo.getParam1() != 0 ?
|
||||
static_cast<u32>(mDemo.getParam1()) :
|
||||
dusk::mods::item_give_queue_take_tag();
|
||||
#endif
|
||||
fpc_ProcID item_partner_id = fopAcM_createItemForPresentDemo(¤t.pos, item_no, 0, -1,
|
||||
fopAcM_GetRoomNo(this), NULL, NULL IF_DUSK_ARG(dusk::mods::item_give_queue_take_tag()));
|
||||
fopAcM_GetRoomNo(this), NULL, NULL IF_DUSK_ARG(giveTag));
|
||||
if (item_partner_id != fpcM_ERROR_PROCESS_ID_e) {
|
||||
dComIfGp_event_setItemPartnerId(item_partner_id);
|
||||
}
|
||||
@@ -2533,6 +2545,16 @@ int daAlink_c::procCoGetItem() {
|
||||
} else if (mProcVar2.field_0x300c == 0x23 && checkStageName("D_MN11")) {
|
||||
field_0x32cc = 0x5C0;
|
||||
} else if (mProcVar2.field_0x300c == 0xE0) {
|
||||
#if TARGET_PC
|
||||
// Dusklight increments the Poe count when the displayed item is granted.
|
||||
if (dComIfGs_getPohSpiritNum() + 1 == 20) {
|
||||
field_0x32cc = 0x4CF;
|
||||
} else if (dComIfGs_getPohSpiritNum() + 1 == 60) {
|
||||
field_0x32cc = 0x4D0;
|
||||
} else {
|
||||
field_0x32cc = mProcVar2.field_0x300c + 0x65;
|
||||
}
|
||||
#else
|
||||
if (dComIfGs_getPohSpiritNum() == 20) {
|
||||
field_0x32cc = 0x4CF;
|
||||
} else if (dComIfGs_getPohSpiritNum() == 60) {
|
||||
@@ -2540,6 +2562,7 @@ int daAlink_c::procCoGetItem() {
|
||||
} else {
|
||||
field_0x32cc = mProcVar2.field_0x300c + 0x65;
|
||||
}
|
||||
#endif
|
||||
} else if (mProcVar2.field_0x300c == 0x21) {
|
||||
static u32 const heartPieceMessage[5] = {0x86, 0x9C, 0x9D, 0x9E, 0x9F};
|
||||
field_0x32cc = heartPieceMessage[dComIfGs_getMaxLife() % 5];
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
#include "f_op/f_op_actor_enemy.h"
|
||||
#include "Z2AudioLib/Z2Instances.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
|
||||
enum daB_DS_Joint {
|
||||
DS_JNT_BACKBONE1,
|
||||
DS_JNT_BACKBONE2,
|
||||
@@ -4086,7 +4090,8 @@ void daB_DS_c::executeBattle2Dead() {
|
||||
dComIfGs_onStageBossEnemy(0x13);
|
||||
#if TARGET_PC
|
||||
// This reward has no original grant at this point in the cutscene.
|
||||
dusk::mods::item_check_enqueue("Arbiters Grounds Dungeon Reward", dItemNo_NONE_e);
|
||||
dusk::mods::item_check_enqueue_deferred(
|
||||
ITEM_CHECK_DUNGEON_REWARD_ARBITERS, dItemNo_NONE_e);
|
||||
#endif
|
||||
/* dSv_event_flag_c::F_0265 - Arbiter's Grounds - Arbiter's Grounds clear */
|
||||
dComIfGs_onEventBit(0x2010);
|
||||
|
||||
@@ -1090,6 +1090,13 @@ inline int daDemo00_c::execute() {
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
#if TARGET_PC
|
||||
// Suppress demo22_01's M_077 write. On Dusklight, the transform flag
|
||||
// is set by the Shadow Crystal item.
|
||||
if (dSv_event_flag_c::saveBitLabels[sp0E] == dSv_event_flag_c::M_077) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[sp0E]);
|
||||
break;
|
||||
|
||||
|
||||
@@ -449,7 +449,7 @@ int daDitem_c::Delete() {
|
||||
|
||||
endInsectEffect();
|
||||
mSound.deleteObject();
|
||||
return DeleteBase(dItem_data::getArcName(m_itemNo));
|
||||
return DeleteBase(dItem_data::getArcName(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo)));
|
||||
}
|
||||
|
||||
static int daDitem_Delete(daDitem_c* i_this) {
|
||||
@@ -461,8 +461,16 @@ int daDitem_c::create() {
|
||||
|
||||
m_itemNo = daDitem_prm::getNo(this);
|
||||
|
||||
#if TARGET_PC
|
||||
const auto [item, displayItem] = dusk::mods::item_check_resolve(mItemGiveTag, m_itemNo, this);
|
||||
m_itemNo = item;
|
||||
setDisplayItemNo(displayItem);
|
||||
const char* arc_name = dItem_data::getArcName(displayItem);
|
||||
s16 bmd_name = dItem_data::getBmdName(displayItem);
|
||||
#else
|
||||
const char* arc_name = dItem_data::getArcName(m_itemNo);
|
||||
s16 bmd_name = dItem_data::getBmdName(m_itemNo);
|
||||
#endif
|
||||
|
||||
if (bmd_name < 0 || arc_name == NULL) {
|
||||
if (bmd_name == 0) {
|
||||
@@ -476,9 +484,13 @@ int daDitem_c::create() {
|
||||
}
|
||||
|
||||
m_itemNo = dItemNo_GREEN_RUPEE_e;
|
||||
#if TARGET_PC
|
||||
setDisplayItemNo(dItemNo_NONE_e);
|
||||
#endif
|
||||
}
|
||||
|
||||
int phase_state = dComIfG_resLoad(&mPhase, dItem_data::getArcName(m_itemNo));
|
||||
int phase_state = dComIfG_resLoad(
|
||||
&mPhase, dItem_data::getArcName(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo)));
|
||||
if (phase_state == cPhs_COMPLEATE_e) {
|
||||
if (!fopAcM_entrySolidHeap(this, CheckItemCreateHeap, 0x80003390)) {
|
||||
return cPhs_ERROR_e;
|
||||
|
||||
@@ -727,19 +727,26 @@ void daE_HP_c::executeDead() {
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
mItemCheckOverridden =
|
||||
dusk::mods::item_check_poe(bitSw, dItemNo_POU_SPIRIT_e, this) != dItemNo_POU_SPIRIT_e;
|
||||
if (mItemCheckOverridden) {
|
||||
dusk::mods::item_check_enqueue_poe(bitSw, dItemNo_POU_SPIRIT_e);
|
||||
} else
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_poe(bitSw), dItemNo_POU_SPIRIT_e, this);
|
||||
mItemCheckHandled = true;
|
||||
if (itemCheck.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(itemCheck, this);
|
||||
} else {
|
||||
daAlink_getAlinkActorClass()->procWolfAtnActorMoveInit();
|
||||
dusk::mods::item_check_enqueue(itemCheck, dusk::mods::ItemGiveMode::ForcedDemo);
|
||||
}
|
||||
#else
|
||||
dComIfGs_addPohSpiritNum();
|
||||
#endif
|
||||
dComIfGs_addPohSpiritNum();
|
||||
|
||||
field_0x784 = -1;
|
||||
|
||||
if (dComIfGs_getPohSpiritNum() == 20 IF_DUSK(&&!mItemCheckOverridden)) {
|
||||
#if !TARGET_PC
|
||||
if (dComIfGs_getPohSpiritNum() == 20) {
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[0x1c9]);
|
||||
}
|
||||
#endif
|
||||
|
||||
movemode++;
|
||||
}
|
||||
@@ -759,7 +766,7 @@ void daE_HP_c::executeDead() {
|
||||
field_0x788 = 1;
|
||||
}
|
||||
}
|
||||
} else if (field_0x788 != 0 IF_DUSK(|| mItemCheckOverridden)) {
|
||||
} else if (field_0x788 != 0 IF_DUSK(|| mItemCheckHandled)) {
|
||||
fopAcM_createDisappear(this, ¤t.pos, 8, 3, 0xff);
|
||||
fopAcM_delete(this);
|
||||
} else {
|
||||
|
||||
+12
-12
@@ -1132,20 +1132,14 @@ static void e_po_dead(e_po_class* i_this) {
|
||||
camera_player->mCamera.Start();
|
||||
camera_player->mCamera.SetTrimSize(0);
|
||||
dComIfGp_event_reset();
|
||||
#if TARGET_PC
|
||||
if (dusk::mods::item_check_poe(i_this->BitSW, dItemNo_POU_SPIRIT_e, a_this) ==
|
||||
dItemNo_POU_SPIRIT_e)
|
||||
{
|
||||
#endif
|
||||
dComIfGs_addPohSpiritNum();
|
||||
#if !TARGET_PC
|
||||
dComIfGs_addPohSpiritNum();
|
||||
#if !PLATFORM_SHIELD
|
||||
if (dComIfGs_getPohSpiritNum() == 0x14) {
|
||||
/* dSv_event_flag_c::F_0457 - Castle Town - Revived cat */
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[457]);
|
||||
}
|
||||
#endif
|
||||
#if TARGET_PC
|
||||
}
|
||||
#endif
|
||||
daPy_getPlayerActorClass()->cancelOriginalDemo();
|
||||
} else if (mArg0Check(i_this, 0) != 0) {
|
||||
@@ -1274,10 +1268,16 @@ static void e_po_dead(e_po_class* i_this) {
|
||||
} else {
|
||||
if (i_this->field_0x75C == -1) {
|
||||
#if TARGET_PC
|
||||
const u8 itemNo =
|
||||
dusk::mods::item_check_poe(i_this->BitSW, dItemNo_POU_SPIRIT_e, a_this);
|
||||
i_this->field_0x75C = fopAcM_createItemForPresentDemo(&a_this->current.pos, itemNo,
|
||||
0, -1, -1, NULL, NULL, dusk::mods::item_give_tag_poe(i_this->BitSW));
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_poe(i_this->BitSW), dItemNo_POU_SPIRIT_e, a_this);
|
||||
if (itemCheck.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(itemCheck, a_this);
|
||||
i_this->field_0x75B = 1;
|
||||
} else {
|
||||
i_this->field_0x75C = fopAcM_createItemForPresentDemo(
|
||||
&a_this->current.pos, itemCheck.itemNo, 0, -1, -1, NULL, NULL,
|
||||
itemCheck.tag);
|
||||
}
|
||||
#else
|
||||
i_this->field_0x75C = fopAcM_createItemForPresentDemo(&a_this->current.pos, 0xE0, 0,
|
||||
-1, -1, NULL, NULL);
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
#include "f_op/f_op_camera_mng.h"
|
||||
#include <cstring>
|
||||
|
||||
#if TARGET_PC
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
|
||||
class daE_RDB_HIO_c : public JORReflexible {
|
||||
public:
|
||||
daE_RDB_HIO_c();
|
||||
@@ -1250,9 +1254,18 @@ static void demo_camera(e_rdb_class* i_this) {
|
||||
}
|
||||
|
||||
if (iVar1 != 0) {
|
||||
daPy_getPlayerActorClass()->changeDemoMode(11,
|
||||
DUSK_ITEM_CHECK_EXPR("bulblin_key:D_MN09", dItemNo_SMALL_KEY_e, &i_this->enemy), 0,
|
||||
0);
|
||||
#if TARGET_PC
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
ITEM_CHECK_BULBLIN_KEY, dItemNo_SMALL_KEY_e, &i_this->enemy);
|
||||
if (itemCheck.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(itemCheck, &i_this->enemy);
|
||||
}
|
||||
daPy_getPlayerActorClass()->changeDemoMode(
|
||||
11, itemCheck.itemNo == dItemNo_NONE_e ? 0 : itemCheck.itemNo,
|
||||
itemCheck.itemNo == dItemNo_NONE_e ? 0 : static_cast<int>(itemCheck.tag), 0);
|
||||
#else
|
||||
daPy_getPlayerActorClass()->changeDemoMode(11, dItemNo_SMALL_KEY_e, 0, 0);
|
||||
#endif
|
||||
i_this->mDemoMode = 12;
|
||||
i_this->field_0x10aa = 0;
|
||||
i_this->field_0xfe5 = 1;
|
||||
|
||||
@@ -242,21 +242,21 @@ BOOL daItemBase_c::chkFlag(int i_flag) {
|
||||
}
|
||||
|
||||
s8 daItemBase_c::getTevFrm() {
|
||||
return dItem_data::getTevFrm(m_itemNo);
|
||||
return dItem_data::getTevFrm(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo));
|
||||
}
|
||||
|
||||
s8 daItemBase_c::getBtpFrm() {
|
||||
return dItem_data::getBtpFrm(m_itemNo);
|
||||
return dItem_data::getBtpFrm(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo));
|
||||
}
|
||||
|
||||
u8 daItemBase_c::getShadowSize() {
|
||||
return dItem_data::getShadowSize(m_itemNo);
|
||||
return dItem_data::getShadowSize(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo));
|
||||
}
|
||||
|
||||
u8 daItemBase_c::getCollisionH() {
|
||||
return dItem_data::getH(m_itemNo);
|
||||
return dItem_data::getH(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo));
|
||||
}
|
||||
|
||||
u8 daItemBase_c::getCollisionR() {
|
||||
return dItem_data::getR(m_itemNo);
|
||||
return dItem_data::getR(DUSK_IF_ELSE(getDisplayItemNo(), m_itemNo));
|
||||
}
|
||||
|
||||
@@ -27,8 +27,10 @@
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include "dusk/mods/item.hpp"
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/version.hpp"
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
|
||||
class dmg_rod_HIO_c : public JORReflexible {
|
||||
@@ -2955,7 +2957,17 @@ static void lure_heart(dmg_rod_class* i_this) {
|
||||
if (obj_life != NULL) {
|
||||
fopAcM_delete(obj_life);
|
||||
fopAcM_onItem(obj_life, 0x80);
|
||||
#if TARGET_PC
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
ITEM_CHECK_FISHING_HEART_PIECE, dItemNo_KAKERA_HEART_e, actor);
|
||||
if (itemCheck.itemNo == dItemNo_KAKERA_HEART_e) {
|
||||
execItemGet(dItemNo_KAKERA_HEART_e, itemCheck.tag, actor);
|
||||
} else if (itemCheck.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(itemCheck, actor);
|
||||
}
|
||||
#else
|
||||
execItemGet(dItemNo_KAKERA_HEART_e);
|
||||
#endif
|
||||
u8 eventReg = dComIfGs_getEventReg(0xECFF);
|
||||
eventReg |= (u8)0x40;
|
||||
dComIfGs_setEventReg(0xECFF, eventReg);
|
||||
@@ -4090,7 +4102,15 @@ static void uki_catch(dmg_rod_class* i_this) {
|
||||
} else if (mgfish->mCaughtType == MG_CATCH_BIN) {
|
||||
i_this->msgflow.init(actor, 0x139A, 0, NULL);
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[468]);
|
||||
#if TARGET_PC
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
ITEM_CHECK_FISHING_BOTTLE, dItemNo_EMPTY_BOTTLE_e, actor);
|
||||
if (itemCheck.itemNo == dItemNo_EMPTY_BOTTLE_e) {
|
||||
dComIfGs_setEmptyBottle();
|
||||
}
|
||||
#else
|
||||
dComIfGs_setEmptyBottle();
|
||||
#endif
|
||||
} else if (mgfish->mCaughtType == MG_CATCH_KN) {
|
||||
i_this->msgflow.init(actor, 0x139C, 0, NULL);
|
||||
} else if (mgfish->mCaughtType == MG_CATCH_ED) {
|
||||
@@ -4167,6 +4187,18 @@ static void uki_catch(dmg_rod_class* i_this) {
|
||||
if (mgfish->mCaughtType == MG_CATCH_LH) {
|
||||
dComIfGp_setItemRupeeCount(10.0f + cM_rndF(40.9f));
|
||||
}
|
||||
#if TARGET_PC
|
||||
else if (mgfish->mCaughtType == MG_CATCH_BIN)
|
||||
{
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
ITEM_CHECK_FISHING_BOTTLE, dItemNo_EMPTY_BOTTLE_e, actor);
|
||||
if (itemCheck.itemNo == dItemNo_EMPTY_BOTTLE_e ||
|
||||
itemCheck.itemNo == dItemNo_NONE_e)
|
||||
{
|
||||
dusk::mods::item_check_complete(itemCheck, actor);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
dComIfGs_addFishNum(fish_kind);
|
||||
if (i_this->field_0x14c0 != 0) {
|
||||
|
||||
@@ -1806,17 +1806,21 @@ int daNpcChin_c::_Evt_GameSucceed_CutMain(const int& param_0) {
|
||||
|
||||
#if TARGET_PC
|
||||
const char* itemCheckName = nullptr;
|
||||
u32 itemGiveTag = 0;
|
||||
if (itemId1 == dItemNo_ARROW_LV2_e) {
|
||||
itemCheckName = "star_reward_1";
|
||||
} else if (itemId1 == dItemNo_ARROW_LV3_e) {
|
||||
itemCheckName = "star_reward_2";
|
||||
}
|
||||
if (itemCheckName != nullptr) {
|
||||
itemId1 = dusk::mods::item_check(itemCheckName, itemId1, this);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit(itemCheckName, itemId1, this);
|
||||
itemId1 = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
#endif
|
||||
fpc_ProcID itemId2 = fopAcM_createItemForPresentDemo(¤t.pos, itemId1, 0, -1, -1,
|
||||
0, 0 IF_DUSK_ARG(dusk::mods::item_give_tag(itemCheckName)));
|
||||
0, 0 IF_DUSK_ARG(itemGiveTag));
|
||||
if (itemId2 != -1) {
|
||||
dComIfGp_event_setItemPartnerId(itemId2);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
#include "d/actor/d_a_npc_gra.h"
|
||||
#include "d/actor/d_a_tag_gra.h"
|
||||
#include "Z2AudioLib/Z2Instances.h"
|
||||
#if TARGET_PC
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
#include <cstring>
|
||||
|
||||
DUSK_GAME_DATA const daNpc_grA_HIOParam daNpc_grA_Param_c::m = {
|
||||
@@ -1323,7 +1326,7 @@ BOOL daNpc_grA_c::isDelete() {
|
||||
return FALSE;
|
||||
}
|
||||
fopAcM_createItemForBoss(¤t.pos, 0x21, fopAcM_GetRoomNo(this), NULL, NULL, 0.0f, 0.0f,
|
||||
0x80);
|
||||
0x80 IF_DUSK_ARG(ITEM_CHECK_GORON_SPRINGWATER_RUSH));
|
||||
return TRUE;
|
||||
}
|
||||
return TRUE;
|
||||
@@ -2812,7 +2815,7 @@ BOOL daNpc_grA_c::ECut_carrySpaWater(int i_staffID) {
|
||||
c.y += 200.0f;
|
||||
csXyz c2(0, fopAcM_searchPlayerAngleY(this), 0);
|
||||
fopAcM_createItemForBoss(&c, 0x21, fopAcM_GetRoomNo(this), &c2, NULL, 0.0f, 20.0f,
|
||||
0x80);
|
||||
0x80 IF_DUSK_ARG(ITEM_CHECK_GORON_SPRINGWATER_RUSH));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@@ -4019,14 +4022,16 @@ BOOL daNpc_grA_c::talk(void*) {
|
||||
if (r26 && talkProc(NULL, TRUE, NULL)) {
|
||||
if (mFlow.getEventId(&sp8) == 1) {
|
||||
#if TARGET_PC
|
||||
const char* itemCheckName = nullptr;
|
||||
u32 itemGiveTag = 0;
|
||||
if (sp8 == dItemNo_BOMB_IN_BAG_e) {
|
||||
itemCheckName = "goron_reward:F_SP113";
|
||||
sp8 = dusk::mods::item_check(itemCheckName, sp8, this);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit("goron_reward:F_SP113", sp8, this);
|
||||
sp8 = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
#endif
|
||||
field_0x1480 = fopAcM_createItemForPresentDemo(¤t.pos, sp8, 0, -1, -1, NULL,
|
||||
NULL IF_DUSK_ARG(dusk::mods::item_give_tag(itemCheckName)));
|
||||
NULL IF_DUSK_ARG(itemGiveTag));
|
||||
if (field_0x1480 != fpcM_ERROR_PROCESS_ID_e) {
|
||||
s16 r25 = dComIfGp_getEventManager().getEventIdx(this, "DEFAULT_GETITEM", 0xff);
|
||||
dComIfGp_getEvent()->reset(this);
|
||||
|
||||
@@ -1495,9 +1495,11 @@ int daNpcIns_c::talk(void* param_1) {
|
||||
#if TARGET_PC
|
||||
u32 itemGiveTag = 0;
|
||||
if (s_givenInsectId != dItemNo_NONE_e) {
|
||||
itemNo = dusk::mods::item_check_bug(
|
||||
s_givenInsectId, itemNo & 0xFF, this);
|
||||
itemGiveTag = dusk::mods::item_give_tag_bug(s_givenInsectId);
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_bug(s_givenInsectId), itemNo & 0xFF,
|
||||
this);
|
||||
itemNo = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
s_givenInsectId = dItemNo_NONE_e;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1182,15 +1182,17 @@ int daNpc_Kkri_c::talk(void*) {
|
||||
case 1:
|
||||
if (mItemPartnerId == fpcM_ERROR_PROCESS_ID_e) {
|
||||
#if TARGET_PC
|
||||
const char* itemCheckName = nullptr;
|
||||
u32 itemGiveTag = 0;
|
||||
if (item_no == dItemNo_OIL_BOTTLE3_e) {
|
||||
itemCheckName = "coro_bottle";
|
||||
item_no = dusk::mods::item_check(itemCheckName, item_no, this);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit("coro_bottle", item_no, this);
|
||||
item_no = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
#endif
|
||||
mItemPartnerId = fopAcM_createItemForPresentDemo(¤t.pos, item_no,
|
||||
0, -1, -1, NULL,
|
||||
NULL IF_DUSK_ARG(dusk::mods::item_give_tag(itemCheckName)));
|
||||
NULL IF_DUSK_ARG(itemGiveTag));
|
||||
}
|
||||
|
||||
if (fopAcM_IsExecuting(mItemPartnerId)) {
|
||||
|
||||
@@ -1192,14 +1192,16 @@ int daNpc_myna2_c::ECut_gameGoalSuccess(int i_staffId) {
|
||||
int itemNo = 0;
|
||||
if (mFlow.getEventId(&itemNo) == 1) {
|
||||
#if TARGET_PC
|
||||
const char* itemCheckName = nullptr;
|
||||
u32 itemGiveTag = 0;
|
||||
if (itemNo == dItemNo_KAKERA_HEART_e) {
|
||||
itemCheckName = "plumm_minigame_reward";
|
||||
itemNo = dusk::mods::item_check(itemCheckName, itemNo, this);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit("plumm_minigame_reward", itemNo, this);
|
||||
itemNo = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
#endif
|
||||
mItemPid = fopAcM_createItemForPresentDemo(¤t.pos, itemNo, 0, -1, -1, NULL,
|
||||
NULL IF_DUSK_ARG(dusk::mods::item_give_tag(itemCheckName)));
|
||||
NULL IF_DUSK_ARG(itemGiveTag));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -960,17 +960,21 @@ int daNpc_Pouya_c::cutHaveFavorToAsk(int param_0) {
|
||||
if (mItemPartnerId == fpcM_ERROR_PROCESS_ID_e) {
|
||||
#if TARGET_PC
|
||||
const char* itemCheckName = nullptr;
|
||||
u32 itemGiveTag = 0;
|
||||
if (local_64 == dItemNo_DROP_BOTTLE_e) {
|
||||
itemCheckName = "jovani_reward_1";
|
||||
} else if (local_64 == dItemNo_SILVER_RUPEE_e) {
|
||||
itemCheckName = "jovani_reward_2";
|
||||
}
|
||||
if (itemCheckName != nullptr) {
|
||||
local_64 = dusk::mods::item_check(itemCheckName, local_64, this);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit(itemCheckName, local_64, this);
|
||||
local_64 = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
#endif
|
||||
mItemPartnerId = fopAcM_createItemForPresentDemo(¤t.pos, local_64, 0,
|
||||
-1, -1, 0, 0 IF_DUSK_ARG(dusk::mods::item_give_tag(itemCheckName)));
|
||||
-1, -1, 0, 0 IF_DUSK_ARG(itemGiveTag));
|
||||
}
|
||||
if (fopAcM_IsExecuting(mItemPartnerId)) {
|
||||
field_0xfce = 1;
|
||||
|
||||
@@ -2611,17 +2611,21 @@ BOOL daNpc_zrA_c::ECut_thanksBlast(int i_staffID) {
|
||||
if (mFlow.getEventId(&item_id) == 1) {
|
||||
#if TARGET_PC
|
||||
const char* itemCheckName = nullptr;
|
||||
u32 itemGiveTag = 0;
|
||||
if (item_id == dItemNo_BOMB_IN_BAG_e) {
|
||||
itemCheckName = "iza_reward_1";
|
||||
} else if (item_id == dItemNo_BOMB_BAG_LV2_e) {
|
||||
itemCheckName = "iza_reward_2";
|
||||
}
|
||||
if (itemCheckName != nullptr) {
|
||||
item_id = dusk::mods::item_check(itemCheckName, item_id, this);
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit(itemCheckName, item_id, this);
|
||||
item_id = itemCheck.itemNo;
|
||||
itemGiveTag = itemCheck.tag;
|
||||
}
|
||||
#endif
|
||||
mItemID = fopAcM_createItemForPresentDemo(¤t.pos, item_id, 0, -1, -1, NULL,
|
||||
NULL IF_DUSK_ARG(dusk::mods::item_give_tag(itemCheckName)));
|
||||
NULL IF_DUSK_ARG(itemGiveTag));
|
||||
}
|
||||
field_0x9eb = true;
|
||||
break;
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
#include "d/actor/d_a_obj_ystone.h"
|
||||
#include <cstring>
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/mods/item.hpp"
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
|
||||
static DUSK_CONST char* l_arcName = "ef_Portal";
|
||||
|
||||
static char const* l_clearEvName[9] = {
|
||||
@@ -77,6 +82,27 @@ static int getNowLevel() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
static const char* dungeon_reward_check_name(int level) {
|
||||
switch (level) {
|
||||
case 0:
|
||||
return ITEM_CHECK_DUNGEON_REWARD_FOREST;
|
||||
case 1:
|
||||
return ITEM_CHECK_DUNGEON_REWARD_GORON;
|
||||
case 2:
|
||||
return ITEM_CHECK_DUNGEON_REWARD_LAKEBED;
|
||||
case 4:
|
||||
return ITEM_CHECK_DUNGEON_REWARD_SNOWPEAK;
|
||||
case 5:
|
||||
return ITEM_CHECK_DUNGEON_REWARD_TIME;
|
||||
case 6:
|
||||
return ITEM_CHECK_DUNGEON_REWARD_CITY;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void daObjBossWarp_c::initBaseMtx() {
|
||||
scale.y = 0.15f;
|
||||
mpModel->setBaseScale(scale);
|
||||
@@ -485,6 +511,9 @@ int daObjBossWarp_c::demoProc() {
|
||||
player->onSceneChangeArea(scene, 0xff, 0);
|
||||
break;
|
||||
case 4: // STONE_FALL
|
||||
#if TARGET_PC
|
||||
{
|
||||
#endif
|
||||
if (ystone != NULL) {
|
||||
mYstonePos = ystone->current.pos;
|
||||
if (getNowLevel() < 3) {
|
||||
@@ -506,28 +535,52 @@ int daObjBossWarp_c::demoProc() {
|
||||
mDoMtx_stack_c::multVec(&mYstoneTargetPos, &mYstoneTargetPos);
|
||||
mYstonePos.x = mYstoneTargetPos.x;
|
||||
mYstonePos.z = mYstoneTargetPos.z;
|
||||
switch (getNowLevel()) {
|
||||
case 0:
|
||||
dComIfGs_onCollectCrystal(0);
|
||||
break;
|
||||
case 1:
|
||||
dComIfGs_onCollectCrystal(1);
|
||||
break;
|
||||
case 2:
|
||||
dComIfGs_onCollectCrystal(2);
|
||||
break;
|
||||
case 4:
|
||||
dComIfGs_onCollectMirror(1);
|
||||
break;
|
||||
case 5:
|
||||
dComIfGs_onCollectMirror(2);
|
||||
break;
|
||||
case 6:
|
||||
dComIfGs_onCollectMirror(3);
|
||||
break;
|
||||
#if TARGET_PC
|
||||
int level = getNowLevel();
|
||||
const char* checkName = dungeon_reward_check_name(level);
|
||||
dusk::mods::ItemCheckResult itemCheck{};
|
||||
bool applyVanillaReward = true;
|
||||
if (checkName != nullptr) {
|
||||
itemCheck = dusk::mods::item_check_commit(checkName, dItemNo_NONE_e, this);
|
||||
applyVanillaReward = itemCheck.itemNo == dItemNo_NONE_e;
|
||||
}
|
||||
if (applyVanillaReward) {
|
||||
switch (level) {
|
||||
#else
|
||||
switch (getNowLevel()) {
|
||||
#endif
|
||||
case 0:
|
||||
dComIfGs_onCollectCrystal(0);
|
||||
break;
|
||||
case 1:
|
||||
dComIfGs_onCollectCrystal(1);
|
||||
break;
|
||||
case 2:
|
||||
dComIfGs_onCollectCrystal(2);
|
||||
break;
|
||||
case 4:
|
||||
dComIfGs_onCollectMirror(1);
|
||||
break;
|
||||
case 5:
|
||||
dComIfGs_onCollectMirror(2);
|
||||
break;
|
||||
case 6:
|
||||
dComIfGs_onCollectMirror(3);
|
||||
break;
|
||||
}
|
||||
#if TARGET_PC
|
||||
if (checkName != nullptr) {
|
||||
dusk::mods::item_check_complete(itemCheck, this);
|
||||
}
|
||||
} else {
|
||||
dusk::mods::item_check_enqueue(itemCheck, dusk::mods::ItemGiveMode::Silent);
|
||||
}
|
||||
#endif
|
||||
mCounter = 0;
|
||||
break;
|
||||
#if TARGET_PC
|
||||
}
|
||||
#endif
|
||||
case 5: // STONE_MIDNA
|
||||
mCounter = 0;
|
||||
break;
|
||||
|
||||
@@ -158,8 +158,8 @@ void daItem_c::CreateInit() {
|
||||
mCcCyl.SetCoHitCallback(itemGetCoCallBack);
|
||||
mCcCyl.SetTgHitCallback(itemGetTgCallBack);
|
||||
|
||||
f32 cylHeight = dItem_data::getH(m_itemNo);
|
||||
f32 cylRadius = dItem_data::getR(m_itemNo);
|
||||
f32 cylHeight = DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo));
|
||||
f32 cylRadius = DUSK_IF_ELSE(getCollisionR(), dItem_data::getR(m_itemNo));
|
||||
|
||||
if (scale.x > 1.0f) {
|
||||
cylHeight *= scale.x;
|
||||
@@ -267,12 +267,13 @@ int daItem_c::_daItem_create() {
|
||||
#if TARGET_PC
|
||||
const u32 params = fopAcM_GetParam(this);
|
||||
mOriginalItemNo = params & 0xFF;
|
||||
const u8 resolvedItem = dusk::mods::item_check_freestanding(
|
||||
daItem_prm::getItemBitNo(this), mOriginalItemNo, this);
|
||||
mItemOverridden = resolvedItem != mOriginalItemNo;
|
||||
mItemGiveTag = dusk::mods::item_give_tag_freestanding(daItem_prm::getItemBitNo(this));
|
||||
const auto [item, displayItem] =
|
||||
dusk::mods::item_check_resolve(mItemGiveTag, mOriginalItemNo, this);
|
||||
mItemOverridden = item != mOriginalItemNo;
|
||||
setDisplayItemNo(displayItem);
|
||||
if (mItemOverridden) {
|
||||
fopAcM_SetParam(this, (params & 0xFFFFFF00) | resolvedItem);
|
||||
fopAcM_SetParam(this, (params & 0xFFFFFF00) | item);
|
||||
}
|
||||
#endif
|
||||
field_0x95d = true;
|
||||
@@ -287,7 +288,11 @@ int daItem_c::_daItem_create() {
|
||||
BOOL flag = dItem_data::chkFlag(m_itemNo, 2);
|
||||
|
||||
#if DEBUG
|
||||
#if TARGET_PC
|
||||
if (dItem_fieldModelArc(getDisplayItemNo()) == NULL) {
|
||||
#else
|
||||
if (dItem_data::getFieldArc(m_itemNo) == NULL) {
|
||||
#endif
|
||||
// "Item Num<%d>: No Resource Archive specified!!\n"
|
||||
OS_REPORT_ERROR("アイテム番号<%d>:リソースのアーカイブ指定がありません!!\n", m_itemNo);
|
||||
return cPhs_ERROR_e;
|
||||
@@ -319,10 +324,22 @@ int daItem_c::_daItem_create() {
|
||||
if (flag) {
|
||||
CreateInit();
|
||||
} else {
|
||||
#if TARGET_PC
|
||||
const u8 displayItemNo = getDisplayItemNo();
|
||||
phase_state = dComIfG_resLoad(&mPhase, dItem_fieldModelArc(displayItemNo));
|
||||
#else
|
||||
phase_state = dComIfG_resLoad(&mPhase, dItem_data::getFieldArc(m_itemNo));
|
||||
#endif
|
||||
if (phase_state == cPhs_COMPLEATE_e) {
|
||||
#if TARGET_PC
|
||||
const bool useModelFallback = dItem_data::getFieldArc(displayItemNo) == NULL;
|
||||
if (!fopAcM_entrySolidHeap(this,
|
||||
useModelFallback ? CheckItemCreateHeap : CheckFieldItemCreateHeap,
|
||||
useModelFallback ? 0x4000 : dItem_data::getFieldHeapSize(displayItemNo)))
|
||||
#else
|
||||
if (!fopAcM_entrySolidHeap(this, CheckFieldItemCreateHeap,
|
||||
dItem_data::getFieldHeapSize(m_itemNo)))
|
||||
#endif
|
||||
{
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
@@ -339,7 +356,7 @@ int daItem_c::_daItem_execute() {
|
||||
CountTimer();
|
||||
|
||||
eyePos = current.pos;
|
||||
eyePos.y += (f32)dItem_data::getH(m_itemNo) / 2;
|
||||
eyePos.y += (f32)DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo)) / 2;
|
||||
|
||||
attention_info.position = current.pos;
|
||||
|
||||
@@ -412,7 +429,11 @@ int daItem_c::_daItem_delete() {
|
||||
mSparkleEmtr.remove();
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
DeleteBase(dItem_fieldModelArc(getDisplayItemNo()));
|
||||
#else
|
||||
DeleteBase(dItem_data::getFieldArc(m_itemNo));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -520,9 +541,10 @@ void daItem_c::procInitGetDemoEvent() {
|
||||
|
||||
#if TARGET_PC
|
||||
const u8 displayItemNo = m_itemNo;
|
||||
if (mItemOverridden) {
|
||||
m_itemNo = dusk::mods::item_check_tagged(mItemGiveTag, mOriginalItemNo, this);
|
||||
}
|
||||
const auto itemCheck = dusk::mods::item_check_commit(mItemGiveTag, mOriginalItemNo, this);
|
||||
m_itemNo = itemCheck.itemNo;
|
||||
mItemGiveTag = itemCheck.tag;
|
||||
mItemOverridden = m_itemNo != mOriginalItemNo;
|
||||
#endif
|
||||
m_item_id = fopAcM_createItemForTrBoxDemo(
|
||||
¤t.pos, m_itemNo, -1, fopAcM_GetRoomNo(this), NULL, NULL IF_DUSK_ARG(mItemGiveTag));
|
||||
@@ -581,8 +603,8 @@ void daItem_c::procInitBoomerangCarry() {
|
||||
scale = mItemScale;
|
||||
mBoomerangMove.initOffset(¤t.pos);
|
||||
|
||||
u8 height = dItem_data::getH(m_itemNo);
|
||||
u8 radius = dItem_data::getR(m_itemNo);
|
||||
u8 height = DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo));
|
||||
u8 radius = DUSK_IF_ELSE(getCollisionR(), dItem_data::getR(m_itemNo));
|
||||
mCcCyl.SetR((f32)radius * 2.0f);
|
||||
mCcCyl.SetH((f32)height * 2.0f);
|
||||
mCcCyl.OnCoSPrmBit(1);
|
||||
@@ -907,9 +929,10 @@ void daItem_c::itemGetNextExecute() {
|
||||
void daItem_c::itemGet() {
|
||||
#if TARGET_PC
|
||||
const u8 displayItemNo = m_itemNo;
|
||||
if (mItemOverridden) {
|
||||
m_itemNo = dusk::mods::item_check_tagged(mItemGiveTag, mOriginalItemNo, this);
|
||||
}
|
||||
const auto itemCheck = dusk::mods::item_check_commit(mItemGiveTag, mOriginalItemNo, this);
|
||||
m_itemNo = itemCheck.itemNo;
|
||||
mItemGiveTag = itemCheck.tag;
|
||||
mItemOverridden = m_itemNo != mOriginalItemNo;
|
||||
#endif
|
||||
switch (m_itemNo) {
|
||||
#if TARGET_PC
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "d/dolzel_rel.h" // IWYU pragma: keep
|
||||
|
||||
#include "d/actor/d_a_obj_life_container.h"
|
||||
#include "d/d_a_itembase_static.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/actor/d_a_player.h"
|
||||
#include "d/d_item_data.h"
|
||||
@@ -87,8 +88,8 @@ int daObjLife_c::Create() {
|
||||
mCcCyl.SetStts(&mCcStts);
|
||||
mCcCyl.SetCoHitCallback(lifeGetCoCallBack);
|
||||
mCcCyl.SetTgHitCallback(lifeGetTgCallBack);
|
||||
mCcCyl.SetR(dItem_data::getR(m_itemNo));
|
||||
mCcCyl.SetH(dItem_data::getH(m_itemNo));
|
||||
mCcCyl.SetR(DUSK_IF_ELSE(getCollisionR(), dItem_data::getR(m_itemNo)));
|
||||
mCcCyl.SetH(DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo)));
|
||||
|
||||
fopAcM_SetCullSize(this, fopAc_CULLSPHERE_0_e);
|
||||
fopAcM_SetGravity(this, -3.2f);
|
||||
@@ -151,16 +152,30 @@ int daObjLife_c::create() {
|
||||
const u8 parameterItemNo = params & 0xFF;
|
||||
if (mItemGiveOriginalNo == dItemNo_NONE_e) {
|
||||
mOriginalItemNo = parameterItemNo;
|
||||
const u8 resolvedItem =
|
||||
dusk::mods::item_check_freestanding(getSaveBitNo(), mOriginalItemNo, this);
|
||||
mItemGiveTag = dusk::mods::item_give_tag_freestanding(getSaveBitNo());
|
||||
mItemOverridden = resolvedItem != mOriginalItemNo;
|
||||
const auto [item, displayItem] =
|
||||
dusk::mods::item_check_resolve(mItemGiveTag, mOriginalItemNo, this);
|
||||
setDisplayItemNo(displayItem);
|
||||
mItemOverridden = item != mOriginalItemNo;
|
||||
if (mItemOverridden) {
|
||||
fopAcM_SetParam(this, (params & 0xFFFFFF00) | resolvedItem);
|
||||
fopAcM_SetParam(this, (params & 0xFFFFFF00) | item);
|
||||
}
|
||||
} else if (mGoldenWolfItem) {
|
||||
mOriginalItemNo = mItemGiveOriginalNo;
|
||||
mItemGiveTag = dusk::mods::item_give_tag_golden_wolf(static_cast<u16>(field_0x938));
|
||||
const auto [item, displayItem] =
|
||||
dusk::mods::item_check_resolve(mItemGiveTag, mOriginalItemNo, this);
|
||||
setDisplayItemNo(displayItem);
|
||||
mItemOverridden = item != mOriginalItemNo;
|
||||
if (item != parameterItemNo) {
|
||||
fopAcM_SetParam(this, (params & 0xFFFFFF00) | item);
|
||||
}
|
||||
} else {
|
||||
mOriginalItemNo = mItemGiveOriginalNo;
|
||||
mItemOverridden = parameterItemNo != mItemGiveOriginalNo;
|
||||
setDisplayItemNo(
|
||||
dusk::mods::item_check_resolve(mItemGiveTag, parameterItemNo, this)
|
||||
.display_item);
|
||||
mItemOverridden = parameterItemNo != mOriginalItemNo;
|
||||
}
|
||||
mOverrideHover =
|
||||
mItemOverridden &&
|
||||
@@ -184,11 +199,24 @@ int daObjLife_c::create() {
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
// Resolved items may have no field model; display their get-demo model instead.
|
||||
const u8 displayItemNo = getDisplayItemNo();
|
||||
const bool useGetModel = dItem_data::getFieldArc(displayItemNo) == NULL;
|
||||
int phase_state = dComIfG_resLoad(&mPhase, dItem_fieldModelArc(displayItemNo));
|
||||
if (phase_state == cPhs_COMPLEATE_e) {
|
||||
if (!fopAcM_entrySolidHeap(
|
||||
this, useGetModel ? CheckItemCreateHeap : CheckFieldItemCreateHeap, 0x4000))
|
||||
{
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
#else
|
||||
int phase_state = dComIfG_resLoad(&mPhase, dItem_data::getFieldArc(m_itemNo));
|
||||
if (phase_state == cPhs_COMPLEATE_e) {
|
||||
if (!fopAcM_entrySolidHeap(this, CheckFieldItemCreateHeap, 0x4000)) {
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Create()) {
|
||||
return cPhs_ERROR_e;
|
||||
@@ -325,9 +353,10 @@ int daObjLife_c::initActionOrderGetDemo() {
|
||||
|
||||
#if TARGET_PC
|
||||
const u8 displayItemNo = m_itemNo;
|
||||
if (mItemOverridden) {
|
||||
m_itemNo = dusk::mods::item_check_tagged(mItemGiveTag, mOriginalItemNo, this);
|
||||
}
|
||||
const auto itemCheck = dusk::mods::item_check_commit(mItemGiveTag, mOriginalItemNo, this);
|
||||
m_itemNo = itemCheck.itemNo;
|
||||
mItemGiveTag = itemCheck.tag;
|
||||
mItemOverridden = m_itemNo != mOriginalItemNo;
|
||||
#endif
|
||||
mItemId = fopAcM_createItemForTrBoxDemo(
|
||||
¤t.pos, m_itemNo, -1, fopAcM_GetRoomNo(this), NULL, NULL IF_DUSK_ARG(mItemGiveTag));
|
||||
@@ -397,8 +426,8 @@ int daObjLife_c::actionInitBoomerangCarry() {
|
||||
mCcCyl.OnTgSPrmBit(1);
|
||||
mCcCyl.OnCoSPrmBit(1);
|
||||
|
||||
f32 height = dItem_data::getH(m_itemNo) * 4.0f;
|
||||
f32 radius = dItem_data::getR(m_itemNo) * 4.0f;
|
||||
f32 height = DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo)) * 4.0f;
|
||||
f32 radius = DUSK_IF_ELSE(getCollisionR(), dItem_data::getR(m_itemNo)) * 4.0f;
|
||||
mCcCyl.SetR(radius);
|
||||
mCcCyl.SetH(height);
|
||||
|
||||
@@ -519,7 +548,11 @@ int daObjLife_c::_delete() {
|
||||
endEffect00();
|
||||
endEffect02();
|
||||
|
||||
#if TARGET_PC
|
||||
DeleteBase(dItem_fieldModelArc(getDisplayItemNo()));
|
||||
#else
|
||||
DeleteBase(dItem_data::getFieldArc(m_itemNo));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file d_a_obj_master_sword.cpp
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "d/dolzel_rel.h" // IWYU pragma: keep
|
||||
@@ -10,6 +10,12 @@
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/d_meter2_info.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "d/d_item.h"
|
||||
#include "dusk/mods/item.hpp"
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
|
||||
DUSK_GAME_DATA daObjMasterSword_Attr_c const daObjMasterSword_c::mAttr = {1.0f};
|
||||
|
||||
void daObjMasterSword_c::initBaseMtx() {
|
||||
@@ -145,7 +151,11 @@ void daObjMasterSword_c::create_init() {
|
||||
int daObjMasterSword_c::create() {
|
||||
fopAcM_ct(this, daObjMasterSword_c);
|
||||
|
||||
#if TARGET_PC
|
||||
if (dComIfGs_isEventBit(dSv_event_flag_c::F_0264)) {
|
||||
#else
|
||||
if (dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[getFlagNo()])) {
|
||||
#endif
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
|
||||
@@ -186,12 +196,41 @@ int daObjMasterSword_c::execute() {
|
||||
mBrk.play();
|
||||
|
||||
if (dComIfGs_isTmpBit(dSv_event_tmp_flag_c::tempBitLabels[73])) {
|
||||
#if TARGET_PC
|
||||
const auto masterSword = dusk::mods::item_check_commit(
|
||||
ITEM_CHECK_MASTER_SWORD, dItemNo_MASTER_SWORD_e, this);
|
||||
if (masterSword.itemNo == dItemNo_MASTER_SWORD_e) {
|
||||
dComIfGs_onItemFirstBit(dItemNo_MASTER_SWORD_e);
|
||||
dMeter2Info_setSword(dItemNo_MASTER_SWORD_e, false);
|
||||
dComIfGs_setSelectEquipSword(dItemNo_MASTER_SWORD_e);
|
||||
dusk::mods::item_check_complete(masterSword, this);
|
||||
} else if (masterSword.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(masterSword, this);
|
||||
} else {
|
||||
dusk::mods::item_check_enqueue(masterSword, dusk::mods::ItemGiveMode::Demo);
|
||||
}
|
||||
|
||||
dComIfGp_setItemLifeCount(dComIfGs_getMaxLife(), 0);
|
||||
|
||||
const auto shadowCrystal = dusk::mods::item_check_commit(
|
||||
ITEM_CHECK_SHADOW_CRYSTAL, dItemNo_SHADOW_CRYSTAL_e, this);
|
||||
if (shadowCrystal.itemNo == dItemNo_SHADOW_CRYSTAL_e) {
|
||||
execItemGet(shadowCrystal.itemNo, shadowCrystal.tag, this);
|
||||
} else if (shadowCrystal.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(shadowCrystal, this);
|
||||
} else {
|
||||
dusk::mods::item_check_enqueue(shadowCrystal, dusk::mods::ItemGiveMode::Demo);
|
||||
}
|
||||
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::F_0264);
|
||||
#else
|
||||
dComIfGs_onItemFirstBit(dItemNo_MASTER_SWORD_e);
|
||||
dMeter2Info_setSword(dItemNo_MASTER_SWORD_e, false);
|
||||
dComIfGs_setSelectEquipSword(dItemNo_MASTER_SWORD_e);
|
||||
|
||||
dComIfGp_setItemLifeCount(dComIfGs_getMaxLife(), 0);
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[getFlagNo()]);
|
||||
#endif
|
||||
fopAcM_delete(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ int daItemShield_c::__CreateHeap() {
|
||||
int daItemShield_c::create() {
|
||||
fopAcM_ct(this, daItemShield_c);
|
||||
m_itemNo = dItemNo_WOOD_SHIELD_e;
|
||||
DUSK_ITEM_CHECK("ordon_shield", m_itemNo, this);
|
||||
DUSK_ITEM_CHECK_PREVIEW("ordon_shield", m_itemNo, this);
|
||||
if (fopAcM_isSwitch(this, getSwBit2())) {
|
||||
OS_REPORT("木の盾:もう取ったので出ません\n");
|
||||
return cPhs_ERROR_e;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file d_a_obj_smallkey.cpp
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "d/dolzel_rel.h" // IWYU pragma: keep
|
||||
@@ -119,9 +119,9 @@ int daKey_c::Create() {
|
||||
mCcCyl.SetStts(&mCcStts);
|
||||
mCcCyl.SetCoHitCallback(keyGetCoCallBack);
|
||||
mCcCyl.SetTgHitCallback(keyGetTgCallBack);
|
||||
mCcCyl.SetR(dItem_data::getR(m_itemNo));
|
||||
mCcCyl.SetH(dItem_data::getH(m_itemNo));
|
||||
|
||||
mCcCyl.SetR(DUSK_IF_ELSE(getCollisionR(), dItem_data::getR(m_itemNo)));
|
||||
mCcCyl.SetH(DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo)));
|
||||
|
||||
fopAcM_SetCullSize(this, fopAc_CULLSPHERE_0_e);
|
||||
|
||||
if (getSwNo() == 0xFF) {
|
||||
@@ -155,7 +155,21 @@ int daKey_c::create() {
|
||||
mIsPrmInit = TRUE;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
mItemGiveTag = dusk::mods::item_give_tag_freestanding(getSaveBitNo());
|
||||
const auto [item, displayItem] =
|
||||
dusk::mods::item_check_resolve(mItemGiveTag, dItemNo_SMALL_KEY_e, this);
|
||||
m_itemNo = item;
|
||||
if (m_itemNo == dItemNo_NONE_e) {
|
||||
// Keep the pickup visible until the empty check is collected.
|
||||
m_itemNo = dItemNo_SMALL_KEY_e;
|
||||
setDisplayItemNo(dItemNo_NONE_e);
|
||||
} else {
|
||||
setDisplayItemNo(displayItem);
|
||||
}
|
||||
#else
|
||||
m_itemNo = dItemNo_SMALL_KEY_e;
|
||||
#endif
|
||||
|
||||
if (strcmp(dComIfGp_getStartStageName(), "F_SP118") == 0) {
|
||||
OS_REPORT(" SMKEY 0\n");
|
||||
@@ -170,9 +184,21 @@ int daKey_c::create() {
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
const u8 displayItemNo = getDisplayItemNo();
|
||||
int phase_state = dComIfG_resLoad(&mPhase, dItem_fieldModelArc(displayItemNo));
|
||||
#else
|
||||
int phase_state = dComIfG_resLoad(&mPhase, dItem_data::getFieldArc(m_itemNo));
|
||||
#endif
|
||||
if (phase_state == cPhs_COMPLEATE_e) {
|
||||
#if TARGET_PC
|
||||
const bool useModelFallback = dItem_data::getFieldArc(displayItemNo) == NULL;
|
||||
if (!fopAcM_entrySolidHeap(
|
||||
this, useModelFallback ? CheckItemCreateHeap : CheckFieldItemCreateHeap, 0x4000))
|
||||
{
|
||||
#else
|
||||
if (!fopAcM_entrySolidHeap(this, CheckFieldItemCreateHeap, 0x840)) {
|
||||
#endif
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
|
||||
@@ -317,10 +343,26 @@ int daKey_c::initActionOrderGetDemo() {
|
||||
hide();
|
||||
effectStop();
|
||||
|
||||
#if TARGET_PC
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit(mItemGiveTag, dItemNo_SMALL_KEY_e, this);
|
||||
m_itemNo = itemCheck.itemNo;
|
||||
if (m_itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(itemCheck, this);
|
||||
dComIfGs_onTbox(getSaveBitNo());
|
||||
dTres_c::offStatus(getSaveBitNo(), 1);
|
||||
dComIfGp_event_reset();
|
||||
fopAcM_delete(this);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
fopAcM_orderItemEvent(this, 0, 0);
|
||||
eventInfo.onCondition(8);
|
||||
|
||||
mItemId = fopAcM_createItemForTrBoxDemo(¤t.pos, m_itemNo, -1, fopAcM_GetRoomNo(this), NULL, NULL);
|
||||
mItemId = fopAcM_createItemForTrBoxDemo(
|
||||
¤t.pos, m_itemNo, -1, fopAcM_GetRoomNo(this), NULL,
|
||||
NULL IF_DUSK_ARG(itemCheck.tag));
|
||||
JUT_ASSERT(699, mItemId != fpcM_ERROR_PROCESS_ID_e);
|
||||
|
||||
setStatus(STATUS_ORDER_GET_DEMO_e);
|
||||
@@ -387,8 +429,8 @@ int daKey_c::actionInitBoomerangCarry() {
|
||||
mCcCyl.OnTgSPrmBit(1);
|
||||
mCcCyl.OnCoSPrmBit(1);
|
||||
|
||||
u8 height = dItem_data::getH(m_itemNo);
|
||||
u8 radius = dItem_data::getR(m_itemNo);
|
||||
u8 height = DUSK_IF_ELSE(getCollisionH(), dItem_data::getH(m_itemNo));
|
||||
u8 radius = DUSK_IF_ELSE(getCollisionR(), dItem_data::getR(m_itemNo));
|
||||
|
||||
mCcCyl.SetR(4.0f * radius);
|
||||
mCcCyl.SetH(4.0f * height);
|
||||
@@ -527,7 +569,11 @@ int daKey_c::draw() {
|
||||
|
||||
int daKey_c::_delete() {
|
||||
effectStop();
|
||||
#if TARGET_PC
|
||||
DeleteBase(dItem_fieldModelArc(getDisplayItemNo()));
|
||||
#else
|
||||
DeleteBase(dItem_data::getFieldArc(m_itemNo));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ int daObjSword_c::Create() {
|
||||
cPhs_Step daObjSword_c::create() {
|
||||
fopAcM_ct(this, daObjSword_c);
|
||||
m_itemNo = 0x28;
|
||||
DUSK_ITEM_CHECK("ordon_sword", m_itemNo, this);
|
||||
DUSK_ITEM_CHECK_PREVIEW("ordon_sword", m_itemNo, this);
|
||||
if (fopAcM_isItem(this, getItemBit())) {
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ int daObjZCloth_c::Create() {
|
||||
int daObjZCloth_c::create() {
|
||||
fopAcM_ct(this, daObjZCloth_c);
|
||||
m_itemNo = 0x31;
|
||||
DUSK_ITEM_CHECK("zora_armor", m_itemNo, this);
|
||||
DUSK_ITEM_CHECK_PREVIEW("zora_armor", m_itemNo, this);
|
||||
int phase = dComIfG_resLoad(&mPhase, dItem_data::getFieldArc(m_itemNo));
|
||||
if (phase == cPhs_COMPLEATE_e) {
|
||||
if (!fopAcM_entrySolidHeap(this, (heapCallbackFunc)CheckFieldItemCreateHeap, 0x2fb0)) {
|
||||
|
||||
@@ -105,17 +105,19 @@ const char* daShopItem_c::getShopArcname() {
|
||||
#if TARGET_PC
|
||||
if (m_itemNo != dItemNo_NONE_e && mItemGiveOriginalNo == dItemNo_NONE_e) {
|
||||
mItemGiveOriginalNo = m_itemNo;
|
||||
const u8 resolvedItem = dusk::mods::item_check_shop(mItemGiveOriginalNo, this);
|
||||
mItemOverridden = resolvedItem != mItemGiveOriginalNo;
|
||||
mItemGiveTag = dusk::mods::item_give_tag_shop(mItemGiveOriginalNo);
|
||||
const auto [_, displayItem] =
|
||||
dusk::mods::item_check_resolve(mItemGiveTag, mItemGiveOriginalNo, this);
|
||||
mItemOverridden = displayItem != mItemGiveOriginalNo;
|
||||
if (mItemOverridden) {
|
||||
mOverrideData = mData[mShopItemID];
|
||||
mOverrideData.mArcName = dItem_data::getArcName(resolvedItem);
|
||||
mOverrideData.mBmdName = dItem_data::getBmdName(resolvedItem);
|
||||
mOverrideData.mBtkName = dItem_data::getBtkName(resolvedItem);
|
||||
mOverrideData.mBckName = dItem_data::getBckName(resolvedItem);
|
||||
mOverrideData.mBrkName = dItem_data::getBrkName(resolvedItem);
|
||||
mOverrideData.mBtpName = dItem_data::getBtpName(resolvedItem);
|
||||
mOverrideData.mTevFrm = dItem_data::getTevFrm(resolvedItem);
|
||||
mOverrideData.mArcName = dItem_data::getArcName(displayItem);
|
||||
mOverrideData.mBmdName = dItem_data::getBmdName(displayItem);
|
||||
mOverrideData.mBtkName = dItem_data::getBtkName(displayItem);
|
||||
mOverrideData.mBckName = dItem_data::getBckName(displayItem);
|
||||
mOverrideData.mBrkName = dItem_data::getBrkName(displayItem);
|
||||
mOverrideData.mBtpName = dItem_data::getBtpName(displayItem);
|
||||
mOverrideData.mTevFrm = dItem_data::getTevFrm(displayItem);
|
||||
mOverrideData.mBtpFrm = -1;
|
||||
mOverrideData.mFlag = static_cast<u32>(-1);
|
||||
mOverrideData.mOffsetY = mShopItemID == SHOP_ITEMNO_ARMOR ? 60.0f : 15.0f;
|
||||
|
||||
@@ -363,10 +363,13 @@ int daTagStatue_c::demoProc() {
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
item = dusk::mods::item_check_sky_character(item & 0xFF, this);
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_sky_character(), item & 0xFF, this);
|
||||
item = itemCheck.itemNo;
|
||||
#endif
|
||||
mItemId = fopAcM_createItemForTrBoxDemo(¤t.pos, item, -1,
|
||||
fopAcM_GetRoomNo(this), 0, 0 IF_DUSK_ARG(dusk::mods::item_give_tag_sky_character()));
|
||||
mItemId =
|
||||
fopAcM_createItemForTrBoxDemo(¤t.pos, item, -1, fopAcM_GetRoomNo(this), 0,
|
||||
0 IF_DUSK_ARG(itemCheck.tag));
|
||||
|
||||
JUT_ASSERT(580, mItemId != fpcM_ERROR_PROCESS_ID_e);
|
||||
|
||||
|
||||
@@ -1391,8 +1391,9 @@ u8 daTbox_c::getBombItemNoMain(u8 i_itemNo) {
|
||||
int daTbox_c::setGetDemoItem() {
|
||||
u8 item_no = getItemNo();
|
||||
#if TARGET_PC
|
||||
const u32 giveTag = dusk::mods::item_give_tag_chest(getTboxNo());
|
||||
item_no = dusk::mods::item_check_tagged(giveTag, mOriginalItemNo, this);
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_chest(getTboxNo()), mOriginalItemNo, this);
|
||||
item_no = itemCheck.itemNo;
|
||||
#endif
|
||||
if (item_no == dItemNo_BOMB_5_e || item_no == dItemNo_BOMB_10_e || item_no == dItemNo_BOMB_20_e || item_no == dItemNo_BOMB_30_e ||
|
||||
item_no == dItemNo_WATER_BOMB_5_e || item_no == dItemNo_WATER_BOMB_10_e || item_no == dItemNo_WATER_BOMB_20_e || item_no == dItemNo_WATER_BOMB_30_e ||
|
||||
@@ -1404,10 +1405,10 @@ int daTbox_c::setGetDemoItem() {
|
||||
fpc_ProcID item_id;
|
||||
if (field_0x718) {
|
||||
item_id = fopAcM_createItemForPresentDemo(
|
||||
¤t.pos, item_no, 1, -1, -1, NULL, NULL IF_DUSK_ARG(giveTag));
|
||||
¤t.pos, item_no, 1, -1, -1, NULL, NULL IF_DUSK_ARG(itemCheck.tag));
|
||||
} else {
|
||||
item_id = fopAcM_createItemForTrBoxDemo(
|
||||
¤t.pos, item_no, -1, -1, NULL, NULL IF_DUSK_ARG(giveTag));
|
||||
¤t.pos, item_no, -1, -1, NULL, NULL IF_DUSK_ARG(itemCheck.tag));
|
||||
}
|
||||
|
||||
if (item_id != fpcM_ERROR_PROCESS_ID_e) {
|
||||
|
||||
@@ -383,15 +383,18 @@ int daTbox2_c::setGetDemoItem() {
|
||||
u8 item_no = getItemNo();
|
||||
#if TARGET_PC
|
||||
int tboxNo = fopAcM_GetParamBit(this, 16, 8);
|
||||
const u32 giveTag = dusk::mods::item_give_tag_chest(tboxNo);
|
||||
item_no = dusk::mods::item_check_tagged(giveTag, mOriginalItemNo, this);
|
||||
const auto itemCheck = dusk::mods::item_check_commit(
|
||||
dusk::mods::item_give_tag_chest(tboxNo), mOriginalItemNo, this);
|
||||
item_no = itemCheck.itemNo;
|
||||
#endif
|
||||
|
||||
u32 partner_id;
|
||||
if (mReturnRupee) {
|
||||
partner_id = fopAcM_createItemForPresentDemo(¤t.pos, item_no, 1, -1, -1, NULL, NULL IF_DUSK_ARG(giveTag));
|
||||
partner_id = fopAcM_createItemForPresentDemo(
|
||||
¤t.pos, item_no, 1, -1, -1, NULL, NULL IF_DUSK_ARG(itemCheck.tag));
|
||||
} else {
|
||||
partner_id = fopAcM_createItemForTrBoxDemo(¤t.pos, item_no, -1, -1, NULL, NULL IF_DUSK_ARG(giveTag));
|
||||
partner_id = fopAcM_createItemForTrBoxDemo(
|
||||
¤t.pos, item_no, -1, -1, NULL, NULL IF_DUSK_ARG(itemCheck.tag));
|
||||
}
|
||||
|
||||
if (partner_id != -1) {
|
||||
|
||||
@@ -50,17 +50,24 @@ bool daItemBase_c::chkDead() {
|
||||
int CheckItemCreateHeap(fopAc_ac_c* i_this) {
|
||||
daItemBase_c* a_this = static_cast<daItemBase_c*>(i_this);
|
||||
|
||||
u8 item_no = a_this->getItemNo();
|
||||
u8 item_no = DUSK_IF_ELSE(a_this->getDisplayItemNo(), a_this->getItemNo());
|
||||
return a_this->CreateItemHeap(dItem_data::getArcName(item_no), dItem_data::getBmdName(item_no),
|
||||
dItem_data::getBtkName(item_no), dItem_data::getBpkName(item_no),
|
||||
dItem_data::getBckName(item_no), dItem_data::getBxaName(item_no),
|
||||
dItem_data::getBrkName(item_no), dItem_data::getBtpName(item_no));
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
const char* dItem_fieldModelArc(u8 itemNo) {
|
||||
const char* arcName = dItem_data::getFieldArc(itemNo);
|
||||
return arcName != NULL ? arcName : dItem_data::getArcName(itemNo);
|
||||
}
|
||||
#endif
|
||||
|
||||
int CheckFieldItemCreateHeap(fopAc_ac_c* i_this) {
|
||||
daItemBase_c* a_this = static_cast<daItemBase_c*>(i_this);
|
||||
|
||||
u8 item_no = a_this->getItemNo();
|
||||
u8 item_no = DUSK_IF_ELSE(a_this->getDisplayItemNo(), a_this->getItemNo());
|
||||
return a_this->CreateItemHeap(
|
||||
dItem_data::getFieldArc(item_no), dItem_data::getItemBmdName(item_no),
|
||||
dItem_data::getItemBtkName(item_no), dItem_data::getItemBpkName(item_no),
|
||||
|
||||
+1
-1
@@ -7595,7 +7595,7 @@ bool dCamera_c::executeDebugFlyCam() {
|
||||
if (ImGui::IsKeyDown(ImGuiKey_Q)) rollInput -= 1.0f;
|
||||
if (ImGui::IsKeyDown(ImGuiKey_E)) rollInput += 1.0f;
|
||||
}
|
||||
bool mouseValid = !io.WantCaptureMouse && io.MousePos.x >= 0.0f && io.MousePos.y >= 0.0f;
|
||||
bool mouseValid = !io.WantCaptureMouse && io.MousePos.x >= 0.0f && io.MousePos.y >= 0.0f && ImGui::IsMouseDown(ImGuiMouseButton_Right);
|
||||
if (mouseValid && sFlyCamLastMousePos.x >= 0.0f) {
|
||||
cStickX -= (io.MousePos.x - sFlyCamLastMousePos.x) * 2.0f;
|
||||
cStickY -= (io.MousePos.y - sFlyCamLastMousePos.y) * 2.0f;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+40
-7
@@ -23,6 +23,7 @@
|
||||
#include "m_Do/m_Do_graphic.h"
|
||||
#include <cstring>
|
||||
|
||||
#include "dusk/utilities.hpp"
|
||||
#include "dusk/version.hpp"
|
||||
|
||||
#if TARGET_PC
|
||||
@@ -4153,11 +4154,43 @@ bool dFile_select_c::yesnoWakuAlpahAnm(u8 param_1) {
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
|
||||
static dusk::utils::PaneCache mSelDtPanes[] = {
|
||||
{MULTI_CHAR('tate_n0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('tate_n1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('ken_n0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('ken_n1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fuku_n0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fuku_n1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fuku_n2'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('gray_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('b_base'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('b_base1'), 0.0f, 0.0f, false},
|
||||
};
|
||||
|
||||
static dusk::utils::PaneCache fileSelPanes[] = {
|
||||
{MULTI_CHAR('w_uzu00'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu01'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu02'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu03'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu04'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu05'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu06'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu07'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu08'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_uzu09'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_er_msg'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_er_msE'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_er_msR'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('er_for0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('er_for1'), 0.0f, 0.0f, false},
|
||||
};
|
||||
|
||||
void dFile_select_c::fileSelectWide() {
|
||||
static bool cachedPanes = false;
|
||||
// Get pre-scale values for each pane
|
||||
if (!cachedPanes) {
|
||||
for (PaneCache& entry : mSelDtPanes) {
|
||||
for (dusk::utils::PaneCache& entry : mSelDtPanes) {
|
||||
J2DPane* pane = mSelDt.ScrDt->search(entry.tag);
|
||||
if (!entry.cached) {
|
||||
entry.origTransX = pane->getTranslateX();
|
||||
@@ -4165,7 +4198,7 @@ void dFile_select_c::fileSelectWide() {
|
||||
entry.cached = true;
|
||||
}
|
||||
}
|
||||
for (PaneCache& entry : fileSelPanes) {
|
||||
for (dusk::utils::PaneCache& entry : fileSelPanes) {
|
||||
J2DPane* pane = fileSel.Scr->search(entry.tag);
|
||||
if (!entry.cached) {
|
||||
entry.origTransX = pane->getTranslateX();
|
||||
@@ -4179,13 +4212,13 @@ void dFile_select_c::fileSelectWide() {
|
||||
// Reset all panes
|
||||
mSelDt.ScrDt->scale(1.0f, 1.0f);
|
||||
mSelDt.ScrDt->translate(0.0f, 0.0f);
|
||||
for (PaneCache& entry : mSelDtPanes) {
|
||||
for (dusk::utils::PaneCache& entry : mSelDtPanes) {
|
||||
J2DPane* pane = mSelDt.ScrDt->search(entry.tag);
|
||||
pane->setBasePosition(J2DBasePosition_4);
|
||||
pane->scale(1.0f, 1.0f);
|
||||
pane->translate(entry.origTransX, entry.origTransY);
|
||||
}
|
||||
for (PaneCache& entry : fileSelPanes) {
|
||||
for (dusk::utils::PaneCache& entry : fileSelPanes) {
|
||||
J2DPane* pane = fileSel.Scr->search(entry.tag);
|
||||
pane->setBasePosition(J2DBasePosition_4);
|
||||
pane->scale(1.0f, 1.0f);
|
||||
@@ -4257,7 +4290,7 @@ void dFile_select_c::fileSelectWide() {
|
||||
mSelDt.ScrDt->search(MULTI_CHAR('fuku_n2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
|
||||
// Spirals & Memory Card Text
|
||||
for (PaneCache& entry : fileSelPanes) {
|
||||
for (dusk::utils::PaneCache& entry : fileSelPanes) {
|
||||
J2DPane* pane = fileSel.Scr->search(entry.tag);
|
||||
pane->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
}
|
||||
@@ -4283,7 +4316,7 @@ void dFile_select_c::fileSelectWide() {
|
||||
const f32 wideShiftFactor = mSelDt.ScrDt->search(MULTI_CHAR('gray_n'))->getTranslateX() * (wideScaleFactor - mDoGph_gInf_c::hudAspectScaleDown);
|
||||
const f32 ultraShiftFactor = mSelDt.ScrDt->search(MULTI_CHAR('gray_n'))->getTranslateX() * (ultraScaleFactor - mDoGph_gInf_c::hudAspectScaleDown);
|
||||
|
||||
for (PaneCache& entry : mSelDtPanes) {
|
||||
for (dusk::utils::PaneCache& entry : mSelDtPanes) {
|
||||
const size_t index = &entry - mSelDtPanes;
|
||||
J2DPane* pane = mSelDt.ScrDt->search(entry.tag);
|
||||
pane->setBasePosition(J2DBasePosition_0);
|
||||
@@ -4351,7 +4384,7 @@ void dFile_select_c::fileSelectWide() {
|
||||
}
|
||||
|
||||
// Spirals & Memory Card Text
|
||||
for (PaneCache& entry : fileSelPanes) {
|
||||
for (dusk::utils::PaneCache& entry : fileSelPanes) {
|
||||
J2DPane* pane = fileSel.Scr->search(entry.tag);
|
||||
pane->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
}
|
||||
|
||||
+17
-1
@@ -741,8 +741,12 @@ void item_func_ARMOR() {}
|
||||
void item_func_WEAR_ZORA() {}
|
||||
|
||||
void item_func_MAGIC_LV1() {
|
||||
#if TARGET_PC
|
||||
dComIfGs_onEventBit(0xD04);
|
||||
#else
|
||||
dComIfGp_setItemMagicCount(16);
|
||||
dComIfGp_setItemMaxMagicCount(16);
|
||||
#endif
|
||||
}
|
||||
|
||||
void item_func_DUNGEON_EXIT_2() {
|
||||
@@ -1152,7 +1156,15 @@ void item_func_M_MAYFLY() {}
|
||||
|
||||
void item_func_F_MAYFLY() {}
|
||||
|
||||
void item_func_POU_SPIRIT() {}
|
||||
void item_func_POU_SPIRIT() {
|
||||
#if TARGET_PC
|
||||
dComIfGs_addPohSpiritNum();
|
||||
if (dComIfGs_getPohSpiritNum() == 20) {
|
||||
/* dSv_event_flag_c::F_0457 - Castle Town - Revived cat */
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[457]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void item_func_ANCIENT_DOCUMENT() {
|
||||
dComIfGs_setItem(SLOT_22, dItemNo_ANCIENT_DOCUMENT_e);
|
||||
@@ -1411,7 +1423,11 @@ int item_getcheck_func_WEAR_ZORA() {
|
||||
}
|
||||
|
||||
int item_getcheck_func_MAGIC_LV1() {
|
||||
#if TARGET_PC
|
||||
return dComIfGs_isEventBit(0xD04);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int item_getcheck_func_DUNGEON_EXIT_2() {
|
||||
|
||||
@@ -53,7 +53,11 @@ DUSK_GAME_DATA dItem_itemResource dItem_data::item_resource[] = {
|
||||
{"F_gD_rupy", 0x0004,-0x0001,-0x0001, 0x0007,-0x0001, 0x0, -0x1, 0x006B, 0x64, 0x0000},
|
||||
{"O_gD_marm", 0x0003,-0x0001,-0x0001,-0x0001,-0x0001, -0x1, -0x1, 0x0041, 0x64, 0x01A9},
|
||||
{"O_gD_zora", 0x0003,-0x0001,-0x0001,-0x0001,-0x0001, -0x1, -0x1, 0x004D, 0x64, 0x01AA},
|
||||
#if TARGET_PC
|
||||
{"O_gD_Injy", 0x0003,-0x0001,-0x0001,-0x0001,-0x0001, -0x1, -0x1, 0x002E, 0x64, 0x0000},
|
||||
#else
|
||||
{"O_gD_Injy", 0x0003,-0x0001,-0x0001,-0x0001,-0x0001, -0x1, -0x1, 0x002D, 0x64, 0x0000},
|
||||
#endif
|
||||
{"O_gD_TKS", 0x0008,-0x0001, 0x0005,-0x0001,-0x0001, -0x1, -0x1, 0x0028, 0x64, 0x0000},
|
||||
{"O_gD_puL2", 0x0003,-0x0001,-0x0001,-0x0001,-0x0001, -0x1, -0x1, 0x0047, 0x64, 0x0000},
|
||||
{"O_gD_puL2", 0x0003,-0x0001,-0x0001,-0x0001,-0x0001, -0x1, -0x1, 0x0048, 0x64, 0x0000},
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/menu_pointer.h"
|
||||
#include "dusk/utilities.hpp"
|
||||
#endif
|
||||
|
||||
typedef void (dMenu_Collect2D_c::*initFunc)();
|
||||
@@ -101,11 +102,44 @@ dMenu_Collect2D_c::~dMenu_Collect2D_c() {
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
static dusk::utils::PaneCache mpScreenPanes[] = {
|
||||
{MULTI_CHAR('sa_tex_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('op_tex_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('heart_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('wolf_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('item_0_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('item_1_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('item_2_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fish_3_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('lett_4_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('maki_5_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fuku_n0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fuku_n1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('fuku_n2'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('tate_n0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('tate_n1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('ken_n0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('ken_n1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('kabu_6n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('t_t00'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('f_t00'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('itemn_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('infotxtn'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('sa_op_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('title_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('menu_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('w_er_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('center_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('info_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('lavel_n'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('modelbgn'), 0.0f, 0.0f, false},
|
||||
};
|
||||
|
||||
void dMenu_Collect2D_c::menuCollectWide() {
|
||||
static bool cachedPanes = false;
|
||||
// Get pre-scale values for each pane
|
||||
if (!cachedPanes) {
|
||||
for (PaneCache& entry : mpScreenPanes) {
|
||||
for (dusk::utils::PaneCache& entry : mpScreenPanes) {
|
||||
J2DPane* pane = mpScreen->search(entry.tag);
|
||||
if (!entry.cached) {
|
||||
entry.origTransX = pane->getTranslateX();
|
||||
@@ -119,7 +153,7 @@ void dMenu_Collect2D_c::menuCollectWide() {
|
||||
// Reset all panes
|
||||
mpScreen->scale(1.0f, 1.0f);
|
||||
mpScreen->translate(0.0f, 0.0f);
|
||||
for (PaneCache& entry : mpScreenPanes) {
|
||||
for (dusk::utils::PaneCache& entry : mpScreenPanes) {
|
||||
J2DPane* pane = mpScreen->search(entry.tag);
|
||||
pane->scale(1.0f, 1.0f);
|
||||
pane->translate(entry.origTransX, entry.origTransY);
|
||||
|
||||
@@ -1900,3 +1900,542 @@ void dMeter2Info_set2DVibrationT() {}
|
||||
void dMeter2Info_set2DVibration() {}
|
||||
|
||||
void dMeter2Info_set2DVibrationM() {}
|
||||
|
||||
#if TARGET_PC
|
||||
void dMeter2Info_Initialize() {
|
||||
g_meter2_info.init();
|
||||
}
|
||||
|
||||
dMeterMap_c* dMeter2Info_getMeterMapClass() {
|
||||
return g_meter2_info.getMeterMapClass();
|
||||
}
|
||||
|
||||
dMw_c* dMeter2Info_getMenuWindowClass() {
|
||||
return g_meter2_info.getMenuWindowClass();
|
||||
}
|
||||
|
||||
void dMeter2Info_setWindowStatus(u8 i_status) {
|
||||
g_meter2_info.setWindowStatus(i_status);
|
||||
}
|
||||
|
||||
CPaneMgr* dMeter2Info_getMeterItemPanePtr(s32 i_idx) {
|
||||
return g_meter2_info.getMeterItemPanePtr(i_idx);
|
||||
}
|
||||
|
||||
void dMeter2Info_getString(u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry) {
|
||||
g_meter2_info.getString(i_stringID, o_string, i_msgEntry);
|
||||
}
|
||||
|
||||
void dMeter2Info_getStringKanji(u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry) {
|
||||
g_meter2_info.getStringKanji(i_stringID, o_string, i_msgEntry);
|
||||
}
|
||||
|
||||
void dMeter2Info_getStringKana(u32 i_stringID, TEXT_SPAN o_string, JMSMesgEntry_c* i_msgEntry) {
|
||||
g_meter2_info.getStringKana(i_stringID, o_string, i_msgEntry);
|
||||
}
|
||||
|
||||
f32 dMeter2Info_getStringLength(JUTFont* i_font, f32 param_2, f32 param_3, char* i_string) {
|
||||
return g_meter2_info.getStringLength(i_font, param_2, param_3, i_string);
|
||||
}
|
||||
|
||||
f32 dMeter2Info_getStringLength(J2DTextBox* i_textbox, char* i_string) {
|
||||
return g_meter2_info.getStringLength(i_textbox, i_string);
|
||||
}
|
||||
|
||||
void dMeter2Info_setHotSpringTimer(u8 i_slotNo) {
|
||||
g_meter2_info.setHotSpringTimer(i_slotNo);
|
||||
}
|
||||
|
||||
u16 dMeter2Info_getOilGaugeBackUp() {
|
||||
return g_meter2_info.getOilGaugeBackUp();
|
||||
}
|
||||
|
||||
void dMeter2Info_setOilGaugeBackUp(u16 param_1) {
|
||||
g_meter2_info.setOilGaugeBackUp(param_1);
|
||||
}
|
||||
|
||||
void dMeter2Info_setSaveStageName(const char* i_stageName) {
|
||||
g_meter2_info.setSaveStageName(i_stageName);
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getInsectSelectType() {
|
||||
return g_meter2_info.getInsectSelectType();
|
||||
}
|
||||
|
||||
void dMeter2Info_setInsectSelectType(u8 i_type) {
|
||||
g_meter2_info.setInsectSelectType(i_type);
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getWarpStatus() {
|
||||
return g_meter2_info.getWarpStatus();
|
||||
}
|
||||
|
||||
void dMeter2Info_setWarpStatus(u8 i_status) {
|
||||
return g_meter2_info.setWarpStatus(i_status);
|
||||
}
|
||||
|
||||
int dMeter2Info_readItemTexture(u8 i_itemNo, void* i_texBuf1, J2DPicture* i_pic1, void* i_texBuf2,
|
||||
J2DPicture* i_pic2, void* i_texBuf3, J2DPicture* i_pic3, void* i_texBuf4, J2DPicture* i_pic4,
|
||||
int param_9) {
|
||||
return g_meter2_info.readItemTexture(i_itemNo, i_texBuf1, i_pic1, i_texBuf2, i_pic2, i_texBuf3,
|
||||
i_pic3, i_texBuf4, i_pic4, param_9);
|
||||
}
|
||||
|
||||
void dMeter2Info_setItemColor(
|
||||
u8 i_itemNo, J2DPicture* i_pic1, J2DPicture* i_pic2, J2DPicture* i_pic3, J2DPicture* i_pic4) {
|
||||
g_meter2_info.setItemColor(i_itemNo, i_pic1, i_pic2, i_pic3, i_pic4);
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getWarpRoomNo() {
|
||||
return g_meter2_info.getWarpRoomNo();
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getWarpPlayerNo() {
|
||||
return g_meter2_info.getWarpPlayerNo();
|
||||
}
|
||||
|
||||
cXyz& dMeter2Info_getWarpPos() {
|
||||
return g_meter2_info.getWarpPos();
|
||||
}
|
||||
|
||||
const char* dMeter2Info_getWarpStageName() {
|
||||
return g_meter2_info.getWarpStageName();
|
||||
}
|
||||
|
||||
void dMeter2Info_setNowCount(u8 i_count) {
|
||||
g_meter2_info.setNowCount(i_count);
|
||||
}
|
||||
|
||||
void dMeter2Info_setMaxCount(u8 i_count) {
|
||||
g_meter2_info.setMaxCount(i_count);
|
||||
}
|
||||
|
||||
BOOL dMeter2Info_isDirectUseItem(int param_0) {
|
||||
return g_meter2_info.isDirectUseItem(param_0);
|
||||
}
|
||||
|
||||
bool dMeter2Info_isUseButton(int i_buttonBit) {
|
||||
return g_meter2_info.isUseButton(i_buttonBit);
|
||||
}
|
||||
|
||||
void dMeter2Info_setMeterMapClass(dMeterMap_c* i_map) {
|
||||
g_meter2_info.setMeterMapClass(i_map);
|
||||
}
|
||||
|
||||
void dMeter2Info_decHotSpringTimer() {
|
||||
g_meter2_info.decHotSpringTimer();
|
||||
}
|
||||
|
||||
void dMeter2Info_allUseButton() {
|
||||
g_meter2_info.allUseButton();
|
||||
}
|
||||
|
||||
void dMeter2Info_offUseButton(int i_buttonBit) {
|
||||
g_meter2_info.offUseButton(i_buttonBit);
|
||||
}
|
||||
|
||||
void dMeter2Info_resetGameStatus() {
|
||||
g_meter2_info.resetGameStatus();
|
||||
}
|
||||
|
||||
void dMeter2Info_onGameStatus(int i_status) {
|
||||
g_meter2_info.onGameStatus(i_status);
|
||||
}
|
||||
|
||||
void dMeter2Info_setMapStatus(u8 i_status) {
|
||||
g_meter2_info.setMapStatus(i_status);
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getMapStatus() {
|
||||
return g_meter2_info.getMapStatus();
|
||||
}
|
||||
|
||||
void dMeter2Info_setPauseStatus(u8 i_status) {
|
||||
g_meter2_info.setPauseStatus(i_status);
|
||||
}
|
||||
|
||||
void dMeter2Info_resetPauseStatus() {
|
||||
g_meter2_info.resetPauseStatus();
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getPauseStatus() {
|
||||
return g_meter2_info.getPauseStatus();
|
||||
}
|
||||
|
||||
bool dMeter2Info_isGameStatus(int i_status) {
|
||||
return g_meter2_info.isGameStatus(i_status);
|
||||
}
|
||||
|
||||
bool dMeter2Info_isTouchKeyCheck(int i_status) {
|
||||
return g_meter2_info.isTouchKeyCheck(i_status);
|
||||
}
|
||||
|
||||
void dMeter2Info_setMapKeyDirection(u16 i_direction) {
|
||||
g_meter2_info.setMapKeyDirection(i_direction);
|
||||
}
|
||||
|
||||
bool dMeter2Info_isSub2DStatus(int i_flag) {
|
||||
return g_meter2_info.isSub2DStatus(i_flag);
|
||||
}
|
||||
|
||||
void dMeter2Info_offMenuInForce(int i_flag) {
|
||||
g_meter2_info.offMenuInForce(i_flag);
|
||||
}
|
||||
|
||||
bool dMeter2Info_isMenuInForce(int i_flag) {
|
||||
return g_meter2_info.isMenuInForce(i_flag);
|
||||
}
|
||||
|
||||
void dMeter2Info_setMenuWindowClass(dMw_c* i_menu) {
|
||||
g_meter2_info.setMenuWindowClass(i_menu);
|
||||
}
|
||||
|
||||
void dMeter2Info_resetWarpStatus() {
|
||||
g_meter2_info.resetWarpStatus();
|
||||
}
|
||||
|
||||
u16 dMeter2Info_getMapKeyDirection() {
|
||||
return g_meter2_info.getMapKeyDirection();
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getWindowStatus() {
|
||||
return g_meter2_info.getWindowStatus();
|
||||
}
|
||||
|
||||
void dMeter2Info_setMsgResource(void* i_res) {
|
||||
g_meter2_info.setMsgResource(i_res);
|
||||
}
|
||||
|
||||
void dMeter2Info_setStageMsgResource(void* i_res) {
|
||||
g_meter2_info.setStageMsgResource(i_res);
|
||||
}
|
||||
|
||||
void dMeter2Info_setMsgUnitResource(void* i_res) {
|
||||
g_meter2_info.setMsgUnitResource(i_res);
|
||||
}
|
||||
|
||||
void* dMeter2Info_getMsgResource() {
|
||||
return g_meter2_info.getMsgResource();
|
||||
}
|
||||
|
||||
void* dMeter2Info_getStageMsgResource() {
|
||||
return g_meter2_info.getStageMsgResource();
|
||||
}
|
||||
|
||||
void* dMeter2Info_getMsgUnitResource() {
|
||||
return g_meter2_info.getMsgUnitResource();
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getLightDropGetFlag(int i_no) {
|
||||
return g_meter2_info.getLightDropGetFlag(i_no);
|
||||
}
|
||||
|
||||
s32 dMeter2Info_getMeterStringType() {
|
||||
return g_meter2_info.getMeterStringType();
|
||||
}
|
||||
|
||||
void dMeter2Info_setMeterClass(dMeter2_c* i_meter) {
|
||||
g_meter2_info.setMeterClass(i_meter);
|
||||
}
|
||||
|
||||
void dMeter2Info_onLifeGaugeSE() {
|
||||
g_meter2_info.onLifeGaugeSE();
|
||||
}
|
||||
|
||||
void dMeter2Info_offLifeGaugeSE() {
|
||||
g_meter2_info.offLifeGaugeSE();
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getLifeGaugeSE() {
|
||||
return g_meter2_info.getLifeGaugeSE();
|
||||
}
|
||||
|
||||
const char* dMeter2Info_getSaveStageName() {
|
||||
return g_meter2_info.getSaveStageName();
|
||||
}
|
||||
|
||||
void dMeter2Info_onShopTalkFlag() {
|
||||
g_meter2_info.onShopTalkFlag();
|
||||
}
|
||||
|
||||
void dMeter2Info_setLightDropGetFlag(int i_no, u8 i_flag) {
|
||||
g_meter2_info.setLightDropGetFlag(i_no, i_flag);
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getRentalBombBag() {
|
||||
return g_meter2_info.getRentalBombBag();
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getMiniGameItemSetFlag() {
|
||||
return g_meter2_info.getMiniGameItemSetFlag();
|
||||
}
|
||||
|
||||
void dMeter2Info_setMiniGameItem(u8 i_minigameFlag) {
|
||||
g_meter2_info.setMiniGameItem(i_minigameFlag);
|
||||
}
|
||||
|
||||
void dMeter2Info_resetMiniGameItem(bool i_saveItem) {
|
||||
g_meter2_info.resetMiniGameItem(i_saveItem);
|
||||
}
|
||||
|
||||
void dMeter2Info_setTableMapRegionNo(u8 i_regionNo) {
|
||||
g_meter2_info.setTableMapRegionNo(i_regionNo);
|
||||
}
|
||||
|
||||
void dMeter2Info_setGoldWolfMapType(u8 i_mapType) {
|
||||
g_meter2_info.setGoldWolfMapType(i_mapType);
|
||||
}
|
||||
|
||||
void dMeter2Info_changeWater(u8 i_slotNo) {
|
||||
g_meter2_info.changeWater(i_slotNo);
|
||||
}
|
||||
|
||||
void dMeter2Info_warpInProc() {
|
||||
g_meter2_info.warpInProc();
|
||||
}
|
||||
|
||||
void dMeter2Info_warpOutProc() {
|
||||
g_meter2_info.warpOutProc();
|
||||
}
|
||||
|
||||
dMeter2_c* dMeter2Info_getMeterClass() {
|
||||
return g_meter2_info.getMeterClass();
|
||||
}
|
||||
|
||||
s16 dMeter2Info_getMsgKeyWaitTimer() {
|
||||
return g_meter2_info.getMsgKeyWaitTimer();
|
||||
}
|
||||
|
||||
void dMeter2Info_onDirectUseItem(int param_0) {
|
||||
g_meter2_info.onDirectUseItem(param_0);
|
||||
}
|
||||
|
||||
void dMeter2Info_setFloatingFlow(u16 i_flowID, s16 i_msgTimer, bool i_wakuVisible) {
|
||||
g_meter2_info.setFloatingFlow(i_flowID, i_msgTimer, i_wakuVisible);
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getGameOverType() {
|
||||
return g_meter2_info.getGameOverType();
|
||||
}
|
||||
|
||||
void dMeter2Info_setGameOverType(u8 i_gameoverType) {
|
||||
g_meter2_info.setGameOverType(i_gameoverType);
|
||||
}
|
||||
|
||||
void dMeter2Info_setMsgKeyWaitTimer(s16 i_waitTimer) {
|
||||
g_meter2_info.setMsgKeyWaitTimer(i_waitTimer);
|
||||
}
|
||||
|
||||
s32 dMeter2Info_getMsgTimeMs() {
|
||||
return g_meter2_info.getMsgTimeMs();
|
||||
}
|
||||
|
||||
s32 dMeter2Info_getTimeMs() {
|
||||
return g_meter2_info.getTimeMs();
|
||||
}
|
||||
|
||||
void dMeter2Info_setMsgTimeMs(s32 i_msgTime) {
|
||||
g_meter2_info.setMsgTimeMs(i_msgTime);
|
||||
}
|
||||
|
||||
void dMeter2Info_setTimeMs(s32 i_time) {
|
||||
g_meter2_info.setTimeMs(i_time);
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getNowCount() {
|
||||
return g_meter2_info.getNowCount();
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getMaxCount() {
|
||||
return g_meter2_info.getMaxCount();
|
||||
}
|
||||
|
||||
void dMeter2Info_setScopeZoomPointer(u8 param_0) {
|
||||
g_meter2_info.setScopeZoomPointer(param_0);
|
||||
}
|
||||
|
||||
void dMeter2Info_decMsgKeyWaitTimer() {
|
||||
g_meter2_info.decMsgKeyWaitTimer();
|
||||
}
|
||||
|
||||
bool dMeter2Info_isFloatingMessageVisible() {
|
||||
return g_meter2_info.isFloatingMessageVisible();
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getItemExplainWindowStatus() {
|
||||
return g_meter2_info.getItemExplainWindowStatus();
|
||||
}
|
||||
|
||||
void dMeter2Info_setItemExplainWindowStatus(u8 i_value) {
|
||||
g_meter2_info.setItemExplainWindowStatus(i_value);
|
||||
}
|
||||
|
||||
void dMeter2Info_resetDirectUseItem() {
|
||||
g_meter2_info.resetDirectUseItem();
|
||||
}
|
||||
|
||||
u16 dMeter2Info_getFloatingFlowID() {
|
||||
return g_meter2_info.getFloatingFlowID();
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getCollectCursorPosX() {
|
||||
return g_meter2_info.getCollectCursorPosX();
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getCollectCursorPosY() {
|
||||
return g_meter2_info.getCollectCursorPosY();
|
||||
}
|
||||
|
||||
void dMeter2Info_setCollectCursorPosXY(u8 x, u8 y) {
|
||||
g_meter2_info.setCollectCursorPosXY(x, y);
|
||||
}
|
||||
|
||||
void dMeter2Info_onBlinkButton(int i_flag) {
|
||||
g_meter2_info.onBlinkButton(i_flag);
|
||||
}
|
||||
|
||||
bool dMeter2Info_isFloatingMessageWakuVisible() {
|
||||
return g_meter2_info.isFloatingMessageWakuVisible();
|
||||
}
|
||||
|
||||
bool dMeter2Info_isBlinkButton(int i_flag) {
|
||||
return g_meter2_info.isBlinkButton(i_flag);
|
||||
}
|
||||
|
||||
void dMeter2Info_resetBlinkButton() {
|
||||
g_meter2_info.resetBlinkButton();
|
||||
}
|
||||
|
||||
void dMeter2Info_resetFloatingMessage() {
|
||||
g_meter2_info.resetFloatingMessage();
|
||||
}
|
||||
|
||||
s16 dMeter2Info_decFloatingMessageTimer() {
|
||||
return g_meter2_info.decFloatingMessageTimer();
|
||||
}
|
||||
|
||||
s16 dMeter2Info_getFloatingMessageTimer() {
|
||||
return g_meter2_info.getFloatingMessageTimer();
|
||||
}
|
||||
|
||||
u16 dMeter2Info_getFloatingMessageID() {
|
||||
return g_meter2_info.getFloatingMessageID();
|
||||
}
|
||||
|
||||
s16 dMeter2Info_getHorseLifeCount() {
|
||||
return g_meter2_info.getHorseLifeCount();
|
||||
}
|
||||
|
||||
void dMeter2Info_setMeterString(s32 i_string) {
|
||||
g_meter2_info.setMeterString(i_string);
|
||||
}
|
||||
|
||||
void dMeter2Info_resetMeterString() {
|
||||
g_meter2_info.resetMeterString();
|
||||
}
|
||||
|
||||
void dMeter2Info_setMeterItemPanePtr(int i_no, CPaneMgr* i_pane) {
|
||||
g_meter2_info.setMeterItemPanePtr(i_no, i_pane);
|
||||
}
|
||||
|
||||
bool dMeter2Info_isShopTalkFlag() {
|
||||
return g_meter2_info.isShopTalkFlag();
|
||||
}
|
||||
|
||||
void dMeter2Info_setMapDrugFlag(bool i_flag) {
|
||||
g_meter2_info.setMapDrugFlag(i_flag);
|
||||
}
|
||||
|
||||
bool dMeter2Info_isTempBit(int i_bit) {
|
||||
return g_meter2_info.isTempBit(i_bit);
|
||||
}
|
||||
|
||||
void dMeter2Info_offSub2DStatus(int i_bit) {
|
||||
g_meter2_info.offSub2DStatus(i_bit);
|
||||
}
|
||||
|
||||
void dMeter2Info_onSub2DStatus(int i_bit) {
|
||||
g_meter2_info.onSub2DStatus(i_bit);
|
||||
}
|
||||
|
||||
void dMeter2Info_set2DWidth(f32 i_width) {
|
||||
g_meter2_info.set2DWidth(i_width);
|
||||
}
|
||||
|
||||
void dMeter2Info_set2DHeight(f32 i_height) {
|
||||
g_meter2_info.set2DHeight(i_height);
|
||||
}
|
||||
|
||||
void dMeter2Info_set2DPosH(f32 i_posH) {
|
||||
g_meter2_info.set2DPosH(i_posH);
|
||||
}
|
||||
|
||||
void dMeter2Info_set2DPosV(f32 i_posV) {
|
||||
g_meter2_info.set2DPosV(i_posV);
|
||||
}
|
||||
|
||||
void dMeter2Info_offShopTalkFlag() {
|
||||
g_meter2_info.offShopTalkFlag();
|
||||
}
|
||||
|
||||
void dMeter2Info_onUseButton(int i_button) {
|
||||
g_meter2_info.onUseButton(i_button);
|
||||
}
|
||||
|
||||
f32 dMeter2Info_get2DWidth() {
|
||||
return g_meter2_info.get2DWidth();
|
||||
}
|
||||
|
||||
f32 dMeter2Info_get2DHeight() {
|
||||
return g_meter2_info.get2DHeight();
|
||||
}
|
||||
|
||||
void dMeter2Info_setWarpInfo(const char* i_stageName, const cXyz& i_position, s16 i_angle,
|
||||
u8 i_roomNo, u8 param_4, u8 i_warpPlayerNo) {
|
||||
g_meter2_info.setWarpInfo(i_stageName, i_position, i_angle, i_roomNo, param_4, i_warpPlayerNo);
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getTableMapRegionNo() {
|
||||
return g_meter2_info.getTableMapRegionNo();
|
||||
}
|
||||
|
||||
u8 dMeter2Info_getGoldWolfMapType() {
|
||||
return g_meter2_info.getGoldWolfMapType();
|
||||
}
|
||||
|
||||
bool dMeter2Info_isWindowAccept(int param_0) {
|
||||
return g_meter2_info.isWindowAccept(param_0);
|
||||
}
|
||||
|
||||
void dMeter2Info_setHorseLifeCount(s16 i_count) {
|
||||
g_meter2_info.setHorseLifeCount(i_count);
|
||||
}
|
||||
|
||||
void dMeter2Info_offTempBit(int i_bit) {
|
||||
g_meter2_info.offTempBit(i_bit);
|
||||
}
|
||||
|
||||
void dMeter2Info_onTempBit(int i_bit) {
|
||||
g_meter2_info.onTempBit(i_bit);
|
||||
}
|
||||
|
||||
void dMeter2Info_setFloatingMessage(u16 i_msgID, s16 i_msgTimer, bool i_wakuVisible) {
|
||||
g_meter2_info.setFloatingMessage(i_msgID, i_msgTimer, i_wakuVisible);
|
||||
}
|
||||
|
||||
void dMeter2Info_setMiniGameCount(s8 i_count) {
|
||||
g_meter2_info.setMiniGameCount(i_count);
|
||||
}
|
||||
|
||||
void dMeter2Info_onWindowAccept(int param_0) {
|
||||
g_meter2_info.onWindowAccept(param_0);
|
||||
}
|
||||
|
||||
void dMeter2Info_offWindowAccept(int param_0) {
|
||||
g_meter2_info.offWindowAccept(param_0);
|
||||
}
|
||||
|
||||
void dMeter2Info_onMenuInForce(int param_0) {
|
||||
g_meter2_info.onMenuInForce(param_0);
|
||||
}
|
||||
#endif
|
||||
|
||||
+93
-3
@@ -16,6 +16,21 @@
|
||||
#if TARGET_PC
|
||||
#include "dusk/menu_pointer.h"
|
||||
#include "dusk/scope_guard.hpp"
|
||||
#include "helpers/bits.hpp"
|
||||
|
||||
static bool read_full_color(const void* data, u32 size, u32& ccColor, u32& gcColor) {
|
||||
if (size == 4) {
|
||||
ccColor = dusk::read_bits<u32>(data);
|
||||
gcColor = ccColor;
|
||||
return true;
|
||||
}
|
||||
if (size == 8) {
|
||||
ccColor = dusk::read_bits<u32>(data);
|
||||
gcColor = dusk::read_bits<u32>(static_cast<const u8*>(data) + sizeof(ccColor));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
@@ -400,6 +415,9 @@ jmessage_tReference::jmessage_tReference() {
|
||||
resetCharCountBuffer();
|
||||
mNowColorType = 0;
|
||||
mTopColorType = 0;
|
||||
#if TARGET_PC
|
||||
resetColors();
|
||||
#endif
|
||||
mButtonTagStopFlag = 0;
|
||||
mPageEndCount = 0;
|
||||
mSelectNum = 0;
|
||||
@@ -594,6 +612,13 @@ void jmessage_tReference::pageSend() {
|
||||
if (mNowColorType != mTopColorType) {
|
||||
mTopColorType = mNowColorType;
|
||||
}
|
||||
#if TARGET_PC
|
||||
mTopFullColor = mNowFullColor;
|
||||
if (mNowFullColor) {
|
||||
mTopCCColor = mNowCCColor;
|
||||
mTopGCColor = mNowGCColor;
|
||||
}
|
||||
#endif
|
||||
|
||||
mTopWordCount = mNowWordCount;
|
||||
mCharAlpha = 0.0f;
|
||||
@@ -1917,6 +1942,9 @@ void jmessage_tSequenceProcessor::do_begin(void const* pEntry, char const* pszTe
|
||||
pReference->resetCharCnt();
|
||||
pReference->setNowColorType(0);
|
||||
pReference->setTopColorType(0);
|
||||
#if TARGET_PC
|
||||
pReference->resetColors();
|
||||
#endif
|
||||
pReference->setNowWordCount(0);
|
||||
pReference->setTopWordCount(0);
|
||||
pReference->setBatchColorFlag(0);
|
||||
@@ -2280,9 +2308,21 @@ bool jmessage_tSequenceProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_si
|
||||
return true;
|
||||
case MSGTAG_GROUP(255):
|
||||
switch (i_tag) {
|
||||
case MSGTAG_COLOR:
|
||||
case MSGTAG_COLOR: {
|
||||
#if TARGET_PC
|
||||
u32 ccColor;
|
||||
u32 gcColor;
|
||||
if (read_full_color(i_data, i_size, ccColor, gcColor)) {
|
||||
pReference->setFullColor(ccColor, gcColor);
|
||||
} else if (i_size == 1) {
|
||||
pReference->clearNowFullColor();
|
||||
pReference->setNowColorType(*(u8*)i_data & 0xFF);
|
||||
}
|
||||
#else
|
||||
pReference->setNowColorType(*(u8*)i_data & 0xFF);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
case MSGTAG_SCALE:
|
||||
pReference->setNowTagScale(*(BE(u16)*)i_data & 0xFFFF);
|
||||
return true;
|
||||
@@ -2863,7 +2903,15 @@ void jmessage_tRenderingProcessor::do_begin(void const* pEntry, char const* pszT
|
||||
do_scale(field_0x44);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (pReference->hasTopFullColor()) {
|
||||
do_fullcolor(pReference->getTopCCColor(), pReference->getTopGCColor());
|
||||
} else {
|
||||
do_color(pReference->getTopColorType());
|
||||
}
|
||||
#else
|
||||
do_color(pReference->getTopColorType());
|
||||
#endif
|
||||
pReference->resetDrawLightCount();
|
||||
|
||||
do_widthcenter();
|
||||
@@ -3017,9 +3065,20 @@ bool jmessage_tRenderingProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_s
|
||||
return 1;
|
||||
case MSGTAG_GROUP(255):
|
||||
switch (i_tag) {
|
||||
case MSGTAG_COLOR:
|
||||
case MSGTAG_COLOR: {
|
||||
#if TARGET_PC
|
||||
u32 ccColor;
|
||||
u32 gcColor;
|
||||
if (read_full_color(i_data, i_size, ccColor, gcColor)) {
|
||||
do_fullcolor(ccColor, gcColor);
|
||||
} else if (i_size == 1) {
|
||||
do_color(*(u8*)i_data & 0xFF);
|
||||
}
|
||||
#else
|
||||
do_color(*(u8*)i_data & 0xFF);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
case MSGTAG_SCALE:
|
||||
field_0x13c = *(BE(u16)*)i_data & 0xFFFF;
|
||||
do_scale(field_0x13c / 100.0f);
|
||||
@@ -3630,6 +3689,18 @@ void jmessage_tRenderingProcessor::do_color(u8 i_colorNo) {
|
||||
do_strcat(buffer, false, false, false);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
void jmessage_tRenderingProcessor::do_fullcolor(u32 ccColor, u32 gcColor) {
|
||||
mColorNo = 0xFF;
|
||||
mCCColor = ccColor;
|
||||
mGCColor = gcColor;
|
||||
|
||||
char buffer[40];
|
||||
SAFE_SPRINTF(buffer, "\x1B" "CC[%08x]" "\x1B" "GC[%08x]", mCCColor, mGCColor);
|
||||
do_strcat(buffer, false, false, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
void jmessage_tRenderingProcessor::do_scale(f32 param_1) {
|
||||
jmessage_tReference* pReference = (jmessage_tReference*)getReference();
|
||||
|
||||
@@ -4684,9 +4755,20 @@ bool jmessage_string_tRenderingProcessor::do_tag(u32 i_tag, void const* i_data,
|
||||
switch(i_tag & 0xFF0000) {
|
||||
case MSGTAG_GROUP(255):
|
||||
switch(i_tag) {
|
||||
case MSGTAG_COLOR:
|
||||
case MSGTAG_COLOR: {
|
||||
#if TARGET_PC
|
||||
u32 ccColor;
|
||||
u32 gcColor;
|
||||
if (read_full_color(i_data, i_size, ccColor, gcColor)) {
|
||||
do_fullcolor(ccColor, gcColor);
|
||||
} else if (i_size == 1) {
|
||||
do_color(*(u8*)i_data & 0xFF);
|
||||
}
|
||||
#else
|
||||
do_color(*(u8*)i_data & 0xFF);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case MSGTAG_SCALE:
|
||||
do_scale(*(BE(u16)*)i_data / 100.0f);
|
||||
break;
|
||||
@@ -5336,6 +5418,14 @@ void jmessage_string_tRenderingProcessor::do_color(u8 i_colorNo) {
|
||||
do_strcat(buffer);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
void jmessage_string_tRenderingProcessor::do_fullcolor(u32 ccColor, u32 gcColor) {
|
||||
char buffer[32];
|
||||
SAFE_SPRINTF(buffer, "\x1b" "CC[%08x]" "\x1b" "GC[%08x]", ccColor, gcColor);
|
||||
do_strcat(buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
void jmessage_string_tRenderingProcessor::do_scale(f32 i_scale) {
|
||||
J2DTextBox::TFontSize fontSize;
|
||||
mpReference->getPanePtr()->getFontSize(fontSize);
|
||||
|
||||
+13
-4
@@ -43,6 +43,11 @@ u16 message_id(const MessageEntryData& entry) {
|
||||
return static_cast<u16>(static_cast<u16>(entry.bytes[4]) << 8 | entry.bytes[5]);
|
||||
}
|
||||
|
||||
u16 flow_group(int flowId) {
|
||||
const bool isCommonFlow = flowId >= 3000 && flowId < dusk::flow::kCustomNodeMin;
|
||||
return isCommonFlow ? 0 : static_cast<u16>(dMsgObject_getGroupID());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
@@ -70,8 +75,7 @@ void dMsgFlow_c::init(fopAc_ac_c* i_partner, int i_flowID, int param_2, fopAc_ac
|
||||
dMsgObject_changeFlowGroup(i_flowID);
|
||||
|
||||
#if TARGET_PC
|
||||
dusk::flow::bind_resource(dMsgObject_getMsgDtPtr(),
|
||||
i_flowID >= 3000 ? 0 : static_cast<u16>(dMsgObject_getGroupID()));
|
||||
dusk::flow::bind_resource(dMsgObject_getMsgDtPtr(), flow_group(i_flowID));
|
||||
#endif
|
||||
|
||||
if (param_2 == 0) {
|
||||
@@ -399,8 +403,7 @@ void dMsgFlow_c::setInitValueGroupChange(int i_msgNo, fopAc_ac_c** i_talkPartner
|
||||
|
||||
dMsgObject_changeFlowGroup(i_msgNo);
|
||||
#if TARGET_PC
|
||||
dusk::flow::bind_resource(dMsgObject_getMsgDtPtr(),
|
||||
i_msgNo >= 3000 ? 0 : static_cast<u16>(dMsgObject_getGroupID()));
|
||||
dusk::flow::bind_resource(dMsgObject_getMsgDtPtr(), flow_group(i_msgNo));
|
||||
#endif
|
||||
setInitValue(0);
|
||||
|
||||
@@ -446,6 +449,12 @@ u8* dMsgFlow_c::getMsgDataBlock(char const* block_tag) {
|
||||
}
|
||||
|
||||
u16 dMsgFlow_c::getInitNodeIndex(u16 param_1) {
|
||||
#if TARGET_PC
|
||||
if (param_1 >= dusk::flow::kCustomNodeMin) {
|
||||
return param_1;
|
||||
}
|
||||
#endif
|
||||
|
||||
u8* var_r30 = NULL;
|
||||
u16 var_r27 = -1;
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "dusk/language.hpp"
|
||||
#include "dusk/logging.h"
|
||||
#include "dusk/menu_pointer.h"
|
||||
#include "dusk/mods/item.hpp"
|
||||
#include "dusk/mods/svc/flow.hpp"
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/version.hpp"
|
||||
@@ -832,6 +833,9 @@ u32 dMsgObject_c::getMessageIndex(u32 param_0) {
|
||||
|
||||
u32 dMsgObject_c::getRevoMessageIndex(u32 param_1) {
|
||||
#if TARGET_PC
|
||||
const u16 sourceGroup = param_1 > 5000 ? static_cast<u16>(s_groupID) : 0;
|
||||
param_1 = dusk::mods::item_check_message(sourceGroup, param_1);
|
||||
|
||||
u16 customGroup = 0;
|
||||
if (param_1 <= 0xffff &&
|
||||
dusk::flow::custom_message_group(static_cast<u16>(param_1), customGroup))
|
||||
@@ -1861,7 +1865,11 @@ void dMsgObject_c::readMessageGroupLocal(mDoDvdThd_mountXArchive_c** p_arcMount)
|
||||
|
||||
void dMsgObject_c::changeFlowGroupLocal(s32 param_0) {
|
||||
mFlowChk = 1;
|
||||
#if TARGET_PC
|
||||
changeGroup(param_0 >= 3000 && param_0 < dusk::flow::kCustomNodeMin ? (s16)0 : s_groupID);
|
||||
#else
|
||||
changeGroup(param_0 >= 3000 ? (s16)0 : s_groupID);
|
||||
#endif
|
||||
}
|
||||
|
||||
void dMsgObject_c::demoMessageGroupLocal() {
|
||||
|
||||
+30
-9
@@ -10,6 +10,7 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "JSystem/J2DGraph/J2DAnmLoader.h"
|
||||
#include "dusk/utilities.hpp"
|
||||
#include "dusk/version.hpp"
|
||||
#include "f_op/f_op_msg_mng.h"
|
||||
|
||||
@@ -1512,11 +1513,31 @@ void dName_c::selectCursorPosSet(int row) {
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
|
||||
static dusk::utils::PaneCache l_tagName[] = {
|
||||
{MULTI_CHAR('m_00_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_00_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_00_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_00_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_00_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_01_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_01_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_01_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_01_3'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m_01_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_02_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_02_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_02_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_02_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_02_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m03_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m03_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m03_2'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m03_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m03_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_04_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_04_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_04_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_04_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_04_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_05_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_05_1'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m_05_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_05_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_05_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_06_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_06_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_06_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_06_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_06_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_07_0'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m_07_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_07_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_07_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_07_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_08_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_08_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_08_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_08_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_08_4'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m_09_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_09_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_09_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_09_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_09_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_10_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_10_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_10_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_10_3'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m_10_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_11_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_11_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_11_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_11_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m_11_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('m12_0'), 0.0f, 0.0f, false}, {MULTI_CHAR('m12_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('m12_2'), 0.0f, 0.0f, false},
|
||||
{MULTI_CHAR('m12_3'), 0.0f, 0.0f, false}, {MULTI_CHAR('m12_4'), 0.0f, 0.0f, false}, {MULTI_CHAR('p_end_2'), 0.0f, 0.0f, false}, {MULTI_CHAR('p_end_1'), 0.0f, 0.0f, false}, {MULTI_CHAR('p_end_0'), 0.0f, 0.0f, false},
|
||||
};
|
||||
|
||||
static dusk::utils::PaneCache l_nameTagName[] = {
|
||||
{MULTI_CHAR('name_00'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_01'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_02'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_03'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_04'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_05'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_06'), 0.0f, 0.0f, false}, {MULTI_CHAR('name_07'), 0.0f, 0.0f, false},
|
||||
};
|
||||
|
||||
static dusk::utils::PaneCache l_nameCurTagName[] = {
|
||||
{MULTI_CHAR('s__n_00'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_01'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_02'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_03'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_04'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_05'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_06'), 0.0f, 0.0f, false}, {MULTI_CHAR('s__n_07'), 0.0f, 0.0f, false},
|
||||
};
|
||||
|
||||
void dName_c::nameWide() {
|
||||
static bool cachedPanes = false;
|
||||
// Get pre-scale values for each pane
|
||||
if (!cachedPanes) {
|
||||
for (PaneCache& entry : l_tagName) {
|
||||
for (dusk::utils::PaneCache& entry : l_tagName) {
|
||||
J2DPane* pane = nameIn.NameInScr->search(entry.tag);
|
||||
if (!entry.cached) {
|
||||
entry.origTransX = pane->getTranslateX();
|
||||
@@ -1524,7 +1545,7 @@ void dName_c::nameWide() {
|
||||
entry.cached = true;
|
||||
}
|
||||
}
|
||||
for (PaneCache& entry : l_nameTagName) {
|
||||
for (dusk::utils::PaneCache& entry : l_nameTagName) {
|
||||
J2DPane* pane = nameIn.NameInScr->search(entry.tag);
|
||||
if (!entry.cached) {
|
||||
entry.origTransX = pane->getTranslateX();
|
||||
@@ -1532,7 +1553,7 @@ void dName_c::nameWide() {
|
||||
entry.cached = true;
|
||||
}
|
||||
}
|
||||
for (PaneCache& entry : l_nameCurTagName) {
|
||||
for (dusk::utils::PaneCache& entry : l_nameCurTagName) {
|
||||
J2DPane* pane = nameIn.NameInScr->search(entry.tag);
|
||||
if (!entry.cached) {
|
||||
entry.origTransX = pane->getTranslateX();
|
||||
@@ -1546,19 +1567,19 @@ void dName_c::nameWide() {
|
||||
// Reset all panes
|
||||
nameIn.NameInScr->scale(1.0f, 1.0f);
|
||||
nameIn.NameInScr->translate(0.0f, 0.0f);
|
||||
for (PaneCache& entry : l_tagName) {
|
||||
for (dusk::utils::PaneCache& entry : l_tagName) {
|
||||
J2DPane* pane = nameIn.NameInScr->search(entry.tag);
|
||||
pane->setBasePosition(J2DBasePosition_4);
|
||||
pane->scale(1.0f, 1.0f);
|
||||
pane->translate(entry.origTransX, entry.origTransY);
|
||||
}
|
||||
for (PaneCache& entry : l_nameTagName) {
|
||||
for (dusk::utils::PaneCache& entry : l_nameTagName) {
|
||||
J2DPane* pane = nameIn.NameInScr->search(entry.tag);
|
||||
pane->setBasePosition(J2DBasePosition_4);
|
||||
pane->scale(1.0f, 1.0f);
|
||||
pane->translate(entry.origTransX, entry.origTransY);
|
||||
}
|
||||
for (PaneCache& entry : l_nameCurTagName) {
|
||||
for (dusk::utils::PaneCache& entry : l_nameCurTagName) {
|
||||
J2DPane* pane = nameIn.NameInScr->search(entry.tag);
|
||||
pane->setBasePosition(J2DBasePosition_4);
|
||||
pane->scale(1.0f, 1.0f);
|
||||
@@ -1574,17 +1595,17 @@ void dName_c::nameWide() {
|
||||
break;
|
||||
default: // Wii and Dusklight
|
||||
// List of Characters Box
|
||||
for (PaneCache& entry : l_tagName) {
|
||||
for (dusk::utils::PaneCache& entry : l_tagName) {
|
||||
J2DPane* pane = nameIn.NameInScr->search(entry.tag);
|
||||
pane->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
}
|
||||
// Letters being typed
|
||||
for (PaneCache& entry : l_nameTagName) {
|
||||
for (dusk::utils::PaneCache& entry : l_nameTagName) {
|
||||
J2DPane* pane = nameIn.NameInScr->search(entry.tag);
|
||||
pane->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
}
|
||||
// Underscores when typing below letters
|
||||
for (PaneCache& entry : l_nameCurTagName) {
|
||||
for (dusk::utils::PaneCache& entry : l_nameCurTagName) {
|
||||
J2DPane* pane = nameIn.NameInScr->search(entry.tag);
|
||||
pane->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
|
||||
}
|
||||
|
||||
+28
-2
@@ -42,7 +42,9 @@
|
||||
#if TARGET_PC
|
||||
#include "dusk/autosave.h"
|
||||
#include "dusk/memory.h"
|
||||
#include "dusk/mods/item.hpp"
|
||||
#include "dusk/ui/ui.hpp"
|
||||
#include "mods/items.h"
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
@@ -1192,11 +1194,35 @@ static int phase_1(dScnPly_c* i_this) {
|
||||
}
|
||||
|
||||
// Stage: Ordon Spring, Room: Ordon Spring
|
||||
#if TARGET_PC
|
||||
const bool iliaMemoryArrival =
|
||||
!strcmp(dComIfGp_getStartStageName(), "F_SP104") && dComIfGp_getStartStageRoomNo() == 1 &&
|
||||
dComIfGp_getStartStagePoint() == 23 && dComIfGp_getStartStageLayer() == 12;
|
||||
const u32 iliaMemoryTag = dusk::mods::item_give_tag(ITEM_CHECK_ILIA_MEMORY);
|
||||
if (!iliaMemoryArrival) {
|
||||
dusk::mods::item_check_cancel(iliaMemoryTag);
|
||||
}
|
||||
if (iliaMemoryArrival)
|
||||
#else
|
||||
if (!strcmp(dComIfGp_getStartStageName(), "F_SP104") && dComIfGp_getStartStageRoomNo() == 1 &&
|
||||
dComIfGp_getStartStagePoint() == 23 && dComIfGp_getStartStageLayer() == 12)
|
||||
#endif
|
||||
{
|
||||
dComIfGs_onItemFirstBit(dItemNo_HORSE_FLUTE_e);
|
||||
dComIfGs_setItem(SLOT_21, dItemNo_HORSE_FLUTE_e);
|
||||
#if TARGET_PC
|
||||
const auto itemCheck =
|
||||
dusk::mods::item_check_commit(iliaMemoryTag, dItemNo_HORSE_FLUTE_e, nullptr);
|
||||
if (itemCheck.itemNo == dItemNo_HORSE_FLUTE_e) {
|
||||
#endif
|
||||
dComIfGs_onItemFirstBit(dItemNo_HORSE_FLUTE_e);
|
||||
dComIfGs_setItem(SLOT_21, dItemNo_HORSE_FLUTE_e);
|
||||
#if TARGET_PC
|
||||
dusk::mods::item_check_complete(itemCheck, nullptr);
|
||||
} else if (itemCheck.itemNo == dItemNo_NONE_e) {
|
||||
dusk::mods::item_check_complete(itemCheck, nullptr);
|
||||
} else {
|
||||
dusk::mods::item_check_enqueue(itemCheck, dusk::mods::ItemGiveMode::Silent);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((u8)dKy_darkworld_stage_check(dComIfGp_getStartStageName(),
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user