* 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.
This commit is contained in:
toasterbabe 2018-04-26 20:18:51 +01:00
parent 976331fb03
commit 1eb84f57c5
9 changed files with 291 additions and 259 deletions

View file

@ -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

View file

@ -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

View file

@ -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<<FRACBITS)|1), 0, S_BIGMINE_IDLE}, // S_BIGMINE_IDLE
{SPR_BMNE, 1, 2, {A_MineRange}, 112, 0, S_BIGMINE_ALERT2}, // S_BIGMINE_ALERT1
{SPR_BMNE, 2, 2, {A_MineRange}, 112, 0, S_BIGMINE_ALERT3}, // S_BIGMINE_ALERT2
{SPR_BMNE, 0, 1, {A_Look}, ((224<<FRACBITS)|1), 1, S_BIGMINE_IDLE}, // S_BIGMINE_ALERT3
{SPR_BMNE, 3, 25, {A_Pain}, 0, 0, S_BIGMINE_SET2}, // S_BIGMINE_SET1
{SPR_BMNE, 3, 10, {A_SetObjectFlags}, MF_SHOOTABLE, 1, S_BIGMINE_SET3}, // S_BIGMINE_SET1
{SPR_BMNE, 3, 1, {A_MineExplode}, 0, 0, S_BIGMINE_BLAST1}, // S_BIGMINE_SET3
{SPR_BMNB, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BIGMINE_BLAST2}, // S_BIGMINE_BLAST1
{SPR_BMNB, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_BIGMINE_BLAST3}, // S_BIGMINE_BLAST2
{SPR_BMNB, 2|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BIGMINE_BLAST4}, // S_BIGMINE_BLAST3
{SPR_BMNB, 3|FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_BIGMINE_BLAST5}, // S_BIGMINE_BLAST4
{SPR_NULL, 0, 35, {NULL}, 0, 0, S_NULL}, // S_BIGMINE_BLAST5
// Cannon launcher
{SPR_NULL, 0, 1, {A_FindTarget}, MT_PLAYER, 0, S_CANNONLAUNCHER2}, // S_CANNONLAUNCHER1
@ -1980,24 +1985,18 @@ state_t states[NUMSTATES] =
{SPR_DSTG, 1, -1, {NULL}, 0, 0, S_NULL}, // S_DSZ2STALAGMITE
// DSZ Light beam
{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {A_LightBeamReset}, 0, 0, S_LIGHTBEAM2}, // S_LIGHTBEAM1
{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM3}, // S_LIGHTBEAM2
{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM4}, // S_LIGHTBEAM3
{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM5}, // S_LIGHTBEAM4
{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM6}, // S_LIGHTBEAM5
{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM7}, // S_LIGHTBEAM6
{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM8}, // S_LIGHTBEAM7
{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM9}, // S_LIGHTBEAM8
{SPR_LIBE, 0|FF_TRANS30|FF_FULLBRIGHT|FF_PAPERSPRITE, 9, {NULL}, 0, 0, S_LIGHTBEAM10}, // S_LIGHTBEAM9
{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM11}, // S_LIGHTBEAM10
{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM12}, // S_LIGHTBEAM11
{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM13}, // S_LIGHTBEAM12
{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM14}, // S_LIGHTBEAM13
{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM15}, // S_LIGHTBEAM14
{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM16}, // S_LIGHTBEAM15
{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM17}, // S_LIGHTBEAM16
{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM18}, // S_LIGHTBEAM17
{SPR_NULL, 0, 2, {A_SetRandomTics}, 4, 35, S_LIGHTBEAM1}, // S_LIGHTBEAM18
{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {A_LightBeamReset}, 0, 0, S_LIGHTBEAM2}, // S_LIGHTBEAM1
{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM3}, // S_LIGHTBEAM2
{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM4}, // S_LIGHTBEAM3
{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM5}, // S_LIGHTBEAM4
{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM6}, // S_LIGHTBEAM5
{SPR_LIBE, 0|FF_TRANS30|FF_FULLBRIGHT|FF_PAPERSPRITE, 9, {NULL}, 0, 0, S_LIGHTBEAM7}, // S_LIGHTBEAM6
{SPR_LIBE, 0|FF_TRANS40|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM8}, // S_LIGHTBEAM7
{SPR_LIBE, 0|FF_TRANS50|FF_FULLBRIGHT|FF_PAPERSPRITE, 2, {NULL}, 0, 0, S_LIGHTBEAM9}, // S_LIGHTBEAM8
{SPR_LIBE, 0|FF_TRANS60|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM10}, // S_LIGHTBEAM9
{SPR_LIBE, 0|FF_TRANS70|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM11}, // S_LIGHTBEAM10
{SPR_LIBE, 0|FF_TRANS80|FF_FULLBRIGHT|FF_PAPERSPRITE, 4, {NULL}, 0, 0, S_LIGHTBEAM12}, // S_LIGHTBEAM11
{SPR_NULL, 0, 2, {A_SetRandomTics}, 4, 35, S_LIGHTBEAM1}, // S_LIGHTBEAM12
// CEZ Chain
{SPR_CHAN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CEZCHAIN
@ -6348,55 +6347,55 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_BIGMINE
524, // doomednum
S_BIGMINE1, // spawnstate
S_BIGMINE_IDLE, // spawnstate
1, // spawnhealth
S_BIGMINE_ALERT1, // seestate
sfx_s3k5c, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_s3k86, // painsound
S_BIGMINE_SET1, // meleestate
S_NULL, // missilestate
S_BIGMINE_SET2, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
2*FRACUNIT, // speed
28*FRACUNIT, // radius
56*FRACUNIT, // height
0, // display offset
MT_UWEXPLODE, // mass
0, // damage
sfx_s3k9e, // activesound
MF_SPECIAL|MF_NOGRAVITY|MF_SHOOTABLE|MF_ENEMY, // flags
S_NULL // raisestate
},
{ // MT_BLASTEXECUTOR
1505, // doomednum
S_INVISIBLE, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
TICRATE, // painchance
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
2*FRACUNIT, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
8, // speed
32*FRACUNIT, // radius
16*FRACUNIT, // height
0, // display offset
MT_UWEXPLODE, // mass
64*FRACUNIT, // damage
sfx_gbeep, // activesound
MF_SPECIAL|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_BIGAIRMINE
527, // doomednum
S_BIGMINE1, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
TICRATE, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_bexpld, // deathsound
2*FRACUNIT, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
0, // display offset
MT_BOSSEXPLODE, // mass
64*FRACUNIT, // damage
sfx_gbeep, // activesound
MF_SPECIAL|MF_NOGRAVITY, // flags
4, // mass
0, // damage
sfx_None, // activesound
MF_SHOOTABLE|MF_NOGRAVITY|MF_NOCLIPTHING, // flags
S_NULL // raisestate
},
@ -15512,7 +15511,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOGRAVITY|MF_SCENERY, // flags
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
},

