1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354 |
- /*
- ===========================================================================
- 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_bbox.h"
- #include "m_random.h"
- #include "i_system.h"
- #include "doomdef.h"
- #include "p_local.h"
- #include "s_sound.h"
- // State.
- #include "doomstat.h"
- #include "r_state.h"
- // Data.
- #include "sounds.h"
- #include "Main.h"
- // If "floatok" true, move would be ok
- // if within "tmfloorz - tmceilingz".
- // keep track of the line that lowers the ceiling,
- // so missiles don't explode against sky hack walls
- // keep track of special ::g->lines as they are hit,
- // but don't process them until the move is proven valid
- //
- // TELEPORT MOVE
- //
- //
- // PIT_StompThing
- //
- qboolean PIT_StompThing (mobj_t* thing)
- {
- fixed_t blockdist;
-
- if (!(thing->flags & MF_SHOOTABLE) )
- return true;
-
- blockdist = thing->radius + ::g->tmthing->radius;
-
- if ( abs(thing->x - ::g->tmx) >= blockdist
- || abs(thing->y - ::g->tmy) >= blockdist )
- {
- // didn't hit it
- return true;
- }
-
- // don't clip against self
- if (thing == ::g->tmthing)
- return true;
-
- // monsters don't stomp things except on boss level
- if ( !::g->tmthing->player && ::g->gamemap != 30)
- return false;
-
- P_DamageMobj (thing, ::g->tmthing, ::g->tmthing, 10000);
-
- return true;
- }
- //
- // P_TeleportMove
- //
- qboolean
- P_TeleportMove
- ( mobj_t* thing,
- fixed_t x,
- fixed_t y )
- {
- int xl;
- int xh;
- int yl;
- int yh;
- int bx;
- int by;
-
- subsector_t* newsubsec;
-
- // kill anything occupying the position
- ::g->tmthing = thing;
- ::g->tmflags = thing->flags;
-
- ::g->tmx = x;
- ::g->tmy = y;
-
- ::g->tmbbox[BOXTOP] = y + ::g->tmthing->radius;
- ::g->tmbbox[BOXBOTTOM] = y - ::g->tmthing->radius;
- ::g->tmbbox[BOXRIGHT] = x + ::g->tmthing->radius;
- ::g->tmbbox[BOXLEFT] = x - ::g->tmthing->radius;
- newsubsec = R_PointInSubsector (x,y);
- ::g->ceilingline = NULL;
-
- // The base floor/ceiling is from the subsector
- // that contains the point.
- // Any contacted ::g->lines the step closer together
- // will adjust them.
- ::g->tmfloorz = ::g->tmdropoffz = newsubsec->sector->floorheight;
- ::g->tmceilingz = newsubsec->sector->ceilingheight;
-
- ::g->validcount++;
- ::g->numspechit = 0;
-
- // stomp on any things contacted
- xl = (::g->tmbbox[BOXLEFT] - ::g->bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
- xh = (::g->tmbbox[BOXRIGHT] - ::g->bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
- yl = (::g->tmbbox[BOXBOTTOM] - ::g->bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
- yh = (::g->tmbbox[BOXTOP] - ::g->bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
- for (bx=xl ; bx<=xh ; bx++)
- for (by=yl ; by<=yh ; by++)
- if (!P_BlockThingsIterator(bx,by,PIT_StompThing))
- return false;
-
- // the move is ok,
- // so link the thing into its new position
- P_UnsetThingPosition (thing);
- thing->floorz = ::g->tmfloorz;
- thing->ceilingz = ::g->tmceilingz;
- thing->x = x;
- thing->y = y;
- P_SetThingPosition (thing);
-
- return true;
- }
- //
- // MOVEMENT ITERATOR FUNCTIONS
- //
- //
- // PIT_CheckLine
- // Adjusts ::g->tmfloorz and ::g->tmceilingz as ::g->lines are contacted
- //
- qboolean PIT_CheckLine (line_t* ld)
- {
- if (::g->tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
- || ::g->tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
- || ::g->tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
- || ::g->tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] )
- return true;
- if (P_BoxOnLineSide (::g->tmbbox, ld) != -1)
- return true;
-
- // A line has been hit
-
- // The moving thing's destination position will cross
- // the given line.
- // If this should not be allowed, return false.
- // If the line is special, keep track of it
- // to process later if the move is proven ok.
- // NOTE: specials are NOT sorted by order,
- // so two special ::g->lines that are only 8 pixels apart
- // could be crossed in either order.
-
- if (!ld->backsector)
- return false; // one sided line
-
- if (!(::g->tmthing->flags & MF_MISSILE) )
- {
- if ( ld->flags & ML_BLOCKING )
- return false; // explicitly blocking everything
- if ( !::g->tmthing->player && ld->flags & ML_BLOCKMONSTERS )
- return false; // block monsters only
- }
- // set ::g->openrange, ::g->opentop, ::g->openbottom
- P_LineOpening (ld);
-
- // adjust floor / ceiling heights
- if (::g->opentop < ::g->tmceilingz)
- {
- ::g->tmceilingz = ::g->opentop;
- ::g->ceilingline = ld;
- }
- if (::g->openbottom > ::g->tmfloorz)
- ::g->tmfloorz = ::g->openbottom;
- if (::g->lowfloor < ::g->tmdropoffz)
- ::g->tmdropoffz = ::g->lowfloor;
- // if contacted a special line, add it to the list
- if (ld->special && ::g->numspechit < MAXSPECIALCROSS )
- {
- ::g->spechit[::g->numspechit] = ld;
- ::g->numspechit++;
- }
- return true;
- }
- //
- // PIT_CheckThing
- //
- qboolean PIT_CheckThing (mobj_t* thing)
- {
- fixed_t blockdist;
- qboolean solid;
- int damage;
-
- if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE) ))
- return true;
-
- blockdist = thing->radius + ::g->tmthing->radius;
- if ( abs(thing->x - ::g->tmx) >= blockdist
- || abs(thing->y - ::g->tmy) >= blockdist )
- {
- // didn't hit it
- return true;
- }
-
- // don't clip against self
- if (thing == ::g->tmthing)
- return true;
-
- // check for skulls slamming into things
- if (::g->tmthing->flags & MF_SKULLFLY)
- {
- damage = ((P_Random()%8)+1)*::g->tmthing->info->damage;
-
- P_DamageMobj (thing, ::g->tmthing, ::g->tmthing, damage);
-
- ::g->tmthing->flags &= ~MF_SKULLFLY;
- ::g->tmthing->momx = ::g->tmthing->momy = ::g->tmthing->momz = 0;
-
- P_SetMobjState (::g->tmthing, (statenum_t)::g->tmthing->info->spawnstate);
-
- return false; // stop moving
- }
-
- // missiles can hit other things
- if (::g->tmthing->flags & MF_MISSILE)
- {
- // see if it went over / under
- if (::g->tmthing->z > thing->z + thing->height)
- return true; // overhead
- if (::g->tmthing->z+::g->tmthing->height < thing->z)
- return true; // underneath
-
- if (::g->tmthing->target && (
- ::g->tmthing->target->type == thing->type ||
- (::g->tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)||
- (::g->tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT) ) )
- {
- // Don't hit same species as originator.
- if (thing == ::g->tmthing->target)
- return true;
- if (thing->type != MT_PLAYER)
- {
- // Explode, but do no damage.
- // Let ::g->players missile other ::g->players.
- return false;
- }
- }
-
- if (! (thing->flags & MF_SHOOTABLE) )
- {
- // didn't do any damage
- return !(thing->flags & MF_SOLID);
- }
-
- // damage / explode
- damage = ((P_Random()%8)+1)*::g->tmthing->info->damage;
- P_DamageMobj (thing, ::g->tmthing, ::g->tmthing->target, damage);
- // don't traverse any more
- return false;
- }
-
- // check for special pickup
- if (thing->flags & MF_SPECIAL)
- {
- solid = thing->flags&MF_SOLID;
- if (::g->tmflags&MF_PICKUP)
- {
- // can remove thing
- P_TouchSpecialThing (thing, ::g->tmthing);
- }
- return !solid;
- }
-
- return !(thing->flags & MF_SOLID);
- }
- //
- // MOVEMENT CLIPPING
- //
- //
- // P_CheckPosition
- // This is purely informative, nothing is modified
- // (except things picked up).
- //
- // in:
- // a mobj_t (can be valid or invalid)
- // a position to be checked
- // (doesn't need to be related to the mobj_t->x,y)
- //
- // during:
- // special things are touched if MF_PICKUP
- // early out on solid lines?
- //
- // out:
- // newsubsec
- // floorz
- // ceilingz
- // ::g->tmdropoffz
- // the lowest point contacted
- // (monsters won't move to a dropoff)
- // speciallines[]
- // numspeciallines
- //
- qboolean
- P_CheckPosition
- ( mobj_t* thing,
- fixed_t x,
- fixed_t y )
- {
- int xl;
- int xh;
- int yl;
- int yh;
- int bx;
- int by;
- subsector_t* newsubsec;
- ::g->tmthing = thing;
- ::g->tmflags = thing->flags;
-
- ::g->tmx = x;
- ::g->tmy = y;
-
- ::g->tmbbox[BOXTOP] = y + ::g->tmthing->radius;
- ::g->tmbbox[BOXBOTTOM] = y - ::g->tmthing->radius;
- ::g->tmbbox[BOXRIGHT] = x + ::g->tmthing->radius;
- ::g->tmbbox[BOXLEFT] = x - ::g->tmthing->radius;
- newsubsec = R_PointInSubsector (x,y);
- ::g->ceilingline = NULL;
-
- // The base floor / ceiling is from the subsector
- // that contains the point.
- // Any contacted ::g->lines the step closer together
- // will adjust them.
- ::g->tmfloorz = ::g->tmdropoffz = newsubsec->sector->floorheight;
- ::g->tmceilingz = newsubsec->sector->ceilingheight;
-
- ::g->validcount++;
- ::g->numspechit = 0;
- if ( ::g->tmflags & MF_NOCLIP )
- return true;
-
- // Check things first, possibly picking things up.
- // The bounding box is extended by MAXRADIUS
- // because mobj_ts are grouped into mapblocks
- // based on their origin point, and can overlap
- // into adjacent blocks by up to MAXRADIUS units.
- xl = (::g->tmbbox[BOXLEFT] - ::g->bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
- xh = (::g->tmbbox[BOXRIGHT] - ::g->bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
- yl = (::g->tmbbox[BOXBOTTOM] - ::g->bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
- yh = (::g->tmbbox[BOXTOP] - ::g->bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
- for (bx=xl ; bx<=xh ; bx++)
- for (by=yl ; by<=yh ; by++)
- if (!P_BlockThingsIterator(bx,by,PIT_CheckThing))
- return false;
-
- // check ::g->lines
- xl = (::g->tmbbox[BOXLEFT] - ::g->bmaporgx)>>MAPBLOCKSHIFT;
- xh = (::g->tmbbox[BOXRIGHT] - ::g->bmaporgx)>>MAPBLOCKSHIFT;
- yl = (::g->tmbbox[BOXBOTTOM] - ::g->bmaporgy)>>MAPBLOCKSHIFT;
- yh = (::g->tmbbox[BOXTOP] - ::g->bmaporgy)>>MAPBLOCKSHIFT;
- for (bx=xl ; bx<=xh ; bx++)
- for (by=yl ; by<=yh ; by++)
- if (!P_BlockLinesIterator (bx,by,PIT_CheckLine))
- return false;
- return true;
- }
- //
- // P_TryMove
- // Attempt to move to a new position,
- // crossing special ::g->lines unless MF_TELEPORT is set.
- //
- qboolean
- P_TryMove
- ( mobj_t* thing,
- fixed_t x,
- fixed_t y )
- {
- fixed_t oldx;
- fixed_t oldy;
- int side;
- int oldside;
- line_t* ld;
- ::g->floatok = false;
- if (!P_CheckPosition (thing, x, y))
- return false; // solid wall or thing
-
- if ( !(thing->flags & MF_NOCLIP) )
- {
- if (::g->tmceilingz - ::g->tmfloorz < thing->height)
- return false; // doesn't fit
- ::g->floatok = true;
-
- if ( !(thing->flags&MF_TELEPORT)
- &&::g->tmceilingz - thing->z < thing->height)
- return false; // mobj must lower itself to fit
- if ( !(thing->flags&MF_TELEPORT)
- && ::g->tmfloorz - thing->z > 24*FRACUNIT )
- return false; // too big a step up
- if ( !(thing->flags&(MF_DROPOFF|MF_FLOAT))
- && ::g->tmfloorz - ::g->tmdropoffz > 24*FRACUNIT )
- return false; // don't stand over a dropoff
- }
-
- // the move is ok,
- // so link the thing into its new position
- P_UnsetThingPosition (thing);
- oldx = thing->x;
- oldy = thing->y;
- thing->floorz = ::g->tmfloorz;
- thing->ceilingz = ::g->tmceilingz;
- thing->x = x;
- thing->y = y;
- P_SetThingPosition (thing);
-
- // if any special ::g->lines were hit, do the effect
- if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
- {
- while (::g->numspechit--)
- {
- // see if the line was crossed
- ld = ::g->spechit[::g->numspechit];
- side = P_PointOnLineSide (thing->x, thing->y, ld);
- oldside = P_PointOnLineSide (oldx, oldy, ld);
- if (side != oldside)
- {
- if (ld->special)
- P_CrossSpecialLine (ld-::g->lines, oldside, thing);
- }
- }
- }
- return true;
- }
- //
- // P_ThingHeightClip
- // Takes a valid thing and adjusts the thing->floorz,
- // thing->ceilingz, and possibly thing->z.
- // This is called for all nearby monsters
- // whenever a sector changes height.
- // If the thing doesn't fit,
- // the z will be set to the lowest value
- // and false will be returned.
- //
- qboolean P_ThingHeightClip (mobj_t* thing)
- {
- qboolean onfloor;
-
- onfloor = (thing->z == thing->floorz);
-
- P_CheckPosition (thing, thing->x, thing->y);
- // what about stranding a monster partially off an edge?
-
- thing->floorz = ::g->tmfloorz;
- thing->ceilingz = ::g->tmceilingz;
-
- if (onfloor)
- {
- // walking monsters rise and fall with the floor
- thing->z = thing->floorz;
- }
- else
- {
- // don't adjust a floating monster unless forced to
- if (thing->z+thing->height > thing->ceilingz)
- thing->z = thing->ceilingz - thing->height;
- }
-
- if (thing->ceilingz - thing->floorz < thing->height)
- return false;
-
- return true;
- }
- //
- // SLIDE MOVE
- // Allows the player to slide along any angled walls.
- //
- //
- // P_HitSlideLine
- // Adjusts the xmove / ymove
- // so that the next move will slide along the wall.
- //
- void P_HitSlideLine (line_t* ld)
- {
- int side;
- angle_t lineangle;
- angle_t moveangle;
- angle_t deltaangle;
-
- fixed_t movelen;
- fixed_t newlen;
-
-
- if (ld->slopetype == ST_HORIZONTAL)
- {
- ::g->tmymove = 0;
- return;
- }
-
- if (ld->slopetype == ST_VERTICAL)
- {
- ::g->tmxmove = 0;
- return;
- }
-
- side = P_PointOnLineSide (::g->slidemo->x, ::g->slidemo->y, ld);
-
- lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
- if (side == 1)
- lineangle += ANG180;
- moveangle = R_PointToAngle2 (0,0, ::g->tmxmove, ::g->tmymove);
- deltaangle = moveangle-lineangle;
- if (deltaangle > ANG180)
- deltaangle += ANG180;
- // I_Error ("SlideLine: ang>ANG180");
- lineangle >>= ANGLETOFINESHIFT;
- deltaangle >>= ANGLETOFINESHIFT;
-
- movelen = P_AproxDistance (::g->tmxmove, ::g->tmymove);
- newlen = FixedMul (movelen, finecosine[deltaangle]);
- ::g->tmxmove = FixedMul (newlen, finecosine[lineangle]);
- ::g->tmymove = FixedMul (newlen, finesine[lineangle]);
- }
- //
- // PTR_SlideTraverse
- //
- qboolean PTR_SlideTraverse (intercept_t* in)
- {
- line_t* li;
-
- if (!in->isaline)
- I_Error ("PTR_SlideTraverse: not a line?");
-
- li = in->d.line;
-
- if ( ! (li->flags & ML_TWOSIDED) )
- {
- if (P_PointOnLineSide (::g->slidemo->x, ::g->slidemo->y, li))
- {
- // don't hit the back side
- return true;
- }
- goto isblocking;
- }
- // set ::g->openrange, ::g->opentop, ::g->openbottom
- P_LineOpening (li);
-
- if (::g->openrange < ::g->slidemo->height)
- goto isblocking; // doesn't fit
-
- if (::g->opentop - ::g->slidemo->z < ::g->slidemo->height)
- goto isblocking; // mobj is too high
- if (::g->openbottom - ::g->slidemo->z > 24*FRACUNIT )
- goto isblocking; // too big a step up
- // this line doesn't block movement
- return true;
-
- // the line does block movement,
- // see if it is closer than best so far
- isblocking:
- if (in->frac < ::g->bestslidefrac)
- {
- ::g->secondslidefrac = ::g->bestslidefrac;
- ::g->secondslideline = ::g->bestslideline;
- ::g->bestslidefrac = in->frac;
- ::g->bestslideline = li;
- }
-
- return false; // stop
- }
- //
- // P_SlideMove
- // The momx / momy move is bad, so try to slide
- // along a wall.
- // Find the first line hit, move flush to it,
- // and slide along it
- //
- // This is a kludgy mess.
- //
- void P_SlideMove (mobj_t* mo)
- {
- fixed_t leadx;
- fixed_t leady;
- fixed_t trailx;
- fixed_t traily;
- fixed_t newx;
- fixed_t newy;
- int hitcount;
-
- ::g->slidemo = mo;
- hitcount = 0;
-
- retry:
- if (++hitcount == 3)
- goto stairstep; // don't loop forever
-
- // ::g->trace along the three leading corners
- if (mo->momx > 0)
- {
- leadx = mo->x + mo->radius;
- trailx = mo->x - mo->radius;
- }
- else
- {
- leadx = mo->x - mo->radius;
- trailx = mo->x + mo->radius;
- }
-
- if (mo->momy > 0)
- {
- leady = mo->y + mo->radius;
- traily = mo->y - mo->radius;
- }
- else
- {
- leady = mo->y - mo->radius;
- traily = mo->y + mo->radius;
- }
-
- ::g->bestslidefrac = FRACUNIT+1;
-
- P_PathTraverse ( leadx, leady, leadx+mo->momx, leady+mo->momy,
- PT_ADDLINES, PTR_SlideTraverse );
- P_PathTraverse ( trailx, leady, trailx+mo->momx, leady+mo->momy,
- PT_ADDLINES, PTR_SlideTraverse );
- P_PathTraverse ( leadx, traily, leadx+mo->momx, traily+mo->momy,
- PT_ADDLINES, PTR_SlideTraverse );
-
- // move up to the wall
- if (::g->bestslidefrac == FRACUNIT+1)
- {
- // the move most have hit the middle, so stairstep
- stairstep:
- if (!P_TryMove (mo, mo->x, mo->y + mo->momy))
- P_TryMove (mo, mo->x + mo->momx, mo->y);
- return;
- }
- // fudge a bit to make sure it doesn't hit
- ::g->bestslidefrac -= 0x800;
- if (::g->bestslidefrac > 0)
- {
- newx = FixedMul (mo->momx, ::g->bestslidefrac);
- newy = FixedMul (mo->momy, ::g->bestslidefrac);
-
- if (!P_TryMove (mo, mo->x+newx, mo->y+newy))
- goto stairstep;
- }
-
- // Now continue along the wall.
- // First calculate remainder.
- ::g->bestslidefrac = FRACUNIT-(::g->bestslidefrac+0x800);
-
- if (::g->bestslidefrac > FRACUNIT)
- ::g->bestslidefrac = FRACUNIT;
-
- if (::g->bestslidefrac <= 0)
- return;
-
- ::g->tmxmove = FixedMul (mo->momx, ::g->bestslidefrac);
- ::g->tmymove = FixedMul (mo->momy, ::g->bestslidefrac);
- P_HitSlideLine (::g->bestslideline); // clip the moves
- mo->momx = ::g->tmxmove;
- mo->momy = ::g->tmymove;
-
- if (!P_TryMove (mo, mo->x+::g->tmxmove, mo->y+::g->tmymove))
- {
- goto retry;
- }
- }
- //
- // P_LineAttack
- //
- // Height if not aiming up or down
- // ???: use slope for monsters?
- // slopes to top and bottom of target
- //
- // PTR_AimTraverse
- // Sets linetaget and ::g->aimslope when a target is aimed at.
- //
- qboolean
- PTR_AimTraverse (intercept_t* in)
- {
- line_t* li;
- mobj_t* th;
- fixed_t slope;
- fixed_t thingtopslope;
- fixed_t thingbottomslope;
- fixed_t dist;
-
- if (in->isaline)
- {
- li = in->d.line;
-
- if ( !(li->flags & ML_TWOSIDED) )
- return false; // stop
-
- // Crosses a two sided line.
- // A two sided line will restrict
- // the possible target ranges.
- P_LineOpening (li);
-
- if (::g->openbottom >= ::g->opentop)
- return false; // stop
-
- dist = FixedMul (::g->attackrange, in->frac);
- if (li->frontsector->floorheight != li->backsector->floorheight)
- {
- slope = FixedDiv (::g->openbottom - ::g->shootz , dist);
- if (slope > ::g->bottomslope)
- ::g->bottomslope = slope;
- }
-
- if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
- {
- slope = FixedDiv (::g->opentop - ::g->shootz , dist);
- if (slope < ::g->topslope)
- ::g->topslope = slope;
- }
-
- if (::g->topslope <= ::g->bottomslope)
- return false; // stop
-
- return true; // shot continues
- }
-
- // shoot a thing
- th = in->d.thing;
- if (th == ::g->shootthing)
- return true; // can't shoot self
-
- if (!(th->flags&MF_SHOOTABLE))
- return true; // corpse or something
- // check angles to see if the thing can be aimed at
- dist = FixedMul (::g->attackrange, in->frac);
- thingtopslope = FixedDiv (th->z+th->height - ::g->shootz , dist);
- if (thingtopslope < ::g->bottomslope)
- return true; // shot over the thing
- thingbottomslope = FixedDiv (th->z - ::g->shootz, dist);
- if (thingbottomslope > ::g->topslope)
- return true; // shot under the thing
-
- // this thing can be hit!
- if (thingtopslope > ::g->topslope)
- thingtopslope = ::g->topslope;
-
- if (thingbottomslope < ::g->bottomslope)
- thingbottomslope = ::g->bottomslope;
- ::g->aimslope = (thingtopslope+thingbottomslope)/2;
- ::g->linetarget = th;
- return false; // don't go any farther
- }
- //
- // PTR_ShootTraverse
- //
- qboolean PTR_ShootTraverse (intercept_t* in)
- {
- fixed_t x;
- fixed_t y;
- fixed_t z;
- fixed_t frac;
-
- line_t* li;
-
- mobj_t* th;
- fixed_t slope;
- fixed_t dist;
- fixed_t thingtopslope;
- fixed_t thingbottomslope;
-
- if (in->isaline)
- {
- li = in->d.line;
-
- if (li->special)
- P_ShootSpecialLine (::g->shootthing, li);
- if ( !(li->flags & ML_TWOSIDED) )
- goto hitline;
-
- // crosses a two sided line
- P_LineOpening (li);
-
- dist = FixedMul (::g->attackrange, in->frac);
- if (li->frontsector->floorheight != li->backsector->floorheight)
- {
- slope = FixedDiv (::g->openbottom - ::g->shootz , dist);
- if (slope > ::g->aimslope)
- goto hitline;
- }
-
- if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
- {
- slope = FixedDiv (::g->opentop - ::g->shootz , dist);
- if (slope < ::g->aimslope)
- goto hitline;
- }
- // shot continues
- return true;
-
-
- // hit line
- hitline:
- // position a bit closer
- frac = in->frac - FixedDiv (4*FRACUNIT,::g->attackrange);
- x = ::g->trace.x + FixedMul (::g->trace.dx, frac);
- y = ::g->trace.y + FixedMul (::g->trace.dy, frac);
- z = ::g->shootz + FixedMul (::g->aimslope, FixedMul(frac, ::g->attackrange));
- if (li->frontsector->ceilingpic == ::g->skyflatnum)
- {
- // don't shoot the sky!
- if (z > li->frontsector->ceilingheight)
- return false;
-
- // it's a sky hack wall
- if (li->backsector && li->backsector->ceilingpic == ::g->skyflatnum)
- return false;
- }
- mobj_t * sourceObject = ::g->shootthing;
- if( sourceObject ) {
- if( ( sourceObject->player) == &(::g->players[DoomLib::GetPlayer()]) ) {
-
- // Fist Punch.
- if( ::g->attackrange == MELEERANGE ) {
- }
- }
- }
- // Spawn bullet puffs.
- P_SpawnPuff (x,y,z);
-
- // don't go any farther
- return false;
- }
-
- // shoot a thing
- th = in->d.thing;
- if (th == ::g->shootthing)
- return true; // can't shoot self
-
- if (!(th->flags&MF_SHOOTABLE))
- return true; // corpse or something
-
- // check angles to see if the thing can be aimed at
- dist = FixedMul (::g->attackrange, in->frac);
- thingtopslope = FixedDiv (th->z+th->height - ::g->shootz , dist);
- if (thingtopslope < ::g->aimslope)
- return true; // shot over the thing
- thingbottomslope = FixedDiv (th->z - ::g->shootz, dist);
- if (thingbottomslope > ::g->aimslope)
- return true; // shot under the thing
-
- // hit thing
- // position a bit closer
- frac = in->frac - FixedDiv (10*FRACUNIT,::g->attackrange);
- x = ::g->trace.x + FixedMul (::g->trace.dx, frac);
- y = ::g->trace.y + FixedMul (::g->trace.dy, frac);
- z = ::g->shootz + FixedMul (::g->aimslope, FixedMul(frac, ::g->attackrange));
- // check for friendly fire.
- #ifdef ID_ENABLE_DOOM_CLASSIC_NETWORKING
- if( th && gameLocal->GetMatchParms().GetGameType() != GAME_TYPE_PVP ) {
- player_t * hitPlayer = th->player;
- if( hitPlayer ) {
- mobj_t * sourceObject = ::g->shootthing;
- if( sourceObject ) {
- player_t* sourcePlayer = sourceObject->player;
- if( sourcePlayer != NULL && sourcePlayer != hitPlayer && !gameLocal->GetMatchParms().AllowFriendlyFire() ) {
- return true;
- }
- }
- }
- }
- #endif
- mobj_t * sourceObject = ::g->shootthing;
- if( sourceObject ) {
- if( ( sourceObject->player) == &(::g->players[DoomLib::GetPlayer()]) ) {
- // Fist Punch.
- if( ::g->attackrange == MELEERANGE ) {
- }
- }
- }
- // Spawn bullet puffs or blod spots,
- // depending on target type.
- if (in->d.thing->flags & MF_NOBLOOD)
- P_SpawnPuff (x,y,z);
- else
- P_SpawnBlood (x,y,z, ::g->la_damage);
- if (::g->la_damage)
- P_DamageMobj (th, ::g->shootthing, ::g->shootthing, ::g->la_damage);
- // don't go any farther
- return false;
-
- }
- //
- // P_AimLineAttack
- //
- fixed_t
- P_AimLineAttack
- ( mobj_t* t1,
- angle_t angle,
- fixed_t distance )
- {
- fixed_t x2;
- fixed_t y2;
-
- angle >>= ANGLETOFINESHIFT;
- ::g->shootthing = t1;
-
- x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
- y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
- ::g->shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
- // can't shoot outside view angles
- ::g->topslope = 100*FRACUNIT/160;
- ::g->bottomslope = -100*FRACUNIT/160;
-
- ::g->attackrange = distance;
- ::g->linetarget = NULL;
-
- P_PathTraverse ( t1->x, t1->y,
- x2, y2,
- PT_ADDLINES|PT_ADDTHINGS,
- PTR_AimTraverse );
-
- if (::g->linetarget)
- return ::g->aimslope;
- return 0;
- }
-
- //
- // P_LineAttack
- // If damage == 0, it is just a test ::g->trace
- // that will leave ::g->linetarget set.
- //
- void
- P_LineAttack
- ( mobj_t* t1,
- angle_t angle,
- fixed_t distance,
- fixed_t slope,
- int damage )
- {
- fixed_t x2;
- fixed_t y2;
-
- angle >>= ANGLETOFINESHIFT;
- ::g->shootthing = t1;
- ::g->la_damage = damage;
- x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
- y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
- ::g->shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
- ::g->attackrange = distance;
- ::g->aimslope = slope;
-
- P_PathTraverse ( t1->x, t1->y,
- x2, y2,
- PT_ADDLINES|PT_ADDTHINGS,
- PTR_ShootTraverse );
- }
-
- //
- // USE LINES
- //
- qboolean PTR_UseTraverse (intercept_t* in)
- {
- int side;
-
- if (!in->d.line->special)
- {
- P_LineOpening (in->d.line);
- if (::g->openrange <= 0)
- {
- S_StartSound (::g->usething, sfx_noway);
-
- // can't use through a wall
- return false;
- }
- // not a special line, but keep checking
- return true ;
- }
-
- side = 0;
- if (P_PointOnLineSide (::g->usething->x, ::g->usething->y, in->d.line) == 1)
- side = 1;
-
- // return false; // don't use back side
-
- P_UseSpecialLine (::g->usething, in->d.line, side);
- // can't use for than one special line in a row
- return false;
- }
- //
- // P_UseLines
- // Looks for special ::g->lines in front of the player to activate.
- //
- void P_UseLines (player_t* player)
- {
- int angle;
- fixed_t x1;
- fixed_t y1;
- fixed_t x2;
- fixed_t y2;
-
- ::g->usething = player->mo;
-
- angle = player->mo->angle >> ANGLETOFINESHIFT;
- x1 = player->mo->x;
- y1 = player->mo->y;
- x2 = x1 + (USERANGE>>FRACBITS)*finecosine[angle];
- y2 = y1 + (USERANGE>>FRACBITS)*finesine[angle];
-
- P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
- }
- //
- // RADIUS ATTACK
- //
- //
- // PIT_RadiusAttack
- // "bombsource" is the creature
- // that caused the explosion at "bombspot".
- //
- qboolean PIT_RadiusAttack (mobj_t* thing)
- {
- fixed_t dx;
- fixed_t dy;
- fixed_t dist;
-
- if (!(thing->flags & MF_SHOOTABLE) )
- return true;
- // Boss spider and cyborg
- // take no damage from concussion.
- if (thing->type == MT_CYBORG
- || thing->type == MT_SPIDER)
- return true;
-
- dx = abs(thing->x - ::g->bombspot->x);
- dy = abs(thing->y - ::g->bombspot->y);
-
- dist = dx>dy ? dx : dy;
- dist = (dist - thing->radius) >> FRACBITS;
- if (dist < 0)
- dist = 0;
- if (dist >= ::g->bombdamage)
- return true; // out of range
- if ( P_CheckSight (thing, ::g->bombspot) )
- {
- // must be in direct path
- P_DamageMobj (thing, ::g->bombspot, ::g->bombsource, ::g->bombdamage - dist);
- }
-
- return true;
- }
- //
- // P_RadiusAttack
- // Source is the creature that caused the explosion at spot.
- //
- void
- P_RadiusAttack
- ( mobj_t* spot,
- mobj_t* source,
- int damage )
- {
- int x;
- int y;
-
- int xl;
- int xh;
- int yl;
- int yh;
-
- fixed_t dist;
-
- dist = (damage+MAXRADIUS)<<FRACBITS;
- yh = (spot->y + dist - ::g->bmaporgy)>>MAPBLOCKSHIFT;
- yl = (spot->y - dist - ::g->bmaporgy)>>MAPBLOCKSHIFT;
- xh = (spot->x + dist - ::g->bmaporgx)>>MAPBLOCKSHIFT;
- xl = (spot->x - dist - ::g->bmaporgx)>>MAPBLOCKSHIFT;
- ::g->bombspot = spot;
- ::g->bombsource = source;
- ::g->bombdamage = damage;
-
- for (y=yl ; y<=yh ; y++)
- for (x=xl ; x<=xh ; x++)
- P_BlockThingsIterator (x, y, PIT_RadiusAttack );
- }
- //
- // SECTOR HEIGHT CHANGING
- // After modifying a ::g->sectors floor or ceiling height,
- // call this routine to adjust the positions
- // of all things that touch the sector.
- //
- // If anything doesn't fit anymore, true will be returned.
- // If crunch is true, they will take damage
- // as they are being crushed.
- // If Crunch is false, you should set the sector height back
- // the way it was and call P_ChangeSector again
- // to undo the changes.
- //
- //
- // PIT_ChangeSector
- //
- qboolean PIT_ChangeSector (mobj_t* thing)
- {
- mobj_t* mo;
-
- if (P_ThingHeightClip (thing))
- {
- // keep checking
- return true;
- }
-
- // crunch bodies to giblets
- if (thing->health <= 0)
- {
- P_SetMobjState (thing, S_GIBS);
- thing->flags &= ~MF_SOLID;
- thing->height = 0;
- thing->radius = 0;
- // keep checking
- return true;
- }
- // crunch dropped items
- if (thing->flags & MF_DROPPED)
- {
- P_RemoveMobj (thing);
-
- // keep checking
- return true;
- }
- if (! (thing->flags & MF_SHOOTABLE) )
- {
- // assume it is bloody gibs or something
- return true;
- }
-
- ::g->nofit = true;
- if (::g->crushchange && !(::g->leveltime&3) )
- {
- P_DamageMobj(thing,NULL,NULL,10);
- // spray blood in a random direction
- mo = P_SpawnMobj (thing->x,
- thing->y,
- thing->z + thing->height/2, MT_BLOOD);
-
- mo->momx = (P_Random() - P_Random ())<<12;
- mo->momy = (P_Random() - P_Random ())<<12;
- }
- // keep checking (crush other things)
- return true;
- }
- //
- // P_ChangeSector
- //
- qboolean
- P_ChangeSector
- ( sector_t* sector,
- qboolean crunch )
- {
- int x;
- int y;
-
- ::g->nofit = false;
- ::g->crushchange = crunch;
-
- // re-check heights for all things near the moving sector
- for (x=sector->blockbox[BOXLEFT] ; x<= sector->blockbox[BOXRIGHT] ; x++)
- for (y=sector->blockbox[BOXBOTTOM];y<= sector->blockbox[BOXTOP] ; y++)
- P_BlockThingsIterator (x, y, PIT_ChangeSector);
-
-
- return ::g->nofit;
- }
|