Merge branch 'master' into musicplus-sdlmixerx

This commit is contained in:
Steel Titanium 2019-07-22 22:20:08 -04:00
commit c35afa2c96
53 changed files with 4577 additions and 3175 deletions

View file

@ -4270,14 +4270,9 @@ static INT16 Consistancy(void)
ret += P_GetRandSeed();
#ifdef MOBJCONSISTANCY
if (!thinkercap.next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
DEBFILE(va("Consistancy = %u\n", ret));
return ret;
}
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)th;

View file

@ -4260,8 +4260,8 @@ static void Command_Archivetest_f(void)
// assign mobjnum
i = 1;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed)
((mobj_t *)th)->mobjnum = i++;
// allocate buffer

View file

@ -196,6 +196,7 @@ typedef enum
SH_PITY = 1, // the world's most basic shield ever, given to players who suck at Match
SH_WHIRLWIND,
SH_ARMAGEDDON,
SH_PINK, // PITY IN PINK!
// Normal shields that use flags
SH_ATTRACT = SH_PITY|SH_PROTECTELECTRIC,

View file

@ -28,6 +28,7 @@
#include "p_local.h" // for var1 and var2, and some constants
#include "p_setup.h"
#include "r_data.h"
#include "r_draw.h"
#include "r_sky.h"
#include "fastcmp.h"
#include "lua_script.h"
@ -4666,6 +4667,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
// Boss 3
"S_EGGMOBILE3_STND",
"S_EGGMOBILE3_LAUGH1",
"S_EGGMOBILE3_LAUGH2",
"S_EGGMOBILE3_LAUGH3",
"S_EGGMOBILE3_LAUGH4",
"S_EGGMOBILE3_LAUGH5",
"S_EGGMOBILE3_ATK1",
"S_EGGMOBILE3_ATK2",
"S_EGGMOBILE3_ATK3A",
@ -4674,11 +4680,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_EGGMOBILE3_ATK3D",
"S_EGGMOBILE3_ATK4",
"S_EGGMOBILE3_ATK5",
"S_EGGMOBILE3_LAUGH1",
"S_EGGMOBILE3_LAUGH2",
"S_EGGMOBILE3_LAUGH3",
"S_EGGMOBILE3_LAUGH4",
"S_EGGMOBILE3_LAUGH5",
"S_EGGMOBILE3_LAUGH6",
"S_EGGMOBILE3_LAUGH7",
"S_EGGMOBILE3_LAUGH8",
@ -4731,8 +4732,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_FAKEMOBILE_ATK3B",
"S_FAKEMOBILE_ATK3C",
"S_FAKEMOBILE_ATK3D",
"S_FAKEMOBILE_ATK4",
"S_FAKEMOBILE_ATK5",
"S_FAKEMOBILE_DIE1",
"S_FAKEMOBILE_DIE2",
// Boss 4
"S_EGGMOBILE4_STND",
@ -4750,15 +4751,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_EGGMOBILE4_RATK6",
"S_EGGMOBILE4_RAISE1",
"S_EGGMOBILE4_RAISE2",
"S_EGGMOBILE4_RAISE3",
"S_EGGMOBILE4_RAISE4",
"S_EGGMOBILE4_RAISE5",
"S_EGGMOBILE4_RAISE6",
"S_EGGMOBILE4_RAISE7",
"S_EGGMOBILE4_RAISE8",
"S_EGGMOBILE4_RAISE9",
"S_EGGMOBILE4_RAISE10",
"S_EGGMOBILE4_PAIN",
"S_EGGMOBILE4_PAIN1",
"S_EGGMOBILE4_PAIN2",
"S_EGGMOBILE4_DIE1",
"S_EGGMOBILE4_DIE2",
"S_EGGMOBILE4_DIE3",
@ -4776,10 +4770,21 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_EGGMOBILE4_FLEE1",
"S_EGGMOBILE4_FLEE2",
"S_EGGMOBILE4_MACE",
"S_EGGMOBILE4_MACE_DIE1",
"S_EGGMOBILE4_MACE_DIE2",
"S_EGGMOBILE4_MACE_DIE3",
// Boss 4 jet flame
"S_JETFLAME1",
"S_JETFLAME2",
"S_JETFLAME",
// Boss 4 Spectator Eggrobo
"S_EGGROBO1_IDLE",
"S_EGGROBO1_BSLAP1",
"S_EGGROBO2_BSLAP2",
"S_EGGROBO1_PISSED",
// Boss 4 Spectator Eggrobo jet flame
"S_EGGROBOJET",
// Boss 5
"S_FANG_IDLE1",
@ -5132,7 +5137,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_METALSONIC_BADBOUNCE",
"S_METALSONIC_SHOOT",
"S_METALSONIC_PAIN",
"S_METALSONIC_DEATH",
"S_METALSONIC_DEATH1",
"S_METALSONIC_DEATH2",
"S_METALSONIC_DEATH3",
"S_METALSONIC_DEATH4",
"S_METALSONIC_FLEE1",
"S_METALSONIC_FLEE2",
"S_METALSONIC_FLEE3",
@ -6170,6 +6178,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_PITY4",
"S_PITY5",
"S_PITY6",
"S_PITY7",
"S_PITY8",
"S_PITY9",
"S_PITY10",
"S_PITY11",
"S_PITY12",
"S_FIRS1",
"S_FIRS2",
@ -6654,6 +6668,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_LOCKON1",
"S_LOCKON2",
"S_LOCKON3",
"S_LOCKON4",
"S_LOCKONINF1",
"S_LOCKONINF2",
"S_LOCKONINF3",
"S_LOCKONINF4",
// Tag Sign
"S_TTAG",
@ -6662,6 +6682,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_GOTFLAG",
"S_CORK",
"S_LHRT",
// Red Ring
"S_RRNG1",
@ -7167,6 +7188,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_ROCKCRUMBLEN",
"S_ROCKCRUMBLEO",
"S_ROCKCRUMBLEP",
"S_BRICKDEBRIS",
#ifdef SEENAMES
"S_NAMECHECK",
@ -7251,11 +7273,14 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_EGGMOBILE3",
"MT_PROPELLER",
"MT_FAKEMOBILE",
"MT_SHOCK",
// Boss 4
"MT_EGGMOBILE4",
"MT_EGGMOBILE4_MACE",
"MT_JETFLAME",
"MT_EGGROBO1",
"MT_EGGROBO1JET",
// Boss 5
"MT_FANG",
@ -7732,6 +7757,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_DROWNNUMBERS", // Drowning Timer
"MT_GOTEMERALD", // Chaos Emerald (intangible)
"MT_LOCKON", // Target
"MT_LOCKONINF", // In-level Target
"MT_TAG", // Tag Sign
"MT_GOTFLAG", // Got Flag sign
@ -7749,6 +7775,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_MACHINEAMBIENCE",
"MT_CORK",
"MT_LHRT",
// Ring Weapons
"MT_REDRING",
@ -7881,6 +7908,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_ROCKCRUMBLE14",
"MT_ROCKCRUMBLE15",
"MT_ROCKCRUMBLE16",
"MT_BRICKDEBRIS",
#ifdef SEENAMES
"MT_NAMECHECK",
@ -8521,6 +8549,7 @@ struct {
{"SH_PITY",SH_PITY},
{"SH_WHIRLWIND",SH_WHIRLWIND},
{"SH_ARMAGEDDON",SH_ARMAGEDDON},
{"SH_PINK",SH_PINK},
// normal shields that use flags
{"SH_ATTRACT",SH_ATTRACT},
{"SH_ELEMENTAL",SH_ELEMENTAL},
@ -8764,10 +8793,8 @@ struct {
#endif
#ifdef ESLOPE
// Slope flags
{"SL_NOPHYSICS",SL_NOPHYSICS}, // Don't do momentum adjustment with this slope
{"SL_NODYNAMIC",SL_NODYNAMIC}, // Slope will never need to move during the level, so don't fuss with recalculating it
{"SL_ANCHORVERTEX",SL_ANCHORVERTEX},// Slope is using a Slope Vertex Thing to anchor its position
{"SL_VERTEXSLOPE",SL_VERTEXSLOPE}, // Slope is built from three Slope Vertex Things
{"SL_NOPHYSICS",SL_NOPHYSICS},
{"SL_DYNAMIC",SL_DYNAMIC},
#endif
// Angles
@ -8911,6 +8938,14 @@ struct {
{"KR_TIMEOUT",KR_TIMEOUT},
{"KR_BAN",KR_BAN},
{"KR_LEAVE",KR_LEAVE},
// translation colormaps
{"TC_DEFAULT",TC_DEFAULT},
{"TC_BOSS",TC_BOSS},
{"TC_METALSONIC",TC_METALSONIC},
{"TC_ALLWHITE",TC_ALLWHITE},
{"TC_RAINBOW",TC_RAINBOW},
{"TC_BLINK",TC_BLINK},
#endif
{NULL,0}
@ -9575,11 +9610,6 @@ static inline int lib_getenum(lua_State *L)
lua_pushinteger(L, ((lua_Integer)1<<i));
return 1;
}
if (fastcmp(p, "NETONLY"))
{
lua_pushinteger(L, (lua_Integer)ML_NETONLY);
return 1;
}
if (mathlib) return luaL_error(L, "linedef flag '%s' could not be found.\n", word);
return 0;
}

View file

@ -130,11 +130,9 @@ typedef struct
#define ML_EFFECT4 512
#define ML_EFFECT5 1024
// New ones to disable lines for characters
#define ML_NOSONIC 2048
#define ML_NOTAILS 4096
#define ML_NOKNUX 8192
#define ML_NETONLY 14336 // all of the above
#define ML_NETONLY 2048 // Apply effect only in netgames
#define ML_NONET 4096 // Apply effect only in single player games
#define ML_EFFECT6 8192
// Bounce off walls!
#define ML_BOUNCY 16384

View file

@ -384,7 +384,7 @@ enum {
LE_PINCHPHASE = -2, // A boss entered pinch phase (and, in most cases, is preparing their pinch phase attack!)
LE_ALLBOSSESDEAD = -3, // All bosses in the map are dead (Egg capsule raise)
LE_BOSSDEAD = -4, // A boss in the map died (Chaos mode boss tally)
LE_BOSS4DROP = -5, // CEZ boss dropped its cage
LE_BOSS4DROP = -5, // CEZ boss dropped its cage (also subtract the number of hitpoints it's lost)
LE_BRAKVILEATACK = -6, // Brak's doing his LOS attack, oh noes
LE_TURRET = 32000, // THZ turret
LE_BRAKPLATFORM = 4200, // v2.0 Black Eggman destroys platform

View file

@ -1022,6 +1022,7 @@ static const char *credits[] = {
"",
"\1Boss Design",
"Ben \"Mystic\" Geyer",
"Vivian \"toaster\" Grannell",
"Thomas \"Shadow Hog\" Igoe",
"John \"JTE\" Muniz",
"Samuel \"Prime 2.0\" Peters",
@ -1692,9 +1693,9 @@ void F_TitleScreenTicker(boolean run)
// If there's a Line 422 Switch Cut-Away view, don't force us.
if (!titlemapcameraref || titlemapcameraref->type != MT_ALTVIEWMAN)
{
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;

View file

@ -2565,9 +2565,9 @@ void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo)
I_Assert((oldmo != NULL) && (newmo != NULL));
// scan all thinkers
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -4467,16 +4467,15 @@ void G_ConsGhostTic(void)
demo_p += sizeof(angle_t); // angle, unnecessary for cons.
mobj = NULL;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mobj = (mobj_t *)th;
if (mobj->type == (mobjtype_t)type && mobj->x == x && mobj->y == y && mobj->z == z)
break;
mobj = NULL; // wasn't this one, keep searching.
}
if (mobj && mobj->health != health) // Wasn't damaged?! This is desync! Fix it!
if (th != &thlist[THINK_MOBJ] && mobj->health != health) // Wasn't damaged?! This is desync! Fix it!
{
if (demosynced)
CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n"));
@ -5863,9 +5862,9 @@ void G_DoPlayMetal(void)
metalbuffer = metal_p = W_CacheLumpNum(l, PU_STATIC);
// find metal sonic
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)th;
@ -5874,7 +5873,7 @@ void G_DoPlayMetal(void)
break;
}
if (!mo)
if (th == &thlist[THINK_MOBJ])
{
CONS_Alert(CONS_ERROR, M_GetText("Failed to find bot entity.\n"));
Z_Free(metalbuffer);

View file

@ -202,6 +202,7 @@ light_t *t_lspr[NUMSPRITES] =
// Boss 4 (Castle Eggman)
&lspr[NOLIGHT], // SPR_EGGP
&lspr[REDBALL_L], // SPR_EFIR
&lspr[NOLIGHT], // SPR_EGR1
// Boss 5 (Arid Canyon)
&lspr[NOLIGHT], //SPR_FANG // replaces EGGQ
@ -487,6 +488,7 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_GFLG
&lspr[NOLIGHT], // SPR_CORK
&lspr[NOLIGHT], // SPR_LHRT
// Ring Weapons
&lspr[RINGLIGHT_L], // SPR_RRNG
@ -580,6 +582,9 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_ROIO
&lspr[NOLIGHT], // SPR_ROIP
// Bricks
&lspr[NOLIGHT], // SPR_BRIC
// Gravity Well Objects
&lspr[NOLIGHT], // SPR_GWLG
&lspr[NOLIGHT], // SPR_GWLR
@ -799,6 +804,14 @@ void HWR_WallLighting(FOutVector *wlVerts)
FSurfaceInfo Surf;
float dist_p2d, d[4], s;
if (!dynlights->mo[j])
continue;
if (P_MobjWasRemoved(dynlights->mo[j]))
{
P_SetTarget(&dynlights->mo[j], NULL);
continue;
}
// check bounding box first
if (SphereTouchBBox3D(&wlVerts[2], &wlVerts[0], &LIGHT_POS(j), DL_RADIUS(j))==false)
continue;
@ -849,8 +862,6 @@ void HWR_WallLighting(FOutVector *wlVerts)
#ifdef DL_HIGH_QUALITY
Surf.FlatColor.s.alpha = (UINT8)((1-dist_p2d/DL_SQRRADIUS(j))*Surf.FlatColor.s.alpha);
#endif
if (!dynlights->mo[j]->state)
return;
// next state is null so fade out with alpha
if (dynlights->mo[j]->state->nextstate == S_NULL)
Surf.FlatColor.s.alpha = (UINT8)(((float)dynlights->mo[j]->tics/(float)dynlights->mo[j]->state->tics)*Surf.FlatColor.s.alpha);
@ -881,6 +892,14 @@ void HWR_PlaneLighting(FOutVector *clVerts, int nrClipVerts)
FSurfaceInfo Surf;
float dist_p2d, s;
if (!dynlights->mo[j])
continue;
if (P_MobjWasRemoved(dynlights->mo[j]))
{
P_SetTarget(&dynlights->mo[j], NULL);
continue;
}
// BP: The kickass Optimization: check if light touch bounding box
if (SphereTouchBBox3D(&p1, &p2, &dynlights->position[j], DL_RADIUS(j))==false)
continue;
@ -912,8 +931,6 @@ void HWR_PlaneLighting(FOutVector *clVerts, int nrClipVerts)
#ifdef DL_HIGH_QUALITY
Surf.FlatColor.s.alpha = (unsigned char)((1 - dist_p2d/DL_SQRRADIUS(j))*Surf.FlatColor.s.alpha);
#endif
if (!dynlights->mo[j]->state)
return;
// next state is null so fade out with alpha
if ((dynlights->mo[j]->state->nextstate == S_NULL))
Surf.FlatColor.s.alpha = (unsigned char)(((float)dynlights->mo[j]->tics/(float)dynlights->mo[j]->state->tics)*Surf.FlatColor.s.alpha);
@ -1044,6 +1061,14 @@ void HWR_DrawCoronas(void)
if (!(p_lspr->type & CORONA_SPR))
continue;
if (!dynlights->mo[j])
continue;
if (P_MobjWasRemoved(dynlights->mo[j]))
{
P_SetTarget(&dynlights->mo[j], NULL);
continue;
}
transform(&cx,&cy,&cz);
// more realistique corona !
@ -1105,7 +1130,8 @@ void HWR_DrawCoronas(void)
// --------------------------------------------------------------------------
void HWR_ResetLights(void)
{
dynlights->nb = 0;
while (dynlights->nb)
P_SetTarget(&dynlights->mo[--dynlights->nb], NULL);
}
// --------------------------------------------------------------------------
@ -1136,14 +1162,16 @@ void HWR_DL_AddLight(gr_vissprite_t *spr, GLPatch_t *patch)
return;
#endif
if (dynlights->nb >= DL_MAX_LIGHT)
return;
// check if sprite contain dynamic light
p_lspr = t_lspr[spr->mobj->sprite];
if ((p_lspr->type&DYNLIGHT_SPR)
&& ((p_lspr->type != LIGHT_SPR) || cv_grstaticlighting.value)
&& (dynlights->nb < DL_MAX_LIGHT)
if (!(p_lspr->type & DYNLIGHT_SPR))
return;
if ((p_lspr->type != LIGHT_SPR) || cv_grstaticlighting.value)
return;
&& spr->mobj->state)
{
LIGHT_POS(dynlights->nb).x = FIXED_TO_FLOAT(spr->mobj->x);
LIGHT_POS(dynlights->nb).y = FIXED_TO_FLOAT(spr->mobj->z)+FIXED_TO_FLOAT(spr->mobj->height>>1)+p_lspr->light_yoffset;
LIGHT_POS(dynlights->nb).z = FIXED_TO_FLOAT(spr->mobj->y);
@ -1154,7 +1182,6 @@ void HWR_DL_AddLight(gr_vissprite_t *spr, GLPatch_t *patch)
dynlights->nb++;
}
}
static GLPatch_t lightmappatch;
@ -1307,6 +1334,14 @@ static void HWR_CheckSubsector(size_t num, fixed_t *bbox)
// if (CircleTouchBBox(&p1, &p2, &LIGHT_POS(lightnum), DL_RADIUS(lightnum))==false)
// continue;
if (!dynlights->mo[lightnum])
continue;
if (P_MobjWasRemoved(dynlights->mo[lightnum]))
{
P_SetTarget(&dynlights->mo[lightnum], NULL);
continue;
}
count = sub->numlines; // how many linedefs
line = &segs[sub->firstline]; // first line seg
while (count--)
@ -1324,18 +1359,20 @@ static void HWR_CheckSubsector(size_t num, fixed_t *bbox)
// --------------------------------------------------------------------------
static void HWR_AddMobjLights(mobj_t *thing)
{
if (t_lspr[thing->sprite]->type & CORONA_SPR)
{
if (dynlights->nb >= DL_MAX_LIGHT)
return;
if (!(t_lspr[thing->sprite]->type & CORONA_SPR))
return;
LIGHT_POS(dynlights->nb).x = FIXED_TO_FLOAT(thing->x);
LIGHT_POS(dynlights->nb).y = FIXED_TO_FLOAT(thing->z) + t_lspr[thing->sprite]->light_yoffset;
LIGHT_POS(dynlights->nb).z = FIXED_TO_FLOAT(thing->y);
P_SetTarget(&dynlights->mo[dynlights->nb], thing);
dynlights->p_lspr[dynlights->nb] = t_lspr[thing->sprite];
dynlights->nb++;
if (dynlights->nb > DL_MAX_LIGHT)
dynlights->nb = DL_MAX_LIGHT;
}
}
//Hurdler: The goal of this function is to walk through all the bsp starting
@ -1361,13 +1398,10 @@ static void HWR_SearchLightsInMobjs(void)
//mobj_t * mobj;
// search in the list of thinkers
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
// a mobj ?
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed)
HWR_AddMobjLights((mobj_t *)th);
}
}
#endif
//
@ -1378,7 +1412,7 @@ void HWR_CreateStaticLightmaps(int bspnum)
#ifdef STATICLIGHT
CONS_Debug(DBG_RENDER, "HWR_CreateStaticLightmaps\n");
dynlights->nb = 0;
HWR_ResetLights();
// First: Searching for lights
// BP: if i was you, I will make it in create mobj since mobj can be create
@ -1389,8 +1423,6 @@ void HWR_CreateStaticLightmaps(int bspnum)
// Second: Build all lightmap for walls covered by lights
validcount++; // to be sure
HWR_ComputeLightMapsInBSPNode(bspnum, NULL);
dynlights->nb = 0;
#else
(void)bspnum;
#endif

View file

