summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--include/g3dhax.h40
-rw-r--r--kamek_pal.x24
-rw-r--r--koopatlas.yaml12
-rw-r--r--src/bonusRoom.cpp62
-rw-r--r--src/koopatlas/core.cpp25
-rw-r--r--src/koopatlas/core.h6
-rw-r--r--src/koopatlas/map.cpp4
-rw-r--r--src/koopatlas/pathmanager.cpp8
-rw-r--r--src/koopatlas/shop.cpp507
-rw-r--r--src/koopatlas/shop.h62
10 files changed, 718 insertions, 32 deletions
diff --git a/include/g3dhax.h b/include/g3dhax.h
index d358436..551af40 100644
--- a/include/g3dhax.h
+++ b/include/g3dhax.h
@@ -30,6 +30,7 @@ namespace nw4r {
class ResAnmChr { public: void* data; ResAnmChr(void *p = NULL) { data = p; } };
class ResAnmVis { public: void* data; ResAnmVis(void *p = NULL) { data = p; } };
+ class ResAnmClr { public: void* data; ResAnmClr(void *p = NULL) { data = p; } };
class ResAnmTexPat { public: void* data; ResAnmTexPat(void *p = NULL) { data = p; } };
class ResAnmTexSrt { public: void* data; ResAnmTexSrt(void *p = NULL) { data = p; } };
@@ -51,7 +52,7 @@ namespace nw4r {
void * /*ResTex*/ GetResTex(u32 idx) const;
ResAnmChr GetResAnmChr(const char *str) const;
ResAnmVis GetResAnmVis(const char *str) const;
- void * /*ResAnmClr*/ GetResAnmClr(const char *str) const;
+ ResAnmClr GetResAnmClr(const char *str) const;
ResAnmTexPat GetResAnmTexPat(const char *str) const;
ResAnmTexSrt GetResAnmTexSrt(const char *str) const;
void * /*ResAnmScn*/ GetResAnmScn(const char *str) const;
@@ -89,6 +90,13 @@ namespace nw4r {
void * /*ResMdl*/ resMdl);
+ void *__AnmObjClrRes__Construct(
+ void * /*MEMAllocator*/ pHeap,
+ u32 *pSize,
+ void * /*ResAnmVis*/ resAnm,
+ void * /*ResMdl*/ resMdl);
+
+
void *__AnmObjTexPatRes__Construct(
void * /*MEMAllocator*/ pHeap,
u32 *pSize,
@@ -315,6 +323,36 @@ namespace m3d {
void bind(/*b*/mdl_c *model, nw4r::g3d::ResAnmVis anmRes, int unk);
};
+ class anmClr_c : public fanm_c {
+ public:
+ class child_c : public fanm_c {
+ ~child_c();
+ int _vf0C();
+ // some methods missing
+ };
+
+ ~anmClr_c();
+ int _vf0C();
+ void detach();
+ void process();
+
+ bool setup(nw4r::g3d::ResMdl modelRes, nw4r::g3d::ResAnmClr anmRes,
+ mAllocator_c *allocator, u32 *sizeOutPtr, int count); // count usually 1 or 2, sizeOutPtr usually 0
+
+ void bind(/*b*/mdl_c *model, nw4r::g3d::ResAnmClr anmRes, int entryNumber, int _param4); // usually entryNumber is 0, param4 is 0 or 1
+
+
+ float getFrameForEntry(int number);
+ void setFrameForEntry(float value, int number);
+ float getUpdateRateForEntry(int number);
+ void setUpdateRateForEntry(float value, int number);
+ bool isEntryAnimationDone(int number);
+ bool queryEntrySomething(float value, int number);
+ void setEntryByte34(u8 value, int number);
+ float getEntryField28(int number);
+
+ };
+
class anmTexPat_c : public banm_c {
public:
class child_c : public fanm_c {
diff --git a/kamek_pal.x b/kamek_pal.x
index 7978605..8c337d3 100644
--- a/kamek_pal.x
+++ b/kamek_pal.x
@@ -737,6 +737,7 @@ SECTIONS {
resetAnim__Q23m2d13EmbedLayout_cFib = 0x800C94C0;
disableAllAnimations__Q23m2d13EmbedLayout_cFv = 0x800C95F0;
isAnimOn__Q23m2d13EmbedLayout_cFi = 0x800C9700;
+ isAnyAnimOn__Q23m2d13EmbedLayout_cFv = 0x800C9730;
free__Q23m2d13EmbedLayout_cFv = 0x800C9A20;
execAnimations__Q23m2d13EmbedLayout_cFv = 0x800C9650;
scheduleForDrawing__Q23m2d6Base_cFv = 0x80163990;
@@ -1237,11 +1238,13 @@ SECTIONS {
GetResMdl = 0x80239F70;
GetResAnmChr = 0x8023A1F0;
GetResAnmVis = 0x8023A260;
+ GetResAnmClr = 0x8023A2D0;
GetResAnmTexPat = 0x8023A340;
GetResAnmTexSrt = 0x8023a3b0;
GetResAnmChr__Q34nw4r3g3d7ResFileCFPCc = 0x8023a1f0;
GetResAnmVis__Q34nw4r3g3d7ResFileCFPCc = 0x8023a260;
+ GetResAnmClr__Q34nw4r3g3d7ResFileCFPCc = 0x8023A2D0;
GetResAnmTexPat__Q34nw4r3g3d7ResFileCFPCc = 0x8023a340;
GetResAnmTexSrt__Q34nw4r3g3d7ResFileCFPCc = 0x8023a3b0;
@@ -1285,6 +1288,27 @@ SECTIONS {
bind__Q23m3d8anmVis_cFPQ23m3d5mdl_cQ34nw4r3g3d9ResAnmVisi = 0x80167ea0;
internalBind__Q23m3d8anmVis_cFv = 0x80167f90;
+ /* m3d::anmClr_c */
+ __vt__Q23m3d8anmClr_c = 0x80329860;
+ __dt__Q23m3d8anmClr_cFv = 0x80165FB0;
+ vf0C__Q23m3d8anmClr_cFv = 0x801664E0;
+ detach__Q23m3d8anmClrFv = 0x80166020;
+ process__Q23m3d8anmClrFv = 0x80166310;
+
+ setup__Q23m3d8anmClr_cFQ34nw4r3g3d6ResMdlQ34nw4r3g3d9ResAnmClrP12mAllocator_cPUii = 0x80165D70;
+ bind__Q23m3d8anmClr_cFPQ23m3d5mdl_cQ34nw4r3g3d9ResAnmClrii = 0x80166110;
+
+ getFrameForEntry__Q23m3d8anmClrFv = 0x80166420;
+ setFrameForEntry__Q23m3d8anmClrFfi = 0x80166430;
+ getUpdateRateForEntry__Q23m3d8anmClrFv = 0x80166440;
+ setUpdateRateForEntry__Q23m3d8anmClrFfi = 0x80166450;
+ isEntryAnimationDone__Q23m3d8anmClrFv = 0x80166460;
+ queryEntrySomething__Q23m3d8anmClrFv = 0x80166470;
+ setEntryByte34__Q23m3d8anmClrFUci = 0x80166480;
+ getEntryField28__Q23m3d8anmClrFv = 0x801664A0;
+
+
+ /* m3d::anmTexPat_c */
__vt__Q23m3d11anmTexPat_c = 0x80329890;
__dt__Q23m3d11anmTexPat_cFv = 0x80166bb0;
detach__Q23m3d11anmTexPat_cFv = 0x80166c20;
diff --git a/koopatlas.yaml b/koopatlas.yaml
index c376f51..1bc3466 100644
--- a/koopatlas.yaml
+++ b/koopatlas.yaml
@@ -12,6 +12,7 @@ source_files:
- ../src/koopatlas/map.cpp
- ../src/koopatlas/mapdata.cpp
- ../src/koopatlas/pathmanager.cpp
+ - ../src/koopatlas/shop.cpp
hooks:
- name: BuildWorldMap
@@ -39,6 +40,17 @@ hooks:
src_addr_pal: 0x80984710
target_func: 'dWMMap_c::build(void)'
+ - name: BuildWMShop
+ type: add_func_pointer
+ src_addr_pal: 0x80986074
+ target_func: 'dWMShop_c::build(void)'
+
+ - name: BuildWMdShopItem
+ type: add_func_pointer
+ src_addr_pal: 0x809894B4
+ target_func: 'dShopItem::build(void)'
+
+
# fix the STOCK_ITEM references
- name: StockItemFix
type: patch
diff --git a/src/bonusRoom.cpp b/src/bonusRoom.cpp
index 2b0144d..c4a84cd 100644
--- a/src/bonusRoom.cpp
+++ b/src/bonusRoom.cpp
@@ -10,6 +10,8 @@ extern "C" void *PlaySoundAsync(dStageActor_c *, int soundID);
extern "C" void *StopBGMMusic();
extern "C" void *StartBGMMusic();
extern "C" dStageActor_c* GetSpecificPlayerActor(int number);
+extern "C" void *SoundRelatedClass;
+extern "C" void *MapSoundPlayer(void *SoundClass, int soundID, int unk);
int Songs[16][4][16][3] = {
@@ -159,8 +161,8 @@ const char* Prizes[10][4] = {
{ "I_penguin", "g3d/I_penguin.brres", "I_penguin", "wait2" },
{ "I_propeller", "g3d/I_propeller_model.brres", "I_propeller_model", "wait2" },
{ "I_kinoko_bundle","g3d/I_mini_kinoko.brres", "I_mini_kinoko", "wait2" },
- { "I_hammer", "g3d/I_hammer.brres", "I_hammer", "wait2" },
{ "I_star", "g3d/I_star.brres", "I_star", "wait2" },
+ { "I_hammer", "g3d/I_fireflower.brres", "I_hammer", "wait2" },
{ "I_kinoko_bundle","g3d/I_life_kinoko.brres", "I_life_kinoko", "wait2" },
{ "obj_coin", "g3d/obj_coin.brres", "obj_coin", "wait2" }
};
@@ -199,30 +201,30 @@ int PrizePacks[16][4] = { // Numbers list prizes for each level
};
int Notes[24] = {
- SE_EMY_PATAMET_STEP,
- SE_EMY_PATAMET_STEP_2,
- SE_EMY_PATAMET_STEP_3,
- SE_EMY_PATAMET_STEP_4,
- SE_EMY_PATAMET_STEP_5,
- SE_EMY_PATAMET_STEP_6,
- SE_EMY_PATAMET_STEP_7,
- SE_EMY_PATAMET_STEP_8,
- SE_EMY_PATAMET_STEP,
- SE_EMY_PATAMET_STEP_2,
- SE_EMY_PATAMET_STEP_3,
- SE_EMY_PATAMET_STEP_4,
- SE_EMY_PATAMET_STEP_5,
- SE_EMY_PATAMET_STEP_6,
- SE_EMY_PATAMET_STEP_7,
- SE_EMY_PATAMET_STEP_8,
- SE_EMY_PATAMET_STEP,
- SE_EMY_PATAMET_STEP_2,
- SE_EMY_PATAMET_STEP_3,
- SE_EMY_PATAMET_STEP_4,
- SE_EMY_PATAMET_STEP_5,
- SE_EMY_PATAMET_STEP_6,
- SE_EMY_PATAMET_STEP_7,
- SE_EMY_PATAMET_STEP_8,
+ STRM_BGM_HIKOUSEN_ROUKA, // C
+ STRM_BGM_HIKOUSEN_ROUKA_FAST,
+ STRM_BGM_LAST_BOSS_FAST, // D
+ STRM_BGM_LAST_BOSS,
+ STRM_BGM_ROAD_TO_LAST_FAST, // E
+ STRM_BGM_ROAD_TO_LAST, // F
+ STRM_BGM_LAST_CASTLE_APPEAR,
+ STRM_BGM_SELECT_W5, // G
+ STRM_BGM_SELECT_W7,
+ STRM_BGM_HIKOUSEN, // A
+ STRM_BGM_HIKOUSEN_BOSS_FAST,
+ STRM_BGM_HIKOUSEN_FAST, // B
+ STRM_BGM_OBAKE, // C
+ STRM_BGM_SHIRO_FAST,
+ STRM_BGM_SHIRO, // D
+ STRM_BGM_WATER_FAST,
+ STRM_BGM_WATER, // E
+ STRM_BGM_TORIDE_BOSS_FAST, // F
+ STRM_BGM_TORIDE_BOSS,
+ STRM_BGM_DEMO_ED, // G
+ STRM_BGM_DEMO_OP,
+ STRM_BGM_SELECT_W8, // A
+ STRM_BGM_MG_BTL,
+ STRM_BGM_OBAKE_FAST, // B
};
@@ -524,10 +526,10 @@ int dSingAlong::onCreate() {
OSReport("Creating the Sing Along gang.");
// Load in the settings
this->song = this->settings & 0xF;
- this->prize[0] = (this->settings >> 16) & 0xF;
- this->prize[1] = (this->settings >> 20) & 0xF;
- this->prize[2] = (this->settings >> 24) & 0xF;
- this->prize[3] = (this->settings >> 28) & 0xF;
+ this->prize[0] = (this->settings >> 28) & 0xF;
+ this->prize[1] = (this->settings >> 24) & 0xF;
+ this->prize[2] = (this->settings >> 20) & 0xF;
+ this->prize[3] = (this->settings >> 16) & 0xF;
this->chorus = -1;
this->currentNote = 0;
@@ -588,7 +590,7 @@ void dSingAlong::RegisterNote(int note) {
OSReport("State was checked");
if (note == Songs[song][chorus][currentNote][0]) {
- PlaySoundAsync(this, Notes[Songs[song][chorus][currentNote][1]-1]);
+ MapSoundPlayer(SoundRelatedClass, Notes[Songs[song][chorus][currentNote][1]-1], 1);
OSReport("Note was correct");
currentNote += 1;
}
diff --git a/src/koopatlas/core.cpp b/src/koopatlas/core.cpp
index 2317d00..bce31b1 100644
--- a/src/koopatlas/core.cpp
+++ b/src/koopatlas/core.cpp
@@ -17,6 +17,7 @@ CREATE_STATE_E(dScKoopatlas_c, TitleConfirmHitWait);
CREATE_STATE_E(dScKoopatlas_c, PlayerChangeWait);
CREATE_STATE_E(dScKoopatlas_c, EasyPairingWait);
CREATE_STATE_E(dScKoopatlas_c, PowerupsWait);
+CREATE_STATE_E(dScKoopatlas_c, ShopWait);
CREATE_STATE_E(dScKoopatlas_c, SaveOpen);
CREATE_STATE_E(dScKoopatlas_c, SaveSelect);
CREATE_STATE_E(dScKoopatlas_c, SaveWindowClose);
@@ -142,6 +143,15 @@ bool WMInit_LoadSIAnims(void *ptr) {
DVD_LoadFile(GetDVDClass(), "WorldMap", "SI_star", 0);
DVD_LoadFile(GetDVDClass(), "Object", "I_hammer", 0);
DVD_LoadFile(GetDVDClass(), "Object", "cobCourse", 0);
+ DVD_LoadFile(GetDVDClass(), "Object", "obj_coin", 0);
+ DVD_LoadFile(GetDVDClass(), "Object", "I_kinoko", 0);
+ DVD_LoadFile(GetDVDClass(), "Object", "I_fireflower", 0);
+ DVD_LoadFile(GetDVDClass(), "Object", "I_iceflower", 0);
+ DVD_LoadFile(GetDVDClass(), "Object", "I_penguin", 0);
+ DVD_LoadFile(GetDVDClass(), "Object", "I_propeller", 0);
+ DVD_LoadFile(GetDVDClass(), "Object", "I_star", 0);
+ DVD_LoadFile(GetDVDClass(), "Object", "I_kinoko_bundle", 0);
+ DVD_LoadFile(GetDVDClass(), "Object", "lakitu", 0);
return true;
}
@@ -246,6 +256,10 @@ bool WMInit_SetupExtra(void *ptr) {
// because we require it earlier
// it is created in dScKoopatlas_c::onCreate
+ SpammyReport("creating SHOP\n");
+ wm->shop = (dWMShop_c*)CreateParentedObject(WM_SHOP, wm, 0, 0);
+
+
SpammyReport("SetupExtra done\n");
return true;
@@ -649,6 +663,17 @@ void dScKoopatlas_c::executeState_PowerupsWait() {
}
+
+/**********************************************************************/
+// STATE_ShopWait : Wait for the user to exit the Shop screen.
+void dScKoopatlas_c::executeState_ShopWait() {
+
+ if (shop->isHidden) {
+ state.setState(&StateID_Normal);
+ }
+
+}
+
/**********************************************************************/
// STATE_SaveOpen : Waiting for the "Save?" YesNoWindow to open
void dScKoopatlas_c::executeState_SaveOpen() {
diff --git a/src/koopatlas/core.h b/src/koopatlas/core.h
index 55baf95..760de19 100644
--- a/src/koopatlas/core.h
+++ b/src/koopatlas/core.h
@@ -12,6 +12,7 @@
#include "levelinfo.h"
#include "koopatlas/mapdata.h"
+#include "koopatlas/shop.h"
#include "koopatlas/pathmanager.h"
#define WM_DEBUGGING
@@ -32,10 +33,13 @@
void NewerMapDrawFunc();
#define WM_HUD WM_DANCE_PAKKUN
+#define WM_SHOP WM_TOGEZO
+#define WM_SHOPITEM WM_PUKU
class daWMPlayer_c;
class dWMHud_c;
class dWMMap_c;
+class dWMShop_c;
class dWorldCamera_c;
class dScKoopatlas_c : public dScene_c {
@@ -57,6 +61,7 @@ class dScKoopatlas_c : public dScene_c {
DECLARE_STATE(PlayerChangeWait);
DECLARE_STATE(EasyPairingWait);
DECLARE_STATE(PowerupsWait);
+ DECLARE_STATE(ShopWait);
DECLARE_STATE(SaveOpen);
DECLARE_STATE(SaveSelect);
DECLARE_STATE(SaveWindowClose);
@@ -92,6 +97,7 @@ class dScKoopatlas_c : public dScene_c {
daWMPlayer_c *player;
dWMHud_c *hud;
dWMMap_c *map;
+ dWMShop_c *shop;
int currentMapID;
const char *mapPath;
diff --git a/src/koopatlas/map.cpp b/src/koopatlas/map.cpp
index 2486d34..e37ee4b 100644
--- a/src/koopatlas/map.cpp
+++ b/src/koopatlas/map.cpp
@@ -371,6 +371,7 @@ void dWMMap_c::renderer_c::renderDoodadLayer(dKPLayer_s *layer) {
else
frame = anim->start + (delta * value);
+ float scaleYMod;
// and apply it!
switch (anim->type) {
case dKPDoodad_s::animation_s::X_POS:
@@ -387,6 +388,9 @@ void dWMMap_c::renderer_c::renderDoodadLayer(dKPLayer_s *layer) {
break;
case dKPDoodad_s::animation_s::Y_SCALE:
effectiveHeight = (effectiveHeight * frame / 100.0);
+
+ scaleYMod = doodad->height - effectiveHeight;
+ effectiveY += scaleYMod;
break;
case dKPDoodad_s::animation_s::OPACITY:
// TODO
diff --git a/src/koopatlas/pathmanager.cpp b/src/koopatlas/pathmanager.cpp
index ee7b596..de2a584 100644
--- a/src/koopatlas/pathmanager.cpp
+++ b/src/koopatlas/pathmanager.cpp
@@ -530,7 +530,13 @@ void dWMPathManager_c::activatePoint() {
int w = currentNode->levelNumber[0] - 1;
int l = currentNode->levelNumber[1] - 1;
- if ((l > 29) && (l < 38)) {
+ if (l == 0) {
+ dWMShop_c::instance->LoadShopForWorld(w);
+ dScKoopatlas_c::instance->state.setState(&dScKoopatlas_c::instance->StateID_ShopWait);
+ return;
+ }
+
+ if ((l >= 29) && (l <= 36)) {
SaveBlock *save = GetSaveFile()->GetBlock(-1);
u32 conds = save->GetLevelCondition(w, l);
diff --git a/src/koopatlas/shop.cpp b/src/koopatlas/shop.cpp
new file mode 100644
index 0000000..ed64c8e
--- /dev/null
+++ b/src/koopatlas/shop.cpp
@@ -0,0 +1,507 @@
+#include "koopatlas/shop.h"
+
+
+int getStarCoinCountShop() {
+ SaveBlock *save = GetSaveFile()->GetBlock(-1);
+ int coinsSpent = save->credits_hiscore;
+ int coinsEarned = 0;
+
+ for (int w = 0; w < 10; w++) {
+ for (int l = 0; l < 10; l++) {
+ u32 conds = save->GetLevelCondition(w, l);
+
+ if (conds & COND_COIN1) { coinsEarned++; }
+ if (conds & COND_COIN2) { coinsEarned++; }
+ if (conds & COND_COIN3) { coinsEarned++; }
+ }
+ }
+
+ int coinsLeft = coinsEarned - coinsSpent;
+ return coinsLeft;
+}
+
+
+const char* Produce[10][4] = {
+ { "I_kinoko", "g3d/I_kinoko.brres", "I_kinoko", "wait2" },
+ { "I_fireflower", "g3d/I_fireflower.brres", "I_fireflower", "wait2" },
+ { "I_iceflower", "g3d/I_iceflower.brres", "I_iceflower", "wait2" },
+ { "I_penguin", "g3d/I_penguin.brres", "I_penguin", "wait2" },
+ { "I_propeller", "g3d/I_propeller_model.brres", "I_propeller_model", "wait2" },
+ { "I_kinoko_bundle","g3d/I_mini_kinoko.brres", "I_mini_kinoko", "wait2" },
+ { "I_star", "g3d/I_star.brres", "I_star", "wait2" },
+ { "I_hammer", "g3d/I_hammer.brres", "I_hammer", "wait2" },
+ { "I_kinoko_bundle","g3d/I_life_kinoko.brres", "I_life_kinoko", "wait2" },
+ { "obj_coin", "g3d/obj_coin.brres", "obj_coin", "wait2" }
+};
+
+/*****************************************************************************/
+// Shop Model
+
+class dShopItem: public dActor_c {
+public:
+ int onCreate();
+ int onDelete();
+ int onExecute();
+ int onDraw();
+
+ int p;
+
+ mHeapAllocator_c allocator;
+ nw4r::g3d::ResFile resFile;
+ m3d::mdl_c bodyModel;
+ m3d::anmChr_c aw;
+
+ static dShopItem *build();
+};
+
+dShopItem *dShopItem::build() {
+ void *buffer = AllocFromGameHeap1(sizeof(dShopItem));
+ return new(buffer) dShopItem;
+}
+
+int dShopItem::onCreate() {
+
+ // Settings
+ p = settings & 0xF;
+
+ // Model creation
+ allocator.link(-1, GameHeaps[0], 0, 0x20);
+
+ resFile.data = getResource(Produce[p][0], Produce[p][1]);
+ nw4r::g3d::ResMdl mdl = resFile.GetResMdl(Produce[p][2]);
+ bodyModel.setup(mdl, &allocator, 0x224, 1, 0);
+ SetupTextures_Item(&bodyModel, 0); // 800B42B0
+
+ // Animation Assignment
+ nw4r::g3d::ResAnmChr anmChr = resFile.GetResAnmChr("wait2");
+ aw.setup(mdl, anmChr, &allocator, 0);
+ aw.bind(&bodyModel, anmChr, 1);
+ bodyModel.bindAnim(&aw, 0.0);
+ aw.setUpdateRate(1.0);
+ allocator.unlink();
+
+ return true;
+}
+
+int dShopItem::onDelete() { return true; }
+int dShopItem::onExecute() { return true; }
+int dShopItem::onDraw() {
+ if (p == 9) { matrix.translation(pos.x, pos.y + (8.0 * scale.y), pos.z); }
+ else { matrix.translation(pos.x, pos.y, pos.z); }
+
+ matrix.applyRotationYXZ(&rot.x, &rot.y, &rot.z);
+
+ bodyModel.setDrawMatrix(matrix);
+ bodyModel.setScale(&scale);
+ bodyModel.calcWorld(false);
+ bodyModel.scheduleForDrawing();
+ bodyModel._vf1C();
+
+ if(this->aw.isAnimationDone())
+ this->aw.setCurrentFrame(0.0);
+
+ return true;
+}
+
+
+/*****************************************************************************/
+// Shop Layout
+//
+
+
+const char* Lakitu[10] = {
+ "g3d/yoshi.brres", "g3d/desert.brres", "g3d/mountain.brres", "g3d/sakura.brres", "g3d/santa.brres",
+ "g3d/ghost.brres", "g3d/space.brres", "g3d/koopa.brres", "g3d/sewer.brres", "g3d/goldwood.brres"
+};
+
+
+dWMShop_c *dWMShop_c::instance = 0;
+
+dWMShop_c *dWMShop_c::build() {
+ void *buffer = AllocFromGameHeap1(sizeof(dWMShop_c));
+ dWMShop_c *c = new(buffer) dWMShop_c;
+
+ instance = c;
+ return c;
+}
+
+dWMShop_c::dWMShop_c() {
+ layoutLoaded = false;
+}
+
+int dWMShop_c::onCreate() {
+
+ if (!layoutLoaded) {
+ bool gotFile = layout.loadArc("shop.arc", false);
+ if (!gotFile)
+ return false;
+
+ currentItem = 0;
+ isHidden = true;
+
+ static const char *brlanNames[5] = {"shop_hitButton.brlan", "shop_offButton.brlan", "shop_onButton.brlan", "shop_inWindow.brlan", "shop_outWindow.brlan"};
+ static const char *groupNames[20] = {"B00_Button", "B01_Button", "B02_Button", "B03_Button", "B05_Button", "B08_Button",
+ "B00_Button", "B01_Button", "B02_Button", "B03_Button", "B05_Button", "B08_Button",
+ "B00_Button", "B01_Button", "B02_Button", "B03_Button", "B05_Button", "B08_Button",
+ "A00_Window", "A00_Window"};
+
+ bool output = layout.build("shop.brlyt");
+
+ if (!IsWideScreen()) {
+ layout.clippingEnabled = true;
+ layout.clipX = 0;
+ layout.clipY = 52;
+ layout.clipWidth = 640;
+ layout.clipHeight = 352;
+ layout.layout.rootPane->scale.x = 0.7711f;
+ layout.layout.rootPane->scale.y = 0.7711f;
+ }
+
+ layout.loadAnimations(brlanNames, 5);
+ layout.loadGroups(groupNames, (int[20]){0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 4}, 20);
+ layout.disableAllAnimations();
+
+ for (int i = 6; i < 12; i++) {
+ layout.enableNonLoopAnim(i);
+ }
+
+ layout.drawOrder = 0x01;
+
+ layoutLoaded = true;
+ }
+
+ return true;
+}
+
+
+int dWMShop_c::onDelete() {
+ return layout.free();
+}
+
+
+int dWMShop_c::onExecute() {
+ layout.execAnimations();
+ layout.update();
+
+ if (!isHidden) {
+ int nowPressed = Remocon_GetPressed(GetActiveRemocon());
+
+ if (!layout.isAnyAnimOn()) {
+ if (nowPressed & WPAD_B) {
+ MapSoundPlayer(SoundRelatedClass, SE_SYS_DIALOGUE_OUT_AUTO, 1);
+ CloseUpShop();
+ } else if (nowPressed & WPAD_DOWN) {
+ if (currentItem == 6) { return true; }
+ MapSoundPlayer(SoundRelatedClass, SE_SYS_CURSOR, 1);
+ int last = currentItem;
+ if (currentItem == 0) { currentItem = 1; }
+ else if (currentItem < 5) { currentItem = 5; }
+ else { currentItem = 6; }
+ changeItem(last, currentItem);
+ } else if (nowPressed & WPAD_UP) {
+ if (currentItem == 0) { return true; }
+ MapSoundPlayer(SoundRelatedClass, SE_SYS_CURSOR, 1);
+ int last = currentItem;
+ if (currentItem < 5) { currentItem = 0; }
+ else if (currentItem == 5) { currentItem = 1; }
+ else { currentItem = 5; }
+ changeItem(last, currentItem);
+ } else if (nowPressed & WPAD_RIGHT) {
+ if (currentItem == 6) { currentItem = 6; return true; }
+ MapSoundPlayer(SoundRelatedClass, SE_SYS_CURSOR, 1);
+ int last = currentItem;
+ currentItem += 1;
+ changeItem(last, currentItem);
+ } else if (nowPressed & WPAD_LEFT) {
+ if (currentItem == 0) { return true; }
+ MapSoundPlayer(SoundRelatedClass, SE_SYS_CURSOR, 1);
+ int last = currentItem;
+ currentItem -= 1;
+ changeItem(last, currentItem);
+ } else if (nowPressed & WPAD_TWO) {
+ BuyItem(currentItem);
+ }
+ }
+ }
+
+ return true;
+}
+
+int dWMShop_c::onDraw() {
+ if (isHidden) {
+ if (layout.isAnimOn(19)) { layout.scheduleForDrawing(); }
+ }
+
+ if (!isHidden) {
+ layout.scheduleForDrawing();
+
+ Vec pos = {layout.posX, layout.posY, 40000.0};
+ S16Vec rot = {0,0,0};
+ Vec scale = {1.0, 1.0, 1.0};
+ matrix.translation(pos.x, pos.y, pos.z);
+ matrix.applyRotationYXZ(&rot.x, &rot.y, &rot.z);
+
+ shopkeep.setDrawMatrix(matrix);
+ shopkeep.setScale(&scale);
+ shopkeep.calcWorld(false);
+ shopkeep.scheduleForDrawing();
+ shopkeep._vf1C();
+
+ if(this->ska.isAnimationDone())
+ this->ska.setCurrentFrame(0.0);
+ }
+
+ return true;
+}
+
+void dWMShop_c::specialDraw1() {
+ OSReport("Lakionnnne....");
+ if (!isHidden) {
+ Vec pos = {layout.posX, layout.posY, 40000.0};
+ S16Vec rot = {0,0,0};
+ Vec scale = {1.0, 1.0, 1.0};
+ matrix.translation(pos.x, pos.y, pos.z);
+ matrix.applyRotationYXZ(&rot.x, &rot.y, &rot.z);
+
+ shopkeep.setDrawMatrix(matrix);
+ shopkeep.setScale(&scale);
+ shopkeep.calcWorld(false);
+ shopkeep.scheduleForDrawing();
+ shopkeep._vf1C();
+
+ if(this->ska.isAnimationDone())
+ this->ska.setCurrentFrame(0.0);
+ }
+ return;
+}
+
+void dWMShop_c::specialDraw2() {
+ OSReport("Lakituuu....");
+ if (!isHidden) {
+ Vec pos = {layout.posX, layout.posY, 40000.0};
+ S16Vec rot = {0,0,0};
+ Vec scale = {1.0, 1.0, 1.0};
+ matrix.translation(pos.x, pos.y, pos.z);
+ matrix.applyRotationYXZ(&rot.x, &rot.y, &rot.z);
+
+ shopkeep.setDrawMatrix(matrix);
+ shopkeep.setScale(&scale);
+ shopkeep.calcWorld(false);
+ shopkeep.scheduleForDrawing();
+ shopkeep._vf1C();
+
+ if(this->ska.isAnimationDone())
+ this->ska.setCurrentFrame(0.0);
+ }
+ return;
+}
+
+
+void dWMShop_c::changeItem(int last, int current) {
+
+ if (last) { layout.enableNonLoopAnim(last - 1 + 6); }
+ if (current) { layout.enableNonLoopAnim(current - 1 + 12); }
+
+}
+
+ // Powerup Listing:
+ // 0 = Mushroom - 1
+ // 1 = Fireflower - 2
+ // 2 = Iceflower - 2
+ // 3 = Penguin - 3
+ // 4 = Propeller - 3
+ // 5 = MiniShroom - 2
+ // 6 = Starman - 2
+ // 7 = Hammer - 3
+ // 8 = 1-ups - 2
+ // 9 = Coins - 1
+ //
+ // Format: 1coin, 1coin, 2coins, 3coins, 5coins[3] (Value 6-9), 8coins[5] (Value 10-15)
+ //
+ // Possible 5 coin combos = 2,2,2 / 1,2,3 / 2,3,2 / 3,2,3 / 3,3,3
+ // Possible 8 coin combos = 1,1,2,3,3 / 1,2,2,3,3 / 1,2,3,3,3 / 2,2,2,3,3 / 2,2,3,3,3 / 1,3,3,3,3 / 2,3,3,3,3 / 3,3,3,3,3
+
+int Inventory[10][12] = {
+ { 9, 0, 1, 4, 1, 2, 1, 0, 0, 8, 4, 4 }, // Yoshi Island Shop
+ { 9, 0, 1, 4, 1, 6, 1, 0, 1, 1, 4, 4 }, // Desert Shop
+ { 9, 0, 5, 4, 0, 5, 4, 0, 5, 4, 4, 7 }, // Mountain Shop
+ { 9, 0, 8, 7, 8, 8, 8, 4, 2, 8, 1, 4 }, // Japan Shop
+ { 9, 0, 2, 3, 2, 3, 2, 2, 3, 3, 3, 2 }, // FreezeFlame Shop
+ { 9, 0, 6, 4, 5, 4, 5, 4, 4, 9, 4, 4 }, // Ghost Shop
+ { 9, 0, 6, 7, 6, 6, 6, 7, 7, 8, 7, 7 }, // Space Shop
+ { 0, 8, 4, 7, 7, 4, 7, 4, 7, 4, 7, 4 }, // Koopa Shop
+ { 9, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0 }, // Sewer Shop?
+ { 0, 8, 1, 5, 1, 4, 1, 1, 1, 6, 1, 1 }, // Goldwood Shop
+};
+
+void dWMShop_c::LoadShopForWorld(int world) {
+ if (!isHidden) {
+ return; }
+
+ // Handle showing it
+ MapSoundPlayer(SoundRelatedClass, SE_SYS_DIALOGUE_IN, 1);
+ isHidden = false;
+ layout.enableNonLoopAnim(18);
+
+ // Model creation
+ allocator.link(-1, GameHeaps[0], 0, 0x20);
+
+ res.data = getResource("lakitu", Lakitu[world]);
+ nw4r::g3d::ResMdl mdl = res.GetResMdl("lakitu");
+ shopkeep.setup(mdl, &allocator, 0x224, 1, 0);
+ SetupTextures_Item(&shopkeep, 0); // 800B42B0
+
+ // Animation Assignment (idle, notenough)
+ nw4r::g3d::ResAnmChr anmChr = res.GetResAnmChr("idle");
+ ska.setup(mdl, anmChr, &allocator, 0);
+ ska.bind(&shopkeep, anmChr, 1);
+ shopkeep.bindAnim(&ska, 0.0);
+ ska.setUpdateRate(1.0);
+ allocator.unlink();
+
+
+ Vec pos = {layout.posX, layout.posY, 40000.0};
+
+ // Setup all the item buttons for sale
+ // itemA = (dShopItem*)CreateChildObject(WM_SHOPITEM, this, Inventory[world][0], 0, 0);
+ // itemB = (dShopItem*)CreateChildObject(WM_SHOPITEM, this, Inventory[world][1], 0, 0);
+ // itemC = (dShopItem*)CreateChildObject(WM_SHOPITEM, this, Inventory[world][2], 0, 0);
+ // itemD = (dShopItem*)CreateChildObject(WM_SHOPITEM, this, Inventory[world][3], 0, 0);
+ // itemEA = (dShopItem*)CreateChildObject(WM_SHOPITEM, this, Inventory[world][4], 0, 0);
+ // itemEB = (dShopItem*)CreateChildObject(WM_SHOPITEM, this, Inventory[world][5], 0, 0);
+ // itemEC = (dShopItem*)CreateChildObject(WM_SHOPITEM, this, Inventory[world][6], 0, 0);
+ // itemFA = (dShopItem*)CreateChildObject(WM_SHOPITEM, this, Inventory[world][7], 0, 0);
+ // itemFB = (dShopItem*)CreateChildObject(WM_SHOPITEM, this, Inventory[world][8], 0, 0);
+ // itemFC = (dShopItem*)CreateChildObject(WM_SHOPITEM, this, Inventory[world][9], 0, 0);
+ // itemFD = (dShopItem*)CreateChildObject(WM_SHOPITEM, this, Inventory[world][10], 0, 0);
+ // itemFE = (dShopItem*)CreateChildObject(WM_SHOPITEM, this, Inventory[world][11], 0, 0);
+}
+
+
+void dWMShop_c::CloseUpShop() {
+ isHidden = true;
+ layout.enableNonLoopAnim(19);
+ changeItem(currentItem, 0);
+ currentItem = 0;
+
+ // itemA->Delete();
+ // itemB->Delete();
+ // itemC->Delete();
+ // itemD->Delete();
+ // itemEA->Delete();
+ // itemEB->Delete();
+ // itemEC->Delete();
+ // itemFA->Delete();
+ // itemFB->Delete();
+ // itemFC->Delete();
+ // itemFD->Delete();
+ // itemFE->Delete();
+}
+
+
+void dWMShop_c::BuyItem(int item) {
+ OSReport("Buy item %d", item);
+
+ if (item == 0) {
+ MapSoundPlayer(SoundRelatedClass, SE_SYS_INVALID, 1);
+ return;
+ }
+
+ layout.enableNonLoopAnim(item-1);
+
+ int cash = getStarCoinCountShop();
+ int cost;
+
+ int Powerups[10];
+
+ Powerups[0] = 0; // Mushroom
+ Powerups[1] = 0; // Fireflower
+ Powerups[2] = 0; // Iceflower
+ Powerups[3] = 0; // Penguin
+ Powerups[4] = 0; // Propeller
+ Powerups[5] = 0; // MiniShroom
+ Powerups[6] = 0; // Starman
+ Powerups[7] = 0; // Hammer
+ Powerups[8] = 0; // 1-ups
+ Powerups[9] = 0; // Coins
+
+ switch(item) {
+ case 1:
+ cost = 1;
+ Powerups[Inventory[world][item-1]]++;
+ break;
+ case 2:
+ cost = 1;
+ Powerups[Inventory[world][item-1]]++;
+ break;
+ case 3:
+ cost = 2;
+ Powerups[Inventory[world][item-1]]++;
+ break;
+ case 4:
+ cost = 3;
+ Powerups[Inventory[world][item-1]]++;
+ break;
+ case 5:
+ cost = 5;
+ Powerups[Inventory[world][item-1]]++;
+ Powerups[Inventory[world][item+0]]++;
+ Powerups[Inventory[world][item+1]]++;
+ break;
+ case 6:
+ cost = 8;
+ Powerups[Inventory[world][item+1]]++;
+ Powerups[Inventory[world][item+2]]++;
+ Powerups[Inventory[world][item+3]]++;
+ Powerups[Inventory[world][item+4]]++;
+ Powerups[Inventory[world][item+5]]++;
+ break;
+ }
+
+ if (cost > cash) {
+ MapSoundPlayer(SoundRelatedClass, SE_SYS_INVALID, 1);
+ return;
+ }
+
+ MapSoundPlayer(SoundRelatedClass, SE_SYS_DECIDE, 1);
+
+
+ SaveFile *file = GetSaveFile();
+ SaveBlock *block = file->GetBlock(file->header.current_file);
+
+ block->credits_hiscore += cost;
+
+
+ for (int i = 0; i < 7; i++) { // Change this to 8 to support hammers
+ block->powerups_available[i] = block->powerups_available[i] + Powerups[i];
+
+ if (block->powerups_available[i] > 99) { block->powerups_available[i] = 99; }
+ }
+
+ for (int i = 0; i < 4; i++) { // Make sure all players get the reward!
+ block->player_coins[i] = (Powerups[9] * 50) + block->player_coins[i];
+
+ for (;block->player_coins[i] < 100; block->player_coins[i] - 100) {
+ block->player_coins[i] = 1 + block->player_coins[i];
+ }
+
+ block->player_lives[i] = Powerups[8] + block->player_lives[i];
+ if (block->player_lives[i] > 99) { block->player_lives[i] = 99; }
+ }
+
+ CloseUpShop();
+ return;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/koopatlas/shop.h b/src/koopatlas/shop.h
new file mode 100644
index 0000000..b4281b7
--- /dev/null
+++ b/src/koopatlas/shop.h
@@ -0,0 +1,62 @@
+#ifndef __KOOPATLAS_SHOP_H
+#define __KOOPATLAS_SHOP_H
+
+#include "koopatlas/core.h"
+
+extern "C" void *SoundRelatedClass;
+extern "C" void *MapSoundPlayer(void *SoundClass, int soundID, int unk);
+
+class dShopItem;
+
+class dWMShop_c : public dActor_c {
+ public:
+ dWMShop_c();
+
+ int onCreate();
+ int onDelete();
+ int onExecute();
+ int onDraw();
+ void specialDraw1();
+ void specialDraw2();
+
+ bool layoutLoaded;
+ m2d::EmbedLayout_c layout;
+
+ mHeapAllocator_c allocator;
+ nw4r::g3d::ResFile res;
+ m3d::mdl_c shopkeep;
+ m3d::anmChr_c ska;
+ mMtx matrix;
+
+ char currentItem;
+ bool isHidden;
+ int world;
+
+ dShopItem *itemA;
+ dShopItem *itemB;
+ dShopItem *itemC;
+ dShopItem *itemD;
+
+ dShopItem *itemEA;
+ dShopItem *itemEB;
+ dShopItem *itemEC;
+
+ dShopItem *itemFA;
+ dShopItem *itemFB;
+ dShopItem *itemFC;
+ dShopItem *itemFD;
+ dShopItem *itemFE;
+
+
+ void LoadShopForWorld(int world);
+ void CloseUpShop();
+ void BuyItem(int item);
+
+ void changeItem(int last, int current);
+
+ static dWMShop_c *build();
+ static dWMShop_c *instance;
+};
+
+#endif
+