From 1eb84f57c5f9035349b7df8f31dc5cb03795df7d Mon Sep 17 00:00:00 2001 From: toasterbabe Date: Thu, 26 Apr 2018 20:18:51 +0100 Subject: [PATCH] * Billiards mines! With support for both above and below water, replacing both the below-and-above-water old mines at once. * Explosion executors. * Minor refactor of P_KillMobj. --- src/dehacked.c | 30 +++--- src/hardware/hw_light.c | 1 + src/info.c | 125 ++++++++++++------------ src/info.h | 31 +++--- src/p_enemy.c | 89 ++++++++++++++++- src/p_inter.c | 207 +++++++++++++++------------------------- src/p_map.c | 25 +++++ src/p_mobj.c | 40 ++------ src/sounds.c | 2 +- 9 files changed, 291 insertions(+), 259 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 83e3177ff..e5bafabad 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -1811,6 +1811,8 @@ static actionpointer_t actionpointers[] = {{A_FadeOverlay}, "A_FADEOVERLAY"}, {{A_Boss5Jump}, "A_BOSS5JUMP"}, {{A_LightBeamReset}, "A_LIGHTBEAMRESET"}, + {{A_MineExplode}, "A_MINEEXPLODE"}, + {{A_MineRange}, "A_MINERANGE"}, {{NULL}, "NONE"}, @@ -4504,14 +4506,18 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_STARPOST_ENDSPIN", // Big floating mine - "S_BIGMINE1", - "S_BIGMINE2", - "S_BIGMINE3", - "S_BIGMINE4", - "S_BIGMINE5", - "S_BIGMINE6", - "S_BIGMINE7", - "S_BIGMINE8", + "S_BIGMINE_IDLE", + "S_BIGMINE_ALERT1", + "S_BIGMINE_ALERT2", + "S_BIGMINE_ALERT3", + "S_BIGMINE_SET1", + "S_BIGMINE_SET2", + "S_BIGMINE_SET3", + "S_BIGMINE_BLAST1", + "S_BIGMINE_BLAST2", + "S_BIGMINE_BLAST3", + "S_BIGMINE_BLAST4", + "S_BIGMINE_BLAST5", // Cannon Launcher "S_CANNONLAUNCHER1", @@ -4780,12 +4786,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_LIGHTBEAM10", "S_LIGHTBEAM11", "S_LIGHTBEAM12", - "S_LIGHTBEAM13", - "S_LIGHTBEAM14", - "S_LIGHTBEAM15", - "S_LIGHTBEAM16", - "S_LIGHTBEAM17", - "S_LIGHTBEAM18", // CEZ Chain "S_CEZCHAIN", @@ -6111,7 +6111,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_WALLSPIKEBASE", "MT_STARPOST", "MT_BIGMINE", - "MT_BIGAIRMINE", + "MT_BLASTEXECUTOR", "MT_CANNONLAUNCHER", // Monitor miscellany diff --git a/src/hardware/hw_light.c b/src/hardware/hw_light.c index 267666749..0496e6423 100644 --- a/src/hardware/hw_light.c +++ b/src/hardware/hw_light.c @@ -246,6 +246,7 @@ light_t *t_lspr[NUMSPRITES] = &lspr[NOLIGHT], // SPR_WSPB &lspr[NOLIGHT], // SPR_STPT &lspr[NOLIGHT], // SPR_BMNE + &lspr[REDBALL_L], // SPR_BMNB // Monitor Boxes &lspr[NOLIGHT], // SPR_MSTV diff --git a/src/info.c b/src/info.c index 9fe41090a..1805c555b 100644 --- a/src/info.c +++ b/src/info.c @@ -134,6 +134,7 @@ char sprnames[NUMSPRITES + 1][5] = "WSPB", // Wall spike base "STPT", // Starpost "BMNE", // Big floating mine + "BMNB", // Monitor Boxes "MSTV", // MiSc TV sprites @@ -1717,14 +1718,18 @@ state_t states[NUMSTATES] = {SPR_STPT, FF_ANIMATE|15, 2, {NULL}, 1, 1, S_STARPOST_FLASH}, // S_STARPOST_ENDSPIN // Big floating mine - {SPR_BMNE, 0, 5, {NULL}, 0, 0, S_BIGMINE2}, // S_BIGMINE1 - {SPR_BMNE, 1, 5, {NULL}, 0, 0, S_BIGMINE3}, // S_BIGMINE2 - {SPR_BMNE, 2, 5, {NULL}, 0, 0, S_BIGMINE4}, // S_BIGMINE3 - {SPR_BMNE, 3, 5, {NULL}, 0, 0, S_BIGMINE5}, // S_BIGMINE4 - {SPR_BMNE, 4, 5, {NULL}, 0, 0, S_BIGMINE6}, // S_BIGMINE5 - {SPR_BMNE, 5, 5, {NULL}, 0, 0, S_BIGMINE7}, // S_BIGMINE6 - {SPR_BMNE, 6, 5, {NULL}, 0, 0, S_BIGMINE8}, // S_BIGMINE7 - {SPR_BMNE, 7, 5, {NULL}, 0, 0, S_BIGMINE1}, // S_BIGMINE8 + {SPR_BMNE, 0, 2, {A_Look}, ((224<z++; // Horizontal axes first. First parameter is initial horizontal impulse, second is to correct its angle. - actor->momx = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINECOSINE(actor->angle >> ANGLETOFINESHIFT)); - actor->momy = FixedMul(FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)), FINESINE(actor->angle >> ANGLETOFINESHIFT)); + fixedHypotenuse = FixedMul(v, FINECOSINE(theta >> ANGLETOFINESHIFT)); // variable reuse + actor->momx = FixedMul(fixedHypotenuse, FINECOSINE(actor->angle >> ANGLETOFINESHIFT)); + actor->momy = FixedMul(fixedHypotenuse, FINESINE(actor->angle >> ANGLETOFINESHIFT)); // Then the vertical axis. No angle-correction needed here. actor->momz = FixedMul(v, FINESINE(theta >> ANGLETOFINESHIFT)); // I hope that's all that's needed, ugh @@ -10630,6 +10633,9 @@ void A_Boss5Jump(mobj_t *actor) // void A_LightBeamReset(mobj_t *actor) { + // INT32 locvar1 = var1; + // INT32 locvar2 = var2; + #ifdef HAVE_BLUA if (LUA_CallAction("A_LightBeamReset", actor)) return; @@ -10651,3 +10657,82 @@ void A_LightBeamReset(mobj_t *actor) actor->z = actor->spawnpoint->z*FRACUNIT + P_SignedRandom()*FRACUNIT/2; P_SetThingPosition(actor); } + +// Function: A_MineExplode +// Description: Handles the explosion of a DSZ mine. +// +// var1 = unused +// var2 = unused +// +void A_MineExplode(mobj_t *actor) +{ + // INT32 locvar1 = var1; + // INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MineExplode", actor)) + return; +#endif + + A_Scream(actor); + actor->flags = MF_NOGRAVITY|MF_NOCLIP; + + quake.epicenter = NULL; + quake.radius = 512*FRACUNIT; + quake.intensity = 8*FRACUNIT; + quake.time = TICRATE/3; + + P_RadiusAttack(actor, actor->tracer, 192*FRACUNIT); + P_MobjCheckWater(actor); + + { +#define dist 64 + UINT8 i; + mobjtype_t type = ((actor->eflags & MFE_UNDERWATER) ? MT_UWEXPLODE : MT_BOSSEXPLODE); + S_StartSound(actor, ((actor->eflags & MFE_UNDERWATER) ? sfx_s3k57 : sfx_s3k4e)); + P_SpawnMobj(actor->x, actor->y, actor->z, type); + for (i = 0; i < 16; i++) + { + mobj_t *b = P_SpawnMobj(actor->x+P_RandomRange(-dist, dist)*FRACUNIT, + actor->y+P_RandomRange(-dist, dist)*FRACUNIT, + actor->z+P_RandomRange(((actor->eflags & MFE_UNDERWATER) ? -dist : 0), dist)*FRACUNIT, + type); + fixed_t dx = b->x - actor->x, dy = b->y - actor->y, dz = b->z - actor->z; + fixed_t dm = P_AproxDistance(dz, P_AproxDistance(dy, dx)); + b->momx = FixedDiv(dx, dm)*3; + b->momy = FixedDiv(dy, dm)*3; + b->momz = FixedDiv(dz, dm)*3; + if ((actor->watertop == INT32_MAX) || (b->z + b->height > actor->watertop)) + b->flags &= ~MF_NOGRAVITY; + } +#undef dist + + if (actor->watertop != INT32_MAX) + P_SpawnMobj(actor->x, actor->y, actor->watertop, MT_SPLISH); + } +} + +// Function: A_MineRange +// Description: If the target gets too close, change the state to meleestate. +// +// var1 = Distance to alert at +// var2 = unused +// +void A_MineRange(mobj_t *actor) +{ + fixed_t dm; + INT32 locvar1 = var1; + // INT32 locvar2 = var2; + +#ifdef HAVE_BLUA + if (LUA_CallAction("A_MineRange", actor)) + return; +#endif + + if (!actor->target) + return; + + dm = P_AproxDistance(actor->z - actor->target->z, P_AproxDistance(actor->y - actor->target->y, actor->x - actor->target->x)); + if ((dm>>FRACBITS) < locvar1) + P_SetMobjState(actor, actor->info->meleestate); +} diff --git a/src/p_inter.c b/src/p_inter.c index 7892e0bcf..5de8b7fd3 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -412,7 +412,22 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) //////////////////////////////////////////////////////// /////ENEMIES!!////////////////////////////////////////// //////////////////////////////////////////////////////// - if (special->type == MT_GSNAPPER && !(((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) + if (special->type == MT_BIGMINE) + { + special->momx = toucher->momx/3; + special->momy = toucher->momy/3; + special->momz = toucher->momz/3; + toucher->momx /= -8; + toucher->momy /= -8; + toucher->momz /= -8; + special->flags &= ~MF_SPECIAL; + if (special->info->activesound) + S_StartSound(special, special->info->activesound); + P_SetTarget(&special->tracer, toucher); + player->homing = 0; + return; + } + else if (special->type == MT_GSNAPPER && !(((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING)) || player->powers[pw_invulnerability] || player->powers[pw_super] || elementalpierce) && toucher->z < special->z + special->height && toucher->z + toucher->height > special->z && !(player->powers[pw_shield] & SH_PROTECTSPIKE)) @@ -1529,14 +1544,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) // Can't jump first frame player->pflags |= PF_JUMPSTASIS; - return; - case MT_BIGMINE: - case MT_BIGAIRMINE: - // Spawn explosion! - P_SpawnMobj(special->x, special->y, special->z, special->info->mass); - P_RadiusAttack(special, special, special->info->damage); - S_StartSound(special, special->info->deathsound); - P_SetMobjState(special, special->info->deathstate); return; case MT_SPECIALSPIKEBALL: if (!useNightsSS && G_IsSpecialStage(gamemap)) // Only for old special stages @@ -2349,78 +2356,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (source && target && target->player && source->player) P_PlayVictorySound(source); // Killer laughs at you. LAUGHS! BWAHAHAHA! -#ifdef OLDANIMALSPAWNING - // Drop stuff. - // This determines the kind of object spawned - // during the death frame of a thing. - if (!mariomode // Don't show birds, etc. in Mario Mode Tails 12-23-2001 - && target->flags & MF_ENEMY) - { - mobjtype_t item; - INT32 prandom; - - switch (target->type) - { - case MT_REDCRAWLA: - case MT_GOLDBUZZ: - case MT_SKIM: - case MT_UNIDUS: - item = MT_FLICKY_02/*MT_BUNNY*/; - break; - - case MT_BLUECRAWLA: - case MT_JETTBOMBER: - case MT_GFZFISH: - item = MT_FLICKY_01/*MT_BIRD*/; - break; - - case MT_JETTGUNNER: - case MT_CRAWLACOMMANDER: - case MT_REDBUZZ: - case MT_DETON: - item = MT_FLICKY_12/*MT_MOUSE*/; - break; - - case MT_GSNAPPER: - case MT_EGGGUARD: - case MT_SPRINGSHELL: - item = MT_FLICKY_11/*MT_COW*/; - break; - - case MT_MINUS: - case MT_VULTURE: - case MT_POINTY: - case MT_YELLOWSHELL: - item = MT_FLICKY_03/*MT_CHICKEN*/; - break; - - case MT_AQUABUZZ: - item = MT_FLICKY_01/*MT_REDBIRD*/; - break; - - default: - if (target->info->doomednum) - prandom = target->info->doomednum%5; // "Random" animal for new enemies. - else - prandom = P_RandomKey(5); // No placable object, just use a random number. - - switch(prandom) - { - default: item = MT_FLICKY_02/*MT_BUNNY*/; break; - case 1: item = MT_FLICKY_01/*MT_BIRD*/; break; - case 2: item = MT_FLICKY_12/*MT_MOUSE*/; break; - case 3: item = MT_FLICKY_11/*MT_COW*/; break; - case 4: item = MT_FLICKY_03/*MT_CHICKEN*/; break; - } - break; - } - - mo = P_SpawnMobj(target->x, target->y, target->z + (target->height / 2) - FixedMul(mobjinfo[item].height / 2, target->scale), item); - mo->destscale = target->scale; - P_SetScale(mo, mo->destscale); - } - else -#endif // Other death animation effects switch(target->type) { @@ -2434,6 +2369,64 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget target->fuse = target->info->damage; break; + case MT_AQUABUZZ: + if (inflictor && inflictor->player // did a player kill you? Spawn relative to the player so they're bound to get it + && P_AproxDistance(inflictor->x - target->x, inflictor->y - target->y) <= inflictor->radius + target->radius + FixedMul(8*FRACUNIT, inflictor->scale) // close enough? + && inflictor->z <= target->z + target->height + FixedMul(8*FRACUNIT, inflictor->scale) + && inflictor->z + inflictor->height >= target->z - FixedMul(8*FRACUNIT, inflictor->scale)) + mo = P_SpawnMobj(inflictor->x + inflictor->momx, inflictor->y + inflictor->momy, inflictor->z + (inflictor->height / 2) + inflictor->momz, MT_EXTRALARGEBUBBLE); + else + mo = P_SpawnMobj(target->x, target->y, target->z, MT_EXTRALARGEBUBBLE); + mo->destscale = target->scale; + P_SetScale(mo, mo->destscale); + break; + + case MT_YELLOWSHELL: + P_SpawnMobjFromMobj(target, 0, 0, 0, MT_YELLOWSPRING); + break; + + case MT_EGGMOBILE3: + { + thinker_t *th; + UINT32 i = 0; // to check how many clones we've removed + + // scan the thinkers to make sure all the old pinch dummies are gone on death + // this can happen if the boss was hurt earlier than expected + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo = (mobj_t *)th; + if (mo->type == (mobjtype_t)target->info->mass && mo->tracer == target) + { + P_RemoveMobj(mo); + i++; + } + if (i == 2) // we've already removed 2 of these, let's stop now + break; + } + } + break; + + case MT_BIGMINE: + if (inflictor) + { + fixed_t dx = target->x - inflictor->x, dy = target->y - inflictor->y, dz = target->z - inflictor->z; + fixed_t dm = FixedHypot(dz, FixedHypot(dy, dx)); + target->momx = FixedDiv(FixedDiv(dx, dm), dm)*512; + target->momy = FixedDiv(FixedDiv(dy, dm), dm)*512; + target->momz = FixedDiv(FixedDiv(dz, dm), dm)*512; + } + if (source) + P_SetTarget(&target->tracer, source); + break; + + case MT_BLASTEXECUTOR: + if (target->spawnpoint) + P_LinedefExecute(target->spawnpoint->angle, (source ? source : inflictor), target->subsector->sector); + break; + case MT_EGGTRAP: // Time for birdies! Yaaaaaaaay! target->fuse = TICRATE*2; @@ -2467,57 +2460,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget break; } - // Enemy drops that ALWAYS occur regardless of mode - if (target->type == MT_AQUABUZZ) // Additionally spawns breathable bubble for players to get - { - if (inflictor && inflictor->player // did a player kill you? Spawn relative to the player so he's bound to get it - && P_AproxDistance(inflictor->x - target->x, inflictor->y - target->y) <= inflictor->radius + target->radius + FixedMul(8*FRACUNIT, inflictor->scale) // close enough? - && inflictor->z <= target->z + target->height + FixedMul(8*FRACUNIT, inflictor->scale) - && inflictor->z + inflictor->height >= target->z - FixedMul(8*FRACUNIT, inflictor->scale)) - mo = P_SpawnMobj(inflictor->x + inflictor->momx, inflictor->y + inflictor->momy, inflictor->z + (inflictor->height / 2) + inflictor->momz, MT_EXTRALARGEBUBBLE); - else - mo = P_SpawnMobj(target->x, target->y, target->z, MT_EXTRALARGEBUBBLE); - mo->destscale = target->scale; - P_SetScale(mo, mo->destscale); - } - else if (target->type == MT_YELLOWSHELL) // Spawns a spring that falls to the ground - { - mobjtype_t spawnspring = MT_YELLOWSPRING; - fixed_t spawnheight = target->z; - if (!(target->eflags & MFE_VERTICALFLIP)) - spawnheight += target->height; - - mo = P_SpawnMobj(target->x, target->y, spawnheight, spawnspring); - mo->destscale = target->scale; - P_SetScale(mo, mo->destscale); - - if (target->flags2 & MF2_OBJECTFLIP) - mo->flags2 |= MF2_OBJECTFLIP; - } - - if (target->type == MT_EGGMOBILE3) - { - thinker_t *th; - UINT32 i = 0; // to check how many clones we've removed - - // scan the thinkers to make sure all the old pinch dummies are gone on death - // this can happen if the boss was hurt earlier than expected - for (th = thinkercap.next; th != &thinkercap; th = th->next) - { - if (th->function.acp1 != (actionf_p1)P_MobjThinker) - continue; - - mo = (mobj_t *)th; - if (mo->type == (mobjtype_t)target->info->mass && mo->tracer == target) - { - P_RemoveMobj(mo); - i++; - } - if (i == 2) // we've already removed 2 of these, let's stop now - break; - } - } - + // Final state setting - do something instead of P_SetMobjState; if (target->type == MT_SPIKE && target->info->deathstate != S_NULL) { const angle_t ang = ((inflictor) ? inflictor->angle : 0) + ANGLE_90; diff --git a/src/p_map.c b/src/p_map.c index 6d1760596..3715e765b 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -622,6 +622,31 @@ static boolean PIT_CheckThing(mobj_t *thing) } #endif + // Billiards mines! + if (thing->type == MT_BIGMINE && tmthing->type == MT_BIGMINE) + { + if (!tmthing->momx && !tmthing->momy) + return true; + if ((statenum_t)(thing->state-states) != thing->info->spawnstate) + return true; + if (thing->z > tmthing->z + tmthing->height) + return true; // overhead + if (thing->z + thing->height < tmthing->z) + return true; // underneath + + thing->momx = tmthing->momx/3; + thing->momy = tmthing->momy/3; + thing->momz = tmthing->momz/3; + tmthing->momx /= -8; + tmthing->momy /= -8; + tmthing->momz /= -8; + if (thing->info->activesound) + S_StartSound(thing, thing->info->activesound); + P_SetMobjState(thing, thing->info->meleestate); + P_SetTarget(&thing->tracer, tmthing->tracer); + return true; + } + // When solid spikes move, assume they just popped up and teleport things on top of them to hurt. if (tmthing->type == MT_SPIKE && tmthing->flags & MF_SOLID) { diff --git a/src/p_mobj.c b/src/p_mobj.c index 185a48340..45e1434d2 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7379,9 +7379,7 @@ void P_MobjThinker(mobj_t *mobj) } break; case MT_AQUABUZZ: - P_MobjCheckWater(mobj); // solely for MFE_UNDERWATER for A_FlickySpawn - /* FALLTHRU */ - case MT_BIGAIRMINE: + mobj->eflags |= MFE_UNDERWATER; //P_MobjCheckWater(mobj); // solely for MFE_UNDERWATER for A_FlickySpawn { if (mobj->tracer && mobj->tracer->player && mobj->tracer->health > 0 && P_AproxDistance(P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y), mobj->tracer->z - mobj->z) <= mobj->radius * 16) @@ -7406,34 +7404,11 @@ void P_MobjThinker(mobj_t *mobj) } break; case MT_BIGMINE: - { - if (mobj->tracer && mobj->tracer->player && mobj->tracer->health > 0 - && P_AproxDistance(P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y), mobj->tracer->z - mobj->z) <= mobj->radius * 16) - { - P_MobjCheckWater(mobj); - - // Home in on the target. - P_HomingAttack(mobj, mobj->tracer); - - // Don't let it go out of water - if (mobj->z + mobj->height > mobj->watertop) - mobj->z = mobj->watertop - mobj->height; - - if (mobj->z < mobj->floorz) - mobj->z = mobj->floorz; - - if (leveltime % mobj->info->painchance == 0) - S_StartSound(mobj, mobj->info->activesound); - } - else - { - // Try to find a player - P_LookForPlayers(mobj, true, true, mobj->radius * 16); - mobj->momx >>= 1; - mobj->momy >>= 1; - mobj->momz >>= 1; - } - } + mobj->extravalue1 += 3; + mobj->extravalue1 %= 360; + P_UnsetThingPosition(mobj); + mobj->z += FINESINE(mobj->extravalue1*(FINEMASK+1)/360); + P_SetThingPosition(mobj); break; case MT_EGGCAPSULE: if (!mobj->reactiontime) @@ -8496,6 +8471,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) } break; } + case MT_BIGMINE: + mobj->extravalue1 = FixedHypot(mobj->x, mobj->y)>>FRACBITS; + break; case MT_EGGMOBILE2: // Special condition for the 2nd boss. mobj->watertop = mobj->info->speed; diff --git a/src/sounds.c b/src/sounds.c index 293ce381d..3a7219c6d 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -310,7 +310,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3k54", false, 64, 64, -1, NULL, 0, -1, -1, LUMPERROR, "Firing"}, // MetalSonic shot fire {"s3k55", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Mechanical movement"}, {"s3k56", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy landing"}, - {"s3k57", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Splash"}, + {"s3k57", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Burst"}, {"s3k58", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Mechanical movement"}, {"s3k59", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crumbling"}, {"s3k5a", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Aiming"},