ref: 4c9a85fa61a4298b342a76d4ac128c036b199055
dir: /src/strife/p_mobj.c/
// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // Copyright(C) 1993-1996 Id Software, Inc. // Copyright(C) 2005 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA // 02111-1307, USA. // // DESCRIPTION: // Moving object handling. Spawn functions. // //----------------------------------------------------------------------------- #include <stdio.h> #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] void G_PlayerReborn (int player); void P_SpawnMapThing (mapthing_t* mthing); // // P_SetMobjState // Returns true if the mobj is still present. // 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 // void P_ExplodeMissile (mobj_t* mo) { mo->momx = mo->momy = mo->momz = 0; P_SetMobjState (mo, mobjinfo[mo->type].deathstate); // villsa [STRIFE] unused /*mo->tics -= P_Random()&3; if (mo->tics < 1) mo->tics = 1;*/ mo->flags &= ~MF_MISSILE; if (mo->info->deathsound) S_StartSound (mo, mo->info->deathsound); } // // P_XYMovement // #define STOPSPEED 0x1000 #define FRICTION 0xe800 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) { // 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; } if (mo->flags & (MF_MISSILE | MF_BOUNCE) ) // villsa [STRIFE] replace skullfly flag with MF_BOUNCE return; // no friction for missiles ever if (mo->z > mo->floorz) 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] TODO - verify 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 // 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 // Note (id): // somebody left this after the setting momz to 0, // kinda useless there. // // cph - This was the a bug in the linuxdoom-1.10 source which // caused it not to sync Doom 2 v1.9 demos. Someone // added the above comment and moved up the following code. So // demos would desync in close lost soul fights. // Note that this only applies to original Doom 1 or Doom2 demos - not // Final Doom and Ultimate Doom. So we test demo_compatibility *and* // gamemission. (Note we assume that Doom1 is always Ult Doom, which // seems to hold for most published demos.) // // fraggle - cph got the logic here slightly wrong. There are three // versions of Doom 1.9: // // * The version used in registered doom 1.9 + doom2 - no bounce // * The version used in ultimate doom - has bounce // * The version used in final doom - has bounce // // So we need to check that this is either retail or commercial // (but not doom2) //int correct_lost_soul_bounce = gameversion >= exe_ultimate; if (/*correct_lost_soul_bounce &&*/ 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 if(mo->momz < -(20*FRACUNIT)) { P_DamageMobj(mo, NULL, mo, (mo->momz >> 32) / -25000); 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); return; } } else 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); return; } } } // // P_NightmareRespawn // void P_NightmareRespawn (mobj_t* mobj) { fixed_t x; fixed_t y; fixed_t z; subsector_t* ss; 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); mo = P_SpawnMobj (x, y, ss->sector->floorheight , 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; mo->reactiontime = 18; // remove the old monster, P_RemoveMobj (mobj); } // // P_MobjThinker // 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] 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] 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--; // 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++; if (mobj->movecount < 12*TICRATE) return; if ( leveltime&31 ) return; if (P_Random () > 4) return; P_NightmareRespawn (mobj); } } // // P_SpawnMobj // 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; 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 // mapthing_t itemrespawnque[ITEMQUESIZE]; int itemrespawntime[ITEMQUESIZE]; int iquehead; int iquetail; void P_RemoveMobj (mobj_t* mobj) { if ((mobj->flags & MF_SPECIAL) && !(mobj->flags & MF_DROPPED) /*&& (mobj->type != MT_INV) // villsa [STRIFE] unused && (mobj->type != MT_INS)*/) { itemrespawnque[iquehead] = mobj->spawnpoint; itemrespawntime[iquehead] = leveltime; 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 // 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; // wait at least 30 seconds if (leveltime - itemrespawntime[iquetail] < 30*TICRATE) 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. // void P_SpawnPlayer(mapthing_t* mthing) { player_t* p; fixed_t x; fixed_t y; fixed_t z; mobj_t* mobj; int i; 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)<<MF_TRANSSHIFT; mobj->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 giving cards in deathmatch mode, set // accuracy to 50 and give all quest flags if(deathmatch) { 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. // 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 // STRIFE-TODO: Need 8 player starts if (mthing->type <= 4) { // 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); */ // haleyjd 08/29/10: STRIFE-FIXME: Temporarily disabled I_Error for testing purposes if (i == NUMMOBJTYPES) return; // 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 // extern fixed_t attackrange; void P_SpawnPuff ( fixed_t x, fixed_t y, fixed_t z ) { mobj_t* th; int t = P_Random(); z += ((t - P_Random())<<10); // [STRIFE] Unused //th->momz = FRACUNIT; //th->tics -= P_Random()&3; 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) { return P_SpawnMobj(x, y, ((P_Random() - P_Random()) << 10) + z, MT_SPARKPUFF); } // // P_SpawnBlood // void P_SpawnBlood ( fixed_t x, fixed_t y, fixed_t z, int damage ) { mobj_t* th; z += ((P_Random()-P_Random())<<10); th = P_SpawnMobj (x,y,z, MT_BLOOD_DEATH); th->momz = FRACUNIT*2; //th->tics -= P_Random()&3; // villsa [STRIFE] unused // villsa [STRIFE] unused /*if (th->tics < 1) th->tics = 1;*/ // villsa [STRIFE] different checks for damage range if (damage >= 10 && damage <= 13) P_SetMobjState (th,S_BLOD_00); else if (damage < 10 && damage >= 7) 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. // void P_CheckMissileSpawn (mobj_t* th) { // villsa [STRIFE] unused /*th->tics -= P_Random()&3; if (th->tics < 1) th->tics = 1;*/ // 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 // 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) an += (P_Random()-P_Random())<<21; // villsa [STRIFE] check for heavily transparent things else if(dest->flags & MF_MVIS) an += (P_Random()-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 // 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; 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; slope = P_AimLineAttack(source, source->angle, 1024*FRACUNIT); th->momx = FixedMul(th->info->speed, finecosine[an]); th->momy = FixedMul(th->info->speed, finesine[an]); th->momz = FixedMul(th->info->speed, slope); P_CheckMissileSpawn(th); return th; }