Skip to content

Protection Icons Overhaul#47

Open
Myszax wants to merge 45 commits intoFranisz:masterfrom
Myszax:dev
Open

Protection Icons Overhaul#47
Myszax wants to merge 45 commits intoFranisz:masterfrom
Myszax:dev

Conversation

@Myszax
Copy link
Copy Markdown
Contributor

@Myszax Myszax commented Dec 15, 2025

I've extended ShowTargetProtection functionality.
Split ShowTargetProtection into two separate settings ShowTargetProtectionNoFight and ShowTargetProtectionInFight.
Why? When I am playing Gothic I've found that current settings does not me freedom to choose what I want to see on my screen.
For example: When I wandering around the game world talking with NPCs etc. I'd rather see their All protection info or see the ones that matters AllButZeros. In fight mode I want to be focused on CurrentWeapon only.
Players now will able to choose what fits them :)

System looks more consistent now. When NPC has NPC_FLAG_IMMORTAL there is no point in showing all icons, just Shield in gray color. When target is immune to some damage type then corresponding icon and value MAX is shown.

There is another option to choose icon types. "New" ones are the same as DamagePopup icons as suggested in #40 . Second option is to use Shield icons those that have been used so far.

Last but not least. System is now checking for all equipped weapon/spells damage types. Not only for GetTopDmgIndex.
For example Uriziel in G1 has magic and fire damage type. So for this weapon and CurrentWeapon setting both fire and magic protection icons will be shown.

@Myszax
Copy link
Copy Markdown
Contributor Author

Myszax commented Dec 16, 2025

I am wondering about oEDamageIndex_Barrier. Is it even considerable to show barrier damage type protection? I've never seen something with oEDamageType_Barrier.
Kinda same applies to oEDamageIndex_Fall. But I left it as it was originally.

@Myszax
Copy link
Copy Markdown
Contributor Author

Myszax commented Dec 16, 2025

Another thing came into my mind. Idk if it would be an overkill xD
Add fifth option for ShowTargetProtectionNoFight/ShowTargetProtectionInFight called Custom that player would be able to set custom order of icons and choose exactly those he wants to see.

@Myszax
Copy link
Copy Markdown
Contributor Author

Myszax commented Dec 17, 2025

Don't know if spell->spellType == 2 should be checked before MarkSpellDamage.
There are 3 constants in G1/G2 scrips:

const int SPELL_GOOD = 0;
const int SPELL_NEUTRAL = 1;
const int SPELL_BAD = 2;

0 is never used, 1 is used for no charm spells like (heal/light), 2 is used for all kind of damaging/transformation.
Could mods change this behavior?

@Myszax
Copy link
Copy Markdown
Contributor Author

Myszax commented Dec 19, 2025

Seems like engine (at least G2A) is transforming oETypeDamage done by distance weapons to oEDamageType_Point. No matter if ITM_CAT_FF or ITEM_KAT_MUN (in current implementation I do not even check for amunition) has damageType different than DAM_POINT it's still converted. Tested on magic crossbow.
Is there a point of checking damage values for distance weapons? Or just set bit for oEDamageType_Point and go on.

@Franisz
Copy link
Copy Markdown
Owner

Franisz commented Dec 19, 2025

Seems like engine (at least G2A) is transforming oETypeDamage done by distance weapons to oEDamageType_Point. No matter if ITM_CAT_FF or ITEM_KAT_MUN (in current implementation I do not even check for amunition) has damageType different than DAM_POINT it's still converted. Tested on magic crossbow. Is there a point of checking damage values for distance weapons? Or just set bit for oEDamageType_Point and go on.

IIRC some mods or Ninja FreeAim allows for dealing different types of damage. I don't think there would be any universal solution for this so maybe it would be good to check for actual damage type dealt at runtime and flag whether dmg matches the weapon or the arrow or the fixed point damage type and save the flag to ini. On mismatch overwrite the flag.

@Myszax
Copy link
Copy Markdown
Contributor Author

Myszax commented Dec 21, 2025

Seems like engine (at least G2A) is transforming oETypeDamage done by distance weapons to oEDamageType_Point. No matter if ITM_CAT_FF or ITEM_KAT_MUN (in current implementation I do not even check for amunition) has damageType different than DAM_POINT it's still converted. Tested on magic crossbow. Is there a point of checking damage values for distance weapons? Or just set bit for oEDamageType_Point and go on.

IIRC some mods or Ninja FreeAim allows for dealing different types of damage. I don't think there would be any universal solution for this so maybe it would be good to check for actual damage type dealt at runtime and flag whether dmg matches the weapon or the arrow or the fixed point damage type and save the flag to ini. On mismatch overwrite the flag.

So I'd have to hook OnDamage_Hit and check enuModeDamage in oSDamageDescriptor?
So the damage type information would only appear after the hit.
So, shouldn't I show anything before the hit? Or should I show the resistance taken from MarkWeaponDamage and then correct it if it's different?
A system for resetting the saved flag when the player reequips a ranged weapon would also be useful.
Why save the flag to the ini file?
I don't know how to approach this xD

@Franisz
Copy link
Copy Markdown
Owner

Franisz commented Dec 21, 2025

Seems like engine (at least G2A) is transforming oETypeDamage done by distance weapons to oEDamageType_Point. No matter if ITM_CAT_FF or ITEM_KAT_MUN (in current implementation I do not even check for amunition) has damageType different than DAM_POINT it's still converted. Tested on magic crossbow. Is there a point of checking damage values for distance weapons? Or just set bit for oEDamageType_Point and go on.

