• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Shield Spell

Status
Not open for further replies.
Level 30
Joined
Jan 31, 2010
Messages
3,551
Simple as that. I'm in a need of a shield ability which protects the target from a certain amount of damage until it dies, or duration runs out. GUI or vJass, I don't care as long as it is MUI (Multiple unit instances), MPI (Multiple player instances) and absolutely leakless. Whatever systems I've encountered so far either had things I didn't want (such as having a reversed effect if cast on enemies, or damaging enemies if the shield dies, and so on) which I wasn't able to locate and erase or nullify, or the shield systems didn't work at all. So. It would be nice if the system had a permanent text tag (or the handy progress bar) saying how much damage is left to absorb (in this format: "+63 HP" if shield has 63 HP more).

Heart of Oak [Q]

Envelops an ally with living brambles which will absorb a set amount of damage for the shielded unit. Protects the unit from 100/150/200/250/300 damage. Lasts for up to 20/30/40/50/60 seconds or until the shield dies.
 
Level 30
Joined
Jan 31, 2010
Messages
3,551
I won't be able to enter World Editor for some time so I just posted out of my head, will this work? Used the Shield.add(unit target, real amount, real duration, string sfx, string attachPt) as reference and some what little knowledge I have in scripting.


call Shield.add(GetSpellTargetUnit,( 50.00 + ( 50.00 * I2R(GetUnitAbilityLevelSwapped('AHab', GetTriggerUnit())) ) ),( 10. + ( 10. * I2R(GetUnitAbilityLevelSwapped('AHab', GetTriggerUnit())) ) ),Abilities\\Spells\\NightElf\\Rejuvenation\\RejuvenationTarget.mdl,chest
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
I won't be able to enter World Editor for some time so I just posted out of my head, will this work? Used the Shield.add(unit target, real amount, real duration, string sfx, string attachPt) as reference and some what little knowledge I have in scripting.


call Shield.add(GetSpellTargetUnit,( 50.00 + ( 50.00 * I2R(GetUnitAbilityLevelSwapped('AHab', GetTriggerUnit())) ) ),( 10. + ( 10. * I2R(GetUnitAbilityLevelSwapped('AHab', GetTriggerUnit())) ) ),Abilities\\Spells\\NightElf\\Rejuvenation\\RejuvenationTarget.mdl,chest

Syntax error:
- should be GetSpellTargetUnit()
- strings should be enclosed in quotes ""
Also, you might wanna avoid using BJ (red functions) and store GetTriggerUnit() to a variable.
 
Level 3
Joined
May 9, 2011
Messages
37
I won't be able to enter World Editor for some time so I just posted out of my head, will this work? Used the Shield.add(unit target, real amount, real duration, string sfx, string attachPt) as reference and some what little knowledge I have in scripting.


call Shield.add(GetSpellTargetUnit,( 50.00 + ( 50.00 * I2R(GetUnitAbilityLevelSwapped('AHab', GetTriggerUnit())) ) ),( 10. + ( 10. * I2R(GetUnitAbilityLevelSwapped('AHab', GetTriggerUnit())) ) ),Abilities\\Spells\\NightElf\\Rejuvenation\\RejuvenationTarget.mdl,chest

You can probably simplify it to something like this:
JASS:
globals
    constant integer SHIELD_ID = 'AHab'
endglobals

function GetShieldAmount takes unit u returns real
    return 50.0 + (50.0*GetUnitAbilityLevel(u, SHIELD_ID))
endfunction

function GetShieldDuration takes unit u returns real
    return 10.0 + (10.0*GetUnitAbilityLevel(u, SHIELD_ID))
endfunction

Then use Shield.add(GetSpellTargetUnit(), GetShieldAmount(GetTriggerUnit()), GetShieldDuration(GetTriggerUnit()), "Abilities\\Spells\\NightElf\\Rejuvenation\\RejuvenationTarget.mdl", "chest").

As Shadow Flux said, store GetTriggerUnit() to a variable.
 
Level 30
Joined
Jan 31, 2010
Messages
3,551
Consider this solved :)

...nope. When I try to copy the script into a trigger editor in GUI via "Custom Script" on general action,, the World Editor crashes instantly when I click "ok". Why?

Can I be so rude to ask for a full code instead that will fire off on casting? I really lack coding skills.
 
Level 3
Joined
May 9, 2011
Messages
37
Make sure you're using the latest JNGP and not just regular World Editor. Also get all the library requirements for Shield and make sure you make a new trigger and convert to "custom text".

If its still not working i'll try to make some code for you.
 
Level 22
Joined
Feb 6, 2014
Messages
2,466
Take a look at the sample map I made.

I added a Floating Text showing how much damage the unit can take before the Shield is gone. To edit it, go to Shield Trigger (in the Libraries Folder) and CTRL+F (Search) the keyword "Floating Text". You can edit the floating text's lifespan, fadepoint, color, size, height offset, and velocity.

Although the System seems buggy to me when I re-cast the spell on the same unit. Also, the first hit doesn't seem to be blocked. You should ask Cokemonkey11 about the bug if you are also experiencing it since I don't wanna modify his system a lot without permission.

Take a look for yourself.
 

Attachments

  • spell shield.w3x
    39.9 KB · Views: 45
Last edited:
Level 3
Joined
May 9, 2011
Messages
37
If you want to prevent recasting to a unit that has a shield, try making a boolean array which is the unit has a shield based on the unit index (via a unit indexer) of the unit and checks if they have a shield or not before it is casted. When the shield is destroyed, set the value to false.
 
Level 30
Joined
Jan 31, 2010
Messages
3,551
This system won't work for me. Well it does work, or at least, it tried, but when I went a full test, several very odd things happened:

- The shield couldn't block first instance of damage (very important for my map)
- The shield healed the target first before applying it (shouldn't give HP, just shield points)
- Healed units had 0 shield on some occasions, sometimes they got both a heal and the shield
- Effect and shield, along with text tags, stayed on the unit after it ended, even tho it blocked 0 damage

This makes this specific system out of the league for my map. These might be small errors but I really can't afford to have them.

So, I'm still looking for a shield system.

edit: Just tested Daffa the Mage's system and it works like a charm. If you could be so kind to add some type of visual indicator of shield's HP, I'd be very grateful :)
 
Well, it's a spell mostly xD (I was thinking of making a pack, but scrapped it due to high complexity + my laziness).
I'll consider it, though it's possible to hijack the code directly to add a floating text to show the Hit Points. Anyway, what style of hit point? bar? number floats for a few seconds?
Also, no promises since I got stuffs to do as well :(
 

TKF

TKF

Level 19
Joined
Nov 29, 2006
Messages
1,266
This system won't work for me. Well it does work, or at least, it tried, but when I went a full test, several very odd things happened:

- The shield couldn't block first instance of damage (very important for my map)
- The shield healed the target first before applying it (shouldn't give HP, just shield points)
- Healed units had 0 shield on some occasions, sometimes they got both a heal and the shield
- Effect and shield, along with text tags, stayed on the unit after it ended, even tho it blocked 0 damage

I manage to make a shield spell that block the first damage, even at full hp, I noticed the wc3 hardcoded bug that for some reason add hp before unit takes the damage and added a timer delay to prevent that. With a moving floating text that follows the unit (well, the text gets recreated)

You can use the regular editor with this, and no unit indexer or other system is required. Doesn't use Unit custom value either. Using a system that adds integer value to a unit so it can be MUI.

JASS:
function Damage_Block takes nothing returns boolean
        local timer t = GetExpiredTimer()
        local real Damage = LoadReal(udg_hashdamage, GetHandleId(t), 1)
        local unit target = LoadUnitHandle(udg_hashdamage, GetHandleId(t), 2)
        local real CurrentLife = LoadReal(udg_hashdamage, GetHandleId(t), 3)
        local real MaxLife = GetUnitState(target,UNIT_STATE_MAX_LIFE)
        local integer shieldvalue = GetCustomIntValue(target)
        local real shieldvaluereal = I2R(GetCustomIntValue(target))
        local timer t2 = CreateTimer()
        call DestroyTimer(t) //Warning: Only destroy non-periodic timers without pausing them beforehead
        //Adds same hp same as the negative value to null out hp adjust
        if LoadBoolean(udg_hashdamage, GetHandleId(t), 4) == true then
            call UnitAddAbility(target, 'A001')
            call SetUnitAbilityLevel(target, 'A001', 3 )
            call UnitRemoveAbility(target, 'A001')
            if Damage < 3 then
                call SetUnitState(target, UNIT_STATE_LIFE, CurrentLife)
            else
            endif  
        else
        endif  
        //Set to 3 - prevents unecesary calls
	if Damage > 3 then
		//ShieldBlock : 'B000 is the buff ID in test map, you have to replace this with the abilities buff code in your own map'
                if UnitHasBuffBJ(target, 'B000') == true then
				if shieldvaluereal > Damage then
					call SetUnitState(target, UNIT_STATE_LIFE, CurrentLife)
                                        set shieldvaluereal = shieldvaluereal - Damage
                                        set shieldvalue = R2I(shieldvaluereal)
                                        call SetCustomIntValue(target, shieldvalue)
				else
					call SetUnitState(target, UNIT_STATE_LIFE, CurrentLife+shieldvaluereal-Damage)
                                        call SetCustomIntValue(target, 0)
                                        set shieldvaluereal = 0.00
                                        call UnitRemoveBuffBJ( 'B000', target )
                                        call GroupRemoveUnit(udg_OakShieldGroup,target)
				endif
                else
		endif
        else
	endif
        call FlushChildHashtable(udg_hashdamage, GetHandleId(t)) //remove the entrys from the hash
	set target = null
return false
endfunction


//This timer is important, otherwise full hp units will be taken damage
function Trig_Damage_Detection_Conditions_Copy takes nothing returns boolean
    local unit tu = GetTriggerUnit()
    local real DamageMemory = GetEventDamage()
    local real CurrentLifeMem = GetUnitState(tu,UNIT_STATE_LIFE)
    local real MaxLifeMem = GetUnitState(tu,UNIT_STATE_MAX_LIFE)
    local real shieldvaluerealmem = I2R(GetCustomIntValue(tu))
    local timer t = CreateTimer()  
    call SaveReal(udg_hashdamage, GetHandleId(t), 1, DamageMemory)
    call SaveUnitHandle(udg_hashdamage, GetHandleId(t), 2, tu)
    call SaveReal(udg_hashdamage, GetHandleId(t), 3, CurrentLifeMem)
    if UnitHasBuffBJ(tu, 'B000') == true then
        if DamageMemory > CurrentLifeMem then
            call SaveBoolean(udg_hashdamage, GetHandleId(t), 4, true)
            call UnitAddAbility(tu, 'A001')
            //negative hp first, somehow I had to do this first for some odd reason
            call SetUnitAbilityLevel( tu, 'A001', 2 )
            call UnitRemoveAbility(tu, 'A001')          
        else
        endif
        call TimerStart(t, 0.00, false, function Damage_Block)
    else
        call FlushChildHashtable(udg_hashdamage, GetHandleId(t))
        set t = null
    endif  
    set tu = null
return false
endfunction


//===========================================================================
function InitTrig_Damage_Detection_Copy takes nothing returns nothing
	set gg_trg_Damage_Detection_Copy = CreateTrigger(  )
	call DisableTrigger( gg_trg_Damage_Detection_Copy )
	call TriggerAddCondition( gg_trg_Damage_Detection_Copy, Condition( function Trig_Damage_Detection_Conditions_Copy ) )
endfunction

  • Heart Of Oak Ability
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Heart of Oak
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • ((Target unit of ability being cast) is in UnitAlreadyInEvent) Equal to False
        • Then - Actions
          • -------- This is important, otherwise the trigger will fire multiple times on same unit and heal --------
          • Trigger - Add to Damage Detection Copy <gen> the event (Unit - (Target unit of ability being cast) Takes damage)
          • Unit Group - Add (Target unit of ability being cast) to UnitAlreadyInEvent
        • Else - Actions
      • Set Temp_Integer = (Level of Heart of Oak for (Triggering unit))
      • Trigger - Turn on Damage Detection Copy <gen>
      • Trigger - Turn on Heart Of Oak Text Movement <gen>
      • Set Temp_Real = (50.10 + (50.00 x (Real(Temp_Integer))))
      • Custom script: call SetCustomIntValue( GetSpellTargetUnit(), R2I(udg_Temp_Real) )
      • Set DmgDetect_Count = (DmgDetect_Count + 1)
      • Set HeartOakIndexCount = (HeartOakIndexCount + 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • HeartOakIndexCount Greater than 30
        • Then - Actions
          • Set HeartOakIndexCount = 1
        • Else - Actions
      • Set HeartOakUnitTextIndex[HeartOakIndexCount] = (Target unit of ability being cast)
      • Floating Text - Create floating text that reads (+ + ((String((Integer(Temp_Real)))) + HP)) above (Target unit of ability being cast) with Z offset 40.00, using font size 9.00, color (20.00%, 100.00%, 20.00%), and 30.00% transparency
      • Floating Text - Change (Last created floating text): Disable permanence
      • Floating Text - Change the fading age of (Last created floating text) to 1.20 seconds
      • Floating Text - Change the lifespan of (Last created floating text) to 1.00 seconds
      • Set HeartOakText[HeartOakIndexCount] = (Last created floating text)
      • -------- Unit group is only for floating text purposes only --------
      • Unit Group - Add (Target unit of ability being cast) to OakShieldGroup
      • -------- You add the target unit to the unit takes damage --------
      • Wait (10.00 + (10.00 x (Real(Temp_Integer)))) seconds
      • Set DmgDetect_Count = (DmgDetect_Count - 1)
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • DmgDetect_Count Less than or equal to 0
        • Then - Actions
          • Set DmgDetect_Count = 0
          • Trigger - Turn off Damage Detection Copy <gen>
          • Trigger - Turn off Heart Of Oak Text Movement <gen>
        • Else - Actions
  • Heart Of Oak Text Movement
    • Events
      • Time - Every 0.05 seconds of game time
    • Conditions
    • Actions
      • Unit Group - Pick every unit in OakShieldGroup and do (Actions)
        • Loop - Actions
          • Custom script: set udg_Temp_Integer = GetCustomIntValue (GetEnumUnit())
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • Temp_Integer Greater than 0
            • Then - Actions
              • For each (Integer A) from 1 to HeartOakIndexCount, do (Actions)
                • Loop - Actions
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • HeartOakUnitTextIndex[(Integer A)] Equal to (Picked unit)
                    • Then - Actions
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ((Picked unit) has buff Heart of Oak ) Equal to False
                        • Then - Actions
                          • Custom script: call SetCustomIntValue(GetEnumUnit(), 0)
                          • Floating Text - Destroy HeartOakText[(Integer A)]
                          • Set HeartOakUnitTextIndex[(Integer A)] = No unit
                          • Unit Group - Remove (Picked unit) from OakShieldGroup
                        • Else - Actions
                          • Floating Text - Destroy HeartOakText[(Integer A)]
                          • Set Temp_Real = (Real(Temp_Integer))
                          • Floating Text - Create floating text that reads (+ + ((String((Integer(Temp_Real)))) + HP)) above HeartOakUnitTextIndex[(Integer A)] with Z offset 40.00, using font size 8.00, color (20.00%, 100.00%, 20.00%), and 30.00% transparency
                          • Floating Text - Change HeartOakText[(Integer A)]: Disable permanence
                          • Floating Text - Change the lifespan of HeartOakText[(Integer A)] to 0.20 seconds
                          • Set HeartOakText[(Integer A)] = (Last created floating text)
                    • Else - Actions
            • Else - Actions
              • Unit Group - Remove (Picked unit) from OakShieldGroup
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • (Number of units in OakShieldGroup) Equal to 0
        • Then - Actions
          • Trigger - Turn off (This trigger)
        • Else - Actions
Shield Spell test map link - Updated



I had to learn some JASS while creating this for the damage prevention. I'm very bad at it as it took several hours. With help of codes I found in Battle Tanks and googling I found a nice way to block damage. I'm not used to JASS, so I'm used to GUI when creating triggers.
________

Edit:
Code has been improved to counter 1 hit kill, but requires item ability in addition.
 
Last edited:
Status
Not open for further replies.
Top