Screen Armor [Updated 12/4/21]

Post your example zscripts/ACS scripts/etc here.
Forum rules
The Projects forums are only for projects. If you are asking questions about a project, either find that project's thread, or start a thread in the General section instead.

Got a cool project idea but nothing else? Put it in the project ideas thread instead!

Projects for any Doom-based engine (especially 3DGE) are perfectly acceptable here too.

Please read the full rules for more details.
Post Reply
Hey Doomer
Posts: 283
Joined: Sat Sep 25, 2021 3:38 am

Screen Armor [Updated 12/4/21]

Post by Hey Doomer »

While Doom armor provides protection, there's no real indication that anything is happening other than a HUD counter. What if the screen showed some visual indicator of a hit and how much armor was left? Perhaps, this has been addressed by other mods. This is my take.

Code: Select all

class armor_EventHandler : EventHandler
{
	bool bGrid;
	int tCounter;
	int armor;
	
	override void WorldLoaded(WorldEvent e)
	{
		bGrid = false;
	}
	override void RenderOverlay(RenderEvent e)
	{
		if (bGrid)
		{
			color hexColor = "Green";
			int alpha = 255;
			double thickness = 5;
			int edge = 400;

			if (armor < 100)
			{
				alpha = int(255 * armor / 100);
				thickness = 5 * armor / 100;
			}

			for (int cX = 100; cX < Screen.GetWidth(); cX += 100)
			{
				if (cX < edge || cX > Screen.GetWidth() - edge && cX + 40 < Screen.GetWidth())
				{
					for (int cY = 100; cY < Screen.GetHeight() - 50; cY += 100)
					{
						if (Random(0, 100) < armor)
						{
							// top
							Screen.DrawThickLine(cX - 40, cY, cX - 20, cY + 33, thickness, hexColor, alpha);
							Screen.DrawThickLine(cX - 20, cY + 33, cX + 20, cY + 33, thickness, hexColor, alpha);
							Screen.DrawThickLine(cX + 20, cY + 33, cX + 40, cY, thickness, hexColor, alpha);

							// bottom
							Screen.DrawThickLine(cX + 40, cY, cX + 20, cY - 33, thickness, hexColor, alpha);
							Screen.DrawThickLine(cX + 20, cY - 33, cX - 20, cY - 33, thickness, hexColor, alpha);
							Screen.DrawThickLine(cX - 20, cY - 33, cX - 40, cY, thickness, hexColor, alpha);
						}
					}
				}
			}
		}
	}
	override void WorldTick()
	{
		if (tCounter < 14)
		{
			tCounter++;
		}
		else
		{
			bGrid = false;
		}
	}
	override void WorldThingDamaged(WorldEvent e)
	{
		if (e.thing && e.thing is "PlayerPawn")
		{
			armor = e.thing.CountInv("BasicArmor");
			if (armor > 0)
			{
				e.thing.A_StartSound("arhit", CHAN_BODY, CHANF_OVERLAP);
				bGrid = true;
				tCounter = 0;
			}
		}
	}
}
How this works is simple. When a player is damaged if armor is in the inventory a partial screen grid of hexagons flashes on the screen. The number of hexagons drawn varies according to the amount of armor in player inventory. I've added a minimal sound effect, which of course is drowned out in close quarters. I use absolute coordinates for performance reasons, although I suppose drawing these on some kind of curve might be effective.

Can't decide how I feel about this as is - it's a work in progress - but it does the job.
Last edited by Hey Doomer on Sat Dec 04, 2021 4:16 am, edited 2 times in total.
User avatar
Xim
Posts: 2085
Joined: Fri Feb 20, 2009 2:46 pm
Location: somewhere with trees

Re: Screen Armor

Post by Xim »

This would work great for mods that have energy shields for armor. Very good stuff here, good work!
User avatar
Enjay
 
 
Posts: 26534
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Re: Screen Armor

Post by Enjay »

This is a neat idea.

Personally, I think it would be even better if the hexagons were translucent (at values over 100 they have quite a powerful presence on the screen) and it would be nice if there was some colour support for +100 armour too (blue would be an obvious choice).
Hey Doomer
Posts: 283
Joined: Sat Sep 25, 2021 3:38 am

Re: Screen Armor [Updated 12/3/21]

Post by Hey Doomer »