View file

@ -219,6 +219,8 @@ void A_FlameParticle();
void A_FadeOverlay();
void A_Boss5Jump();
void A_LightBeamReset();
void A_MineExplode();
void A_MineRange();
// ratio of states to sprites to mobj types is roughly 6 : 1 : 1
#define NUMMOBJFREESLOTS 256
@ -334,6 +336,7 @@ typedef enum sprite
SPR_WSPB, // Wall spike base
SPR_STPT, // Starpost
SPR_BMNE, // Big floating mine
SPR_BMNB,
// Monitor Boxes
SPR_MSTV, // MiSc TV sprites
@ -1822,14 +1825,18 @@ typedef enum state
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,
@ -2100,12 +2107,6 @@ typedef enum state
S_LIGHTBEAM10,
S_LIGHTBEAM11,
S_LIGHTBEAM12,
S_LIGHTBEAM13,
S_LIGHTBEAM14,
S_LIGHTBEAM15,
S_LIGHTBEAM16,
S_LIGHTBEAM17,
S_LIGHTBEAM18,
// CEZ Chain
S_CEZCHAIN,
@ -3451,7 +3452,7 @@ typedef enum mobj_type
MT_WALLSPIKEBASE,
MT_STARPOST,
MT_BIGMINE,
MT_BIGAIRMINE,
MT_BLASTEXECUTOR,
MT_CANNONLAUNCHER,
// Monitor miscellany

View file

@ -247,6 +247,8 @@ void A_FlameParticle(mobj_t *actor);
void A_FadeOverlay(mobj_t *actor);
void A_Boss5Jump(mobj_t *actor);
void A_LightBeamReset(mobj_t *actor);
void A_MineExplode(mobj_t *actor);
void A_MineRange(mobj_t *actor);
//
// ENEMY THINKING
@ -10615,8 +10617,9 @@ void A_Boss5Jump(mobj_t *actor)
actor->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);
}

View file

@ -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;

View file

@ -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)
{

View file

@ -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;

View file

@ -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"},