Blizzard weather option + much more sane workflow for adding new precipitation options

"precipprops" lets you create a new precipitation type by picking a mobj type to use, how many random states it has, and flags for effects such as thunder/lightning. Seesound on the mobj type sets an ambient sound (like rain drops) and mass sets the sound's frequency in tics. This could open up the possibility for SOC/Lua Weather options later.
This commit is contained in:
TehRealSalt 2019-11-14 04:26:41 -05:00
parent 2c67c97c58
commit 80bb59031c
13 changed files with 283 additions and 360 deletions

View file

@ -5690,6 +5690,11 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_SNOW2", "S_SNOW2",
"S_SNOW3", "S_SNOW3",
// Blizzard Snowball
"S_BLIZZARDSNOW1",
"S_BLIZZARDSNOW2",
"S_BLIZZARDSNOW3",
// Water Splish // Water Splish
"S_SPLISH1", "S_SPLISH1",
"S_SPLISH2", "S_SPLISH2",
@ -7589,6 +7594,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
// Environmental Effects // Environmental Effects
"MT_RAIN", // Rain "MT_RAIN", // Rain
"MT_SNOWFLAKE", // Snowflake "MT_SNOWFLAKE", // Snowflake
"MT_BLIZZARDSNOW", // Blizzard Snowball
"MT_SPLISH", // Water splish! "MT_SPLISH", // Water splish!
"MT_SMOKE", "MT_SMOKE",
"MT_SMALLBUBBLE", // small bubble "MT_SMALLBUBBLE", // small bubble
@ -8700,10 +8706,10 @@ struct {
// Precipitation // Precipitation
{"PRECIP_NONE",PRECIP_NONE}, {"PRECIP_NONE",PRECIP_NONE},
{"PRECIP_STORM",PRECIP_STORM},
{"PRECIP_SNOW",PRECIP_SNOW},
{"PRECIP_RAIN",PRECIP_RAIN}, {"PRECIP_RAIN",PRECIP_RAIN},
{"PRECIP_BLANK",PRECIP_BLANK}, {"PRECIP_SNOW",PRECIP_SNOW},
{"PRECIP_BLIZZARD",PRECIP_BLIZZARD},
{"PRECIP_STORM",PRECIP_STORM},
{"PRECIP_STORM_NORAIN",PRECIP_STORM_NORAIN}, {"PRECIP_STORM_NORAIN",PRECIP_STORM_NORAIN},
{"PRECIP_STORM_NOSTRIKES",PRECIP_STORM_NOSTRIKES}, {"PRECIP_STORM_NOSTRIKES",PRECIP_STORM_NOSTRIKES},

View file

@ -41,18 +41,37 @@ extern UINT32 mapmusposition;
extern INT16 maptol; extern INT16 maptol;
extern UINT8 globalweather; extern UINT8 globalweather;
extern INT32 curWeather; extern UINT8 curWeather;
extern INT32 cursaveslot; extern INT32 cursaveslot;
extern INT16 lastmapsaved; extern INT16 lastmapsaved;
extern boolean gamecomplete; extern boolean gamecomplete;
#define PRECIP_NONE 0 typedef enum
#define PRECIP_STORM 1 {
#define PRECIP_SNOW 2 PRECIP_NONE = 0,
#define PRECIP_RAIN 3 PRECIP_RAIN,
#define PRECIP_BLANK 4 PRECIP_SNOW,
#define PRECIP_STORM_NORAIN 5 PRECIP_BLIZZARD,
#define PRECIP_STORM_NOSTRIKES 6 PRECIP_STORM,
PRECIP_STORM_NORAIN,
PRECIP_STORM_NOSTRIKES,
MAXPRECIP
} preciptype_t;
typedef enum
{
PRECIPFX_THUNDER = 1,
PRECIPFX_LIGHTNING = 1<<1
} precipeffect_t;
typedef struct
{
mobjtype_t type;
precipeffect_t effects;
UINT8 randomstates;
} precipprops_t;
extern precipprops_t precipprops[MAXPRECIP];
// Set if homebrew PWAD stuff has been added. // Set if homebrew PWAD stuff has been added.
extern boolean modifiedgame; extern boolean modifiedgame;

View file

@ -83,8 +83,21 @@ UINT32 mapmusposition; // Position to jump to
INT16 gamemap = 1; INT16 gamemap = 1;
INT16 maptol; INT16 maptol;
UINT8 globalweather = 0; UINT8 globalweather = 0;
INT32 curWeather = PRECIP_NONE; UINT8 curWeather = PRECIP_NONE;
precipprops_t precipprops[MAXPRECIP] =
{
{MT_NULL, 0, 0}, // PRECIP_NONE
{MT_RAIN, 0, 0}, // PRECIP_RAIN
{MT_SNOWFLAKE, 0, 2}, // PRECIP_SNOW
{MT_BLIZZARDSNOW, 0, 2}, // PRECIP_BLIZZARD
{MT_RAIN, PRECIPFX_THUNDER|PRECIPFX_LIGHTNING, 0}, // PRECIP_STORM
{MT_NULL, PRECIPFX_THUNDER|PRECIPFX_LIGHTNING, 0}, // PRECIP_STORM_NORAIN
{MT_RAIN, PRECIPFX_THUNDER, 0} // PRECIP_STORM_NOSTRIKES
};
INT32 cursaveslot = -1; // Auto-save 1p savegame slot INT32 cursaveslot = -1; // Auto-save 1p savegame slot
INT16 lastmapsaved = 0; // Last map we auto-saved at INT16 lastmapsaved = 0; // Last map we auto-saved at
boolean gamecomplete = false; boolean gamecomplete = false;

View file

