Permanent Armor and Upgrades?

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!
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!)
Post Reply
User avatar
NeoTerraNova
Posts: 153
Joined: Tue Mar 14, 2017 5:18 pm
Location: Western North Southlandia (East Side)

Permanent Armor and Upgrades?

Post by NeoTerraNova »

Greetings and happy holiday season to everyone. Once more, I find myself in need of help, and I'm grateful to anyone that can assist me. Thank you in advance to anyone that stops by.


For various reasons, I'd like to mess around with the armor system. I have a feeling this isn't going to be simple, so I'm prepared to get this done in ZScript. If some simpler, down-scaled version is possible in DECORATE, I'd accept that. My problem is, I have no idea how to go about this, and I've searched the Forum already, and the Wiki, for answers.

My goal is this:
-Have a number of Armor Items in the game. These items would not have "Armor Points" to them in the conventional DOOM sense. Instead, they would be permanent upgrades that never go away. Of course, each would be different, etc.

-(Optional but desired) Have upgrades available. Each "Grade" of armor, from the starting armor to the best armor, would each have a specific number of possible upgrade slots. Each upgrade would add a bonus damage reduction to them (i.e. how conventional BasicArmorPickup can do). This should be stackable somehow. I'd like it if these upgrades were permanent and not removable from the armor they're attached to. These upgrades would be rare drops from certain enemies.

