diff --git a/src/p_mobj.c b/src/p_mobj.c index 8907ba41a..3fc1db618 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -329,10 +329,11 @@ boolean P_SetMobjStateNF(mobj_t *mobj, statenum_t state) state_t *st; if (state == S_NULL) - { // Remove mobj - P_RemoveMobj(mobj); + { + P_RemoveMobj(mobj); // Remove mobj return false; } + st = &states[state]; mobj->state = st; mobj->tics = st->tics; @@ -348,10 +349,11 @@ static boolean P_SetPrecipMobjState(precipmobj_t *mobj, statenum_t state) state_t *st; if (state == S_NULL) - { // Remove mobj - P_FreePrecipMobj(mobj); + { + P_FreePrecipMobj(mobj); // Remove mobj return false; } + st = &states[state]; mobj->state = st; mobj->tics = st->tics; @@ -369,19 +371,7 @@ static boolean P_SetPrecipMobjState(precipmobj_t *mobj, statenum_t state) // boolean P_WeaponOrPanel(mobjtype_t type) { - if (type == MT_BOUNCERING - || type == MT_AUTOMATICRING - || type == MT_INFINITYRING - || type == MT_RAILRING - || type == MT_EXPLOSIONRING - || type == MT_SCATTERRING - || type == MT_GRENADERING - || type == MT_BOUNCEPICKUP - || type == MT_RAILPICKUP - || type == MT_AUTOPICKUP - || type == MT_EXPLODEPICKUP - || type == MT_SCATTERPICKUP - || type == MT_GRENADEPICKUP) + if (type >= MT_BOUNCERING && type <= MT_GRENADEPICKUP) return true; return false; @@ -407,6 +397,7 @@ void P_ExplodeMissile(mobj_t *mo) P_RadiusAttack(mo, mo, 96*FRACUNIT); explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE); + if (explodemo) { P_SetScale(explodemo, mo->scale); @@ -415,7 +406,9 @@ void P_ExplodeMissile(mobj_t *mo) explodemo->momy += (P_RandomByte() % 32) * FixedMul(FRACUNIT/8, explodemo->scale); S_StartSound(explodemo, sfx_pop); } + explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE); + if (explodemo) { P_SetScale(explodemo, mo->scale); @@ -424,7 +417,9 @@ void P_ExplodeMissile(mobj_t *mo) explodemo->momy -= (P_RandomByte() % 64) * FixedMul(FRACUNIT/8, explodemo->scale); S_StartSound(explodemo, sfx_dmpain); } + explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE); + if (explodemo) { P_SetScale(explodemo, mo->scale); @@ -433,7 +428,9 @@ void P_ExplodeMissile(mobj_t *mo) explodemo->momy += (P_RandomByte() % 128) * FixedMul(FRACUNIT/8, explodemo->scale); S_StartSound(explodemo, sfx_pop); } + explodemo = P_SpawnMobj(mo->x, mo->y, mo->z, MT_EXPLODE); + if (explodemo) { P_SetScale(explodemo, mo->scale); @@ -474,10 +471,7 @@ boolean P_InsideANonSolidFFloor(mobj_t *mobj, ffloor_t *rover) topheight = P_GetFFloorTopZAt (rover, mobj->x, mobj->y); bottomheight = P_GetFFloorBottomZAt(rover, mobj->x, mobj->y); - if (mobj->z > topheight) - return false; - - if (mobj->z + mobj->height < bottomheight) + if (mobj->z > topheight || (mobj->z + mobj->height < bottomheight)) return false; return true; @@ -500,18 +494,8 @@ static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line, v2.x = line->v2->x; v2.y = line->v2->y; - /*CONS_Printf("BEFORE: v1 = %f %f %f\n", - FIXED_TO_FLOAT(v1.x), - FIXED_TO_FLOAT(v1.y), - FIXED_TO_FLOAT(P_GetSlopeZAt(slope, v1.x, v1.y)) - ); - CONS_Printf(" v2 = %f %f %f\n", - FIXED_TO_FLOAT(v2.x), - FIXED_TO_FLOAT(v2.y), - FIXED_TO_FLOAT(P_GetSlopeZAt(slope, v2.x, v2.y)) - );*/ - - if (abs(v1.x-x) > radius) { + if (abs(v1.x-x) > radius) + { // v1's x is out of range, so rein it in fixed_t diff = abs(v1.x-x) - radius; @@ -524,7 +508,8 @@ static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line, } } - if (abs(v1.y-y) > radius) { + if (abs(v1.y-y) > radius) + { // v1's y is out of range, so rein it in fixed_t diff = abs(v1.y-y) - radius; @@ -537,7 +522,8 @@ static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line, } } - if (abs(v2.x-x) > radius) { + if (abs(v2.x-x) > radius) + { // v1's x is out of range, so rein it in fixed_t diff = abs(v2.x-x) - radius; @@ -550,7 +536,8 @@ static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line, } } - if (abs(v2.y-y) > radius) { + if (abs(v2.y-y) > radius) + { // v2's y is out of range, so rein it in fixed_t diff = abs(v2.y-y) - radius; @@ -563,17 +550,6 @@ static fixed_t HighestOnLine(fixed_t radius, fixed_t x, fixed_t y, line_t *line, } } - /*CONS_Printf("AFTER: v1 = %f %f %f\n", - FIXED_TO_FLOAT(v1.x), - FIXED_TO_FLOAT(v1.y), - FIXED_TO_FLOAT(P_GetSlopeZAt(slope, v1.x, v1.y)) - ); - CONS_Printf(" v2 = %f %f %f\n", - FIXED_TO_FLOAT(v2.x), - FIXED_TO_FLOAT(v2.y), - FIXED_TO_FLOAT(P_GetSlopeZAt(slope, v2.x, v2.y)) - );*/ - // Return the higher of the two points if (actuallylowest) return min( @@ -635,6 +611,7 @@ fixed_t P_MobjFloorZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed_t bbox[BOXRIGHT] = x+mobj->radius; bbox[BOXTOP] = y+mobj->radius; bbox[BOXBOTTOM] = y-mobj->radius; + for (i = 0; i < boundsec->linecount; i++) { ld = boundsec->lines[i]; @@ -714,6 +691,7 @@ fixed_t P_MobjCeilingZ(mobj_t *mobj, sector_t *sector, sector_t *boundsec, fixed bbox[BOXRIGHT] = x+mobj->radius; bbox[BOXTOP] = y+mobj->radius; bbox[BOXBOTTOM] = y-mobj->radius; + for (i = 0; i < boundsec->linecount; i++) { ld = boundsec->lines[i]; @@ -794,6 +772,7 @@ fixed_t P_CameraFloorZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, fix bbox[BOXRIGHT] = x+mobj->radius; bbox[BOXTOP] = y+mobj->radius; bbox[BOXBOTTOM] = y-mobj->radius; + for (i = 0; i < boundsec->linecount; i++) { ld = boundsec->lines[i]; @@ -873,6 +852,7 @@ fixed_t P_CameraCeilingZ(camera_t *mobj, sector_t *sector, sector_t *boundsec, f bbox[BOXRIGHT] = x+mobj->radius; bbox[BOXTOP] = y+mobj->radius; bbox[BOXBOTTOM] = y-mobj->radius; + for (i = 0; i < boundsec->linecount; i++) { ld = boundsec->lines[i]; @@ -1176,6 +1156,7 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy) I_Assert(!P_MobjWasRemoved(mo)); player = mo->player; + if (player) // valid only if player avatar { // spinning friction @@ -1250,18 +1231,19 @@ static void P_PushableCheckBustables(mobj_t *mo) for (rover = node->m_sector->ffloors; rover; rover = rover->next) { - if (!(rover->flags & FF_EXISTS)) continue; - - if (!(rover->flags & FF_BUSTUP)) continue; + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_BUSTUP)) + continue; // Needs ML_EFFECT4 flag for pushables to break it - if (!(rover->master->flags & ML_EFFECT4)) continue; + if (!(rover->master->flags & ML_EFFECT4)) + continue; if (rover->master->frontsector->crumblestate) continue; topheight = P_GetFOFTopZ(mo, node->m_sector, rover, mo->x, mo->y, NULL); bottomheight = P_GetFOFBottomZ(mo, node->m_sector, rover, mo->x, mo->y, NULL); + // Height checks if (rover->flags & FF_SHATTERBOTTOM) { @@ -1305,6 +1287,7 @@ static void P_PushableCheckBustables(mobj_t *mo) goto bustupdone; } } + bustupdone: P_UnsetThingPosition(mo); mo->x = oldx; @@ -1423,10 +1406,11 @@ void P_XYMovement(mobj_t *mo) // blocked move moved = false; - if (player) { - if (player->bot) - B_MoveBlocked(player); + if (player && player->bot) + { + B_MoveBlocked(player); } + //{ SRB2kart - Jawz if (mo->type == MT_JAWZ || mo->type == MT_JAWZ_DUD) { @@ -1521,8 +1505,8 @@ void P_XYMovement(mobj_t *mo) return; } } - else if (player || mo->flags & (MF_SLIDEME|MF_PUSHABLE)) - { // try to slide along it + else if (player || mo->flags & (MF_SLIDEME|MF_PUSHABLE)) // try to slide along it + { P_SlideMove(mo, false); xmove = ymove = 0; } @@ -1580,9 +1564,10 @@ void P_XYMovement(mobj_t *mo) if (P_MobjWasRemoved(mo)) // MF_SPECIAL touched a player! O_o;; return; - if (moved && oldslope) { // Check to see if we ran off - - if (oldslope != mo->standingslope) { // First, compare different slopes + if (moved && oldslope) // Check to see if we ran off + { + if (oldslope != mo->standingslope) // First, compare different slopes + { angle_t oldangle, newangle; angle_t moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); @@ -1594,37 +1579,28 @@ void P_XYMovement(mobj_t *mo) newangle = 0; // Now compare the Zs of the different quantizations - if (oldangle-newangle > ANG30 && oldangle-newangle < ANGLE_180) { // Allow for a bit of sticking - this value can be adjusted later + if (oldangle-newangle > ANG30 && oldangle-newangle < ANGLE_180) // Allow for a bit of sticking - this value can be adjusted later + { mo->standingslope = oldslope; P_SlopeLaunch(mo); - - //CONS_Printf("launched off of slope - "); } - - /*CONS_Printf("old angle %f - new angle %f = %f\n", - FIXED_TO_FLOAT(AngleFixed(oldangle)), - FIXED_TO_FLOAT(AngleFixed(newangle)), - FIXED_TO_FLOAT(AngleFixed(oldangle-newangle)) - );*/ - // Sryder 2018-11-26: Don't launch here if it's a slope without physics, we stick to those like glue anyway - } else if (predictedz-mo->z > abs(slopemom.z/2) - && !(mo->standingslope->flags & SL_NOPHYSICS)) { // Now check if we were supposed to stick to this slope - //CONS_Printf("%d-%d > %d\n", (predictedz), (mo->z), (slopemom.z/2)); + } + else if (predictedz-mo->z > abs(slopemom.z/2) // Sryder 2018-11-26: Don't launch here if it's a slope without physics, we stick to those like glue anyway + && !(mo->standingslope->flags & SL_NOPHYSICS)) // Now check if we were supposed to stick to this slope + { P_SlopeLaunch(mo); } - } else if (moved && mo->standingslope && predictedz) { + } + else if (moved && mo->standingslope && predictedz) + { angle_t moveangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); angle_t newangle = FixedMul((signed)mo->standingslope->zangle, FINECOSINE((moveangle - mo->standingslope->xydirection) >> ANGLETOFINESHIFT)); - /*CONS_Printf("flat to angle %f - predicted z of %f\n", - FIXED_TO_FLOAT(AngleFixed(ANGLE_MAX-newangle)), - FIXED_TO_FLOAT(predictedz) - );*/ - if (ANGLE_MAX-newangle > ANG30 && newangle > ANGLE_180) { + if (ANGLE_MAX-newangle > ANG30 && newangle > ANGLE_180) + { mo->momz = P_MobjFlip(mo)*FRACUNIT/2; mo->z = predictedz + P_MobjFlip(mo); mo->standingslope = NULL; - //CONS_Printf("Launched off of flat surface running into downward slope\n"); } } @@ -1638,6 +1614,7 @@ void P_XYMovement(mobj_t *mo) P_UnsetThingPosition(mo); player->angle_pos = player->old_angle_pos; player->speed = FixedMul(player->speed, 4*FRACUNIT/5); + if (player->flyangle >= 0 && player->flyangle < 90) player->flyangle = 135; else if (player->flyangle >= 90 && player->flyangle < 180) @@ -1646,6 +1623,7 @@ void P_XYMovement(mobj_t *mo) player->flyangle = 315; else player->flyangle = 225; + player->flyangle %= 360; if (player->pflags & PF_TRANSFERTOCLOSEST) @@ -3012,6 +2990,7 @@ void P_MobjCheckWater(mobj_t *mobj) { // Spawn a splash mobj_t *splish; + if (mobj->eflags & MFE_VERTICALFLIP) { splish = P_SpawnMobj(mobj->x, mobj->y, mobj->waterbottom-FixedMul(mobjinfo[MT_SPLISH].height, mobj->scale), MT_SPLISH); @@ -3020,6 +2999,7 @@ void P_MobjCheckWater(mobj_t *mobj) } else splish = P_SpawnMobj(mobj->x, mobj->y, mobj->watertop, MT_SPLISH); + splish->destscale = mobj->scale; P_SetScale(splish, mobj->scale); } @@ -3210,6 +3190,7 @@ void P_DestroyRobots(void) continue; // not a mobj thinker mo = (mobj_t *)think; + if (mo->health <= 0 || !(mo->flags & MF_ENEMY || mo->flags & MF_BOSS)) continue; // not a valid enemy @@ -3946,6 +3927,7 @@ static void P_Boss3Thinker(mobj_t *mobj) P_SetMobjState(mobj, mobj->info->spawnstate); mobj->reactiontime--; + if (!mobj->reactiontime) { ffloor_t *rover; @@ -3956,10 +3938,7 @@ static void P_Boss3Thinker(mobj_t *mobj) if (!playeringame[i] || players[i].spectator) continue; - if (!players[i].mo) - continue; - - if (players[i].mo->health <= 0) + if (!players[i].mo || (players[i].mo->health <= 0)) continue; if (players[i].mo->eflags & MFE_UNDERWATER) @@ -3974,10 +3953,7 @@ static void P_Boss3Thinker(mobj_t *mobj) for (rover = sectors[i].ffloors; rover; rover = rover->next) { - if (!(rover->flags & FF_EXISTS)) - continue; - - if (!(rover->flags & FF_SWIMMABLE)) + if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_SWIMMABLE)) continue; P_SpawnLightningFlash(rover->master->frontsector); @@ -4005,15 +3981,16 @@ static void P_Boss3Thinker(mobj_t *mobj) continue; if (players[i].mo->eflags & MFE_UNDERWATER) - { // Stay put - mobj->reactiontime = 2*TICRATE; + { + mobj->reactiontime = 2*TICRATE; // Stay put return; } } } + // Spawn pinch dummies from the center when we're leaving it. 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; @@ -4030,11 +4007,13 @@ 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 break; } @@ -4122,16 +4101,10 @@ static void P_Boss3Thinker(mobj_t *mobj) mo2 = (mobj_t *)th; - if (!mo2) + if (!mo2 || mo2->type != MT_BOSS3WAYPOINT) continue; - if (mo2->type != MT_BOSS3WAYPOINT) - continue; - - if (!mo2->spawnpoint) - continue; - - if (mo2->spawnpoint->angle != mobj->threshold) + if (!mo2->spawnpoint || mo2->spawnpoint->angle != mobj->threshold) continue; P_SetTarget(&mobj->target, mo2); @@ -4149,7 +4122,7 @@ static void P_Boss3Thinker(mobj_t *mobj) if (dist < 1) dist = 1; - if ((mobj->movedir) || (mobj->health <= mobj->info->damage)) + if (mobj->movedir || (mobj->health <= mobj->info->damage)) speed = mobj->info->speed * 2; else speed = mobj->info->speed; @@ -4738,10 +4711,7 @@ static void P_Boss7Thinker(mobj_t *mobj) if (!playeringame[i] || players[i].spectator) continue; - if (!players[i].mo) - continue; - - if (players[i].mo->health <= 0) + if (!players[i].mo || (players[i].mo->health <= 0)) continue; if (players[i].powers[pw_ingoop]) @@ -4812,9 +4782,7 @@ static void P_Boss7Thinker(mobj_t *mobj) mo2 = (mobj_t *)th; - if (mo2->type != MT_BOSS3WAYPOINT) - continue; - if (!mo2->spawnpoint) + if (mo2->type != MT_BOSS3WAYPOINT || !mo2->spawnpoint) continue; if ((mo2->spawnpoint->options & 7) == waypointNum) @@ -4883,19 +4851,14 @@ static void P_Boss7Thinker(mobj_t *mobj) if (!playeringame[i] || players[i].spectator) continue; - if (!players[i].mo) - continue; - - if (players[i].mo->health <= 0) + if (!players[i].mo || (players[i].mo->health <= 0)) continue; if (P_AproxDistance(players[i].mo->x - mobj->x, players[i].mo->y - mobj->y) > mobj->radius*4) continue; - if (players[i].mo->z > mobj->z + 128*FRACUNIT) - continue; - - if (players[i].mo->z < mobj->z - 64*FRACUNIT) + if ((players[i].mo->z > mobj->z + 128*FRACUNIT) + || (players[i].mo->z < mobj->z - 64*FRACUNIT)) continue; P_DamageMobj(players[i].mo, mobj, mobj, 1); @@ -4940,15 +4903,17 @@ static void P_Boss9Thinker(mobj_t *mobj) continue; mo2 = (mobj_t *)th; - if (mo2->type == MT_BOSS9GATHERPOINT) - { - if (last) - P_SetTarget(&last->hnext, mo2); - else - P_SetTarget(&mobj->hnext, mo2); - P_SetTarget(&mo2->hprev, last); - last = mo2; - } + + if (mo2->type != MT_BOSS9GATHERPOINT) + continue; + + if (last) + P_SetTarget(&last->hnext, mo2); + else + P_SetTarget(&mobj->hnext, mo2); + + P_SetTarget(&mo2->hprev, last); + last = mo2; } } @@ -4960,6 +4925,7 @@ static void P_Boss9Thinker(mobj_t *mobj) P_BossTargetPlayer(mobj, false); if (mobj->target && (!P_IsObjectOnGround(mobj->target) || mobj->target->player->pflags & PF_SPINNING)) P_SetTarget(&mobj->target, NULL); // Wait for them to hit the ground first + if (!mobj->target) // Still no target, aww. { // Reset the boss. @@ -5004,6 +4970,7 @@ static void P_Boss9Thinker(mobj_t *mobj) P_BossTargetPlayer(mobj, true); angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); // absolute angle angle = (angle-mobj->angle); // relative angle + if (angle < ANGLE_180) mobj->angle += angle/8; else @@ -5016,6 +4983,7 @@ static void P_Boss9Thinker(mobj_t *mobj) if (P_RandomRange(1,(dist>>FRACBITS)/16) == 1) break; } + if (spawner && dist) { mobj_t *missile = P_SpawnMissile(spawner, mobj, MT_MSGATHER); @@ -5155,11 +5123,8 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->momx = mobj->momy = 0; mobj->threshold--; if (!mobj->threshold) - { // Go into stun after dodge. - // from 3*TICRATE down to 1.25*TICRATE - //mobj->reactiontime = 5*TICRATE/4 + (FixedMul((7*TICRATE/4)<health-1)<info->spawnhealth-1)<>FRACBITS); - // from 3*TICRATE down to 2*TICRATE - mobj->reactiontime = 2*TICRATE + (FixedMul((1*TICRATE)<health-1)<info->spawnhealth-1)<>FRACBITS); + { + mobj->reactiontime = 2*TICRATE + (FixedMul((1*TICRATE)<health-1)<info->spawnhealth-1)<>FRACBITS); // Go into stun after dodge. mobj->flags |= MF_SPECIAL|MF_SHOOTABLE; P_SetMobjState(mobj, mobj->state->nextstate); } @@ -5182,10 +5147,12 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->angle -= FixedAngle(FixedMul(AngleFixed(InvAngle(mobj->movedir)),FixedDiv(mobj->reactiontime<angle += FixedAngle(FixedMul(AngleFixed(mobj->movedir),FixedDiv(mobj->reactiontime<reactiontime--; - if (!mobj->reactiontime) - // Out of stun. + + if (!mobj->reactiontime) // Out of stun. P_SetMobjState(mobj, mobj->state->nextstate); + return; } @@ -5335,7 +5302,6 @@ static void P_Boss9Thinker(mobj_t *mobj) mobj->angle += angle/8; else mobj->angle -= InvAngle(angle)/8; - //A_FaceTarget(mobj); // Check if we're being attacked if (!(mobj->target->player->pflags & (PF_JUMPED|PF_SPINNING) @@ -6059,874 +6025,784 @@ angle_t P_MobjPitchAndRoll(mobj_t *mobj) return return_angle; } -// -// P_MobjThinker -// -void P_MobjThinker(mobj_t *mobj) +static void P_MobjScaleThink(mobj_t *mobj) { - I_Assert(mobj != NULL); - I_Assert(!P_MobjWasRemoved(mobj)); + fixed_t oldheight = mobj->height; + UINT8 correctionType = 0; // Don't correct Z position, just gain height - if (UNLIKELY(mobj->flags & MF_NOTHINK)) + if (mobj->z > mobj->floorz && mobj->z + mobj->height < mobj->ceilingz + && mobj->type != MT_EGGMOBILE_FIRE) + correctionType = 1; // Correct Z position by centering + else if (mobj->eflags & MFE_VERTICALFLIP) + correctionType = 2; // Correct Z position by moving down + + if (abs(mobj->scale - mobj->destscale) < mobj->scalespeed) + P_SetScale(mobj, mobj->destscale); + else if (mobj->scale < mobj->destscale) + P_SetScale(mobj, mobj->scale + mobj->scalespeed); + else if (mobj->scale > mobj->destscale) + P_SetScale(mobj, mobj->scale - mobj->scalespeed); + + if (correctionType == 1) + mobj->z -= (mobj->height - oldheight)/2; + else if (correctionType == 2) + mobj->z -= mobj->height - oldheight; + + if (mobj->scale == mobj->destscale && mobj->type == MT_EGGMOBILE_FIRE) + { + /// \todo Lua hook for "reached destscale"? + mobj->destscale = FRACUNIT; + mobj->scalespeed = FRACUNIT>>4; + } +} + +// Special thinker for scenery objects +// this does not need to return anything +static void P_MobjSceneryThink(mobj_t *mobj) +{ + if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjThinker))) 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); - // hnext/hprev changes suggested by toaster - if (mobj->hnext && P_MobjWasRemoved(mobj->hnext)) - P_SetTarget(&mobj->hnext, NULL); - if (mobj->hprev && P_MobjWasRemoved(mobj->hprev)) - P_SetTarget(&mobj->hprev, NULL); + if (P_MobjWasRemoved(mobj)) + return; - mobj->flags2 &= ~MF2_PUSHED; - mobj->eflags &= ~(MFE_SPRUNG|MFE_JUSTBOUNCEDWALL); - - tmfloorthing = tmhitthing = NULL; - - const sector_t *sec1 = mobj->subsector ? mobj->subsector->sector : NULL; - - // 970 allows ANY mobj to trigger a linedef exec - if (UNLIKELY(!mobj->islocal && sec1 && GETSECSPECIAL(sec1->special, 2) == 8)) // BEWARE: islocal does not exist in vanilla + switch (mobj->type) { - sector_t *sec2; - sec2 = P_ThingOnSpecial3DFloor(mobj); - if (sec2 && GETSECSPECIAL(sec2->special, 2) == 1) - P_LinedefExecute(sec2->tag, mobj, sec2); - } + case MT_HOOP: + if (mobj->fuse > 1) + P_MoveHoop(mobj); + else if (mobj->fuse == 1) + mobj->movecount = 1; - // Slowly scale up/down to reach your destscale. - if (mobj->scale != mobj->destscale) - { - fixed_t oldheight = mobj->height; - UINT8 correctionType = 0; // Don't correct Z position, just gain height - - if (mobj->z > mobj->floorz && mobj->z + mobj->height < mobj->ceilingz - && mobj->type != MT_EGGMOBILE_FIRE) - correctionType = 1; // Correct Z position by centering - else if (mobj->eflags & MFE_VERTICALFLIP) - correctionType = 2; // Correct Z position by moving down - - if (abs(mobj->scale - mobj->destscale) < mobj->scalespeed) - P_SetScale(mobj, mobj->destscale); - else if (mobj->scale < mobj->destscale) - P_SetScale(mobj, mobj->scale + mobj->scalespeed); - else if (mobj->scale > mobj->destscale) - P_SetScale(mobj, mobj->scale - mobj->scalespeed); - - if (correctionType == 1) - mobj->z -= (mobj->height - oldheight)/2; - else if (correctionType == 2) - mobj->z -= mobj->height - oldheight; - - if (mobj->scale == mobj->destscale) - /// \todo Lua hook for "reached destscale"? - switch(mobj->type) + if (mobj->movecount) { - case MT_EGGMOBILE_FIRE: - mobj->destscale = FRACUNIT; - mobj->scalespeed = FRACUNIT>>4; - break; - default: - break; + mobj->fuse++; + + if (mobj->fuse > 32) + { + // Don't kill the hoop center. For the sake of respawning. + //if (mobj->target) + // P_RemoveMobj(mobj->target); + + P_RemoveMobj(mobj); + } } - } - - if (mobj->type == MT_GHOST && mobj->fuse > 0 // Not guaranteed to be MF_SCENERY or not MF_SCENERY! - && (signed)(mobj->frame >> 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) - { - if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjThinker))) + else + mobj->fuse--; return; + case MT_NIGHTSPARKLE: + if (mobj->tics != -1) + { + mobj->tics--; - if (P_MobjWasRemoved(mobj)) + // you can cycle through multiple states in a tic + if (!mobj->tics) + if (!P_SetMobjState(mobj, mobj->state->nextstate)) + return; // freed itself + } + + P_UnsetThingPosition(mobj); + mobj->x += mobj->momx; + mobj->y += mobj->momy; + mobj->z += mobj->momz; + P_SetThingPosition(mobj); return; + case MT_NIGHTSLOOPHELPER: + if (--mobj->tics <= 0) + P_RemoveMobj(mobj); - switch (mobj->type) - { - case MT_HOOP: - if (mobj->fuse > 1) - P_MoveHoop(mobj); - else if (mobj->fuse == 1) - mobj->movecount = 1; - - if (mobj->movecount) - { - mobj->fuse++; - - if (mobj->fuse > 32) - { - // Don't kill the hoop center. For the sake of respawning. - //if (mobj->target) - // P_RemoveMobj(mobj->target); - - P_RemoveMobj(mobj); - } - } - else - mobj->fuse--; + // Don't touch my fuse! + return; + case MT_OVERLAY: + if (!mobj->target) + { + P_RemoveMobj(mobj); return; - case MT_NIGHTSPARKLE: - if (mobj->tics != -1) - { - mobj->tics--; + } - // you can cycle through multiple states in a tic - if (!mobj->tics) - if (!P_SetMobjState(mobj, mobj->state->nextstate)) - return; // freed itself - } + if (mobj->state == &states[S_PLAY_SIGN]) // hack to make the player sign icon roll with the sign itself + { + mobj->slopepitch = mobj->target->slopepitch; + mobj->sloperoll = mobj->target->sloperoll; + } - P_UnsetThingPosition(mobj); - mobj->x += mobj->momx; - mobj->y += mobj->momy; - mobj->z += mobj->momz; - P_SetThingPosition(mobj); + P_AddOverlay(mobj); + break; + case MT_SHADOW: + if (!mobj->target) + { + P_RemoveMobj(mobj); return; - case MT_NIGHTSLOOPHELPER: - if (--mobj->tics <= 0) - P_RemoveMobj(mobj); + } - // Don't touch my fuse! + K_RollMobjBySlopes(mobj, mobj->target->standingslope); + + P_AddShadow(mobj); + break; + //{ SRB2kart mobs + case MT_ORBINAUT_SHIELD: // Kart orbit/trail items + case MT_JAWZ_SHIELD: + case MT_BANANA_SHIELD: + case MT_SSMINE_SHIELD: + case MT_EGGMANITEM_SHIELD: + case MT_SINK_SHIELD: + if ((mobj->health > 0 + && (!mobj->target || !mobj->target->player || mobj->target->player->health <= 0 || mobj->target->player->spectator)) + || (mobj->health <= 0 && P_IsObjectOnGround(mobj)) + || P_CheckDeathPitCollide(mobj)) // When in death state + { + P_RemoveMobj(mobj); return; - case MT_OVERLAY: - if (!mobj->target) - { - P_RemoveMobj(mobj); - return; - } + } - if (mobj->state == &states[S_PLAY_SIGN]) // hack to make the player sign icon roll with the sign itself - { - mobj->slopepitch = mobj->target->slopepitch; - mobj->sloperoll = mobj->target->sloperoll; - } - - P_AddOverlay(mobj); - break; - case MT_SHADOW: - if (!mobj->target) - { - P_RemoveMobj(mobj); - return; - } - - K_RollMobjBySlopes(mobj, mobj->target->standingslope); - - P_AddShadow(mobj); - break; - //{ SRB2kart mobs - case MT_ORBINAUT_SHIELD: // Kart orbit/trail items - case MT_JAWZ_SHIELD: - case MT_BANANA_SHIELD: - case MT_SSMINE_SHIELD: - case MT_EGGMANITEM_SHIELD: - case MT_SINK_SHIELD: - if ((mobj->health > 0 - && (!mobj->target || !mobj->target->player || mobj->target->player->health <= 0 || mobj->target->player->spectator)) - || (mobj->health <= 0 && P_IsObjectOnGround(mobj)) - || P_CheckDeathPitCollide(mobj)) // When in death state - { - P_RemoveMobj(mobj); - return; - } - - P_RollPitchMobj(mobj); - break; - case MT_SMOLDERING: + P_RollPitchMobj(mobj); + break; + case MT_SMOLDERING: + if (leveltime % 2 == 0) + { + fixed_t x = P_RandomRange(-35, 35)*mobj->scale; + fixed_t y = P_RandomRange(-35, 35)*mobj->scale; + fixed_t z = P_RandomRange(0, 70)*mobj->scale; + mobj_t *smoke = P_SpawnMobj(mobj->x + x, mobj->y + y, mobj->z + z, MT_SMOKE); + P_SetMobjState(smoke, S_OPAQUESMOKE1); + K_MatchGenericExtraFlags(smoke, mobj); + smoke->scale = mobj->scale * 2; + smoke->destscale = mobj->scale * 6; + smoke->momz = P_RandomRange(4, 9)*FRACUNIT*P_MobjFlip(smoke); + } + break; + case MT_BOOMPARTICLE: + { + fixed_t x = P_RandomRange(-16, 16)*mobj->scale; + fixed_t y = P_RandomRange(-16, 16)*mobj->scale; + fixed_t z = P_RandomRange(0, 32)*mobj->scale*P_MobjFlip(mobj); if (leveltime % 2 == 0) { - fixed_t x = P_RandomRange(-35, 35)*mobj->scale; - fixed_t y = P_RandomRange(-35, 35)*mobj->scale; - fixed_t z = P_RandomRange(0, 70)*mobj->scale; + mobj_t *smoke = P_SpawnMobj(mobj->x + x, mobj->y + y, mobj->z + z, MT_BOSSEXPLODE); + K_MatchGenericExtraFlags(smoke, mobj); + P_SetMobjState(smoke, S_QUICKBOOM1); + smoke->scale = mobj->scale/2; + smoke->destscale = mobj->scale; + smoke->color = mobj->color; + } + else + { mobj_t *smoke = P_SpawnMobj(mobj->x + x, mobj->y + y, mobj->z + z, MT_SMOKE); P_SetMobjState(smoke, S_OPAQUESMOKE1); K_MatchGenericExtraFlags(smoke, mobj); - smoke->scale = mobj->scale * 2; - smoke->destscale = mobj->scale * 6; - smoke->momz = P_RandomRange(4, 9)*FRACUNIT*P_MobjFlip(smoke); + smoke->scale = mobj->scale; + smoke->destscale = mobj->scale*2; } - break; - case MT_BOOMPARTICLE: + if (mobj->tics <= TICRATE) { - fixed_t x = P_RandomRange(-16, 16)*mobj->scale; - fixed_t y = P_RandomRange(-16, 16)*mobj->scale; - fixed_t z = P_RandomRange(0, 32)*mobj->scale*P_MobjFlip(mobj); - if (leveltime % 2 == 0) - { - mobj_t *smoke = P_SpawnMobj(mobj->x + x, mobj->y + y, mobj->z + z, MT_BOSSEXPLODE); - K_MatchGenericExtraFlags(smoke, mobj); - P_SetMobjState(smoke, S_QUICKBOOM1); - smoke->scale = mobj->scale/2; - smoke->destscale = mobj->scale; - smoke->color = mobj->color; - } - else - { - mobj_t *smoke = P_SpawnMobj(mobj->x + x, mobj->y + y, mobj->z + z, MT_SMOKE); - P_SetMobjState(smoke, S_OPAQUESMOKE1); - K_MatchGenericExtraFlags(smoke, mobj); - smoke->scale = mobj->scale; - smoke->destscale = mobj->scale*2; - } - if (mobj->tics <= TICRATE) - { - mobj->destscale = FixedDiv(mobj->scale, 100*FRACUNIT); - } + mobj->destscale = FixedDiv(mobj->scale, 100*FRACUNIT); } - break; - case MT_BATTLEBUMPER: - if (mobj->health > 0 && mobj->target && mobj->target->player - && mobj->target->player->health > 0 && !mobj->target->player->spectator) - { - fixed_t rad = 32*mobj->target->scale; - fixed_t offz; - angle_t ang, diff; + } + break; + case MT_BATTLEBUMPER: + if (mobj->health > 0 && mobj->target && mobj->target->player + && mobj->target->player->health > 0 && !mobj->target->player->spectator) + { + fixed_t rad = 32*mobj->target->scale; + fixed_t offz; + angle_t ang, diff; - if (!((mobj->target->player-players) & 1)) - ang = (FixedAngle(mobj->info->speed) * -1); - else - ang = FixedAngle(mobj->info->speed); + if (!((mobj->target->player-players) & 1)) + ang = (FixedAngle(mobj->info->speed) * -1); + else + ang = FixedAngle(mobj->info->speed); - if (mobj->target->player->kartstuff[k_bumper] <= 1) - diff = 0; - else - diff = FixedAngle(360*FRACUNIT/mobj->target->player->kartstuff[k_bumper]); + if (mobj->target->player->kartstuff[k_bumper] <= 1) + diff = 0; + else + diff = FixedAngle(360*FRACUNIT/mobj->target->player->kartstuff[k_bumper]); - ang = (ang*leveltime) + (diff * (mobj->threshold-1)); - - // If the player is on the ceiling, then flip your items as well. - if (mobj->target->eflags & MFE_VERTICALFLIP) - { - mobj->eflags |= MFE_VERTICALFLIP; - offz = mobj->target->height / 2; - } - else - { - mobj->eflags &= ~MFE_VERTICALFLIP; - offz = mobj->target->height / 5; - } - - if (mobj->target->eflags & MFE_DRAWONLYFORP1) // groooooaann... - mobj->eflags |= MFE_DRAWONLYFORP1; - else - mobj->eflags &= ~MFE_DRAWONLYFORP1; - - if (mobj->target->eflags & MFE_DRAWONLYFORP2) - mobj->eflags |= MFE_DRAWONLYFORP2; - else - mobj->eflags &= ~MFE_DRAWONLYFORP2; - - if (mobj->target->eflags & MFE_DRAWONLYFORP3) - mobj->eflags |= MFE_DRAWONLYFORP3; - else - mobj->eflags &= ~MFE_DRAWONLYFORP3; - - if (mobj->target->eflags & MFE_DRAWONLYFORP4) - mobj->eflags |= MFE_DRAWONLYFORP4; - else - mobj->eflags &= ~MFE_DRAWONLYFORP4; - - if (mobj->target->flags2 & MF2_DONTDRAW) - mobj->flags2 |= MF2_DONTDRAW; - else - mobj->flags2 &= ~MF2_DONTDRAW; - - if (mobj->target->eflags & MFE_VERTICALFLIP) - offz += 4*FRACUNIT; - else - offz -= 4*FRACUNIT; - - if (mobj->tracer && mobj->tracer->player && mobj->tracer->player->mo - && mobj->tracer->player->health > 0 && !mobj->tracer->player->spectator) // STOLEN - mobj->color = mobj->tracer->player->skincolor; // don't do star flashing for stolen bumpers - else - mobj->color = mobj->target->color; // but do so if it belongs to you :B - - if (mobj->target->player->kartstuff[k_bumper] < 2) - P_SetMobjState(mobj, S_BATTLEBUMPER3); - else if (mobj->target->player->kartstuff[k_bumper] < 3) - P_SetMobjState(mobj, S_BATTLEBUMPER2); - else - P_SetMobjState(mobj, S_BATTLEBUMPER1); - - // Shrink your items if the player shrunk too. - mobj->scale = mobj->target->scale; - - P_UnsetThingPosition(mobj); - { - const angle_t fa = ang>>ANGLETOFINESHIFT; - mobj->x = mobj->target->x + FixedMul(FINECOSINE(fa), rad); - mobj->y = mobj->target->y + FixedMul(FINESINE(fa), rad); - mobj->z = mobj->target->z + offz; - P_SetThingPosition(mobj); - } - - // Was this so hard? - if (mobj->target->player->kartstuff[k_bumper] <= mobj->threshold) - { - P_RemoveMobj(mobj); - return; - } - } - else if ((mobj->health > 0 - && (!mobj->target || !mobj->target->player || !mobj->target->player->mo || mobj->target->player->health <= 0 || mobj->target->player->spectator)) - || (mobj->health <= 0 && P_IsObjectOnGround(mobj)) - || P_CheckDeathPitCollide(mobj)) // When in death state - { - P_RemoveMobj(mobj); - return; - } - break; - case MT_PLAYERARROW: - if (mobj->target && mobj->target->health - && mobj->target->player && !mobj->target->player->spectator - && mobj->target->player->health && mobj->target->player->playerstate != PST_DEAD - /*&& players[displayplayers[0]].mo && !players[displayplayers[0]].spectator*/) - { - fixed_t scale = 3*mobj->target->scale; - mobj->color = mobj->target->color; - K_MatchGenericExtraFlags(mobj, mobj->target); - - if ((G_RaceGametype() || mobj->target->player->kartstuff[k_bumper] <= 0) -#if 1 // Set to 0 to test without needing to host - || ((mobj->target->player == &players[displayplayers[0]]) || P_IsLocalPlayer(mobj->target->player)) -#endif - ) - mobj->flags2 |= MF2_DONTDRAW; - - P_UnsetThingPosition(mobj); - mobj->x = mobj->target->x; - mobj->y = mobj->target->y; - - mobj->angle = R_PointToAngle(mobj->x, mobj->y) + ANGLE_90; // literally only happened because i wanted to ^L^R the SPR_ITEM's - - if (!splitscreen && players[displayplayers[0]].mo) - { - scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayers[0]].mo->x-mobj->target->x, - players[displayplayers[0]].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); - if (scale > 16*mobj->target->scale) - scale = 16*mobj->target->scale; - } - mobj->destscale = scale; - - if (!(mobj->target->eflags & MFE_VERTICALFLIP)) - { - mobj->z = mobj->target->z + P_GetPlayerHeight(mobj->target->player) + (16*mobj->target->scale); - mobj->eflags &= ~MFE_VERTICALFLIP; - } - else - { - mobj->z = mobj->target->z - P_GetPlayerHeight(mobj->target->player) - (16*mobj->target->scale); - mobj->eflags |= MFE_VERTICALFLIP; - } - P_SetThingPosition(mobj); - - if (!mobj->tracer) - { - mobj_t *overlay = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); - P_SetTarget(&mobj->tracer, overlay); - P_SetTarget(&mobj->tracer->target, mobj); - P_SetMobjState(mobj->tracer, S_PLAYERARROW_ITEM); - P_SetScale(mobj->tracer, (mobj->tracer->destscale = mobj->scale)); - } - - // Do this in an easy way - if (mobj->target->player->kartstuff[k_itemroulette]) - { - mobj->tracer->color = mobj->target->player->skincolor; - mobj->tracer->colorized = true; - } - else - { - mobj->tracer->color = SKINCOLOR_NONE; - mobj->tracer->colorized = false; - } - - if (!(mobj->flags2 & MF2_DONTDRAW)) - { - const INT32 numberdisplaymin = ((mobj->target->player->kartstuff[k_itemtype] == KITEM_ORBINAUT) ? 5 : 2); - - // Set it to use the correct states for its condition - if (mobj->target->player->kartstuff[k_itemroulette]) - { - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|(((mobj->target->player->kartstuff[k_itemroulette] % (13*3)) / 3) + 1); - mobj->tracer->flags2 &= ~MF2_DONTDRAW; - } - else if (mobj->target->player->kartstuff[k_stolentimer] > 0) - { - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|KITEM_HYUDORO; - if (leveltime & 2) - mobj->tracer->flags2 &= ~MF2_DONTDRAW; - else - mobj->tracer->flags2 |= MF2_DONTDRAW; - } - else if ((mobj->target->player->kartstuff[k_stealingtimer] > 0) && (leveltime & 2)) - { - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|KITEM_HYUDORO; - mobj->tracer->flags2 &= ~MF2_DONTDRAW; - } - else if (mobj->target->player->kartstuff[k_eggmanexplode] > 1) - { - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|KITEM_EGGMAN; - if (leveltime & 1) - mobj->tracer->flags2 &= ~MF2_DONTDRAW; - else - mobj->tracer->flags2 |= MF2_DONTDRAW; - } - else if (mobj->target->player->kartstuff[k_rocketsneakertimer] > 1) - { - //itembar = mobj->target->player->kartstuff[k_rocketsneakertimer]; -- not today satan - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|KITEM_ROCKETSNEAKER; - if (leveltime & 1) - mobj->tracer->flags2 &= ~MF2_DONTDRAW; - else - mobj->tracer->flags2 |= MF2_DONTDRAW; - } - else if (mobj->target->player->kartstuff[k_growshrinktimer] > 0) - { - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|KITEM_GROW; - - if (leveltime & 1) - mobj->tracer->flags2 &= ~MF2_DONTDRAW; - else - mobj->tracer->flags2 |= MF2_DONTDRAW; - } - else if (mobj->target->player->kartstuff[k_itemtype] && mobj->target->player->kartstuff[k_itemamount] > 0) - { - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - - switch (mobj->target->player->kartstuff[k_itemtype]) - { - case KITEM_ORBINAUT: - mobj->tracer->sprite = SPR_ITMO; - mobj->tracer->frame = FF_FULLBRIGHT|(min(mobj->target->player->kartstuff[k_itemamount]-1, 3)); - break; - case KITEM_INVINCIBILITY: - mobj->tracer->sprite = SPR_ITMI; - mobj->tracer->frame = FF_FULLBRIGHT|((leveltime % (7*3)) / 3); - break; - case KITEM_SAD: - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT; - break; - default: - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|(mobj->target->player->kartstuff[k_itemtype]); - break; - } - - if (mobj->target->player->kartstuff[k_itemheld]) - { - if (leveltime & 1) - mobj->tracer->flags2 &= ~MF2_DONTDRAW; - else - mobj->tracer->flags2 |= MF2_DONTDRAW; - } - else - mobj->tracer->flags2 &= ~MF2_DONTDRAW; - } - else - { - P_SetMobjState(mobj, S_PLAYERARROW); - P_SetMobjState(mobj->tracer, S_PLAYERARROW_ITEM); - } - - mobj->tracer->destscale = scale; - - if (mobj->target->player->kartstuff[k_itemamount] >= numberdisplaymin - && mobj->target->player->kartstuff[k_itemamount] <= 10) // Meh, too difficult to support greater than this; convert this to a decent HUD object and then maybe :V - { - mobj_t *number = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); - mobj_t *numx = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); - - P_SetTarget(&number->target, mobj); - P_SetMobjState(number, S_PLAYERARROW_NUMBER); - P_SetScale(number, mobj->scale); - number->destscale = scale; - number->frame = FF_FULLBRIGHT|(mobj->target->player->kartstuff[k_itemamount]); - - P_SetTarget(&numx->target, mobj); - P_SetMobjState(numx, S_PLAYERARROW_X); - P_SetScale(numx, mobj->scale); - numx->destscale = scale; - } - - if (K_IsPlayerWanted(mobj->target->player) && mobj->movecount != 1) - { - mobj_t *wanted = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_PLAYERWANTED); - P_SetTarget(&wanted->target, mobj->target); - P_SetTarget(&wanted->tracer, mobj); - P_SetScale(wanted, mobj->scale); - wanted->destscale = scale; - mobj->movecount = 1; - } - else if (!K_IsPlayerWanted(mobj->target->player)) - mobj->movecount = 0; - } - else - mobj->tracer->flags2 |= MF2_DONTDRAW; - } - else if (mobj->health > 0) - { - P_KillMobj(mobj, NULL, NULL); - return; - } - break; - case MT_PLAYERWANTED: - if (mobj->target && mobj->target->health && mobj->tracer - && mobj->target->player && !mobj->target->player->spectator - && mobj->target->player->health && mobj->target->player->playerstate != PST_DEAD - && players[displayplayers[0]].mo && !players[displayplayers[0]].spectator) - { - fixed_t scale = 3*mobj->target->scale; - - if (!K_IsPlayerWanted(mobj->target->player)) - { - mobj->tracer->movecount = 0; - P_RemoveMobj(mobj); - return; - } - - if (mobj->tracer->flags2 & MF2_DONTDRAW) - mobj->flags2 |= MF2_DONTDRAW; - else - mobj->flags2 &= ~MF2_DONTDRAW; - - P_UnsetThingPosition(mobj); - mobj->x = mobj->target->x; - mobj->y = mobj->target->y; - - if (!splitscreen) - { - scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayers[0]].mo->x-mobj->target->x, - players[displayplayers[0]].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); - if (scale > 16*mobj->target->scale) - scale = 16*mobj->target->scale; - } - mobj->destscale = scale; - - if (!(mobj->target->eflags & MFE_VERTICALFLIP)) - { - mobj->z = mobj->target->z + (P_GetPlayerHeight(mobj->target->player)) + (16*mobj->target->scale) + (64*scale); - mobj->eflags &= ~MFE_VERTICALFLIP; - } - else - { - mobj->z = mobj->target->z - (P_GetPlayerHeight(mobj->target->player)) - (16*mobj->target->scale) - (64*scale); - mobj->eflags |= MFE_VERTICALFLIP; - } - P_SetThingPosition(mobj); - } - else if (mobj->health > 0) - { - P_KillMobj(mobj, NULL, NULL); - return; - } - break; - case MT_PETSMOKER: - if (!(leveltime % 10)) - { - mobj_t *smok = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_PETSMOKE); - if (mobj->spawnpoint && mobj->spawnpoint->options & MTF_OBJECTSPECIAL) - P_SetMobjStateNF(smok, smok->info->painstate); // same function, diff sprite - } - break; - //} - case MT_WATERDROP: - P_SceneryCheckWater(mobj); - if ((mobj->z <= mobj->floorz || mobj->z <= mobj->watertop) - && mobj->health > 0) - { - mobj->health = 0; - P_SetMobjState(mobj, mobj->info->deathstate); - S_StartSound(mobj, mobj->info->deathsound+P_RandomKey(mobj->info->mass)); - return; - } - break; - case MT_BUBBLES: - P_SceneryCheckWater(mobj); - break; - case MT_SMALLBUBBLE: - case MT_MEDIUMBUBBLE: - case MT_EXTRALARGEBUBBLE: // start bubble dissipate - P_SceneryCheckWater(mobj); - if (P_MobjWasRemoved(mobj)) // bubble was removed by not being in water - return; - if (!(mobj->eflags & MFE_UNDERWATER) - || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + mobj->height >= mobj->ceilingz) - || (mobj->eflags & MFE_VERTICALFLIP && mobj->z <= mobj->floorz) - || (P_CheckDeathPitCollide(mobj)) - || --mobj->fuse <= 0) // Bubbles eventually dissipate if they can't reach the surface. - { - // no playing sound: no point; the object is being removed - P_RemoveMobj(mobj); - return; - } - break; - case MT_DROWNNUMBERS: - if (!mobj->target) - { - P_RemoveMobj(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); + ang = (ang*leveltime) + (diff * (mobj->threshold-1)); + // If the player is on the ceiling, then flip your items as well. 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; + mobj->eflags |= MFE_VERTICALFLIP; + offz = mobj->target->height / 2; } else - mobj->z = mobj->target->z + (mobj->target->height) + FixedMul(8*FRACUNIT, mobj->target->scale); // Adjust height for height changes + { + mobj->eflags &= ~MFE_VERTICALFLIP; + offz = mobj->target->height / 5; + } - if (mobj->threshold <= 35) + if (mobj->target->eflags & MFE_DRAWONLYFORP1) // groooooaann... + mobj->eflags |= MFE_DRAWONLYFORP1; + else + mobj->eflags &= ~MFE_DRAWONLYFORP1; + + if (mobj->target->eflags & MFE_DRAWONLYFORP2) + mobj->eflags |= MFE_DRAWONLYFORP2; + else + mobj->eflags &= ~MFE_DRAWONLYFORP2; + + if (mobj->target->eflags & MFE_DRAWONLYFORP3) + mobj->eflags |= MFE_DRAWONLYFORP3; + else + mobj->eflags &= ~MFE_DRAWONLYFORP3; + + if (mobj->target->eflags & MFE_DRAWONLYFORP4) + mobj->eflags |= MFE_DRAWONLYFORP4; + else + mobj->eflags &= ~MFE_DRAWONLYFORP4; + + if (mobj->target->flags2 & MF2_DONTDRAW) 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) + + if (mobj->target->eflags & MFE_VERTICALFLIP) + offz += 4*FRACUNIT; + else + offz -= 4*FRACUNIT; + + if (mobj->tracer && mobj->tracer->player && mobj->tracer->player->mo + && mobj->tracer->player->health > 0 && !mobj->tracer->player->spectator) // STOLEN + mobj->color = mobj->tracer->player->skincolor; // don't do star flashing for stolen bumpers + else + mobj->color = mobj->target->color; // but do so if it belongs to you :B + + if (mobj->target->player->kartstuff[k_bumper] < 2) + P_SetMobjState(mobj, S_BATTLEBUMPER3); + else if (mobj->target->player->kartstuff[k_bumper] < 3) + P_SetMobjState(mobj, S_BATTLEBUMPER2); + else + P_SetMobjState(mobj, S_BATTLEBUMPER1); + + // Shrink your items if the player shrunk too. + mobj->scale = mobj->target->scale; + + P_UnsetThingPosition(mobj); { - 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); - - 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); + const angle_t fa = ang>>ANGLETOFINESHIFT; + mobj->x = mobj->target->x + FixedMul(FINECOSINE(fa), rad); + mobj->y = mobj->target->y + FixedMul(FINESINE(fa), rad); + mobj->z = mobj->target->z + offz; + P_SetThingPosition(mobj); } - break; - case MT_VERTICALFLAMEJET: - if ((mobj->flags2 & MF2_FIRING) && (leveltime & 3) == 0) + + // Was this so hard? + if (mobj->target->player->kartstuff[k_bumper] <= mobj->threshold) { - 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_InstaThrust(flame, mobj->angle, FixedDiv(mobj->fuse*FRACUNIT,3*FRACUNIT)); - S_StartSound(flame, sfx_fire); - } - break; - case MT_SEED: - mobj->momz = mobj->info->speed; - break; - case MT_ROCKCRUMBLE1: - case MT_ROCKCRUMBLE2: - case MT_ROCKCRUMBLE3: - case MT_ROCKCRUMBLE4: - case MT_ROCKCRUMBLE5: - case MT_ROCKCRUMBLE6: - case MT_ROCKCRUMBLE7: - case MT_ROCKCRUMBLE8: - case MT_ROCKCRUMBLE9: - case MT_ROCKCRUMBLE10: - case MT_ROCKCRUMBLE11: - case MT_ROCKCRUMBLE12: - case MT_ROCKCRUMBLE13: - case MT_ROCKCRUMBLE14: - case MT_ROCKCRUMBLE15: - case MT_ROCKCRUMBLE16: - if (mobj->z <= P_FloorzAtPos(mobj->x, mobj->y, mobj->z, mobj->height) - && mobj->state != &states[mobj->info->deathstate]) - { - P_SetMobjState(mobj, mobj->info->deathstate); + P_RemoveMobj(mobj); return; } - break; - case MT_FIREDITEM: - if (mobj->target && !P_MobjWasRemoved(mobj->target)) + } + else if ((mobj->health > 0 + && (!mobj->target || !mobj->target->player || !mobj->target->player->mo || mobj->target->player->health <= 0 || mobj->target->player->spectator)) + || (mobj->health <= 0 && P_IsObjectOnGround(mobj)) + || P_CheckDeathPitCollide(mobj)) // When in death state + { + P_RemoveMobj(mobj); + return; + } + break; + case MT_PLAYERARROW: + if (mobj->target && mobj->target->health + && mobj->target->player && !mobj->target->player->spectator + && mobj->target->player->health && mobj->target->player->playerstate != PST_DEAD) + { + fixed_t scale = 3*mobj->target->scale; + mobj->color = mobj->target->color; + K_MatchGenericExtraFlags(mobj, mobj->target); + + if ((G_RaceGametype() || mobj->target->player->kartstuff[k_bumper] <= 0) +#if 1 // Set to 0 to test without needing to host + || ((mobj->target->player == &players[displayplayers[0]]) || P_IsLocalPlayer(mobj->target->player)) +#endif + ) + mobj->flags2 |= MF2_DONTDRAW; + + P_UnsetThingPosition(mobj); + mobj->x = mobj->target->x; + mobj->y = mobj->target->y; + + mobj->angle = R_PointToAngle(mobj->x, mobj->y) + ANGLE_90; // literally only happened because i wanted to ^L^R the SPR_ITEM's + + if (!splitscreen && players[displayplayers[0]].mo) { - fixed_t x, y, z; - if (mobj->movecount) + scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayers[0]].mo->x-mobj->target->x, + players[displayplayers[0]].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); + if (scale > 16*mobj->target->scale) + scale = 16*mobj->target->scale; + } + mobj->destscale = scale; + + if (!(mobj->target->eflags & MFE_VERTICALFLIP)) + { + mobj->z = mobj->target->z + P_GetPlayerHeight(mobj->target->player) + (16*mobj->target->scale); + mobj->eflags &= ~MFE_VERTICALFLIP; + } + else + { + mobj->z = mobj->target->z - P_GetPlayerHeight(mobj->target->player) - (16*mobj->target->scale); + mobj->eflags |= MFE_VERTICALFLIP; + } + P_SetThingPosition(mobj); + + if (!mobj->tracer) + { + mobj_t *overlay = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); + P_SetTarget(&mobj->tracer, overlay); + P_SetTarget(&mobj->tracer->target, mobj); + P_SetMobjState(mobj->tracer, S_PLAYERARROW_ITEM); + P_SetScale(mobj->tracer, (mobj->tracer->destscale = mobj->scale)); + } + + // Do this in an easy way + if (mobj->target->player->kartstuff[k_itemroulette]) + { + mobj->tracer->color = mobj->target->player->skincolor; + mobj->tracer->colorized = true; + } + else + { + mobj->tracer->color = SKINCOLOR_NONE; + mobj->tracer->colorized = false; + } + + if (!(mobj->flags2 & MF2_DONTDRAW)) + { + const INT32 numberdisplaymin = ((mobj->target->player->kartstuff[k_itemtype] == KITEM_ORBINAUT) ? 5 : 2); + + // Set it to use the correct states for its condition + if (mobj->target->player->kartstuff[k_itemroulette]) { - x = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle + mobj->movedir, mobj->target->radius + mobj->radius); - y = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle + mobj->movedir, mobj->target->radius + mobj->radius); - z = mobj->target->z + mobj->target->height/3; + P_SetMobjState(mobj, S_PLAYERARROW_BOX); + mobj->tracer->sprite = SPR_ITEM; + mobj->tracer->frame = FF_FULLBRIGHT|(((mobj->target->player->kartstuff[k_itemroulette] % (13*3)) / 3) + 1); + mobj->tracer->flags2 &= ~MF2_DONTDRAW; + } + else if (mobj->target->player->kartstuff[k_stolentimer] > 0) + { + P_SetMobjState(mobj, S_PLAYERARROW_BOX); + mobj->tracer->sprite = SPR_ITEM; + mobj->tracer->frame = FF_FULLBRIGHT|KITEM_HYUDORO; + if (leveltime & 2) + mobj->tracer->flags2 &= ~MF2_DONTDRAW; + else + mobj->tracer->flags2 |= MF2_DONTDRAW; + } + else if ((mobj->target->player->kartstuff[k_stealingtimer] > 0) && (leveltime & 2)) + { + P_SetMobjState(mobj, S_PLAYERARROW_BOX); + mobj->tracer->sprite = SPR_ITEM; + mobj->tracer->frame = FF_FULLBRIGHT|KITEM_HYUDORO; + mobj->tracer->flags2 &= ~MF2_DONTDRAW; + } + else if (mobj->target->player->kartstuff[k_eggmanexplode] > 1) + { + P_SetMobjState(mobj, S_PLAYERARROW_BOX); + mobj->tracer->sprite = SPR_ITEM; + mobj->tracer->frame = FF_FULLBRIGHT|KITEM_EGGMAN; + if (leveltime & 1) + mobj->tracer->flags2 &= ~MF2_DONTDRAW; + else + mobj->tracer->flags2 |= MF2_DONTDRAW; + } + else if (mobj->target->player->kartstuff[k_rocketsneakertimer] > 1) + { + //itembar = mobj->target->player->kartstuff[k_rocketsneakertimer]; -- not today satan + P_SetMobjState(mobj, S_PLAYERARROW_BOX); + mobj->tracer->sprite = SPR_ITEM; + mobj->tracer->frame = FF_FULLBRIGHT|KITEM_ROCKETSNEAKER; + if (leveltime & 1) + mobj->tracer->flags2 &= ~MF2_DONTDRAW; + else + mobj->tracer->flags2 |= MF2_DONTDRAW; + } + else if (mobj->target->player->kartstuff[k_growshrinktimer] > 0) + { + P_SetMobjState(mobj, S_PLAYERARROW_BOX); + mobj->tracer->sprite = SPR_ITEM; + mobj->tracer->frame = FF_FULLBRIGHT|KITEM_GROW; + + if (leveltime & 1) + mobj->tracer->flags2 &= ~MF2_DONTDRAW; + else + mobj->tracer->flags2 |= MF2_DONTDRAW; + } + else if (mobj->target->player->kartstuff[k_itemtype] && mobj->target->player->kartstuff[k_itemamount] > 0) + { + P_SetMobjState(mobj, S_PLAYERARROW_BOX); + + switch (mobj->target->player->kartstuff[k_itemtype]) + { + case KITEM_ORBINAUT: + mobj->tracer->sprite = SPR_ITMO; + mobj->tracer->frame = FF_FULLBRIGHT|(min(mobj->target->player->kartstuff[k_itemamount]-1, 3)); + break; + case KITEM_INVINCIBILITY: + mobj->tracer->sprite = SPR_ITMI; + mobj->tracer->frame = FF_FULLBRIGHT|((leveltime % (7*3)) / 3); + break; + case KITEM_SAD: + mobj->tracer->sprite = SPR_ITEM; + mobj->tracer->frame = FF_FULLBRIGHT; + break; + default: + mobj->tracer->sprite = SPR_ITEM; + mobj->tracer->frame = FF_FULLBRIGHT|(mobj->target->player->kartstuff[k_itemtype]); + break; + } + + if (mobj->target->player->kartstuff[k_itemheld]) + { + if (leveltime & 1) + mobj->tracer->flags2 &= ~MF2_DONTDRAW; + else + mobj->tracer->flags2 |= MF2_DONTDRAW; + } + else + mobj->tracer->flags2 &= ~MF2_DONTDRAW; } else { - x = mobj->target->x; - y = mobj->target->y; - z = mobj->target->z + (80*mapobjectscale); + P_SetMobjState(mobj, S_PLAYERARROW); + P_SetMobjState(mobj->tracer, S_PLAYERARROW_ITEM); } - if (mobj->target->eflags & MFE_VERTICALFLIP) - z += mobj->target->height - FixedMul(mobj->target->scale, mobj->height); - P_MoveOrigin(mobj, x, y, z); - } - break; - default: - if (mobj->fuse) - { // Scenery object fuse! Very basic! - mobj->fuse--; - if (!mobj->fuse) + mobj->tracer->destscale = scale; + + if (mobj->target->player->kartstuff[k_itemamount] >= numberdisplaymin + && mobj->target->player->kartstuff[k_itemamount] <= 10) // Meh, too difficult to support greater than this; convert this to a decent HUD object and then maybe :V { - if (!LUA_HookMobj(mobj, MOBJ_HOOK(MobjFuse))) - P_RemoveMobj(mobj); - return; + mobj_t *number = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); + mobj_t *numx = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); + + P_SetTarget(&number->target, mobj); + P_SetMobjState(number, S_PLAYERARROW_NUMBER); + P_SetScale(number, mobj->scale); + number->destscale = scale; + number->frame = FF_FULLBRIGHT|(mobj->target->player->kartstuff[k_itemamount]); + + P_SetTarget(&numx->target, mobj); + P_SetMobjState(numx, S_PLAYERARROW_X); + P_SetScale(numx, mobj->scale); + numx->destscale = scale; } + + if (K_IsPlayerWanted(mobj->target->player) && mobj->movecount != 1) + { + mobj_t *wanted = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_PLAYERWANTED); + P_SetTarget(&wanted->target, mobj->target); + P_SetTarget(&wanted->tracer, mobj); + P_SetScale(wanted, mobj->scale); + wanted->destscale = scale; + mobj->movecount = 1; + } + else if (!K_IsPlayerWanted(mobj->target->player)) + mobj->movecount = 0; } - break; - } - - P_SceneryThinker(mobj); - return; - } - - // Check for a Lua thinker first - if (!mobj->player) - { - if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjThinker)) || P_MobjWasRemoved(mobj)) - return; - } - else if (!mobj->player->spectator) - { - // You cannot short-circuit the player thinker like you can other thinkers. - LUA_HookMobj(mobj, MOBJ_HOOK(MobjThinker)); - if (P_MobjWasRemoved(mobj)) - return; - } - - // if it's pushable, or if it would be pushable other than temporary disablement, use the - // separate thinker - if (mobj->flags & MF_PUSHABLE || (mobj->info->flags & MF_PUSHABLE && mobj->fuse)) - { - if (!mobj) - return; - - P_MobjCheckWater(mobj); - P_PushableThinker(mobj); - - // Extinguish fire objects in water. (Yes, it's extraordinarily rare to have a pushable flame object, but Brak uses such a case.) - if (mobj->flags & MF_FIRE && mobj->type != MT_PUMA && mobj->type != MT_FIREBALL - && (mobj->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))) - { - P_KillMobj(mobj, NULL, NULL); - return; - } - } - else if (mobj->flags & MF_BOSS) - { - if (LUA_HookMobj(mobj, MOBJ_HOOK(BossThinker))) - { - if (P_MobjWasRemoved(mobj)) + else + mobj->tracer->flags2 |= MF2_DONTDRAW; + } + else if (mobj->health > 0) + { + P_KillMobj(mobj, NULL, NULL); return; - } - else if (P_MobjWasRemoved(mobj)) - return; - else - switch (mobj->type) - { - case MT_EGGMOBILE: - if (mobj->health < mobj->info->damage+1 && leveltime & 1 && mobj->health > 0) - P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SMOKE); - if (mobj->flags2 & MF2_SKULLFLY) - P_SpawnGhostMobj(mobj); - P_Boss1Thinker(mobj); - break; - case MT_EGGMOBILE2: - P_Boss2Thinker(mobj); - break; - case MT_EGGMOBILE3: - P_Boss3Thinker(mobj); - break; - case MT_EGGMOBILE4: - P_Boss4Thinker(mobj); - break; - case MT_BLACKEGGMAN: - P_Boss7Thinker(mobj); - break; - case MT_METALSONIC_BATTLE: - P_Boss9Thinker(mobj); - break; - default: // Generic SOC-made boss - if (mobj->flags2 & MF2_SKULLFLY) - P_SpawnGhostMobj(mobj); - P_GenericBossThinker(mobj); - break; - } - if (mobj->flags2 & MF2_BOSSFLEE) - P_InstaThrust(mobj, mobj->angle, FixedMul(12*FRACUNIT, mobj->scale)); + } + break; + case MT_PLAYERWANTED: + if (mobj->target && mobj->target->health && mobj->tracer + && mobj->target->player && !mobj->target->player->spectator + && mobj->target->player->health && mobj->target->player->playerstate != PST_DEAD + && players[displayplayers[0]].mo && !players[displayplayers[0]].spectator) + { + fixed_t scale = 3*mobj->target->scale; + + if (!K_IsPlayerWanted(mobj->target->player)) + { + mobj->tracer->movecount = 0; + P_RemoveMobj(mobj); + return; + } + + if (mobj->tracer->flags2 & MF2_DONTDRAW) + mobj->flags2 |= MF2_DONTDRAW; + else + mobj->flags2 &= ~MF2_DONTDRAW; + + P_UnsetThingPosition(mobj); + mobj->x = mobj->target->x; + mobj->y = mobj->target->y; + + if (!splitscreen) + { + scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayers[0]].mo->x-mobj->target->x, + players[displayplayers[0]].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); + if (scale > 16*mobj->target->scale) + scale = 16*mobj->target->scale; + } + mobj->destscale = scale; + + if (!(mobj->target->eflags & MFE_VERTICALFLIP)) + { + mobj->z = mobj->target->z + (P_GetPlayerHeight(mobj->target->player)) + (16*mobj->target->scale) + (64*scale); + mobj->eflags &= ~MFE_VERTICALFLIP; + } + else + { + mobj->z = mobj->target->z - (P_GetPlayerHeight(mobj->target->player)) - (16*mobj->target->scale) - (64*scale); + mobj->eflags |= MFE_VERTICALFLIP; + } + P_SetThingPosition(mobj); + } + else if (mobj->health > 0) + { + P_KillMobj(mobj, NULL, NULL); + return; + } + break; + case MT_PETSMOKER: + if (!(leveltime % 10)) + { + mobj_t *smok = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_PETSMOKE); + if (mobj->spawnpoint && mobj->spawnpoint->options & MTF_OBJECTSPECIAL) + P_SetMobjStateNF(smok, smok->info->painstate); // same function, diff sprite + } + break; + //} + case MT_WATERDROP: + P_SceneryCheckWater(mobj); + if ((mobj->z <= mobj->floorz || mobj->z <= mobj->watertop) + && mobj->health > 0) + { + mobj->health = 0; + P_SetMobjState(mobj, mobj->info->deathstate); + S_StartSound(mobj, mobj->info->deathsound+P_RandomKey(mobj->info->mass)); + return; + } + break; + case MT_BUBBLES: + P_SceneryCheckWater(mobj); + break; + case MT_SMALLBUBBLE: + case MT_MEDIUMBUBBLE: + case MT_EXTRALARGEBUBBLE: // start bubble dissipate + P_SceneryCheckWater(mobj); + if (P_MobjWasRemoved(mobj)) // bubble was removed by not being in water + return; + if (!(mobj->eflags & MFE_UNDERWATER) + || (!(mobj->eflags & MFE_VERTICALFLIP) && mobj->z + mobj->height >= mobj->ceilingz) + || (mobj->eflags & MFE_VERTICALFLIP && mobj->z <= mobj->floorz) + || (P_CheckDeathPitCollide(mobj)) + || --mobj->fuse <= 0) // Bubbles eventually dissipate if they can't reach the surface. + { + // no playing sound: no point; the object is being removed + P_RemoveMobj(mobj); + return; + } + break; + case MT_DROWNNUMBERS: + if (!mobj->target) + { + P_RemoveMobj(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); + + 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); + } + 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_InstaThrust(flame, mobj->angle, FixedDiv(mobj->fuse*FRACUNIT,3*FRACUNIT)); + S_StartSound(flame, sfx_fire); + } + break; + case MT_SEED: + mobj->momz = mobj->info->speed; + break; + case MT_ROCKCRUMBLE1 ... MT_ROCKCRUMBLE16: + if (mobj->z <= P_FloorzAtPos(mobj->x, mobj->y, mobj->z, mobj->height) + && mobj->state != &states[mobj->info->deathstate]) + { + P_SetMobjState(mobj, mobj->info->deathstate); + return; + } + break; + case MT_FIREDITEM: + if (mobj->target && !P_MobjWasRemoved(mobj->target)) + { + fixed_t x, y, z; + if (mobj->movecount) + { + x = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle + mobj->movedir, mobj->target->radius + mobj->radius); + y = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle + mobj->movedir, mobj->target->radius + mobj->radius); + z = mobj->target->z + mobj->target->height/3; + } + else + { + x = mobj->target->x; + y = mobj->target->y; + z = mobj->target->z + (80*mapobjectscale); + } + if (mobj->target->eflags & MFE_VERTICALFLIP) + z += mobj->target->height - FixedMul(mobj->target->scale, mobj->height); + + P_MoveOrigin(mobj, x, y, z); + } + break; + default: + if (mobj->fuse) // Scenery object fuse! Very basic! + { + mobj->fuse--; + + if (!mobj->fuse) + { + if (!LUA_HookMobj(mobj, MOBJ_HOOK(MobjFuse))) + P_RemoveMobj(mobj); + return; + } + } + break; } - else if (mobj->health <= 0) // Dead things think differently than the living. - switch (mobj->type) - { + + P_SceneryThinker(mobj); +} + +static boolean P_MobjBossThink(mobj_t *mobj) +{ + if (LUA_HookMobj(mobj, MOBJ_HOOK(BossThinker))) + { + if (P_MobjWasRemoved(mobj)) + return false; + } + + if (P_MobjWasRemoved(mobj)) + return false; + + switch (mobj->type) + { + case MT_EGGMOBILE: + if (mobj->health < mobj->info->damage+1 && leveltime & 1 && mobj->health > 0) + P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SMOKE); + if (mobj->flags2 & MF2_SKULLFLY) + P_SpawnGhostMobj(mobj); + P_Boss1Thinker(mobj); + break; + case MT_EGGMOBILE2: + P_Boss2Thinker(mobj); + break; + case MT_EGGMOBILE3: + P_Boss3Thinker(mobj); + break; + case MT_EGGMOBILE4: + P_Boss4Thinker(mobj); + break; + case MT_BLACKEGGMAN: + P_Boss7Thinker(mobj); + break; + case MT_METALSONIC_BATTLE: + P_Boss9Thinker(mobj); + break; + default: // Generic SOC-made boss + if (mobj->flags2 & MF2_SKULLFLY) + P_SpawnGhostMobj(mobj); + P_GenericBossThinker(mobj); + break; + } + + if (mobj->flags2 & MF2_BOSSFLEE) + P_InstaThrust(mobj, mobj->angle, FixedMul(12*FRACUNIT, mobj->scale)); + + return true; +} + +static boolean P_MobjDeadThink(mobj_t *mobj) +{ + switch (mobj->type) + { case MT_BLUEBALL: if ((mobj->tics>>2)+1 > 0 && (mobj->tics>>2)+1 <= tr_trans60) // tr_trans50 through tr_trans90, shifting once every second frame mobj->frame = (NUMTRANSMAPS-((mobj->tics>>2)+1))<z <= mobj->floorz) { P_RemoveMobj(mobj); - return; + return false; } break; case MT_EGGTRAP: // Egg Capsule animal release @@ -6951,6 +6827,7 @@ void P_MobjThinker(mobj_t *mobj) i = P_RandomByte(); z = mobj->subsector->sector->floorheight + ((P_RandomByte()&63)*FRACUNIT); + for (j = 0; j < 2; j++) { const angle_t fa = (P_RandomByte()*FINEANGLES/16) & FINEMASK; @@ -6987,8 +6864,8 @@ void P_MobjThinker(mobj_t *mobj) /// \todo Have the player's dead body completely finish its animation even if they've already respawned. if (!(mobj->flags2 & MF2_DONTDRAW)) { - if (!mobj->fuse) - { // Go away. + if (!mobj->fuse) // Go away. + { /// \todo Actually go ahead and remove mobj completely, and fix any bugs and crashes doing this creates. Chasecam should stop moving, and F12 should never return to it. mobj->momz = 0; if (mobj->player) @@ -6996,7 +6873,7 @@ void P_MobjThinker(mobj_t *mobj) else // safe to remove, nobody's going to complain! { P_RemoveMobj(mobj); - return; + return false; } } else // Apply gravity to fall downwards. @@ -7007,18 +6884,15 @@ void P_MobjThinker(mobj_t *mobj) } } break; - //{ SRB2kart Items - Death States + //{ SRB2kart Items - Death States case MT_BANANA: if (cv_bananthrowroll.value) { //mobj->angle -= spin; - if (cv_bananthrowroll.value == 1 && K_CheckSlopeRollDist(mobj)) mobj->sloperoll += (angle_t)FixedMul(FixedDiv(abs(mobj->momz), 8 * mobj->scale), ANGLE_67h); // im lazy but this makes sure the banan goes back to upright when it lands lmao else if (cv_bananthrowroll.value == 2) mobj->rollangle += (angle_t)FixedMul(FixedDiv(abs(mobj->momz), 8 * mobj->scale), ANGLE_67h); - - //if (P_IsObjectOnGround(mobj) && mobj->momz * P_MobjFlip(mobj) <= 0) } /* FALLTHRU */ case MT_ORBINAUT: @@ -7027,7 +6901,7 @@ void P_MobjThinker(mobj_t *mobj) if (P_IsObjectOnGround(mobj)) { P_RemoveMobj(mobj); - return; + return false; } /* FALLTHRU */ case MT_ORBINAUT_SHIELD: @@ -7053,12 +6927,12 @@ void P_MobjThinker(mobj_t *mobj) else { P_RemoveMobj(mobj); - return; + return false; } break; case MT_MINEEXPLOSIONSOUND: P_RemoveMobj(mobj); - return; + return false; case MT_CDUFO: if (mobj->fuse > TICRATE) mobj->flags2 ^= MF2_DONTDRAW; // only by good fortune does this end with it having MF2_DONTDRAW... don't touch! @@ -7068,13 +6942,13 @@ void P_MobjThinker(mobj_t *mobj) P_SetMobjStateNF(mobj, mobj->info->seestate); else P_SetMobjStateNF(mobj, mobj->info->spawnstate); - /* FALLTHRU */ + /* FALLTHRU */ case MT_SMK_MOLE: mobj->flags2 ^= MF2_DONTDRAW; if (P_IsObjectOnGround(mobj)) { P_RemoveMobj(mobj); - return; + return false; } break; case MT_SMK_THWOMP: @@ -7095,14 +6969,20 @@ void P_MobjThinker(mobj_t *mobj) if (P_IsObjectOnGround(mobj)) { P_RemoveMobj(mobj); - return; + return false; } break; - //} + //} default: break; - } - else switch (mobj->type) + } + + return true; +} + +static boolean P_MobjRegularThink(mobj_t *mobj) +{ + switch (mobj->type) { case MT_FALLINGROCK: // Despawn rocks here in case zmovement code can't do so (blame slopes) @@ -7111,8 +6991,6 @@ void P_MobjThinker(mobj_t *mobj) mobj->z + mobj->height >= mobj->ceilingz : mobj->z <= mobj->floorz)) { - //P_RemoveMobj(mobj); - //return; mobj->fuse = TICRATE; } P_MobjCheckWater(mobj); @@ -7207,12 +7085,9 @@ void P_MobjThinker(mobj_t *mobj) if (!playeringame[i] || !players[i].mo) continue; - if (players[i].mare != mobj->threshold) + if ((players[i].mare != mobj->threshold) || (players[i].health <= 1)) continue; - if (!(players[i].health > 1)) - continue; - fixed_t dist = P_AproxDistance(players[i].mo->x - mobj->x, players[i].mo->y - mobj->y); if (!(dist < shortest)) @@ -7230,7 +7105,7 @@ void P_MobjThinker(mobj_t *mobj) || mobj->target->state == &states[mobj->target->info->raisestate]) { P_RemoveMobj(mobj); - return; + return false; } P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z - mobj->height); break; @@ -7238,7 +7113,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->z <= mobj->floorz) { P_RemoveMobj(mobj); - return; + return false; } break; case MT_KOOPA: @@ -7249,11 +7124,11 @@ void P_MobjThinker(mobj_t *mobj) && mobj->flags & MF_MISSILE) { P_ExplodeMissile(mobj); - return; + return false; } break; case MT_BOSSFLYPOINT: - return; + return false; case MT_NIGHTSCORE: mobj->color = (UINT8)(leveltime % SKINCOLOR_WHITE); break; @@ -7263,67 +7138,76 @@ void P_MobjThinker(mobj_t *mobj) if (!mobj->target // if you have no target || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now - { // then remove yourself as well! - P_RemoveMobj(mobj); - return; + { + P_RemoveMobj(mobj); // then remove yourself as well! + return false; } jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, FixedMul(-64*FRACUNIT, mobj->target->scale)); jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, FixedMul(-64*FRACUNIT, mobj->target->scale)); - if (mobj->fuse == 56) // First one + switch (mobj->fuse) { - P_UnsetThingPosition(mobj); - mobj->x = jetx; - mobj->y = jety; - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(38*FRACUNIT, mobj->target->scale); - else - mobj->z = mobj->target->z + FixedMul(38*FRACUNIT, mobj->target->scale); - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - else if (mobj->fuse == 57) - { - P_UnsetThingPosition(mobj); - mobj->x = jetx + P_ReturnThrustX(mobj->target, mobj->target->angle-ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); - mobj->y = jety + P_ReturnThrustY(mobj->target, mobj->target->angle-ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(12*FRACUNIT, mobj->target->scale); - else - mobj->z = mobj->target->z + FixedMul(12*FRACUNIT, mobj->target->scale); - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - else if (mobj->fuse == 58) - { - P_UnsetThingPosition(mobj); - mobj->x = jetx + P_ReturnThrustX(mobj->target, mobj->target->angle+ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); - mobj->y = jety + P_ReturnThrustY(mobj->target, mobj->target->angle+ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(12*FRACUNIT, mobj->target->scale); - else - mobj->z = mobj->target->z + FixedMul(12*FRACUNIT, mobj->target->scale); - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); - } - else if (mobj->fuse == 59) - { - jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, -mobj->target->radius); - jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, -mobj->target->radius); - P_UnsetThingPosition(mobj); - mobj->x = jetx; - mobj->y = jety; - if (mobj->target->eflags & MFE_VERTICALFLIP) - mobj->z = mobj->target->z + mobj->target->height/2 + mobj->height/2; - else - mobj->z = mobj->target->z + mobj->target->height/2 - mobj->height/2; - mobj->floorz = mobj->z; - mobj->ceilingz = mobj->z+mobj->height; - P_SetThingPosition(mobj); + case 56: // First one + { + P_UnsetThingPosition(mobj); + mobj->x = jetx; + mobj->y = jety; + if (mobj->target->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(38*FRACUNIT, mobj->target->scale); + else + mobj->z = mobj->target->z + FixedMul(38*FRACUNIT, mobj->target->scale); + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_SetThingPosition(mobj); + } + break; + case 57: + { + P_UnsetThingPosition(mobj); + mobj->x = jetx + P_ReturnThrustX(mobj->target, mobj->target->angle-ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); + mobj->y = jety + P_ReturnThrustY(mobj->target, mobj->target->angle-ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); + if (mobj->target->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(12*FRACUNIT, mobj->target->scale); + else + mobj->z = mobj->target->z + FixedMul(12*FRACUNIT, mobj->target->scale); + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_SetThingPosition(mobj); + } + break; + case 58: + { + P_UnsetThingPosition(mobj); + mobj->x = jetx + P_ReturnThrustX(mobj->target, mobj->target->angle+ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); + mobj->y = jety + P_ReturnThrustY(mobj->target, mobj->target->angle+ANGLE_90, FixedMul(24*FRACUNIT, mobj->target->scale)); + if (mobj->target->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->target->z + mobj->target->height - mobj->height - FixedMul(12*FRACUNIT, mobj->target->scale); + else + mobj->z = mobj->target->z + FixedMul(12*FRACUNIT, mobj->target->scale); + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_SetThingPosition(mobj); + } + break; + case 59: + { + jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, -mobj->target->radius); + jety = mobj->target->y + P_ReturnThrustY(mobj->target, mobj->target->angle, -mobj->target->radius); + P_UnsetThingPosition(mobj); + mobj->x = jetx; + mobj->y = jety; + if (mobj->target->eflags & MFE_VERTICALFLIP) + mobj->z = mobj->target->z + mobj->target->height/2 + mobj->height/2; + else + mobj->z = mobj->target->z + mobj->target->height/2 - mobj->height/2; + mobj->floorz = mobj->z; + mobj->ceilingz = mobj->z+mobj->height; + P_SetThingPosition(mobj); + } + break; + default: + break; } mobj->fuse++; } @@ -7336,7 +7220,7 @@ void P_MobjThinker(mobj_t *mobj) || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now { // then remove yourself as well! P_RemoveMobj(mobj); - return; + return false; } jetx = mobj->target->x + P_ReturnThrustX(mobj->target, mobj->target->angle, FixedMul(-60*FRACUNIT, mobj->target->scale)); @@ -7358,7 +7242,7 @@ void P_MobjThinker(mobj_t *mobj) || (!(mobj->target->flags & MF_BOSS) && mobj->target->health <= 0)) // or your target isn't a boss and it's popped now { // then remove yourself as well! P_RemoveMobj(mobj); - return; + return false; } P_UnsetThingPosition(mobj); @@ -7432,7 +7316,7 @@ void P_MobjThinker(mobj_t *mobj) case MT_PLAYER: if (mobj->player) P_PlayerMobjThinker(mobj); - return; + return false; case MT_SKIM: // check mobj against possible water content, before movement code P_MobjCheckWater(mobj); @@ -7467,7 +7351,7 @@ void P_MobjThinker(mobj_t *mobj) P_NightsItemChase(mobj); else A_AttractChase(mobj); - return; + return false; // Flung items case MT_FLINGRING: case MT_FLINGCOIN: @@ -7505,7 +7389,7 @@ void P_MobjThinker(mobj_t *mobj) if (P_CheckDeathPitCollide(mobj)) { P_RemoveMobj(mobj); - return; + return false; } else if (P_IsObjectOnGround(mobj)) { @@ -7524,7 +7408,7 @@ void P_MobjThinker(mobj_t *mobj) || mobj->scale <= mapobjectscale>>4) { P_RemoveMobj(mobj); - return; + return false; } P_Attract(mobj, mobj->tracer, true); } @@ -7641,6 +7525,7 @@ void P_MobjThinker(mobj_t *mobj) if (G_RaceGametype() && mobj->tracer) { distaway = P_AproxDistance(mobj->tracer->x - mobj->x, mobj->tracer->y - mobj->y); + if (distaway < distbarrier) { if (mobj->tracer->player) @@ -7809,8 +7694,10 @@ void P_MobjThinker(mobj_t *mobj) // you can cycle through multiple states in a tic if (!mobj->tics) + { if (!P_SetMobjState(mobj, mobj->state->nextstate)) - return; // freed itself + return false; // freed itself + } } P_UnsetThingPosition(mobj); @@ -7818,7 +7705,7 @@ void P_MobjThinker(mobj_t *mobj) mobj->y += mobj->momy; mobj->z += mobj->momz; P_SetThingPosition(mobj); - return; + return false; case MT_MINEEXPLOSIONSOUND: if (mobj->health == 100) S_StartSound(mobj, sfx_s3k4e); @@ -7828,7 +7715,7 @@ void P_MobjThinker(mobj_t *mobj) if (!mobj->target || !mobj->target->health) { P_RemoveMobj(mobj); - return; + return false; } mobj->angle = mobj->target->angle; @@ -7838,6 +7725,7 @@ void P_MobjThinker(mobj_t *mobj) { player_t *p = NULL; + if (mobj->target->target && mobj->target->target->player) p = mobj->target->target->player; else if (mobj->target->player) @@ -7870,7 +7758,7 @@ void P_MobjThinker(mobj_t *mobj) if (!mobj->target) { P_RemoveMobj(mobj); - return; + return false; } mobj->color = mobj->target->color; mobj->colorized = mobj->target->colorized; @@ -7879,7 +7767,7 @@ void P_MobjThinker(mobj_t *mobj) if (!mobj->target || !mobj->target->health || (mobj->target->player && !mobj->target->player->kartstuff[k_invincibilitytimer])) { P_RemoveMobj(mobj); - return; + return false; } P_SetOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z); break; @@ -7890,7 +7778,7 @@ void P_MobjThinker(mobj_t *mobj) || !(mobj->target->player->cmd.buttons & BT_ACCELERATE))) // Letting go of accel functions about the same as brake-drifting { P_RemoveMobj(mobj); - return; + return false; } else { @@ -7927,7 +7815,7 @@ void P_MobjThinker(mobj_t *mobj) if (!mobj->target || !mobj->target->health) { P_RemoveMobj(mobj); - return; + return false; } P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z); break; @@ -7938,7 +7826,7 @@ void P_MobjThinker(mobj_t *mobj) if (!mobj->target || !mobj->target->health || (mobj->target->player && !mobj->target->player->kartstuff[k_instashield])) { P_RemoveMobj(mobj); - return; + return false; } K_MatchGenericExtraFlags(mobj, mobj->target); @@ -7948,7 +7836,7 @@ void P_MobjThinker(mobj_t *mobj) if (!mobj->target || P_MobjWasRemoved(mobj->target)) { P_RemoveMobj(mobj); - return; + return false; } if (mobj->movefactor < 48*mobj->target->scale) @@ -7972,7 +7860,7 @@ void P_MobjThinker(mobj_t *mobj) if (!mobj->target || !mobj->target->health || (mobj->target->player && mobj->target->player->kartstuff[k_curshield] != 1)) { P_RemoveMobj(mobj); - return; + return false; } P_SetScale(mobj, (mobj->destscale = (5*mobj->target->destscale)>>2)); @@ -8008,7 +7896,7 @@ void P_MobjThinker(mobj_t *mobj) if (!mobj->target || !mobj->target->health) { P_RemoveMobj(mobj); - return; + return false; } if (mobj->target->player && !mobj->target->player->kartstuff[k_rocketsneakertimer]) { @@ -8022,7 +7910,7 @@ void P_MobjThinker(mobj_t *mobj) else if (P_IsObjectOnGround(mobj)) { P_RemoveMobj(mobj); - return; + return false; } } break; @@ -8034,7 +7922,7 @@ void P_MobjThinker(mobj_t *mobj) || (G_RaceGametype() || mobj->target->player->kartstuff[k_bumper])) { P_RemoveMobj(mobj); - return; + return false; } P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z); @@ -8520,7 +8408,7 @@ void P_MobjThinker(mobj_t *mobj) if (!mobj->target || P_MobjWasRemoved(mobj->target)) { P_RemoveMobj(mobj); - return; + return false; } break; case MT_SMK_PIPE: @@ -8534,7 +8422,7 @@ void P_MobjThinker(mobj_t *mobj) { mobj_t *newmole = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SMK_MOLE); P_SetTarget(&mobj->target, newmole); - return; + return false; } break; case MT_SMK_MOLE: @@ -8655,7 +8543,6 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->z == mobj->movefactor) { mobj->extravalue1 = 1; - //S_StartSound(mobj, sfx_s1bb); } else mobj->momz = (mobj->info->speed/16) * P_MobjFlip(mobj); @@ -8676,7 +8563,7 @@ void P_MobjThinker(mobj_t *mobj) if (mobj->momz == 0) { P_RemoveMobj(mobj); - return; + return false; } else { @@ -8694,7 +8581,7 @@ void P_MobjThinker(mobj_t *mobj) P_MobjCheckWater(mobj); P_CheckPosition(mobj, mobj->x, mobj->y); if (P_MobjWasRemoved(mobj)) - return; + return false; mobj->floorz = tmfloorz; mobj->ceilingz = tmceilingz; @@ -8764,264 +8651,419 @@ void P_MobjThinker(mobj_t *mobj) && (mobj->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))) { P_KillMobj(mobj, NULL, NULL); - return; + return false; } break; } + + return true; +} + +static void P_FlagFuseThink(mobj_t *mobj) +{ + subsector_t *ss; + fixed_t x, y, z; + mobj_t* flagmo; + + if (!mobj->spawnpoint) + return; + + x = mobj->spawnpoint->x << FRACBITS; + y = mobj->spawnpoint->y << FRACBITS; + ss = R_PointInSubsector(x, y); + + if (mobj->spawnpoint->options & MTF_OBJECTFLIP) + { + z = ss->sector->ceilingheight - mobjinfo[mobj->type].height; + if (mobj->spawnpoint->options >> ZSHIFT) + z -= (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; + } + else + { + z = ss->sector->floorheight; + if (mobj->spawnpoint->options >> ZSHIFT) + z += (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; + } + + flagmo = P_SpawnMobj(x, y, z, mobj->type); + flagmo->spawnpoint = mobj->spawnpoint; + + if (mobj->spawnpoint->options & MTF_OBJECTFLIP) + { + flagmo->eflags |= MFE_VERTICALFLIP; + flagmo->flags2 |= MF2_OBJECTFLIP; + } + + if (mobj->type == MT_REDFLAG) + { + if (!(mobj->flags2 & MF2_JUSTATTACKED)) + CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x85, M_GetText("Red flag"), 0x80); + + // Assumedly in splitscreen players will be on opposing teams + if (players[consoleplayer].ctfteam == 1 || splitscreen) + S_StartSound(NULL, sfx_hoop1); + else if (players[consoleplayer].ctfteam == 2) + S_StartSound(NULL, sfx_hoop3); + + redflag = flagmo; + } + else // MT_BLUEFLAG + { + if (!(mobj->flags2 & MF2_JUSTATTACKED)) + CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x84, M_GetText("Blue flag"), 0x80); + + // Assumedly in splitscreen players will be on opposing teams + if (players[consoleplayer].ctfteam == 2 || splitscreen) + S_StartSound(NULL, sfx_hoop1); + else if (players[consoleplayer].ctfteam == 1) + S_StartSound(NULL, sfx_hoop3); + + blueflag = flagmo; + } + + P_RemoveMobj(mobj); +} + + +static void P_MonitorFuseThink(mobj_t *mobj) +{ + mobj_t *newmobj; + + if ((mobj->flags2 & MF2_AMBUSH || mobj->flags2 & MF2_STRONGBOX) && mobj->type != MT_QUESTIONBOX) + { + mobjtype_t spawnchance[64]; + INT32 numchoices = 0, i = 0; + + // This define should make it a lot easier to organize and change monitor weights +#define SETMONITORCHANCES(type, strongboxamt, weakboxamt) \ + for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) spawnchance[numchoices++] = type + + // Type SRM WRM + SETMONITORCHANCES(MT_SNEAKERTV, 0, 10); // Super Sneakers + SETMONITORCHANCES(MT_INV, 2, 0); // Invincibility + SETMONITORCHANCES(MT_WHITETV, 3, 8); // Whirlwind Shield + SETMONITORCHANCES(MT_GREENTV, 3, 8); // Elemental Shield + SETMONITORCHANCES(MT_YELLOWTV, 2, 0); // Attraction Shield + SETMONITORCHANCES(MT_BLUETV, 3, 3); // Force Shield + SETMONITORCHANCES(MT_BLACKTV, 2, 0); // Armageddon Shield + SETMONITORCHANCES(MT_MIXUPBOX, 0, 1); // Teleporters + SETMONITORCHANCES(MT_RECYCLETV, 0, 1); // Recycler + SETMONITORCHANCES(MT_PRUP, 1, 1); // 1-Up + // ====================================== + // Total 16 32 + +#undef SETMONITORCHANCES + + i = P_RandomKey(numchoices); // Gotta love those random numbers! + newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]); + + // Transfer flags2 (strongbox, objectflip, ambush) + newmobj->flags2 = mobj->flags2; + } + else + { + newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type); + + // Transfer flags2 (strongbox, objectflip) + newmobj->flags2 = mobj->flags2; + } + + P_RemoveMobj(mobj); // make sure they disappear +} + +static boolean P_RandomItemFuseThink(mobj_t *mobj) +{ + mobj_t *newmobj; + + if (G_BattleGametype()) + { + if (mobj->threshold != 69) + return false; + } + else + { + // Respawn from mapthing if you have one! + if (mobj->spawnpoint) + { + P_SpawnMapThing(mobj->spawnpoint); + newmobj = mobj->spawnpoint->mobj; // this is set to the new mobj in P_SpawnMapThing + } + else + newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type); + + // Transfer flags2 (strongbox, objectflip) + newmobj->flags2 = mobj->flags2 & ~MF2_DONTDRAW; + } + + return true; +} + +static void P_IceBlockFuseThink(mobj_t *mobj) +{ + mobj_t *cur = mobj->hnext, *next; + UINT8 i; + + for (i = 0; i < 5; i++) + { + mobj_t *debris = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SMK_ICEBLOCK_DEBRIS); + debris->angle = FixedAngle(P_RandomRange(0,360)<angle, P_RandomRange(3,18)*(FRACUNIT/4)); + debris->momz = P_RandomRange(4,8)<hnext; + P_RemoveMobj(cur); + cur = next; + } + + P_RemoveMobj(mobj); +} + +static boolean P_FuseThink(mobj_t *mobj) +{ + mobj->fuse--; + + if (mobj->fuse) + { + if (((mobj->type == MT_RANDOMITEM && mobj->threshold == 69) || mobj->type == MT_EGGMANITEM || mobj->type == MT_FALLINGROCK) && mobj->fuse <= TICRATE) + mobj->flags2 ^= MF2_DONTDRAW; + + return true; + } + + if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjFuse)) || P_MobjWasRemoved(mobj)) + ; + else switch (mobj->type) + { + // gargoyle and snowman handled in P_PushableThinker, not here + case MT_THROWNGRENADE: + case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: + P_SetMobjState(mobj, mobj->info->deathstate); + break; + case MT_BLUEFLAG: + case MT_REDFLAG: + P_FlagFuseThink(mobj); + return false; + case MT_YELLOWTV: // Ring shield box + case MT_BLUETV: // Force shield box + case MT_GREENTV: // Water shield box + case MT_BLACKTV: // Bomb shield box + case MT_WHITETV: // Jump shield box + case MT_SNEAKERTV: // Super Sneaker box + case MT_SUPERRINGBOX: // 10-Ring box + case MT_REDRINGBOX: // Red Team 10-Ring box + case MT_BLUERINGBOX: // Blue Team 10-Ring box + case MT_INV: // Invincibility box + case MT_MIXUPBOX: // Teleporter Mixup box + case MT_RECYCLETV: // Recycler box + case MT_SCORETVSMALL: + case MT_SCORETVLARGE: + case MT_PRUP: // 1up! + case MT_EGGMANBOX: // Eggman box + case MT_GRAVITYBOX: // Gravity box + case MT_QUESTIONBOX: + P_MonitorFuseThink(mobj); + return false; + case MT_RANDOMITEM: + if (!P_RandomItemFuseThink(mobj)) + break; + P_RemoveMobj(mobj); // make sure they disappear + return false; + case MT_METALSONIC_BATTLE: + break; // don't remove + case MT_SPIKE: + P_SetMobjState(mobj, mobj->state->nextstate); + mobj->fuse = mobj->info->speed; + if (mobj->spawnpoint) + mobj->fuse += mobj->spawnpoint->angle; + break; + case MT_NIGHTSCORE: + P_RemoveMobj(mobj); + return false; + case MT_PLAYER: + break; // don't remove + case MT_SMK_ICEBLOCK: + P_IceBlockFuseThink(mobj); + return false; + default: + P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL. + break; + } + + return !P_MobjWasRemoved(mobj); +} + +static boolean P_MobjPushableThink(mobj_t *mobj) +{ + // would be cool if we could use P_MobjWasRemoved Zzz... + if (!mobj) + return false; + + P_MobjCheckWater(mobj); + P_PushableThinker(mobj); + + // Extinguish fire objects in water. (Yes, it's extraordinarily rare to have a pushable flame object, but Brak uses such a case.) + if (mobj->flags & MF_FIRE && mobj->type != MT_PUMA && mobj->type != MT_FIREBALL + && (mobj->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER))) + { + P_KillMobj(mobj, NULL, NULL); + return false; + } + + return true; +} + +static void P_FiringThink(mobj_t *mobj) +{ + if (mobj->state->action.acp1 == (actionf_p1)A_Boss1Laser) + { + var1 = mobj->state->var1; + var2 = mobj->state->var2; + mobj->state->action.acp1(mobj); + } + else if (leveltime & 1) // Fire mode + { + mobj_t *missile; + + if (mobj->target->player && mobj->target->player->nightstime) + { + fixed_t oldval = mobjinfo[mobj->extravalue1].speed; + + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x+mobj->target->momx, mobj->target->y+mobj->target->momy); + mobjinfo[mobj->extravalue1].speed = FixedMul(60*FRACUNIT, mobj->scale); + missile = P_SpawnMissile(mobj, mobj->target, mobj->extravalue1); + mobjinfo[mobj->extravalue1].speed = oldval; + } + else + { + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); + missile = P_SpawnMissile(mobj, mobj->target, mobj->extravalue1); + } + + if (missile) + { + if (mobj->flags2 & MF2_SUPERFIRE) + missile->flags2 |= MF2_SUPERFIRE; + + if (mobj->info->attacksound) + S_StartSound(missile, mobj->info->attacksound); + } + } + else + mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); +} + +// +// P_MobjThinker +// +void P_MobjThinker(mobj_t *mobj) +{ + I_Assert(mobj != NULL); + I_Assert(!P_MobjWasRemoved(mobj)); + + if (mobj->flags & MF_NOTHINK) + 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); + // hnext/hprev changes suggested by toaster + 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->flags2 &= ~MF2_PUSHED; + mobj->eflags &= ~(MFE_SPRUNG|MFE_JUSTBOUNCEDWALL); + + tmfloorthing = tmhitthing = NULL; + + // 970 allows ANY mobj to trigger a linedef exec + if (UNLIKELY(!mobj->islocal && sec1 && GETSECSPECIAL(sec1->special, 2) == 8)) // BEWARE: islocal does not exist in vanilla + { + 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->fuse > 0 // Not guaranteed to be MF_SCENERY or not MF_SCENERY! + && (signed)(mobj->frame >> 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; + } + + // Check for a Lua thinker first + if (!mobj->player) + { + if (LUA_HookMobj(mobj, MOBJ_HOOK(MobjThinker)) || P_MobjWasRemoved(mobj)) + return; + } + else if (!mobj->player->spectator) + { + // You cannot short-circuit the player thinker like you can other thinkers. + LUA_HookMobj(mobj, MOBJ_HOOK(MobjThinker)); + if (P_MobjWasRemoved(mobj)) + return; + } + + // if it's pushable, or if it would be pushable other than temporary disablement, use the + // separate thinker + if (mobj->flags & MF_PUSHABLE || (mobj->info->flags & MF_PUSHABLE && mobj->fuse)) + { + if (!P_MobjPushableThink(mobj)) + return; + } + else if (mobj->flags & MF_BOSS) + { + if (!P_MobjBossThink(mobj)) + return; + } + else if (mobj->health <= 0) // Dead things think differently than the living. + { + if (!P_MobjDeadThink(mobj)) + return; + } + else + { + if (!P_MobjRegularThink(mobj)) + return; + } + if (P_MobjWasRemoved(mobj)) return; if (mobj->flags2 & MF2_FIRING && mobj->target && mobj->health > 0) + P_FiringThink(mobj); + + if (mobj->flags & MF_AMBIENT) { - if (mobj->state->action.acp1 == (actionf_p1)A_Boss1Laser) - { - var1 = mobj->state->var1; - var2 = mobj->state->var2; - mobj->state->action.acp1(mobj); - } - else if (leveltime & 1) // Fire mode - { - mobj_t *missile; - - if (mobj->target->player && mobj->target->player->nightstime) - { - fixed_t oldval = mobjinfo[mobj->extravalue1].speed; - - mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x+mobj->target->momx, mobj->target->y+mobj->target->momy); - mobjinfo[mobj->extravalue1].speed = FixedMul(60*FRACUNIT, mobj->scale); - missile = P_SpawnMissile(mobj, mobj->target, mobj->extravalue1); - mobjinfo[mobj->extravalue1].speed = oldval; - } - else - { - mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); - missile = P_SpawnMissile(mobj, mobj->target, mobj->extravalue1); - } - - if (missile) - { - if (mobj->flags2 & MF2_SUPERFIRE) - missile->flags2 |= MF2_SUPERFIRE; - - if (mobj->info->attacksound) - S_StartSound(missile, mobj->info->attacksound); - } - } - else - mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y); - } - - if (UNLIKELY(mobj->flags & MF_AMBIENT)) - { - if (!(leveltime % mobj->health) && mobj->info->seesound) + if (leveltime % mobj->health) + return; + if (mobj->info->seesound) S_StartSound(mobj, mobj->info->seesound); return; } // Check fuse - if (mobj->fuse) - { - mobj->fuse--; - if (!mobj->fuse) - { - subsector_t *ss; - fixed_t x, y, z; - mobj_t *flagmo, *newmobj; - - if (!LUA_HookMobj(mobj, MOBJ_HOOK(MobjFuse)) && !P_MobjWasRemoved(mobj)) - { - switch (mobj->type) - { - // gargoyle and snowman handled in P_PushableThinker, not here - case MT_THROWNGRENADE: - case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE: - P_SetMobjState(mobj, mobj->info->deathstate); - break; - case MT_BLUEFLAG: - case MT_REDFLAG: - if (mobj->spawnpoint) - { - x = mobj->spawnpoint->x << FRACBITS; - y = mobj->spawnpoint->y << FRACBITS; - ss = R_PointInSubsector(x, y); - if (mobj->spawnpoint->options & MTF_OBJECTFLIP) - { - z = ss->sector->ceilingheight - mobjinfo[mobj->type].height; - if (mobj->spawnpoint->options >> ZSHIFT) - z -= (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; - } - else - { - z = ss->sector->floorheight; - if (mobj->spawnpoint->options >> ZSHIFT) - z += (mobj->spawnpoint->options >> ZSHIFT) << FRACBITS; - } - flagmo = P_SpawnMobj(x, y, z, mobj->type); - flagmo->spawnpoint = mobj->spawnpoint; - if (mobj->spawnpoint->options & MTF_OBJECTFLIP) - { - flagmo->eflags |= MFE_VERTICALFLIP; - flagmo->flags2 |= MF2_OBJECTFLIP; - } - - if (mobj->type == MT_REDFLAG) - { - if (!(mobj->flags2 & MF2_JUSTATTACKED)) - CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x85, M_GetText("Red flag"), 0x80); - - // Assumedly in splitscreen players will be on opposing teams - if (players[consoleplayer].ctfteam == 1 || splitscreen) - S_StartSound(NULL, sfx_hoop1); - else if (players[consoleplayer].ctfteam == 2) - S_StartSound(NULL, sfx_hoop3); - - redflag = flagmo; - } - else // MT_BLUEFLAG - { - if (!(mobj->flags2 & MF2_JUSTATTACKED)) - CONS_Printf(M_GetText("The %c%s%c has returned to base.\n"), 0x84, M_GetText("Blue flag"), 0x80); - - // Assumedly in splitscreen players will be on opposing teams - if (players[consoleplayer].ctfteam == 2 || splitscreen) - S_StartSound(NULL, sfx_hoop1); - else if (players[consoleplayer].ctfteam == 1) - S_StartSound(NULL, sfx_hoop3); - - blueflag = flagmo; - } - } - P_RemoveMobj(mobj); - return; - case MT_YELLOWTV: // Ring shield box - case MT_BLUETV: // Force shield box - case MT_GREENTV: // Water shield box - case MT_BLACKTV: // Bomb shield box - case MT_WHITETV: // Jump shield box - case MT_SNEAKERTV: // Super Sneaker box - case MT_SUPERRINGBOX: // 10-Ring box - case MT_REDRINGBOX: // Red Team 10-Ring box - case MT_BLUERINGBOX: // Blue Team 10-Ring box - case MT_INV: // Invincibility box - case MT_MIXUPBOX: // Teleporter Mixup box - case MT_RECYCLETV: // Recycler box - case MT_SCORETVSMALL: - case MT_SCORETVLARGE: - case MT_PRUP: // 1up! - case MT_EGGMANBOX: // Eggman box - case MT_GRAVITYBOX: // Gravity box - case MT_QUESTIONBOX: - if ((mobj->flags2 & MF2_AMBUSH || mobj->flags2 & MF2_STRONGBOX) && mobj->type != MT_QUESTIONBOX) - { - mobjtype_t spawnchance[64]; - INT32 numchoices = 0, i = 0; - - // This define should make it a lot easier to organize and change monitor weights -#define SETMONITORCHANCES(type, strongboxamt, weakboxamt) \ - for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) spawnchance[numchoices++] = type - - // Type SRM WRM - SETMONITORCHANCES(MT_SNEAKERTV, 0, 10); // Super Sneakers - SETMONITORCHANCES(MT_INV, 2, 0); // Invincibility - SETMONITORCHANCES(MT_WHITETV, 3, 8); // Whirlwind Shield - SETMONITORCHANCES(MT_GREENTV, 3, 8); // Elemental Shield - SETMONITORCHANCES(MT_YELLOWTV, 2, 0); // Attraction Shield - SETMONITORCHANCES(MT_BLUETV, 3, 3); // Force Shield - SETMONITORCHANCES(MT_BLACKTV, 2, 0); // Armageddon Shield - SETMONITORCHANCES(MT_MIXUPBOX, 0, 1); // Teleporters - SETMONITORCHANCES(MT_RECYCLETV, 0, 1); // Recycler - SETMONITORCHANCES(MT_PRUP, 1, 1); // 1-Up - // ====================================== - // Total 16 32 - -#undef SETMONITORCHANCES - - i = P_RandomKey(numchoices); // Gotta love those random numbers! - newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, spawnchance[i]); - - // Transfer flags2 (strongbox, objectflip, ambush) - newmobj->flags2 = mobj->flags2; - } - else - { - newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type); - - // Transfer flags2 (strongbox, objectflip) - newmobj->flags2 = mobj->flags2; - } - P_RemoveMobj(mobj); // make sure they disappear - return; - case MT_RANDOMITEM: - if (G_BattleGametype()) - { - if (mobj->threshold != 69) - break; - } - else - { - // Respawn from mapthing if you have one! - if (mobj->spawnpoint) - { - P_SpawnMapThing(mobj->spawnpoint); - newmobj = mobj->spawnpoint->mobj; // this is set to the new mobj in P_SpawnMapThing - } - else - newmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobj->type); - - // Transfer flags2 (strongbox, objectflip) - newmobj->flags2 = mobj->flags2 & ~MF2_DONTDRAW; - } - P_RemoveMobj(mobj); // make sure they disappear - return; - case MT_METALSONIC_BATTLE: - break; // don't remove - case MT_SPIKE: - P_SetMobjState(mobj, mobj->state->nextstate); - mobj->fuse = mobj->info->speed; - if (mobj->spawnpoint) - mobj->fuse += mobj->spawnpoint->angle; - break; - case MT_NIGHTSCORE: - P_RemoveMobj(mobj); - return; - case MT_PLAYER: - break; // don't remove - case MT_SMK_ICEBLOCK: - { - mobj_t *cur = mobj->hnext, *next; - UINT8 i; - - for (i = 0; i < 5; i++) - { - mobj_t *debris = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SMK_ICEBLOCK_DEBRIS); - debris->angle = FixedAngle(P_RandomRange(0,360)<angle, P_RandomRange(3,18)*(FRACUNIT/4)); - debris->momz = P_RandomRange(4,8)<hnext; - P_RemoveMobj(cur); - cur = next; - } - - P_RemoveMobj(mobj); - return; - } - default: - P_SetMobjState(mobj, mobj->info->xdeathstate); // will remove the mobj if S_NULL. - break; - } - } - if (P_MobjWasRemoved(mobj)) - return; - } - else if (((mobj->type == MT_RANDOMITEM && mobj->threshold == 69) || mobj->type == MT_EGGMANITEM || mobj->type == MT_FALLINGROCK) && mobj->fuse <= TICRATE) - mobj->flags2 ^= MF2_DONTDRAW; - } + if (mobj->fuse && !P_FuseThink(mobj)) + return; I_Assert(mobj != NULL); I_Assert(!P_MobjWasRemoved(mobj)); @@ -9042,7 +9084,9 @@ void P_MobjThinker(mobj_t *mobj) { if (!P_ZMovement(mobj)) return; // mobj was removed + P_CheckPosition(mobj, mobj->x, mobj->y); // Need this to pick up objects! + if (P_MobjWasRemoved(mobj)) return; } @@ -9136,7 +9180,6 @@ boolean P_RailThinker(mobj_t *mobj) { if (!P_ZMovement(mobj)) return true; // mobj was removed - //P_CheckPosition(mobj, mobj->x, mobj->y); } return P_MobjWasRemoved(mobj) || (x == mobj->x && y == mobj->y && z == mobj->z); @@ -9166,6 +9209,9 @@ void P_PushableThinker(mobj_t *mobj) if (mobj->flags & MF_PUSHABLE && !(mobj->momx || mobj->momy)) P_TryMove(mobj, mobj->x, mobj->y, true); + if (!mobj) + return; + if (mobj->fuse == 1) // it would explode in the MobjThinker code { mobj_t *spawnmo; @@ -9190,12 +9236,16 @@ void P_PushableThinker(mobj_t *mobj) z = ss->sector->floorheight; spawnmo = P_SpawnMobj(x, y, z, mobj->type); - spawnmo->spawnpoint = mobj->spawnpoint; - P_UnsetThingPosition(spawnmo); - spawnmo->flags = mobj->flags; - P_SetThingPosition(spawnmo); - spawnmo->flags2 = mobj->flags2; - spawnmo->flags |= MF_PUSHABLE; + if (spawnmo) + { + spawnmo->spawnpoint = mobj->spawnpoint; + P_UnsetThingPosition(spawnmo); + spawnmo->flags = mobj->flags; + P_SetThingPosition(spawnmo); + spawnmo->flags2 = mobj->flags2; + spawnmo->flags |= MF_PUSHABLE; + } + P_RemoveMobj(mobj); break; default: @@ -9204,6 +9254,39 @@ void P_PushableThinker(mobj_t *mobj) } } +static void P_RandomAudienceThink(mobj_t *mobj) +{ + if (!mobj->colorized) // a fan of someone? + return; + + if (mobj->threshold >= 0) // not already happy or sad? + { + if (!playeringame[mobj->threshold] || players[mobj->threshold].spectator) // focused on a valid player? + return; + + if (!(players[mobj->threshold].exiting) && !(players[mobj->threshold].pflags & PF_TIMEOVER)) // not finished yet? + return; + + if (K_IsPlayerLosing(&players[mobj->threshold])) + mobj->threshold = -2; + else + { + mobj->threshold = -1; + S_StartSound(mobj, sfx_chaooo); + } + } + + if (mobj->threshold == -1) + mobj->angle += ANGLE_22h; + + if (((statenum_t)(mobj->state-states) != S_AUDIENCE_CHAO_CHEER2) || (mobj->tics != states[S_AUDIENCE_CHAO_CHEER2].tics)) // not at the start of your cheer jump? + return; + + mobj->momz = 0; + + P_SetMobjState(mobj, ((mobj->threshold == -1) ? S_AUDIENCE_CHAO_WIN2 : S_AUDIENCE_CHAO_LOSE)); +} + // Quick, optimized function for scenery void P_SceneryThinker(mobj_t *mobj) { @@ -9243,9 +9326,12 @@ void P_SceneryThinker(mobj_t *mobj) { if (!P_SceneryZMovement(mobj)) return; // mobj was removed + P_CheckPosition(mobj, mobj->x, mobj->y); // Need this to pick up objects! + if (P_MobjWasRemoved(mobj)) return; + mobj->floorz = tmfloorz; mobj->ceilingz = tmceilingz; } @@ -9257,40 +9343,8 @@ void P_SceneryThinker(mobj_t *mobj) P_CycleMobjState(mobj); - if (mobj->type != MT_RANDOMAUDIENCE) - return; - - { - if (!mobj->colorized) // a fan of someone? - return; - - if (mobj->threshold >= 0) // not already happy or sad? - { - if (!playeringame[mobj->threshold] || players[mobj->threshold].spectator) // focused on a valid player? - return; - - if (!(players[mobj->threshold].exiting) && !(players[mobj->threshold].pflags & PF_TIMEOVER)) // not finished yet? - return; - - if (K_IsPlayerLosing(&players[mobj->threshold])) - mobj->threshold = -2; - else - { - mobj->threshold = -1; - S_StartSound(mobj, sfx_chaooo); - } - } - - if (mobj->threshold == -1) - mobj->angle += ANGLE_22h; - - if (((statenum_t)(mobj->state-states) != S_AUDIENCE_CHAO_CHEER2) || (mobj->tics != states[S_AUDIENCE_CHAO_CHEER2].tics)) // not at the start of your cheer jump? - return; - - mobj->momz = 0; - - P_SetMobjState(mobj, ((mobj->threshold == -1) ? S_AUDIENCE_CHAO_WIN2 : S_AUDIENCE_CHAO_LOSE)); - } + if (mobj->type == MT_RANDOMAUDIENCE) + P_RandomAudienceThink(mobj); } // @@ -10586,9 +10640,6 @@ void P_SpawnPlayer(INT32 playernum) P_SetScale(mobj, mobj->destscale); P_FlashPal(p, 0, 0); // Resets - // Spawn with a pity shield if necessary. - //P_DoPityCheck(p); - p->grieftime = 0; p->hitemtimer = 0; p->hitemvictim = 255; @@ -10828,7 +10879,6 @@ void P_MovePlayerToStarpost(INT32 playernum) else z = (p->starpostz<starpostz + 128) << FRACBITS; // reverse gravity exists, pls mobj->player->kartstuff[k_starpostflip] = 0; if (z < floor) @@ -10848,9 +10898,6 @@ void P_MovePlayerToStarpost(INT32 playernum) p->kartstuff[k_waypoint] = p->kartstuff[k_starpostwp]; // SRB2kart P_AfterPlayerSpawn(playernum); - - //if (!(netgame || multiplayer)) - // leveltime = p->starposttime; } #define MAXHUNTEMERALDS 64 @@ -10892,51 +10939,44 @@ void P_SpawnMapThing(mapthing_t *mthing) } // count deathmatch start positions - if (mthing->type == 33) + switch (mthing->type) { - if (numdmstarts < MAX_DM_STARTS) - { - deathmatchstarts[numdmstarts] = mthing; - mthing->type = 0; - numdmstarts++; - } - return; - } - - else if (mthing->type == 34) // Red CTF Starts - { - if (numredctfstarts < MAXPLAYERS) - { - redctfstarts[numredctfstarts] = mthing; - mthing->type = 0; - numredctfstarts++; - } - return; - } - - else if (mthing->type == 35) // Blue CTF Starts - { - if (numbluectfstarts < MAXPLAYERS) - { - bluectfstarts[numbluectfstarts] = mthing; - mthing->type = 0; - numbluectfstarts++; - } - return; - } - - else if (mthing->type == 750) // Slope vertex point (formerly chaos spawn) - return; - - else if (mthing->type == 300 // Ring - || mthing->type == 308 || mthing->type == 309 // Team Rings - || mthing->type == 1706 // Nights Wing - || (mthing->type >= 600 && mthing->type <= 609) // Placement patterns - || mthing->type == 1705 || mthing->type == 1713 // NiGHTS Hoops - || mthing->type == 1800) // Mario Coin - { - // Don't spawn hoops, wings, or rings yet! - return; + case 33: + if (numdmstarts < MAX_DM_STARTS) + { + deathmatchstarts[numdmstarts] = mthing; + mthing->type = 0; + numdmstarts++; + } + return; + case 34: // Red CTF Starts + if (numredctfstarts < MAXPLAYERS) + { + redctfstarts[numredctfstarts] = mthing; + mthing->type = 0; + numredctfstarts++; + } + return; + case 35: // Blue CTF Starts + if (numbluectfstarts < MAXPLAYERS) + { + bluectfstarts[numbluectfstarts] = mthing; + mthing->type = 0; + numbluectfstarts++; + } + return; + case 300: // Ring + case 308: + case 309: // Team Rings + case 600 ... 609: // Placement patterns + case 750: // Slope vertex point (formerly chaos spawn) + case 1705: + case 1706: // Nights Wing + case 1713: // NiGHTS Hoops + case 1800: // Mario Coin + return; // Don't spawn hoops, wings, or rings yet! + default: + break; } // check for players specially @@ -10956,28 +10996,35 @@ void P_SpawnMapThing(mapthing_t *mthing) return; } + // If recording, you ARE Metal Sonic. Do not spawn it, do not save normal spawnpoints. if (metalrecording && mthing->type == mobjinfo[MT_METALSONIC_RACE].doomednum) - { // If recording, you ARE Metal Sonic. Do not spawn it, do not save normal spawnpoints. + { playerstarts[0] = mthing; return; } // find which type to spawn for (i = 0; i < NUMMOBJTYPES; i++) + { if (mthing->type == mobjinfo[i].doomednum) break; + } if (i == NUMMOBJTYPES) { if (mthing->type == 3328) // 3D Mode start Thing return; + CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y); + i = MT_UNKNOWN; } if (metalrecording) // Metal Sonic can't use these things. + { if (mobjinfo[i].flags & (MF_ENEMY|MF_BOSS) || i == MT_EMMY || i == MT_STARPOST) return; + } if (i >= MT_EMERALD1 && i <= MT_EMERALD7) // Pickupable Emeralds { @@ -10992,8 +11039,10 @@ void P_SpawnMapThing(mapthing_t *mthing) } if (!G_BattleGametype() || !cv_specialrings.value) + { if (P_WeaponOrPanel(i)) return; // Don't place weapons/panels in non-ringslinger modes + } if (i == MT_EMERHUNT) { @@ -11011,60 +11060,71 @@ void P_SpawnMapThing(mapthing_t *mthing) if (i == MT_EMERALDSPAWN) { - if (!cv_powerstones.value) - return; - - if (!G_BattleGametype()) + if (!cv_powerstones.value || !G_BattleGametype()) return; runemeraldmanager = true; } if (!G_RaceGametype()) // No enemies in match or CTF modes + { if ((mobjinfo[i].flags & MF_ENEMY) || (mobjinfo[i].flags & MF_BOSS)) return; - - // Set powerup boxes to user settings for competition. - if (gametype == GT_COMPETITION) - { - if ((mobjinfo[i].flags & MF_MONITOR) && cv_competitionboxes.value) // not Normal - { - if (cv_competitionboxes.value == 1) // Random - i = MT_QUESTIONBOX; - else if (cv_competitionboxes.value == 2) // Teleports - i = MT_MIXUPBOX; - else if (cv_competitionboxes.value == 3) // None - return; // Don't spawn! - } } - // Set powerup boxes to user settings for other netplay modes - else if (gametype != GT_COOP) + // Set powerup boxes to user settings for competition. + if (gametype == GT_COMPETITION && cv_competitionboxes.value && (mobjinfo[i].flags & MF_MONITOR)) // not Normal { - if ((mobjinfo[i].flags & MF_MONITOR) && cv_matchboxes.value) // not Normal + switch (cv_competitionboxes.value) { - if (cv_matchboxes.value == 1) // Random + case 1: // Random i = MT_QUESTIONBOX; - else if (cv_matchboxes.value == 3) // Don't spawn - return; - else // cv_matchboxes.value == 2, Non-Random - { + break; + case 2: // Teleports + i = MT_MIXUPBOX; + break; + case 3: // None + return; // Don't spawn! + default: + break; + } + } + // Set powerup boxes to user settings for other netplay modes + else if (gametype != GT_COOP && cv_matchboxes.value && (mobjinfo[i].flags & MF_MONITOR)) // not Normal + { + switch (cv_matchboxes.value) + { + case 1: // Random + i = MT_QUESTIONBOX; + break; + case 3: // None + return; // Don't spawn! + default: if (i == MT_QUESTIONBOX) return; // don't spawn in Non-Random - mthing->options &= ~(MTF_AMBUSH|MTF_OBJECTSPECIAL); // no random respawning! - } + break; } } if (gametype != GT_CTF) // CTF specific things { - if (i == MT_BLUETEAMRING || i == MT_REDTEAMRING) - i = MT_RING; - else if (i == MT_BLUERINGBOX || i == MT_REDRINGBOX) - i = MT_SUPERRINGBOX; - else if (i == MT_BLUEFLAG || i == MT_REDFLAG) - return; // No flags in non-CTF modes! + switch (i) + { + case MT_BLUETEAMRING: + case MT_REDTEAMRING: + i = MT_RING; + break; + case MT_BLUERINGBOX: + case MT_REDRINGBOX: + i = MT_SUPERRINGBOX; + break; + case MT_BLUEFLAG: + case MT_REDFLAG: + return; // No flags in non-CTF modes! + default: + break; + } } else { @@ -11161,12 +11221,25 @@ void P_SpawnMapThing(mapthing_t *mthing) // offsetting if (mthing->options >> ZSHIFT) offset = ((mthing->options >> ZSHIFT) << FRACBITS); - else if (i == MT_CRAWLACOMMANDER || i == MT_DETON || i == MT_JETTBOMBER || i == MT_JETTGUNNER || i == MT_EGGMOBILE2) - offset = 33*FRACUNIT; - else if (i == MT_EGGMOBILE) - offset = 128*FRACUNIT; - else if (i == MT_GOLDBUZZ || i == MT_REDBUZZ) - offset = 288*FRACUNIT; + else switch (i) + { + case MT_CRAWLACOMMANDER: + case MT_DETON: + case MT_JETTBOMBER: + case MT_JETTGUNNER: + case MT_EGGMOBILE2: + offset = 33*FRACUNIT; + break; + case MT_EGGMOBILE: + offset = 128*FRACUNIT; + break; + case MT_GOLDBUZZ: + case MT_REDBUZZ: + offset = 288*FRACUNIT; + break; + default: + break; + } // applying offsets! (if any) if (flip)