12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009 |
- // Emacs style mode select -*- C++ -*-
- //-----------------------------------------------------------------------------
- //
- // $Id:$
- //
- // Copyright (C) 1993-1996 by id Software, Inc.
- //
- // This source is available for distribution and/or modification
- // only under the terms of the DOOM Source Code License as
- // published by id Software. All rights reserved.
- //
- // The source is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
- // for more details.
- //
- // $Log:$
- //
- // DESCRIPTION:
- // Enemy thinking, AI.
- // Action Pointer Functions
- // that are associated with states/frames.
- //
- //-----------------------------------------------------------------------------
- static const char
- rcsid[] = "$Id: p_enemy.c,v 1.5 1997/02/03 22:45:11 b1 Exp $";
- #include <stdlib.h>
- #include "m_random.h"
- #include "i_system.h"
- #include "doomdef.h"
- #include "p_local.h"
- #include "s_sound.h"
- #include "g_game.h"
- // State.
- #include "doomstat.h"
- #include "r_state.h"
- // Data.
- #include "sounds.h"
- typedef enum
- {
- DI_EAST,
- DI_NORTHEAST,
- DI_NORTH,
- DI_NORTHWEST,
- DI_WEST,
- DI_SOUTHWEST,
- DI_SOUTH,
- DI_SOUTHEAST,
- DI_NODIR,
- NUMDIRS
-
- } dirtype_t;
- //
- // P_NewChaseDir related LUT.
- //
- dirtype_t opposite[] =
- {
- DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
- DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR
- };
- dirtype_t diags[] =
- {
- DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST
- };
- void A_Fall (mobj_t *actor);
- //
- // ENEMY THINKING
- // Enemies are allways spawned
- // with targetplayer = -1, threshold = 0
- // Most monsters are spawned unaware of all players,
- // but some can be made preaware
- //
- //
- // Called by P_NoiseAlert.
- // Recursively traverse adjacent sectors,
- // sound blocking lines cut off traversal.
- //
- mobj_t* soundtarget;
- void
- P_RecursiveSound
- ( sector_t* sec,
- int soundblocks )
- {
- int i;
- line_t* check;
- sector_t* other;
-
- // wake up all monsters in this sector
- if (sec->validcount == validcount
- && sec->soundtraversed <= soundblocks+1)
- {
- return; // already flooded
- }
-
- sec->validcount = validcount;
- sec->soundtraversed = soundblocks+1;
- sec->soundtarget = soundtarget;
-
- for (i=0 ;i<sec->linecount ; i++)
- {
- check = sec->lines[i];
- if (! (check->flags & ML_TWOSIDED) )
- continue;
-
- P_LineOpening (check);
- if (openrange <= 0)
- continue; // closed door
-
- if ( sides[ check->sidenum[0] ].sector == sec)
- other = sides[ check->sidenum[1] ] .sector;
- else
- other = sides[ check->sidenum[0] ].sector;
-
- if (check->flags & ML_SOUNDBLOCK)
- {
- if (!soundblocks)
- P_RecursiveSound (other, 1);
- }
- else
- P_RecursiveSound (other, soundblocks);
- }
- }
- //
- // P_NoiseAlert
- // If a monster yells at a player,
- // it will alert other monsters to the player.
- //
- void
- P_NoiseAlert
- ( mobj_t* target,
- mobj_t* emmiter )
- {
- soundtarget = target;
- validcount++;
- P_RecursiveSound (emmiter->subsector->sector, 0);
- }
- //
- // P_CheckMeleeRange
- //
- boolean P_CheckMeleeRange (mobj_t* actor)
- {
- mobj_t* pl;
- fixed_t dist;
-
- if (!actor->target)
- return false;
-
- pl = actor->target;
- dist = P_AproxDistance (pl->x-actor->x, pl->y-actor->y);
- if (dist >= MELEERANGE-20*FRACUNIT+pl->info->radius)
- return false;
-
- if (! P_CheckSight (actor, actor->target) )
- return false;
-
- return true;
- }
- //
- // P_CheckMissileRange
- //
- boolean P_CheckMissileRange (mobj_t* actor)
- {
- fixed_t dist;
-
- if (! P_CheckSight (actor, actor->target) )
- return false;
-
- if ( actor->flags & MF_JUSTHIT )
- {
- // the target just hit the enemy,
- // so fight back!
- actor->flags &= ~MF_JUSTHIT;
- return true;
- }
-
- if (actor->reactiontime)
- return false; // do not attack yet
-
- // OPTIMIZE: get this from a global checksight
- dist = P_AproxDistance ( actor->x-actor->target->x,
- actor->y-actor->target->y) - 64*FRACUNIT;
-
- if (!actor->info->meleestate)
- dist -= 128*FRACUNIT; // no melee attack, so fire more
- dist >>= 16;
- if (actor->type == MT_VILE)
- {
- if (dist > 14*64)
- return false; // too far away
- }
-
- if (actor->type == MT_UNDEAD)
- {
- if (dist < 196)
- return false; // close for fist attack
- dist >>= 1;
- }
-
- if (actor->type == MT_CYBORG
- || actor->type == MT_SPIDER
- || actor->type == MT_SKULL)
- {
- dist >>= 1;
- }
-
- if (dist > 200)
- dist = 200;
-
- if (actor->type == MT_CYBORG && dist > 160)
- dist = 160;
-
- if (P_Random () < dist)
- return false;
-
- return true;
- }
- //
- // P_Move
- // Move in the current direction,
- // returns false if the move is blocked.
- //
- fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
- fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
- #define MAXSPECIALCROSS 8
- extern line_t* spechit[MAXSPECIALCROSS];
- extern int numspechit;
- boolean P_Move (mobj_t* actor)
- {
- fixed_t tryx;
- fixed_t tryy;
-
- line_t* ld;
-
- // warning: 'catch', 'throw', and 'try'
- // are all C++ reserved words
- boolean try_ok;
- boolean good;
-
- if (actor->movedir == DI_NODIR)
- return false;
-
- if ((unsigned)actor->movedir >= 8)
- I_Error ("Weird actor->movedir!");
-
- tryx = actor->x + actor->info->speed*xspeed[actor->movedir];
- tryy = actor->y + actor->info->speed*yspeed[actor->movedir];
- try_ok = P_TryMove (actor, tryx, tryy);
- if (!try_ok)
- {
- // open any specials
- if (actor->flags & MF_FLOAT && floatok)
- {
- // must adjust height
- if (actor->z < tmfloorz)
- actor->z += FLOATSPEED;
- else
- actor->z -= FLOATSPEED;
- actor->flags |= MF_INFLOAT;
- return true;
- }
-
- if (!numspechit)
- return false;
-
- actor->movedir = DI_NODIR;
- good = false;
- while (numspechit--)
- {
- ld = spechit[numspechit];
- // if the special is not a door
- // that can be opened,
- // return false
- if (P_UseSpecialLine (actor, ld,0))
- good = true;
- }
- return good;
- }
- else
- {
- actor->flags &= ~MF_INFLOAT;
- }
-
-
- if (! (actor->flags & MF_FLOAT) )
- actor->z = actor->floorz;
- return true;
- }
- //
- // TryWalk
- // Attempts to move actor on
- // in its current (ob->moveangle) direction.
- // If blocked by either a wall or an actor
- // returns FALSE
- // If move is either clear or blocked only by a door,
- // returns TRUE and sets...
- // If a door is in the way,
- // an OpenDoor call is made to start it opening.
- //
- boolean P_TryWalk (mobj_t* actor)
- {
- if (!P_Move (actor))
- {
- return false;
- }
- actor->movecount = P_Random()&15;
- return true;
- }
- void P_NewChaseDir (mobj_t* actor)
- {
- fixed_t deltax;
- fixed_t deltay;
-
- dirtype_t d[3];
-
- int tdir;
- dirtype_t olddir;
-
- dirtype_t turnaround;
- if (!actor->target)
- I_Error ("P_NewChaseDir: called with no target");
-
- olddir = actor->movedir;
- turnaround=opposite[olddir];
- deltax = actor->target->x - actor->x;
- deltay = actor->target->y - actor->y;
- if (deltax>10*FRACUNIT)
- d[1]= DI_EAST;
- else if (deltax<-10*FRACUNIT)
- d[1]= DI_WEST;
- else
- d[1]=DI_NODIR;
- if (deltay<-10*FRACUNIT)
- d[2]= DI_SOUTH;
- else if (deltay>10*FRACUNIT)
- d[2]= DI_NORTH;
- else
- d[2]=DI_NODIR;
- // try direct route
- if (d[1] != DI_NODIR
- && d[2] != DI_NODIR)
- {
- actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
- if (actor->movedir != turnaround && P_TryWalk(actor))
- return;
- }
- // try other directions
- if (P_Random() > 200
- || abs(deltay)>abs(deltax))
- {
- tdir=d[1];
- d[1]=d[2];
- d[2]=tdir;
- }
- if (d[1]==turnaround)
- d[1]=DI_NODIR;
- if (d[2]==turnaround)
- d[2]=DI_NODIR;
-
- if (d[1]!=DI_NODIR)
- {
- actor->movedir = d[1];
- if (P_TryWalk(actor))
- {
- // either moved forward or attacked
- return;
- }
- }
- if (d[2]!=DI_NODIR)
- {
- actor->movedir =d[2];
- if (P_TryWalk(actor))
- return;
- }
- // there is no direct path to the player,
- // so pick another direction.
- if (olddir!=DI_NODIR)
- {
- actor->movedir =olddir;
- if (P_TryWalk(actor))
- return;
- }
- // randomly determine direction of search
- if (P_Random()&1)
- {
- for ( tdir=DI_EAST;
- tdir<=DI_SOUTHEAST;
- tdir++ )
- {
- if (tdir!=turnaround)
- {
- actor->movedir =tdir;
-
- if ( P_TryWalk(actor) )
- return;
- }
- }
- }
- else
- {
- for ( tdir=DI_SOUTHEAST;
- tdir != (DI_EAST-1);
- tdir-- )
- {
- if (tdir!=turnaround)
- {
- actor->movedir =tdir;
-
- if ( P_TryWalk(actor) )
- return;
- }
- }
- }
- if (turnaround != DI_NODIR)
- {
- actor->movedir =turnaround;
- if ( P_TryWalk(actor) )
- return;
- }
- actor->movedir = DI_NODIR; // can not move
- }
- //
- // P_LookForPlayers
- // If allaround is false, only look 180 degrees in front.
- // Returns true if a player is targeted.
- //
- boolean
- P_LookForPlayers
- ( mobj_t* actor,
- boolean allaround )
- {
- int c;
- int stop;
- player_t* player;
- sector_t* sector;
- angle_t an;
- fixed_t dist;
-
- sector = actor->subsector->sector;
-
- c = 0;
- stop = (actor->lastlook-1)&3;
-
- for ( ; ; actor->lastlook = (actor->lastlook+1)&3 )
- {
- if (!playeringame[actor->lastlook])
- continue;
-
- if (c++ == 2
- || actor->lastlook == stop)
- {
- // done looking
- return false;
- }
-
- player = &players[actor->lastlook];
- if (player->health <= 0)
- continue; // dead
- if (!P_CheckSight (actor, player->mo))
- continue; // out of sight
-
- if (!allaround)
- {
- an = R_PointToAngle2 (actor->x,
- actor->y,
- player->mo->x,
- player->mo->y)
- - actor->angle;
-
- if (an > ANG90 && an < ANG270)
- {
- dist = P_AproxDistance (player->mo->x - actor->x,
- player->mo->y - actor->y);
- // if real close, react anyway
- if (dist > MELEERANGE)
- continue; // behind back
- }
- }
-
- actor->target = player->mo;
- return true;
- }
- return false;
- }
- //
- // A_KeenDie
- // DOOM II special, map 32.
- // Uses special tag 666.
- //
- void A_KeenDie (mobj_t* mo)
- {
- thinker_t* th;
- mobj_t* mo2;
- line_t junk;
- A_Fall (mo);
-
- // scan the remaining thinkers
- // to see if all Keens are dead
- for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
- {
- if (th->function.acp1 != (actionf_p1)P_MobjThinker)
- continue;
- mo2 = (mobj_t *)th;
- if (mo2 != mo
- && mo2->type == mo->type
- && mo2->health > 0)
- {
- // other Keen not dead
- return;
- }
- }
- junk.tag = 666;
- EV_DoDoor(&junk,open);
- }
- //
- // ACTION ROUTINES
- //
- //
- // A_Look
- // Stay in state until a player is sighted.
- //
- void A_Look (mobj_t* actor)
- {
- mobj_t* targ;
-
- actor->threshold = 0; // any shot will wake up
- targ = actor->subsector->sector->soundtarget;
- if (targ
- && (targ->flags & MF_SHOOTABLE) )
- {
- actor->target = targ;
- if ( actor->flags & MF_AMBUSH )
- {
- if (P_CheckSight (actor, actor->target))
- goto seeyou;
- }
- else
- goto seeyou;
- }
-
-
- if (!P_LookForPlayers (actor, false) )
- return;
-
- // go into chase state
- seeyou:
- if (actor->info->seesound)
- {
- int sound;
-
- switch (actor->info->seesound)
- {
- case sfx_posit1:
- case sfx_posit2:
- case sfx_posit3:
- sound = sfx_posit1+P_Random()%3;
- break;
- case sfx_bgsit1:
- case sfx_bgsit2:
- sound = sfx_bgsit1+P_Random()%2;
- break;
- default:
- sound = actor->info->seesound;
- break;
- }
- if (actor->type==MT_SPIDER
- || actor->type == MT_CYBORG)
- {
- // full volume
- S_StartSound (NULL, sound);
- }
- else
- S_StartSound (actor, sound);
- }
- P_SetMobjState (actor, actor->info->seestate);
- }
- //
- // A_Chase
- // Actor has a melee attack,
- // so it tries to close as fast as possible
- //
- void A_Chase (mobj_t* actor)
- {
- int delta;
- if (actor->reactiontime)
- actor->reactiontime--;
-
- // modify target threshold
- if (actor->threshold)
- {
- if (!actor->target
- || actor->target->health <= 0)
- {
- actor->threshold = 0;
- }
- else
- actor->threshold--;
- }
-
- // turn towards movement direction if not there yet
- if (actor->movedir < 8)
- {
- actor->angle &= (7<<29);
- delta = actor->angle - (actor->movedir << 29);
-
- if (delta > 0)
- actor->angle -= ANG90/2;
- else if (delta < 0)
- actor->angle += ANG90/2;
- }
- if (!actor->target
- || !(actor->target->flags&MF_SHOOTABLE))
- {
- // look for a new target
- if (P_LookForPlayers(actor,true))
- return; // got a new target
-
- P_SetMobjState (actor, actor->info->spawnstate);
- return;
- }
-
- // do not attack twice in a row
- if (actor->flags & MF_JUSTATTACKED)
- {
- actor->flags &= ~MF_JUSTATTACKED;
- if (gameskill != sk_nightmare && !fastparm)
- P_NewChaseDir (actor);
- return;
- }
-
- // check for melee attack
- if (actor->info->meleestate
- && P_CheckMeleeRange (actor))
- {
- if (actor->info->attacksound)
- S_StartSound (actor, actor->info->attacksound);
- P_SetMobjState (actor, actor->info->meleestate);
- return;
- }
-
- // check for missile attack
- if (actor->info->missilestate)
- {
- if (gameskill < sk_nightmare
- && !fastparm && actor->movecount)
- {
- goto nomissile;
- }
-
- if (!P_CheckMissileRange (actor))
- goto nomissile;
-
- P_SetMobjState (actor, actor->info->missilestate);
- actor->flags |= MF_JUSTATTACKED;
- return;
- }
- // ?
- nomissile:
- // possibly choose another target
- if (netgame
- && !actor->threshold
- && !P_CheckSight (actor, actor->target) )
- {
- if (P_LookForPlayers(actor,true))
- return; // got a new target
- }
-
- // chase towards player
- if (--actor->movecount<0
- || !P_Move (actor))
- {
- P_NewChaseDir (actor);
- }
-
- // make active sound
- if (actor->info->activesound
- && P_Random () < 3)
- {
- S_StartSound (actor, actor->info->activesound);
- }
- }
- //
- // A_FaceTarget
- //
- void A_FaceTarget (mobj_t* actor)
- {
- if (!actor->target)
- return;
-
- actor->flags &= ~MF_AMBUSH;
-
- actor->angle = R_PointToAngle2 (actor->x,
- actor->y,
- actor->target->x,
- actor->target->y);
-
- if (actor->target->flags & MF_SHADOW)
- actor->angle += (P_Random()-P_Random())<<21;
- }
- //
- // A_PosAttack
- //
- void A_PosAttack (mobj_t* actor)
- {
- int angle;
- int damage;
- int slope;
-
- if (!actor->target)
- return;
-
- A_FaceTarget (actor);
- angle = actor->angle;
- slope = P_AimLineAttack (actor, angle, MISSILERANGE);
- S_StartSound (actor, sfx_pistol);
- angle += (P_Random()-P_Random())<<20;
- damage = ((P_Random()%5)+1)*3;
- P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
- }
- void A_SPosAttack (mobj_t* actor)
- {
- int i;
- int angle;
- int bangle;
- int damage;
- int slope;
-
- if (!actor->target)
- return;
- S_StartSound (actor, sfx_shotgn);
- A_FaceTarget (actor);
- bangle = actor->angle;
- slope = P_AimLineAttack (actor, bangle, MISSILERANGE);
- for (i=0 ; i<3 ; i++)
- {
- angle = bangle + ((P_Random()-P_Random())<<20);
- damage = ((P_Random()%5)+1)*3;
- P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
- }
- }
- void A_CPosAttack (mobj_t* actor)
- {
- int angle;
- int bangle;
- int damage;
- int slope;
-
- if (!actor->target)
- return;
- S_StartSound (actor, sfx_shotgn);
- A_FaceTarget (actor);
- bangle = actor->angle;
- slope = P_AimLineAttack (actor, bangle, MISSILERANGE);
- angle = bangle + ((P_Random()-P_Random())<<20);
- damage = ((P_Random()%5)+1)*3;
- P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
- }
- void A_CPosRefire (mobj_t* actor)
- {
- // keep firing unless target got out of sight
- A_FaceTarget (actor);
- if (P_Random () < 40)
- return;
- if (!actor->target
- || actor->target->health <= 0
- || !P_CheckSight (actor, actor->target) )
- {
- P_SetMobjState (actor, actor->info->seestate);
- }
- }
- void A_SpidRefire (mobj_t* actor)
- {
- // keep firing unless target got out of sight
- A_FaceTarget (actor);
- if (P_Random () < 10)
- return;
- if (!actor->target
- || actor->target->health <= 0
- || !P_CheckSight (actor, actor->target) )
- {
- P_SetMobjState (actor, actor->info->seestate);
- }
- }
- void A_BspiAttack (mobj_t *actor)
- {
- if (!actor->target)
- return;
-
- A_FaceTarget (actor);
- // launch a missile
- P_SpawnMissile (actor, actor->target, MT_ARACHPLAZ);
- }
- //
- // A_TroopAttack
- //
- void A_TroopAttack (mobj_t* actor)
- {
- int damage;
-
- if (!actor->target)
- return;
-
- A_FaceTarget (actor);
- if (P_CheckMeleeRange (actor))
- {
- S_StartSound (actor, sfx_claw);
- damage = (P_Random()%8+1)*3;
- P_DamageMobj (actor->target, actor, actor, damage);
- return;
- }
-
- // launch a missile
- P_SpawnMissile (actor, actor->target, MT_TROOPSHOT);
- }
- void A_SargAttack (mobj_t* actor)
- {
- int damage;
- if (!actor->target)
- return;
-
- A_FaceTarget (actor);
- if (P_CheckMeleeRange (actor))
- {
- damage = ((P_Random()%10)+1)*4;
- P_DamageMobj (actor->target, actor, actor, damage);
- }
- }
- void A_HeadAttack (mobj_t* actor)
- {
- int damage;
-
- if (!actor->target)
- return;
-
- A_FaceTarget (actor);
- if (P_CheckMeleeRange (actor))
- {
- damage = (P_Random()%6+1)*10;
- P_DamageMobj (actor->target, actor, actor, damage);
- return;
- }
-
- // launch a missile
- P_SpawnMissile (actor, actor->target, MT_HEADSHOT);
- }
- void A_CyberAttack (mobj_t* actor)
- {
- if (!actor->target)
- return;
-
- A_FaceTarget (actor);
- P_SpawnMissile (actor, actor->target, MT_ROCKET);
- }
- void A_BruisAttack (mobj_t* actor)
- {
- int damage;
-
- if (!actor->target)
- return;
-
- if (P_CheckMeleeRange (actor))
- {
- S_StartSound (actor, sfx_claw);
- damage = (P_Random()%8+1)*10;
- P_DamageMobj (actor->target, actor, actor, damage);
- return;
- }
-
- // launch a missile
- P_SpawnMissile (actor, actor->target, MT_BRUISERSHOT);
- }
- //
- // A_SkelMissile
- //
- void A_SkelMissile (mobj_t* actor)
- {
- mobj_t* mo;
-
- if (!actor->target)
- return;
-
- A_FaceTarget (actor);
- actor->z += 16*FRACUNIT; // so missile spawns higher
- mo = P_SpawnMissile (actor, actor->target, MT_TRACER);
- actor->z -= 16*FRACUNIT; // back to normal
- mo->x += mo->momx;
- mo->y += mo->momy;
- mo->tracer = actor->target;
- }
- int TRACEANGLE = 0xc000000;
- void A_Tracer (mobj_t* actor)
- {
- angle_t exact;
- fixed_t dist;
- fixed_t slope;
- mobj_t* dest;
- mobj_t* th;
-
- if (gametic & 3)
- return;
-
- // spawn a puff of smoke behind the rocket
- P_SpawnPuff (actor->x, actor->y, actor->z);
-
- th = P_SpawnMobj (actor->x-actor->momx,
- actor->y-actor->momy,
- actor->z, MT_SMOKE);
-
- th->momz = FRACUNIT;
- th->tics -= P_Random()&3;
- if (th->tics < 1)
- th->tics = 1;
-
- // adjust direction
- dest = actor->tracer;
-
- if (!dest || dest->health <= 0)
- return;
-
- // change angle
- exact = R_PointToAngle2 (actor->x,
- actor->y,
- dest->x,
- dest->y);
- if (exact != actor->angle)
- {
- if (exact - actor->angle > 0x80000000)
- {
- actor->angle -= TRACEANGLE;
- if (exact - actor->angle < 0x80000000)
- actor->angle = exact;
- }
- else
- {
- actor->angle += TRACEANGLE;
- if (exact - actor->angle > 0x80000000)
- actor->angle = exact;
- }
- }
-
- exact = actor->angle>>ANGLETOFINESHIFT;
- actor->momx = FixedMul (actor->info->speed, finecosine[exact]);
- actor->momy = FixedMul (actor->info->speed, finesine[exact]);
-
- // change slope
- dist = P_AproxDistance (dest->x - actor->x,
- dest->y - actor->y);
-
- dist = dist / actor->info->speed;
- if (dist < 1)
- dist = 1;
- slope = (dest->z+40*FRACUNIT - actor->z) / dist;
- if (slope < actor->momz)
- actor->momz -= FRACUNIT/8;
- else
- actor->momz += FRACUNIT/8;
- }
- void A_SkelWhoosh (mobj_t* actor)
- {
- if (!actor->target)
- return;
- A_FaceTarget (actor);
- S_StartSound (actor,sfx_skeswg);
- }
- void A_SkelFist (mobj_t* actor)
- {
- int damage;
- if (!actor->target)
- return;
-
- A_FaceTarget (actor);
-
- if (P_CheckMeleeRange (actor))
- {
- damage = ((P_Random()%10)+1)*6;
- S_StartSound (actor, sfx_skepch);
- P_DamageMobj (actor->target, actor, actor, damage);
- }
- }
- //
- // PIT_VileCheck
- // Detect a corpse that could be raised.
- //
- mobj_t* corpsehit;
- mobj_t* vileobj;
- fixed_t viletryx;
- fixed_t viletryy;
- boolean PIT_VileCheck (mobj_t* thing)
- {
- int maxdist;
- boolean check;
-
- if (!(thing->flags & MF_CORPSE) )
- return true; // not a monster
-
- if (thing->tics != -1)
- return true; // not lying still yet
-
- if (thing->info->raisestate == S_NULL)
- return true; // monster doesn't have a raise state
-
- maxdist = thing->info->radius + mobjinfo[MT_VILE].radius;
-
- if ( abs(thing->x - viletryx) > maxdist
- || abs(thing->y - viletryy) > maxdist )
- return true; // not actually touching
-
- corpsehit = thing;
- corpsehit->momx = corpsehit->momy = 0;
- corpsehit->height <<= 2;
- check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y);
- corpsehit->height >>= 2;
- if (!check)
- return true; // doesn't fit here
-
- return false; // got one, so stop checking
- }
- //
- // A_VileChase
- // Check for ressurecting a body
- //
- void A_VileChase (mobj_t* actor)
- {
- int xl;
- int xh;
- int yl;
- int yh;
-
- int bx;
- int by;
- mobjinfo_t* info;
- mobj_t* temp;
-
- if (actor->movedir != DI_NODIR)
- {
- // check for corpses to raise
- viletryx =
- actor->x + actor->info->speed*xspeed[actor->movedir];
- viletryy =
- actor->y + actor->info->speed*yspeed[actor->movedir];
- xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT;
- xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT;
- yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT;
- yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT;
-
- vileobj = actor;
- for (bx=xl ; bx<=xh ; bx++)
- {
- for (by=yl ; by<=yh ; by++)
- {
- // Call PIT_VileCheck to check
- // whether object is a corpse
- // that canbe raised.
- if (!P_BlockThingsIterator(bx,by,PIT_VileCheck))
- {
- // got one!
- temp = actor->target;
- actor->target = corpsehit;
- A_FaceTarget (actor);
- actor->target = temp;
-
- P_SetMobjState (actor, S_VILE_HEAL1);
- S_StartSound (corpsehit, sfx_slop);
- info = corpsehit->info;
-
- P_SetMobjState (corpsehit,info->raisestate);
- corpsehit->height <<= 2;
- corpsehit->flags = info->flags;
- corpsehit->health = info->spawnhealth;
- corpsehit->target = NULL;
- return;
- }
- }
- }
- }
- // Return to normal attack.
- A_Chase (actor);
- }
- //
- // A_VileStart
- //
- void A_VileStart (mobj_t* actor)
- {
- S_StartSound (actor, sfx_vilatk);
- }
- //
- // A_Fire
- // Keep fire in front of player unless out of sight
- //
- void A_Fire (mobj_t* actor);
- void A_StartFire (mobj_t* actor)
- {
- S_StartSound(actor,sfx_flamst);
- A_Fire(actor);
- }
- void A_FireCrackle (mobj_t* actor)
- {
- S_StartSound(actor,sfx_flame);
- A_Fire(actor);
- }
- void A_Fire (mobj_t* actor)
- {
- mobj_t* dest;
- unsigned an;
-
- dest = actor->tracer;
- if (!dest)
- return;
-
- // don't move it if the vile lost sight
- if (!P_CheckSight (actor->target, dest) )
- return;
- an = dest->angle >> ANGLETOFINESHIFT;
- P_UnsetThingPosition (actor);
- actor->x = dest->x + FixedMul (24*FRACUNIT, finecosine[an]);
- actor->y = dest->y + FixedMul (24*FRACUNIT, finesine[an]);
- actor->z = dest->z;
- P_SetThingPosition (actor);
- }
- //
- // A_VileTarget
- // Spawn the hellfire
- //
- void A_VileTarget (mobj_t* actor)
- {
- mobj_t* fog;
-
- if (!actor->target)
- return;
- A_FaceTarget (actor);
- fog = P_SpawnMobj (actor->target->x,
- actor->target->x,
- actor->target->z, MT_FIRE);
-
- actor->tracer = fog;
- fog->target = actor;
- fog->tracer = actor->target;
- A_Fire (fog);
- }
- //
- // A_VileAttack
- //
- void A_VileAttack (mobj_t* actor)
- {
- mobj_t* fire;
- int an;
-
- if (!actor->target)
- return;
-
- A_FaceTarget (actor);
- if (!P_CheckSight (actor, actor->target) )
- return;
- S_StartSound (actor, sfx_barexp);
- P_DamageMobj (actor->target, actor, actor, 20);
- actor->target->momz = 1000*FRACUNIT/actor->target->info->mass;
-
- an = actor->angle >> ANGLETOFINESHIFT;
- fire = actor->tracer;
- if (!fire)
- return;
-
- // move the fire between the vile and the player
- fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
- fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
- P_RadiusAttack (fire, actor, 70 );
- }
- //
- // Mancubus attack,
- // firing three missiles (bruisers)
- // in three different directions?
- // Doesn't look like it.
- //
- #define FATSPREAD (ANG90/8)
- void A_FatRaise (mobj_t *actor)
- {
- A_FaceTarget (actor);
- S_StartSound (actor, sfx_manatk);
- }
- void A_FatAttack1 (mobj_t* actor)
- {
- mobj_t* mo;
- int an;
-
- A_FaceTarget (actor);
- // Change direction to ...
- actor->angle += FATSPREAD;
- P_SpawnMissile (actor, actor->target, MT_FATSHOT);
- mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
- mo->angle += FATSPREAD;
- an = mo->angle >> ANGLETOFINESHIFT;
- mo->momx = FixedMul (mo->info->speed, finecosine[an]);
- mo->momy = FixedMul (mo->info->speed, finesine[an]);
- }
- void A_FatAttack2 (mobj_t* actor)
- {
- mobj_t* mo;
- int an;
- A_FaceTarget (actor);
- // Now here choose opposite deviation.
- actor->angle -= FATSPREAD;
- P_SpawnMissile (actor, actor->target, MT_FATSHOT);
- mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
- mo->angle -= FATSPREAD*2;
- an = mo->angle >> ANGLETOFINESHIFT;
- mo->momx = FixedMul (mo->info->speed, finecosine[an]);
- mo->momy = FixedMul (mo->info->speed, finesine[an]);
- }
- void A_FatAttack3 (mobj_t* actor)
- {
- mobj_t* mo;
- int an;
- A_FaceTarget (actor);
-
- mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
- mo->angle -= FATSPREAD/2;
- an = mo->angle >> ANGLETOFINESHIFT;
- mo->momx = FixedMul (mo->info->speed, finecosine[an]);
- mo->momy = FixedMul (mo->info->speed, finesine[an]);
- mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
- mo->angle += FATSPREAD/2;
- an = mo->angle >> ANGLETOFINESHIFT;
- mo->momx = FixedMul (mo->info->speed, finecosine[an]);
- mo->momy = FixedMul (mo->info->speed, finesine[an]);
- }
- //
- // SkullAttack
- // Fly at the player like a missile.
- //
- #define SKULLSPEED (20*FRACUNIT)
- void A_SkullAttack (mobj_t* actor)
- {
- mobj_t* dest;
- angle_t an;
- int dist;
- if (!actor->target)
- return;
-
- dest = actor->target;
- actor->flags |= MF_SKULLFLY;
- S_StartSound (actor, actor->info->attacksound);
- A_FaceTarget (actor);
- an = actor->angle >> ANGLETOFINESHIFT;
- actor->momx = FixedMul (SKULLSPEED, finecosine[an]);
- actor->momy = FixedMul (SKULLSPEED, finesine[an]);
- dist = P_AproxDistance (dest->x - actor->x, dest->y - actor->y);
- dist = dist / SKULLSPEED;
-
- if (dist < 1)
- dist = 1;
- actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist;
- }
- //
- // A_PainShootSkull
- // Spawn a lost soul and launch it at the target
- //
- void
- A_PainShootSkull
- ( mobj_t* actor,
- angle_t angle )
- {
- fixed_t x;
- fixed_t y;
- fixed_t z;
-
- mobj_t* newmobj;
- angle_t an;
- int prestep;
- int count;
- thinker_t* currentthinker;
- // count total number of skull currently on the level
- count = 0;
- currentthinker = thinkercap.next;
- while (currentthinker != &thinkercap)
- {
- if ( (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
- && ((mobj_t *)currentthinker)->type == MT_SKULL)
- count++;
- currentthinker = currentthinker->next;
- }
- // if there are allready 20 skulls on the level,
- // don't spit another one
- if (count > 20)
- return;
- // okay, there's playe for another one
- an = angle >> ANGLETOFINESHIFT;
-
- prestep =
- 4*FRACUNIT
- + 3*(actor->info->radius + mobjinfo[MT_SKULL].radius)/2;
-
- x = actor->x + FixedMul (prestep, finecosine[an]);
- y = actor->y + FixedMul (prestep, finesine[an]);
- z = actor->z + 8*FRACUNIT;
-
- newmobj = P_SpawnMobj (x , y, z, MT_SKULL);
- // Check for movements.
- if (!P_TryMove (newmobj, newmobj->x, newmobj->y))
- {
- // kill it immediately
- P_DamageMobj (newmobj,actor,actor,10000);
- return;
- }
-
- newmobj->target = actor->target;
- A_SkullAttack (newmobj);
- }
- //
- // A_PainAttack
- // Spawn a lost soul and launch it at the target
- //
- void A_PainAttack (mobj_t* actor)
- {
- if (!actor->target)
- return;
- A_FaceTarget (actor);
- A_PainShootSkull (actor, actor->angle);
- }
- void A_PainDie (mobj_t* actor)
- {
- A_Fall (actor);
- A_PainShootSkull (actor, actor->angle+ANG90);
- A_PainShootSkull (actor, actor->angle+ANG180);
- A_PainShootSkull (actor, actor->angle+ANG270);
- }
- void A_Scream (mobj_t* actor)
- {
- int sound;
-
- switch (actor->info->deathsound)
- {
- case 0:
- return;
-
- case sfx_podth1:
- case sfx_podth2:
- case sfx_podth3:
- sound = sfx_podth1 + P_Random ()%3;
- break;
-
- case sfx_bgdth1:
- case sfx_bgdth2:
- sound = sfx_bgdth1 + P_Random ()%2;
- break;
-
- default:
- sound = actor->info->deathsound;
- break;
- }
- // Check for bosses.
- if (actor->type==MT_SPIDER
- || actor->type == MT_CYBORG)
- {
- // full volume
- S_StartSound (NULL, sound);
- }
- else
- S_StartSound (actor, sound);
- }
- void A_XScream (mobj_t* actor)
- {
- S_StartSound (actor, sfx_slop);
- }
- void A_Pain (mobj_t* actor)
- {
- if (actor->info->painsound)
- S_StartSound (actor, actor->info->painsound);
- }
- void A_Fall (mobj_t *actor)
- {
- // actor is on ground, it can be walked over
- actor->flags &= ~MF_SOLID;
- // So change this if corpse objects
- // are meant to be obstacles.
- }
- //
- // A_Explode
- //
- void A_Explode (mobj_t* thingy)
- {
- P_RadiusAttack ( thingy, thingy->target, 128 );
- }
- //
- // A_BossDeath
- // Possibly trigger special effects
- // if on first boss level
- //
- void A_BossDeath (mobj_t* mo)
- {
- thinker_t* th;
- mobj_t* mo2;
- line_t junk;
- int i;
-
- if ( gamemode == commercial)
- {
- if (gamemap != 7)
- return;
-
- if ((mo->type != MT_FATSO)
- && (mo->type != MT_BABY))
- return;
- }
- else
- {
- switch(gameepisode)
- {
- case 1:
- if (gamemap != 8)
- return;
- if (mo->type != MT_BRUISER)
- return;
- break;
-
- case 2:
- if (gamemap != 8)
- return;
- if (mo->type != MT_CYBORG)
- return;
- break;
-
- case 3:
- if (gamemap != 8)
- return;
-
- if (mo->type != MT_SPIDER)
- return;
-
- break;
-
- case 4:
- switch(gamemap)
- {
- case 6:
- if (mo->type != MT_CYBORG)
- return;
- break;
-
- case 8:
- if (mo->type != MT_SPIDER)
- return;
- break;
-
- default:
- return;
- break;
- }
- break;
-
- default:
- if (gamemap != 8)
- return;
- break;
- }
-
- }
-
- // make sure there is a player alive for victory
- for (i=0 ; i<MAXPLAYERS ; i++)
- if (playeringame[i] && players[i].health > 0)
- break;
-
- if (i==MAXPLAYERS)
- return; // no one left alive, so do not end game
-
- // scan the remaining thinkers to see
- // if all bosses are dead
- for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
- {
- if (th->function.acp1 != (actionf_p1)P_MobjThinker)
- continue;
-
- mo2 = (mobj_t *)th;
- if (mo2 != mo
- && mo2->type == mo->type
- && mo2->health > 0)
- {
- // other boss not dead
- return;
- }
- }
-
- // victory!
- if ( gamemode == commercial)
- {
- if (gamemap == 7)
- {
- if (mo->type == MT_FATSO)
- {
- junk.tag = 666;
- EV_DoFloor(&junk,lowerFloorToLowest);
- return;
- }
-
- if (mo->type == MT_BABY)
- {
- junk.tag = 667;
- EV_DoFloor(&junk,raiseToTexture);
- return;
- }
- }
- }
- else
- {
- switch(gameepisode)
- {
- case 1:
- junk.tag = 666;
- EV_DoFloor (&junk, lowerFloorToLowest);
- return;
- break;
-
- case 4:
- switch(gamemap)
- {
- case 6:
- junk.tag = 666;
- EV_DoDoor (&junk, blazeOpen);
- return;
- break;
-
- case 8:
- junk.tag = 666;
- EV_DoFloor (&junk, lowerFloorToLowest);
- return;
- break;
- }
- }
- }
-
- G_ExitLevel ();
- }
- void A_Hoof (mobj_t* mo)
- {
- S_StartSound (mo, sfx_hoof);
- A_Chase (mo);
- }
- void A_Metal (mobj_t* mo)
- {
- S_StartSound (mo, sfx_metal);
- A_Chase (mo);
- }
- void A_BabyMetal (mobj_t* mo)
- {
- S_StartSound (mo, sfx_bspwlk);
- A_Chase (mo);
- }
- void
- A_OpenShotgun2
- ( player_t* player,
- pspdef_t* psp )
- {
- S_StartSound (player->mo, sfx_dbopn);
- }
- void
- A_LoadShotgun2
- ( player_t* player,
- pspdef_t* psp )
- {
- S_StartSound (player->mo, sfx_dbload);
- }
- void
- A_ReFire
- ( player_t* player,
- pspdef_t* psp );
- void
- A_CloseShotgun2
- ( player_t* player,
- pspdef_t* psp )
- {
- S_StartSound (player->mo, sfx_dbcls);
- A_ReFire(player,psp);
- }
- mobj_t* braintargets[32];
- int numbraintargets;
- int braintargeton;
- void A_BrainAwake (mobj_t* mo)
- {
- thinker_t* thinker;
- mobj_t* m;
-
- // find all the target spots
- numbraintargets = 0;
- braintargeton = 0;
-
- thinker = thinkercap.next;
- for (thinker = thinkercap.next ;
- thinker != &thinkercap ;
- thinker = thinker->next)
- {
- if (thinker->function.acp1 != (actionf_p1)P_MobjThinker)
- continue; // not a mobj
- m = (mobj_t *)thinker;
- if (m->type == MT_BOSSTARGET )
- {
- braintargets[numbraintargets] = m;
- numbraintargets++;
- }
- }
-
- S_StartSound (NULL,sfx_bossit);
- }
- void A_BrainPain (mobj_t* mo)
- {
- S_StartSound (NULL,sfx_bospn);
- }
- void A_BrainScream (mobj_t* mo)
- {
- int x;
- int y;
- int z;
- mobj_t* th;
-
- for (x=mo->x - 196*FRACUNIT ; x< mo->x + 320*FRACUNIT ; x+= FRACUNIT*8)
- {
- y = mo->y - 320*FRACUNIT;
- z = 128 + P_Random()*2*FRACUNIT;
- th = P_SpawnMobj (x,y,z, MT_ROCKET);
- th->momz = P_Random()*512;
- P_SetMobjState (th, S_BRAINEXPLODE1);
- th->tics -= P_Random()&7;
- if (th->tics < 1)
- th->tics = 1;
- }
-
- S_StartSound (NULL,sfx_bosdth);
- }
- void A_BrainExplode (mobj_t* mo)
- {
- int x;
- int y;
- int z;
- mobj_t* th;
-
- x = mo->x + (P_Random () - P_Random ())*2048;
- y = mo->y;
- z = 128 + P_Random()*2*FRACUNIT;
- th = P_SpawnMobj (x,y,z, MT_ROCKET);
- th->momz = P_Random()*512;
- P_SetMobjState (th, S_BRAINEXPLODE1);
- th->tics -= P_Random()&7;
- if (th->tics < 1)
- th->tics = 1;
- }
- void A_BrainDie (mobj_t* mo)
- {
- G_ExitLevel ();
- }
- void A_BrainSpit (mobj_t* mo)
- {
- mobj_t* targ;
- mobj_t* newmobj;
-
- static int easy = 0;
-
- easy ^= 1;
- if (gameskill <= sk_easy && (!easy))
- return;
-
- // shoot a cube at current target
- targ = braintargets[braintargeton];
- braintargeton = (braintargeton+1)%numbraintargets;
- // spawn brain missile
- newmobj = P_SpawnMissile (mo, targ, MT_SPAWNSHOT);
- newmobj->target = targ;
- newmobj->reactiontime =
- ((targ->y - mo->y)/newmobj->momy) / newmobj->state->tics;
- S_StartSound(NULL, sfx_bospit);
- }
- void A_SpawnFly (mobj_t* mo);
- // travelling cube sound
- void A_SpawnSound (mobj_t* mo)
- {
- S_StartSound (mo,sfx_boscub);
- A_SpawnFly(mo);
- }
- void A_SpawnFly (mobj_t* mo)
- {
- mobj_t* newmobj;
- mobj_t* fog;
- mobj_t* targ;
- int r;
- mobjtype_t type;
-
- if (--mo->reactiontime)
- return; // still flying
-
- targ = mo->target;
- // First spawn teleport fog.
- fog = P_SpawnMobj (targ->x, targ->y, targ->z, MT_SPAWNFIRE);
- S_StartSound (fog, sfx_telept);
- // Randomly select monster to spawn.
- r = P_Random ();
- // Probability distribution (kind of :),
- // decreasing likelihood.
- if ( r<50 )
- type = MT_TROOP;
- else if (r<90)
- type = MT_SERGEANT;
- else if (r<120)
- type = MT_SHADOWS;
- else if (r<130)
- type = MT_PAIN;
- else if (r<160)
- type = MT_HEAD;
- else if (r<162)
- type = MT_VILE;
- else if (r<172)
- type = MT_UNDEAD;
- else if (r<192)
- type = MT_BABY;
- else if (r<222)
- type = MT_FATSO;
- else if (r<246)
- type = MT_KNIGHT;
- else
- type = MT_BRUISER;
- newmobj = P_SpawnMobj (targ->x, targ->y, targ->z, type);
- if (P_LookForPlayers (newmobj, true) )
- P_SetMobjState (newmobj, newmobj->info->seestate);
-
- // telefrag anything in this spot
- P_TeleportMove (newmobj, newmobj->x, newmobj->y);
- // remove self (i.e., cube).
- P_RemoveMobj (mo);
- }
- void A_PlayerScream (mobj_t* mo)
- {
- // Default death sound.
- int sound = sfx_pldeth;
-
- if ( (gamemode == commercial)
- && (mo->health < -50))
- {
- // IF THE PLAYER DIES
- // LESS THAN -50% WITHOUT GIBBING
- sound = sfx_pdiehi;
- }
-
- S_StartSound (mo, sound);
- }
|