@ -580,7 +580,7 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is
if (nrPlaneVerts < 3) //not even a triangle ?
return;
if (nrPlaneVerts > UINT16_MAX) // FIXME: exceeds plVerts size
if (nrPlaneVerts > (INT32)UINT16_MAX) // FIXME: exceeds plVerts size
{
CONS_Debug(DBG_RENDER, "polygon size of %d exceeds max value of %d vertices\n", nrPlaneVerts, UINT16_MAX);
return;
@ -3190,7 +3190,7 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling,
if (nrPlaneVerts < 3) //not even a triangle ?
return;
if (nrPlaneVerts > UINT16_MAX) // FIXME: exceeds plVerts size
if (nrPlaneVerts > (size_t)UINT16_MAX) // FIXME: exceeds plVerts size
{
CONS_Debug(DBG_RENDER, "polygon size of %s exceeds max value of %d vertices\n", sizeu1(nrPlaneVerts), UINT16_MAX);
return;
@ -5660,9 +5660,9 @@ static void HWR_ProjectSprite(mobj_t *thing)
vis->z2 = z2;
//Hurdler: 25/04/2000: now support colormap in hardware mode
if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash"
if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
{
if (vis->mobj->type == MT_CYBRAKDEMON)
if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized)
vis->colormap = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
else if (vis->mobj->type == MT_METALSONIC_BATTLE)
vis->colormap = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE);
@ -5672,7 +5672,9 @@ static void HWR_ProjectSprite(mobj_t *thing)
else if (thing->color)
{
// New colormap stuff for skins Tails 06-07-2002
if (thing->skin && thing->sprite == SPR_PLAY) // This thing is a player!
if (thing->colorized)
vis->colormap = R_GetTranslationColormap(TC_RAINBOW, thing->color, GTC_CACHE);
else if (thing->skin && thing->sprite == SPR_PLAY) // This thing is a player!
{
size_t skinnum = (skin_t*)thing->skin-skins;
vis->colormap = R_GetTranslationColormap((INT32)skinnum, thing->color, GTC_CACHE);

View file

@ -40,6 +40,8 @@
#include "../w_wad.h"
#include "../z_zone.h"
#include "../r_things.h"
#include "../r_draw.h"
#include "../p_tick.h"
#include "hw_main.h"
#include "../v_video.h"
@ -978,8 +980,18 @@ spritemd2found:
fclose(f);
}
static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, skincolors_t color)
// Define for getting accurate color brightness readings according to how the human eye sees them.
// https://en.wikipedia.org/wiki/Relative_luminance
// 0.2126 to red
// 0.7152 to green
// 0.0722 to blue
// (See this same define in k_kart.c!)
#define SETBRIGHTNESS(brightness,r,g,b) \
brightness = (UINT8)(((1063*((UINT16)r)/5000) + (3576*((UINT16)g)/5000) + (361*((UINT16)b)/5000)) / 3)
static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, INT32 skinnum, skincolors_t color)
{
UINT8 i;
UINT16 w = gpatch->width, h = gpatch->height;
UINT32 size = w*h;
RGBA_t *image, *blendimage, *cur, blendcolor;
@ -1005,11 +1017,70 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
image = gpatch->mipmap.grInfo.data;
blendimage = blendgpatch->mipmap.grInfo.data;
// Average all of the translation's colors
if (color == SKINCOLOR_NONE || color >= MAXTRANSLATIONS)
blendcolor = V_GetColor(0xff);
else
blendcolor = V_GetColor(Color_Index[color-1][4]);
{
const UINT8 div = 6;
const UINT8 start = 4;
UINT32 r, g, b;
blendcolor = V_GetColor(Color_Index[color-1][start]);
r = (UINT32)(blendcolor.s.red*blendcolor.s.red);
g = (UINT32)(blendcolor.s.green*blendcolor.s.green);
b = (UINT32)(blendcolor.s.blue*blendcolor.s.blue);
for (i = 1; i < div; i++)
{
RGBA_t nextcolor = V_GetColor(Color_Index[color-1][start+i]);
r += (UINT32)(nextcolor.s.red*nextcolor.s.red);
g += (UINT32)(nextcolor.s.green*nextcolor.s.green);
b += (UINT32)(nextcolor.s.blue*nextcolor.s.blue);
}
blendcolor.s.red = (UINT8)(FixedSqrt((r/div)<<FRACBITS)>>FRACBITS);
blendcolor.s.green = (UINT8)(FixedSqrt((g/div)<<FRACBITS)>>FRACBITS);
blendcolor.s.blue = (UINT8)(FixedSqrt((b/div)<<FRACBITS)>>FRACBITS);
}
// rainbow support, could theoretically support boss ones too
if (skinnum == TC_RAINBOW)
{
while (size--)
{
if (image->s.alpha == 0 && blendimage->s.alpha == 0)
{
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
cur->rgba = image->rgba;
}
else
{
UINT32 tempcolor;
UINT16 imagebright, blendbright, finalbright, colorbright;
SETBRIGHTNESS(imagebright,image->s.red,image->s.green,image->s.blue);
SETBRIGHTNESS(blendbright,blendimage->s.red,blendimage->s.green,blendimage->s.blue);
// slightly dumb average between the blend image color and base image colour, usually one or the other will be fully opaque anyway
finalbright = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255;
SETBRIGHTNESS(colorbright,blendcolor.s.red,blendcolor.s.green,blendcolor.s.blue);
tempcolor = (finalbright*blendcolor.s.red)/colorbright;
tempcolor = min(255, tempcolor);
cur->s.red = (UINT8)tempcolor;
tempcolor = (finalbright*blendcolor.s.green)/colorbright;
tempcolor = min(255, tempcolor);
cur->s.green = (UINT8)tempcolor;
tempcolor = (finalbright*blendcolor.s.blue)/colorbright;
tempcolor = min(255, tempcolor);
cur->s.blue = (UINT8)tempcolor;
cur->s.alpha = image->s.alpha;
}
cur++; image++; blendimage++;
}
}
else
{
while (size--)
{
if (blendimage->s.alpha == 0)
@ -1044,11 +1115,14 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
cur++; image++; blendimage++;
}
}
return;
}
static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, const UINT8 *colormap, skincolors_t color)
#undef SETBRIGHTNESS
static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT32 skinnum, const UINT8 *colormap, skincolors_t color)
{
// mostly copied from HWR_GetMappedPatch, hence the similarities and comment
GLMipmap_t *grmip, *newmip;
@ -1089,13 +1163,14 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, con
grmip->nextcolormap = newmip;
newmip->colormap = colormap;
HWR_CreateBlendedTexture(gpatch, blendgpatch, newmip, color);
HWR_CreateBlendedTexture(gpatch, blendgpatch, newmip, skinnum, color);
HWD.pfnSetTexture(newmip);
Z_ChangeTag(newmip->grInfo.data, PU_HWRCACHE_UNLOCKED);
}
// -----------------+
// HWR_DrawMD2 : Draw MD2
// : (monsters, bonuses, weapons, lights, ...)
@ -1285,7 +1360,30 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
md2->blendgrpatch && ((GLPatch_t *)md2->blendgrpatch)->mipmap.grInfo.format
&& gpatch->width == ((GLPatch_t *)md2->blendgrpatch)->width && gpatch->height == ((GLPatch_t *)md2->blendgrpatch)->height)
{
HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, spr->colormap, (skincolors_t)spr->mobj->color);
INT32 skinnum = TC_DEFAULT;
if ((spr->mobj->flags & (MF_ENEMY|MF_BOSS)) && (spr->mobj->flags2 & MF2_FRET) && !(spr->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
{
if (spr->mobj->type == MT_CYBRAKDEMON || spr->mobj->colorized)
skinnum = TC_ALLWHITE;
else if (spr->mobj->type == MT_METALSONIC_BATTLE)
skinnum = TC_METALSONIC;
else
skinnum = TC_BOSS;
}
else if (spr->mobj->color)
{
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
{
if (spr->mobj->colorized)
skinnum = TC_RAINBOW;
else
{
skinnum = (INT32)((skin_t*)spr->mobj->skin-skins);
}
}
else skinnum = TC_DEFAULT;
}
HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolors_t)spr->mobj->color);
}
else
{

View file

@ -90,6 +90,7 @@ char sprnames[NUMSPRITES + 1][5] =
// Boss 4 (Castle Eggman)
"EGGP",
"EFIR", // Boss 4 jet flame
"EGR1", // Boss 4 Spectator Eggrobo
// Boss 5 (Arid Canyon)
"FANG", // replaces EGGQ
@ -382,6 +383,7 @@ char sprnames[NUMSPRITES + 1][5] =
"GFLG", // Got Flag sign
"CORK",
"LHRT",
// Ring Weapons
"RRNG", // Red Ring
@ -475,6 +477,9 @@ char sprnames[NUMSPRITES + 1][5] =
"ROIO",
"ROIP",
// Bricks
"BRIC",
// Gravity Well Objects
"GWLG",
"GWLR",
@ -742,10 +747,10 @@ state_t states[NUMSTATES] =
{SPR_PLAY, SPR2_FIRE, 15, {NULL}, S_PLAY_STND, 0, S_PLAY_STND}, // S_PLAY_FIRE_FINISH
// CA_TWINSPIN
{SPR_PLAY, SPR2_TWIN|FF_SPR2ENDSTATE, 1, {NULL}, S_PLAY_JUMP, 0, S_PLAY_TWINSPIN}, // S_PLAY_TWINSPIN
{SPR_PLAY, SPR2_TWIN|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_JUMP, 0, S_PLAY_TWINSPIN}, // S_PLAY_TWINSPIN
// CA2_MELEE
{SPR_PLAY, SPR2_MLEE|FF_SPR2ENDSTATE, 1, {NULL}, S_PLAY_MELEE_FINISH, 0, S_PLAY_MELEE}, // S_PLAY_MELEE
{SPR_PLAY, SPR2_MLEE|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_MELEE_FINISH, 0, S_PLAY_MELEE}, // S_PLAY_MELEE
{SPR_PLAY, SPR2_MLEE, 70, {NULL}, 0, 0, S_PLAY_FALL}, // S_PLAY_MELEE_FINISH
{SPR_PLAY, SPR2_MLEL, 35, {NULL}, 0, 0, S_PLAY_WALK}, // S_PLAY_MELEE_LANDING
@ -1268,6 +1273,11 @@ state_t states[NUMSTATES] =
// Boss 3
{SPR_EGGO, 0, 1, {NULL}, 0, 0, S_EGGMOBILE3_STND}, // S_EGGMOBILE3_STND
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH2}, // S_EGGMOBILE3_LAUGH1
{SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH3}, // S_EGGMOBILE3_LAUGH2
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH4}, // S_EGGMOBILE3_LAUGH3
{SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH5}, // S_EGGMOBILE3_LAUGH4
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_ATK1}, // S_EGGMOBILE3_LAUGH5
{SPR_EGGO, 1, 2, {NULL}, 0, 0, S_EGGMOBILE3_ATK2}, // S_EGGMOBILE3_ATK1
{SPR_EGGO, 2, 2, {NULL}, 0, 0, S_EGGMOBILE3_ATK3A}, // S_EGGMOBILE3_ATK2
{SPR_EGGO, 3, 2, {A_BossFireShot}, MT_TORPEDO, 2, S_EGGMOBILE3_ATK3B}, // S_EGGMOBILE3_ATK3A
@ -1275,12 +1285,7 @@ state_t states[NUMSTATES] =
{SPR_EGGO, 3, 2, {A_BossFireShot}, MT_TORPEDO, 3, S_EGGMOBILE3_ATK3D}, // S_EGGMOBILE3_ATK3C
{SPR_EGGO, 3, 2, {A_BossFireShot}, MT_TORPEDO, 5, S_EGGMOBILE3_ATK4}, // S_EGGMOBILE3_ATK3D
{SPR_EGGO, 4, 2, {NULL}, 0, 0, S_EGGMOBILE3_ATK5}, // S_EGGMOBILE3_ATK4
{SPR_EGGO, 5, 2, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH1}, // S_EGGMOBILE3_ATK5
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH2}, // S_EGGMOBILE3_LAUGH1
{SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH3}, // S_EGGMOBILE3_LAUGH2
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH4}, // S_EGGMOBILE3_LAUGH3
{SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH5}, // S_EGGMOBILE3_LAUGH4
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH6}, // S_EGGMOBILE3_LAUGH5
{SPR_EGGO, 5, 2, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH6}, // S_EGGMOBILE3_ATK5
{SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH7}, // S_EGGMOBILE3_LAUGH6
{SPR_EGGO, 6, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH8}, // S_EGGMOBILE3_LAUGH7
{SPR_EGGO, 7, 4, {NULL}, 0, 0, S_EGGMOBILE3_LAUGH9}, // S_EGGMOBILE3_LAUGH8
@ -1327,14 +1332,14 @@ state_t states[NUMSTATES] =
// Boss 3 Pinch
{SPR_FAKE, 0, 1, {A_BossJetFume}, 1, 0, S_FAKEMOBILE}, // S_FAKEMOBILE_INIT
{SPR_FAKE, 0, 1, {A_Boss3Path}, 0, 0, S_FAKEMOBILE}, // S_FAKEMOBILE
{SPR_FAKE, 0, 2, {NULL}, 0, 0, S_FAKEMOBILE_ATK2}, // S_FAKEMOBILE_ATK1
{SPR_FAKE, 0, 22, {NULL}, 0, 0, S_FAKEMOBILE_ATK2}, // S_FAKEMOBILE_ATK1
{SPR_FAKE, 0, 2, {NULL}, 0, 0, S_FAKEMOBILE_ATK3A}, // S_FAKEMOBILE_ATK2
{SPR_FAKE, 0, 2, {A_BossFireShot}, MT_TORPEDO2, 2, S_FAKEMOBILE_ATK3B}, // S_FAKEMOBILE_ATK3A
{SPR_FAKE, 0, 2, {A_BossFireShot}, MT_TORPEDO2, 4, S_FAKEMOBILE_ATK3C}, // S_FAKEMOBILE_ATK3B
{SPR_FAKE, 0, 2, {A_BossFireShot}, MT_TORPEDO2, 3, S_FAKEMOBILE_ATK3D}, // S_FAKEMOBILE_ATK3C
{SPR_FAKE, 0, 2, {A_BossFireShot}, MT_TORPEDO2, 5, S_FAKEMOBILE_ATK4}, // S_FAKEMOBILE_ATK3D
{SPR_FAKE, 0, 2, {NULL}, 0, 0, S_FAKEMOBILE_ATK5}, // S_FAKEMOBILE_ATK4
{SPR_FAKE, 0, 2, {NULL}, 0, 0, S_FAKEMOBILE}, // S_FAKEMOBILE_ATK5
{SPR_FAKE, 0, 2, {A_BossFireShot}, MT_TORPEDO2, 5, S_FAKEMOBILE}, // S_FAKEMOBILE_ATK3D
{SPR_FAKE, 0, 1, {NULL}, 0, 0, S_FAKEMOBILE_DIE2}, // S_FAKEMOBILE_DIE1
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_FAKEMOBILE_DIE1}, // S_FAKEMOBILE_DIE2
// Boss 4
{SPR_EGGP, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGMOBILE4_STND
@ -1351,16 +1356,9 @@ state_t states[NUMSTATES] =
{SPR_EGGP, 9,150, {A_Boss4SpeedUp}, sfx_mswing, 0, S_EGGMOBILE4_RATK6}, // S_EGGMOBILE4_RATK5
{SPR_EGGP,10, 2, {NULL}, 0, 0, S_EGGMOBILE4_STND}, // S_EGGMOBILE4_RATK6
{SPR_EGGP, 0, 20, {A_Boss4Raise}, sfx_doord1, 0, S_EGGMOBILE4_RAISE2}, // S_EGGMOBILE4_RAISE1
{SPR_EGGP,13, 10, {NULL}, 0, 0, S_EGGMOBILE4_RAISE3}, // S_EGGMOBILE4_RAISE2
{SPR_EGGP,14, 10, {NULL}, 0, 0, S_EGGMOBILE4_RAISE4}, // S_EGGMOBILE4_RAISE3
{SPR_EGGP,13, 10, {NULL}, 0, 0, S_EGGMOBILE4_RAISE5}, // S_EGGMOBILE4_RAISE4
{SPR_EGGP,14, 10, {NULL}, 0, 0, S_EGGMOBILE4_RAISE6}, // S_EGGMOBILE4_RAISE5
{SPR_EGGP,13, 10, {NULL}, 0, 0, S_EGGMOBILE4_RAISE7}, // S_EGGMOBILE4_RAISE6
{SPR_EGGP,14, 10, {NULL}, 0, 0, S_EGGMOBILE4_RAISE8}, // S_EGGMOBILE4_RAISE7
{SPR_EGGP,13, 10, {NULL}, 0, 0, S_EGGMOBILE4_RAISE9}, // S_EGGMOBILE4_RAISE8
{SPR_EGGP,14, 10, {NULL}, 0, 0, S_EGGMOBILE4_RAISE10},// S_EGGMOBILE4_RAISE9
{SPR_EGGP,13, 10, {NULL}, 0, 0, S_EGGMOBILE4_STND}, // S_EGGMOBILE4_RAISE10
{SPR_EGGP,11, 24, {A_Pain}, 0, 0, S_EGGMOBILE4_STND}, // S_EGGMOBILE4_PAIN
{SPR_EGGP,13|FF_ANIMATE, -1, {NULL}, 1, 10, S_NULL}, // S_EGGMOBILE4_RAISE2
{SPR_EGGP,11, 0, {A_Boss4Reverse}, sfx_alarm, sfx_s3k60, S_EGGMOBILE4_PAIN2}, // S_EGGMOBILE4_PAIN1
{SPR_EGGP,11, 24, {A_Pain}, 0, 0, S_EGGMOBILE4_STND}, // S_EGGMOBILE4_PAIN2
{SPR_EGGP,12, 8, {A_Fall}, 0, 0, S_EGGMOBILE4_DIE2}, // S_EGGMOBILE4_DIE1
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE3}, // S_EGGMOBILE4_DIE2
{SPR_EGGP,12, 8, {A_BossScream}, 0, 0, S_EGGMOBILE4_DIE4}, // S_EGGMOBILE4_DIE3
@ -1378,10 +1376,21 @@ state_t states[NUMSTATES] =
{SPR_EGGP,13, 5, {NULL}, 0, 0, S_EGGMOBILE4_FLEE2}, // S_EGGMOBILE4_FLEE1
{SPR_EGGP,14, 5, {NULL}, 0, 0, S_EGGMOBILE4_FLEE1}, // S_EGGMOBILE4_FLEE2
{SPR_BMCE, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGMOBILE4_MACE
{SPR_BMCE, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_EGGMOBILE4_MACE_DIE2}, // S_EGGMOBILE4_MACE_DIE1
{SPR_NULL, 0, 2, {A_BossScream}, 1, MT_SONIC3KBOSSEXPLODE, S_EGGMOBILE4_MACE_DIE3}, // S_EGGMOBILE4_MACE_DIE2
{SPR_NULL, 0, 0, {A_Repeat}, 7, S_EGGMOBILE4_MACE_DIE1, S_BOSSEXPLODE}, // S_EGGMOBILE4_MACE_DIE3
// Boss 4 Jet flame
{SPR_EFIR, FF_FULLBRIGHT, 1, {NULL}, 0, 0, S_JETFLAME2}, // S_JETFLAME1
{SPR_EFIR, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_JETFLAME1}, // S_JETFLAME2
// Boss 4 jet flame
{SPR_EFIR, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 1, 1, S_NULL}, // S_JETFLAME
// Boss 4 Spectator Eggrobo
{SPR_EGR1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_EGGROBO1_STND
{SPR_EGR1, 5, 2, {NULL}, 0, 0, S_EGGROBO1_BSLAP2}, // S_EGGROBO1_BSLAP1
{SPR_EGR1, FF_ANIMATE|6, 35, {NULL}, 1, 2, S_EGGROBO1_STND}, // S_EGGROBO1_BSLAP2
{SPR_EGR1, FF_ANIMATE|3, -1, {NULL}, 1, 2, S_NULL}, // S_EGGROBO1_PISSED
// Boss 4 Spectator Eggrobo jet flame
{SPR_EFIR, FF_FULLBRIGHT|2, -1, {NULL}, 0, 0, S_NULL}, // S_EGGROBOJET
// Boss 5
{SPR_FANG, 2, 16, {A_Look}, 1, 0, S_FANG_IDLE2}, // S_FANG_IDLE1
@ -1746,20 +1755,23 @@ state_t states[NUMSTATES] =
{SPR_METL, 9, 2, {NULL}, 0, 0, S_METALSONIC_RUN1}, // S_METALSONIC_RUN4
{SPR_METL, 4, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_FLOAT
{SPR_METL, 12, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR
{SPR_METL, 0, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN
{SPR_METL, 13, 40, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE
{SPR_METL, 12|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR
{SPR_METL, 11, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN
{SPR_METL, 13, 20, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE
{SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_GATHER
{SPR_METL, 15, -1, {NULL}, 0, 0, S_METALSONIC_BOUNCE},// S_METALSONIC_DASH
{SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BOUNCE
{SPR_METL, 16, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BADBOUNCE
{SPR_METL, 13, -1, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_SHOOT
{SPR_METL, 11, 40, {A_Pain}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_PAIN
{SPR_METL, 11, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH
{SPR_METL, 3, 4, {NULL}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1
{SPR_METL, 4, 4, {A_BossScream}, 0, 0, S_METALSONIC_FLEE3}, // S_METALSONIC_FLEE2
{SPR_METL, 5, 4, {NULL}, 0, 0, S_METALSONIC_FLEE4}, // S_METALSONIC_FLEE3
{SPR_METL, 4, 4, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE4
{SPR_METL, 13, 8, {A_Fall}, 0, 0, S_METALSONIC_DEATH2},// S_METALSONIC_DEATH1
{SPR_METL, 13, 8, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3},// S_METALSONIC_DEATH2
{SPR_METL, 13, 0, {A_Repeat}, 11, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4}, // S_METALSONIC_DEATH3
{SPR_METL, 13, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH4
{SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1
{SPR_METL, 11, 4, {A_BossScream}, 0, 0, S_METALSONIC_FLEE3}, // S_METALSONIC_FLEE2
{SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE4}, // S_METALSONIC_FLEE3
{SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE4
{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 0, 1, {NULL}, 0, 0, S_MSSHIELD_F2}, // S_MSSHIELD_F1
{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 1, 1, {NULL}, 0, 0, S_MSSHIELD_F3}, // S_MSSHIELD_F2
@ -2806,9 +2818,15 @@ state_t states[NUMSTATES] =
{SPR_PITY, FF_TRANS30 , 2, {NULL}, 0, 0, S_PITY2}, // S_PITY1
{SPR_PITY, FF_TRANS30| 1, 2, {NULL}, 0, 0, S_PITY3}, // S_PITY2
{SPR_PITY, FF_TRANS30| 2, 2, {NULL}, 0, 0, S_PITY4}, // S_PITY3
{SPR_PITY, FF_TRANS20|3, 2, {NULL}, 0, 0, S_PITY5}, // S_PITY4
{SPR_PITY, FF_TRANS30| 3, 2, {NULL}, 0, 0, S_PITY5}, // S_PITY4
{SPR_PITY, FF_TRANS30| 4, 2, {NULL}, 0, 0, S_PITY6}, // S_PITY5
{SPR_PITY, FF_TRANS20|5, 2, {NULL}, 0, 0, S_PITY1}, // S_PITY6
{SPR_PITY, FF_TRANS30| 5, 2, {NULL}, 0, 0, S_PITY7}, // S_PITY6
{SPR_PITY, FF_TRANS30| 6, 2, {NULL}, 0, 0, S_PITY8}, // S_PITY7
{SPR_PITY, FF_TRANS30| 7, 2, {NULL}, 0, 0, S_PITY9}, // S_PITY8
{SPR_PITY, FF_TRANS30| 8, 2, {NULL}, 0, 0, S_PITY10}, // S_PITY9
{SPR_PITY, FF_TRANS30| 9, 2, {NULL}, 0, 0, S_PITY11}, // S_PITY10
{SPR_PITY, FF_TRANS30|10, 2, {NULL}, 0, 0, S_PITY12}, // S_PITY11
{SPR_PITY, FF_TRANS30|11, 2, {NULL}, 0, 0, S_PITY1}, // S_PITY12
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40 , 2, {NULL}, 0, 0, S_FIRS2}, // S_FIRS1
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|1, 2, {NULL}, 0, 0, S_FIRS3}, // S_FIRS2
@ -2886,7 +2904,7 @@ state_t states[NUMSTATES] =
{SPR_NULL, 0, 15*2, {NULL}, 0, 0, S_ZAPSB2 }, // S_ZAPSB11
// Thunder spark
{SPR_SSPK, FF_ANIMATE, 18, {NULL}, 1, 2, S_NULL}, // S_THUNDERCOIN_SPARK
{SPR_SSPK, FF_ANIMATE, -1, {NULL}, 1, 2, S_NULL}, // S_THUNDERCOIN_SPARK
// Invincibility Sparkles
{SPR_IVSP, FF_ANIMATE, 32, {NULL}, 31, 1, S_NULL}, // S_IVSP
@ -3187,8 +3205,8 @@ state_t states[NUMSTATES] =
{SPR_SSWB, 1, 1, {NULL}, 0, 0, S_BHORIZ1}, // S_BHORIZ8
// Rain
{SPR_RAIN, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1
{SPR_RAIN, FF_TRANS50, 1, {NULL}, 0, 0, S_RAIN1}, // S_RAINRETURN
{SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1
{SPR_RAIN, FF_FULLBRIGHT|FF_TRANS50, 1, {NULL}, 0, 0, S_RAIN1}, // S_RAINRETURN
// Snowflake
{SPR_SNO1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW1
@ -3298,6 +3316,13 @@ state_t states[NUMSTATES] =
{SPR_LCKN, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON1
{SPR_LCKN, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON2
{SPR_LCKN, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON3
{SPR_LCKN, 3|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_LOCKON4
{SPR_LCKN, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF1
{SPR_LCKN, 1|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF2
{SPR_LCKN, 2|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF3
{SPR_LCKN, 3|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LOCKONINF4
{SPR_TTAG, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_TTAG
@ -3305,6 +3330,7 @@ state_t states[NUMSTATES] =
{SPR_GFLG, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_GOTFLAG
{SPR_CORK, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORK
{SPR_LHRT, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LHRT
// Red Rings (thrown)
{SPR_RRNG, FF_FULLBRIGHT, 1, {A_ThrownRing}, 0, 0, S_RRNG2}, // S_RRNG1
@ -3861,6 +3887,8 @@ state_t states[NUMSTATES] =
{SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEO
{SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEP
{SPR_BRIC, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL}, // S_BRICKDEBRIS
#ifdef SEENAMES
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK
#endif
@ -5500,7 +5528,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
MT_PROPELLER, // painchance
sfx_dmpain, // painsound
S_NULL, // meleestate
S_EGGMOBILE3_ATK1, // missilestate
S_EGGMOBILE3_LAUGH1,// missilestate
S_EGGMOBILE3_DIE1, // deathstate
S_EGGMOBILE3_FLEE1, // xdeathstate
sfx_cybdth, // deathsound
@ -5555,9 +5583,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_s3k7b, // painsound
S_NULL, // meleestate
S_FAKEMOBILE_ATK1, // missilestate
S_XPLD1, // deathstate
S_FAKEMOBILE_DIE1, // deathstate
S_NULL, // xdeathstate
sfx_pop, // deathsound
sfx_mswarp, // deathsound
8*FRACUNIT, // speed
32*FRACUNIT, // radius
116*FRACUNIT, // height
@ -5569,6 +5597,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_SHOCK
-1, // doomednum
S_THUNDERCOIN_SPARK, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_SPRK1, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
10*FRACUNIT, // speed
16*FRACUNIT, // radius
35*FRACUNIT, // height
0, // display offset
DMG_ELECTRIC|(sfx_buzz2<<8), // mass
20, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_MISSILE|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_EGGMOBILE4
203, // doomednum
S_EGGMOBILE4_STND, // spawnstate
@ -5577,7 +5632,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_EGGMOBILE4_PAIN, // painstate
S_EGGMOBILE4_PAIN1,// painstate
0, // painchance
sfx_dmpain, // painsound
S_EGGMOBILE4_LATK1,// meleestate
@ -5609,9 +5664,9 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_BOSSEXPLODE, // deathstate
S_EGGMOBILE4_MACE_DIE1, // deathstate
S_NULL, // xdeathstate
sfx_cybdth, // deathsound
sfx_None, // deathsound
48*FRACUNIT, // speed
34*FRACUNIT, // radius
68*FRACUNIT, // height
@ -5625,7 +5680,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_JETFLAME
-1, // doomednum
S_JETFLAME1, // spawnstate
S_JETFLAME, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
@ -5646,7 +5701,61 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
DMG_FIRE, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_PAIN|MF_FIRE, // flags
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_EGGROBO1
1127, // doomednum
S_EGGROBO1_STND,// spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_s3ka0, // seesound
8, // reactiontime
sfx_bsnipe, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_EGGROBO1_BSLAP1, // meleestate
S_NULL, // missilestate
S_EGGROBO1_PISSED, // deathstate
S_NULL, // xdeathstate
sfx_s3ka0, // deathsound
12*FRACUNIT, // speed
20*FRACUNIT, // radius
72*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
S_NULL // raisestate
},
{ // MT_EGGROBOJET
-1, // doomednum
S_EGGROBOJET, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
1, // speed
10*FRACUNIT, // radius
28*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
@ -5673,7 +5782,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
3, // damage
sfx_boingf, // activesound
MF_SPECIAL|MF_BOSS|MF_SHOOTABLE, // flags
MF_SPECIAL|MF_BOSS|MF_SHOOTABLE|MF_GRENADEBOUNCE, // flags
S_NULL // raisestate
},
@ -6251,13 +6360,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_METALSONIC_DASH, // seestate
sfx_s3k54, // seesound
0, // reactiontime
sfx_trpowr, // attacksound
sfx_bechrg, // attacksound
S_METALSONIC_PAIN, // painstate
S_METALSONIC_VECTOR,// painchance
sfx_dmpain, // painsound
S_METALSONIC_BADBOUNCE, // meleestate
S_METALSONIC_SHOOT, // missilestate
S_METALSONIC_DEATH, // deathstate
S_METALSONIC_DEATH1,// deathstate
S_METALSONIC_FLEE1, // xdeathstate
sfx_s3k6e, // deathsound
MT_ENERGYBALL, // speed
@ -6289,7 +6398,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // deathsound
0, // speed
32*FRACUNIT, // radius
64*FRACUNIT, // height
52*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
@ -7383,7 +7492,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // painstate
0, // painchance
sfx_s3k64, // painsound
S_NULL, // meleestate
S_WALLSPIKE4, // meleestate
S_NULL, // missilestate
S_WALLSPIKED1, // deathstate
S_WALLSPIKED2, // xdeathstate
@ -9086,7 +9195,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_MINE_BOOM1, // deathstate
S_XPLD1, // deathstate
S_NULL, // xdeathstate
sfx_cybdth, // deathsound
20*FRACUNIT, // speed
@ -9113,7 +9222,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_MINE_BOOM1, // deathstate
S_XPLD1, // deathstate
S_NULL, // xdeathstate
sfx_cybdth, // deathsound
20*FRACUNIT, // speed
@ -9132,7 +9241,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_ENERGYBALL1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_s3k54, // seesound
sfx_bexpld, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
@ -16113,7 +16222,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
-24*FRACUNIT, // speed
-72*FRACUNIT, // speed
1*FRACUNIT, // radius
8*FRACUNIT, // height
0, // display offset
@ -16529,6 +16638,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_LOCKONINF
1126, // doomednum
S_INVISIBLE, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
8, // speed
16*FRACUNIT, // radius
32*FRACUNIT, // height
111, // display offset
16, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_TAG
-1, // doomednum
S_TTAG, // spawnstate
@ -16915,6 +17051,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_LHRT
-1, // doomednum
S_LHRT, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_SPRK1, // deathstate
S_SPRK1, // xdeathstate
sfx_None, // deathsound
60*FRACUNIT, // speed
16*FRACUNIT, // radius
16*FRACUNIT, // height
0, // display offset
0, // mass
1, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_MISSILE, // flags
S_NULL // raisestate
},
{ // MT_REDRING
-1, // doomednum
S_RRNG1, // spawnstate
@ -19479,7 +19642,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
sfx_wbreak, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_RUNSPAWNFUNC|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
S_NULL // raisestate
},
@ -19970,6 +20133,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_BRICKDEBRIS
-1, // doomednum
S_BRICKDEBRIS, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
16*FRACUNIT, // radius
16*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_RUNSPAWNFUNC|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
S_NULL // raisestate
},
#ifdef SEENAMES
{ // MT_NAMECHECK
-1, // doomednum

View file

@ -335,6 +335,7 @@ typedef enum sprite
// Boss 4 (Castle Eggman)
SPR_EGGP,
SPR_EFIR, // Boss 4 jet flame
SPR_EGR1, // Boss 4 Spectator Eggrobo
// Boss 5 (Arid Canyon)
SPR_FANG, // replaces EGGQ
@ -627,6 +628,7 @@ typedef enum sprite
SPR_GFLG, // Got Flag sign
SPR_CORK,
SPR_LHRT,
// Ring Weapons
SPR_RRNG, // Red Ring
@ -720,6 +722,9 @@ typedef enum sprite
SPR_ROIO,
SPR_ROIP,
// Bricks
SPR_BRIC,
// Gravity Well Objects
SPR_GWLG,
SPR_GWLR,
@ -1421,6 +1426,11 @@ typedef enum state
// Boss 3
S_EGGMOBILE3_STND,
S_EGGMOBILE3_LAUGH1,
S_EGGMOBILE3_LAUGH2,
S_EGGMOBILE3_LAUGH3,
S_EGGMOBILE3_LAUGH4,
S_EGGMOBILE3_LAUGH5,
S_EGGMOBILE3_ATK1,
S_EGGMOBILE3_ATK2,
S_EGGMOBILE3_ATK3A,
@ -1429,11 +1439,6 @@ typedef enum state
S_EGGMOBILE3_ATK3D,
S_EGGMOBILE3_ATK4,
S_EGGMOBILE3_ATK5,
S_EGGMOBILE3_LAUGH1,
S_EGGMOBILE3_LAUGH2,
S_EGGMOBILE3_LAUGH3,
S_EGGMOBILE3_LAUGH4,
S_EGGMOBILE3_LAUGH5,
S_EGGMOBILE3_LAUGH6,
S_EGGMOBILE3_LAUGH7,
S_EGGMOBILE3_LAUGH8,
@ -1486,8 +1491,8 @@ typedef enum state
S_FAKEMOBILE_ATK3B,
S_FAKEMOBILE_ATK3C,
S_FAKEMOBILE_ATK3D,
S_FAKEMOBILE_ATK4,
S_FAKEMOBILE_ATK5,
S_FAKEMOBILE_DIE1,
S_FAKEMOBILE_DIE2,
// Boss 4
S_EGGMOBILE4_STND,
@ -1505,15 +1510,8 @@ typedef enum state
S_EGGMOBILE4_RATK6,
S_EGGMOBILE4_RAISE1,
S_EGGMOBILE4_RAISE2,
S_EGGMOBILE4_RAISE3,
S_EGGMOBILE4_RAISE4,
S_EGGMOBILE4_RAISE5,
S_EGGMOBILE4_RAISE6,
S_EGGMOBILE4_RAISE7,
S_EGGMOBILE4_RAISE8,
S_EGGMOBILE4_RAISE9,
S_EGGMOBILE4_RAISE10,
S_EGGMOBILE4_PAIN,
S_EGGMOBILE4_PAIN1,
S_EGGMOBILE4_PAIN2,
S_EGGMOBILE4_DIE1,
S_EGGMOBILE4_DIE2,
S_EGGMOBILE4_DIE3,
@ -1531,10 +1529,21 @@ typedef enum state
S_EGGMOBILE4_FLEE1,
S_EGGMOBILE4_FLEE2,
S_EGGMOBILE4_MACE,
S_EGGMOBILE4_MACE_DIE1,
S_EGGMOBILE4_MACE_DIE2,
S_EGGMOBILE4_MACE_DIE3,
// Boss 4 jet flame
S_JETFLAME1,
S_JETFLAME2,
S_JETFLAME,
// Boss 4 Spectator Eggrobo
S_EGGROBO1_STND,
S_EGGROBO1_BSLAP1,
S_EGGROBO1_BSLAP2,
S_EGGROBO1_PISSED,
// Boss 4 Spectator Eggrobo jet flame
S_EGGROBOJET,
// Boss 5
S_FANG_IDLE1,
@ -1887,7 +1896,10 @@ typedef enum state
S_METALSONIC_BADBOUNCE,
S_METALSONIC_SHOOT,
S_METALSONIC_PAIN,
S_METALSONIC_DEATH,
S_METALSONIC_DEATH1,
S_METALSONIC_DEATH2,
S_METALSONIC_DEATH3,
S_METALSONIC_DEATH4,
S_METALSONIC_FLEE1,
S_METALSONIC_FLEE2,
S_METALSONIC_FLEE3,
@ -2925,6 +2937,12 @@ typedef enum state
S_PITY4,
S_PITY5,
S_PITY6,
S_PITY7,
S_PITY8,
S_PITY9,
S_PITY10,
S_PITY11,
S_PITY12,
S_FIRS1,
S_FIRS2,
@ -3409,6 +3427,12 @@ typedef enum state
S_LOCKON1,
S_LOCKON2,
S_LOCKON3,
S_LOCKON4,
S_LOCKONINF1,
S_LOCKONINF2,
S_LOCKONINF3,
S_LOCKONINF4,
// Tag Sign
S_TTAG,
@ -3417,6 +3441,7 @@ typedef enum state
S_GOTFLAG,
S_CORK,
S_LHRT,
// Red Ring
S_RRNG1,
@ -3923,6 +3948,9 @@ typedef enum state
S_ROCKCRUMBLEO,
S_ROCKCRUMBLEP,
// Bricks
S_BRICKDEBRIS,
#ifdef SEENAMES
S_NAMECHECK,
#endif
@ -4026,11 +4054,14 @@ typedef enum mobj_type
MT_EGGMOBILE3,
MT_PROPELLER,
MT_FAKEMOBILE,
MT_SHOCK,
// Boss 4
MT_EGGMOBILE4,
MT_EGGMOBILE4_MACE,
MT_JETFLAME,
MT_EGGROBO1,
MT_EGGROBO1JET,
// Boss 5
MT_FANG,
@ -4507,6 +4538,7 @@ typedef enum mobj_type
MT_DROWNNUMBERS, // Drowning Timer
MT_GOTEMERALD, // Chaos Emerald (intangible)
MT_LOCKON, // Target
MT_LOCKONINF, // In-level Target
MT_TAG, // Tag Sign
MT_GOTFLAG, // Got Flag sign
@ -4524,6 +4556,7 @@ typedef enum mobj_type
MT_MACHINEAMBIENCE,
MT_CORK,
MT_LHRT,
// Ring Weapons
MT_REDRING,
@ -4657,6 +4690,9 @@ typedef enum mobj_type
MT_ROCKCRUMBLE15,
MT_ROCKCRUMBLE16,
// Bricks
MT_BRICKDEBRIS,
#ifdef SEENAMES
MT_NAMECHECK,
#endif

View file

@ -539,7 +539,8 @@ static int lib_pSpawnLockOn(lua_State *L)
if (P_IsLocalPlayer(player)) // Only display it on your own view.
{
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
visual->target = lockon;
P_SetTarget(&visual->target, lockon);
visual->flags2 |= MF2_DONTDRAW;
P_SetMobjStateNF(visual, state);
}
return 0;
@ -951,6 +952,21 @@ static int lib_pResetPlayer(lua_State *L)
return 0;
}
static int lib_pPlayerCanDamage(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
NOHUD // was hud safe but then i added a lua hook
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_PlayerCanDamage(player, thing));
return 1;
}
static int lib_pIsObjectInGoop(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@ -1219,8 +1235,8 @@ static int lib_pHomingAttack(lua_State *L)
INLEVEL
if (!source || !enemy)
return LUA_ErrInvalid(L, "mobj_t");
P_HomingAttack(source, enemy);
return 0;
lua_pushboolean(L, P_HomingAttack(source, enemy));
return 1;
}
static int lib_pSuperReady(lua_State *L)
@ -2774,6 +2790,7 @@ static luaL_Reg lib[] = {
{"P_PlayerInPain",lib_pPlayerInPain},
{"P_DoPlayerPain",lib_pDoPlayerPain},
{"P_ResetPlayer",lib_pResetPlayer},
{"P_PlayerCanDamage",lib_pPlayerCanDamage},
{"P_IsObjectInGoop",lib_pIsObjectInGoop},
{"P_IsObjectOnGround",lib_pIsObjectOnGround},
{"P_InSpaceSector",lib_pInSpaceSector},

View file

@ -54,10 +54,12 @@ static UINT8 lib_searchBlockmap_Objects(lua_State *L, INT32 x, INT32 y, mobj_t *
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

View file

@ -48,6 +48,7 @@ enum hook {
hook_MobjMoveBlocked,
hook_MapThingSpawn,
hook_FollowMobj,
hook_PlayerCanDamage,
hook_PlayerQuit,
hook_MAX // last hook
@ -87,7 +88,8 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8
#define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities
#define LUAh_MobjMoveBlocked(mo) LUAh_MobjHook(mo, hook_MobjMoveBlocked) // Hook for P_XYMovement (when movement is blocked)
boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnMapThing by mobj type
boolean LUAh_FollowMobj(player_t *player, mobj_t *mo); // Hook for P_PlayerAfterThink Smiles mobj-following
boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj); // Hook for P_PlayerAfterThink Smiles mobj-following
UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj); // Hook for P_PlayerCanDamage
void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting
#endif

View file

@ -59,6 +59,7 @@ const char *const hookNames[hook_MAX+1] = {
"MobjMoveBlocked",
"MapThingSpawn",
"FollowMobj",
"PlayerCanDamage",
"PlayerQuit",
NULL
};
@ -200,6 +201,7 @@ static int lib_addHook(lua_State *L)
case hook_JumpSpinSpecial:
case hook_PlayerSpawn:
case hook_FollowMobj:
case hook_PlayerCanDamage:
case hook_ShieldSpawn:
case hook_ShieldSpecial:
lastp = &playerhooks;
@ -250,8 +252,10 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which)
// Look for all generic mobj hooks
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
if (hookp->type == which)
{
if (hookp->type != which)
continue;
if (lua_gettop(gL) == 0)
LUA_PushUserdata(gL, mo, META_MOBJ);
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
@ -270,8 +274,10 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which)
}
for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next)
if (hookp->type == which)
{
if (hookp->type != which)
continue;
if (lua_gettop(gL) == 0)
LUA_PushUserdata(gL, mo, META_MOBJ);
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
@ -303,8 +309,10 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which)
lua_settop(gL, 0);
for (hookp = playerhooks; hookp; hookp = hookp->next)
if (hookp->type == which)
{
if (hookp->type != which)
continue;
if (lua_gettop(gL) == 0)
LUA_PushUserdata(gL, plr, META_PLAYER);
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
@ -337,8 +345,10 @@ void LUAh_MapChange(INT16 mapnumber)
lua_pushinteger(gL, mapnumber);
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_MapChange)
{
if (hookp->type != hook_MapChange)
continue;
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -2);
@ -359,8 +369,10 @@ void LUAh_MapLoad(void)
lua_pushinteger(gL, gamemap);
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_MapLoad)
{
if (hookp->type != hook_MapLoad)
continue;
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -2);
@ -381,8 +393,10 @@ void LUAh_PlayerJoin(int playernum)
lua_pushinteger(gL, playernum);
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_PlayerJoin)
{
if (hookp->type != hook_PlayerJoin)
continue;
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -2);
@ -400,8 +414,10 @@ void LUAh_ThinkFrame(void)
return;
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_ThinkFrame)
{
if (hookp->type != hook_ThinkFrame)
continue;
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
if (lua_pcall(gL, 0, 0, 0)) {
@ -427,8 +443,10 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
// Look for all generic mobj collision hooks
for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next)
if (hookp->type == which)
{
if (hookp->type != which)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, thing1, META_MOBJ);
@ -456,8 +474,10 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which)
}
for (hookp = mobjcollidehooks[thing1->type]; hookp; hookp = hookp->next)
if (hookp->type == which)
{
if (hookp->type != which)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, thing1, META_MOBJ);
@ -557,8 +577,10 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
// Look for all generic touch special hooks
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
if (hookp->type == hook_TouchSpecial)
{
if (hookp->type != hook_TouchSpecial)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, special, META_MOBJ);
@ -581,8 +603,10 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher)
}
for (hookp = mobjhooks[special->type]; hookp; hookp = hookp->next)
if (hookp->type == hook_TouchSpecial)
{
if (hookp->type != hook_TouchSpecial)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, special, META_MOBJ);
@ -622,8 +646,10 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
// Look for all generic should damage hooks
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
if (hookp->type == hook_ShouldDamage)
{
if (hookp->type != hook_ShouldDamage)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, target, META_MOBJ);
@ -655,8 +681,9 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
}
for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
if (hookp->type == hook_ShouldDamage)
{
if (hookp->type != hook_ShouldDamage)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, target, META_MOBJ);
@ -707,8 +734,10 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
// Look for all generic mobj damage hooks
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
if (hookp->type == hook_MobjDamage)
{
if (hookp->type != hook_MobjDamage)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, target, META_MOBJ);
@ -735,8 +764,10 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32
}
for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
if (hookp->type == hook_MobjDamage)
{
if (hookp->type != hook_MobjDamage)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, target, META_MOBJ);
@ -782,8 +813,10 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8
// Look for all generic mobj death hooks
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
if (hookp->type == hook_MobjDeath)
{
if (hookp->type != hook_MobjDeath)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, target, META_MOBJ);
@ -808,8 +841,10 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8
}
for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next)
if (hookp->type == hook_MobjDeath)
{
if (hookp->type != hook_MobjDeath)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, target, META_MOBJ);
@ -850,8 +885,10 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd)
lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_BotTiccmd)
{
if (hookp->type != hook_BotTiccmd)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, bot, META_PLAYER);
@ -888,9 +925,11 @@ boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd)
lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_BotAI
&& (hookp->s.skinname == NULL || !strcmp(hookp->s.skinname, ((skin_t*)tails->skin)->name)))
{
if (hookp->type != hook_BotAI
|| (hookp->s.skinname && strcmp(hookp->s.skinname, ((skin_t*)tails->skin)->name)))
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, sonic, META_MOBJ);
@ -949,8 +988,10 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector)
lua_settop(gL, 0);
for (hookp = linedefexecutorhooks; hookp; hookp = hookp->next)
if (!strcmp(hookp->s.funcname, line->text))
{
if (strcmp(hookp->s.funcname, line->text))
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, line, META_LINE);
@ -981,8 +1022,10 @@ boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg)
lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_PlayerMsg)
{
if (hookp->type != hook_PlayerMsg)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player
@ -1035,9 +1078,11 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8
lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_HurtMsg
&& (hookp->s.mt == MT_NULL || (inflictor && hookp->s.mt == inflictor->type)))
{
if (hookp->type != hook_HurtMsg
|| (hookp->s.mt && !(inflictor && hookp->s.mt == inflictor->type)))
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, player, META_PLAYER);
@ -1084,8 +1129,10 @@ void LUAh_NetArchiveHook(lua_CFunction archFunc)
// stack: tables, archFunc
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_NetVars)
{
if (hookp->type != hook_NetVars)
continue;
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -2); // archFunc
@ -1107,8 +1154,10 @@ boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing)
// Look for all generic mobj map thing spawn hooks
for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next)
if (hookp->type == hook_MapThingSpawn)
{
if (hookp->type != hook_MapThingSpawn)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, mo, META_MOBJ);
@ -1131,8 +1180,10 @@ boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing)
}
for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next)
if (hookp->type == hook_MapThingSpawn)
{
if (hookp->type != hook_MapThingSpawn)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, mo, META_MOBJ);
@ -1169,8 +1220,10 @@ boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj)
lua_settop(gL, 0);
for (hookp = playerhooks; hookp; hookp = hookp->next)
if (hookp->type == hook_FollowMobj)
{
if (hookp->type != hook_FollowMobj)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, player, META_PLAYER);
@ -1196,6 +1249,51 @@ boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj)
return hooked;
}
// Hook for P_PlayerCanDamage
UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj)
{
hook_p hookp;
UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no.
if (!gL || !(hooksAvailable[hook_PlayerCanDamage/8] & (1<<(hook_PlayerCanDamage%8))))
return 0;
lua_settop(gL, 0);
for (hookp = playerhooks; hookp; hookp = hookp->next)
{
if (hookp->type != hook_PlayerCanDamage)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, player, META_PLAYER);
LUA_PushUserdata(gL, mobj, META_MOBJ);
}
lua_pushfstring(gL, FMT_HOOKID, hookp->id);
lua_gettable(gL, LUA_REGISTRYINDEX);
lua_pushvalue(gL, -3);
lua_pushvalue(gL, -3);
if (lua_pcall(gL, 2, 1, 0)) {
if (!hookp->error || cv_debug & DBG_LUA)
CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1));
lua_pop(gL, 1);
hookp->error = true;
continue;
}
if (!lua_isnil(gL, -1))
{ // if nil, leave shouldCollide = 0.
if (lua_toboolean(gL, -1))
shouldCollide = 1; // Force yes
else
shouldCollide = 2; // Force no
}
lua_pop(gL, 1);
}
lua_settop(gL, 0);
return shouldCollide;
}
void LUAh_PlayerQuit(player_t *plr, int reason)
{
hook_p hookp;
@ -1205,8 +1303,10 @@ void LUAh_PlayerQuit(player_t *plr, int reason)
lua_settop(gL, 0);
for (hookp = roothook; hookp; hookp = hookp->next)
if (hookp->type == hook_PlayerQuit)
{
if (hookp->type != hook_PlayerQuit)
continue;
if (lua_gettop(gL) == 0)
{
LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit

View file

@ -670,8 +670,8 @@ static int libd_getColormap(lua_State *L)
else if (lua_type(L, 1) == LUA_TNUMBER) // skin number
{
skinnum = (INT32)luaL_checkinteger(L, 1);
if (skinnum < TC_ALLWHITE || skinnum >= MAXSKINS)
return luaL_error(L, "skin number %d is out of range (%d - %d)", skinnum, TC_ALLWHITE, MAXSKINS-1);
if (skinnum < TC_BLINK || skinnum >= MAXSKINS)
return luaL_error(L, "skin number %d is out of range (%d - %d)", skinnum, TC_BLINK, MAXSKINS-1);
}
else // skin name
{

View file

@ -292,8 +292,6 @@ enum slope_e {
slope_normal,
slope_zangle,
slope_xydirection,
slope_sourceline,
slope_refpos,
slope_flags
};
@ -305,8 +303,6 @@ static const char *const slope_opt[] = {
"normal",
"zangle",
"xydirection",
"sourceline",
"refpos",
"flags",
NULL};
@ -1831,12 +1827,6 @@ static int slope_get(lua_State *L)
case slope_xydirection: // xydirection
lua_pushangle(L, slope->xydirection);
return 1;
case slope_sourceline: // source linedef
LUA_PushUserdata(L, slope->sourceline, META_LINE);
return 1;
case slope_refpos: // refpos
lua_pushinteger(L, slope->refpos);
return 1;
case slope_flags: // flags
lua_pushinteger(L, slope->flags);
return 1;
@ -1858,11 +1848,9 @@ static int slope_set(lua_State *L)
switch(field) // todo: reorganize this shit
{
case slope_valid: // valid
case slope_sourceline: // sourceline
case slope_d: // d
case slope_flags: // flags
case slope_normal: // normal
case slope_refpos: // refpos
default:
return luaL_error(L, "pslope_t field " LUA_QS " cannot be set.", slope_opt[field]);
case slope_o: { // o

View file

@ -83,12 +83,11 @@ enum mobj_e {
mobj_extravalue1,
mobj_extravalue2,
mobj_cusval,
#ifdef ESLOPE
mobj_cvmem,
mobj_standingslope
#else
mobj_cvmem
#ifdef ESLOPE
mobj_standingslope,
#endif
mobj_colorized
};
static const char *const mobj_opt[] = {
@ -154,6 +153,7 @@ static const char *const mobj_opt[] = {
#ifdef ESLOPE
"standingslope",
#endif
"colorized",
NULL};
#define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field])
@ -274,10 +274,19 @@ static int mobj_get(lua_State *L)
// bprev -- same deal as sprev above, but for the blockmap.
return UNIMPLEMENTED;
case mobj_hnext:
if (mo->hnext && P_MobjWasRemoved(mo->hnext))
{ // don't put invalid mobj back into Lua.
P_SetTarget(&mo->hnext, NULL);
return 0;
}
LUA_PushUserdata(L, mo->hnext, META_MOBJ);
break;
case mobj_hprev:
// implimented differently from sprev and bprev because SSNTails.
if (mo->hprev && P_MobjWasRemoved(mo->hprev))
{ // don't put invalid mobj back into Lua.
P_SetTarget(&mo->hprev, NULL);
return 0;
}
LUA_PushUserdata(L, mo->hprev, META_MOBJ);
break;
case mobj_type:
@ -371,6 +380,9 @@ static int mobj_get(lua_State *L)
LUA_PushUserdata(L, mo->standingslope, META_SLOPE);
break;
#endif
case mobj_colorized:
lua_pushboolean(L, mo->colorized);
break;
default: // extra custom variables in Lua memory
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1));
@ -692,6 +704,9 @@ static int mobj_set(lua_State *L)
case mobj_standingslope:
return NOSET;
#endif
case mobj_colorized:
mo->colorized = luaL_checkboolean(L, 3);
break;
default:
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1));

View file

@ -476,7 +476,12 @@ static int player_set(lua_State *L)
else if (fastcmp(field,"followitem"))
plr->followitem = luaL_checkinteger(L, 3);
else if (fastcmp(field,"followmobj"))
P_SetTarget(&plr->followmobj, *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)));
{
mobj_t *mo = NULL;
if (!lua_isnil(L, 3))
mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
P_SetTarget(&plr->followmobj, mo);
}
else if (fastcmp(field,"actionspd"))
plr->actionspd = (INT32)luaL_checkinteger(L, 3);
else if (fastcmp(field,"mindash"))
@ -560,9 +565,19 @@ static int player_set(lua_State *L)
else if (fastcmp(field,"old_angle_pos"))
plr->old_angle_pos = luaL_checkangle(L, 3);
else if (fastcmp(field,"axis1"))
P_SetTarget(&plr->axis1, *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)));
{
mobj_t *mo = NULL;
if (!lua_isnil(L, 3))
mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
P_SetTarget(&plr->axis1, mo);
}
else if (fastcmp(field,"axis2"))
P_SetTarget(&plr->axis2, *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ)));
{
mobj_t *mo = NULL;
if (!lua_isnil(L, 3))
mo = *((mobj_t **)luaL_checkudata(L, 3, META_MOBJ));
P_SetTarget(&plr->axis2, mo);
}
else if (fastcmp(field,"bumpertime"))
plr->bumpertime = (tic_t)luaL_checkinteger(L, 3);
else if (fastcmp(field,"flyangle"))

