mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2024-11-22 04:21:23 +00:00
Merge branch 'blockmap-links' into 'next'
Make objects able to collide with others if they occupy multiple blockmap cells (resolves #592) Closes #592 See merge request STJr/SRB2!2267
This commit is contained in:
commit
41613d89a1
12 changed files with 595 additions and 297 deletions
|
@ -34,46 +34,28 @@ typedef UINT8 (*blockmap_func)(lua_State *, INT32, INT32, mobj_t *);
|
|||
static boolean blockfuncerror = false; // errors should only print once per search blockmap call
|
||||
|
||||
// Helper function for "objects" search
|
||||
static UINT8 lib_searchBlockmap_Objects(lua_State *L, INT32 x, INT32 y, mobj_t *thing)
|
||||
static UINT8 lib_searchBlockmap_Objects(lua_State *L, mobj_t *thing, mobj_t *mobj)
|
||||
{
|
||||
mobj_t *mobj, *bnext = NULL;
|
||||
|
||||
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
|
||||
return 0;
|
||||
|
||||
// Check interaction with the objects in the blockmap.
|
||||
for (mobj = blocklinks[y*bmapwidth + x]; mobj; mobj = bnext)
|
||||
{
|
||||
P_SetTarget(&bnext, mobj->bnext); // We want to note our reference to bnext here incase it is MF_NOTHINK and gets removed!
|
||||
if (mobj == thing)
|
||||
continue; // our thing just found itself, so move on
|
||||
lua_pushvalue(L, 1); // push function
|
||||
LUA_PushUserdata(L, thing, META_MOBJ);
|
||||
LUA_PushUserdata(L, mobj, META_MOBJ);
|
||||
if (lua_pcall(gL, 2, 1, 0)) {
|
||||
if (!blockfuncerror || cv_debug & DBG_LUA)
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
blockfuncerror = true;
|
||||
P_SetTarget(&bnext, NULL);
|
||||
return 0; // *shrugs*
|
||||
}
|
||||
if (!lua_isnil(gL, -1))
|
||||
{ // if nil, continue
|
||||
P_SetTarget(&bnext, NULL);
|
||||
if (lua_toboolean(gL, -1))
|
||||
return 2; // stop whole search
|
||||
else
|
||||
return 1; // stop block search
|
||||
}
|
||||
lua_pushvalue(L, 1); // push function
|
||||
LUA_PushUserdata(L, thing, META_MOBJ);
|
||||
LUA_PushUserdata(L, mobj, META_MOBJ);
|
||||
if (lua_pcall(gL, 2, 1, 0)) {
|
||||
if (!blockfuncerror || cv_debug & DBG_LUA)
|
||||
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
|
||||
lua_pop(gL, 1);
|
||||
if (P_MobjWasRemoved(thing) // func just popped our thing, cannot continue.
|
||||
|| (bnext && P_MobjWasRemoved(bnext))) // func just broke blockmap chain, cannot continue.
|
||||
{
|
||||
P_SetTarget(&bnext, NULL);
|
||||
return (P_MobjWasRemoved(thing)) ? 2 : 1;
|
||||
}
|
||||
blockfuncerror = true;
|
||||
return 0; // *shrugs*
|
||||
}
|
||||
if (!lua_isnil(gL, -1))
|
||||
{ // if nil, continue
|
||||
if (lua_toboolean(gL, -1))
|
||||
return 2; // stop whole search
|
||||
else
|
||||
return 1; // stop block search
|
||||
}
|
||||
lua_pop(gL, 1);
|
||||
if (P_MobjWasRemoved(thing)) // func just popped our thing, cannot continue.
|
||||
return P_MobjWasRemoved(thing) ? 2 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -233,6 +215,7 @@ static int lib_searchBlockmap(lua_State *L)
|
|||
boolean retval = true;
|
||||
UINT8 funcret = 0;
|
||||
blockmap_func searchFunc;
|
||||
boolean searchObjects = false;
|
||||
|
||||
lua_remove(L, 1); // remove searchtype, stack is now function, mobj, [x1, x2, y1, y2]
|
||||
luaL_checktype(L, 1, LUA_TFUNCTION);
|
||||
|
@ -241,7 +224,8 @@ static int lib_searchBlockmap(lua_State *L)
|
|||
{
|
||||
case 0: // "objects"
|
||||
default:
|
||||
searchFunc = lib_searchBlockmap_Objects;
|
||||
searchObjects = true;
|
||||
searchFunc = NULL;
|
||||
break;
|
||||
case 1: // "lines"
|
||||
searchFunc = lib_searchBlockmap_Lines;
|
||||
|
@ -286,24 +270,66 @@ static int lib_searchBlockmap(lua_State *L)
|
|||
BMBOUNDFIX(xl, xh, yl, yh);
|
||||
|
||||
blockfuncerror = false; // reset
|
||||
validcount++;
|
||||
for (bx = xl; bx <= xh; bx++)
|
||||
for (by = yl; by <= yh; by++)
|
||||
{
|
||||
funcret = searchFunc(L, bx, by, mobj);
|
||||
// return value of searchFunc determines searchFunc's return value and/or when to stop
|
||||
if (funcret == 2){ // stop whole search
|
||||
lua_pushboolean(L, false); // return false
|
||||
return 1;
|
||||
|
||||
if (!searchObjects) {
|
||||
validcount++;
|
||||
|
||||
for (bx = xl; bx <= xh; bx++)
|
||||
for (by = yl; by <= yh; by++)
|
||||
{
|
||||
funcret = searchFunc(L, bx, by, mobj);
|
||||
|
||||
// return value of searchFunc determines searchFunc's return value and/or when to stop
|
||||
if (funcret == 2) { // stop whole search
|
||||
lua_pushboolean(L, false); // return false
|
||||
return 1;
|
||||
}
|
||||
else if (funcret == 1) // search was interrupted for this block
|
||||
retval = false; // this changes the return value, but doesn't stop the whole search
|
||||
|
||||
// else don't do anything, continue as normal
|
||||
if (P_MobjWasRemoved(mobj)) { // ...unless the original object was removed
|
||||
lua_pushboolean(L, false); // in which case we have to stop now regardless
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (funcret == 1) // search was interrupted for this block
|
||||
retval = false; // this changes the return value, but doesn't stop the whole search
|
||||
// else don't do anything, continue as normal
|
||||
if (P_MobjWasRemoved(mobj)){ // ...unless the original object was removed
|
||||
lua_pushboolean(L, false); // in which case we have to stop now regardless
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
bthingit_t *it = P_NewBlockThingsIterator(xl, yl, xh, yh);
|
||||
if (!it) {
|
||||
lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
mobj_t *itmobj = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
itmobj = P_BlockThingsIteratorNext(it, false);
|
||||
if (itmobj)
|
||||
{
|
||||
if (mobj == itmobj)
|
||||
continue; // our thing just found itself, so move on
|
||||
|
||||
funcret = lib_searchBlockmap_Objects(L, mobj, itmobj);
|
||||
if (funcret == 2) {
|
||||
lua_pushboolean(L, false);
|
||||
return 1;
|
||||
}
|
||||
else if (funcret == 1)
|
||||
retval = false;
|
||||
|
||||
if (P_MobjWasRemoved(mobj)) {
|
||||
retval = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (itmobj != NULL);
|
||||
|
||||
P_FreeBlockThingsIterator(it);
|
||||
}
|
||||
|
||||
lua_pushboolean(L, retval);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -355,8 +355,12 @@ static int mobj_get(lua_State *L)
|
|||
lua_pushinteger(L, mo->blendmode);
|
||||
break;
|
||||
case mobj_bnext:
|
||||
LUA_PushUserdata(L, mo->bnext, META_MOBJ);
|
||||
break;
|
||||
if (mo->blocknode && mo->blocknode->bnext) {
|
||||
LUA_PushUserdata(L, mo->blocknode->bnext->mobj, META_MOBJ);
|
||||
break;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
case mobj_bprev:
|
||||
// bprev -- same deal as sprev above, but for the blockmap.
|
||||
return UNIMPLEMENTED;
|
||||
|
@ -669,7 +673,6 @@ static int mobj_set(lua_State *L)
|
|||
sector_list = NULL;
|
||||
}
|
||||
mo->snext = NULL, mo->sprev = NULL;
|
||||
mo->bnext = NULL, mo->bprev = NULL;
|
||||
P_SetThingPosition(mo);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -5821,15 +5821,12 @@ void A_MinusDigging(mobj_t *actor)
|
|||
fixed_t yl = (unsigned)(actor->y - radius - bmaporgy) >> MAPBLOCKSHIFT;
|
||||
fixed_t xh = (unsigned)(actor->x + radius - bmaporgx) >> MAPBLOCKSHIFT;
|
||||
fixed_t xl = (unsigned)(actor->x - radius - bmaporgx) >> MAPBLOCKSHIFT;
|
||||
fixed_t bx, by;
|
||||
|
||||
BMBOUNDFIX(xl, xh, yl, yh);
|
||||
|
||||
minus = actor;
|
||||
|
||||
for (bx = xl; bx <= xh; bx++)
|
||||
for (by = yl; by <= yh; by++)
|
||||
P_BlockThingsIterator(bx, by, PIT_MinusCarry);
|
||||
P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_MinusCarry);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -13889,7 +13886,7 @@ void A_DustDevilThink(mobj_t *actor)
|
|||
{
|
||||
fixed_t scale = actor->scale;
|
||||
mobj_t *layer = actor->tracer;
|
||||
INT32 bx, by, xl, xh, yl, yh;
|
||||
INT32 xl, xh, yl, yh;
|
||||
fixed_t radius = actor->radius;
|
||||
|
||||
if (LUA_CallAction(A_DUSTDEVILTHINK, actor))
|
||||
|
@ -13953,9 +13950,7 @@ void A_DustDevilThink(mobj_t *actor)
|
|||
|
||||
dustdevil = actor;
|
||||
|
||||
for (bx = xl; bx <= xh; bx++)
|
||||
for (by = yl; by <= yh; by++)
|
||||
P_BlockThingsIterator(bx, by, PIT_DustDevilLaunch);
|
||||
P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_DustDevilLaunch);
|
||||
|
||||
//Whirlwind sound effect.
|
||||
if (leveltime % 70 == 0)
|
||||
|
@ -14035,7 +14030,6 @@ static boolean PIT_TNTExplode(mobj_t *nearby)
|
|||
void A_TNTExplode(mobj_t *actor)
|
||||
{
|
||||
INT32 locvar1 = var1;
|
||||
INT32 x, y;
|
||||
INT32 xl, xh, yl, yh;
|
||||
static mappoint_t epicenter = {0,0,0};
|
||||
|
||||
|
@ -14072,9 +14066,7 @@ void A_TNTExplode(mobj_t *actor)
|
|||
|
||||
barrel = actor;
|
||||
|
||||
for (x = xl; x <= xh; x++)
|
||||
for (y = yl; y <= yh; y++)
|
||||
P_BlockThingsIterator(x, y, PIT_TNTExplode);
|
||||
P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_TNTExplode);
|
||||
|
||||
// cause a quake -- P_StartQuake does not exist yet
|
||||
epicenter.x = actor->x;
|
||||
|
|
|
@ -462,7 +462,7 @@ extern INT32 bmapwidth;
|
|||
extern INT32 bmapheight; // in mapblocks
|
||||
extern fixed_t bmaporgx;
|
||||
extern fixed_t bmaporgy; // origin of block map
|
||||
extern mobj_t **blocklinks; // for thing chains
|
||||
extern blocknode_t **blocklinks; // for thing chains
|
||||
|
||||
//
|
||||
// P_INTER
|
||||
|
|
324
src/p_map.c
324
src/p_map.c
|
@ -752,20 +752,25 @@ static void P_PlayerBarrelCollide(mobj_t *toucher, mobj_t *barrel)
|
|||
P_DamageMobj(barrel, toucher, toucher, 1, 0);
|
||||
}
|
||||
|
||||
//
|
||||
// PIT_CheckThing
|
||||
//
|
||||
static boolean PIT_CheckThing(mobj_t *thing)
|
||||
enum
|
||||
{
|
||||
CHECKTHING_NOCOLLIDE,
|
||||
CHECKTHING_COLLIDE,
|
||||
CHECKTHING_DONE,
|
||||
CHECKTHING_IGNORE
|
||||
};
|
||||
|
||||
static unsigned PIT_DoCheckThing(mobj_t *thing)
|
||||
{
|
||||
fixed_t blockdist;
|
||||
|
||||
// don't clip against self
|
||||
if (thing == tmthing)
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
|
||||
// Ignore... things.
|
||||
if (!tmthing || !thing || P_MobjWasRemoved(thing))
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
|
||||
I_Assert(!P_MobjWasRemoved(tmthing));
|
||||
I_Assert(!P_MobjWasRemoved(thing));
|
||||
|
@ -773,7 +778,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
// Ignore spectators
|
||||
if ((tmthing->player && tmthing->player->spectator)
|
||||
|| (thing->player && thing->player->spectator))
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
|
||||
// Do name checks all the way up here
|
||||
// So that NOTHING ELSE can see MT_NAMECHECK because it is client-side.
|
||||
|
@ -781,24 +786,24 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
{
|
||||
// Ignore things that aren't players, ignore spectators, ignore yourself.
|
||||
if (!thing->player || !(tmthing->target && tmthing->target->player) || thing->player->spectator || (tmthing->target && thing->player == tmthing->target->player))
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
|
||||
// Now check that you actually hit them.
|
||||
blockdist = thing->radius + tmthing->radius;
|
||||
if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
|
||||
return true; // didn't hit it
|
||||
return CHECKTHING_NOCOLLIDE; // didn't hit it
|
||||
// see if it went over / under
|
||||
if (tmthing->z > thing->z + thing->height)
|
||||
return true; // overhead
|
||||
return CHECKTHING_NOCOLLIDE; // overhead
|
||||
if (tmthing->z + tmthing->height < thing->z)
|
||||
return true; // underneath
|
||||
return CHECKTHING_NOCOLLIDE; // underneath
|
||||
|
||||
// REX HAS SEEN YOU
|
||||
// Call any SeenPlayer Lua hooks
|
||||
if (!LUA_HookSeenPlayer(tmthing->target->player, thing->player))
|
||||
return false;
|
||||
return CHECKTHING_DONE;
|
||||
|
||||
seenplayer = thing->player;
|
||||
return false;
|
||||
return CHECKTHING_DONE;
|
||||
}
|
||||
|
||||
// Metal Sonic destroys tiny baby objects.
|
||||
|
@ -808,15 +813,15 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
|| thing->type == MT_WALLSPIKE)))
|
||||
{
|
||||
if ((thing->flags & (MF_ENEMY|MF_BOSS)) && (thing->health <= 0 || !(thing->flags & MF_SHOOTABLE)))
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
blockdist = thing->radius + tmthing->radius;
|
||||
if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
|
||||
return true; // didn't hit it
|
||||
return CHECKTHING_NOCOLLIDE; // didn't hit it
|
||||
// see if it went over / under
|
||||
if (tmthing->z > thing->z + thing->height)
|
||||
return true; // overhead
|
||||
return CHECKTHING_NOCOLLIDE; // overhead
|
||||
if (tmthing->z + tmthing->height < thing->z)
|
||||
return true; // underneath
|
||||
return CHECKTHING_NOCOLLIDE; // underneath
|
||||
if (thing->type == MT_SPIKE
|
||||
|| thing->type == MT_WALLSPIKE)
|
||||
{
|
||||
|
@ -832,28 +837,28 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
thing->health = 0;
|
||||
P_KillMobj(thing, tmthing, tmthing, 0);
|
||||
}
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
|
||||
// STR_SPIKE users destroy spikes
|
||||
if ((tmthing->player) && ((tmthing->player->powers[pw_strong] & STR_SPIKE) && (thing->type == MT_SPIKE || thing->type == MT_WALLSPIKE)))
|
||||
{
|
||||
mobj_t *iter;
|
||||
blockdist = thing->radius + tmthing->radius;
|
||||
if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
|
||||
return true; // didn't hit it
|
||||
// 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
|
||||
blockdist = thing->radius + tmthing->radius;
|
||||
if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
|
||||
return CHECKTHING_NOCOLLIDE; // didn't hit it
|
||||
// see if it went over / under
|
||||
if (tmthing->z > thing->z + thing->height)
|
||||
return CHECKTHING_NOCOLLIDE; // overhead
|
||||
if (tmthing->z + tmthing->height < thing->z)
|
||||
return CHECKTHING_NOCOLLIDE; // underneath
|
||||
|
||||
if (thing->flags & MF_SOLID)
|
||||
S_StartSound(tmthing, thing->info->deathsound);
|
||||
for (iter = thing->subsector->sector->thinglist; iter; iter = iter->snext)
|
||||
if (iter->type == thing->type && iter->health > 0 && iter->flags & MF_SOLID && (iter == thing || P_AproxDistance(P_AproxDistance(thing->x - iter->x, thing->y - iter->y), thing->z - iter->z) < 56*thing->scale))//FixedMul(56*FRACUNIT, thing->scale))
|
||||
P_KillMobj(iter, tmthing, tmthing, 0);
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
|
||||
// vectorise metal - done in a special case as at this point neither has the right flags for touching
|
||||
|
@ -865,30 +870,30 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
blockdist = thing->radius + tmthing->radius;
|
||||
|
||||
if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
|
||||
return true; // didn't hit it
|
||||
return CHECKTHING_NOCOLLIDE; // didn't hit it
|
||||
|
||||
if (tmthing->z > thing->z + thing->height)
|
||||
return true; // overhead
|
||||
return CHECKTHING_NOCOLLIDE; // overhead
|
||||
if (tmthing->z + tmthing->height < thing->z)
|
||||
return true; // underneath
|
||||
return CHECKTHING_NOCOLLIDE; // underneath
|
||||
|
||||
thing->flags2 |= MF2_CLASSICPUSH;
|
||||
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
|
||||
if ((thing->flags & MF_NOCLIPTHING) || !(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING)))
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
|
||||
// Don't collide with your buddies while NiGHTS-flying.
|
||||
if (tmthing->player && thing->player && (maptol & TOL_NIGHTS)
|
||||
&& ((tmthing->player->powers[pw_carry] == CR_NIGHTSMODE) || (thing->player->powers[pw_carry] == CR_NIGHTSMODE)))
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
|
||||
blockdist = thing->radius + tmthing->radius;
|
||||
|
||||
if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
|
||||
return true; // didn't hit it
|
||||
return CHECKTHING_NOCOLLIDE; // didn't hit it
|
||||
|
||||
if (thing->flags & MF_PAPERCOLLISION) // CAUTION! Very easy to get stuck inside MF_SOLID objects. Giving the player MF_PAPERCOLLISION is a bad idea unless you know what you're doing.
|
||||
{
|
||||
|
@ -915,23 +920,23 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
fixed_t tmcosradius = FixedMul(tmthing->radius, FINECOSINE(tmthing->angle>>ANGLETOFINESHIFT));
|
||||
fixed_t tmsinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT));
|
||||
if (abs(thing->x - tmx) >= (abs(tmcosradius) + abs(cosradius)) || abs(thing->y - tmy) >= (abs(tmsinradius) + abs(sinradius)))
|
||||
return true; // didn't hit it
|
||||
return CHECKTHING_NOCOLLIDE; // didn't hit it
|
||||
check1 = P_PointOnLineSide(tmx - tmcosradius, tmy - tmsinradius, &junk);
|
||||
check2 = P_PointOnLineSide(tmx + tmcosradius, tmy + tmsinradius, &junk);
|
||||
check3 = P_PointOnLineSide(tmx + tmthing->momx - tmcosradius, tmy + tmthing->momy - tmsinradius, &junk);
|
||||
check4 = P_PointOnLineSide(tmx + tmthing->momx + tmcosradius, tmy + tmthing->momy + tmsinradius, &junk);
|
||||
if ((check1 == check2) && (check2 == check3) && (check3 == check4))
|
||||
return true; // the line doesn't cross between collider's start or end
|
||||
return CHECKTHING_NOCOLLIDE; // the line doesn't cross between collider's start or end
|
||||
}
|
||||
else
|
||||
{
|
||||
if (abs(thing->x - tmx) >= (tmthing->radius + abs(cosradius)) || abs(thing->y - tmy) >= (tmthing->radius + abs(sinradius)))
|
||||
return true; // didn't hit it
|
||||
return CHECKTHING_NOCOLLIDE; // didn't hit it
|
||||
if ((P_PointOnLineSide(tmx - tmthing->radius, tmy - tmthing->radius, &junk)
|
||||
== P_PointOnLineSide(tmx + tmthing->radius, tmy + tmthing->radius, &junk))
|
||||
&& (P_PointOnLineSide(tmx + tmthing->radius, tmy - tmthing->radius, &junk)
|
||||
== P_PointOnLineSide(tmx - tmthing->radius, tmy + tmthing->radius, &junk)))
|
||||
return true; // the line doesn't cross between either pair of opposite corners
|
||||
return CHECKTHING_NOCOLLIDE; // the line doesn't cross between either pair of opposite corners
|
||||
}
|
||||
}
|
||||
else if (tmthing->flags & MF_PAPERCOLLISION)
|
||||
|
@ -944,7 +949,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
tmsinradius = FixedMul(tmthing->radius, FINESINE(tmthing->angle>>ANGLETOFINESHIFT));
|
||||
|
||||
if (abs(thing->x - tmx) >= (thing->radius + abs(tmcosradius)) || abs(thing->y - tmy) >= (thing->radius + abs(tmsinradius)))
|
||||
return true; // didn't hit it
|
||||
return CHECKTHING_NOCOLLIDE; // didn't hit it
|
||||
|
||||
v1.x = tmx - tmcosradius;
|
||||
v1.y = tmy - tmsinradius;
|
||||
|
@ -961,32 +966,32 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
== P_PointOnLineSide(thing->x + thing->radius, thing->y + thing->radius, &junk))
|
||||
&& (P_PointOnLineSide(thing->x + thing->radius, thing->y - thing->radius, &junk)
|
||||
== P_PointOnLineSide(thing->x - thing->radius, thing->y + thing->radius, &junk)))
|
||||
return true; // the line doesn't cross between either pair of opposite corners
|
||||
return CHECKTHING_NOCOLLIDE; // the line doesn't cross between either pair of opposite corners
|
||||
}
|
||||
|
||||
{
|
||||
UINT8 shouldCollide = LUA_Hook2Mobj(thing, tmthing, MOBJ_HOOK(MobjCollide)); // checks hook for thing's type
|
||||
if (P_MobjWasRemoved(tmthing) || P_MobjWasRemoved(thing))
|
||||
return true; // one of them was removed???
|
||||
return CHECKTHING_NOCOLLIDE; // one of them was removed???
|
||||
if (shouldCollide == 1)
|
||||
return false; // force collide
|
||||
return CHECKTHING_DONE; // force collide
|
||||
else if (shouldCollide == 2)
|
||||
return true; // force no collide
|
||||
return CHECKTHING_NOCOLLIDE; // force no collide
|
||||
|
||||
shouldCollide = LUA_Hook2Mobj(tmthing, thing, MOBJ_HOOK(MobjMoveCollide)); // checks hook for tmthing's type
|
||||
if (P_MobjWasRemoved(tmthing) || P_MobjWasRemoved(thing))
|
||||
return true; // one of them was removed???
|
||||
return CHECKTHING_NOCOLLIDE; // one of them was removed???
|
||||
if (shouldCollide == 1)
|
||||
return false; // force collide
|
||||
return CHECKTHING_DONE; // force collide
|
||||
else if (shouldCollide == 2)
|
||||
return true; // force no collide
|
||||
return CHECKTHING_NOCOLLIDE; // force no collide
|
||||
}
|
||||
|
||||
if (tmthing->type == MT_LAVAFALL_LAVA && (thing->type == MT_RING || thing->type == MT_REDTEAMRING || thing->type == MT_BLUETEAMRING || thing->type == MT_FLINGRING))
|
||||
{
|
||||
//height check
|
||||
if (tmthing->z > thing->z + thing->height || thing->z > tmthing->z + tmthing->height || !(thing->health))
|
||||
return true;
|
||||
return CHECKTHING_NOCOLLIDE;
|
||||
|
||||
P_KillMobj(thing, tmthing, tmthing, DMG_FIRE);
|
||||
}
|
||||
|
@ -995,7 +1000,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
{
|
||||
//height check
|
||||
if (tmthing->z > thing->z + thing->height || thing->z > tmthing->z + tmthing->height || !(thing->health))
|
||||
return true;
|
||||
return CHECKTHING_NOCOLLIDE;
|
||||
|
||||
if (thing->type == MT_TNTBARREL)
|
||||
P_KillMobj(thing, tmthing, tmthing->target, 0);
|
||||
|
@ -1018,7 +1023,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
fixed_t s = FINESINE((ang >> ANGLETOFINESHIFT) & FINEMASK);
|
||||
S_StartSound(tmthing, thing->info->activesound);
|
||||
thing->extravalue2 += 2*FixedMul(s, dm)/3;
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1026,14 +1031,14 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
{
|
||||
if (((thing->flags2 & MF2_AMBUSH) && (tmthing->z <= thing->z + thing->height) && (tmthing->z + tmthing->height >= thing->z))
|
||||
|| (tmthing->player->powers[pw_carry] == CR_MINECART && tmthing->tracer && !P_MobjWasRemoved(tmthing->tracer)))
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
|
||||
if (thing->type == MT_ROLLOUTROCK && tmthing->player && tmthing->health)
|
||||
{
|
||||
if (tmthing->player->powers[pw_carry] == CR_ROLLOUT)
|
||||
{
|
||||
return true;
|
||||
return CHECKTHING_NOCOLLIDE;
|
||||
}
|
||||
if ((thing->flags & MF_PUSHABLE) // not carrying a player
|
||||
&& (tmthing->player->powers[pw_carry] == CR_NONE) // player is not already riding something
|
||||
|
@ -1052,26 +1057,26 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
P_SetTarget(&tmthing->tracer, thing);
|
||||
if (!P_IsObjectOnGround(thing))
|
||||
thing->momz += tmthing->momz;
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
}
|
||||
else if (tmthing->type == MT_ROLLOUTROCK)
|
||||
{
|
||||
if (tmthing->z > thing->z + thing->height || thing->z > tmthing->z + tmthing->height || !thing->health)
|
||||
return true;
|
||||
return CHECKTHING_NOCOLLIDE;
|
||||
|
||||
if (thing == tmthing->tracer) // don't collide with rider
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
|
||||
if (thing->flags & MF_SPRING) // bounce on springs
|
||||
{
|
||||
P_DoSpring(thing, tmthing);
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
else if ((thing->flags & (MF_MONITOR|MF_SHOOTABLE)) == (MF_MONITOR|MF_SHOOTABLE) && !(tmthing->flags & MF_PUSHABLE)) // pop monitors while carrying a player
|
||||
{
|
||||
P_KillMobj(thing, tmthing, tmthing->tracer, 0);
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
|
||||
if (thing->type == tmthing->type // bounce against other rollout rocks
|
||||
|
@ -1106,11 +1111,11 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
if (tmthing->type == MT_FANG && thing->type == MT_FSGNB)
|
||||
{
|
||||
if (thing->z > tmthing->z + tmthing->height)
|
||||
return true; // overhead
|
||||
return CHECKTHING_NOCOLLIDE; // overhead
|
||||
if (thing->z + thing->height < tmthing->z)
|
||||
return true; // underneath
|
||||
return CHECKTHING_NOCOLLIDE; // underneath
|
||||
if (!thing->tracer || !thing->tracer->tracer)
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
P_SlapStick(tmthing, thing);
|
||||
// no return value was used in the original prototype script at this point,
|
||||
// so I'm assuming we fall back on the solid code to determine how it all ends?
|
||||
|
@ -1123,13 +1128,13 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
if (tmthing->type == MT_BIGMINE)
|
||||
{
|
||||
if (!tmthing->momx && !tmthing->momy)
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
if ((statenum_t)(thing->state-states) >= thing->info->meleestate)
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
if (thing->z > tmthing->z + tmthing->height)
|
||||
return true; // overhead
|
||||
return CHECKTHING_NOCOLLIDE; // overhead
|
||||
if (thing->z + thing->height < tmthing->z)
|
||||
return true; // underneath
|
||||
return CHECKTHING_NOCOLLIDE; // underneath
|
||||
|
||||
thing->momx = tmthing->momx/3;
|
||||
thing->momy = tmthing->momy/3;
|
||||
|
@ -1141,18 +1146,18 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
S_StartSound(thing, thing->info->activesound);
|
||||
P_SetMobjState(thing, thing->info->meleestate);
|
||||
P_SetTarget(&thing->tracer, tmthing->tracer);
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
else if (tmthing->type == MT_CRUSHCLAW)
|
||||
{
|
||||
if (tmthing->extravalue1 <= 0)
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
if ((statenum_t)(thing->state-states) >= thing->info->meleestate)
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
if (thing->z > tmthing->z + tmthing->height)
|
||||
return true; // overhead
|
||||
return CHECKTHING_NOCOLLIDE; // overhead
|
||||
if (thing->z + thing->height < tmthing->z)
|
||||
return true; // underneath
|
||||
return CHECKTHING_NOCOLLIDE; // underneath
|
||||
|
||||
thing->momx = P_ReturnThrustX(tmthing, tmthing->angle, 2*tmthing->extravalue1*tmthing->scale/3);
|
||||
thing->momy = P_ReturnThrustY(tmthing, tmthing->angle, 2*tmthing->extravalue1*tmthing->scale/3);
|
||||
|
@ -1161,7 +1166,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
P_SetMobjState(thing, thing->info->meleestate);
|
||||
if (tmthing->tracer)
|
||||
P_SetTarget(&thing->tracer, tmthing->tracer->target);
|
||||
return false;
|
||||
return CHECKTHING_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1169,9 +1174,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
if (tmthing->type == MT_SPIKE && (thing->flags & MF_SOLID) && (tmthing->flags & MF_SOLID))
|
||||
{
|
||||
if (thing->z > tmthing->z + tmthing->height)
|
||||
return true; // overhead
|
||||
return CHECKTHING_NOCOLLIDE; // overhead
|
||||
if (thing->z + thing->height < tmthing->z)
|
||||
return true; // underneath
|
||||
return CHECKTHING_NOCOLLIDE; // underneath
|
||||
|
||||
if (tmthing->eflags & MFE_VERTICALFLIP)
|
||||
P_SetOrigin(thing, thing->x, thing->y, tmthing->z - thing->height - FixedMul(FRACUNIT, tmthing->scale));
|
||||
|
@ -1179,16 +1184,16 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
P_SetOrigin(thing, thing->x, thing->y, tmthing->z + tmthing->height + FixedMul(FRACUNIT, tmthing->scale));
|
||||
if (thing->flags & MF_SHOOTABLE)
|
||||
P_DamageMobj(thing, tmthing, tmthing, 1, DMG_SPIKE);
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
|
||||
if (thing->flags & MF_PAIN && tmthing->player)
|
||||
{ // Player touches painful thing sitting on the floor
|
||||
// see if it went over / under
|
||||
if (thing->z > tmthing->z + tmthing->height)
|
||||
return true; // overhead
|
||||
return CHECKTHING_NOCOLLIDE; // overhead
|
||||
if (thing->z + thing->height < tmthing->z)
|
||||
return true; // underneath
|
||||
return CHECKTHING_NOCOLLIDE; // underneath
|
||||
if (tmthing->flags & MF_SHOOTABLE && thing->health > 0)
|
||||
{
|
||||
UINT32 damagetype = (thing->info->mass & 0xFF);
|
||||
|
@ -1196,16 +1201,17 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
damagetype = DMG_FIRE;
|
||||
if (P_DamageMobj(tmthing, thing, thing, 1, damagetype) && (damagetype = (thing->info->mass>>8)))
|
||||
S_StartSound(thing, damagetype);
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
return true;
|
||||
return CHECKTHING_NOCOLLIDE;
|
||||
}
|
||||
else if (tmthing->flags & MF_PAIN && thing->player)
|
||||
{ // Painful thing splats player in the face
|
||||
// see if it went over / under
|
||||
if (tmthing->z > thing->z + thing->height)
|
||||
return true; // overhead
|
||||
return CHECKTHING_NOCOLLIDE; // overhead
|
||||
if (tmthing->z + tmthing->height < thing->z)
|
||||
return true; // underneath
|
||||
return CHECKTHING_NOCOLLIDE; // underneath
|
||||
if (thing->flags & MF_SHOOTABLE && tmthing->health > 0)
|
||||
{
|
||||
UINT32 damagetype = (tmthing->info->mass & 0xFF);
|
||||
|
@ -1213,32 +1219,33 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
damagetype = DMG_FIRE;
|
||||
if (P_DamageMobj(thing, tmthing, tmthing, 1, damagetype) && (damagetype = (tmthing->info->mass>>8)))
|
||||
S_StartSound(tmthing, damagetype);
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
return true;
|
||||
return CHECKTHING_NOCOLLIDE;
|
||||
}
|
||||
|
||||
if (thing->type == MT_HOOPCOLLIDE && thing->flags & MF_SPECIAL && tmthing->player)
|
||||
{
|
||||
P_TouchSpecialThing(thing, tmthing, true);
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
|
||||
// check for skulls slamming into things
|
||||
if (tmthing->flags2 & MF2_SKULLFLY)
|
||||
{
|
||||
if (tmthing->type == MT_EGGMOBILE) // Don't make Eggman stop!
|
||||
return true; // Let him RUN YOU RIGHT OVER. >:3
|
||||
return CHECKTHING_COLLIDE; // Let him RUN YOU RIGHT OVER. >:3
|
||||
else
|
||||
{
|
||||
// see if it went over / under
|
||||
if (tmthing->z > thing->z + thing->height)
|
||||
return true; // overhead
|
||||
return CHECKTHING_NOCOLLIDE; // overhead
|
||||
if (tmthing->z + tmthing->height < thing->z)
|
||||
return true; // underneath
|
||||
return CHECKTHING_NOCOLLIDE; // underneath
|
||||
|
||||
tmthing->flags2 &= ~MF2_SKULLFLY;
|
||||
tmthing->momx = tmthing->momy = tmthing->momz = 0;
|
||||
return false; // stop moving
|
||||
return CHECKTHING_DONE; // stop moving
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1254,10 +1261,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
if ((tmznext <= thzh && tmz > thzh) || (tmznext > thzh - sprarea && tmznext < thzh))
|
||||
{
|
||||
P_DoSpring(thing, tmthing);
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
else if (tmz > thzh - sprarea && tmz < thzh) // Don't damage people springing up / down
|
||||
return true;
|
||||
return CHECKTHING_NOCOLLIDE;
|
||||
}
|
||||
|
||||
// missiles can hit other things
|
||||
|
@ -1265,31 +1272,31 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
{
|
||||
// see if it went over / under
|
||||
if (tmthing->z > thing->z + thing->height)
|
||||
return true; // overhead
|
||||
return CHECKTHING_NOCOLLIDE; // overhead
|
||||
if (tmthing->z + tmthing->height < thing->z)
|
||||
return true; // underneath
|
||||
return CHECKTHING_NOCOLLIDE; // underneath
|
||||
|
||||
if (tmthing->type != MT_SHELL && tmthing->target && tmthing->target->type == thing->type)
|
||||
{
|
||||
// Don't hit same species as originator.
|
||||
if (thing == tmthing->target)
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
|
||||
if (thing->type != MT_PLAYER)
|
||||
{
|
||||
// Explode, but do no damage.
|
||||
// Let players missile other players.
|
||||
return false;
|
||||
return CHECKTHING_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
// Special case for bounce rings so they don't get caught behind solid objects.
|
||||
if ((tmthing->type == MT_THROWNBOUNCE && tmthing->fuse > 8*TICRATE) && thing->flags & MF_SOLID)
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
|
||||
// Missiles ignore Brak's helper.
|
||||
if (thing->type == MT_BLACKEGGMAN_HELPER)
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
|
||||
// Hurting Brak
|
||||
if (tmthing->type == MT_BLACKEGGMAN_MISSILE
|
||||
|
@ -1298,19 +1305,22 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
// Not if Brak's already in pain
|
||||
if (!(thing->state >= &states[S_BLACKEGG_PAIN1] && thing->state <= &states[S_BLACKEGG_PAIN35]))
|
||||
P_SetMobjState(thing, thing->info->painstate);
|
||||
return false;
|
||||
return CHECKTHING_DONE;
|
||||
}
|
||||
|
||||
if (!(thing->flags & MF_SHOOTABLE) && !(thing->type == MT_EGGSHIELD))
|
||||
{
|
||||
// didn't do any damage
|
||||
return !(thing->flags & MF_SOLID);
|
||||
if (thing->flags & MF_SOLID)
|
||||
return CHECKTHING_COLLIDE;
|
||||
else
|
||||
return CHECKTHING_NOCOLLIDE;
|
||||
}
|
||||
|
||||
if (tmthing->flags & MF_MISSILE && thing->player && tmthing->target && tmthing->target->player
|
||||
&& thing->player->ctfteam == tmthing->target->player->ctfteam
|
||||
&& thing->player->powers[pw_carry] == CR_PLAYER && thing->tracer == tmthing->target)
|
||||
return true; // Don't give rings to your carry player by accident.
|
||||
return CHECKTHING_IGNORE; // Don't give rings to your carry player by accident.
|
||||
|
||||
if (thing->type == MT_EGGSHIELD)
|
||||
{
|
||||
|
@ -1318,7 +1328,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
|
||||
if (angle < ANGLE_180) // hit shield from behind, shield is destroyed!
|
||||
P_KillMobj(thing, tmthing, tmthing, 0);
|
||||
return false;
|
||||
return CHECKTHING_DONE;
|
||||
}
|
||||
|
||||
// damage / explode
|
||||
|
@ -1344,7 +1354,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
if (!demoplayback || P_ControlStyle(thing->player) == CS_LMAOGALOG)
|
||||
P_SetPlayerAngle(thing->player, thing->angle);
|
||||
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
else if (tmthing->type == MT_BLACKEGGMAN_MISSILE && thing->player && ((thing->player->powers[pw_carry] == CR_GENERIC) || (thing->player->pflags & PF_JUMPED)))
|
||||
{
|
||||
|
@ -1371,11 +1381,10 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
P_KillMobj(tmthing, NULL, NULL, 0);
|
||||
|
||||
// don't traverse any more
|
||||
|
||||
if (tmthing->type == MT_SHELL)
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
else
|
||||
return false;
|
||||
return CHECKTHING_DONE;
|
||||
}
|
||||
|
||||
if (thing->flags & MF_PUSHABLE && (tmthing->player || tmthing->flags & MF_PUSHABLE)
|
||||
|
@ -1478,13 +1487,13 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
if (thing->flags & MF_SPECIAL && tmthing->player)
|
||||
{
|
||||
P_TouchSpecialThing(thing, tmthing, true); // can remove thing
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
// check again for special pickup
|
||||
if (tmthing->flags & MF_SPECIAL && thing->player)
|
||||
{
|
||||
P_TouchSpecialThing(tmthing, thing, true); // can remove thing
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
|
||||
// Sprite Spikes!
|
||||
|
@ -1544,7 +1553,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
if (playerangle > ANGLE_180)
|
||||
playerangle = InvAngle(playerangle);
|
||||
if (playerangle < ANGLE_90)
|
||||
return true; // Yes, this is intentionally outside the z-height check. No standing on spikes whilst moving away from them.
|
||||
return CHECKTHING_IGNORE; // Yes, this is intentionally outside the z-height check. No standing on spikes whilst moving away from them.
|
||||
}
|
||||
|
||||
bottomz = thing->z;
|
||||
|
@ -1578,15 +1587,15 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
if (thing->type == MT_FAN || thing->type == MT_STEAM)
|
||||
{
|
||||
P_DoFanAndGasJet(thing, tmthing);
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
else if (thing->flags & MF_SPRING)
|
||||
{
|
||||
if ( thing->z <= tmthing->z + tmthing->height
|
||||
&& tmthing->z <= thing->z + thing->height)
|
||||
if (P_DoSpring(thing, tmthing))
|
||||
return false;
|
||||
return true;
|
||||
return CHECKTHING_DONE;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1595,7 +1604,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
{
|
||||
if ((thing->z + thing->height >= tmthing->z)
|
||||
&& (tmthing->z + tmthing->height >= thing->z))
|
||||
return false;
|
||||
return CHECKTHING_DONE;
|
||||
}
|
||||
|
||||
// Damage other players when invincible
|
||||
|
@ -1630,7 +1639,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
if (tmthing->player && thing->player)
|
||||
{
|
||||
P_DoTailsCarry(thing->player, tmthing->player);
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
}
|
||||
else if (thing->player) {
|
||||
|
@ -1677,7 +1686,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
if (tmthing->player) // Is the moving/interacting object the player?
|
||||
{
|
||||
if (!tmthing->health)
|
||||
return true;
|
||||
return CHECKTHING_IGNORE;
|
||||
|
||||
if (thing->type == MT_FAN || thing->type == MT_STEAM)
|
||||
P_DoFanAndGasJet(thing, tmthing);
|
||||
|
@ -1686,14 +1695,16 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
if ( thing->z <= tmthing->z + tmthing->height
|
||||
&& tmthing->z <= thing->z + thing->height)
|
||||
if (P_DoSpring(thing, tmthing))
|
||||
return false;
|
||||
return true;
|
||||
return CHECKTHING_DONE;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
// Monitor?
|
||||
else if (thing->flags & MF_MONITOR
|
||||
&& !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != 2))
|
||||
&& (!(thing->flags & MF_SOLID) || P_PlayerCanDamage(tmthing->player, thing)))
|
||||
{
|
||||
unsigned collide = CHECKTHING_NOCOLLIDE;
|
||||
|
||||
if (thing->z - thing->scale <= tmthing->z + tmthing->height
|
||||
&& thing->z + thing->height + thing->scale >= tmthing->z)
|
||||
{
|
||||
|
@ -1725,21 +1736,25 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
*momz /= 2;
|
||||
*momz -= (*momz/(underwater ? 8 : 4)); // Cap the height!
|
||||
}
|
||||
collide = CHECKTHING_COLLIDE;
|
||||
}
|
||||
if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough.
|
||||
{
|
||||
if (player->pflags & PF_BOUNCING)
|
||||
P_DoAbilityBounce(player, false);
|
||||
return false;
|
||||
collide = CHECKTHING_DONE;
|
||||
}
|
||||
else
|
||||
*z -= *momz; // to ensure proper collision.
|
||||
}
|
||||
|
||||
return true;
|
||||
return collide;
|
||||
}
|
||||
}
|
||||
|
||||
// not solid not blocked
|
||||
unsigned collide = CHECKTHING_NOCOLLIDE;
|
||||
|
||||
if ((tmthing->flags & MF_SPRING || tmthing->type == MT_STEAM || tmthing->type == MT_SPIKE || tmthing->type == MT_WALLSPIKE) && (thing->player))
|
||||
; // springs, gas jets and springs should never be able to step up onto a player
|
||||
// z checking at last
|
||||
|
@ -1762,25 +1777,27 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
tmfloorrover = NULL;
|
||||
tmfloorslope = NULL;
|
||||
}
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
|
||||
topz = thing->z - thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
|
||||
|
||||
// block only when jumping not high enough,
|
||||
// (dont climb max. 24units while already in air)
|
||||
// since return false doesn't handle momentum properly,
|
||||
// since return CHECKTHING_DONE doesn't handle momentum properly,
|
||||
// we lie to P_TryMove() so it's always too high
|
||||
if (tmthing->player && tmthing->z + tmthing->height > topz
|
||||
&& tmthing->z + tmthing->height < tmthing->ceilingz)
|
||||
{
|
||||
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->info->flags & MF_MONITOR)) // Gold monitor hack...
|
||||
return false;
|
||||
return CHECKTHING_DONE;
|
||||
|
||||
tmfloorz = tmceilingz = topz; // block while in air
|
||||
tmceilingrover = NULL;
|
||||
tmceilingslope = NULL;
|
||||
tmfloorthing = thing; // needed for side collision
|
||||
|
||||
collide = CHECKTHING_COLLIDE;
|
||||
}
|
||||
else if (topz < tmceilingz && tmthing->z <= thing->z+thing->height)
|
||||
{
|
||||
|
@ -1788,6 +1805,8 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
tmceilingrover = NULL;
|
||||
tmceilingslope = NULL;
|
||||
tmfloorthing = thing; // thing we may stand on
|
||||
|
||||
collide = CHECKTHING_COLLIDE;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1803,25 +1822,27 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
tmceilingrover = NULL;
|
||||
tmceilingslope = NULL;
|
||||
}
|
||||
return true;
|
||||
return CHECKTHING_COLLIDE;
|
||||
}
|
||||
|
||||
topz = thing->z + thing->height + thing->scale; // FixedMul(FRACUNIT, thing->scale), but thing->scale == FRACUNIT in base scale anyways
|
||||
|
||||
// block only when jumping not high enough,
|
||||
// (dont climb max. 24units while already in air)
|
||||
// since return false doesn't handle momentum properly,
|
||||
// since return CHECKTHING_DONE doesn't handle momentum properly,
|
||||
// we lie to P_TryMove() so it's always too high
|
||||
if (tmthing->player && tmthing->z < topz
|
||||
&& tmthing->z > tmthing->floorz)
|
||||
{
|
||||
if (thing->flags & MF_GRENADEBOUNCE && (thing->flags & MF_MONITOR || thing->info->flags & MF_MONITOR)) // Gold monitor hack...
|
||||
return false;
|
||||
return CHECKTHING_DONE;
|
||||
|
||||
tmfloorz = tmceilingz = topz; // block while in air
|
||||
tmfloorrover = NULL;
|
||||
tmfloorslope = NULL;
|
||||
tmfloorthing = thing; // needed for side collision
|
||||
|
||||
collide = CHECKTHING_COLLIDE;
|
||||
}
|
||||
else if (topz > tmfloorz && tmthing->z+tmthing->height >= thing->z)
|
||||
{
|
||||
|
@ -1829,12 +1850,18 @@ static boolean PIT_CheckThing(mobj_t *thing)
|
|||
tmfloorrover = NULL;
|
||||
tmfloorslope = NULL;
|
||||
tmfloorthing = thing; // thing we may stand on
|
||||
|
||||
collide = CHECKTHING_COLLIDE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// not solid not blocked
|
||||
return true;
|
||||
return collide;
|
||||
}
|
||||
|
||||
static boolean PIT_CheckThing(mobj_t *thing)
|
||||
{
|
||||
return PIT_DoCheckThing(thing) != CHECKTHING_DONE;
|
||||
}
|
||||
|
||||
// PIT_CheckCameraLine
|
||||
|
@ -2010,38 +2037,6 @@ static boolean PIT_CheckLine(line_t *ld)
|
|||
// =========================================================================
|
||||
// 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
|
||||
// tmfloorz
|
||||
// tmceilingz
|
||||
// tmdropoffz
|
||||
// tmdrpoffceilz
|
||||
// the lowest point contacted
|
||||
// (monsters won't move to a dropoff)
|
||||
// speciallines[]
|
||||
// numspeciallines
|
||||
//
|
||||
|
||||
// tmfloorz
|
||||
// the nearest floor or thing's top under tmthing
|
||||
// tmceilingz
|
||||
// the nearest ceiling or thing's bottom over tmthing
|
||||
//
|
||||
boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
|
||||
{
|
||||
INT32 xl, xh, yl, yh, bx, by;
|
||||
|
@ -2282,9 +2277,7 @@ boolean P_CheckPosition(mobj_t *thing, fixed_t x, fixed_t y)
|
|||
if (tmflags & MF_NOCLIP)
|
||||
return true;
|
||||
|
||||
// Check things first, possibly picking things up.
|
||||
|
||||
// MF_NOCLIPTHING: used by camera to not be blocked by things
|
||||
// Check things first.
|
||||
if (!(thing->flags & MF_NOCLIPTHING))
|
||||
{
|
||||
for (bx = xl; bx <= xh; bx++)
|
||||
|
@ -2893,7 +2886,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
|||
// standing on top and move it, too.
|
||||
if (thing->flags & MF_PUSHABLE)
|
||||
{
|
||||
INT32 bx, by, xl, xh, yl, yh;
|
||||
INT32 xl, xh, yl, yh;
|
||||
|
||||
yh = (unsigned)(thing->y + MAXRADIUS - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
yl = (unsigned)(thing->y - MAXRADIUS - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
|
@ -2906,9 +2899,7 @@ boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff)
|
|||
standx = x;
|
||||
standy = y;
|
||||
|
||||
for (by = yl; by <= yh; by++)
|
||||
for (bx = xl; bx <= xh; bx++)
|
||||
P_BlockThingsIterator(bx, by, PIT_PushableMoved);
|
||||
P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_PushableMoved);
|
||||
}
|
||||
|
||||
// Link the thing into its new position
|
||||
|
@ -4217,7 +4208,6 @@ static boolean PIT_RadiusAttack(mobj_t *thing)
|
|||
//
|
||||
void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 damagetype, boolean sightcheck)
|
||||
{
|
||||
INT32 x, y;
|
||||
INT32 xl, xh, yl, yh;
|
||||
fixed_t dist;
|
||||
|
||||
|
@ -4235,9 +4225,7 @@ void P_RadiusAttack(mobj_t *spot, mobj_t *source, fixed_t damagedist, UINT8 dama
|
|||
bombdamagetype = damagetype;
|
||||
bombsightcheck = sightcheck;
|
||||
|
||||
for (y = yl; y <= yh; y++)
|
||||
for (x = xl; x <= xh; x++)
|
||||
P_BlockThingsIterator(x, y, PIT_RadiusAttack);
|
||||
P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_RadiusAttack);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -4392,16 +4380,18 @@ static boolean P_CheckSectorPolyObjects(sector_t *sector, boolean realcrush, boo
|
|||
for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x)
|
||||
{
|
||||
mobj_t *mo;
|
||||
blocknode_t *block;
|
||||
|
||||
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
|
||||
continue;
|
||||
|
||||
mo = blocklinks[y * bmapwidth + x];
|
||||
block = blocklinks[y * bmapwidth + x];
|
||||
|
||||
for (; mo; mo = mo->bnext)
|
||||
for (; block; block = block->mnext)
|
||||
{
|
||||
// Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect
|
||||
mo = block->mobj;
|
||||
|
||||
// Monster Iestyn: do we need to check if a mobj has already been checked? ...probably not I suspect
|
||||
if (!P_MobjInsidePolyobj(po, mo))
|
||||
continue;
|
||||
|
||||
|
|
318
src/p_maputl.c
318
src/p_maputl.c
|
@ -680,6 +680,35 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
|
|||
openrange = opentop - openbottom;
|
||||
}
|
||||
|
||||
static blocknode_t *freeblocks;
|
||||
|
||||
static blocknode_t *P_CreateBlockNode(mobj_t *thing, int x, int y)
|
||||
{
|
||||
blocknode_t *block;
|
||||
|
||||
if (freeblocks != NULL)
|
||||
{
|
||||
block = freeblocks;
|
||||
freeblocks = block->bnext;
|
||||
}
|
||||
else
|
||||
block = Z_Malloc(sizeof(blocknode_t), PU_LEVEL, NULL);
|
||||
|
||||
block->blockindex = x + y*bmapwidth;
|
||||
block->mobj = thing;
|
||||
block->mnext = NULL;
|
||||
block->mprev = NULL;
|
||||
block->bprev = NULL;
|
||||
block->bnext = NULL;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
static void P_ReleaseBlockNode(blocknode_t *node)
|
||||
{
|
||||
node->bnext = freeblocks;
|
||||
freeblocks = node;
|
||||
}
|
||||
|
||||
//
|
||||
// THING POSITION SETTING
|
||||
|
@ -730,20 +759,20 @@ void P_UnsetThingPosition(mobj_t *thing)
|
|||
|
||||
if (!(thing->flags & MF_NOBLOCKMAP))
|
||||
{
|
||||
/* inert things don't need to be in blockmap
|
||||
*
|
||||
* killough 8/11/98: simpler scheme using pointers-to-pointers for prev
|
||||
* pointers, allows head node pointers to be treated like everything else
|
||||
*
|
||||
* Also more robust, since it doesn't depend on current position for
|
||||
* unlinking. Old method required computing head node based on position
|
||||
* at time of unlinking, assuming it was the same position as during
|
||||
* linking.
|
||||
*/
|
||||
// [RH] Unlink from all blocks this actor uses
|
||||
blocknode_t *block = thing->blocknode;
|
||||
|
||||
mobj_t *bnext, **bprev = thing->bprev;
|
||||
if (bprev && (*bprev = bnext = thing->bnext) != NULL) // unlink from block map
|
||||
bnext->bprev = bprev;
|
||||
while (block != NULL)
|
||||
{
|
||||
if (block->mnext != NULL)
|
||||
block->mnext->mprev = block->mprev;
|
||||
*(block->mprev) = block->mnext;
|
||||
blocknode_t *next = block->bnext;
|
||||
P_ReleaseBlockNode(block);
|
||||
block = next;
|
||||
}
|
||||
|
||||
thing->blocknode = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -814,24 +843,45 @@ void P_SetThingPosition(mobj_t *thing)
|
|||
if (!(thing->flags & MF_NOBLOCKMAP))
|
||||
{
|
||||
// inert things don't need to be in blockmap
|
||||
const INT32 blockx = (unsigned)(thing->x - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
const INT32 blocky = (unsigned)(thing->y - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
if (blockx >= 0 && blockx < bmapwidth
|
||||
&& blocky >= 0 && blocky < bmapheight)
|
||||
{
|
||||
// killough 8/11/98: simpler scheme using
|
||||
// pointer-to-pointer prev pointers --
|
||||
// allows head nodes to be treated like everything else
|
||||
INT32 x1 = (unsigned)(thing->x - thing->radius - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
INT32 y1 = (unsigned)(thing->y - thing->radius - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
INT32 x2 = (unsigned)(thing->x + thing->radius - bmaporgx)>>MAPBLOCKSHIFT;
|
||||
INT32 y2 = (unsigned)(thing->y + thing->radius - bmaporgy)>>MAPBLOCKSHIFT;
|
||||
|
||||
mobj_t **link = &blocklinks[blocky*bmapwidth + blockx];
|
||||
mobj_t *bnext = *link;
|
||||
if ((thing->bnext = bnext) != NULL)
|
||||
bnext->bprev = &thing->bnext;
|
||||
thing->bprev = link;
|
||||
*link = thing;
|
||||
thing->blocknode = NULL;
|
||||
|
||||
blocknode_t **alink = &thing->blocknode;
|
||||
|
||||
if (!(x1 >= bmapwidth || x2 < 0 || y1 >= bmapheight || y2 < 0))
|
||||
{
|
||||
// [RH] Link into every block this actor touches, not just the center one
|
||||
x1 = max(0, x1);
|
||||
y1 = max(0, y1);
|
||||
x2 = min(bmapwidth - 1, x2);
|
||||
y2 = min(bmapheight - 1, y2);
|
||||
for (int y = y1; y <= y2; ++y)
|
||||
{
|
||||
for (int x = x1; x <= x2; ++x)
|
||||
{
|
||||
blocknode_t **link = &blocklinks[y*bmapwidth + x];
|
||||
blocknode_t *node = P_CreateBlockNode(thing, x, y);
|
||||
|
||||
// Link in to block
|
||||
if ((node->mnext = *link) != NULL)
|
||||
{
|
||||
(*link)->mprev = &node->mnext;
|
||||
}
|
||||
node->mprev = link;
|
||||
*link = node;
|
||||
|
||||
// Link in to actor
|
||||
node->bprev = alink;
|
||||
node->bnext = NULL;
|
||||
(*alink) = node;
|
||||
alink = &node->bnext;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // thing is off the map
|
||||
thing->bnext = NULL, thing->bprev = NULL;
|
||||
}
|
||||
|
||||
// Allows you to 'step' on a new linedef exec when the previous
|
||||
|
@ -971,36 +1021,222 @@ boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean (*func)(line_t *))
|
|||
return true; // Everything was checked.
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// P_BlockThingsIterator
|
||||
//
|
||||
boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean (*func)(mobj_t *))
|
||||
{
|
||||
mobj_t *mobj, *bnext = NULL;
|
||||
mobj_t *mobj;
|
||||
blocknode_t *block;
|
||||
|
||||
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
|
||||
return true;
|
||||
|
||||
// Check interaction with the objects in the blockmap.
|
||||
for (mobj = blocklinks[y*bmapwidth + x]; mobj; mobj = bnext)
|
||||
for (block = blocklinks[y*bmapwidth + x]; block; block = block->mnext)
|
||||
{
|
||||
P_SetTarget(&bnext, mobj->bnext); // We want to note our reference to bnext here incase it is MF_NOTHINK and gets removed!
|
||||
mobj = block->mobj;
|
||||
|
||||
if (!func(mobj))
|
||||
{
|
||||
P_SetTarget(&bnext, NULL);
|
||||
return false;
|
||||
}
|
||||
if (P_MobjWasRemoved(tmthing) // func just popped our tmthing, cannot continue.
|
||||
|| (bnext && P_MobjWasRemoved(bnext))) // func just broke blockmap chain, cannot continue.
|
||||
{
|
||||
P_SetTarget(&bnext, NULL);
|
||||
if (P_MobjWasRemoved(tmthing)) // func just broke blockmap chain, cannot continue.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean P_DoBlockThingsIterate(int x1, int y1, int x2, int y2, boolean (*func)(mobj_t *))
|
||||
{
|
||||
boolean status = true;
|
||||
|
||||
for (INT32 bx = x1; bx <= x2; bx++)
|
||||
for (INT32 by = y1; by <= y2; by++)
|
||||
if (!P_BlockThingsIterator(bx, by, func))
|
||||
status = false;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static bthingit_hash_entry_t *GetHashEntryForIterator(bthingit_t *it, int i)
|
||||
{
|
||||
if (i < NUM_BTHINGIT_FIXEDHASH)
|
||||
return &it->fixedhash[i];
|
||||
else
|
||||
return &it->dynhash[i - NUM_BTHINGIT_FIXEDHASH];
|
||||
}
|
||||
|
||||
static blocknode_t *GetBlockmapBlock(int x, int y)
|
||||
{
|
||||
if (x >= 0 && y >= 0 && x < bmapwidth && y < bmapheight)
|
||||
{
|
||||
return blocklinks[y*bmapwidth + x];
|
||||
}
|
||||
else
|
||||
{
|
||||
// invalid block
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bthingit_t *freeiters;
|
||||
|
||||
bthingit_t *P_NewBlockThingsIterator(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
bthingit_t *it;
|
||||
blocknode_t *block;
|
||||
|
||||
x1 = max(0, x1);
|
||||
y1 = max(0, y1);
|
||||
x2 = min(bmapwidth - 1, x2);
|
||||
y2 = min(bmapheight - 1, y2);
|
||||
|
||||
if (x1 > x2 || y1 > y2)
|
||||
return NULL;
|
||||
|
||||
block = GetBlockmapBlock(x1, y1);
|
||||
if (!block)
|
||||
return NULL;
|
||||
|
||||
if (freeiters != NULL)
|
||||
{
|
||||
it = freeiters;
|
||||
freeiters = it->freechain;
|
||||
}
|
||||
else
|
||||
it = Z_Calloc(sizeof(bthingit_t), PU_LEVEL, NULL);
|
||||
|
||||
it->x1 = x1;
|
||||
it->y1 = y1;
|
||||
it->x2 = x2;
|
||||
it->y2 = y2;
|
||||
it->curx = x1;
|
||||
it->cury = y1;
|
||||
it->block = block;
|
||||
it->freechain = NULL;
|
||||
it->numfixedhash = 0;
|
||||
it->dynhashcount = 0;
|
||||
|
||||
for (size_t i = 0; i < NUM_BTHINGIT_BUCKETS; i++)
|
||||
it->buckets[i] = -1;
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
mobj_t *P_BlockThingsIteratorNext(bthingit_t *it, boolean centeronly)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
while (it->block != NULL)
|
||||
{
|
||||
mobj_t *mobj = it->block->mobj;
|
||||
blocknode_t *node = it->block;
|
||||
|
||||
it->block = it->block->mnext;
|
||||
|
||||
// Don't recheck things that were already checked
|
||||
if (node->bnext == NULL && node->bprev == &mobj->blocknode)
|
||||
{
|
||||
// This actor doesn't span blocks, so we know it can only ever be checked once.
|
||||
return mobj;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Block boundaries for compatibility mode
|
||||
if (centeronly)
|
||||
{
|
||||
fixed_t blockleft = (it->curx * MAPBLOCKUNITS) + bmaporgx;
|
||||
fixed_t blockright = blockleft + MAPBLOCKUNITS;
|
||||
fixed_t blockbottom = (it->cury * MAPBLOCKUNITS) + bmaporgy;
|
||||
fixed_t blocktop = blockbottom + MAPBLOCKUNITS;
|
||||
|
||||
// only return actors with the center in this block
|
||||
if (mobj->x >= blockleft && mobj->x < blockright &&
|
||||
mobj->y >= blockbottom && mobj->y < blocktop)
|
||||
{
|
||||
return mobj;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bthingit_hash_entry_t *entry;
|
||||
int i;
|
||||
size_t hash = ((size_t)mobj >> 3) % NUM_BTHINGIT_BUCKETS;
|
||||
|
||||
for (i = it->buckets[hash]; i >= 0; )
|
||||
{
|
||||
entry = GetHashEntryForIterator(it, i);
|
||||
if (entry->mobj == mobj)
|
||||
{
|
||||
// I've already been checked. Skip to the next mobj.
|
||||
break;
|
||||
}
|
||||
i = entry->next;
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
// Add mobj to the hash table and return it.
|
||||
if (it->numfixedhash < NUM_BTHINGIT_FIXEDHASH)
|
||||
{
|
||||
entry = &it->fixedhash[it->numfixedhash];
|
||||
entry->next = it->buckets[hash];
|
||||
it->buckets[hash] = it->numfixedhash++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!it->dynhash)
|
||||
{
|
||||
it->dynhashcapacity = 50;
|
||||
Z_Calloc(it->dynhashcapacity * sizeof(it->dynhashcapacity), PU_LEVEL, &it->dynhash);
|
||||
}
|
||||
if (it->dynhashcount == it->dynhashcapacity)
|
||||
{
|
||||
it->dynhashcapacity *= 2;
|
||||
it->dynhash = Z_Realloc(it->dynhash, it->dynhashcapacity * sizeof(it->dynhashcapacity), PU_LEVEL, &it->dynhash);
|
||||
}
|
||||
i = (int)it->dynhashcount;
|
||||
it->dynhashcount++;
|
||||
entry = &it->dynhash[i];
|
||||
entry->next = it->buckets[hash];
|
||||
it->buckets[hash] = i + NUM_BTHINGIT_FIXEDHASH;
|
||||
}
|
||||
|
||||
entry->mobj = mobj;
|
||||
return mobj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (++it->curx > it->x2)
|
||||
{
|
||||
it->curx = it->x1;
|
||||
if (++it->cury > it->y2)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
it->block = GetBlockmapBlock(it->curx, it->cury);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void P_FreeBlockThingsIterator(bthingit_t *it)
|
||||
{
|
||||
if (it)
|
||||
{
|
||||
it->freechain = freeiters;
|
||||
freeiters = it;
|
||||
}
|
||||
}
|
||||
|
||||
void P_ClearBlockNodes(void)
|
||||
{
|
||||
freeblocks = NULL;
|
||||
freeiters = NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// INTERCEPT ROUTINES
|
||||
//
|
||||
|
|
|
@ -63,6 +63,39 @@ void P_LineOpening(line_t *plinedef, mobj_t *mobj);
|
|||
boolean P_BlockLinesIterator(INT32 x, INT32 y, boolean(*func)(line_t *));
|
||||
boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean(*func)(mobj_t *));
|
||||
|
||||
void P_ClearBlockNodes(void);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
mobj_t *mobj;
|
||||
int next;
|
||||
} bthingit_hash_entry_t;
|
||||
|
||||
#define NUM_BTHINGIT_BUCKETS 32
|
||||
#define NUM_BTHINGIT_FIXEDHASH 10
|
||||
|
||||
typedef struct bthingit_s
|
||||
{
|
||||
int x1, y1, x2, y2;
|
||||
int curx, cury;
|
||||
blocknode_t *block;
|
||||
|
||||
int buckets[NUM_BTHINGIT_BUCKETS];
|
||||
bthingit_hash_entry_t fixedhash[NUM_BTHINGIT_FIXEDHASH];
|
||||
int numfixedhash;
|
||||
|
||||
bthingit_hash_entry_t *dynhash;
|
||||
size_t dynhashcount;
|
||||
size_t dynhashcapacity;
|
||||
|
||||
struct bthingit_s *freechain;
|
||||
} bthingit_t;
|
||||
|
||||
bthingit_t *P_NewBlockThingsIterator(int x1, int y1, int x2, int y2);
|
||||
mobj_t *P_BlockThingsIteratorNext(bthingit_t *it, boolean centeronly);
|
||||
void P_FreeBlockThingsIterator(bthingit_t *it);
|
||||
boolean P_DoBlockThingsIterate(int x1, int y1, int x2, int y2, boolean (*func)(mobj_t *));
|
||||
|
||||
#define PT_ADDLINES 1
|
||||
#define PT_ADDTHINGS 2
|
||||
#define PT_EARLYOUT 4
|
||||
|
|
|
@ -9455,7 +9455,7 @@ static inline boolean PIT_PushThing(mobj_t *thing)
|
|||
|
||||
static void P_PointPushThink(mobj_t *mobj)
|
||||
{
|
||||
INT32 xl, xh, yl, yh, bx, by;
|
||||
INT32 xl, xh, yl, yh;
|
||||
fixed_t radius;
|
||||
|
||||
if (!mobj->spawnpoint)
|
||||
|
@ -9470,9 +9470,8 @@ static void P_PointPushThink(mobj_t *mobj)
|
|||
xh = (unsigned)(mobj->x + radius - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT;
|
||||
yl = (unsigned)(mobj->y - radius - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT;
|
||||
yh = (unsigned)(mobj->y + radius - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT;
|
||||
for (bx = xl; bx <= xh; bx++)
|
||||
for (by = yl; by <= yh; by++)
|
||||
P_BlockThingsIterator(bx, by, PIT_PushThing);
|
||||
|
||||
P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_PushThing);
|
||||
}
|
||||
|
||||
static boolean P_MobjRegularThink(mobj_t *mobj)
|
||||
|
|
16
src/p_mobj.h
16
src/p_mobj.h
|
@ -273,6 +273,19 @@ typedef enum {
|
|||
PCF_THUNK = 32,
|
||||
} precipflag_t;
|
||||
|
||||
// [RH] Like msecnode_t, but for the blockmap
|
||||
typedef struct blocknode_s
|
||||
{
|
||||
struct mobj_s *mobj;
|
||||
|
||||
int blockindex; // index into blocklinks for the block this node is in
|
||||
|
||||
struct blocknode_s **mprev; // previous actor in this block
|
||||
struct blocknode_s *mnext; // next actor in this block
|
||||
struct blocknode_s **bprev; // previous block this actor is in
|
||||
struct blocknode_s *bnext; // next block this actor is in
|
||||
} blocknode_t;
|
||||
|
||||
// Map Object definition.
|
||||
typedef struct mobj_s
|
||||
{
|
||||
|
@ -344,8 +357,7 @@ typedef struct mobj_s
|
|||
|
||||
// Interaction info, by BLOCKMAP.
|
||||
// Links in blocks (if needed).
|
||||
struct mobj_s *bnext;
|
||||
struct mobj_s **bprev; // killough 8/11/98: change to ptr-to-ptr
|
||||
blocknode_t *blocknode;
|
||||
|
||||
// Additional pointers for NiGHTS hoops
|
||||
struct mobj_s *hnext;
|
||||
|
|
|
@ -877,14 +877,17 @@ static void Polyobj_carryThings(polyobj_t *po, fixed_t dx, fixed_t dy)
|
|||
for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x)
|
||||
{
|
||||
mobj_t *mo;
|
||||
blocknode_t *block;
|
||||
|
||||
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
|
||||
continue;
|
||||
|
||||
mo = blocklinks[y * bmapwidth + x];
|
||||
block = blocklinks[y * bmapwidth + x];
|
||||
|
||||
for (; mo; mo = mo->bnext)
|
||||
for (; block; block = block->mnext)
|
||||
{
|
||||
mo = block->mobj;
|
||||
|
||||
if (mo->lastlook == pomovecount)
|
||||
continue;
|
||||
|
||||
|
@ -937,10 +940,12 @@ static INT32 Polyobj_clipThings(polyobj_t *po, line_t *line)
|
|||
{
|
||||
if (!(x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight))
|
||||
{
|
||||
mobj_t *mo = blocklinks[y * bmapwidth + x];
|
||||
mobj_t *mo = NULL;
|
||||
blocknode_t *block = blocklinks[y * bmapwidth + x];
|
||||
|
||||
for (; mo; mo = mo->bnext)
|
||||
for (; block; block = block->mnext)
|
||||
{
|
||||
mo = block->mobj;
|
||||
|
||||
// Don't scroll objects that aren't affected by gravity
|
||||
if (mo->flags & MF_NOGRAVITY)
|
||||
|
@ -1109,14 +1114,17 @@ static void Polyobj_rotateThings(polyobj_t *po, vector2_t origin, angle_t delta,
|
|||
for (x = po->blockbox[BOXLEFT]; x <= po->blockbox[BOXRIGHT]; ++x)
|
||||
{
|
||||
mobj_t *mo;
|
||||
blocknode_t *block;
|
||||
|
||||
if (x < 0 || y < 0 || x >= bmapwidth || y >= bmapheight)
|
||||
continue;
|
||||
|
||||
mo = blocklinks[y * bmapwidth + x];
|
||||
block = blocklinks[y * bmapwidth + x];
|
||||
|
||||
for (; mo; mo = mo->bnext)
|
||||
for (; block; block = block->mnext)
|
||||
{
|
||||
mo = block->mobj;
|
||||
|
||||
if (mo->lastlook == pomovecount)
|
||||
continue;
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ INT32 *blockmaplump; // Big blockmap
|
|||
// origin of block map
|
||||
fixed_t bmaporgx, bmaporgy;
|
||||
// for thing chains
|
||||
mobj_t **blocklinks;
|
||||
blocknode_t **blocklinks;
|
||||
|
||||
// REJECT
|
||||
// For fast sight rejection.
|
||||
|
@ -7869,6 +7869,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
Z_Free(ss->attachedsolid);
|
||||
}
|
||||
|
||||
P_ClearBlockNodes();
|
||||
|
||||
// Clear pointers that would be left dangling by the purge
|
||||
R_FlushTranslationColormapCache();
|
||||
|
||||
|
|
11
src/p_user.c
11
src/p_user.c
|
@ -3807,6 +3807,8 @@ static boolean PIT_CheckSolidsTeeter(mobj_t *thing)
|
|||
if (abs(thing->x - teeterer->x) >= blockdist || abs(thing->y - teeterer->y) >= blockdist)
|
||||
return true; // didn't hit it
|
||||
|
||||
highesttop = INT32_MIN;
|
||||
|
||||
if (teeterer->eflags & MFE_VERTICALFLIP)
|
||||
{
|
||||
if (thingtop < teeterer->z)
|
||||
|
@ -4110,13 +4112,8 @@ static void P_DoTeeter(player_t *player)
|
|||
teeteryl = teeteryh = player->mo->y;
|
||||
couldteeter = false;
|
||||
solidteeter = teeter;
|
||||
for (by = yl; by <= yh; by++)
|
||||
for (bx = xl; bx <= xh; bx++)
|
||||
{
|
||||
highesttop = INT32_MIN;
|
||||
if (!P_BlockThingsIterator(bx, by, PIT_CheckSolidsTeeter))
|
||||
goto teeterdone; // we've found something that stops us teetering at all, how about we stop already
|
||||
}
|
||||
if (!P_DoBlockThingsIterate(xl, yl, xh, yh, PIT_CheckSolidsTeeter))
|
||||
goto teeterdone; // we've found something that stops us teetering at all
|
||||
teeterdone:
|
||||
teeter = solidteeter;
|
||||
P_SetTarget(&tmthing, oldtmthing); // restore old tmthing, goodness knows what the game does with this before mobj thinkers
|
||||
|
|
Loading…
Reference in a new issue