1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029 |
- /*
- ===========================================================================
- 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 <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"
- extern bool globalNetworking;
- //
- // P_NewChaseDir related LUT.
- //
- const dirtype_t opposite[] =
- {
- DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
- DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR
- };
- const dirtype_t diags[] =
- {
- DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST
- };
- extern "C" void A_Fall (mobj_t *actor, void *);
- //
- // ENEMY THINKING
- // Enemies are allways spawned
- // with targetplayer = -1, threshold = 0
- // Most monsters are spawned unaware of all ::g->players,
- // but some can be made preaware
- //
- //
- // Called by P_NoiseAlert.
- // Recursively traverse adjacent ::g->sectors,
- // sound blocking ::g->lines cut off traversal.
- //
- 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 == ::g->validcount
- && sec->soundtraversed <= soundblocks+1)
- {
- return; // already flooded
- }
-
- sec->validcount = ::g->validcount;
- sec->soundtraversed = soundblocks+1;
- sec->soundtarget = ::g->soundtarget;
-
- for (i=0 ;i<sec->linecount ; i++)
- {
- check = sec->lines[i];
- if (! (check->flags & ML_TWOSIDED) )
- continue;
-
- P_LineOpening (check);
- if (::g->openrange <= 0)
- continue; // closed door
-
- if ( ::g->sides[ check->sidenum[0] ].sector == sec)
- other = ::g->sides[ check->sidenum[1] ] .sector;
- else
- other = ::g->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 )
- {
- ::g->soundtarget = target;
- ::g->validcount++;
- P_RecursiveSound (emmiter->subsector->sector, 0);
- }
- //
- // P_CheckMeleeRange
- //
- qboolean 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
- //
- qboolean 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.
- //
- const fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
- const fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
- qboolean P_Move (mobj_t* actor)
- {
- fixed_t tryx;
- fixed_t tryy;
-
- line_t* ld;
-
- // warning: 'catch', 'throw', and 'try'
- // are all C++ reserved words
- qboolean try_ok;
- qboolean 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 && ::g->floatok)
- {
- // must adjust height
- if (actor->z < ::g->tmfloorz)
- actor->z += FLOATSPEED;
- else
- actor->z -= FLOATSPEED;
- actor->flags |= MF_INFLOAT;
- return true;
- }
-
- if (!::g->numspechit)
- return false;
-
- actor->movedir = DI_NODIR;
- good = false;
- while (::g->numspechit--)
- {
- ld = ::g->spechit[::g->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.
- //
- qboolean 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 = (dirtype_t)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]=(dirtype_t)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.
- //
- qboolean
- P_LookForPlayers
- ( mobj_t* actor,
- qboolean 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 (!::g->playeringame[actor->lastlook])
- continue;
-
- if (c++ == 2
- || actor->lastlook == stop)
- {
- // done looking
- return false;
- }
-
- player = &::g->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;
- }
- extern "C" {
- //
- // A_KeenDie
- // DOOM II special, map 32.
- // Uses special tag 666.
- //
- void A_KeenDie (mobj_t* mo, void * )
- {
- thinker_t* th;
- mobj_t* mo2;
- line_t junk;
- A_Fall (mo, 0);
-
- // scan the remaining thinkers
- // to see if all Keens are dead
- for (th = ::g->thinkercap.next ; th != &::g->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,opened);
- }
- //
- // ACTION ROUTINES
- //
- //
- // A_Look
- // Stay in state until a player is sighted.
- //
- void A_Look (mobj_t* actor, void * )
- {
- 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, (statenum_t)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, void * )
- {
- 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, (statenum_t)actor->info->spawnstate);
- return;
- }
-
- // do not attack twice in a row
- if (actor->flags & MF_JUSTATTACKED)
- {
- actor->flags &= ~MF_JUSTATTACKED;
- if (::g->gameskill != sk_nightmare && !::g->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, (statenum_t)actor->info->meleestate);
- return;
- }
-
- // check for missile attack
- if (actor->info->missilestate)
- {
- if (::g->gameskill < sk_nightmare
- && !::g->fastparm && actor->movecount)
- {
- goto nomissile;
- }
-
- if (!P_CheckMissileRange (actor))
- goto nomissile;
-
- P_SetMobjState (actor, (statenum_t)actor->info->missilestate);
- actor->flags |= MF_JUSTATTACKED;
- return;
- }
- // ?
- nomissile:
- // possibly choose another target
- if (::g->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, void * )
- {
- 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, void * )
- {
- int angle;
- int damage;
- int slope;
-
- if (!actor->target)
- return;
-
- A_FaceTarget (actor, 0);
- 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, void * )
- {
- int i;
- int angle;
- int bangle;
- int damage;
- int slope;
-
- if (!actor->target)
- return;
- S_StartSound (actor, sfx_shotgn);
- A_FaceTarget (actor, 0);
- 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, void * )
- {
- int angle;
- int bangle;
- int damage;
- int slope;
-
- if (!actor->target)
- return;
- S_StartSound (actor, sfx_shotgn);
- A_FaceTarget (actor, 0);
- 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, void * )
- {
- // keep firing unless target got out of sight
- A_FaceTarget (actor, 0);
- if (P_Random () < 40)
- return;
- if (!actor->target
- || actor->target->health <= 0
- || !P_CheckSight (actor, actor->target) )
- {
- P_SetMobjState (actor, (statenum_t)actor->info->seestate);
- }
- }
- void A_SpidRefire (mobj_t* actor, void * )
- {
- // keep firing unless target got out of sight
- A_FaceTarget (actor, 0);
- if (P_Random () < 10)
- return;
- if (!actor->target
- || actor->target->health <= 0
- || !P_CheckSight (actor, actor->target) )
- {
- P_SetMobjState (actor, (statenum_t)actor->info->seestate);
- }
- }
- void A_BspiAttack (mobj_t *actor, void * )
- {
- if (!actor->target)
- return;
-
- A_FaceTarget (actor, 0);
- // launch a missile
- P_SpawnMissile (actor, actor->target, MT_ARACHPLAZ);
- }
- //
- // A_TroopAttack
- //
- void A_TroopAttack (mobj_t* actor, void * )
- {
- int damage;
-
- if (!actor->target)
- return;
-
- A_FaceTarget (actor, 0);
- 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, void * )
- {
- int damage;
- if (!actor->target)
- return;
-
- A_FaceTarget (actor, 0);
- if (P_CheckMeleeRange (actor))
- {
- damage = ((P_Random()%10)+1)*4;
- P_DamageMobj (actor->target, actor, actor, damage);
- }
- }
- void A_HeadAttack (mobj_t* actor, void * )
- {
- int damage;
-
- if (!actor->target)
- return;
-
- A_FaceTarget (actor, 0);
- 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, void * )
- {
- if (!actor->target)
- return;
-
- A_FaceTarget (actor, 0);
- P_SpawnMissile (actor, actor->target, MT_ROCKET);
- }
- void A_BruisAttack (mobj_t* actor, void * )
- {
- 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, void * )
- {
- mobj_t* mo;
-
- if (!actor->target)
- return;
-
- A_FaceTarget (actor, 0);
- 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;
- }
- void A_Tracer (mobj_t* actor, void * )
- {
- angle_t exact;
- fixed_t dist;
- fixed_t slope;
- mobj_t* dest;
- mobj_t* th;
-
- //if (::g->gametic & 3)
- //return;
- // DHM - Nerve :: Demo fix - Keep the game state deterministic!!!
- if ( ::g->leveltime & 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 -= ::g->TRACEANGLE;
- if (exact - actor->angle < 0x80000000)
- actor->angle = exact;
- }
- else
- {
- actor->angle += ::g->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, void * )
- {
- if (!actor->target)
- return;
- A_FaceTarget (actor, 0);
- S_StartSound (actor,sfx_skeswg);
- }
- void A_SkelFist (mobj_t* actor, void * )
- {
- int damage;
- if (!actor->target)
- return;
-
- A_FaceTarget (actor, 0);
-
- 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.
- //
- qboolean PIT_VileCheck (mobj_t* thing )
- {
- int maxdist;
- qboolean 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 - ::g->viletryx) > maxdist
- || abs(thing->y - ::g->viletryy) > maxdist )
- return true; // not actually touching
-
- ::g->corpsehit = thing;
- ::g->corpsehit->momx = ::g->corpsehit->momy = 0;
- ::g->corpsehit->height <<= 2;
- check = P_CheckPosition (::g->corpsehit, ::g->corpsehit->x, ::g->corpsehit->y);
- ::g->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, void * )
- {
- int xl;
- int xh;
- int yl;
- int yh;
-
- int bx;
- int by;
- const mobjinfo_t* info;
- mobj_t* temp;
-
- if (actor->movedir != DI_NODIR)
- {
- // check for corpses to raise
- ::g->viletryx =
- actor->x + actor->info->speed*xspeed[actor->movedir];
- ::g->viletryy =
- actor->y + actor->info->speed*yspeed[actor->movedir];
- xl = (::g->viletryx - ::g->bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT;
- xh = (::g->viletryx - ::g->bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT;
- yl = (::g->viletryy - ::g->bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT;
- yh = (::g->viletryy - ::g->bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT;
-
- ::g->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 = ::g->corpsehit;
- A_FaceTarget (actor, 0);
- actor->target = temp;
-
- P_SetMobjState (actor, S_VILE_HEAL1);
- S_StartSound (::g->corpsehit, sfx_slop);
- info = ::g->corpsehit->info;
-
- P_SetMobjState (::g->corpsehit,(statenum_t)info->raisestate);
- ::g->corpsehit->height <<= 2;
- ::g->corpsehit->flags = info->flags;
- ::g->corpsehit->health = info->spawnhealth;
- ::g->corpsehit->target = NULL;
- return;
- }
- }
- }
- }
- // Return to normal attack.
- A_Chase (actor, 0);
- }
- //
- // A_VileStart
- //
- void A_VileStart (mobj_t* actor, void * )
- {
- S_StartSound (actor, sfx_vilatk);
- }
- //
- // A_Fire
- // Keep fire in front of player unless out of sight
- //
- void A_Fire (mobj_t* actor, void * );
- void A_StartFire (mobj_t* actor, void * )
- {
- S_StartSound(actor,sfx_flamst);
- A_Fire(actor, 0 );
- }
- void A_FireCrackle (mobj_t* actor, void * )
- {
- S_StartSound(actor,sfx_flame);
- A_Fire(actor, 0);
- }
- void A_Fire (mobj_t* actor, void * )
- {
- 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, void * )
- {
- mobj_t* fog;
-
- if (!actor->target)
- return;
- A_FaceTarget (actor, 0);
- 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, 0);
- }
- //
- // A_VileAttack
- //
- void A_VileAttack (mobj_t* actor, void * )
- {
- mobj_t* fire;
- int an;
-
- if (!actor->target)
- return;
-
- A_FaceTarget (actor, 0);
- 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.
- //
- void A_FatRaise (mobj_t *actor, void * )
- {
- A_FaceTarget (actor, 0);
- S_StartSound (actor, sfx_manatk);
- }
- void A_FatAttack1 (mobj_t* actor, void * )
- {
- mobj_t* mo;
- int an;
-
- A_FaceTarget (actor, 0);
- // 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, void * )
- {
- mobj_t* mo;
- int an;
- A_FaceTarget (actor, 0);
- // 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, void * )
- {
- mobj_t* mo;
- int an;
- A_FaceTarget (actor, 0);
-
- 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.
- //
- void A_SkullAttack (mobj_t* actor, void * )
- {
- 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, 0);
- 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 = ::g->thinkercap.next;
- while (currentthinker != &::g->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, 0);
- }
- //
- // A_PainAttack
- // Spawn a lost soul and launch it at the target
- //
- void A_PainAttack (mobj_t* actor, void * )
- {
- if (!actor->target)
- return;
- A_FaceTarget (actor, 0);
- A_PainShootSkull (actor, actor->angle);
- }
- void A_PainDie (mobj_t* actor, void * )
- {
- A_Fall (actor, 0);
- A_PainShootSkull (actor, actor->angle+ANG90);
- A_PainShootSkull (actor, actor->angle+ANG180);
- A_PainShootSkull (actor, actor->angle+ANG270);
- }
- void A_Scream (mobj_t* actor, void * )
- {
- 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, void * )
- {
- S_StartSound (actor, sfx_slop);
- }
- void A_Pain (mobj_t* actor, void * )
- {
- if (actor->info->painsound )
- S_StartSound (actor, actor->info->painsound);
- }
- void A_Fall (mobj_t *actor, void * )
- {
- // 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, void * )
- {
- P_RadiusAttack ( thingy, thingy->target, 128 );
- }
- //
- // A_BossDeath
- // Possibly trigger special effects
- // if on first boss level
- //
- void A_BossDeath (mobj_t* mo, void * )
- {
- thinker_t* th;
- mobj_t* mo2;
- line_t junk;
- int i;
-
- if ( ::g->gamemode == commercial)
- {
- if (::g->gamemap != 7)
- return;
-
- if ((mo->type != MT_FATSO)
- && (mo->type != MT_BABY))
- return;
- }
- else
- {
- switch(::g->gameepisode)
- {
- case 1:
- if (::g->gamemap != 8)
- return;
- if (mo->type != MT_BRUISER)
- return;
- break;
-
- case 2:
- if (::g->gamemap != 8)
- return;
- if (mo->type != MT_CYBORG)
- return;
- break;
-
- case 3:
- if (::g->gamemap != 8)
- return;
-
- if (mo->type != MT_SPIDER)
- return;
-
- break;
-
- case 4:
- switch(::g->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 (::g->gamemap != 8)
- return;
- break;
- }
-
- }
-
- // make sure there is a player alive for victory
- for (i=0 ; i<MAXPLAYERS ; i++)
- if (::g->playeringame[i] && ::g->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 = ::g->thinkercap.next ; th != &::g->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 ( ::g->gamemode == commercial)
- {
- if (::g->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(::g->gameepisode)
- {
- case 1:
- junk.tag = 666;
- EV_DoFloor (&junk, lowerFloorToLowest);
- return;
- break;
-
- case 4:
- switch(::g->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, void * )
- {
- S_StartSound (mo, sfx_hoof);
- A_Chase (mo, 0);
- }
- void A_Metal (mobj_t* mo, void * )
- {
- S_StartSound (mo, sfx_metal);
- A_Chase (mo, 0);
- }
- void A_BabyMetal (mobj_t* mo, void * )
- {
- S_StartSound (mo, sfx_bspwlk);
- A_Chase (mo, 0);
- }
- void
- A_OpenShotgun2
- ( player_t* player,
- pspdef_t* psp )
- {
- if (globalNetworking || (player == &::g->players[::g->consoleplayer]))
- S_StartSound (player->mo, sfx_dbopn);
- }
- void
- A_LoadShotgun2
- ( player_t* player,
- pspdef_t* psp )
- {
- if (globalNetworking || (player == &::g->players[::g->consoleplayer]))
- S_StartSound (player->mo, sfx_dbload);
- }
- void
- A_ReFire
- ( player_t* player,
- pspdef_t* psp );
- void
- A_CloseShotgun2
- ( player_t* player,
- pspdef_t* psp )
- {
- if (globalNetworking || (player == &::g->players[::g->consoleplayer]))
- S_StartSound (player->mo, sfx_dbcls);
- A_ReFire(player,psp);
- }
- void A_BrainAwake (mobj_t* mo, void * )
- {
- thinker_t* thinker;
- mobj_t* m;
-
- // find all the target spots
- ::g->easy = 0;
- ::g->numbraintargets = 0;
- ::g->braintargeton = 0;
-
- thinker = ::g->thinkercap.next;
- for (thinker = ::g->thinkercap.next ;
- thinker != &::g->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 )
- {
- ::g->braintargets[::g->numbraintargets] = m;
- ::g->numbraintargets++;
- }
- }
-
- S_StartSound (NULL,sfx_bossit);
- }
- void A_BrainPain (mobj_t* mo, void * )
- {
- S_StartSound (NULL,sfx_bospn);
- }
- void A_BrainScream (mobj_t* mo, void * )
- {
- 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, void * )
- {
- 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, void * )
- {
- G_ExitLevel ();
- }
- void A_BrainSpit (mobj_t* mo, void * )
- {
- mobj_t* targ;
- mobj_t* newmobj;
- ::g->easy ^= 1;
- if (::g->gameskill <= sk_easy && (!::g->easy))
- return;
- if ( 1 ) {
- // count number of thinkers
- int numCorpse = 0;
- int numEnemies = 0;
- for ( thinker_t* th = ::g->thinkercap.next; th != &::g->thinkercap; th = th->next ) {
- if ( th->function.acp1 == (actionf_p1)P_MobjThinker ) {
- mobj_t* obj = (mobj_t*)th;
- if ( obj->flags & MF_CORPSE ) {
- numCorpse++;
- }
- else if ( obj->type > MT_PLAYER && obj->type < MT_KEEN ) {
- numEnemies++;
- }
- }
- }
- if ( numCorpse > 48 ) {
- for ( int i = 0; i < 12; i++ ) {
- for ( thinker_t* th = ::g->thinkercap.next; th != &::g->thinkercap; th = th->next ) {
- if ( th->function.acp1 == (actionf_p1)P_MobjThinker ) {
- mobj_t* obj = (mobj_t*)th;
- if ( obj->flags & MF_CORPSE ) {
- P_RemoveMobj( obj );
- break;
- }
- }
- }
- }
- }
- if ( numEnemies > 32 ) {
- return;
- }
- }
- // shoot a cube at current target
- targ = ::g->braintargets[::g->braintargeton];
- ::g->braintargeton = (::g->braintargeton+1) % ::g->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, void * );
- // travelling cube sound
- void A_SpawnSound (mobj_t* mo, void * )
- {
- S_StartSound (mo,sfx_boscub);
- A_SpawnFly(mo, 0);
- }
- void A_SpawnFly (mobj_t* mo, void * )
- {
- 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, (statenum_t)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, void * )
- {
- // Default death sound.
- int sound = sfx_pldeth;
-
- if ( (::g->gamemode == commercial)
- && (mo->health < -50))
- {
- // IF THE PLAYER DIES
- // LESS THAN -50% WITHOUT GIBBING
- sound = sfx_pdiehi;
- }
-
- if ( ::g->demoplayback || globalNetworking || (mo == ::g->players[::g->consoleplayer].mo))
- S_StartSound (mo, sound);
- }
- }; // extern "C"
|