ha ha ha ha ha ha ha ha

Sea Egg is majorly changed according to Mystic's ancient instructions (excepting the flying FOF rock, I cared not for fucking around with FOFs).

Specifically:
* Faster paced fight.
* Instantly travels horizontal distance.
* Fakes no longer hurt papa, and spin out like a deflating balloon when he dies.
* New attack: When surfacing, produces an electric shockwave. Replaces underwater shock. Designed for new, shallow arena.
* Support for multiple bosses in the same map distinguished by parameter.

Will upload map to fight the new battle in on the MR.
This commit is contained in:
toaster 2019-06-29 14:10:32 +01:00
parent e5a0bd8be3
commit f9f92abc44
7 changed files with 305 additions and 254 deletions

View File

@ -4666,6 +4666,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
// Boss 3
"S_EGGMOBILE3_STND",
"S_EGGMOBILE3_LAUGH1",
"S_EGGMOBILE3_LAUGH2",
"S_EGGMOBILE3_LAUGH3",
"S_EGGMOBILE3_LAUGH4",
"S_EGGMOBILE3_LAUGH5",
"S_EGGMOBILE3_ATK1",
"S_EGGMOBILE3_ATK2",
"S_EGGMOBILE3_ATK3A",
@ -4674,11 +4679,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_EGGMOBILE3_ATK3D",
"S_EGGMOBILE3_ATK4",
"S_EGGMOBILE3_ATK5",
"S_EGGMOBILE3_LAUGH1",
"S_EGGMOBILE3_LAUGH2",
"S_EGGMOBILE3_LAUGH3",
"S_EGGMOBILE3_LAUGH4",
"S_EGGMOBILE3_LAUGH5",
"S_EGGMOBILE3_LAUGH6",
"S_EGGMOBILE3_LAUGH7",
"S_EGGMOBILE3_LAUGH8",
@ -4731,8 +4731,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FAKEMOBILE_ATK3B",
"S_FAKEMOBILE_ATK3C",
"S_FAKEMOBILE_ATK3D",
"S_FAKEMOBILE_ATK4",
"S_FAKEMOBILE_ATK5",
"S_FAKEMOBILE_DIE1",
"S_FAKEMOBILE_DIE2",
// Boss 4
"S_EGGMOBILE4_STND",
@ -7251,6 +7251,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_EGGMOBILE3",
"MT_PROPELLER",
"MT_FAKEMOBILE",
"MT_SHOCK",
// Boss 4
"MT_EGGMOBILE4",

View File

