Merge branch 'polyobj-fade' into 'master'

Linedef Exec 492: Fade PolyObject

See merge request STJr/SRB2Internal!192
This commit is contained in:
Digiku 2018-09-18 10:48:46 -04:00
commit 843ed289a6
4 changed files with 321 additions and 2 deletions

View File

@ -2853,6 +2853,165 @@ INT32 EV_DoPolyObjFlag(line_t *pfdata)
return 1;
}
void T_PolyObjFade(polyfade_t *th)
{
boolean stillfading = false;
polyobj_t *po = Polyobj_GetForNum(th->polyObjNum);
if (!po)
#ifdef RANGECHECK
I_Error("T_PolyObjFade: thinker has invalid id %d\n", th->polyObjNum);
#else
{
CONS_Debug(DBG_POLYOBJ, "T_PolyObjFade: thinker with invalid id %d removed.\n", th->polyObjNum);
P_RemoveThinkerDelayed(&th->thinker);
return;
}
#endif
// check for displacement due to override and reattach when possible
if (po->thinker == NULL)
po->thinker = &th->thinker;
stillfading = th->ticbased ? !(--(th->timer) <= 0)
: !((th->timer -= th->duration) <= 0);
if (th->timer <= 0)
{
po->translucency = max(min(th->destvalue, NUMTRANSMAPS), 0);
// remove thinker
if (po->thinker == &th->thinker)
po->thinker = NULL;
P_RemoveThinker(&th->thinker);
}
else
{
INT16 delta = abs(th->destvalue - th->sourcevalue);
INT32 duration = th->ticbased ? th->duration
: abs(FixedMul(FixedDiv(256, NUMTRANSMAPS), NUMTRANSMAPS - th->destvalue)
- FixedMul(FixedDiv(256, NUMTRANSMAPS), NUMTRANSMAPS - th->sourcevalue)); // speed-based internal counter duration: delta in 256 scale
fixed_t factor = min(FixedDiv(duration - th->timer, duration), 1*FRACUNIT);
if (th->destvalue < th->sourcevalue)
po->translucency = max(min(po->translucency, th->sourcevalue - (INT16)FixedMul(delta, factor)), th->destvalue);
else if (th->destvalue > th->sourcevalue)
po->translucency = min(max(po->translucency, th->sourcevalue + (INT16)FixedMul(delta, factor)), th->destvalue);
}
if (!stillfading)
{
// set render flags
if (po->translucency >= NUMTRANSMAPS) // invisible
po->flags &= ~POF_RENDERALL;
else
po->flags |= (po->spawnflags & POF_RENDERALL);
// set collision
if (th->docollision)
{
if (th->destvalue > th->sourcevalue) // faded out
{
po->flags &= ~POF_SOLID;
po->flags |= POF_NOSPECIALS;
}
else
{
po->flags |= (po->spawnflags & POF_SOLID);
if (!(po->spawnflags & POF_NOSPECIALS))
po->flags &= ~POF_NOSPECIALS;
}
}
}
else
{
if (po->translucency >= NUMTRANSMAPS)
// HACK: OpenGL renders fully opaque when >= NUMTRANSMAPS
po->translucency = NUMTRANSMAPS-1;
po->flags |= (po->spawnflags & POF_RENDERALL);
// set collision
if (th->docollision)
{
if (th->doghostfade)
{
po->flags &= ~POF_SOLID;
po->flags |= POF_NOSPECIALS;
}
else
{
po->flags |= (po->spawnflags & POF_SOLID);
if (!(po->spawnflags & POF_NOSPECIALS))
po->flags &= ~POF_NOSPECIALS;
}
}
}
}
INT32 EV_DoPolyObjFade(polyfadedata_t *pfdata)
{
polyobj_t *po;
polyobj_t *oldpo;
polyfade_t *th;
INT32 start;
if (!(po = Polyobj_GetForNum(pfdata->polyObjNum)))
{
CONS_Debug(DBG_POLYOBJ, "EV_DoPolyObjFade: bad polyobj %d\n", pfdata->polyObjNum);
return 0;
}
// don't allow line actions to affect bad polyobjects
if (po->isBad)
return 0;
// already equal, nothing to do
if (po->translucency == pfdata->destvalue)
return 1;
if (po->thinker && po->thinker->function.acp1 == (actionf_p1)T_PolyObjFade)
P_RemoveThinker(po->thinker);
// 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);
po->thinker = &th->thinker;
// set fields
th->polyObjNum = pfdata->polyObjNum;
th->sourcevalue = po->translucency;
th->destvalue = pfdata->destvalue;
th->docollision = pfdata->docollision;
th->doghostfade = pfdata->doghostfade;
if (pfdata->ticbased)
{
th->ticbased = true;
th->timer = th->duration = abs(pfdata->speed); // pfdata->speed is duration
}
else
{
th->ticbased = false;
th->timer = abs(FixedMul(FixedDiv(256, NUMTRANSMAPS), NUMTRANSMAPS - th->destvalue)
- FixedMul(FixedDiv(256, NUMTRANSMAPS), NUMTRANSMAPS - th->sourcevalue)); // delta converted to 256 scale, use as internal counter
th->duration = abs(pfdata->speed); // use th->duration as speed decrement
}
oldpo = po;
// apply action to mirroring polyobjects as well
start = 0;
while ((po = Polyobj_GetChild(oldpo, &start)))
{
pfdata->polyObjNum = po->id;
EV_DoPolyObjFade(pfdata);
}
// action was successful
return 1;
}
#endif // ifdef POLYOBJECTS
// EOF

View File

@ -207,6 +207,20 @@ typedef struct polydisplace_s
fixed_t oldHeights;
} polydisplace_t;
typedef struct polyfade_s
{
thinker_t thinker; // must be first
INT32 polyObjNum;
INT32 sourcevalue;
INT32 destvalue;
boolean docollision;
boolean doghostfade;
boolean ticbased;
INT32 duration;
INT32 timer;
} polyfade_t;
//
// Line Activation Data Structures
//
@ -266,6 +280,16 @@ typedef struct polydisplacedata_s
fixed_t dy;
} polydisplacedata_t;
typedef struct polyfadedata_s
{
INT32 polyObjNum;
INT32 destvalue;
boolean docollision;
boolean doghostfade;
boolean ticbased;
INT32 speed;
} polyfadedata_t;
//
// Functions
//
@ -287,6 +311,7 @@ void T_PolyDoorSlide(polyslidedoor_t *);
void T_PolyDoorSwing(polyswingdoor_t *);
void T_PolyObjDisplace (polydisplace_t *);
void T_PolyObjFlag (polymove_t *);
void T_PolyObjFade (polyfade_t *);
INT32 EV_DoPolyDoor(polydoordata_t *);
INT32 EV_DoPolyObjMove(polymovedata_t *);
@ -294,6 +319,7 @@ INT32 EV_DoPolyObjWaypoint(polywaypointdata_t *);
INT32 EV_DoPolyObjRotate(polyrotdata_t *);
INT32 EV_DoPolyObjDisplace(polydisplacedata_t *);
INT32 EV_DoPolyObjFlag(struct line_s *);
INT32 EV_DoPolyObjFade(polyfadedata_t *);
//

View File

@ -1298,6 +1298,7 @@ typedef enum
tc_polyswingdoor,
tc_polyflag,
tc_polydisplace,
tc_polyfade,
#endif
tc_end
} specials_e;
@ -1984,6 +1985,20 @@ static void SavePolydisplaceThinker(const thinker_t *th, const UINT8 type)
WRITEFIXED(save_p, ht->oldHeights);
}
static void SavePolyfadeThinker(const thinker_t *th, const UINT8 type)
{
const polyfade_t *ht = (const void *)th;
WRITEUINT8(save_p, type);
WRITEINT32(save_p, ht->polyObjNum);
WRITEINT32(save_p, ht->sourcevalue);
WRITEINT32(save_p, ht->destvalue);
WRITEUINT8(save_p, (UINT8)ht->docollision);
WRITEUINT8(save_p, (UINT8)ht->doghostfade);
WRITEUINT8(save_p, (UINT8)ht->ticbased);
WRITEINT32(save_p, ht->duration);
WRITEINT32(save_p, ht->timer);
}
#endif
/*
//
@ -2208,6 +2223,11 @@ static void P_NetArchiveThinkers(void)
SavePolydisplaceThinker(th, tc_polydisplace);
continue;
}
else if (th->function.acp1 == (actionf_p1)T_PolyObjFade)
{
SavePolyfadeThinker(th, tc_polyfade);
continue;
}
#endif
#ifdef PARANOIA
else if (th->function.acv != P_RemoveThinkerDelayed) // wait garbage collection
@ -2985,6 +3005,26 @@ static inline void LoadPolydisplaceThinker(actionf_p1 thinker)
ht->oldHeights = READFIXED(save_p);
P_AddThinker(&ht->thinker);
}
//
// LoadPolyfadeThinker
//
// Loads a polyfadet_t thinker
//
static void LoadPolyfadeThinker(actionf_p1 thinker)
{
polyfade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL);
ht->thinker.function.acp1 = thinker;
ht->polyObjNum = READINT32(save_p);
ht->sourcevalue = READINT32(save_p);
ht->destvalue = READINT32(save_p);
ht->docollision = (boolean)READUINT8(save_p);
ht->doghostfade = (boolean)READUINT8(save_p);
ht->ticbased = (boolean)READUINT8(save_p);
ht->duration = READINT32(save_p);
ht->timer = READINT32(save_p);
P_AddThinker(&ht->thinker);
}
#endif
/*
@ -3186,6 +3226,10 @@ static void P_NetUnArchiveThinkers(void)
case tc_polydisplace:
LoadPolydisplaceThinker((actionf_p1)T_PolyObjDisplace);
break;
case tc_polyfade:
LoadPolyfadeThinker((actionf_p1)T_PolyObjFade);
break;
#endif
case tc_scroll:
LoadScrollThinker((actionf_p1)T_Scroll);

View File

@ -1218,7 +1218,7 @@ static void PolyVisible(line_t *line)
po->flags |= POF_SOLID;
po->flags &= ~POF_NOSPECIALS;
po->flags |= POF_RENDERALL;
po->flags |= (po->spawnflags & POF_RENDERALL);
}
//
@ -1242,7 +1242,94 @@ static void PolyTranslucency(line_t *line)
if (po->isBad)
return;
po->translucency = (line->frontsector->floorheight >> FRACBITS) / 100;
// if DONTPEGBOTTOM, specify raw translucency value in Front X Offset
// else, take it out of 1000. If Front X Offset is specified, use that. Else, use floorheight.
if (line->flags & ML_EFFECT3) // relative calc
po->translucency = max(min(po->translucency + ((line->flags & ML_DONTPEGBOTTOM) ?
(sides[line->sidenum[0]].textureoffset ?
max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, NUMTRANSMAPS), -NUMTRANSMAPS)
: max(min(line->frontsector->floorheight>>FRACBITS, NUMTRANSMAPS), -NUMTRANSMAPS))
: (sides[line->sidenum[0]].textureoffset ?
max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, 1000), -1000) / 100
: max(min(line->frontsector->floorheight>>FRACBITS, 1000), -1000) / 100)),
NUMTRANSMAPS), 0);
else
po->translucency = (line->flags & ML_DONTPEGBOTTOM) ?
(sides[line->sidenum[0]].textureoffset ?
max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, NUMTRANSMAPS), 0)
: max(min(line->frontsector->floorheight>>FRACBITS, NUMTRANSMAPS), 0))
: (sides[line->sidenum[0]].textureoffset ?
max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, 1000), 0) / 100
: max(min(line->frontsector->floorheight>>FRACBITS, 1000), 0) / 100);
}
//
// PolyFade
//
// Makes a polyobject translucency fade and applies tangibility
//
static boolean PolyFade(line_t *line)
{
INT32 polyObjNum = line->tag;
polyobj_t *po;
polyfadedata_t pfd;
if (!(po = Polyobj_GetForNum(polyObjNum)))
{
CONS_Debug(DBG_POLYOBJ, "PolyFade: bad polyobj %d\n", polyObjNum);
return 0;
}
// don't allow line actions to affect bad polyobjects
if (po->isBad)
return 0;
// Prevent continuous execs from interfering on an existing fade
if (!(line->flags & ML_EFFECT5)
&& po->thinker
&& po->thinker->function.acp1 == (actionf_p1)T_PolyObjFade)
{
CONS_Debug(DBG_POLYOBJ, "Line type 492 Executor: Fade PolyObject thinker already exists\n");
return 0;
}
pfd.polyObjNum = polyObjNum;
// if DONTPEGBOTTOM, specify raw translucency value in Front X Offset
// else, take it out of 1000. If Front X Offset is specified, use that. Else, use floorheight.
if (line->flags & ML_EFFECT3) // relative calc
pfd.destvalue = max(min(po->translucency + ((line->flags & ML_DONTPEGBOTTOM) ?
(sides[line->sidenum[0]].textureoffset ?
max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, NUMTRANSMAPS), -NUMTRANSMAPS)
: max(min(line->frontsector->floorheight>>FRACBITS, NUMTRANSMAPS), -NUMTRANSMAPS))
: (sides[line->sidenum[0]].textureoffset ?
max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, 1000), -1000) / 100
: max(min(line->frontsector->floorheight>>FRACBITS, 1000), -1000) / 100)),
NUMTRANSMAPS), 0);
else
pfd.destvalue = (line->flags & ML_DONTPEGBOTTOM) ?
(sides[line->sidenum[0]].textureoffset ?
max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, NUMTRANSMAPS), 0)
: max(min(line->frontsector->floorheight>>FRACBITS, NUMTRANSMAPS), 0))
: (sides[line->sidenum[0]].textureoffset ?
max(min(sides[line->sidenum[0]].textureoffset>>FRACBITS, 1000), 0) / 100
: max(min(line->frontsector->floorheight>>FRACBITS, 1000), 0) / 100);
// already equal, nothing to do
if (po->translucency == pfd.destvalue)
return 1;
pfd.docollision = !(line->flags & ML_BOUNCY); // do not handle collision flags
pfd.doghostfade = (line->flags & ML_EFFECT1); // do ghost fade (no collision flags during fade)
pfd.ticbased = (line->flags & ML_EFFECT4); // Speed = Tic Duration
// allow Back Y Offset to be consistent with other fade specials
pfd.speed = (line->sidenum[1] != 0xFFFF && !sides[line->sidenum[0]].rowoffset) ?
abs(sides[line->sidenum[1]].rowoffset>>FRACBITS)
: abs(sides[line->sidenum[0]].rowoffset>>FRACBITS);
return EV_DoPolyObjFade(&pfd);
}
//
@ -3355,6 +3442,9 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
case 491:
PolyTranslucency(line);
break;
case 492:
PolyFade(line);
break;
#endif
default: