#include #include #include #include #include extern "C" void *MakeMarioEnterDemoMode(); extern "C" void *MakeMarioExitDemoMode(); extern "C" bool SpawnEffect(const char*, int, Vec*, S16Vec*, Vec*); extern "C" void *StopBGMMusic(); extern "C" void *StartBGMMusic(); extern "C" void *SoundRelatedClass; extern "C" void *MapSoundPlayer(void *SoundClass, int soundID, int unk); // THIS IS A DUMB NAME extern bool NoMichaelBuble; int Songs[16][4][16][3] = { // First number is the block, Second is the note/sfx, Third is timing: 30 is one quarter note at 120 bpm, 0,0 ends the sequence // SMW Donut Plains // SMW Forest of Illusion // Paper Mario Battle Theme // Gusty Garden Galaxy // Thwomp Volcano: PiT // SMRPG Forest? // SMRPG Nimbus Land? // Teehee Valley: Superstar Saga // SML Theme // Mario Sunshine Main Theme // Mario Kart DS Theme // Overworld Themes: 5-6 // Cave Themes: 2-3 // Themed: Yoshi, Ghost, Snow, Star, Desert, Space, Castle, Bowser // Currently.... // Overworld Themes: 1,4,5,8,10 // Cave Themes: 2,6 // Themed: 9, -, 12, 3, -, -, 7, 11 { // Song 1 - Super Mario Bros Melody |*** | {{3,17,0},{3,17,15},{3,17,45},{1,13,75},{3,17,90},{5,20,120},{0,0,0}}, {{1,13,0},{5,8,22},{3,5,45},{6,10,67},{7,12,82},{6,11,97},{6,10,105},{0,0,0}}, {{1,13,0},{1,13,7},{1,13,22},{1,13,37},{2,15,45},{3,17,60},{1,13,67},{7,10,82},{6,8,90},{0,0,0}}, {{1,13,0},{1,13,7},{1,13,22},{1,13,37},{2,15,45},{3,17,52},{0,0,0}} }, { // Song 2 - Super Mario Bros. Underground |**** | {{7,12,0},{7,24,15},{5,9,30},{5,21,45},{6,10,60},{6,22,75},{0,0,0}}, {{3,5,0},{3,17,15},{1,2,30},{1,14,45},{2,3,60},{2,15,75},{0,0,0}}, {{2,15,0},{1,14,10},{1,13,20},{7,12,30},{2,15,45},{1,14,60},{5,8,75},{4,7,90},{1,13,105},{0,0,0}}, {{7,12,0},{4,18,10},{3,17,20},{2,16,30},{6,22,40},{5,21,50},{4,20,60},{2,15,80},{6,11,100},{6,10,120},{5,9,140},{5,8,150},{0,0,0}} }, { // Song 3 - SMB Starman |** | {{4,6,0},{4,6,15},{4,6,30},{2,3,45},{4,6,52},{4,6,68},{2,3,82},{4,6,90},{2,3,98},{4,6,105},{0,0,0}}, {{3,5,0},{3,5,15},{3,5,30},{1,1,45},{3,5,52},{3,5,68},{1,1,82},{3,5,90},{1,1,98},{3,5,105},{0,0,0}}, {{4,18,0},{4,18,15},{4,18,30},{2,15,45},{4,18,52},{4,18,68},{2,15,82},{4,18,90},{2,15,98},{4,18,105},{0,0,0}}, {{3,17,0},{3,17,15},{3,17,30},{1,13,45},{3,17,52},{3,17,68},{1,13,82},{3,17,90},{1,13,98},{3,17,105},{0,0,0}} }, { // Song 4 - SMB3 Clouds |* | {{5,8,0},{5,20,30},{5,8,90},{6,9,120},{6,21,150},{0,0,0}}, {{6,23,0},{5,20,30},{5,8,60},{3,17,120},{4,18,150},{1,14,180},{6,11,240},{0,0,0}}, {{1,8,0},{6,20,30},{1,8,90},{2,9,120},{7,21,150},{0,0,0}}, {{6,23,0},{5,20,30},{1,8,60},{3,17,120},{4,18,150},{1,14,180},{6,11,240},{0,0,0}} }, { // Song 5 - SMB3 Hammer Bros |*****| {{2,16,0},{3,17,15},{2,16,30},{3,17,45},{2,15,60},{1,13,75},{6,10,90},{1,13,105},{0,0,0}}, {{2,16,0},{3,17,15},{2,16,30},{3,17,45},{2,15,60},{1,13,75},{6,10,90},{1,13,105},{1,13,135},{3,16,150},{2,15,158},{1,13,165},{6,10,195},{1,13,210},{0,0,0}}, {{4,17,0},{4,17,15},{5,19,30},{6,20,45},{7,21,60},{4,17,75},{4,17,105},{3,15,120},{3,15,135},{2,14,150},{3,15,165},{0,0,0}}, {{2,16,0},{3,17,15},{2,16,30},{3,17,45},{2,15,60},{1,13,75},{6,10,90},{1,13,105},{5,17,135},{5,17,150},{5,17,165},{5,17,180},{5,17,195},{5,17,210},{5,17,225},{0,0,0}} }, { // Song 6 - SMB3 Underwater |**** | {{1,8,0},{3,13,15},{6,20,30},{5,19,45},{7,22,75},{5,19,105},{6,20,120},{4,17,135},{3,13,150},{1,8,165},{2,10,195},{0,0,0}}, {{1,7,0},{2,8,15},{4,13,30},{6,20,45},{5,19,60},{7,22,90},{5,19,120},{6,20,135},{0,0,0}}, {{2,10,0},{3,13,15},{6,22,30},{5,21,45},{7,24,75},{6,22,105},{4,20,120},{1,8,135},{6,22,150},{4,20,165},{0,0,0}}, {{1,8,0},{2,11,15},{5,20,30},{4,18,45},{5,20,75},{3,16,105},{6,22,120},{5,20,180},{0,0,0}} }, { // Song 7 - SMW Castle |* | {{5,9,0},{4,6,60},{1,1,90},{2,3,120},{4,6,150},{0,0,0}}, {{1,1,0},{4,6,30},{7,13,60},{5,9,90},{4,8,150},{0,0,0}}, {{3,16,0},{2,15,30},{1,13,60},{6,15,90},{1,10,150},{0,0,0}}, {{2,15,0},{1,13,30},{2,15,60},{3,16,90},{1,15,150},{0,0,0}} }, { // Song 8 - SMW Theme |** | {{6,10,0},{4,6,30},{1,1,52},{2,3,60},{4,6,68},{4,6,82},{0,0,0}}, {{2,3,0},{1,1,8},{4,6,22},{4,6,38},{7,13,52},{6,10,68},{5,8,90},{0,0,0}}, {{6,10,0},{4,6,30},{1,1,52},{2,3,60},{4,6,68},{4,6,82},{5,8,112},{6,10,120},{4,6,128},{1,1,135},{2,3,150},{4,6,172},{0,0,0}}, {{1,13,0},{2,15,15},{1,13,30},{2,15,45},{1,13,60},{1,1,82},{7,11,90},{6,10,98},{5,8,105},{4,6,120},{0,0,0}} }, { // Song 9 - Yoshi Story Theme |* | {{5,17,0},{6,19,60},{5,17,75},{6,19,90},{5,17,120},{0,0,0}}, {{3,14,0},{4,15,60},{3,14,75},{4,15,90},{3,14,120},{0,0,0}}, {{5,17,0},{6,19,60},{5,17,75},{6,19,90},{5,17,120},{0,0,0}}, {{4,15,0},{3,14,15},{4,15,30},{3,14,60},{2,12,120},{1,10,135},{2,12,150},{1,10,180},{0,0,0}} }, { // Song 10 - SM64 Peaches Castle |*** | {{4,8,0},{5,10,45},{4,8,75},{3,7,105},{4,8,120},{6,13,135},{7,17,150},{0,0,0}}, {{3,6,0},{4,8,45},{3,6,75},{2,5,105},{3,6,120},{5,12,135},{6,15,150},{0,0,0}}, {{2,5,0},{3,6,45},{2,5,75},{1,4,105},{2,5,120},{4,10,135},{5,13,150},{0,0,0}}, {{4,10,15},{5,12,30},{6,13,45},{7,15,60},{6,13,75},{7,15,90},{4,10,105},{5,12,135},{4,10,150},{5,12,165},{6,13,180},{6,13,210},{6,13,255},{6,13,270},{6,13,285},{0,0,0}} }, { // Song 11 - SM64 Koopa Road |*** | {{3,6,0},{1,1,75},{3,6,90},{7,16,105},{6,15,120},{5,11,135},{3,6,150},{0,0,0}}, {{3,6,0},{2,4,45},{3,6,75},{5,11,90},{4,9,105},{5,11,120},{0,0,0}}, {{3,6,0},{1,1,75},{3,6,90},{7,16,105},{6,15,120},{5,11,135},{3,6,150},{0,0,0}}, {{1,1,0},{3,6,15},{7,18,30},{6,16,45},{5,15,75},{4,13,150},{5,15,165},{0,0,0}} }, { // Song 12 - Frappe Snowland |*** | {{1,14,15},{2,15,22},{3,17,30},{6,22,38},{3,17,52},{0,0,0}}, {{2,15,0},{1,14,15},{2,15,30},{1,14,38},{6,10,52},{3,5,68},{4,7,75},{3,5,82},{0,0,0}}, {{1,14,15},{2,15,22},{3,17,30},{6,22,38},{3,17,52},{0,0,0}}, {{2,15,0},{1,14,15},{2,15,30},{1,14,38},{6,10,52},{6,10,68},{7,12,75},{6,10,82},{0,0,0}} }, { // Song 13 - Ghost Luigi Mansion theme |**** | {{7,17,15},{7,17,30},{7,17,45},{7,17,60},{4,13,90},{7,17,105},{6,16,120},{3,12,150},{0,0,0}}, {{5,15,15},{5,15,30},{5,15,45},{5,15,60},{3,12,90},{5,15,105},{4,13,120},{2,11,165},{3,12,180},{1,5,210},{0,0,0}}, {{7,17,15},{7,17,30},{7,17,45},{7,17,60},{4,13,90},{7,17,105},{6,16,120},{3,12,150},{0,0,0}}, {{5,15,15},{5,15,30},{5,15,45},{5,15,60},{3,12,90},{5,15,105},{7,17,120},{5,15,135},{4,13,150},{3,12,165},{1,10,180},{0,0,0}} }, { // Song 14 - Desert |** | {{6,9,0},{4,6,30},{3,5,90},{3,5,120},{4,6,135},{0,0,0}}, {{6,9,0},{4,6,30},{3,5,90},{3,5,120},{4,6,135},{0,0,0}}, {{4,13,0},{3,12,150},{5,14,165},{6,17,180},{5,14,195},{4,13,240},{0,0,0}}, {{1,9,0},{2,11,15},{3,12,30},{5,14,60},{4,13,90},{0,0,0}} }, { // Song 15 - Gusty Garden Galaxy |*****| {{5,14,0},{4,13,75},{6,16,90},{5,14,105},{3,9,120},{1,6,195},{2,7,210},{3,9,225},{3,9,240},{2,7,285},{0,0,0}}, {{6,16,0},{5,15,75},{7,18,90},{6,16,105},{4,14,120},{3,13,165},{2,11,195},{3,13,225},{2,11,240},{1,9,285},{0,0,0}}, {{6,21,0},{5,20,75},{7,23,90},{6,21,105},{4,19,120},{3,18,165},{4,19,240},{3,18,315},{6,21,330},{4,19,345},{3,18,360},{1,16,405},{0,0,0}}, {{5,18,0},{4,17,75},{6,19,90},{5,18,105},{4,16,120},{3,15,165},{5,18,195},{4,16,225},{2,14,240},{1,13,285},{2,14,360},{4,16,405},{0,0,0}} }, { // Song 16 - Overworld or Cave {{0,0,0}}, {{0,0,0}}, {{0,0,0}}, {{0,0,0}} } }; const char* Prizes[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_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" } }; int PrizePacks[16][4] = { // Numbers list prizes for each level // 0 = Mushroom // 1 = Fireflower // 2 = Iceflower // 3 = Penguin // 4 = Propeller // 5 = MiniShroom // 6 = Starman // 7 = Hammer // 8 = 1-ups // 9 = Coins {9, 9, 0, 8}, // Coins, Coins, Mushroom, 1-up {9, 0, 8, 1}, // Coins, Mushroom, 1-up, Fireflower {9, 0, 1, 2}, // Coins, Mushroom, Fireflower, Iceflower {9, 0, 5, 4}, // Coins, Mushroom, MiniShroom, Propellor {0, 0, 8, 5}, // Mushroom, Mushroom, 1-up, MiniShroom {0, 1, 2, 7}, // Mushroom, Fireflower, IceFlower, Hammer {0, 8, 4, 4}, // Mushroom, 1-up, Propeller, Propeller {0, 1, 2, 6}, // Mushroom, Fireflower, IceFlower, Starman {8, 8, 8, 8}, // 1-up, 1-up, 1-up, 1-up {8, 1, 4, 7}, // 1-up, Fireflower, Propellor, Hammer {8, 1, 7, 6}, // 1-up, Fireflower, Hammer, Starman {8, 6, 5, 6}, // 1-up, Starman, MiniShroom, Starman {2, 2, 3, 6}, // Iceflower, Iceflower, Penguin, Starman {0, 0, 5, 5}, // Mushroom, Mushroom, MiniShroom, MiniShroom {4, 4, 4, 4}, // Propeller, Propeller, Propeller, Propeller {6, 6, 6, 6} // Starman, Starman, Starman, Starman }; int Notes[24] = { 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 }; const char* SAarcNameList [] = { "obj_coin", "I_hammer", "I_star", "block_light", "block_light_color", "I_kinoko_bundle", NULL }; /*****************************************************************************/ // The Prize Model class dSongPrize: public dEn_c { public: int onCreate(); int onDelete(); int onExecute(); int beforeDraw(); int onDraw(); void doSpin(); mHeapAllocator_c allocator; nw4r::g3d::ResFile resFile; m3d::mdl_c bodyModel; m3d::anmChr_c aw; int queue; int p; int timer; HermiteKey keysX[0x10]; unsigned int Xkey_count; HermiteKey keysY[0x10]; unsigned int Ykey_count; HermiteKey keysS[0x10]; unsigned int Skey_count; USING_STATES(dSongPrize); DECLARE_STATE(Wait); DECLARE_STATE(Shrink); DECLARE_STATE(Spin); static dSongPrize *build(); }; CREATE_STATE(dSongPrize, Wait); CREATE_STATE(dSongPrize, Shrink); CREATE_STATE(dSongPrize, Spin); dSongPrize *dSongPrize::build() { void *buffer = AllocFromGameHeap1(sizeof(dSongPrize)); return new(buffer) dSongPrize; } int dSongPrize::onCreate() { // Settings queue = this->settings & 0xF; int prize = this->settings >> 16; scale = (Vec){ 3.0, 3.0, 3.0 }; p = prize; // Model creation allocator.link(-1, GameHeaps[0], 0, 0x20); resFile.data = getResource(Prizes[p][0], Prizes[p][1]); nw4r::g3d::ResMdl mdl = resFile.GetResMdl(Prizes[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(); // Change State doStateChange(&dSongPrize::StateID_Wait); return true; } int dSongPrize::onDelete() { return true; } int dSongPrize::onExecute() { acState.execute(); return true; } int dSongPrize::beforeDraw() { return 1; } int dSongPrize::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; } void dSongPrize::beginState_Wait() {} void dSongPrize::executeState_Wait() {} void dSongPrize::endState_Wait() {} void dSongPrize::beginState_Shrink() { this->timer = 0; Xkey_count = 2; Ykey_count = 2; Skey_count = 2; // /* keysX[i] = { frame, value, slope }; */ keysX[0] = (HermiteKey){ 0.0, pos.x, 0.8 }; keysY[0] = (HermiteKey){ 0.0, pos.y, 0.8 }; keysS[0] = (HermiteKey){ 0.0, 3.0, -0.8 }; keysX[1] = (HermiteKey){ 60.0, pos.x + (30.0 * queue) - 172.0, 1.0 }; keysY[1] = (HermiteKey){ 60.0, pos.y + 64.0, 1.0 }; keysS[1] = (HermiteKey){ 60.0, 1.0, 0.0 }; } void dSongPrize::executeState_Shrink() { float modX = GetHermiteCurveValue(timer, keysX, Xkey_count); float modY = GetHermiteCurveValue(timer, keysY, Ykey_count); //float modS = GetHermiteCurveValue(timer, keysS, Skey_count); float modS = 3.0f - (timer * (2.0f / 60.0f)); pos = (Vec){ modX, modY, pos.z }; //OSReport("Item scale according to Hermite Keys: %f from frame %d\n", modS, timer); scale = (Vec){ modS, modS, modS }; if (timer == 60) { doStateChange(&StateID_Wait); } timer += 1; } void dSongPrize::endState_Shrink() {} void dSongPrize::beginState_Spin() { this->timer = 0; Xkey_count = 2; keysX[0] = (HermiteKey){ 0.0, 0.0, 0.0 }; keysX[1] = (HermiteKey){ 20.0, 65535.0, 0.0 }; } void dSongPrize::executeState_Spin() { float modX = GetHermiteCurveValue(timer, keysX, Xkey_count); rot.y = (int)modX; if (timer == 20) { SpawnEffect("Wm_ob_flagget", 0, &(Vec){pos.x-10.0, pos.y-2.0, pos.z-100.0}, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); } if (timer == 30) { doStateChange(&StateID_Wait); } timer += 1; } void dSongPrize::endState_Spin() {} class dSongBlock : public daEnBlockMain_c { public: Physics::Info physicsInfo; int onCreate(); int onDelete(); int onExecute(); int beforeDraw(); int onDraw(); mHeapAllocator_c allocator; nw4r::g3d::ResFile resFile; m3d::mdl_c bodyModel; m3d::mdl_c glowModel; m3d::mdl_c deadModel; m3d::mdl_c deadglowModel; StageActorLight light; mHeapAllocator_c allocatorB; int note; int isGlowing; int glowTimer; int isDead; int standAlone; int item; void calledWhenUpMoveExecutes(); void calledWhenDownMoveExecutes(); void blockWasHit(bool isDown); void glow(); void unglow(); USING_STATES(dSongBlock); DECLARE_STATE(Wait); static dSongBlock *build(); }; /*****************************************************************************/ // Sing Along class dSingAlong : public dStageActor_c { public: static dSingAlong *instance; static dSingAlong *build(); void RegisterNote(int note); void addPowerups(); int onCreate(); int onDelete(); int onExecute(); int onDraw(); //int beforeExecute() { return true; } int afterExecute(int) { return true; } dSingAlong() : state(this, &StateID_Intro) { } mHeapAllocator_c allocator; dSongPrize *PrizeModel; dSongPrize *Pa; dSongPrize *Pb; dSongPrize *Pc; dSongPrize *Pd; dSongBlock *SBa; dSongBlock *SBb; dSongBlock *SBc; dSongBlock *SBd; dSongBlock *SBe; dSongBlock *SBf; dSongBlock *SBg; int song; int prize[4]; int chorus; int currentNote; int endNote; int timer; int counter; int Powerups[10]; int isResponding; dStateWrapper_c state; // Intro, Call, Response, Display Prize, Failure, Win, Collect Prizes USING_STATES(dSingAlong); DECLARE_STATE(Intro); DECLARE_STATE(Call); DECLARE_STATE(Response); DECLARE_STATE(Prize); DECLARE_STATE(Failure); DECLARE_STATE(Win); }; dSingAlong *dSingAlong::instance = 0; dSingAlong *dSingAlong::build() { OSReport("Building Sing Along."); void *buffer = AllocFromGameHeap1(sizeof(dSingAlong)); dSingAlong *c = new(buffer) dSingAlong; instance = c; return c; } /*****************************************************************************/ // Events int dSingAlong::onCreate() { NoMichaelBuble = true; OSReport("Creating the Sing Along gang."); // Load in the settings this->song = this->settings & 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; this->Powerups[0] = 0; // Mushroom this->Powerups[1] = 0; // Fireflower this->Powerups[2] = 0; // Iceflower this->Powerups[3] = 0; // Penguin this->Powerups[4] = 0; // Propeller this->Powerups[5] = 0; // MiniShroom this->Powerups[6] = 0; // Starman this->Powerups[7] = 0; // Hammer this->Powerups[8] = 0; // 1-ups this->Powerups[9] = 0; // Coins // Create and prepare the blocks S16Vec rot = (S16Vec){0,0,0}; float x = pos.x; float y = pos.y - 40.0; float z = pos.z; SBa = (dSongBlock*)create(WM_KILLER, 1, &(Vec){x-96.0+(32.0*0), y, z}, &rot, 0); SBb = (dSongBlock*)create(WM_KILLER, 2, &(Vec){x-96.0+(32.0*1), y, z}, &rot, 0); SBc = (dSongBlock*)create(WM_KILLER, 3, &(Vec){x-96.0+(32.0*2), y, z}, &rot, 0); SBd = (dSongBlock*)create(WM_KILLER, 4, &(Vec){x-96.0+(32.0*3), y, z}, &rot, 0); SBe = (dSongBlock*)create(WM_KILLER, 5, &(Vec){x-96.0+(32.0*4), y, z}, &rot, 0); SBf = (dSongBlock*)create(WM_KILLER, 6, &(Vec){x-96.0+(32.0*5), y, z}, &rot, 0); SBg = (dSongBlock*)create(WM_KILLER, 7, &(Vec){x-96.0+(32.0*6), y, z}, &rot, 0); // // Trigger the intro state state.setState(&StateID_Intro); isResponding = 0; return true; } int dSingAlong::onExecute() { state.execute(); return true; } int dSingAlong::onDraw() { return true; } int dSingAlong::onDelete() { OSReport("Sing Along Instance Remove"); instance = 0; OSReport("Sing Along Delete"); return 1; } /*****************************************************************************/ // Register a Note being played by the players void dSingAlong::RegisterNote(int note) { OSReport("Register Note begins: %d", note); OSReport("Responding is: %d", isResponding); if (isResponding == 1) { OSReport("State was checked"); if (note == Songs[song][chorus][currentNote][0]) { MapSoundPlayer(SoundRelatedClass, Notes[Songs[song][chorus][currentNote][1]-1], 1); OSReport("Note was correct"); currentNote += 1; } else { OSReport("Player failed"); nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_MG_CMN_WIN_CLOSE, 1); isResponding = 0; state.setState(&StateID_Failure); } } } /*****************************************************************************/ // Intro CREATE_STATE(dSingAlong, Intro); void dSingAlong::beginState_Intro() {} void dSingAlong::endState_Intro() {} void dSingAlong::executeState_Intro() { MakeMarioEnterDemoMode(); state.setState(&StateID_Prize); } //*****************************************************************************/ // Prize CREATE_STATE(dSingAlong, Prize); void dSingAlong::beginState_Prize() { this->timer = 120; } void dSingAlong::executeState_Prize() { if ((timer == 120) && (chorus >= 0)) { // Play a nice success sound, and wait a second nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_MG_IH_PAIR_OK, 1); //PlaySound(this, SE_MG_IH_PAIR_OK); // SE_MG_IH_NICE or SE_MG_UH_NICE int p; p = prize[chorus]; this->Powerups[p] += 1; } if ((timer == 60) && (chorus >= 0)) { OSReport("Switching PrizeModel States"); if (chorus == 0) { Pa = PrizeModel; } if (chorus == 1) { Pb = PrizeModel; } if (chorus == 2) { Pc = PrizeModel; } if (chorus == 3) { Pd = PrizeModel; } PrizeModel->doStateChange(&dSongPrize::StateID_Shrink); } if (timer == 0) { chorus += 1; if (chorus == 4) { state.setState(&StateID_Win); return; } SpawnEffect("Wm_en_blockcloud", 0, &(Vec){pos.x, pos.y+32.0, pos.z+500.0}, &(S16Vec){0,0,0}, &(Vec){1.5, 1.5, 1.5}); nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_OBJ_ITEM_APPEAR, 1); //PlaySound(this, SE_OBJ_ITEM_APPEAR); // SE_OBJ_GOOD_ITEM_APPEAR OSReport("Making the prize model"); PrizeModel = (dSongPrize*)create(WM_SINKSHIP, chorus + (prize[chorus] << 16), &pos, &rot, 0); OSReport("Prize Model Made"); } if (timer == -90) { state.setState(&StateID_Call); } timer -= 1; } void dSingAlong::endState_Prize() {} //*****************************************************************************/ // Call CREATE_STATE(dSingAlong, Call); void dSingAlong::beginState_Call() { timer = 0; currentNote = 0; OSReport("SONG: {%d, %d} {%d %d} {%d %d}", Songs[song][chorus][0][0], Songs[song][chorus][0][1], Songs[song][chorus][1][0], Songs[song][chorus][1][1], Songs[song][chorus][2][0], Songs[song][chorus][2][1]); } void dSingAlong::executeState_Call() { // OSReport("%d: Waiting for timer %d", timer, *currentNote[1]); if (timer == (Songs[song][chorus][currentNote][2] * 2)) { OSReport("Playing Note %d", Songs[song][chorus][currentNote][0]); nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, Notes[Songs[song][chorus][currentNote][1]-1], 1); Vec effPos; if (Songs[song][chorus][currentNote][0] == 1) { SBa->glow(); effPos = SBa->pos; } else if (Songs[song][chorus][currentNote][0] == 2) { SBb->glow(); effPos = SBb->pos; } else if (Songs[song][chorus][currentNote][0] == 3) { SBc->glow(); effPos = SBc->pos; } else if (Songs[song][chorus][currentNote][0] == 4) { SBd->glow(); effPos = SBd->pos; } else if (Songs[song][chorus][currentNote][0] == 5) { SBe->glow(); effPos = SBe->pos; } else if (Songs[song][chorus][currentNote][0] == 6) { SBf->glow(); effPos = SBf->pos; } else if (Songs[song][chorus][currentNote][0] == 7) { SBg->glow(); effPos = SBg->pos; } SpawnEffect("Wm_en_vshit_ring", 0, &(Vec){effPos.x, effPos.y+8.0, effPos.z-100.0}, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); currentNote += 1; OSReport("Next Note %d", Songs[song][chorus][currentNote][0]); if (Songs[song][chorus][currentNote][0] == 0) { OSReport("Switching to Response Mode"); state.setState(&StateID_Response); } } timer += 1; } void dSingAlong::endState_Call() { MakeMarioExitDemoMode(); } /*****************************************************************************/ // Response CREATE_STATE(dSingAlong, Response); void dSingAlong::beginState_Response() { timer = 0; currentNote = 0; isResponding = 1; OSReport("Is now responding: %d", isResponding); } void dSingAlong::executeState_Response() { if (Songs[song][chorus][currentNote][0] == 0) { isResponding = 0; OSReport("Switching to some other mode: %d", isResponding); MakeMarioEnterDemoMode(); state.setState(&StateID_Prize); } } void dSingAlong::endState_Response() {} /*****************************************************************************/ // Failure CREATE_STATE(dSingAlong, Failure); void dSingAlong::beginState_Failure() { this->timer = 0; SBa->unglow(); SBb->unglow(); SBc->unglow(); SBd->unglow(); SBe->unglow(); SBf->unglow(); SBg->unglow(); MakeMarioEnterDemoMode(); } void dSingAlong::executeState_Failure() { if (timer == 5 && chorus == 0) for (int i = 0; i < 4; i++) if (dAcPy_c *player = dAcPy_c::findByID(i)) player->setAnimePlayWithAnimID(dm_surprise); // Play a success/failure sound if (timer == 20) { nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, STRM_BGM_MINIGAME_FANFARE_BAD, 1); StopBGMMusic(); } if (timer == 260 && chorus > 0) { nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, STRM_BGM_MINIGAME_FANFARE_GOOD, 1); for (int i = 0; i < 4; i++) if (dAcPy_c *player = dAcPy_c::findByID(i)) { player->setAnimePlayWithAnimID(dm_glad); player->setFlag(0x24); } } // Delete the big powerup with a poof if it's fail if (timer == 30*1) { SpawnEffect("Wm_en_blockcloud", 0, &(Vec){pos.x, pos.y+32.0, pos.z+500.0}, &(S16Vec){0,0,0}, &(Vec){1.5, 1.5, 1.5}); nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_MG_IH_NOPAIR_OK, 1); PrizeModel->Delete(1); if (chorus == 0) timer += 140; } // Make the banked powerups do a little dance/effect // Play a sound for each powerup gained if (timer == 30*9) { if (chorus >= 1) { Pa->doStateChange(&dSongPrize::StateID_Spin); nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_OBJ_ITEM_FROM_KINOPIO, 1); } else { timer += 29; } } if (timer == 30*10) { if (chorus >= 2) { Pb->doStateChange(&dSongPrize::StateID_Spin); nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_OBJ_ITEM_FROM_KINOPIO, 1); } else { timer += 29; } } if (timer == 30*11) { if (chorus >= 3) { Pc->doStateChange(&dSongPrize::StateID_Spin); nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_OBJ_ITEM_FROM_KINOPIO, 1); } else { timer += 29; } } // If victory, make mario do a little dance/sound if (timer == 30*13) { nw4r::snd::SoundHandle handle1, handle2, handle3, handle4; if (GetSpecificPlayerActor(0) != 0) PlaySoundWithFunctionB4(SoundRelatedClass, &handle1, (chorus == 0) ? SE_VOC_MA_CS_COURSE_MISS : SE_VOC_MA_CLEAR_MULTI, 1); if (GetSpecificPlayerActor(1) != 0) PlaySoundWithFunctionB4(SoundRelatedClass, &handle2, (chorus == 0) ? SE_VOC_LU_CS_COURSE_MISS : SE_VOC_LU_CLEAR_MULTI, 1); if (GetSpecificPlayerActor(2) != 0) PlaySoundWithFunctionB4(SoundRelatedClass, &handle3, (chorus == 0) ? SE_VOC_KO_CS_COURSE_MISS : SE_VOC_KO_CLEAR_MULTI, 1); if (GetSpecificPlayerActor(3) != 0) PlaySoundWithFunctionB4(SoundRelatedClass, &handle4, (chorus == 0) ? SE_VOC_KO2_CS_COURSE_MISS : SE_VOC_KO2_CLEAR_MULTI, 1); } // Add the powerups and exit the stage if (timer == 30*15) { this->addPowerups(); ExitStage(WORLD_MAP, 0, BEAT_LEVEL, MARIO_WIPE); } timer += 1; } void dSingAlong::endState_Failure() {} /*****************************************************************************/ // Win CREATE_STATE(dSingAlong, Win); void dSingAlong::beginState_Win() { this->timer = 0; MakeMarioEnterDemoMode(); } void dSingAlong::executeState_Win() { if (timer == 5) for (int i = 0; i < 4; i++) if (dAcPy_c *player = dAcPy_c::findByID(i)) { player->setAnimePlayWithAnimID(dm_glad); player->setFlag(0x24); } // Play a success/failure sound if (timer == 30) { nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, STRM_BGM_MINIGAME_FANFARE_GOOD, 1); StopBGMMusic(); } // Make the banked powerups do a little dance/effect // Play a sound for each powerup gained if (timer == 30*3 || timer == 30*4 || timer == 30*5 || timer == 30*6) { dSongPrize *bullshit = 0; if (timer == 30*3) bullshit = Pa; else if (timer == 30*4) bullshit = Pb; else if (timer == 30*5) bullshit = Pc; else if (timer == 30*6) bullshit = Pd; bullshit->doStateChange(&dSongPrize::StateID_Spin); nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_OBJ_ITEM_FROM_KINOPIO, 1); } // If victory, make mario do a little dance/sound if (timer == 30*8) { nw4r::snd::SoundHandle handle1, handle2, handle3, handle4; if (GetSpecificPlayerActor(0) != 0) PlaySoundWithFunctionB4(SoundRelatedClass, &handle1, SE_VOC_MA_CLEAR_MULTI, 1); if (GetSpecificPlayerActor(1) != 0) PlaySoundWithFunctionB4(SoundRelatedClass, &handle2, SE_VOC_LU_CLEAR_MULTI, 1); if (GetSpecificPlayerActor(2) != 0) PlaySoundWithFunctionB4(SoundRelatedClass, &handle3, SE_VOC_KO_CLEAR_MULTI, 1); if (GetSpecificPlayerActor(3) != 0) PlaySoundWithFunctionB4(SoundRelatedClass, &handle4, SE_VOC_KO2_CLEAR_MULTI, 1); SpawnEffect("Wm_ob_fireworks_y", 0, &(Vec){pos.x-80.0, pos.y+20.0, pos.z+500.0}, &(S16Vec){0,0,0}, &(Vec){0.75, 0.75, 0.75}); } if (timer == (int)30*8.5) { SpawnEffect("Wm_ob_fireworks_b", 0, &(Vec){pos.x+108.0, pos.y+32.0, pos.z+500.0}, &(S16Vec){0,0,0}, &(Vec){0.75, 0.75, 0.75}); } if (timer == 30*9) { SpawnEffect("Wm_ob_fireworks_g", 0, &(Vec){pos.x, pos.y+50.0, pos.z+500.0}, &(S16Vec){0,0,0}, &(Vec){0.75, 0.75, 0.75}); } // Add the powerups and exit the stage if (timer == 30*11) { this->addPowerups(); ExitStage(WORLD_MAP, 0, BEAT_LEVEL, MARIO_WIPE); } timer += 1; } void dSingAlong::endState_Win() {} /*****************************************************************************/ // Add Powerups at the End of the Stage void dSingAlong::addPowerups() { SaveFile *file = GetSaveFile(); SaveBlock *block = file->GetBlock(file->header.current_file); for (int i = 0; i < 7; i++) { // Change this to 8 to support hammers block->powerups_available[i] = block->powerups_available[i] + this->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] = (this->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] = this->Powerups[8] + block->player_lives[i]; if (block->player_lives[i] > 99) { block->player_lives[i] = 99; } } return; } /*****************************************************************************/ /*****************************************************************************/ /*****************************************************************************/ // Replaces: Nothing yet CREATE_STATE(dSongBlock, Wait); dSongBlock *dSongBlock::build() { void *buffer = AllocFromGameHeap1(sizeof(dSongBlock)); return new(buffer) dSongBlock; } int dSongBlock::onCreate() { // Settings this->note = this->settings & 0xF; this->standAlone = (this->settings >> 4) & 0xF; this->item = (this->settings >> 16) & 0xFF; // Model creation allocator.link(-1, GameHeaps[0], 0, 0x20); char modelName [24]; sprintf(modelName, "g3d/block_light_%d.brres", this->note); this->resFile.data = getResource("block_light", modelName); nw4r::g3d::ResMdl mdl = this->resFile.GetResMdl("block_light"); bodyModel.setup(mdl, &allocator, 0x224, 1, 0); SetupTextures_MapObj(&bodyModel, 0); // 800B42B0 char glowName [25]; sprintf(glowName, "g3d/block_light_g%d.brres", this->note); this->resFile.data = getResource("block_light", glowName); mdl = this->resFile.GetResMdl("block_light"); glowModel.setup(mdl, &allocator, 0x224, 1, 0); SetupTextures_MapObj(&glowModel, 0); // 800B42B0 // Dead Models this->resFile.data = getResource("block_light", "g3d/block_light_8.brres"); mdl = this->resFile.GetResMdl("block_light"); deadModel.setup(mdl, &allocator, 0x224, 1, 0); SetupTextures_MapObj(&deadModel, 0); // 800B42B0 this->resFile.data = getResource("block_light", "g3d/block_light_g8.brres"); mdl = this->resFile.GetResMdl("block_light"); deadglowModel.setup(mdl, &allocator, 0x224, 1, 0); SetupTextures_MapObj(&deadglowModel, 0); // 800B42B0 allocator.unlink(); // Glow related isGlowing = 0; glowTimer = 0; isDead = 0; light.init(&allocatorB, 2); // Block Physics 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(); // Change State doStateChange(&dSongBlock::StateID_Wait); return true; } int dSongBlock::onDelete() { physics.removeFromList(); return true; } int dSongBlock::onExecute() { acState.execute(); physics.update(); blockUpdate(); if (glowTimer > 0) { glowTimer--; } else { isGlowing = 0; } light.pos.x = pos.x; light.pos.y = pos.y+8.0; light.pos.z = pos.z; light.size = 226.0; light.update(); // now check zone bounds based on state if (acState.getCurrentState()->isEqual(&StateID_Wait)) { checkZoneBoundaries(0); } return true; } int dSongBlock::beforeDraw() { light.draw(); return dStageActor_c::beforeDraw(); } int dSongBlock::onDraw() { matrix.translation(pos.x, pos.y+8.0, pos.z); matrix.applyRotationYXZ(&rot.x, &rot.y, &rot.z); if (isDead == 0) { if (isGlowing == 0) { bodyModel.setDrawMatrix(matrix); bodyModel.setScale(&scale); bodyModel.calcWorld(false); bodyModel.scheduleForDrawing(); } else { glowModel.setDrawMatrix(matrix); glowModel.setScale(&scale); glowModel.calcWorld(false); glowModel.scheduleForDrawing(); } } else { if (isGlowing == 0) { deadModel.setDrawMatrix(matrix); deadModel.setScale(&scale); deadModel.calcWorld(false); deadModel.scheduleForDrawing(); } else { deadglowModel.setDrawMatrix(matrix); deadglowModel.setScale(&scale); deadglowModel.calcWorld(false); deadglowModel.scheduleForDrawing(); } } return true; } void dSongBlock::blockWasHit(bool isDown) { pos.y = initialY; SpawnEffect("Wm_en_vshit_ring", 0, &(Vec){pos.x, pos.y+8.0, pos.z-100.0}, &(S16Vec){0,0,0}, &(Vec){1.0, 1.0, 1.0}); SpawnEffect("Wm_ob_keyget02_lighit", 0, &(Vec){pos.x, pos.y+8.0, pos.z-100.0}, &(S16Vec){0,0,0}, &(Vec){0.5, 0.5, 0.5}); if (item > 0) { create(EN_ITEM, item, &(Vec){pos.x, pos.y, pos.z}, &rot, 0); } if (standAlone) { int play; // C, C#, D, D#, E, F, F#, G, G#, A, A#, B if (note == 0) { play = 12; } else if (note == 1) { play = 12; } else if (note == 2) { play = 14; } else if (note == 3) { play = 16; } else if (note == 4) { play = 17; } else if (note == 5) { play = 19; } else if (note == 6) { play = 21; } else if (note == 7) { play = 23; } else if (note == 8) { play = 0; } nw4r::snd::SoundHandle handle; PlaySoundWithFunctionB4(SoundRelatedClass, &handle, Notes[play], 1); } else { dSingAlong::instance->RegisterNote(this->note); } physics.setup(this, &physicsInfo, 3, currentLayerID); physics.addToList(); doStateChange(&StateID_Wait); } void dSongBlock::calledWhenUpMoveExecutes() { if (initialY >= pos.y) blockWasHit(false); } void dSongBlock::calledWhenDownMoveExecutes() { if (initialY <= pos.y) blockWasHit(true); } void dSongBlock::glow() { isGlowing = 1; glowTimer = 15; } void dSongBlock::unglow() { isDead = 1; SpawnEffect("Wm_en_sanbohit_smk", 0, &(Vec){pos.x, pos.y+8.0, pos.z-100.0}, &(S16Vec){0,0,0}, &(Vec){0.4, 0.4, 0.4}); } void dSongBlock::beginState_Wait() {} void dSongBlock::endState_Wait() {} void dSongBlock::executeState_Wait() { int result = blockResult(); if (result == 0) return; if (result == 1) { glow(); doStateChange(&daEnBlockMain_c::StateID_UpMove); anotherFlag = 2; isGroundPound = false; } else { glow(); doStateChange(&daEnBlockMain_c::StateID_DownMove); anotherFlag = 1; isGroundPound = true; } }