Moderator
M
Moderator
[COLOR="gray" |
Two Spells
Mend:
Mend with the targeted allied unit or tree transfering HP. If the target is a unit, this Hero will give its HP for a certain duration and moves with the targeted unit. Mending with a tree heals this Hero.
Time Phase:
Distort space-time continuum allowing you to save your current location, hitpoints and mana at the time this spell was casted. After a short delay or when 'Return Time' is activated, you will go back in time at the moment this spell was casted restoring location but can only recover portion of the hitpoints and mana lost.
CONFIGURABLES:
- The amount of HP transfer per level (target it unit)
- The amount of HP heal per level (target is tree)
- Mend duration
- Time Phase Delay
- Percentage of HP recovered
- Percentage of Mana recovered
- Image transparency
REQUIREMENTS:
- JNGP
SPELL TRIGGERS:
Mend
JASS:scope Mend initializer OnInit /* MEND by Shadow Flux, idea by jonbon29 SPELL INFO Mend with the targeted allied unit or tree transfering HP. If the target is a unit, this Hero will give its HP for a certain duration and moves with the targeted unit. Mending with a tree heals this Hero. NOTES: - Stops when the targeted unit becomes invisible - Does not start cooldown, effect and does not reduce mana cost when target is initially invisible. - Stops when the mended tree dies. - Stops when targeted unit comes to an unwalkable path. - Targeting an amphibious unit makes it's pathing off. EDITABLE AT OBJECT EDITOR: - To change the duration of the spell, edit the "Mend Dummy Channeling" Follow Through Timer - To change animation when unit is targeted, edit the "Mend Dummy Channeling" Art-Animation Names */ native UnitAlive takes unit u returns boolean //=========================================================== //========= MEND CONFIGURABLES ============================== //=========================================================== globals private constant integer MEND_ABILITYCODE = 'Amnd' private constant integer CHANNEL_MEND_ABILITYCODE = 'Achm' private constant string CHANNEL_STRINGID = "mount" //Base Order Id of Mend Channeling private constant string MEND_ANIMATION_TREE = "stand lumber" //the animation of the unit when the target is tree endglobals //The amount of HP Mend Heals per second private function MendHeal takes integer level, boolean targetIsUnit returns real if (targetIsUnit) then //HP TRANSFER WHEN UNIT IS TARGETED return 0.0 + 10.0*level else //HP HEAL WHEN TREE IS TARGETED return 10.0 + 10.0*level endif endfunction //=========================================================== //========= END CONFIGURABLES =============================== //=========================================================== //=========================================================== //========= Important Spell Variables ======================= //=========================================================== globals private integer index = -1 private timer period = CreateTimer() private constant real FPS = 0.0312500 private constant integer GHOST_ABILITYCODE = 'Aeth' private constant player NEUTRAL_PASSIVE_PLAYER = Player(PLAYER_NEUTRAL_PASSIVE) endglobals private struct SpellData unit caster unit target destructable treeTarget real hpHeal method destroy takes nothing returns nothing if index == -1 then call PauseTimer(period) endif call this.deallocate() endmethod endstruct globals private SpellData array data endglobals //=========================================================== //========= MEND LOOP ======================================= //=========================================================== private function Periodic takes nothing returns nothing local SpellData this local integer i = 0 local real hp local real x local real y loop exitwhen i > index //========== MEND PERIODIC ACTIONS ============ set this = data[i] if (this.target != null) then //Positioning Code and HP set x = GetUnitX(this.target) set y = GetUnitY(this.target) set hp = GetWidgetLife(this.target) //if target is at unwalkable path, target is invisible, or target is dead if (IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) or IsUnitInvisible(this.target, NEUTRAL_PASSIVE_PLAYER) or not(UnitAlive(this.target)) ) then call UnitRemoveAbility(this.caster, CHANNEL_MEND_ABILITYCODE) else call SetUnitX(this.caster, x) call SetUnitY(this.caster, y) endif if (hp < GetUnitState(this.target, UNIT_STATE_MAX_LIFE) and UnitAlive(this.target)) then //only heals when target hp is not full and not dead call SetWidgetLife(this.target, hp + this.hpHeal) call SetWidgetLife(this.caster, GetWidgetLife(this.caster) - this.hpHeal) endif else set hp = GetWidgetLife(this.caster) if (GetWidgetLife(this.treeTarget) >= 0.405) then //if target tree is still alive, continue healing even if (hp < GetUnitState(this.caster, UNIT_STATE_MAX_LIFE)) then //only heals when hp is not full call SetWidgetLife(this.caster, hp + this.hpHeal) endif else call UnitRemoveAbility(this.caster, CHANNEL_MEND_ABILITYCODE) endif endif //============================================================= set i = i + 1 endloop endfunction //=========================================================== //========= MEND CASTED ===================================== //=========================================================== private function Casted takes nothing returns boolean local SpellData this local integer level local boolean b = false if GetSpellAbilityId() == MEND_ABILITYCODE then set this = SpellData.create() set this.caster = GetTriggerUnit() set this.target = GetSpellTargetUnit() if (this.target != null) then set b = true if not(IsUnitType(this.target, UNIT_TYPE_GROUND)) then //For avoiding collision when target is amphibious call SetUnitPathing(this.target, false) endif else set this.treeTarget = GetSpellTargetDestructable() call SetUnitPathing(this.caster, false) call SetUnitX(this.caster, GetDestructableX(this.treeTarget)) call SetUnitY(this.caster, GetDestructableY(this.treeTarget)) endif set level = GetUnitAbilityLevel(this.caster, MEND_ABILITYCODE) set this.hpHeal = MendHeal(level, b)*FPS call UnitAddAbility(this.caster, GHOST_ABILITYCODE) //call SetUnitPathing(this.caster, false) //CHANNEL MEND call UnitAddAbility(this.caster, CHANNEL_MEND_ABILITYCODE) call IssueImmediateOrder(this.caster, CHANNEL_STRINGID) if (b == false) then call SetUnitAnimation(this.caster, MEND_ANIMATION_TREE) endif set index = index + 1 set data[index] = this if (index == 0) then call TimerStart(period, FPS, true, function Periodic) endif endif return false endfunction private function BeginCasting takes nothing returns boolean local SpellData this local unit target = GetSpellTargetUnit() if GetSpellAbilityId() == MEND_ABILITYCODE then if (target != null and IsUnitInvisible(target, NEUTRAL_PASSIVE_PLAYER) ) then call IssueImmediateOrder(GetTriggerUnit(), "stop") endif endif set target = null return false endfunction //=========================================================== //========= NO LONGER MENDING =============================== //=========================================================== private function End takes nothing returns boolean local integer i = 0 local SpellData this local unit u if GetSpellAbilityId() == CHANNEL_MEND_ABILITYCODE then set u = GetTriggerUnit() loop //========== STOP AND REMOVE FROM INDEX ========== set this = data[i] if this.caster == u then call UnitRemoveAbility(this.caster, CHANNEL_MEND_ABILITYCODE) call SetUnitPathing(this.caster, true) call SetUnitPathing(this.target, true) call UnitRemoveAbility(this.caster, GHOST_ABILITYCODE) set this.caster = null set this.target = null set this.treeTarget = null set data[i] = data[index] set index = index - 1 call this.destroy() exitwhen true endif //============================================================= set i = i + 1 endloop set u = null endif return false endfunction //=========================================================================== private function OnInit takes nothing returns nothing local trigger t1 = CreateTrigger( ) // trigger when casted local trigger t2 = CreateTrigger( ) // trigger when ended local trigger t3 = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( t1, EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddCondition( t1, Condition( function Casted ) ) call TriggerRegisterAnyUnitEventBJ( t2, EVENT_PLAYER_UNIT_SPELL_ENDCAST ) call TriggerAddCondition( t2, Condition( function End ) ) //To have the ability to stop the unit when targeted on invisible units call TriggerRegisterAnyUnitEventBJ( t3, EVENT_PLAYER_UNIT_SPELL_CAST) call TriggerAddCondition( t3, Condition( function BeginCasting ) ) //for invisibility detection if (GetLocalPlayer() == NEUTRAL_PASSIVE_PLAYER) then call FogMaskEnable(false) call FogEnable(false) endif set t1 = null set t2 = null set t3 = null endfunction endscope [/size]
Time Phase
JASS:scope TimePhase initializer OnInit /* TIME PHASE by Shadow Flux SPELL INFO Distort space-time continuum allowing you to save your current location, hitpoints and mana at the time this spell was casted. After a short delay or when 'Return Time' is activated, you will go back in time at the moment this spell was casted restoring location but can only recover portion of the hitpoints and mana lost. NOTES: - Image and floating text created is only visible to player casting the spell. - Does not desync when tested in Multiplayer Emulation of JNGP. */ native UnitAlive takes unit u returns boolean //=========================================================== //========= TIME PHASE CONFIGURABLES ======================== //=========================================================== globals private constant integer TIMEPHASE_ABILITYCODE = 'Atmp' // The Hero Ability Time Phase private constant integer RETURNTIME_ABILITYCODE = 'Atpr' // Return Time Ability private constant integer TIMEPHASE_HIDE_ABILITYCODE = 'Ahde' // The Dummy Ability based on Engineering Upgrades that hides Time Phase ability private constant integer IMAGE_TRANSPARENCY = 160 // How transparent the image is. Max value is 255 which is fully non-transparent private constant string SPELL_EFFECT_CASTER = "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportCaster.mdl" private constant string SPELL_EFFECT_TARGET = "Abilities\\Spells\\Human\\MassTeleport\\MassTeleportTarget.mdl" private constant real TEXT_HEIGHT = 150 //height offset of the floating text private constant real TEXT_SIZE = 0.035 endglobals private function Duration takes integer level returns real return 4.5 + 0.5*level endfunction //THE PERCENTAGE OF HP RECOVERED UPON RETURNING IN Time /*Example: Time Phase (level 1) casted at 1000 HP and after taking damage resulting to 500 HP left, returning in time, caster will recover (1000-500)*0.6 = 300 resulting to 800 HP. */ private function PortionHp takes integer level returns real return 0.1 + 0.2*level endfunction private function PortionMana takes integer level returns real return 0.1 + 0.2*level endfunction //=========================================================== //========= END CONFIGURABLES =============================== //=========================================================== //=========================================================== //========= Important Spell Variables ======================= //=========================================================== globals private integer index = -1 private timer period = CreateTimer() private constant real FPS = 0.0312500 private constant player NEUTRAL_PASSIVE_PLAYER = Player(PLAYER_NEUTRAL_PASSIVE) private constant integer TIMEPHASE_ORDERINT = 852589 endglobals private struct SpellData unit caster unit imageUnit boolean exchange integer lvl real delay real hp real mana texttag timeLeft method destroy takes nothing returns nothing if index == -1 then call PauseTimer(period) endif call this.deallocate() endmethod endstruct globals private SpellData array data endglobals private function ReturnTime takes integer i returns nothing local SpellData this local real x local real y local real hp local real hpRecover local real mana local real manaRecover set this = data[i] if (UnitAlive(this.caster)) then set x = GetUnitX(this.imageUnit) set y = GetUnitY(this.imageUnit) //SPELL VISUAL EFFECTS call DestroyEffect(AddSpecialEffect(SPELL_EFFECT_CASTER, GetUnitX(this.caster), GetUnitY(this.caster))) call DestroyEffect(AddSpecialEffect(SPELL_EFFECT_TARGET, x, y)) //SPELL ACTIONS call SetUnitFacing(this.caster, GetUnitFacing(this.imageUnit)) call SetUnitPosition(this.caster, x, y) //HP RECOVER set hp = GetWidgetLife(this.caster) set hpRecover = (this.hp - hp)*PortionHp(this.lvl) if (hpRecover > 0) then //if saved hp > current hp, recover hp call SetWidgetLife(this.caster, hp + hpRecover) else //if saved hp < current hp, set hp to saved hp call SetWidgetLife(this.caster, this.hp) endif //MANA RECOVER set mana = GetUnitState(this.caster, UNIT_STATE_MANA) set manaRecover = (this.mana-mana)*PortionMana(this.lvl) if (manaRecover > 0) then //if saved mana > current mana, recover mana call SetUnitState(this.caster, UNIT_STATE_MANA, mana + manaRecover) else //if saved mana < current mana, set mana to saved mana call SetUnitState(this.caster, UNIT_STATE_MANA, this.mana) endif endif call RemoveUnit(this.imageUnit) call DestroyTextTag(this.timeLeft) //RESET ABILITIES call UnitRemoveAbility(this.caster, RETURNTIME_ABILITYCODE) call UnitRemoveAbility(this.caster, TIMEPHASE_HIDE_ABILITYCODE) //CLEANUP set this.caster = null set this.imageUnit = null set this.timeLeft = null set data[i] = data[index] set index = index - 1 call this.destroy() endfunction //=========================================================== //========= TIME PHASE LOOP ================================= //=========================================================== private function Periodic takes nothing returns nothing local SpellData this local integer i = 0 loop exitwhen i > index //========== TIME PHASE PERIODIC ACTIONS ============ set this = data[i] set this.delay = this.delay - FPS call SetTextTagText(this.timeLeft, R2S(this.delay), TEXT_SIZE) if this.delay <= 0 then call ReturnTime(i) else //HIDE ABILITY if (this.exchange) then call UnitAddAbility(this.caster, RETURNTIME_ABILITYCODE) call UnitAddAbility(this.caster, TIMEPHASE_HIDE_ABILITYCODE) call UnitMakeAbilityPermanent(this.caster, true, RETURNTIME_ABILITYCODE) call UnitMakeAbilityPermanent(this.caster, true, TIMEPHASE_HIDE_ABILITYCODE) set this.mana = GetUnitState(this.caster, UNIT_STATE_MANA) set this.exchange = false endif endif //============================================================= set i = i + 1 endloop endfunction //=========================================================== //========= TIME PHASE CASTED =============================== //=========================================================== private function Casted takes nothing returns boolean local SpellData this local integer id local real x local real y if (GetIssuedOrderId() == TIMEPHASE_ORDERINT) then //STORE SPELL STRUCT VARIABLES set this = SpellData.create() set this.caster = GetTriggerUnit() set this.lvl = GetUnitAbilityLevel(this.caster, TIMEPHASE_ABILITYCODE) set this.exchange = true set this.hp = GetWidgetLife(this.caster) set this.delay = Duration(this.lvl) //LOCAL VARIABLES set x = GetUnitX(this.caster) set y = GetUnitY(this.caster) //FLOATING TEXT SCRIPTS set this.timeLeft = CreateTextTag() call SetTextTagPos(this.timeLeft, x, y, TEXT_HEIGHT) call SetTextTagColor(this.timeLeft, 80, 175, 250, 230) call SetTextTagVisibility(this.timeLeft, false) //IMAGE UNIT set id = GetUnitTypeId(this.caster) set this.imageUnit = CreateUnit(NEUTRAL_PASSIVE_PLAYER, id, x, y, GetUnitFacing(this.caster)) //ONLY SHOW THE IMAGE UNIT AND TIME LEFT TO THE CASTER PLAYER call SetUnitVertexColor(this.imageUnit, 255, 255, 255, 0) if (GetLocalPlayer() == GetTriggerPlayer()) then call SetUnitVertexColor(this.imageUnit, 255, 255, 255, IMAGE_TRANSPARENCY) call SetTextTagVisibility(this.timeLeft, true) endif call UnitAddAbility(this.imageUnit, 'Aloc') //make the image unit unselectable call SetUnitTimeScale(this.imageUnit, 0) //stop image unit animation call PauseUnit(this.imageUnit, true) //disable image unit from auto-attacking //MAKE IMAGE UNIT GOES THROUGH CASTER call SetUnitX(this.imageUnit, x) call SetUnitY(this.imageUnit, y) //INDEXING set index = index + 1 set data[index] = this if (index == 0) then call TimerStart(period, FPS, true, function Periodic) endif endif return false endfunction //=========================================================== //========= TIME PHASE RETURN =============================== //=========================================================== private function ReturnTimeActivated takes nothing returns boolean local SpellData this local unit u local integer i = 0 if (GetSpellAbilityId() == RETURNTIME_ABILITYCODE) then set u = GetTriggerUnit() loop set this = data[i] if this.caster == u then set u = null call ReturnTime(i) exitwhen true endif //============================================================= set i = i + 1 endloop set u = null endif return false endfunction private function Disable takes nothing returns nothing call SetPlayerAbilityAvailable(GetEnumPlayer(), TIMEPHASE_HIDE_ABILITYCODE, false) endfunction //=========================================================================== private function OnInit takes nothing returns nothing local trigger t1 = CreateTrigger( ) local trigger t2 = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( t1, EVENT_PLAYER_UNIT_ISSUED_ORDER) call TriggerAddCondition( t1, Condition( function Casted ) ) call TriggerRegisterAnyUnitEventBJ( t2, EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddCondition( t2, Condition( function ReturnTimeActivated ) ) set t1 = null set t2 = null //for hiding the other ability call ForForce(bj_FORCE_ALL_PLAYERS, function Disable) endfunction endscope
IMPLEMENTATION
1) Copy the Abilities in Object Editor to your map.
2) Copy the Spell Trigger Folder to your map.