From 745b147d185f38d710649c61aceac68a93fbbc3e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 15 Apr 2014 16:40:53 +0200 Subject: [PATCH 01/11] - fixed typo in xlat files (they don't use exactly C syntax.) --- wadsrc/static/xlat/defines.i | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/xlat/defines.i b/wadsrc/static/xlat/defines.i index 0acc2465e5..04c8b21cc5 100644 --- a/wadsrc/static/xlat/defines.i +++ b/wadsrc/static/xlat/defines.i @@ -240,5 +240,5 @@ enum // ML_PASSTHROUGH = -1, ML_TRANSLUCENT = -2, - ML_TRANSPARENT = -3, + ML_TRANSPARENT = -3 } \ No newline at end of file From e5578934ad711fa2e38369f1bbe9e1eb36fc191e Mon Sep 17 00:00:00 2001 From: Gaerzi Date: Tue, 15 Apr 2014 17:16:33 +0200 Subject: [PATCH 02/11] Init new non-0 fields for non-UDMF maps. --- src/p_mobj.cpp | 3 --- src/p_setup.cpp | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 291f51a946..2a26d7ef0f 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4795,10 +4795,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) // Set various UDMF options if (mthing->alpha != -1) - { - DPrintf("Setting alpha to %f", FIXED2FLOAT(mthing->alpha)); mobj->alpha = mthing->alpha; - } if (mthing->RenderStyle != STYLE_Count) mobj->RenderStyle = (ERenderStyle)mthing->RenderStyle; if (mthing->scaleX) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 315da4ffcc..b2d007f970 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1764,6 +1764,9 @@ void P_LoadThings (MapData * map) mti[i].Conversation = 0; mti[i].SkillFilter = MakeSkill(flags); mti[i].ClassFilter = 0xffff; // Doom map format doesn't have class flags so spawn for all player classes + mti[i].RenderStyle = STYLE_Count; + mti[i].alpha = -1; + mti[i].health = 1; flags &= ~MTF_SKILLMASK; mti[i].flags = (short)((flags & 0xf) | 0x7e0); if (gameinfo.gametype == GAME_Strife) From 8e3360453fa5d90cbfda05e28817060d8f98dde3 Mon Sep 17 00:00:00 2001 From: Gaerzi Date: Tue, 15 Apr 2014 17:18:55 +0200 Subject: [PATCH 03/11] Hexen too. --- src/p_setup.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index b2d007f970..f56d761f2b 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1840,6 +1840,9 @@ void P_LoadThings2 (MapData * map) mti[i].flags &= ~(MTF_SKILLMASK|MTF_CLASS_MASK); mti[i].Conversation = 0; mti[i].gravity = FRACUNIT; + mti[i].RenderStyle = STYLE_Count; + mti[i].alpha = -1; + mti[i].health = 1; } delete[] mtp; } From 6f2fd8edbfec14a62a6a96ddf3b1050ab3ad9bcb Mon Sep 17 00:00:00 2001 From: Gaerzi Date: Tue, 15 Apr 2014 17:22:56 +0200 Subject: [PATCH 04/11] Hexen also needs to init 0 fields. --- src/p_setup.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index f56d761f2b..c14fcdec0c 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1843,6 +1843,7 @@ void P_LoadThings2 (MapData * map) mti[i].RenderStyle = STYLE_Count; mti[i].alpha = -1; mti[i].health = 1; + mti[i].fillcolor = 0 = mti[i].scaleX = mti[i].scaleY = mti[i].score = 0; } delete[] mtp; } From c54f5571ea174c19022354eb35dd3704d08f5ac8 Mon Sep 17 00:00:00 2001 From: Gaerzi Date: Tue, 15 Apr 2014 17:24:01 +0200 Subject: [PATCH 05/11] Typo. --- src/p_setup.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index c14fcdec0c..77b9b077b7 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1843,7 +1843,7 @@ void P_LoadThings2 (MapData * map) mti[i].RenderStyle = STYLE_Count; mti[i].alpha = -1; mti[i].health = 1; - mti[i].fillcolor = 0 = mti[i].scaleX = mti[i].scaleY = mti[i].score = 0; + mti[i].fillcolor = mti[i].scaleX = mti[i].scaleY = mti[i].score = 0; } delete[] mtp; } From 83182b703de94b7645026db155e979bf0535d778 Mon Sep 17 00:00:00 2001 From: Gaerzi Date: Tue, 15 Apr 2014 21:01:49 +0200 Subject: [PATCH 06/11] Added slow monsters, the inverse of fast monsters This is a skill setting only, no "always slow" or "never slow" actor flags, and no DM flags. --- src/actor.h | 1 + src/g_level.h | 2 ++ src/g_skill.cpp | 9 +++++++++ src/info.h | 1 + src/p_mobj.cpp | 11 ++++++++++- src/thingdef/thingdef_states.cpp | 5 +++++ 6 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/actor.h b/src/actor.h index d3cba00411..21057d86c3 100644 --- a/src/actor.h +++ b/src/actor.h @@ -1008,6 +1008,7 @@ public: bool SetState (FState *newstate, bool nofunction=false); virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true); bool isFast(); + bool isSlow(); void SetIdle(); void ClearCounters(); diff --git a/src/g_level.h b/src/g_level.h index c431b96956..4a84e6871f 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -554,6 +554,7 @@ enum ESkillProperty SKILLP_NoPain, SKILLP_ArmorFactor, SKILLP_EasyKey, + SKILLP_SlowMonsters, }; int G_SkillProperty(ESkillProperty prop); const char * G_SkillName(); @@ -568,6 +569,7 @@ struct FSkillInfo fixed_t AmmoFactor, DoubleAmmoFactor, DropAmmoFactor; fixed_t DamageFactor; bool FastMonsters; + bool SlowMonsters; bool DisableCheats; bool AutoUseHealth; diff --git a/src/g_skill.cpp b/src/g_skill.cpp index 46b9a1702a..ddfdbb4cc1 100644 --- a/src/g_skill.cpp +++ b/src/g_skill.cpp @@ -64,6 +64,7 @@ void FMapInfoParser::ParseSkill () skill.DropAmmoFactor = -1; skill.DamageFactor = FRACUNIT; skill.FastMonsters = false; + skill.SlowMonsters = false; skill.DisableCheats = false; skill.EasyBossBrain = false; skill.EasyKey = false; @@ -118,6 +119,10 @@ void FMapInfoParser::ParseSkill () { skill.FastMonsters = true; } + else if (sc.Compare ("slowmonsters")) + { + skill.SlowMonsters = true; + } else if (sc.Compare ("disablecheats")) { skill.DisableCheats = true; @@ -336,6 +341,9 @@ int G_SkillProperty(ESkillProperty prop) case SKILLP_FastMonsters: return AllSkills[gameskill].FastMonsters || (dmflags & DF_FAST_MONSTERS); + case SKILLP_SlowMonsters: + return AllSkills[gameskill].SlowMonsters; + case SKILLP_Respawn: if (dmflags & DF_MONSTERS_RESPAWN && AllSkills[gameskill].RespawnCounter==0) return TICRATE * gameinfo.defaultrespawntime; @@ -433,6 +441,7 @@ FSkillInfo &FSkillInfo::operator=(const FSkillInfo &other) DropAmmoFactor = other.DropAmmoFactor; DamageFactor = other.DamageFactor; FastMonsters = other.FastMonsters; + SlowMonsters = other.SlowMonsters; DisableCheats = other.DisableCheats; AutoUseHealth = other.AutoUseHealth; EasyBossBrain = other.EasyBossBrain; diff --git a/src/info.h b/src/info.h index 9a316c78de..51c4bd629d 100644 --- a/src/info.h +++ b/src/info.h @@ -77,6 +77,7 @@ struct FState BYTE Fast:1; BYTE NoDelay:1; // Spawn states executes its action normally BYTE CanRaise:1; // Allows a monster to be resurrected without waiting for an infinate frame + BYTE Slow:1; // Inverse of fast int ParameterIndex; inline int GetFrame() const diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 291f51a946..f82cf9bce4 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -405,7 +405,7 @@ bool AActor::InStateSequence(FState * newstate, FState * basestate) // // Get the actual duration of the next state // We are using a state flag now to indicate a state that should be -// accelerated in Fast mode. +// accelerated in Fast mode or slowed in Slow mode. // //========================================================================== @@ -416,6 +416,10 @@ int AActor::GetTics(FState * newstate) { return tics - (tics>>1); } + else if (isSlow() && newstate->Slow) + { + return tics<<1; + } return tics; } @@ -4082,6 +4086,11 @@ bool AActor::isFast() return !!G_SkillProperty(SKILLP_FastMonsters); } +bool AActor::isSlow() +{ + return !!G_SkillProperty(SKILLP_SlowMonsters); +} + void AActor::Activate (AActor *activator) { if ((flags3 & MF3_ISMONSTER) && (health > 0 || (flags & MF_ICECORPSE))) diff --git a/src/thingdef/thingdef_states.cpp b/src/thingdef/thingdef_states.cpp index 5cc2de1c03..6a28e54cdf 100644 --- a/src/thingdef/thingdef_states.cpp +++ b/src/thingdef/thingdef_states.cpp @@ -275,6 +275,11 @@ do_stop: state.Fast = true; continue; } + if (sc.Compare("SLOW")) + { + state.Slow = true; + continue; + } if (sc.Compare("NODELAY")) { if (bag.statedef.GetStateLabelIndex(NAME_Spawn) == bag.statedef.GetStateCount()) From 94d47efbb5fa2b7269b50858a9dda9307c436ebb Mon Sep 17 00:00:00 2001 From: Gaerzi Date: Tue, 15 Apr 2014 21:02:20 +0200 Subject: [PATCH 07/11] Added slow monsters to Strife's easiest skill --- wadsrc/static/mapinfo/strife.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wadsrc/static/mapinfo/strife.txt b/wadsrc/static/mapinfo/strife.txt index 83c2285e64..5a25f37795 100644 --- a/wadsrc/static/mapinfo/strife.txt +++ b/wadsrc/static/mapinfo/strife.txt @@ -238,6 +238,7 @@ skill baby AmmoFactor = 2 DamageFactor = 0.5 EasyBossBrain + SlowMonsters SpawnFilter = Baby PicName = "M_JKILL" Name = "$SSKILL_BABY" From 48b926e5b47cf2380db412b6c08e8c7aeec1138a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 16 Apr 2014 09:53:07 +0200 Subject: [PATCH 08/11] - check +logfile explicitly at the start of execution. Due to the custom CVAR rewrite it would get called so late that it'd miss half of the log. - added version check for Windows 8. I also would have liked to add 8.1 but due to some incredibly stupid changes in the version API it's no longer possible to reliably retrieve the correct Windows version for later builds. --- src/c_cmds.cpp | 26 ++++++++++++++++---------- src/c_dispatch.h | 2 ++ src/d_main.cpp | 7 +++++++ src/win32/i_system.cpp | 12 ++++++++++++ 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index cdf615ef49..0e7adb8ef3 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -441,27 +441,33 @@ CCMD (exec) } } +void execLogfile(const char *fn) +{ + if ((Logfile = fopen(fn, "w"))) + { + const char *timestr = myasctime(); + Printf("Log started: %s\n", timestr); + } + else + { + Printf("Could not start log\n"); + } +} + CCMD (logfile) { - const char *timestr = myasctime (); if (Logfile) { - Printf ("Log stopped: %s\n", timestr); + const char *timestr = myasctime(); + Printf("Log stopped: %s\n", timestr); fclose (Logfile); Logfile = NULL; } if (argv.argc() >= 2) { - if ( (Logfile = fopen (argv[1], "w")) ) - { - Printf ("Log started: %s\n", timestr); - } - else - { - Printf ("Could not start log\n"); - } + execLogfile(argv[1]); } } diff --git a/src/c_dispatch.h b/src/c_dispatch.h index 96dc50644e..f4518608df 100644 --- a/src/c_dispatch.h +++ b/src/c_dispatch.h @@ -168,4 +168,6 @@ extern unsigned int MakeKey (const char *s); extern unsigned int MakeKey (const char *s, size_t len); extern unsigned int SuperFastHash (const char *data, size_t len); +void execLogfile(const char *fn); + #endif //__C_DISPATCH_H__ diff --git a/src/d_main.cpp b/src/d_main.cpp index 6c938ef53f..695e7e517a 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2223,6 +2223,13 @@ void D_DoomMain (void) FString *args; int argcount; + // +logfile gets checked too late to catch the full startup log in the logfile so do some extra check for it here. + FString logfile = Args->TakeValue("+logfile"); + if (logfile != NULL) + { + execLogfile(logfile); + } + D_DoomInit(); PClass::StaticInit (); atterm(FinalGC); diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index a82cb65f9c..4690c253d6 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -581,6 +581,18 @@ void I_DetectOS(void) osname = "Server 2008 R2"; } } + else if (info.dwMinorVersion == 2) + { + // Microsoft broke this API for 8.1 so without jumping through hoops it won't be possible anymore to detect never versions aside from the build number, especially for older compilers. + if (info.wProductType == VER_NT_WORKSTATION) + { + osname = "8 (or higher)"; + } + else + { + osname = "Server 2012 (or higher)"; + } + } } break; From d855bd66b301ebd8ad969e6816a4c190d9e3ec8f Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Thu, 17 Apr 2014 00:46:33 +1200 Subject: [PATCH 09/11] Fixed P_LookForPlayers scanning redundancies - Players could be scanned multiple times, repeating expensive tests - Players could be skipped completely and become invisible as a result --- src/p_enemy.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 8b1dd951bd..3be53cd64a 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -1542,7 +1542,6 @@ bool P_LookForEnemies (AActor *actor, INTBOOL allaround, FLookExParams *params) bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) { int c; - int stop; int pnum; player_t* player; bool chasegoal = params? (!(params->flags & LOF_DONTCHASEGOAL)) : true; @@ -1615,20 +1614,22 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) { pnum = actor->LastLookPlayerNumber; } - stop = (pnum - 1) & (MAXPLAYERS-1); for (;;) { - pnum = (pnum + 1) & (MAXPLAYERS-1); - if (!playeringame[pnum]) - continue; - - if (actor->TIDtoHate == 0) + // [ED850] Each and every player should only ever be checked once. + if (c++ < MAXPLAYERS) { - actor->LastLookPlayerNumber = pnum; - } + pnum = (pnum + 1) & (MAXPLAYERS - 1); + if (!playeringame[pnum]) + continue; - if (++c == MAXPLAYERS-1 || pnum == stop) + if (actor->TIDtoHate == 0) + { + actor->LastLookPlayerNumber = pnum; + } + } + else { // done looking if (actor->target == NULL) From 897d87a6a3841a0e484cc5de1e1b411848a3c6a8 Mon Sep 17 00:00:00 2001 From: Edward Richardson Date: Thu, 17 Apr 2014 01:13:18 +1200 Subject: [PATCH 10/11] Invisibility would could P_LookForPlayers early --- src/p_enemy.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 3be53cd64a..e187dfb7c1 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -1693,11 +1693,11 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) && P_AproxDistance (player->mo->velx, player->mo->vely) < 5*FRACUNIT) { // Player is sneaking - can't detect - return false; + continue; } if (pr_lookforplayers() < 225) { // Player isn't sneaking, but still didn't detect - return false; + continue; } } } From 60fe07df7451176803f4fe28b42160d02a72bd9c Mon Sep 17 00:00:00 2001 From: Gaerzi Date: Thu, 17 Apr 2014 17:42:16 +0200 Subject: [PATCH 11/11] Added slow states to relevant Strife monsters Namely, acolyte, shadow acolyte, reaver, stalker, and turret. Info on which states needed the slow flag was obtained with Quasar's permission by looking at G_InitNew() in g_game.c and the info.c state tables from Chocolate Strife. Also added fast flag to acolyte states that needed it, based on the same source. --- wadsrc/static/actors/strife/acolyte.txt | 16 ++++++++-------- wadsrc/static/actors/strife/crusader.txt | 19 ++++++++----------- wadsrc/static/actors/strife/reaver.txt | 12 ++++++------ wadsrc/static/actors/strife/stalker.txt | 12 ++++++------ wadsrc/static/actors/strife/strifestuff.txt | 4 ++-- 5 files changed, 30 insertions(+), 33 deletions(-) diff --git a/wadsrc/static/actors/strife/acolyte.txt b/wadsrc/static/actors/strife/acolyte.txt index 1d04147f03..3ca1dec627 100644 --- a/wadsrc/static/actors/strife/acolyte.txt +++ b/wadsrc/static/actors/strife/acolyte.txt @@ -39,16 +39,16 @@ ACTOR Acolyte : StrifeHumanoid AGRD ABCDABCD 5 A_Wander Loop See: - AGRD A 6 A_AcolyteBits - AGRD BCD 6 A_Chase + AGRD A 6 Fast Slow A_AcolyteBits + AGRD BCD 6 Fast Slow A_Chase Loop Missile: - AGRD E 8 A_FaceTarget - AGRD FE 4 A_ShootGun - AGRD F 6 A_ShootGun + AGRD E 8 Fast Slow A_FaceTarget + AGRD FE 4 Fast Slow A_ShootGun + AGRD F 6 Fast Slow A_ShootGun Goto See Pain: - AGRD O 8 A_Pain + AGRD O 8 Fast Slow A_Pain Goto See Death: AGRD G 4 @@ -170,8 +170,8 @@ ACTOR AcolyteShadow : Acolyte 58 AGRD A 6 A_BeShadowyFoe Goto Super::See+1 Pain: - AGRD O 0 A_SetShadow - AGRD O 8 A_Pain + AGRD O 0 Fast Slow A_SetShadow + AGRD O 8 Fast Slow A_Pain Goto See } } diff --git a/wadsrc/static/actors/strife/crusader.txt b/wadsrc/static/actors/strife/crusader.txt index 36d89ed57b..7f7a0d0c50 100644 --- a/wadsrc/static/actors/strife/crusader.txt +++ b/wadsrc/static/actors/strife/crusader.txt @@ -42,19 +42,16 @@ ACTOR Crusader 3005 ROB2 AABBCCDD 3 A_Chase Loop Missile: - ROB2 E 3 A_FaceTarget - ROB2 F 2 Bright A_CrusaderChoose - ROB2 E 2 Bright A_CrusaderSweepLeft - ROB2 F 3 Bright A_CrusaderSweepLeft - ROB2 E 2 Bright A_CrusaderSweepLeft - ROB2 F 2 Bright A_CrusaderSweepLeft - ROB2 E 2 Bright A_CrusaderSweepRight - ROB2 F 2 Bright A_CrusaderSweepRight - ROB2 E 2 Bright A_CrusaderSweepRight - ROB2 F 2 A_CrusaderRefire + ROB2 E 3 Slow A_FaceTarget + ROB2 F 2 Slow Bright A_CrusaderChoose + ROB2 E 2 Slow Bright A_CrusaderSweepLeft + ROB2 F 3 Slow Bright A_CrusaderSweepLeft + ROB2 EF 2 Slow Bright A_CrusaderSweepLeft + ROB2 EFE 2 Slow Bright A_CrusaderSweepRight + ROB2 F 2 Slow A_CrusaderRefire Loop Pain: - ROB2 D 1 A_Pain + ROB2 D 1 Slow A_Pain Goto See Death: ROB2 G 3 A_Scream diff --git a/wadsrc/static/actors/strife/reaver.txt b/wadsrc/static/actors/strife/reaver.txt index 23439b9ba4..a699473737 100644 --- a/wadsrc/static/actors/strife/reaver.txt +++ b/wadsrc/static/actors/strife/reaver.txt @@ -32,16 +32,16 @@ ACTOR Reaver 3001 ROB1 BBCCDDEE 3 A_Chase Loop Melee: - ROB1 H 6 A_FaceTarget - ROB1 I 8 A_CustomMeleeAttack(random[ReaverMelee](1,8)*3, "reaver/blade") - ROB1 H 6 + ROB1 H 6 Slow A_FaceTarget + ROB1 I 8 Slow A_CustomMeleeAttack(random[ReaverMelee](1,8)*3, "reaver/blade") + ROB1 H 6 Slow Goto See Missile: - ROB1 F 8 A_FaceTarget - ROB1 G 11 BRIGHT A_ReaverRanged + ROB1 F 8 Slow A_FaceTarget + ROB1 G 11 Slow BRIGHT A_ReaverRanged Goto See Pain: - ROB1 A 2 + ROB1 A 2 Slow ROB1 A 2 A_Pain Goto See Death: diff --git a/wadsrc/static/actors/strife/stalker.txt b/wadsrc/static/actors/strife/stalker.txt index 80732131ea..0a537c7625 100644 --- a/wadsrc/static/actors/strife/stalker.txt +++ b/wadsrc/static/actors/strife/stalker.txt @@ -45,14 +45,14 @@ ACTOR Stalker 186 STLK J 10 A_Look Loop See: - STLK A 1 A_StalkerChaseDecide - STLK ABB 3 A_Chase - STLK C 3 A_StalkerWalk - STLK C 3 A_Chase + STLK A 1 Slow A_StalkerChaseDecide + STLK ABB 3 Slow A_Chase + STLK C 3 Slow A_StalkerWalk + STLK C 3 Slow A_Chase Loop Melee: - STLK J 3 A_FaceTarget - STLK K 3 A_StalkerAttack + STLK J 3 Slow A_FaceTarget + STLK K 3 Slow A_StalkerAttack SeeFloor: STLK J 3 A_StalkerWalk STLK KK 3 A_Chase diff --git a/wadsrc/static/actors/strife/strifestuff.txt b/wadsrc/static/actors/strife/strifestuff.txt index b0f4024f41..ef762cbb6f 100644 --- a/wadsrc/static/actors/strife/strifestuff.txt +++ b/wadsrc/static/actors/strife/strifestuff.txt @@ -1786,8 +1786,8 @@ ACTOR CeilingTurret 27 Loop Missile: Pain: - TURT B 4 A_ShootGun - TURT D 3 A_SentinelRefire + TURT B 4 Slow A_ShootGun + TURT D 3 Slow A_SentinelRefire TURT A 4 A_SentinelRefire Loop Death: