summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreeki <treeki@gmail.com>2012-01-30 00:40:28 +0100
committerTreeki <treeki@gmail.com>2012-01-30 00:40:28 +0100
commit96bc2e0026a369ecf8598fb2168d0a4e02e9e1bd (patch)
tree75cad32a169d79f81c1adf1945d49c9b6fc3310b
parent4d1cccfc209619919c2cae99fb5e58aa62b2bc64 (diff)
downloadkamek-96bc2e0026a369ecf8598fb2168d0a4e02e9e1bd.tar.gz
kamek-96bc2e0026a369ecf8598fb2168d0a4e02e9e1bd.zip
message boxes are now functional
Diffstat (limited to '')
-rw-r--r--NewerProject.yaml2
-rw-r--r--NewerProjectKP.yaml2
-rw-r--r--msgbox.yaml11
-rw-r--r--src/msgbox.S1
-rw-r--r--src/msgbox.cpp576
-rw-r--r--tools/msgbox_data.py36
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)
+