#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; isHidden = true; } int dWMShop_c::onCreate() { if (!layoutLoaded) { bool gotFile = layout.loadArc("shop.arc", false); if (!gotFile) return false; currentItem = 0; wasOff = false; 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); } } shopkeep._vf1C(); } return true; } int dWMShop_c::onDraw() { if (isHidden) { if (layout.isAnimOn(19)) { layout.scheduleForDrawing(); } } if (!isHidden) { layout.scheduleForDrawing(); } return true; } void dWMShop_c::specialDraw1() { if (!isHidden && !layout.isAnimOn(18) && !layout.isAnimOn(19)) { Vec pos = {250.0f, 170.0f, 1000.0f}; S16Vec rot = {0,0,0}; Vec scale = {1.0f, 1.0f, 1.0f}; 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(); if (wasOff) { effect.spawn("Wm_ob_greencoinkira", 0, &pos, &rot, &scale); wasOff = false; } 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; } wasOff = true; // 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, 1); // 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; effect.spawn("Wm_ob_greencoinkira", 0, &pos, &rot, &scale); // 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; }