Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Iskhodnyy_kod_Doom

.pdf
Скачиваний:
7
Добавлен:
13.02.2015
Размер:
1.01 Mб
Скачать

#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

//

381

//

//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

382

( 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)

 

383

{

 

 

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!");

384

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;

}

385

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;

386

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) )

387

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

 

388

}

}

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;

389

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--;

390

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]