diff --git a/src/gamedata/r_defs.h b/src/gamedata/r_defs.h index a1bca88a1f..16b7b41845 100644 --- a/src/gamedata/r_defs.h +++ b/src/gamedata/r_defs.h @@ -501,13 +501,16 @@ enum SECF_ENDLEVEL = 512, // ends level when health goes below 10 SECF_HAZARD = 1024, // Change to Strife's delayed damage handling. SECF_NOATTACK = 2048, // monsters cannot start attacks in this sector. + SECF_EXIT1 = 4096, + SECF_EXIT2 = 8192, + SECF_KILLMONSTERS = 16384, SECF_WASSECRET = 1 << 30, // a secret that was discovered SECF_SECRET = 1 << 31, // a secret sector SECF_DAMAGEFLAGS = SECF_ENDGODMODE|SECF_ENDLEVEL|SECF_DMGTERRAINFX|SECF_HAZARD, SECF_NOMODIFY = SECF_SECRET|SECF_WASSECRET, // not modifiable by Sector_ChangeFlags - SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH, // these flags originate from 'special and must be transferrable by floor thinkers + SECF_SPECIALFLAGS = SECF_DAMAGEFLAGS|SECF_FRICTION|SECF_PUSH|SECF_EXIT1|SECF_EXIT2|SECF_KILLMONSTERS, // these flags originate from 'special' and must be transferrable by floor thinkers }; enum @@ -592,7 +595,7 @@ struct secspecial_t { FName damagetype; // [RH] Means-of-death for applied damage int damageamount; // [RH] Damage to do while standing on floor - short special; + int special; short damageinterval; // Interval for damage application short leakydamage; // chance of leaking through radiation suit int Flags; @@ -668,8 +671,7 @@ struct sector_t FColormap Colormap; // Sector's own color/fog info. - short special; // map-defined sector special type - short lightlevel; + int special; // map-defined sector special type int sky; // MBF sky transfer info. int validcount; // if == validcount, already checked @@ -679,6 +681,7 @@ struct sector_t // the alpha mask is non-zero bool transdoor; // For transparent door hacks + short lightlevel; uint16_t MoreFlags; // [RH] Internal sector flags uint32_t Flags; // Sector flags @@ -689,9 +692,8 @@ struct sector_t int sectornum; // for comparing sector copies // GL only stuff starts here - float reflect[2]; - int subsectorcount; // list of subsectors + float reflect[2]; double transdoorheight; // for transparent door hacks subsector_t ** subsectors; FSectorPortalGroup * portals[2]; // floor and ceiling portals diff --git a/src/maploader/specials.cpp b/src/maploader/specials.cpp index 7dcb138f36..6304c41d95 100644 --- a/src/maploader/specials.cpp +++ b/src/maploader/specials.cpp @@ -449,7 +449,7 @@ void MapLoader::SpawnSkybox(AActor *origin) static void SetupSectorDamage(sector_t *sector, int damage, int interval, int leakchance, FName type, int flags) { // Only set if damage is not yet initialized. This ensures that UDMF takes precedence over sector specials. - if (sector->damageamount == 0) + if (sector->damageamount == 0 && !(sector->Flags & (SECF_EXIT1|SECF_EXIT2))) { sector->damageamount = damage; sector->damageinterval = MAX(1, interval); @@ -484,17 +484,43 @@ void MapLoader::InitSectorSpecial(sector_t *sector, int special) { sector->Flags |= SECF_PUSH; } - if ((sector->special & DAMAGE_MASK) == 0x100) + if (sector->special & KILL_MONSTERS_MASK) { - SetupSectorDamage(sector, 5, 32, 0, NAME_Fire, 0); + sector->Flags |= SECF_KILLMONSTERS; } - else if ((sector->special & DAMAGE_MASK) == 0x200) + if (!(sector->special & DEATH_MASK)) { - SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0); + if ((sector->special & DAMAGE_MASK) == 0x100) + { + SetupSectorDamage(sector, 5, 32, 0, NAME_Fire, 0); + } + else if ((sector->special & DAMAGE_MASK) == 0x200) + { + SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0); + } + else if ((sector->special & DAMAGE_MASK) == 0x300) + { + SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); + } } - else if ((sector->special & DAMAGE_MASK) == 0x300) + else { - SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0); + if ((sector->special & DAMAGE_MASK) == 0x100) + { + SetupSectorDamage(sector, TELEFRAG_DAMAGE, 0, 0, NAME_InstantDeath, 0); + } + else if ((sector->special & DAMAGE_MASK) == 0x200) + { + sector->Flags |= SECF_EXIT1; + } + else if ((sector->special & DAMAGE_MASK) == 0x300) + { + sector->Flags |= SECF_EXIT2; + } + else // 0 + { + SetupSectorDamage(sector, TELEFRAG_DAMAGE-1, 0, 0, NAME_InstantDeath, 0); + } } sector->special &= 0xff; diff --git a/src/playsim/p_lnspec.h b/src/playsim/p_lnspec.h index 044605b159..7072e31e53 100644 --- a/src/playsim/p_lnspec.h +++ b/src/playsim/p_lnspec.h @@ -180,10 +180,18 @@ typedef enum { // [RH] Equivalents for BOOM's generalized sector types -#define DAMAGE_MASK 0x0300 -#define SECRET_MASK 0x0400 -#define FRICTION_MASK 0x0800 -#define PUSH_MASK 0x1000 +enum +{ + DAMAGE_MASK = 0x0300, + SECRET_MASK = 0x0400, + FRICTION_MASK = 0x0800, + PUSH_MASK = 0x1000, + SILENCE_MASK = 0x2000, // Unimplemented Boom flag - handled differently. + SILENTMOVE_MASK = 0x4000, // Unimplemented Boom flag - handled differently. + // mbf21 + DEATH_MASK = 0x8000, + KILL_MONSTERS_MASK = 0x10000 +}; struct line_t; class AActor; diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index 018b378d67..b01abc2ff1 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -4097,12 +4097,20 @@ void AActor::Tick () } if (!CheckNoDelay()) return; // freed itself - // cycle through states, calling action functions at transitions UpdateRenderSectorList(); + if (Sector->Flags & SECF_KILLMONSTERS && Z() == floorz && + player == nullptr && (flags & MF_SHOOTABLE) && !(flags & MF_FLOAT)) + { + P_DamageMobj(this, nullptr, nullptr, TELEFRAG_DAMAGE, NAME_InstantDeath); + // must have been removed + if (ObjectFlags & OF_EuthanizeMe) return; + } + if (tics != -1) { + // cycle through states, calling action functions at transitions // [RH] Use tics <= 0 instead of == 0 so that spawnstates // of 0 tics work as expected. if (--tics <= 0) diff --git a/src/playsim/p_spec.cpp b/src/playsim/p_spec.cpp index 7940ad3c1e..147a34db1d 100644 --- a/src/playsim/p_spec.cpp +++ b/src/playsim/p_spec.cpp @@ -436,6 +436,18 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector) if (sector->damageinterval <= 0) sector->damageinterval = 32; // repair invalid damageinterval values + if (sector->Flags & (SECF_EXIT1 | SECF_EXIT2)) + { + for (int i = 0; i < MAXPLAYERS; i++) + if (playeringame[i]) + P_DamageMobj(players[i].mo, nullptr, nullptr, TELEFRAG_DAMAGE, NAME_InstantDeath); + if (sector->Flags & SECF_EXIT2) + Level->SecretExitLevel(0); + else + Level->ExitLevel(0, false); + return; + } + if (sector->damageamount > 0) { // Allow subclasses. Better would be to implement it as armor and let that reduce diff --git a/wadsrc/static/xlat/doom.txt b/wadsrc/static/xlat/doom.txt index 14ecdd7d0d..c3c037d770 100644 --- a/wadsrc/static/xlat/doom.txt +++ b/wadsrc/static/xlat/doom.txt @@ -1,8 +1,8 @@ include "xlat/base.txt" -sector bitmask 0xf000 clear; -sector bitmask 0xfe0 <<= 3; +sector bitmask 0xc000 clear; +sector bitmask 0x3fe0 <<= 3; sector 1 = dLight_Flicker; sector 2 = dLight_StrobeFast; diff --git a/wadsrc/static/zscript/mapdata.zs b/wadsrc/static/zscript/mapdata.zs index 9654ce63ac..08ecddf1f8 100644 --- a/wadsrc/static/zscript/mapdata.zs +++ b/wadsrc/static/zscript/mapdata.zs @@ -278,7 +278,7 @@ struct SecSpecial play { Name damagetype; int damageamount; - short special; + int special; short damageinterval; short leakydamage; int Flags; @@ -302,7 +302,7 @@ struct Sector native play native Actor SoundTarget; - native int16 special; + native int special; native int16 lightlevel; native int16 seqType;