diff options
author | Treeki <treeki@gmail.com> | 2012-01-30 00:40:28 +0100 |
---|---|---|
committer | Treeki <treeki@gmail.com> | 2012-01-30 00:40:28 +0100 |
commit | 96bc2e0026a369ecf8598fb2168d0a4e02e9e1bd (patch) | |
tree | 75cad32a169d79f81c1adf1945d49c9b6fc3310b | |
parent | 4d1cccfc209619919c2cae99fb5e58aa62b2bc64 (diff) | |
download | kamek-96bc2e0026a369ecf8598fb2168d0a4e02e9e1bd.tar.gz kamek-96bc2e0026a369ecf8598fb2168d0a4e02e9e1bd.zip |
message boxes are now functional
-rw-r--r-- | NewerProject.yaml | 2 | ||||
-rw-r--r-- | NewerProjectKP.yaml | 2 | ||||
-rw-r--r-- | msgbox.yaml | 11 | ||||
-rw-r--r-- | src/msgbox.S | 1 | ||||
-rw-r--r-- | src/msgbox.cpp | 576 | ||||
-rw-r--r-- | tools/msgbox_data.py | 36 |
6 files changed, 435 insertions, 193 deletions
diff --git a/NewerProject.yaml b/NewerProject.yaml index 0b5dbec..0a68909 100644 --- a/NewerProject.yaml +++ b/NewerProject.yaml @@ -20,7 +20,7 @@ modules: - processed/tilesetfixer.yaml - processed/switchblock.yaml - processed/eventblock.yaml -# - processed/msgbox.yaml + - processed/msgbox.yaml # - processed/replay.yaml - processed/growup.yaml - processed/eventlooper.yaml diff --git a/NewerProjectKP.yaml b/NewerProjectKP.yaml index 3468497..3c9657b 100644 --- a/NewerProjectKP.yaml +++ b/NewerProjectKP.yaml @@ -21,7 +21,7 @@ modules: - processed/tilesetfixer.yaml - processed/switchblock.yaml - processed/eventblock.yaml -# - processed/msgbox.yaml + - processed/msgbox.yaml # - processed/replay.yaml - processed/growup.yaml - processed/eventlooper.yaml diff --git a/msgbox.yaml b/msgbox.yaml index 5eef67e..2ca00cd 100644 --- a/msgbox.yaml +++ b/msgbox.yaml @@ -5,5 +5,14 @@ hooks: type: branch_insn
branch_type: b
src_addr_pal: 0x800B3B50
- src_addr_ntsc: 0xdeadbeef
target_func: 'Query5758Replacement'
+
+ - name: BuildMsgManager
+ type: add_func_pointer
+ src_addr_pal: 0x80AF96F8
+ target_func: 'dMsgBoxManager_c::build(void)'
+
+ - name: BuildMsgBlock
+ type: add_func_pointer
+ src_addr_pal: 0x80ADD890
+ target_func: 'daEnMsgBlock_c::build(void)'
diff --git a/src/msgbox.S b/src/msgbox.S index ac49676..ee8c52e 100644 --- a/src/msgbox.S +++ b/src/msgbox.S @@ -11,6 +11,7 @@ #endif .extern Global5758 +.global MessageBoxIsShowing # -if param & 1 /and/ messagebox is on, # otherwise, return Global5758 & param diff --git a/src/msgbox.cpp b/src/msgbox.cpp index f99f73f..c480070 100644 --- a/src/msgbox.cpp +++ b/src/msgbox.cpp @@ -1,227 +1,423 @@ #include <common.h> #include <game.h> -#include "layoutlib.h" -#include "fileload.h" +// Replaces: EN_LIFT_ROTATION_HALF (Sprite 107; Profile ID 481 @ 80AF96F8) -struct MsgData_Header { - u32 magic; - u32 msgCount; -}; +class dMsgBoxManager_c : public dStageActor_c { + public: + void showMessage(int id); -struct MsgData_Entry { - u32 number; - u32 titleOffset; - u32 msgOffset; -}; + dMsgBoxManager_c() : state(this, &StateID_LoadRes) { } + int onCreate(); + int onDelete(); + int onExecute(); + int onDraw(); + int beforeExecute() { return true; } + int afterExecute(int) { return true; } -struct dMsgBoxManager_c { - // 0x00 - int ID; - unsigned int Settings; - short Type; - char Unk_0A; - char Unk_0B; - char Unk_0C; - char Unk_0D; - char Unk_0E; - char Unk_0F; - - // 0x10 - void *CONNECT_parent; - void *CONNECT_child; - void *CONNECT_prev; - void *CONNECT_next; - - // 0x20 - void *CONNECT_thisObj; - void *EXECUTE_prev; - void *EXECUTE_next; - void *EXECUTE_thisObj; - - // 0x30 - short Unk_30; - short Unk_32; - void *DRAW_prev; - void *DRAW_next; - void *DRAW_thisObj; - - // 0x40 - short Unk_40; - short Unk_42; - void *IDLookup_prev; - void *IDLookup_next; - void *IDLookup_thisObj; - - // 0x50 - void *Unk_50; - int Unk_54; - int Unk_58; - void *Unk_5C; - - // 0x60 - void *vtable; - int Unk_64; // dBase_c starts here - char *weirdTypeString; - char *actorName; - - // dMsgBoxManager_c starts here (offset 0x70) - Layout *layout; - int state; - FileHandle msgDataFH; - - // 0x80 - void *msgData; - - // current allocated class size: 0xD0 + m2d::EmbedLayout_c layout; + dDvdLoader_c msgDataLoader; + + bool layoutLoaded; + bool visible; + + dStateWrapper_c<dMsgBoxManager_c> state; + + USING_STATES(dMsgBoxManager_c); + DECLARE_STATE(LoadRes); + DECLARE_STATE(Wait); + DECLARE_STATE(BoxAppearWait); +// DECLARE_STATE(ButtonAppearWait); + DECLARE_STATE(ShownWait); +// DECLARE_STATE(ButtonDisappearWait); + DECLARE_STATE(BoxDisappearWait); + + static dMsgBoxManager_c *instance; + static dMsgBoxManager_c *build(); + + private: + struct entry_s { + u32 id; + u32 titleOffset; + u32 msgOffset; + }; + + struct header_s { + u32 count; + entry_s entry[1]; + }; }; +dMsgBoxManager_c *dMsgBoxManager_c::instance = 0; +dMsgBoxManager_c *dMsgBoxManager_c::build() { + void *buffer = AllocFromGameHeap1(sizeof(dMsgBoxManager_c)); + dMsgBoxManager_c *c = new(buffer) dMsgBoxManager_c; -#define STATE_NULL 0 -#define STATE_BOX_APPEAR_WAIT 1 -#define STATE_BUTTON_APPEAR_WAIT 2 -#define STATE_SHOWN 3 -#define STATE_BUTTON_DISAPPEAR_WAIT 4 -#define STATE_BOX_DISAPPEAR_WAIT 5 + instance = c; + return c; +} -#define animBoxAppear 0 -#define animBoxDisappear 1 -#define animButtonAppear 2 -#define animButtonDisappear 3 +#define ANIM_BOX_APPEAR 0 +#define ANIM_BOX_DISAPPEAR 1 +//#define ANIM_BUTTON_APPEAR 2 +//#define ANIM_BUTTON_DISAPPEAR 3 extern int MessageBoxIsShowing; -dMsgBoxManager_c *CurrentMsgBoxManager; -const char *brlan_BoxAppear = "BoxAppear.brlan"; -const char *brlan_BoxDisappear = "BoxDisappear.brlan"; -const char *brlan_ButtonAppear = "ButtonAppear.brlan"; -const char *brlan_ButtonDisappear = "ButtonDisappear.brlan"; +/*****************************************************************************/ +// Events +int dMsgBoxManager_c::onCreate() { + if (!layoutLoaded) { + if (!layout.loadArc("msgbox.arc", false)) + return false; -const char *group_Box = "G_Box"; -const char *group_Button = "G_Button"; + static const char *brlanNames[2] = { + "BoxAppear.brlan", + "BoxDisappear.brlan", +// "ButtonAppear.brlan", +// "ButtonDisappear.brlan" + }; -bool dMsgBoxManager_c__Create(dMsgBoxManager_c *self) { - self->layout = (Layout*)AllocFromGameHeap1(sizeof(Layout)); - - if (!self->layout) { - OSReport("memalloc fail\n"); - InfiniteLoop; - } - - EmbeddedLayout_ctor(self->layout); - EmbeddedLayout_LoadArc(self->layout, "NewerRes/msgbox.arc"); - - if (!EmbeddedLayout_Build(self->layout, "MessageBox.brlyt", 0)) { - OSReport("build fail\n"); - InfiniteLoop; + static const char *groupNames[2] = { + "G_Box", "G_Box", +// "G_Button", "G_Button" + }; + + layout.build("MessageBox.brlyt"); + + if (IsWideScreen()) { + layout.layout.rootPane->scale.x = 0.7711f; + } + + layout.loadAnimations(brlanNames, 2); + layout.loadGroups(groupNames, (int[2]){0,1}, 2); + layout.disableAllAnimations(); + + layout.drawOrder = 0xA0; + + layoutLoaded = true; } - - - const char *anims[4] = {brlan_BoxAppear, brlan_BoxDisappear, brlan_ButtonAppear, brlan_ButtonDisappear}; - EmbeddedLayout_LoadBrlans(self->layout, anims, 4); - - const char *groups[4] = {group_Box, group_Box, group_Button, group_Button}; - - int mappings[4] = {0, 1, 2, 3}; - EmbeddedLayout_LoadGroups(self->layout, groups, mappings, 4); - - EmbeddedLayout_DisableAllAnims(self->layout); - - for (int i = 0; i < 4; i++) { - EmbeddedLayout_ResetAnimToInitialState(self->layout, i, false); + + visible = false; + + return true; +} + +int dMsgBoxManager_c::onExecute() { + //OSReport("E: %s\n", state.getCurrentState()->getName()); + state.execute(); + + layout.execAnimations(); + layout.update(); + + return true; +} + +int dMsgBoxManager_c::onDraw() { + if (visible) { + layout.scheduleForDrawing(); } - self->msgData = LoadFile(&self->msgDataFH, "/NewerRes/MsgData.bin"); - - self->state = STATE_NULL; - self->layout->drawOrder = 0xA0; - - CurrentMsgBoxManager = self; - return true; } -bool dMsgBoxManager_c__Execute(dMsgBoxManager_c *self) { - if (self->state == STATE_NULL) - return true; - - - switch (self->state) { - /**************************************************************************/ - case STATE_BOX_APPEAR_WAIT: - if (!EmbeddedLayout_CheckIfAnimationIsOn(self->layout, animBoxAppear)) { - EmbeddedLayout_EnableNonLoopAnim(self->layout, animButtonAppear, false); - self->state = STATE_BUTTON_APPEAR_WAIT; - } - - break; - - /**************************************************************************/ - case STATE_BUTTON_APPEAR_WAIT: - if (!EmbeddedLayout_CheckIfAnimationIsOn(self->layout, animButtonAppear)) { - self->state = STATE_SHOWN; - } - - break; - - /**************************************************************************/ - case STATE_SHOWN: - if (false) { - EmbeddedLayout_EnableNonLoopAnim(self->layout, animButtonDisappear, false); - self->state = STATE_BUTTON_DISAPPEAR_WAIT; - } - - break; - - /**************************************************************************/ - case STATE_BUTTON_DISAPPEAR_WAIT: - if (!EmbeddedLayout_CheckIfAnimationIsOn(self->layout, animButtonDisappear)) { - EmbeddedLayout_EnableNonLoopAnim(self->layout, animBoxDisappear, false); - self->state = STATE_BOX_DISAPPEAR_WAIT; - } - - break; - - /**************************************************************************/ - case STATE_BOX_DISAPPEAR_WAIT: - if (!EmbeddedLayout_CheckIfAnimationIsOn(self->layout, animBoxDisappear)) { - self->state = STATE_NULL; - - EmbeddedLayout_DisableAllAnims(self->layout); - - for (int i = 0; i < 4; i++) { - EmbeddedLayout_ResetAnimToInitialState(self->layout, i, false); - } - } +int dMsgBoxManager_c::onDelete() { + instance = 0; + + return layout.free(); +} + +/*****************************************************************************/ +// Load Resources +CREATE_STATE_E(dMsgBoxManager_c, LoadRes); + +void dMsgBoxManager_c::executeState_LoadRes() { + OSReport("Trying to load\n"); + if (msgDataLoader.load("/NewerRes/Messages.bin")) { + OSReport(":)\n"); + state.setState(&StateID_Wait); + OSReport("changed\n"); + } else { + OSReport(":(\n"); + } +} + +/*****************************************************************************/ +// Waiting +CREATE_STATE_E(dMsgBoxManager_c, Wait); + +void dMsgBoxManager_c::executeState_Wait() { + // null +} + +/*****************************************************************************/ +// Show Box +void dMsgBoxManager_c::showMessage(int id) { + // get the data file + header_s *data = (header_s*)msgDataLoader.buffer; + + const wchar_t *title = 0, *msg = 0; + + for (int i = 0; i < data->count; i++) { + if (data->entry[i].id == id) { + title = (const wchar_t*)((u32)data + data->entry[i].titleOffset); + msg = (const wchar_t*)((u32)data + data->entry[i].msgOffset); break; + } } + + if (title == 0) { + OSReport("WARNING! Tried to show message %x but it could not be found!\n", id); + return; + } + + layout.findTextBoxByName("T_title")->SetString(title); + layout.findTextBoxByName("T_msg")->SetString(msg); + + state.setState(&StateID_BoxAppearWait); +} + + +CREATE_STATE(dMsgBoxManager_c, BoxAppearWait); + +void dMsgBoxManager_c::beginState_BoxAppearWait() { + visible = true; + MessageBoxIsShowing = true; + layout.enableNonLoopAnim(ANIM_BOX_APPEAR); + OSReport("Enabling box appear @ %d\n", GlobalTickCount); +} + +void dMsgBoxManager_c::executeState_BoxAppearWait() { + if (!layout.isAnimOn(ANIM_BOX_APPEAR)) { + OSReport("Box appeared @ %d\n", GlobalTickCount); + state.setState(&StateID_ShownWait); + } +} + +void dMsgBoxManager_c::endState_BoxAppearWait() { } + +/*****************************************************************************/ +// Show Button +/*CREATE_STATE(dMsgBoxManager_c, ButtonAppearWait); + +void dMsgBoxManager_c::beginState_ButtonAppearWait() { + layout.enableNonLoopAnim(ANIM_BUTTON_APPEAR); + OSReport("Enabling button appear @ %d\n", GlobalTickCount); +} + +void dMsgBoxManager_c::executeState_ButtonAppearWait() { + if (!layout.isAnimOn(ANIM_BUTTON_APPEAR)) { + OSReport("Button appeared @ %d\n", GlobalTickCount); + state.setState(&StateID_ShownWait); + } +} + +void dMsgBoxManager_c::endState_ButtonAppearWait() { }*/ + +/*****************************************************************************/ +// Wait For Player To Finish +CREATE_STATE(dMsgBoxManager_c, ShownWait); + +void dMsgBoxManager_c::beginState_ShownWait() { } +void dMsgBoxManager_c::executeState_ShownWait() { + int nowPressed = Remocon_GetPressed(GetActiveRemocon()); - - EmbeddedLayout_Process(self->layout); - EmbeddedLayout_UpdateMatrix(self->layout); - + if (nowPressed & WPAD_TWO) { + state.setState(&StateID_BoxDisappearWait); + } +} +void dMsgBoxManager_c::endState_ShownWait() { } + +/*****************************************************************************/ +// Hide Button +/*CREATE_STATE(dMsgBoxManager_c, ButtonDisappearWait); + +void dMsgBoxManager_c::beginState_ButtonDisappearWait() { + layout.enableNonLoopAnim(ANIM_BUTTON_DISAPPEAR); + OSReport("Enabling button disappear @ %d\n", GlobalTickCount); +} + +void dMsgBoxManager_c::executeState_ButtonDisappearWait() { + if (!layout.isAnimOn(ANIM_BUTTON_DISAPPEAR)) { + OSReport("Button disappeared @ %d\n", GlobalTickCount); + state.setState(&StateID_BoxDisappearWait); + } +} + +void dMsgBoxManager_c::endState_ButtonDisappearWait() { }*/ + +/*****************************************************************************/ +// Hide Box +CREATE_STATE(dMsgBoxManager_c, BoxDisappearWait); + +void dMsgBoxManager_c::beginState_BoxDisappearWait() { + layout.enableNonLoopAnim(ANIM_BOX_DISAPPEAR); + OSReport("Enabling box disappear @ %d\n", GlobalTickCount); +} + +void dMsgBoxManager_c::executeState_BoxDisappearWait() { + if (!layout.isAnimOn(ANIM_BOX_DISAPPEAR)) { + OSReport("Box disappeared @ %d\n", GlobalTickCount); + state.setState(&StateID_Wait); + + for (int i = 0; i < 2; i++) + layout.resetAnim(i); + layout.disableAllAnimations(); + } +} + +void dMsgBoxManager_c::endState_BoxDisappearWait() { + visible = false; + MessageBoxIsShowing = false; +} + + + +/*****************************************************************************/ +/*****************************************************************************/ +/*****************************************************************************/ +// Replaces: EN_BLUR (Sprite 152; Profile ID 603 @ 80ADD890) + + +class daEnMsgBlock_c : public daEnBlockMain_c { +public: + TileRenderer tile; + Physics::Info physicsInfo; + + int onCreate(); + int onDelete(); + int onExecute(); + + void calledWhenUpMoveExecutes(); + void calledWhenDownMoveExecutes(); + + void blockWasHit(bool isDown); + + USING_STATES(daEnMsgBlock_c); + DECLARE_STATE(Wait); + + static daEnMsgBlock_c *build(); +}; + + +CREATE_STATE(daEnMsgBlock_c, Wait); + + +int daEnMsgBlock_c::onCreate() { + OSReport("Creating Block\n"); + blockInit(pos.y); + + physicsInfo.x1 = -8; + physicsInfo.y1 = 16; + physicsInfo.x2 = 8; + physicsInfo.y2 = 0; + + physicsInfo.otherCallback1 = &daEnBlockMain_c::OPhysicsCallback1; + physicsInfo.otherCallback2 = &daEnBlockMain_c::OPhysicsCallback2; + physicsInfo.otherCallback3 = &daEnBlockMain_c::OPhysicsCallback3; + + physics.setup(this, &physicsInfo, 3, currentLayerID); + physics.flagsMaybe = 0x260; + physics.callback1 = &daEnBlockMain_c::PhysicsCallback1; + physics.callback2 = &daEnBlockMain_c::PhysicsCallback2; + physics.callback3 = &daEnBlockMain_c::PhysicsCallback3; + physics.addToList(); + + TileRenderer::List *list = dBgGm_c::instance->getTileRendererList(0); + list->add(&tile); + + tile.x = pos.x - 8; + tile.y = -(16 + pos.y); + tile.tileNumber = 0x98; + + doStateChange(&daEnMsgBlock_c::StateID_Wait); + OSReport("Created Block\n"); + + return true; +} + + +int daEnMsgBlock_c::onDelete() { + TileRenderer::List *list = dBgGm_c::instance->getTileRendererList(0); + list->remove(&tile); + + physics.removeFromList(); + return true; } -bool dMsgBoxManager_c__Draw(dMsgBoxManager_c *self) { - if (self->state != STATE_NULL) { - EmbeddedLayout_AddToDrawList(self->layout); + +int daEnMsgBlock_c::onExecute() { + acState.execute(); + physics.update(); + blockUpdate(); + + tile.setPosition(pos.x-8, -(16+pos.y), pos.z); + tile.setVars(scale.x); + + // now check zone bounds based on state + if (acState.getCurrentState()->isEqual(&StateID_Wait)) { + checkZoneBoundaries(0); } - + return true; } -bool dMsgBoxManager_c__Delete(dMsgBoxManager_c *self) { - EmbeddedLayout_FreeArc(self->layout); - EmbeddedLayout_Free(self->layout); - EmbeddedLayout_dtor(self->layout, false); - FreeFromGameHeap1(self->layout); - - CurrentMsgBoxManager = 0; + +daEnMsgBlock_c *daEnMsgBlock_c::build() { + void *buffer = AllocFromGameHeap1(sizeof(daEnMsgBlock_c)); + return new(buffer) daEnMsgBlock_c; +} + + +void daEnMsgBlock_c::blockWasHit(bool isDown) { + pos.y = initialY; + + dMsgBoxManager_c::instance->showMessage(settings); + + physics.setup(this, &physicsInfo, 3, currentLayerID); + physics.addToList(); - return true; + doStateChange(&StateID_Wait); +} + + + +void daEnMsgBlock_c::calledWhenUpMoveExecutes() { + if (initialY >= pos.y) + blockWasHit(false); +} + +void daEnMsgBlock_c::calledWhenDownMoveExecutes() { + if (initialY <= pos.y) + blockWasHit(true); +} + + + +void daEnMsgBlock_c::beginState_Wait() { +} + +void daEnMsgBlock_c::endState_Wait() { +} + +void daEnMsgBlock_c::executeState_Wait() { + int result = blockResult(); + + if (result == 0) + return; + + if (result == 1) { + doStateChange(&daEnBlockMain_c::StateID_UpMove); + anotherFlag = 2; + isGroundPound = false; + } else { + doStateChange(&daEnBlockMain_c::StateID_DownMove); + anotherFlag = 1; + isGroundPound = true; + } } diff --git a/tools/msgbox_data.py b/tools/msgbox_data.py new file mode 100644 index 0000000..06eec2b --- /dev/null +++ b/tools/msgbox_data.py @@ -0,0 +1,36 @@ +messages = [ + # Message 0 + (0x100, 'A Test Message', + 'This is a test message.\nWith some lines.\nAnd more lines.\nAnd a really long line to see if nw4r::lyt can handle wrapping or not...\nFinal line.' + ), + ] + +import struct, sys, os.path, codecs + +if len(sys.argv) > 1: + target = sys.argv[1] +elif os.path.exists('/home/me/Games/Newer'): + target = '/home/me/Games/Newer/ISO/files/NewerRes/Messages.bin' +else: + target = 'Messages.bin' + +messageCount = len(messages) + +stringOffset = (messageCount * 0xC) + 4 +infoStruct = struct.Struct('>III') + +headerData = bytearray(struct.pack('>I', messageCount)) +stringData = bytearray() + +for msgID, title, msg in messages: + titleOffset = stringOffset + len(stringData) + stringData += codecs.utf_16_be_encode(title)[0] + '\0\0' + msgOffset = stringOffset + len(stringData) + stringData += codecs.utf_16_be_encode(msg)[0] + '\0\0' + + headerData += infoStruct.pack(msgID, titleOffset, msgOffset) + +with open(target, 'wb') as out: + out.write(headerData) + out.write(stringData) + |