12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code 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 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #include "Precompiled.h"
- #include "globaldata.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"
- extern bool globalNetworking;
- void G_PlayerReborn (int player);
- void P_SpawnMapThing (mapthing_t* mthing);
- //
- // P_SetMobjState
- // Returns true if the mobj is still present.
- //
- qboolean
- P_SetMobjState
- ( mobj_t* mobj,
- statenum_t state )
- {
- const state_t* st;
- do
- {
- if (state == S_NULL)
- {
- mobj->state = (const state_t *) S_NULL;
- P_RemoveMobj (mobj);
- return false;
- }
- st = &::g->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)
- st->action(mobj, NULL);
- 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, (statenum_t)mobjinfo[mo->type].deathstate);
- 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
- //
- void P_XYMovement (mobj_t* mo)
- {
- fixed_t ptryx;
- fixed_t ptryy;
- player_t* player;
- fixed_t xmove;
- fixed_t ymove;
- 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, (statenum_t)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);
- }
- else if (mo->flags & MF_MISSILE)
- {
- // explode a missile
- if (::g->ceilingline &&
- ::g->ceilingline->backsector &&
- ::g->ceilingline->backsector->ceilingpic == ::g->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_SKULLFLY) )
- 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
- if ( player&&(unsigned)((player->mo->state - ::g->states)- S_PLAY_RUN1) < 4)
- P_SetMobjState (player->mo, S_PLAY);
- 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
- mo->z += mo->momz;
- if ( mo->flags & MF_FLOAT
- && mo->target)
- {
- // float down towards target if too close
- if ( !(mo->flags & MF_SKULLFLY)
- && !(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.
- if (mo->flags & MF_SKULLFLY)
- {
- // the skull slammed into something
- mo->momz = -mo->momz;
- }
- if (mo->momz < 0)
- {
- if (mo->player
- && mo->momz < -GRAVITY*8)
- {
- // Squat down.
- // Decrease ::g->viewheight for a moment
- // after hitting the ground (hard),
- // and utter appropriate sound.
- mo->player->deltaviewheight = mo->momz>>3;
- if (globalNetworking || (mo->player == &::g->players[::g->consoleplayer]))
- S_StartSound (mo, sfx_oof);
- }
- mo->momz = 0;
- }
- mo->z = mo->floorz;
- if ( (mo->flags & MF_MISSILE)
- && !(mo->flags & MF_NOCLIP) )
- {
- 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)
- {
- // hit the ceiling
- if (mo->momz > 0)
- mo->momz = 0;
- {
- mo->z = mo->ceilingz - mo->height;
- }
- if (mo->flags & MF_SKULLFLY)
- { // the skull slammed into something
- mo->momz = -mo->momz;
- }
- if ( (mo->flags & MF_MISSILE)
- && !(mo->flags & MF_NOCLIP) )
- {
- 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) )
- {
- P_XYMovement (mobj);
- // FIXME: decent NOP/NULL/Nil function pointer please.
- if (mobj->thinker.function.acv == (actionf_v) (-1))
- return; // mobj was removed
- }
- if ( (mobj->z != mobj->floorz)
- || 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
- }
- // 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 (!::g->respawnmonsters)
- return;
- mobj->movecount++;
- if (mobj->movecount < 12*TICRATE)
- return;
- if ( ::g->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;
- const state_t* st;
- const mobjinfo_t* info;
- mobj = (mobj_t*)DoomLib::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 (::g->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 = &::g->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;
- 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
- //
- void P_RemoveMobj (mobj_t* mobj)
- {
- if ((mobj->flags & MF_SPECIAL)
- && !(mobj->flags & MF_DROPPED)
- && (mobj->type != MT_INV)
- && (mobj->type != MT_INS))
- {
- ::g->itemrespawnque[::g->iquehead] = mobj->spawnpoint;
- ::g->itemrespawntime[::g->iquehead] = ::g->leveltime;
- ::g->iquehead = (::g->iquehead+1)&(ITEMQUESIZE-1);
- // lose one off the end?
- if (::g->iquehead == ::g->iquetail)
- ::g->iquetail = (::g->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 ::g->deathmatch
- if (::g->deathmatch != 2)
- return; //
- // nothing left to respawn?
- if (::g->iquehead == ::g->iquetail)
- return;
- // wait at least 30 seconds
- if (::g->leveltime - ::g->itemrespawntime[::g->iquetail] < 30*TICRATE)
- return;
- mthing = &::g->itemrespawnque[::g->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 = (mobj_t*)P_SpawnMobj (x,y,z, (mobjtype_t)i);
- mo->spawnpoint = *mthing;
- mo->angle = ANG45 * (mthing->angle/45);
- // pull it from the que
- ::g->iquetail = (::g->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;
- // not playing?
- if (!::g->playeringame[mthing->type-1])
- return;
- p = &::g->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 ::g->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);
- // give all cards in death match mode
- if (::g->deathmatch)
- for (i=0 ; i<NUMCARDS ; i++)
- p->cards[i] = true;
- if (mthing->type-1 == ::g->consoleplayer)
- {
- // wake up the status bar
- ST_Start ();
- // wake up the heads up text
- HU_Start ();
- }
- // Give him everything is Give All is on.
- if( p->cheats & CF_GIVEALL ) {
- p->armorpoints = 200;
- p->armortype = 2;
- int i;
- for (i=0;i<NUMWEAPONS;i++)
- p->weaponowned[i] = true;
- for (i=0;i<NUMAMMO;i++)
- p->ammo[i] = p->maxammo[i];
- for (i=0;i<NUMCARDS;i++)
- p->cards[i] = true;
- }
- }
- //
- // 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 ::g->deathmatch start positions
- if (mthing->type == 11)
- {
- if (::g->deathmatch_p < &::g->deathmatchstarts[10])
- {
- memcpy (::g->deathmatch_p, mthing, sizeof(*mthing));
- ::g->deathmatch_p++;
- }
- return;
- }
- // check for ::g->players specially
- if (mthing->type <= 4)
- {
- // save spots for respawning in network games
- ::g->playerstarts[mthing->type-1] = *mthing;
- if (!::g->deathmatch)
- P_SpawnPlayer (mthing);
- return;
- }
- // check for apropriate skill level
- if (!::g->netgame && (mthing->options & 16) )
- return;
- if (::g->gameskill == sk_baby)
- bit = 1;
- else if (::g->gameskill == sk_nightmare)
- bit = 4;
- else
- bit = 1<<(::g->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 ) {
- //printf( "P_SpawnMapThing: Unknown type %i at (%i, %i)", mthing->type, mthing->x, mthing->y);
- return;
- //I_Error ("P_SpawnMapThing: Unknown type %i at (%i, %i)",
- //mthing->type,
- //mthing->x, mthing->y);
- }
- // don't spawn keycards and ::g->players in ::g->deathmatch
- if (::g->deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
- return;
- // don't spawn any monsters if -::g->nomonsters
- if (::g->nomonsters
- && ( i == MT_SKULL
- || (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 = (mobj_t*)P_SpawnMobj (x,y,z, (mobjtype_t)i);
- mobj->spawnpoint = *mthing;
- if (mobj->tics > 0)
- mobj->tics = 1 + (P_Random () % mobj->tics);
- if (mobj->flags & MF_COUNTKILL)
- ::g->totalkills++;
- if (mobj->flags & MF_COUNTITEM)
- ::g->totalitems++;
- mobj->angle = ANG45 * (mthing->angle/45);
- if (mthing->options & MTF_AMBUSH)
- mobj->flags |= MF_AMBUSH;
- }
- //
- // GAME SPAWN FUNCTIONS
- //
- //
- // P_SpawnPuff
- //
- void
- P_SpawnPuff
- ( fixed_t x,
- fixed_t y,
- fixed_t z )
- {
- mobj_t* th;
- z += ((P_Random()-P_Random())<<10);
- th = P_SpawnMobj (x,y,z, MT_PUFF);
- th->momz = FRACUNIT;
- th->tics -= P_Random()&3;
- if (th->tics < 1)
- th->tics = 1;
- // don't make punches spark on the wall
- if (::g->attackrange == MELEERANGE) {
- P_SetMobjState (th, S_PUFF3);
-
- }
- }
- //
- // 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);
- th->momz = FRACUNIT*2;
- th->tics -= P_Random()&3;
- if (th->tics < 1)
- th->tics = 1;
- if (damage <= 12 && damage >= 9)
- P_SetMobjState (th,S_BLOOD2);
- else if (damage < 9)
- P_SetMobjState (th,S_BLOOD3);
- }
- //
- // P_CheckMissileSpawn
- // Moves the missile forward a bit
- // and possibly explodes it right there.
- //
- void P_CheckMissileSpawn (mobj_t* th)
- {
- 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);
- }
- //
- // 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())<<20;
- 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_SpawnPlayerMissile
- // Tries to aim at a nearby monster
- //
- void
- 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 (!::g->linetarget)
- {
- an += 1<<26;
- slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
- if (!::g->linetarget)
- {
- an -= 2<<26;
- slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
- }
- if (!::g->linetarget)
- {
- an = source->angle;
- slope = 0;
- }
- }
- x = source->x;
- y = source->y;
- z = source->z + 4*8*FRACUNIT;
- th = P_SpawnMobj (x,y,z, type);
- if (th->info->seesound && (source->player == &::g->players[::g->consoleplayer]) ) {
- 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);
- }
|