From caef5344b0304b07dcb14eba1424a0934c47934f Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@users.noreply.github.com>
Date: Mon, 28 Nov 2016 21:33:14 +0100
Subject: [PATCH] - scriptified a_thingstoblowup.cpp. - changed the power
 crystal floor movement to use DFloor instead of an incomplete in-place hack
 to ensure that everything is processed properly.

---
 src/CMakeLists.txt                            |   1 -
 src/g_strife/a_strifestuff.cpp                |  42 ------
 src/g_strife/a_thingstoblowup.cpp             | 121 ------------------
 src/p_floor.cpp                               |  15 +++
 src/scripting/codegeneration/codegen.cpp      |   3 +-
 wadsrc/static/zscript/actor.txt               |   5 -
 wadsrc/static/zscript/base.txt                |  68 ++++++++++
 .../static/zscript/strife/strifehumanoid.txt  |  27 ++++
 .../static/zscript/strife/thingstoblowup.txt  |  86 ++++++++++++-
 9 files changed, 194 insertions(+), 174 deletions(-)
 delete mode 100644 src/g_strife/a_thingstoblowup.cpp

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 841521802..3ca87affa 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -863,7 +863,6 @@ set( NOT_COMPILED_SOURCE_FILES
 	g_hexen/a_spike.cpp
 	g_strife/a_strifeitems.cpp
 	g_strife/a_strifeweapons.cpp
-	g_strife/a_thingstoblowup.cpp
 	g_shared/sbarinfo_commands.cpp
 	xlat/xlat_parser.y
 	xlat_parser.c
diff --git a/src/g_strife/a_strifestuff.cpp b/src/g_strife/a_strifestuff.cpp
index 3d475a58b..18a758e2e 100644
--- a/src/g_strife/a_strifestuff.cpp
+++ b/src/g_strife/a_strifestuff.cpp
@@ -26,7 +26,6 @@
 // Include all the other Strife stuff here to reduce compile time
 #include "a_strifeitems.cpp"
 #include "a_strifeweapons.cpp"
-#include "a_thingstoblowup.cpp"
 
 // Notes so I don't forget them:
 // Strife does some extra stuff in A_Explode if a player caused the explosion. (probably NoiseAlert)
@@ -67,47 +66,6 @@ int AForceFieldGuard::TakeSpecialDamage (AActor *inflictor, AActor *source, int
 	return health;
 }
 
-// Kneeling Guy -------------------------------------------------------------
-
-DEFINE_ACTION_FUNCTION(AActor, A_SetShadow)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	self->flags |= MF_STRIFEx8000000|MF_SHADOW;
-	self->RenderStyle = STYLE_Translucent;
-	self->Alpha = HR_SHADOW;
-	return 0;
-}
-
-DEFINE_ACTION_FUNCTION(AActor, A_ClearShadow)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	self->flags &= ~(MF_STRIFEx8000000|MF_SHADOW);
-	self->RenderStyle = STYLE_Normal;
-	self->Alpha = 1.;
-	return 0;
-}
-
-static FRandom pr_gethurt ("HurtMe!");
-
-DEFINE_ACTION_FUNCTION(AActor, A_GetHurt)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	self->flags4 |= MF4_INCOMBAT;
-	if ((pr_gethurt() % 5) == 0)
-	{
-		S_Sound (self, CHAN_VOICE, self->PainSound, 1, ATTN_NORM);
-		self->health--;
-	}
-	if (self->health <= 0)
-	{
-		self->CallDie (self->target, self->target);
-	}
-	return 0;
-}
-
 // Klaxon Warning Light -----------------------------------------------------
 
 DEFINE_ACTION_FUNCTION(AActor, A_TurretLook)
