mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 07:12:02 +00:00
Merge branch 'master' of https://github.com/rheit/zdoom
This commit is contained in:
commit
1b20a06ec4
35 changed files with 1206 additions and 1058 deletions
|
@ -204,10 +204,15 @@ Note: All <bool> fields default to false unless mentioned otherwise.
|
||||||
hidden = <bool>; // if true this sector will not be drawn on the textured automap.
|
hidden = <bool>; // if true this sector will not be drawn on the textured automap.
|
||||||
waterzone = <bool>; // Sector is under water and swimmable
|
waterzone = <bool>; // Sector is under water and swimmable
|
||||||
moreids = <string>; // Additional sector IDs/tags, specified as a space separated list of numbers (e.g. "2 666 1003 4505")
|
moreids = <string>; // Additional sector IDs/tags, specified as a space separated list of numbers (e.g. "2 666 1003 4505")
|
||||||
damageamount = <int>; // Amount of damage inflicted by this sector, default = 0
|
damageamount = <int>; // Amount of damage inflicted by this sector, default = 0. If this is 0, all other damage properties will be ignored.
|
||||||
|
// Setting damage through these properties will override any damage set through 'special'.
|
||||||
|
// Setting damageamount to a negative value will create a healing sector.
|
||||||
damagetype = <string>; // Damage type for sector damage, Default = "None". (generic damage)
|
damagetype = <string>; // Damage type for sector damage, Default = "None". (generic damage)
|
||||||
damageinterval = <int>; // Interval in tics between damage application, default = 32.
|
damageinterval = <int>; // Interval in tics between damage application, default = 32.
|
||||||
leakiness = <int>; // Probability of leaking through radiation suit (0 = never, 256 = always), default = 0.
|
leakiness = <int>; // Probability of leaking through radiation suit (0 = never, 256 = always), default = 0.
|
||||||
|
damageterraineffect = <bool>; // Will spawn a terrain splash when damage is inflicted. Default = false.
|
||||||
|
damagehazard = <bool>; // Changes damage model to Strife's delayed damage for the given sector. Default = false.
|
||||||
|
|
||||||
|
|
||||||
* Note about dropactors
|
* Note about dropactors
|
||||||
|
|
||||||
|
|
|
@ -2071,17 +2071,17 @@ static bool AM_CheckSecret(line_t *line)
|
||||||
{
|
{
|
||||||
if (line->frontsector != NULL)
|
if (line->frontsector != NULL)
|
||||||
{
|
{
|
||||||
if (line->frontsector->secretsector)
|
if (line->frontsector->wasSecret())
|
||||||
{
|
{
|
||||||
if (am_map_secrets!=0 && !(line->frontsector->special&SECRET_MASK)) return true;
|
if (am_map_secrets!=0 && !line->frontsector->isSecret()) return true;
|
||||||
if (am_map_secrets==2 && !(line->flags & ML_SECRET)) return true;
|
if (am_map_secrets==2 && !(line->flags & ML_SECRET)) return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (line->backsector != NULL)
|
if (line->backsector != NULL)
|
||||||
{
|
{
|
||||||
if (line->backsector->secretsector)
|
if (line->backsector->wasSecret())
|
||||||
{
|
{
|
||||||
if (am_map_secrets!=0 && !(line->backsector->special&SECRET_MASK)) return true;
|
if (am_map_secrets!=0 && !line->backsector->isSecret()) return true;
|
||||||
if (am_map_secrets==2 && !(line->flags & ML_SECRET)) return true;
|
if (am_map_secrets==2 && !(line->flags & ML_SECRET)) return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,21 +354,5 @@ void DBot::Pitch (AActor *target)
|
||||||
//Checks if a sector is dangerous.
|
//Checks if a sector is dangerous.
|
||||||
bool FCajunMaster::IsDangerous (sector_t *sec)
|
bool FCajunMaster::IsDangerous (sector_t *sec)
|
||||||
{
|
{
|
||||||
int special;
|
return sec->damageamount > 0;
|
||||||
|
|
||||||
return
|
|
||||||
sec->damageamount
|
|
||||||
|| sec->special & DAMAGE_MASK
|
|
||||||
|| (special = sec->special & 0xff, special == dLight_Strobe_Hurt)
|
|
||||||
|| special == dDamage_Hellslime
|
|
||||||
|| special == dDamage_Nukage
|
|
||||||
|| special == dDamage_End
|
|
||||||
|| special == dDamage_SuperHellslime
|
|
||||||
|| special == dDamage_LavaWimpy
|
|
||||||
|| special == dDamage_LavaHefty
|
|
||||||
|| special == dScroll_EastLavaDamage
|
|
||||||
|| special == hDamage_Sludge
|
|
||||||
|| special == sLight_Strobe_Hurt
|
|
||||||
|| special == Damage_InstantDeath
|
|
||||||
|| special == sDamage_SuperHellslime;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1106,11 +1106,8 @@ static void PrintSecretString(const char *string, bool thislevel)
|
||||||
if (*string == ';') string++;
|
if (*string == ';') string++;
|
||||||
if (thislevel && secnum >= 0 && secnum < numsectors)
|
if (thislevel && secnum >= 0 && secnum < numsectors)
|
||||||
{
|
{
|
||||||
if (sectors[secnum].secretsector)
|
if (sectors[secnum].isSecret()) colstr = TEXTCOLOR_RED;
|
||||||
{
|
else if (sectors[secnum].wasSecret()) colstr = TEXTCOLOR_GREEN;
|
||||||
if ((sectors[secnum].special & SECRET_MASK)) colstr = TEXTCOLOR_RED;
|
|
||||||
else colstr = TEXTCOLOR_GREEN;
|
|
||||||
}
|
|
||||||
else colstr = TEXTCOLOR_ORANGE;
|
else colstr = TEXTCOLOR_ORANGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -422,6 +422,8 @@ public:
|
||||||
int killcount, itemcount, secretcount; // for intermission
|
int killcount, itemcount, secretcount; // for intermission
|
||||||
int damagecount, bonuscount;// for screen flashing
|
int damagecount, bonuscount;// for screen flashing
|
||||||
int hazardcount; // for delayed Strife damage
|
int hazardcount; // for delayed Strife damage
|
||||||
|
int hazardinterval; // Frequency of damage infliction
|
||||||
|
FName hazardtype; // Damage type of last hazardous damage encounter.
|
||||||
int poisoncount; // screen flash for poison damage
|
int poisoncount; // screen flash for poison damage
|
||||||
FName poisontype; // type of poison damage to apply
|
FName poisontype; // type of poison damage to apply
|
||||||
FName poisonpaintype; // type of Pain state to enter for poison damage
|
FName poisonpaintype; // type of Pain state to enter for poison damage
|
||||||
|
|
|
@ -4323,44 +4323,12 @@ void FParser::SF_KillInSector()
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// new for GZDoom: Sets a sector's type
|
// new for GZDoom: Sets a sector's type
|
||||||
// (Sure, this is not particularly useful. But having it made it possible
|
|
||||||
// to fix a few annoying bugs in some old maps ;) )
|
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
void FParser::SF_SectorType(void)
|
void FParser::SF_SectorType(void)
|
||||||
{
|
{
|
||||||
int tagnum, secnum;
|
// I don't think this was ever used publicly so I'm not going to bother fixing it.
|
||||||
sector_t *sector;
|
|
||||||
|
|
||||||
if (CheckArgs(1))
|
|
||||||
{
|
|
||||||
tagnum = intvalue(t_argv[0]);
|
|
||||||
|
|
||||||
// argv is sector tag
|
|
||||||
secnum = T_FindFirstSectorFromTag(tagnum);
|
|
||||||
|
|
||||||
if(secnum < 0)
|
|
||||||
{ script_error("sector not found with tagnum %i\n", tagnum); return;}
|
|
||||||
|
|
||||||
sector = §ors[secnum];
|
|
||||||
|
|
||||||
if(t_argc > 1)
|
|
||||||
{
|
|
||||||
int i = -1;
|
|
||||||
int spec = intvalue(t_argv[1]);
|
|
||||||
|
|
||||||
// set all sectors with tag
|
|
||||||
FSSectorTagIterator itr(tagnum);
|
|
||||||
while ((i = itr.Next()) >= 0)
|
|
||||||
{
|
|
||||||
sectors[i].special = spec;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
t_return.type = svt_int;
|
|
||||||
t_return.value.i = sector->special;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -87,7 +87,6 @@ DEFINE_MAP_OPTION(fs_nocheckposition, false)
|
||||||
{
|
{
|
||||||
FFsOptions *opt = info->GetOptData<FFsOptions>("fragglescript");
|
FFsOptions *opt = info->GetOptData<FFsOptions>("fragglescript");
|
||||||
|
|
||||||
parse.ParseAssign();
|
|
||||||
if (parse.CheckAssign())
|
if (parse.CheckAssign())
|
||||||
{
|
{
|
||||||
parse.sc.MustGetNumber();
|
parse.sc.MustGetNumber();
|
||||||
|
|
|
@ -139,7 +139,7 @@ void DLightningThinker::LightningFlash ()
|
||||||
for (i = numsectors, j = 0; i > 0; --i, ++j, ++tempSec)
|
for (i = numsectors, j = 0; i > 0; --i, ++j, ++tempSec)
|
||||||
{
|
{
|
||||||
// allow combination of the lightning sector specials with bit masks
|
// allow combination of the lightning sector specials with bit masks
|
||||||
int special = tempSec->special & 0xff;
|
int special = tempSec->special;
|
||||||
if (tempSec->GetTexture(sector_t::ceiling) == skyflatnum
|
if (tempSec->GetTexture(sector_t::ceiling) == skyflatnum
|
||||||
|| special == Light_IndoorLightning1
|
|| special == Light_IndoorLightning1
|
||||||
|| special == Light_IndoorLightning2
|
|| special == Light_IndoorLightning2
|
||||||
|
|
|
@ -630,11 +630,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain)
|
||||||
|
|
||||||
if (self->z == sec->floorplane.ZatPoint (self->x, self->y))
|
if (self->z == sec->floorplane.ZatPoint (self->x, self->y))
|
||||||
{
|
{
|
||||||
if ((sec->special & 0xFF) == Damage_InstantDeath)
|
if (sec->special == Damage_InstantDeath)
|
||||||
{
|
{
|
||||||
P_DamageMobj (self, NULL, NULL, 999, NAME_None);
|
P_DamageMobj (self, NULL, NULL, 999, NAME_InstantDeath);
|
||||||
}
|
}
|
||||||
else if ((sec->special & 0xFF) == Scroll_StrifeCurrent)
|
else if (sec->special == Scroll_StrifeCurrent)
|
||||||
{
|
{
|
||||||
int anglespeed = tagManager.GetFirstSectorTag(sec) - 100;
|
int anglespeed = tagManager.GetFirstSectorTag(sec) - 100;
|
||||||
fixed_t speed = (anglespeed % 10) << (FRACBITS - 4);
|
fixed_t speed = (anglespeed % 10) << (FRACBITS - 4);
|
||||||
|
|
|
@ -329,6 +329,7 @@ void DIntermissionScreenText::Drawer ()
|
||||||
int c;
|
int c;
|
||||||
const FRemapTable *range;
|
const FRemapTable *range;
|
||||||
const char *ch = mText;
|
const char *ch = mText;
|
||||||
|
const int kerning = SmallFont->GetDefaultKerning();
|
||||||
|
|
||||||
// Count number of rows in this text. Since it does not word-wrap, we just count
|
// Count number of rows in this text. Since it does not word-wrap, we just count
|
||||||
// line feed characters.
|
// line feed characters.
|
||||||
|
@ -380,6 +381,7 @@ void DIntermissionScreenText::Drawer ()
|
||||||
}
|
}
|
||||||
|
|
||||||
pic = SmallFont->GetChar (c, &w);
|
pic = SmallFont->GetChar (c, &w);
|
||||||
|
w += kerning;
|
||||||
w *= CleanXfac;
|
w *= CleanXfac;
|
||||||
if (cx + w > SCREENWIDTH)
|
if (cx + w > SCREENWIDTH)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -510,6 +510,8 @@ xx(damageamount)
|
||||||
xx(damagetype)
|
xx(damagetype)
|
||||||
xx(damageinterval)
|
xx(damageinterval)
|
||||||
xx(leakiness)
|
xx(leakiness)
|
||||||
|
xx(damageterraineffect)
|
||||||
|
xx(damagehazard)
|
||||||
|
|
||||||
// USDF keywords
|
// USDF keywords
|
||||||
xx(Amount)
|
xx(Amount)
|
||||||
|
|
|
@ -345,8 +345,7 @@ void P_PlayerOnSpecial3DFloor(player_t* player)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply sector specials
|
// Apply sector specials
|
||||||
if (rover->model->special || rover->model->damageamount)
|
P_PlayerInSpecialSector(player, rover->model);
|
||||||
P_PlayerInSpecialSector(player, rover->model);
|
|
||||||
|
|
||||||
// Apply flat specials (using the ceiling!)
|
// Apply flat specials (using the ceiling!)
|
||||||
P_PlayerOnSpecialFlat(
|
P_PlayerOnSpecialFlat(
|
||||||
|
|
|
@ -90,6 +90,7 @@ void DCeiling::Serialize (FArchive &arc)
|
||||||
|
|
||||||
void DCeiling::PlayCeilingSound ()
|
void DCeiling::PlayCeilingSound ()
|
||||||
{
|
{
|
||||||
|
if (m_Sector->Flags & SECF_SILENTMOVE) return;
|
||||||
if (m_Sector->seqType >= 0)
|
if (m_Sector->seqType >= 0)
|
||||||
{
|
{
|
||||||
SN_StartSequence (m_Sector, CHAN_CEILING, m_Sector->seqType, SEQ_PLATFORM, 0, false);
|
SN_StartSequence (m_Sector, CHAN_CEILING, m_Sector->seqType, SEQ_PLATFORM, 0, false);
|
||||||
|
@ -142,7 +143,7 @@ void DCeiling::Tick ()
|
||||||
// movers with texture change, change the texture then get removed
|
// movers with texture change, change the texture then get removed
|
||||||
case genCeilingChgT:
|
case genCeilingChgT:
|
||||||
case genCeilingChg0:
|
case genCeilingChg0:
|
||||||
m_Sector->special = m_NewSpecial;
|
m_Sector->SetSpecial(&m_NewSpecial);
|
||||||
// fall through
|
// fall through
|
||||||
case genCeilingChg:
|
case genCeilingChg:
|
||||||
m_Sector->SetTexture(sector_t::ceiling, m_Texture);
|
m_Sector->SetTexture(sector_t::ceiling, m_Texture);
|
||||||
|
@ -175,7 +176,7 @@ void DCeiling::Tick ()
|
||||||
// then remove the active ceiling
|
// then remove the active ceiling
|
||||||
case genCeilingChgT:
|
case genCeilingChgT:
|
||||||
case genCeilingChg0:
|
case genCeilingChg0:
|
||||||
m_Sector->special = m_NewSpecial;
|
m_Sector->SetSpecial(&m_NewSpecial);
|
||||||
// fall through
|
// fall through
|
||||||
case genCeilingChg:
|
case genCeilingChg:
|
||||||
m_Sector->SetTexture(sector_t::ceiling, m_Texture);
|
m_Sector->SetTexture(sector_t::ceiling, m_Texture);
|
||||||
|
@ -435,11 +436,11 @@ DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line,
|
||||||
switch (change & 3)
|
switch (change & 3)
|
||||||
{
|
{
|
||||||
case 1: // type is zeroed
|
case 1: // type is zeroed
|
||||||
ceiling->m_NewSpecial = 0;
|
ceiling->m_NewSpecial.Clear();
|
||||||
ceiling->m_Type = genCeilingChg0;
|
ceiling->m_Type = genCeilingChg0;
|
||||||
break;
|
break;
|
||||||
case 2: // type is copied
|
case 2: // type is copied
|
||||||
ceiling->m_NewSpecial = sec->special;
|
sec->GetSpecial(&ceiling->m_NewSpecial);
|
||||||
ceiling->m_Type = genCeilingChgT;
|
ceiling->m_Type = genCeilingChgT;
|
||||||
break;
|
break;
|
||||||
case 3: // type is left alone
|
case 3: // type is left alone
|
||||||
|
@ -454,11 +455,11 @@ DCeiling *DCeiling::Create(sector_t *sec, DCeiling::ECeiling type, line_t *line,
|
||||||
switch (change & 3)
|
switch (change & 3)
|
||||||
{
|
{
|
||||||
case 1: // type is zeroed
|
case 1: // type is zeroed
|
||||||
ceiling->m_NewSpecial = 0;
|
ceiling->m_NewSpecial.Clear();
|
||||||
ceiling->m_Type = genCeilingChg0;
|
ceiling->m_Type = genCeilingChg0;
|
||||||
break;
|
break;
|
||||||
case 2: // type is copied
|
case 2: // type is copied
|
||||||
ceiling->m_NewSpecial = line->frontsector->special;
|
line->frontsector->GetSpecial(&ceiling->m_NewSpecial);
|
||||||
ceiling->m_Type = genCeilingChgT;
|
ceiling->m_Type = genCeilingChgT;
|
||||||
break;
|
break;
|
||||||
case 3: // type is left alone
|
case 3: // type is left alone
|
||||||
|
|
|
@ -250,6 +250,8 @@ void DDoor::DoorSound(bool raise, DSeqNode *curseq) const
|
||||||
|
|
||||||
choice = !raise;
|
choice = !raise;
|
||||||
|
|
||||||
|
if (m_Sector->Flags & SECF_SILENTMOVE) return;
|
||||||
|
|
||||||
if (m_Speed >= FRACUNIT*8)
|
if (m_Speed >= FRACUNIT*8)
|
||||||
{
|
{
|
||||||
choice += 2;
|
choice += 2;
|
||||||
|
@ -511,8 +513,6 @@ void P_SpawnDoorCloseIn30 (sector_t *sec)
|
||||||
fixed_t height;
|
fixed_t height;
|
||||||
DDoor *door = new DDoor (sec);
|
DDoor *door = new DDoor (sec);
|
||||||
|
|
||||||
sec->special = 0;
|
|
||||||
|
|
||||||
door->m_Sector = sec;
|
door->m_Sector = sec;
|
||||||
door->m_Direction = 0;
|
door->m_Direction = 0;
|
||||||
door->m_Type = DDoor::doorRaise;
|
door->m_Type = DDoor::doorRaise;
|
||||||
|
@ -533,7 +533,6 @@ void P_SpawnDoorCloseIn30 (sector_t *sec)
|
||||||
|
|
||||||
void P_SpawnDoorRaiseIn5Mins (sector_t *sec)
|
void P_SpawnDoorRaiseIn5Mins (sector_t *sec)
|
||||||
{
|
{
|
||||||
sec->special = 0;
|
|
||||||
new DDoor (sec, DDoor::doorRaiseIn5Mins, 2*FRACUNIT, TICRATE*30/7, 0);
|
new DDoor (sec, DDoor::doorRaiseIn5Mins, 2*FRACUNIT, TICRATE*30/7, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,8 @@ inline FArchive &operator<< (FArchive &arc, DFloor::EFloor &type)
|
||||||
|
|
||||||
static void StartFloorSound (sector_t *sec)
|
static void StartFloorSound (sector_t *sec)
|
||||||
{
|
{
|
||||||
|
if (sec->Flags & SECF_SILENTMOVE) return;
|
||||||
|
|
||||||
if (sec->seqType >= 0)
|
if (sec->seqType >= 0)
|
||||||
{
|
{
|
||||||
SN_StartSequence (sec, CHAN_FLOOR, sec->seqType, SEQ_PLATFORM, 0);
|
SN_StartSequence (sec, CHAN_FLOOR, sec->seqType, SEQ_PLATFORM, 0);
|
||||||
|
@ -159,7 +161,7 @@ void DFloor::Tick ()
|
||||||
case donutRaise:
|
case donutRaise:
|
||||||
case genFloorChgT:
|
case genFloorChgT:
|
||||||
case genFloorChg0:
|
case genFloorChg0:
|
||||||
m_Sector->special = (m_Sector->special & SECRET_MASK) | m_NewSpecial;
|
m_Sector->SetSpecial(&m_NewSpecial);
|
||||||
//fall thru
|
//fall thru
|
||||||
case genFloorChg:
|
case genFloorChg:
|
||||||
m_Sector->SetTexture(sector_t::floor, m_Texture);
|
m_Sector->SetTexture(sector_t::floor, m_Texture);
|
||||||
|
@ -175,7 +177,7 @@ void DFloor::Tick ()
|
||||||
case floorLowerAndChange:
|
case floorLowerAndChange:
|
||||||
case genFloorChgT:
|
case genFloorChgT:
|
||||||
case genFloorChg0:
|
case genFloorChg0:
|
||||||
m_Sector->special = (m_Sector->special & SECRET_MASK) | m_NewSpecial;
|
m_Sector->SetSpecial(&m_NewSpecial);
|
||||||
//fall thru
|
//fall thru
|
||||||
case genFloorChg:
|
case genFloorChg:
|
||||||
m_Sector->SetTexture(sector_t::floor, m_Texture);
|
m_Sector->SetTexture(sector_t::floor, m_Texture);
|
||||||
|
@ -233,14 +235,14 @@ void DFloor::SetFloorChangeType (sector_t *sec, int change)
|
||||||
switch (change & 3)
|
switch (change & 3)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
m_NewSpecial = 0;
|
m_NewSpecial.Clear();
|
||||||
m_Type = DFloor::genFloorChg0;
|
m_Type = DFloor::genFloorChg0;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
m_Type = DFloor::genFloorChg;
|
m_Type = DFloor::genFloorChg;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
m_NewSpecial = sec->special & ~SECRET_MASK;
|
sec->GetSpecial(&m_NewSpecial);
|
||||||
m_Type = DFloor::genFloorChgT;
|
m_Type = DFloor::genFloorChgT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -438,11 +440,11 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag,
|
||||||
{
|
{
|
||||||
FTextureID oldpic = sec->GetTexture(sector_t::floor);
|
FTextureID oldpic = sec->GetTexture(sector_t::floor);
|
||||||
sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor));
|
sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor));
|
||||||
sec->special = (sec->special & SECRET_MASK) | (line->frontsector->special & ~SECRET_MASK);
|
sec->TransferSpecial(line->frontsector);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sec->special &= SECRET_MASK;
|
sec->ClearSpecial();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -453,8 +455,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag,
|
||||||
floor->m_Texture = sec->GetTexture(sector_t::floor);
|
floor->m_Texture = sec->GetTexture(sector_t::floor);
|
||||||
// jff 1/24/98 make sure floor->m_NewSpecial gets initialized
|
// jff 1/24/98 make sure floor->m_NewSpecial gets initialized
|
||||||
// in case no surrounding sector is at floordestheight
|
// in case no surrounding sector is at floordestheight
|
||||||
// --> should not affect compatibility <--
|
sec->GetSpecial(&floor->m_NewSpecial);
|
||||||
floor->m_NewSpecial = sec->special & ~SECRET_MASK;
|
|
||||||
|
|
||||||
//jff 5/23/98 use model subroutine to unify fixes and handling
|
//jff 5/23/98 use model subroutine to unify fixes and handling
|
||||||
sector_t *modelsec;
|
sector_t *modelsec;
|
||||||
|
@ -462,7 +463,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag,
|
||||||
if (modelsec != NULL)
|
if (modelsec != NULL)
|
||||||
{
|
{
|
||||||
floor->m_Texture = modelsec->GetTexture(sector_t::floor);
|
floor->m_Texture = modelsec->GetTexture(sector_t::floor);
|
||||||
floor->m_NewSpecial = modelsec->special & ~SECRET_MASK;
|
modelsec->GetSpecial(&floor->m_NewSpecial);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -635,7 +636,7 @@ bool EV_BuildStairs (int tag, DFloor::EStair type, line_t *line,
|
||||||
{
|
{
|
||||||
// [RH] Find the next sector by scanning for Stairs_Special?
|
// [RH] Find the next sector by scanning for Stairs_Special?
|
||||||
tsec = sec->NextSpecialSector (
|
tsec = sec->NextSpecialSector (
|
||||||
(sec->special & 0xff) == Stairs_Special1 ?
|
sec->special == Stairs_Special1 ?
|
||||||
Stairs_Special2 : Stairs_Special1, prev);
|
Stairs_Special2 : Stairs_Special1, prev);
|
||||||
|
|
||||||
if ( (ok = (tsec != NULL)) )
|
if ( (ok = (tsec != NULL)) )
|
||||||
|
@ -792,7 +793,7 @@ bool EV_DoDonut (int tag, line_t *line, fixed_t pillarspeed, fixed_t slimespeed)
|
||||||
floor->m_Sector = s2;
|
floor->m_Sector = s2;
|
||||||
floor->m_Speed = slimespeed;
|
floor->m_Speed = slimespeed;
|
||||||
floor->m_Texture = s3->GetTexture(sector_t::floor);
|
floor->m_Texture = s3->GetTexture(sector_t::floor);
|
||||||
floor->m_NewSpecial = 0;
|
floor->m_NewSpecial.Clear();
|
||||||
height = s3->FindHighestFloorPoint (&spot);
|
height = s3->FindHighestFloorPoint (&spot);
|
||||||
floor->m_FloorDestDist = s2->floorplane.PointToDist (spot, height);
|
floor->m_FloorDestDist = s2->floorplane.PointToDist (spot, height);
|
||||||
floor->StartFloorSound ();
|
floor->StartFloorSound ();
|
||||||
|
@ -1091,7 +1092,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag)
|
||||||
if (line)
|
if (line)
|
||||||
{ // [RH] if no line, no change
|
{ // [RH] if no line, no change
|
||||||
sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor));
|
sec->SetTexture(sector_t::floor, line->frontsector->GetTexture(sector_t::floor));
|
||||||
sec->special = (sec->special & SECRET_MASK) | (line->frontsector->special & ~SECRET_MASK);
|
sec->TransferSpecial(line->frontsector);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case numChangeOnly:
|
case numChangeOnly:
|
||||||
|
@ -1099,7 +1100,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag)
|
||||||
if (secm)
|
if (secm)
|
||||||
{ // if no model, no change
|
{ // if no model, no change
|
||||||
sec->SetTexture(sector_t::floor, secm->GetTexture(sector_t::floor));
|
sec->SetTexture(sector_t::floor, secm->GetTexture(sector_t::floor));
|
||||||
sec->special = secm->special;
|
sec->TransferSpecial(secm);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1255,8 +1255,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage,
|
||||||
}
|
}
|
||||||
|
|
||||||
// end of game hell hack
|
// end of game hell hack
|
||||||
if ((target->Sector->special & 255) == dDamage_End
|
if ((target->Sector->Flags & SECF_ENDLEVEL) && damage >= target->health)
|
||||||
&& damage >= target->health)
|
|
||||||
{
|
{
|
||||||
damage = target->health - 1;
|
damage = target->health - 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -786,12 +786,12 @@ int DPhased::PhaseHelper (sector_t *sector, int index, int light, sector_t *prev
|
||||||
l = new DPhased (sector, baselevel);
|
l = new DPhased (sector, baselevel);
|
||||||
|
|
||||||
int numsteps = PhaseHelper (sector->NextSpecialSector (
|
int numsteps = PhaseHelper (sector->NextSpecialSector (
|
||||||
(sector->special & 0x00ff) == LightSequenceSpecial1 ?
|
sector->special == LightSequenceSpecial1 ?
|
||||||
LightSequenceSpecial2 : LightSequenceSpecial1, prev),
|
LightSequenceSpecial2 : LightSequenceSpecial1, prev),
|
||||||
index + 1, l->m_BaseLevel, sector);
|
index + 1, l->m_BaseLevel, sector);
|
||||||
l->m_Phase = ((numsteps - index - 1) * 64) / numsteps;
|
l->m_Phase = ((numsteps - index - 1) * 64) / numsteps;
|
||||||
|
|
||||||
sector->special &= 0xff00;
|
sector->special = 0;
|
||||||
|
|
||||||
return numsteps;
|
return numsteps;
|
||||||
}
|
}
|
||||||
|
@ -820,7 +820,6 @@ DPhased::DPhased (sector_t *sector, int baselevel, int phase)
|
||||||
{
|
{
|
||||||
m_BaseLevel = baselevel;
|
m_BaseLevel = baselevel;
|
||||||
m_Phase = phase;
|
m_Phase = phase;
|
||||||
sector->special &= 0xff00;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
|
@ -1945,6 +1945,9 @@ FUNC(LS_Sector_ChangeFlags)
|
||||||
|
|
||||||
rtn = false;
|
rtn = false;
|
||||||
FSectorTagIterator itr(arg0);
|
FSectorTagIterator itr(arg0);
|
||||||
|
// exclude protected flags
|
||||||
|
arg1 &= ~SECF_NOMODIFY;
|
||||||
|
arg2 &= ~SECF_NOMODIFY;
|
||||||
while ((secNum = itr.Next()) >= 0)
|
while ((secNum = itr.Next()) >= 0)
|
||||||
{
|
{
|
||||||
sectors[secNum].Flags = (sectors[secNum].Flags | arg1) & ~arg2;
|
sectors[secNum].Flags = (sectors[secNum].Flags | arg1) & ~arg2;
|
||||||
|
|
1288
src/p_local.h
1288
src/p_local.h
File diff suppressed because it is too large
Load diff
|
@ -630,7 +630,7 @@ int P_GetFriction(const AActor *mo, int *frictionfactor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(sec->special & FRICTION_MASK) &&
|
if (!(sec->Flags & SECF_FRICTION) &&
|
||||||
Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].Friction == 0)
|
Terrains[TerrainTypes[sec->GetTexture(sector_t::floor)]].Friction == 0)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -3452,7 +3452,7 @@ void AActor::Tick ()
|
||||||
|
|
||||||
if (player != NULL)
|
if (player != NULL)
|
||||||
{
|
{
|
||||||
int scrolltype = sec->special & 0xff;
|
int scrolltype = sec->special;
|
||||||
|
|
||||||
if (scrolltype >= Scroll_North_Slow &&
|
if (scrolltype >= Scroll_North_Slow &&
|
||||||
scrolltype <= Scroll_SouthWest_Fast)
|
scrolltype <= Scroll_SouthWest_Fast)
|
||||||
|
@ -4424,7 +4424,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
|
||||||
( gameaction != ga_worlddone ) &&
|
( gameaction != ga_worlddone ) &&
|
||||||
( p->mo != NULL ) &&
|
( p->mo != NULL ) &&
|
||||||
( !(p->mo->Sector->Flags & SECF_NORESPAWN) ) &&
|
( !(p->mo->Sector->Flags & SECF_NORESPAWN) ) &&
|
||||||
( (p->mo->Sector->special & 255) != Damage_InstantDeath ))
|
( p->mo->Sector->damageamount < TELEFRAG_DAMAGE )) // this really should be a bit smarter...
|
||||||
{
|
{
|
||||||
spawn_x = p->mo->x;
|
spawn_x = p->mo->x;
|
||||||
spawn_y = p->mo->y;
|
spawn_y = p->mo->y;
|
||||||
|
@ -5320,7 +5320,7 @@ int P_GetThingFloorType (AActor *thing)
|
||||||
// Returns true if hit liquid and splashed, false if not.
|
// Returns true if hit liquid and splashed, false if not.
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool checkabove, bool alert)
|
bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z, bool checkabove, bool alert, bool force)
|
||||||
{
|
{
|
||||||
if (thing->flags3 & MF3_DONTSPLASH)
|
if (thing->flags3 & MF3_DONTSPLASH)
|
||||||
return false;
|
return false;
|
||||||
|
@ -5362,24 +5362,27 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for(unsigned int i=0;i<sec->e->XFloor.ffloors.Size();i++)
|
if (!force)
|
||||||
{
|
{
|
||||||
F3DFloor * rover = sec->e->XFloor.ffloors[i];
|
for (unsigned int i = 0; i<sec->e->XFloor.ffloors.Size(); i++)
|
||||||
if (!(rover->flags & FF_EXISTS)) continue;
|
|
||||||
fixed_t planez = rover->top.plane->ZatPoint(x, y);
|
|
||||||
if (z > planez - FRACUNIT/2 && z < planez + FRACUNIT/2) // allow minor imprecisions
|
|
||||||
{
|
{
|
||||||
if (rover->flags & (FF_SOLID|FF_SWIMMABLE) )
|
F3DFloor * rover = sec->e->XFloor.ffloors[i];
|
||||||
|
if (!(rover->flags & FF_EXISTS)) continue;
|
||||||
|
fixed_t planez = rover->top.plane->ZatPoint(x, y);
|
||||||
|
if (z > planez - FRACUNIT / 2 && z < planez + FRACUNIT / 2) // allow minor imprecisions
|
||||||
{
|
{
|
||||||
terrainnum = TerrainTypes[*rover->top.texture];
|
if (rover->flags & (FF_SOLID | FF_SWIMMABLE))
|
||||||
goto foundone;
|
{
|
||||||
|
terrainnum = TerrainTypes[*rover->top.texture];
|
||||||
|
goto foundone;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
planez = rover->bottom.plane->ZatPoint(x, y);
|
||||||
|
if (planez < z && !(planez < thing->floorz)) return false;
|
||||||
}
|
}
|
||||||
planez = rover->bottom.plane->ZatPoint(x, y);
|
|
||||||
if (planez < z && !(planez < thing->floorz)) return false;
|
|
||||||
}
|
}
|
||||||
hsec = sec->GetHeightSec();
|
hsec = sec->GetHeightSec();
|
||||||
if (hsec == NULL || !(hsec->MoreFlags & SECF_CLIPFAKEPLANES))
|
if (force || hsec == NULL || !(hsec->MoreFlags & SECF_CLIPFAKEPLANES))
|
||||||
{
|
{
|
||||||
terrainnum = TerrainTypes[sec->GetTexture(sector_t::floor)];
|
terrainnum = TerrainTypes[sec->GetTexture(sector_t::floor)];
|
||||||
}
|
}
|
||||||
|
@ -5403,7 +5406,7 @@ foundone:
|
||||||
|
|
||||||
// Don't splash for living things with small vertical velocities.
|
// Don't splash for living things with small vertical velocities.
|
||||||
// There are levels where the constant splashing from the monsters gets extremely annoying
|
// There are levels where the constant splashing from the monsters gets extremely annoying
|
||||||
if ((thing->flags3&MF3_ISMONSTER || thing->player) && thing->velz >= -6*FRACUNIT)
|
if (((thing->flags3&MF3_ISMONSTER || thing->player) && thing->velz >= -6*FRACUNIT) && !force)
|
||||||
return Terrains[terrainnum].IsLiquid;
|
return Terrains[terrainnum].IsLiquid;
|
||||||
|
|
||||||
splash = &Splashes[splashnum];
|
splash = &Splashes[splashnum];
|
||||||
|
|
|
@ -198,17 +198,20 @@ DPillar::DPillar (sector_t *sector, EPillar type, fixed_t speed,
|
||||||
m_FloorSpeed = Scale (speed, floordist, ceilingdist);
|
m_FloorSpeed = Scale (speed, floordist, ceilingdist);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sector->seqType >= 0)
|
if (!(m_Sector->Flags & SECF_SILENTMOVE))
|
||||||
{
|
{
|
||||||
SN_StartSequence (sector, CHAN_FLOOR, sector->seqType, SEQ_PLATFORM, 0);
|
if (sector->seqType >= 0)
|
||||||
}
|
{
|
||||||
else if (sector->SeqName != NAME_None)
|
SN_StartSequence(sector, CHAN_FLOOR, sector->seqType, SEQ_PLATFORM, 0);
|
||||||
{
|
}
|
||||||
SN_StartSequence (sector, CHAN_FLOOR, sector->SeqName, 0);
|
else if (sector->SeqName != NAME_None)
|
||||||
}
|
{
|
||||||
else
|
SN_StartSequence(sector, CHAN_FLOOR, sector->SeqName, 0);
|
||||||
{
|
}
|
||||||
SN_StartSequence (sector, CHAN_FLOOR, "Floor", 0);
|
else
|
||||||
|
{
|
||||||
|
SN_StartSequence(sector, CHAN_FLOOR, "Floor", 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,8 @@ void DPlat::Serialize (FArchive &arc)
|
||||||
|
|
||||||
void DPlat::PlayPlatSound (const char *sound)
|
void DPlat::PlayPlatSound (const char *sound)
|
||||||
{
|
{
|
||||||
|
if (m_Sector->Flags & SECF_SILENTMOVE) return;
|
||||||
|
|
||||||
if (m_Sector->seqType >= 0)
|
if (m_Sector->seqType >= 0)
|
||||||
{
|
{
|
||||||
SN_StartSequence (m_Sector, CHAN_FLOOR, m_Sector->seqType, SEQ_PLATFORM, 0);
|
SN_StartSequence (m_Sector, CHAN_FLOOR, m_Sector->seqType, SEQ_PLATFORM, 0);
|
||||||
|
@ -280,8 +282,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, int height,
|
||||||
{
|
{
|
||||||
if (line)
|
if (line)
|
||||||
sec->SetTexture(sector_t::floor, line->sidedef[0]->sector->GetTexture(sector_t::floor));
|
sec->SetTexture(sector_t::floor, line->sidedef[0]->sector->GetTexture(sector_t::floor));
|
||||||
if (change == 1)
|
if (change == 1) sec->ClearSpecial();
|
||||||
sec->special &= SECRET_MASK; // Stop damage and other stuff, if any
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
|
@ -293,7 +294,7 @@ bool EV_DoPlat (int tag, line_t *line, DPlat::EPlatType type, int height,
|
||||||
plat->m_Low = sec->floorplane.d;
|
plat->m_Low = sec->floorplane.d;
|
||||||
plat->m_Status = DPlat::up;
|
plat->m_Status = DPlat::up;
|
||||||
plat->PlayPlatSound ("Floor");
|
plat->PlayPlatSound ("Floor");
|
||||||
sec->special &= SECRET_MASK; // NO MORE DAMAGE, IF APPLICABLE
|
sec->ClearSpecial();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DPlat::platUpByValue:
|
case DPlat::platUpByValue:
|
||||||
|
|
|
@ -368,8 +368,17 @@ void P_SerializeWorld (FArchive &arc)
|
||||||
<< sec->planes[sector_t::ceiling]
|
<< sec->planes[sector_t::ceiling]
|
||||||
<< sec->heightsec
|
<< sec->heightsec
|
||||||
<< sec->bottommap << sec->midmap << sec->topmap
|
<< sec->bottommap << sec->midmap << sec->topmap
|
||||||
<< sec->gravity
|
<< sec->gravity;
|
||||||
<< sec->damageamount;
|
if (SaveVersion >= 4529)
|
||||||
|
{
|
||||||
|
arc << sec->damageamount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
short dmg;
|
||||||
|
arc << dmg;
|
||||||
|
sec->damageamount = dmg;
|
||||||
|
}
|
||||||
if (SaveVersion >= 4528)
|
if (SaveVersion >= 4528)
|
||||||
{
|
{
|
||||||
arc << sec->damageinterval
|
arc << sec->damageinterval
|
||||||
|
@ -398,15 +407,22 @@ void P_SerializeWorld (FArchive &arc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
arc << sec->SoundTarget
|
arc << sec->SoundTarget
|
||||||
<< sec->SecActTarget
|
<< sec->SecActTarget
|
||||||
<< sec->sky
|
<< sec->sky
|
||||||
<< sec->MoreFlags
|
<< sec->MoreFlags
|
||||||
<< sec->Flags
|
<< sec->Flags
|
||||||
<< sec->FloorSkyBox << sec->CeilingSkyBox
|
<< sec->FloorSkyBox << sec->CeilingSkyBox
|
||||||
<< sec->ZoneNumber
|
<< sec->ZoneNumber;
|
||||||
<< sec->secretsector
|
if (SaveVersion < 4529)
|
||||||
<< sec->interpolations[0]
|
{
|
||||||
|
short secretsector;
|
||||||
|
arc << secretsector;
|
||||||
|
if (secretsector) sec->Flags |= SECF_WASSECRET;
|
||||||
|
sec->special &= ~(SECRET_MASK|FRICTION_MASK|PUSH_MASK);
|
||||||
|
P_InitSectorSpecial(sec, sec->special, true);
|
||||||
|
}
|
||||||
|
arc << sec->interpolations[0]
|
||||||
<< sec->interpolations[1]
|
<< sec->interpolations[1]
|
||||||
<< sec->interpolations[2]
|
<< sec->interpolations[2]
|
||||||
<< sec->interpolations[3]
|
<< sec->interpolations[3]
|
||||||
|
|
|
@ -49,7 +49,7 @@ sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const
|
||||||
|
|
||||||
if (NULL != (tsec = getNextSector (ln, this)) &&
|
if (NULL != (tsec = getNextSector (ln, this)) &&
|
||||||
tsec != nogood &&
|
tsec != nogood &&
|
||||||
(tsec->special & 0x00ff) == type)
|
tsec->special == type)
|
||||||
{
|
{
|
||||||
return tsec;
|
return tsec;
|
||||||
}
|
}
|
||||||
|
@ -843,6 +843,60 @@ sector_t *sector_t::GetHeightSec() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void sector_t::GetSpecial(secspecial_t *spec)
|
||||||
|
{
|
||||||
|
spec->special = special;
|
||||||
|
spec->damageamount = damageamount;
|
||||||
|
spec->damagetype = damagetype;
|
||||||
|
spec->damageinterval = damageinterval;
|
||||||
|
spec->leakydamage = leakydamage;
|
||||||
|
spec->Flags = Flags & SECF_SPECIALFLAGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sector_t::SetSpecial(const secspecial_t *spec)
|
||||||
|
{
|
||||||
|
special = spec->special;
|
||||||
|
damageamount = spec->damageamount;
|
||||||
|
damagetype = spec->damagetype;
|
||||||
|
damageinterval = spec->damageinterval;
|
||||||
|
leakydamage = spec->leakydamage;
|
||||||
|
Flags = (Flags & ~SECF_SPECIALFLAGS) | (spec->Flags & SECF_SPECIALFLAGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sector_t::TransferSpecial(sector_t *model)
|
||||||
|
{
|
||||||
|
special = model->special;
|
||||||
|
damageamount = model->damageamount;
|
||||||
|
damagetype = model->damagetype;
|
||||||
|
damageinterval = model->damageinterval;
|
||||||
|
leakydamage = model->leakydamage;
|
||||||
|
Flags = (Flags&~SECF_SPECIALFLAGS) | (model->Flags & SECF_SPECIALFLAGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
FArchive &operator<< (FArchive &arc, secspecial_t &p)
|
||||||
|
{
|
||||||
|
if (SaveVersion < 4529)
|
||||||
|
{
|
||||||
|
short special;
|
||||||
|
arc << special;
|
||||||
|
sector_t sec;
|
||||||
|
P_InitSectorSpecial(&sec, special, true);
|
||||||
|
sec.GetSpecial(&p);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arc << p.special
|
||||||
|
<< p.damageamount
|
||||||
|
<< p.damagetype
|
||||||
|
<< p.damageinterval
|
||||||
|
<< p.leakydamage
|
||||||
|
<< p.Flags;
|
||||||
|
}
|
||||||
|
return arc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool secplane_t::CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const
|
bool secplane_t::CopyPlaneIfValid (secplane_t *dest, const secplane_t *opp) const
|
||||||
{
|
{
|
||||||
bool copy = false;
|
bool copy = false;
|
||||||
|
|
|
@ -1512,7 +1512,6 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex)
|
||||||
ss->special = LittleShort(ms->special);
|
ss->special = LittleShort(ms->special);
|
||||||
else // [RH] Translate to new sector special
|
else // [RH] Translate to new sector special
|
||||||
ss->special = P_TranslateSectorSpecial (LittleShort(ms->special));
|
ss->special = P_TranslateSectorSpecial (LittleShort(ms->special));
|
||||||
ss->secretsector = !!(ss->special&SECRET_MASK);
|
|
||||||
tagManager.AddSectorTag(i, LittleShort(ms->tag));
|
tagManager.AddSectorTag(i, LittleShort(ms->tag));
|
||||||
ss->thinglist = NULL;
|
ss->thinglist = NULL;
|
||||||
ss->touching_thinglist = NULL; // phares 3/14/98
|
ss->touching_thinglist = NULL; // phares 3/14/98
|
||||||
|
@ -4049,7 +4048,7 @@ void P_SetupLevel (const char *lumpname, int position)
|
||||||
{
|
{
|
||||||
if (mo->flags & MF_COUNTKILL)
|
if (mo->flags & MF_COUNTKILL)
|
||||||
{
|
{
|
||||||
if (mo->Sector->special == dDamage_End)
|
if (mo->Sector->damageamount > 0 && (mo->Sector->Flags & (SECF_ENDGODMODE|SECF_ENDLEVEL)) == (SECF_ENDGODMODE|SECF_ENDLEVEL))
|
||||||
{
|
{
|
||||||
mo->ClearCounters();
|
mo->ClearCounters();
|
||||||
}
|
}
|
||||||
|
|
527
src/p_spec.cpp
527
src/p_spec.cpp
|
@ -437,146 +437,55 @@ void P_PlayerInSpecialSector (player_t *player, sector_t * sector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int special = sector->special & ~SECRET_MASK;
|
|
||||||
|
|
||||||
// Has hit ground.
|
// Has hit ground.
|
||||||
AInventory *ironfeet;
|
AInventory *ironfeet;
|
||||||
|
|
||||||
// Allow subclasses. Better would be to implement it as armor and let that reduce
|
|
||||||
// the damage as part of the normal damage procedure. Unfortunately, I don't have
|
|
||||||
// different damage types yet, so that's not happening for now.
|
|
||||||
for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory)
|
|
||||||
{
|
|
||||||
if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet)))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// [RH] Normal DOOM special or BOOM specialized?
|
|
||||||
if (special >= dLight_Flicker && special <= 255)
|
|
||||||
{
|
|
||||||
switch (special)
|
|
||||||
{
|
|
||||||
case Sector_Heal:
|
|
||||||
// CoD's healing sector
|
|
||||||
if (!(level.time & 0x1f))
|
|
||||||
P_GiveBody (player->mo, 1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Damage_InstantDeath:
|
|
||||||
// Strife's instant death sector
|
|
||||||
P_DamageMobj (player->mo, NULL, NULL, 999, NAME_InstantDeath);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dDamage_Hellslime:
|
|
||||||
// HELLSLIME DAMAGE
|
|
||||||
if (ironfeet == NULL && !(level.time&0x1f))
|
|
||||||
P_DamageMobj (player->mo, NULL, NULL, 10, NAME_Slime);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dDamage_Nukage:
|
|
||||||
// NUKAGE DAMAGE
|
|
||||||
case sLight_Strobe_Hurt:
|
|
||||||
if (ironfeet == NULL && !(level.time&0x1f))
|
|
||||||
P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Slime);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case hDamage_Sludge:
|
|
||||||
if (ironfeet == NULL && !(level.time&0x1f))
|
|
||||||
P_DamageMobj (player->mo, NULL, NULL, 4, NAME_Slime);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dDamage_SuperHellslime:
|
|
||||||
// SUPER HELLSLIME DAMAGE
|
|
||||||
case dLight_Strobe_Hurt:
|
|
||||||
// STROBE HURT
|
|
||||||
if (ironfeet == NULL || pr_playerinspecialsector() < 5)
|
|
||||||
{
|
|
||||||
if (!(level.time&0x1f))
|
|
||||||
P_DamageMobj (player->mo, NULL, NULL, 20, NAME_Slime);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case sDamage_Hellslime:
|
|
||||||
if (ironfeet == NULL)
|
|
||||||
player->hazardcount += 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case sDamage_SuperHellslime:
|
|
||||||
if (ironfeet == NULL)
|
|
||||||
player->hazardcount += 4;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dDamage_End:
|
|
||||||
// EXIT SUPER DAMAGE! (for E1M8 finale)
|
|
||||||
player->cheats &= ~CF_GODMODE;
|
|
||||||
|
|
||||||
if (!(level.time & 0x1f))
|
|
||||||
P_DamageMobj (player->mo, NULL, NULL, 20, NAME_None);
|
|
||||||
|
|
||||||
if (player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT)))
|
|
||||||
G_ExitLevel(0, false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dDamage_LavaWimpy:
|
|
||||||
case dScroll_EastLavaDamage:
|
|
||||||
if (!(level.time & 15))
|
|
||||||
{
|
|
||||||
P_DamageMobj(player->mo, NULL, NULL, 5, NAME_Fire);
|
|
||||||
P_HitFloor(player->mo);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dDamage_LavaHefty:
|
|
||||||
if(!(level.time & 15))
|
|
||||||
{
|
|
||||||
P_DamageMobj(player->mo, NULL, NULL, 8, NAME_Fire);
|
|
||||||
P_HitFloor(player->mo);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// [RH] Ignore unknown specials
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//jff 3/14/98 handle extended sector types for secrets and damage
|
|
||||||
switch (special & DAMAGE_MASK)
|
|
||||||
{
|
|
||||||
case 0x000: // no damage
|
|
||||||
break;
|
|
||||||
case 0x100: // 2/5 damage per 31 ticks
|
|
||||||
if (ironfeet == NULL && !(level.time&0x1f))
|
|
||||||
P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Fire);
|
|
||||||
break;
|
|
||||||
case 0x200: // 5/10 damage per 31 ticks
|
|
||||||
if (ironfeet == NULL && !(level.time&0x1f))
|
|
||||||
P_DamageMobj (player->mo, NULL, NULL, 10, NAME_Slime);
|
|
||||||
break;
|
|
||||||
case 0x300: // 10/20 damage per 31 ticks
|
|
||||||
if (ironfeet == NULL
|
|
||||||
|| pr_playerinspecialsector() < 5) // take damage even with suit
|
|
||||||
{
|
|
||||||
if (!(level.time&0x1f))
|
|
||||||
P_DamageMobj (player->mo, NULL, NULL, 20, NAME_Slime);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// [RH] Apply any customizable damage
|
// [RH] Apply any customizable damage
|
||||||
if (sector->damageamount != 0)
|
if (sector->damageamount > 0)
|
||||||
{
|
{
|
||||||
if (level.time % sector->damageinterval == 0 && (ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage))
|
// Allow subclasses. Better would be to implement it as armor and let that reduce
|
||||||
|
// the damage as part of the normal damage procedure. Unfortunately, I don't have
|
||||||
|
// different damage types yet, so that's not happening for now.
|
||||||
|
for (ironfeet = player->mo->Inventory; ironfeet != NULL; ironfeet = ironfeet->Inventory)
|
||||||
{
|
{
|
||||||
P_DamageMobj (player->mo, NULL, NULL, sector->damageamount, sector->damagetype);
|
if (ironfeet->IsKindOf (RUNTIME_CLASS(APowerIronFeet)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sector->Flags & SECF_ENDGODMODE) player->cheats &= ~CF_GODMODE;
|
||||||
|
if ((ironfeet == NULL || pr_playerinspecialsector() < sector->leakydamage))
|
||||||
|
{
|
||||||
|
if (sector->Flags & SECF_HAZARD)
|
||||||
|
{
|
||||||
|
player->hazardcount += sector->damageamount;
|
||||||
|
player->hazardtype = sector->damagetype;
|
||||||
|
player->hazardinterval = sector->damageinterval;
|
||||||
|
}
|
||||||
|
else if (level.time % sector->damageinterval == 0)
|
||||||
|
{
|
||||||
|
P_DamageMobj(player->mo, NULL, NULL, sector->damageamount, sector->damagetype);
|
||||||
|
if ((sector->Flags & SECF_ENDLEVEL) && player->health <= 10 && (!deathmatch || !(dmflags & DF_NO_EXIT)))
|
||||||
|
{
|
||||||
|
G_ExitLevel(0, false);
|
||||||
|
}
|
||||||
|
if (sector->Flags & SECF_DMGTERRAINFX)
|
||||||
|
{
|
||||||
|
P_HitWater(player->mo, sector, INT_MIN, INT_MIN, INT_MIN, false, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sector->damageamount < 0)
|
||||||
|
{
|
||||||
|
if (level.time % sector->damageinterval == 0)
|
||||||
|
{
|
||||||
|
P_GiveBody(player->mo, -sector->damageamount, 100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sector->special & SECRET_MASK)
|
if (sector->isSecret())
|
||||||
{
|
{
|
||||||
sector->special &= ~SECRET_MASK;
|
sector->ClearSecret();
|
||||||
P_GiveSecret(player->mo, true, true, int(sector - sectors));
|
P_GiveSecret(player->mo, true, true, int(sector - sectors));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1167,6 +1076,228 @@ void P_SpawnPortal(line_t *line, int sectortag, int plane, int alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// P_SetSectorDamage
|
||||||
|
//
|
||||||
|
// Sets damage properties for one sector. Allows combination of original specials with explicit use of the damage properties
|
||||||
|
//
|
||||||
|
|
||||||
|
static void P_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)
|
||||||
|
{
|
||||||
|
sector->damageamount = damage;
|
||||||
|
sector->damageinterval = MAX(1, interval);
|
||||||
|
sector->leakydamage = leakchance;
|
||||||
|
sector->damagetype = type;
|
||||||
|
sector->Flags = (sector->Flags & ~SECF_DAMAGEFLAGS) | (flags & SECF_DAMAGEFLAGS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// P_InitSectorSpecial
|
||||||
|
//
|
||||||
|
// Sets up everything derived from 'sector->special' for one sector
|
||||||
|
// ('fromload' is necessary to allow conversion upon savegame load.)
|
||||||
|
//
|
||||||
|
|
||||||
|
void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers)
|
||||||
|
{
|
||||||
|
// [RH] All secret sectors are marked with a BOOM-ish bitfield
|
||||||
|
if (sector->special & SECRET_MASK)
|
||||||
|
{
|
||||||
|
sector->Flags |= SECF_SECRET | SECF_WASSECRET;
|
||||||
|
level.total_secrets++;
|
||||||
|
}
|
||||||
|
if (sector->special & FRICTION_MASK)
|
||||||
|
{
|
||||||
|
sector->Flags |= SECF_FRICTION;
|
||||||
|
}
|
||||||
|
if (sector->special & PUSH_MASK)
|
||||||
|
{
|
||||||
|
sector->Flags |= SECF_PUSH;
|
||||||
|
}
|
||||||
|
if ((sector->special & DAMAGE_MASK) == 0x100)
|
||||||
|
{
|
||||||
|
P_SetupSectorDamage(sector, 5, 32, 0, NAME_Fire, 0);
|
||||||
|
}
|
||||||
|
else if ((sector->special & DAMAGE_MASK) == 0x200)
|
||||||
|
{
|
||||||
|
P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0);
|
||||||
|
}
|
||||||
|
else if ((sector->special & DAMAGE_MASK) == 0x300)
|
||||||
|
{
|
||||||
|
P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
|
||||||
|
}
|
||||||
|
sector->special &= 0xff;
|
||||||
|
|
||||||
|
// [RH] Normal DOOM special or BOOM specialized?
|
||||||
|
bool keepspecial = false;
|
||||||
|
switch (sector->special)
|
||||||
|
{
|
||||||
|
case Light_Phased:
|
||||||
|
if (!nothinkers) new DPhased (sector, 48, 63 - (sector->lightlevel & 63));
|
||||||
|
break;
|
||||||
|
|
||||||
|
// [RH] Hexen-like phased lighting
|
||||||
|
case LightSequenceStart:
|
||||||
|
if (!nothinkers) new DPhased (sector);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dLight_Flicker:
|
||||||
|
if (!nothinkers) new DLightFlash (sector);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dLight_StrobeFast:
|
||||||
|
if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dLight_StrobeSlow:
|
||||||
|
if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dLight_Strobe_Hurt:
|
||||||
|
if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
|
||||||
|
P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dDamage_Hellslime:
|
||||||
|
P_SetupSectorDamage(sector, 10, 32, 0, NAME_Slime, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dDamage_Nukage:
|
||||||
|
P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dLight_Glow:
|
||||||
|
if (!nothinkers) new DGlow (sector);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dSector_DoorCloseIn30:
|
||||||
|
P_SpawnDoorCloseIn30 (sector);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dDamage_End:
|
||||||
|
P_SetupSectorDamage(sector, 20, 32, 256, NAME_None, SECF_ENDGODMODE|SECF_ENDLEVEL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dLight_StrobeSlowSync:
|
||||||
|
if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dLight_StrobeFastSync:
|
||||||
|
if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dSector_DoorRaiseIn5Mins:
|
||||||
|
P_SpawnDoorRaiseIn5Mins (sector);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dFriction_Low:
|
||||||
|
sector->friction = FRICTION_LOW;
|
||||||
|
sector->movefactor = 0x269;
|
||||||
|
sector->Flags |= SECF_FRICTION;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dDamage_SuperHellslime:
|
||||||
|
P_SetupSectorDamage(sector, 20, 32, 5, NAME_Slime, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dLight_FireFlicker:
|
||||||
|
if (!nothinkers) new DFireFlicker (sector);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dDamage_LavaWimpy:
|
||||||
|
P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dDamage_LavaHefty:
|
||||||
|
P_SetupSectorDamage(sector, 8, 32, 256, NAME_Fire, SECF_DMGTERRAINFX);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dScroll_EastLavaDamage:
|
||||||
|
P_SetupSectorDamage(sector, 5, 32, 256, NAME_Fire, SECF_DMGTERRAINFX);
|
||||||
|
if (!nothinkers)
|
||||||
|
{
|
||||||
|
new DStrobe(sector, STROBEBRIGHT, FASTDARK, false);
|
||||||
|
new DScroller(DScroller::sc_floor, (-FRACUNIT / 2) << 3,
|
||||||
|
0, -1, int(sector - sectors), 0);
|
||||||
|
}
|
||||||
|
keepspecial = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case hDamage_Sludge:
|
||||||
|
P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sLight_Strobe_Hurt:
|
||||||
|
P_SetupSectorDamage(sector, 5, 32, 0, NAME_Slime, 0);
|
||||||
|
if (!nothinkers) new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sDamage_Hellslime:
|
||||||
|
P_SetupSectorDamage(sector, 2, 32, 0, NAME_Slime, SECF_HAZARD);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Damage_InstantDeath:
|
||||||
|
// Strife's instant death sector
|
||||||
|
P_SetupSectorDamage(sector, TELEFRAG_DAMAGE, 1, 256, NAME_InstantDeath, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sDamage_SuperHellslime:
|
||||||
|
P_SetupSectorDamage(sector, 4, 32, 0, NAME_Slime, SECF_HAZARD);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Sector_Hidden:
|
||||||
|
sector->MoreFlags |= SECF_HIDDEN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Sector_Heal:
|
||||||
|
// CoD's healing sector
|
||||||
|
P_SetupSectorDamage(sector, -1, 32, 0, NAME_None, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Sky2:
|
||||||
|
sector->sky = PL_SKYFLAT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (sector->special >= Scroll_North_Slow &&
|
||||||
|
sector->special <= Scroll_SouthWest_Fast)
|
||||||
|
{ // Hexen scroll special
|
||||||
|
static const char hexenScrollies[24][2] =
|
||||||
|
{
|
||||||
|
{ 0, 1 }, { 0, 2 }, { 0, 4 },
|
||||||
|
{ -1, 0 }, { -2, 0 }, { -4, 0 },
|
||||||
|
{ 0, -1 }, { 0, -2 }, { 0, -4 },
|
||||||
|
{ 1, 0 }, { 2, 0 }, { 4, 0 },
|
||||||
|
{ 1, 1 }, { 2, 2 }, { 4, 4 },
|
||||||
|
{ -1, 1 }, { -2, 2 }, { -4, 4 },
|
||||||
|
{ -1, -1 }, { -2, -2 }, { -4, -4 },
|
||||||
|
{ 1, -1 }, { 2, -2 }, { 4, -4 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int i = sector->special - Scroll_North_Slow;
|
||||||
|
fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2);
|
||||||
|
fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2);
|
||||||
|
if (!nothinkers) new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0);
|
||||||
|
}
|
||||||
|
else if (sector->special >= Carry_East5 &&
|
||||||
|
sector->special <= Carry_East35)
|
||||||
|
{ // Heretic scroll special
|
||||||
|
// Only east scrollers also scroll the texture
|
||||||
|
if (!nothinkers) new DScroller (DScroller::sc_floor,
|
||||||
|
(-FRACUNIT/2)<<(sector->special - Carry_East5),
|
||||||
|
0, -1, int(sector-sectors), 0);
|
||||||
|
}
|
||||||
|
keepspecial = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!keepspecial) sector->special = 0;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// P_SpawnSpecials
|
// P_SpawnSpecials
|
||||||
//
|
//
|
||||||
|
@ -1187,135 +1318,7 @@ void P_SpawnSpecials (void)
|
||||||
if (sector->special == 0)
|
if (sector->special == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// [RH] All secret sectors are marked with a BOOM-ish bitfield
|
P_InitSectorSpecial(sector, sector->special, false);
|
||||||
if (sector->special & SECRET_MASK)
|
|
||||||
level.total_secrets++;
|
|
||||||
|
|
||||||
switch (sector->special & 0xff)
|
|
||||||
{
|
|
||||||
// [RH] Normal DOOM/Hexen specials. We clear off the special for lights
|
|
||||||
// here instead of inside the spawners.
|
|
||||||
|
|
||||||
case dLight_Flicker:
|
|
||||||
// FLICKERING LIGHTS
|
|
||||||
new DLightFlash (sector);
|
|
||||||
sector->special &= 0xff00;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dLight_StrobeFast:
|
|
||||||
// STROBE FAST
|
|
||||||
new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
|
|
||||||
sector->special &= 0xff00;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dLight_StrobeSlow:
|
|
||||||
// STROBE SLOW
|
|
||||||
new DStrobe (sector, STROBEBRIGHT, SLOWDARK, false);
|
|
||||||
sector->special &= 0xff00;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dLight_Strobe_Hurt:
|
|
||||||
case sLight_Strobe_Hurt:
|
|
||||||
// STROBE FAST/DEATH SLIME
|
|
||||||
new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dLight_Glow:
|
|
||||||
// GLOWING LIGHT
|
|
||||||
new DGlow (sector);
|
|
||||||
sector->special &= 0xff00;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dSector_DoorCloseIn30:
|
|
||||||
// DOOR CLOSE IN 30 SECONDS
|
|
||||||
P_SpawnDoorCloseIn30 (sector);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dLight_StrobeSlowSync:
|
|
||||||
// SYNC STROBE SLOW
|
|
||||||
new DStrobe (sector, STROBEBRIGHT, SLOWDARK, true);
|
|
||||||
sector->special &= 0xff00;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dLight_StrobeFastSync:
|
|
||||||
// SYNC STROBE FAST
|
|
||||||
new DStrobe (sector, STROBEBRIGHT, FASTDARK, true);
|
|
||||||
sector->special &= 0xff00;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dSector_DoorRaiseIn5Mins:
|
|
||||||
// DOOR RAISE IN 5 MINUTES
|
|
||||||
P_SpawnDoorRaiseIn5Mins (sector);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dLight_FireFlicker:
|
|
||||||
// fire flickering
|
|
||||||
new DFireFlicker (sector);
|
|
||||||
sector->special &= 0xff00;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dFriction_Low:
|
|
||||||
sector->friction = FRICTION_LOW;
|
|
||||||
sector->movefactor = 0x269;
|
|
||||||
sector->special &= 0xff00;
|
|
||||||
sector->special |= FRICTION_MASK;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// [RH] Hexen-like phased lighting
|
|
||||||
case LightSequenceStart:
|
|
||||||
new DPhased (sector);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Light_Phased:
|
|
||||||
new DPhased (sector, 48, 63 - (sector->lightlevel & 63));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Sky2:
|
|
||||||
sector->sky = PL_SKYFLAT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dScroll_EastLavaDamage:
|
|
||||||
new DStrobe (sector, STROBEBRIGHT, FASTDARK, false);
|
|
||||||
new DScroller (DScroller::sc_floor, (-FRACUNIT/2)<<3,
|
|
||||||
0, -1, int(sector-sectors), 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Sector_Hidden:
|
|
||||||
sector->MoreFlags |= SECF_HIDDEN;
|
|
||||||
sector->special &= 0xff00;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if ((sector->special & 0xff) >= Scroll_North_Slow &&
|
|
||||||
(sector->special & 0xff) <= Scroll_SouthWest_Fast)
|
|
||||||
{ // Hexen scroll special
|
|
||||||
static const char hexenScrollies[24][2] =
|
|
||||||
{
|
|
||||||
{ 0, 1 }, { 0, 2 }, { 0, 4 },
|
|
||||||
{ -1, 0 }, { -2, 0 }, { -4, 0 },
|
|
||||||
{ 0, -1 }, { 0, -2 }, { 0, -4 },
|
|
||||||
{ 1, 0 }, { 2, 0 }, { 4, 0 },
|
|
||||||
{ 1, 1 }, { 2, 2 }, { 4, 4 },
|
|
||||||
{ -1, 1 }, { -2, 2 }, { -4, 4 },
|
|
||||||
{ -1, -1 }, { -2, -2 }, { -4, -4 },
|
|
||||||
{ 1, -1 }, { 2, -2 }, { 4, -4 }
|
|
||||||
};
|
|
||||||
|
|
||||||
int i = (sector->special & 0xff) - Scroll_North_Slow;
|
|
||||||
fixed_t dx = hexenScrollies[i][0] * (FRACUNIT/2);
|
|
||||||
fixed_t dy = hexenScrollies[i][1] * (FRACUNIT/2);
|
|
||||||
new DScroller (DScroller::sc_floor, dx, dy, -1, int(sector-sectors), 0);
|
|
||||||
}
|
|
||||||
else if ((sector->special & 0xff) >= Carry_East5 &&
|
|
||||||
(sector->special & 0xff) <= Carry_East35)
|
|
||||||
{ // Heretic scroll special
|
|
||||||
// Only east scrollers also scroll the texture
|
|
||||||
new DScroller (DScroller::sc_floor,
|
|
||||||
(-FRACUNIT/2)<<((sector->special & 0xff) - Carry_East5),
|
|
||||||
0, -1, int(sector-sectors), 0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init other misc stuff
|
// Init other misc stuff
|
||||||
|
@ -2056,11 +2059,11 @@ void P_SetSectorFriction (int tag, int amount, bool alterFlag)
|
||||||
// can be enabled and disabled at will.
|
// can be enabled and disabled at will.
|
||||||
if (friction == ORIG_FRICTION)
|
if (friction == ORIG_FRICTION)
|
||||||
{
|
{
|
||||||
sectors[s].special &= ~FRICTION_MASK;
|
sectors[s].Flags &= ~SECF_FRICTION;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sectors[s].special |= FRICTION_MASK;
|
sectors[s].Flags |= SECF_FRICTION;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2176,7 +2179,7 @@ void DPusher::Tick ()
|
||||||
// Be sure the special sector type is still turned on. If so, proceed.
|
// Be sure the special sector type is still turned on. If so, proceed.
|
||||||
// Else, bail out; the sector type has been changed on us.
|
// Else, bail out; the sector type has been changed on us.
|
||||||
|
|
||||||
if (!(sec->special & PUSH_MASK))
|
if (!(sec->Flags & SECF_PUSH))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// For constant pushers (wind/current) there are 3 situations:
|
// For constant pushers (wind/current) there are 3 situations:
|
||||||
|
|
|
@ -158,6 +158,7 @@ bool PIT_PushThing (AActor *thing);
|
||||||
bool CheckIfExitIsGood (AActor *self, level_info_t *info);
|
bool CheckIfExitIsGood (AActor *self, level_info_t *info);
|
||||||
|
|
||||||
// at map load
|
// at map load
|
||||||
|
void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers);
|
||||||
void P_SpawnSpecials (void);
|
void P_SpawnSpecials (void);
|
||||||
|
|
||||||
// every tic
|
// every tic
|
||||||
|
@ -673,7 +674,7 @@ protected:
|
||||||
|
|
||||||
// [RH] Need these for BOOM-ish transferring ceilings
|
// [RH] Need these for BOOM-ish transferring ceilings
|
||||||
FTextureID m_Texture;
|
FTextureID m_Texture;
|
||||||
int m_NewSpecial;
|
secspecial_t m_NewSpecial;
|
||||||
|
|
||||||
// ID
|
// ID
|
||||||
int m_Tag;
|
int m_Tag;
|
||||||
|
@ -760,7 +761,7 @@ protected:
|
||||||
int m_Crush;
|
int m_Crush;
|
||||||
bool m_Hexencrush;
|
bool m_Hexencrush;
|
||||||
int m_Direction;
|
int m_Direction;
|
||||||
int m_NewSpecial;
|
secspecial_t m_NewSpecial;
|
||||||
FTextureID m_Texture;
|
FTextureID m_Texture;
|
||||||
fixed_t m_FloorDestDist;
|
fixed_t m_FloorDestDist;
|
||||||
fixed_t m_Speed;
|
fixed_t m_Speed;
|
||||||
|
|
|
@ -1542,6 +1542,14 @@ public:
|
||||||
sec->leakydamage = CheckInt(key);
|
sec->leakydamage = CheckInt(key);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NAME_damageterraineffect:
|
||||||
|
Flag(sec->Flags, SECF_DMGTERRAINFX, key);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NAME_damagehazard:
|
||||||
|
Flag(sec->Flags, SECF_HAZARD, key);
|
||||||
|
break;
|
||||||
|
|
||||||
case NAME_MoreIds:
|
case NAME_MoreIds:
|
||||||
// delay parsing of the tag string until parsing of the sector is complete
|
// delay parsing of the tag string until parsing of the sector is complete
|
||||||
// This ensures that the ID is always the first tag in the list.
|
// This ensures that the ID is always the first tag in the list.
|
||||||
|
@ -1568,7 +1576,15 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sec->secretsector = !!(sec->special&SECRET_MASK);
|
if (sec->damageamount == 0)
|
||||||
|
{
|
||||||
|
// If no damage is set, clear all other related properties so that they do not interfere
|
||||||
|
// with other means of setting them.
|
||||||
|
sec->damagetype = NAME_None;
|
||||||
|
sec->damageinterval = 0;
|
||||||
|
sec->leakydamage = 0;
|
||||||
|
sec->Flags &= ~SECF_DAMAGEFLAGS;
|
||||||
|
}
|
||||||
|
|
||||||
// Reset the planes to their defaults if not all of the plane equation's parameters were found.
|
// Reset the planes to their defaults if not all of the plane equation's parameters were found.
|
||||||
if (fplaneflags != 15)
|
if (fplaneflags != 15)
|
||||||
|
@ -1612,10 +1628,10 @@ public:
|
||||||
{
|
{
|
||||||
// [RH] Sectors default to white light with the default fade.
|
// [RH] Sectors default to white light with the default fade.
|
||||||
// If they are outside (have a sky ceiling), they use the outside fog.
|
// If they are outside (have a sky ceiling), they use the outside fog.
|
||||||
if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special&0xff) == Sector_Outside))
|
if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special & 0xff) == Sector_Outside))
|
||||||
{
|
{
|
||||||
if (fogMap == NULL)
|
if (fogMap == NULL)
|
||||||
fogMap = GetSpecialLights (PalEntry (255,255,255), level.outsidefog, 0);
|
fogMap = GetSpecialLights(PalEntry(255, 255, 255), level.outsidefog, 0);
|
||||||
sec->ColorMap = fogMap;
|
sec->ColorMap = fogMap;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1628,9 +1644,9 @@ public:
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (lightcolor == -1) lightcolor = PalEntry(255,255,255);
|
if (lightcolor == -1) lightcolor = PalEntry(255,255,255);
|
||||||
if (fadecolor == -1)
|
if (fadecolor == -1)
|
||||||
{
|
{
|
||||||
if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special&0xff) == Sector_Outside))
|
if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special & 0xff) == Sector_Outside))
|
||||||
fadecolor = level.outsidefog;
|
fadecolor = level.outsidefog;
|
||||||
else
|
else
|
||||||
fadecolor = level.fadeto;
|
fadecolor = level.fadeto;
|
||||||
|
|
|
@ -362,6 +362,8 @@ player_t &player_t::operator=(const player_t &p)
|
||||||
damagecount = p.damagecount;
|
damagecount = p.damagecount;
|
||||||
bonuscount = p.bonuscount;
|
bonuscount = p.bonuscount;
|
||||||
hazardcount = p.hazardcount;
|
hazardcount = p.hazardcount;
|
||||||
|
hazardtype = p.hazardtype;
|
||||||
|
hazardinterval = p.hazardinterval;
|
||||||
poisoncount = p.poisoncount;
|
poisoncount = p.poisoncount;
|
||||||
poisontype = p.poisontype;
|
poisontype = p.poisontype;
|
||||||
poisonpaintype = p.poisonpaintype;
|
poisonpaintype = p.poisonpaintype;
|
||||||
|
@ -2538,10 +2540,8 @@ void P_PlayerThink (player_t *player)
|
||||||
if (!(player->cheats & CF_PREDICTING))
|
if (!(player->cheats & CF_PREDICTING))
|
||||||
{
|
{
|
||||||
P_PlayerOnSpecial3DFloor (player);
|
P_PlayerOnSpecial3DFloor (player);
|
||||||
if (player->mo->Sector->special || player->mo->Sector->damageamount != 0)
|
P_PlayerInSpecialSector (player);
|
||||||
{
|
|
||||||
P_PlayerInSpecialSector (player);
|
|
||||||
}
|
|
||||||
if (player->mo->z <= player->mo->Sector->floorplane.ZatPoint(
|
if (player->mo->z <= player->mo->Sector->floorplane.ZatPoint(
|
||||||
player->mo->x, player->mo->y) ||
|
player->mo->x, player->mo->y) ||
|
||||||
player->mo->waterlevel)
|
player->mo->waterlevel)
|
||||||
|
@ -2600,8 +2600,8 @@ void P_PlayerThink (player_t *player)
|
||||||
if (player->hazardcount)
|
if (player->hazardcount)
|
||||||
{
|
{
|
||||||
player->hazardcount--;
|
player->hazardcount--;
|
||||||
if (!(level.time & 31) && player->hazardcount > 16*TICRATE)
|
if (!(level.time % player->hazardinterval) && player->hazardcount > 16*TICRATE)
|
||||||
P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Slime);
|
P_DamageMobj (player->mo, NULL, NULL, 5, player->hazardtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player->poisoncount && !(level.time & 15))
|
if (player->poisoncount && !(level.time & 15))
|
||||||
|
@ -3014,7 +3014,12 @@ void player_t::Serialize (FArchive &arc)
|
||||||
<< air_finished
|
<< air_finished
|
||||||
<< turnticks
|
<< turnticks
|
||||||
<< oldbuttons;
|
<< oldbuttons;
|
||||||
bool IsBot;
|
if (SaveVersion >= 4929)
|
||||||
|
{
|
||||||
|
arc << hazardtype
|
||||||
|
<< hazardinterval;
|
||||||
|
}
|
||||||
|
bool IsBot = false;
|
||||||
if (SaveVersion >= 4514)
|
if (SaveVersion >= 4514)
|
||||||
{
|
{
|
||||||
arc << Bot;
|
arc << Bot;
|
||||||
|
|
62
src/r_defs.h
62
src/r_defs.h
|
@ -392,6 +392,20 @@ enum
|
||||||
SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector
|
SECF_NOFALLINGDAMAGE= 2, // No falling damage in this sector
|
||||||
SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast.
|
SECF_FLOORDROP = 4, // all actors standing on this floor will remain on it when it lowers very fast.
|
||||||
SECF_NORESPAWN = 8, // players can not respawn in this sector
|
SECF_NORESPAWN = 8, // players can not respawn in this sector
|
||||||
|
SECF_FRICTION = 16, // sector has friction enabled
|
||||||
|
SECF_PUSH = 32, // pushers enabled
|
||||||
|
SECF_SILENTMOVE = 64, // Sector movement makes mo sound (Eternity got this so this may be useful for an extended cross-port standard.)
|
||||||
|
SECF_DMGTERRAINFX = 128, // spawns terrain splash when inflicting damage
|
||||||
|
SECF_ENDGODMODE = 256, // getting damaged by this sector ends god mode
|
||||||
|
SECF_ENDLEVEL = 512, // ends level when health goes below 10
|
||||||
|
SECF_HAZARD = 1024, // Change to Strife's delayed damage handling.
|
||||||
|
|
||||||
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -466,6 +480,23 @@ struct FTransform
|
||||||
fixed_t base_angle, base_yoffs;
|
fixed_t base_angle, base_yoffs;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct secspecial_t
|
||||||
|
{
|
||||||
|
FNameNoInit damagetype; // [RH] Means-of-death for applied damage
|
||||||
|
int damageamount; // [RH] Damage to do while standing on floor
|
||||||
|
short special;
|
||||||
|
short damageinterval; // Interval for damage application
|
||||||
|
short leakydamage; // chance of leaking through radiation suit
|
||||||
|
int Flags;
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
memset(this, 0, sizeof(*this));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FArchive &operator<< (FArchive &arc, secspecial_t &p);
|
||||||
|
|
||||||
struct sector_t
|
struct sector_t
|
||||||
{
|
{
|
||||||
// Member functions
|
// Member functions
|
||||||
|
@ -695,7 +726,35 @@ struct sector_t
|
||||||
return pos == floor? floorplane:ceilingplane;
|
return pos == floor? floorplane:ceilingplane;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isSecret() const
|
||||||
|
{
|
||||||
|
return !!(Flags & SECF_SECRET);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wasSecret() const
|
||||||
|
{
|
||||||
|
return !!(Flags & SECF_WASSECRET);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearSecret()
|
||||||
|
{
|
||||||
|
Flags &= ~SECF_SECRET;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearSpecial()
|
||||||
|
{
|
||||||
|
// clears all variables that originate from 'special'. Used for sector type transferring thinkers
|
||||||
|
special = 0;
|
||||||
|
damageamount = 0;
|
||||||
|
damageinterval = 0;
|
||||||
|
damagetype = NAME_None;
|
||||||
|
leakydamage = 0;
|
||||||
|
Flags &= ~SECF_SPECIALFLAGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransferSpecial(sector_t *model);
|
||||||
|
void GetSpecial(secspecial_t *spec);
|
||||||
|
void SetSpecial(const secspecial_t *spec);
|
||||||
bool PlaneMoving(int pos);
|
bool PlaneMoving(int pos);
|
||||||
|
|
||||||
|
|
||||||
|
@ -764,7 +823,7 @@ struct sector_t
|
||||||
|
|
||||||
float gravity; // [RH] Sector gravity (1.0 is normal)
|
float gravity; // [RH] Sector gravity (1.0 is normal)
|
||||||
FNameNoInit damagetype; // [RH] Means-of-death for applied damage
|
FNameNoInit damagetype; // [RH] Means-of-death for applied damage
|
||||||
short damageamount; // [RH] Damage to do while standing on floor
|
int damageamount; // [RH] Damage to do while standing on floor
|
||||||
short damageinterval; // Interval for damage application
|
short damageinterval; // Interval for damage application
|
||||||
short leakydamage; // chance of leaking through radiation suit
|
short leakydamage; // chance of leaking through radiation suit
|
||||||
|
|
||||||
|
@ -782,7 +841,6 @@ struct sector_t
|
||||||
// regular sky.
|
// regular sky.
|
||||||
TObjPtr<ASkyViewpoint> FloorSkyBox, CeilingSkyBox;
|
TObjPtr<ASkyViewpoint> FloorSkyBox, CeilingSkyBox;
|
||||||
|
|
||||||
short secretsector; //jff 2/16/98 remembers if sector WAS secret (automap)
|
|
||||||
int sectornum; // for comparing sector copies
|
int sectornum; // for comparing sector copies
|
||||||
|
|
||||||
extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat.
|
extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat.
|
||||||
|
|
|
@ -58,7 +58,7 @@ CUSTOM_CVAR (Int, timidity_pipe, 90, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CUSTOM_CVAR (Int, timidity_frequency, 22050, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
CUSTOM_CVAR (Int, timidity_frequency, 44100, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
|
||||||
{ // Clamp frequency to Timidity's limits
|
{ // Clamp frequency to Timidity's limits
|
||||||
if (self < 4000)
|
if (self < 4000)
|
||||||
self = 4000;
|
self = 4000;
|
||||||
|
|
|
@ -76,7 +76,7 @@ const char *GetVersionString();
|
||||||
|
|
||||||
// Use 4500 as the base git save version, since it's higher than the
|
// Use 4500 as the base git save version, since it's higher than the
|
||||||
// SVN revision ever got.
|
// SVN revision ever got.
|
||||||
#define SAVEVER 4528
|
#define SAVEVER 4529
|
||||||
|
|
||||||
#define SAVEVERSTRINGIFY2(x) #x
|
#define SAVEVERSTRINGIFY2(x) #x
|
||||||
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)
|
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)
|
||||||
|
|
29
wadsrc/static/filter/doom.freedoom/decaldef.z
Normal file
29
wadsrc/static/filter/doom.freedoom/decaldef.z
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
/***** BFG Scorches ********************************************************/
|
||||||
|
|
||||||
|
decal BFGLightning1
|
||||||
|
{
|
||||||
|
pic BFGLITE1
|
||||||
|
shade "80 80 ff"
|
||||||
|
fullbright
|
||||||
|
randomflipx
|
||||||
|
animator GoAway2
|
||||||
|
lowerdecal BFGScorch
|
||||||
|
}
|
||||||
|
|
||||||
|
decal BFGLightning2
|
||||||
|
{
|
||||||
|
pic BFGLITE2
|
||||||
|
shade "80 80 ff"
|
||||||
|
fullbright
|
||||||
|
randomflipy
|
||||||
|
animator GoAway2
|
||||||
|
lowerdecal BFGScorch
|
||||||
|
}
|
||||||
|
|
||||||
|
decalgroup BFGLightning
|
||||||
|
{
|
||||||
|
BFGLightning1 1
|
||||||
|
BFGLightning2 1
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ include "mapinfo/doom2.txt"
|
||||||
|
|
||||||
gameinfo
|
gameinfo
|
||||||
{
|
{
|
||||||
titlepage = "INTERPIC"
|
titlepage = "DMENUPIC"
|
||||||
}
|
}
|
||||||
|
|
||||||
clearepisodes
|
clearepisodes
|
||||||
|
|
Loading…
Reference in a new issue