@ -1268,6 +1268,11 @@ state_t states[NUMSTATES] =
// Boss 3
{SPR_EGGO, 0, 1, {NULL}, 0, 0, S_EGGMOBILE3_STND}, // S_EGGMOBILE3_STND
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH2}, // S_EGGMOBILE3_LAUGH1
{SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH3}, // S_EGGMOBILE3_LAUGH2
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH4}, // S_EGGMOBILE3_LAUGH3
{SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH5}, // S_EGGMOBILE3_LAUGH4
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_ATK1}, // S_EGGMOBILE3_LAUGH5
{SPR_EGGO, 1, 2, {NULL}, 0, 0, S_EGGMOBILE3_ATK2}, // S_EGGMOBILE3_ATK1
{SPR_EGGO, 2, 2, {NULL}, 0, 0, S_EGGMOBILE3_ATK3A}, // S_EGGMOBILE3_ATK2
{SPR_EGGO, 3, 2, {A_BossFireShot}, MT_TORPEDO, 2, S_EGGMOBILE3_ATK3B}, // S_EGGMOBILE3_ATK3A
@ -1275,12 +1280,7 @@ state_t states[NUMSTATES] =
{SPR_EGGO, 3, 2, {A_BossFireShot}, MT_TORPEDO, 3, S_EGGMOBILE3_ATK3D}, // S_EGGMOBILE3_ATK3C
{SPR_EGGO, 3, 2, {A_BossFireShot}, MT_TORPEDO, 5, S_EGGMOBILE3_ATK4}, // S_EGGMOBILE3_ATK3D
{SPR_EGGO, 4, 2, {NULL}, 0, 0, S_EGGMOBILE3_ATK5}, // S_EGGMOBILE3_ATK4
{SPR_EGGO, 5, 2, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH1}, // S_EGGMOBILE3_ATK5
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH2}, // S_EGGMOBILE3_LAUGH1
{SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH3}, // S_EGGMOBILE3_LAUGH2
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH4}, // S_EGGMOBILE3_LAUGH3
{SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH5}, // S_EGGMOBILE3_LAUGH4
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH6}, // S_EGGMOBILE3_LAUGH5
{SPR_EGGO, 5, 2, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH6}, // S_EGGMOBILE3_ATK5
{SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH7}, // S_EGGMOBILE3_LAUGH6
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH8}, // S_EGGMOBILE3_LAUGH7
{SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH9}, // S_EGGMOBILE3_LAUGH8
@ -1327,14 +1327,14 @@ state_t states[NUMSTATES] =
// Boss 3 Pinch
{SPR_FAKE, 0, 1, {A_BossJetFume}, 1, 0, S_FAKEMOBILE}, // S_FAKEMOBILE_INIT
{SPR_FAKE, 0, 1, {A_Boss3Path}, 0, 0, S_FAKEMOBILE}, // S_FAKEMOBILE
{SPR_FAKE, 0, 2, {NULL}, 0, 0, S_FAKEMOBILE_ATK2}, // S_FAKEMOBILE_ATK1
{SPR_FAKE, 0, 22, {NULL}, 0, 0, S_FAKEMOBILE_ATK2}, // S_FAKEMOBILE_ATK1
{SPR_FAKE, 0, 2, {NULL}, 0, 0, S_FAKEMOBILE_ATK3A}, // S_FAKEMOBILE_ATK2
{SPR_FAKE, 0, 2, {A_BossFireShot}, MT_TORPEDO2, 2, S_FAKEMOBILE_ATK3B}, // S_FAKEMOBILE_ATK3A
{SPR_FAKE, 0, 2, {A_BossFireShot}, MT_TORPEDO2, 4, S_FAKEMOBILE_ATK3C}, // S_FAKEMOBILE_ATK3B
{SPR_FAKE, 0, 2, {A_BossFireShot}, MT_TORPEDO2, 3, S_FAKEMOBILE_ATK3D}, // S_FAKEMOBILE_ATK3C
{SPR_FAKE, 0, 2, {A_BossFireShot}, MT_TORPEDO2, 5, S_FAKEMOBILE_ATK4}, // S_FAKEMOBILE_ATK3D
{SPR_FAKE, 0, 2, {NULL}, 0, 0, S_FAKEMOBILE_ATK5}, // S_FAKEMOBILE_ATK4
{SPR_FAKE, 0, 2, {NULL}, 0, 0, S_FAKEMOBILE}, // S_FAKEMOBILE_ATK5
{SPR_FAKE, 0, 2, {A_BossFireShot}, MT_TORPEDO2, 5, S_FAKEMOBILE}, // S_FAKEMOBILE_ATK3D
{SPR_FAKE, 0, 1, {NULL}, 0, 0, S_FAKEMOBILE_DIE2}, // S_FAKEMOBILE_DIE1
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_FAKEMOBILE_DIE1}, // S_FAKEMOBILE_DIE2
// Boss 4
{SPR_EGGP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGMOBILE4_STND
@ -2886,7 +2886,7 @@ state_t states[NUMSTATES] =
{SPR_NULL, 0, 15*2, {NULL}, 0, 0, S_ZAPSB2 }, // S_ZAPSB11
// Thunder spark
{SPR_SSPK, FF_ANIMATE, 18, {NULL}, 1, 2, S_NULL}, // S_THUNDERCOIN_SPARK
{SPR_SSPK, FF_ANIMATE, -1, {NULL}, 1, 2, S_NULL}, // S_THUNDERCOIN_SPARK
// Invincibility Sparkles
{SPR_IVSP, FF_ANIMATE, 32, {NULL}, 31, 1, S_NULL}, // S_IVSP
@ -5500,7 +5500,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
MT_PROPELLER, // painchance
sfx_dmpain, // painsound
S_NULL, // meleestate
S_EGGMOBILE3_ATK1, // missilestate
S_EGGMOBILE3_LAUGH1,// missilestate
S_EGGMOBILE3_DIE1, // deathstate
S_EGGMOBILE3_FLEE1, // xdeathstate
sfx_cybdth, // deathsound
@ -5555,9 +5555,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_s3k7b, // painsound
S_NULL, // meleestate
S_FAKEMOBILE_ATK1, // missilestate
S_XPLD1, // deathstate
S_FAKEMOBILE_DIE1, // deathstate
S_NULL, // xdeathstate
sfx_pop, // deathsound
sfx_mswarp, // deathsound
8*FRACUNIT, // speed
32*FRACUNIT, // radius
116*FRACUNIT, // height
@ -5569,6 +5569,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_SHOCK
-1, // doomednum
S_THUNDERCOIN_SPARK, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_SPRK1, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
10*FRACUNIT, // speed
16*FRACUNIT, // radius
35*FRACUNIT, // height
0, // display offset
DMG_ELECTRIC|(sfx_buzz2<<8), // mass
20, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_EGGMOBILE4
203, // doomednum
S_EGGMOBILE4_STND, // spawnstate
@ -9086,7 +9113,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_MINE_BOOM1, // deathstate
S_XPLD1, // deathstate
S_NULL, // xdeathstate
sfx_cybdth, // deathsound
20*FRACUNIT, // speed
@ -9113,7 +9140,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_MINE_BOOM1, // deathstate
S_XPLD1, // deathstate
S_NULL, // xdeathstate
sfx_cybdth, // deathsound
20*FRACUNIT, // speed

View File

@ -1421,6 +1421,11 @@ typedef enum state
// Boss 3
S_EGGMOBILE3_STND,
S_EGGMOBILE3_LAUGH1,
S_EGGMOBILE3_LAUGH2,
S_EGGMOBILE3_LAUGH3,
S_EGGMOBILE3_LAUGH4,
S_EGGMOBILE3_LAUGH5,
S_EGGMOBILE3_ATK1,
S_EGGMOBILE3_ATK2,
S_EGGMOBILE3_ATK3A,
@ -1429,11 +1434,6 @@ typedef enum state
S_EGGMOBILE3_ATK3D,
S_EGGMOBILE3_ATK4,
S_EGGMOBILE3_ATK5,
S_EGGMOBILE3_LAUGH1,
S_EGGMOBILE3_LAUGH2,
S_EGGMOBILE3_LAUGH3,
S_EGGMOBILE3_LAUGH4,
S_EGGMOBILE3_LAUGH5,
S_EGGMOBILE3_LAUGH6,
S_EGGMOBILE3_LAUGH7,
S_EGGMOBILE3_LAUGH8,
@ -1486,8 +1486,8 @@ typedef enum state
S_FAKEMOBILE_ATK3B,
S_FAKEMOBILE_ATK3C,
S_FAKEMOBILE_ATK3D,
S_FAKEMOBILE_ATK4,
S_FAKEMOBILE_ATK5,
S_FAKEMOBILE_DIE1,
S_FAKEMOBILE_DIE2,
// Boss 4
S_EGGMOBILE4_STND,
@ -4026,6 +4026,7 @@ typedef enum mobj_type
MT_EGGMOBILE3,
MT_PROPELLER,
MT_FAKEMOBILE,
MT_SHOCK,
// Boss 4
MT_EGGMOBILE4,

View File

@ -2858,6 +2858,7 @@ void A_BossFireShot(mobj_t *actor)
fixed_t x, y, z;
INT32 locvar1 = var1;
INT32 locvar2 = var2;
mobj_t *missile;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_BossFireShot", actor))
@ -2925,7 +2926,10 @@ void A_BossFireShot(mobj_t *actor)
break;
}
P_SpawnXYZMissile(actor, actor->target, locvar1, x, y, z);
missile = P_SpawnXYZMissile(actor, actor->target, locvar1, x, y, z);
if (missile && actor->tracer && (actor->tracer->flags & MF_BOSS)) // Don't harm your papa.
P_SetTarget(&missile->target, actor->tracer);
}
// Function: A_Boss7FireMissiles
@ -7762,9 +7766,11 @@ void A_Boss3TakeDamage(mobj_t *actor)
return;
#endif
actor->movecount = var1;
actor->movefactor = -512*FRACUNIT;
/*if (actor->target && actor->target->spawnpoint)
actor->threshold = actor->target->spawnpoint->extrainfo;*/
if (actor->target && actor->target->spawnpoint)
actor->threshold = actor->target->spawnpoint->extrainfo;
}
// Function: A_Boss3Path
@ -7801,24 +7807,34 @@ void A_Boss3Path(mobj_t *actor)
}
else if (actor->threshold >= 0) // Traveling mode
{
thinker_t *th;
mobj_t *mo2;
fixed_t dist, dist2;
fixed_t dist = 0;
fixed_t speed;
P_SetTarget(&actor->target, NULL);
// scan the thinkers
// to find a point that matches
// the number
for (th = thinkercap.next; th != &thinkercap; th = th->next)
if (!(actor->flags2 & MF2_STRONGBOX))
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
thinker_t *th;
mobj_t *mo2;
mo2 = (mobj_t *)th;
if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && mo2->spawnpoint->angle == actor->threshold)
P_SetTarget(&actor->target, NULL);
// scan the thinkers
// to find a point that matches
// the number
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
mo2 = (mobj_t *)th;
if (mo2->type != MT_BOSS3WAYPOINT)
continue;
if (!mo2->spawnpoint)
continue;
if (mo2->spawnpoint->angle != actor->threshold)
continue;
if (mo2->spawnpoint->extrainfo != actor->cusval)
continue;
P_SetTarget(&actor->target, mo2);
break;
}
@ -7826,67 +7842,62 @@ void A_Boss3Path(mobj_t *actor)
if (!actor->target) // Should NEVER happen
{
CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy was unable to find specified waypoint: %d\n", actor->threshold);
CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy was unable to find specified waypoint: %d, %d\n", actor->threshold, actor->cusval);
return;
}
dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), actor->target->z - actor->z);
if (dist < 1)
dist = 1;
if (actor->tracer && ((actor->tracer->movedir)
|| (actor->tracer->health <= actor->tracer->info->damage)))
speed = actor->info->speed * 2;
else
speed = actor->info->speed;
actor->momx = FixedMul(FixedDiv(actor->target->x - actor->x, dist), speed);
actor->momy = FixedMul(FixedDiv(actor->target->y - actor->y, dist), speed);
actor->momz = FixedMul(FixedDiv(actor->target->z - actor->z, dist), speed);
if (actor->target->x == actor->x && actor->target->y == actor->y)
{
dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), actor->target->z + actor->movefactor - actor->z);
if (actor->momx != 0 || actor->momy != 0)
actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy);
if (dist < 1)
dist = 1;
dist2 = P_AproxDistance(P_AproxDistance(actor->target->x - (actor->x + actor->momx), actor->target->y - (actor->y + actor->momy)), actor->target->z - (actor->z + actor->momz));
actor->momx = FixedMul(FixedDiv(actor->target->x - actor->x, dist), speed);
actor->momy = FixedMul(FixedDiv(actor->target->y - actor->y, dist), speed);
actor->momz = FixedMul(FixedDiv(actor->target->z + actor->movefactor - actor->z, dist), speed);
if (dist2 < 1)
dist2 = 1;
if (actor->momx != 0 || actor->momy != 0)
actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy);
}
if ((dist >> FRACBITS) <= (dist2 >> FRACBITS))
if (dist <= speed)
{
// If further away, set XYZ of mobj to waypoint location
P_UnsetThingPosition(actor);
actor->x = actor->target->x;
actor->y = actor->target->y;
actor->z = actor->target->z;
actor->z = actor->target->z + actor->movefactor;
actor->momx = actor->momy = actor->momz = 0;
P_SetThingPosition(actor);
if (actor->threshold == 0)
if (!actor->movefactor) // firing mode
{
actor->movecount |= 2;
actor->movefactor = -512*FRACUNIT;
actor->flags2 &= ~MF2_STRONGBOX;
}
else if (!(actor->flags2 & MF2_STRONGBOX)) // just spawned or going down
{
actor->flags2 |= MF2_STRONGBOX;
actor->movefactor = -512*FRACUNIT;
}
else if (!(actor->flags2 & MF2_AMBUSH)) // just shifted tube
{
actor->flags2 |= MF2_AMBUSH;
actor->movefactor = 0;
}
else // just hit the bottom of your tube
{
P_RemoveMobj(actor); // Cycle completed. Dummy removed.
return;
}
// Set to next waypoint in sequence
if (actor->target->spawnpoint)
{
// From the center point, choose one of the five paths
if (actor->target->spawnpoint->angle == 0)
{
P_RemoveMobj(actor); // Cycle completed. Dummy removed.
return;
}
else
actor->threshold = actor->target->spawnpoint->extrainfo;
// If the deaf flag is set, go into firing mode
if (actor->target->spawnpoint->options & MTF_AMBUSH)
actor->movecount |= 2;
}
else // This should never happen, as well
CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy waypoint has no spawnpoint associated with it.\n");
}
}
}

