Romek
Super Moderator
- Reaction score
- 963
Heroic Guard
By Romek
By Romek
Code: vJASS
MUI / MPI: MUI
Leaks: None
Description: Makes this unit take damage for the target unit. Damage will be reduced to 100/80/60%.
Lasts 30 seconds.
Icon:
Thanks to Grymlax!
Notes:
I've remade this spell since last time. I said I would over Christmas, but I didn't have time.
The old version used a timer per instance, and dynamic triggers.
This uses no dynamic triggers, and 2 timers altogether. :thup:
Screenshot:
The Code:
JASS:
scope HeroicGuard initializer Init // requires PUI
// ______________________________________________________________________
// +--------------------------------------------------------------------+
// | H E R O I C G U A R D |
// |____________________________________________________________________|
// +--------------------------------------------------------------------+
// | -== By Romek -- Version 2.2 ==- |
// |____________________________________________________________________|
// +--------------------------------------------------------------------+
// | 2.0: |
// | - Remade the entire spell so it uses no dynamic triggers |
// | and 2 timers |
// | |
// | 2.1: |
// | - Fixed a critical error caused by casting the spell on the |
// | same unit twice |
// | |
// | 2.2: |
// | - Made the spell use index 0. (Uberplayer complained) |
// | - Prevented a critical crash which occured when the spell was |
// | cast by 2 heroes at eachother. |
// |____________________________________________________________________|
// +--------------------------------------------------------------------+
// | -== C o n f i g u r a t i o n: ==- |
// +--------------------------------------------------------------------+
globals
// The raw code of the ability
private constant integer ID = 039;A000039;
// How often the lightning will be moved, the duration will also be accurate to this amount
private constant real TIMEOUT = 0.03125
// The raw code ot the lightning
private constant string LIGHTNING = "DRAL"
// How high from the units 'base' the lightning will be.
private constant real LIGHT_OFFSET = 50.
// The RGBA values of the lightning. 1 = 100%. 0 = 0%
private constant real L_R = 1. // Red
private constant real L_G = 1. // Green
private constant real L_B = 1. // Blue
private constant real L_A = 0.2 // Alpha
// Should the effects be preloaded?
private constant boolean PRELOAD = true
// The effect created on the caster when the spell is cast
private constant string CAST_EFFECT_C = "Abilities\\Spells\\Orc\\Disenchant\\DisenchantSpecialArt.mdl"
// ...Attached to the casters:
private constant string CAST_EFFECT_C_ATTACH = "chest"
// The effect created on the target when the spell is cast
private constant string CAST_EFFECT_T = "Abilities\\Spells\\Orc\\Disenchant\\DisenchantSpecialArt.mdl"
// ...Attached to the targets:
private constant string CAST_EFFECT_T_ATTACH = "chest"
// The effect created on the caster when the target is damaged
private constant string DAMAGE_EFFECT_C = "Abilities\\Spells\\Orc\\FeralSpirit\\feralspiritdone.mdl"
// ...Attached to the casters:
private constant string DAMAGE_EFFECT_C_ATTACH = "origin"
// The effect created on the target when it is damaged
private constant string DAMAGE_EFFECT_T = "Abilities\\Spells\\Undead\\ReplenishHealth\\ReplenishHealthCasterOverhead.mdl"
// ... Attached to the targets:
private constant string DAMAGE_EFFECT_T_ATTACH = "overhead"
// The raw code of an item ability which gives +999999 life
private constant integer LIFEBONUS = 039;A001039;
// The attack, damage and weapon type of the damage done to the caster when the target is damaged
private constant attacktype AT = ATTACK_TYPE_CHAOS // Attack type
private constant damagetype DT = DAMAGE_TYPE_UNIVERSAL // Damage type
private constant weapontype WT = WEAPON_TYPE_WHOKNOWS // Weapon type
// Leaving these as the default values will ensure the caster takes the full damage the target did.
// (Assuming MULTIPLIER returns 1.)
// The message displayed to the owner of the caster when the target is already affected by the spell
private constant string ERROR = "|cFFFFBF00This unit is already affected by Heroic Guard|r"
// The message displayed when the target is already casting the spell
private constant string ERRORB = "|cFFFFBF00This unit is currently casting Heroic Guard|r"
endglobals
// What the damage is multiplied by before it is dealt to the caster.
private constant function MULTIPLIER takes integer level returns real
return 1 - ((level - 1) * 0.2) // 1, 0.8, 0.6, 0.4
// Any lower should use '0.1', or IMaxBJ()
endfunction
// How long the spell lasts. Accurate to TIMEOUT.
private constant function DURATION takes integer level returns real
return 30.
endfunction
// The mana cost of the spell. This is used to restore mana if the target incase the spell fails.
private constant function MANA takes integer level returns real
return 150.
endfunction
// ____________________________________________________________________
// +--------------------------------------------------------------------+
// | -== E n d o f C o n f i g u r a t i o n: ==- |
// |____________________________________________________________________|
// +--------------------------------------------------------------------+
// -== D O N O T T O U C H B E L O W ==-
private keyword Data
globals
private trigger Trig = CreateTrigger()
private timer T = CreateTimer()
private Data array D
private integer I = 0
private group Registered = CreateGroup()
private group Wanted = CreateGroup()
private group Casters = CreateGroup()
private Data array Z
private timer X = CreateTimer()
private integer Y = 0
endglobals
private struct Data
//! runtextmacro PUI()
unit caster
unit target
integer level
lightning light
real total
real ticks = 0.
real damage
boolean abil
method onDestroy takes nothing returns nothing
call DestroyLightning(.light)
endmethod
endstruct
private function HitEx takes nothing returns nothing
local integer i = 0
loop
exitwhen i >= Y
call SetWidgetLife(Z<i>.target, GetWidgetLife(Z<i>.target) + Z<i>.damage)
if Z<i>.abil then
call UnitRemoveAbility(Z<i>.target, LIFEBONUS)
set Z<i>.abil = false
endif
set Z<i> = Z[Y]
set Y = Y - 1
set i = i + 1
endloop
if Y == 0 then
call PauseTimer(X)
endif
endfunction
private function Hit takes nothing returns nothing
local Data d = Data[GetTriggerUnit()]
set d.damage = GetEventDamage()
call DestroyEffect(AddSpecialEffectTarget(DAMAGE_EFFECT_T, d.target, DAMAGE_EFFECT_T_ATTACH))
call DestroyEffect(AddSpecialEffectTarget(DAMAGE_EFFECT_C, d.caster, DAMAGE_EFFECT_C_ATTACH))
if GetWidgetLife(d.target) - d.damage < 1 then
call UnitAddAbility(d.target, LIFEBONUS)
set d.abil = true
else
set d.abil = false
endif
set Z[Y] = d
set Y = Y + 1
if Y == 1 then
call TimerStart(X, 0., true, function HitEx)
endif
call UnitDamageTarget(GetEventDamageSource(), d.caster, d.damage*MULTIPLIER(d.level), false, true, AT, DT, WT)
endfunction
private function HitCond takes nothing returns boolean
return IsUnitInGroup(GetTriggerUnit(), Wanted)
endfunction
private function Expire takes nothing returns nothing
local integer i = 0
loop
exitwhen i >= I
set D<i>.ticks = D<i>.ticks + TIMEOUT
if D<i>.ticks >= D<i>.total or IsUnitType(D<i>.caster, UNIT_TYPE_DEAD) then
call D<i>.release()
call GroupRemoveUnit(Casters, D<i>.caster)
call GroupRemoveUnit(Wanted, D<i>.target)
set D<i> = D[I ]
set I = I - 1
else
call MoveLightningEx(D<i>.light, true, GetUnitX(D<i>.caster), GetUnitY(D<i>.caster), GetUnitFlyHeight(D<i>.caster) + LIGHT_OFFSET, GetUnitX(D<i>.target), GetUnitY(D<i>.target), GetUnitFlyHeight(D<i>.target) + LIGHT_OFFSET)
endif
set i = i + 1
endloop
if I == 0 then
call PauseTimer(T)
endif
endfunction
private function SpellRestore takes unit u, integer level returns nothing
call TriggerSleepAction(0.)
call UnitRemoveAbility(u, ID)
call UnitAddAbility(u, ID)
call SetUnitAbilityLevel(u, ID, level)
call SetUnitState(u, UNIT_STATE_MANA, GetUnitState(u, UNIT_STATE_MANA) + MANA(level))
endfunction
private function Act takes nothing returns nothing
local Data d = Data.create()
set d.target = GetSpellTargetUnit()
set d.caster = GetTriggerUnit()
set d.level = GetUnitAbilityLevel(d.caster, ID)
if IsUnitInGroup(d.target, Wanted) then
call DisplayTimedTextToPlayer(GetOwningPlayer(d.caster), 0., 0., 3., ERROR)
call SpellRestore.execute(d.caster, d.level)
call d.release()
return
elseif IsUnitInGroup(d.target, Casters) then
call DisplayTimedTextToPlayer(GetOwningPlayer(d.caster), 0., 0., 3., ERRORB)
call SpellRestore.execute(d.caster, d.level)
call d.release()
return
endif
call GroupAddUnit(Casters, d.caster)
call DestroyEffect(AddSpecialEffectTarget(CAST_EFFECT_C, d.caster, CAST_EFFECT_C_ATTACH))
call DestroyEffect(AddSpecialEffectTarget(CAST_EFFECT_T, d.target, CAST_EFFECT_T_ATTACH))
set d.total = DURATION(d.level)
set d.light = AddLightningEx(LIGHTNING, true, GetUnitX(d.caster), GetUnitY(d.caster), GetUnitFlyHeight(d.caster) + LIGHT_OFFSET, GetUnitX(d.target), GetUnitY(d.target), GetUnitFlyHeight(d.target) + LIGHT_OFFSET)
call SetLightningColor(d.light, L_R, L_G, L_B, L_A)
set D[I ] = d
set I = I + 1
if I == 1 then
call TimerStart(T, TIMEOUT, true, function Expire)
endif
call GroupAddUnit(Wanted, d.target)
if not IsUnitInGroup(d.target, Registered) then
call TriggerRegisterUnitEvent(Trig, d.target, EVENT_UNIT_DAMAGED)
call GroupAddUnit(Registered, d.target)
endif
set Data[d.target] = d
endfunction
private function Cond takes nothing returns boolean
return GetSpellAbilityId() == ID
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Filter(function Cond))
call TriggerAddAction(t, function Act)
call TriggerAddCondition(Trig, Filter(function HitCond))
call TriggerAddAction(Trig, function Hit)
if PRELOAD then
call DestroyEffect(AddSpecialEffect(CAST_EFFECT_C, 0., 0.))
call DestroyEffect(AddSpecialEffect(CAST_EFFECT_T, 0., 0.))
call DestroyEffect(AddSpecialEffect(DAMAGE_EFFECT_C, 0., 0.))
call DestroyEffect(AddSpecialEffect(DAMAGE_EFFECT_T, 0., 0.))
endif
endfunction
endscope</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>
Requires PUI
The Map: