Add reversed weather

- Negative speed weather will spawn from a floor in a sector with a sky ceiling, and go up into the ceiling.
- (Not really the same as reverse gravity weather in that aspect, because that would be for sky floors.)
- Fixed invert precipitation flag for linedef type 8 being completely unimplemented. (How long has it been like this...?)
- Fix swapping weather on the fly having reversed momz
This commit is contained in:
Sally Coolatta 2022-06-05 05:39:35 -04:00
parent 35cc746adf
commit 6106ce1624
4 changed files with 108 additions and 68 deletions

View file

@ -277,6 +277,7 @@ void P_RespawnSpecials(void);
mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type);
void P_CalculatePrecipFloor(precipmobj_t *mobj);
void P_RecalcPrecipInSector(sector_t *sector);
void P_PrecipitationEffects(void);

View file

@ -3760,19 +3760,22 @@ animonly:
P_CyclePlayerMobjState(mobj);
}
static void CalculatePrecipFloor(precipmobj_t *mobj)
void P_CalculatePrecipFloor(precipmobj_t *mobj)
{
// recalculate floorz each time
const sector_t *mobjsecsubsec;
if (mobj && mobj->subsector && mobj->subsector->sector)
mobjsecsubsec = mobj->subsector->sector;
else
return;
mobj->floorz = P_GetSectorFloorZAt(mobjsecsubsec, mobj->x, mobj->y);
if (mobjsecsubsec->ffloors)
{
ffloor_t *rover;
fixed_t topheight;
fixed_t height;
for (rover = mobjsecsubsec->ffloors; rover; rover = rover->next)
{
@ -3783,9 +3786,9 @@ static void CalculatePrecipFloor(precipmobj_t *mobj)
if (!(rover->flags & FF_BLOCKOTHERS) && !(rover->flags & FF_SWIMMABLE))
continue;
topheight = P_GetFFloorTopZAt(rover, mobj->x, mobj->y);
if (topheight > mobj->floorz)
mobj->floorz = topheight;
height = P_GetFFloorTopZAt(rover, mobj->x, mobj->y);
if (height > mobj->floorz)
mobj->floorz = height;
}
}
}
@ -3800,7 +3803,7 @@ void P_RecalcPrecipInSector(sector_t *sector)
sector->moved = true; // Recalc lighting and things too, maybe
for (psecnode = sector->touching_preciplist; psecnode; psecnode = psecnode->m_thinglist_next)
CalculatePrecipFloor(psecnode->m_thing);
P_CalculatePrecipFloor(psecnode->m_thing);
}
//
@ -3817,13 +3820,15 @@ void P_NullPrecipThinker(precipmobj_t *mobj)
void P_PrecipThinker(precipmobj_t *mobj)
{
boolean flip = (mobj->precipflags & PCF_FLIP);
P_CycleStateAnimation((mobj_t *)mobj);
if (mobj->state == &states[S_RAINRETURN])
{
// Reset to ceiling!
P_SetPrecipMobjState(mobj, mobj->info->spawnstate);
mobj->z = mobj->ceilingz;
mobj->z = (flip) ? (mobj->floorz) : (mobj->ceilingz);
mobj->momz = -mobj->info->speed;
mobj->precipflags &= ~PCF_SPLASH;
R_ResetPrecipitationMobjInterpolationState(mobj);
@ -3858,18 +3863,20 @@ void P_PrecipThinker(precipmobj_t *mobj)
if (mobj->precipflags & PCF_SPLASH)
return;
mobj->z += mobj->momz;
// adjust height
if ((mobj->z += mobj->momz) <= mobj->floorz)
if ((flip) ? (mobj->z >= mobj->ceilingz) : (mobj->z <= mobj->floorz))
{
if ((mobj->info->deathstate == S_NULL) || (mobj->precipflags & PCF_PIT)) // no splashes on sky or bottomless pits
{
mobj->z = mobj->ceilingz;
mobj->z = (flip) ? (mobj->floorz) : (mobj->ceilingz);
R_ResetPrecipitationMobjInterpolationState(mobj);
}
else
{
P_SetPrecipMobjState(mobj, mobj->info->deathstate);
mobj->z = mobj->floorz;
mobj->z = (flip) ? (mobj->ceilingz) : (mobj->floorz);
mobj->precipflags |= PCF_SPLASH;
R_ResetPrecipitationMobjInterpolationState(mobj);
}
@ -10341,8 +10348,8 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
{
const mobjinfo_t *info = &mobjinfo[type];
state_t *st;
fixed_t start_z = INT32_MIN;
precipmobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
fixed_t starting_floorz;
mobj->type = type;
mobj->info = info;
@ -10364,8 +10371,8 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
// set subsector and/or block links
P_SetPrecipitationThingPosition(mobj);
mobj->floorz = starting_floorz = P_GetSectorFloorZAt (mobj->subsector->sector, x, y);
mobj->ceilingz = P_GetSectorCeilingZAt(mobj->subsector->sector, x, y);
mobj->floorz = P_GetSectorFloorZAt (mobj->subsector->sector, x, y);
mobj->ceilingz = P_GetSectorCeilingZAt(mobj->subsector->sector, x, y);
mobj->floorrover = NULL;
mobj->ceilingrover = NULL;
@ -10373,17 +10380,34 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
mobj->z = z;
mobj->momz = -info->speed;
if (info->speed < 0)
{
mobj->precipflags |= PCF_FLIP;
}
start_z = mobj->floorz;
mobj->thinker.function.acp1 = (actionf_p1)P_NullPrecipThinker;
P_AddThinker(THINK_PRECIP, &mobj->thinker);
CalculatePrecipFloor(mobj);
P_CalculatePrecipFloor(mobj);
if (mobj->floorz != starting_floorz)
mobj->precipflags |= PCF_FOF;
else if (GETSECSPECIAL(mobj->subsector->sector->special, 1) == 7
|| GETSECSPECIAL(mobj->subsector->sector->special, 1) == 6
|| mobj->subsector->sector->floorpic == skyflatnum)
mobj->precipflags |= PCF_PIT;
if (mobj->floorz != start_z)
{
; //mobj->precipflags |= PCF_FOF;
}
else
{
INT32 special = GETSECSPECIAL(mobj->subsector->sector->special, 1);
boolean sFlag = (mobj->precipflags & PCF_FLIP) ? (mobj->subsector->sector->flags & SF_FLIPSPECIAL_CEILING) : (mobj->subsector->sector->flags & SF_FLIPSPECIAL_FLOOR);
boolean pitFloor = ((special == 6 || special == 7) && sFlag);
boolean skyFloor = (mobj->precipflags & PCF_FLIP) ? (mobj->subsector->sector->ceilingpic == skyflatnum) : (mobj->subsector->sector->floorpic == skyflatnum);
if (pitFloor || skyFloor)
{
mobj->precipflags |= PCF_PIT;
}
}
R_ResetPrecipitationMobjInterpolationState(mobj);
@ -10588,13 +10612,19 @@ consvar_t cv_itemrespawn = CVAR_INIT ("respawnitem", "On", CV_NETVAR, CV_OnOff,
void P_SpawnPrecipitation(void)
{
INT32 i, j, k;
mobjtype_t type = precipprops[curWeather].type;
UINT8 randomstates = (UINT8)mobjinfo[type].damage;
const mobjtype_t type = precipprops[curWeather].type;
const UINT8 randomstates = (UINT8)mobjinfo[type].damage;
const boolean flip = (mobjinfo[type].speed < 0);
fixed_t basex, basey, x, y, z, height;
UINT16 numparticles = 0;
boolean condition = false;
subsector_t *precipsector = NULL;
precipmobj_t *rainmo = NULL;
if (dedicated || !cv_drawdist_precip.value || curWeather == PRECIP_NONE) // SRB2Kart
if (dedicated || !cv_drawdist_precip.value || type == MT_NULL)
return;
// Use the blockmap to narrow down our placing patterns
@ -10603,58 +10633,63 @@ void P_SpawnPrecipitation(void)
basex = bmaporgx + (i % bmapwidth) * MAPBLOCKSIZE;
basey = bmaporgy + (i / bmapwidth) * MAPBLOCKSIZE;
x = basex + ((M_RandomKey(MAPBLOCKUNITS << 3) << FRACBITS) >> 3);
y = basey + ((M_RandomKey(MAPBLOCKUNITS << 3) << FRACBITS) >> 3);
precipsector = R_PointInSubsectorOrNull(x, y);
// No sector? Stop wasting time,
// move on to the next entry in the blockmap
if (!precipsector)
continue;
// Not in a sector with visible sky?
condition = (precipsector->sector->ceilingpic == skyflatnum);
if (precipsector->sector->flags & SF_INVERTPRECIP)
{
UINT16 numparticles = 0;
condition = !condition;
}
x = basex + ((M_RandomKey(MAPBLOCKUNITS<<3)<<FRACBITS)>>3);
y = basey + ((M_RandomKey(MAPBLOCKUNITS<<3)<<FRACBITS)>>3);
if (!condition)
{
continue;
}
precipsector = R_PointInSubsectorOrNull(x, y);
height = precipsector->sector->ceilingheight - precipsector->sector->floorheight;
// No sector? Stop wasting time,
// move on to the next entry in the blockmap
if (!precipsector)
continue;
// Exists, but is too small for reasonable precipitation.
if (height < 64<<FRACBITS)
continue;
// Not in a sector with visible sky?
if (precipsector->sector->ceilingpic != skyflatnum)
continue;
// Hack around a quirk of this entire system, where taller sectors look like they get less precipitation.
numparticles = 1 + (height / (MAPBLOCKUNITS<<4<<FRACBITS));
height = precipsector->sector->ceilingheight - precipsector->sector->floorheight;
// Don't set z properly yet...
z = (flip) ? (precipsector->sector->floorheight) : (precipsector->sector->ceilingheight);
// Exists, but is too small for reasonable precipitation.
if (height < 64<<FRACBITS)
continue;
for (j = 0; j < numparticles; j++)
{
rainmo = P_SpawnPrecipMobj(x, y, z, type);
// Hack around a quirk of this entire system, where taller sectors look like they get less precipitation.
numparticles = 1 + (height / (MAPBLOCKUNITS<<4<<FRACBITS));
// Don't set z properly yet...
z = precipsector->sector->ceilingheight;
for (j = 0; j < numparticles; j++)
if (randomstates > 0)
{
rainmo = P_SpawnPrecipMobj(x, y, z, type);
UINT8 mrand = M_RandomByte();
UINT8 threshold = UINT8_MAX / (randomstates + 1);
statenum_t st = mobjinfo[type].spawnstate;
if (randomstates > 0)
for (k = 0; k < randomstates; k++)
{
UINT8 mrand = M_RandomByte();
UINT8 threshold = UINT8_MAX / (randomstates + 1);
statenum_t st = mobjinfo[type].spawnstate;
for (k = 0; k < randomstates; k++)
if (mrand < (threshold * (k+1)))
{
if (mrand < (threshold * (k+1)))
{
P_SetPrecipMobjState(rainmo, st+k+1);
break;
}
P_SetPrecipMobjState(rainmo, st+k+1);
break;
}
}
// Randomly assign a height, now that floorz is set.
rainmo->z = M_RandomRange(rainmo->floorz>>FRACBITS, rainmo->ceilingz>>FRACBITS)<<FRACBITS;
}
// Randomly assign a height, now that floorz is set.
rainmo->z = M_RandomRange(rainmo->floorz >> FRACBITS, rainmo->ceilingz >> FRACBITS) << FRACBITS;
}
}
}

View file

@ -262,12 +262,11 @@ typedef enum
// PRECIPITATION flags ?! ?! ?!
//
typedef enum {
PCF_INVISIBLE = 1, // Don't draw.
PCF_PIT = 1<<1, // Above pit.
PCF_FOF = 1<<2, // Above FOF.
PCF_MOVINGFOF = 1<<3, // Above MOVING FOF (this means we need to keep floorz up to date...)
PCF_SPLASH = 1<<4, // Splashed on the ground, return to the ceiling after the animation's over
PCF_THUNK = 1<<5, // Ran the thinker this tic.
PCF_THUNK = 1, // Ran the thinker this tic.
PCF_SPLASH = 1<<1, // Splashed on the ground, return to the ceiling after the animation's over
PCF_INVISIBLE = 1<<2, // Don't draw.
PCF_PIT = 1<<3, // Above pit.
PCF_FLIP = 1<<4, // Spawning from floor, moving upwards.
} precipflag_t;
// Map Object definition.

View file

@ -1851,8 +1851,13 @@ void P_SwitchWeather(preciptype_t newWeather)
precipmobj->sprite = precipmobj->state->sprite;
precipmobj->frame = precipmobj->state->frame;
precipmobj->momz = mobjinfo[swap].speed;
precipmobj->precipflags &= ~PCF_INVISIBLE;
precipmobj->momz = -mobjinfo[swap].speed;
precipmobj->precipflags &= ~(PCF_INVISIBLE|PCF_FLIP);
if (precipmobj->momz > 0)
{
precipmobj->precipflags |= PCF_FLIP;
}
}
}