Better actor viewer (#3544)

* Update actorViewer.cpp

* Add more actors

* Add a search function

* Update actorViewer.cpp

* Add advanced mode for params
This commit is contained in:
Pepe20129 2023-12-27 01:09:04 +01:00 committed by GitHub
parent 70e1017923
commit e8096a2d94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 840 additions and 4 deletions

View File

@ -74,7 +74,7 @@ static std::unordered_map<u16, const char*> actorDescriptions = {
{ ACTOR_EN_BUBBLE, "Shabom" }, { ACTOR_EN_BUBBLE, "Shabom" },
{ ACTOR_DOOR_SHUTTER, "Shutter Door" }, { ACTOR_DOOR_SHUTTER, "Shutter Door" },
{ ACTOR_EN_DODOJR, "Baby Dodongo" }, { ACTOR_EN_DODOJR, "Baby Dodongo" },
{ ACTOR_EN_BDFIRE, "Empty" }, { ACTOR_EN_BDFIRE, "King Dodongo's Fire Breath" },
{ ACTOR_EN_BOOM, "Boomerang" }, { ACTOR_EN_BOOM, "Boomerang" },
{ ACTOR_EN_TORCH2, "Dark Link" }, { ACTOR_EN_TORCH2, "Dark Link" },
{ ACTOR_EN_BILI, "Biri" }, { ACTOR_EN_BILI, "Biri" },
@ -132,7 +132,7 @@ static std::unordered_map<u16, const char*> actorDescriptions = {
{ ACTOR_BG_TOKI_HIKARI, "Windows (Temple of Time)" }, { ACTOR_BG_TOKI_HIKARI, "Windows (Temple of Time)" },
{ ACTOR_EN_YUKABYUN, "Flying Floor Tile" }, { ACTOR_EN_YUKABYUN, "Flying Floor Tile" },
{ ACTOR_BG_TOKI_SWD, "Master Sword" }, { ACTOR_BG_TOKI_SWD, "Master Sword" },
{ ACTOR_EN_FHG_FIRE, "Empty" }, { ACTOR_EN_FHG_FIRE, "Phantom Ganon's Lighting Attack" },
{ ACTOR_BG_MJIN, "Warp Song Pad" }, { ACTOR_BG_MJIN, "Warp Song Pad" },
{ ACTOR_BG_HIDAN_KOUSI, "Sliding Metal Gate" }, { ACTOR_BG_HIDAN_KOUSI, "Sliding Metal Gate" },
{ ACTOR_DOOR_TOKI, "Door of Time Collision" }, { ACTOR_DOOR_TOKI, "Door of Time Collision" },
@ -548,6 +548,10 @@ int ActorDB::RetrieveId(const std::string& name) {
return entry->second; return entry->second;
} }
int ActorDB::GetEntryCount() {
return db.size();
}
ActorDB::Entry::Entry() { ActorDB::Entry::Entry() {
entry.name = nullptr; entry.name = nullptr;
entry.desc = nullptr; entry.desc = nullptr;

View File

@ -64,6 +64,7 @@ public:
static void AddBuiltInCustomActors(); static void AddBuiltInCustomActors();
int GetEntryCount();
private: private:
Entry& AddEntry(const std::string& name, const std::string& desc, size_t index); Entry& AddEntry(const std::string& name, const std::string& desc, size_t index);
Entry& AddEntry(const std::string& name, const std::string& desc, const ActorInit& init); Entry& AddEntry(const std::string& name, const std::string& desc, const ActorInit& init);

View File

@ -8,6 +8,7 @@
#include <array> #include <array>
#include <bit> #include <bit>
#include <map> #include <map>
#include <unordered_map>
#include <string> #include <string>
#include <libultraship/bridge.h> #include <libultraship/bridge.h>
#include <libultraship/libultraship.h> #include <libultraship/libultraship.h>
@ -24,6 +25,7 @@ extern PlayState* gPlayState;
#include "textures/icon_item_24_static/icon_item_24_static.h" #include "textures/icon_item_24_static/icon_item_24_static.h"
} }
#define DEKUNUTS_FLOWER 10
#define DEBUG_ACTOR_NAMETAG_TAG "debug_actor_viewer" #define DEBUG_ACTOR_NAMETAG_TAG "debug_actor_viewer"
typedef struct { typedef struct {
@ -107,6 +109,783 @@ void PopulateActorDropdown(int i, std::vector<Actor*>& data) {
} }
} }
//actors that don't use params at all
static std::vector<u16> noParamsActors = {
ACTOR_ARMS_HOOK,
ACTOR_ARROW_FIRE,
ACTOR_ARROW_ICE,
ACTOR_ARROW_LIGHT,
ACTOR_BG_BOM_GUARD,
ACTOR_BG_DY_YOSEIZO,
ACTOR_BG_GATE_SHUTTER,
ACTOR_BG_GJYO_BRIDGE,
ACTOR_BG_HIDAN_FSLIFT,
ACTOR_BG_HIDAN_RSEKIZOU,
ACTOR_BG_HIDAN_SYOKU,
ACTOR_BG_JYA_GOROIWA,
ACTOR_BG_MIZU_UZU,
ACTOR_BG_MORI_RAKKATENJO,
ACTOR_BG_PUSHBOX,
ACTOR_BG_SPOT01_FUSYA,
ACTOR_BG_SPOT01_IDOHASHIRA,
ACTOR_BG_SPOT01_IDOMIZU,
ACTOR_BG_SPOT01_IDOSOKO,
ACTOR_BG_SPOT11_OASIS,
ACTOR_BG_SPOT15_SAKU,
ACTOR_BG_SPOT18_FUTA,
ACTOR_BG_TOKI_SWD,
ACTOR_BG_TREEMOUTH,
ACTOR_BG_VB_SIMA,
ACTOR_BOSS_DODONGO,
ACTOR_BOSS_FD,
ACTOR_BOSS_GOMA,
ACTOR_DEMO_EXT,
ACTOR_DEMO_SHD,
ACTOR_DEMO_TRE_LGT,
ACTOR_DOOR_TOKI,
ACTOR_EFC_ERUPC,
ACTOR_EN_ANI,
ACTOR_EN_AROW_TRAP,
ACTOR_EN_BIRD,
ACTOR_EN_BLKOBJ,
ACTOR_EN_BOM_BOWL_MAN,
ACTOR_EN_BOM_BOWL_PIT,
ACTOR_EN_BOM_CHU,
ACTOR_EN_BUBBLE,
ACTOR_EN_DIVING_GAME,
ACTOR_EN_DNT_DEMO,
ACTOR_EN_DNT_JIJI,
ACTOR_EN_DS,
ACTOR_EN_DU,
ACTOR_EN_EG,
ACTOR_EN_FU,
ACTOR_EN_GB,
ACTOR_EN_GE3,
ACTOR_EN_GUEST,
ACTOR_EN_HATA,
ACTOR_EN_HORSE_GANON,
ACTOR_EN_HORSE_LINK_CHILD,
ACTOR_EN_HORSE_ZELDA,
ACTOR_EN_HS2,
ACTOR_EN_JS,
ACTOR_EN_KAKASI,
ACTOR_EN_KAKASI3,
ACTOR_EN_MA1,
ACTOR_EN_MA2,
ACTOR_EN_MA3,
ACTOR_EN_MAG,
ACTOR_EN_MK,
ACTOR_EN_MS,
ACTOR_EN_NIW_LADY,
ACTOR_EN_NWC,
ACTOR_EN_OE2,
ACTOR_EN_OKARINA_EFFECT,
ACTOR_EN_RR,
ACTOR_EN_SA,
ACTOR_EN_SCENE_CHANGE,
ACTOR_EN_SKJNEEDLE,
ACTOR_EN_SYATEKI_ITM,
ACTOR_EN_SYATEKI_MAN,
ACTOR_EN_TAKARA_MAN,
ACTOR_EN_TORYO,
ACTOR_EN_VASE,
ACTOR_EN_ZL1,
ACTOR_MAGIC_DARK,
ACTOR_MAGIC_FIRE,
ACTOR_OBJ_DEKUJR,
ACTOR_OCEFF_SPOT,
ACTOR_UNSET_1,
ACTOR_UNSET_3,
ACTOR_UNSET_5,
ACTOR_UNSET_6,
ACTOR_UNSET_17,
ACTOR_UNSET_1A,
ACTOR_UNSET_1F,
ACTOR_UNSET_22,
ACTOR_UNSET_31,
ACTOR_UNSET_36,
ACTOR_UNSET_53,
ACTOR_UNSET_73,
ACTOR_UNSET_74,
ACTOR_UNSET_75,
ACTOR_UNSET_76,
ACTOR_UNSET_78,
ACTOR_UNSET_79,
ACTOR_UNSET_7A,
ACTOR_UNSET_7B,
ACTOR_UNSET_7E,
ACTOR_UNSET_7F,
ACTOR_UNSET_83,
ACTOR_UNSET_A0,
ACTOR_UNSET_B2,
ACTOR_UNSET_CE,
ACTOR_UNSET_D8,
ACTOR_UNSET_EA,
ACTOR_UNSET_EB,
ACTOR_UNSET_F2,
ACTOR_UNSET_F3,
ACTOR_UNSET_FB,
ACTOR_UNSET_109,
ACTOR_UNSET_10D,
ACTOR_UNSET_10E,
ACTOR_UNSET_128,
ACTOR_UNSET_129,
ACTOR_UNSET_134,
ACTOR_UNSET_154,
ACTOR_UNSET_15D,
ACTOR_UNSET_161,
ACTOR_UNSET_180,
ACTOR_UNSET_1AA
};
static std::unordered_map<u16, std::function<s16(s16)>> actorSpecificData;
void CreateActorSpecificData() {
if (!actorSpecificData.empty()) {
return;
}
actorSpecificData[ACTOR_EN_DEKUNUTS] = [](s16 params) -> s16 {
bool isFlower = params == DEKUNUTS_FLOWER;
s16 shotsPerRound = (params >> 8) & 0xFF;
if (shotsPerRound == 0xFF || shotsPerRound == 0) {
shotsPerRound = 1;
}
ImGui::Checkbox("Flower", &isFlower);
if (!isFlower) {
ImGui::InputScalar("Shots Per Round", ImGuiDataType_S16, &shotsPerRound);
}
return isFlower ? DEKUNUTS_FLOWER : (shotsPerRound << 8);
};
actorSpecificData[ACTOR_EN_TITE] = [](s16 params) -> s16 {
static const char* items[] = { "Blue", "Red" };
if (params == 0) {
params = -2;
}
//the + 2 is because the params are -2 & -1 instead of 0 & 1
int selectedItem = params + 2;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem - 2;
}
return params;
};
actorSpecificData[ACTOR_EN_AM] = [](s16 params) -> s16 {
static const char* items[] = { "Statue", "Enemy" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_BG_ICE_TURARA] = [](s16 params) -> s16 {
static const char* items[] = { "Stalagmite", "Stalactite", "Stalactite (Regrow)" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_BG_BREAKWALL] = [](s16 params) -> s16 {
static const char* items[] = { "DC Entrance", "Wall", "KD Floor", "KD Lava Cover" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_TEST] = [](s16 params) -> s16 {
static const char* items[] = { "Invisible", "1", "2", "Ceiling", "4", "5" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_TANA] = [](s16 params) -> s16 {
static const char* items[] = { "Wooden", "Stone (1)", "Stone (2)" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_XC] = [](s16 params) -> s16 {
static const char* items[] = { "0", "1", "2", "3", "4", "5", "Minuet", "Bolero", "Serenade", "9" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_SHOT_SUN] = [](s16 params) -> s16 {
static const char* items[] = { "Sun's Song", "Song of Storms", "LH Sun" };
if (params == 0) {
params = 0x40;
}
//the - 0x40 is because the params are 0x40 & 0x41 instead of 0 & 1
int selectedItem = params - 0x40;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem + 0x40;
}
return params;
};
actorSpecificData[ACTOR_EN_HONOTRAP] = [](s16 params) -> s16 {
static const char* items[] = { "Eye", "Flame Move", "Flame Drop" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_REEBA] = [](s16 params) -> s16 {
bool isBig = params != 0;
ImGui::Checkbox("Big", &isBig);
return isBig;
};
actorSpecificData[ACTOR_EN_TK] = [](s16 params) -> s16 {
bool canTurn = params >= 0;
ImGui::Checkbox("Can Turn", &canTurn);
return canTurn ? 0 : -1;
};
actorSpecificData[ACTOR_EN_ITEM00] = [](s16 params) -> s16 {
bool autoCollect = params & 0x8000;
ImGui::Checkbox("Automatically Collect", &autoCollect);
u8 collectibleFlag = (params & 0x3F00) >> 8;
ImGui::InputScalar("Collectible Flag", ImGuiDataType_U8, &collectibleFlag);
if (collectibleFlag > 0x3F) {
collectibleFlag = 0x3F;
}
static const char* items[] = {
"Green Rupee",
"Blue Rupee",
"Red Rupee",
"Recovery Heart",
"Bombs (A)",
"Arrow",
"Heart Piece",
"Heart Container",
"Arrows (5)",
"Arrows (10)",
"Arrows (30)",
"Bombs (B)",
"Deku Nuts (5)",
"Deku Stick",
"Magic (Large)",
"Magic (Small)",
"Deku Seeds (5)",
"Small Key",
"Flexible",
"Gold Rupee",
"Purple Rupee",
"Deku Shield",
"Hylian Shield",
"Zora Tunic",
"Goron Tunic",
"Bombs (Special)",
"Bombchus"
};
int selectedItem = params & 0xFF;
ImGui::Combo("Item", &selectedItem, items, IM_ARRAYSIZE(items));
return autoCollect * 0x8000 + (collectibleFlag << 8) + selectedItem;
};
actorSpecificData[ACTOR_OBJ_COMB] = [](s16 params) -> s16 {
static const char* items[] = {
"Green Rupee",
"Blue Rupee",
"Red Rupee",
"Recovery Heart",
"Bombs (A)",
"Arrow",
"Heart Piece",
"Heart Container",
"Arrows (5)",
"Arrows (10)",
"Arrows (30)",
"Bombs (B)",
"Deku Nuts (5)",
"Deku Stick",
"Magic (Large)",
"Magic (Small)",
"Deku Seeds (5)",
"Small Key",
"Flexible",
"Gold Rupee",
"Purple Rupee",
"Deku Shield",
"Hylian Shield",
"Zora Tunic",
"Goron Tunic",
"Bombs (Special)",
"Bombchus"
};
int selectedItem = params & 0xFF;
ImGui::Combo("Item Drop", &selectedItem, items, IM_ARRAYSIZE(items));
u8 collectibleFlag = (params & 0x3F00) >> 8;
if (selectedItem == 6) {
ImGui::InputScalar("PoH Collectible Flag", ImGuiDataType_U8, &collectibleFlag);
if (collectibleFlag > 0x3F) {
collectibleFlag = 0x3F;
}
}
return (collectibleFlag << 8) + selectedItem;
};
actorSpecificData[ACTOR_EN_GM] = [](s16 params) -> s16 {
u8 switchFlag = (params & 0x3F00) >> 8;
ImGui::InputScalar("Switch Flag", ImGuiDataType_U8, &switchFlag);
if (switchFlag > 0x3F) {
switchFlag = 0x3F;
}
return switchFlag << 8;
};
actorSpecificData[ACTOR_EN_GIRLA] = [](s16 params) -> s16 {
static const char* items[] = {
"Deku Nuts (5)",
"Arrows (30)",
"Arrows (50)",
"Bombs (5) (25 Rupees)",
"Deku Nuts (10)",
"Deku Stick",
"Bombs (10)",
"Fish",
"Red Potion (30 Rupees)",
"Green Potion",
"Blue Potion",
"Longsword",
"Hylian Shield",
"Deku Shield",
"Goron Tunic",
"Zora Tunic",
"Heart",
"Milk Bottle",
"Weird Egg",
"19",
"20",
"Bomchu (10) [1]",
"Bomchu (20) [1]",
"Bomchu (20) [2]",
"Bomchu (10) [2]",
"Bomchu (10) [3]",
"Bomchu (20) [3]",
"Bomchu (20) [4]",
"Bomchu (10) [4]",
"Deku Seeds (30)",
"Keaton Mask",
"Spooky Mask",
"Skull Mask",
"Bunny Hood",
"Mask Of Truth",
"Zora Mask",
"Goron Mask",
"Gerudo Mask",
"Sold Out",
"Blue Fire",
"Bugs",
"Big Poe",
"Poe",
"Fairy",
"Arrows (10)",
"Bombs (20)",
"Bombs (30)",
"Bombs (5) (35 Rupees)",
"Red Potion (40 Rupees)",
"Red Potion (50 Rupees)",
"Randomizer Item"
};
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_FIRE_ROCK] = [](s16 params) -> s16 {
static const char* items[] = {
"Spawned Falling (1)",
"Broken Piece (1)",
"Broken Piece (2)",
"Spawned Falling (2)",
//"INVALID",
"Ceiling Spot Spawner",
"On Floor"
};
int selectedItem = params > 3 ? params - 1 : params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem > 3 ? selectedItem + 1 : selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_EX_ITEM] = [](s16 params) -> s16 {
static const char* items[] = {
"Bomb Bag Bowling",
"Heart Piece Bowling",
"Bombchus Bowling",
"Bombs Bowling",
"Purple Rupee Bowling",
"Bomb Bag Counter",
"Heart Piece Counter",
"Bombchus Counter",
"Bombs Counter",
"Purple Rupee Counter",
"Green Rupee Chest",
"Blue Rupee Chest",
"Red Rupee Chest",
"13",
"14",
"Small Key Chest",
"Magic Fire",
"Magic Wind",
"Magic Dark",
"Bullet Bag"
};
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_ELF] = [](s16 params) -> s16 {
static const char* items[] = {
"Navi",
"Revive Bottle",
"Heal Timed",
"Kokiri",
"Spawner",
"Revive Death",
"Heal",
"Heal Big"
};
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_CLEAR_TAG] = [](s16 params) -> s16 {
static const char* items[] = {
"Cutscene", //0
"Normal", //1
"Laser" //100
};
int selectedItem = params == 100 ? 2 : params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem == 2 ? 100 : selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_BOMBF] = [](s16 params) -> s16 {
static const char* items[] = { "Flower", "Body", "Explosion" };
//the + 1 is because the params are -1, 0 & 1 instead of 0, 1 & 2
int selectedItem = params + 1;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem - 1;
}
return params;
};
actorSpecificData[ACTOR_EN_BOM] = [](s16 params) -> s16 {
static const char* items[] = { "Body", "Explosion" };
int selectedItem = params;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_DOOR_WARP1] = [](s16 params) -> s16 {
static const char* items[] = {
"Blue Crystal", // -2
"Dungeon Adult",
"Dungeon Child",
"Clear Flag", // Activate on temp clear flag
"Sages", // Used by sages warping into chamber of sages during their cutscene
"Purple Crystal",
"Yellow", // The colored variants don't warp, they are cutscene setpieces
"Blue Ruto",
"Destination", // Spawning in after having taken a warp
"UNK 7",
"Orange",
"Green",
"Red"
};
int selectedItem = params + 2;
if (ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem - 2;
}
return params;
};
actorSpecificData[ACTOR_EN_DY_EXTRA] = [](s16 params) -> s16 {
static const char* items[] = { "Orange", "Green" };
int selectedItem = params;
if (ImGui::Combo("Color", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
actorSpecificData[ACTOR_EN_SKB] = [](s16 params) -> s16 {
u8 size = params;
ImGui::InputScalar("Size", ImGuiDataType_U8, &size);
return size;
};
actorSpecificData[ACTOR_EN_WF] = [](s16 params) -> s16 {
static const char* items[] = { "Normal", "White" };
int selectedItem = params;
ImGui::Combo("Type", &selectedItem, items, IM_ARRAYSIZE(items));
u8 switchFlag = (params & 0x3F00) >> 8;
ImGui::InputScalar("Switch Flag", ImGuiDataType_U8, &switchFlag);
return (switchFlag << 8) + selectedItem;
};
actorSpecificData[ACTOR_EN_BOX] = [](s16 params) -> s16 {
/*
trasureFlag = params & 0x1F; //0b0000 0000 0001 1111
itemId = (params >> 5) & 0x7F; //0b0000 1111 1110 0000
type = (params >> 12) & 0xF; //0b1111 0000 0000 0000
*/
u8 treasureFlag = params & 0x1F;
ImGui::InputScalar("Treasure Flag", ImGuiDataType_U8, &treasureFlag);
if (treasureFlag > 0x1F) {
treasureFlag = 0x1F;
}
u8 itemId = (params >> 5) & 0x7F;
ImGui::InputScalar("Item Id", ImGuiDataType_U8, &itemId);
if (itemId > 0x7F) {
itemId = 0x7F;
}
static const char* items[] = {
"Big (Default)",
"Room Clear Big",
"Decorated Big",
"Switch Flag Fall Big",
"4",
"Small",
"6",
"Room Clear Small",
"Switch Flag Fall Small",
"9",
"10",
"Switch Flag Big"
};
int type = (params >> 12) & 0xF;
ImGui::Combo("Type", &type, items, IM_ARRAYSIZE(items));
if (type > 0xF) {
type = 0xF;
}
return (type << 12) + (itemId << 5) + treasureFlag;
};
actorSpecificData[ACTOR_EN_DOOR] = [](s16 params) -> s16 {
/**
* Actor Parameters
*
* | | | |
* | Transition Index | Type | Double Door | Switch Flag OR Text Id - 0x0200
* |------------------|-------|-------------|---------------------------------
* | 0 0 0 0 0 0 | 0 0 0 | 0 | 0 0 0 0 0 0
* | 6 | 3 | 1 | 6
* |
*
* Transition Index 1111110000000000 Set by the actor engine when the door is spawned
* Type 0000001110000000
* Double Door 0000000001000000
* Switch Flag 0000000000111111 For use with the `DOOR_LOCKED` type
* Text id - 0x0200 0000000000111111 For use with the `DOOR_CHECKABLE` type
*
*/
u8 transitionIndex = params >> 10;
ImGui::InputScalar("Transition Index", ImGuiDataType_U8, &transitionIndex);
if (transitionIndex > 0x3F) {
transitionIndex = 0x3F;
}
static const char* items[] = {
"Room Load", // loads rooms
"Locked", // small key locked door
"Room Load (2)", // loads rooms
"Scene Exit", // doesn't load rooms, used for doors paired with scene transition polygons
"Ajar", // open slightly but slams shut if Link gets too close
"Checkable", // doors that display a textbox when interacting
"Evening", // unlocked between 18:00 and 21:00, Dampé's hut
"Room Load (7)" // loads rooms
};
int type = (params >> 7) & 7;
ImGui::Combo("Type", &type, items, IM_ARRAYSIZE(items));
if (type > 7) {
type = 7;
}
bool doubleDoor = ((params >> 6) & 1) != 0;
ImGui::Checkbox("Double Door", &doubleDoor);
u8 lowerBits = params & 0x3F;
if (type == 1) {
ImGui::InputScalar("Switch Flag", ImGuiDataType_U8, &lowerBits);
if (lowerBits > 0x3F) {
lowerBits = 0x3F;
}
} else if (type == 5) {
ImGui::InputScalar("Text ID - 0x200", ImGuiDataType_U8, &lowerBits);
if (lowerBits > 0x3F) {
lowerBits = 0x3F;
}
} else {
lowerBits = 0;
}
return (transitionIndex << 10) + (type << 7) + (doubleDoor << 6) + lowerBits;
};
actorSpecificData[ACTOR_EN_PO_DESERT] = [](s16 params) -> s16 {
u8 switchFlag = params >> 8;
ImGui::InputScalar("Path", ImGuiDataType_U8, &switchFlag);
return switchFlag << 8;
};
actorSpecificData[ACTOR_EN_KANBAN] = [](s16 params) -> s16 {
bool piece = params == (s16)0xFFDD;
bool fishingSign = params == 0x300;
if (ImGui::Checkbox("Piece", &piece)) {
fishingSign = false;
}
if (ImGui::Checkbox("Fishing Sign", &fishingSign)) {
piece = false;
}
u8 textId = params;
if (!piece && !fishingSign) {
if (ImGui::InputScalar("Text ID", ImGuiDataType_U8, &textId)) {
textId |= 0x300;
}
}
return piece ? (s16)0xFFDD : (fishingSign ? 0x300 : textId);
};
actorSpecificData[ACTOR_EN_KUSA] = [](s16 params) -> s16 {
static const char* items[] = {
"0",
"1",
"2"
};
int type = params & 3;
ImGui::Combo("Type", &type, items, IM_ARRAYSIZE(items));
bool bugs = ((params >> 4) & 1) != 0;
ImGui::Checkbox("Bugs", &bugs);
u8 drop = (params >> 8) & 0xF;
if (type == 2) {
ImGui::InputScalar("Random Drop Params", ImGuiDataType_U8, &drop);
if (drop > 0xD) {
drop = 0xD;
}
} else {
drop = 0;
}
return (drop << 8) + (bugs << 4) + type;
};
actorSpecificData[ActorDB::Instance->RetrieveId("En_Partner")] = [](s16 params) -> s16 {
static const char* items[] = {
"Port 1",
"Port 2",
"Port 3",
"Port 4"
};
int selectedItem = params;
if (ImGui::Combo("Controller Port", &selectedItem, items, IM_ARRAYSIZE(items))) {
return selectedItem;
}
return params;
};
}
std::vector<u16> GetActorsWithDescriptionContainingString(std::string s) {
std::locale loc;
for (size_t i = 0; i < s.length(); i += 1) {
s[i] = std::tolower(s[i], loc);
}
std::vector<u16> actors;
for (int i = 0; i < ActorDB::Instance->GetEntryCount(); i += 1) {
ActorDB::Entry actorEntry = ActorDB::Instance->RetrieveEntry(i);
std::string desc = actorEntry.desc;
for (size_t j = 0; j < desc.length(); j += 1) {
desc[j] = std::tolower(desc[j], loc);
}
if (desc.find(s) != std::string::npos) {
actors.push_back((u16)i);
}
}
return actors;
}
void ActorViewer_AddTagForActor(Actor* actor) { void ActorViewer_AddTagForActor(Actor* actor) {
int val = CVarGetInteger("gDebugActorViewerNameTags", ACTORVIEWER_NAMETAGS_NONE); int val = CVarGetInteger("gDebugActorViewerNameTags", ACTORVIEWER_NAMETAGS_NONE);
auto entry = ActorDB::Instance->RetrieveEntry(actor->id); auto entry = ActorDB::Instance->RetrieveEntry(actor->id);
@ -163,6 +942,9 @@ void ActorViewerWindow::DrawElement() {
static std::string filler = "Please select"; static std::string filler = "Please select";
static std::vector<Actor*> list; static std::vector<Actor*> list;
static u16 lastSceneId = 0; static u16 lastSceneId = 0;
static char searchString[64] = "";
static s16 currentSelectedInDropdown;
static std::vector<u16> actors;
if (gPlayState != nullptr) { if (gPlayState != nullptr) {
needs_reset = lastSceneId != gPlayState->sceneNum; needs_reset = lastSceneId != gPlayState->sceneNum;
@ -173,6 +955,11 @@ void ActorViewerWindow::DrawElement() {
filler = "Please Select"; filler = "Please Select";
list.clear(); list.clear();
needs_reset = false; needs_reset = false;
for (size_t i = 0; i < ARRAY_COUNT(searchString); i += 1) {
searchString[i] = 0;
}
currentSelectedInDropdown = -1;
actors.clear();
} }
lastSceneId = gPlayState->sceneNum; lastSceneId = gPlayState->sceneNum;
if (ImGui::BeginCombo("Actor Type", acMapping[category])) { if (ImGui::BeginCombo("Actor Type", acMapping[category])) {
@ -316,9 +1103,48 @@ void ActorViewerWindow::DrawElement() {
if (ImGui::TreeNode("New...")) { if (ImGui::TreeNode("New...")) {
ImGui::PushItemWidth(ImGui::GetFontSize() * 10); ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
if (ImGui::InputText("Search Actor", searchString, ARRAY_COUNT(searchString))) {
actors = GetActorsWithDescriptionContainingString(std::string(searchString));
currentSelectedInDropdown = -1;
}
if (searchString[0] != 0 && !actors.empty()) {
std::string preview = currentSelectedInDropdown == -1 ? "Please Select" : ActorDB::Instance->RetrieveEntry(actors[currentSelectedInDropdown]).desc;
if (ImGui::BeginCombo("Results", preview.c_str())) {
for (u8 i = 0; i < actors.size(); i++) {
if (ImGui::Selectable(
ActorDB::Instance->RetrieveEntry(actors[i]).desc.c_str(),
i == currentSelectedInDropdown
)) {
currentSelectedInDropdown = i;
newActor.id = actors[i];
}
}
ImGui::EndCombo();
}
}
ImGui::Text("%s", GetActorDescription(newActor.id).c_str()); ImGui::Text("%s", GetActorDescription(newActor.id).c_str());
ImGui::InputScalar("ID", ImGuiDataType_S16, &newActor.id, &one); if (ImGui::InputScalar("ID", ImGuiDataType_S16, &newActor.id, &one)) {
ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one); newActor.params = 0;
}
UIWidgets::EnhancementCheckbox("Advanced mode", "gActorViewerAdvancedParams");
UIWidgets::InsertHelpHoverText("Changes the actor specific param menus with a direct input");
if (CVarGetInteger("gActorViewerAdvancedParams", 0)) {
ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one);
} else if (std::find(noParamsActors.begin(), noParamsActors.end(), newActor.id) == noParamsActors.end()) {
CreateActorSpecificData();
if (actorSpecificData.find(newActor.id) == actorSpecificData.end()) {
ImGui::InputScalar("params", ImGuiDataType_S16, &newActor.params, &one);
} else {
DrawGroupWithBorder([&]() {
ImGui::Text("Actor Specific Data");
newActor.params = actorSpecificData[newActor.id](newActor.params);
});
}
}
ImGui::PushItemWidth(ImGui::GetFontSize() * 6); ImGui::PushItemWidth(ImGui::GetFontSize() * 6);
@ -401,6 +1227,11 @@ void ActorViewerWindow::DrawElement() {
filler = "Please Select"; filler = "Please Select";
list.clear(); list.clear();
needs_reset = false; needs_reset = false;
for (size_t i = 0; i < ARRAY_COUNT(searchString); i += 1) {
searchString[i] = 0;
}
currentSelectedInDropdown = -1;
actors.clear();
} }
} }