1998-04-07 00:00:00 +00:00
|
|
|
// 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:
|
|
|
|
// Movement, collision handling.
|
|
|
|
// Shooting and aiming.
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
1998-07-14 00:00:00 +00:00
|
|
|
#include <math.h>
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
#include "vectors.h"
|
|
|
|
|
|
|
|
#include "m_alloc.h"
|
1998-04-07 00:00:00 +00:00
|
|
|
#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"
|
|
|
|
|
1998-07-26 00:00:00 +00:00
|
|
|
#include "z_zone.h"
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
fixed_t tmbbox[4];
|
1998-12-22 00:00:00 +00:00
|
|
|
static mobj_t *tmthing;
|
|
|
|
static int tmflags;
|
|
|
|
static fixed_t tmx;
|
|
|
|
static fixed_t tmy;
|
|
|
|
static fixed_t tmz; // [RH] Needed for third dimension of teleporters
|
|
|
|
static int pe_x; // Pain Elemental position for Lost Soul checks // phares
|
|
|
|
static int pe_y; // Pain Elemental position for Lost Soul checks // phares
|
|
|
|
static int ls_x; // Lost Soul position for Lost Soul checks // phares
|
|
|
|
static int ls_y; // Lost Soul position for Lost Soul checks // phares
|
|
|
|
|
|
|
|
BOOL oldshootactivation; // [RH] True if no distinction is made between
|
|
|
|
// projectile cross and projectile hit
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
// If "floatok" true, move would be ok
|
|
|
|
// if within "tmfloorz - tmceilingz".
|
1998-12-22 00:00:00 +00:00
|
|
|
BOOL floatok;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
fixed_t tmfloorz;
|
|
|
|
fixed_t tmceilingz;
|
|
|
|
fixed_t tmdropoffz;
|
|
|
|
|
|
|
|
// keep track of the line that lowers the ceiling,
|
|
|
|
// so missiles don't explode against sky hack walls
|
|
|
|
line_t* ceilingline;
|
|
|
|
|
|
|
|
// keep track of special lines as they are hit,
|
|
|
|
// but don't process them until the move is proven valid
|
1998-12-22 00:00:00 +00:00
|
|
|
// [RH] MaxSpecialCross grows as needed
|
1998-07-14 00:00:00 +00:00
|
|
|
int MaxSpecialCross = 0;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
line_t** spechit;
|
1998-04-07 00:00:00 +00:00
|
|
|
int numspechit;
|
|
|
|
|
1998-07-26 00:00:00 +00:00
|
|
|
// Temporary holder for thing_sectorlist threads
|
|
|
|
msecnode_t* sector_list = NULL; // phares 3/16/98
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// TELEPORT MOVE
|
|
|
|
//
|
|
|
|
|
|
|
|
//
|
|
|
|
// PIT_StompThing
|
|
|
|
//
|
1998-07-26 00:00:00 +00:00
|
|
|
static BOOL StompAlwaysFrags;
|
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
BOOL PIT_StompThing (mobj_t* thing)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
1998-12-22 00:00:00 +00:00
|
|
|
fixed_t blockdist;
|
|
|
|
|
|
|
|
if (!(thing->flags & MF_SHOOTABLE))
|
1998-04-07 00:00:00 +00:00
|
|
|
return true;
|
1998-12-22 00:00:00 +00:00
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
// don't clip against self
|
|
|
|
if (thing == tmthing)
|
|
|
|
return true;
|
1998-12-22 00:00:00 +00:00
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
blockdist = thing->radius + tmthing->radius;
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
// didn't hit it
|
|
|
|
return true;
|
|
|
|
}
|
1998-07-14 00:00:00 +00:00
|
|
|
|
|
|
|
// [RH] Z-Check
|
1998-07-26 00:00:00 +00:00
|
|
|
if (!olddemo) {
|
|
|
|
if (tmz > thing->z + thing->height)
|
|
|
|
return true; // overhead
|
|
|
|
if (tmz+tmthing->height < thing->z)
|
|
|
|
return true; // underneath
|
|
|
|
}
|
1998-07-14 00:00:00 +00:00
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
// monsters don't stomp things except on boss level
|
1998-07-26 00:00:00 +00:00
|
|
|
if (StompAlwaysFrags) {
|
|
|
|
P_DamageMobj (thing, tmthing, tmthing, 10000, MOD_TELEFRAG);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
1998-04-07 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// P_TeleportMove
|
|
|
|
//
|
1998-07-26 00:00:00 +00:00
|
|
|
// [RH] Added telefrag parameter: When true, anything in the spawn spot
|
|
|
|
// will always be telefragged, and the move will be successful.
|
|
|
|
// Added z parameter. Originally, the thing's z was set *after* the
|
|
|
|
// move was made, so the height checking I added for 1.13 could
|
|
|
|
// potentially erroneously indicate the move was okay if the thing
|
|
|
|
// was being teleported between two non-overlapping height ranges.
|
|
|
|
BOOL P_TeleportMove (mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, BOOL telefrag)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
int xl;
|
|
|
|
int xh;
|
|
|
|
int yl;
|
|
|
|
int yh;
|
|
|
|
int bx;
|
|
|
|
int by;
|
|
|
|
|
|
|
|
subsector_t* newsubsec;
|
|
|
|
|
|
|
|
// kill anything occupying the position
|
|
|
|
tmthing = thing;
|
|
|
|
tmflags = thing->flags;
|
|
|
|
|
|
|
|
tmx = x;
|
|
|
|
tmy = y;
|
1998-07-26 00:00:00 +00:00
|
|
|
tmz = z;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
tmbbox[BOXTOP] = y + tmthing->radius;
|
|
|
|
tmbbox[BOXBOTTOM] = y - tmthing->radius;
|
|
|
|
tmbbox[BOXRIGHT] = x + tmthing->radius;
|
|
|
|
tmbbox[BOXLEFT] = x - tmthing->radius;
|
|
|
|
|
|
|
|
newsubsec = R_PointInSubsector (x,y);
|
|
|
|
ceilingline = NULL;
|
|
|
|
|
|
|
|
// The base floor/ceiling is from the subsector
|
|
|
|
// that contains the point.
|
|
|
|
// Any contacted lines the step closer together
|
|
|
|
// will adjust them.
|
|
|
|
tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
|
|
|
|
tmceilingz = newsubsec->sector->ceilingheight;
|
|
|
|
|
|
|
|
validcount++;
|
|
|
|
numspechit = 0;
|
1998-07-26 00:00:00 +00:00
|
|
|
|
|
|
|
StompAlwaysFrags = tmthing->player || (level.flags & LEVEL_MONSTERSTELEFRAG) ||
|
|
|
|
(!olddemo && telefrag);
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
// stomp on any things contacted
|
|
|
|
xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
yh = (tmbbox[BOXTOP] - 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 = tmfloorz;
|
|
|
|
thing->ceilingz = tmceilingz;
|
|
|
|
thing->x = x;
|
|
|
|
thing->y = y;
|
1998-12-22 00:00:00 +00:00
|
|
|
thing->z = z;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
P_SetThingPosition (thing);
|
1998-07-26 00:00:00 +00:00
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
// P_GetMoveFactor() returns the value by which the x,y // phares 3/19/98
|
|
|
|
// movements are multiplied to add to player movement. // |
|
|
|
|
// V
|
|
|
|
int P_GetMoveFactor(mobj_t* mo)
|
|
|
|
{
|
|
|
|
int movefactor = ORIG_FRICTION_FACTOR;
|
|
|
|
|
|
|
|
// If the floor is icy or muddy, it's harder to get moving. This is where
|
|
|
|
// the different friction factors are applied to 'trying to move'. In
|
|
|
|
// p_mobj.c, the friction factors are applied as you coast and slow down.
|
|
|
|
|
|
|
|
int momentum, friction;
|
|
|
|
|
|
|
|
if (!olddemo && boom_friction->value &&
|
|
|
|
!(mo->flags & (MF_NOGRAVITY | MF_NOCLIP)))
|
|
|
|
{
|
|
|
|
friction = mo->friction;
|
|
|
|
if (friction == ORIG_FRICTION) // normal floor
|
|
|
|
;
|
|
|
|
else if (friction > ORIG_FRICTION) // ice
|
|
|
|
{
|
|
|
|
movefactor = mo->movefactor;
|
|
|
|
mo->movefactor = ORIG_FRICTION_FACTOR; // reset
|
|
|
|
}
|
|
|
|
else // sludge
|
|
|
|
{
|
|
|
|
|
|
|
|
// phares 3/11/98: you start off slowly, then increase as
|
|
|
|
// you get better footing
|
|
|
|
|
|
|
|
momentum = (P_AproxDistance (mo->momx, mo->momy));
|
|
|
|
movefactor = mo->movefactor;
|
|
|
|
if (momentum > MORE_FRICTION_MOMENTUM<<2)
|
|
|
|
movefactor <<= 3;
|
|
|
|
|
|
|
|
else if (momentum > MORE_FRICTION_MOMENTUM<<1)
|
|
|
|
movefactor <<= 2;
|
|
|
|
|
|
|
|
else if (momentum > MORE_FRICTION_MOMENTUM)
|
|
|
|
movefactor <<= 1;
|
|
|
|
|
|
|
|
mo->movefactor = ORIG_FRICTION_FACTOR; // reset
|
|
|
|
}
|
|
|
|
} // ^
|
|
|
|
return (movefactor); // |
|
|
|
|
} // phares 3/19/98
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// MOVEMENT ITERATOR FUNCTIONS
|
|
|
|
//
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
// // phares
|
|
|
|
// PIT_CrossLine // |
|
|
|
|
// Checks to see if a PE->LS trajectory line crosses a blocking // V
|
|
|
|
// line. Returns false if it does.
|
|
|
|
//
|
|
|
|
// tmbbox holds the bounding box of the trajectory. If that box
|
|
|
|
// does not touch the bounding box of the line in question,
|
|
|
|
// then the trajectory is not blocked. If the PE is on one side
|
|
|
|
// of the line and the LS is on the other side, then the
|
|
|
|
// trajectory is blocked.
|
|
|
|
//
|
|
|
|
// Currently this assumes an infinite line, which is not quite
|
|
|
|
// correct. A more correct solution would be to check for an
|
|
|
|
// intersection of the trajectory and the line, but that takes
|
|
|
|
// longer and probably really isn't worth the effort.
|
|
|
|
//
|
|
|
|
|
|
|
|
static // killough 3/26/98: make static
|
|
|
|
BOOL PIT_CrossLine (line_t* ld)
|
|
|
|
{
|
|
|
|
if (!(ld->flags & ML_TWOSIDED) ||
|
|
|
|
(ld->flags & (ML_BLOCKING|ML_BLOCKMONSTERS|ML_BLOCKEVERYTHING)))
|
|
|
|
if (!(tmbbox[BOXLEFT] > ld->bbox[BOXRIGHT] ||
|
|
|
|
tmbbox[BOXRIGHT] < ld->bbox[BOXLEFT] ||
|
|
|
|
tmbbox[BOXTOP] < ld->bbox[BOXBOTTOM] ||
|
|
|
|
tmbbox[BOXBOTTOM] > ld->bbox[BOXTOP]))
|
|
|
|
if (P_PointOnLineSide(pe_x,pe_y,ld) != P_PointOnLineSide(ls_x,ls_y,ld))
|
|
|
|
return(false); // line blocks trajectory // ^
|
|
|
|
return(true); // line doesn't block trajectory // |
|
|
|
|
} // phares
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// PIT_CheckLine
|
|
|
|
// Adjusts tmfloorz and tmceilingz as lines are contacted
|
|
|
|
//
|
1998-12-22 00:00:00 +00:00
|
|
|
|
|
|
|
// [RH] Moved this out of PIT_CheckLine()
|
|
|
|
static void AddSpecialLine (line_t *ld)
|
|
|
|
{
|
|
|
|
if (ld->special)
|
|
|
|
{
|
|
|
|
// [RH] Grow the spechit array as needed
|
|
|
|
if (numspechit >= MaxSpecialCross) {
|
|
|
|
MaxSpecialCross = MaxSpecialCross ? MaxSpecialCross * 2 : 8;
|
|
|
|
spechit = Realloc (spechit, MaxSpecialCross * sizeof(*spechit));
|
|
|
|
DPrintf ("MaxSpecialCross increased to %d\n", MaxSpecialCross);
|
|
|
|
}
|
|
|
|
spechit[numspechit++] = ld;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static // killough 3/26/98: make static
|
|
|
|
BOOL PIT_CheckLine (line_t *ld)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT]
|
|
|
|
|| tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT]
|
|
|
|
|| tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM]
|
|
|
|
|| tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP] )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (P_BoxOnLineSide (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 lines that are only 8 pixels apart
|
|
|
|
// could be crossed in either order.
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
if (!ld->backsector) {
|
|
|
|
// [RH] Let somebody push it if they want to
|
|
|
|
if ((ld->flags & ML_ACTIVATIONMASK) == ML_ACTIVATEPUSH)
|
|
|
|
AddSpecialLine (ld);
|
1998-04-07 00:00:00 +00:00
|
|
|
return false; // one sided line
|
1998-12-22 00:00:00 +00:00
|
|
|
}
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
if (!(tmthing->flags & MF_MISSILE) || (ld->flags & ML_BLOCKEVERYTHING))
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
1998-12-22 00:00:00 +00:00
|
|
|
if ((ld->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING)) || // explicitly blocking everything
|
|
|
|
(!tmthing->player && ld->flags & ML_BLOCKMONSTERS)) { // block monsters only
|
|
|
|
// [RH] Add pushable lines to the special list
|
|
|
|
if ((ld->flags & ML_ACTIVATIONMASK) == ML_ACTIVATEPUSH)
|
|
|
|
AddSpecialLine (ld);
|
|
|
|
return false;
|
|
|
|
}
|
1998-04-07 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// set openrange, opentop, openbottom
|
|
|
|
P_LineOpening (ld);
|
|
|
|
|
|
|
|
// adjust floor / ceiling heights
|
|
|
|
if (opentop < tmceilingz)
|
|
|
|
{
|
|
|
|
tmceilingz = opentop;
|
|
|
|
ceilingline = ld;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (openbottom > tmfloorz)
|
|
|
|
tmfloorz = openbottom;
|
|
|
|
|
|
|
|
if (lowfloor < tmdropoffz)
|
|
|
|
tmdropoffz = lowfloor;
|
|
|
|
|
|
|
|
// if contacted a special line, add it to the list
|
1998-12-22 00:00:00 +00:00
|
|
|
AddSpecialLine (ld);
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// PIT_CheckThing
|
|
|
|
//
|
1998-12-22 00:00:00 +00:00
|
|
|
static // killough 3/26/98: make static
|
1998-07-14 00:00:00 +00:00
|
|
|
BOOL PIT_CheckThing (mobj_t *thing)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
1998-07-14 00:00:00 +00:00
|
|
|
fixed_t blockdist;
|
|
|
|
BOOL solid;
|
|
|
|
int damage;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
// don't clip against self
|
|
|
|
if (thing == tmthing)
|
|
|
|
return true;
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_SHOOTABLE)) )
|
|
|
|
return true;
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
blockdist = thing->radius + tmthing->radius;
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
// didn't hit it
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
// [RH] Z-Check
|
1998-07-14 00:00:00 +00:00
|
|
|
if (!olddemo) {
|
|
|
|
if (tmthing->z >= thing->z + thing->height)
|
|
|
|
return true; // overhead (or on)
|
|
|
|
if (tmthing->z+tmthing->height < thing->z)
|
|
|
|
return true; // underneath
|
|
|
|
}
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
// check for skulls slamming into things
|
|
|
|
if (tmthing->flags & MF_SKULLFLY)
|
|
|
|
{
|
1998-07-14 00:00:00 +00:00
|
|
|
damage = ((P_Random(pr_checkthing)%8)+1)*tmthing->info->damage;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
P_DamageMobj (thing, tmthing, tmthing, damage, MOD_UNKNOWN);
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
tmthing->flags &= ~MF_SKULLFLY;
|
|
|
|
tmthing->momx = tmthing->momy = tmthing->momz = 0;
|
|
|
|
|
|
|
|
P_SetMobjState (tmthing, tmthing->info->spawnstate);
|
|
|
|
|
|
|
|
return false; // stop moving
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// missiles can hit other things
|
|
|
|
if (tmthing->flags & MF_MISSILE)
|
|
|
|
{
|
1998-07-14 00:00:00 +00:00
|
|
|
// [RH] Only check here if this is an old demo
|
|
|
|
if (olddemo) {
|
|
|
|
// see if it went over / under
|
|
|
|
if (tmthing->z > thing->z + thing->height)
|
|
|
|
return true; // overhead
|
|
|
|
if (tmthing->z+tmthing->height < thing->z)
|
|
|
|
return true; // underneath
|
|
|
|
}
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
if (tmthing->target && (
|
|
|
|
tmthing->target->type == thing->type ||
|
|
|
|
(tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER)||
|
|
|
|
(tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT) ) )
|
|
|
|
{
|
|
|
|
// Don't hit same species as originator.
|
|
|
|
if (thing == tmthing->target)
|
|
|
|
return true;
|
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
// [RH] DeHackEd infighting is here.
|
1998-12-22 00:00:00 +00:00
|
|
|
if (!deh.Infight && thing->type != MT_PLAYER)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
// Explode, but do no damage.
|
|
|
|
// Let players missile other players.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! (thing->flags & MF_SHOOTABLE) )
|
|
|
|
{
|
|
|
|
// didn't do any damage
|
|
|
|
return !(thing->flags & MF_SOLID);
|
|
|
|
}
|
|
|
|
|
|
|
|
// damage / explode
|
1998-07-14 00:00:00 +00:00
|
|
|
damage = ((P_Random(pr_checkthing)%8)+1)*tmthing->info->damage;
|
|
|
|
{
|
|
|
|
// [RH] figure out the means of death
|
|
|
|
int mod;
|
|
|
|
|
|
|
|
switch (tmthing->type) {
|
|
|
|
case MT_ROCKET:
|
|
|
|
mod = MOD_ROCKET;
|
|
|
|
break;
|
|
|
|
case MT_PLASMA:
|
|
|
|
mod = MOD_PLASMARIFLE;
|
|
|
|
break;
|
|
|
|
case MT_BFG:
|
|
|
|
mod = MOD_BFG_BOOM;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
mod = MOD_UNKNOWN;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
P_DamageMobj (thing, tmthing, tmthing->target, damage, mod);
|
|
|
|
}
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
// don't traverse any more
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for special pickup
|
|
|
|
if (thing->flags & MF_SPECIAL)
|
|
|
|
{
|
|
|
|
solid = thing->flags&MF_SOLID;
|
|
|
|
if (tmflags&MF_PICKUP)
|
|
|
|
{
|
|
|
|
// can remove thing
|
|
|
|
P_TouchSpecialThing (thing, tmthing);
|
|
|
|
}
|
|
|
|
return !solid;
|
|
|
|
}
|
1998-12-22 00:00:00 +00:00
|
|
|
|
|
|
|
// [RH] Allow step up on top of things up to 24 units (like stairs)
|
|
|
|
// The movement code will automatically place the moving object
|
|
|
|
// on top of the other one.
|
|
|
|
if (!olddemo
|
|
|
|
&& !(tmthing->z & MF2_JUMPING)
|
|
|
|
&& tmthing->z < thing->z + thing->height
|
|
|
|
&& thing->z + thing->height - tmthing->z <= 24 * FRACUNIT
|
|
|
|
&& thing->z + thing->height + tmthing->height < thing->subsector->sector->ceilingheight
|
|
|
|
) {
|
|
|
|
tmthing->z = thing->z;
|
|
|
|
tmthing->momz = 1;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// killough 3/16/98: Allow non-solid moving objects to move through solid
|
|
|
|
// ones, by allowing the moving thing (tmthing) to move if it's non-solid,
|
|
|
|
// despite another solid thing being in the way.
|
|
|
|
// killough 4/11/98: Treat no-clipping things as not blocking
|
|
|
|
|
|
|
|
return !((thing->flags & MF_SOLID && !(thing->flags & MF_NOCLIP))
|
|
|
|
&& (tmthing->flags & MF_SOLID || olddemo));
|
|
|
|
|
|
|
|
// return !(thing->flags & MF_SOLID); // old code -- killough
|
1998-04-07 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
// This routine checks for Lost Souls trying to be spawned // phares
|
|
|
|
// across 1-sided lines, impassible lines, or "monsters can't // |
|
|
|
|
// cross" lines. Draw an imaginary line between the PE // V
|
|
|
|
// and the new Lost Soul spawn spot. If that line crosses
|
|
|
|
// a 'blocking' line, then disallow the spawn. Only search
|
|
|
|
// lines in the blocks of the blockmap where the bounding box
|
|
|
|
// of the trajectory line resides. Then check bounding box
|
|
|
|
// of the trajectory vs. the bounding box of each blocking
|
|
|
|
// line to see if the trajectory and the blocking line cross.
|
|
|
|
// Then check the PE and LS to see if they're on different
|
|
|
|
// sides of the blocking line. If so, return true, otherwise
|
|
|
|
// false.
|
|
|
|
|
|
|
|
BOOL Check_Sides(mobj_t* actor, int x, int y)
|
|
|
|
{
|
|
|
|
int bx,by,xl,xh,yl,yh;
|
|
|
|
|
|
|
|
pe_x = actor->x;
|
|
|
|
pe_y = actor->y;
|
|
|
|
ls_x = x;
|
|
|
|
ls_y = y;
|
|
|
|
|
|
|
|
// Here is the bounding box of the trajectory
|
|
|
|
|
|
|
|
tmbbox[BOXLEFT] = pe_x < x ? pe_x : x;
|
|
|
|
tmbbox[BOXRIGHT] = pe_x > x ? pe_x : x;
|
|
|
|
tmbbox[BOXTOP] = pe_y > y ? pe_y : y;
|
|
|
|
tmbbox[BOXBOTTOM] = pe_y < y ? pe_y : y;
|
|
|
|
|
|
|
|
// Determine which blocks to look in for blocking lines
|
|
|
|
|
|
|
|
xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
|
|
|
|
xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
|
|
|
|
yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
|
|
|
|
yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
|
|
|
|
|
|
|
|
// xl->xh, yl->yh determine the mapblock set to search
|
|
|
|
|
|
|
|
validcount++; // prevents checking same line twice
|
|
|
|
for (bx = xl ; bx <= xh ; bx++)
|
|
|
|
for (by = yl ; by <= yh ; by++)
|
|
|
|
if (!P_BlockLinesIterator(bx,by,PIT_CrossLine))
|
|
|
|
return true; // ^
|
|
|
|
return(false); // |
|
|
|
|
} // phares
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// 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
|
|
|
|
// tmdropoffz
|
|
|
|
// the lowest point contacted
|
|
|
|
// (monsters won't move to a dropoff)
|
|
|
|
// speciallines[]
|
|
|
|
// numspeciallines
|
|
|
|
//
|
1998-07-14 00:00:00 +00:00
|
|
|
BOOL P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
1998-12-22 00:00:00 +00:00
|
|
|
int xl, xh;
|
|
|
|
int yl, yh;
|
|
|
|
int bx, by;
|
|
|
|
subsector_t *newsubsec;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
tmthing = thing;
|
|
|
|
tmflags = thing->flags;
|
|
|
|
|
|
|
|
tmx = x;
|
|
|
|
tmy = y;
|
|
|
|
|
|
|
|
tmbbox[BOXTOP] = y + tmthing->radius;
|
|
|
|
tmbbox[BOXBOTTOM] = y - tmthing->radius;
|
|
|
|
tmbbox[BOXRIGHT] = x + tmthing->radius;
|
|
|
|
tmbbox[BOXLEFT] = x - tmthing->radius;
|
|
|
|
|
|
|
|
newsubsec = R_PointInSubsector (x,y);
|
|
|
|
ceilingline = NULL;
|
|
|
|
|
|
|
|
// The base floor / ceiling is from the subsector
|
|
|
|
// that contains the point.
|
|
|
|
// Any contacted lines the step closer together
|
|
|
|
// will adjust them.
|
|
|
|
tmfloorz = tmdropoffz = newsubsec->sector->floorheight;
|
|
|
|
tmceilingz = newsubsec->sector->ceilingheight;
|
|
|
|
|
|
|
|
validcount++;
|
|
|
|
numspechit = 0;
|
|
|
|
|
|
|
|
if ( 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 = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
yh = (tmbbox[BOXTOP] - 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 lines
|
|
|
|
xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
|
|
|
|
xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
|
|
|
|
yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
|
|
|
|
yh = (tmbbox[BOXTOP] - 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 lines unless MF_TELEPORT is set.
|
|
|
|
//
|
1998-12-22 00:00:00 +00:00
|
|
|
BOOL P_TryMove (mobj_t *thing, fixed_t x, fixed_t y,
|
|
|
|
BOOL dropoff) // killough 3/15/98: allow dropoff as option
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
fixed_t oldx;
|
|
|
|
fixed_t oldy;
|
|
|
|
int side;
|
|
|
|
int oldside;
|
|
|
|
line_t* ld;
|
|
|
|
|
|
|
|
floatok = false;
|
|
|
|
if (!P_CheckPosition (thing, x, y))
|
|
|
|
return false; // solid wall or thing
|
|
|
|
|
|
|
|
if ( !(thing->flags & MF_NOCLIP) )
|
|
|
|
{
|
1998-12-22 00:00:00 +00:00
|
|
|
#ifdef CEILCARRY
|
|
|
|
// killough 4/11/98: if the thing hangs from
|
|
|
|
// a ceiling, don't worry about it fitting
|
|
|
|
|
|
|
|
if (!(thing->flags & MF_SPAWNCEILING) || demo_compatibility)
|
|
|
|
#endif
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
if (tmceilingz - tmfloorz < thing->height)
|
|
|
|
return false; // doesn't fit
|
|
|
|
|
|
|
|
floatok = true;
|
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
if ( !(thing->flags&MF_TELEPORT) && tmceilingz - thing->z < thing->height)
|
1998-04-07 00:00:00 +00:00
|
|
|
return false; // mobj must lower itself to fit
|
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
if ( !(thing->flags&MF_TELEPORT) && tmfloorz - thing->z > 24*FRACUNIT )
|
1998-04-07 00:00:00 +00:00
|
|
|
return false; // too big a step up
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
// killough 3/15/98: Allow certain objects to drop off
|
|
|
|
|
|
|
|
if (olddemo || !dropoff)
|
|
|
|
if ( !(thing->flags&(MF_DROPOFF|MF_FLOAT))
|
|
|
|
&& tmfloorz - tmdropoffz > 24*FRACUNIT )
|
|
|
|
return false; // don't stand over a dropoff
|
1998-04-07 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// the move is ok,
|
|
|
|
// so link the thing into its new position
|
|
|
|
P_UnsetThingPosition (thing);
|
|
|
|
|
|
|
|
oldx = thing->x;
|
|
|
|
oldy = thing->y;
|
|
|
|
thing->floorz = tmfloorz;
|
1998-07-14 00:00:00 +00:00
|
|
|
thing->ceilingz = tmceilingz;
|
1998-04-07 00:00:00 +00:00
|
|
|
thing->x = x;
|
|
|
|
thing->y = y;
|
|
|
|
|
|
|
|
P_SetThingPosition (thing);
|
|
|
|
|
|
|
|
// if any special lines were hit, do the effect
|
|
|
|
if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) )
|
|
|
|
{
|
|
|
|
while (numspechit--)
|
|
|
|
{
|
|
|
|
// see if the line was crossed
|
|
|
|
ld = spechit[numspechit];
|
|
|
|
side = P_PointOnLineSide (thing->x, thing->y, ld);
|
|
|
|
oldside = P_PointOnLineSide (oldx, oldy, ld);
|
1998-12-22 00:00:00 +00:00
|
|
|
if (side != oldside && ld->special)
|
|
|
|
P_CrossSpecialLine (ld-lines, oldside, thing);
|
1998-04-07 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
//
|
1998-07-14 00:00:00 +00:00
|
|
|
BOOL P_ThingHeightClip (mobj_t* thing)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
1998-07-14 00:00:00 +00:00
|
|
|
// [RH] Move mobjs standing on other mobjs
|
|
|
|
mobj_t *floor;
|
|
|
|
fixed_t oldfloorz;
|
|
|
|
|
|
|
|
oldfloorz = thing->floorz;
|
|
|
|
floor = P_FindFloor (thing);
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
P_CheckPosition (thing, thing->x, thing->y);
|
|
|
|
// what about stranding a monster partially off an edge?
|
|
|
|
|
|
|
|
thing->floorz = tmfloorz;
|
|
|
|
thing->ceilingz = tmceilingz;
|
1998-07-14 00:00:00 +00:00
|
|
|
|
|
|
|
if (floor)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
// walking monsters rise and fall with the floor
|
1998-07-14 00:00:00 +00:00
|
|
|
if (floor == (mobj_t *)-1)
|
|
|
|
thing->z = thing->floorz;
|
|
|
|
else
|
|
|
|
thing->z -= oldfloorz - tmfloorz;
|
1998-04-07 00:00:00 +00:00
|
|
|
}
|
1998-07-14 00:00:00 +00:00
|
|
|
// don't adjust a floating monster unless forced to
|
|
|
|
else if (thing->z + thing->height > thing->ceilingz)
|
|
|
|
thing->z = thing->ceilingz - thing->height;
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
if (thing->ceilingz - thing->floorz < thing->height)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// SLIDE MOVE
|
|
|
|
// Allows the player to slide along any angled walls.
|
|
|
|
//
|
|
|
|
fixed_t bestslidefrac;
|
|
|
|
fixed_t secondslidefrac;
|
|
|
|
|
|
|
|
line_t* bestslideline;
|
|
|
|
line_t* secondslideline;
|
|
|
|
|
|
|
|
mobj_t* slidemo;
|
|
|
|
|
|
|
|
fixed_t tmxmove;
|
|
|
|
fixed_t tmymove;
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
extern mobj_t *onground;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// P_HitSlideLine
|
|
|
|
// Adjusts the xmove / ymove
|
|
|
|
// so that the next move will slide along the wall.
|
1998-12-22 00:00:00 +00:00
|
|
|
// If the floor is icy, then you can bounce off a wall. // phares
|
1998-04-07 00:00:00 +00:00
|
|
|
//
|
|
|
|
void P_HitSlideLine (line_t* ld)
|
|
|
|
{
|
1998-12-22 00:00:00 +00:00
|
|
|
int side;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
angle_t lineangle;
|
|
|
|
angle_t moveangle;
|
|
|
|
angle_t deltaangle;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
fixed_t movelen;
|
|
|
|
fixed_t newlen;
|
|
|
|
BOOL icyfloor; // is floor icy? // phares
|
|
|
|
// |
|
|
|
|
// Under icy conditions, if the angle of approach to the wall // V
|
|
|
|
// is more than 45 degrees, then you'll bounce and lose half
|
|
|
|
// your momentum. If less than 45 degrees, you'll slide along
|
|
|
|
// the wall. 45 is arbitrary and is believable.
|
|
|
|
|
|
|
|
// Check for the special cases of horz or vert walls.
|
|
|
|
|
|
|
|
if (!olddemo && boom_friction->value && slidemo->player)
|
|
|
|
// player must be on ground
|
|
|
|
icyfloor = ((onground == (mobj_t *)-1) && (slidemo->friction > ORIG_FRICTION));
|
|
|
|
else
|
|
|
|
icyfloor = false;
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
if (ld->slopetype == ST_HORIZONTAL)
|
|
|
|
{
|
1998-12-22 00:00:00 +00:00
|
|
|
if (icyfloor && (abs(tmymove) > abs(tmxmove)))
|
|
|
|
{
|
|
|
|
tmxmove /= 2; // absorb half the momentum
|
|
|
|
tmymove = -tmymove/2;
|
|
|
|
S_StartSound (slidemo, "*grunt1", 78); // oooff!
|
|
|
|
}
|
|
|
|
else
|
|
|
|
tmymove = 0; // no more movement in the Y direction
|
1998-04-07 00:00:00 +00:00
|
|
|
return;
|
|
|
|
}
|
1998-12-22 00:00:00 +00:00
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
if (ld->slopetype == ST_VERTICAL)
|
|
|
|
{
|
1998-12-22 00:00:00 +00:00
|
|
|
if (icyfloor && (abs(tmxmove) > abs(tmymove)))
|
|
|
|
{
|
|
|
|
tmxmove = -tmxmove/2; // absorb half the momentum
|
|
|
|
tmymove /= 2;
|
|
|
|
S_StartSound (slidemo, "*grunt1", 78); // oooff! // ^
|
|
|
|
} // |
|
|
|
|
else // phares
|
|
|
|
tmxmove = 0; // no more movement in the X direction
|
1998-04-07 00:00:00 +00:00
|
|
|
return;
|
|
|
|
}
|
1998-12-22 00:00:00 +00:00
|
|
|
|
|
|
|
// The wall is angled. Bounce if the angle of approach is // phares
|
|
|
|
// less than 45 degrees. // phares
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
side = P_PointOnLineSide (slidemo->x, slidemo->y, ld);
|
1998-12-22 00:00:00 +00:00
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
lineangle = R_PointToAngle2 (0,0, ld->dx, ld->dy);
|
|
|
|
|
|
|
|
if (side == 1)
|
|
|
|
lineangle += ANG180;
|
|
|
|
|
|
|
|
moveangle = R_PointToAngle2 (0,0, tmxmove, tmymove);
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
// killough 3/2/98:
|
|
|
|
// The moveangle+=10 breaks v1.9 demo compatibility in
|
|
|
|
// some demos, so it needs demo_compatibility switch.
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
if (!olddemo)
|
|
|
|
moveangle += 10; // prevents sudden path reversal due to // phares
|
|
|
|
// rounding error // |
|
|
|
|
deltaangle = moveangle-lineangle; // V
|
1998-04-07 00:00:00 +00:00
|
|
|
movelen = P_AproxDistance (tmxmove, tmymove);
|
1998-12-22 00:00:00 +00:00
|
|
|
if (icyfloor && (deltaangle > ANG45) && (deltaangle < ANG90+ANG45))
|
|
|
|
{
|
|
|
|
moveangle = lineangle - deltaangle;
|
|
|
|
movelen /= 2; // absorb
|
|
|
|
S_StartSound (slidemo, "*grunt1", 78); // oooff!
|
|
|
|
moveangle >>= ANGLETOFINESHIFT;
|
|
|
|
tmxmove = FixedMul (movelen, finecosine[moveangle]);
|
|
|
|
tmymove = FixedMul (movelen, finesine[moveangle]);
|
|
|
|
} // ^
|
|
|
|
else // |
|
|
|
|
{ // phares
|
|
|
|
if (deltaangle > ANG180)
|
|
|
|
deltaangle += ANG180;
|
|
|
|
// I_Error ("SlideLine: ang>ANG180");
|
|
|
|
|
|
|
|
lineangle >>= ANGLETOFINESHIFT;
|
|
|
|
deltaangle >>= ANGLETOFINESHIFT;
|
|
|
|
|
|
|
|
movelen = P_AproxDistance (tmxmove, tmymove);
|
|
|
|
newlen = FixedMul (movelen, finecosine[deltaangle]);
|
|
|
|
|
|
|
|
tmxmove = FixedMul (newlen, finecosine[lineangle]);
|
|
|
|
tmymove = FixedMul (newlen, finesine[lineangle]);
|
|
|
|
} // phares
|
1998-04-07 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// PTR_SlideTraverse
|
|
|
|
//
|
1998-07-14 00:00:00 +00:00
|
|
|
BOOL PTR_SlideTraverse (intercept_t* in)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
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 (slidemo->x, slidemo->y, li))
|
|
|
|
{
|
|
|
|
// don't hit the back side
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
goto isblocking;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set openrange, opentop, openbottom
|
|
|
|
P_LineOpening (li);
|
|
|
|
|
|
|
|
if (openrange < slidemo->height)
|
|
|
|
goto isblocking; // doesn't fit
|
|
|
|
|
|
|
|
if (opentop - slidemo->z < slidemo->height)
|
|
|
|
goto isblocking; // mobj is too high
|
|
|
|
|
|
|
|
if (openbottom - 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 < bestslidefrac)
|
|
|
|
{
|
|
|
|
secondslidefrac = bestslidefrac;
|
|
|
|
secondslideline = bestslideline;
|
|
|
|
bestslidefrac = in->frac;
|
|
|
|
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;
|
|
|
|
|
|
|
|
slidemo = mo;
|
|
|
|
hitcount = 0;
|
|
|
|
|
|
|
|
retry:
|
|
|
|
if (++hitcount == 3)
|
|
|
|
goto stairstep; // don't loop forever
|
|
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 (bestslidefrac == FRACUNIT+1)
|
|
|
|
{
|
|
|
|
// the move most have hit the middle, so stairstep
|
|
|
|
stairstep:
|
1998-12-22 00:00:00 +00:00
|
|
|
// killough 3/15/98: Allow objects to drop off ledges
|
|
|
|
|
|
|
|
if (!P_TryMove (mo, mo->x, mo->y + mo->momy, true))
|
|
|
|
|
|
|
|
// phares 5/4/98: kill momentum if you can't move at all
|
|
|
|
// This eliminates player bobbing if pressed against a wall
|
|
|
|
// while on ice.
|
|
|
|
|
|
|
|
if (!P_TryMove (mo, mo->x + mo->momx, mo->y, true))
|
|
|
|
if (!olddemo)
|
|
|
|
mo->momx = mo->momy = 0;
|
1998-04-07 00:00:00 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// fudge a bit to make sure it doesn't hit
|
|
|
|
bestslidefrac -= 0x800;
|
|
|
|
if (bestslidefrac > 0)
|
|
|
|
{
|
|
|
|
newx = FixedMul (mo->momx, bestslidefrac);
|
|
|
|
newy = FixedMul (mo->momy, bestslidefrac);
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
// killough 3/15/98: Allow objects to drop off ledges
|
|
|
|
|
|
|
|
if (!P_TryMove (mo, mo->x+newx, mo->y+newy, true))
|
1998-04-07 00:00:00 +00:00
|
|
|
goto stairstep;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now continue along the wall.
|
|
|
|
// First calculate remainder.
|
|
|
|
bestslidefrac = FRACUNIT-(bestslidefrac+0x800);
|
|
|
|
|
|
|
|
if (bestslidefrac > FRACUNIT)
|
|
|
|
bestslidefrac = FRACUNIT;
|
|
|
|
|
|
|
|
if (bestslidefrac <= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
tmxmove = FixedMul (mo->momx, bestslidefrac);
|
|
|
|
tmymove = FixedMul (mo->momy, bestslidefrac);
|
|
|
|
|
|
|
|
P_HitSlideLine (bestslideline); // clip the moves
|
|
|
|
|
|
|
|
mo->momx = tmxmove;
|
|
|
|
mo->momy = tmymove;
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
// killough 3/15/98: Allow objects to drop off ledges
|
|
|
|
|
|
|
|
if (!P_TryMove (mo, mo->x+tmxmove, mo->y+tmymove, true))
|
1998-04-07 00:00:00 +00:00
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// P_LineAttack
|
|
|
|
//
|
|
|
|
mobj_t* linetarget; // who got hit (or NULL)
|
|
|
|
mobj_t* shootthing;
|
|
|
|
|
|
|
|
// Height if not aiming up or down
|
|
|
|
// ???: use slope for monsters?
|
|
|
|
fixed_t shootz;
|
|
|
|
|
|
|
|
int la_damage;
|
|
|
|
fixed_t attackrange;
|
|
|
|
|
|
|
|
fixed_t aimslope;
|
|
|
|
|
|
|
|
// slopes to top and bottom of target
|
1998-12-22 00:00:00 +00:00
|
|
|
// killough 4/20/98: make static instead of using ones in p_sight.c
|
|
|
|
|
|
|
|
static fixed_t topslope;
|
|
|
|
static fixed_t bottomslope;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// PTR_AimTraverse
|
|
|
|
// Sets linetaget and aimslope when a target is aimed at.
|
|
|
|
//
|
1998-12-22 00:00:00 +00:00
|
|
|
BOOL PTR_AimTraverse (intercept_t* in)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
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 (openbottom >= opentop)
|
|
|
|
return false; // stop
|
|
|
|
|
|
|
|
dist = FixedMul (attackrange, in->frac);
|
|
|
|
|
|
|
|
if (li->frontsector->floorheight != li->backsector->floorheight)
|
|
|
|
{
|
|
|
|
slope = FixedDiv (openbottom - shootz , dist);
|
|
|
|
if (slope > bottomslope)
|
|
|
|
bottomslope = slope;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
|
|
|
|
{
|
|
|
|
slope = FixedDiv (opentop - shootz , dist);
|
|
|
|
if (slope < topslope)
|
|
|
|
topslope = slope;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (topslope <= bottomslope)
|
|
|
|
return false; // stop
|
|
|
|
|
|
|
|
return true; // shot continues
|
|
|
|
}
|
|
|
|
|
|
|
|
// shoot a thing
|
|
|
|
th = in->d.thing;
|
|
|
|
if (th == 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 (attackrange, in->frac);
|
|
|
|
thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
|
|
|
|
|
|
|
|
if (thingtopslope < bottomslope)
|
|
|
|
return true; // shot over the thing
|
|
|
|
|
|
|
|
thingbottomslope = FixedDiv (th->z - shootz, dist);
|
|
|
|
|
|
|
|
if (thingbottomslope > topslope)
|
|
|
|
return true; // shot under the thing
|
|
|
|
|
|
|
|
// this thing can be hit!
|
|
|
|
if (thingtopslope > topslope)
|
|
|
|
thingtopslope = topslope;
|
|
|
|
|
|
|
|
if (thingbottomslope < bottomslope)
|
|
|
|
thingbottomslope = bottomslope;
|
|
|
|
|
|
|
|
aimslope = (thingtopslope+thingbottomslope)/2;
|
|
|
|
linetarget = th;
|
|
|
|
|
|
|
|
return false; // don't go any farther
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// PTR_ShootTraverse
|
|
|
|
//
|
1998-07-14 00:00:00 +00:00
|
|
|
BOOL PTR_ShootTraverse (intercept_t* in)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
if (oldshootactivation && li->special)
|
1998-04-07 00:00:00 +00:00
|
|
|
P_ShootSpecialLine (shootthing, li);
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
if ( !(li->flags & ML_TWOSIDED) || (li->flags & ML_BLOCKEVERYTHING))
|
1998-04-07 00:00:00 +00:00
|
|
|
goto hitline;
|
|
|
|
|
|
|
|
// crosses a two sided line
|
|
|
|
P_LineOpening (li);
|
|
|
|
|
|
|
|
dist = FixedMul (attackrange, in->frac);
|
|
|
|
|
|
|
|
if (li->frontsector->floorheight != li->backsector->floorheight)
|
|
|
|
{
|
|
|
|
slope = FixedDiv (openbottom - shootz , dist);
|
|
|
|
if (slope > aimslope)
|
|
|
|
goto hitline;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (li->frontsector->ceilingheight != li->backsector->ceilingheight)
|
|
|
|
{
|
1998-12-22 00:00:00 +00:00
|
|
|
slope = FixedDiv (opentop - shootz, dist);
|
1998-04-07 00:00:00 +00:00
|
|
|
if (slope < aimslope)
|
|
|
|
goto hitline;
|
|
|
|
}
|
|
|
|
|
|
|
|
// shot continues
|
1998-12-22 00:00:00 +00:00
|
|
|
// [RH] Possibly trigger activation
|
|
|
|
if (!oldshootactivation && li->special)
|
|
|
|
P_ShotCrossSpecialLine (shootthing, li);
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
// hit line
|
|
|
|
hitline:
|
1998-12-22 00:00:00 +00:00
|
|
|
// [RH] Possibly trigger activation
|
|
|
|
if (!oldshootactivation && li->special)
|
|
|
|
P_ShootSpecialLine (shootthing, li);
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
// position a bit closer
|
|
|
|
frac = in->frac - FixedDiv (4*FRACUNIT,attackrange);
|
|
|
|
z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
|
|
|
|
|
|
|
|
if (li->frontsector->ceilingpic == 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 == skyflatnum)
|
1998-12-22 00:00:00 +00:00
|
|
|
// fix bullet-eaters -- killough:
|
|
|
|
// WARNING: Almost all demos will lose sync without this
|
|
|
|
// demo_compatibility flag check!!! killough 1/18/98
|
|
|
|
if (olddemo || li->backsector->ceilingheight < z)
|
|
|
|
return false;
|
1998-04-07 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
// [RH] If the trace went below/above the floor/ceiling, make the puff
|
|
|
|
// appear in the right place and not on a wall.
|
|
|
|
{
|
|
|
|
fixed_t ceilingheight, floorheight;
|
|
|
|
|
|
|
|
if (!li->backsector || !P_PointOnLineSide (trace.x, trace.y, li)) {
|
|
|
|
ceilingheight = li->frontsector->ceilingheight;
|
|
|
|
floorheight = li->frontsector->floorheight;
|
|
|
|
} else {
|
|
|
|
ceilingheight = li->backsector->ceilingheight;
|
|
|
|
floorheight = li->backsector->floorheight;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (z < floorheight) {
|
|
|
|
frac = FixedDiv (FixedMul (floorheight - shootz, frac), z - shootz);
|
|
|
|
z = floorheight;
|
|
|
|
} else if (z > ceilingheight) {
|
|
|
|
// Puffs on the ceiling need to be lowered to compensate for the height of the puff
|
|
|
|
ceilingheight -= mobjinfo[MT_PUFF].height;
|
|
|
|
frac = FixedDiv (FixedMul (ceilingheight - shootz, frac), z - shootz);
|
|
|
|
z = ceilingheight;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
x = trace.x + FixedMul (trace.dx, frac);
|
|
|
|
y = trace.y + FixedMul (trace.dy, frac);
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
// Spawn bullet puffs.
|
1998-12-22 00:00:00 +00:00
|
|
|
P_SpawnPuff (x, y, z);
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
// don't go any farther
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// shoot a thing
|
|
|
|
th = in->d.thing;
|
|
|
|
if (th == 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 (attackrange, in->frac);
|
|
|
|
thingtopslope = FixedDiv (th->z+th->height - shootz , dist);
|
|
|
|
|
|
|
|
if (thingtopslope < aimslope)
|
|
|
|
return true; // shot over the thing
|
|
|
|
|
|
|
|
thingbottomslope = FixedDiv (th->z - shootz, dist);
|
|
|
|
|
|
|
|
if (thingbottomslope > aimslope)
|
|
|
|
return true; // shot under the thing
|
|
|
|
|
|
|
|
|
|
|
|
// hit thing
|
|
|
|
// position a bit closer
|
|
|
|
frac = in->frac - FixedDiv (10*FRACUNIT,attackrange);
|
|
|
|
|
|
|
|
x = trace.x + FixedMul (trace.dx, frac);
|
|
|
|
y = trace.y + FixedMul (trace.dy, frac);
|
|
|
|
z = shootz + FixedMul (aimslope, FixedMul(frac, attackrange));
|
|
|
|
|
|
|
|
// Spawn bullet puffs or blod spots,
|
|
|
|
// depending on target type.
|
1998-12-22 00:00:00 +00:00
|
|
|
if ((in->d.thing->flags & MF_NOBLOOD) || (in->d.thing->flags2 & MF2_INVULNERABLE))
|
1998-04-07 00:00:00 +00:00
|
|
|
P_SpawnPuff (x,y,z);
|
|
|
|
else
|
|
|
|
P_SpawnBlood (x,y,z, la_damage);
|
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
if (la_damage) {
|
1998-12-22 00:00:00 +00:00
|
|
|
// [RH] try and figure out means of death;
|
1998-07-14 00:00:00 +00:00
|
|
|
int mod = MOD_UNKNOWN;
|
|
|
|
|
|
|
|
if (shootthing->player) {
|
|
|
|
switch (shootthing->player->readyweapon) {
|
1998-12-22 00:00:00 +00:00
|
|
|
case wp_fist:
|
|
|
|
mod = MOD_FIST;
|
|
|
|
break;
|
1998-07-14 00:00:00 +00:00
|
|
|
case wp_pistol:
|
|
|
|
mod = MOD_PISTOL;
|
|
|
|
break;
|
|
|
|
case wp_shotgun:
|
|
|
|
mod = MOD_SHOTGUN;
|
|
|
|
break;
|
|
|
|
case wp_chaingun:
|
|
|
|
mod = MOD_CHAINGUN;
|
|
|
|
break;
|
|
|
|
case wp_supershotgun:
|
|
|
|
mod = MOD_SSHOTGUN;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
P_DamageMobj (th, shootthing, shootthing, la_damage, mod);
|
|
|
|
}
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
// don't go any farther
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// P_AimLineAttack
|
|
|
|
//
|
1998-12-22 00:00:00 +00:00
|
|
|
fixed_t P_AimLineAttack (mobj_t *t1, angle_t angle, fixed_t distance)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
fixed_t x2;
|
|
|
|
fixed_t y2;
|
|
|
|
|
|
|
|
angle >>= ANGLETOFINESHIFT;
|
|
|
|
shootthing = t1;
|
|
|
|
|
|
|
|
x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
|
|
|
|
y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
|
|
|
|
shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
|
|
|
|
|
|
|
|
// can't shoot outside view angles
|
1998-07-14 00:00:00 +00:00
|
|
|
// [RH] also adjust for view pitch
|
|
|
|
{
|
|
|
|
fixed_t slopediff = FixedMul (t1->pitch, -40960);
|
|
|
|
topslope = 100*FRACUNIT/160 + slopediff;
|
|
|
|
bottomslope = -100*FRACUNIT/160 + slopediff;
|
|
|
|
}
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
attackrange = distance;
|
|
|
|
linetarget = NULL;
|
|
|
|
|
|
|
|
P_PathTraverse ( t1->x, t1->y,
|
|
|
|
x2, y2,
|
|
|
|
PT_ADDLINES|PT_ADDTHINGS,
|
|
|
|
PTR_AimTraverse );
|
|
|
|
|
|
|
|
if (linetarget)
|
|
|
|
return aimslope;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// P_LineAttack
|
|
|
|
// If damage == 0, it is just a test trace
|
|
|
|
// that will leave linetarget set.
|
|
|
|
//
|
1998-07-14 00:00:00 +00:00
|
|
|
void P_LineAttack (mobj_t *t1, angle_t angle, fixed_t distance,
|
|
|
|
fixed_t slope, int damage)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
fixed_t x2;
|
|
|
|
fixed_t y2;
|
|
|
|
|
|
|
|
angle >>= ANGLETOFINESHIFT;
|
|
|
|
shootthing = t1;
|
|
|
|
la_damage = damage;
|
|
|
|
x2 = t1->x + (distance>>FRACBITS)*finecosine[angle];
|
|
|
|
y2 = t1->y + (distance>>FRACBITS)*finesine[angle];
|
|
|
|
shootz = t1->z + (t1->height>>1) + 8*FRACUNIT;
|
|
|
|
attackrange = distance;
|
|
|
|
aimslope = slope;
|
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
P_PathTraverse (t1->x, t1->y, x2, y2, PT_ADDLINES|PT_ADDTHINGS, PTR_ShootTraverse);
|
1998-04-07 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// USE LINES
|
|
|
|
//
|
1998-07-14 00:00:00 +00:00
|
|
|
mobj_t *usething;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
BOOL PTR_UseTraverse (intercept_t *in)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
1998-07-14 00:00:00 +00:00
|
|
|
int side;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
if (!in->d.line->special)
|
|
|
|
{
|
|
|
|
P_LineOpening (in->d.line);
|
|
|
|
if (openrange <= 0)
|
|
|
|
{
|
1998-12-22 00:00:00 +00:00
|
|
|
S_StartSound (usething, "*grunt1", 78);
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
// can't use through a wall
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// not a special line, but keep checking
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
|
|
|
|
side = 0;
|
|
|
|
if (P_PointOnLineSide (usething->x, usething->y, in->d.line) == 1)
|
|
|
|
side = 1;
|
|
|
|
|
|
|
|
// return false; // don't use back side
|
|
|
|
|
|
|
|
P_UseSpecialLine (usething, in->d.line, side);
|
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
//WAS can't use for than one special line in a row
|
|
|
|
//jff 3/21/98 NOW multiple use allowed with enabling line flag
|
|
|
|
|
|
|
|
return (!olddemo && (in->d.line->flags & ML_PASSUSE)) ? true : false;
|
1998-04-07 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
// Returns false if a "oof" sound should be made because of a blocking
|
|
|
|
// linedef. Makes 2s middles which are impassable, as well as 2s uppers
|
|
|
|
// and lowers which block the player, cause the sound effect when the
|
|
|
|
// player tries to activate them. Specials are excluded, although it is
|
|
|
|
// assumed that all special linedefs within reach have been considered
|
|
|
|
// and rejected already (see P_UseLines).
|
|
|
|
//
|
|
|
|
// by Lee Killough
|
|
|
|
//
|
|
|
|
|
|
|
|
BOOL PTR_NoWayTraverse(intercept_t* in)
|
|
|
|
{
|
|
|
|
line_t *ld = in->d.line; // This linedef
|
|
|
|
|
|
|
|
return ld->special || !( // Ignore specials
|
|
|
|
ld->flags & (ML_BLOCKING|ML_BLOCKEVERYTHING) || ( // Always blocking
|
|
|
|
P_LineOpening(ld), // Find openings
|
|
|
|
openrange <= 0 || // No opening
|
|
|
|
openbottom > usething->z+24*FRACUNIT || // Too high it blocks
|
|
|
|
opentop < usething->z+usething->height // Too low it blocks
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// P_UseLines
|
|
|
|
// Looks for special 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;
|
|
|
|
|
|
|
|
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];
|
1998-12-22 00:00:00 +00:00
|
|
|
|
|
|
|
// old code:
|
|
|
|
//
|
|
|
|
// P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse );
|
|
|
|
//
|
|
|
|
// This added test makes the "oof" sound work on 2s lines -- killough:
|
|
|
|
|
|
|
|
if (P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse ))
|
|
|
|
if (!P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_NoWayTraverse ))
|
|
|
|
S_StartSound (usething, "*grunt1", 78);
|
1998-04-07 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
// -> [RH] Z-Check
|
|
|
|
static mobj_t *cfthing, *sfthing;
|
|
|
|
|
|
|
|
BOOL PIT_CheckFloor (mobj_t *thing)
|
|
|
|
{
|
|
|
|
fixed_t blockdist;
|
|
|
|
|
|
|
|
// don't stand on self
|
|
|
|
if (thing == cfthing)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// don't stand on nonsolid objects
|
|
|
|
if (!(thing->flags & MF_SOLID))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// don't stand on dead corpses
|
|
|
|
if (thing->flags & MF_CORPSE && thing->health <= 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
blockdist = thing->radius + cfthing->radius;
|
|
|
|
|
|
|
|
if ( abs(thing->x - cfthing->x) >= blockdist
|
|
|
|
|| abs(thing->y - cfthing->y) >= blockdist )
|
|
|
|
// nowhere near it
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (cfthing->z > thing->z + thing->height || // above it
|
|
|
|
cfthing->z < thing->z) // below it
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// on (in) it
|
|
|
|
sfthing = thing;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mobj_t *P_FindFloor (mobj_t *thing)
|
|
|
|
{
|
|
|
|
int xl;
|
|
|
|
int xh;
|
|
|
|
int yl;
|
|
|
|
int yh;
|
|
|
|
|
|
|
|
int bx;
|
|
|
|
int by;
|
|
|
|
|
|
|
|
fixed_t ffbox[4];
|
|
|
|
|
|
|
|
if (thing->z <= thing->floorz)
|
|
|
|
return (mobj_t *)-1; // On floor
|
|
|
|
|
|
|
|
if (!(thing->flags & MF_SOLID)) // Non-solid objects can't stand on other mobjs
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (thing->flags & (MF_NOCLIP|MF_NOBLOCKMAP))
|
|
|
|
return NULL; // Noclip objects don't use mobjs as floors
|
|
|
|
|
|
|
|
if (thing->flags & MF_CORPSE && thing->health <= 0)
|
|
|
|
return NULL; // Dead corpses also don't sense other mobjs
|
|
|
|
|
|
|
|
ffbox[BOXTOP] = thing->y + thing->radius;
|
|
|
|
ffbox[BOXBOTTOM] = thing->y - thing->radius;
|
|
|
|
ffbox[BOXRIGHT] = thing->x + thing->radius;
|
|
|
|
ffbox[BOXLEFT] = thing->x - thing->radius;
|
|
|
|
|
|
|
|
// check for things underneath us
|
|
|
|
xl = (ffbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
xh = (ffbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
yl = (ffbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
yh = (ffbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
|
|
|
|
cfthing = thing;
|
|
|
|
|
|
|
|
for (bx=xl ; bx<=xh ; bx++)
|
|
|
|
for (by=yl ; by<=yh ; by++)
|
|
|
|
if (!P_BlockThingsIterator(bx,by,PIT_CheckFloor))
|
|
|
|
return sfthing;
|
|
|
|
|
|
|
|
return NULL; // In midair
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL PIT_CheckCeiling (mobj_t *thing)
|
|
|
|
{
|
|
|
|
fixed_t blockdist;
|
|
|
|
|
|
|
|
// don't hit self
|
|
|
|
if (thing == cfthing)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// don't hit nonsolid objects
|
|
|
|
if (!(thing->flags & MF_SOLID))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// don't hit dead corpses
|
|
|
|
if (thing->flags & MF_CORPSE && thing->health <= 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
blockdist = thing->radius + cfthing->radius;
|
|
|
|
|
|
|
|
if ( abs(thing->x - cfthing->x) >= blockdist
|
|
|
|
|| abs(thing->y - cfthing->y) >= blockdist )
|
|
|
|
// nowhere near it
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (cfthing->z + cfthing->height < thing->z || // below it
|
|
|
|
cfthing->z + cfthing->height > thing->z + thing->height) // above it
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// hit it
|
|
|
|
sfthing = thing;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
mobj_t *P_FindCeiling (mobj_t *thing)
|
|
|
|
{
|
|
|
|
int xl;
|
|
|
|
int xh;
|
|
|
|
int yl;
|
|
|
|
int yh;
|
|
|
|
|
|
|
|
int bx;
|
|
|
|
int by;
|
|
|
|
|
|
|
|
fixed_t ffbox[4];
|
|
|
|
|
|
|
|
if (thing->z + thing->height >= thing->ceilingz)
|
|
|
|
return (mobj_t *)-1; // Hit ceiling
|
|
|
|
|
|
|
|
if (!(thing->flags & MF_SOLID)) // Non-solid objects aren't blocked by other mobjs
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (thing->flags & (MF_NOCLIP|MF_NOBLOCKMAP))
|
|
|
|
return NULL; // Noclip objects don't use mobjs as ceilings
|
|
|
|
|
|
|
|
if (thing->flags & MF_CORPSE && thing->health <= 0)
|
|
|
|
return NULL; // Dead corpses also don't sense other mobjs
|
|
|
|
|
|
|
|
ffbox[BOXTOP] = thing->y + thing->radius;
|
|
|
|
ffbox[BOXBOTTOM] = thing->y - thing->radius;
|
|
|
|
ffbox[BOXRIGHT] = thing->x + thing->radius;
|
|
|
|
ffbox[BOXLEFT] = thing->x - thing->radius;
|
|
|
|
|
|
|
|
// check for things above us
|
|
|
|
xl = (ffbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
xh = (ffbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
yl = (ffbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
yh = (ffbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
|
|
|
|
|
|
cfthing = thing;
|
|
|
|
|
|
|
|
for (bx=xl ; bx<=xh ; bx++)
|
|
|
|
for (by=yl ; by<=yh ; by++)
|
|
|
|
if (!P_BlockThingsIterator(bx,by,PIT_CheckCeiling))
|
|
|
|
return sfthing;
|
|
|
|
|
|
|
|
return NULL; // In midair
|
|
|
|
}
|
|
|
|
|
|
|
|
void P_StandOnThing (mobj_t *thing, mobj_t *spot)
|
|
|
|
{
|
|
|
|
if (!spot)
|
|
|
|
spot = P_FindFloor (thing);
|
|
|
|
|
|
|
|
if (spot && spot != (mobj_t *)-1)
|
|
|
|
thing->z = spot->z + spot->height;
|
|
|
|
else
|
|
|
|
thing->z = thing->floorz;
|
1998-12-22 00:00:00 +00:00
|
|
|
|
|
|
|
if (thing->flags2 & MF2_JUMPING)
|
|
|
|
thing->flags2 &= ~MF2_JUMPING;
|
1998-07-14 00:00:00 +00:00
|
|
|
}
|
|
|
|
// [RH] Z-Check <-
|
|
|
|
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
//
|
|
|
|
// RADIUS ATTACK
|
|
|
|
//
|
|
|
|
mobj_t* bombsource;
|
|
|
|
mobj_t* bombspot;
|
|
|
|
int bombdamage;
|
1998-07-14 00:00:00 +00:00
|
|
|
float bombdamagefloat;
|
|
|
|
int bombmod;
|
|
|
|
vec3_t bombvec;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// PIT_RadiusAttack
|
|
|
|
// "bombsource" is the creature
|
|
|
|
// that caused the explosion at "bombspot".
|
1998-07-14 00:00:00 +00:00
|
|
|
// [RH] Now it knows about vertical distances and
|
|
|
|
// can thrust things vertically, too.
|
1998-04-07 00:00:00 +00:00
|
|
|
//
|
1998-12-22 00:00:00 +00:00
|
|
|
|
|
|
|
// [RH] Damage scale to apply to thing that shot the missile.
|
|
|
|
cvar_t *splashfactor;
|
|
|
|
static float selfthrustscale;
|
|
|
|
|
|
|
|
void SplashFactorCallback (cvar_t *var) {
|
|
|
|
if (var->value <= 0.0f) {
|
|
|
|
SetCVarFloat (var, 1.0f);
|
|
|
|
} else {
|
|
|
|
selfthrustscale = 1.0f / var->value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
BOOL PIT_RadiusAttack (mobj_t *thing)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
if (!(thing->flags & MF_SHOOTABLE) )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Boss spider and cyborg
|
|
|
|
// take no damage from concussion.
|
1998-07-14 00:00:00 +00:00
|
|
|
if (thing->type == MT_CYBORG || thing->type == MT_SPIDER)
|
1998-04-07 00:00:00 +00:00
|
|
|
return true;
|
1998-07-14 00:00:00 +00:00
|
|
|
|
1998-07-26 00:00:00 +00:00
|
|
|
// Barrels always use the original code, since this makes
|
|
|
|
// them far too "active."
|
|
|
|
if (!olddemo && bombspot->type != MT_BARREL && thing->type != MT_BARREL) {
|
1998-07-14 00:00:00 +00:00
|
|
|
// [RH] New code (based on stuff in Q2)
|
|
|
|
float points;
|
|
|
|
vec3_t thingvec;
|
|
|
|
|
|
|
|
VectorPosition (thing, thingvec);
|
|
|
|
thingvec[2] += (float)(thing->height >> (FRACBITS+1));
|
|
|
|
{
|
|
|
|
vec3_t v;
|
1998-07-26 00:00:00 +00:00
|
|
|
float len;
|
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
VectorSubtract (bombvec, thingvec, v);
|
1998-07-26 00:00:00 +00:00
|
|
|
len = VectorLength (v);
|
|
|
|
points = bombdamagefloat - len;
|
1998-07-14 00:00:00 +00:00
|
|
|
}
|
|
|
|
if (thing == bombsource)
|
1998-12-22 00:00:00 +00:00
|
|
|
points = points * splashfactor->value;
|
1998-07-14 00:00:00 +00:00
|
|
|
if (points > 0) {
|
1998-12-22 00:00:00 +00:00
|
|
|
if (P_CheckSight (thing, bombspot, true)) {
|
1998-07-14 00:00:00 +00:00
|
|
|
vec3_t dir;
|
|
|
|
float thrust;
|
|
|
|
fixed_t momx = thing->momx;
|
|
|
|
fixed_t momy = thing->momy;
|
|
|
|
|
|
|
|
P_DamageMobj (thing, bombspot, bombsource, (int)points, bombmod);
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
thrust = points * 35000.0f / (float)thing->info->mass;
|
1998-07-14 00:00:00 +00:00
|
|
|
VectorSubtract (thingvec, bombvec, dir);
|
|
|
|
VectorScale (dir, thrust, dir);
|
1998-12-22 00:00:00 +00:00
|
|
|
if (bombsource != thing) {
|
1998-07-14 00:00:00 +00:00
|
|
|
dir[2] *= 0.5f;
|
1998-12-22 00:00:00 +00:00
|
|
|
} else if (splashfactor->value) {
|
|
|
|
dir[0] *= selfthrustscale;
|
|
|
|
dir[1] *= selfthrustscale;
|
|
|
|
dir[2] *= selfthrustscale;
|
|
|
|
}
|
1998-07-14 00:00:00 +00:00
|
|
|
thing->momx = momx + (fixed_t)(dir[0]);
|
|
|
|
thing->momy = momy + (fixed_t)(dir[1]);
|
|
|
|
thing->momz += (fixed_t)(dir[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// [RH] Old code in a futile attempt to maintain demo compatibility
|
|
|
|
fixed_t dx;
|
|
|
|
fixed_t dy;
|
|
|
|
fixed_t dist;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
dx = abs(thing->x - bombspot->x);
|
|
|
|
dy = abs(thing->y - bombspot->y);
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
dist = dx>dy ? dx : dy;
|
|
|
|
dist = (dist - thing->radius) >> FRACBITS;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
if (dist >= bombdamage)
|
|
|
|
return true; // out of range
|
|
|
|
|
|
|
|
if (dist < 0)
|
|
|
|
dist = 0;
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
if ( P_CheckSight (thing, bombspot, true) )
|
1998-07-14 00:00:00 +00:00
|
|
|
{
|
|
|
|
// must be in direct path
|
|
|
|
P_DamageMobj (thing, bombspot, bombsource, bombdamage - dist, bombmod);
|
|
|
|
}
|
1998-04-07 00:00:00 +00:00
|
|
|
}
|
1998-07-14 00:00:00 +00:00
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// P_RadiusAttack
|
|
|
|
// Source is the creature that caused the explosion at spot.
|
|
|
|
//
|
1998-07-14 00:00:00 +00:00
|
|
|
void P_RadiusAttack (mobj_t *spot, mobj_t *source, int damage, int mod)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
|
|
|
|
int xl;
|
|
|
|
int xh;
|
|
|
|
int yl;
|
|
|
|
int yh;
|
|
|
|
|
|
|
|
fixed_t dist;
|
|
|
|
|
|
|
|
dist = (damage+MAXRADIUS)<<FRACBITS;
|
|
|
|
yh = (spot->y + dist - bmaporgy)>>MAPBLOCKSHIFT;
|
|
|
|
yl = (spot->y - dist - bmaporgy)>>MAPBLOCKSHIFT;
|
|
|
|
xh = (spot->x + dist - bmaporgx)>>MAPBLOCKSHIFT;
|
|
|
|
xl = (spot->x - dist - bmaporgx)>>MAPBLOCKSHIFT;
|
|
|
|
bombspot = spot;
|
|
|
|
bombsource = source;
|
|
|
|
bombdamage = damage;
|
1998-07-14 00:00:00 +00:00
|
|
|
bombdamagefloat = (float)damage;
|
|
|
|
bombmod = mod;
|
|
|
|
VectorPosition (spot, bombvec);
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
for (y=yl ; y<=yh ; y++)
|
|
|
|
for (x=xl ; x<=xh ; x++)
|
|
|
|
P_BlockThingsIterator (x, y, PIT_RadiusAttack );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// SECTOR HEIGHT CHANGING
|
|
|
|
// After modifying a 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.
|
|
|
|
//
|
1998-12-22 00:00:00 +00:00
|
|
|
// [RH] If crushchange is non-negative, they will take the
|
|
|
|
// specified amount of damage as they are being crushed.
|
|
|
|
// If crushchange is negative, you should set the sector
|
|
|
|
// height back the way it was and call P_ChangeSector
|
|
|
|
// again to undo the changes.
|
|
|
|
// Note that this is very different from the original
|
|
|
|
// true/false usage of crushchange! If you want regular
|
|
|
|
// DOOM crushing behavior set crushchange to 10 or -1
|
|
|
|
// if no crushing is desired.
|
|
|
|
//
|
|
|
|
int crushchange;
|
|
|
|
BOOL nofit;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// PIT_ChangeSector
|
|
|
|
//
|
1998-07-26 00:00:00 +00:00
|
|
|
BOOL PIT_ChangeSector (mobj_t *thing)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
1998-07-14 00:00:00 +00:00
|
|
|
mobj_t *mo;
|
|
|
|
int t;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
nofit = true;
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
if ((crushchange >= 0) && !(level.time&3) )
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
1998-12-22 00:00:00 +00:00
|
|
|
P_DamageMobj (thing, NULL, NULL, crushchange, MOD_CRUSH);
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
// spray blood in a random direction
|
|
|
|
mo = P_SpawnMobj (thing->x,
|
|
|
|
thing->y,
|
1998-07-14 00:00:00 +00:00
|
|
|
thing->z + thing->height/2, MT_BLOOD, 0);
|
1998-04-07 00:00:00 +00:00
|
|
|
|
1998-07-14 00:00:00 +00:00
|
|
|
t = P_Random (pr_changesector);
|
|
|
|
mo->momx = (t - P_Random (pr_changesector)) << 12;
|
|
|
|
t = P_Random (pr_changesector);
|
|
|
|
mo->momy = (t - P_Random (pr_changesector)) << 12;
|
1998-04-07 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// keep checking (crush other things)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// P_ChangeSector
|
|
|
|
//
|
1998-12-22 00:00:00 +00:00
|
|
|
BOOL P_ChangeSector (sector_t *sector, int crunch)
|
1998-04-07 00:00:00 +00:00
|
|
|
{
|
1998-07-26 00:00:00 +00:00
|
|
|
int x;
|
|
|
|
int y;
|
1998-04-07 00:00:00 +00:00
|
|
|
|
|
|
|
nofit = false;
|
|
|
|
crushchange = crunch;
|
1998-12-22 00:00:00 +00:00
|
|
|
|
|
|
|
// ARRGGHHH!!!!
|
|
|
|
// This is horrendously slow!!!
|
|
|
|
// killough 3/14/98
|
|
|
|
|
1998-04-07 00:00:00 +00:00
|
|
|
// 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 nofit;
|
|
|
|
}
|
|
|
|
|
1998-07-26 00:00:00 +00:00
|
|
|
//
|
|
|
|
// P_CheckSector
|
|
|
|
// jff 3/19/98 added to just check monsters on the periphery
|
|
|
|
// of a moving sector instead of all in bounding box of the
|
|
|
|
// sector. Both more accurate and faster.
|
|
|
|
//
|
|
|
|
|
1998-12-22 00:00:00 +00:00
|
|
|
BOOL P_CheckSector (sector_t *sector, int crunch)
|
1998-07-26 00:00:00 +00:00
|
|
|
{
|
|
|
|
msecnode_t *n;
|
|
|
|
|
|
|
|
if (olddemo) // use the old routine for old demos though
|
1998-12-22 00:00:00 +00:00
|
|
|
return P_ChangeSector (sector, crunch);
|
1998-07-26 00:00:00 +00:00
|
|
|
|
|
|
|
nofit = false;
|
|
|
|
crushchange = crunch;
|
|
|
|
|
|
|
|
// killough 4/4/98: scan list front-to-back until empty or exhausted,
|
|
|
|
// restarting from beginning after each thing is processed. Avoids
|
|
|
|
// crashes, and is sure to examine all things in the sector, and only
|
|
|
|
// the things which are in the sector, until a steady-state is reached.
|
|
|
|
// Things can arbitrarily be inserted and removed and it won't mess up.
|
|
|
|
//
|
|
|
|
// killough 4/7/98: simplified to avoid using complicated counter
|
|
|
|
|
|
|
|
// Mark all things invalid
|
|
|
|
|
|
|
|
for (n=sector->touching_thinglist; n; n=n->m_snext)
|
|
|
|
n->visited = false;
|
|
|
|
|
|
|
|
do
|
|
|
|
for (n=sector->touching_thinglist; n; n=n->m_snext) // go through list
|
|
|
|
if (!n->visited) // unprocessed thing found
|
|
|
|
{
|
|
|
|
n->visited = true; // mark thing as processed
|
|
|
|
if (!(n->m_thing->flags & MF_NOBLOCKMAP)) //jff 4/7/98 don't do these
|
|
|
|
PIT_ChangeSector(n->m_thing); // process it
|
|
|
|
break; // exit and start over
|
|
|
|
}
|
|
|
|
while (n); // repeat from scratch until all things left are marked valid
|
|
|
|
|
|
|
|
return nofit;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// phares 3/21/98
|
|
|
|
//
|
|
|
|
// Maintain a freelist of msecnode_t's to reduce memory allocs and frees.
|
|
|
|
|
|
|
|
msecnode_t *headsecnode = NULL;
|
|
|
|
|
|
|
|
// P_GetSecnode() retrieves a node from the freelist. The calling routine
|
|
|
|
// should make sure it sets all fields properly.
|
|
|
|
|
|
|
|
msecnode_t *P_GetSecnode()
|
|
|
|
{
|
|
|
|
msecnode_t *node;
|
|
|
|
|
|
|
|
if (headsecnode)
|
|
|
|
{
|
|
|
|
node = headsecnode;
|
|
|
|
headsecnode = headsecnode->m_snext;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
node = Z_Malloc (sizeof(*node), PU_LEVEL, NULL);
|
|
|
|
return(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
// P_PutSecnode() returns a node to the freelist.
|
|
|
|
|
|
|
|
void P_PutSecnode (msecnode_t* node)
|
|
|
|
{
|
|
|
|
node->m_snext = headsecnode;
|
|
|
|
headsecnode = node;
|
|
|
|
}
|
|
|
|
|
|
|
|
// phares 3/16/98
|
|
|
|
//
|
|
|
|
// P_AddSecnode() searches the current list to see if this sector is
|
|
|
|
// already there. If not, it adds a sector node at the head of the list of
|
|
|
|
// sectors this object appears in. This is called when creating a list of
|
|
|
|
// nodes that will get linked in later. Returns a pointer to the new node.
|
|
|
|
|
|
|
|
msecnode_t* P_AddSecnode(sector_t* s, mobj_t* thing, msecnode_t* nextnode)
|
|
|
|
{
|
|
|
|
msecnode_t* node;
|
|
|
|
|
|
|
|
node = nextnode;
|
|
|
|
while (node)
|
|
|
|
{
|
|
|
|
if (node->m_sector == s) // Already have a node for this sector?
|
|
|
|
{
|
|
|
|
node->m_thing = thing; // Yes. Setting m_thing says 'keep it'.
|
|
|
|
return(nextnode);
|
|
|
|
}
|
|
|
|
node = node->m_tnext;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Couldn't find an existing node for this sector. Add one at the head
|
|
|
|
// of the list.
|
|
|
|
|
|
|
|
node = P_GetSecnode();
|
|
|
|
|
|
|
|
// killough 4/4/98, 4/7/98: mark new nodes unvisited.
|
|
|
|
node->visited = 0;
|
|
|
|
|
|
|
|
node->m_sector = s; // sector
|
|
|
|
node->m_thing = thing; // mobj
|
|
|
|
node->m_tprev = NULL; // prev node on Thing thread
|
|
|
|
node->m_tnext = nextnode; // next node on Thing thread
|
|
|
|
if (nextnode)
|
|
|
|
nextnode->m_tprev = node; // set back link on Thing
|
|
|
|
|
|
|
|
// Add new node at head of sector thread starting at s->touching_thinglist
|
|
|
|
|
|
|
|
node->m_sprev = NULL; // prev node on sector thread
|
|
|
|
node->m_snext = s->touching_thinglist; // next node on sector thread
|
|
|
|
if (s->touching_thinglist)
|
|
|
|
node->m_snext->m_sprev = node;
|
|
|
|
s->touching_thinglist = node;
|
|
|
|
return(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// P_DelSecnode() deletes a sector node from the list of
|
|
|
|
// sectors this object appears in. Returns a pointer to the next node
|
|
|
|
// on the linked list, or NULL.
|
|
|
|
|
|
|
|
msecnode_t* P_DelSecnode(msecnode_t* node)
|
|
|
|
{
|
|
|
|
msecnode_t* tp; // prev node on thing thread
|
|
|
|
msecnode_t* tn; // next node on thing thread
|
|
|
|
msecnode_t* sp; // prev node on sector thread
|
|
|
|
msecnode_t* sn; // next node on sector thread
|
|
|
|
|
|
|
|
if (node)
|
|
|
|
{
|
|
|
|
|
|
|
|
// Unlink from the Thing thread. The Thing thread begins at
|
|
|
|
// sector_list and not from mobj_t->touching_sectorlist.
|
|
|
|
|
|
|
|
tp = node->m_tprev;
|
|
|
|
tn = node->m_tnext;
|
|
|
|
if (tp)
|
|
|
|
tp->m_tnext = tn;
|
|
|
|
if (tn)
|
|
|
|
tn->m_tprev = tp;
|
|
|
|
|
|
|
|
// Unlink from the sector thread. This thread begins at
|
|
|
|
// sector_t->touching_thinglist.
|
|
|
|
|
|
|
|
sp = node->m_sprev;
|
|
|
|
sn = node->m_snext;
|
|
|
|
if (sp)
|
|
|
|
sp->m_snext = sn;
|
|
|
|
else
|
|
|
|
node->m_sector->touching_thinglist = sn;
|
|
|
|
if (sn)
|
|
|
|
sn->m_sprev = sp;
|
|
|
|
|
|
|
|
// Return this node to the freelist
|
|
|
|
|
|
|
|
P_PutSecnode(node);
|
|
|
|
return(tn);
|
|
|
|
}
|
|
|
|
return(NULL);
|
|
|
|
} // phares 3/13/98
|
|
|
|
|
|
|
|
// Delete an entire sector list
|
|
|
|
|
|
|
|
void P_DelSeclist(msecnode_t* node)
|
|
|
|
{
|
|
|
|
while (node)
|
|
|
|
node = P_DelSecnode(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// phares 3/14/98
|
|
|
|
//
|
|
|
|
// PIT_GetSectors
|
|
|
|
// Locates all the sectors the object is in by looking at the lines that
|
|
|
|
// cross through it. You have already decided that the object is allowed
|
|
|
|
// at this location, so don't bother with checking impassable or
|
|
|
|
// blocking lines.
|
|
|
|
|
|
|
|
BOOL PIT_GetSectors(line_t* ld)
|
|
|
|
{
|
|
|
|
if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] ||
|
|
|
|
tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] ||
|
|
|
|
tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] ||
|
|
|
|
tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP])
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (P_BoxOnLineSide(tmbbox, ld) != -1)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// This line crosses through the object.
|
|
|
|
|
|
|
|
// Collect the sector(s) from the line and add to the
|
|
|
|
// sector_list you're examining. If the Thing ends up being
|
|
|
|
// allowed to move to this position, then the sector_list
|
|
|
|
// will be attached to the Thing's mobj_t at touching_sectorlist.
|
|
|
|
|
|
|
|
sector_list = P_AddSecnode(ld->frontsector,tmthing,sector_list);
|
|
|
|
|
|
|
|
// Don't assume all lines are 2-sided, since some Things
|
|
|
|
// like MT_TFOG are allowed regardless of whether their radius takes
|
|
|
|
// them beyond an impassable linedef.
|
|
|
|
|
|
|
|
// killough 3/27/98, 4/4/98:
|
|
|
|
// Use sidedefs instead of 2s flag to determine two-sidedness.
|
|
|
|
|
|
|
|
if (ld->backsector)
|
|
|
|
sector_list = P_AddSecnode(ld->backsector, tmthing, sector_list);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// phares 3/14/98
|
|
|
|
//
|
|
|
|
// P_CreateSecNodeList alters/creates the sector_list that shows what sectors
|
|
|
|
// the object resides in.
|
|
|
|
|
|
|
|
void P_CreateSecNodeList(mobj_t* thing,fixed_t x,fixed_t y)
|
|
|
|
{
|
|
|
|
int xl;
|
|
|
|
int xh;
|
|
|
|
int yl;
|
|
|
|
int yh;
|
|
|
|
int bx;
|
|
|
|
int by;
|
|
|
|
msecnode_t* node;
|
|
|
|
|
|
|
|
// First, clear out the existing m_thing fields. As each node is
|
|
|
|
// added or verified as needed, m_thing will be set properly. When
|
|
|
|
// finished, delete all nodes where m_thing is still NULL. These
|
|
|
|
// represent the sectors the Thing has vacated.
|
|
|
|
|
|
|
|
node = sector_list;
|
|
|
|
while (node)
|
|
|
|
{
|
|
|
|
node->m_thing = NULL;
|
|
|
|
node = node->m_tnext;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmthing = thing;
|
|
|
|
tmflags = thing->flags;
|
|
|
|
|
|
|
|
tmx = x;
|
|
|
|
tmy = y;
|
|
|
|
|
|
|
|
tmbbox[BOXTOP] = y + tmthing->radius;
|
|
|
|
tmbbox[BOXBOTTOM] = y - tmthing->radius;
|
|
|
|
tmbbox[BOXRIGHT] = x + tmthing->radius;
|
|
|
|
tmbbox[BOXLEFT] = x - tmthing->radius;
|
|
|
|
|
|
|
|
validcount++; // used to make sure we only process a line once
|
|
|
|
|
|
|
|
xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT;
|
|
|
|
xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT;
|
|
|
|
yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT;
|
|
|
|
yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT;
|
|
|
|
|
|
|
|
for (bx=xl ; bx<=xh ; bx++)
|
|
|
|
for (by=yl ; by<=yh ; by++)
|
|
|
|
P_BlockLinesIterator(bx,by,PIT_GetSectors);
|
|
|
|
|
|
|
|
// Add the sector of the (x,y) point to sector_list.
|
|
|
|
|
|
|
|
sector_list = P_AddSecnode(thing->subsector->sector,thing,sector_list);
|
|
|
|
|
|
|
|
// Now delete any nodes that won't be used. These are the ones where
|
|
|
|
// m_thing is still NULL.
|
|
|
|
|
|
|
|
node = sector_list;
|
|
|
|
while (node)
|
|
|
|
{
|
|
|
|
if (node->m_thing == NULL)
|
|
|
|
{
|
|
|
|
if (node == sector_list)
|
|
|
|
sector_list = node->m_tnext;
|
|
|
|
node = P_DelSecnode(node);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
node = node->m_tnext;
|
|
|
|
}
|
|
|
|
}
|