diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/chestnut.cpp | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/src/chestnut.cpp b/src/chestnut.cpp new file mode 100644 index 0000000..def7041 --- /dev/null +++ b/src/chestnut.cpp @@ -0,0 +1,325 @@ +#include <game.h> +#include <sfx.h> +const char *ChestnutFileList[] = {"chestnut", 0}; + +class daEnChestnut_c : public dEn_c { + public: + static daEnChestnut_c *build(); + + mHeapAllocator_c allocator; + nw4r::g3d::ResFile resFile; + m3d::mdl_c model; + m3d::anmChr_c animation; + + void playAnimation(const char *name, bool loop = false); + void playLoopedAnimation(const char *name) { + playAnimation(name, true); + } + + int objNumber; + int starCoinNumber; + bool ignorePlayers; + bool breaksBlocks; + + int timeSpentExploding; + + float nearestPlayerDistance(); + + int onCreate(); + int onDelete(); + int onExecute(); + int onDraw(); + + void spawnObject(); + + bool collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther); + + bool CreateIceActors(); + + u32 canBePowed(); + void powBlockActivated(bool isMPGP); + + USING_STATES(daEnChestnut_c); + DECLARE_STATE(Idle); + DECLARE_STATE(Shake); + DECLARE_STATE(Fall); + DECLARE_STATE(Explode); +}; + +CREATE_STATE(daEnChestnut_c, Idle); +CREATE_STATE(daEnChestnut_c, Shake); +CREATE_STATE(daEnChestnut_c, Fall); +CREATE_STATE(daEnChestnut_c, Explode); + +daEnChestnut_c *daEnChestnut_c::build() { + void *buf = AllocFromGameHeap1(sizeof(daEnChestnut_c)); + return new(buf) daEnChestnut_c; +} + + +int daEnChestnut_c::onCreate() { + // Get settings + int texNum = settings & 0xF; + int rawScale = (settings & 0xF0) >> 4; + starCoinNumber = (settings & 0xF00) >> 8; + ignorePlayers = ((settings & 0x1000) != 0); + breaksBlocks = ((settings & 0x2000) != 0); + objNumber = (settings & 0xF0000) >> 16; + + // Set up models + allocator.link(-1, GameHeaps[0], 0, 0x20); + + char rfName[64]; + sprintf(rfName, "g3d/t%02d.brres", texNum); + + resFile.data = getResource("chestnut", rfName); + + nw4r::g3d::ResMdl resMdl = resFile.GetResMdl("kuribo_iga"); + nw4r::g3d::ResAnmChr resAnm = resFile.GetResAnmChr("wait"); + + model.setup(resMdl, &allocator, 0x224, 1, 0); + SetupTextures_Enemy(&model, 0); + + animation.setup(resMdl, resAnm, &allocator, 0); + + allocator.unlink(); + + + // Scale us + scale.x = scale.y = scale.z = (1.0f + (float(rawScale) * 0.5f)); + + // Physics and crap + ActivePhysics::Info ccInfo; + ccInfo.xDistToCenter = 0.0f; + ccInfo.xDistToEdge = 12.0f * scale.x; + ccInfo.yDistToCenter = 12.0f * scale.y; + ccInfo.yDistToEdge = 12.0f * scale.y; + + ccInfo.category1 = 3; + ccInfo.category2 = 0; + ccInfo.bitfield1 = 0x6F; + ccInfo.bitfield2 = 0xFFBAFFFE; + + ccInfo.unkShort1C = 0; + ccInfo.callback = &dEn_c::collisionCallback; + + aPhysics.initWithStruct(this, &ccInfo); + aPhysics.addToList(); + + // WE'RE READY + doStateChange(&StateID_Idle); + + return true; +} + +void daEnChestnut_c::playAnimation(const char *name, bool loop) { + animation.bind(&model, resFile.GetResAnmChr(name), !loop); + model.bindAnim(&animation, 0.0f); + animation.setUpdateRate(1.0f); +} + +int daEnChestnut_c::onDelete() { + aPhysics.removeFromList(); + return true; +} + +int daEnChestnut_c::onExecute() { + acState.execute(); + + matrix.translation(pos.x, pos.y, pos.z); + + model.setDrawMatrix(matrix); + model.setScale(&scale); + model.calcWorld(false); + + model._vf1C(); + + return true; +} + +int daEnChestnut_c::onDraw() { + model.scheduleForDrawing(); + + return true; +} + +float daEnChestnut_c::nearestPlayerDistance() { + float bestSoFar = 10000.0f; + + for (int i = 0; i < 4; i++) { + if (dAcPy_c *player = dAcPy_c::findByID(i)) { + float thisDist = abs(player->pos.x - pos.x); + if (thisDist < bestSoFar) + bestSoFar = thisDist; + } + } + + return bestSoFar; +} + + + +void daEnChestnut_c::beginState_Idle() { + playLoopedAnimation("wait"); +} +void daEnChestnut_c::endState_Idle() { } + + +void daEnChestnut_c::executeState_Idle() { + if (ignorePlayers) + return; + + float dist = nearestPlayerDistance(); + + if (dist < 32.0f) + doStateChange(&StateID_Fall); + else if (dist < 64.0f) + doStateChange(&StateID_Shake); +} + + + +void daEnChestnut_c::beginState_Shake() { + playLoopedAnimation("shake"); + animation.setUpdateRate(2.0f); + + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_PLY_CLIMB_KUSARI, 1); +} +void daEnChestnut_c::endState_Shake() { } + +void daEnChestnut_c::executeState_Shake() { + float dist = nearestPlayerDistance(); + + if (dist >= 64.0f) + doStateChange(&StateID_Idle); + else if (dist < 32.0f) + doStateChange(&StateID_Fall); +} + + + +void daEnChestnut_c::beginState_Fall() { + animation.setUpdateRate(0.0f); // stop animation + + int size = 12*scale.x; + + u32 sFlags = 0; + if (breaksBlocks) + sFlags = SENSOR_BREAK_BLOCK | SENSOR_BREAK_BRICK; + + static const lineSensor_s below(sFlags, -size << 12, size << 12, 0 << 12); + collMgr.init(this, &below, 0, 0); + + speed.y = 0.0f; + y_speed_inc = -0.1875f; + max_speed.y = -4.0f; + + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_DEMO_OP_PRESENT_THROW_2308f, 1); +} + +void daEnChestnut_c::endState_Fall() { } + +void daEnChestnut_c::executeState_Fall() { + HandleYSpeed(); + doSpriteMovement(); + UpdateObjectPosBasedOnSpeedValuesReal(); + + if (collMgr.calculateBelowCollision()) { + doStateChange(&StateID_Explode); + } +} + + + +void daEnChestnut_c::beginState_Explode() { + OSReport("Entering Explode\n"); + playAnimation("break"); + animation.setUpdateRate(2.0f); + + nw4r::snd::SoundHandle handle; + PlaySoundWithFunctionB4(SoundRelatedClass, &handle, SE_DEMO_OP_LAND_JR_0983f, 1); + + timeSpentExploding = 0; +} +void daEnChestnut_c::endState_Explode() { } + +void daEnChestnut_c::executeState_Explode() { + timeSpentExploding++; + + if (timeSpentExploding == 10) { + S16Vec efRot = {0,0,0}; + SpawnEffect("Wm_en_burst_ss", 0, &pos, &efRot, &scale); + spawnObject(); + } + + if (animation.isAnimationDone()) { + Delete(1); + } +} + + + +bool daEnChestnut_c::CreateIceActors() { + animation.setUpdateRate(0.0f); + + IceActorSpawnInfo info; + info.flags = 0; + info.pos = pos; + info.pos.y -= (6.0f * info.scale.y); + info.scale.x = info.scale.y = info.scale.z = scale.x * 1.35f; + for (int i = 0; i < 8; i++) + info.what[0] = 0.0f; + + return frzMgr.Create_ICEACTORs(&info, 1); +} + +u32 daEnChestnut_c::canBePowed() { + return true; +} +void daEnChestnut_c::powBlockActivated(bool isMPGP) { + if (isMPGP) + return; + + dStateBase_c *state = acState.getCurrentState(); + if (state == &StateID_Idle || state == &StateID_Shake) + doStateChange(&StateID_Fall); +} + +bool daEnChestnut_c::collisionCat1_Fireball_E_Explosion(ActivePhysics *apThis, ActivePhysics *apOther) { + SpawnEffect("Wm_en_igafirehit", 0, &pos, &rot, &scale); + + if (acState.getCurrentState() != &StateID_Explode) + doStateChange(&StateID_Explode); + + return true; +} + + + +void daEnChestnut_c::spawnObject() { + VEC3 acPos = pos; + + static const u32 things[] = { + EN_KURIBO, 0, + EN_TOGEZO, 0, + EN_COIN_JUMP, 0, + EN_ITEM, 0x05000009, + EN_STAR_COIN, 0x10000000, + }; + + u32 acSettings = things[objNumber*2+1]; + + if (objNumber == 4) { + acSettings |= (starCoinNumber << 8); + acPos.x -= 12.0f; + acPos.y += 32.0f; + } + + OSReport("Crap %d, %d, %08x\n", objNumber, things[objNumber*2], acSettings); + dStageActor_c::create((Actors)things[objNumber*2], acSettings, &acPos, 0, currentLayerID); + + S16Vec efRot = {0,0,0}; + SpawnEffect("Wm_ob_itemsndlandsmk", 0, &pos, &efRot, &scale); +} |