View file

@ -420,8 +420,8 @@ void LUA_InvalidateLevel(void)
ffloor_t *rover = NULL;
if (!gL)
return;
for (th = thinkercap.next; th && th != &thinkercap; th = th->next)
for (i = 0; i < NUM_THINKERLISTS; i++)
for (th = thlist[i].next; th && th != &thlist[i]; th = th->next)
LUA_InvalidateUserdata(th);
LUA_InvalidateMapthings();
@ -1127,13 +1127,16 @@ void LUA_Archive(void)
ArchiveExtVars(&players[i], "player");
}
for (th = thinkercap.next; th != &thinkercap; th = th->next)
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
// archive function will determine when to skip mobjs,
// and write mobjnum in otherwise.
ArchiveExtVars(th, "mobj");
}
WRITEUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum.
LUAh_NetArchiveHook(NetArchive); // call the NetArchive hook in archive mode
@ -1161,10 +1164,14 @@ void LUA_UnArchive(void)
do {
mobjnum = READUINT32(save_p); // read a mobjnum
for (th = thinkercap.next; th != &thinkercap; th = th->next)
if (th->function.acp1 == (actionf_p1)P_MobjThinker
&& ((mobj_t *)th)->mobjnum == mobjnum) // find matching mobj
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj
continue;
UnArchiveExtVars(th); // apply variables
}
} while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker.
LUAh_NetArchiveHook(NetUnArchive); // call the NetArchive hook in unarchive mode

View file

@ -18,7 +18,7 @@
#define META_ITERATIONSTATE "iteration state"
static const char *const iter_opt[] = {
/*static const char *const iter_opt[] = {
"all",
"mobj",
NULL};
@ -26,7 +26,7 @@ static const char *const iter_opt[] = {
static const actionf_p1 iter_funcs[] = {
NULL,
(actionf_p1)P_MobjThinker
};
};*/
struct iterationState {
actionf_p1 filter;
@ -64,7 +64,7 @@ static int lib_iterateThinkers(lua_State *L)
lua_settop(L, 2);
if (lua_isnil(L, 2))
th = &thinkercap;
th = &thlist[THINK_MOBJ];
else if (lua_isuserdata(L, 2))
{
if (lua_islightuserdata(L, 2))
@ -94,11 +94,11 @@ static int lib_iterateThinkers(lua_State *L)
if (!next)
return luaL_error(L, "next thinker invalidated during iteration");
for (; next != &thinkercap; next = next->next)
for (; next != &thlist[THINK_MOBJ]; next = next->next)
if (!it->filter || next->function.acp1 == it->filter)
{
push_thinker(next);
if (next->next != &thinkercap)
if (next->next != &thlist[THINK_MOBJ])
{
push_thinker(next->next);
it->next = luaL_ref(L, LUA_REGISTRYINDEX);
@ -120,7 +120,7 @@ static int lib_startIterate(lua_State *L)
luaL_getmetatable(L, META_ITERATIONSTATE);
lua_setmetatable(L, -2);
it->filter = iter_funcs[luaL_checkoption(L, 1, "mobj", iter_opt)];
it->filter = (actionf_p1)P_MobjThinker; //iter_funcs[luaL_checkoption(L, 1, "mobj", iter_opt)];
it->next = LUA_REFNIL;
return 2;
}
@ -138,7 +138,7 @@ int LUA_ThinkerLib(lua_State *L)
lua_pushcfunction(L, lib_iterateThinkers);
lua_pushcclosure(L, lib_startIterate, 1);
lua_setfield(L, -2, "iterate");
lua_setglobal(L, "thinkers");
lua_setglobal(L, "mobjs");
return 0;
}

View file

@ -577,9 +577,9 @@ void Command_Teleport_f(void)
INT32 starpostmax = 0;
intz = starpostpath; // variable reuse - counting down for selection purposes
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -600,7 +600,7 @@ void Command_Teleport_f(void)
break;
}
if (th == &thinkercap)
if (th == &thlist[THINK_MOBJ])
{
if (intz == starpostpath)
CONS_Alert(CONS_NOTICE, M_GetText("No starpost of position %d found (%d max).\n"), starpostnum, starpostmax);
@ -1069,14 +1069,15 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
thinker_t *th;
mobj_t *mo;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)th;
// get offset from mt, which points to old mapthings, then add new location
if (mo->spawnpoint)
if (!mo->spawnpoint)
continue;
mo->spawnpoint = (mo->spawnpoint - mt) + mapthings;
}
}

View file

@ -2973,8 +2973,9 @@ boolean M_Responder(event_t *ev)
return true;
M_StartControlPanel();
M_Options(0);
currentMenu = &OP_SoundOptionsDef;
itemOn = 0;
// Uncomment the below if you want the menu to reset to the top each time like before. M_SetupNextMenu will fix it automatically.
//OP_SoundOptionsDef.lastOn = 0;
M_SetupNextMenu(&OP_SoundOptionsDef);
return true;
case KEY_F5: // Video Mode

View file

@ -409,7 +409,7 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type)
// new door thinker
rtn = 1;
ceiling = Z_Calloc(sizeof (*ceiling), PU_LEVSPEC, NULL);
P_AddThinker(&ceiling->thinker);
P_AddThinker(THINK_MAIN, &ceiling->thinker);
sec->ceilingdata = ceiling;
ceiling->thinker.function.acp1 = (actionf_p1)T_MoveCeiling;
ceiling->sector = sec;
@ -629,7 +629,7 @@ INT32 EV_DoCrush(line_t *line, ceiling_e type)
// new door thinker
rtn = 1;
ceiling = Z_Calloc(sizeof (*ceiling), PU_LEVSPEC, NULL);
P_AddThinker(&ceiling->thinker);
P_AddThinker(THINK_MAIN, &ceiling->thinker);
sec->ceilingdata = ceiling;
ceiling->thinker.function.acp1 = (actionf_p1)T_CrushCeiling;
ceiling->sector = sec;

View file

@ -1391,7 +1391,7 @@ void A_StatueBurst(mobj_t *actor)
return;
new->angle = actor->angle;
new->target = actor->target;
P_SetTarget(&new->target, actor->target);
if (locvar2)
P_SetMobjState(new, (statenum_t)locvar2);
S_StartSound(new, new->info->attacksound);
@ -2155,7 +2155,7 @@ void A_CrushclawLaunch(mobj_t *actor)
for (i = 0; (i < CSEGS); i++)
{
mobj_t *newchain = P_SpawnMobjFromMobj(actor, 0, 0, 0, actor->info->raisestate);
prevchain->target = newchain;
P_SetTarget(&prevchain->target, newchain);
prevchain = newchain;
}
actor->target->angle = R_PointToAngle2(actor->target->x, actor->target->y, crab->target->x, crab->target->y);
@ -2348,7 +2348,7 @@ void A_VultureHover(mobj_t *actor)
fixed_t targetz;
fixed_t distdif;
fixed_t memz = actor->z;
INT8 i;
SINT8 i;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_VultureHover", actor))
@ -2411,6 +2411,8 @@ void A_VultureBlast(mobj_t *actor)
{
mobj_t *dust;
UINT8 i;
angle_t faa;
fixed_t faacos, faasin;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_VultureBlast", actor))
@ -2419,18 +2421,21 @@ void A_VultureBlast(mobj_t *actor)
S_StartSound(actor, actor->info->attacksound);
faa = (actor->angle >> ANGLETOFINESHIFT) & FINEMASK;
faacos = FINECOSINE(faa);
faasin = FINESINE(faa);
for (i = 0; i <= 7; i++)
{
angle_t fa = ((i*(angle_t)ANGLE_45) >> ANGLETOFINESHIFT) & FINEMASK;
angle_t faa = (actor->angle >> ANGLETOFINESHIFT) & FINEMASK;
dust = P_SpawnMobj(actor->x + 48*FixedMul(FINECOSINE(fa), -FINESINE(faa)), actor->y + 48*FixedMul(FINECOSINE(fa), FINECOSINE(faa)), actor->z + actor->height/2 + 48*FINESINE(fa), MT_PARTICLE);
dust = P_SpawnMobj(actor->x + 48*FixedMul(FINECOSINE(fa), -faasin), actor->y + 48*FixedMul(FINECOSINE(fa), faacos), actor->z + actor->height/2 + 48*FINESINE(fa), MT_PARTICLE);
P_SetScale(dust, 4*FRACUNIT);
dust->destscale = FRACUNIT;
dust->scalespeed = 4*FRACUNIT/TICRATE;
dust->fuse = TICRATE;
dust->momx = FixedMul(FINECOSINE(fa), -FINESINE(faa))*3;
dust->momy = FixedMul(FINECOSINE(fa), FINECOSINE(faa))*3;
dust->momx = FixedMul(FINECOSINE(fa), -faasin)*3;
dust->momy = FixedMul(FINECOSINE(fa), faacos)*3;
dust->momz = FINESINE(fa)*6;
}
}
@ -2858,6 +2863,7 @@ void A_BossFireShot(mobj_t *actor)
fixed_t x, y, z;
INT32 locvar1 = var1;
INT32 locvar2 = var2;
mobj_t *missile;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_BossFireShot", actor))
@ -2925,7 +2931,10 @@ void A_BossFireShot(mobj_t *actor)
break;
}
P_SpawnXYZMissile(actor, actor->target, locvar1, x, y, z);
missile = P_SpawnXYZMissile(actor, actor->target, locvar1, x, y, z);
if (missile && actor->tracer && (actor->tracer->flags & MF_BOSS)) // Don't harm your papa.
P_SetTarget(&missile->target, actor->tracer);
}
// Function: A_Boss7FireMissiles
@ -3079,7 +3088,7 @@ void A_Boss1Laser(mobj_t *actor)
if (z - floorz < mobjinfo[MT_EGGMOBILE_FIRE].height>>1)
{
point = P_SpawnMobj(x, y, floorz+1, MT_EGGMOBILE_FIRE);
point->target = actor;
P_SetTarget(&point->target, actor);
point->destscale = 3*FRACUNIT;
point->scalespeed = FRACUNIT>>2;
point->fuse = TICRATE;
@ -3154,22 +3163,36 @@ void A_FocusTarget(mobj_t *actor)
// Description: Reverse arms direction.
//
// var1 = sfx to play
// var2 = unused
// var2 = sfx to play in pinch
//
void A_Boss4Reverse(mobj_t *actor)
{
sfxenum_t locvar1 = (sfxenum_t)var1;
sfxenum_t locvar2 = (sfxenum_t)var2;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_Boss4Reverse", actor))
return;
#endif
S_StartSound(NULL, locvar1);
actor->reactiontime = 0;
if (actor->movedir < 3)
{
S_StartSound(NULL, locvar1);
if (actor->movedir == 1)
actor->movedir = 2;
else
actor->movedir = 1;
}
else
{
S_StartSound(NULL, locvar2);
if (actor->movedir == 4)
actor->movedir = 5;
else
actor->movedir = 4;
actor->angle += ANGLE_180;
actor->movefactor = -actor->movefactor;
}
}
// Function: A_Boss4SpeedUp
//
@ -3465,9 +3488,11 @@ void A_1upThinker(mobj_t *actor)
if (closestplayer == -1 || skins[players[closestplayer].skin].sprites[SPR2_LIFE].numframes == 0)
{ // Closest player not found (no players in game?? may be empty dedicated server!), or does not have correct sprite.
if (actor->tracer) {
P_RemoveMobj(actor->tracer);
actor->tracer = NULL;
if (actor->tracer)
{
mobj_t *tracer = actor->tracer;
P_SetTarget(&actor->tracer, NULL);
P_RemoveMobj(tracer);
}
return;
}
@ -3761,9 +3786,9 @@ void A_BossDeath(mobj_t *mo)
// scan the remaining thinkers to see
// if all bosses are dead
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -3862,9 +3887,9 @@ bossjustdie:
// Flee! Flee! Find a point to escape to! If none, just shoot upward!
// scan the thinkers to find the runaway point
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -6118,9 +6143,9 @@ void A_RingExplode(mobj_t *actor)
S_StartSound(actor, sfx_prloop);
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -6631,6 +6656,9 @@ void A_RecyclePowers(mobj_t *actor)
players[recv_pl].ringweapons = weapons[send_pl];
players[recv_pl].currentweapon = weaponheld[send_pl];
if (((players[recv_pl].powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (players[recv_pl].revitem == MT_LHRT || players[recv_pl].spinitem == MT_LHRT || players[recv_pl].thokitem == MT_LHRT)) // Healers can't keep their buff.
players[recv_pl].powers[pw_shield] &= SH_STACK;
P_SpawnShieldOrb(&players[recv_pl]);
if (P_IsLocalPlayer(&players[recv_pl]))
P_RestoreMusic(&players[recv_pl]);
@ -7246,7 +7274,7 @@ void A_Boss2PogoTarget(mobj_t *actor)
if (actor->info->missilestate) // spawn the pogo stick collision box
{
mobj_t *pogo = P_SpawnMobj(actor->x, actor->y, actor->z - mobjinfo[actor->info->missilestate].height, (mobjtype_t)actor->info->missilestate);
pogo->target = actor;
P_SetTarget(&pogo->target, actor);
}
actor->reactiontime = 1;
@ -7762,9 +7790,11 @@ void A_Boss3TakeDamage(mobj_t *actor)
return;
#endif
actor->movecount = var1;
actor->movefactor = -512*FRACUNIT;
/*if (actor->target && actor->target->spawnpoint)
actor->threshold = actor->target->spawnpoint->extrainfo;*/
if (actor->target && actor->target->spawnpoint)
actor->threshold = actor->target->spawnpoint->extrainfo;
}
// Function: A_Boss3Path
@ -7800,25 +7830,35 @@ void A_Boss3Path(mobj_t *actor)
return;
}
else if (actor->threshold >= 0) // Traveling mode
{
fixed_t dist = 0;
fixed_t speed;
if (!(actor->flags2 & MF2_STRONGBOX))
{
thinker_t *th;
mobj_t *mo2;
fixed_t dist, dist2;
fixed_t speed;
P_SetTarget(&actor->target, NULL);
// scan the thinkers
// to find a point that matches
// the number
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_BOSS3WAYPOINT && mo2->spawnpoint && mo2->spawnpoint->angle == actor->threshold)
{
if (mo2->type != MT_BOSS3WAYPOINT)
continue;
if (!mo2->spawnpoint)
continue;
if (mo2->spawnpoint->angle != actor->threshold)
continue;
if (mo2->spawnpoint->extrainfo != actor->cusval)
continue;
P_SetTarget(&actor->target, mo2);
break;
}
@ -7826,67 +7866,62 @@ void A_Boss3Path(mobj_t *actor)
if (!actor->target) // Should NEVER happen
{
CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy was unable to find specified waypoint: %d\n", actor->threshold);
CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy was unable to find specified waypoint: %d, %d\n", actor->threshold, actor->cusval);
return;
}
dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), actor->target->z - actor->z);
if (dist < 1)
dist = 1;
if (actor->tracer && ((actor->tracer->movedir)
|| (actor->tracer->health <= actor->tracer->info->damage)))
speed = actor->info->speed * 2;
else
speed = actor->info->speed;
if (actor->target->x == actor->x && actor->target->y == actor->y)
{
dist = P_AproxDistance(P_AproxDistance(actor->target->x - actor->x, actor->target->y - actor->y), actor->target->z + actor->movefactor - actor->z);
if (dist < 1)
dist = 1;
actor->momx = FixedMul(FixedDiv(actor->target->x - actor->x, dist), speed);
actor->momy = FixedMul(FixedDiv(actor->target->y - actor->y, dist), speed);
actor->momz = FixedMul(FixedDiv(actor->target->z - actor->z, dist), speed);
actor->momz = FixedMul(FixedDiv(actor->target->z + actor->movefactor - actor->z, dist), speed);
if (actor->momx != 0 || actor->momy != 0)
actor->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy);
}
dist2 = P_AproxDistance(P_AproxDistance(actor->target->x - (actor->x + actor->momx), actor->target->y - (actor->y + actor->momy)), actor->target->z - (actor->z + actor->momz));
if (dist2 < 1)
dist2 = 1;
if ((dist >> FRACBITS) <= (dist2 >> FRACBITS))
if (dist <= speed)
{
// If further away, set XYZ of mobj to waypoint location
P_UnsetThingPosition(actor);
actor->x = actor->target->x;
actor->y = actor->target->y;
actor->z = actor->target->z;
actor->z = actor->target->z + actor->movefactor;
actor->momx = actor->momy = actor->momz = 0;
P_SetThingPosition(actor);
if (actor->threshold == 0)
if (!actor->movefactor) // firing mode
{
P_RemoveMobj(actor); // Cycle completed. Dummy removed.
return;
}
// Set to next waypoint in sequence
if (actor->target->spawnpoint)
{
// From the center point, choose one of the five paths
if (actor->target->spawnpoint->angle == 0)
{
P_RemoveMobj(actor); // Cycle completed. Dummy removed.
return;
}
else
actor->threshold = actor->target->spawnpoint->extrainfo;
// If the deaf flag is set, go into firing mode
if (actor->target->spawnpoint->options & MTF_AMBUSH)
actor->movecount |= 2;
actor->movefactor = -512*FRACUNIT;
actor->flags2 &= ~MF2_STRONGBOX;
}
else if (!(actor->flags2 & MF2_STRONGBOX)) // just spawned or going down
{
actor->flags2 |= MF2_STRONGBOX;
actor->movefactor = -512*FRACUNIT;
}
else if (!(actor->flags2 & MF2_AMBUSH)) // just shifted tube
{
actor->flags2 |= MF2_AMBUSH;
actor->movefactor = 0;
}
else // just hit the bottom of your tube
{
P_RemoveMobj(actor); // Cycle completed. Dummy removed.
return;
}
else // This should never happen, as well
CONS_Debug(DBG_GAMELOGIC, "Error: Boss 3 Dummy waypoint has no spawnpoint associated with it.\n");
}
}
}
@ -8204,9 +8239,9 @@ void A_FindTarget(mobj_t *actor)
CONS_Debug(DBG_GAMELOGIC, "A_FindTarget called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
// scan the thinkers
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -8269,9 +8304,9 @@ void A_FindTracer(mobj_t *actor)
CONS_Debug(DBG_GAMELOGIC, "A_FindTracer called from object type %d, var1: %d, var2: %d\n", actor->type, locvar1, locvar2);
// scan the thinkers
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -8684,8 +8719,8 @@ void A_BossJetFume(mobj_t *actor)
{
fixed_t jetx, jety, jetz;
jetx = actor->x + P_ReturnThrustX(actor, actor->angle, -FixedMul(60*FRACUNIT, actor->scale));
jety = actor->y + P_ReturnThrustY(actor, actor->angle, -FixedMul(60*FRACUNIT, actor->scale));
jetx = actor->x + P_ReturnThrustX(actor, actor->angle, -60*actor->scale);
jety = actor->y + P_ReturnThrustY(actor, actor->angle, -60*actor->scale);
if (actor->eflags & MFE_VERTICALFLIP)
jetz = actor->z + actor->height - FixedMul(17*FRACUNIT + mobjinfo[MT_PROPELLER].height, actor->scale);
else
@ -8718,7 +8753,7 @@ void A_BossJetFume(mobj_t *actor)
if (actor->eflags & MFE_VERTICALFLIP)
jetz = actor->z + actor->height + FixedMul(50*FRACUNIT - mobjinfo[MT_JETFLAME].height, actor->scale);
else
jetz = actor->z - FixedMul(50*FRACUNIT, actor->scale);
jetz = actor->z - 50*actor->scale;
filler = P_SpawnMobj(actor->x, actor->y, jetz, MT_JETFLAME);
P_SetTarget(&filler->target, actor);
// Boss 4 already uses its tracer for other things
@ -8727,6 +8762,30 @@ void A_BossJetFume(mobj_t *actor)
if (actor->eflags & MFE_VERTICALFLIP)
filler->flags2 |= MF2_OBJECTFLIP;
}
else if (locvar1 == 4) // Boss 4 Spectator Eggrobo jet flame
{
fixed_t jetx, jety, jetz, movefactor = 12;
jetz = actor->z;
if (actor->eflags & MFE_VERTICALFLIP)
jetz += (actor->height - FixedMul(mobjinfo[MT_EGGROBO1JET].height, actor->scale));
while (true)
{
jetx = actor->x + P_ReturnThrustX(actor, actor->angle+ANGLE_90, movefactor*actor->scale) - P_ReturnThrustX(actor, actor->angle, 19*actor->scale);
jety = actor->y + P_ReturnThrustY(actor, actor->angle+ANGLE_90, movefactor*actor->scale) - P_ReturnThrustY(actor, actor->angle, 19*actor->scale);
filler = P_SpawnMobj(jetx, jety, jetz, MT_EGGROBO1JET);
filler->movefactor = movefactor;
P_SetTarget(&filler->target, actor);
filler->destscale = actor->scale;
P_SetScale(filler, filler->destscale);
if (actor->eflags & MFE_VERTICALFLIP)
filler->flags2 |= MF2_OBJECTFLIP;
if (movefactor <= 0)
break;
movefactor = -movefactor;
}
}
}
// Function: A_RandomState
@ -8832,9 +8891,9 @@ void A_RemoteAction(mobj_t *actor)
fixed_t dist1 = 0, dist2 = 0;
// scan the thinkers
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -9098,9 +9157,9 @@ void A_SetObjectTypeState(mobj_t *actor)
return;
#endif
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -9736,9 +9795,9 @@ void A_CheckThingCount(mobj_t *actor)
return;
#endif
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -13015,7 +13074,14 @@ static boolean PIT_TNTExplode(mobj_t *nearby)
nearby->momx = FixedMul(FixedDiv(dx, dm), explodethrust);
nearby->momy = FixedMul(FixedDiv(dy, dm), explodethrust);
nearby->momz = FixedMul(FixedDiv(dz, dm), explodethrust);
P_UnsetThingPosition(nearby);
if (sector_list)
{
P_DelSeclist(sector_list);
sector_list = NULL;
}
nearby->flags = MF_NOBLOCKMAP|MF_MISSILE;
P_SetThingPosition(nearby);
P_SetMobjState(nearby, nearby->info->missilestate);
}
}
@ -13024,9 +13090,10 @@ static boolean PIT_TNTExplode(mobj_t *nearby)
if (barrel->target == nearby)
{
mobj_t *tar = barrel->target; // temporarily store barrel's target
barrel->target = NULL;
P_SetTarget(&barrel->target, NULL);
P_DamageMobj(nearby, barrel, NULL, 1, 0);
barrel->target = tar;
if (!P_MobjWasRemoved(barrel))
P_SetTarget(&barrel->target, tar);
}
else
{
@ -13059,8 +13126,14 @@ void A_TNTExplode(mobj_t *actor)
if (LUA_CallAction("A_TNTExplode", actor))
return;
#endif
P_UnsetThingPosition(actor);
if (sector_list)
{
P_DelSeclist(sector_list);
sector_list = NULL;
}
actor->flags = MF_NOCLIP|MF_NOGRAVITY|MF_NOBLOCKMAP;
P_SetThingPosition(actor);
actor->flags2 = MF2_EXPLOSION;
if (actor->info->deathsound)
S_StartSound(actor, actor->info->deathsound);
@ -13522,7 +13595,7 @@ void A_SaloonDoorSpawn(mobj_t *actor)
door->extravalue2 = 0;
// Origin door
door->tracer = actor;
P_SetTarget(&door->tracer, actor);
//Back
door = P_SpawnMobj(x - c*d, y - s*d, z, MT_SALOONDOOR);
@ -13535,7 +13608,7 @@ void A_SaloonDoorSpawn(mobj_t *actor)
door->extravalue2 = 0;
// Origin door
door->tracer = actor;
P_SetTarget(&door->tracer, actor);
}
// Function: A_MinecartSparkThink

View file

@ -1975,27 +1975,29 @@ void T_ThwompSector(levelspecthink_t *thwomp)
}
else // Not going anywhere, so look for players.
{
thinker_t *th;
mobj_t *mo;
if (!rover || (rover->flags & FF_EXISTS))
{
// scan the thinkers to find players!
for (th = thinkercap.next; th != &thinkercap; th = th->next)
UINT8 i;
// scan the players to find victims!
for (i = 0; i < MAXPLAYERS; i++)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (!playeringame[i])
continue;
if (players[i].spectator)
continue;
if (!players[i].mo)
continue;
if (!players[i].mo->health)
continue;
if (players[i].mo->z > thwomp->sector->ceilingheight)
continue;
if (P_AproxDistance(thwompx - players[i].mo->x, thwompy - players[i].mo->y) > 96 * FRACUNIT)
continue;
mo = (mobj_t *)th;
if (mo->type == MT_PLAYER && mo->health && mo->player && !mo->player->spectator
&& mo->z <= thwomp->sector->ceilingheight
&& P_AproxDistance(thwompx - mo->x, thwompy - mo->y) <= 96*FRACUNIT)
{
thwomp->direction = -1;
break;
}
}
}
thwomp->sector->ceilspeed = 0;
thwomp->sector->floorspeed = 0;
@ -2701,7 +2703,7 @@ INT32 EV_DoFloor(line_t *line, floor_e floortype)
// new floor thinker
rtn = 1;
dofloor = Z_Calloc(sizeof (*dofloor), PU_LEVSPEC, NULL);
P_AddThinker(&dofloor->thinker);
P_AddThinker(THINK_MAIN, &dofloor->thinker);
// make sure another floor thinker won't get started over this one
sec->floordata = dofloor;
@ -2922,7 +2924,7 @@ INT32 EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed)
// create and initialize new elevator thinker
rtn = 1;
elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL);
P_AddThinker(&elevator->thinker);
P_AddThinker(THINK_MAIN, &elevator->thinker);
sec->floordata = elevator;
sec->ceilingdata = elevator;
elevator->thinker.function.acp1 = (actionf_p1)T_MoveElevator;
@ -3133,7 +3135,7 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover)
// no longer exists (can't collide with again)
rover->flags &= ~FF_EXISTS;
rover->master->frontsector->moved = true;
sec->moved = true;
P_RecalcPrecipInSector(sec);
}
// Used for bobbing platforms on the water
@ -3149,7 +3151,7 @@ INT32 EV_BounceSector(sector_t *sec, fixed_t momz, line_t *sourceline)
return 0;
bouncer = Z_Calloc(sizeof (*bouncer), PU_LEVSPEC, NULL);
P_AddThinker(&bouncer->thinker);
P_AddThinker(THINK_MAIN, &bouncer->thinker);
sec->ceilingdata = bouncer;
bouncer->thinker.function.acp1 = (actionf_p1)T_BounceCheese;
@ -3183,7 +3185,7 @@ INT32 EV_DoContinuousFall(sector_t *sec, sector_t *backsector, fixed_t spd, bool
// create and initialize new thinker
faller = Z_Calloc(sizeof (*faller), PU_LEVSPEC, NULL);
P_AddThinker(&faller->thinker);
P_AddThinker(THINK_MAIN, &faller->thinker);
faller->thinker.function.acp1 = (actionf_p1)T_ContinuousFalling;
// set up the fields
@ -3232,7 +3234,7 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating,
// create and initialize new elevator thinker
elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL);
P_AddThinker(&elevator->thinker);
P_AddThinker(THINK_MAIN, &elevator->thinker);
elevator->thinker.function.acp1 = (actionf_p1)T_StartCrumble;
// Does this crumbler return?
@ -3311,7 +3313,7 @@ INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher)
// create and initialize new elevator thinker
block = Z_Calloc(sizeof (*block), PU_LEVSPEC, NULL);
P_AddThinker(&block->thinker);
P_AddThinker(THINK_MAIN, &block->thinker);
roversec->floordata = block;
roversec->ceilingdata = block;
block->thinker.function.acp1 = (actionf_p1)T_MarioBlock;

