[ZScript] DropItem Amount Changed To ReadOnly?

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
User avatar
Lycanite
Posts: 41
Joined: Thu Apr 13, 2017 12:28 pm

[ZScript] DropItem Amount Changed To ReadOnly?

Post by Lycanite »

I currently use this class to map cvars to random monster spawners so that I can pick and choose what groups of monsters spawner via cvars.

Code: Select all

class CVARRandomSpawner : RandomSpawner
{
	override void BeginPlay()
	{
		int cvarAmountMin = 15;
		int cvarAmountMax = 19;
		string cvarAmountMap[20];
		cvarAmountMap[15] = 'spawners_nephrite';
		cvarAmountMap[16] = 'spawners_doom';
		cvarAmountMap[17] = 'spawners_heretic';
		cvarAmountMap[18] = 'spawners_hexen';
		cvarAmountMap[19] = 'spawners_blood';
		
		DropItem dropIter = GetDropItems();
		string lastNonCvarDrop = "";
		while (dropIter != null)
		{
			if (dropIter.Amount >= cvarAmountMin && dropIter.Amount <= cvarAmountMax)
			{
				CVar amountCvar = CVar.FindCVar(cvarAmountMap[dropIter.Amount]);
				int amount = amountCvar.GetInt();
				dropIter.Amount = amount;
			}
			else
			{
				lastNonCvarDrop = dropIter.Name;
			}
			dropIter = dropIter.Next;
		}
		
		Super.BeginPlay ();
	}
}
But it seems that Amount is now read only in the latest builds so I can no longer change it on this line

Code: Select all

dropIter.Amount = amount;
What's the workaround for this or is there a better way to do this in general?
User avatar
Lycanite
Posts: 41
Joined: Thu Apr 13, 2017 12:28 pm

Re: [ZScript] DropItem Amount Changed To ReadOnly?

Post by Lycanite »

So in the end I decided just to copy the BeginPlay from the RandomSpawner class and just modify it from there, seems to work well again.

Code: Select all

class CVARRandomSpawner : RandomSpawner
{
	override void BeginPlay()
	{
		DropItem di;   // di will be our drop item list iterator
		DropItem drop; // while drop stays as the reference point.
		int n = 0;
		bool nomonsters = sv_nomonsters || level.nomonsters;

		//Super.BeginPlay();
		drop = di = GetDropItems();
		if (di != null)
		{
			while (di != null)
			{
				if (di.Name != 'None')
				{
					if (!nomonsters || !IsMonster(di))
					{
						int amt = getCVARAmount (di.Amount);
						if (amt < 0) amt = 1; // default value is -1, we need a positive value.
						n += amt; // this is how we can weight the list.
					}
					di = di.Next;
				}
			}
			if (n == 0)
			{ // Nothing left to spawn. They must have all been monsters, and monsters are disabled.
				Destroy();
				return;
			}
			
			// Then we reset the iterator to the start position...
			di = drop;
			
			// Take a random number...
			n = random[randomspawn](0, n-1);
			
			// And iterate in the array up to the random number chosen.
			while (n > -1 && di != null)
			{
				if (di.Name != 'None' &&
					(!nomonsters || !IsMonster(di)))
				{
					int amt = getCVARAmount (di.Amount);
					if (amt < 0) amt = 1;
					n -= amt;
					if ((di.Next != null) && (n > -1))
						di = di.Next;
					else
						n = -1;
				}
				else
				{
					di = di.Next;
				}
			}
			
			// So now we can spawn the dropped item.
			if (di == null || bouncecount >= MAX_RANDOMSPAWNERS_RECURSION)	// Prevents infinite recursions
			{
				Spawn("Unknown", Pos, NO_REPLACE);		// Show that there's a problem.
				Destroy();
				return;
			}
			else if (random[randomspawn]() <= di.Probability)	// prob 255 = always spawn, prob 0 = almost never spawn.
			{
				// Handle replacement here so as to get the proper speed and flags for missiles
				Class<Actor> cls = di.Name;
				if (cls != null)
				{
					Class<Actor> rep = GetReplacement(cls);
					if (rep != null)
					{
						cls = rep;
					}
				}
				if (cls != null)
				{
					Species = Name(cls);
					readonly<Actor> defmobj = GetDefaultByType(cls);
					Speed = defmobj.Speed;
					bMissile |= defmobj.bMissile;
					bSeekerMissile |= defmobj.bSeekerMissile;
					bSpectral |= defmobj.bSpectral;
				}
				else
				{
					A_Log(TEXTCOLOR_RED .. "Unknown item class ".. di.Name .." to drop from a cvar random spawner\n");
					Species = 'None';
				}
			}
		}
	}
	
	int getCVARAmount (int amt)
	{
		int cvarAmountMin = 15;
		int cvarAmountMax = 19;
		string cvarAmountMap[20];
		cvarAmountMap[15] = 'spawners_nephrite';
		cvarAmountMap[16] = 'spawners_doom';
		cvarAmountMap[17] = 'spawners_heretic';
		cvarAmountMap[18] = 'spawners_hexen';
		cvarAmountMap[19] = 'spawners_blood';
		
		if (amt >= cvarAmountMin && amt <= cvarAmountMax)
		{
			CVar amountCvar = CVar.FindCVar(cvarAmountMap[amt]);
			amt = amountCvar.GetInt();
		}
		
		return amt;
	}
}
I suppose I should look into adding my own struct or something which can hold more information rather than using the amount as a hack, but this works for now!

Return to “Scripting”