diff --git a/src/dehacked.c b/src/dehacked.c index 4c2ee06fd..06e3c3e95 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -4667,6 +4667,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", @@ -4675,11 +4680,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", @@ -4732,8 +4732,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", @@ -7263,6 +7263,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", diff --git a/src/info.c b/src/info.c index aad24d6df..2fc02fe9c 100644 --- a/src/info.c +++ b/src/info.c @@ -1272,6 +1272,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 @@ -1279,12 +1284,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 @@ -1331,14 +1331,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 @@ -2899,7 +2899,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 @@ -5516,7 +5516,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 @@ -5571,9 +5571,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 @@ -5585,6 +5585,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 @@ -9102,7 +9129,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 @@ -9129,7 +9156,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 diff --git a/src/info.h b/src/info.h index 1d7d4a41e..a0f6fcaa5 100644 --- a/src/info.h +++ b/src/info.h @@ -1425,6 +1425,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, @@ -1433,11 +1438,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, @@ -1490,8 +1490,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, @@ -4043,6 +4043,7 @@ typedef enum mobj_type MT_EGGMOBILE3, MT_PROPELLER, MT_FAKEMOBILE, + MT_SHOCK, // Boss 4 MT_EGGMOBILE4, diff --git a/src/p_enemy.c b/src/p_enemy.c index f58924e2c..113db8258 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2863,6 +2863,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)) @@ -2930,7 +2931,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 @@ -7761,9 +7765,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 @@ -7800,21 +7806,31 @@ 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 = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + if (!(actor->flags2 & MF2_STRONGBOX)) { - mo2 = (mobj_t *)th; - if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && mo2->spawnpoint->angle == actor->threshold) + thinker_t *th; + mobj_t *mo2; + + P_SetTarget(&actor->target, NULL); + + // scan the thinkers + // to find a point that matches + // the number + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { + 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; } @@ -7822,67 +7838,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"); } } } diff --git a/src/p_inter.c b/src/p_inter.c index cf2efe54d..f1266d113 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2538,13 +2538,20 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { 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)<info->deathsound); // done once to prevent sound stacking } } break; diff --git a/src/p_mobj.c b/src/p_mobj.c index 1668d8ba1..18e6c94e8 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -4374,6 +4374,8 @@ static void P_Boss3Thinker(mobj_t *mobj) } if (mobj->health <= 0) + return; + /* { mobj->movecount = 0; mobj->reactiontime = 0; @@ -4386,89 +4388,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 @@ -4477,63 +4427,68 @@ static void P_Boss3Thinker(mobj_t *mobj) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { 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); @@ -4548,9 +4503,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); @@ -4559,86 +4512,101 @@ 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 = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + if (!(mobj->flags2 & MF2_STRONGBOX)) { - mo2 = (mobj_t *)th; - if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && mo2->spawnpoint->angle == mobj->threshold) + thinker_t *th; + mobj_t *mo2; + + P_SetTarget(&mobj->tracer, NULL); + + // scan the thinkers + // to find a point that matches + // the number + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { - P_SetTarget(&mobj->target, mo2); + 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"); } } } @@ -7679,6 +7647,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; @@ -9445,6 +9441,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; @@ -10853,6 +10853,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) { diff --git a/src/p_user.c b/src/p_user.c index 3e464d0cf..b2ae9b692 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4456,6 +4456,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