Excellent suggestion, Enjay. I've posted an update after playing around with this adding the following:
  • - Lower alpha (you're right about the screen presence, it should be almost subliminal
    - Drawing hexagons on an arc to simulate a curved HUD (this is not yet optimized)
    - Colors for different armor strengths
If the armor is < 50 it starts to flicker on the screen. Not fancy but seems to work. I balked at the notion of trig functions, but even without angle optimization it works.

The curvature draws a circular arc from either edge to the other with a slightly increasing radius and incremented angle to offset the hexagons. Again not fancy but seems to work, and my HS math teacher would be proud.
User avatar
Enjay
 
 
Posts: 26534
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Re: Screen Armor [Updated 12/3/21]

Post by Enjay »

I think that works really nicely. It definitely makes the mod feel more complete.

I guess the only additional thing I can think of would be some menu options to tailor the effects. Not sure what all the options would be though. An on/off toggle is obvious. Perhaps sound on/off, an alpha scale (so that the alpha of the effect is multiplied by the users preference), colour settings if you feel really ambitious...
User avatar
ramon.dexter
Posts: 1529
Joined: Tue Oct 20, 2015 12:50 pm
Graphics Processor: nVidia with Vulkan support
Location: Kozolupy, Bohemia

Re: Screen Armor [Updated 12/3/21]

Post by ramon.dexter »

May I borrow this for my World of Strife? It's like exactly I was thinking about when I wanted to improve new armor type. Great, just great!

Enjay: Also, armor level detection could be easily applied. It's really wonderful what could be done with zscript. I tried to include this eventhandler into my eventhandler with this slight modification:

Code: Select all

    override void WorldThingDamaged(WorldEvent e) {
        if (e.thing && e.Thing is "binderPlayer") {
            let pawn = binderPlayer(e.Thing);
			If(e.Damage>9/*&&(e.DamageType=="Bullet"||e.DamageType=="Melee")*/) {
				//console.printf(string.format("%i", pawn.bleedlevel));
				pawn.bleedlevel++;				
				If(pawn.bleedlevel>5){pawn.bleedlevel=5;}
			}
            pawn.stamin -= e.Damage*7;
            if (pawn.stamin<0) {
                pawn.stamin = 0;
            }
// modified part //////////////////////////////////////////////////////////////////////////////
			armor = pawn.armoramount; //where pawn.armoramount is integer marking, well, armor amount on player. I'm using jarewill's zscript armor system, so there is no real inventory armor item on player.
			if ( armor > 0 && pawn.currentarmor == 5 ) { //where pawn.currentarmor marks armor level, so this shield effect is displayed only for this one type of armor
				//pawn.A_print("!!!HIT!!!");
				e.thing.A_StartSound("arhit", CHAN_BODY, CHANF_OVERLAP);
				bGrid = true;
				tCounter = 0;
			}
//////////////////////////////////////////////////////////////////////////////////////////////
        }
    }

edit:
Aaand I'm thinking about making several types of differently colored shields for different types/level if armor.
Hey Doomer
Posts: 283
Joined: Sat Sep 25, 2021 3:38 am

Re: Screen Armor [Updated 12/4/21]

Post by Hey Doomer »

Interesting problem to optimize given ZScript's limitations. My goal was to make "holes" in the armor (missing hexagons) persistent and random. My solution was to define the structures of hexagons and the grid in the WorldLoaded() event. This optimizes use of the trig functions, for one.

Code: Select all

	struct point
	{
		int x;
		int y;
		int armor;
	}
	point grid[100];
	int gCount;
The point array defines the grid; I chose an arbitrary number of 100 (can't use user defined structures in dynamic arrays), because my display defined 78 points. point.armor is a random threshold where a hexagon is damaged and isn't displayed on the screen e.g. armor holes. The random limits are zero to the blue armor threshold. These seems to be working OK and avoids that seizure-inducing flickering effect.

Drawing the grid has been optimized as well:

Code: Select all

			color hexColor = armor > ar_blue ? co_blue : armor > ar_green ? co_green : armor > ar_yellow ? co_yellow : co_red;
			int alpha = 80;
			double thickness = armor * .05;

			for (int i = 0; i < gCount; i++)
			{
				// make or repair armor holes
				if (armor > grid[i].armor)
				{
					for (int ii = 0; ii < 6; ii++)
					{
						Screen.DrawThickLine(grid[i].x + sides[ii].x1, grid[i].y + sides[ii].y1, grid[i].x + sides[ii].x2, grid[i].y + sides[ii].y2, 
							thickness, hexColor, alpha);
					}
				}
			}
If armor is above a threshold for a grid point, a hexagon is drawn at a thickness defined by armor. The weaker the armor, the thinner the line.

Colors are arbitrarily named Blue (strongest armor), Green (still OK but shows some weakness), Yellow (warning levels of weakness), and Red (just plain trouble). These colors can be changed in a MENUDEF color picker to be anything. Since these Cvars are pulled in real time during the game, changes are immediate. The only thing that isn't is the random hexagon armor thresholds, which are defined when the grid is loaded. Thresholds for the armor colors can also be defined in the Options menu, although I'm unsure what happens if these are mutually exclusive. Weird things may happen.

Mind you I still don't really know what armor does in terms of protecting the player from damage. That's another matter.
Hey Doomer
Posts: 283
Joined: Sat Sep 25, 2021 3:38 am

Re: Screen Armor [Updated 12/3/21]

Post by Hey Doomer »

ramon.dexter wrote:May I borrow this for my World of Strife? It's like exactly I was thinking about when I wanted to improve new armor type. Great, just great!

Enjay: Also, armor level detection could be easily applied. It's really wonderful what could be done with zscript. I tried to include this eventhandler into my eventhandler with this slight modification:

Code: Select all

    override void WorldThingDamaged(WorldEvent e) {
        if (e.thing && e.Thing is "binderPlayer") {
            let pawn = binderPlayer(e.Thing);
			If(e.Damage>9/*&&(e.DamageType=="Bullet"||e.DamageType=="Melee")*/) {
				//console.printf(string.format("%i", pawn.bleedlevel));
				pawn.bleedlevel++;				
				If(pawn.bleedlevel>5){pawn.bleedlevel=5;}
			}
            pawn.stamin -= e.Damage*7;
            if (pawn.stamin<0) {
                pawn.stamin = 0;
            }
// modified part //////////////////////////////////////////////////////////////////////////////
			armor = pawn.armoramount; //where pawn.armoramount is integer marking, well, armor amount on player. I'm using jarewill's zscript armor system, so there is no real inventory armor item on player.
			if ( armor > 0 && pawn.currentarmor == 5 ) { //where pawn.currentarmor marks armor level, so this shield effect is displayed only for this one type of armor
				//pawn.A_print("!!!HIT!!!");
				e.thing.A_StartSound("arhit", CHAN_BODY, CHANF_OVERLAP);
				bGrid = true;
				tCounter = 0;
			}
//////////////////////////////////////////////////////////////////////////////////////////////
        }
    }

edit:
Aaand I'm thinking about making several types of differently colored shields for different types/level if armor.
Sure. Glad I can help.

I'm not sure if the released and updated version will help or offer other ideas, as I have included options for different color thresholds and persistent holes. The flickering drove me a little crazy. I also have not done this with multiplayer in mind, as I only play singleplayer.

Note that it's easy to define different shapes. I chose a hexagon as reasonably complex, but this can be any shape at all. This sides array defines hexagon offsets but can be any shape at all:

Code: Select all

	// structures
	struct hex
	{
		int x1;
		int y1;
		int x2;
		int y2;
	}
	hex sides[6];
Since DrawLine draws from x,y to x,y and x,y is a point on the grid, x1 etc are center offsets. It's an easy matter to plot any other shape (a pentagon, or five sided array) on paper and add those offsets to a new array. My definition goes in a clockwise manner, but it doesn't matter so long as offsets define start and end of lines compared to a center.

I suppose different shapes for different point thresholds or armor levels are possible. Also possible to have different sizes of the same shape, although I haven't included a scaling function. (I played around with that and didn't like the way it looked.) The different sizes would have to be defined separately as written.
User avatar
Enjay
 
 
Posts: 26534
Joined: Tue Jul 15, 2003 4:58 pm
Location: Scotland
Contact:

Re: Screen Armor [Updated 12/4/21]

Post by Enjay »

I like the new improvements. :) An option for toggling sound would still be good (I don't think that was in the menu).

>where a hexagon is damaged and isn't displayed on the screen e.g. armor holes.
Yup, I got that straight away. Very intuitive and just makes sense.

>The weaker the armor, the thinner the line.
Also makes sense but, for me, the holes and colours are enough. I find the very thick lines a bit too thick. However, I guess it does make sense for 100+ armour to look beefier on screen.

Good ideas from ramon.dexter too.
Post Reply

Return to “Script Library”