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); 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_RecalcPrecipInSector(sector_t *sector);
void P_PrecipitationEffects(void); void P_PrecipitationEffects(void);

View file

@ -3760,19 +3760,22 @@ animonly:
P_CyclePlayerMobjState(mobj); P_CyclePlayerMobjState(mobj);
} }
static void CalculatePrecipFloor(precipmobj_t *mobj) void P_CalculatePrecipFloor(precipmobj_t *mobj)
{ {
// recalculate floorz each time // recalculate floorz each time
const sector_t *mobjsecsubsec; const sector_t *mobjsecsubsec;
if (mobj && mobj->subsector && mobj->subsector->sector) if (mobj && mobj->subsector && mobj->subsector->sector)
mobjsecsubsec = mobj->subsector->sector; mobjsecsubsec = mobj->subsector->sector;
else else
return; return;
mobj->floorz = P_GetSectorFloorZAt(mobjsecsubsec, mobj->x, mobj->y); mobj->floorz = P_GetSectorFloorZAt(mobjsecsubsec, mobj->x, mobj->y);
if (mobjsecsubsec->ffloors) if (mobjsecsubsec->ffloors)
{ {
ffloor_t *rover; ffloor_t *rover;
fixed_t topheight; fixed_t height;
for (rover = mobjsecsubsec->ffloors; rover; rover = rover->next) 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)) if (!(rover->flags & FF_BLOCKOTHERS) && !(rover->flags & FF_SWIMMABLE))
continue; continue;
topheight = P_GetFFloorTopZAt(rover, mobj->x, mobj->y); height = P_GetFFloorTopZAt(rover, mobj->x, mobj->y);
if (topheight > mobj->floorz) if (height > mobj->floorz)
mobj->floorz = topheight; mobj->floorz = height;
} }
} }
} }
@ -3800,7 +3803,7 @@ void P_RecalcPrecipInSector(sector_t *sector)
sector->moved = true; // Recalc lighting and things too, maybe sector->moved = true; // Recalc lighting and things too, maybe
for (psecnode = sector->touching_preciplist; psecnode; psecnode = psecnode->m_thinglist_next) 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) void P_PrecipThinker(precipmobj_t *mobj)
{ {
boolean flip = (mobj->precipflags & PCF_FLIP);
P_CycleStateAnimation((mobj_t *)mobj); P_CycleStateAnimation((mobj_t *)mobj);
if (mobj->state == &states[S_RAINRETURN]) if (mobj->state == &states[S_RAINRETURN])
{ {
// Reset to ceiling! // Reset to ceiling!
P_SetPrecipMobjState(mobj, mobj->info->spawnstate); P_SetPrecipMobjState(mobj, mobj->info->spawnstate);
mobj->z = mobj->ceilingz; mobj->z = (flip) ? (mobj->floorz) : (mobj->ceilingz);
mobj->momz = -mobj->info->speed; mobj->momz = -mobj->info->speed;
mobj->precipflags &= ~PCF_SPLASH; mobj->precipflags &= ~PCF_SPLASH;
R_ResetPrecipitationMobjInterpolationState(mobj); R_ResetPrecipitationMobjInterpolationState(mobj);
@ -3858,18 +3863,20 @@ void P_PrecipThinker(precipmobj_t *mobj)
if (mobj->precipflags & PCF_SPLASH) if (mobj->precipflags & PCF_SPLASH)
return; return;
mobj->z += mobj->momz;
// adjust height // 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 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); R_ResetPrecipitationMobjInterpolationState(mobj);
} }
else else
{ {
P_SetPrecipMobjState(mobj, mobj->info->deathstate); P_SetPrecipMobjState(mobj, mobj->info->deathstate);
mobj->z = mobj->floorz; mobj->z = (flip) ? (mobj->ceilingz) : (mobj->floorz);
mobj->precipflags |= PCF_SPLASH; mobj->precipflags |= PCF_SPLASH;
R_ResetPrecipitationMobjInterpolationState(mobj); 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]; const mobjinfo_t *info = &mobjinfo[type];
state_t *st; state_t *st;
fixed_t start_z = INT32_MIN;
precipmobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); precipmobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
fixed_t starting_floorz;
mobj->type = type; mobj->type = type;
mobj->info = info; 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 // set subsector and/or block links
P_SetPrecipitationThingPosition(mobj); P_SetPrecipitationThingPosition(mobj);
mobj->floorz = starting_floorz = P_GetSectorFloorZAt (mobj->subsector->sector, x, y); mobj->floorz = P_GetSectorFloorZAt (mobj->subsector->sector, x, y);
mobj->ceilingz = P_GetSectorCeilingZAt(mobj->subsector->sector, x, y); mobj->ceilingz = P_GetSectorCeilingZAt(mobj->subsector->sector, x, y);
mobj->floorrover = NULL; mobj->floorrover = NULL;
mobj->ceilingrover = 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->z = z;
mobj->momz = -info->speed; mobj->momz = -info->speed;
if (info->speed < 0)
{
mobj->precipflags |= PCF_FLIP;
}
start_z = mobj->floorz;
mobj->thinker.function.acp1 = (actionf_p1)P_NullPrecipThinker; mobj->thinker.function.acp1 = (actionf_p1)P_NullPrecipThinker;
P_AddThinker(THINK_PRECIP, &mobj->thinker); P_AddThinker(THINK_PRECIP, &mobj->thinker);
CalculatePrecipFloor(mobj); P_CalculatePrecipFloor(mobj);
if (mobj->floorz != starting_floorz) if (mobj->floorz != start_z)
mobj->precipflags |= PCF_FOF; {
else if (GETSECSPECIAL(mobj->subsector->sector->special, 1) == 7 ; //mobj->precipflags |= PCF_FOF;
|| GETSECSPECIAL(mobj->subsector->sector->special, 1) == 6 }
|| mobj->subsector->sector->floorpic == skyflatnum) else
mobj->precipflags |= PCF_PIT; {
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); R_ResetPrecipitationMobjInterpolationState(mobj);
@ -10588,13 +10612,19 @@ consvar_t cv_itemrespawn = CVAR_INIT ("respawnitem", "On", CV_NETVAR, CV_OnOff,
void P_SpawnPrecipitation(void) void P_SpawnPrecipitation(void)
{ {
INT32 i, j, k; 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; fixed_t basex, basey, x, y, z, height;
UINT16 numparticles = 0;
boolean condition = false;
subsector_t *precipsector = NULL; subsector_t *precipsector = NULL;
precipmobj_t *rainmo = 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; return;
// Use the blockmap to narrow down our placing patterns // Use the blockmap to narrow down our placing patterns
@ -10603,58 +10633,63 @@ void P_SpawnPrecipitation(void)
basex = bmaporgx + (i % bmapwidth) * MAPBLOCKSIZE; basex = bmaporgx + (i % bmapwidth) * MAPBLOCKSIZE;
basey = bmaporgy + (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); if (!condition)
y = basey + ((M_RandomKey(MAPBLOCKUNITS<<3)<<FRACBITS)>>3); {
continue;
}
precipsector = R_PointInSubsectorOrNull(x, y); height = precipsector->sector->ceilingheight - precipsector->sector->floorheight;
// No sector? Stop wasting time, // Exists, but is too small for reasonable precipitation.
// move on to the next entry in the blockmap if (height < 64<<FRACBITS)
if (!precipsector) continue;
continue;
// Not in a sector with visible sky? // Hack around a quirk of this entire system, where taller sectors look like they get less precipitation.
if (precipsector->sector->ceilingpic != skyflatnum) numparticles = 1 + (height / (MAPBLOCKUNITS<<4<<FRACBITS));
continue;
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. for (j = 0; j < numparticles; j++)
if (height < 64<<FRACBITS) {
continue; rainmo = P_SpawnPrecipMobj(x, y, z, type);
// Hack around a quirk of this entire system, where taller sectors look like they get less precipitation. if (randomstates > 0)
numparticles = 1 + (height / (MAPBLOCKUNITS<<4<<FRACBITS));
// Don't set z properly yet...
z = precipsector->sector->ceilingheight;
for (j = 0; j < numparticles; j++)
{ {
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(); if (mrand < (threshold * (k+1)))
UINT8 threshold = UINT8_MAX / (randomstates + 1);
statenum_t st = mobjinfo[type].spawnstate;
for (k = 0; k < randomstates; k++)
{ {
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 ?! ?! ?! // PRECIPITATION flags ?! ?! ?!
// //
typedef enum { typedef enum {
PCF_INVISIBLE = 1, // Don't draw. PCF_THUNK = 1, // Ran the thinker this tic.
PCF_PIT = 1<<1, // Above pit. PCF_SPLASH = 1<<1, // Splashed on the ground, return to the ceiling after the animation's over
PCF_FOF = 1<<2, // Above FOF. PCF_INVISIBLE = 1<<2, // Don't draw.
PCF_MOVINGFOF = 1<<3, // Above MOVING FOF (this means we need to keep floorz up to date...) PCF_PIT = 1<<3, // Above pit.
PCF_SPLASH = 1<<4, // Splashed on the ground, return to the ceiling after the animation's over PCF_FLIP = 1<<4, // Spawning from floor, moving upwards.
PCF_THUNK = 1<<5, // Ran the thinker this tic.
} precipflag_t; } precipflag_t;
// Map Object definition. // Map Object definition.

View file

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