P_MobjThinker(): Separate scale thinking and scenery thinking into their own functions

This commit is contained in:
MascaraSnake 2019-12-24 21:07:55 +01:00
parent 13eb71e1ee
commit ddccfbd73d
1 changed files with 878 additions and 836 deletions

View File

@ -7143,46 +7143,7 @@ static void P_PyreFlyBurn(mobj_t *mobj, fixed_t hoffs, INT16 vrange, mobjtype_t
particle->momz = momz;
}
//
// P_MobjThinker
//
void P_MobjThinker(mobj_t *mobj)
{
I_Assert(mobj != NULL);
I_Assert(!P_MobjWasRemoved(mobj));
if (mobj->flags & MF_NOTHINK)
return;
if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && (bossdisabled & (1<<mobj->spawnpoint->extrainfo)))
return;
// Remove dead target/tracer.
if (mobj->target && P_MobjWasRemoved(mobj->target))
P_SetTarget(&mobj->target, NULL);
if (mobj->tracer && P_MobjWasRemoved(mobj->tracer))
P_SetTarget(&mobj->tracer, NULL);
if (mobj->hnext && P_MobjWasRemoved(mobj->hnext))
P_SetTarget(&mobj->hnext, NULL);
if (mobj->hprev && P_MobjWasRemoved(mobj->hprev))
P_SetTarget(&mobj->hprev, NULL);
mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG);
tmfloorthing = tmhitthing = NULL;
// 970 allows ANY mobj to trigger a linedef exec
if (mobj->subsector && GETSECSPECIAL(mobj->subsector->sector->special, 2) == 8)
{
sector_t *sec2;
sec2 = P_ThingOnSpecial3DFloor(mobj);
if (sec2 && GETSECSPECIAL(sec2->special, 2) == 1)
P_LinedefExecute(sec2->tag, mobj, sec2);
}
// Slowly scale up/down to reach your destscale.
if (mobj->scale != mobj->destscale)
static void P_MobjScaleThink(mobj_t *mobj)
{
fixed_t oldheight = mobj->height;
UINT8 correctionType = 0; // Don't correct Z position, just gain height
@ -7218,48 +7179,7 @@ void P_MobjThinker(mobj_t *mobj)
}
}
if ((mobj->type == MT_GHOST || mobj->type == MT_THOK) && mobj->fuse > 0) // Not guaranteed to be MF_SCENERY or not MF_SCENERY!
{
if (mobj->flags2 & MF2_BOSSNOTRAP) // "fast" flag
{
if ((signed)((mobj->frame & FF_TRANSMASK) >> FF_TRANSSHIFT) < (NUMTRANSMAPS-1) - (2*mobj->fuse)/3)
// fade out when nearing the end of fuse...
mobj->frame = (mobj->frame & ~FF_TRANSMASK) | (((NUMTRANSMAPS-1) - (2*mobj->fuse)/3) << FF_TRANSSHIFT);
}
else
{
if ((signed)((mobj->frame & FF_TRANSMASK) >> FF_TRANSSHIFT) < (NUMTRANSMAPS-1) - mobj->fuse / 2)
// fade out when nearing the end of fuse...
mobj->frame = (mobj->frame & ~FF_TRANSMASK) | (((NUMTRANSMAPS-1) - mobj->fuse / 2) << FF_TRANSSHIFT);
}
}
// Special thinker for scenery objects
if (mobj->flags & MF_SCENERY)
{
#ifdef HAVE_BLUA
if (LUAh_MobjThinker(mobj))
return;
if (P_MobjWasRemoved(mobj))
return;
#endif
if (mobj->flags2 & MF2_SHIELD)
if (!P_AddShield(mobj))
return;
switch (mobj->type)
{
case MT_BOSSJUNK:
mobj->flags2 ^= MF2_DONTDRAW;
break;
case MT_MACEPOINT:
case MT_CHAINMACEPOINT:
case MT_SPRINGBALLPOINT:
case MT_CHAINPOINT:
case MT_FIREBARPOINT:
case MT_CUSTOMMACEPOINT:
case MT_HIDDEN_SLING:
static void P_MaceSceneryThink(mobj_t *mobj)
{
angle_t oldmovedir = mobj->movedir;
@ -7295,8 +7215,7 @@ void P_MobjThinker(mobj_t *mobj)
mobj->flags2 |= MF2_BEYONDTHEGRAVE;
}
break; // don't make bubble!
return; // don't make bubble!
}
else if (mobj->flags2 & MF2_BEYONDTHEGRAVE)
{
@ -7321,6 +7240,419 @@ void P_MobjThinker(mobj_t *mobj)
// Okay, time to MOVE
P_MaceRotate(mobj, mobj->movedir, oldmovedir);
}
static boolean P_DrownNumbersSceneryThink(mobj_t *mobj)
{
if (!mobj->target)
{
P_RemoveMobj(mobj);
return false;
}
if (!mobj->target->player || !(mobj->target->player->powers[pw_underwater] || mobj->target->player->powers[pw_spacetime]))
{
P_RemoveMobj(mobj);
return false;
}
mobj->x = mobj->target->x;
mobj->y = mobj->target->y;
mobj->destscale = mobj->target->destscale;
P_SetScale(mobj, mobj->target->scale);
if (mobj->target->eflags & MFE_VERTICALFLIP)
{
mobj->z = mobj->target->z - FixedMul(16*FRACUNIT, mobj->target->scale) - mobj->height;
if (mobj->target->player->pflags & PF_FLIPCAM)
mobj->eflags |= MFE_VERTICALFLIP;
}
else
mobj->z = mobj->target->z + (mobj->target->height) + FixedMul(8*FRACUNIT, mobj->target->scale); // Adjust height for height changes
if (mobj->threshold <= 35)
mobj->flags2 |= MF2_DONTDRAW;
else
mobj->flags2 &= ~MF2_DONTDRAW;
if (mobj->threshold <= 30)
mobj->threshold = 40;
mobj->threshold--;
return true;
}
static void P_FlameJetSceneryThink(mobj_t *mobj)
{
mobj_t *flame;
fixed_t strength;
if (!(mobj->flags2 & MF2_FIRING))
return;
if ((leveltime & 3) == 0)
return;
// Wave the flames back and forth. Reactiontime determines which direction it's going.
if (mobj->fuse <= -16)
mobj->reactiontime = 1;
else if (mobj->fuse >= 16)
mobj->reactiontime = 0;
if (mobj->reactiontime)
mobj->fuse += 2;
else
mobj->fuse -= 2;
flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME);
P_SetMobjState(flame, S_FLAMEJETFLAME4);
flame->angle = mobj->angle;
if (mobj->flags2 & MF2_AMBUSH) // Wave up and down instead of side-to-side
flame->momz = mobj->fuse << (FRACBITS - 2);
else
flame->angle += FixedAngle(mobj->fuse<<FRACBITS);
strength = 20*FRACUNIT;
strength -= ((20*FRACUNIT)/16)*mobj->movedir;
P_InstaThrust(flame, flame->angle, strength);
S_StartSound(flame, sfx_fire);
}
static void P_VerticalFlameJetSceneryThink(mobj_t *mobj)
{
mobj_t *flame;
fixed_t strength;
if (!(mobj->flags2 & MF2_FIRING))
return;
if ((leveltime & 3) == 0)
return;
// Wave the flames back and forth. Reactiontime determines which direction it's going.
if (mobj->fuse <= -16)
mobj->reactiontime = 1;
else if (mobj->fuse >= 16)
mobj->reactiontime = 0;
if (mobj->reactiontime)
mobj->fuse++;
else
mobj->fuse--;
flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME);
strength = 20*FRACUNIT;
strength -= ((20*FRACUNIT)/16)*mobj->movedir;
// If deaf'd, the object spawns on the ceiling.
if (mobj->flags2 & MF2_AMBUSH)
{
mobj->z = mobj->ceilingz - mobj->height;
flame->momz = -strength;
}
else
{
flame->momz = strength;
P_SetMobjState(flame, S_FLAMEJETFLAME7);
}
P_InstaThrust(flame, mobj->angle, FixedDiv(mobj->fuse*FRACUNIT, 3*FRACUNIT));
S_StartSound(flame, sfx_fire);
}
static boolean P_ParticleGenSceneryThink(mobj_t *mobj)
{
if (!mobj->lastlook)
return false;
if (!mobj->threshold)
return false;
if (--mobj->fuse <= 0)
{
INT32 i = 0;
mobj_t *spawn;
fixed_t bottomheight, topheight;
INT32 type = mobj->threshold, line = mobj->cvmem;
mobj->fuse = (tic_t)mobj->reactiontime;
bottomheight = lines[line].frontsector->floorheight;
topheight = lines[line].frontsector->ceilingheight - mobjinfo[(mobjtype_t)type].height;
if (mobj->waterbottom != bottomheight || mobj->watertop != topheight)
{
if (mobj->movefactor && (topheight > bottomheight))
mobj->health = (tic_t)(FixedDiv((topheight - bottomheight), abs(mobj->movefactor)) >> FRACBITS);
else
mobj->health = 0;
mobj->z = ((mobj->flags2 & MF2_OBJECTFLIP) ? topheight : bottomheight);
}
if (!mobj->health)
return false;
for (i = 0; i < mobj->lastlook; i++)
{
spawn = P_SpawnMobj(
mobj->x + FixedMul(FixedMul(mobj->friction, mobj->scale), FINECOSINE(mobj->angle >> ANGLETOFINESHIFT)),
mobj->y + FixedMul(FixedMul(mobj->friction, mobj->scale), FINESINE(mobj->angle >> ANGLETOFINESHIFT)),
mobj->z,
(mobjtype_t)mobj->threshold);
P_SetScale(spawn, mobj->scale);
spawn->momz = FixedMul(mobj->movefactor, spawn->scale);
spawn->destscale = spawn->scale/100;
spawn->scalespeed = spawn->scale/mobj->health;
spawn->tics = (tic_t)mobj->health;
spawn->flags2 |= (mobj->flags2 & MF2_OBJECTFLIP);
spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones
mobj->angle += mobj->movedir;
}
mobj->angle += (angle_t)mobj->movecount;
}
return true;
}
static void P_RosySceneryThink(mobj_t *mobj)
{
UINT8 i;
fixed_t pdist = 1700*mobj->scale, work, actualwork;
player_t *player = NULL;
statenum_t stat = (mobj->state - states);
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (!players[i].mo)
continue;
if (players[i].bot)
continue;
if (!players[i].mo->health)
continue;
actualwork = work = FixedHypot(mobj->x - players[i].mo->x, mobj->y - players[i].mo->y);
if (player)
{
if (players[i].skin == 0 || players[i].skin == 5)
work = (2*work)/3;
if (work >= pdist)
continue;
}
pdist = actualwork;
player = &players[i];
}
if (stat == S_ROSY_JUMP || stat == S_ROSY_PAIN)
{
if (P_IsObjectOnGround(mobj))
{
mobj->momx = mobj->momy = 0;
if (player && mobj->cvmem < (-2*TICRATE))
stat = S_ROSY_UNHAPPY;
else
stat = S_ROSY_WALK;
P_SetMobjState(mobj, stat);
}
else if (P_MobjFlip(mobj)*mobj->momz < 0)
mobj->frame = mobj->state->frame + mobj->state->var1;
}
if (!player)
{
if ((stat < S_ROSY_IDLE1 || stat > S_ROSY_IDLE4) && stat != S_ROSY_JUMP)
{
mobj->momx = mobj->momy = 0;
P_SetMobjState(mobj, S_ROSY_IDLE1);
}
}
else
{
boolean dojump = false, targonground, love, makeheart = false;
if (mobj->target != player->mo)
P_SetTarget(&mobj->target, player->mo);
// Tatsuru: Don't try to hug them if they're above or below you!
targonground = (P_IsObjectOnGround(mobj->target) && (player->panim == PA_IDLE || player->panim == PA_WALK || player->panim == PA_RUN) && player->mo->z == mobj->z);
love = (player->skin == 0 || player->skin == 5);
switch (stat)
{
case S_ROSY_IDLE1:
case S_ROSY_IDLE2:
case S_ROSY_IDLE3:
case S_ROSY_IDLE4:
dojump = true;
break;
case S_ROSY_JUMP:
case S_ROSY_PAIN:
// handled above
break;
case S_ROSY_WALK:
{
fixed_t x = mobj->x, y = mobj->y, z = mobj->z;
angle_t angletoplayer = R_PointToAngle2(x, y, mobj->target->x, mobj->target->y);
boolean allowed = P_TryMove(mobj, mobj->target->x, mobj->target->y, false);
P_UnsetThingPosition(mobj);
mobj->x = x;
mobj->y = y;
mobj->z = z;
P_SetThingPosition(mobj);
if (allowed)
{
fixed_t mom, max;
P_Thrust(mobj, angletoplayer, (3*FRACUNIT) >> 1);
mom = FixedHypot(mobj->momx, mobj->momy);
max = pdist;
if ((--mobj->extravalue1) <= 0)
{
if (++mobj->frame > mobj->state->frame + mobj->state->var1)
mobj->frame = mobj->state->frame;
if (mom > 12*mobj->scale)
mobj->extravalue1 = 2;
else if (mom > 6*mobj->scale)
mobj->extravalue1 = 3;
else
mobj->extravalue1 = 4;
}
if (max < (mobj->radius + mobj->target->radius))
{
mobj->momx = mobj->target->player->cmomx;
mobj->momy = mobj->target->player->cmomy;
if ((mobj->cvmem > TICRATE && !player->exiting) || !targonground)
P_SetMobjState(mobj, (stat = S_ROSY_STND));
else
{
mobj->target->momx = mobj->momx;
mobj->target->momy = mobj->momy;
P_SetMobjState(mobj, (stat = S_ROSY_HUG));
S_StartSound(mobj, sfx_cdpcm6);
mobj->angle = angletoplayer;
}
}
else
{
max /= 3;
if (max > 30*mobj->scale)
max = 30*mobj->scale;
if (mom > max && max > mobj->scale)
{
max = FixedDiv(max, mom);
mobj->momx = FixedMul(mobj->momx, max);
mobj->momy = FixedMul(mobj->momy, max);
}
if (abs(mobj->momx) > mobj->scale || abs(mobj->momy) > mobj->scale)
mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy);
}
}
else
dojump = true;
}
break;
case S_ROSY_HUG:
if (targonground)
{
player->pflags |= PF_STASIS;
if (mobj->cvmem < 5*TICRATE)
mobj->cvmem++;
if (love && !(leveltime & 7))
makeheart = true;
}
else
{
if (mobj->cvmem < (love ? 5*TICRATE : 0))
{
P_SetMobjState(mobj, (stat = S_ROSY_PAIN));
S_StartSound(mobj, sfx_cdpcm7);
}
else
P_SetMobjState(mobj, (stat = S_ROSY_JUMP));
var1 = var2 = 0;
A_DoNPCPain(mobj);
mobj->cvmem -= TICRATE;
}
break;
case S_ROSY_STND:
if ((pdist > (mobj->radius + mobj->target->radius + 3*(mobj->scale + mobj->target->scale))))
P_SetMobjState(mobj, (stat = S_ROSY_WALK));
else if (!targonground)
;
else
{
if (love && !(leveltime & 15))
makeheart = true;
if (player->exiting || --mobj->cvmem < TICRATE)
{
P_SetMobjState(mobj, (stat = S_ROSY_HUG));
S_StartSound(mobj, sfx_cdpcm6);
mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y);
mobj->target->momx = mobj->momx;
mobj->target->momy = mobj->momy;
}
}
break;
case S_ROSY_UNHAPPY:
default:
break;
}
if (stat == S_ROSY_HUG)
{
if (player->panim != PA_IDLE)
P_SetPlayerMobjState(mobj->target, S_PLAY_STND);
player->pflags |= PF_STASIS;
}
if (dojump)
{
P_SetMobjState(mobj, S_ROSY_JUMP);
mobj->z += P_MobjFlip(mobj);
mobj->momx = mobj->momy = 0;
P_SetObjectMomZ(mobj, 6 << FRACBITS, false);
S_StartSound(mobj, sfx_cdfm02);
}
if (makeheart)
{
mobj_t *cdlhrt = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_CDLHRT);
cdlhrt->destscale = (5*mobj->scale) >> 4;
P_SetScale(cdlhrt, cdlhrt->destscale);
cdlhrt->fuse = (5*TICRATE) >> 1;
cdlhrt->momz = mobj->scale;
P_SetTarget(&cdlhrt->target, mobj);
cdlhrt->extravalue1 = mobj->x;
cdlhrt->extravalue2 = mobj->y;
}
}
}
static void P_MobjSceneryThink(mobj_t *mobj)
{
#ifdef HAVE_BLUA
if (LUAh_MobjThinker(mobj))
return;
if (P_MobjWasRemoved(mobj))
return;
#endif
if ((mobj->flags2 & MF2_SHIELD) && !P_AddShield(mobj))
return;
switch (mobj->type)
{
case MT_BOSSJUNK:
mobj->flags2 ^= MF2_DONTDRAW;
break;
case MT_MACEPOINT:
case MT_CHAINMACEPOINT:
case MT_SPRINGBALLPOINT:
case MT_CHAINPOINT:
case MT_FIREBARPOINT:
case MT_CUSTOMMACEPOINT:
case MT_HIDDEN_SLING:
P_MaceSceneryThink(mobj);
break;
case MT_HOOP:
if (mobj->fuse > 1)
@ -7558,109 +7890,14 @@ void P_MobjThinker(mobj_t *mobj)
mobj->z = mobj->threshold - FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->scale);
break;
case MT_DROWNNUMBERS:
if (!mobj->target)
{
P_RemoveMobj(mobj);
if (!P_DrownNumbersSceneryThink(mobj))
return;
}
if (!mobj->target->player || !(mobj->target->player->powers[pw_underwater] || mobj->target->player->powers[pw_spacetime]))
{
P_RemoveMobj(mobj);
return;
}
mobj->x = mobj->target->x;
mobj->y = mobj->target->y;
mobj->destscale = mobj->target->destscale;
P_SetScale(mobj, mobj->target->scale);
if (mobj->target->eflags & MFE_VERTICALFLIP)
{
mobj->z = mobj->target->z - FixedMul(16*FRACUNIT, mobj->target->scale) - mobj->height;
if (mobj->target->player->pflags & PF_FLIPCAM)
mobj->eflags |= MFE_VERTICALFLIP;
}
else
mobj->z = mobj->target->z + (mobj->target->height) + FixedMul(8*FRACUNIT, mobj->target->scale); // Adjust height for height changes
if (mobj->threshold <= 35)
mobj->flags2 |= MF2_DONTDRAW;
else
mobj->flags2 &= ~MF2_DONTDRAW;
if (mobj->threshold <= 30)
mobj->threshold = 40;
mobj->threshold--;
break;
case MT_FLAMEJET:
if ((mobj->flags2 & MF2_FIRING) && (leveltime & 3) == 0)
{
mobj_t *flame;
fixed_t strength;
// Wave the flames back and forth. Reactiontime determines which direction it's going.
if (mobj->fuse <= -16)
mobj->reactiontime = 1;
else if (mobj->fuse >= 16)
mobj->reactiontime = 0;
if (mobj->reactiontime)
mobj->fuse += 2;
else
mobj->fuse -= 2;
flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME);
P_SetMobjState(flame, S_FLAMEJETFLAME4);
flame->angle = mobj->angle;
if (mobj->flags2 & MF2_AMBUSH) // Wave up and down instead of side-to-side
flame->momz = mobj->fuse << (FRACBITS-2);
else
flame->angle += FixedAngle(mobj->fuse*FRACUNIT);
strength = 20*FRACUNIT;
strength -= ((20*FRACUNIT)/16)*mobj->movedir;
P_InstaThrust(flame, flame->angle, strength);
S_StartSound(flame, sfx_fire);
}
P_FlameJetSceneryThink(mobj);
break;
case MT_VERTICALFLAMEJET:
if ((mobj->flags2 & MF2_FIRING) && (leveltime & 3) == 0)
{
mobj_t *flame;
fixed_t strength;
// Wave the flames back and forth. Reactiontime determines which direction it's going.
if (mobj->fuse <= -16)
mobj->reactiontime = 1;
else if (mobj->fuse >= 16)
mobj->reactiontime = 0;
if (mobj->reactiontime)
mobj->fuse++;
else
mobj->fuse--;
flame = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_FLAMEJETFLAME);
strength = 20*FRACUNIT;
strength -= ((20*FRACUNIT)/16)*mobj->movedir;
// If deaf'd, the object spawns on the ceiling.
if (mobj->flags2 & MF2_AMBUSH)
{
mobj->z = mobj->ceilingz-mobj->height;
flame->momz = -strength;
}
else
{
flame->momz = strength;
P_SetMobjState(flame, S_FLAMEJETFLAME7);
}
P_InstaThrust(flame, mobj->angle, FixedDiv(mobj->fuse*FRACUNIT,3*FRACUNIT));
S_StartSound(flame, sfx_fire);
}
P_VerticalFlameJetSceneryThink(mobj);
break;
case MT_FLICKY_01_CENTER:
case MT_FLICKY_02_CENTER:
@ -7721,273 +7958,15 @@ void P_MobjThinker(mobj_t *mobj)
}
break;
case MT_PARTICLEGEN:
if (!mobj->lastlook)
if (!P_ParticleGenSceneryThink(mobj))
return;
if (!mobj->threshold)
return;
if (--mobj->fuse <= 0)
{
INT32 i = 0;
mobj_t *spawn;
fixed_t bottomheight, topheight;
INT32 type = mobj->threshold, line = mobj->cvmem;
mobj->fuse = (tic_t)mobj->reactiontime;
bottomheight = lines[line].frontsector->floorheight;
topheight = lines[line].frontsector->ceilingheight - mobjinfo[(mobjtype_t)type].height;
if (mobj->waterbottom != bottomheight || mobj->watertop != topheight)
{
if (mobj->movefactor && (topheight > bottomheight))
mobj->health = (tic_t)(FixedDiv((topheight - bottomheight), abs(mobj->movefactor)) >> FRACBITS);
else
mobj->health = 0;
mobj->z = ((mobj->flags2 & MF2_OBJECTFLIP) ? topheight : bottomheight);
}
if (!mobj->health)
return;
for (i = 0; i < mobj->lastlook; i++)
{
spawn = P_SpawnMobj(
mobj->x + FixedMul(FixedMul(mobj->friction, mobj->scale), FINECOSINE(mobj->angle>>ANGLETOFINESHIFT)),
mobj->y + FixedMul(FixedMul(mobj->friction, mobj->scale), FINESINE(mobj->angle>>ANGLETOFINESHIFT)),
mobj->z,
(mobjtype_t)mobj->threshold);
P_SetScale(spawn, mobj->scale);
spawn->momz = FixedMul(mobj->movefactor, spawn->scale);
spawn->destscale = spawn->scale/100;
spawn->scalespeed = spawn->scale/mobj->health;
spawn->tics = (tic_t)mobj->health;
spawn->flags2 |= (mobj->flags2 & MF2_OBJECTFLIP);
spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones
mobj->angle += mobj->movedir;
}
mobj->angle += (angle_t)mobj->movecount;
}
break;
case MT_FSGNA:
if (mobj->movedir)
mobj->angle += mobj->movedir;
break;
case MT_ROSY:
{
UINT8 i;
fixed_t pdist = 1700*mobj->scale, work, actualwork;
player_t *player = NULL;
statenum_t stat = (mobj->state-states);
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (!players[i].mo)
continue;
if (players[i].bot)
continue;
if (!players[i].mo->health)
continue;
actualwork = work = FixedHypot(mobj->x-players[i].mo->x, mobj->y-players[i].mo->y);
if (player)
{
if (players[i].skin == 0 || players[i].skin == 5)
work = (2*work)/3;
if (work >= pdist)
continue;
}
pdist = actualwork;
player = &players[i];
}
if (stat == S_ROSY_JUMP || stat == S_ROSY_PAIN)
{
if (P_IsObjectOnGround(mobj))
{
mobj->momx = mobj->momy = 0;
if (player && mobj->cvmem < (-2*TICRATE))
stat = S_ROSY_UNHAPPY;
else
stat = S_ROSY_WALK;
P_SetMobjState(mobj, stat);
}
else if (P_MobjFlip(mobj)*mobj->momz < 0)
mobj->frame = mobj->state->frame+mobj->state->var1;
}
if (!player)
{
if ((stat < S_ROSY_IDLE1 || stat > S_ROSY_IDLE4) && stat != S_ROSY_JUMP)
{
mobj->momx = mobj->momy = 0;
P_SetMobjState(mobj, S_ROSY_IDLE1);
}
}
else
{
boolean dojump = false, targonground, love, makeheart = false;
if (mobj->target != player->mo)
P_SetTarget(&mobj->target, player->mo);
// Tatsuru: Don't try to hug them if they're above or below you!
targonground = (P_IsObjectOnGround(mobj->target) && (player->panim == PA_IDLE || player->panim == PA_WALK || player->panim == PA_RUN) && player->mo->z == mobj->z);
love = (player->skin == 0 || player->skin == 5);
switch (stat)
{
case S_ROSY_IDLE1:
case S_ROSY_IDLE2:
case S_ROSY_IDLE3:
case S_ROSY_IDLE4:
dojump = true;
break;
case S_ROSY_JUMP:
case S_ROSY_PAIN:
// handled above
break;
case S_ROSY_WALK:
{
fixed_t x = mobj->x, y = mobj->y, z = mobj->z;
angle_t angletoplayer = R_PointToAngle2(x, y, mobj->target->x, mobj->target->y);
boolean allowed = P_TryMove(mobj, mobj->target->x, mobj->target->y, false);
P_UnsetThingPosition(mobj);
mobj->x = x;
mobj->y = y;
mobj->z = z;
P_SetThingPosition(mobj);
if (allowed)
{
fixed_t mom, max;
P_Thrust(mobj, angletoplayer, (3*FRACUNIT)>>1);
mom = FixedHypot(mobj->momx, mobj->momy);
max = pdist;
if ((--mobj->extravalue1) <= 0)
{
if (++mobj->frame > mobj->state->frame+mobj->state->var1)
mobj->frame = mobj->state->frame;
if (mom > 12*mobj->scale)
mobj->extravalue1 = 2;
else if (mom > 6*mobj->scale)
mobj->extravalue1 = 3;
else
mobj->extravalue1 = 4;
}
if (max < (mobj->radius + mobj->target->radius))
{
mobj->momx = mobj->target->player->cmomx;
mobj->momy = mobj->target->player->cmomy;
if ((mobj->cvmem > TICRATE && !player->exiting) || !targonground)
P_SetMobjState(mobj, (stat = S_ROSY_STND));
else
{
mobj->target->momx = mobj->momx;
mobj->target->momy = mobj->momy;
P_SetMobjState(mobj, (stat = S_ROSY_HUG));
S_StartSound(mobj, sfx_cdpcm6);
mobj->angle = angletoplayer;
}
}
else
{
max /= 3;
if (max > 30*mobj->scale)
max = 30*mobj->scale;
if (mom > max && max > mobj->scale)
{
max = FixedDiv(max, mom);
mobj->momx = FixedMul(mobj->momx, max);
mobj->momy = FixedMul(mobj->momy, max);
}
if (abs(mobj->momx) > mobj->scale || abs(mobj->momy) > mobj->scale)
mobj->angle = R_PointToAngle2(0, 0, mobj->momx, mobj->momy);
}
}
else
dojump = true;
}
break;
case S_ROSY_HUG:
if (targonground)
{
player->pflags |= PF_STASIS;
if (mobj->cvmem < 5*TICRATE)
mobj->cvmem++;
if (love && !(leveltime & 7))
makeheart = true;
}
else
{
if (mobj->cvmem < (love ? 5*TICRATE : 0))
{
P_SetMobjState(mobj, (stat = S_ROSY_PAIN));
S_StartSound(mobj, sfx_cdpcm7);
}
else
P_SetMobjState(mobj, (stat = S_ROSY_JUMP));
var1 = var2 = 0;
A_DoNPCPain(mobj);
mobj->cvmem -= TICRATE;
}
break;
case S_ROSY_STND:
if ((pdist > (mobj->radius + mobj->target->radius + 3*(mobj->scale + mobj->target->scale))))
P_SetMobjState(mobj, (stat = S_ROSY_WALK));
else if (!targonground)
;
else
{
if (love && !(leveltime & 15))
makeheart = true;
if (player->exiting || --mobj->cvmem < TICRATE)
{
P_SetMobjState(mobj, (stat = S_ROSY_HUG));
S_StartSound(mobj, sfx_cdpcm6);
mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y);
mobj->target->momx = mobj->momx;
mobj->target->momy = mobj->momy;
}
}
break;
case S_ROSY_UNHAPPY:
default:
break;
}
if (stat == S_ROSY_HUG)
{
if (player->panim != PA_IDLE)
P_SetPlayerMobjState(mobj->target, S_PLAY_STND);
player->pflags |= PF_STASIS;
}
if (dojump)
{
P_SetMobjState(mobj, S_ROSY_JUMP);
mobj->z += P_MobjFlip(mobj);
mobj->momx = mobj->momy = 0;
P_SetObjectMomZ(mobj, 6<<FRACBITS, false);
S_StartSound(mobj, sfx_cdfm02);
}
if (makeheart)
{
mobj_t *cdlhrt = P_SpawnMobjFromMobj(mobj, 0, 0, mobj->height, MT_CDLHRT);
cdlhrt->destscale = (5*mobj->scale)>>4;
P_SetScale(cdlhrt, cdlhrt->destscale);
cdlhrt->fuse = (5*TICRATE)>>1;
cdlhrt->momz = mobj->scale;
P_SetTarget(&cdlhrt->target, mobj);
cdlhrt->extravalue1 = mobj->x;
cdlhrt->extravalue2 = mobj->y;
}
}
}
P_RosySceneryThink(mobj);
break;
case MT_CDLHRT:
{
@ -8037,6 +8016,69 @@ void P_MobjThinker(mobj_t *mobj)
}
P_SceneryThinker(mobj);
}
//
// P_MobjThinker
//
void P_MobjThinker(mobj_t *mobj)
{
I_Assert(mobj != NULL);
I_Assert(!P_MobjWasRemoved(mobj));
if (mobj->flags & MF_NOTHINK)
return;
if ((mobj->flags & MF_BOSS) && mobj->spawnpoint && (bossdisabled & (1<<mobj->spawnpoint->extrainfo)))
return;
// Remove dead target/tracer.
if (mobj->target && P_MobjWasRemoved(mobj->target))
P_SetTarget(&mobj->target, NULL);
if (mobj->tracer && P_MobjWasRemoved(mobj->tracer))
P_SetTarget(&mobj->tracer, NULL);
if (mobj->hnext && P_MobjWasRemoved(mobj->hnext))
P_SetTarget(&mobj->hnext, NULL);
if (mobj->hprev && P_MobjWasRemoved(mobj->hprev))
P_SetTarget(&mobj->hprev, NULL);
mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG);
tmfloorthing = tmhitthing = NULL;
// Sector special (2,8) allows ANY mobj to trigger a linedef exec
if (mobj->subsector && GETSECSPECIAL(mobj->subsector->sector->special, 2) == 8)
{
sector_t *sec2;
sec2 = P_ThingOnSpecial3DFloor(mobj);
if (sec2 && GETSECSPECIAL(sec2->special, 2) == 1)
P_LinedefExecute(sec2->tag, mobj, sec2);
}
if (mobj->scale != mobj->destscale)
P_MobjScaleThink(mobj); // Slowly scale up/down to reach your destscale.
if ((mobj->type == MT_GHOST || mobj->type == MT_THOK) && mobj->fuse > 0) // Not guaranteed to be MF_SCENERY or not MF_SCENERY!
{
if (mobj->flags2 & MF2_BOSSNOTRAP) // "fast" flag
{
if ((signed)((mobj->frame & FF_TRANSMASK) >> FF_TRANSSHIFT) < (NUMTRANSMAPS-1) - (2*mobj->fuse)/3)
// fade out when nearing the end of fuse...
mobj->frame = (mobj->frame & ~FF_TRANSMASK) | (((NUMTRANSMAPS-1) - (2*mobj->fuse)/3) << FF_TRANSSHIFT);
}
else
{
if ((signed)((mobj->frame & FF_TRANSMASK) >> FF_TRANSSHIFT) < (NUMTRANSMAPS-1) - mobj->fuse / 2)
// fade out when nearing the end of fuse...
mobj->frame = (mobj->frame & ~FF_TRANSMASK) | (((NUMTRANSMAPS-1) - mobj->fuse / 2) << FF_TRANSSHIFT);
}
}
// Special thinker for scenery objects
if (mobj->flags & MF_SCENERY)
{
P_MobjSceneryThink(mobj);
return;
}