-Set up the spawner so that it never spawns an "inferior Grade" of armor to pick up, always a superior one. My intent is to more or less replace the BlueArmor spawners with at least a chance of finding one of these Permanent Armors, but only be able to find the "nextmost superior" armor (so the Player doesn't go from Grade 1 armor to Grade 5 because of a lucky spawn).

-Set up the Armor so that, if by some chance there IS an "inferior grade" of armor spawned somehow, the player can't pick it up by accident. Equal grade? I don't really care. Whatever's easier.

-I wouldn't care if the Armor could be conventionally discarded/respawned, or was simply destroyed when "superior Grade" armor is picked up.


My main problems are.. well, first, I can't seem to find a code snippet for Armor in ZScript on the Wiki to look at and try and learn from, as a starting point. Second, I have no idea how I'd pull off the Armor Upgrades. And, third, of course, I don't know how to lock out the spawner so it behaves how I want it to.


I realize this may be a very tall order to sort out, but I would be immensely thankful to anyone that can at least point me in the right direction. Thank you all for your time.
User avatar
Dan_The_Noob
Posts: 880
Joined: Tue May 07, 2019 12:24 pm
Graphics Processor: nVidia with Vulkan support
Contact:

Re: Permanent Armor and Upgrades?

Post by Dan_The_Noob »

DamageFactor is the actor property you would probably use for this. or you could just have armor that is infinite and applies the damage reduction in the same way as normal doom armor.
User avatar
NeoTerraNova
Posts: 153
Joined: Tue Mar 14, 2017 5:18 pm
Location: Western North Southlandia (East Side)

Re: Permanent Armor and Upgrades?

Post by NeoTerraNova »

I'm sorry, I don't understand what you're saying. I don't know how to make armor "infinite" in the first place - setting its saveamount to negative one (-1) doesn't do anything, and beyond that, I have no idea how else to make this work. I know how to make custom armor through BasicArmorPickup and BasicArmorBonus, and I know what the DamageFactor flags are for - I mentioned this in my post, though somewhat obtusely. I'm sorry if I didn't make this clear. I have made "standard" armor in the past that does things beyond the scope of BlueArmor and GreenArmor, but they've all been standard Armor-type Actors, with a normal saveamount (Armor Points, if you will).

I understand the basic concept of armor in DECORATE and how to work it, but with what I'm trying to do, I think I need ZScript to pull off. Part of the problem I'm having is that there's no examples of either GreenArmor or BlueArmor in ZScript on the Wiki for me to look at and get some idea of where to start.

I appreciate the answer, Dan, but I'm afraid it didn't help my situation any. Thank you very much for taking the time to respond, though!
User avatar
Virathas
Posts: 254
Joined: Thu Aug 10, 2017 9:38 am

Re: Permanent Armor and Upgrades?

Post by Virathas »

It is all doable in ZScript, and actually not that hard.

First thing, is to think of it differently, do not think that you need to redesign the armor system. For this you need just inventory.

ripping and editing part of my code:

Code: Select all

class MMFlatSpiritualArmor : Inventory 
{
	Default
	{
		Inventory.Amount 1;
		Inventory.MaxAmount 1;
		Inventory.PickupMessage "You've picked up a Spritiual Armor";
	}

	States
	{
	Spawn:
		SPAR ABCDEFGHIJKJIHGFEDCB 2 Bright;
		Loop;
	}

	override void AbsorbDamage (int damage, Name damageType, out int newdamage)
	{
				if (damage <= 10)
				{
				newdamage = 0;
				}
				else
				{
				newdamage = damage - 10;
				}
	}
}
this simple item, once picked up, will cause all damage taken to be reduced by 10. If you want to have a percentage reduction you can simple add that to the equation, and if DamageFactors are required, there is a function [wiki]ApplyDamageFactors[/wiki]

For the spawner, it is significantly harder, but still doable. I don't have any piece of code for this, the best i can do is to send you to viewtopic.php?f=122&t=70725, but it is most definitely harder

Pickup control:

Simple really:

part of the item's code:

Code: Select all

	override bool TryPickup (in out Actor toucher)
	{
if (Toucher.CountInv("BetterArmor)
return false;
return Super.TryPickup(toucher);
        }
This simple code snippet will block pickup if the owner has that particular item. You could have a specific property in your armor that denotes grades, or you could simply have a list of items here.

Discarding armor might be actually more difficult here to do, But simply removing is not a problem:

You could actually create additional conditions in the "TryPickup" method, after "Super.TryPickup(toucher);" resolves:

Code: Select all

	override bool TryPickup (in out Actor toucher)
	{
if (Toucher.CountInv("BetterArmor)
return false;
bool WeGood = Super.TryPickup(toucher);
if (WeGood)
{
Toucher.TakeInventory("CrapArmor, 1)'
return true;
}
else
{
 return false
}
return true;
        }
BONUS UPGRADES:
Yup, fully doable. First, defne two new variables to the new item (Let's call it ArmorBase). "int slotsused" and "int maxslots".
Now we need a pickup item it can be extremely simple item, with no actual functionality, let us call it ArmorUpgrade.
Next we need to create a function in the ArmorBase:

Code: Select all

	override bool HandlePickup (Inventory item)
	{
		if (item.GetClass() == "ArmorUpgrade")
		{
                    if (slotsused < maxslots)
                    {
                     slotsused++;
                    return true;
                   }
		}
                item.bPickupGood = false;
		return false;
	}
(This part of the code is untested, but should at the very least help you start. HandlePickup is called by every single inventory item when attempting to pickup any item, this is how ammo intercepts the pickups, and adds it where it should)

Once we have all this, all that remains is to add the benefits of this armor. Using this in ArmorBase

Code: Select all

	override void AbsorbDamage (int damage, Name damageType, out int newdamage)
	{
				if (damage <= 5 + slotsused)
				{
				newdamage = 0;
				}
				else
				{
				newdamage = damage - (5 + slotsused);
				}
	}
And that should be it :)
If you have any questions, i am here to help.
User avatar
NeoTerraNova
Posts: 153
Joined: Tue Mar 14, 2017 5:18 pm
Location: Western North Southlandia (East Side)

Re: Permanent Armor and Upgrades?

Post by NeoTerraNova »

I'll give this a shot and see what I can come up with. Thank you, again!

EDIT:
For this you need just inventory.
Honestly, I never would have thought of this. Never. I was thinking I had to construct a new Armor thing from scratch, or base it on the existing Armor definitions. Thank you! This solves a lot of problems and kinda somewhat puts me on familiar ground (manipulating things using Inventory).
If you want to have a percentage reduction you can simple add that to the equation, and if DamageFactors are required, there is a function ApplyDamageFactors

..uh, I apologize, where do I add this, exactly? I've only found one code snippet that mentions this, and it's from: viewtopic.php?f=122&t=67423 and the code isn't something I can understand.

Would I create a new array under the ArmorBase, that specifically returns the mathematics of calculating damage against each damage source, since I would prefer to list each incoming damage type and its specific reductions, or would I just add a small line like seen in the code snippet in the first post to the link above? I apologize for asking, but I don't have an example to learn from.

For example, the Grade2Armor item I intend to code would reduce damage from physical hits by 5% (Imp Punches, Demon attacks), Bullet damage by 25% (Zombiemen), and Fire Damage by 12% (Imp Fireballs). Do I need a specific ApplyDamageFactors for each one, and how do I list them in the code?

For the spawner, it is significantly harder, but still doable.
I see that code, and.. I have to ask if there's just a simple method of putting CheckInventory into the spawner's code, and if it returns True, then spawn X item.

For example:
-Player Character starts the level wearing Grade 2 Armor.
-There's a matching Spawner on the level that can give Armor
-Spawner checks to see what Grade of Armor the Player is equipped with at the start of the level. It returns a result of "Grade2Armor."
-Spawner then generates a pickup from a list of possible matches (Grade3Armor, Grade2Armor, random ArmorUpgrade)

For various reasons, of course, multiple matching spawners in the same Level could be.. problematic to the Player, though I would consider this intentional, even on rare levels where there's more than one regular Doom Armor Spawner, I'd consider it logical and fitting for semi-real-world chance that the Player Character might have bad luck and not find superior armor at these spawn points, or find multiple of the same armor, etc. - things to chalk up to RNGsus and simple good or bad luck.

I will admit that while I comprehend the concept here, I don't know how to program the code for it.

EDIT 2:
Discarding armor might be actually more difficult here to do,
This part I figured out on my own. Since I'm running with a usable Inventory, I just made it accessible through that, and discardable normally. Once I realized I could make this a normal Inventory Item, this part made sense once I started messing with the code and such.


Thank you very much for your patience, and your continued help and support.
User avatar
Virathas
Posts: 254
Joined: Thu Aug 10, 2017 9:38 am

Re: Permanent Armor and Upgrades?

Post by Virathas »

For the damage factors reduction you can look into PowerProtection in GZDoom.pk3.

Generally, ApplyDamageFactor is a convienient function that uses the earlier defined "DamageFactor" to modify the resulting damage.

The line code that interests you the most is

Code: Select all

	override void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive, Actor inflictor, Actor source, int flags)
	{
		if (passive && damage > 0)
		{
			newdamage = max(0, ApplyDamageFactors(GetClass(), damageType, damage, damage / 4));
			if (Owner != null && newdamage < damage) Owner.A_StartSound(ActiveSound, CHAN_AUTO, CHANF_DEFAULT, 1.0, ATTN_NONE);
		}
	}
Note that in the earlier example i used [wiki]AbsorbDamage[/wiki] instead of [wiki]ModifyDamage[/wiki]. The main reason is I wanted it to work before any protection powerups. Wiki has more info about both of them.

A simple item code to show it in work:

Code: Select all

class MMFlatSpiritualArmor : Inventory
{
   Default
   {
      Inventory.Amount 1;
      Inventory.MaxAmount 1;
      Inventory.PickupMessage "You've picked up a Spritiual Armor";
      damagefactor "Fire", 0.88;
      damagefactor "Normal", 0.95;
   }

   States
   {
   Spawn:
      SPAR ABCDEFGHIJKJIHGFEDCB 2 Bright;
      Loop;
   }

   override void AbsorbDamage (int damage, Name damageType, out int newdamage)
   {
	newdamage = max(0, ApplyDamageFactors(GetClass(), damageType, damage, damage / 4));
	if (Owner != null && newdamage < damage) Owner.A_PlaySound(ActiveSound, CHAN_AUTO, 1.0, false, ATTN_NONE);
   }
}
To be fair, i have not tried changing those factors "dynamically". You could however, just use your own "system" for this. For example define a new variable "FireReduction" and do something as simple as that.

Code: Select all

   override void AbsorbDamage (int damage, Name damageType, out int newdamage)
   {
        if (damageType == "Fire")
	newdamage = damage * FireReduction;
        else
        newdamage = damage;
   }
For the spawner? If you're willing to wait, i think i can repurpose my spawner system to allow "easy edit".

It would go exactly as your example, includingf the RNG "issues" that could happen.
User avatar
NeoTerraNova
Posts: 153
Joined: Tue Mar 14, 2017 5:18 pm
Location: Western North Southlandia (East Side)

Re: Permanent Armor and Upgrades?

Post by NeoTerraNova »

See, this is what I thought - I'd be using some set of arrays (if that's the proper term) within the Actor to quantify damage reduction per damage type that a specific Armor protects against. When I get a chance, I'll code this up and run it through, and report the results.

As for the spawner - take all the time you need. I hope to learn ZScript better by seeing these examples and working with them. I'm not in any rush.

Thank you again for your continued help.
User avatar
Virathas
Posts: 254
Joined: Thu Aug 10, 2017 9:38 am

Re: Permanent Armor and Upgrades?

Post by Virathas »

Got you the spawner, it is pretty robust so i put it in a spoiler.

It contains several actors that are just placeholders, to show what is needed for it to work
Afterwards there is "EditableSpawner" - which is "the spawner you actually want to spawn in the map (either via map, or replaces XXXX)
Then there is SuperSpawner, which is the actual meat, the spawner itself. Unless you have multiple playerclasses that you'd like them to have items filtered in terms of random spawners - you don't have to edit at all.

The main assumptions of the code:
- each armor grade inherits from a single class (ArmorBase in this code).
- Mutiplayer support - we don't check only the highest armor quality, we check both lowest and highest, and choosing based on that.
- There is no "safety" code for cases that player hass several armorgrades at the same time, i.e. gets level2 armor and then level1 -> this would break the spawner, making it think that the player has only level1 (It would check the "latest obtained)

I did test the code a little and all seems as "intended"
Spoiler:
If you still have questions, or would like some adjustments, feel free to ask :)
User avatar
NeoTerraNova
Posts: 153
Joined: Tue Mar 14, 2017 5:18 pm
Location: Western North Southlandia (East Side)

Re: Permanent Armor and Upgrades?

Post by NeoTerraNova »

This is amazing. Thank you so much. I'm still testing the last hunk of code you gave me, and trying to integrate it. I will keep you updated. If it takes too long for me to get this done because of IRL issues, I'll just PM you if I have troubles, rather than necro-bump this post.

Again, thank you so very much!
Post Reply

Return to “Scripting”