// // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // Moving object handling. Spawn functions. // #include #include "i_system.h" #include "z_zone.h" #include "m_random.h" #include "doomdef.h" #include "p_local.h" #include "sounds.h" #include "st_stuff.h" #include "hu_stuff.h" #include "s_sound.h" #include "doomstat.h" #include "d_main.h" // villsa [STRIFE] extern line_t *spechit[]; // haleyjd: extern int numspechit; // [STRIFE] - needed in P_XYMovement void G_PlayerReborn (int player); void P_SpawnMapThing (mapthing_t* mthing); // // P_SetMobjState // Returns true if the mobj is still present. // // [STRIFE] Verified unmodified // int test; boolean P_SetMobjState ( mobj_t* mobj, statenum_t state ) { state_t* st; do { if (state == S_NULL) { mobj->state = (state_t *) S_NULL; P_RemoveMobj (mobj); return false; } st = &states[state]; mobj->state = st; mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; // Modified handling. // Call action functions when the state is set if (st->action.acp1) st->action.acp1(mobj); state = st->nextstate; } while (!mobj->tics); return true; } // // P_ExplodeMissile // // [STRIFE] Removed randomization of deathstate tics // void P_ExplodeMissile (mobj_t* mo) { mo->momx = mo->momy = mo->momz = 0; P_SetMobjState (mo, mobjinfo[mo->type].deathstate); // villsa [STRIFE] removed tics randomization mo->flags &= ~MF_MISSILE; if (mo->info->deathsound) S_StartSound (mo, mo->info->deathsound); } // // P_XYMovement // // [STRIFE] Modifications for: // * No SKULLFLY logic (replaced by BOUNCE flag) // * Missiles can activate G1/GR line types // * Player walking logic // * Air friction for players // #define STOPSPEED 0x1000 #define FRICTION 0xe800 #define AIRFRICTION 0xfff0 // [STRIFE] void P_XYMovement (mobj_t* mo) { fixed_t ptryx; fixed_t ptryy; player_t* player; fixed_t xmove; fixed_t ymove; // villsa [STRIFE] unused /* if (!mo->momx && !mo->momy) { if (mo->flags & MF_SKULLFLY) { // the skull slammed into something mo->flags &= ~MF_SKULLFLY; mo->momx = mo->momy = mo->momz = 0; P_SetMobjState (mo, mo->info->spawnstate); } return; } */ player = mo->player; if (mo->momx > MAXMOVE) mo->momx = MAXMOVE; else if (mo->momx < -MAXMOVE) mo->momx = -MAXMOVE; if (mo->momy > MAXMOVE) mo->momy = MAXMOVE; else if (mo->momy < -MAXMOVE) mo->momy = -MAXMOVE; xmove = mo->momx; ymove = mo->momy; do { if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2) { ptryx = mo->x + xmove/2; ptryy = mo->y + ymove/2; xmove >>= 1; ymove >>= 1; } else { ptryx = mo->x + xmove; ptryy = mo->y + ymove; xmove = ymove = 0; } if (!P_TryMove (mo, ptryx, ptryy)) { // blocked move if (mo->player) { // try to slide along it P_SlideMove (mo); } // villsa [STRIFE] check for bouncy missiles else if(mo->flags & MF_BOUNCE) { mo->momx >>= 3; mo->momy >>= 3; if (P_TryMove(mo, mo->x - xmove, ymove + mo->y)) mo->momy = -mo->momy; else mo->momx = -mo->momx; xmove = 0; ymove = 0; } else if (mo->flags & MF_MISSILE) { // haley 20110203: [STRIFE] // This modification allows missiles to activate shoot specials. // *** BUG: In vanilla Strife the second condition is simply // if(numspechit). However, numspechit can be negative, and // when it is, this accesses spechit[-2]. This always causes the // DOS exe to read from NULL, and the 'special' value there (in // DOS 6.22 at least) is 0x70, which does nothing. if(blockingline && blockingline->special) P_ShootSpecialLine(mo, blockingline); if(numspechit > 0) P_ShootSpecialLine(mo, spechit[numspechit-1]); // explode a missile if (ceilingline && ceilingline->backsector && ceilingline->backsector->ceilingpic == skyflatnum) { // Hack to prevent missiles exploding // against the sky. // Does not handle sky floors. P_RemoveMobj (mo); return; } P_ExplodeMissile (mo); } else mo->momx = mo->momy = 0; } } while (xmove || ymove); // slow down if (player && player->cheats & CF_NOMOMENTUM) { // debug option for no sliding at all mo->momx = mo->momy = 0; return; } // villsa [STRIFE] replace skullfly flag with MF_BOUNCE if (mo->flags & (MF_MISSILE | MF_BOUNCE) ) return; // no friction for missiles ever // haleyjd 20110224: [STRIFE] players experience friction even in the air, // although less than when on the ground. With this fix, the 1.2-and-up // IWAD demo is now in sync! if (mo->z > mo->floorz) { if(player) { mo->momx = FixedMul (mo->momx, AIRFRICTION); mo->momy = FixedMul (mo->momy, AIRFRICTION); } return; // no friction when airborne } if (mo->flags & MF_CORPSE) { // do not stop sliding // if halfway off a step with some momentum if (mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4 || mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4) { if (mo->floorz != mo->subsector->sector->floorheight) return; } } if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED && mo->momy > -STOPSPEED && mo->momy < STOPSPEED && (!player || (player->cmd.forwardmove == 0 && player->cmd.sidemove == 0 ) ) ) { // if in a walking frame, stop moving // villsa [STRIFE]: different player state (haleyjd - verified 20110202) if ( player&&(unsigned)((player->mo->state - states) - S_PLAY_01) < 4) P_SetMobjState (player->mo, S_PLAY_00); mo->momx = 0; mo->momy = 0; } else { mo->momx = FixedMul (mo->momx, FRICTION); mo->momy = FixedMul (mo->momy, FRICTION); } } // // P_ZMovement // // [STRIFE] Modifications for: // * 3D Object Clipping // * Different momz handling // * No SKULLFLY logic (replaced with BOUNCE) // * Missiles don't hit sky flats // void P_ZMovement (mobj_t* mo) { fixed_t dist; fixed_t delta; // check for smooth step up if (mo->player && mo->z < mo->floorz) { mo->player->viewheight -= mo->floorz-mo->z; mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3; } // adjust height // villsa [STRIFE] check for things standing on top of other things if(!P_CheckPositionZ(mo, mo->z + mo->momz)) { if(mo->momz >= 0) mo->ceilingz = mo->height + mo->z; else mo->floorz = mo->z; } //mo->z += mo->momz; // villsa [STRIFE] unused if ( mo->flags & MF_FLOAT && mo->target) { // float down towards target if too close if ( /*!(mo->flags & MF_SKULLFLY) // villsa [STRIFE] unused &&*/ !(mo->flags & MF_INFLOAT) ) { dist = P_AproxDistance (mo->x - mo->target->x, mo->y - mo->target->y); delta =(mo->target->z + (mo->height>>1)) - mo->z; if (delta<0 && dist < -(delta*3) ) mo->z -= FLOATSPEED; else if (delta>0 && dist < (delta*3) ) mo->z += FLOATSPEED; } } // clip movement if (mo->z <= mo->floorz) { // hit the floor if (mo->flags & MF_BOUNCE) { // the skull slammed into something // villsa [STRIFE] affect reactiontime // momz is also shifted by 1 mo->momz = -mo->momz >> 1; mo->reactiontime >>= 1; // villsa [STRIFE] get terrain type if(P_GetTerrainType(mo) != FLOOR_SOLID) mo->flags &= ~MF_BOUNCE; } if (mo->momz < 0) { if (mo->player && mo->momz < -GRAVITY*8) { // Squat down. // Decrease viewheight for a moment // after hitting the ground (hard), // and utter appropriate sound. mo->player->deltaviewheight = mo->momz>>3; // villsa [STRIFE] fall damage // haleyjd 09/18/10: Repaired calculation if(mo->momz < -20*FRACUNIT) P_DamageMobj(mo, NULL, mo, mo->momz / -25000); // haleyjd 20110224: *Any* fall centers your view, not just // damaging falls (moved outside the above if). mo->player->centerview = 1; S_StartSound (mo, sfx_oof); } mo->momz = 0; } mo->z = mo->floorz; // cph 2001/05/26 - // See lost soul bouncing comment above. We need this here for bug // compatibility with original Doom2 v1.9 - if a soul is charging and // hit by a raising floor this incorrectly reverses its Y momentum. // // villsa [STRIFE] unused /* if (!correct_lost_soul_bounce && mo->flags & MF_SKULLFLY) mo->momz = -mo->momz; */ // villsa [STRIFE] also check for MF_BOUNCE if ( (mo->flags & MF_MISSILE) && !(mo->flags & (MF_NOCLIP|MF_BOUNCE)) ) { P_ExplodeMissile (mo); } } else // haleyjd 20110224: else here, not else if - Strife change or what? { if (! (mo->flags & MF_NOGRAVITY) ) { if (mo->momz == 0) mo->momz = -GRAVITY*2; else mo->momz -= GRAVITY; } if (mo->z + mo->height > mo->ceilingz) { // villsa [STRIFE] replace skullfly flag with MF_BOUNCE if (mo->flags & MF_BOUNCE) { // villsa [STRIFE] affect reactiontime // momz is also shifted by 1 mo->momz = -mo->momz >> 1; mo->reactiontime >>= 1; } // hit the ceiling if (mo->momz > 0) mo->momz = 0; mo->z = mo->ceilingz - mo->height; // villsa [STRIFE] also check for MF_BOUNCE if ( (mo->flags & MF_MISSILE) && !(mo->flags & (MF_NOCLIP|MF_BOUNCE)) ) { // villsa [STRIFE] check against skies if(mo->subsector->sector->ceilingpic == skyflatnum) P_RemoveMobj(mo); else P_ExplodeMissile (mo); } } } } // // P_NightmareRespawn // // [STRIFE] Modifications for: // * Destination fog z coordinate // * Restoration of all Strife mapthing flags // void P_NightmareRespawn (mobj_t* mobj) { fixed_t x; fixed_t y; fixed_t z; mobj_t* mo; mapthing_t* mthing; x = mobj->spawnpoint.x << FRACBITS; y = mobj->spawnpoint.y << FRACBITS; // somthing is occupying it's position? if (!P_CheckPosition (mobj, x, y) ) return; // no respwan // spawn a teleport fog at old spot // because of removal of the body? mo = P_SpawnMobj (mobj->x, mobj->y, mobj->subsector->sector->floorheight , MT_TFOG); // initiate teleport sound S_StartSound (mo, sfx_telept); // spawn a teleport fog at the new spot //ss = R_PointInSubsector (x,y); // haleyjd [STRIFE]: Uses ONFLOORZ instead of ss->sector->floorheight mo = P_SpawnMobj (x, y, ONFLOORZ , MT_TFOG); S_StartSound (mo, sfx_telept); // spawn the new monster mthing = &mobj->spawnpoint; // spawn it if (mobj->info->flags & MF_SPAWNCEILING) z = ONCEILINGZ; else z = ONFLOORZ; // inherit attributes from deceased one mo = P_SpawnMobj (x,y,z, mobj->type); mo->spawnpoint = mobj->spawnpoint; mo->angle = ANG45 * (mthing->angle/45); if (mthing->options & MTF_AMBUSH) mo->flags |= MF_AMBUSH; if (mthing->options & MTF_STAND) // [STRIFE] Standing mode, for NPCs mobj->flags |= MF_STAND; if (mthing->options & MTF_FRIEND) // [STRIFE] Allies mobj->flags |= MF_ALLY; if (mthing->options & MTF_TRANSLUCENT) // [STRIFE] Translucent object mobj->flags |= MF_SHADOW; if (mthing->options & MTF_MVIS) // [STRIFE] Alt. Translucency mobj->flags |= MF_MVIS; mo->reactiontime = 18; // remove the old monster, P_RemoveMobj (mobj); } // // P_MobjThinker // // [STRIFE] Modified for: // * Terrain effects // * Stonecold cheat // * Altered skill 5 respawn behavior // void P_MobjThinker (mobj_t* mobj) { // momentum movement if (mobj->momx || mobj->momy /*|| (mobj->flags&MF_SKULLFLY)*/ ) // villsa [STRIFE] unused { P_XYMovement (mobj); // FIXME: decent NOP/NULL/Nil function pointer please. if (mobj->thinker.function.acv == (actionf_v) (-1)) return; // mobj was removed // villsa [STRIFE] terrain clipping if(P_GetTerrainType(mobj) == FLOOR_SOLID) mobj->flags &= ~MF_FEETCLIPPED; else mobj->flags |= MF_FEETCLIPPED; } if ( (mobj->z != mobj->floorz && !(mobj->flags & MF_NOGRAVITY)) // villsa [STRIFE] || mobj->momz ) { P_ZMovement (mobj); // FIXME: decent NOP/NULL/Nil function pointer please. if (mobj->thinker.function.acv == (actionf_v) (-1)) return; // mobj was removed // villsa [STRIFE] terrain clipping and sounds if(P_GetTerrainType(mobj) == FLOOR_SOLID) mobj->flags &= ~MF_FEETCLIPPED; else { S_StartSound(mobj, sfx_wsplsh); mobj->flags |= MF_FEETCLIPPED; } } // cycle through states, // calling action functions at transitions if (mobj->tics != -1) { mobj->tics--; // villsa [STRIFE] stonecold cheat if(stonecold) { if(mobj->flags & MF_COUNTKILL) P_DamageMobj(mobj, mobj, mobj, 10); } // you can cycle through multiple states in a tic if (!mobj->tics) if (!P_SetMobjState (mobj, mobj->state->nextstate) ) return; // freed itself } else { // check for nightmare respawn if (! (mobj->flags & MF_COUNTKILL) ) return; if (!respawnmonsters) return; mobj->movecount++; // haleyjd [STRIFE]: respawn time increased from 12 to 16 if (mobj->movecount < 16*TICRATE) return; if ( leveltime&31 ) return; if (P_Random () > 4) return; // haleyjd [STRIFE]: NOTDMATCH things don't respawn if(mobj->flags & MF_NOTDMATCH) return; P_NightmareRespawn (mobj); } } // // P_SpawnMobj // // [STRIFE] Modifications to reactiontime and for terrain types. // mobj_t* P_SpawnMobj ( fixed_t x, fixed_t y, fixed_t z, mobjtype_t type ) { mobj_t* mobj; state_t* st; mobjinfo_t* info; mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL); memset (mobj, 0, sizeof (*mobj)); info = &mobjinfo[type]; mobj->type = type; mobj->info = info; mobj->x = x; mobj->y = y; mobj->radius = info->radius; mobj->height = info->height; mobj->flags = info->flags; mobj->health = info->spawnhealth; // haleyjd 09/25/10: [STRIFE] Doesn't do this; messes up flamethrower // and a lot of other stuff using reactiontime as a counter. //if (gameskill != sk_nightmare) mobj->reactiontime = info->reactiontime; mobj->lastlook = P_Random () % MAXPLAYERS; // do not set the state with P_SetMobjState, // because action routines can not be called yet st = &states[info->spawnstate]; mobj->state = st; mobj->tics = st->tics; mobj->sprite = st->sprite; mobj->frame = st->frame; // set subsector and/or block links P_SetThingPosition (mobj); mobj->floorz = mobj->subsector->sector->floorheight; mobj->ceilingz = mobj->subsector->sector->ceilingheight; if (z == ONFLOORZ) { mobj->z = mobj->floorz; // villsa [STRIFE] if(P_GetTerrainType(mobj) != FLOOR_SOLID) mobj->flags |= MF_FEETCLIPPED; } else if (z == ONCEILINGZ) mobj->z = mobj->ceilingz - mobj->info->height; else mobj->z = z; mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; P_AddThinker (&mobj->thinker); return mobj; } // // P_RemoveMobj // // [STRIFE] Modifications for item respawn timing // mapthing_t itemrespawnque[ITEMQUESIZE]; int itemrespawntime[ITEMQUESIZE]; int iquehead; int iquetail; void P_RemoveMobj (mobj_t* mobj) { // villsa [STRIFE] removed invuln/invis. sphere exceptions if ((mobj->flags & MF_SPECIAL) && !(mobj->flags & MF_DROPPED)) { itemrespawnque[iquehead] = mobj->spawnpoint; itemrespawntime[iquehead] = leveltime + 30*TICRATE; // [STRIFE] // [STRIFE] haleyjd 20130915 // -random parameter affects the behavior of respawning items here. if(randomparm && iquehead != iquetail) { short type = itemrespawnque[iquehead].type; short options = itemrespawnque[iquehead].options; // swap the type and options of iquehead and iquetail itemrespawnque[iquehead].type = itemrespawnque[iquetail].type; itemrespawnque[iquehead].options = itemrespawnque[iquetail].options; itemrespawnque[iquetail].type = type; itemrespawnque[iquetail].options = options; } iquehead = (iquehead+1)&(ITEMQUESIZE-1); // lose one off the end? if (iquehead == iquetail) iquetail = (iquetail+1)&(ITEMQUESIZE-1); } // unlink from sector and block lists P_UnsetThingPosition (mobj); // stop any playing sound S_StopSound (mobj); // free block P_RemoveThinker ((thinker_t*)mobj); } // // P_RespawnSpecials // // [STRIFE] modification to item respawn time handling // void P_RespawnSpecials (void) { fixed_t x; fixed_t y; fixed_t z; subsector_t* ss; mobj_t* mo; mapthing_t* mthing; int i; // only respawn items in deathmatch if (deathmatch != 2) return; // nothing left to respawn? if (iquehead == iquetail) return; // haleyjd [STRIFE]: 30 second wait is not accounted for here, see above. if (leveltime < itemrespawntime[iquetail]) return; mthing = &itemrespawnque[iquetail]; x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; // spawn a teleport fog at the new spot ss = R_PointInSubsector (x,y); mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG); S_StartSound (mo, sfx_itmbk); // find which type to spawn for (i=0 ; i< NUMMOBJTYPES ; i++) { if (mthing->type == mobjinfo[i].doomednum) break; } // spawn it if (mobjinfo[i].flags & MF_SPAWNCEILING) z = ONCEILINGZ; else z = ONFLOORZ; mo = P_SpawnMobj (x,y,z, i); mo->spawnpoint = *mthing; mo->angle = ANG45 * (mthing->angle/45); // pull it from the que iquetail = (iquetail+1)&(ITEMQUESIZE-1); } // // P_SpawnPlayer // Called when a player is spawned on the level. // Most of the player structure stays unchanged // between levels. // // [STRIFE] Modifications for: // * stonecold cheat, -workparm // * default inventory/questflags // void P_SpawnPlayer(mapthing_t* mthing) { player_t* p; fixed_t x; fixed_t y; fixed_t z; mobj_t* mobj; if(mthing->type == 0) return; // not playing? if(!playeringame[mthing->type-1]) return; p = &players[mthing->type-1]; if (p->playerstate == PST_REBORN) G_PlayerReborn (mthing->type-1); x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; z = ONFLOORZ; mobj = P_SpawnMobj (x,y,z, MT_PLAYER); // set color translations for player sprites if(mthing->type > 1) mobj->flags |= (mthing->type-1)<angle = ANG45 * (mthing->angle/45); mobj->player = p; mobj->health = p->health; p->mo = mobj; p->playerstate = PST_LIVE; p->refire = 0; p->message = NULL; p->damagecount = 0; p->bonuscount = 0; p->extralight = 0; p->fixedcolormap = 0; p->viewheight = VIEWHEIGHT; // setup gun psprite P_SetupPsprites(p); // villsa [STRIFE] stonecold = false; // villsa [STRIFE] what a nasty hack... if(gamemap == 10) p->weaponowned[wp_sigil] = true; // villsa [STRIFE] instead of just giving cards in deathmatch mode, also // set accuracy to 50 and give all quest flags if(deathmatch) { int i; p->accuracy = 50; p->questflags = QF_ALLQUESTS; // 0x7fffffff for(i = 0; i < NUMCARDS; i++) p->cards[i] = true; } // villsa [STRIFE] set godmode? if(workparm) p->cheats |= CF_GODMODE; if(mthing->type - 1 == consoleplayer) { // wake up the status bar ST_Start (); // wake up the heads up text HU_Start (); } } // // P_SpawnMapThing // The fields of the mapthing should // already be in host byte order. // // [STRIFE] Modifications for: // * No Lost Souls, item count // * New mapthing_t flag bits // * 8-player support // void P_SpawnMapThing (mapthing_t* mthing) { int i; int bit; mobj_t* mobj; fixed_t x; fixed_t y; fixed_t z; // count deathmatch start positions if (mthing->type == 11) { if (deathmatch_p < &deathmatchstarts[10]) { memcpy (deathmatch_p, mthing, sizeof(*mthing)); deathmatch_p++; } return; } if (mthing->type <= 0) { // Thing type 0 is actually "player -1 start". // For some reason, Vanilla Doom accepts/ignores this. return; } // check for players specially // haleyjd 20120209: [STRIFE] 8 player starts if (mthing->type <= 8) { // save spots for respawning in network games playerstarts[mthing->type-1] = *mthing; if (!deathmatch) P_SpawnPlayer (mthing); return; } // check for apropriate skill level if (!netgame && (mthing->options & 16) ) return; if (gameskill == sk_baby) bit = 1; else if (gameskill == sk_nightmare) bit = 4; else bit = 1<<(gameskill-1); if (!(mthing->options & bit) ) return; // find which type to spawn for (i=0 ; i< NUMMOBJTYPES ; i++) if (mthing->type == mobjinfo[i].doomednum) break; if (i==NUMMOBJTYPES) I_Error ("P_SpawnMapThing: Unknown type %i at (%i, %i)", mthing->type, mthing->x, mthing->y); // don't spawn keycards and players in deathmatch if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH) return; // don't spawn any monsters if -nomonsters // villsa [STRIFE] Removed MT_SKULL if (nomonsters && (mobjinfo[i].flags & MF_COUNTKILL)) return; // spawn it x = mthing->x << FRACBITS; y = mthing->y << FRACBITS; if (mobjinfo[i].flags & MF_SPAWNCEILING) z = ONCEILINGZ; else z = ONFLOORZ; mobj = P_SpawnMobj (x,y,z, i); mobj->spawnpoint = *mthing; if (mobj->tics > 0) mobj->tics = 1 + (P_Random () % mobj->tics); if (mobj->flags & MF_COUNTKILL) totalkills++; // villsa [STRIFE] unused /* if (mobj->flags & MF_COUNTITEM) totalitems++; */ mobj->angle = ANG45 * (mthing->angle/45); if (mthing->options & MTF_AMBUSH) mobj->flags |= MF_AMBUSH; if (mthing->options & MTF_STAND) // [STRIFE] Standing mode, for NPCs mobj->flags |= MF_STAND; if (mthing->options & MTF_FRIEND) // [STRIFE] Allies mobj->flags |= MF_ALLY; if (mthing->options & MTF_TRANSLUCENT) // [STRIFE] Translucent object mobj->flags |= MF_SHADOW; if (mthing->options & MTF_MVIS) // [STRIFE] Alt. Translucency mobj->flags |= MF_MVIS; } // // GAME SPAWN FUNCTIONS // // // P_SpawnPuff // // [STRIFE] Modifications for: // * No spawn tics randomization // * Player melee behavior // extern fixed_t attackrange; void P_SpawnPuff ( fixed_t x, fixed_t y, fixed_t z ) { mobj_t* th; int t; t = P_Random(); z += ((t - P_Random()) << 10); // [STRIFE] removed momz and tics randomization th = P_SpawnMobj(x, y, z, MT_STRIFEPUFF); // [STRIFE]: new type // don't make punches spark on the wall // [STRIFE] Use a separate melee attack range for the player if(attackrange == PLAYERMELEERANGE) P_SetMobjState(th, S_POW2_00); // 141 // villsa [STRIFE] unused /* if (th->tics < 1) th->tics = 1; */ } // // P_SpawnSparkPuff // // villsa [STRIFE] new function // mobj_t* P_SpawnSparkPuff(fixed_t x, fixed_t y, fixed_t z) { int t = P_Random(); return P_SpawnMobj(x, y, ((t - P_Random()) << 10) + z, MT_SPARKPUFF); } // // P_SpawnBlood // // [STRIFE] Modifications for: // * No spawn tics randomization // * Different damage ranges for state setting // void P_SpawnBlood ( fixed_t x, fixed_t y, fixed_t z, int damage ) { mobj_t* th; int temp; temp = P_Random(); z += (temp - P_Random()) << 10; th = P_SpawnMobj(x, y, z, MT_BLOOD_DEATH); th->momz = FRACUNIT*2; // villsa [STRIFE]: removed tics randomization // villsa [STRIFE] different checks for damage range if(damage >= 10 && damage <= 13) P_SetMobjState(th, S_BLOD_00); else if(damage >= 7 && damage < 10) P_SetMobjState(th, S_BLOD_01); else if(damage < 7) P_SetMobjState(th, S_BLOD_02); } // // P_CheckMissileSpawn // Moves the missile forward a bit // and possibly explodes it right there. // // [STRIFE] Modifications for: // * No spawn tics randomization // void P_CheckMissileSpawn (mobj_t* th) { // villsa [STRIFE] removed tics randomization // move a little forward so an angle can // be computed if it immediately explodes th->x += (th->momx>>1); th->y += (th->momy>>1); th->z += (th->momz>>1); if (!P_TryMove (th, th->x, th->y)) P_ExplodeMissile (th); } // Certain functions assume that a mobj_t pointer is non-NULL, // causing a crash in some situations where it is NULL. Vanilla // Doom did not crash because of the lack of proper memory // protection. This function substitutes NULL pointers for // pointers to a dummy mobj, to avoid a crash. mobj_t *P_SubstNullMobj(mobj_t *mobj) { if (mobj == NULL) { static mobj_t dummy_mobj; dummy_mobj.x = 0; dummy_mobj.y = 0; dummy_mobj.z = 0; dummy_mobj.flags = 0; mobj = &dummy_mobj; } return mobj; } // // P_SpawnMissile // // [STRIFE] Added MVIS inaccuracy // mobj_t* P_SpawnMissile ( mobj_t* source, mobj_t* dest, mobjtype_t type ) { mobj_t* th; angle_t an; int dist; th = P_SpawnMobj (source->x, source->y, source->z + 4*8*FRACUNIT, type); if (th->info->seesound) S_StartSound (th, th->info->seesound); th->target = source; // where it came from an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y); // fuzzy player if (dest->flags & MF_SHADOW) { int t = P_Random(); // haleyjd 20110223: remove order-of-evaluation dependencies an += (t - P_Random()) << 21; } // villsa [STRIFE] check for heavily transparent things else if(dest->flags & MF_MVIS) { int t = P_Random(); an += (t - P_Random()) << 22; } th->angle = an; an >>= ANGLETOFINESHIFT; th->momx = FixedMul (th->info->speed, finecosine[an]); th->momy = FixedMul (th->info->speed, finesine[an]); dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); dist = dist / th->info->speed; if (dist < 1) dist = 1; th->momz = (dest->z - source->z) / dist; P_CheckMissileSpawn (th); return th; } // // P_SpawnFacingMissile // // villsa [STRIFE] new function // Spawn a missile based on source's angle // mobj_t* P_SpawnFacingMissile(mobj_t* source, mobj_t* target, mobjtype_t type) { mobj_t* th; angle_t an; fixed_t dist; th = P_SpawnMobj(source->x, source->y, source->z + (32*FRACUNIT), type); if(th->info->seesound) S_StartSound(th, th->info->seesound); th->target = source; // where it came from th->angle = source->angle; // haleyjd 09/06/10: fix0red an = th->angle; // fuzzy player if (target->flags & MF_SHADOW) { int t = P_Random(); an += (t - P_Random()) << 21; } // villsa [STRIFE] check for heavily transparent things else if(target->flags & MF_MVIS) { int t = P_Random(); an += (t - P_Random()) << 22; } an >>= ANGLETOFINESHIFT; th->momx = FixedMul (th->info->speed, finecosine[an]); th->momy = FixedMul (th->info->speed, finesine[an]); dist = P_AproxDistance (target->x - source->x, target->y - source->y); dist = dist / th->info->speed; if(dist < 1) dist = 1; th->momz = (target->z - source->z) / dist; P_CheckMissileSpawn (th); return th; } // // P_SpawnPlayerMissile // // Tries to aim at a nearby monster // villsa [STRIFE] now returns a mobj // * Also modified to allow up/down look, and to account for foot-clipping // by liquid terrain. // mobj_t* P_SpawnPlayerMissile(mobj_t* source, mobjtype_t type) { mobj_t* th; angle_t an; fixed_t x; fixed_t y; fixed_t z; fixed_t slope; // see which target is to be aimed at an = source->angle; slope = P_AimLineAttack (source, an, 16*64*FRACUNIT); if (!linetarget) { an += 1<<26; slope = P_AimLineAttack (source, an, 16*64*FRACUNIT); if (!linetarget) { an -= 2<<26; slope = P_AimLineAttack (source, an, 16*64*FRACUNIT); } if (!linetarget) { an = source->angle; // haleyjd 09/21/10: [STRIFE] Removed, for look up/down support. //slope = 0; } } // villsa [STRIFE] if(linetarget) source->target = linetarget; x = source->x; y = source->y; // villsa [STRIFE] if(!(source->flags & MF_FEETCLIPPED)) z = source->z + 32*FRACUNIT; else z = source->z + 22*FRACUNIT; th = P_SpawnMobj (x,y,z, type); if (th->info->seesound) S_StartSound (th, th->info->seesound); th->target = source; th->angle = an; th->momx = FixedMul( th->info->speed, finecosine[an>>ANGLETOFINESHIFT]); th->momy = FixedMul( th->info->speed, finesine[an>>ANGLETOFINESHIFT]); th->momz = FixedMul( th->info->speed, slope); P_CheckMissileSpawn (th); return th; } // // P_SpawnMortar // // villsa [STRIFE] new function // Spawn a high-arcing ballistic projectile // mobj_t* P_SpawnMortar(mobj_t *source, mobjtype_t type) { mobj_t* th; angle_t an; fixed_t slope; an = source->angle; th = P_SpawnMobj(source->x, source->y, source->z, type); th->target = source; th->angle = an; an >>= ANGLETOFINESHIFT; // haleyjd 20110203: corrected order of function calls th->momx = FixedMul(th->info->speed, finecosine[an]); th->momy = FixedMul(th->info->speed, finesine[an]); P_CheckMissileSpawn(th); slope = P_AimLineAttack(source, source->angle, 1024*FRACUNIT); th->momz = FixedMul(th->info->speed, slope); return th; }