Name | Type | is_array | initial_value |
ability | abilcode | No | |
Hashtable | hashtable | No |
//TESH.scrollpos=165
//TESH.alwaysfold=0
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
//TESH.scrollpos=197
//TESH.alwaysfold=0
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