From 94dedf9aa96e012857a982eaec851422c698944e Mon Sep 17 00:00:00 2001
From: MaxED <j.maxed@gmail.com>
Date: Sun, 17 Jul 2016 00:00:29 +0000
Subject: [PATCH] Added support for USEACTORPITCH and USEACTORROLL MODELDEF
 flags. Changed: LOKCDEFS keys are now sorted alphabetically. Fixed, MAPINFO
 parser: blocks inside map definition block were parsed incorrectly when using
 new MAPINFO format. Fixed, rendering: custom MODELDEF scale was applied
 incorrectly when "Stretched view in visual modes" option was enabled. Updated
 ZDoom_DECORATE.cfg. Updated GZDoom_MODELDEF.cfg.

---
 Build/Scripting/GZDoom_MODELDEF.cfg     |  3 +++
 Build/Scripting/ZDoom_DECORATE.cfg      | 15 +++++++++++---
 Source/Core/Data/DataManager.cs         |  3 ++-
 Source/Core/GZBuilder/Data/ModelData.cs |  7 ++++---
 Source/Core/Map/Thing.cs                | 12 ++++++-----
 Source/Core/Rendering/Renderer2D.cs     |  2 +-
 Source/Core/Rendering/Renderer3D.cs     |  5 ++---
 Source/Core/ZDoom/MapinfoParser.cs      |  2 +-
 Source/Core/ZDoom/ModeldefParser.cs     |  2 +-
 Source/Core/ZDoom/ModeldefStructure.cs  | 27 +++++++++++++++++++++----
 10 files changed, 56 insertions(+), 22 deletions(-)

diff --git a/Build/Scripting/GZDoom_MODELDEF.cfg b/Build/Scripting/GZDoom_MODELDEF.cfg
index 9d80b9e5d..9cc3e1f07 100644
--- a/Build/Scripting/GZDoom_MODELDEF.cfg
+++ b/Build/Scripting/GZDoom_MODELDEF.cfg
@@ -19,6 +19,7 @@ keywords
   Path = "Path <\"path\">";
   Model = "Model <model index> <\"model file\">";
   Skin = "Skin <model index> <\"skin file\">";
+  SurfaceSkin = "SurfaceSkin <model index> <surface index> <\"skin file\">";
   Scale = "Scale <float X scale> <float Y scale> <float Z scale>";
   Frame = "Frame <XXXX> <X> <model index> <\"frame name\">";
   FrameIndex = "FrameIndex <XXXX> <X> <model index> <frame number>";
@@ -40,4 +41,6 @@ constants
   NOINTERPOLATION;
   INHERITACTORPITCH;
   INHERITACTORROLL;
+  USEACTORPITCH;
+  USEACTORROLL;
 }
\ No newline at end of file
diff --git a/Build/Scripting/ZDoom_DECORATE.cfg b/Build/Scripting/ZDoom_DECORATE.cfg
index 76c793570..62cf2870c 100644
--- a/Build/Scripting/ZDoom_DECORATE.cfg
+++ b/Build/Scripting/ZDoom_DECORATE.cfg
@@ -119,7 +119,7 @@ keywords
 	A_Wander = "A_Wander";
 //Generic monster attacks
 	A_CustomMissile = "A_CustomMissile(str missiletype[, float spawnheight = 32.0[, float spawnofs_horiz = 0.0[, int angle = 0[, int aimflags = 0[, int pitch = 0[, int target = AAPTR_TARGET]]]]]])";
-	A_CustomBulletAttack = "A_CustomBulletAttack(float horz_spread, float vert_spread, int numbullets, int damageperbullet[, str pufftype = \"BulletPuff\"[, float range = 0.0[, int flags = 0[, int target = AAPTR_TARGET]]]])";
+	A_CustomBulletAttack = "A_CustomBulletAttack(float horz_spread, float vert_spread, int numbullets, int damageperbullet[, str pufftype = \"BulletPuff\"[, float range = 0.0[, int flags = 0[, int target = AAPTR_TARGET[, str missile = \"none\"[, float spawnheight = 32.0[, float spawnofs_xy = 0.0]]]]]]])";
 	A_CustomRailgun = "A_CustomRailgun(int damage[, int offset[, color ringcolor[, color corecolor[, int flags = 0[, bool aim = false[, float maxdiff = 0.0[, str pufftype = \"\"[, float spread_xy = 0.0[, float spread_z = 0.0[, float range = 8192[, int duration = 35[, float sparsity = 1.0[, float driftspeed = 1.0[, str spawnclass = \"\"[, float spawnofs_z = 0[, int spiraloffset = 270[, int actorpiercelimit = 0]]]]]]]]]]]]]]]]])";
 	A_CustomMeleeAttack = "A_CustomMeleeAttack[(int damage = 0[, str meleesound = \"\"[, str misssound = \"\"[, str damagetype = \"Melee\"[, bool bleed = true]]]])]";
 	A_CustomComboAttack = "A_CustomComboAttack(str missiletype, float spawnheight, int damage, str meleesound[, str damagetype = \"Melee\"[, bool bleed = true]])";
@@ -318,7 +318,7 @@ keywords
 	A_Punch = "A_Punch";
 	A_Saw = "A_Saw[(str fullsound = \"weapons/sawfull\"[, str hitsound = \"weapons/sawhit\"[, int damage = 0[, str pufftype = \"BulletPuff\"[, int flags = 0[, float range = 65.0[, float spread_xy = 2.8125[, float spread_z = 0.0[, float lifesteal = 0.0[, int lifestealmax = 0[, str armorbonustype = \"ArmorBonus\"]]]]]]]]]])]";
 	A_CustomPunch = "A_CustomPunch(int damage[, bool norandom = false[, int flags = 0[, str pufftype = \"BulletPuff\"[, float range = 64.0[, float lifesteal = 0.0[, int lifestealmax = 0[, str armorbonustype = \"ArmorBonus\"[, str meleesound[, str misssound]]]]]]]]])";
-	A_FireBullets = "A_FireBullets(int spread_horz, int spread_vert, int numbullets, int damage[, str pufftype = \"\"[, int flags = FBF_USEAMMO[, float range = 0.0]]])";
+	A_FireBullets = "A_FireBullets(int spread_horz, int spread_vert, int numbullets, int damage[, str pufftype = \"\"[, int flags = FBF_USEAMMO[, float range = 0.0[, str missile = \"none\"[, float spawnheight = 32.0[, float spawnofs_xy = 0.0]]]]]])";
 	A_FireCustomMissile = "A_FireCustomMissile(str missiletype[, int angle = 0[, bool useammo = false[, float spawnofs_horz = 0.0[, int spawnheight = 0[, int flags = 0[, angle pitch = 0]]]]]])";
 	A_RailAttack = "A_RailAttack(int damage[, int spawnofs_horz[, bool useammo[, str ringcolor[, str corecolor[, int flags[, int maxdiff[, str pufftype[, float spread_xy = 0.0[, float spread_z = 0.0[, float range = 8192.0[, int duration = 35[, float sparsity = 1.0[, float driftspeed = 1.0[, str spawnclass[, float spawnofs_z = 0.0[, int spiraloffset = 270[, int actorpiercelimit = 0]]]]]]]]]]]]]]]]])";
 	A_FireAssaultGun = "A_FireAssaultGun";
@@ -432,7 +432,7 @@ keywords
 //Special functions
 	CheckClass = "bool CheckClass(str classname[, int ptr_select = AAPTR_DEFAULT[, bool match_superclass = false]])";
 	CountInv = "int CountInv(str itemclassname[, int ptr_select = AAPTR_DEFAULT])";
-	GetAngle = "GetAngle(bool relative[, int ptr_target = AAPTR_TARGET])\nGets the angle in degrees (normalized to -180..180)"; 
+	GetAngle = "GetAngle(int flags[, int ptr_target = AAPTR_TARGET])\nGets the angle in degrees (normalized to -180..180)\nflags: GAF flags"; 
 	GetCVar = "int GetCVar(str name)";
 	GetUserCVar = "int GetUserCVar(int playernum, str name)";
 	GetCrouchFactor = "float GetCrouchFactor(int ptr = AAPTR_PLAYER1)";
@@ -825,6 +825,9 @@ constants
 	FBF_EXPLICITANGLE;
 	FBF_NOPITCH;
 	FBF_NORANDOMPUFFZ;
+	FBF_SETTARGET;
+	FBF_SETMASTER;
+	FBF_SETTRACER;
 //monster flags
 	PAF_NOSKULLATTACK;
 	PAF_AIMFACING;
@@ -1117,6 +1120,9 @@ constants
 	CBAF_NOPITCH;
 	CBAF_NORANDOM;
 	CBAF_NORANDOMPUFFZ;
+	CBAF_SETTARGET;
+	CBAF_SETMASTER;
+	CBAF_SETTRACER;
 	CBF_NOLINES;
 	CBF_SETTARGET;
 	CBF_SETMASTER;
@@ -1381,4 +1387,7 @@ constants
 	BFGF_HURTSOURCE;
 //A_RadiusDamageSelf flags
 	RDSF_BFGDAMAGE;
+//GetAngle flags
+	GAF_RELATIVE;
+	GAF_SWITCH;	
 }
diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs
index 6f26d7122..3255a2612 100644
--- a/Source/Core/Data/DataManager.cs
+++ b/Source/Core/Data/DataManager.cs
@@ -1999,7 +1999,7 @@ namespace CodeImp.DoomBuilder.Data
 						// Update the main collection
 						EnumList newenums = new EnumList();
 						newenums.AddRange(configspawnnums.Values);
-						newenums.Sort();
+						newenums.Sort((a, b) => a.Title.CompareTo(b.Title));
 						General.Map.Config.Enums["spawnthing"] = newenums;
 
 						// Update all ArgumentInfos...
@@ -2805,6 +2805,7 @@ namespace CodeImp.DoomBuilder.Data
 			lockableactions = new Dictionary<int, int>();
 			if(keys.Count > 0)
 			{
+				keys.Sort((a, b) => a.Title.CompareTo(b.Title));
 				keys.Insert(0, new EnumItem("0", "None"));
 				General.Map.Config.Enums["keys"] = keys;
 				
diff --git a/Source/Core/GZBuilder/Data/ModelData.cs b/Source/Core/GZBuilder/Data/ModelData.cs
index 3e2207ae1..0c5dcc39a 100644
--- a/Source/Core/GZBuilder/Data/ModelData.cs
+++ b/Source/Core/GZBuilder/Data/ModelData.cs
@@ -41,7 +41,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
 		internal bool OverridePalette; // Used for voxel models only 
 		internal float AngleOffset; // Used for voxel models only
 		internal bool InheritActorPitch;
-		internal bool InheritActorRoll;
+		internal bool UseActorPitch;
+		internal bool UseActorRoll;
 
 		internal bool IsVoxel;
 
@@ -90,8 +91,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
 		internal void SetTransform(Matrix rotation, Matrix offset, Vector3 scale)
 		{
 			this.scale = scale;
-			this.transform = rotation * Matrix.Scaling(scale) * offset;
-			this.transformstretched = rotation * Matrix.Scaling(scale.X, scale.Y, scale.Z * Renderer3D.GZDOOM_INVERTED_VERTICAL_VIEW_STRETCH) * offset;
+			transform = rotation * Matrix.Scaling(scale) * offset;
+			transformstretched = Matrix.Scaling(1.0f, 1.0f, Renderer3D.GZDOOM_INVERTED_VERTICAL_VIEW_STRETCH) * transform;
 		}
 
 		//mxd. This greatly speeds up Dictionary lookups
diff --git a/Source/Core/Map/Thing.cs b/Source/Core/Map/Thing.cs
index aee4b4100..998a905a7 100644
--- a/Source/Core/Map/Thing.cs
+++ b/Source/Core/Map/Thing.cs
@@ -443,8 +443,9 @@ namespace CodeImp.DoomBuilder.Map
 			BeforePropsChange();
 
 			pitch = General.ClampAngle(newpitch);
-			pitchrad = ((rendermode == ThingRenderMode.FLATSPRITE || (rendermode == ThingRenderMode.MODEL && General.Map.Data.ModeldefEntries[type].InheritActorPitch))
-				? Angle2D.DegToRad(pitch) : 0);
+			ModelData md = General.Map.Data.ModeldefEntries[type];
+			pitchrad = ((rendermode == ThingRenderMode.FLATSPRITE || (rendermode == ThingRenderMode.MODEL && (md.InheritActorPitch || md.UseActorPitch)))
+				? Angle2D.DegToRad(md.InheritActorPitch ? -pitch : pitch) : 0);
 
 			if(type != General.Map.Config.Start3DModeThingType)
 				General.Map.IsChanged = true;
@@ -456,7 +457,7 @@ namespace CodeImp.DoomBuilder.Map
 			BeforePropsChange();
 
 			roll = General.ClampAngle(newroll);
-			rollrad = ((rollsprite || (rendermode == ThingRenderMode.MODEL && General.Map.Data.ModeldefEntries[type].InheritActorRoll))
+			rollrad = ((rollsprite || (rendermode == ThingRenderMode.MODEL && General.Map.Data.ModeldefEntries[type].UseActorRoll))
 				? Angle2D.DegToRad(roll) : 0);
 
 			if(type != General.Map.Config.Start3DModeThingType)
@@ -555,8 +556,9 @@ namespace CodeImp.DoomBuilder.Map
 			switch(rendermode)
 			{
 				case ThingRenderMode.MODEL:
-					rollrad = (General.Map.Data.ModeldefEntries[type].InheritActorRoll ? Angle2D.DegToRad(roll) : 0);
-					pitchrad = (General.Map.Data.ModeldefEntries[type].InheritActorPitch ? Angle2D.DegToRad(pitch) : 0);
+					ModelData md = General.Map.Data.ModeldefEntries[type];
+					rollrad = (md.UseActorRoll ? Angle2D.DegToRad(roll) : 0);
+					pitchrad = ((md.InheritActorPitch || md.UseActorPitch) ? Angle2D.DegToRad(md.InheritActorPitch ? -pitch : pitch) : 0);
 					break;
 
 				case ThingRenderMode.FLATSPRITE:
diff --git a/Source/Core/Rendering/Renderer2D.cs b/Source/Core/Rendering/Renderer2D.cs
index 51b924ee6..60f7f2b3d 100644
--- a/Source/Core/Rendering/Renderer2D.cs
+++ b/Source/Core/Rendering/Renderer2D.cs
@@ -1467,7 +1467,7 @@ namespace CodeImp.DoomBuilder.Rendering
 							float sy = t.ScaleY * t.ActorScale.Height;
 							
 							Matrix modelscale = Matrix.Scaling(sx, sx, sy);
-							Matrix rotation = Matrix.RotationY(-t.RollRad) * Matrix.RotationX(t.PitchRad) * Matrix.RotationZ(t.Angle);
+							Matrix rotation = Matrix.RotationY(-t.RollRad) * Matrix.RotationX(-t.PitchRad) * Matrix.RotationZ(t.Angle);
 							Matrix position = Matrix.Translation(screenpos.x, screenpos.y, 0.0f);
 							Matrix world = General.Map.Data.ModeldefEntries[t.Type].Transform * modelscale * rotation * viewscale * position;
 
diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs
index 479d8cd0f..ce5e31d1a 100644
--- a/Source/Core/Rendering/Renderer3D.cs
+++ b/Source/Core/Rendering/Renderer3D.cs
@@ -19,7 +19,6 @@
 using System;
 using System.Collections.Generic;
 using System.Drawing;
-using CodeImp.DoomBuilder.Config;
 using CodeImp.DoomBuilder.Data;
 using CodeImp.DoomBuilder.Geometry;
 using CodeImp.DoomBuilder.GZBuilder.Data;
@@ -1444,7 +1443,7 @@ namespace CodeImp.DoomBuilder.Rendering
 					float sy = t.Thing.ScaleY * t.Thing.ActorScale.Height;
 
 					Matrix modelscale = Matrix.Scaling(sx, sx, sy);
-					Matrix modelrotation = Matrix.RotationY(-t.Thing.RollRad) * Matrix.RotationX(t.Thing.PitchRad) * Matrix.RotationZ(t.Thing.Angle);
+					Matrix modelrotation = Matrix.RotationY(-t.Thing.RollRad) * Matrix.RotationX(-t.Thing.PitchRad) * Matrix.RotationZ(t.Thing.Angle);
 
 					world = General.Map.Data.ModeldefEntries[t.Thing.Type].Transform * modelscale * modelrotation * t.Position;
 					ApplyMatrices3D();
@@ -1543,7 +1542,7 @@ namespace CodeImp.DoomBuilder.Rendering
 				float sy = t.Thing.ScaleY * t.Thing.ActorScale.Height;
 
 				Matrix modelscale = Matrix.Scaling(sx, sx, sy);
-				Matrix modelrotation = Matrix.RotationY(-t.Thing.RollRad) * Matrix.RotationX(t.Thing.PitchRad) * Matrix.RotationZ(t.Thing.Angle);
+				Matrix modelrotation = Matrix.RotationY(-t.Thing.RollRad) * Matrix.RotationX(-t.Thing.PitchRad) * Matrix.RotationZ(t.Thing.Angle);
 
 				world = General.Map.Data.ModeldefEntries[t.Thing.Type].Transform * modelscale * modelrotation * t.Position;
 				ApplyMatrices3D();
diff --git a/Source/Core/ZDoom/MapinfoParser.cs b/Source/Core/ZDoom/MapinfoParser.cs
index 7d6ddb990..83166fd45 100644
--- a/Source/Core/ZDoom/MapinfoParser.cs
+++ b/Source/Core/ZDoom/MapinfoParser.cs
@@ -412,7 +412,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 			bool classicformat = !NextTokenIs("{", false);
 			
 			// Track brace level
-			int bracelevel = 0;
+			int bracelevel = (classicformat ? 0 : 1); // Track map block opening brace
 
 			// Parse required values
 			while(SkipWhitespace(true))
diff --git a/Source/Core/ZDoom/ModeldefParser.cs b/Source/Core/ZDoom/ModeldefParser.cs
index 30280d58b..62654eaa0 100644
--- a/Source/Core/ZDoom/ModeldefParser.cs
+++ b/Source/Core/ZDoom/ModeldefParser.cs
@@ -92,7 +92,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 							if(mds.Frames.ContainsKey(targetsprite))
 							{
 								// Create model data
-								ModelData md = new ModelData { InheritActorPitch = mds.InheritActorPitch, InheritActorRoll = mds.InheritActorRoll };
+								ModelData md = new ModelData { InheritActorPitch = mds.InheritActorPitch, UseActorPitch = mds.UseActorPitch, UseActorRoll = mds.UseActorRoll };
 
 								// Things are complicated in GZDoom...
 								Matrix moffset = Matrix.Translation(mds.Offset.Y, -mds.Offset.X, mds.Offset.Z);
diff --git a/Source/Core/ZDoom/ModeldefStructure.cs b/Source/Core/ZDoom/ModeldefStructure.cs
index af5dbc678..b4b0dcbb0 100644
--- a/Source/Core/ZDoom/ModeldefStructure.cs
+++ b/Source/Core/ZDoom/ModeldefStructure.cs
@@ -42,7 +42,8 @@ namespace CodeImp.DoomBuilder.ZDoom
 		private float pitchoffset;
 		private float rolloffset;
 		private bool inheritactorpitch;
-		private bool inheritactorroll;
+		private bool useactorpitch;
+		private bool useactorroll;
 
 		private Dictionary<string, HashSet<FrameStructure>> frames;
 
@@ -58,7 +59,8 @@ namespace CodeImp.DoomBuilder.ZDoom
 		public float PitchOffset { get { return pitchoffset; } }
 		public float RollOffset { get { return rolloffset; } }
 		public bool InheritActorPitch { get { return inheritactorpitch; } }
-		public bool InheritActorRoll { get { return inheritactorroll; } }
+		public bool UseActorPitch { get { return useactorpitch; } }
+		public bool UseActorRoll { get { return useactorroll; } }
 
 		public Dictionary<string, HashSet<FrameStructure>> Frames { get { return frames; } }
 
@@ -297,8 +299,25 @@ namespace CodeImp.DoomBuilder.ZDoom
 						}
 						break;
 
-					case "inheritactorpitch": inheritactorpitch = true; break;
-					case "inheritactorroll": inheritactorroll = true; break;
+					case "useactorpitch":
+						inheritactorpitch = false;
+						useactorpitch = true;
+						break;
+
+					case "useactorroll":
+						useactorroll = true;
+						break;
+
+					case "inheritactorpitch":
+						inheritactorpitch = true;
+						useactorpitch = false;
+						parser.LogWarning("INHERITACTORPITCH flag is deprecated. Consider using USEACTORPITCH flag instead");
+						break;
+
+					case "inheritactorroll": 
+						useactorroll = true;
+						parser.LogWarning("INHERITACTORROLL flag is deprecated. Consider using USEACTORROLL flag instead");
+						break;
 
 					//FrameIndex <XXXX> <X> <model index> <frame number>
 					case "frameindex":
-- 
GitLab