diff --git a/src/g_strife/a_thingstoblowup.cpp b/src/g_strife/a_thingstoblowup.cpp
deleted file mode 100644
index 08670d484..000000000
--- a/src/g_strife/a_thingstoblowup.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
-#include "actor.h"
-#include "m_random.h"
-#include "p_local.h"
-#include "c_console.h"
-#include "p_enemy.h"
-#include "a_action.h"
-#include "gstrings.h"
-#include "vm.h"
-#include "vm.h"
-#include "doomstat.h"
-*/
-
-static FRandom pr_bang4cloud ("Bang4Cloud");
-static FRandom pr_lightout ("LightOut");
-
-DEFINE_ACTION_FUNCTION(AActor, A_Bang4Cloud)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	double xo = (pr_bang4cloud.Random2() & 3) * (10. / 64);
-	double yo = (pr_bang4cloud.Random2() & 3) * (10. / 64);
-	Spawn("Bang4Cloud", self->Vec3Offset(xo, yo, 0.), ALLOW_REPLACE);
-	return 0;
-}
-
-// -------------------------------------------------------------------
-
-DEFINE_ACTION_FUNCTION(AActor, A_GiveQuestItem)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-	PARAM_INT(questitem);
-
-	// Give one of these quest items to every player in the game
-	if (questitem >= 0 && questitem < (int)countof(QuestItemClasses))
-	{
-		for (int i = 0; i < MAXPLAYERS; ++i)
-		{
-			if (playeringame[i])
-			{
-				AInventory *item = static_cast<AInventory *>(Spawn (QuestItemClasses[questitem - 1]));
-				if (!item->CallTryPickup (players[i].mo))
-				{
-					item->Destroy ();
-				}
-			}
-		}
-	}
-
-	char messageid[64];
-
-	mysnprintf(messageid, countof(messageid), "TXT_QUEST_%d", questitem);
-	const char * name = GStrings[messageid];
-
-	if (name != NULL)
-	{
-		C_MidPrint (SmallFont, name);
-	}
-	return 0;
-}
-
-// PowerCrystal -------------------------------------------------------------------
-
-DEFINE_ACTION_FUNCTION(AActor, A_ExtraLightOff)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	if (self->target != NULL && self->target->player != NULL)
-	{
-		self->target->player->extralight = 0;
-	}
-	return 0;
-}
-
-DEFINE_ACTION_FUNCTION(AActor, A_Explode512)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	P_RadiusAttack (self, self->target, 512, 512, NAME_None, RADF_HURTSOURCE);
-	if (self->target != NULL && self->target->player != NULL)
-	{
-		self->target->player->extralight = 5;
-	}
-	P_CheckSplash(self, 512);
-
-	// Strife didn't do this next part, but it looks good
-	self->RenderStyle = STYLE_Add;
-	return 0;
-}
-
-DEFINE_ACTION_FUNCTION(AActor, A_LightGoesOut)
-{
-	PARAM_SELF_PROLOGUE(AActor);
-
-	AActor *foo;
-	sector_t *sec = self->Sector;
-	vertex_t *spot;
-	double newheight;
-
-	sec->SetLightLevel(0);
-
-	double oldtheight = sec->floorplane.fD();
-	newheight = sec->FindLowestFloorSurrounding(&spot);
-	sec->floorplane.setD(sec->floorplane.PointToDist (spot, newheight));
-	double newtheight = sec->floorplane.fD();
-	sec->ChangePlaneTexZ(sector_t::floor, newtheight - oldtheight);
-	sec->CheckPortalPlane(sector_t::floor);
-
-	for (int i = 0; i < 8; ++i)
-	{
-		foo = Spawn("Rubble1", self->Pos(), ALLOW_REPLACE);
-		if (foo != NULL)
-		{
-			int t = pr_lightout() & 15;
-			foo->Vel.X = t - (pr_lightout() & 7);
-			foo->Vel.Y = pr_lightout.Random2() & 7;
-			foo->Vel.Z = 7 + (pr_lightout() & 3);
-		}
-	}
-	return 0;
-}
diff --git a/src/p_floor.cpp b/src/p_floor.cpp
index 0431fa808..8fd5ad038 100644
--- a/src/p_floor.cpp
+++ b/src/p_floor.cpp
@@ -492,6 +492,21 @@ bool P_CreateFloor(sector_t *sec, DFloor::EFloor floortype, line_t *line,
 	return true;
 }
 
+DEFINE_ACTION_FUNCTION(DFloor, CreateFloor)
+{
+	PARAM_PROLOGUE;
+	PARAM_POINTER(sec, sector_t);
+	PARAM_INT(floortype);
+	PARAM_POINTER(ln, line_t);
+	PARAM_FLOAT(speed);
+	PARAM_FLOAT_DEF(height);
+	PARAM_INT_DEF(crush);
+	PARAM_INT_DEF(change);
+	PARAM_BOOL_DEF(hereticlower);
+	PARAM_BOOL_DEF(hexencrush);
+	ACTION_RETURN_BOOL(P_CreateFloor(sec, (DFloor::EFloor)floortype, ln, speed, height, crush, change, hexencrush, hereticlower));
+}
+
 //==========================================================================
 //
 // HANDLE FLOOR TYPES
diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp
index 5277ad70e..6912755b4 100644
--- a/src/scripting/codegeneration/codegen.cpp
+++ b/src/scripting/codegeneration/codegen.cpp
@@ -9512,7 +9512,8 @@ int BuiltinNameToClass(VMFrameStack *stack, VMValue *param, TArray<VMValue> &def
 
 		if (!cls->IsDescendantOf(desttype))
 		{
-			Printf("class '%s' is not compatible with '%s'\n", clsname.GetChars(), desttype->TypeName.GetChars());
+			// Let the caller check this. The message can be enabled for diagnostic purposes.
+			DPrintf(DMSG_SPAMMY, "class '%s' is not compatible with '%s'\n", clsname.GetChars(), desttype->TypeName.GetChars());
 			cls = nullptr;
 		}
 		ret->SetPointer(const_cast<PClass *>(cls), ATAG_OBJECT);
diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt
index 2d716f444..90cffb81a 100644
--- a/wadsrc/static/zscript/actor.txt
+++ b/wadsrc/static/zscript/actor.txt
@@ -619,9 +619,6 @@ class Actor : Thinker native
 	native void A_Wander(int flags = 0);
 	native void A_Look2();
 	native void A_TossGib();
-	native void A_SetShadow();
-	native void A_ClearShadow();
-	native void A_GetHurt();
 	native void A_TurretLook();
 	native void A_KlaxonBlare();
 	native void A_Countdown();
@@ -701,9 +698,7 @@ class Actor : Thinker native
 	native bool A_SelectWeapon(class<Weapon> whichweapon, int flags = 0);
 	native void A_ClassBossHealth();
 	native void A_RocketInFlight();
-	native void A_Bang4Cloud();
 	native void A_DropFire();
-	native void A_GiveQuestItem(int itemno);
 	native void A_RemoveForcefield();
 	native void A_SetAngle(double angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT);
 	native void A_SetPitch(double pitch, int flags = 0, int ptr = AAPTR_DEFAULT);
diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt
index 8d2e7a71b..6f9b2dfe1 100644
--- a/wadsrc/static/zscript/base.txt
+++ b/wadsrc/static/zscript/base.txt
@@ -212,6 +212,28 @@ struct Sector native
 
 	native uint16		ZoneNumber;
 	native uint16		MoreFlags;
+	
+	enum ESectorFlags
+	{
+		SECF_SILENT			= 1,	// actors in sector make no noise
+		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
+	}
 	native uint			Flags;
 
 	native SectorAction		SecActTarget;
@@ -286,3 +308,49 @@ struct String native
 {
 	native void Replace(String pattern, String replacement);
 }
+
+class Floor : Thinker native
+{
+	// only here so that some constants and functions can be added. Not directly usable yet.
+	enum EFloor
+	{
+		floorLowerToLowest,
+		floorLowerToNearest,
+		floorLowerToHighest,
+		floorLowerByValue,
+		floorRaiseByValue,
+		floorRaiseToHighest,
+		floorRaiseToNearest,
+		floorRaiseAndCrush,
+		floorRaiseAndCrushDoom,
+		floorCrushStop,
+		floorLowerInstant,
+		floorRaiseInstant,
+		floorMoveToValue,
+		floorRaiseToLowestCeiling,
+		floorRaiseByTexture,
+
+		floorLowerAndChange,
+		floorRaiseAndChange,
+
+		floorRaiseToLowest,
+		floorRaiseToCeiling,
+		floorLowerToLowestCeiling,
+		floorLowerByTexture,
+		floorLowerToCeiling,
+
+		donutRaise,
+
+		buildStair,
+		waitStair,
+		resetStair,
+
+		// Not to be used as parameters to EV_DoFloor()
+		genFloorChg0,
+		genFloorChgT,
+		genFloorChg
+	};
+
+	native static bool CreateFloor(sector sec, EFloor floortype, line ln, double speed, double height = 0, int crush = -1, int change = 0, bool hexencrush = false, bool hereticlower = false);
+	
+}
\ No newline at end of file
diff --git a/wadsrc/static/zscript/strife/strifehumanoid.txt b/wadsrc/static/zscript/strife/strifehumanoid.txt
index 7cec969ea..0686ec098 100644
--- a/wadsrc/static/zscript/strife/strifehumanoid.txt
+++ b/wadsrc/static/zscript/strife/strifehumanoid.txt
@@ -72,5 +72,32 @@ extend class Actor
 		double pitch = AimLineAttack (angle, MISSILERANGE);
 		LineAttack (Angle + Random2[ShootGun]() * (11.25 / 256), MISSILERANGE, pitch, 3*(random[ShootGun]() % 5 + 1), 'Hitscan', "StrifePuff");
 	}
+	
+	// Kneeling Guy -------------------------------------------------------------
 
+	void A_SetShadow()
+	{
+		bShadow = true;
+		A_SetRenderStyle(HR_SHADOW, STYLE_Translucent);
+	}
+
+	void A_ClearShadow()
+	{
+		bShadow = false;
+		A_SetRenderStyle(1, STYLE_Normal);
+	}
+
+	void A_GetHurt()
+	{
+		bInCombat = true;
+		if ((random[HurtMe]() % 5) == 0)
+		{
+			A_PlaySound (PainSound, CHAN_VOICE);
+			health--;
+		}
+		if (health <= 0)
+		{
+			Die (target, target);
+		}
+	}
 }
\ No newline at end of file
diff --git a/wadsrc/static/zscript/strife/thingstoblowup.txt b/wadsrc/static/zscript/strife/thingstoblowup.txt
index dbbad8ed6..5e5bfac21 100644
--- a/wadsrc/static/zscript/strife/thingstoblowup.txt
+++ b/wadsrc/static/zscript/strife/thingstoblowup.txt
@@ -1,4 +1,42 @@
+extend class Actor
+{
 
+	void A_Bang4Cloud()
+	{
+		double xo = (random[Bang4Cloud]() & 3) * (10. / 64);
+		double yo = (random[Bang4Cloud]() & 3) * (10. / 64);
+		Spawn("Bang4Cloud", Vec3Offset(xo, yo, 0.), ALLOW_REPLACE);
+	}
+	
+	void A_GiveQuestItem(int questitem)
+	{
+		// Give one of these quest items to every player in the game
+		if (questitem >= 0)
+		{
+			String itemname = "QuestItem" .. questitem;
+			class<Inventory> item = itemname;
+			if (item != null)
+			{
+				for (int i = 0; i < MAXPLAYERS; ++i)
+				{
+					if (playeringame[i])
+					{
+						players[i].mo.GiveInventoryType(item);
+					}
+				}
+			}
+		}
+
+		String msgid = "TXT_QUEST_" .. questitem;
+		String msg = StringTable.Localize(msgid);
+
+		if (msg != msgid)	// if both are identical there was no message of this name in the stringtable.
+		{
+			C_MidPrint ("SmallFont", msg);
+		}
+	}
+	
+}
 
 // A Cloud used for varius explosions ---------------------------------------
 // This actor has no direct equivalent in strife. To create this, Strife
@@ -121,10 +159,6 @@ class PowerCrystal : Actor
 		ActiveSound "misc/reactor";
 	}
 
-	native void A_ExtraLightOff ();
-	native void A_Explode512 ();
-	native void A_LightGoesOut ();
-
 	States
 	{
 	Spawn:
@@ -150,4 +184,48 @@ class PowerCrystal : Actor
 		BOOM VWXY 3 Bright;
 		Stop;
 	}
+	
+	// PowerCrystal -------------------------------------------------------------------
+
+	void A_ExtraLightOff()
+	{
+		if (target != NULL && target.player != NULL)
+		{
+			target.player.extralight = 0;
+		}
+	}
+
+	void A_Explode512()
+	{
+		A_Explode(512, 512);
+		if (target != NULL && target.player != NULL)
+		{
+			target.player.extralight = 5;
+		}
+		A_SetRenderStyle(1, STYLE_Add);
+	}
+
+	void A_LightGoesOut()
+	{
+		sector sec = CurSector;
+
+		sec.Flags |= Sector.SECF_SILENTMOVE;
+		sec.lightlevel = 0;
+		// Do this right with proper checks instead of just hacking the floor height.
+		Floor.CreateFloor(sec, Floor.floorLowerToLowest, null, 65536.);
+		
+
+		for (int i = 0; i < 8; ++i)
+		{
+			Actor foo = Spawn("Rubble1", Pos, ALLOW_REPLACE);
+			if (foo != NULL)
+			{
+				int t = random[LightOut]() & 15;
+				foo.Vel.X = t - (random[LightOut]() & 7);
+				foo.Vel.Y = random2[LightOut]() & 7;
+				foo.Vel.Z = 7 + (random[LightOut]() & 3);
+			}
+		}
+	}
+	
 }