diff --git a/specs/udmf_zdoom.txt b/specs/udmf_zdoom.txt index f20525d13c..74d5fb4f73 100644 --- a/specs/udmf_zdoom.txt +++ b/specs/udmf_zdoom.txt @@ -204,10 +204,15 @@ Note: All fields default to false unless mentioned otherwise. hidden = ; // if true this sector will not be drawn on the textured automap. waterzone = ; // Sector is under water and swimmable moreids = ; // Additional sector IDs/tags, specified as a space separated list of numbers (e.g. "2 666 1003 4505") - damageamount = ; // Amount of damage inflicted by this sector, default = 0 + damageamount = ; // 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 = ; // Damage type for sector damage, Default = "None". (generic damage) damageinterval = ; // Interval in tics between damage application, default = 32. leakiness = ; // Probability of leaking through radiation suit (0 = never, 256 = always), default = 0. + damageterraineffect = ; // Will spawn a terrain splash when damage is inflicted. Default = false. + damagehazard = ; // Changes damage model to Strife's delayed damage for the given sector. Default = false. + * Note about dropactors diff --git a/src/am_map.cpp b/src/am_map.cpp index 81e45c6858..606a65ae85 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2071,17 +2071,17 @@ static bool AM_CheckSecret(line_t *line) { 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 (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; } } diff --git a/src/b_move.cpp b/src/b_move.cpp index 2a76f19259..4759f22d96 100644 --- a/src/b_move.cpp +++ b/src/b_move.cpp @@ -354,21 +354,5 @@ void DBot::Pitch (AActor *target) //Checks if a sector is dangerous. bool FCajunMaster::IsDangerous (sector_t *sec) { - int special; - - 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; + return sec->damageamount > 0; } diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 0a9e4f0e38..57290a98ae 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -1106,11 +1106,8 @@ static void PrintSecretString(const char *string, bool thislevel) if (*string == ';') string++; if (thislevel && secnum >= 0 && secnum < numsectors) { - if (sectors[secnum].secretsector) - { - if ((sectors[secnum].special & SECRET_MASK)) colstr = TEXTCOLOR_RED; - else colstr = TEXTCOLOR_GREEN; - } + if (sectors[secnum].isSecret()) colstr = TEXTCOLOR_RED; + else if (sectors[secnum].wasSecret()) colstr = TEXTCOLOR_GREEN; else colstr = TEXTCOLOR_ORANGE; } } diff --git a/src/d_player.h b/src/d_player.h index 11611cded5..38879a63a4 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -422,6 +422,8 @@ public: int killcount, itemcount, secretcount; // for intermission int damagecount, bonuscount;// for screen flashing 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 FName poisontype; // type of poison damage to apply FName poisonpaintype; // type of Pain state to enter for poison damage diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 7e05be8da3..fdf9047642 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -4323,44 +4323,12 @@ void FParser::SF_KillInSector() //========================================================================== // // 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) { - int tagnum, secnum; - 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; - } + // I don't think this was ever used publicly so I'm not going to bother fixing it. } //========================================================================== diff --git a/src/fragglescript/t_load.cpp b/src/fragglescript/t_load.cpp index eedb68f7cf..cd40d809a4 100644 --- a/src/fragglescript/t_load.cpp +++ b/src/fragglescript/t_load.cpp @@ -87,7 +87,6 @@ DEFINE_MAP_OPTION(fs_nocheckposition, false) { FFsOptions *opt = info->GetOptData("fragglescript"); - parse.ParseAssign(); if (parse.CheckAssign()) { parse.sc.MustGetNumber(); diff --git a/src/g_shared/a_lightning.cpp b/src/g_shared/a_lightning.cpp index e7c598d3e8..33d51c02d9 100644 --- a/src/g_shared/a_lightning.cpp +++ b/src/g_shared/a_lightning.cpp @@ -139,7 +139,7 @@ void DLightningThinker::LightningFlash () for (i = numsectors, j = 0; i > 0; --i, ++j, ++tempSec) { // 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 || special == Light_IndoorLightning1 || special == Light_IndoorLightning2 diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp index 1edea19faa..05f6367dc4 100644 --- a/src/g_strife/a_strifestuff.cpp +++ b/src/g_strife/a_strifestuff.cpp @@ -630,11 +630,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain) 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; fixed_t speed = (anglespeed % 10) << (FRACBITS - 4); diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 2a52df58a8..a19d0a479c 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -329,6 +329,7 @@ void DIntermissionScreenText::Drawer () int c; const FRemapTable *range; 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 // line feed characters. @@ -380,6 +381,7 @@ void DIntermissionScreenText::Drawer () } pic = SmallFont->GetChar (c, &w); + w += kerning; w *= CleanXfac; if (cx + w > SCREENWIDTH) continue; diff --git a/src/namedef.h b/src/namedef.h index cad58bfa38..9ca8cb8ed9 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -510,6 +510,8 @@ xx(damageamount) xx(damagetype) xx(damageinterval) xx(leakiness) +xx(damageterraineffect) +xx(damagehazard) // USDF keywords xx(Amount) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 0835b83d04..77376ba513 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -345,8 +345,7 @@ void P_PlayerOnSpecial3DFloor(player_t* player) } // 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!) P_PlayerOnSpecialFlat( diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 7efef80a53..3203cf7779 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -90,6 +90,7 @@ void DCeiling::Serialize (FArchive &arc) void DCeiling::PlayCeilingSound () { + if (m_Sector->Flags & SECF_SILENTMOVE) return; if (m_Sector->seqType >= 0) { 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 case genCeilingChgT: case genCeilingChg0: - m_Sector->special = m_NewSpecial; + m_Sector->SetSpecial(&m_NewSpecial); // fall through case genCeilingChg: m_Sector->SetTexture(sector_t::ceiling, m_Texture); @@ -175,7 +176,7 @@ void DCeiling::Tick () // then remove the active ceiling case genCeilingChgT: case genCeilingChg0: - m_Sector->special = m_NewSpecial; + m_Sector->SetSpecial(&m_NewSpecial); // fall through case genCeilingChg: 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) { case 1: // type is zeroed - ceiling->m_NewSpecial = 0; + ceiling->m_NewSpecial.Clear(); ceiling->m_Type = genCeilingChg0; break; case 2: // type is copied - ceiling->m_NewSpecial = sec->special; + sec->GetSpecial(&ceiling->m_NewSpecial); ceiling->m_Type = genCeilingChgT; break; 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) { case 1: // type is zeroed - ceiling->m_NewSpecial = 0; + ceiling->m_NewSpecial.Clear(); ceiling->m_Type = genCeilingChg0; break; case 2: // type is copied - ceiling->m_NewSpecial = line->frontsector->special; + line->frontsector->GetSpecial(&ceiling->m_NewSpecial); ceiling->m_Type = genCeilingChgT; break; case 3: // type is left alone diff --git a/src/p_doors.cpp b/src/p_doors.cpp index 49ed20f460..bce3249024 100644 --- a/src/p_doors.cpp +++ b/src/p_doors.cpp @@ -250,6 +250,8 @@ void DDoor::DoorSound(bool raise, DSeqNode *curseq) const choice = !raise; + if (m_Sector->Flags & SECF_SILENTMOVE) return; + if (m_Speed >= FRACUNIT*8) { choice += 2; @@ -511,8 +513,6 @@ void P_SpawnDoorCloseIn30 (sector_t *sec) fixed_t height; DDoor *door = new DDoor (sec); - sec->special = 0; - door->m_Sector = sec; door->m_Direction = 0; door->m_Type = DDoor::doorRaise; @@ -533,7 +533,6 @@ void P_SpawnDoorCloseIn30 (sector_t *sec) void P_SpawnDoorRaiseIn5Mins (sector_t *sec) { - sec->special = 0; new DDoor (sec, DDoor::doorRaiseIn5Mins, 2*FRACUNIT, TICRATE*30/7, 0); } diff --git a/src/p_floor.cpp b/src/p_floor.cpp index 9e78060391..e3763e677a 100644 --- a/src/p_floor.cpp +++ b/src/p_floor.cpp @@ -55,6 +55,8 @@ inline FArchive &operator<< (FArchive &arc, DFloor::EFloor &type) static void StartFloorSound (sector_t *sec) { + if (sec->Flags & SECF_SILENTMOVE) return; + if (sec->seqType >= 0) { SN_StartSequence (sec, CHAN_FLOOR, sec->seqType, SEQ_PLATFORM, 0); @@ -159,7 +161,7 @@ void DFloor::Tick () case donutRaise: case genFloorChgT: case genFloorChg0: - m_Sector->special = (m_Sector->special & SECRET_MASK) | m_NewSpecial; + m_Sector->SetSpecial(&m_NewSpecial); //fall thru case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); @@ -175,7 +177,7 @@ void DFloor::Tick () case floorLowerAndChange: case genFloorChgT: case genFloorChg0: - m_Sector->special = (m_Sector->special & SECRET_MASK) | m_NewSpecial; + m_Sector->SetSpecial(&m_NewSpecial); //fall thru case genFloorChg: m_Sector->SetTexture(sector_t::floor, m_Texture); @@ -233,14 +235,14 @@ void DFloor::SetFloorChangeType (sector_t *sec, int change) switch (change & 3) { case 1: - m_NewSpecial = 0; + m_NewSpecial.Clear(); m_Type = DFloor::genFloorChg0; break; case 2: m_Type = DFloor::genFloorChg; break; case 3: - m_NewSpecial = sec->special & ~SECRET_MASK; + sec->GetSpecial(&m_NewSpecial); m_Type = DFloor::genFloorChgT; break; } @@ -438,11 +440,11 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, { FTextureID oldpic = sec->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 { - sec->special &= SECRET_MASK; + sec->ClearSpecial(); } break; @@ -453,8 +455,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, floor->m_Texture = sec->GetTexture(sector_t::floor); // jff 1/24/98 make sure floor->m_NewSpecial gets initialized // in case no surrounding sector is at floordestheight - // --> should not affect compatibility <-- - floor->m_NewSpecial = sec->special & ~SECRET_MASK; + sec->GetSpecial(&floor->m_NewSpecial); //jff 5/23/98 use model subroutine to unify fixes and handling sector_t *modelsec; @@ -462,7 +463,7 @@ bool EV_DoFloor (DFloor::EFloor floortype, line_t *line, int tag, if (modelsec != NULL) { floor->m_Texture = modelsec->GetTexture(sector_t::floor); - floor->m_NewSpecial = modelsec->special & ~SECRET_MASK; + modelsec->GetSpecial(&floor->m_NewSpecial); } 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? tsec = sec->NextSpecialSector ( - (sec->special & 0xff) == Stairs_Special1 ? + sec->special == Stairs_Special1 ? Stairs_Special2 : Stairs_Special1, prev); 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_Speed = slimespeed; floor->m_Texture = s3->GetTexture(sector_t::floor); - floor->m_NewSpecial = 0; + floor->m_NewSpecial.Clear(); height = s3->FindHighestFloorPoint (&spot); floor->m_FloorDestDist = s2->floorplane.PointToDist (spot, height); floor->StartFloorSound (); @@ -1091,7 +1092,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag) if (line) { // [RH] if no line, no change 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; case numChangeOnly: @@ -1099,7 +1100,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag) if (secm) { // if no model, no change sec->SetTexture(sector_t::floor, secm->GetTexture(sector_t::floor)); - sec->special = secm->special; + sec->TransferSpecial(secm); } break; default: diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 203d1688df..b2e27adc87 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1255,8 +1255,7 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, } // end of game hell hack - if ((target->Sector->special & 255) == dDamage_End - && damage >= target->health) + if ((target->Sector->Flags & SECF_ENDLEVEL) && damage >= target->health) { damage = target->health - 1; } diff --git a/src/p_lights.cpp b/src/p_lights.cpp index 49ef130e8a..656b861124 100644 --- a/src/p_lights.cpp +++ b/src/p_lights.cpp @@ -786,12 +786,12 @@ int DPhased::PhaseHelper (sector_t *sector, int index, int light, sector_t *prev l = new DPhased (sector, baselevel); int numsteps = PhaseHelper (sector->NextSpecialSector ( - (sector->special & 0x00ff) == LightSequenceSpecial1 ? + sector->special == LightSequenceSpecial1 ? LightSequenceSpecial2 : LightSequenceSpecial1, prev), index + 1, l->m_BaseLevel, sector); l->m_Phase = ((numsteps - index - 1) * 64) / numsteps; - sector->special &= 0xff00; + sector->special = 0; return numsteps; } @@ -820,7 +820,6 @@ DPhased::DPhased (sector_t *sector, int baselevel, int phase) { m_BaseLevel = baselevel; m_Phase = phase; - sector->special &= 0xff00; } //============================================================================ diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 8fa8691b2e..53090ef186 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1945,6 +1945,9 @@ FUNC(LS_Sector_ChangeFlags) rtn = false; FSectorTagIterator itr(arg0); + // exclude protected flags + arg1 &= ~SECF_NOMODIFY; + arg2 &= ~SECF_NOMODIFY; while ((secNum = itr.Next()) >= 0) { sectors[secNum].Flags = (sectors[secNum].Flags | arg1) & ~arg2; diff --git a/src/p_local.h b/src/p_local.h index 11e6678c1a..63ee4c1b17 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -1,647 +1,647 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// DESCRIPTION: -// Play functions, animation, global header. -// -//----------------------------------------------------------------------------- - - -#ifndef __P_LOCAL__ -#define __P_LOCAL__ - -#include "doomtype.h" -#include "doomdef.h" -#include "tables.h" -#include "r_state.h" -#include "r_utility.h" -#include "d_player.h" - -#include "a_morph.h" - -#include - -#define STEEPSLOPE 46342 // [RH] Minimum floorplane.c value for walking - -#define BONUSADD 6 - -// mapblocks are used to check movement -// against lines and things -#define MAPBLOCKUNITS 128 -#define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT) -#define MAPBLOCKSHIFT (FRACBITS+7) -#define MAPBMASK (MAPBLOCKSIZE-1) -#define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS) - -// Inspired by Maes -extern int bmapnegx; -extern int bmapnegy; - -inline int GetSafeBlockX(int blockx) -{ - blockx >>= MAPBLOCKSHIFT; - return (blockx <= bmapnegx) ? blockx & 0x1FF : blockx; -} -inline int GetSafeBlockX(long long blockx) -{ - blockx >>= MAPBLOCKSHIFT; - return int((blockx <= bmapnegx) ? blockx & 0x1FF : blockx); -} - -inline int GetSafeBlockY(int blocky) -{ - blocky >>= MAPBLOCKSHIFT; - return (blocky <= bmapnegy) ? blocky & 0x1FF: blocky; -} -inline int GetSafeBlockY(long long blocky) -{ - blocky >>= MAPBLOCKSHIFT; - return int((blocky <= bmapnegy) ? blocky & 0x1FF: blocky); -} - -// MAXRADIUS is for precalculated sector block boxes -// the spider demon is larger, -// but we do not have any moving sectors nearby -#define MAXRADIUS 0/*32*FRACUNIT*/ - -//#define GRAVITY FRACUNIT -#define MAXMOVE (30*FRACUNIT) - -#define TALKRANGE (128*FRACUNIT) -#define USERANGE (64*FRACUNIT) -#define MELEERANGE (64*FRACUNIT) -#define MISSILERANGE (32*64*FRACUNIT) -#define PLAYERMISSILERANGE (8192*FRACUNIT) // [RH] New MISSILERANGE for players - -// follow a player exlusively for 3 seconds -#define BASETHRESHOLD 100 - - -// -// P_PSPR -// -void P_SetupPsprites (player_t* curplayer, bool startweaponup); -void P_MovePsprites (player_t* curplayer); -void P_DropWeapon (player_t* player); - - -// -// P_USER -// -void P_FallingDamage (AActor *ent); -void P_PlayerThink (player_t *player); -void P_PredictPlayer (player_t *player); -void P_UnPredictPlayer (); -void P_PredictionLerpReset(); - -// -// P_MOBJ -// - -#define ONFLOORZ FIXED_MIN -#define ONCEILINGZ FIXED_MAX -#define FLOATRANDZ (FIXED_MAX-1) - -#define SPF_TEMPPLAYER 1 // spawning a short-lived dummy player -#define SPF_WEAPONFULLYUP 2 // spawn with weapon already raised - -APlayerPawn *P_SpawnPlayer (struct FPlayerStart *mthing, int playernum, int flags=0); - -void P_ThrustMobj (AActor *mo, angle_t angle, fixed_t move); -int P_FaceMobj (AActor *source, AActor *target, angle_t *delta); -bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool precise = false, bool usecurspeed=false); - -enum EPuffFlags -{ - PF_HITTHING = 1, - PF_MELEERANGE = 2, - PF_TEMPORARY = 4, - PF_HITTHINGBLEED = 8, - PF_NORANDOMZ = 16 -}; - -AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0, AActor *vict = NULL); -void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator); -void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator); -void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator); -void P_RipperBlood (AActor *mo, AActor *bleeder); -int P_GetThingFloorType (AActor *thing); -void P_ExplodeMissile (AActor *missile, line_t *explodeline, AActor *target); - -AActor *P_SpawnMissile (AActor* source, AActor* dest, const PClass *type, AActor* owner = NULL); -AActor *P_SpawnMissileZ (AActor* source, fixed_t z, AActor* dest, const PClass *type); -AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, AActor *source, AActor *dest, const PClass *type, bool checkspawn = true, AActor *owner = NULL); -AActor *P_SpawnMissileAngle (AActor *source, const PClass *type, angle_t angle, fixed_t velz); -AActor *P_SpawnMissileAngleSpeed (AActor *source, const PClass *type, angle_t angle, fixed_t velz, fixed_t speed); -AActor *P_SpawnMissileAngleZ (AActor *source, fixed_t z, const PClass *type, angle_t angle, fixed_t velz); -AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, const PClass *type, angle_t angle, fixed_t velz, fixed_t speed, AActor *owner=NULL, bool checkspawn = true); -AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PClass *type); - -AActor *P_SpawnPlayerMissile (AActor* source, const PClass *type); -AActor *P_SpawnPlayerMissile (AActor *source, const PClass *type, angle_t angle); -AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, const PClass *type, angle_t angle, - AActor **pLineTarget = NULL, AActor **MissileActor = NULL, bool nofreeaim = false, bool noautoaim = false); - -void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheight=false); - -// -// [RH] P_THINGS -// -extern FClassMap SpawnableThings; -extern FClassMap StrifeTypes; - -bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, int newtid); -bool P_Thing_Projectile (int tid, AActor *source, int type, const char * type_name, angle_t angle, - fixed_t speed, fixed_t vspeed, int dest, AActor *forcedest, int gravity, int newtid, - bool leadTarget); -bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog); -bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog); -int P_Thing_Damage (int tid, AActor *whofor0, int amount, FName type); -void P_Thing_SetVelocity(AActor *actor, fixed_t vx, fixed_t vy, fixed_t vz, bool add, bool setbob); -void P_RemoveThing(AActor * actor); -bool P_Thing_Raise(AActor *thing, AActor *raiser); -bool P_Thing_CanRaise(AActor *thing); -const PClass *P_GetSpawnableType(int spawnnum); -void InitSpawnablesFromMapinfo(); -int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags, fixed_t heightoffset, fixed_t radiusoffset, angle_t pitch); - -enum WARPF +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id:$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This source is available for distribution and/or modification +// only under the terms of the DOOM Source Code License as +// published by id Software. All rights reserved. +// +// The source is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License +// for more details. +// +// DESCRIPTION: +// Play functions, animation, global header. +// +//----------------------------------------------------------------------------- + + +#ifndef __P_LOCAL__ +#define __P_LOCAL__ + +#include "doomtype.h" +#include "doomdef.h" +#include "tables.h" +#include "r_state.h" +#include "r_utility.h" +#include "d_player.h" + +#include "a_morph.h" + +#include + +#define STEEPSLOPE 46342 // [RH] Minimum floorplane.c value for walking + +#define BONUSADD 6 + +// mapblocks are used to check movement +// against lines and things +#define MAPBLOCKUNITS 128 +#define MAPBLOCKSIZE (MAPBLOCKUNITS*FRACUNIT) +#define MAPBLOCKSHIFT (FRACBITS+7) +#define MAPBMASK (MAPBLOCKSIZE-1) +#define MAPBTOFRAC (MAPBLOCKSHIFT-FRACBITS) + +// Inspired by Maes +extern int bmapnegx; +extern int bmapnegy; + +inline int GetSafeBlockX(int blockx) { - WARPF_ABSOLUTEOFFSET = 0x1, - WARPF_ABSOLUTEANGLE = 0x2, - WARPF_USECALLERANGLE = 0x4, - - WARPF_NOCHECKPOSITION = 0x8, - - WARPF_INTERPOLATE = 0x10, - WARPF_WARPINTERPOLATION = 0x20, - WARPF_COPYINTERPOLATION = 0x40, - - WARPF_STOP = 0x80, - WARPF_TOFLOOR = 0x100, - WARPF_TESTONLY = 0x200, - WARPF_ABSOLUTEPOSITION = 0x400, - WARPF_BOB = 0x800, - WARPF_MOVEPTR = 0x1000, - WARPF_USEPTR = 0x2000, - WARPF_USETID = 0x2000, - WARPF_COPYVELOCITY = 0x4000, - WARPF_COPYPITCH = 0x8000, + blockx >>= MAPBLOCKSHIFT; + return (blockx <= bmapnegx) ? blockx & 0x1FF : blockx; +} +inline int GetSafeBlockX(long long blockx) +{ + blockx >>= MAPBLOCKSHIFT; + return int((blockx <= bmapnegx) ? blockx & 0x1FF : blockx); +} + +inline int GetSafeBlockY(int blocky) +{ + blocky >>= MAPBLOCKSHIFT; + return (blocky <= bmapnegy) ? blocky & 0x1FF: blocky; +} +inline int GetSafeBlockY(long long blocky) +{ + blocky >>= MAPBLOCKSHIFT; + return int((blocky <= bmapnegy) ? blocky & 0x1FF: blocky); +} + +// MAXRADIUS is for precalculated sector block boxes +// the spider demon is larger, +// but we do not have any moving sectors nearby +#define MAXRADIUS 0/*32*FRACUNIT*/ + +//#define GRAVITY FRACUNIT +#define MAXMOVE (30*FRACUNIT) + +#define TALKRANGE (128*FRACUNIT) +#define USERANGE (64*FRACUNIT) +#define MELEERANGE (64*FRACUNIT) +#define MISSILERANGE (32*64*FRACUNIT) +#define PLAYERMISSILERANGE (8192*FRACUNIT) // [RH] New MISSILERANGE for players + +// follow a player exlusively for 3 seconds +#define BASETHRESHOLD 100 + + +// +// P_PSPR +// +void P_SetupPsprites (player_t* curplayer, bool startweaponup); +void P_MovePsprites (player_t* curplayer); +void P_DropWeapon (player_t* player); + + +// +// P_USER +// +void P_FallingDamage (AActor *ent); +void P_PlayerThink (player_t *player); +void P_PredictPlayer (player_t *player); +void P_UnPredictPlayer (); +void P_PredictionLerpReset(); + +// +// P_MOBJ +// + +#define ONFLOORZ FIXED_MIN +#define ONCEILINGZ FIXED_MAX +#define FLOATRANDZ (FIXED_MAX-1) + +#define SPF_TEMPPLAYER 1 // spawning a short-lived dummy player +#define SPF_WEAPONFULLYUP 2 // spawn with weapon already raised + +APlayerPawn *P_SpawnPlayer (struct FPlayerStart *mthing, int playernum, int flags=0); + +void P_ThrustMobj (AActor *mo, angle_t angle, fixed_t move); +int P_FaceMobj (AActor *source, AActor *target, angle_t *delta); +bool P_SeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax, bool precise = false, bool usecurspeed=false); + +enum EPuffFlags +{ + PF_HITTHING = 1, + PF_MELEERANGE = 2, + PF_TEMPORARY = 4, + PF_HITTHINGBLEED = 8, + PF_NORANDOMZ = 16 }; - - -// -// P_MAPUTL -// -struct divline_t -{ - fixed_t x; - fixed_t y; - fixed_t dx; - fixed_t dy; - -}; - -struct intercept_t -{ - fixed_t frac; // along trace line - bool isaline; - bool done; - union { - AActor *thing; - line_t *line; - } d; -}; - -typedef bool (*traverser_t) (intercept_t *in); - -fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); - -//========================================================================== -// -// P_PointOnLineSide -// -// Returns 0 (front/on) or 1 (back) -// [RH] inlined, stripped down, and made more precise -// -//========================================================================== - -inline int P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line) -{ - extern int P_VanillaPointOnLineSide(fixed_t x, fixed_t y, const line_t* line); - - return i_compatflags2 & COMPATF2_POINTONLINE - ? P_VanillaPointOnLineSide(x, y, line) - : DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy) > 0; -} - -//========================================================================== -// -// P_PointOnDivlineSide -// -// Same as P_PointOnLineSide except it uses divlines -// [RH] inlined, stripped down, and made more precise -// -//========================================================================== - -inline int P_PointOnDivlineSide (fixed_t x, fixed_t y, const divline_t *line) -{ - extern int P_VanillaPointOnDivlineSide(fixed_t x, fixed_t y, const divline_t* line); - - return (i_compatflags2 & COMPATF2_POINTONLINE) - ? P_VanillaPointOnDivlineSide(x, y, line) - : (DMulScale32 (y-line->y, line->dx, line->x-x, line->dy) > 0); -} - -//========================================================================== -// -// P_MakeDivline -// -//========================================================================== - -inline void P_MakeDivline (const line_t *li, divline_t *dl) -{ - dl->x = li->v1->x; - dl->y = li->v1->y; - dl->dx = li->dx; - dl->dy = li->dy; -} - -fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1); - -struct FLineOpening -{ - fixed_t top; - fixed_t bottom; - fixed_t range; - fixed_t lowfloor; - sector_t *bottomsec; - sector_t *topsec; - FTextureID ceilingpic; - FTextureID floorpic; - bool touchmidtex; - bool abovemidtex; -}; - -void P_LineOpening (FLineOpening &open, AActor *thing, const line_t *linedef, fixed_t x, fixed_t y, fixed_t refx=FIXED_MIN, fixed_t refy=0, int flags=0); - -class FBoundingBox; -struct polyblock_t; - -class FBlockLinesIterator -{ - int minx, maxx; - int miny, maxy; - - int curx, cury; - polyblock_t *polyLink; - int polyIndex; - int *list; - - void StartBlock(int x, int y); - -public: - FBlockLinesIterator(int minx, int miny, int maxx, int maxy, bool keepvalidcount = false); - FBlockLinesIterator(const FBoundingBox &box); - line_t *Next(); - void Reset() { StartBlock(minx, miny); } -}; - -class FBlockThingsIterator -{ - int minx, maxx; - int miny, maxy; - - int curx, cury; - - FBlockNode *block; - - int Buckets[32]; - - struct HashEntry - { - AActor *Actor; - int Next; - }; - HashEntry FixedHash[10]; - int NumFixedHash; - TArray DynHash; - - HashEntry *GetHashEntry(int i) { return i < (int)countof(FixedHash) ? &FixedHash[i] : &DynHash[i - countof(FixedHash)]; } - - void StartBlock(int x, int y); - void SwitchBlock(int x, int y); - void ClearHash(); - - // The following is only for use in the path traverser - // and therefore declared private. - FBlockThingsIterator(); - - friend class FPathTraverse; - -public: - FBlockThingsIterator(int minx, int miny, int maxx, int maxy); - FBlockThingsIterator(const FBoundingBox &box); - AActor *Next(bool centeronly = false); - void Reset() { StartBlock(minx, miny); } -}; - -class FPathTraverse -{ - static TArray intercepts; - - divline_t trace; - unsigned int intercept_index; - unsigned int intercept_count; - fixed_t maxfrac; - unsigned int count; - - void AddLineIntercepts(int bx, int by); - void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible); -public: - - intercept_t *Next(); - - FPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags); - ~FPathTraverse(); - const divline_t &Trace() const { return trace; } -}; - - -#define PT_ADDLINES 1 -#define PT_ADDTHINGS 2 -#define PT_COMPATIBLE 4 -#define PT_DELTA 8 // x2,y2 is passed as a delta, not as an endpoint - -AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL); -AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false); - -// -// P_MAP -// - -struct FCheckPosition -{ - // in - AActor *thing; - fixed_t x; - fixed_t y; - fixed_t z; - - // out - sector_t *sector; - fixed_t floorz; - fixed_t ceilingz; - fixed_t dropoffz; - FTextureID floorpic; - sector_t *floorsector; - FTextureID ceilingpic; - sector_t *ceilingsector; - bool touchmidtex; - bool abovemidtex; - bool floatok; - bool FromPMove; - line_t *ceilingline; - AActor *stepthing; - // [RH] These are used by PIT_CheckThing and P_XYMovement to apply - // ripping damage once per tic instead of once per move. - bool DoRipping; - AActor *LastRipped; - int PushTime; - - FCheckPosition(bool rip=false) - { - DoRipping = rip; - LastRipped = NULL; - PushTime = 0; - FromPMove = false; - } -}; - - - -// If "floatok" true, move would be ok -// if within "tmfloorz - tmceilingz". -extern msecnode_t *sector_list; // phares 3/16/98 - -extern TArray spechit; - - -bool P_TestMobjLocation (AActor *mobj); -bool P_TestMobjZ (AActor *mobj, bool quick=true, AActor **pOnmobj = NULL); -bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bool actorsonly=false); -bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, bool actorsonly=false); -AActor *P_CheckOnmobj (AActor *thing); -void P_FakeZMovement (AActor *mo); -bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane_t * onfloor, FCheckPosition &tm, bool missileCheck = false); -bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane_t * onfloor = NULL); -bool P_CheckMove(AActor *thing, fixed_t x, fixed_t y); -void P_ApplyTorque(AActor *mo); -bool P_TeleportMove (AActor* thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag); // [RH] Added z and telefrag parameters -void P_PlayerStartStomp (AActor *actor); // [RH] Stomp on things for a newly spawned player -void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps); -bool P_BounceWall (AActor *mo); -bool P_BounceActor (AActor *mo, AActor *BlockingMobj, bool ontop); -bool P_CheckSight (const AActor *t1, const AActor *t2, int flags=0); - -enum ESightFlags -{ - SF_IGNOREVISIBILITY=1, - SF_SEEPASTSHOOTABLELINES=2, - SF_SEEPASTBLOCKEVERYTHING=4, - SF_IGNOREWATERBOUNDARY=8 -}; - -void P_ResetSightCounters (bool full); -bool P_TalkFacing (AActor *player); -void P_UseLines (player_t* player); -bool P_UsePuzzleItem (AActor *actor, int itemType); - -enum -{ - FFCF_ONLYSPAWNPOS = 1, - FFCF_SAMESECTOR = 2, - FFCF_ONLY3DFLOORS = 4, // includes 3D midtexes - FFCF_3DRESTRICT = 8, // ignore 3D midtexes and floors whose floorz are above thing's z -}; -void P_FindFloorCeiling (AActor *actor, int flags=0); - -bool P_ChangeSector (sector_t* sector, int crunch, int amt, int floorOrCeil, bool isreset); - -fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget = NULL, fixed_t vrange=0, int flags = 0, AActor *target=NULL, AActor *friender=NULL); - -enum // P_AimLineAttack flags -{ - ALF_FORCENOSMART = 1, - ALF_CHECK3D = 2, - ALF_CHECKNONSHOOTABLE = 4, - ALF_CHECKCONVERSATION = 8, - ALF_NOFRIENDS = 16, -}; - -enum // P_LineAttack flags -{ - LAF_ISMELEEATTACK = 1, - LAF_NORANDOMPUFFZ = 2, - LAF_NOIMPACTDECAL = 4 -}; - -AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); -AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); -AActor *P_LinePickActor (AActor *t1, angle_t angle, fixed_t distance, int pitch, ActorFlags actorMask, DWORD wallMask); -void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); -void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch); -void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version -void P_TraceBleed (int damage, AActor *target); // random direction version -bool P_HitFloor (AActor *thing); -bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true); -void P_CheckSplash(AActor *self, fixed_t distance); -void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, const PClass *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, const PClass *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun - -enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags -{ - RAF_SILENT = 1, - RAF_NOPIERCE = 2, - RAF_EXPLICITANGLE = 4, - RAF_FULLBRIGHT = 8, - RAF_CENTERZ = 16, -}; - - -bool P_CheckMissileSpawn (AActor *missile, fixed_t maxdist); -void P_PlaySpawnSound(AActor *missile, AActor *spawner); - -// [RH] Position the chasecam -void P_AimCamera (AActor *t1, fixed_t &x, fixed_t &y, fixed_t &z, sector_t *&sec); - -// [RH] Means of death -enum -{ - RADF_HURTSOURCE = 1, - RADF_NOIMPACTDAMAGE = 2, - RADF_SOURCEISSPOT = 4, - RADF_NODAMAGE = 8, -}; -void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, - FName damageType, int flags, int fulldamagedistance=0); - -void P_DelSector_List(); -void P_DelSeclist(msecnode_t *); // phares 3/16/98 -msecnode_t* P_DelSecnode(msecnode_t *); -void P_CreateSecNodeList(AActor*,fixed_t,fixed_t); // phares 3/14/98 -int P_GetMoveFactor(const AActor *mo, int *frictionp); // phares 3/6/98 -int P_GetFriction(const AActor *mo, int *frictionfactor); -bool Check_Sides(AActor *, int, int); // phares - -// [RH] -const secplane_t * P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymove); - -//---------------------------------------------------------------------------------- -// -// Added so that in the source there's a clear distinction between -// game engine and renderer specific calls. -// (For ZDoom itself this doesn't make any difference here but for GZDoom it does.) -// -//---------------------------------------------------------------------------------- -subsector_t *P_PointInSubsector (fixed_t x, fixed_t y); -inline sector_t *P_PointInSector(fixed_t x, fixed_t y) -{ - return P_PointInSubsector(x,y)->sector; -} - -// -// P_SETUP -// -extern BYTE* rejectmatrix; // for fast sight rejection -extern int* blockmaplump; // offsets in blockmap are from here - -extern int* blockmap; -extern int bmapwidth; -extern int bmapheight; // in mapblocks -extern fixed_t bmaporgx; -extern fixed_t bmaporgy; // origin of block map -extern FBlockNode** blocklinks; // for thing chains - - - -// -// P_INTER -// -void P_TouchSpecialThing (AActor *special, AActor *toucher); -int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0); -void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period, FName type); -bool P_GiveBody (AActor *actor, int num, int max=0); -bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison); -void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound); - -enum EDmgFlags -{ - DMG_NO_ARMOR = 1, - DMG_INFLICTOR_IS_PUFF = 2, - DMG_THRUSTLESS = 4, - DMG_FORCED = 8, - DMG_NO_FACTOR = 16, - DMG_PLAYERATTACK = 32, - DMG_FOILINVUL = 64, - DMG_FOILBUDDHA = 128, - DMG_NO_PROTECT = 256, -}; - - -// ===== PO_MAN ===== - -typedef enum -{ - PODOOR_NONE, - PODOOR_SLIDE, - PODOOR_SWING, -} podoortype_t; - -bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle, int direction, bool overRide); -bool EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle, fixed_t dist, bool overRide); -bool EV_MovePolyTo (line_t *line, int polyNum, int speed, fixed_t x, fixed_t y, bool overRide); -bool EV_OpenPolyDoor (line_t *line, int polyNum, int speed, angle_t angle, int delay, int distance, podoortype_t type); -bool EV_StopPoly (int polyNum); - - -// [RH] Data structure for P_SpawnMapThing() to keep track -// of polyobject-related things. -struct polyspawns_t -{ - polyspawns_t *next; - fixed_t x; - fixed_t y; - short angle; - short type; -}; - -extern int po_NumPolyobjs; -extern polyspawns_t *polyspawns; // [RH] list of polyobject things to spawn - - -void PO_Init (); -bool PO_Busy (int polyobj); -FPolyObj *PO_GetPolyobj(int polyNum); - -// -// P_SPEC -// -#include "p_spec.h" - -bool P_AlignFlat (int linenum, int side, int fc); - -#endif // __P_LOCAL__ +AActor *P_SpawnPuff (AActor *source, const PClass *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0, AActor *vict = NULL); +void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator); +void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator); +void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator); +void P_RipperBlood (AActor *mo, AActor *bleeder); +int P_GetThingFloorType (AActor *thing); +void P_ExplodeMissile (AActor *missile, line_t *explodeline, AActor *target); + +AActor *P_SpawnMissile (AActor* source, AActor* dest, const PClass *type, AActor* owner = NULL); +AActor *P_SpawnMissileZ (AActor* source, fixed_t z, AActor* dest, const PClass *type); +AActor *P_SpawnMissileXYZ (fixed_t x, fixed_t y, fixed_t z, AActor *source, AActor *dest, const PClass *type, bool checkspawn = true, AActor *owner = NULL); +AActor *P_SpawnMissileAngle (AActor *source, const PClass *type, angle_t angle, fixed_t velz); +AActor *P_SpawnMissileAngleSpeed (AActor *source, const PClass *type, angle_t angle, fixed_t velz, fixed_t speed); +AActor *P_SpawnMissileAngleZ (AActor *source, fixed_t z, const PClass *type, angle_t angle, fixed_t velz); +AActor *P_SpawnMissileAngleZSpeed (AActor *source, fixed_t z, const PClass *type, angle_t angle, fixed_t velz, fixed_t speed, AActor *owner=NULL, bool checkspawn = true); +AActor *P_SpawnMissileZAimed (AActor *source, fixed_t z, AActor *dest, const PClass *type); + +AActor *P_SpawnPlayerMissile (AActor* source, const PClass *type); +AActor *P_SpawnPlayerMissile (AActor *source, const PClass *type, angle_t angle); +AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, const PClass *type, angle_t angle, + AActor **pLineTarget = NULL, AActor **MissileActor = NULL, bool nofreeaim = false, bool noautoaim = false); + +void P_CheckFakeFloorTriggers (AActor *mo, fixed_t oldz, bool oldz_has_viewheight=false); + +// +// [RH] P_THINGS +// +extern FClassMap SpawnableThings; +extern FClassMap StrifeTypes; + +bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, int newtid); +bool P_Thing_Projectile (int tid, AActor *source, int type, const char * type_name, angle_t angle, + fixed_t speed, fixed_t vspeed, int dest, AActor *forcedest, int gravity, int newtid, + bool leadTarget); +bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog); +bool P_Thing_Move (int tid, AActor *source, int mapspot, bool fog); +int P_Thing_Damage (int tid, AActor *whofor0, int amount, FName type); +void P_Thing_SetVelocity(AActor *actor, fixed_t vx, fixed_t vy, fixed_t vz, bool add, bool setbob); +void P_RemoveThing(AActor * actor); +bool P_Thing_Raise(AActor *thing, AActor *raiser); +bool P_Thing_CanRaise(AActor *thing); +const PClass *P_GetSpawnableType(int spawnnum); +void InitSpawnablesFromMapinfo(); +int P_Thing_Warp(AActor *caller, AActor *reference, fixed_t xofs, fixed_t yofs, fixed_t zofs, angle_t angle, int flags, fixed_t heightoffset, fixed_t radiusoffset, angle_t pitch); + +enum WARPF +{ + WARPF_ABSOLUTEOFFSET = 0x1, + WARPF_ABSOLUTEANGLE = 0x2, + WARPF_USECALLERANGLE = 0x4, + + WARPF_NOCHECKPOSITION = 0x8, + + WARPF_INTERPOLATE = 0x10, + WARPF_WARPINTERPOLATION = 0x20, + WARPF_COPYINTERPOLATION = 0x40, + + WARPF_STOP = 0x80, + WARPF_TOFLOOR = 0x100, + WARPF_TESTONLY = 0x200, + WARPF_ABSOLUTEPOSITION = 0x400, + WARPF_BOB = 0x800, + WARPF_MOVEPTR = 0x1000, + WARPF_USEPTR = 0x2000, + WARPF_USETID = 0x2000, + WARPF_COPYVELOCITY = 0x4000, + WARPF_COPYPITCH = 0x8000, +}; + + + +// +// P_MAPUTL +// +struct divline_t +{ + fixed_t x; + fixed_t y; + fixed_t dx; + fixed_t dy; + +}; + +struct intercept_t +{ + fixed_t frac; // along trace line + bool isaline; + bool done; + union { + AActor *thing; + line_t *line; + } d; +}; + +typedef bool (*traverser_t) (intercept_t *in); + +fixed_t P_AproxDistance (fixed_t dx, fixed_t dy); + +//========================================================================== +// +// P_PointOnLineSide +// +// Returns 0 (front/on) or 1 (back) +// [RH] inlined, stripped down, and made more precise +// +//========================================================================== + +inline int P_PointOnLineSide (fixed_t x, fixed_t y, const line_t *line) +{ + extern int P_VanillaPointOnLineSide(fixed_t x, fixed_t y, const line_t* line); + + return i_compatflags2 & COMPATF2_POINTONLINE + ? P_VanillaPointOnLineSide(x, y, line) + : DMulScale32 (y-line->v1->y, line->dx, line->v1->x-x, line->dy) > 0; +} + +//========================================================================== +// +// P_PointOnDivlineSide +// +// Same as P_PointOnLineSide except it uses divlines +// [RH] inlined, stripped down, and made more precise +// +//========================================================================== + +inline int P_PointOnDivlineSide (fixed_t x, fixed_t y, const divline_t *line) +{ + extern int P_VanillaPointOnDivlineSide(fixed_t x, fixed_t y, const divline_t* line); + + return (i_compatflags2 & COMPATF2_POINTONLINE) + ? P_VanillaPointOnDivlineSide(x, y, line) + : (DMulScale32 (y-line->y, line->dx, line->x-x, line->dy) > 0); +} + +//========================================================================== +// +// P_MakeDivline +// +//========================================================================== + +inline void P_MakeDivline (const line_t *li, divline_t *dl) +{ + dl->x = li->v1->x; + dl->y = li->v1->y; + dl->dx = li->dx; + dl->dy = li->dy; +} + +fixed_t P_InterceptVector (const divline_t *v2, const divline_t *v1); + +struct FLineOpening +{ + fixed_t top; + fixed_t bottom; + fixed_t range; + fixed_t lowfloor; + sector_t *bottomsec; + sector_t *topsec; + FTextureID ceilingpic; + FTextureID floorpic; + bool touchmidtex; + bool abovemidtex; +}; + +void P_LineOpening (FLineOpening &open, AActor *thing, const line_t *linedef, fixed_t x, fixed_t y, fixed_t refx=FIXED_MIN, fixed_t refy=0, int flags=0); + +class FBoundingBox; +struct polyblock_t; + +class FBlockLinesIterator +{ + int minx, maxx; + int miny, maxy; + + int curx, cury; + polyblock_t *polyLink; + int polyIndex; + int *list; + + void StartBlock(int x, int y); + +public: + FBlockLinesIterator(int minx, int miny, int maxx, int maxy, bool keepvalidcount = false); + FBlockLinesIterator(const FBoundingBox &box); + line_t *Next(); + void Reset() { StartBlock(minx, miny); } +}; + +class FBlockThingsIterator +{ + int minx, maxx; + int miny, maxy; + + int curx, cury; + + FBlockNode *block; + + int Buckets[32]; + + struct HashEntry + { + AActor *Actor; + int Next; + }; + HashEntry FixedHash[10]; + int NumFixedHash; + TArray DynHash; + + HashEntry *GetHashEntry(int i) { return i < (int)countof(FixedHash) ? &FixedHash[i] : &DynHash[i - countof(FixedHash)]; } + + void StartBlock(int x, int y); + void SwitchBlock(int x, int y); + void ClearHash(); + + // The following is only for use in the path traverser + // and therefore declared private. + FBlockThingsIterator(); + + friend class FPathTraverse; + +public: + FBlockThingsIterator(int minx, int miny, int maxx, int maxy); + FBlockThingsIterator(const FBoundingBox &box); + AActor *Next(bool centeronly = false); + void Reset() { StartBlock(minx, miny); } +}; + +class FPathTraverse +{ + static TArray intercepts; + + divline_t trace; + unsigned int intercept_index; + unsigned int intercept_count; + fixed_t maxfrac; + unsigned int count; + + void AddLineIntercepts(int bx, int by); + void AddThingIntercepts(int bx, int by, FBlockThingsIterator &it, bool compatible); +public: + + intercept_t *Next(); + + FPathTraverse(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2, int flags); + ~FPathTraverse(); + const divline_t &Trace() const { return trace; } +}; + + +#define PT_ADDLINES 1 +#define PT_ADDTHINGS 2 +#define PT_COMPATIBLE 4 +#define PT_DELTA 8 // x2,y2 is passed as a delta, not as an endpoint + +AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL); +AActor *P_RoughMonsterSearch (AActor *mo, int distance, bool onlyseekable=false); + +// +// P_MAP +// + +struct FCheckPosition +{ + // in + AActor *thing; + fixed_t x; + fixed_t y; + fixed_t z; + + // out + sector_t *sector; + fixed_t floorz; + fixed_t ceilingz; + fixed_t dropoffz; + FTextureID floorpic; + sector_t *floorsector; + FTextureID ceilingpic; + sector_t *ceilingsector; + bool touchmidtex; + bool abovemidtex; + bool floatok; + bool FromPMove; + line_t *ceilingline; + AActor *stepthing; + // [RH] These are used by PIT_CheckThing and P_XYMovement to apply + // ripping damage once per tic instead of once per move. + bool DoRipping; + AActor *LastRipped; + int PushTime; + + FCheckPosition(bool rip=false) + { + DoRipping = rip; + LastRipped = NULL; + PushTime = 0; + FromPMove = false; + } +}; + + + +// If "floatok" true, move would be ok +// if within "tmfloorz - tmceilingz". +extern msecnode_t *sector_list; // phares 3/16/98 + +extern TArray spechit; + + +bool P_TestMobjLocation (AActor *mobj); +bool P_TestMobjZ (AActor *mobj, bool quick=true, AActor **pOnmobj = NULL); +bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, FCheckPosition &tm, bool actorsonly=false); +bool P_CheckPosition (AActor *thing, fixed_t x, fixed_t y, bool actorsonly=false); +AActor *P_CheckOnmobj (AActor *thing); +void P_FakeZMovement (AActor *mo); +bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane_t * onfloor, FCheckPosition &tm, bool missileCheck = false); +bool P_TryMove (AActor* thing, fixed_t x, fixed_t y, int dropoff, const secplane_t * onfloor = NULL); +bool P_CheckMove(AActor *thing, fixed_t x, fixed_t y); +void P_ApplyTorque(AActor *mo); +bool P_TeleportMove (AActor* thing, fixed_t x, fixed_t y, fixed_t z, bool telefrag); // [RH] Added z and telefrag parameters +void P_PlayerStartStomp (AActor *actor); // [RH] Stomp on things for a newly spawned player +void P_SlideMove (AActor* mo, fixed_t tryx, fixed_t tryy, int numsteps); +bool P_BounceWall (AActor *mo); +bool P_BounceActor (AActor *mo, AActor *BlockingMobj, bool ontop); +bool P_CheckSight (const AActor *t1, const AActor *t2, int flags=0); + +enum ESightFlags +{ + SF_IGNOREVISIBILITY=1, + SF_SEEPASTSHOOTABLELINES=2, + SF_SEEPASTBLOCKEVERYTHING=4, + SF_IGNOREWATERBOUNDARY=8 +}; + +void P_ResetSightCounters (bool full); +bool P_TalkFacing (AActor *player); +void P_UseLines (player_t* player); +bool P_UsePuzzleItem (AActor *actor, int itemType); + +enum +{ + FFCF_ONLYSPAWNPOS = 1, + FFCF_SAMESECTOR = 2, + FFCF_ONLY3DFLOORS = 4, // includes 3D midtexes + FFCF_3DRESTRICT = 8, // ignore 3D midtexes and floors whose floorz are above thing's z +}; +void P_FindFloorCeiling (AActor *actor, int flags=0); + +bool P_ChangeSector (sector_t* sector, int crunch, int amt, int floorOrCeil, bool isreset); + +fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, AActor **pLineTarget = NULL, fixed_t vrange=0, int flags = 0, AActor *target=NULL, AActor *friender=NULL); + +enum // P_AimLineAttack flags +{ + ALF_FORCENOSMART = 1, + ALF_CHECK3D = 2, + ALF_CHECKNONSHOOTABLE = 4, + ALF_CHECKCONVERSATION = 8, + ALF_NOFRIENDS = 16, +}; + +enum // P_LineAttack flags +{ + LAF_ISMELEEATTACK = 1, + LAF_NORANDOMPUFFZ = 2, + LAF_NOIMPACTDECAL = 4 +}; + +AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); +AActor *P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype, int flags = 0, AActor **victim = NULL, int *actualdamage = NULL); +AActor *P_LinePickActor (AActor *t1, angle_t angle, fixed_t distance, int pitch, ActorFlags actorMask, DWORD wallMask); +void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); +void P_TraceBleed (int damage, AActor *target, angle_t angle, int pitch); +void P_TraceBleed (int damage, AActor *target, AActor *missile); // missile version +void P_TraceBleed (int damage, AActor *target); // random direction version +bool P_HitFloor (AActor *thing); +bool P_HitWater (AActor *thing, sector_t *sec, fixed_t splashx = FIXED_MIN, fixed_t splashy = FIXED_MIN, fixed_t splashz=FIXED_MIN, bool checkabove = false, bool alert = true, bool force = false); +void P_CheckSplash(AActor *self, fixed_t distance); +void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, const PClass *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, const PClass *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun + +enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags +{ + RAF_SILENT = 1, + RAF_NOPIERCE = 2, + RAF_EXPLICITANGLE = 4, + RAF_FULLBRIGHT = 8, + RAF_CENTERZ = 16, +}; + + +bool P_CheckMissileSpawn (AActor *missile, fixed_t maxdist); +void P_PlaySpawnSound(AActor *missile, AActor *spawner); + +// [RH] Position the chasecam +void P_AimCamera (AActor *t1, fixed_t &x, fixed_t &y, fixed_t &z, sector_t *&sec); + +// [RH] Means of death +enum +{ + RADF_HURTSOURCE = 1, + RADF_NOIMPACTDAMAGE = 2, + RADF_SOURCEISSPOT = 4, + RADF_NODAMAGE = 8, +}; +void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, + FName damageType, int flags, int fulldamagedistance=0); + +void P_DelSector_List(); +void P_DelSeclist(msecnode_t *); // phares 3/16/98 +msecnode_t* P_DelSecnode(msecnode_t *); +void P_CreateSecNodeList(AActor*,fixed_t,fixed_t); // phares 3/14/98 +int P_GetMoveFactor(const AActor *mo, int *frictionp); // phares 3/6/98 +int P_GetFriction(const AActor *mo, int *frictionfactor); +bool Check_Sides(AActor *, int, int); // phares + +// [RH] +const secplane_t * P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymove); + +//---------------------------------------------------------------------------------- +// +// Added so that in the source there's a clear distinction between +// game engine and renderer specific calls. +// (For ZDoom itself this doesn't make any difference here but for GZDoom it does.) +// +//---------------------------------------------------------------------------------- +subsector_t *P_PointInSubsector (fixed_t x, fixed_t y); +inline sector_t *P_PointInSector(fixed_t x, fixed_t y) +{ + return P_PointInSubsector(x,y)->sector; +} + +// +// P_SETUP +// +extern BYTE* rejectmatrix; // for fast sight rejection +extern int* blockmaplump; // offsets in blockmap are from here + +extern int* blockmap; +extern int bmapwidth; +extern int bmapheight; // in mapblocks +extern fixed_t bmaporgx; +extern fixed_t bmaporgy; // origin of block map +extern FBlockNode** blocklinks; // for thing chains + + + +// +// P_INTER +// +void P_TouchSpecialThing (AActor *special, AActor *toucher); +int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags=0); +void P_PoisonMobj (AActor *target, AActor *inflictor, AActor *source, int damage, int duration, int period, FName type); +bool P_GiveBody (AActor *actor, int num, int max=0); +bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poison); +void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPainSound); + +enum EDmgFlags +{ + DMG_NO_ARMOR = 1, + DMG_INFLICTOR_IS_PUFF = 2, + DMG_THRUSTLESS = 4, + DMG_FORCED = 8, + DMG_NO_FACTOR = 16, + DMG_PLAYERATTACK = 32, + DMG_FOILINVUL = 64, + DMG_FOILBUDDHA = 128, + DMG_NO_PROTECT = 256, +}; + + +// ===== PO_MAN ===== + +typedef enum +{ + PODOOR_NONE, + PODOOR_SLIDE, + PODOOR_SWING, +} podoortype_t; + +bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle, int direction, bool overRide); +bool EV_MovePoly (line_t *line, int polyNum, int speed, angle_t angle, fixed_t dist, bool overRide); +bool EV_MovePolyTo (line_t *line, int polyNum, int speed, fixed_t x, fixed_t y, bool overRide); +bool EV_OpenPolyDoor (line_t *line, int polyNum, int speed, angle_t angle, int delay, int distance, podoortype_t type); +bool EV_StopPoly (int polyNum); + + +// [RH] Data structure for P_SpawnMapThing() to keep track +// of polyobject-related things. +struct polyspawns_t +{ + polyspawns_t *next; + fixed_t x; + fixed_t y; + short angle; + short type; +}; + +extern int po_NumPolyobjs; +extern polyspawns_t *polyspawns; // [RH] list of polyobject things to spawn + + +void PO_Init (); +bool PO_Busy (int polyobj); +FPolyObj *PO_GetPolyobj(int polyNum); + +// +// P_SPEC +// +#include "p_spec.h" + +bool P_AlignFlat (int linenum, int side, int fc); + +#endif // __P_LOCAL__ diff --git a/src/p_map.cpp b/src/p_map.cpp index 5dd0967b9e..f409dafa48 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -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) { continue; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index bc314dc0e0..48f16ba0ef 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3452,7 +3452,7 @@ void AActor::Tick () if (player != NULL) { - int scrolltype = sec->special & 0xff; + int scrolltype = sec->special; if (scrolltype >= Scroll_North_Slow && scrolltype <= Scroll_SouthWest_Fast) @@ -4424,7 +4424,7 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags) ( gameaction != ga_worlddone ) && ( p->mo != NULL ) && ( !(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_y = p->mo->y; @@ -5320,7 +5320,7 @@ int P_GetThingFloorType (AActor *thing) // 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) return false; @@ -5362,24 +5362,27 @@ bool P_HitWater (AActor * thing, sector_t * sec, fixed_t x, fixed_t y, fixed_t z } #endif - for(unsigned int i=0;ie->XFloor.ffloors.Size();i++) - { - 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 + if (!force) + { + for (unsigned int i = 0; ie->XFloor.ffloors.Size(); i++) { - 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]; - goto foundone; + if (rover->flags & (FF_SOLID | FF_SWIMMABLE)) + { + 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(); - if (hsec == NULL || !(hsec->MoreFlags & SECF_CLIPFAKEPLANES)) + if (force || hsec == NULL || !(hsec->MoreFlags & SECF_CLIPFAKEPLANES)) { terrainnum = TerrainTypes[sec->GetTexture(sector_t::floor)]; } @@ -5403,7 +5406,7 @@ foundone: // Don't splash for living things with small vertical velocities. // 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; splash = &Splashes[splashnum]; diff --git a/src/p_pillar.cpp b/src/p_pillar.cpp index 884218bee7..b1cae3af9b 100644 --- a/src/p_pillar.cpp +++ b/src/p_pillar.cpp @@ -198,17 +198,20 @@ DPillar::DPillar (sector_t *sector, EPillar type, fixed_t speed, 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); - } - else if (sector->SeqName != NAME_None) - { - SN_StartSequence (sector, CHAN_FLOOR, sector->SeqName, 0); - } - else - { - SN_StartSequence (sector, CHAN_FLOOR, "Floor", 0); + if (sector->seqType >= 0) + { + SN_StartSequence(sector, CHAN_FLOOR, sector->seqType, SEQ_PLATFORM, 0); + } + else if (sector->SeqName != NAME_None) + { + SN_StartSequence(sector, CHAN_FLOOR, sector->SeqName, 0); + } + else + { + SN_StartSequence(sector, CHAN_FLOOR, "Floor", 0); + } } } diff --git a/src/p_plats.cpp b/src/p_plats.cpp index 7600637b2f..b0697fc34b 100644 --- a/src/p_plats.cpp +++ b/src/p_plats.cpp @@ -72,6 +72,8 @@ void DPlat::Serialize (FArchive &arc) void DPlat::PlayPlatSound (const char *sound) { + if (m_Sector->Flags & SECF_SILENTMOVE) return; + if (m_Sector->seqType >= 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) sec->SetTexture(sector_t::floor, line->sidedef[0]->sector->GetTexture(sector_t::floor)); - if (change == 1) - sec->special &= SECRET_MASK; // Stop damage and other stuff, if any + if (change == 1) sec->ClearSpecial(); } 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_Status = DPlat::up; plat->PlayPlatSound ("Floor"); - sec->special &= SECRET_MASK; // NO MORE DAMAGE, IF APPLICABLE + sec->ClearSpecial(); break; case DPlat::platUpByValue: diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index cce594ead5..f3c3588f81 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -368,8 +368,17 @@ void P_SerializeWorld (FArchive &arc) << sec->planes[sector_t::ceiling] << sec->heightsec << sec->bottommap << sec->midmap << sec->topmap - << sec->gravity - << sec->damageamount; + << sec->gravity; + if (SaveVersion >= 4529) + { + arc << sec->damageamount; + } + else + { + short dmg; + arc << dmg; + sec->damageamount = dmg; + } if (SaveVersion >= 4528) { arc << sec->damageinterval @@ -398,15 +407,22 @@ void P_SerializeWorld (FArchive &arc) } } - arc << sec->SoundTarget + arc << sec->SoundTarget << sec->SecActTarget << sec->sky << sec->MoreFlags << sec->Flags << sec->FloorSkyBox << sec->CeilingSkyBox - << sec->ZoneNumber - << sec->secretsector - << sec->interpolations[0] + << sec->ZoneNumber; + if (SaveVersion < 4529) + { + 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[2] << sec->interpolations[3] diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 361b220a7d..321ecdd37f 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -49,7 +49,7 @@ sector_t *sector_t::NextSpecialSector (int type, sector_t *nogood) const if (NULL != (tsec = getNextSector (ln, this)) && tsec != nogood && - (tsec->special & 0x00ff) == type) + tsec->special == type) { 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 copy = false; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 50e7f41d6f..7726792696 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1512,7 +1512,6 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex) ss->special = LittleShort(ms->special); else // [RH] Translate to new sector special ss->special = P_TranslateSectorSpecial (LittleShort(ms->special)); - ss->secretsector = !!(ss->special&SECRET_MASK); tagManager.AddSectorTag(i, LittleShort(ms->tag)); ss->thinglist = NULL; 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->Sector->special == dDamage_End) + if (mo->Sector->damageamount > 0 && (mo->Sector->Flags & (SECF_ENDGODMODE|SECF_ENDLEVEL)) == (SECF_ENDGODMODE|SECF_ENDLEVEL)) { mo->ClearCounters(); } diff --git a/src/p_spec.cpp b/src/p_spec.cpp index c439ac50ea..918d07ed2e 100644 --- a/src/p_spec.cpp +++ b/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. 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 - 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)); } } @@ -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 // @@ -1187,135 +1318,7 @@ void P_SpawnSpecials (void) if (sector->special == 0) continue; - // [RH] All secret sectors are marked with a BOOM-ish bitfield - 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; - } + P_InitSectorSpecial(sector, sector->special, false); } // Init other misc stuff @@ -2056,11 +2059,11 @@ void P_SetSectorFriction (int tag, int amount, bool alterFlag) // can be enabled and disabled at will. if (friction == ORIG_FRICTION) { - sectors[s].special &= ~FRICTION_MASK; + sectors[s].Flags &= ~SECF_FRICTION; } 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. // Else, bail out; the sector type has been changed on us. - if (!(sec->special & PUSH_MASK)) + if (!(sec->Flags & SECF_PUSH)) return; // For constant pushers (wind/current) there are 3 situations: diff --git a/src/p_spec.h b/src/p_spec.h index 0c3ee87450..a95e07ce8b 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -158,6 +158,7 @@ bool PIT_PushThing (AActor *thing); bool CheckIfExitIsGood (AActor *self, level_info_t *info); // at map load +void P_InitSectorSpecial(sector_t *sector, int special, bool nothinkers); void P_SpawnSpecials (void); // every tic @@ -673,7 +674,7 @@ protected: // [RH] Need these for BOOM-ish transferring ceilings FTextureID m_Texture; - int m_NewSpecial; + secspecial_t m_NewSpecial; // ID int m_Tag; @@ -760,7 +761,7 @@ protected: int m_Crush; bool m_Hexencrush; int m_Direction; - int m_NewSpecial; + secspecial_t m_NewSpecial; FTextureID m_Texture; fixed_t m_FloorDestDist; fixed_t m_Speed; diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 2169da49fa..e95193860c 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1542,6 +1542,14 @@ public: sec->leakydamage = CheckInt(key); break; + case NAME_damageterraineffect: + Flag(sec->Flags, SECF_DMGTERRAINFX, key); + break; + + case NAME_damagehazard: + Flag(sec->Flags, SECF_HAZARD, key); + break; + case NAME_MoreIds: // 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. @@ -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. if (fplaneflags != 15) @@ -1612,10 +1628,10 @@ public: { // [RH] Sectors default to white light with the default fade. // 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) - fogMap = GetSpecialLights (PalEntry (255,255,255), level.outsidefog, 0); + fogMap = GetSpecialLights(PalEntry(255, 255, 255), level.outsidefog, 0); sec->ColorMap = fogMap; } else @@ -1628,9 +1644,9 @@ public: else { 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; else fadecolor = level.fadeto; diff --git a/src/p_user.cpp b/src/p_user.cpp index 8f8a93fdb2..ba987d3930 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -362,6 +362,8 @@ player_t &player_t::operator=(const player_t &p) damagecount = p.damagecount; bonuscount = p.bonuscount; hazardcount = p.hazardcount; + hazardtype = p.hazardtype; + hazardinterval = p.hazardinterval; poisoncount = p.poisoncount; poisontype = p.poisontype; poisonpaintype = p.poisonpaintype; @@ -2538,10 +2540,8 @@ void P_PlayerThink (player_t *player) if (!(player->cheats & CF_PREDICTING)) { 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( player->mo->x, player->mo->y) || player->mo->waterlevel) @@ -2600,8 +2600,8 @@ void P_PlayerThink (player_t *player) if (player->hazardcount) { player->hazardcount--; - if (!(level.time & 31) && player->hazardcount > 16*TICRATE) - P_DamageMobj (player->mo, NULL, NULL, 5, NAME_Slime); + if (!(level.time % player->hazardinterval) && player->hazardcount > 16*TICRATE) + P_DamageMobj (player->mo, NULL, NULL, 5, player->hazardtype); } if (player->poisoncount && !(level.time & 15)) @@ -3014,7 +3014,12 @@ void player_t::Serialize (FArchive &arc) << air_finished << turnticks << oldbuttons; - bool IsBot; + if (SaveVersion >= 4929) + { + arc << hazardtype + << hazardinterval; + } + bool IsBot = false; if (SaveVersion >= 4514) { arc << Bot; diff --git a/src/r_defs.h b/src/r_defs.h index 385cb34786..5a3e0adaf2 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -392,6 +392,20 @@ enum 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_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 @@ -466,6 +480,23 @@ struct FTransform 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 { // Member functions @@ -695,7 +726,35 @@ struct sector_t 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); @@ -764,7 +823,7 @@ struct sector_t float gravity; // [RH] Sector gravity (1.0 is normal) 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 leakydamage; // chance of leaking through radiation suit @@ -782,7 +841,6 @@ struct sector_t // regular sky. TObjPtr FloorSkyBox, CeilingSkyBox; - short secretsector; //jff 2/16/98 remembers if sector WAS secret (automap) 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. diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp index 9f50b41555..667de88421 100644 --- a/src/sound/music_midi_timidity.cpp +++ b/src/sound/music_midi_timidity.cpp @@ -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 if (self < 4000) self = 4000; diff --git a/src/version.h b/src/version.h index 638c3a5654..ef407490ea 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4528 +#define SAVEVER 4529 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) diff --git a/wadsrc/static/filter/doom.freedoom/decaldef.z b/wadsrc/static/filter/doom.freedoom/decaldef.z new file mode 100644 index 0000000000..68b85a8485 --- /dev/null +++ b/wadsrc/static/filter/doom.freedoom/decaldef.z @@ -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 +} + diff --git a/wadsrc/static/mapinfo/doom2bfg.txt b/wadsrc/static/mapinfo/doom2bfg.txt index cc82c4e191..28bea129d7 100644 --- a/wadsrc/static/mapinfo/doom2bfg.txt +++ b/wadsrc/static/mapinfo/doom2bfg.txt @@ -3,7 +3,7 @@ include "mapinfo/doom2.txt" gameinfo { - titlepage = "INTERPIC" + titlepage = "DMENUPIC" } clearepisodes