View file

@ -97,9 +97,9 @@ void P_ClearStarPost(INT32 postnum)
mobj_t *mo2;
// scan the thinkers
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -126,14 +126,16 @@ void P_ResetStarposts(void)
thinker_t *th;
mobj_t *post;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
post = (mobj_t *)th;
if (post->type == MT_STARPOST)
if (post->type != MT_STARPOST)
continue;
P_SetMobjState(post, post->info->spawnstate);
}
}
@ -321,6 +323,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// Can happen with a sliding player corpse.
if (toucher->health <= 0)
return;
if (special->health <= 0)
return;
if (heightcheck)
{
@ -346,9 +350,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
}
}
if (special->health <= 0)
return;
player = toucher->player;
I_Assert(player != NULL); // Only players can touch stuff!
@ -453,13 +454,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
break;
}
if (((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|| ((player->pflags & PF_JUMPED) && (!(player->pflags & PF_NOJUMPDAMAGE) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|| (player->pflags & (PF_SPINNING|PF_GLIDING))
|| (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)
|| ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0))
|| player->powers[pw_invulnerability] || player->powers[pw_super]
|| elementalpierce) // Do you possess the ability to subdue the object?
if (P_PlayerCanDamage(player, special)) // Do you possess the ability to subdue the object?
{
if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1))
{
@ -474,18 +469,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
{
toucher->momx = -toucher->momx;
toucher->momy = -toucher->momy;
}
P_DamageMobj(special, toucher, toucher, 1, 0);
}
else if (((toucher->z < special->z && !(toucher->eflags & MFE_VERTICALFLIP))
|| (toucher->z + toucher->height > special->z + special->height && (toucher->eflags & MFE_VERTICALFLIP)))
&& player->charability == CA_FLY
&& (player->powers[pw_tailsfly]
|| toucher->state-states == S_PLAY_FLY_TIRED)) // Tails can shred stuff with her propeller.
{
if (player->charability == CA_FLY && player->panim == PA_ABILITY)
toucher->momz = -toucher->momz/2;
}
P_DamageMobj(special, toucher, toucher, 1, 0);
if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)
P_TwinSpinRejuvenate(player, player->thokitem);
}
else
P_DamageMobj(toucher, special, special, 1, 0);
@ -845,15 +834,16 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// The player might have two Ideyas: toucher->tracer and toucher->tracer->hnext
// so handle their anchorpoints accordingly.
// scan the thinkers to find the corresponding anchorpoint
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_IDEYAANCHOR)
{
if (mo2->type != MT_IDEYAANCHOR)
continue;
if (mo2->health == toucher->tracer->health) // do ideya numberes match?
anchorpoint = mo2;
else if (toucher->tracer->hnext && mo2->health == toucher->tracer->hnext->health)
@ -863,7 +853,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|| (toucher->tracer->hnext && anchorpoint && anchorpoint2))
break;
}
}
if (anchorpoint)
{
@ -939,9 +928,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
count = 1;
// scan the remaining thinkers
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -989,9 +978,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
// Now we RE-scan all the thinkers to find close objects to pull
// in from the paraloop. Isn't this just so efficient?
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -1363,9 +1352,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
EV_DoElevator(&junk, bridgeFall, false);
// scan the remaining thinkers to find koopa
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -1463,9 +1452,9 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
thinker_t *th;
mobj_t *mo2;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -1578,6 +1567,45 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
}
return;
case MT_EGGROBO1:
if (special->state == &states[special->info->deathstate])
return;
if (P_PlayerInPain(player))
return;
P_SetMobjState(special, special->info->meleestate);
special->angle = special->movedir;
special->momx = special->momy = 0;
// Buenos Dias Mandy
P_SetPlayerMobjState(toucher, S_PLAY_STUN);
player->pflags &= ~PF_APPLYAUTOBRAKE;
player->drawangle = special->angle + ANGLE_180;
P_InstaThrust(toucher, special->angle, FixedMul(3*special->info->speed, special->scale/2));
toucher->z += P_MobjFlip(toucher);
if (toucher->eflags & MFE_UNDERWATER) // unlikely.
P_SetObjectMomZ(toucher, FixedDiv(10511*FRACUNIT,2600*FRACUNIT), false);
else
P_SetObjectMomZ(toucher, FixedDiv(69*FRACUNIT,10*FRACUNIT), false);
if (P_IsLocalPlayer(player))
{
quake.intensity = 9*FRACUNIT;
quake.time = TICRATE/2;
quake.epicenter = NULL;
}
#if 0 // camera redirection - deemed unnecessary
toucher->angle = special->angle;
if (player == &players[consoleplayer])
localangle = toucher->angle;
else if (player == &players[secondarydisplayplayer])
localangle2 = toucher->angle;
#endif
S_StartSound(toucher, special->info->attacksound); // home run
return;
case MT_BIGTUMBLEWEED:
case MT_LITTLETUMBLEWEED:
if (toucher->momx || toucher->momy)
@ -1819,6 +1847,10 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
deadtarget = (player->mo->health <= 0);
// Don't log every hazard hit if they don't want us to.
if (!deadtarget && !cv_hazardlog.value)
return;
// Target's name
snprintf(targetname, sizeof(targetname), "%s%s%s",
CTFTEAMCODE(player),
@ -1922,7 +1954,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
switch (damagetype)
{
case DMG_WATER:
str = M_GetText("%s was %s by chemical water.\n");
str = M_GetText("%s was %s by dangerous water.\n");
break;
case DMG_FIRE:
str = M_GetText("%s was %s by molten lava.\n");
@ -1970,10 +2002,6 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
if (!str) // Should not happen! Unless we missed catching something above.
return;
// Don't log every hazard hit if they don't want us to.
if (!deadtarget && !cv_hazardlog.value)
return;
if (deathonly)
{
if (!deadtarget)
@ -2567,20 +2595,26 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
UINT32 i = 0; // to check how many clones we've removed
// scan the thinkers to make sure all the old pinch dummies are gone on death
// this can happen if the boss was hurt earlier than expected
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)th;
if (mo->type == (mobjtype_t)target->info->mass && mo->tracer == target)
{
P_RemoveMobj(mo);
i++;
}
if (i == 2) // we've already removed 2 of these, let's stop now
if (mo->type != (mobjtype_t)target->info->mass)
continue;
if (mo->tracer != target)
continue;
P_KillMobj(mo, inflictor, source, damagetype);
mo->destscale = mo->scale/8;
mo->scalespeed = (mo->scale - mo->destscale)/(2*TICRATE);
mo->momz = mo->info->speed;
mo->angle = FixedAngle((P_RandomKey(36)*10)<<FRACBITS);
if (++i == 2) // we've already removed 2 of these, let's stop now
break;
else
S_StartSound(mo, mo->info->deathsound); // done once to prevent sound stacking
}
}
break;
@ -2895,26 +2929,47 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou
if (player->powers[pw_flashing] || player->powers[pw_invulnerability])
return false;
// Ignore IT players shooting each other, unless friendlyfire is on.
if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) &&
source && source->player && source->player->pflags & PF_TAGIT)))
return false;
// Don't allow any damage before the round starts.
if (leveltime <= hidetime * TICRATE)
return false;
// Ignore IT players shooting each other, unless friendlyfire is on.
if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) &&
source && source->player && source->player->pflags & PF_TAGIT)))
{
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
{
if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
{
P_SwitchShield(player, SH_PINK);
S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound);
}
}
return false;
}
// Don't allow players on the same team to hurt one another,
// unless cv_friendlyfire is on.
if (!(cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT))
{
if (!(inflictor->flags & MF_FIRE))
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
{
if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
{
P_SwitchShield(player, SH_PINK);
S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound);
}
}
else if (!(inflictor->flags & MF_FIRE))
P_GivePlayerRings(player, 1);
if (inflictor->flags2 & MF2_BOUNCERING)
inflictor->fuse = 0; // bounce ring disappears at -1 not 0
return false;
}
if (inflictor->type == MT_LHRT)
return false;
// The tag occurs so long as you aren't shooting another tagger with friendlyfire on.
if (source->player->pflags & PF_TAGIT && !(player->pflags & PF_TAGIT))
{
@ -2981,8 +3036,18 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
// In COOP/RACE, you can't hurt other players unless cv_friendlyfire is on
if (!cv_friendlyfire.value && (G_PlatformGametype()))
{
if (gametype == GT_COOP && inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) // co-op only
{
if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
{
P_SwitchShield(player, SH_PINK);
S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound);
}
}
return false;
}
}
// Tag handling
if (G_TagGametype())
@ -2995,7 +3060,15 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
// unless cv_friendlyfire is on.
if (!cv_friendlyfire.value && target->player->ctfteam == source->player->ctfteam)
{
if (!(inflictor->flags & MF_FIRE))
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
{
if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
{
P_SwitchShield(player, SH_PINK);
S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound);
}
}
else if (!(inflictor->flags & MF_FIRE))
P_GivePlayerRings(target->player, 1);
if (inflictor->flags2 & MF2_BOUNCERING)
inflictor->fuse = 0; // bounce ring disappears at -1 not 0
@ -3004,6 +3077,9 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
}
}
if (inflictor->type == MT_LHRT)
return false;
// Add pity.
if (!player->powers[pw_flashing] && !player->powers[pw_invulnerability] && !player->powers[pw_super]
&& source->player->score > player->score)

View file

@ -76,7 +76,7 @@ fireflicker_t *P_SpawnAdjustableFireFlicker(sector_t *minsector, sector_t *maxse
P_RemoveLighting(maxsector); // out with the old, in with the new
flick = Z_Calloc(sizeof (*flick), PU_LEVSPEC, NULL);
P_AddThinker(&flick->thinker);
P_AddThinker(THINK_MAIN, &flick->thinker);
flick->thinker.function.acp1 = (actionf_p1)T_FireFlicker;
flick->sector = maxsector;
@ -155,7 +155,7 @@ void P_SpawnLightningFlash(sector_t *sector)
flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL);
P_AddThinker(&flash->thinker);
P_AddThinker(THINK_MAIN, &flash->thinker);
flash->thinker.function.acp1 = (actionf_p1)T_LightningFlash;
flash->sector = sector;
@ -214,7 +214,7 @@ strobe_t *P_SpawnAdjustableStrobeFlash(sector_t *minsector, sector_t *maxsector,
P_RemoveLighting(maxsector); // out with the old, in with the new
flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL);
P_AddThinker(&flash->thinker);
P_AddThinker(THINK_MAIN, &flash->thinker);
flash->sector = maxsector;
flash->darktime = darktime;
@ -289,7 +289,7 @@ glow_t *P_SpawnAdjustableGlowingLight(sector_t *minsector, sector_t *maxsector,
P_RemoveLighting(maxsector); // out with the old, in with the new
g = Z_Calloc(sizeof (*g), PU_LEVSPEC, NULL);
P_AddThinker(&g->thinker);
P_AddThinker(THINK_MAIN, &g->thinker);
g->sector = maxsector;
g->minlight = minsector->lightlevel;
@ -349,7 +349,7 @@ void P_FadeLightBySector(sector_t *sector, INT32 destvalue, INT32 speed, boolean
ll->thinker.function.acp1 = (actionf_p1)T_LightFade;
sector->lightingdata = ll; // set it to the lightlevel_t
P_AddThinker(&ll->thinker); // add thinker
P_AddThinker(THINK_MAIN, &ll->thinker); // add thinker
ll->sector = sector;
ll->sourcelevel = sector->lightlevel;

View file

@ -61,15 +61,21 @@
#define P_GetPlayerHeight(player) FixedMul(player->height, player->mo->scale)
#define P_GetPlayerSpinHeight(player) FixedMul(player->spinheight, player->mo->scale)
//
// P_TICK
//
// both the head and tail of the thinker list
extern thinker_t thinkercap;
typedef enum
{
THINK_POLYOBJ,
THINK_MAIN,
THINK_MOBJ,
#ifdef ESLOPE
THINK_DYNSLOPE,
#endif
THINK_PRECIP,
NUM_THINKERLISTS
} thinklistnum_t; /**< Thinker lists. */
extern thinker_t thlist[];
void P_InitThinkers(void);
void P_AddThinker(thinker_t *thinker);
void P_AddThinker(const thinklistnum_t n, thinker_t *thinker);
void P_RemoveThinker(thinker_t *thinker);
//
@ -128,6 +134,7 @@ pflags_t P_GetJumpFlags(player_t *player);
boolean P_PlayerInPain(player_t *player);
void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor);
void P_ResetPlayer(player_t *player);
boolean P_PlayerCanDamage(player_t *player, mobj_t *thing);
boolean P_IsLocalPlayer(player_t *player);
boolean P_IsObjectInGoop(mobj_t *mo);
@ -158,6 +165,7 @@ boolean P_AutoPause(void);
void P_DoJumpShield(player_t *player);
void P_DoBubbleBounce(player_t *player);
void P_DoAbilityBounce(player_t *player, boolean changemomz);
void P_TwinSpinRejuvenate(player_t *player, mobjtype_t type);
void P_BlackOw(player_t *player);
void P_ElementalFire(player_t *player, boolean cropcircle);
@ -174,7 +182,7 @@ void P_InstaThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move);
mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet);
void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius);
void P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user
boolean P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user
boolean P_SuperReady(player_t *player);
void P_DoJump(player_t *player, boolean soundandstate);
#if 0

View file

@ -135,6 +135,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
fixed_t vertispeed = spring->info->mass;
fixed_t horizspeed = spring->info->damage;
boolean final = false;
UINT8 strong = 0;
// Object was already sprung this tic
if (object->eflags & MFE_SPRUNG)
@ -148,6 +149,14 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
if (!spring->health || !object->health)
return false;
if (object->player)
{
if (object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY)
strong = 1;
else if (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2)
strong = 2;
}
if (spring->info->painchance == -1) // Pinball bumper mode.
{
// The first of the entirely different spring modes!
@ -188,6 +197,9 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
{
fixed_t playervelocity;
if (strong)
vertispeed <<= 1;
if (!(object->player->pflags & PF_THOKKED) && !(object->player->homing)
&& ((playervelocity = FixedDiv(9*FixedHypot(object->player->speed, object->momz), 10<<FRACBITS)) > vertispeed))
vertispeed = playervelocity;
@ -260,11 +272,8 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
return false;
}
if (object->player
&& ((object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY)
|| (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2)))
if (strong)
{
S_StartSound(object, sfx_s3k8b);
if (horizspeed)
horizspeed = FixedMul(horizspeed, (4*FRACUNIT)/3);
if (vertispeed)
@ -399,6 +408,12 @@ springstate:
P_AddPlayerScore(object->player, 10);
spring->reactiontime--;
}
if (strong)
{
P_TwinSpinRejuvenate(object->player, (strong == 1 ? object->player->thokitem : object->player->revitem));
S_StartSound(object, sfx_sprong); // strong spring. sprong.
}
}
return final;
@ -710,6 +725,27 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true;
}
// vectorise metal - done in a special case as at this point neither has the right flags for touching
if (thing->type == MT_METALSONIC_BATTLE
&& (tmthing->flags & MF_MISSILE)
&& tmthing->target != thing
&& thing->state == &states[thing->info->spawnstate])
{
blockdist = thing->radius + tmthing->radius;
if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
return true; // didn't hit it
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
thing->flags2 |= MF2_CLASSICPUSH;
return true;
}
if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING)))
return true;
@ -1153,7 +1189,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
tmthing->y = thing->y;
P_SetThingPosition(tmthing);
}
else if (!(tmthing->type == MT_SHELL && thing->player)) // player collision handled in touchspecial
else if (!(tmthing->type == MT_SHELL && thing->player)) // player collision handled in touchspecial for shell
{
UINT8 damagetype = tmthing->info->mass;
if (!damagetype && tmthing->flags & MF_FIRE) // BURN!
@ -1482,26 +1518,17 @@ static boolean PIT_CheckThing(mobj_t *thing)
}
// 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)))
{
// 0 = none, 1 = elemental pierce, 2 = bubble bounce
UINT8 elementalpierce = (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (tmthing->player->pflags & PF_SHIELDABILITY)
? (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2)
: 0);
if (!(thing->flags & MF_SOLID)
|| tmthing->player->pflags & (PF_SPINNING|PF_GLIDING)
|| ((tmthing->player->pflags & PF_JUMPED)
&& (!(tmthing->player->pflags & PF_NOJUMPDAMAGE)
|| (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)
|| ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING)
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0))
|| elementalpierce)
&& !((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)))
{
if (thing->z - thing->scale <= tmthing->z + tmthing->height
&& thing->z + thing->height + thing->scale >= tmthing->z)
{
player_t *player = tmthing->player;
// 0 = none, 1 = elemental pierce, 2 = bubble bounce
UINT8 elementalpierce = (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY)
? (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2)
: 0);
SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed.
fixed_t *momz = &tmthing->momz; // tmthing gets changed by P_DamageMobj, so we need a new pointer?! X_x;;
fixed_t *z = &tmthing->z; // aau.
@ -1513,7 +1540,11 @@ static boolean PIT_CheckThing(mobj_t *thing)
if (elementalpierce == 2)
P_DoBubbleBounce(player);
else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
{
*momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically.
if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)
P_TwinSpinRejuvenate(player, player->thokitem);
}
}
if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough.
{
@ -1528,7 +1559,6 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true;
}
}
}
if ((!tmthing->player) && (thing->player))
; // no solid thing should ever be able to step up onto a player
@ -4003,7 +4033,7 @@ static boolean PIT_ChangeSector(mobj_t *thing, boolean realcrush)
thinker_t *think;
elevator_t *crumbler;
for (think = thinkercap.next; think != &thinkercap; think = think->next)
for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
{
if (think->function.acp1 != (actionf_p1)T_StartCrumble)
continue;

View file

@ -1093,7 +1093,10 @@ boolean P_BlockThingsIterator(INT32 x, INT32 y, boolean (*func)(mobj_t *))
{
P_SetTarget(&bnext, mobj->bnext); // We want to note our reference to bnext here incase it is MF_NOTHINK and gets removed!
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.
{

File diff suppressed because it is too large Load diff

View file

@ -371,6 +371,8 @@ typedef struct mobj_s
struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?)
#endif
boolean colorized; // Whether the mobj uses the rainbow colormap
// WARNING: New fields must be added separately to savegame and Lua.
} mobj_t;

View file

@ -146,16 +146,6 @@ FUNCINLINE static ATTRINLINE void Polyobj_vecSub2(vertex_t *dst, vertex_t *v1, v
dst->y = v1->y - v2->y;
}
// Add the polyobject's thinker to the thinker list
// Unlike P_AddThinker, this adds it to the front of the list instead of the back, so that carrying physics can work right. -Red
FUNCINLINE static ATTRINLINE void PolyObj_AddThinker(thinker_t *th)
{
thinkercap.next->prev = th;
th->next = thinkercap.next;
th->prev = &thinkercap;
thinkercap.next = th;
}
//
// P_PointInsidePolyobj
//
@ -1505,6 +1495,7 @@ void Polyobj_InitLevel(void)
mqueue_t anchorqueue;
mobjqitem_t *qitem;
INT32 i, numAnchors = 0;
mobj_t *mo;
M_QueueInit(&spawnqueue);
M_QueueInit(&anchorqueue);
@ -1518,11 +1509,12 @@ void Polyobj_InitLevel(void)
// run down the thinker list, count the number of spawn points, and save
// the mobj_t pointers on a queue for use below.
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
{
mobj_t *mo = (mobj_t *)th;
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)th;
if (mo->info->doomednum == POLYOBJ_SPAWN_DOOMEDNUM ||
mo->info->doomednum == POLYOBJ_SPAWNCRUSH_DOOMEDNUM)
@ -1544,7 +1536,6 @@ void Polyobj_InitLevel(void)
M_QueueInsert(&(qitem->mqitem), &anchorqueue);
}
}
}
if (numPolyObjects)
{
@ -1657,7 +1648,7 @@ void T_PolyObjRotate(polyrotate_t *th)
#else
{
CONS_Debug(DBG_POLYOBJ, "T_PolyObjRotate: thinker with invalid id %d removed.\n", th->polyObjNum);
P_RemoveThinkerDelayed(&th->thinker);
P_RemoveThinker(&th->thinker);
return;
}
#endif
@ -1742,7 +1733,7 @@ void T_PolyObjMove(polymove_t *th)
#else
{
CONS_Debug(DBG_POLYOBJ, "T_PolyObjMove: thinker with invalid id %d removed.\n", th->polyObjNum);
P_RemoveThinkerDelayed(&th->thinker);
P_RemoveThinker(&th->thinker);
return;
}
#endif
@ -1815,7 +1806,7 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
#else
{
CONS_Debug(DBG_POLYOBJ, "T_PolyObjWaypoint: thinker with invalid id %d removed.", th->polyObjNum);
P_RemoveThinkerDelayed(&th->thinker);
P_RemoveThinker(&th->thinker);
return;
}
#endif
@ -1826,9 +1817,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
// Find out target first.
// We redo this each tic to make savegame compatibility easier.
for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
{
if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)wp;
@ -1907,9 +1898,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
CONS_Debug(DBG_POLYOBJ, "Looking for next waypoint...\n");
// Find next waypoint
for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
{
if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)wp;
@ -1917,8 +1908,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
if (mo2->type != MT_TUBEWAYPOINT)
continue;
if (mo2->threshold == th->sequence)
{
if (mo2->threshold != th->sequence)
continue;
if (th->direction == -1)
{
if (mo2->health == target->health - 1)
@ -1936,7 +1928,6 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
}
}
}
}
if (!waypoint && th->wrap) // If specified, wrap waypoints
{
@ -1946,9 +1937,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
th->stophere = true;
}
for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
{
if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)wp;
@ -1956,8 +1947,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
if (mo2->type != MT_TUBEWAYPOINT)
continue;
if (mo2->threshold == th->sequence)
{
if (mo2->threshold != th->sequence)
continue;
if (th->direction == -1)
{
if (waypoint == NULL)
@ -1975,7 +1967,6 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
}
}
}
}
else if (!waypoint && th->comeback) // Come back to the start
{
th->direction = -th->direction;
@ -1983,9 +1974,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
if (!th->continuous)
th->comeback = false;
for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
{
if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)wp;
@ -1993,8 +1984,9 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
if (mo2->type != MT_TUBEWAYPOINT)
continue;
if (mo2->threshold == th->sequence)
{
if (mo2->threshold != th->sequence)
continue;
if (th->direction == -1)
{
if (mo2->health == target->health - 1)
@ -2014,7 +2006,6 @@ void T_PolyObjWaypoint(polywaypoint_t *th)
}
}
}
}
if (waypoint)
{
@ -2089,7 +2080,7 @@ void T_PolyDoorSlide(polyslidedoor_t *th)
#else
{
CONS_Debug(DBG_POLYOBJ, "T_PolyDoorSlide: thinker with invalid id %d removed.\n", th->polyObjNum);
P_RemoveThinkerDelayed(&th->thinker);
P_RemoveThinker(&th->thinker);
return;
}
#endif
@ -2194,7 +2185,7 @@ void T_PolyDoorSwing(polyswingdoor_t *th)
#else
{
CONS_Debug(DBG_POLYOBJ, "T_PolyDoorSwing: thinker with invalid id %d removed.\n", th->polyObjNum);
P_RemoveThinkerDelayed(&th->thinker);
P_RemoveThinker(&th->thinker);
return;
}
#endif
@ -2293,7 +2284,7 @@ void T_PolyObjDisplace(polydisplace_t *th)
#else
{
CONS_Debug(DBG_POLYOBJ, "T_PolyObjDisplace: thinker with invalid id %d removed.\n", th->polyObjNum);
P_RemoveThinkerDelayed(&th->thinker);
P_RemoveThinker(&th->thinker);
return;
}
#endif
@ -2333,7 +2324,7 @@ void T_PolyObjRotDisplace(polyrotdisplace_t *th)
#else
{
CONS_Debug(DBG_POLYOBJ, "T_PolyObjRotDisplace: thinker with invalid id %d removed.\n", th->polyObjNum);
P_RemoveThinkerDelayed(&th->thinker);
P_RemoveThinker(&th->thinker);
return;
}
#endif
@ -2390,7 +2381,7 @@ INT32 EV_DoPolyObjRotate(polyrotdata_t *prdata)
// create a new thinker
th = Z_Malloc(sizeof(polyrotate_t), PU_LEVSPEC, NULL);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjRotate;
PolyObj_AddThinker(&th->thinker);
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;
// set fields
@ -2455,7 +2446,7 @@ INT32 EV_DoPolyObjMove(polymovedata_t *pmdata)
// create a new thinker
th = Z_Malloc(sizeof(polymove_t), PU_LEVSPEC, NULL);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjMove;
PolyObj_AddThinker(&th->thinker);
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;
// set fields
@ -2516,7 +2507,7 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
// create a new thinker
th = Z_Malloc(sizeof(polywaypoint_t), PU_LEVSPEC, NULL);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjWaypoint;
PolyObj_AddThinker(&th->thinker);
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;
// set fields
@ -2534,9 +2525,9 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
th->stophere = false;
// Find the first waypoint we need to use
for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
{
if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)wp;
@ -2544,8 +2535,9 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
if (mo2->type != MT_TUBEWAYPOINT)
continue;
if (mo2->threshold == th->sequence)
{
if (mo2->threshold != th->sequence)
continue;
if (th->direction == -1) // highest waypoint #
{
if (mo2->health == 0)
@ -2571,7 +2563,6 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
}
}
}
}
if (!first)
{
@ -2605,9 +2596,9 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
// Find the actual target movement waypoint
target = first;
/*for (wp = thinkercap.next; wp != &thinkercap; wp = wp->next)
/*for (wp = thlist[THINK_MOBJ].next; wp != &thlist[THINK_MOBJ]; wp = wp->next)
{
if (wp->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
if (wp->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)wp;
@ -2615,8 +2606,9 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
if (mo2->type != MT_TUBEWAYPOINT)
continue;
if (mo2->threshold == th->sequence)
{
if (mo2->threshold != th->sequence)
continue;
if (th->direction == -1) // highest waypoint #
{
if (mo2->health == first->health - 1)
@ -2633,7 +2625,6 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
break;
}
}
}
}*/
if (!target)
@ -2662,7 +2653,7 @@ static void Polyobj_doSlideDoor(polyobj_t *po, polydoordata_t *doordata)
// allocate and add a new slide door thinker
th = Z_Malloc(sizeof(polyslidedoor_t), PU_LEVSPEC, NULL);
th->thinker.function.acp1 = (actionf_p1)T_PolyDoorSlide;
PolyObj_AddThinker(&th->thinker);
P_AddThinker(THINK_POLYOBJ, &th->thinker);
// point the polyobject to this thinker
po->thinker = &th->thinker;
@ -2710,7 +2701,7 @@ static void Polyobj_doSwingDoor(polyobj_t *po, polydoordata_t *doordata)
// allocate and add a new swing door thinker
th = Z_Malloc(sizeof(polyswingdoor_t), PU_LEVSPEC, NULL);
th->thinker.function.acp1 = (actionf_p1)T_PolyDoorSwing;
PolyObj_AddThinker(&th->thinker);
P_AddThinker(THINK_POLYOBJ, &th->thinker);
// point the polyobject to this thinker
po->thinker = &th->thinker;
@ -2792,7 +2783,7 @@ INT32 EV_DoPolyObjDisplace(polydisplacedata_t *prdata)
// create a new thinker
th = Z_Malloc(sizeof(polydisplace_t), PU_LEVSPEC, NULL);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjDisplace;
PolyObj_AddThinker(&th->thinker);
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;
// set fields
@ -2838,7 +2829,7 @@ INT32 EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *prdata)
// create a new thinker
th = Z_Malloc(sizeof(polyrotdisplace_t), PU_LEVSPEC, NULL);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjRotDisplace;
PolyObj_AddThinker(&th->thinker);
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;
// set fields
@ -2875,7 +2866,7 @@ void T_PolyObjFlag(polymove_t *th)
#else
{
CONS_Debug(DBG_POLYOBJ, "T_PolyObjFlag: thinker with invalid id %d removed.\n", th->polyObjNum);
P_RemoveThinkerDelayed(&th->thinker);
P_RemoveThinker(&th->thinker);
return;
}
#endif
@ -2939,7 +2930,7 @@ INT32 EV_DoPolyObjFlag(line_t *pfdata)
// create a new thinker
th = Z_Malloc(sizeof(polymove_t), PU_LEVSPEC, NULL);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjFlag;
PolyObj_AddThinker(&th->thinker);
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;
// set fields
@ -2978,7 +2969,7 @@ void T_PolyObjFade(polyfade_t *th)
#else
{
CONS_Debug(DBG_POLYOBJ, "T_PolyObjFade: thinker with invalid id %d removed.\n", th->polyObjNum);
P_RemoveThinkerDelayed(&th->thinker);
P_RemoveThinker(&th->thinker);
return;
}
#endif
@ -3089,7 +3080,7 @@ INT32 EV_DoPolyObjFade(polyfadedata_t *pfdata)
// create a new thinker
th = Z_Malloc(sizeof(polyfade_t), PU_LEVSPEC, NULL);
th->thinker.function.acp1 = (actionf_p1)T_PolyObjFade;
PolyObj_AddThinker(&th->thinker);
P_AddThinker(THINK_POLYOBJ, &th->thinker);
po->thinker = &th->thinker;
// set fields

View file