IIRC some mods or Ninja FreeAim allows for dealing different types of damage. I don't think there would be any universal solution for this so maybe it would be good to check for actual damage type dealt at runtime and flag whether dmg matches the weapon or the arrow or the fixed point damage type and save the flag to ini. On mismatch overwrite the flag.

So I'd have to hook OnDamage_Hit and check enuModeDamage in oSDamageDescriptor? So the damage type information would only appear after the hit. So, shouldn't I show anything before the hit? Or should I show the resistance taken from MarkWeaponDamage and then correct it if it's different? A system for resetting the saved flag when the player reequips a ranged weapon would also be useful. Why save the flag to the ini file? I don't know how to approach this xD

Before the hit show in default way and then correct, but save in ini so that after restarting the game, we show already the right way. After that the flag in ini would be only overwritten if for eg. player changes the mod and dmg is treated differently there. Random idea, but should work in theory

@Myszax
Copy link
Copy Markdown
Contributor Author

Myszax commented Dec 23, 2025

Okay so I build this system like this:
Before distance weapon damage hit land default distance weapon damage will be shown defined by DamageMask DistanceWeaponDamageType = DamageMask{ oEDamageType::oEDamageType_Point }; in PlayerStatus.cpp.
Then hook to oCNpc::OnDamage_Hit will check if damage done is different than default. If yes then save this damage to variable and ini. It won't be checked again until other hook to oCNpc::EquipItem will reset checking flag (after few checks if distance weapon etc.).
I've created new section in ini called ZUTILITIES_TEMP. Didn't add any trivia. I treat it as temporary plugin variable, not something that is meant to change by user.
It's up to you how do you want to ini file be implemented :)

@Myszax Myszax requested a review from Franisz December 23, 2025 00:57
@Franisz
Copy link
Copy Markdown
Owner

Franisz commented Feb 1, 2026

01-02-2026_12-07-39

With using dmg icons now spacing looks bad in case of some icons. Maybe just increase the spacing a bit.

@Myszax
Copy link
Copy Markdown
Contributor Author

Myszax commented Feb 3, 2026

01-02-2026_12-07-39

With using dmg icons now spacing looks bad in case of some icons. Maybe just increase the spacing a bit.

Sure it looks odd.
I've added same spacing for both versions. It looks kinda long :P
obraz
obraz
Idk, maybe i should add it (or increase further) only to dmg icons, but it looks better in both versions

@Franisz
Copy link
Copy Markdown
Owner

Franisz commented Feb 4, 2026

01-02-2026_12-07-39 With using dmg icons now spacing looks bad in case of some icons. Maybe just increase the spacing a bit.

Sure it looks odd. I've added same spacing for both versions. It looks kinda long :P obraz obraz Idk, maybe i should add it (or increase further) only to dmg icons, but it looks better in both versions

Spacing in both versions is fine. It's inevitable to further clutter the screen the more protections we want to display, that's why the default in plugin is single value in combat only.

Initially I also thought about listing it in column next to the npc, but dunno if that would be better.
04-02-2026_12-48-16

@Myszax
Copy link
Copy Markdown
Contributor Author

Myszax commented Feb 28, 2026

I rewrote the entire FocusStatusBar class.

Main changes

  • Split logic into Model + Layout + Render
  • Render now operates on precomputed layout
  • Removed most per-frame allocations
  • Switched from vector to array to avoid per-frame allocations
  • Added caching for ProtectionModel and selected layout values
  • Added ProtectionRenderMode and ProtectionContext
  • Removed unused methods and legacy helpers
  • General cleanup and method/variable reordering

Impact

  • Reduced memory allocations
  • Cleaner and more maintainable architecture
  • Easier to extend and debug
  • No intended gameplay changes

Performance notes

Benchmarking was done in a simple way:

  • std::chrono::high_resolution_clock::now() at the start and end of NeedAdjustPosition
  • Duration calculated as (end - start).count() / 1000.0f in microseconds
  • Logged every 60 ticks; test subject had 6 icons

Observations:

  • Performance gain is minor for a small number of icons
  • With 1 icon, render time is unchanged
  • At 60 FPS, ~10 microseconds faster
  • At 144 FPS, average times are almost the same
  • Gains become more noticeable with more icons

Class structure improvements

  • Separation into Model, Layout, and Render layers makes the class more modular
  • Easier to maintain and extend without touching unrelated code
  • Future rendering modes can be added with minimal impact on existing logic

iconCache is trivial. In ProtectionIconRenderData copies strings and then IconInfo does it too. I tried to avoid as much allocations as I can :)
I am wondering if cost of switching from vector to array is valuable. Vector is less bug prone and easier to maintain in code.
What about creating zCView every frame protView = new zCView(0, 0, 8192, 8192);?
Shouldn't be created once and then eventually screen->RemoveItem?
iconCache[oEDamageIndex_Barrier] = "DMGICON_BARRIER"; don't even have own icon and probably will not be never need but if yes then I propose this icon :D https://game-icons.net/1x1/delapouite/lightning-dome.html

@Myszax
Copy link
Copy Markdown
Contributor Author

Myszax commented Feb 28, 2026

In G1 setting screen looks like
obraz

Also more options for changing spacing between icons can be added.

@Myszax Myszax requested a review from Franisz February 28, 2026 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants