From db1f2153277382861becb8bcda9014ea5842b874 Mon Sep 17 00:00:00 2001
From: MascaraSnake <jonassauer27@gmail.com>
Date: Mon, 20 Dec 2021 21:14:39 +0100
Subject: [PATCH] Implement generic item rows and circles

---
 extras/conf/udb/Includes/SRB222_things.cfg | 40 ++++++++++++++++
 src/m_cheat.c                              |  4 +-
 src/p_mobj.c                               | 56 ++++++++++++++++++++--
 src/p_setup.c                              | 12 ++---
 4 files changed, 101 insertions(+), 11 deletions(-)

diff --git a/extras/conf/udb/Includes/SRB222_things.cfg b/extras/conf/udb/Includes/SRB222_things.cfg
index cd9d360c8..86fe6b1a5 100644
--- a/extras/conf/udb/Includes/SRB222_things.cfg
+++ b/extras/conf/udb/Includes/SRB222_things.cfg
@@ -4397,6 +4397,46 @@ udmf
 			sprite = "SPHRA0";
 			width = 192;
 		}
+		610
+		{
+			title = "Row of Items";
+			sprite = "RINGA0";
+			arg0
+			{
+				title = "Number of items";
+			}
+			arg1
+			{
+				title = "Horizontal spacing";
+			}
+			arg2
+			{
+				title = "Vertical spacing";
+			}
+			stringarg0
+			{
+				title = "Object types";
+			}
+		}
+		611
+		{
+			title = "Circle of Items";
+			sprite = "RINGA0";
+			width = 96;
+			height = 192;
+			arg0
+			{
+				title = "Number of items";
+			}
+			arg1
+			{
+				title = "Radius";
+			}
+			stringarg0
+			{
+				title = "Object types";
+			}
+		}
 	}
 
 	invisible
diff --git a/src/m_cheat.c b/src/m_cheat.c
index 52202f808..ddc1f6f29 100644
--- a/src/m_cheat.c
+++ b/src/m_cheat.c
@@ -1283,7 +1283,7 @@ void OP_NightsObjectplace(player_t *player)
 		mt = OP_CreateNewMapThing(player, (UINT16)cv_mapthingnum.value, false);
 		mt->angle = angle;
 
-		if (mt->type >= 600 && mt->type <= 609) // Placement patterns
+		if (mt->type >= 600 && mt->type <= 611) // Placement patterns
 			P_SpawnItemPattern(mt, false);
 		else if (mt->type == 1713) // NiGHTS Hoops
 			P_SpawnHoop(mt);
@@ -1414,7 +1414,7 @@ void OP_ObjectplaceMovement(player_t *player)
 			return;
 
 		mt = OP_CreateNewMapThing(player, (UINT16)spawnthing, ceiling);
-		if (mt->type >= 600 && mt->type <= 609) // Placement patterns
+		if (mt->type >= 600 && mt->type <= 611) // Placement patterns
 			P_SpawnItemPattern(mt, false);
 		else if (mt->type == 1713) // NiGHTS Hoops
 			P_SpawnHoop(mt);
diff --git a/src/p_mobj.c b/src/p_mobj.c
index 4d5784129..beed59e8f 100644
--- a/src/p_mobj.c
+++ b/src/p_mobj.c
@@ -11877,7 +11877,7 @@ static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing)
 		return true;
 	}
 	else if (mthing->type == 750 // Slope vertex point (formerly chaos spawn)
-		     || (mthing->type >= 600 && mthing->type <= 609) // Special placement patterns
+		     || (mthing->type >= 600 && mthing->type <= 611) // Special placement patterns
 		     || mthing->type == 1713) // Hoops
 		return true; // These are handled elsewhere.
 	else if (mthing->type == mobjinfo[MT_EMERHUNT].doomednum)
@@ -13373,7 +13373,7 @@ void P_SetBonusTime(mobj_t *mobj)
 	P_SetMobjState(mobj, mobj->info->raisestate);
 }
 
-static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t* itemtypes, UINT8 numitemtypes, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime)
+static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 numitemtypes, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime)
 {
 	mapthing_t dummything;
 	mobj_t *mobj = NULL;
@@ -13424,7 +13424,7 @@ static void P_SpawnItemRow(mapthing_t *mthing, mobjtype_t* itemtypes, UINT8 numi
 	}
 }
 
-static void P_SpawnSingularItemRow(mapthing_t* mthing, mobjtype_t itemtype, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime)
+static void P_SpawnSingularItemRow(mapthing_t *mthing, mobjtype_t itemtype, INT32 numitems, fixed_t horizontalspacing, fixed_t verticalspacing, INT16 fixedangle, boolean bonustime)
 {
 	mobjtype_t itemtypes[1] = { itemtype };
 	return P_SpawnItemRow(mthing, itemtypes, 1, numitems, horizontalspacing, verticalspacing, fixedangle, bonustime);
@@ -13488,6 +13488,35 @@ static void P_SpawnItemCircle(mapthing_t *mthing, mobjtype_t *itemtypes, UINT8 n
 	}
 }
 
+static void P_ParseItemTypes(char *itemstring, mobjtype_t *itemtypes, UINT8 *numitemtypes)
+{
+	char *tok;
+
+	*numitemtypes = 0;
+	if (itemstring)
+	{
+		char *stringcopy = Z_Malloc(strlen(itemstring) + 1, PU_LEVEL, NULL);
+		M_Memcpy(stringcopy, itemstring, strlen(itemstring));
+		stringcopy[strlen(itemstring)] = '\0';
+
+		tok = strtok(stringcopy, " ");
+		while (tok && *numitemtypes < 128)
+		{
+			itemtypes[*numitemtypes] = get_number(tok);
+			tok = strtok(NULL, " ");
+			(*numitemtypes)++;
+		}
+
+		Z_Free(stringcopy);
+	}
+	else
+	{
+		//If no types are supplied, default to ring
+		itemtypes[0] = MT_RING;
+		*numitemtypes = 1;
+	}
+}
+
 void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime)
 {
 	switch (mthing->type)
@@ -13525,6 +13554,27 @@ void P_SpawnItemPattern(mapthing_t *mthing, boolean bonustime)
 		P_SpawnItemCircle(mthing, itemtypes, 2, numitems, size, bonustime);
 		return;
 	}
+	case 610: // Generic item row
+	{
+		mobjtype_t itemtypes[128]; //If you want to have a row with more than 128 different object types, you're crazy.
+		UINT8 numitemtypes;
+		if (!udmf)
+			return;
+		P_ParseItemTypes(mthing->stringargs[0], itemtypes, &numitemtypes);
+		P_SpawnItemRow(mthing, itemtypes, numitemtypes, mthing->args[0], mthing->args[1] << FRACBITS, mthing->args[2] << FRACBITS, mthing->angle, bonustime);
+		return;
+	}
+	case 611: // Generic item circle
+	{
+		mobjtype_t itemtypes[128]; //If you want to have a circle with more than 128 different object types, you're crazy.
+		UINT8 numitemtypes;
+		if (!udmf)
+			return;
+		CONS_Printf("Itemstring: %s\n", mthing->stringargs[0]);
+		P_ParseItemTypes(mthing->stringargs[0], itemtypes, &numitemtypes);
+		P_SpawnItemCircle(mthing, itemtypes, numitemtypes, mthing->args[0], mthing->args[1] << FRACBITS, bonustime);
+		return;
+	}
 	default:
 		return;
 	}
diff --git a/src/p_setup.c b/src/p_setup.c
index aafe89ab3..25250b449 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -734,7 +734,7 @@ void P_ReloadRings(void)
 			mt->mobj = NULL;
 			P_SetBonusTime(P_SpawnMapThing(mt));
 		}
-		else if (mt->type >= 600 && mt->type <= 609) // Item patterns
+		else if (mt->type >= 600 && mt->type <= 611) // Item patterns
 		{
 			mt->mobj = NULL;
 			P_SpawnItemPattern(mt, true);
@@ -893,7 +893,7 @@ static void P_SpawnMapThings(boolean spawnemblems)
 
 		mt->mobj = NULL;
 
-		if (mt->type >= 600 && mt->type <= 609) // item patterns
+		if (mt->type >= 600 && mt->type <= 611) // item patterns
 			P_SpawnItemPattern(mt, false);
 		else if (mt->type == 1713) // hoops
 			P_SpawnHoop(mt);
@@ -1701,9 +1701,9 @@ static void ParseTextmapLinedefParameter(UINT32 i, char *param, char *val)
 		P_SetLinedefV1(i, atol(val));
 	else if (fastcmp(param, "v2"))
 		P_SetLinedefV2(i, atol(val));
-	else if (strlen(param) == 7 && fastncmp(param, "arg", 3) && fastncmp(param + 4, "str", 3))
+	else if (fastncmp(param, "stringarg", 9) && strlen(param) > 9)
 	{
-		size_t argnum = param[3] - '0';
+		size_t argnum = atol(param + 9);
 		if (argnum >= NUMLINESTRINGARGS)
 			return;
 		lines[i].stringargs[argnum] = Z_Malloc(strlen(val) + 1, PU_LEVEL, NULL);
@@ -1800,9 +1800,9 @@ static void ParseTextmapThingParameter(UINT32 i, char *param, char *val)
 	else if (fastcmp(param, "ambush") && fastcmp("true", val))
 		mapthings[i].options |= MTF_AMBUSH;
 
-	else if (strlen(param) == 7 && fastncmp(param, "arg", 3) && fastncmp(param + 4, "str", 3))
+	else if (fastncmp(param, "stringarg", 9) && strlen(param) > 9)
 	{
-		size_t argnum = param[3] - '0';
+		size_t argnum = atol(param + 9);
 		if (argnum >= NUMMAPTHINGSTRINGARGS)
 			return;
 		mapthings[i].stringargs[argnum] = Z_Malloc(strlen(val) + 1, PU_LEVEL, NULL);