@ -5882,10 +5882,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
// okay, we can't return now... this is a hack, but weather isn't networked, so it should be ok // okay, we can't return now... this is a hack, but weather isn't networked, so it should be ok
if (!(thing->precipflags & PCF_THUNK)) if (!(thing->precipflags & PCF_THUNK))
{ {
if (thing->precipflags & PCF_RAIN) P_PrecipThinker(thing);
P_RainThinker(thing);
else
P_SnowThinker(thing);
thing->precipflags |= PCF_THUNK; thing->precipflags |= PCF_THUNK;
} }

View file

@ -44,17 +44,17 @@ char sprnames[NUMSPRITES + 1][5] =
"BSZ7","BSZ8","STLG","DBAL","RCRY","ARMA","ARMF","ARMB","WIND","MAGN", "BSZ7","BSZ8","STLG","DBAL","RCRY","ARMA","ARMF","ARMB","WIND","MAGN",
"ELEM","FORC","PITY","IVSP","SSPK","GOAL","BIRD","BUNY","MOUS","CHIC", "ELEM","FORC","PITY","IVSP","SSPK","GOAL","BIRD","BUNY","MOUS","CHIC",
"COWZ","RBRD","SPVY","SPVR","SPVB","SPVG","SPDY","SPDR","SPDB","SPDG", "COWZ","RBRD","SPVY","SPVR","SPVB","SPVG","SPDY","SPDR","SPDB","SPDG",
"SPHY","SPHR","SPHB","SPHG","RAIN","SNO1","SPLH","SPLA","SMOK","BUBP", "SPHY","SPHR","SPHB","SPHG","RAIN","SNO1","SNO2","SPLH","SPLA","SMOK",
"BUBO","BUBN","BUBM","POPP","TFOG","SEED","PRTL","SCOR","DRWN","TTAG", "BUBP","BUBO","BUBN","BUBM","POPP","TFOG","SEED","PRTL","SCOR","DRWN",
"GFLG","RRNG","RNGB","RNGR","RNGI","RNGA","RNGE","RNGS","RNGG","PIKB", "TTAG","GFLG","RRNG","RNGB","RNGR","RNGI","RNGA","RNGE","RNGS","RNGG",
"PIKR","PIKA","PIKE","PIKS","PIKG","TAUT","TGRE","TSCR","COIN","CPRK", "PIKB","PIKR","PIKA","PIKE","PIKS","PIKG","TAUT","TGRE","TSCR","COIN",
"GOOM","BGOM","FFWR","FBLL","SHLL","PUMA","HAMM","KOOP","BFLM","MAXE", "CPRK","GOOM","BGOM","FFWR","FBLL","SHLL","PUMA","HAMM","KOOP","BFLM",
"MUS1","MUS2","TOAD","NDRN","SUPE","SUPZ","NDRL","NSPK","NBMP","HOOP", "MAXE","MUS1","MUS2","TOAD","NDRN","SUPE","SUPZ","NDRL","NSPK","NBMP",
"NSCR","NPRU","CAPS","SUPT","SPRK","BOM1","BOM2","BOM3","BOM4","ROIA", "HOOP","NSCR","NPRU","CAPS","SUPT","SPRK","BOM1","BOM2","BOM3","BOM4",
"ROIB","ROIC","ROID","ROIE","ROIF","ROIG","ROIH","ROII","ROIJ","ROIK", "ROIA","ROIB","ROIC","ROID","ROIE","ROIF","ROIG","ROIH","ROII","ROIJ",
"ROIL","ROIM","ROIN","ROIO","ROIP","BBAL","GWLG","GWLR","SRBA","SRBB", "ROIK","ROIL","ROIM","ROIN","ROIO","ROIP","BBAL","GWLG","GWLR","SRBA",
"SRBC","SRBD","SRBE","SRBF","SRBG","SRBH","SRBI","SRBJ","SRBK","SRBL", "SRBB","SRBC","SRBD","SRBE","SRBF","SRBG","SRBH","SRBI","SRBJ","SRBK",
"SRBM","SRBN","SRBO", "SRBL","SRBM","SRBN","SRBO",
//SRB2kart Sprites //SRB2kart Sprites
"RNDM","RPOP","SGNS","FAST","DSHR","BOST","BOSM","KFRE","KINV","KINF", "RNDM","RPOP","SGNS","FAST","DSHR","BOST","BOSM","KFRE","KINV","KINF",
"WIPD","DRIF","BDRF","DUST","RSHE","FITM","BANA","ORBN","JAWZ","SSMN", "WIPD","DRIF","BDRF","DUST","RSHE","FITM","BANA","ORBN","JAWZ","SSMN",
@ -1869,13 +1869,18 @@ state_t states[NUMSTATES] =
// Rain // Rain
{SPR_RAIN, FF_TRANS50, -1, {NULL}, 0, 0, S_NULL}, // S_RAIN1 {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_NULL, 0, -1, {NULL}, 0, 0, S_NULL}, // S_RAINRETURN
// Snowflake // Snowflake
{SPR_SNO1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW1 {SPR_SNO1, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW1
{SPR_SNO1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW2 {SPR_SNO1, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW2
{SPR_SNO1, 2, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW3 {SPR_SNO1, 2, -1, {NULL}, 0, 0, S_NULL}, // S_SNOW3
// Blizzard Snowball
{SPR_SNO2, 0, -1, {NULL}, 0, 0, S_NULL}, // S_BLIZZARDSNOW1
{SPR_SNO2, 1, -1, {NULL}, 0, 0, S_NULL}, // S_BLIZZARDSNOW2
{SPR_SNO2, 2, -1, {NULL}, 0, 0, S_NULL}, // S_BLIZZARDSNOW3
// Water Splish // Water Splish
{SPR_SPLH, FF_TRANS50 , 2, {NULL}, 0, 0, S_SPLISH2}, // S_SPLISH1 {SPR_SPLH, FF_TRANS50 , 2, {NULL}, 0, 0, S_SPLISH2}, // S_SPLISH1
{SPR_SPLH, FF_TRANS50|1, 2, {NULL}, 0, 0, S_SPLISH3}, // S_SPLISH2 {SPR_SPLH, FF_TRANS50|1, 2, {NULL}, 0, 0, S_SPLISH3}, // S_SPLISH2
@ -1890,7 +1895,7 @@ state_t states[NUMSTATES] =
// Water Splash // Water Splash
{SPR_SPLA, FF_TRANS50 , 3, {NULL}, 0, 0, S_SPLASH2}, // S_SPLASH1 {SPR_SPLA, FF_TRANS50 , 3, {NULL}, 0, 0, S_SPLASH2}, // S_SPLASH1
{SPR_SPLA, FF_TRANS70|1, 3, {NULL}, 0, 0, S_SPLASH3}, // S_SPLASH2 {SPR_SPLA, FF_TRANS70|1, 3, {NULL}, 0, 0, S_SPLASH3}, // S_SPLASH2
{SPR_SPLA, FF_TRANS90|2, 3, {NULL}, 0, 0, S_RAINRETURN}, // S_SPLASH3 {SPR_SPLA, FF_TRANS90|2, 3, {NULL}, 0, 0, S_NULL}, // S_SPLASH3
// Smoke // Smoke
{SPR_SMOK, FF_TRANS50 , 4, {NULL}, 0, 0, S_SMOKE2}, // S_SMOKE1 {SPR_SMOK, FF_TRANS50 , 4, {NULL}, 0, 0, S_SMOKE2}, // S_SMOKE1
@ -11438,22 +11443,22 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_RAIN1, // spawnstate S_RAIN1, // spawnstate
1000, // spawnhealth 1000, // spawnhealth
S_NULL, // seestate S_NULL, // seestate
sfx_None, // seesound sfx_rainin, // seesound
8, // reactiontime 0, // reactiontime
sfx_None, // attacksound sfx_None, // attacksound
S_NULL, // painstate S_NULL, // painstate
0, // painchance 0, // painchance
sfx_None, // painsound sfx_None, // painsound
S_NULL, // meleestate S_NULL, // meleestate
S_NULL, // missilestate S_NULL, // missilestate
S_NULL, // deathstate S_SPLASH1, // deathstate
S_NULL, // xdeathstate S_NULL, // xdeathstate
sfx_None, // deathsound sfx_None, // deathsound
-72*FRACUNIT, // speed -- -24*FRACUNIT originally, srb2kart x3 (nya) -72*FRACUNIT, // speed -- -24*FRACUNIT originally, srb2kart x3 (nya)
1*FRACUNIT, // radius 1*FRACUNIT, // radius
8*FRACUNIT, // height 8*FRACUNIT, // height
0, // display offset 0, // display offset
4, // mass 80, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_None, // activesound
MF_NOBLOCKMAP, // flags MF_NOBLOCKMAP, // flags
@ -11466,7 +11471,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
1000, // spawnhealth 1000, // spawnhealth
S_NULL, // seestate S_NULL, // seestate
sfx_None, // seesound sfx_None, // seesound
8, // reactiontime 0, // reactiontime
sfx_None, // attacksound sfx_None, // attacksound
S_NULL, // painstate S_NULL, // painstate
0, // painchance 0, // painchance
@ -11480,7 +11485,34 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
4*FRACUNIT, // radius 4*FRACUNIT, // radius
4*FRACUNIT, // height 4*FRACUNIT, // height
0, // display offset 0, // display offset
4, // mass 0, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP, // flags
S_NULL // raisestate
},
{ // MT_BLIZZARDSNOW
-1, // doomednum
S_BLIZZARDSNOW1, // 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_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
-24*FRACUNIT, // speed
4*FRACUNIT, // radius
4*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage 0, // damage
sfx_None, // activesound sfx_None, // activesound
MF_NOBLOCKMAP, // flags MF_NOBLOCKMAP, // flags

View file

@ -475,6 +475,7 @@ typedef enum sprite
// Environmental Effects // Environmental Effects
SPR_RAIN, // Rain SPR_RAIN, // Rain
SPR_SNO1, // Snowflake SPR_SNO1, // Snowflake
SPR_SNO2, // Blizzard Snowball
SPR_SPLH, // Water Splish SPR_SPLH, // Water Splish
SPR_SPLA, // Water Splash SPR_SPLA, // Water Splash
SPR_SMOK, SPR_SMOK,
@ -2579,6 +2580,11 @@ typedef enum state
S_SNOW2, S_SNOW2,
S_SNOW3, S_SNOW3,
// Blizzard Snowball
S_BLIZZARDSNOW1,
S_BLIZZARDSNOW2,
S_BLIZZARDSNOW3,
// Water Splish // Water Splish
S_SPLISH1, S_SPLISH1,
S_SPLISH2, S_SPLISH2,
@ -4510,6 +4516,7 @@ typedef enum mobj_type
// Environmental Effects // Environmental Effects
MT_RAIN, // Rain MT_RAIN, // Rain
MT_SNOWFLAKE, // Snowflake MT_SNOWFLAKE, // Snowflake
MT_BLIZZARDSNOW, // Blizzard Snowball
MT_SPLISH, // Water splish! MT_SPLISH, // Water splish!
MT_SMOKE, MT_SMOKE,
MT_SMALLBUBBLE, // small bubble MT_SMALLBUBBLE, // small bubble

View file

@ -1769,6 +1769,7 @@ static mobj_t *SearchMarioNode(msecnode_t *node)
case MT_SUPERSPARK: case MT_SUPERSPARK:
case MT_RAIN: case MT_RAIN:
case MT_SNOWFLAKE: case MT_SNOWFLAKE:
case MT_BLIZZARDSNOW:
case MT_SPLISH: case MT_SPLISH:
case MT_SMOKE: case MT_SMOKE:
case MT_SMALLBUBBLE: case MT_SMALLBUBBLE:

View file

@ -3928,51 +3928,60 @@ void P_NullPrecipThinker(precipmobj_t *mobj)
mobj->precipflags &= ~PCF_THUNK; mobj->precipflags &= ~PCF_THUNK;
} }
void P_SnowThinker(precipmobj_t *mobj) void P_PrecipThinker(precipmobj_t *mobj)
{ {
P_CycleStateAnimation((mobj_t *)mobj); P_CycleStateAnimation((mobj_t *)mobj);
// adjust height if (mobj->state == &states[S_RAINRETURN])
if ((mobj->z += mobj->momz) <= mobj->floorz)
mobj->z = mobj->ceilingz;
}
void P_RainThinker(precipmobj_t *mobj)
{
P_CycleStateAnimation((mobj_t *)mobj);
if (mobj->state != &states[S_RAIN1])
{ {
// cycle through states, // Reset to ceiling!
// calling action functions at transitions P_SetPrecipMobjState(mobj, mobj->info->spawnstate);
if (mobj->tics <= 0)
return;
if (--mobj->tics)
return;
if (!P_SetPrecipMobjState(mobj, mobj->state->nextstate))
return;
if (mobj->state != &states[S_RAINRETURN])
return;
mobj->z = mobj->ceilingz; mobj->z = mobj->ceilingz;
P_SetPrecipMobjState(mobj, S_RAIN1); mobj->momz = mobj->info->speed;
mobj->precipflags &= ~PCF_SPLASH;
return;
} }
if (mobj->tics != -1)
{
if (mobj->tics)
{
mobj->tics--;
}
if (mobj->tics == 0)
{
if ((mobj->precipflags & PCF_SPLASH) && (mobj->state->nextstate == S_NULL))
{
// HACK: sprite changes are 1 tic late, so you would see splashes on the ceiling if not for this state.
// We need to use the settings from the previous state, since some of those are NOT 1 tic late.
INT32 frame = (mobj->frame & ~FF_FRAMEMASK);
P_SetPrecipMobjState(mobj, S_RAINRETURN);
mobj->frame = frame;
return;
}
else
{
if (!P_SetPrecipMobjState(mobj, mobj->state->nextstate))
return;
}
}
}
if (mobj->precipflags & PCF_SPLASH)
return;
// adjust height // adjust height
if ((mobj->z += mobj->momz) <= mobj->floorz) if ((mobj->z += mobj->momz) <= mobj->floorz)
{ {
// no splashes on sky or bottomless pits if ((mobj->info->deathstate == S_NULL) || (mobj->precipflags & PCF_PIT)) // no splashes on sky or bottomless pits
if (mobj->precipflags & PCF_PIT) {
mobj->z = mobj->ceilingz; mobj->z = mobj->ceilingz;
}
else else
{ {
P_SetPrecipMobjState(mobj, mobj->info->deathstate);
mobj->z = mobj->floorz; mobj->z = mobj->floorz;
P_SetPrecipMobjState(mobj, S_SPLASH1); mobj->precipflags |= PCF_SPLASH;
} }
} }
} }
@ -6354,9 +6363,8 @@ fixed_t P_CalculateShadowFloor(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fi
} }
} }
#if 0
mobj->standingslope = slope; mobj->standingslope = slope;
#endif
#ifdef HWRENDER #ifdef HWRENDER
mobj->modeltilt = slope; mobj->modeltilt = slope;
#endif #endif
@ -10754,17 +10762,21 @@ mobj_t *P_SpawnShadowMobj(mobj_t * caster)
static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
{ {
const mobjinfo_t *info = &mobjinfo[type];
state_t *st; state_t *st;
precipmobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL); precipmobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
fixed_t starting_floorz; fixed_t starting_floorz;
mobj->type = type;
mobj->info = info;
mobj->x = x; mobj->x = x;
mobj->y = y; mobj->y = y;
mobj->flags = mobjinfo[type].flags; mobj->flags = info->flags;
// do not set the state with P_SetMobjState, // do not set the state with P_SetMobjState,
// because action routines can not be called yet // because action routines can not be called yet
st = &states[mobjinfo[type].spawnstate]; st = &states[info->spawnstate];
mobj->state = st; mobj->state = st;
mobj->tics = st->tics; mobj->tics = st->tics;
@ -10787,7 +10799,7 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
mobj->subsector->sector->ceilingheight; mobj->subsector->sector->ceilingheight;
mobj->z = z; mobj->z = z;
mobj->momz = mobjinfo[type].speed; mobj->momz = info->speed;
mobj->thinker.function.acp1 = (actionf_p1)P_NullPrecipThinker; mobj->thinker.function.acp1 = (actionf_p1)P_NullPrecipThinker;
P_AddThinker(&mobj->thinker); P_AddThinker(&mobj->thinker);
@ -10804,21 +10816,6 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
return mobj; return mobj;
} }
static inline precipmobj_t *P_SpawnRainMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
{
precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type);
mo->precipflags |= PCF_RAIN;
//mo->thinker.function.acp1 = (actionf_p1)P_RainThinker;
return mo;
}
static inline precipmobj_t *P_SpawnSnowMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
{
precipmobj_t *mo = P_SpawnPrecipMobj(x,y,z,type);
//mo->thinker.function.acp1 = (actionf_p1)P_SnowThinker;
return mo;
}
// //
// P_RemoveMobj // P_RemoveMobj
// //
@ -11007,8 +11004,8 @@ consvar_t cv_suddendeath = {"suddendeath", "Off", CV_NETVAR|CV_CHEAT|CV_NOSHOWHE
void P_SpawnPrecipitation(void) void P_SpawnPrecipitation(void)
{ {
INT32 i, mrand; INT32 i, j, k;
fixed_t basex, basey, x, y, height; fixed_t basex, basey, x, y, z, height;
subsector_t *precipsector = NULL; subsector_t *precipsector = NULL;
precipmobj_t *rainmo = NULL; precipmobj_t *rainmo = NULL;
@ -11021,8 +11018,9 @@ void P_SpawnPrecipitation(void)
basex = bmaporgx + (i % bmapwidth) * MAPBLOCKSIZE; basex = bmaporgx + (i % bmapwidth) * MAPBLOCKSIZE;
basey = bmaporgy + (i / bmapwidth) * MAPBLOCKSIZE; basey = bmaporgy + (i / bmapwidth) * MAPBLOCKSIZE;
//for (j = 0; j < cv_precipdensity.value; ++j) -- density is 1 for kart always
{ {
UINT16 numparticles = 0;
x = basex + ((M_RandomKey(MAPBLOCKUNITS<<3)<<FRACBITS)>>3); x = basex + ((M_RandomKey(MAPBLOCKUNITS<<3)<<FRACBITS)>>3);
y = basey + ((M_RandomKey(MAPBLOCKUNITS<<3)<<FRACBITS)>>3); y = basey + ((M_RandomKey(MAPBLOCKUNITS<<3)<<FRACBITS)>>3);
@ -11037,39 +11035,42 @@ void P_SpawnPrecipitation(void)
if (precipsector->sector->ceilingpic != skyflatnum) if (precipsector->sector->ceilingpic != skyflatnum)
continue; continue;
height = abs(precipsector->sector->ceilingheight - precipsector->sector->floorheight);
// Exists, but is too small for reasonable precipitation. // Exists, but is too small for reasonable precipitation.
if (!(precipsector->sector->floorheight <= precipsector->sector->ceilingheight - (32<<FRACBITS))) if (height < 64<<FRACBITS)
continue; continue;
// Don't set height yet... // Hack around a quirk of this entire system, where taller sectors look like they get less precipitation.
height = precipsector->sector->ceilingheight; numparticles = 1 + (height / (MAPBLOCKUNITS<<4<<FRACBITS));
if (curWeather == PRECIP_SNOW) // Don't set z properly yet...
z = precipsector->sector->ceilingheight;
for (j = 0; j < numparticles; j++)
{ {
rainmo = P_SpawnSnowMobj(x, y, height, MT_SNOWFLAKE); rainmo = P_SpawnPrecipMobj(x, y, z, precipprops[curWeather].type);
mrand = M_RandomByte();
if (mrand < 64) if (precipprops[curWeather].randomstates > 0)
P_SetPrecipMobjState(rainmo, S_SNOW3); {
else if (mrand < 144) UINT8 mrand = M_RandomByte();
P_SetPrecipMobjState(rainmo, S_SNOW2); UINT8 threshold = UINT8_MAX / (precipprops[curWeather].randomstates + 1);
statenum_t st = mobjinfo[precipprops[curWeather].type].spawnstate;
for (k = 0; k < precipprops[curWeather].randomstates; k++)
{
if (mrand < (threshold * (k+1)))
{
P_SetPrecipMobjState(rainmo, st+k+1);
break;
}
}
} }
else // everything else.
rainmo = P_SpawnRainMobj(x, y, height, MT_RAIN);
// Randomly assign a height, now that floorz is set. // Randomly assign a height, now that floorz is set.
rainmo->z = M_RandomRange(rainmo->floorz>>FRACBITS, rainmo->ceilingz>>FRACBITS)<<FRACBITS; rainmo->z = M_RandomRange(rainmo->floorz>>FRACBITS, rainmo->ceilingz>>FRACBITS)<<FRACBITS;
} }
} }
if (curWeather == PRECIP_BLANK)
{
curWeather = PRECIP_RAIN;
P_SwitchWeather(PRECIP_BLANK);
}
else if (curWeather == PRECIP_STORM_NORAIN)
{
curWeather = PRECIP_RAIN;
P_SwitchWeather(PRECIP_STORM_NORAIN);
} }
} }
@ -11082,47 +11083,38 @@ void P_PrecipitationEffects(void)
INT32 volume; INT32 volume;
size_t i; size_t i;
boolean sounds_rain = true; INT32 rainsfx = mobjinfo[precipprops[curWeather].type].seesound;
boolean sounds_thunder = true; INT32 rainfreq = mobjinfo[precipprops[curWeather].type].mass;
boolean effects_lightning = true;
boolean sounds_thunder = (precipprops[curWeather].effects & PRECIPFX_THUNDER);
boolean effects_lightning = (precipprops[curWeather].effects & PRECIPFX_LIGHTNING);
boolean lightningStrike = false; boolean lightningStrike = false;
// No thunder except every other tic. // No thunder except every other tic.
if (leveltime & 1); if (!(leveltime & 1))
{
if ((precipprops[globalweather].effects & PRECIPFX_THUNDER)
|| (precipprops[globalweather].effects & PRECIPFX_LIGHTNING))
{
// Before, consistency failures were possible if a level started // Before, consistency failures were possible if a level started
// with global rain and switched players to anything else ... // with global rain and switched players to anything else ...
// If the global weather has lightning strikes, // If the global weather has lightning strikes,
// EVERYONE gets them at the SAME time! // EVERYONE gets them at the SAME time!
else if (globalweather == PRECIP_STORM
|| globalweather == PRECIP_STORM_NORAIN)
thunderchance = (P_RandomKey(8192)); thunderchance = (P_RandomKey(8192));
}
else if (sounds_thunder || effects_lightning)
{
// But on the other hand, if the global weather is ANYTHING ELSE, // But on the other hand, if the global weather is ANYTHING ELSE,
// don't sync lightning strikes. // don't sync lightning strikes.
// It doesn't matter whatever curWeather is, we'll only use // While we'll only use the variable if we care about it, it's
// the variable if we care about it. // nice to save on RNG calls when we don't need it.
else
thunderchance = (M_RandomKey(8192)); thunderchance = (M_RandomKey(8192));
}
}
if (thunderchance < 70) if (thunderchance < 70)
lightningStrike = true; lightningStrike = true;
switch (curWeather)
{
case PRECIP_RAIN: // no lightning or thunder whatsoever
sounds_thunder = false;
/* FALLTHRU */
case PRECIP_STORM_NOSTRIKES: // no lightning strikes specifically
effects_lightning = false;
break;
case PRECIP_STORM_NORAIN: // no rain, lightning and thunder allowed
sounds_rain = false;
case PRECIP_STORM: // everything.
break;
default:
// Other weathers need not apply.
return;
}
// Currently thunderstorming with lightning, and we're sounding the thunder... // Currently thunderstorming with lightning, and we're sounding the thunder...
// and where there's thunder, there's gotta be lightning! // and where there's thunder, there's gotta be lightning!
if (effects_lightning && lightningStrike) if (effects_lightning && lightningStrike)
@ -11174,8 +11166,8 @@ void P_PrecipitationEffects(void)
else if (volume > 255) else if (volume > 255)
volume = 255; volume = 255;
if (sounds_rain && (!leveltime || leveltime % 80 == 1)) if (rainsfx != sfx_None && (!leveltime || leveltime % rainfreq == 1))
S_StartSoundAtVolume(players[displayplayers[0]].mo, sfx_rainin, volume); S_StartSoundAtVolume(players[displayplayers[0]].mo, rainsfx, volume);
if (!sounds_thunder) if (!sounds_thunder)
return; return;