@ -1262,12 +1262,11 @@ typedef enum
MD2_HNEXT = 1<<7,
MD2_HPREV = 1<<8,
MD2_FLOORROVER = 1<<9,
#ifdef ESLOPE
MD2_CEILINGROVER = 1<<10,
MD2_SLOPE = 1<<11
#else
MD2_CEILINGROVER = 1<<10
#ifdef ESLOPE
MD2_SLOPE = 1<<11,
#endif
MD2_COLORIZED = 1<<12,
} mobj_diff2_t;
typedef enum
@ -1304,6 +1303,10 @@ typedef enum
tc_fade,
tc_fadecolormap,
tc_planedisplace,
#ifdef ESLOPE
tc_dynslopeline,
tc_dynslopevert,
#endif // ESLOPE
#ifdef POLYOBJECTS
tc_polyrotate, // haleyjd 03/26/06: polyobjects
tc_polymove,
@ -1342,6 +1345,14 @@ static inline UINT32 SavePlayer(const player_t *player)
return 0xFFFFFFFF;
}
#ifdef ESLOPE
static UINT32 SaveSlope(const pslope_t *slope)
{
if (slope) return (UINT32)(slope->id);
return 0xFFFFFFFF;
}
#endif // ESLOPE
//
// SaveMobjThinker
//
@ -1473,6 +1484,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
if (mobj->standingslope)
diff2 |= MD2_SLOPE;
#endif
if (mobj->colorized)
diff2 |= MD2_COLORIZED;
if (diff2 != 0)
diff |= MD_MORE;
@ -1635,6 +1648,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
if (diff2 & MD2_SLOPE)
WRITEUINT16(save_p, mobj->standingslope->id);
#endif
if (diff2 & MD2_COLORIZED)
WRITEUINT8(save_p, mobj->colorized);
WRITEUINT32(save_p, mobj->mobjnum);
}
@ -1979,6 +1994,23 @@ static void SavePlaneDisplaceThinker(const thinker_t *th, const UINT8 type)
WRITEFIXED(save_p, ht->speed);
WRITEUINT8(save_p, ht->type);
}
#ifdef ESLOPE
/// Save a dynamic slope thinker.
static inline void SaveDynamicSlopeThinker(const thinker_t *th, const UINT8 type)
{
const dynplanethink_t* ht = (const void*)th;
WRITEUINT8(save_p, type);
WRITEUINT8(save_p, ht->type);
WRITEUINT32(save_p, SaveSlope(ht->slope));
WRITEUINT32(save_p, SaveLine(ht->sourceline));
WRITEFIXED(save_p, ht->extent);
WRITEMEM(save_p, ht->tags, sizeof(ht->tags));
WRITEMEM(save_p, ht->vex, sizeof(ht->vex));
}
#endif // ESLOPE
#ifdef POLYOBJECTS
//
@ -2135,12 +2167,15 @@ static inline void SaveWhatThinker(const thinker_t *th, const UINT8 type)
static void P_NetArchiveThinkers(void)
{
const thinker_t *th;
UINT32 numsaved = 0;
UINT32 i;
WRITEUINT32(save_p, ARCHIVEBLOCK_THINKERS);
for (i = 0; i < NUM_THINKERLISTS; i++)
{
UINT32 numsaved = 0;
// save off the current thinkers
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[i].next; th != &thlist[i]; th = th->next)
{
if (!(th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed
|| th->function.acp1 == (actionf_p1)P_NullPrecipThinker))
@ -2356,16 +2391,29 @@ static void P_NetArchiveThinkers(void)
continue;
}
#endif
#ifdef ESLOPE
else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeLine)
{
SaveDynamicSlopeThinker(th, tc_dynslopeline);
continue;
}
else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeVert)
{
SaveDynamicSlopeThinker(th, tc_dynslopevert);
continue;
}
#endif // ESLOPE
#ifdef PARANOIA
else if (th->function.acv != P_RemoveThinkerDelayed) // wait garbage collection
else if (th->function.acp1 != P_RemoveThinkerDelayed) // wait garbage collection
I_Error("unknown thinker type %p", th->function.acp1);
#endif
}
CONS_Debug(DBG_NETPLAY, "%u thinkers saved\n", numsaved);
CONS_Debug(DBG_NETPLAY, "%u thinkers saved in list %d\n", numsaved, i);
WRITEUINT8(save_p, tc_end);
}
}
// Now save the pointers, tracer and target, but at load time we must
// relink to this; the savegame contains the old position in the pointer
@ -2376,13 +2424,15 @@ mobj_t *P_FindNewPosition(UINT32 oldposition)
thinker_t *th;
mobj_t *mobj;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mobj = (mobj_t *)th;
if (mobj->mobjnum == oldposition)
if (mobj->mobjnum != oldposition)
continue;
return mobj;
}
CONS_Debug(DBG_GAMELOGIC, "mobj not found\n");
@ -2413,12 +2463,26 @@ static inline player_t *LoadPlayer(UINT32 player)
return &players[player];
}
#ifdef ESLOPE
static inline pslope_t *LoadSlope(UINT32 slopeid)
{
pslope_t *p = slopelist;
if (slopeid > slopecount) return NULL;
do
{
if (p->id == slopeid)
return p;
} while ((p = p->next));
return NULL;
}
#endif // ESLOPE
//
// LoadMobjThinker
//
// Loads a mobj_t from a save game
//
static void LoadMobjThinker(actionf_p1 thinker)
static thinker_t* LoadMobjThinker(actionf_p1 thinker)
{
thinker_t *next;
mobj_t *mobj;
@ -2479,7 +2543,7 @@ static void LoadMobjThinker(actionf_p1 thinker)
if (mapthings[spawnpointnum].type == 1705 || mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case
{
P_SpawnHoopsAndRings(&mapthings[spawnpointnum], false);
return;
return NULL;
}
mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
@ -2660,7 +2724,8 @@ static void LoadMobjThinker(actionf_p1 thinker)
if (diff2 & MD2_SLOPE)
mobj->standingslope = P_SlopeById(READUINT16(save_p));
#endif
if (diff2 & MD2_COLORIZED)
mobj->colorized = READUINT8(save_p);
if (diff & MD_REDFLAG)
{
@ -2686,9 +2751,9 @@ static void LoadMobjThinker(actionf_p1 thinker)
mobj->player->viewz = mobj->player->mo->z + mobj->player->viewheight;
}
P_AddThinker(&mobj->thinker);
mobj->info = (mobjinfo_t *)next; // temporarily, set when leave this function
return &mobj->thinker;
}
//
@ -2702,7 +2767,7 @@ static void LoadMobjThinker(actionf_p1 thinker)
// 2 - Ceiling Only
// 3 - Both
//
static void LoadSpecialLevelThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
static thinker_t* LoadSpecialLevelThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
{
levelspecthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
size_t i;
@ -2723,7 +2788,7 @@ static void LoadSpecialLevelThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
ht->sector->floordata = ht;
}
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -2731,7 +2796,7 @@ static void LoadSpecialLevelThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
//
// Loads a ceiling_t from a save game
//
static void LoadCeilingThinker(actionf_p1 thinker)
static thinker_t* LoadCeilingThinker(actionf_p1 thinker)
{
ceiling_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -2752,7 +2817,7 @@ static void LoadCeilingThinker(actionf_p1 thinker)
ht->sourceline = READFIXED(save_p);
if (ht->sector)
ht->sector->ceilingdata = ht;
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -2760,7 +2825,7 @@ static void LoadCeilingThinker(actionf_p1 thinker)
//
// Loads a floormove_t from a save game
//
static void LoadFloormoveThinker(actionf_p1 thinker)
static thinker_t* LoadFloormoveThinker(actionf_p1 thinker)
{
floormove_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -2776,7 +2841,7 @@ static void LoadFloormoveThinker(actionf_p1 thinker)
ht->delaytimer = READFIXED(save_p);
if (ht->sector)
ht->sector->floordata = ht;
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -2784,7 +2849,7 @@ static void LoadFloormoveThinker(actionf_p1 thinker)
//
// Loads a lightflash_t from a save game
//
static void LoadLightflashThinker(actionf_p1 thinker)
static thinker_t* LoadLightflashThinker(actionf_p1 thinker)
{
lightflash_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -2793,7 +2858,7 @@ static void LoadLightflashThinker(actionf_p1 thinker)
ht->minlight = READINT32(save_p);
if (ht->sector)
ht->sector->lightingdata = ht;
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -2801,7 +2866,7 @@ static void LoadLightflashThinker(actionf_p1 thinker)
//
// Loads a strobe_t from a save game
//
static void LoadStrobeThinker(actionf_p1 thinker)
static thinker_t* LoadStrobeThinker(actionf_p1 thinker)
{
strobe_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -2813,7 +2878,7 @@ static void LoadStrobeThinker(actionf_p1 thinker)
ht->brighttime = READINT32(save_p);
if (ht->sector)
ht->sector->lightingdata = ht;
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -2821,7 +2886,7 @@ static void LoadStrobeThinker(actionf_p1 thinker)
//
// Loads a glow_t from a save game
//
static void LoadGlowThinker(actionf_p1 thinker)
static thinker_t* LoadGlowThinker(actionf_p1 thinker)
{
glow_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -2832,14 +2897,14 @@ static void LoadGlowThinker(actionf_p1 thinker)
ht->speed = READINT32(save_p);
if (ht->sector)
ht->sector->lightingdata = ht;
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
// LoadFireflickerThinker
//
// Loads a fireflicker_t from a save game
//
static void LoadFireflickerThinker(actionf_p1 thinker)
static thinker_t* LoadFireflickerThinker(actionf_p1 thinker)
{
fireflicker_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -2850,14 +2915,14 @@ static void LoadFireflickerThinker(actionf_p1 thinker)
ht->minlight = READINT32(save_p);
if (ht->sector)
ht->sector->lightingdata = ht;
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
// LoadElevatorThinker
//
// Loads a elevator_t from a save game
//
static void LoadElevatorThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
static thinker_t* LoadElevatorThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
{
elevator_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -2887,7 +2952,7 @@ static void LoadElevatorThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
ht->sector->floordata = ht;
}
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -2895,7 +2960,7 @@ static void LoadElevatorThinker(actionf_p1 thinker, UINT8 floorOrCeiling)
//
// Loads a scroll_t from a save game
//
static void LoadScrollThinker(actionf_p1 thinker)
static thinker_t* LoadScrollThinker(actionf_p1 thinker)
{
scroll_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -2909,7 +2974,7 @@ static void LoadScrollThinker(actionf_p1 thinker)
ht->accel = READINT32(save_p);
ht->exclusive = READINT32(save_p);
ht->type = READUINT8(save_p);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -2917,7 +2982,7 @@ static void LoadScrollThinker(actionf_p1 thinker)
//
// Loads a friction_t from a save game
//
static inline void LoadFrictionThinker(actionf_p1 thinker)
static inline thinker_t* LoadFrictionThinker(actionf_p1 thinker)
{
friction_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -2926,7 +2991,7 @@ static inline void LoadFrictionThinker(actionf_p1 thinker)
ht->affectee = READINT32(save_p);
ht->referrer = READINT32(save_p);
ht->roverfriction = READUINT8(save_p);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -2934,7 +2999,7 @@ static inline void LoadFrictionThinker(actionf_p1 thinker)
//
// Loads a pusher_t from a save game
//
static void LoadPusherThinker(actionf_p1 thinker)
static thinker_t* LoadPusherThinker(actionf_p1 thinker)
{
pusher_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -2952,7 +3017,7 @@ static void LoadPusherThinker(actionf_p1 thinker)
ht->exclusive = READINT32(save_p);
ht->slider = READINT32(save_p);
ht->source = P_GetPushThing(ht->affectee);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -2960,7 +3025,7 @@ static void LoadPusherThinker(actionf_p1 thinker)
//
// Loads a laserthink_t from a save game
//
static inline void LoadLaserThinker(actionf_p1 thinker)
static inline thinker_t* LoadLaserThinker(actionf_p1 thinker)
{
laserthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ffloor_t *rover = NULL;
@ -2972,7 +3037,7 @@ static inline void LoadLaserThinker(actionf_p1 thinker)
if (rover->secnum == (size_t)(ht->sec - sectors)
&& rover->master == ht->sourceline)
ht->ffloor = rover;
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -2980,7 +3045,7 @@ static inline void LoadLaserThinker(actionf_p1 thinker)
//
// Loads a lightlevel_t from a save game
//
static inline void LoadLightlevelThinker(actionf_p1 thinker)
static inline thinker_t* LoadLightlevelThinker(actionf_p1 thinker)
{
lightlevel_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -2992,7 +3057,7 @@ static inline void LoadLightlevelThinker(actionf_p1 thinker)
ht->timer = READINT32(save_p);
if (ht->sector)
ht->sector->lightingdata = ht;
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -3000,7 +3065,7 @@ static inline void LoadLightlevelThinker(actionf_p1 thinker)
//
// Loads a executor_t from a save game
//
static inline void LoadExecutorThinker(actionf_p1 thinker)
static inline thinker_t* LoadExecutorThinker(actionf_p1 thinker)
{
executor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -3008,7 +3073,7 @@ static inline void LoadExecutorThinker(actionf_p1 thinker)
ht->caller = LoadMobj(READUINT32(save_p));
ht->sector = LoadSector(READUINT32(save_p));
ht->timer = READINT32(save_p);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -3016,7 +3081,7 @@ static inline void LoadExecutorThinker(actionf_p1 thinker)
//
// Loads a disappear_t thinker
//
static inline void LoadDisappearThinker(actionf_p1 thinker)
static inline thinker_t* LoadDisappearThinker(actionf_p1 thinker)
{
disappear_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -3027,7 +3092,7 @@ static inline void LoadDisappearThinker(actionf_p1 thinker)
ht->affectee = READINT32(save_p);
ht->sourceline = READINT32(save_p);
ht->exists = READINT32(save_p);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -3035,7 +3100,7 @@ static inline void LoadDisappearThinker(actionf_p1 thinker)
//
// Loads a fade_t thinker
//
static inline void LoadFadeThinker(actionf_p1 thinker)
static inline thinker_t* LoadFadeThinker(actionf_p1 thinker)
{
sector_t *ss;
fade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
@ -3074,14 +3139,14 @@ static inline void LoadFadeThinker(actionf_p1 thinker)
j++;
}
}
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
// LoadFadeColormapThinker
//
// Loads a fadecolormap_t from a save game
//
static inline void LoadFadeColormapThinker(actionf_p1 thinker)
static inline thinker_t* LoadFadeColormapThinker(actionf_p1 thinker)
{
fadecolormap_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -3093,7 +3158,7 @@ static inline void LoadFadeColormapThinker(actionf_p1 thinker)
ht->timer = READINT32(save_p);
if (ht->sector)
ht->sector->fadecolormapdata = ht;
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -3101,18 +3166,36 @@ static inline void LoadFadeColormapThinker(actionf_p1 thinker)
//
// Loads a planedisplace_t thinker
//
static inline void LoadPlaneDisplaceThinker(actionf_p1 thinker)
static inline thinker_t* LoadPlaneDisplaceThinker(actionf_p1 thinker)
{
planedisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
ht->affectee = READINT32(save_p);
ht->control = READINT32(save_p);
ht->last_height = READFIXED(save_p);
ht->speed = READFIXED(save_p);
ht->type = READUINT8(save_p);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
#ifdef ESLOPE
/// Save a dynamic slope thinker.
static inline thinker_t* LoadDynamicSlopeThinker(actionf_p1 thinker)
{
dynplanethink_t* ht = Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
ht->type = READUINT8(save_p);
ht->slope = LoadSlope(READUINT32(save_p));
ht->sourceline = LoadLine(READUINT32(save_p));
ht->extent = READFIXED(save_p);
READMEM(save_p, ht->tags, sizeof(ht->tags));
READMEM(save_p, ht->vex, sizeof(ht->vex));
return &ht->thinker;
}
#endif // ESLOPE
#ifdef POLYOBJECTS
//
@ -3120,14 +3203,14 @@ static inline void LoadPlaneDisplaceThinker(actionf_p1 thinker)
//
// Loads a polyrotate_t thinker
//
static inline void LoadPolyrotatetThinker(actionf_p1 thinker)
static inline thinker_t* LoadPolyrotatetThinker(actionf_p1 thinker)
{
polyrotate_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
ht->polyObjNum = READINT32(save_p);
ht->speed = READINT32(save_p);
ht->distance = READINT32(save_p);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -3135,7 +3218,7 @@ static inline void LoadPolyrotatetThinker(actionf_p1 thinker)
//
// Loads a polymovet_t thinker
//
static void LoadPolymoveThinker(actionf_p1 thinker)
static thinker_t* LoadPolymoveThinker(actionf_p1 thinker)
{
polymove_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -3145,7 +3228,7 @@ static void LoadPolymoveThinker(actionf_p1 thinker)
ht->momy = READFIXED(save_p);
ht->distance = READINT32(save_p);
ht->angle = READANGLE(save_p);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -3153,7 +3236,7 @@ static void LoadPolymoveThinker(actionf_p1 thinker)
//
// Loads a polywaypoint_t thinker
//
static inline void LoadPolywaypointThinker(actionf_p1 thinker)
static inline thinker_t* LoadPolywaypointThinker(actionf_p1 thinker)
{
polywaypoint_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -3169,7 +3252,7 @@ static inline void LoadPolywaypointThinker(actionf_p1 thinker)
ht->diffx = READFIXED(save_p);
ht->diffy = READFIXED(save_p);
ht->diffz = READFIXED(save_p);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -3177,7 +3260,7 @@ static inline void LoadPolywaypointThinker(actionf_p1 thinker)
//
// loads a polyslidedoor_t thinker
//
static inline void LoadPolyslidedoorThinker(actionf_p1 thinker)
static inline thinker_t* LoadPolyslidedoorThinker(actionf_p1 thinker)
{
polyslidedoor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -3194,7 +3277,7 @@ static inline void LoadPolyslidedoorThinker(actionf_p1 thinker)
ht->momx = READFIXED(save_p);
ht->momy = READFIXED(save_p);
ht->closing = READUINT8(save_p);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -3202,7 +3285,7 @@ static inline void LoadPolyslidedoorThinker(actionf_p1 thinker)
//
// Loads a polyswingdoor_t thinker
//
static inline void LoadPolyswingdoorThinker(actionf_p1 thinker)
static inline thinker_t* LoadPolyswingdoorThinker(actionf_p1 thinker)
{
polyswingdoor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -3214,7 +3297,7 @@ static inline void LoadPolyswingdoorThinker(actionf_p1 thinker)
ht->initDistance = READINT32(save_p);
ht->distance = READINT32(save_p);
ht->closing = READUINT8(save_p);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -3222,7 +3305,7 @@ static inline void LoadPolyswingdoorThinker(actionf_p1 thinker)
//
// Loads a polydisplace_t thinker
//
static inline void LoadPolydisplaceThinker(actionf_p1 thinker)
static inline thinker_t* LoadPolydisplaceThinker(actionf_p1 thinker)
{
polydisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -3231,10 +3314,10 @@ static inline void LoadPolydisplaceThinker(actionf_p1 thinker)
ht->dx = READFIXED(save_p);
ht->dy = READFIXED(save_p);
ht->oldHeights = READFIXED(save_p);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
static inline void LoadPolyrotdisplaceThinker(actionf_p1 thinker)
static inline thinker_t* LoadPolyrotdisplaceThinker(actionf_p1 thinker)
{
polyrotdisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -3243,7 +3326,7 @@ static inline void LoadPolyrotdisplaceThinker(actionf_p1 thinker)
ht->rotscale = READFIXED(save_p);
ht->turnobjs = READUINT8(save_p);
ht->oldHeights = READFIXED(save_p);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
//
@ -3251,7 +3334,7 @@ static inline void LoadPolyrotdisplaceThinker(actionf_p1 thinker)
//
// Loads a polyfadet_t thinker
//
static void LoadPolyfadeThinker(actionf_p1 thinker)
static thinker_t* LoadPolyfadeThinker(actionf_p1 thinker)
{
polyfade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
@ -3263,7 +3346,7 @@ static void LoadPolyfadeThinker(actionf_p1 thinker)
ht->ticbased = (boolean)READUINT8(save_p);
ht->duration = READINT32(save_p);
ht->timer = READINT32(save_p);
P_AddThinker(&ht->thinker);
return &ht->thinker;
}
#endif
@ -3296,8 +3379,10 @@ static void P_NetUnArchiveThinkers(void)
I_Error("Bad $$$.sav at archive block Thinkers");
// remove all the current thinkers
currentthinker = thinkercap.next;
for (currentthinker = thinkercap.next; currentthinker != &thinkercap; currentthinker = next)
for (i = 0; i < NUM_THINKERLISTS; i++)
{
currentthinker = thlist[i].next;
for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = next)
{
next = currentthinker->next;
@ -3306,6 +3391,7 @@ static void P_NetUnArchiveThinkers(void)
else
Z_Free(currentthinker);
}
}
// we don't want the removed mobjs to come back
iquetail = iquehead = 0;
@ -3318,8 +3404,11 @@ static void P_NetUnArchiveThinkers(void)
}
// read in saved thinkers
for (i = 0; i < NUM_THINKERLISTS; i++)
{
for (;;)
{
thinker_t* th;
tclass = READUINT8(save_p);
if (tclass == tc_end)
@ -3329,195 +3418,208 @@ static void P_NetUnArchiveThinkers(void)
switch (tclass)
{
case tc_mobj:
LoadMobjThinker((actionf_p1)P_MobjThinker);
th = LoadMobjThinker((actionf_p1)P_MobjThinker);
break;
case tc_ceiling:
LoadCeilingThinker((actionf_p1)T_MoveCeiling);
th = LoadCeilingThinker((actionf_p1)T_MoveCeiling);
break;
case tc_crushceiling:
LoadCeilingThinker((actionf_p1)T_CrushCeiling);
th = LoadCeilingThinker((actionf_p1)T_CrushCeiling);
break;
case tc_floor:
LoadFloormoveThinker((actionf_p1)T_MoveFloor);
th = LoadFloormoveThinker((actionf_p1)T_MoveFloor);
break;
case tc_flash:
LoadLightflashThinker((actionf_p1)T_LightningFlash);
th = LoadLightflashThinker((actionf_p1)T_LightningFlash);
break;
case tc_strobe:
LoadStrobeThinker((actionf_p1)T_StrobeFlash);
th = LoadStrobeThinker((actionf_p1)T_StrobeFlash);
break;
case tc_glow:
LoadGlowThinker((actionf_p1)T_Glow);
th = LoadGlowThinker((actionf_p1)T_Glow);
break;
case tc_fireflicker:
LoadFireflickerThinker((actionf_p1)T_FireFlicker);
th = LoadFireflickerThinker((actionf_p1)T_FireFlicker);
break;
case tc_elevator:
LoadElevatorThinker((actionf_p1)T_MoveElevator, 3);
th = LoadElevatorThinker((actionf_p1)T_MoveElevator, 3);
break;
case tc_continuousfalling:
LoadSpecialLevelThinker((actionf_p1)T_ContinuousFalling, 3);
th = LoadSpecialLevelThinker((actionf_p1)T_ContinuousFalling, 3);
break;
case tc_thwomp:
LoadSpecialLevelThinker((actionf_p1)T_ThwompSector, 3);
th = LoadSpecialLevelThinker((actionf_p1)T_ThwompSector, 3);
break;
case tc_noenemies:
LoadSpecialLevelThinker((actionf_p1)T_NoEnemiesSector, 0);
th = LoadSpecialLevelThinker((actionf_p1)T_NoEnemiesSector, 0);
break;
case tc_eachtime:
LoadSpecialLevelThinker((actionf_p1)T_EachTimeThinker, 0);
th = LoadSpecialLevelThinker((actionf_p1)T_EachTimeThinker, 0);
break;
case tc_raisesector:
LoadSpecialLevelThinker((actionf_p1)T_RaiseSector, 0);
th = LoadSpecialLevelThinker((actionf_p1)T_RaiseSector, 0);
break;
/// \todo rewrite all the code that uses an elevator_t but isn't an elevator
/// \note working on it!
case tc_camerascanner:
LoadElevatorThinker((actionf_p1)T_CameraScanner, 0);
th = LoadElevatorThinker((actionf_p1)T_CameraScanner, 0);
break;
case tc_bouncecheese:
LoadSpecialLevelThinker((actionf_p1)T_BounceCheese, 2);
th = LoadSpecialLevelThinker((actionf_p1)T_BounceCheese, 2);
break;
case tc_startcrumble:
LoadElevatorThinker((actionf_p1)T_StartCrumble, 1);
th = LoadElevatorThinker((actionf_p1)T_StartCrumble, 1);
break;
case tc_marioblock:
LoadSpecialLevelThinker((actionf_p1)T_MarioBlock, 3);
th = LoadSpecialLevelThinker((actionf_p1)T_MarioBlock, 3);
break;
case tc_marioblockchecker:
LoadSpecialLevelThinker((actionf_p1)T_MarioBlockChecker, 0);
th = LoadSpecialLevelThinker((actionf_p1)T_MarioBlockChecker, 0);
break;
case tc_spikesector:
LoadSpecialLevelThinker((actionf_p1)T_SpikeSector, 0);
th = LoadSpecialLevelThinker((actionf_p1)T_SpikeSector, 0);
break;
case tc_floatsector:
LoadSpecialLevelThinker((actionf_p1)T_FloatSector, 0);
th = LoadSpecialLevelThinker((actionf_p1)T_FloatSector, 0);
break;
case tc_bridgethinker:
LoadSpecialLevelThinker((actionf_p1)T_BridgeThinker, 3);
th = LoadSpecialLevelThinker((actionf_p1)T_BridgeThinker, 3);
break;
case tc_laserflash:
LoadLaserThinker((actionf_p1)T_LaserFlash);
th = LoadLaserThinker((actionf_p1)T_LaserFlash);
break;
case tc_lightfade:
LoadLightlevelThinker((actionf_p1)T_LightFade);
th = LoadLightlevelThinker((actionf_p1)T_LightFade);
break;
case tc_executor:
LoadExecutorThinker((actionf_p1)T_ExecutorDelay);
th = LoadExecutorThinker((actionf_p1)T_ExecutorDelay);
restoreNum = true;
break;
case tc_disappear:
LoadDisappearThinker((actionf_p1)T_Disappear);
th = LoadDisappearThinker((actionf_p1)T_Disappear);
break;
case tc_fade:
LoadFadeThinker((actionf_p1)T_Fade);
th = LoadFadeThinker((actionf_p1)T_Fade);
break;
case tc_fadecolormap:
LoadFadeColormapThinker((actionf_p1)T_FadeColormap);
th = LoadFadeColormapThinker((actionf_p1)T_FadeColormap);
break;
case tc_planedisplace:
LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace);
th = LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace);
break;
#ifdef POLYOBJECTS
case tc_polyrotate:
LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate);
th = LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate);
break;
case tc_polymove:
LoadPolymoveThinker((actionf_p1)T_PolyObjMove);
th = LoadPolymoveThinker((actionf_p1)T_PolyObjMove);
break;
case tc_polywaypoint:
LoadPolywaypointThinker((actionf_p1)T_PolyObjWaypoint);
th = LoadPolywaypointThinker((actionf_p1)T_PolyObjWaypoint);
break;
case tc_polyslidedoor:
LoadPolyslidedoorThinker((actionf_p1)T_PolyDoorSlide);
th = LoadPolyslidedoorThinker((actionf_p1)T_PolyDoorSlide);
break;
case tc_polyswingdoor:
LoadPolyswingdoorThinker((actionf_p1)T_PolyDoorSwing);
th = LoadPolyswingdoorThinker((actionf_p1)T_PolyDoorSwing);
break;
case tc_polyflag:
LoadPolymoveThinker((actionf_p1)T_PolyObjFlag);
th = LoadPolymoveThinker((actionf_p1)T_PolyObjFlag);
break;
case tc_polydisplace:
LoadPolydisplaceThinker((actionf_p1)T_PolyObjDisplace);
th = LoadPolydisplaceThinker((actionf_p1)T_PolyObjDisplace);
break;
case tc_polyrotdisplace:
LoadPolyrotdisplaceThinker((actionf_p1)T_PolyObjRotDisplace);
th = LoadPolyrotdisplaceThinker((actionf_p1)T_PolyObjRotDisplace);
break;
case tc_polyfade:
LoadPolyfadeThinker((actionf_p1)T_PolyObjFade);
th = LoadPolyfadeThinker((actionf_p1)T_PolyObjFade);
break;
#endif
#ifdef ESLOPE
case tc_dynslopeline:
th = LoadDynamicSlopeThinker((actionf_p1)T_DynamicSlopeLine);
break;
case tc_dynslopevert:
th = LoadDynamicSlopeThinker((actionf_p1)T_DynamicSlopeVert);
break;
#endif // ESLOPE
case tc_scroll:
LoadScrollThinker((actionf_p1)T_Scroll);
th = LoadScrollThinker((actionf_p1)T_Scroll);
break;
case tc_friction:
LoadFrictionThinker((actionf_p1)T_Friction);
th = LoadFrictionThinker((actionf_p1)T_Friction);
break;
case tc_pusher:
LoadPusherThinker((actionf_p1)T_Pusher);
th = LoadPusherThinker((actionf_p1)T_Pusher);
break;
default:
I_Error("P_UnarchiveSpecials: Unknown tclass %d in savegame", tclass);
}
if (th)
P_AddThinker(i, th);
}
CONS_Debug(DBG_NETPLAY, "%u thinkers loaded\n", numloaded);
CONS_Debug(DBG_NETPLAY, "%u thinkers loaded in list %d\n", numloaded, i);
}
if (restoreNum)
{
executor_t *delay = NULL;
UINT32 mobjnum;
for (currentthinker = thinkercap.next; currentthinker != &thinkercap;
for (currentthinker = thlist[i].next; currentthinker != &thlist[i];
currentthinker = currentthinker->next)
{
if (currentthinker->function.acp1 == (actionf_p1)T_ExecutorDelay)
{
if (currentthinker->function.acp1 != (actionf_p1)T_ExecutorDelay)
continue;
delay = (void *)currentthinker;
if ((mobjnum = (UINT32)(size_t)delay->caller))
if (!(mobjnum = (UINT32)(size_t)delay->caller))
continue;
delay->caller = P_FindNewPosition(mobjnum);
}
}
}
}
///////////////////////////////////////////////////////////////////////////////
//
@ -3622,16 +3724,16 @@ static inline void P_FinishMobjs(void)
mobj_t *mobj;
// put info field there real value
for (currentthinker = thinkercap.next; currentthinker != &thinkercap;
for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ];
currentthinker = currentthinker->next)
{
if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
{
if (currentthinker->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mobj = (mobj_t *)currentthinker;
mobj->info = &mobjinfo[mobj->type];
}
}
}
static void P_RelinkPointers(void)
{
@ -3640,11 +3742,12 @@ static void P_RelinkPointers(void)
UINT32 temp;
// use info field (value = oldposition) to relink mobjs
for (currentthinker = thinkercap.next; currentthinker != &thinkercap;
for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ];
currentthinker = currentthinker->next)
{
if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
{
if (currentthinker->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mobj = (mobj_t *)currentthinker;
if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER)
@ -3722,7 +3825,6 @@ static void P_RelinkPointers(void)
}
}
}
}
//
// P_NetArchiveSpecials
@ -4021,16 +4123,16 @@ void P_SaveNetGame(void)
P_NetArchiveMisc();
// Assign the mobjnumber for pointer tracking
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mobj = (mobj_t *)th;
if (mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER)
continue;
mobj->mobjnum = i++;
}
}
P_NetArchivePlayers();
if (gamestate == GS_LEVEL)

View file

@ -815,9 +815,9 @@ void P_ReloadRings(void)
mapthing_t *mt = mapthings;
// scan the thinkers to find rings/spheres/hoops to unset
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)th;
@ -884,9 +884,9 @@ void P_SwitchSpheresBonusMode(boolean bonustime)
#endif
// scan the thinkers to find spheres to switch
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)th;
@ -1288,6 +1288,9 @@ static void P_LoadLineDefs2(void)
// Compile linedef 'text' from both sidedefs 'text' for appropriate specials.
switch(ld->special)
{
case 331: // Trigger linedef executor: Skin - Continuous
case 332: // Trigger linedef executor: Skin - Each time
case 333: // Trigger linedef executor: Skin - Once
case 443: // Calls a named Lua function
if (sides[ld->sidenum[0]].text)
{
@ -1498,6 +1501,9 @@ static void P_LoadRawSideDefs2(void *data)
break;
}
case 331: // Trigger linedef executor: Skin - Continuous
case 332: // Trigger linedef executor: Skin - Each time
case 333: // Trigger linedef executor: Skin - Once
case 443: // Calls a named Lua function
case 459: // Control text prompt (named tag)
{
@ -2284,7 +2290,6 @@ static void P_LevelInitStuff(void)
void P_LoadThingsOnly(void)
{
// Search through all the thinkers.
mobj_t *mo;
thinker_t *think;
INT32 i, viewid = -1, centerid = -1; // for skyboxes
@ -2299,15 +2304,11 @@ void P_LoadThingsOnly(void)
}
for (think = thinkercap.next; think != &thinkercap; think = think->next)
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
continue; // not a mobj thinker
mo = (mobj_t *)think;
if (mo)
P_RemoveMobj(mo);
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
P_RemoveMobj((mobj_t *)think);
}
P_LevelInitStuff();
@ -2867,7 +2868,10 @@ boolean P_SetupLevel(boolean skipprecip)
// reset the player starts
for (i = 0; i < MAXPLAYERS; i++)
playerstarts[i] = NULL;
playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
for (i = 0; i < MAX_DM_STARTS; i++)
deathmatchstarts[i] = NULL;
for (i = 0; i < 2; i++)
skyboxmo[i] = NULL;
@ -2903,7 +2907,10 @@ boolean P_SetupLevel(boolean skipprecip)
// reset the player starts
for (i = 0; i < MAXPLAYERS; i++)
playerstarts[i] = NULL;
playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
for (i = 0; i < MAX_DM_STARTS; i++)
deathmatchstarts[i] = NULL;
for (i = 0; i < 2; i++)
skyboxmo[i] = NULL;
@ -2921,7 +2928,7 @@ boolean P_SetupLevel(boolean skipprecip)
P_InitSpecials();
#ifdef ESLOPE
P_ResetDynamicSlopes();
P_ResetDynamicSlopes(fromnetsave);
#endif
P_LoadThings(loademblems);

View file

@ -25,68 +25,66 @@
#ifdef ESLOPE
static pslope_t *slopelist = NULL;
static UINT16 slopecount = 0;
pslope_t *slopelist = NULL;
UINT16 slopecount = 0;
// Calculate line normal
void P_CalculateSlopeNormal(pslope_t *slope) {
slope->normal.z = FINECOSINE(slope->zangle>>ANGLETOFINESHIFT);
slope->normal.x = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.x);
slope->normal.y = -FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.y);
slope->normal.x = FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.x);
slope->normal.y = FixedMul(FINESINE(slope->zangle>>ANGLETOFINESHIFT), slope->d.y);
}
// With a vertex slope that has its vertices set, configure relevant slope info
static void P_ReconfigureVertexSlope(pslope_t *slope)
/// Setup slope via 3 vertexes.
static void ReconfigureViaVertexes (pslope_t *slope, const vector3_t v1, const vector3_t v2, const vector3_t v3)
{
vector3_t vec1, vec2;
// Set slope normal
vec1.x = (slope->vertices[1]->x - slope->vertices[0]->x) << FRACBITS;
vec1.y = (slope->vertices[1]->y - slope->vertices[0]->y) << FRACBITS;
vec1.z = (slope->vertices[1]->z - slope->vertices[0]->z) << FRACBITS;
// Set origin.
FV3_Copy(&slope->o, &v1);
vec2.x = (slope->vertices[2]->x - slope->vertices[0]->x) << FRACBITS;
vec2.y = (slope->vertices[2]->y - slope->vertices[0]->y) << FRACBITS;
vec2.z = (slope->vertices[2]->z - slope->vertices[0]->z) << FRACBITS;
// Get slope's normal.
FV3_SubEx(&v2, &v1, &vec1);
FV3_SubEx(&v3, &v1, &vec2);
// ugggggggh fixed-point maaaaaaath
slope->extent = max(
max(max(abs(vec1.x), abs(vec1.y)), abs(vec1.z)),
max(max(abs(vec2.x), abs(vec2.y)), abs(vec2.z))
) >> (FRACBITS+5);
vec1.x /= slope->extent;
vec1.y /= slope->extent;
vec1.z /= slope->extent;
vec2.x /= slope->extent;
vec2.y /= slope->extent;
vec2.z /= slope->extent;
// Set some defaults for a non-sloped "slope"
if (vec1.z == 0 && vec2.z == 0)
{
/// \todo Fix fully flat cases.
FV3_Cross(&vec1, &vec2, &slope->normal);
slope->extent = R_PointToDist2(0, 0, R_PointToDist2(0, 0, slope->normal.x, slope->normal.y), slope->normal.z);
if (slope->normal.z < 0)
slope->extent = -slope->extent;
slope->normal.x = FixedDiv(slope->normal.x, slope->extent);
slope->normal.y = FixedDiv(slope->normal.y, slope->extent);
slope->normal.z = FixedDiv(slope->normal.z, slope->extent);
// Set origin
slope->o.x = slope->vertices[0]->x << FRACBITS;
slope->o.y = slope->vertices[0]->y << FRACBITS;
slope->o.z = slope->vertices[0]->z << FRACBITS;
if (slope->normal.x == 0 && slope->normal.y == 0) { // Set some defaults for a non-sloped "slope"
slope->zangle = slope->xydirection = 0;
slope->zdelta = slope->d.x = slope->d.y = 0;
} else {
}
else
{
/// \note Using fixed point for vectorial products easily leads to overflows so we work around by downscaling them.
fixed_t m = max(
max(max(abs(vec1.x), abs(vec1.y)), abs(vec1.z)),
max(max(abs(vec2.x), abs(vec2.y)), abs(vec2.z))
) >> 5; // shifting right by 5 is good enough.
FV3_Cross(
FV3_Divide(&vec1, m),
FV3_Divide(&vec2, m),
&slope->normal
);
// NOTE: FV3_Magnitude() doesn't work properly in some cases, and chaining FixedHypot() seems to give worse results.
m = R_PointToDist2(0, 0, R_PointToDist2(0, 0, slope->normal.x, slope->normal.y), slope->normal.z);
// Invert normal if it's facing down.
if (slope->normal.z < 0)
m = -m;
FV3_Divide(&slope->normal, m);
// Get direction vector
slope->extent = R_PointToDist2(0, 0, slope->normal.x, slope->normal.y);
slope->d.x = -FixedDiv(slope->normal.x, slope->extent);
slope->d.y = -FixedDiv(slope->normal.y, slope->extent);
m = FixedHypot(slope->normal.x, slope->normal.y);
slope->d.x = -FixedDiv(slope->normal.x, m);
slope->d.y = -FixedDiv(slope->normal.y, m);
// Z delta
slope->zdelta = FixedDiv(slope->extent, slope->normal.z);
slope->zdelta = FixedDiv(m, slope->normal.z);
// Get angles
slope->xydirection = R_PointToAngle2(0, 0, slope->d.x, slope->d.y)+ANGLE_180;
@ -94,88 +92,95 @@ static void P_ReconfigureVertexSlope(pslope_t *slope)
}
}
// Recalculate dynamic slopes
void P_RunDynamicSlopes(void) {
pslope_t *slope;
/// Recalculate dynamic slopes.
void T_DynamicSlopeLine (dynplanethink_t* th)
{
pslope_t* slope = th->slope;
line_t* srcline = th->sourceline;
for (slope = slopelist; slope; slope = slope->next) {
fixed_t zdelta;
if (slope->flags & SL_NODYNAMIC)
continue;
switch(th->type) {
case DP_FRONTFLOOR:
zdelta = srcline->backsector->floorheight - srcline->frontsector->floorheight;
slope->o.z = srcline->frontsector->floorheight;
break;
switch(slope->refpos) {
case 1: // front floor
zdelta = slope->sourceline->backsector->floorheight - slope->sourceline->frontsector->floorheight;
slope->o.z = slope->sourceline->frontsector->floorheight;
case DP_FRONTCEIL:
zdelta = srcline->backsector->ceilingheight - srcline->frontsector->ceilingheight;
slope->o.z = srcline->frontsector->ceilingheight;
break;
case 2: // front ceiling
zdelta = slope->sourceline->backsector->ceilingheight - slope->sourceline->frontsector->ceilingheight;
slope->o.z = slope->sourceline->frontsector->ceilingheight;
break;
case 3: // back floor
zdelta = slope->sourceline->frontsector->floorheight - slope->sourceline->backsector->floorheight;
slope->o.z = slope->sourceline->backsector->floorheight;
break;
case 4: // back ceiling
zdelta = slope->sourceline->frontsector->ceilingheight - slope->sourceline->backsector->ceilingheight;
slope->o.z = slope->sourceline->backsector->ceilingheight;
break;
case 5: // vertices
{
mapthing_t *mt;
size_t i;
INT32 l;
line_t *line;
for (i = 0; i < 3; i++) {
mt = slope->vertices[i];
l = P_FindSpecialLineFromTag(799, mt->angle, -1);
if (l != -1) {
line = &lines[l];
mt->z = line->frontsector->floorheight >> FRACBITS;
}
}
case DP_BACKFLOOR:
zdelta = srcline->frontsector->floorheight - srcline->backsector->floorheight;
slope->o.z = srcline->backsector->floorheight;
break;
P_ReconfigureVertexSlope(slope);
}
continue; // TODO
case DP_BACKCEIL:
zdelta = srcline->frontsector->ceilingheight - srcline->backsector->ceilingheight;
slope->o.z = srcline->backsector->ceilingheight;
break;
default:
I_Error("P_RunDynamicSlopes: slope has invalid type!");
return;
}
if (slope->zdelta != FixedDiv(zdelta, slope->extent)) {
slope->zdelta = FixedDiv(zdelta, slope->extent);
slope->zangle = R_PointToAngle2(0, 0, slope->extent, -zdelta);
if (slope->zdelta != FixedDiv(zdelta, th->extent)) {
slope->zdelta = FixedDiv(zdelta, th->extent);
slope->zangle = R_PointToAngle2(0, 0, th->extent, -zdelta);
P_CalculateSlopeNormal(slope);
}
}
/// Mapthing-defined
void T_DynamicSlopeVert (dynplanethink_t* th)
{
pslope_t* slope = th->slope;
size_t i;
INT32 l;
for (i = 0; i < 3; i++) {
l = P_FindSpecialLineFromTag(799, th->tags[i], -1);
if (l != -1) {
th->vex[i].z = lines[l].frontsector->floorheight;
}
else
th->vex[i].z = 0;
}
//
// P_MakeSlope
//
// Alocates and fill the contents of a slope structure.
//
static pslope_t *P_MakeSlope(const vector3_t *o, const vector2_t *d,
const fixed_t zdelta, UINT8 flags)
ReconfigureViaVertexes(slope, th->vex[0], th->vex[1], th->vex[2]);
}
static inline void P_AddDynSlopeThinker (pslope_t* slope, dynplanetype_t type, line_t* sourceline, fixed_t extent, const INT16 tags[3], const vector3_t vx[3])
{
pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL);
memset(ret, 0, sizeof(*ret));
dynplanethink_t* th = Z_Calloc(sizeof (*th), PU_LEVSPEC, NULL);
switch (type)
{
case DP_VERTEX:
th->thinker.function.acp1 = (actionf_p1)T_DynamicSlopeVert;
memcpy(th->tags, tags, sizeof(th->tags));
memcpy(th->vex, vx, sizeof(th->vex));
break;
default:
th->thinker.function.acp1 = (actionf_p1)T_DynamicSlopeLine;
th->sourceline = sourceline;
th->extent = extent;
}
ret->o.x = o->x;
ret->o.y = o->y;
ret->o.z = o->z;
th->slope = slope;
th->type = type;
ret->d.x = d->x;
ret->d.y = d->y;
P_AddThinker(THINK_DYNSLOPE, &th->thinker);
}
ret->zdelta = zdelta;
/// Create a new slope and add it to the slope list.
static inline pslope_t* Slope_Add (const UINT8 flags)
{
pslope_t *ret = Z_Calloc(sizeof(pslope_t), PU_LEVEL, NULL);
ret->flags = flags;
// Add to the slope list
ret->next = slopelist;
slopelist = ret;
@ -185,13 +190,24 @@ static pslope_t *P_MakeSlope(const vector3_t *o, const vector2_t *d,
return ret;
}
//
// P_GetExtent
//
// Returns the distance to the first line within the sector that
// is intersected by a line parallel to the plane normal with the point (ox, oy)
//
static fixed_t P_GetExtent(sector_t *sector, line_t *line)
/// Alocates and fill the contents of a slope structure.
static pslope_t *MakeViaVectors(const vector3_t *o, const vector2_t *d,
const fixed_t zdelta, UINT8 flags)
{
pslope_t *ret = Slope_Add(flags);
FV3_Copy(&ret->o, o);
FV2_Copy(&ret->d, d);
ret->zdelta = zdelta;
ret->flags = flags;
return ret;
}
/// Get furthest perpendicular distance from all vertexes in a sector for a given line.
static fixed_t GetExtent(sector_t *sector, line_t *line)
{
// ZDoom code reference: v3float_t = vertex_t
fixed_t fardist = -FRACUNIT;
@ -224,14 +240,8 @@ static fixed_t P_GetExtent(sector_t *sector, line_t *line)
return fardist;
}
//
// P_SpawnSlope_Line
//
// Creates one or more slopes based on the given line type and front/back
// sectors.
//
void P_SpawnSlope_Line(int linenum)
/// Creates one or more slopes based on the given line type and front/back sectors.
static void line_SpawnViaLine(const int linenum, const boolean spawnthinker)
{
// With dynamic slopes, it's fine to just leave this function as normal,
// because checking to see if a slope had changed will waste more memory than
@ -249,12 +259,10 @@ void P_SpawnSlope_Line(int linenum)
boolean backceil = (special == 711 || special == 712 || special == 703);
UINT8 flags = 0; // Slope flags
if (line->flags & ML_NOSONIC)
if (line->flags & ML_NETONLY)
flags |= SL_NOPHYSICS;
if (!(line->flags & ML_NOTAILS))
flags |= SL_NODYNAMIC;
if (line->flags & ML_NOKNUX)
flags |= SL_ANCHORVERTEX;
if (line->flags & ML_NONET)
flags |= SL_DYNAMIC;
if(!frontfloor && !backfloor && !frontceil && !backceil)
{
@ -274,6 +282,7 @@ void P_SpawnSlope_Line(int linenum)
ny = -FixedDiv(line->dx, len);
}
// Set origin to line's center.
origin.x = line->v1->x + (line->v2->x - line->v1->x)/2;
origin.y = line->v1->y + (line->v2->y - line->v1->y)/2;
@ -286,7 +295,7 @@ void P_SpawnSlope_Line(int linenum)
direction.x = nx;
direction.y = ny;
extent = P_GetExtent(line->frontsector, line);
extent = GetExtent(line->frontsector, line);
if(extent < 0)
{
@ -304,104 +313,43 @@ void P_SpawnSlope_Line(int linenum)
if(frontfloor)
{
fixed_t highest, lowest;
size_t l;
point.z = line->frontsector->floorheight; // Startz
dz = FixedDiv(origin.z - point.z, extent); // Destinationz
// In P_SpawnSlopeLine the origin is the centerpoint of the sourcelinedef
fslope = line->frontsector->f_slope =
P_MakeSlope(&point, &direction, dz, flags);
// Set up some shit
fslope->extent = extent;
fslope->refpos = 1;
MakeViaVectors(&point, &direction, dz, flags);
// Now remember that f_slope IS a vector
// fslope->o = origin 3D point 1 of the vector
// fslope->d = destination 3D point 2 of the vector
// fslope->normal is a 3D line perpendicular to the 3D vector
// Sync the linedata of the line that started this slope
// TODO: Anything special for control sector based slopes later?
fslope->sourceline = line;
// To find the real highz/lowz of a slope, you need to check all the vertexes
// in the slope's sector with P_GetZAt to get the REAL lowz & highz
// Although these slopes are set by floorheights the ANGLE is what a slope is,
// so technically any slope can extend on forever (they are just bound by sectors)
// *You can use sourceline as a reference to see if two slopes really are the same
// Default points for high and low
highest = point.z > origin.z ? point.z : origin.z;
lowest = point.z < origin.z ? point.z : origin.z;
// Now check to see what the REAL high and low points of the slope inside the sector
// TODO: Is this really needed outside of FOFs? -Red
for (l = 0; l < line->frontsector->linecount; l++)
{
fixed_t height = P_GetZAt(line->frontsector->f_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y);
if (height > highest)
highest = height;
if (height < lowest)
lowest = height;
}
// Sets extra clipping data for the frontsector's slope
fslope->highz = highest;
fslope->lowz = lowest;
fslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
fslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
P_CalculateSlopeNormal(fslope);
if (spawnthinker && (flags & SL_DYNAMIC))
P_AddDynSlopeThinker(fslope, DP_FRONTFLOOR, line, extent, NULL, NULL);
}
if(frontceil)
{
fixed_t highest, lowest;
size_t l;
origin.z = line->backsector->ceilingheight;
point.z = line->frontsector->ceilingheight;
dz = FixedDiv(origin.z - point.z, extent);
cslope = line->frontsector->c_slope =
P_MakeSlope(&point, &direction, dz, flags);
// Set up some shit
cslope->extent = extent;
cslope->refpos = 2;
// Sync the linedata of the line that started this slope
// TODO: Anything special for control sector based slopes later?
cslope->sourceline = line;
// Remember the way the slope is formed
highest = point.z > origin.z ? point.z : origin.z;
lowest = point.z < origin.z ? point.z : origin.z;
for (l = 0; l < line->frontsector->linecount; l++)
{
fixed_t height = P_GetZAt(line->frontsector->c_slope, line->frontsector->lines[l]->v1->x, line->frontsector->lines[l]->v1->y);
if (height > highest)
highest = height;
if (height < lowest)
lowest = height;
}
// This line special sets extra clipping data for the frontsector's slope
cslope->highz = highest;
cslope->lowz = lowest;
MakeViaVectors(&point, &direction, dz, flags);
cslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
cslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
P_CalculateSlopeNormal(cslope);
if (spawnthinker && (flags & SL_DYNAMIC))
P_AddDynSlopeThinker(cslope, DP_FRONTCEIL, line, extent, NULL, NULL);
}
}
if(backfloor || backceil)
@ -413,7 +361,7 @@ void P_SpawnSlope_Line(int linenum)
direction.x = -nx;
direction.y = -ny;
extent = P_GetExtent(line->backsector, line);
extent = GetExtent(line->backsector, line);
if(extent < 0)
{
@ -429,88 +377,36 @@ void P_SpawnSlope_Line(int linenum)
if(backfloor)
{
fixed_t highest, lowest;
size_t l;
point.z = line->backsector->floorheight;
dz = FixedDiv(origin.z - point.z, extent);
fslope = line->backsector->f_slope =
P_MakeSlope(&point, &direction, dz, flags);
// Set up some shit
fslope->extent = extent;
fslope->refpos = 3;
// Sync the linedata of the line that started this slope
// TODO: Anything special for control sector based slopes later?
fslope->sourceline = line;
// Remember the way the slope is formed
highest = point.z > origin.z ? point.z : origin.z;
lowest = point.z < origin.z ? point.z : origin.z;
for (l = 0; l < line->backsector->linecount; l++)
{
fixed_t height = P_GetZAt(line->backsector->f_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y);
if (height > highest)
highest = height;
if (height < lowest)
lowest = height;
}
// This line special sets extra clipping data for the frontsector's slope
fslope->highz = highest;
fslope->lowz = lowest;
MakeViaVectors(&point, &direction, dz, flags);
fslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
fslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
P_CalculateSlopeNormal(fslope);
if (spawnthinker && (flags & SL_DYNAMIC))
P_AddDynSlopeThinker(fslope, DP_BACKFLOOR, line, extent, NULL, NULL);
}
if(backceil)
{
fixed_t highest, lowest;
size_t l;
origin.z = line->frontsector->ceilingheight;
point.z = line->backsector->ceilingheight;
dz = FixedDiv(origin.z - point.z, extent);
cslope = line->backsector->c_slope =
P_MakeSlope(&point, &direction, dz, flags);
// Set up some shit
cslope->extent = extent;
cslope->refpos = 4;
// Sync the linedata of the line that started this slope
// TODO: Anything special for control sector based slopes later?
cslope->sourceline = line;
// Remember the way the slope is formed
highest = point.z > origin.z ? point.z : origin.z;
lowest = point.z < origin.z ? point.z : origin.z;
for (l = 0; l < line->backsector->linecount; l++)
{
fixed_t height = P_GetZAt(line->backsector->c_slope, line->backsector->lines[l]->v1->x, line->backsector->lines[l]->v1->y);
if (height > highest)
highest = height;
if (height < lowest)
lowest = height;
}
// This line special sets extra clipping data for the backsector's slope
cslope->highz = highest;
cslope->lowz = lowest;
MakeViaVectors(&point, &direction, dz, flags);
cslope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
cslope->xydirection = R_PointToAngle2(origin.x, origin.y, point.x, point.y);
P_CalculateSlopeNormal(cslope);
if (spawnthinker && (flags & SL_DYNAMIC))
P_AddDynSlopeThinker(cslope, DP_BACKCEIL, line, extent, NULL, NULL);
}
}
@ -518,63 +414,99 @@ void P_SpawnSlope_Line(int linenum)
return;
}
//
// P_NewVertexSlope
//
// Creates a new slope from three vertices with the specified IDs
//
static pslope_t *P_NewVertexSlope(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flags)
/// Creates a new slope from three mapthings with the specified IDs
static pslope_t *MakeViaMapthings(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flags, const boolean spawnthinker)
{
size_t i;
mapthing_t* mt = mapthings;
mapthing_t* vertices[3] = {0};
INT16 tags[3] = {tag1, tag2, tag3};
pslope_t *ret = Z_Malloc(sizeof(pslope_t), PU_LEVEL, NULL);
memset(ret, 0, sizeof(*ret));
// Start by setting flags
ret->flags = flags;
// Now set up the vertex list
ret->vertices = Z_Malloc(3*sizeof(mapthing_t), PU_LEVEL, NULL);
memset(ret->vertices, 0, 3*sizeof(mapthing_t));
vector3_t vx[3];
pslope_t* ret = Slope_Add(flags);
// And... look for the vertices in question.
for (i = 0; i < nummapthings; i++, mt++) {
if (mt->type != 750) // Haha, I'm hijacking the old Chaos Spawn thingtype for something!
continue;
if (!ret->vertices[0] && mt->angle == tag1)
ret->vertices[0] = mt;
else if (!ret->vertices[1] && mt->angle == tag2)
ret->vertices[1] = mt;
else if (!ret->vertices[2] && mt->angle == tag3)
ret->vertices[2] = mt;
if (!vertices[0] && mt->angle == tag1)
vertices[0] = mt;
else if (!vertices[1] && mt->angle == tag2)
vertices[1] = mt;
else if (!vertices[2] && mt->angle == tag3)
vertices[2] = mt;
}
// Now set heights for each vertex, because they haven't been set yet
for (i = 0; i < 3; i++) {
mt = ret->vertices[i];
mt = vertices[i];
if (!mt) // If a vertex wasn't found, it's game over. There's nothing you can do to recover (except maybe try and kill the slope instead - TODO?)
I_Error("P_NewVertexSlope: Slope vertex %s (for linedef tag %d) not found!", sizeu1(i), tag1);
I_Error("MakeViaMapthings: Slope vertex %s (for linedef tag %d) not found!", sizeu1(i), tag1);
vx[i].x = mt->x << FRACBITS;
vx[i].y = mt->y << FRACBITS;
if (mt->extrainfo)
mt->z = mt->options;
vx[i].z = mt->options << FRACBITS;
else
mt->z = (R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector->floorheight >> FRACBITS) + (mt->options >> ZSHIFT);
vx[i].z = (R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector->floorheight) + ((mt->options >> ZSHIFT) << FRACBITS);
}
P_ReconfigureVertexSlope(ret);
ret->refpos = 5;
ReconfigureViaVertexes(ret, vx[0], vx[1], vx[2]);
// Add to the slope list
ret->next = slopelist;
slopelist = ret;
slopecount++;
ret->id = slopecount;
if (spawnthinker && (flags & SL_DYNAMIC))
P_AddDynSlopeThinker(ret, DP_VERTEX, NULL, 0, tags, vx);
return ret;
}
/// Create vertex based slopes.
static void line_SpawnViaVertexes(const int linenum, const boolean spawnthinker)
{
line_t *line = lines + linenum;
side_t *side;
pslope_t **slopetoset;
UINT16 tag1, tag2, tag3;
UINT8 flags = 0;
if (line->flags & ML_NETONLY)
flags |= SL_NOPHYSICS;
if (line->flags & ML_NONET)
flags |= SL_DYNAMIC;
switch(line->special)
{
case 704:
slopetoset = &line->frontsector->f_slope;
side = &sides[line->sidenum[0]];
break;
case 705:
slopetoset = &line->frontsector->c_slope;
side = &sides[line->sidenum[0]];
break;
case 714:
slopetoset = &line->backsector->f_slope;
side = &sides[line->sidenum[1]];
break;
case 715:
slopetoset = &line->backsector->c_slope;
side = &sides[line->sidenum[1]];
default:
return;
}
if (line->flags & ML_EFFECT6)
{
tag1 = line->tag;
tag2 = side->textureoffset >> FRACBITS;
tag3 = side->rowoffset >> FRACBITS;
}
else
tag1 = tag2 = tag3 = line->tag;
*slopetoset = MakeViaMapthings(tag1, tag2, tag3, flags, spawnthinker);
side->sector->hasslope = true;
}
//
@ -620,56 +552,20 @@ pslope_t *P_SlopeById(UINT16 id)
return ret;
}
// Reset the dynamic slopes pointer, and read all of the fancy schmancy slopes
void P_ResetDynamicSlopes(void) {
/// Reset slopes and read them from special lines.
void P_ResetDynamicSlopes(const UINT32 fromsave) {
size_t i;
#ifdef ESLOPE_TYPESHIM // Rewrite old specials to new ones, and give a console warning
boolean warned = false;
#endif
boolean spawnthinkers = !(boolean)fromsave;
slopelist = NULL;
slopecount = 0;
// We'll handle copy slopes later, after all the tag lists have been made.
// Yes, this means copied slopes won't affect things' spawning heights. Too bad for you.
/// Generates line special-defined slopes.
for (i = 0; i < numlines; i++)
{
switch (lines[i].special)
{
#ifdef ESLOPE_TYPESHIM // Rewrite old specials to new ones, and give a console warning
#define WARNME if (!warned) {warned = true; CONS_Alert(CONS_WARNING, "This level uses old slope specials.\nA conversion will be needed before 2.2's release.\n");}
case 386:
case 387:
case 388:
lines[i].special += 700-386;
WARNME
P_SpawnSlope_Line(i);
break;
case 389:
case 390:
case 391:
case 392:
lines[i].special += 710-389;
WARNME
P_SpawnSlope_Line(i);
break;
case 393:
lines[i].special = 703;
WARNME
P_SpawnSlope_Line(i);
break;
case 394:
case 395:
case 396:
lines[i].special += 720-394;
WARNME
break;
#endif
case 700:
case 701:
case 702:
@ -678,62 +574,34 @@ void P_ResetDynamicSlopes(void) {
case 711:
case 712:
case 713:
P_SpawnSlope_Line(i);
line_SpawnViaLine(i, spawnthinkers);
break;
case 704:
case 705:
case 714:
case 715:
{
pslope_t **slopetoset;
size_t which = lines[i].special;
UINT8 flags = SL_VERTEXSLOPE;
if (lines[i].flags & ML_NOSONIC)
flags |= SL_NOPHYSICS;
if (!(lines[i].flags & ML_NOTAILS))
flags |= SL_NODYNAMIC;
if (which == 704)
{
slopetoset = &lines[i].frontsector->f_slope;
which = 0;
}
else if (which == 705)
{
slopetoset = &lines[i].frontsector->c_slope;
which = 0;
}
else if (which == 714)
{
slopetoset = &lines[i].backsector->f_slope;
which = 1;
}
else // 715
{
slopetoset = &lines[i].backsector->c_slope;
which = 1;
}
if (lines[i].flags & ML_NOKNUX)
*slopetoset = P_NewVertexSlope(lines[i].tag, sides[lines[i].sidenum[which]].textureoffset >> FRACBITS,
sides[lines[i].sidenum[which]].rowoffset >> FRACBITS, flags);
else
*slopetoset = P_NewVertexSlope(lines[i].tag, lines[i].tag, lines[i].tag, flags);
sides[lines[i].sidenum[which]].sector->hasslope = true;
}
line_SpawnViaVertexes(i, spawnthinkers);
break;
default:
break;
}
}
/// Copies slopes from tagged sectors via line specials.
/// \note Doesn't actually copy, but instead they share the same pointers.
for (i = 0; i < numlines; i++)
switch (lines[i].special)
{
case 720:
case 721:
case 722:
P_CopySectorSlope(&lines[i]);
default:
break;
}
}
// ============================================================================
//

View file

@ -13,14 +13,17 @@
#ifndef P_SLOPES_H__
#define P_SLOPES_H__
#include "m_fixed.h" // Vectors
#ifdef ESLOPE
extern pslope_t *slopelist;
extern UINT16 slopecount;
void P_LinkSlopeThinkers (void);
void P_CalculateSlopeNormal(pslope_t *slope);
void P_ResetDynamicSlopes(void);
void P_RunDynamicSlopes(void);
// P_SpawnSlope_Line
// Creates one or more slopes based on the given line type and front/back
// sectors.
void P_SpawnSlope_Line(int linenum);
void P_ResetDynamicSlopes(const UINT32 fromsave);
//
// P_CopySectorSlope
@ -42,7 +45,34 @@ fixed_t P_GetWallTransferMomZ(mobj_t *mo, pslope_t *slope);
void P_HandleSlopeLanding(mobj_t *thing, pslope_t *slope);
void P_ButteredSlope(mobj_t *mo);
#endif
// EOF
/// Dynamic plane type enum for the thinker. Will have a different functionality depending on this.
typedef enum {
DP_FRONTFLOOR,
DP_FRONTCEIL,
DP_BACKFLOOR,
DP_BACKCEIL,
DP_VERTEX
} dynplanetype_t;
/// Permit slopes to be dynamically altered through a thinker.
typedef struct
{
thinker_t thinker;
pslope_t* slope;
dynplanetype_t type;
// Used by line slopes.
line_t* sourceline;
fixed_t extent;
// Used by mapthing vertex slopes.
INT16 tags[3];
vector3_t vex[3];
} dynplanethink_t;
void T_DynamicSlopeLine (dynplanethink_t* th);
void T_DynamicSlopeVert (dynplanethink_t* th);
#endif // #ifdef ESLOPE
#endif // #ifndef P_SLOPES_H__

View file

@ -36,6 +36,7 @@
#include "m_cond.h" //unlock triggers
#include "lua_hook.h" // LUAh_LinedefExecute
#include "f_finale.h" // control text prompt
#include "r_things.h" // skins
#ifdef HW3SOUND
#include "hardware/hw3sound.h"
@ -98,7 +99,6 @@ typedef struct
thinker_t **thinkers;
} thinkerlist_t;
static void P_SearchForDisableLinedefs(void);
static void P_SpawnScrollers(void);
static void P_SpawnFriction(void);
static void P_SpawnPushers(void);
@ -1644,7 +1644,7 @@ static void P_AddExecutorDelay(line_t *line, mobj_t *mobj, sector_t *sector)
e->sector = sector;
e->timer = (line->backsector->ceilingheight>>FRACBITS)+(line->backsector->floorheight>>FRACBITS);
P_SetTarget(&e->caller, mobj); // Use P_SetTarget to make sure the mobj doesn't get freed while we're delaying.
P_AddThinker(&e->thinker);
P_AddThinker(THINK_MAIN, &e->thinker);
}
/** Used by P_RunTriggerLinedef to check a NiGHTS trigger linedef's conditions
@ -2008,7 +2008,12 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
if (!P_CheckNightsTriggerLine(triggerline, actor))
return false;
break;
case 331: // continuous
case 332: // each time
case 333: // once
if (!(actor && actor->player && ((stricmp(triggerline->text, skins[actor->player->skin].name) == 0) ^ ((triggerline->flags & ML_NOCLIMB) == ML_NOCLIMB))))
return false;
break;
default:
break;
}
@ -2141,6 +2146,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
|| specialtype == 326 // DeNightserize - Once
|| specialtype == 328 // Nights lap - Once
|| specialtype == 330 // Nights Bonus Time - Once
|| specialtype == 333 // Skin - Once
|| specialtype == 399) // Level Load
triggerline->special = 0; // Clear it out
@ -2181,7 +2187,8 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller)
|| lines[masterline].special == 306 // Character ability - Each time
|| lines[masterline].special == 310 // CTF Red team - Each time
|| lines[masterline].special == 312 // CTF Blue team - Each time
|| lines[masterline].special == 322) // Trigger on X calls - Each Time
|| lines[masterline].special == 322 // Trigger on X calls - Each Time
|| lines[masterline].special == 332)// Skin - Each time
continue;
if (lines[masterline].special < 300
@ -2253,7 +2260,7 @@ void P_SwitchWeather(INT32 weathernum)
thinker_t *think;
precipmobj_t *precipmobj;
for (think = thinkercap.next; think != &thinkercap; think = think->next)
for (think = thlist[THINK_PRECIP].next; think != &thlist[THINK_PRECIP]; think = think->next)
{
if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
continue; // not a precipmobj thinker
@ -2269,7 +2276,7 @@ void P_SwitchWeather(INT32 weathernum)
precipmobj_t *precipmobj;
state_t *st;
for (think = thinkercap.next; think != &thinkercap; think = think->next)
for (think = thlist[THINK_PRECIP].next; think != &thlist[THINK_PRECIP]; think = think->next)
{
if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
continue; // not a precipmobj thinker
@ -3144,7 +3151,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
scroll_t *scroller;
thinker_t *th;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)T_Scroll)
continue;
@ -3382,7 +3389,10 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
// if flags changed, reset sector's light list
if (rover->flags != oldflags)
{
sec->moved = true;
P_RecalcPrecipInSector(sec);
}
}
}
@ -3980,10 +3990,10 @@ void P_SetupSignExit(player_t *player)
// didn't find any signposts in the exit sector.
// spin all signposts in the level then.
for (think = thinkercap.next; think != &thinkercap; think = think->next)
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
continue; // not a mobj thinker
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
thing = (mobj_t *)think;
if (thing->type != MT_SIGN)
@ -4010,23 +4020,18 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
{
thinker_t *think;
mobj_t *mo;
INT32 specialnum = 0;
INT32 specialnum = (flag == MT_REDFLAG) ? 3 : 4;
for (think = thinkercap.next; think != &thinkercap; think = think->next)
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
continue; // not a mobj thinker
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)think;
if (mo->type != flag)
continue;
if (mo->type == MT_REDFLAG)
specialnum = 3;
else if (mo->type == MT_BLUEFLAG)
specialnum = 4;
if (GETSECSPECIAL(mo->subsector->sector->special, 4) == specialnum)
return true;
else if (mo->subsector->sector->ffloors) // Check the 3D floors
@ -4041,8 +4046,10 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
if (GETSECSPECIAL(rover->master->frontsector->special, 4) != specialnum)
continue;
if (mo->z <= P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)
&& mo->z >= P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector))
if (!(mo->z <= P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)
&& mo->z >= P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector)))
continue;
return true;
}
}
@ -4445,13 +4452,13 @@ void P_ProcessSpecialSector(player_t *player, sector_t *sector, sector_t *rovers
// Find the center of the Eggtrap and release all the pretty animals!
// The chimps are my friends.. heeheeheheehehee..... - LouisJM
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_EGGTRAP)
if (mo2->type != MT_EGGTRAP)
continue;
P_KillMobj(mo2, NULL, player->mo, 0);
}
@ -4751,20 +4758,23 @@ DoneSection2:
// scan the thinkers
// to find the first waypoint
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_TUBEWAYPOINT && mo2->threshold == sequence
&& mo2->health == 0)
{
if (mo2->type != MT_TUBEWAYPOINT)
continue;
if (mo2->threshold != sequence)
continue;
if (mo2->health != 0)
continue;
waypoint = mo2;
break;
}
}
if (!waypoint)
{
@ -4830,21 +4840,23 @@ DoneSection2:
// scan the thinkers
// to find the last waypoint
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_TUBEWAYPOINT && mo2->threshold == sequence)
{
if (mo2->type != MT_TUBEWAYPOINT)
continue;
if (mo2->threshold != sequence)
continue;
if (!waypoint)
waypoint = mo2;
else if (mo2->health > waypoint->health)
waypoint = mo2;
}
}
if (!waypoint)
{
@ -4982,9 +4994,9 @@ DoneSection2:
// scan the thinkers
// to find the first waypoint
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -5020,9 +5032,9 @@ DoneSection2:
}
// Find waypoint before this one (waypointlow)
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -5047,9 +5059,9 @@ DoneSection2:
}
// Find waypoint after this one (waypointhigh)
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -5566,11 +5578,6 @@ void P_UpdateSpecials(void)
// POINT LIMIT
P_CheckPointLimit();
#ifdef ESLOPE
// Dynamic slopeness
P_RunDynamicSlopes();
#endif
// ANIMATE TEXTURES
for (anim = anims; anim < lastanim; anim++)
{
@ -5640,26 +5647,26 @@ ffloor_t *P_GetFFloorByID(sector_t *sec, UINT16 id)
/** Adds a newly formed 3Dfloor structure to a sector's ffloors list.
*
* \param sec Target sector.
* \param ffloor Newly formed 3Dfloor structure.
* \param fflr Newly formed 3Dfloor structure.
* \sa P_AddFakeFloor
*/
static inline void P_AddFFloorToList(sector_t *sec, ffloor_t *ffloor)
static inline void P_AddFFloorToList(sector_t *sec, ffloor_t *fflr)
{
ffloor_t *rover;
if (!sec->ffloors)
{
sec->ffloors = ffloor;
ffloor->next = 0;
ffloor->prev = 0;
sec->ffloors = fflr;
fflr->next = 0;
fflr->prev = 0;
return;
}
for (rover = sec->ffloors; rover->next; rover = rover->next);
rover->next = ffloor;
ffloor->prev = rover;
ffloor->next = 0;
rover->next = fflr;
fflr->prev = rover;
fflr->next = 0;
}
/** Adds a 3Dfloor.
@ -5674,7 +5681,7 @@ static inline void P_AddFFloorToList(sector_t *sec, ffloor_t *ffloor)
*/
static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, ffloortype_e flags, thinkerlist_t *secthinkers)
{
ffloor_t *ffloor;
ffloor_t *fflr;
thinker_t *th;
friction_t *f;
pusher_t *p;
@ -5684,8 +5691,8 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
if (sec == sec2)
return NULL; //Don't need a fake floor on a control sector.
if ((ffloor = (P_GetFFloorBySec(sec, sec2))))
return ffloor; // If this ffloor already exists, return it
if ((fflr = (P_GetFFloorBySec(sec, sec2))))
return fflr; // If this ffloor already exists, return it
if (sec2->ceilingheight < sec2->floorheight)
{
@ -5724,27 +5731,27 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
}
// Add the floor
ffloor = Z_Calloc(sizeof (*ffloor), PU_LEVEL, NULL);
ffloor->secnum = sec2 - sectors;
ffloor->target = sec;
ffloor->bottomheight = &sec2->floorheight;
ffloor->bottompic = &sec2->floorpic;
ffloor->bottomxoffs = &sec2->floor_xoffs;
ffloor->bottomyoffs = &sec2->floor_yoffs;
ffloor->bottomangle = &sec2->floorpic_angle;
fflr = Z_Calloc(sizeof (*fflr), PU_LEVEL, NULL);
fflr->secnum = sec2 - sectors;
fflr->target = sec;
fflr->bottomheight = &sec2->floorheight;
fflr->bottompic = &sec2->floorpic;
fflr->bottomxoffs = &sec2->floor_xoffs;
fflr->bottomyoffs = &sec2->floor_yoffs;
fflr->bottomangle = &sec2->floorpic_angle;
// Add the ceiling
ffloor->topheight = &sec2->ceilingheight;
ffloor->toppic = &sec2->ceilingpic;
ffloor->toplightlevel = &sec2->lightlevel;
ffloor->topxoffs = &sec2->ceiling_xoffs;
ffloor->topyoffs = &sec2->ceiling_yoffs;
ffloor->topangle = &sec2->ceilingpic_angle;
fflr->topheight = &sec2->ceilingheight;
fflr->toppic = &sec2->ceilingpic;
fflr->toplightlevel = &sec2->lightlevel;
fflr->topxoffs = &sec2->ceiling_xoffs;
fflr->topyoffs = &sec2->ceiling_yoffs;
fflr->topangle = &sec2->ceilingpic_angle;
#ifdef ESLOPE
// Add slopes
ffloor->t_slope = &sec2->c_slope;
ffloor->b_slope = &sec2->f_slope;
fflr->t_slope = &sec2->c_slope;
fflr->b_slope = &sec2->f_slope;
// mark the target sector as having slopes, if the FOF has any of its own
// (this fixes FOF slopes glitching initially at level load in software mode)
if (sec2->hasslope)
@ -5757,10 +5764,10 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
if ((flags & FF_SOLID) && (master->flags & ML_EFFECT2)) // Block all BUT player
flags &= ~FF_BLOCKPLAYER;
ffloor->spawnflags = ffloor->flags = flags;
ffloor->master = master;
ffloor->norender = INFTICS;
ffloor->fadingdata = NULL;
fflr->spawnflags = fflr->flags = flags;
fflr->master = master;
fflr->norender = INFTICS;
fflr->fadingdata = NULL;
// Scan the thinkers to check for special conditions applying to this FOF.
// If we have thinkers sorted by sector, just check the relevant ones;
@ -5770,7 +5777,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
// Just initialise both of these to placate the compiler.
i = 0;
th = thinkercap.next;
th = thlist[THINK_MAIN].next;
for(;;)
{
@ -5780,7 +5787,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
th = secthinkers[sec2num].thinkers[i];
else break;
}
else if (th == &thinkercap)
else if (th == &thlist[THINK_MAIN])
break;
// Should this FOF have spikeness?
@ -5816,14 +5823,14 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
if (flags & FF_TRANSLUCENT)
{
if (sides[master->sidenum[0]].toptexture > 0)
ffloor->alpha = sides[master->sidenum[0]].toptexture; // for future reference, "#0" is 1, and "#255" is 256. Be warned
fflr->alpha = sides[master->sidenum[0]].toptexture; // for future reference, "#0" is 1, and "#255" is 256. Be warned
else
ffloor->alpha = 0x80;
fflr->alpha = 0x80;
}
else
ffloor->alpha = 0xff;
fflr->alpha = 0xff;
ffloor->spawnalpha = ffloor->alpha; // save for netgames
fflr->spawnalpha = fflr->alpha; // save for netgames
if (flags & FF_QUICKSAND)
CheckForQuicksand = true;
@ -5847,9 +5854,9 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f
CheckForFloatBob = true;
}
P_AddFFloorToList(sec, ffloor);
P_AddFFloorToList(sec, fflr);
return ffloor;
return fflr;
}
//
@ -5870,7 +5877,7 @@ static void P_AddSpikeThinker(sector_t *sec, INT32 referrer)
// create and initialize new thinker
spikes = Z_Calloc(sizeof (*spikes), PU_LEVSPEC, NULL);
P_AddThinker(&spikes->thinker);
P_AddThinker(THINK_MAIN, &spikes->thinker);
spikes->thinker.function.acp1 = (actionf_p1)T_SpikeSector;
@ -5892,7 +5899,7 @@ static void P_AddFloatThinker(sector_t *sec, INT32 tag, line_t *sourceline)
// create and initialize new thinker
floater = Z_Calloc(sizeof (*floater), PU_LEVSPEC, NULL);
P_AddThinker(&floater->thinker);
P_AddThinker(THINK_MAIN, &floater->thinker);
floater->thinker.function.acp1 = (actionf_p1)T_FloatSector;
@ -5916,7 +5923,7 @@ static inline void P_AddBridgeThinker(line_t *sourceline, sector_t *sec)
// create an initialize new thinker
bridge = Z_Calloc(sizeof (*bridge), PU_LEVSPEC, NULL);
P_AddThinker(&bridge->thinker);
P_AddThinker(THINK_MAIN, &bridge->thinker);
bridge->thinker.function.acp1 = (actionf_p1)T_BridgeThinker;
@ -5952,7 +5959,7 @@ static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control,
// create and initialize new displacement thinker
displace = Z_Calloc(sizeof (*displace), PU_LEVSPEC, NULL);
P_AddThinker(&displace->thinker);
P_AddThinker(THINK_MAIN, &displace->thinker);
displace->thinker.function.acp1 = (actionf_p1)T_PlaneDisplace;
displace->affectee = affectee;
@ -5979,7 +5986,7 @@ static void P_AddBlockThinker(sector_t *sec, line_t *sourceline)
// create and initialize new elevator thinker
block = Z_Calloc(sizeof (*block), PU_LEVSPEC, NULL);
P_AddThinker(&block->thinker);
P_AddThinker(THINK_MAIN, &block->thinker);
block->thinker.function.acp1 = (actionf_p1)T_MarioBlockChecker;
block->sourceline = sourceline;
@ -6008,7 +6015,7 @@ static void P_AddRaiseThinker(sector_t *sec, line_t *sourceline)
levelspecthink_t *raise;
raise = Z_Calloc(sizeof (*raise), PU_LEVSPEC, NULL);
P_AddThinker(&raise->thinker);
P_AddThinker(THINK_MAIN, &raise->thinker);
raise->thinker.function.acp1 = (actionf_p1)T_RaiseSector;
@ -6047,7 +6054,7 @@ static void P_AddOldAirbob(sector_t *sec, line_t *sourceline, boolean noadjust)
levelspecthink_t *airbob;
airbob = Z_Calloc(sizeof (*airbob), PU_LEVSPEC, NULL);
P_AddThinker(&airbob->thinker);
P_AddThinker(THINK_MAIN, &airbob->thinker);
airbob->thinker.function.acp1 = (actionf_p1)T_RaiseSector;
@ -6108,7 +6115,7 @@ static inline void P_AddThwompThinker(sector_t *sec, sector_t *actionsector, lin
// create and initialize new elevator thinker
thwomp = Z_Calloc(sizeof (*thwomp), PU_LEVSPEC, NULL);
P_AddThinker(&thwomp->thinker);
P_AddThinker(THINK_MAIN, &thwomp->thinker);
thwomp->thinker.function.acp1 = (actionf_p1)T_ThwompSector;
@ -6144,7 +6151,7 @@ static inline void P_AddNoEnemiesThinker(sector_t *sec, line_t *sourceline)
// create and initialize new thinker
nobaddies = Z_Calloc(sizeof (*nobaddies), PU_LEVSPEC, NULL);
P_AddThinker(&nobaddies->thinker);
P_AddThinker(THINK_MAIN, &nobaddies->thinker);
nobaddies->thinker.function.acp1 = (actionf_p1)T_NoEnemiesSector;
@ -6160,13 +6167,13 @@ static inline void P_AddNoEnemiesThinker(sector_t *sec, line_t *sourceline)
* \sa P_SpawnSpecials, T_EachTimeThinker
* \author SSNTails <http://www.ssntails.org>
*/
static inline void P_AddEachTimeThinker(sector_t *sec, line_t *sourceline)
static void P_AddEachTimeThinker(sector_t *sec, line_t *sourceline)
{
levelspecthink_t *eachtime;
// create and initialize new thinker
eachtime = Z_Calloc(sizeof (*eachtime), PU_LEVSPEC, NULL);
P_AddThinker(&eachtime->thinker);
P_AddThinker(THINK_MAIN, &eachtime->thinker);
eachtime->thinker.function.acp1 = (actionf_p1)T_EachTimeThinker;
@ -6188,7 +6195,7 @@ static inline void P_AddCameraScanner(sector_t *sourcesec, sector_t *actionsecto
// create and initialize new elevator thinker
elevator = Z_Calloc(sizeof (*elevator), PU_LEVSPEC, NULL);
P_AddThinker(&elevator->thinker);
P_AddThinker(THINK_MAIN, &elevator->thinker);
elevator->thinker.function.acp1 = (actionf_p1)T_CameraScanner;
elevator->type = elevateBounce;
@ -6212,30 +6219,30 @@ void T_LaserFlash(laserthink_t *flash)
msecnode_t *node;
mobj_t *thing;
sector_t *sourcesec;
ffloor_t *ffloor = flash->ffloor;
ffloor_t *fflr = flash->ffloor;
sector_t *sector = flash->sector;
fixed_t top, bottom;
if (!ffloor || !(ffloor->flags & FF_EXISTS))
if (!fflr || !(fflr->flags & FF_EXISTS))
return;
if (leveltime & 2)
//ffloor->flags |= FF_RENDERALL;
ffloor->alpha = 0xB0;
//fflr->flags |= FF_RENDERALL;
fflr->alpha = 0xB0;
else
//ffloor->flags &= ~FF_RENDERALL;
ffloor->alpha = 0x90;
//fflr->flags &= ~FF_RENDERALL;
fflr->alpha = 0x90;
sourcesec = ffloor->master->frontsector; // Less to type!
sourcesec = fflr->master->frontsector; // Less to type!
#ifdef ESLOPE
top = (*ffloor->t_slope) ? P_GetZAt(*ffloor->t_slope, sector->soundorg.x, sector->soundorg.y)
: *ffloor->topheight;
bottom = (*ffloor->b_slope) ? P_GetZAt(*ffloor->b_slope, sector->soundorg.x, sector->soundorg.y)
: *ffloor->bottomheight;
top = (*fflr->t_slope) ? P_GetZAt(*fflr->t_slope, sector->soundorg.x, sector->soundorg.y)
: *fflr->topheight;
bottom = (*fflr->b_slope) ? P_GetZAt(*fflr->b_slope, sector->soundorg.x, sector->soundorg.y)
: *fflr->bottomheight;
sector->soundorg.z = (top + bottom)/2;
#else
sector->soundorg.z = (*ffloor->topheight + *ffloor->bottomheight)/2;
sector->soundorg.z = (*fflr->topheight + *fflr->bottomheight)/2;
#endif
S_StartSound(&sector->soundorg, sfx_laser);
@ -6244,7 +6251,7 @@ void T_LaserFlash(laserthink_t *flash)
{
thing = node->m_thing;
if ((ffloor->master->flags & ML_EFFECT1)
if ((fflr->master->flags & ML_EFFECT1)
&& thing->flags & MF_BOSS)
continue; // Don't hurt bosses
@ -6268,7 +6275,7 @@ void T_LaserFlash(laserthink_t *flash)
/** Adds a laser thinker to a 3Dfloor.
*
* \param ffloor 3Dfloor to turn into a laser block.
* \param fflr 3Dfloor to turn into a laser block.
* \param sector Target sector.
* \param secthkiners Lists of thinkers sorted by sector. May be NULL.
* \sa T_LaserFlash
@ -6277,17 +6284,17 @@ void T_LaserFlash(laserthink_t *flash)
static inline void EV_AddLaserThinker(sector_t *sec, sector_t *sec2, line_t *line, thinkerlist_t *secthinkers)
{
laserthink_t *flash;
ffloor_t *ffloor = P_AddFakeFloor(sec, sec2, line, laserflags, secthinkers);
ffloor_t *fflr = P_AddFakeFloor(sec, sec2, line, laserflags, secthinkers);
if (!ffloor)
if (!fflr)
return;
flash = Z_Calloc(sizeof (*flash), PU_LEVSPEC, NULL);
P_AddThinker(&flash->thinker);
P_AddThinker(THINK_MAIN, &flash->thinker);
flash->thinker.function.acp1 = (actionf_p1)T_LaserFlash;
flash->ffloor = ffloor;
flash->ffloor = fflr;
flash->sector = sec; // For finding mobjs
flash->sec = sec2;
flash->sourceline = line;
@ -6351,7 +6358,7 @@ void P_InitSpecials(void)
static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs)
{
if (!(master->flags & ML_NOSONIC)) // Modify floor flat alignment unless NOSONIC flag is set
if (!(master->flags & ML_NETONLY)) // Modify floor flat alignment unless ML_NETONLY flag is set
{
sector->spawn_flrpic_angle = sector->floorpic_angle = flatangle;
sector->floor_xoffs += xoffs;
@ -6361,7 +6368,7 @@ static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flata
sector->spawn_flr_yoffs = sector->floor_yoffs;
}
if (!(master->flags & ML_NOTAILS)) // Modify ceiling flat alignment unless NOTAILS flag is set
if (!(master->flags & ML_NONET)) // Modify ceiling flat alignment unless ML_NONET flag is set
{
sector->spawn_ceilpic_angle = sector->ceilingpic_angle = flatangle;
sector->ceiling_xoffs += xoffs;
@ -6442,8 +6449,6 @@ void P_SpawnSpecials(INT32 fromnetsave)
}
}
P_SearchForDisableLinedefs(); // Disable linedefs are now allowed to disable *any* line
P_SpawnScrollers(); // Add generalized scrollers
P_SpawnFriction(); // Friction model using linedefs
P_SpawnPushers(); // Pusher model using linedefs
@ -6453,7 +6458,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
secthinkers = Z_Calloc(numsectors * sizeof(thinkerlist_t), PU_STATIC, NULL);
// Firstly, find out how many there are in each sector
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)T_SpikeSector)
secthinkers[((levelspecthink_t *)th)->sector - sectors].count++;
@ -6473,7 +6478,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
}
// Finally, populate the lists.
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MAIN].next; th != &thlist[THINK_MAIN]; th = th->next)
{
size_t secnum = (size_t)-1;
@ -6492,29 +6497,23 @@ void P_SpawnSpecials(INT32 fromnetsave)
// Init line EFFECTs
for (i = 0; i < numlines; i++)
{
if (lines[i].special != 7) // This is a hack. I can at least hope nobody wants to prevent flat alignment with arbitrary skin setups...
if (lines[i].special != 7) // This is a hack. I can at least hope nobody wants to prevent flat alignment in netgames...
{
// set line specials to 0 here too, same reason as above
if (netgame || multiplayer)
{
// future: nonet flag?
}
else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY)
if (lines[i].flags & ML_NONET)
{
lines[i].special = 0;
continue;
}
else
{
if ((players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC))
|| (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS))
|| (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX)))
}
else if (lines[i].flags & ML_NETONLY)
{
lines[i].special = 0;
continue;
}
}
}
switch (lines[i].special)
{
@ -6552,20 +6551,14 @@ void P_SpawnSpecials(INT32 fromnetsave)
P_AddCameraScanner(&sectors[sec], &sectors[s], R_PointToAngle2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y));
break;
#ifdef PARANOIA
case 6: // Disable tags if level not cleared
I_Error("Failed to catch a disable linedef");
break;
#endif
case 7: // Flat alignment - redone by toast
if ((lines[i].flags & (ML_NOSONIC|ML_NOTAILS)) != (ML_NOSONIC|ML_NOTAILS)) // If you can do something...
if ((lines[i].flags & (ML_NETONLY|ML_NONET)) != (ML_NETONLY|ML_NONET)) // If you can do something...
{
angle_t flatangle = InvAngle(R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y));
fixed_t xoffs;
fixed_t yoffs;
if (lines[i].flags & ML_NOKNUX) // Set offset through x and y texture offsets if NOKNUX flag is set
if (lines[i].flags & ML_EFFECT6) // Set offset through x and y texture offsets if ML_EFFECT6 flag is set
{
xoffs = sides[lines[i].sidenum[0]].textureoffset;
yoffs = sides[lines[i].sidenum[0]].rowoffset;
@ -7204,6 +7197,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
case 301:
case 310:
case 312:
case 332:
sec = sides[*lines[i].sidenum].sector - sectors;
P_AddEachTimeThinker(&sectors[sec], &lines[i]);
break;
@ -7252,6 +7246,11 @@ void P_SpawnSpecials(INT32 fromnetsave)
case 330:
break;
// Skin trigger executors
case 331:
case 333:
break;
case 399: // Linedef execute on map load
// This is handled in P_RunLevelLoadExecutors.
break;
@ -7368,14 +7367,6 @@ void P_SpawnSpecials(INT32 fromnetsave)
sectors[s].extra_colormap = sectors[s].spawn_extra_colormap = sides[lines[i].sidenum[0]].colormap_data;
break;
#ifdef ESLOPE // Slope copy specials. Handled here for sanity.
case 720:
case 721:
case 722:
P_CopySectorSlope(&lines[i]);
break;
#endif
default:
break;
}
@ -7735,7 +7726,7 @@ static void Add_Scroller(INT32 type, fixed_t dx, fixed_t dy, INT32 control, INT3
if ((s->control = control) != -1)
s->last_height = sectors[control].floorheight + sectors[control].ceilingheight;
s->affectee = affectee;
P_AddThinker(&s->thinker);
P_AddThinker(THINK_MAIN, &s->thinker);
}
/** Initializes the scrollers.
@ -7869,7 +7860,7 @@ static void Add_MasterDisappearer(tic_t appeartime, tic_t disappeartime, tic_t o
d->exists = true;
d->timer = 1;
P_AddThinker(&d->thinker);
P_AddThinker(THINK_MAIN, &d->thinker);
}
/** Makes a FOF appear/disappear
@ -7916,6 +7907,7 @@ void T_Disappear(disappear_t *d)
}
}
sectors[s].moved = true;
P_RecalcPrecipInSector(&sectors[s]);
}
if (d->exists)
@ -8264,7 +8256,7 @@ static void P_AddFakeFloorFader(ffloor_t *rover, size_t sectornum, size_t ffloor
d->ffloornum = (UINT32)ffloornum;
d->alpha = d->sourcevalue = rover->alpha;
d->destvalue = max(1, min(256, relative ? rover->alpha + destvalue : destvalue)); // ffloor->alpha is 1-256
d->destvalue = max(1, min(256, relative ? rover->alpha + destvalue : destvalue)); // rover->alpha is 1-256
if (ticbased)
{
@ -8358,7 +8350,7 @@ static void P_AddFakeFloorFader(ffloor_t *rover, size_t sectornum, size_t ffloor
FixedFloor(FixedDiv(abs(d->destvalue - d->alpha), d->speed))/FRACUNIT);
}
P_AddThinker(&d->thinker);
P_AddThinker(THINK_MAIN, &d->thinker);
}
/** Makes a FOF fade
@ -8428,7 +8420,7 @@ static void Add_ColormapFader(sector_t *sector, extracolormap_t *source_exc, ext
}
sector->fadecolormapdata = d;
P_AddThinker(&d->thinker); // add thinker
P_AddThinker(THINK_MAIN, &d->thinker);
}
void T_FadeColormap(fadecolormap_t *d)
@ -8547,7 +8539,7 @@ static void Add_Friction(INT32 friction, INT32 movefactor, INT32 affectee, INT32
else
f->roverfriction = false;
P_AddThinker(&f->thinker);
P_AddThinker(THINK_MAIN, &f->thinker);
}
/** Applies friction to all things in a sector.
@ -8713,7 +8705,7 @@ static void Add_Pusher(pushertype_e type, fixed_t x_mag, fixed_t y_mag, mobj_t *
p->z = p->source->z;
}
p->affectee = affectee;
P_AddThinker(&p->thinker);
P_AddThinker(THINK_MAIN, &p->thinker);
}
@ -9215,39 +9207,3 @@ static void P_SpawnPushers(void)
break;
}
}
static void P_SearchForDisableLinedefs(void)
{
size_t i;
INT32 j;
// Look for disable linedefs
for (i = 0; i < numlines; i++)
{
if (lines[i].special == 6)
{
// Remove special
// Do *not* remove tag. That would mess with the tag lists
// that P_InitTagLists literally just created!
lines[i].special = 0;
// Ability flags can disable disable linedefs now, lol
if (netgame || multiplayer)
{
// future: nonet flag?
}
else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY)
continue; // Net-only never triggers in single player
else if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC))
continue;
else if (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS))
continue;
else if (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX))
continue;
// Disable any linedef specials with our tag.
for (j = -1; (j = P_FindLineFromLineTag(&lines[i], j)) >= 0;)
lines[j].special = 0;
}
}
}

View file

@ -35,8 +35,8 @@ tic_t leveltime;
// but the first element must be thinker_t.
//
// Both the head and tail of the thinker list.
thinker_t thinkercap;
// The entries will behave like both the head and tail of the lists.
thinker_t thlist[NUM_THINKERLISTS];
void Command_Numthinkers_f(void)
{
@ -44,6 +44,9 @@ void Command_Numthinkers_f(void)
INT32 count = 0;
actionf_p1 action;
thinker_t *think;
thinklistnum_t start = 0;
thinklistnum_t end = NUM_THINKERLISTS - 1;
thinklistnum_t i;
if (gamestate != GS_LEVEL)
{
@ -70,6 +73,7 @@ void Command_Numthinkers_f(void)
switch (num)
{
case 1:
start = end = THINK_MOBJ;
action = (actionf_p1)P_MobjThinker;
CONS_Printf(M_GetText("Number of %s: "), "P_MobjThinker");
break;
@ -82,14 +86,17 @@ void Command_Numthinkers_f(void)
CONS_Printf(M_GetText("Number of %s: "), "P_SnowThinker");
break;*/
case 2:
start = end = THINK_PRECIP;
action = (actionf_p1)P_NullPrecipThinker;
CONS_Printf(M_GetText("Number of %s: "), "P_NullPrecipThinker");
break;
case 3:
start = end = THINK_MAIN;
action = (actionf_p1)T_Friction;
CONS_Printf(M_GetText("Number of %s: "), "T_Friction");
break;
case 4:
start = end = THINK_MAIN;
action = (actionf_p1)T_Pusher;
CONS_Printf(M_GetText("Number of %s: "), "T_Pusher");
break;
@ -102,13 +109,16 @@ void Command_Numthinkers_f(void)
return;
}
for (think = thinkercap.next; think != &thinkercap; think = think->next)
for (i = start; i <= end; i++)
{
for (think = thlist[i].next; think != &thlist[i]; think = think->next)
{
if (think->function.acp1 != action)
continue;
count++;
}
}
CONS_Printf("%d\n", count);
}
@ -139,9 +149,9 @@ void Command_CountMobjs_f(void)
count = 0;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
if (((mobj_t *)th)->type == i)
@ -159,9 +169,9 @@ void Command_CountMobjs_f(void)
{
count = 0;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
if (((mobj_t *)th)->type == i)
@ -178,19 +188,22 @@ void Command_CountMobjs_f(void)
//
void P_InitThinkers(void)
{
thinkercap.prev = thinkercap.next = &thinkercap;
UINT8 i;
for (i = 0; i < NUM_THINKERLISTS; i++)
thlist[i].prev = thlist[i].next = &thlist[i];
}
//
// P_AddThinker
// Adds a new thinker at the end of the list.
//
void P_AddThinker(thinker_t *thinker)
void P_AddThinker(const thinklistnum_t n, thinker_t *thinker)
{
thinkercap.prev->next = thinker;
thinker->next = &thinkercap;
thinker->prev = thinkercap.prev;
thinkercap.prev = thinker;
#ifdef PARANOIA
I_Assert(n >= 0 && n < NUM_THINKERLISTS);
#endif
thlist[n].prev->next = thinker;
thinker->next = &thlist[n];
thinker->prev = thlist[n].prev;
thlist[n].prev = thinker;
thinker->references = 0; // killough 11/98: init reference counter to 0
}
@ -213,23 +226,34 @@ static thinker_t *currentthinker;
// remove it, and set currentthinker to one node preceeding it, so
// that the next step in P_RunThinkers() will get its successor.
//
void P_RemoveThinkerDelayed(void *pthinker)
{
thinker_t *thinker = pthinker;
if (!thinker->references)
void P_RemoveThinkerDelayed(thinker_t *thinker)
{
thinker_t *next;
#ifdef PARANOIA
#define BEENAROUNDBIT (0x40000000) // has to be sufficiently high that it's unlikely to happen in regular gameplay. If you change this, pay attention to the bit pattern of INT32_MIN.
if (thinker->references & ~BEENAROUNDBIT)
{
if (thinker->references & BEENAROUNDBIT) // Usually gets cleared up in one frame; what's going on here, then?
CONS_Printf("Number of potentially faulty references: %d\n", (thinker->references & ~BEENAROUNDBIT));
thinker->references |= BEENAROUNDBIT;
return;
}
#undef BEENAROUNDBIT
#else
if (thinker->references)
return;
#endif
/* Remove from main thinker list */
thinker_t *next = thinker->next;
next = thinker->next;
/* Note that currentthinker is guaranteed to point to us,
* and since we're freeing our memory, we had better change that. So
* point it to thinker->prev, so the iterator will correctly move on to
* thinker->prev->next = thinker->next */
(next->prev = currentthinker = thinker->prev)->next = next;
}
Z_Free(thinker);
}
}
//
// P_RemoveThinker
@ -248,7 +272,7 @@ void P_RemoveThinker(thinker_t *thinker)
#ifdef HAVE_BLUA
LUA_InvalidateUserdata(thinker);
#endif
thinker->function.acp1 = P_RemoveThinkerDelayed;
thinker->function.acp1 = (actionf_p1)P_RemoveThinkerDelayed;
}
/*
@ -296,13 +320,20 @@ if ((*mop = targ) != NULL) // Set new target and if non-NULL, increase its count
//
static inline void P_RunThinkers(void)
{
for (currentthinker = thinkercap.next; currentthinker != &thinkercap; currentthinker = currentthinker->next)
size_t i;
for (i = 0; i < NUM_THINKERLISTS; i++)
{
if (currentthinker->function.acp1)
for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = currentthinker->next)
{
#ifdef PARANOIA
I_Assert(currentthinker->function.acp1 != NULL)
#endif
currentthinker->function.acp1(currentthinker);
}
}
}
//
// P_DoAutobalanceTeams()
//

View file

@ -27,7 +27,7 @@ void Command_CountMobjs_f(void);
void P_Ticker(boolean run);
void P_PreTicker(INT32 frames);
void P_DoTeamscrambling(void);
void P_RemoveThinkerDelayed(void *pthinker); //killed
void P_RemoveThinkerDelayed(thinker_t *thinker); //killed
mobj_t *P_SetTarget(mobj_t **mo, mobj_t *target); // killough 11/98
#endif

View file

@ -343,14 +343,18 @@ UINT8 P_FindLowestMare(void)
// scan the thinkers
// to find the egg capsule with the lowest mare
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_EGGCAPSULE && mo2->health > 0)
if (mo2->type != MT_EGGCAPSULE)
continue;
if (mo2->health <= 0)
continue;
{
const UINT8 threshold = (UINT8)mo2->threshold;
if (mare == 255)
@ -392,17 +396,19 @@ boolean P_TransferToNextMare(player_t *player)
// scan the thinkers
// to find the closest axis point
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_AXIS)
{
if (mo2->threshold == mare)
{
if (mo2->type != MT_AXIS)
continue;
if (mo2->threshold != mare)
continue;
if (closestaxis == NULL)
{
closestaxis = mo2;
@ -421,8 +427,6 @@ boolean P_TransferToNextMare(player_t *player)
}
}
}
}
}
if (closestaxis == NULL)
return false;
@ -443,9 +447,9 @@ static mobj_t *P_FindAxis(INT32 mare, INT32 axisnum)
// scan the thinkers
// to find the closest axis point
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -454,12 +458,14 @@ static mobj_t *P_FindAxis(INT32 mare, INT32 axisnum)
if (!(mo2->flags2 & MF2_AXIS))
return NULL;
if (mo2->type == MT_AXIS)
{
if (mo2->health == axisnum && mo2->threshold == mare)
if (mo2->type != MT_AXIS)
continue;
if (mo2->health != axisnum)
continue;
if (mo2->threshold != mare)
continue;
return mo2;
}
}
return NULL;
}
@ -476,9 +482,9 @@ static mobj_t *P_FindAxisTransfer(INT32 mare, INT32 axisnum, mobjtype_t type)
// scan the thinkers
// to find the closest axis point
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -487,12 +493,14 @@ static mobj_t *P_FindAxisTransfer(INT32 mare, INT32 axisnum, mobjtype_t type)
if (!(mo2->flags2 & MF2_AXIS))
return NULL;
if (mo2->type == type)
{
if (mo2->health == axisnum && mo2->threshold == mare)
if (mo2->type != type)
continue;
if (mo2->health != axisnum)
continue;
if (mo2->threshold != mare)
continue;
return mo2;
}
}
return NULL;
}
@ -515,17 +523,20 @@ void P_TransferToAxis(player_t *player, INT32 axisnum)
// scan the thinkers
// to find the closest axis point
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_AXIS)
{
if (mo2->health == axisnum && mo2->threshold == mare)
{
if (mo2->type != MT_AXIS)
continue;
if (mo2->health != axisnum)
continue;
if (mo2->threshold != mare)
continue;
if (closestaxis == NULL)
{
closestaxis = mo2;
@ -542,8 +553,6 @@ void P_TransferToAxis(player_t *player, INT32 axisnum)
}
}
}
}
}
if (!closestaxis)
{
@ -615,9 +624,9 @@ static void P_DeNightserizePlayer(player_t *player)
}
// Check to see if the player should be killed.
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -866,6 +875,9 @@ boolean P_PlayerInPain(player_t *player)
if (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing])
return true;
if (player->mo->state == &states[S_PLAY_STUN])
return true;
return false;
}
@ -977,6 +989,68 @@ void P_ResetPlayer(player_t *player)
CV_SetValue(&cv_analog2, true);
}
// P_PlayerCanDamage
//
// Can player do damage?
//
boolean P_PlayerCanDamage(player_t *player, mobj_t *thing)
{
if (!player->mo || player->spectator || !thing || P_MobjWasRemoved(thing))
return false;
#ifdef HAVE_BLUA
{
UINT8 shouldCollide = LUAh_PlayerCanDamage(player, thing);
if (P_MobjWasRemoved(thing))
return false; // removed???
if (shouldCollide == 1)
return true; // force yes
else if (shouldCollide == 2)
return false; // force no
}
#endif
// Invinc/super. Not for Monitors.
if (!(thing->flags & MF_MONITOR) && (player->powers[pw_invulnerability] || player->powers[pw_super]))
return true;
// NiGHTS drill. Wasn't originally for monitors, but that's more an oversight being corrected than anything else.
if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING))
return true;
// Jumping.
if ((player->pflags & PF_JUMPED)
&& (!(player->pflags & PF_NOJUMPDAMAGE)
|| (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
return true;
// Spinning.
if (player->pflags & PF_SPINNING)
return true;
// From the front.
if (((player->pflags & PF_GLIDING) || (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
&& (player->drawangle - R_PointToAngle2(player->mo->x - player->mo->momx, player->mo->y - player->mo->momy, thing->x, thing->y) + + ANGLE_90) < ANGLE_180)
return true;
// From the top/bottom.
if (P_MobjFlip(player->mo)*(player->mo->z - (thing->z + thing->height/2)) > 0)
{
if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(player->mo)*player->mo->momz < 0))
return true;
}
else if (player->charability == CA_FLY && player->panim == PA_ABILITY)
return true;
// Shield stomp.
if (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY))
return true;
return false;
}
//
// P_GivePlayerRings
//
@ -1551,6 +1625,7 @@ void P_SpawnShieldOrb(player_t *player)
orbtype = MT_ARMAGEDDON_ORB;
break;
case SH_PITY:
case SH_PINK: // PITY IN PINK
orbtype = MT_PITY_ORB;
break;
case SH_FLAMEAURA:
@ -1567,9 +1642,9 @@ void P_SpawnShieldOrb(player_t *player)
}
// blaze through the thinkers to see if an orb already exists!
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
shieldobj = (mobj_t *)th;
@ -1581,6 +1656,12 @@ void P_SpawnShieldOrb(player_t *player)
shieldobj = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, orbtype);
shieldobj->flags2 |= MF2_SHIELD;
P_SetTarget(&shieldobj->target, player->mo);
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK)
{
shieldobj->color = SKINCOLOR_PINK;
shieldobj->colorized = true;
}
else
shieldobj->color = (UINT8)shieldobj->info->painchance;
shieldobj->threshold = (player->powers[pw_shield] & SH_FORCE) ? SH_FORCE : (player->powers[pw_shield] & SH_NOSTACK);
@ -1687,6 +1768,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
}
ghost->color = mobj->color;
ghost->colorized = mobj->colorized; // alternatively, "true" for sonic advance style colourisation
ghost->angle = (mobj->player ? mobj->player->drawangle : mobj->angle);
ghost->sprite = mobj->sprite;
@ -1729,6 +1811,9 @@ void P_SpawnThokMobj(player_t *player)
if (player->spectator)
return;
if (!type)
return;
if (type == MT_GHOST)
mobj = P_SpawnGhostMobj(player->mo); // virtually does everything here for us
else
@ -1789,6 +1874,9 @@ void P_SpawnSpinMobj(player_t *player, mobjtype_t type)
if (player->spectator)
return;
if (!type)
return;
if (type == MT_GHOST)
mobj = P_SpawnGhostMobj(player->mo); // virtually does everything here for us
else
@ -1944,10 +2032,45 @@ boolean P_PlayerHitFloor(player_t *player)
}
else if (player->charability2 == CA2_MELEE && (player->panim == PA_ABILITY2 && player->mo->state-states != S_PLAY_MELEE_LANDING))
{
mobjtype_t type = player->revitem;
P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING);
player->mo->tics = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS;
S_StartSound(player->mo, sfx_s3k8b);
player->pflags |= PF_FULLSTASIS;
// hearticles
if (type)
{
UINT8 i = 0;
angle_t throwang = -(2*ANG30);
fixed_t xo = P_ReturnThrustX(player->mo, player->drawangle, 16*player->mo->scale);
fixed_t yo = P_ReturnThrustY(player->mo, player->drawangle, 16*player->mo->scale);
fixed_t zo = 6*player->mo->scale;
fixed_t mu = FixedMul(player->maxdash, player->mo->scale);
fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy);
fixed_t ev;
mobj_t *missile;
if (mu2 < mu)
mu2 = mu;
ev = (50*FRACUNIT - (mu/25))/50;
while (i < 5)
{
missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type);
P_SetTarget(&missile->target, player->mo);
missile->angle = throwang + player->drawangle;
P_Thrust(missile, player->drawangle + ANGLE_90,
P_ReturnThrustY(missile, throwang, mu)); // side to side component
P_Thrust(missile, player->drawangle, mu2); // forward component
P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true);
missile->fuse = TICRATE/2;
missile->extravalue2 = ev;
i++;
throwang += ANG30;
}
if (mobjinfo[type].seesound)
S_StartSound(missile, missile->info->seesound);
}
}
else if (player->pflags & PF_JUMPED || !(player->pflags & PF_SPINNING)
|| player->powers[pw_tailsfly] || player->mo->state-states == S_PLAY_FLY_TIRED)
@ -3057,7 +3180,7 @@ static void P_DoClimbing(player_t *player)
angle_t sideangle;
fixed_t dx, dy;
for (think = thinkercap.next; think != &thinkercap; think = think->next)
for (think = thlist[THINK_MAIN].next; think != &thlist[THINK_MAIN]; think = think->next)
{
if (think->function.acp1 != (actionf_p1)T_Scroll)
continue;
@ -3532,7 +3655,8 @@ static void P_DoTeeter(player_t *player)
if (teeter) // only bother with objects as a last resort if you were already teetering
{
mobj_t *oldtmthing = tmthing;
tmthing = teeterer = player->mo;
teeterer = player->mo;
P_SetTarget(&tmthing, teeterer);
teeterxl = teeterxh = player->mo->x;
teeteryl = teeteryh = player->mo->y;
couldteeter = false;
@ -3546,7 +3670,7 @@ static void P_DoTeeter(player_t *player)
}
teeterdone:
teeter = solidteeter;
tmthing = oldtmthing; // restore old tmthing, goodness knows what the game does with this before mobj thinkers
P_SetTarget(&tmthing, oldtmthing); // restore old tmthing, goodness knows what the game does with this before mobj thinkers
}
}
if (teeter)
@ -4221,7 +4345,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
if (P_IsLocalPlayer(player)) // Only display it on your own view.
{
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
visual->target = lockon;
P_SetTarget(&visual->target, lockon);
}
}
if ((cmd->buttons & BT_USE) && !(player->pflags & PF_USEDOWN))
@ -4288,7 +4412,11 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
P_SetObjectMomZ(player->mo, player->mindash, false);
if (player->mo->eflags & MFE_UNDERWATER)
player->mo->momz >>= 1;
#if 0
if (FixedMul(player->speed, FINECOSINE(((player->mo->angle - R_PointToAngle2(0, 0, player->rmomx, player->rmomy)) >> ANGLETOFINESHIFT) & FINEMASK)) < FixedMul(player->maxdash, player->mo->scale))
#else
if (player->speed < FixedMul(player->maxdash, player->mo->scale))
#endif
{
player->drawangle = player->mo->angle;
P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->maxdash, player->mo->scale));
@ -4362,6 +4490,7 @@ void P_DoJumpShield(player_t *player)
P_InstaThrust(spark, travelangle + i*(ANGLE_MAX/numangles), FixedMul(4*FRACUNIT, spark->scale));
if (i % 2)
P_SetObjectMomZ(spark, -4*FRACUNIT, false);
spark->fuse = 18;
}
#undef limitangle
#undef numangles
@ -4422,6 +4551,57 @@ void P_DoAbilityBounce(player_t *player, boolean changemomz)
player->pflags |= PF_BOUNCING|PF_THOKKED;
}
//
// P_TwinSpinRejuvenate
//
// CA_TWINSPIN landing handling
//
void P_TwinSpinRejuvenate(player_t *player, mobjtype_t type)
{
fixed_t actionspd;
angle_t movang, ang, fa;
fixed_t v, h;
UINT8 i;
if (!player->mo || !type)
return;
actionspd = FixedMul(player->actionspd, player->mo->scale);
fa = (R_PointToAngle2(0, 0, player->mo->momz, FixedHypot(player->mo->momx, player->mo->momy))>>ANGLETOFINESHIFT) & FINEMASK;
movang = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
ang = 0;
v = FixedMul(actionspd, FINESINE(fa));
h = actionspd - FixedMul(actionspd, FINECOSINE(fa));
// hearticles
for (i = 0; i <= 7; i++)
{
fixed_t side = actionspd - FixedMul(h, abs(FINESINE((ang>>ANGLETOFINESHIFT) & FINEMASK)));
fixed_t xo = P_ReturnThrustX(NULL, ang + movang, side);
fixed_t yo = P_ReturnThrustY(NULL, ang + movang, side);
fixed_t zo = -FixedMul(FINECOSINE(((ang>>ANGLETOFINESHIFT) & FINEMASK)), v);
mobj_t *missile = P_SpawnMobjFromMobj(player->mo,
xo,
yo,
player->mo->height/2 + zo,
type);
P_SetTarget(&missile->target, player->mo);
P_SetScale(missile, (missile->destscale >>= 1));
missile->angle = ang + movang;
missile->fuse = TICRATE/2;
missile->extravalue2 = (99*FRACUNIT)/100;
missile->momx = xo;
missile->momy = yo;
missile->momz = zo;
ang += ANGLE_45;
}
player->pflags &= ~PF_THOKKED;
}
//
// P_Telekinesis
//
@ -4438,9 +4618,9 @@ void P_Telekinesis(player_t *player, fixed_t thrust, fixed_t range)
if (player->powers[pw_super]) // increase range when super
range *= 2;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -4491,7 +4671,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
if (P_IsLocalPlayer(player)) // Only display it on your own view.
{
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
visual->target = lockon;
P_SetTarget(&visual->target, lockon);
}
}
@ -4637,10 +4817,10 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
player->mo->momx /= 2;
player->mo->momy /= 2;
}
else if (player->charability == CA_HOMINGTHOK)
if (player->charability == CA_HOMINGTHOK)
{
player->mo->momx /= 3;
player->mo->momy /= 3;
player->mo->momx /= 2;
player->mo->momy /= 2;
}
if (player->charability == CA_HOMINGTHOK)
@ -5635,9 +5815,9 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
fixed_t truexspeed = xspeed*(!(player->pflags & PF_TRANSFERTOCLOSEST) && player->mo->target->flags2 & MF2_AMBUSH ? -1 : 1);
// Find next waypoint
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -5645,10 +5825,11 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
// Axis things are only at beginning of list.
if (!(mo2->flags2 & MF2_AXIS))
break;
if (!(mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
continue;
if (mo2->threshold != sequence)
continue;
if ((mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE)
&& mo2->threshold == sequence)
{
if (player->pflags & PF_TRANSFERTOCLOSEST)
{
if (mo2->health == player->axis1->health)
@ -5664,16 +5845,15 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
transfer2 = mo2;
}
}
}
// It might be possible that one wasn't found.
// Is it because we're at the end of the track?
// Look for a wrapper point.
if (!transfer1)
{
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -5681,9 +5861,11 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
// Axis things are only at beginning of list.
if (!(mo2->flags2 & MF2_AXIS))
break;
if (!(mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
continue;
if (mo2->threshold != sequence)
continue;
if (mo2->threshold == sequence && (mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
{
if (!transfer1)
{
transfer1 = mo2;
@ -5696,12 +5878,11 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
}
}
}
}
if (!transfer2)
{
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -5709,9 +5890,11 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
// Axis things are only at beginning of list.
if (!(mo2->flags2 & MF2_AXIS))
break;
if (!(mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
continue;
if (mo2->threshold != sequence)
continue;
if (mo2->threshold == sequence && (mo2->type == MT_AXISTRANSFER || mo2->type == MT_AXISTRANSFERLINE))
{
if (!transfer2)
{
transfer2 = mo2;
@ -5724,7 +5907,6 @@ static void P_NightsTransferPoints(player_t *player, fixed_t xspeed, fixed_t rad
}
}
}
}
if (!(transfer1 && transfer2)) // We can't continue...
I_Error("Mare does not form a complete circuit!\n");
@ -6406,17 +6588,18 @@ static void P_NiGHTSMovement(player_t *player)
// scan the thinkers
// to find the closest axis point
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_AXIS)
{
if (mo2->threshold == player->mare)
{
if (mo2->type != MT_AXIS)
continue;
if (mo2->threshold != player->mare)
continue;
if (closestaxis == NULL)
{
closestaxis = mo2;
@ -6433,9 +6616,6 @@ static void P_NiGHTSMovement(player_t *player)
}
}
}
}
}
P_SetTarget(&player->mo->target, closestaxis);
}
@ -7216,9 +7396,9 @@ static void P_MovePlayer(player_t *player)
thinker_t *th;
mobj_t *mo2;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -7724,7 +7904,7 @@ static void P_MovePlayer(player_t *player)
if (P_IsLocalPlayer(player)) // Only display it on your own view.
{
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
visual->target = lockon;
P_SetTarget(&visual->target, lockon);
P_SetMobjStateNF(visual, visual->info->spawnstate+1);
}
}
@ -7757,7 +7937,7 @@ static void P_MovePlayer(player_t *player)
if (!(player->pflags & (PF_USEDOWN|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player is not holding down BT_USE, or having used an ability previously
&& (!(player->powers[pw_shield] & SH_NOSTACK) || !(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX))) // thokked is optional if you're bubblewrapped/turning super
{
// Force shield activation
// Force stop
if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE)
{
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
@ -7773,17 +7953,17 @@ static void P_MovePlayer(player_t *player)
if (P_SuperReady(player))
P_DoSuperTransformation(player, false);
break;
// Whirlwind/Thundercoin shield activation
// Whirlwind jump/Thunder jump
case SH_WHIRLWIND:
case SH_THUNDERCOIN:
P_DoJumpShield(player);
break;
// Armageddon shield activation
// Armageddon pow
case SH_ARMAGEDDON:
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
P_BlackOw(player);
break;
// Attract shield activation
// Attraction blast
case SH_ATTRACT:
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
player->homing = 2;
@ -7792,13 +7972,14 @@ static void P_MovePlayer(player_t *player)
{
player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockon->x, lockon->y);
player->pflags &= ~PF_NOJUMPDAMAGE;
P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
S_StartSound(player->mo, sfx_s3k40);
player->homing = 3*TICRATE;
}
else
S_StartSound(player->mo, sfx_s3ka6);
break;
// Elemental/Bubblewrap shield activation
// Elemental stomp/Bubble bounce
case SH_ELEMENTAL:
case SH_BUBBLEWRAP:
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
@ -7812,7 +7993,7 @@ static void P_MovePlayer(player_t *player)
? sfx_s3k43
: sfx_s3k44);
break;
// Flame shield activation
// Flame burst
case SH_FLAMEAURA:
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale));
@ -7833,8 +8014,7 @@ static void P_MovePlayer(player_t *player)
{
if (player->homing && player->mo->tracer)
{
P_HomingAttack(player->mo, player->mo->tracer);
if (player->mo->tracer->health <= 0 || (player->mo->tracer->flags2 & MF2_FRET))
if (!P_HomingAttack(player->mo, player->mo->tracer))
{
P_SetObjectMomZ(player->mo, 6*FRACUNIT, false);
if (player->mo->eflags & MFE_UNDERWATER)
@ -7853,10 +8033,9 @@ static void P_MovePlayer(player_t *player)
if (player->homing && player->mo->tracer)
{
P_SpawnThokMobj(player);
P_HomingAttack(player->mo, player->mo->tracer);
// But if you don't, then stop homing.
if (player->mo->tracer->health <= 0 || (player->mo->tracer->flags2 & MF2_FRET))
if (!P_HomingAttack(player->mo, player->mo->tracer))
{
if (player->mo->eflags & MFE_UNDERWATER)
P_SetObjectMomZ(player->mo, FixedDiv(457*FRACUNIT,72*FRACUNIT), false);
@ -8124,9 +8303,9 @@ static void P_DoZoomTube(player_t *player)
CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n");
// Find next waypoint
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -8134,16 +8313,18 @@ static void P_DoZoomTube(player_t *player)
if (mo2->type != MT_TUBEWAYPOINT)
continue;
if (mo2->threshold == sequence)
{
if ((reverse && mo2->health == player->mo->tracer->health - 1)
|| (!reverse && mo2->health == player->mo->tracer->health + 1))
{
if (mo2->threshold != sequence)
continue;
if (reverse && mo2->health != player->mo->tracer->health - 1)
continue;
if (!reverse && mo2->health != player->mo->tracer->health + 1)
continue;
waypoint = mo2;
break;
}
}
}
if (waypoint)
{
@ -8258,9 +8439,9 @@ static void P_DoRopeHang(player_t *player)
CONS_Debug(DBG_GAMELOGIC, "Looking for next waypoint...\n");
// Find next waypoint
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -8268,24 +8449,24 @@ static void P_DoRopeHang(player_t *player)
if (mo2->type != MT_TUBEWAYPOINT)
continue;
if (mo2->threshold == sequence)
{
if (mo2->health == player->mo->tracer->health + 1)
{
if (mo2->threshold != sequence)
continue;
if (mo2->health != player->mo->tracer->health + 1)
continue;
waypoint = mo2;
break;
}
}
}
if (!(player->mo->tracer->flags & MF_SLIDEME) && !waypoint)
{
CONS_Debug(DBG_GAMELOGIC, "Next waypoint not found, wrapping to start...\n");
// Wrap around back to first waypoint
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker) // Not a mobj thinker
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -8293,16 +8474,16 @@ static void P_DoRopeHang(player_t *player)
if (mo2->type != MT_TUBEWAYPOINT)
continue;
if (mo2->threshold == sequence)
{
if (mo2->health == 0)
{
if (mo2->threshold != sequence)
continue;
if (mo2->health != 0)
continue;
waypoint = mo2;
break;
}
}
}
}
if (waypoint)
{
@ -8347,25 +8528,22 @@ static void P_DoRopeHang(player_t *player)
static void P_NukeAllPlayers(player_t *player)
{
mobj_t *mo;
thinker_t *think;
UINT8 i;
for (think = thinkercap.next; think != &thinkercap; think = think->next)
for (i = 0; i < MAXPLAYERS; i++)
{
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
continue; // not a mobj thinker
mo = (mobj_t *)think;
if (!mo->player)
if (!playeringame[i])
continue;
if (players[i].spectator)
continue;
if (!players[i].mo)
continue;
if (players[i].mo == player->mo)
continue;
if (players[i].mo->health <= 0)
continue;
if (mo->health <= 0) // dead
continue;
if (mo == player->mo)
continue;
P_DamageMobj(mo, player->mo, player->mo, 1, 0);
P_DamageMobj(players[i].mo, player->mo, player->mo, 1, 0);
}
CONS_Printf(M_GetText("%s caused a world of pain.\n"), player_names[player-players]);
@ -8397,10 +8575,10 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius)
}
}
for (think = thinkercap.next; think != &thinkercap; think = think->next)
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
continue; // not a mobj thinker
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)think;
@ -8448,13 +8626,13 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
const angle_t span = (bullet ? ANG30 : ANGLE_90);
fixed_t dist, closestdist = 0;
for (think = thinkercap.next; think != &thinkercap; think = think->next)
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{
if (think->function.acp1 != (actionf_p1)P_MobjThinker)
continue; // not a mobj thinker
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo = (mobj_t *)think;
if (!(mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR|MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag
if (!((mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) && (mo->flags & MF_SHOOTABLE)) || (mo->flags & MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag
continue; // not a valid target
if (mo->health <= 0) // dead
@ -8466,9 +8644,6 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
if (mo->flags2 & MF2_FRET)
continue;
if ((mo->flags & (MF_ENEMY|MF_BOSS)) && !(mo->flags & MF_SHOOTABLE)) // don't aim at something you can't shoot at anyway (see Egg Guard or Minus)
continue;
if (!nonenemies && mo->flags & (MF_MONITOR|MF_SPRING))
continue;
@ -8522,17 +8697,23 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
return closestmo;
}
void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target
boolean P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target
{
fixed_t zdist;
fixed_t dist;
fixed_t ns = 0;
if (!enemy)
return;
return false;
if (!(enemy->health))
return;
if (!enemy->health)
return false;
if (enemy->flags2 & MF2_FRET)
return false;
if (!(enemy->flags & (MF_SHOOTABLE|MF_SPRING)) == !(enemy->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag
return false;
// change angle
source->angle = R_PointToAngle2(source->x, source->y, enemy->x, enemy->y);
@ -8575,6 +8756,8 @@ void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target
source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns);
source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), ns);
source->momz = FixedMul(FixedDiv(zdist, dist), ns);
return true;
}
// Search for emeralds
@ -8587,9 +8770,9 @@ void P_FindEmerald(void)
// scan the remaining thinkers
// to find all emeralds
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
@ -9744,12 +9927,12 @@ void P_DoPityCheck(player_t *player)
// Apply pity shield if available.
if ((player->pity >= 3 || player->pity < 0) && player->powers[pw_shield] == SH_NONE)
{
P_SwitchShield(player, SH_PITY);
if (player->pity > 0)
S_StartSound(player->mo, mobjinfo[MT_PITY_ICON].seesound);
player->pity = 0;
player->powers[pw_shield] = SH_PITY;
P_SpawnShieldOrb(player);
}
}
@ -9815,9 +9998,9 @@ static mobj_t *P_GetAxis(INT32 num)
thinker_t *th;
mobj_t *mobj;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mobj = (mobj_t *)th;
@ -9832,6 +10015,7 @@ static mobj_t *P_GetAxis(INT32 num)
return mobj;
}
CONS_Alert(CONS_WARNING, "P_GetAxis: Track segment %d is missing!\n", num);
return NULL;
}
@ -10456,9 +10640,9 @@ void P_PlayerThink(player_t *player)
fixed_t y = player->mo->y;
fixed_t z = player->mo->z;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;

View file

@ -2275,8 +2275,8 @@ void R_PrecacheLevel(void)
spritepresent = calloc(numsprites, sizeof (*spritepresent));
if (spritepresent == NULL) I_Error("%s: Out of memory looking up sprites", "R_PrecacheLevel");
for (th = thinkercap.next; th != &thinkercap; th = th->next)
if (th->function.acp1 == (actionf_p1)P_MobjThinker)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
if (th->function.acp1 != (actionf_p1)P_RemoveThinkerDelayed)
spritepresent[((mobj_t *)th)->sprite] = 1;
spritememory = 0;

View file

@ -237,46 +237,27 @@ typedef struct linechain_s
// Slopes
#ifdef ESLOPE
typedef enum {
SL_NOPHYSICS = 1, // Don't do momentum adjustment with this slope
SL_NODYNAMIC = 1<<1, // Slope will never need to move during the level, so don't fuss with recalculating it
SL_ANCHORVERTEX = 1<<2, // Slope is using a Slope Vertex Thing to anchor its position
SL_VERTEXSLOPE = 1<<3, // Slope is built from three Slope Vertex Things
SL_NOPHYSICS = 1, /// This plane will have no physics applied besides the positioning.
SL_DYNAMIC = 1<<1, /// This plane slope will be assigned a thinker to make it dynamic.
} slopeflags_t;
typedef struct pslope_s
{
UINT16 id; // The number of the slope, mostly used for netgame syncing purposes
struct pslope_s *next; // Make a linked list of dynamic slopes, for easy reference later
// --- Information used in clipping/projection ---
// Origin vector for the plane
vector3_t o;
// The plane's definition.
vector3_t o; /// Plane origin.
vector3_t normal; /// Plane normal.
// 2-Dimentional vector (x, y) normalized. Used to determine distance from
// the origin in 2d mapspace. (Basically a thrust of FRACUNIT in xydirection angle)
vector2_t d;
// The rate at which z changes based on distance from the origin plane.
fixed_t zdelta;
// The normal of the slope; will always point upward, and thus be inverted on ceilings. I think it's only needed for physics? -Red
vector3_t normal;
// For comparing when a slope should be rendered
fixed_t lowz;
fixed_t highz;
vector2_t d; /// Precomputed normalized projection of the normal over XY.
fixed_t zdelta; /// Precomputed Z unit increase per XY unit.
// This values only check and must be updated if the slope itself is modified
angle_t zangle; // Angle of the plane going up from the ground (not mesured in degrees)
angle_t xydirection; // The direction the slope is facing (north, west, south, etc.)
struct line_s *sourceline; // The line that generated the slope
fixed_t extent; // Distance value used for recalculating zdelta
UINT8 refpos; // 1=front floor 2=front ceiling 3=back floor 4=back ceiling (used for dynamic sloping)
angle_t zangle; /// Precomputed angle of the plane going up from the ground (not measured in degrees).
angle_t xydirection;/// Precomputed angle of the normal's projection on the XY plane.
UINT8 flags; // Slope options
mapthing_t **vertices; // List should be three long for slopes made by vertex things, or one long for slopes using one vertex thing to anchor
struct pslope_s *next; // Make a linked list of dynamic slopes, for easy reference later
} pslope_t;
#endif

View file

@ -126,10 +126,12 @@ UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask;
#define BOSS_TT_CACHE_INDEX (MAXSKINS + 1)
#define METALSONIC_TT_CACHE_INDEX (MAXSKINS + 2)
#define ALLWHITE_TT_CACHE_INDEX (MAXSKINS + 3)
#define RAINBOW_TT_CACHE_INDEX (MAXSKINS + 4)
#define BLINK_TT_CACHE_INDEX (MAXSKINS + 5)
#define DEFAULT_STARTTRANSCOLOR 96
#define NUM_PALETTE_ENTRIES 256
static UINT8** translationtablecache[MAXSKINS + 4] = {NULL};
static UINT8** translationtablecache[MAXSKINS + 6] = {NULL};
const UINT8 Color_Index[MAXTRANSLATIONS-1][16] = {
// {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // SKINCOLOR_NONE
@ -457,17 +459,82 @@ void R_InitTranslationTables(void)
\return void
*/
// Define for getting accurate color brightness readings according to how the human eye sees them.
// https://en.wikipedia.org/wiki/Relative_luminance
// 0.2126 to red
// 0.7152 to green
// 0.0722 to blue
// (See this same define in hw_md2.c!)
#define SETBRIGHTNESS(brightness,r,g,b) \
brightness = (UINT8)(((1063*((UINT16)r)/5000) + (3576*((UINT16)g)/5000) + (361*((UINT16)b)/5000)) / 3)
/** \brief Generates the rainbow colourmaps that are used when a player has the invincibility power... stolen from kart, with permission
\param dest_colormap colormap to populate
\param skincolor translation color
*/
static void R_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor)
{
INT32 i;
RGBA_t color;
UINT8 brightness;
INT32 j;
UINT8 colorbrightnesses[16];
UINT16 brightdif;
INT32 temp;
// first generate the brightness of all the colours of that skincolour
for (i = 0; i < 16; i++)
{
color = V_GetColor(Color_Index[skincolor-1][i]);
SETBRIGHTNESS(colorbrightnesses[i], color.s.red, color.s.green, color.s.blue);
}
// next, for every colour in the palette, choose the transcolor that has the closest brightness
for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
{
if (i == 0 || i == 31) // pure black and pure white don't change
{
dest_colormap[i] = (UINT8)i;
continue;
}
color = V_GetColor(i);
SETBRIGHTNESS(brightness, color.s.red, color.s.green, color.s.blue);
brightdif = 256;
for (j = 0; j < 16; j++)
{
temp = abs((INT16)brightness - (INT16)colorbrightnesses[j]);
if (temp < brightdif)
{
brightdif = (UINT16)temp;
dest_colormap[i] = Color_Index[skincolor-1][j];
}
}
}
}
#undef SETBRIGHTNESS
static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color)
{
INT32 i, starttranscolor, skinramplength;
// Handle a couple of simple special cases
if (skinnum == TC_BOSS || skinnum == TC_ALLWHITE || skinnum == TC_METALSONIC || color == SKINCOLOR_NONE)
if (skinnum == TC_BOSS
|| skinnum == TC_ALLWHITE
|| skinnum == TC_METALSONIC
|| skinnum == TC_BLINK
|| color == SKINCOLOR_NONE)
{
if (skinnum == TC_ALLWHITE)
memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8));
else if (skinnum == TC_BLINK && color != SKINCOLOR_NONE)
memset(dest_colormap, Color_Index[color-1][3], NUM_PALETTE_ENTRIES * sizeof(UINT8));
else
{
for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
{
if (skinnum == TC_ALLWHITE) dest_colormap[i] = 0;
else dest_colormap[i] = (UINT8)i;
dest_colormap[i] = (UINT8)i;
}
// White!
@ -478,6 +545,11 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
return;
}
else if (skinnum == TC_RAINBOW)
{
R_RainbowColormap(dest_colormap, color);
return;
}
if (color >= MAXTRANSLATIONS)
I_Error("Invalid skin color #%hu.", (UINT16)color);
@ -522,6 +594,8 @@ UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags)
else if (skinnum == TC_BOSS) skintableindex = BOSS_TT_CACHE_INDEX;
else if (skinnum == TC_METALSONIC) skintableindex = METALSONIC_TT_CACHE_INDEX;
else if (skinnum == TC_ALLWHITE) skintableindex = ALLWHITE_TT_CACHE_INDEX;
else if (skinnum == TC_RAINBOW) skintableindex = RAINBOW_TT_CACHE_INDEX;
else if (skinnum == TC_BLINK) skintableindex = BLINK_TT_CACHE_INDEX;
else skintableindex = skinnum;
if (flags & GTC_CACHE)

View file

@ -105,6 +105,8 @@ extern lumpnum_t viewborderlump[8];
#define TC_BOSS -2
#define TC_METALSONIC -3 // For Metal Sonic battle
#define TC_ALLWHITE -4 // For Cy-Brak-demon
#define TC_RAINBOW -5 // For single colour
#define TC_BLINK -6 // For item blinking, according to kart
// Initialize color translation tables, for player rendering etc.
void R_InitTranslationTables(void);

View file

@ -719,11 +719,11 @@ static void R_DrawVisSprite(vissprite_t *vis)
colfunc = basecolfunc; // hack: this isn't resetting properly somewhere.
dc_colormap = vis->colormap;
if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash"
if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
{
// translate certain pixels to white
colfunc = transcolfunc;
if (vis->mobj->type == MT_CYBRAKDEMON)
if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized)
dc_translation = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
else if (vis->mobj->type == MT_METALSONIC_BATTLE)
dc_translation = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE);
@ -734,7 +734,9 @@ static void R_DrawVisSprite(vissprite_t *vis)
{
colfunc = transtransfunc;
dc_transmap = vis->transmap;
if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_>
if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized)
dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE);
else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_>
{
size_t skinnum = (skin_t*)vis->mobj->skin-skins;
dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE);
@ -753,7 +755,9 @@ static void R_DrawVisSprite(vissprite_t *vis)
colfunc = transcolfunc;
// New colormap stuff for skins Tails 06-07-2002
if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player!
if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized)
dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE);
else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player!
{
size_t skinnum = (skin_t*)vis->mobj->skin-skins;
dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE);
@ -2443,7 +2447,7 @@ static void R_DrawMaskedList (drawnode_t* head)
void R_DrawMasked(maskcount_t* masks, UINT8 nummasks)
{
drawnode_t heads[nummasks]; /**< Drawnode lists; as many as number of views/portals. */
INT8 i;
SINT8 i;
for (i = 0; i < nummasks; i++)
{
@ -2700,6 +2704,9 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem;
player->followitem = skin->followitem;
if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->revitem == MT_LHRT || player->spinitem == MT_LHRT || player->thokitem == MT_LHRT)) // Healers can't keep their buff.
player->powers[pw_shield] &= SH_STACK;
player->actionspd = skin->actionspd;
player->mindash = skin->mindash;
player->maxdash = skin->maxdash;

View file

@ -113,9 +113,11 @@ static UINT16 current_track;
#endif
#ifdef HAVE_OPENMPT
int mod_err = OPENMPT_ERROR_OK;
static int mod_err = OPENMPT_ERROR_OK;
static const char *mod_err_str;
static UINT16 current_subsong;
static size_t probesize;
static int result;
#endif
#ifdef HAVE_MIXERX
@ -473,7 +475,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
gme_track_info(emu, &info, 0);
len = (info->play_length * 441 / 10) << 2;
mem = malloc(len);
mem = Z_Malloc(len, PU_SOUND, 0);
gme_play(emu, len >> 1, mem);
gme_free_info(info);
gme_delete(emu);
@ -546,7 +548,7 @@ void *I_GetSfx(sfxinfo_t *sfx)
gme_track_info(emu, &info, 0);
len = (info->play_length * 441 / 10) << 2;
mem = malloc(len);
mem = Z_Malloc(len, PU_SOUND, 0);
gme_play(emu, len >> 1, mem);
gme_free_info(info);
gme_delete(emu);
@ -1223,6 +1225,36 @@ boolean I_LoadSong(char *data, size_t len)
Mix_Timidity_addToPathList(cv_miditimiditypath.string); // this overwrites previous custom path
#endif
#ifdef HAVE_OPENMPT
/*
If the size of the data to be checked is bigger than the recommended size (> 2048)
Let's just set the probe size to the recommended size
Otherwise let's give it the full data size
*/
if (len > openmpt_probe_file_header_get_recommended_size())
probesize = openmpt_probe_file_header_get_recommended_size();
else
probesize = len;
result = openmpt_probe_file_header(OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT, data, probesize, len, NULL, NULL, NULL, NULL, NULL, NULL);
if (result == OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS) // We only cared if it succeeded, continue on if not.
{
openmpt_mhandle = openmpt_module_create_from_memory2(data, len, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (!openmpt_mhandle) // Failed to create module handle? Show error and return!
{
mod_err = openmpt_module_error_get_last(openmpt_mhandle);
mod_err_str = openmpt_error_string(mod_err);
CONS_Alert(CONS_ERROR, "openmpt_module_create_from_memory2: %s\n", mod_err_str);
return false;
}
else
return true; // All good and we're ready for music playback!
}
#endif
// Let's see if Mixer is able to load this.
rw = SDL_RWFromMem(data, len);
{
music = Mix_LoadMUS_RW(rw, 1);
@ -1233,40 +1265,6 @@ boolean I_LoadSong(char *data, size_t len)
return false;
}
#ifdef HAVE_OPENMPT
switch(Mix_GetMusicType(music))
{
case MUS_MODPLUG:
case MUS_MOD:
openmpt_mhandle = openmpt_module_create_from_memory2(data, len, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (!openmpt_mhandle)
{
mod_err = openmpt_module_error_get_last(openmpt_mhandle);
mod_err_str = openmpt_error_string(mod_err);
CONS_Alert(CONS_ERROR, "openmpt_module_create_from_memory2: %s\n", mod_err_str);
Mix_FreeMusic(music);
music = NULL;
return false;
}
else
{
Mix_FreeMusic(music);
music = NULL;
return true;
}
break;
case MUS_WAV:
case MUS_MID:
case MUS_OGG:
case MUS_MP3:
case MUS_FLAC:
Mix_HookMusic(NULL, NULL);
break;
default:
break;
}
#endif
// Find the OGG loop point.
loop_point = 0.0f;
song_length = 0.0f;

View file

@ -137,7 +137,7 @@ sfxinfo_t S_sfx[NUMSFX] =
// Game objects, etc
{"appear", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Appearing platform"},
{"bkpoof", false, 70, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Armageddon explosion"},
{"bkpoof", false, 70, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Armageddon pow"},
{"bnce1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bounce"}, // Boing!
{"bnce2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Scatter"}, // Boing!
{"cannon", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful shot"},
@ -197,6 +197,8 @@ sfxinfo_t S_sfx[NUMSFX] =
{"corkh", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Cork hit"},
{"bowl", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bowling"},
{"chuchu", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Train horn"},
{"bsnipe", false, 200, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Home-run smash"},
{"sprong", false, 112, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power spring"},
// Menu, interface
{"chchng", false, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Score"},
@ -303,7 +305,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3k3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame Shield"},
{"s3k3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble Shield"},
{"s3k40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction blast"},
{"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning Shield"},
{"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Thunder Shield"},
{"s3k42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Twinspin"},
{"s3k43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame burst"},
{"s3k44", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble bounce"},
@ -334,7 +336,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3k5d", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Heavy hit"},
{"s3k5e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Firing laser"},
{"s3k5f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Crusher stomp"},
{"s3k60", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flying away"},
{"s3k60", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Accelerating"},
{"s3k61", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Drilling"},
{"s3k62", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Jump"},
{"s3k63", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Starpost"},
@ -430,8 +432,8 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3kbcl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // long version of previous
{"s3kbds", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flying fortress"},
{"s3kbdl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flying fortress"}, // ditto
{"s3kbes", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flying away"},
{"s3kbel", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flying away"}, // ditto
{"s3kbes", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flying"},
{"s3kbel", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flying"}, // ditto
{"s3kbfs", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Turbine"},
{"s3kbfl", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Turbine"}, // ditto
{"s3kc0s", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Turbine"},

View file

@ -263,6 +263,8 @@ typedef enum
sfx_corkh,
sfx_bowl,
sfx_chuchu,
sfx_bsnipe,
sfx_sprong,
// Menu, interface
sfx_chchng,

View file

@ -95,6 +95,7 @@ static patch_t *ringshield;
static patch_t *watershield;
static patch_t *bombshield;
static patch_t *pityshield;
static patch_t *pinkshield;
static patch_t *flameshield;
static patch_t *bubbleshield;
static patch_t *thundershield;
@ -285,6 +286,7 @@ void ST_LoadGraphics(void)
watershield = W_CachePatchName("TVELICON", PU_HUDGFX);
bombshield = W_CachePatchName("TVARICON", PU_HUDGFX);
pityshield = W_CachePatchName("TVPIICON", PU_HUDGFX);
pinkshield = W_CachePatchName("TVPPICON", PU_HUDGFX);
flameshield = W_CachePatchName("TVFLICON", PU_HUDGFX);
bubbleshield = W_CachePatchName("TVBBICON", PU_HUDGFX);
thundershield = W_CachePatchName("TVZPICON", PU_HUDGFX);
@ -1250,6 +1252,7 @@ static void ST_drawPowerupHUD(void)
case SH_ARMAGEDDON: p = bombshield; break;
case SH_ATTRACT: p = ringshield; break;
case SH_PITY: p = pityshield; break;
case SH_PINK: p = pinkshield; break;
case SH_FLAMEAURA: p = flameshield; break;
case SH_BUBBLEWRAP: p = bubbleshield; break;
case SH_THUNDERCOIN: p = thundershield; break;
@ -2303,14 +2306,16 @@ static void ST_doItemFinderIconsAndSound(void)
return;
// Scan thinkers to find emblem mobj with these ids
for (th = thinkercap.next; th != &thinkercap; th = th->next)
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
if (mo2->type == MT_EMBLEM)
{
if (mo2->type != MT_EMBLEM)
continue;
if (!(mo2->flags & MF_SPECIAL))
continue;
@ -2327,7 +2332,7 @@ static void ST_doItemFinderIconsAndSound(void)
break;
}
}
}
}
if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0)