View File

@ -2574,13 +2574,20 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
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
if (mo->type != (mobjtype_t)target->info->mass)
continue;
if (mo->tracer != target)
continue;
P_KillMobj(mo, inflictor, source, damagetype);
mo->destscale = mo->scale/8;
mo->scalespeed = (mo->scale - mo->destscale)/(2*TICRATE);
mo->momz = mo->info->speed;
mo->angle = FixedAngle((P_RandomKey(36)*10)<<FRACBITS);
if (++i == 2) // we've already removed 2 of these, let's stop now
break;
else
S_StartSound(mo, mo->info->deathsound); // done once to prevent sound stacking
}
}
break;

View File

@ -4384,6 +4384,8 @@ static void P_Boss3Thinker(mobj_t *mobj)
}
if (mobj->health <= 0)
return;
/*
{
mobj->movecount = 0;
mobj->reactiontime = 0;
@ -4396,89 +4398,37 @@ static void P_Boss3Thinker(mobj_t *mobj)
mobj->momz = mobj->info->speed;
return;
}
}
else
{
mobj->flags |= MF_NOGRAVITY|MF_NOCLIP;
mobj->flags |= MF_NOCLIPHEIGHT;
mobj->threshold = -1;
return;
}
}*/
if (mobj->reactiontime) // Shock mode
if (mobj->reactiontime) // At the bottom of the water
{
UINT32 i;
SINT8 curpath = mobj->threshold;
// Choose one of the paths you're not already on
mobj->threshold = P_RandomKey(8-1);
if (mobj->threshold >= curpath)
mobj->threshold++;
if (mobj->state != &states[mobj->info->spawnstate])
P_SetMobjState(mobj, mobj->info->spawnstate);
mobj->reactiontime--;
if (!mobj->reactiontime)
{
ffloor_t *rover;
// Shock the water
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
continue;
if (!players[i].mo)
continue;
if (players[i].mo->health <= 0)
continue;
if (players[i].mo->eflags & MFE_UNDERWATER)
P_DamageMobj(players[i].mo, mobj, mobj, 1, 0);
}
// Make the water flash
for (i = 0; i < numsectors; i++)
{
if (!sectors[i].ffloors)
continue;
for (rover = sectors[i].ffloors; rover; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS))
continue;
if (!(rover->flags & FF_SWIMMABLE))
continue;
P_SpawnLightningFlash(rover->master->frontsector);
break;
}
}
if ((UINT32)mobj->extravalue1 + TICRATE*2 < leveltime)
{
mobj->extravalue1 = (INT32)leveltime;
S_StartSound(0, sfx_buzz1);
}
// If in the center, check to make sure
// none of the players are in the water
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
continue;
if (!players[i].mo || players[i].bot)
continue;
if (players[i].mo->health <= 0)
continue;
if (players[i].mo->eflags & MFE_UNDERWATER)
{ // Stay put
mobj->reactiontime = 2*TICRATE;
return;
}
}
}
if (!mobj->reactiontime && mobj->health <= mobj->info->damage)
{ // Spawn pinch dummies from the center when we're leaving it.
thinker_t *th;
mobj_t *mo2;
mobj_t *dummy;
SINT8 way = mobj->threshold - 1; // 0 through 4.
SINT8 way2;
SINT8 way0 = mobj->threshold; // 0 through 4.
SINT8 way1, way2;
i = 0; // reset i to 0 so we can check how many clones we've removed
@ -4490,63 +4440,68 @@ static void P_Boss3Thinker(mobj_t *mobj)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == (mobjtype_t)mobj->info->mass && mo2->tracer == mobj)
{
P_RemoveMobj(mo2);
i++;
}
if (i == 2) // we've already removed 2 of these, let's stop now
if (mo2->type != (mobjtype_t)mobj->info->mass)
continue;
if (mo2->tracer != mobj)
continue;
P_RemoveMobj(mo2);
if (++i == 2) // we've already removed 2 of these, let's stop now
break;
}
way = (way + P_RandomRange(1,3)) % 5; // dummy 1 at one of the first three options after eggmobile
way1 = P_RandomKey(8-2);
if (way1 >= curpath)
way1++;
if (way1 >= way0)
{
way1++;
if (way1 == curpath)
way1++;
}
dummy = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->info->mass);
dummy->angle = mobj->angle;
dummy->threshold = way + 1;
dummy->tracer = mobj;
dummy->threshold = way1;
P_SetTarget(&dummy->tracer, mobj);
dummy->movefactor = mobj->movefactor;
dummy->cusval = mobj->cusval;
way2 = P_RandomKey(8-3);
if (way2 >= curpath)
way2++;
if (way2 >= way0)
{
way2++;
if (way2 == curpath)
way2++;
}
if (way2 >= way1)
{
way2++;
if (way2 == curpath || way2 == way0)
way2++;
}
do
way2 = (way + P_RandomRange(1,3)) % 5; // dummy 2 has to be careful,
while (way2 == mobj->threshold - 1); // to make sure it doesn't try to go the Eggman Way if dummy 1 rolled high.
dummy = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->info->mass);
dummy->angle = mobj->angle;
dummy->threshold = way2 + 1;
dummy->tracer = mobj;
dummy->threshold = way2;
P_SetTarget(&dummy->tracer, mobj);
dummy->movefactor = mobj->movefactor;
dummy->cusval = mobj->cusval;
CONS_Debug(DBG_GAMELOGIC, "Eggman path %d - Dummy selected paths %d and %d\n", mobj->threshold, way + 1, dummy->threshold);
P_LinedefExecute(LE_PINCHPHASE, mobj, NULL);
CONS_Debug(DBG_GAMELOGIC, "Eggman path %d - Dummy selected paths %d and %d\n", way0, way1, way2);
P_LinedefExecute(LE_PINCHPHASE+(mobj->cusval*LE_PARAMWIDTH), mobj, NULL);
}
}
else if (mobj->movecount) // Firing mode
{
UINT32 i;
// look for a new target
P_BossTargetPlayer(mobj, false);
if (!mobj->target || !mobj->target->player)
return;
// Are there any players underwater? If so, shock them!
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
continue;
if (!players[i].mo || players[i].bot)
continue;
if (players[i].mo->health <= 0)
continue;
if (players[i].mo->eflags & MFE_UNDERWATER)
{
mobj->movecount = 0;
P_SetMobjState(mobj, mobj->info->spawnstate);
return;
}
}
// Always face your target.
A_FaceTarget(mobj);
@ -4561,9 +4516,7 @@ static void P_Boss3Thinker(mobj_t *mobj)
}
else if (mobj->threshold >= 0) // Traveling mode
{
thinker_t *th;
mobj_t *mo2;
fixed_t dist, dist2;
fixed_t dist = 0;
fixed_t speed;
P_SetTarget(&mobj->target, NULL);
@ -4572,89 +4525,104 @@ static void P_Boss3Thinker(mobj_t *mobj)
&& !(mobj->flags2 & MF2_FRET))
P_SetMobjState(mobj, mobj->info->spawnstate);
// scan the thinkers
// to find a point that matches
// the number
for (th = thinkercap.next; th != &thinkercap; th = th->next)
if (!(mobj->flags2 & MF2_STRONGBOX))
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
thinker_t *th;
mobj_t *mo2;
mo2 = (mobj_t *)th;
if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && mo2->spawnpoint->angle == mobj->threshold)
P_SetTarget(&mobj->tracer, NULL);
// scan the thinkers
// to find a point that matches
// the number
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
P_SetTarget(&mobj->target, mo2);
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
mo2 = (mobj_t *)th;
if (mo2->type != MT_BOSS3WAYPOINT)
continue;
if (!mo2->spawnpoint)
continue;
if (mo2->spawnpoint->angle != mobj->threshold)
continue;
if (mo2->spawnpoint->extrainfo != mobj->cusval)
continue;
P_SetTarget(&mobj->tracer, mo2);
break;
}
}
if (!mobj->target) // Should NEVER happen
if (!mobj->tracer) // Should NEVER happen
{
CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 was unable to find specified waypoint: %d\n", mobj->threshold);
CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 was unable to find specified waypoint: %d, %d\n", mobj->threshold, mobj->cusval);
return;
}
dist = P_AproxDistance(P_AproxDistance(mobj->target->x - mobj->x, mobj->target->y - mobj->y), mobj->target->z - mobj->z);
if (dist < 1)
dist = 1;
if ((mobj->movedir) || (mobj->health <= mobj->info->damage))
speed = mobj->info->speed * 2;
else
speed = mobj->info->speed;
mobj->momx = FixedMul(FixedDiv(mobj->target->x - mobj->x, dist), speed);
mobj->momy = FixedMul(FixedDiv(mobj->target->y - mobj->y, dist), speed);
mobj->momz = FixedMul(FixedDiv(mobj->target->z - mobj->z, dist), speed);
if (mobj->momx != 0 || mobj->momy != 0)
mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy);
dist2 = P_AproxDistance(P_AproxDistance(mobj->target->x - (mobj->x + mobj->momx), mobj->target->y - (mobj->y + mobj->momy)), mobj->target->z - (mobj->z + mobj->momz));
if (dist2 < 1)
dist2 = 1;
if ((dist >> FRACBITS) <= (dist2 >> FRACBITS))
if (mobj->tracer->x == mobj->x && mobj->tracer->y == mobj->y)
{
// If further away, set XYZ of mobj to waypoint location
// apply ambush for old routing, otherwise whack a mole only
dist = P_AproxDistance(P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y), mobj->tracer->z + mobj->movefactor - mobj->z);
if (dist < 1)
dist = 1;
mobj->momx = FixedMul(FixedDiv(mobj->tracer->x - mobj->x, dist), speed);
mobj->momy = FixedMul(FixedDiv(mobj->tracer->y - mobj->y, dist), speed);
mobj->momz = FixedMul(FixedDiv(mobj->tracer->z + mobj->movefactor - mobj->z, dist), speed);
if (mobj->momx != 0 || mobj->momy != 0)
mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy);
}
if (dist <= speed)
{
// If distance to point is less than travel in that frame, set XYZ of mobj to waypoint location
P_UnsetThingPosition(mobj);
mobj->x = mobj->target->x;
mobj->y = mobj->target->y;
mobj->z = mobj->target->z;
mobj->x = mobj->tracer->x;
mobj->y = mobj->tracer->y;
mobj->z = mobj->tracer->z + mobj->movefactor;
mobj->momx = mobj->momy = mobj->momz = 0;
P_SetThingPosition(mobj);
if (mobj->threshold == 0)
if (!mobj->movefactor) // to firing mode
{
mobj->reactiontime = 1; // Bzzt! Shock the water!
mobj->movedir = 0;
UINT8 i;
angle_t ang = 0;
if (mobj->health <= 0)
mobj->movecount = mobj->health+1;
mobj->movefactor = -512*FRACUNIT;
// shock the water!
for (i = 0; i < 64; i++)
{
mobj->flags |= MF_NOGRAVITY|MF_NOCLIP;
mobj->flags |= MF_NOCLIPHEIGHT;
mobj->threshold = -1;
return;
mobj_t *shock = P_SpawnMobjFromMobj(mobj, 0, 0, 4*FRACUNIT, MT_SHOCK);
P_SetTarget(&shock->target, mobj);
P_InstaThrust(shock, ang, shock->info->speed);
P_CheckMissileSpawn(shock);
ang += (ANGLE_MAX/64);
}
S_StartSound(mobj, sfx_fizzle);
}
// Set to next waypoint in sequence
if (mobj->target->spawnpoint)
else if (mobj->flags2 & (MF2_STRONGBOX|MF2_CLASSICPUSH)) // just hit the bottom of your tube
{
// From the center point, choose one of the five paths
if (mobj->target->spawnpoint->angle == 0)
mobj->threshold = P_RandomRange(1,5);
else
mobj->threshold = mobj->target->spawnpoint->extrainfo;
// If the deaf flag is set, go into firing mode
if (mobj->target->spawnpoint->options & MTF_AMBUSH)
mobj->movecount = mobj->health+1;
mobj->flags2 &= ~(MF2_STRONGBOX|MF2_CLASSICPUSH);
mobj->reactiontime = 1; // spawn pinch dummies
mobj->movedir = 0;
}
else // just shifted to another tube
{
mobj->flags2 |= MF2_STRONGBOX;
if (mobj->health > 0)
mobj->movefactor = 0;
}
else // This should never happen, as well
CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 waypoint has no spawnpoint associated with it.\n");
}
}
}
@ -7520,6 +7488,34 @@ void P_MobjThinker(mobj_t *mobj)
return;
}
break;
case MT_FAKEMOBILE:
if (mobj->scale == mobj->destscale)
{
if (!mobj->fuse)
{
S_StartSound(mobj, sfx_s3k77);
mobj->flags2 |= MF2_DONTDRAW;
mobj->fuse = TICRATE;
}
return;
}
if (!mobj->reactiontime)
{
if (P_RandomChance(FRACUNIT/2))
mobj->movefactor = FRACUNIT;
else
mobj->movefactor = -FRACUNIT;
if (P_RandomChance(FRACUNIT/2))
mobj->movedir = ANG20;
else
mobj->movedir = -ANG20;
mobj->reactiontime = 5;
}
mobj->momz += mobj->movefactor;
mobj->angle += mobj->movedir;
P_InstaThrust(mobj, mobj->angle, -mobj->info->speed);
mobj->reactiontime--;
break;
case MT_EGGSHIELD:
mobj->flags2 ^= MF2_DONTDRAW;
break;
@ -9278,6 +9274,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
// Special condition for the 2nd boss.
mobj->watertop = mobj->info->speed;
break;
case MT_EGGMOBILE3:
mobj->movefactor = -512*FRACUNIT;
mobj->flags2 |= MF2_CLASSICPUSH;
break;
case MT_FLICKY_08:
mobj->color = (P_RandomChance(FRACUNIT/2) ? SKINCOLOR_RED : SKINCOLOR_AQUA);
break;
@ -9624,7 +9624,7 @@ consvar_t cv_flagtime = {"flagtime", "30", CV_NETVAR|CV_CHEAT, flagtime_cons_t,
void P_SpawnPrecipitation(void)
{
INT32 i, j, mrand;
INT32 i, mrand;
fixed_t basex, basey, x, y, height;
subsector_t *precipsector = NULL;
precipmobj_t *rainmo = NULL;
@ -10665,6 +10665,9 @@ You should think about modifying the deathmatch starts to take full advantage of
else
skyboxviewpnts[mthing->extrainfo] = mobj;
break;
case MT_EGGMOBILE3:
mobj->cusval = mthing->extrainfo;
break;
case MT_FAN:
if (mthing->options & MTF_OBJECTSPECIAL)
{

View File

@ -4362,6 +4362,7 @@ void P_DoJumpShield(player_t *player)
P_InstaThrust(spark, travelangle + i*(ANGLE_MAX/numangles), FixedMul(4*FRACUNIT, spark->scale));
if (i % 2)
P_SetObjectMomZ(spark, -4*FRACUNIT, false);
spark->fuse = 18;
}
#undef limitangle
#undef numangles