View file

@ -253,25 +253,23 @@ typedef enum
// PRECIPITATION flags ?! ?! ?! // PRECIPITATION flags ?! ?! ?!
// //
typedef enum { typedef enum {
// Don't draw. PCF_INVISIBLE = 1, // Don't draw.
PCF_INVISIBLE = 1, PCF_PIT = 1<<1, // Above pit.
// Above pit. PCF_FOF = 1<<2, // Above FOF.
PCF_PIT = 2, PCF_MOVINGFOF = 1<<3, // Above MOVING FOF (this means we need to keep floorz up to date...)
// Above FOF. PCF_SPLASH = 1<<4, // Splashed on the ground, return to the ceiling after the animation's over
PCF_FOF = 4, PCF_THUNK = 1<<5, // Ran the thinker this tic.
// Above MOVING FOF (this means we need to keep floorz up to date...)
PCF_MOVINGFOF = 8,
// Is rain.
PCF_RAIN = 16,
// Ran the thinker this tic.
PCF_THUNK = 32,
} precipflag_t; } precipflag_t;
// Map Object definition. // Map Object definition.
typedef struct mobj_s typedef struct mobj_s
{ {
// List: thinker links. // List: thinker links.
thinker_t thinker; thinker_t thinker;
mobjtype_t type;
const mobjinfo_t *info; // &mobjinfo[mobj->type]
// Info for drawing: position. // Info for drawing: position.
fixed_t x, y, z; fixed_t x, y, z;
@ -321,9 +319,6 @@ typedef struct mobj_s
struct mobj_s *hnext; struct mobj_s *hnext;
struct mobj_s *hprev; struct mobj_s *hprev;
mobjtype_t type;
const mobjinfo_t *info; // &mobjinfo[mobj->type]
INT32 health; // for player this is rings + 1 INT32 health; // for player this is rings + 1
// Movement direction, movement generation (zig-zagging). // Movement direction, movement generation (zig-zagging).
@ -392,6 +387,9 @@ typedef struct precipmobj_s
// List: thinker links. // List: thinker links.
thinker_t thinker; thinker_t thinker;
mobjtype_t type;
const mobjinfo_t *info; // &mobjinfo[mobj->type]
// Info for drawing: position. // Info for drawing: position.
fixed_t x, y, z; fixed_t x, y, z;
@ -459,8 +457,7 @@ void P_SpawnParaloop(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 numb
boolean P_BossTargetPlayer(mobj_t *actor, boolean closest); boolean P_BossTargetPlayer(mobj_t *actor, boolean closest);
boolean P_SupermanLook4Players(mobj_t *actor); boolean P_SupermanLook4Players(mobj_t *actor);
void P_DestroyRobots(void); void P_DestroyRobots(void);
void P_SnowThinker(precipmobj_t *mobj); void P_PrecipThinker(precipmobj_t *mobj);
void P_RainThinker(precipmobj_t *mobj);
void P_NullPrecipThinker(precipmobj_t *mobj); void P_NullPrecipThinker(precipmobj_t *mobj);
void P_RemovePrecipMobj(precipmobj_t *mobj); void P_RemovePrecipMobj(precipmobj_t *mobj);
void P_SetScale(mobj_t *mobj, fixed_t newscale); void P_SetScale(mobj_t *mobj, fixed_t newscale);

View file

@ -2003,57 +2003,28 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller)
// //
// Switches the weather! // Switches the weather!
// //
void P_SwitchWeather(INT32 weathernum) void P_SwitchWeather(UINT8 newWeather)
{ {
boolean purge = false; boolean purge = false;
INT32 swap = 0; mobjtype_t swap = MT_NULL;
switch (weathernum) if (precipprops[newWeather].type == MT_NULL)
{ {
case PRECIP_NONE: // None // New type is null, we want to purge the weather.
if (curWeather == PRECIP_NONE) if (precipprops[curWeather].type == MT_NULL)
return; // Nothing to do. return; // Nothing to do.
purge = true; purge = true;
break; }
case PRECIP_STORM: // Storm else
case PRECIP_STORM_NOSTRIKES: // Storm w/ no lightning {
case PRECIP_RAIN: // Rain if (precipprops[curWeather].type != MT_NULL)
if (curWeather == PRECIP_SNOW || curWeather == PRECIP_BLANK || curWeather == PRECIP_STORM_NORAIN) {
swap = PRECIP_RAIN; // There are already existing weather particles to reuse.
break; swap = precipprops[newWeather].type;
case PRECIP_SNOW: // Snow }
if (curWeather == PRECIP_SNOW)
return; // Nothing to do.
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES || curWeather == PRECIP_BLANK || curWeather == PRECIP_STORM_NORAIN)
swap = PRECIP_SNOW; // Need to delete the other precips.
break;
case PRECIP_STORM_NORAIN: // Storm w/o rain
if (curWeather == PRECIP_SNOW
|| curWeather == PRECIP_STORM
|| curWeather == PRECIP_STORM_NOSTRIKES
|| curWeather == PRECIP_RAIN
|| curWeather == PRECIP_BLANK)
swap = PRECIP_STORM_NORAIN;
else if (curWeather == PRECIP_STORM_NORAIN)
return;
break;
case PRECIP_BLANK:
if (curWeather == PRECIP_SNOW
|| curWeather == PRECIP_STORM
|| curWeather == PRECIP_STORM_NOSTRIKES
|| curWeather == PRECIP_RAIN)
swap = PRECIP_BLANK;
else if (curWeather == PRECIP_STORM_NORAIN)
swap = PRECIP_BLANK;
else if (curWeather == PRECIP_BLANK)
return;
break;
default:
CONS_Debug(DBG_GAMELOGIC, "P_SwitchWeather: Unknown weather type %d.\n", weathernum);
break;
} }
if (purge) if (purge == true)
{ {
thinker_t *think; thinker_t *think;
precipmobj_t *precipmobj; precipmobj_t *precipmobj;
@ -2068,136 +2039,53 @@ void P_SwitchWeather(INT32 weathernum)
P_RemovePrecipMobj(precipmobj); P_RemovePrecipMobj(precipmobj);
} }
} }
else if (swap && !((swap == PRECIP_BLANK && curWeather == PRECIP_STORM_NORAIN) || (swap == PRECIP_STORM_NORAIN && curWeather == PRECIP_BLANK))) // Rather than respawn all that crap, reuse it! else if (swap != MT_NULL) // Rather than respawn all that crap, reuse it!
{ {
thinker_t *think; thinker_t *think;
precipmobj_t *precipmobj; precipmobj_t *precipmobj;
state_t *st; statenum_t st;
for (think = thinkercap.next; think != &thinkercap; think = think->next) for (think = thinkercap.next; think != &thinkercap; think = think->next)
{ {
if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker) if (think->function.acp1 != (actionf_p1)P_NullPrecipThinker)
continue; // not a precipmobj thinker continue; // not a precipmobj thinker
precipmobj = (precipmobj_t *)think; precipmobj = (precipmobj_t *)think;
if (swap == PRECIP_RAIN) // Snow To Rain precipmobj->flags = mobjinfo[swap].flags;
{
precipmobj->flags = mobjinfo[MT_RAIN].flags;
st = &states[mobjinfo[MT_RAIN].spawnstate];
precipmobj->state = st;
precipmobj->tics = st->tics;
precipmobj->sprite = st->sprite;
precipmobj->frame = st->frame;
precipmobj->momz = mobjinfo[MT_RAIN].speed;
st = mobjinfo[swap].spawnstate;
if (precipprops[curWeather].randomstates > 0)
{
UINT8 mrand = M_RandomByte();
UINT8 threshold = UINT8_MAX / (precipprops[curWeather].randomstates + 1);
UINT8 i;
for (i = 0; i < precipprops[curWeather].randomstates; i++)
{
if (mrand < (threshold * (i+1)))
{
st += i+1;
break;
}
}
}
precipmobj->state = &states[st];
precipmobj->tics = precipmobj->state->tics;
precipmobj->sprite = precipmobj->state->sprite;
precipmobj->frame = precipmobj->state->frame;
precipmobj->momz = mobjinfo[swap].speed;
precipmobj->precipflags &= ~PCF_INVISIBLE; precipmobj->precipflags &= ~PCF_INVISIBLE;
precipmobj->precipflags |= PCF_RAIN;
//think->function.acp1 = (actionf_p1)P_RainThinker;
}
else if (swap == PRECIP_SNOW) // Rain To Snow
{
INT32 z;
precipmobj->flags = mobjinfo[MT_SNOWFLAKE].flags;
z = M_RandomByte();
if (z < 64)
z = 2;
else if (z < 144)
z = 1;
else
z = 0;
st = &states[mobjinfo[MT_SNOWFLAKE].spawnstate+z];
precipmobj->state = st;
precipmobj->tics = st->tics;
precipmobj->sprite = st->sprite;
precipmobj->frame = st->frame;
precipmobj->momz = mobjinfo[MT_SNOWFLAKE].speed;
precipmobj->precipflags &= ~(PCF_INVISIBLE|PCF_RAIN);
//think->function.acp1 = (actionf_p1)P_SnowThinker;
}
else if (swap == PRECIP_BLANK || swap == PRECIP_STORM_NORAIN) // Remove precip, but keep it around for reuse.
{
//think->function.acp1 = (actionf_p1)P_NullPrecipThinker;
precipmobj->precipflags |= PCF_INVISIBLE;
}
} }
} }
switch (weathernum) curWeather = newWeather;
{
case PRECIP_SNOW: // snow
curWeather = PRECIP_SNOW;
if (!swap) if (swap == MT_NULL && precipprops[newWeather].type != MT_NULL)
P_SpawnPrecipitation(); P_SpawnPrecipitation();
break;
case PRECIP_RAIN: // rain
{
boolean dontspawn = false;
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES)
dontspawn = true;
curWeather = PRECIP_RAIN;
if (!dontspawn && !swap)
P_SpawnPrecipitation();
break;
}
case PRECIP_STORM: // storm
{
boolean dontspawn = false;
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES)
dontspawn = true;
curWeather = PRECIP_STORM;
if (!dontspawn && !swap)
P_SpawnPrecipitation();
break;
}
case PRECIP_STORM_NOSTRIKES: // storm w/o lightning
{
boolean dontspawn = false;
if (curWeather == PRECIP_RAIN || curWeather == PRECIP_STORM || curWeather == PRECIP_STORM_NOSTRIKES)
dontspawn = true;
curWeather = PRECIP_STORM_NOSTRIKES;
if (!dontspawn && !swap)
P_SpawnPrecipitation();
break;
}
case PRECIP_STORM_NORAIN: // storm w/o rain
curWeather = PRECIP_STORM_NORAIN;
if (!swap)
P_SpawnPrecipitation();
break;
case PRECIP_BLANK:
curWeather = PRECIP_BLANK;
if (!swap)
P_SpawnPrecipitation();
break;
default:
curWeather = PRECIP_NONE;
break;
}
} }
/** Gets an object. /** Gets an object.
@ -5672,23 +5560,8 @@ void P_InitSpecials(void)
CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false; CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false;
// Set curWeather // Set weather
switch (mapheaderinfo[gamemap-1]->weather) curWeather = globalweather = mapheaderinfo[gamemap-1]->weather;
{
case PRECIP_SNOW: // snow
case PRECIP_RAIN: // rain
case PRECIP_STORM: // storm
case PRECIP_STORM_NORAIN: // storm w/o rain
case PRECIP_STORM_NOSTRIKES: // storm w/o lightning
curWeather = mapheaderinfo[gamemap-1]->weather;
break;
default: // blank/none
curWeather = PRECIP_NONE;
break;
}
// Set globalweather
globalweather = mapheaderinfo[gamemap-1]->weather;
P_InitTagLists(); // Create xref tables for tags P_InitTagLists(); // Create xref tables for tags
} }

View file

@ -59,7 +59,7 @@ INT32 P_FindMinSurroundingLight(sector_t *sector, INT32 max);
void P_SetupSignExit(player_t *player); void P_SetupSignExit(player_t *player);
boolean P_IsFlagAtBase(mobjtype_t flag); boolean P_IsFlagAtBase(mobjtype_t flag);
void P_SwitchWeather(INT32 weathernum); void P_SwitchWeather(UINT8 newWeather);
boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller); boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller);
void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller); void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller);

View file

@ -58,8 +58,6 @@ void Command_Numthinkers_f(void)
CONS_Printf(M_GetText("numthinkers <#>: Count number of thinkers\n")); CONS_Printf(M_GetText("numthinkers <#>: Count number of thinkers\n"));
CONS_Printf( CONS_Printf(
"\t1: P_MobjThinker\n" "\t1: P_MobjThinker\n"
/*"\t2: P_RainThinker\n"
"\t3: P_SnowThinker\n"*/
"\t2: P_NullPrecipThinker\n" "\t2: P_NullPrecipThinker\n"
"\t3: T_Friction\n" "\t3: T_Friction\n"
"\t4: T_Pusher\n" "\t4: T_Pusher\n"
@ -75,14 +73,6 @@ void Command_Numthinkers_f(void)
action = (actionf_p1)P_MobjThinker; action = (actionf_p1)P_MobjThinker;
CONS_Printf(M_GetText("Number of %s: "), "P_MobjThinker"); CONS_Printf(M_GetText("Number of %s: "), "P_MobjThinker");
break; break;
/*case 2:
action = (actionf_p1)P_RainThinker;
CONS_Printf(M_GetText("Number of %s: "), "P_RainThinker");
break;
case 3:
action = (actionf_p1)P_SnowThinker;
CONS_Printf(M_GetText("Number of %s: "), "P_SnowThinker");
break;*/
case 2: case 2:
action = (actionf_p1)P_NullPrecipThinker; action = (actionf_p1)P_NullPrecipThinker;
CONS_Printf(M_GetText("Number of %s: "), "P_NullPrecipThinker"); CONS_Printf(M_GetText("Number of %s: "), "P_NullPrecipThinker");

View file

@ -1639,14 +1639,10 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
// okay, we can't return now except for vertical clipping... this is a hack, but weather isn't networked, so it should be ok // okay, we can't return now except for vertical clipping... this is a hack, but weather isn't networked, so it should be ok
if (!(thing->precipflags & PCF_THUNK)) if (!(thing->precipflags & PCF_THUNK))
{ {
if (thing->precipflags & PCF_RAIN) P_PrecipThinker(thing);
P_RainThinker(thing);
else
P_SnowThinker(thing);
thing->precipflags |= PCF_THUNK; thing->precipflags |= PCF_THUNK;
} }
//SoM: 3/17/2000: Disregard sprites that are out of view.. //SoM: 3/17/2000: Disregard sprites that are out of view..
gzt = thing->z + spritecachedinfo[lump].topoffset; gzt = thing->z + spritecachedinfo[lump].topoffset;
gz = gzt - spritecachedinfo[lump].height; gz = gzt - spritecachedinfo[lump].height;