- Joined
- Feb 2, 2006
- Messages
- 1,631
Hi,
I want to write a small system which allows me to change the level of any hero ability I want to. I use the Tome of Retraining ability for this since I've read that this is the only way to unlearn hero abilities. All ability cooldowns need to be stored and reset. Otherwise, the tome ability won't work for all hero abilities. I store all ability levels and start to reskill giving the one hero ability the highest priority.
My problem is that the tome ability seems to have some delay when I issue the immediate order. Hence, I need to create and start a timer and save all data. This requires some guard to prevent multiple concurrent calls. Is there any way to avoid this delay? Or maybe a better solution to reskilling hero abilities?
This is my current system:
I want to write a small system which allows me to change the level of any hero ability I want to. I use the Tome of Retraining ability for this since I've read that this is the only way to unlearn hero abilities. All ability cooldowns need to be stored and reset. Otherwise, the tome ability won't work for all hero abilities. I store all ability levels and start to reskill giving the one hero ability the highest priority.
My problem is that the tome ability seems to have some delay when I issue the immediate order. Hence, I need to create and start a timer and save all data. This requires some guard to prevent multiple concurrent calls. Is there any way to avoid this delay? Or maybe a better solution to reskilling hero abilities?
This is my current system:
JASS:
/**
* Library which allows setting the exact level of a hero skill.
*/
library HeroAbilityLevel
globals
private integer ABILITY_ID_UNLEARN = 'A00U'
private integer ABILITY_ORDER_ID_UNLEARN = 852471
private hashtable whichHashTable = InitHashtable()
private hashtable timerHashTable = InitHashtable()
endglobals
private function PrintMsg takes string msg returns nothing
call DisplayTextToForce(GetPlayersAll(), msg)
endfunction
function RegisterHeroTypeForAbilityLevel takes integer unitTypeId, integer abilityId0, integer abilityId1, integer abilityId2, integer abilityId3, integer abilityId4 returns nothing
call SaveInteger(whichHashTable, unitTypeId, 0, abilityId0)
call SaveInteger(whichHashTable, unitTypeId, 1, abilityId1)
call SaveInteger(whichHashTable, unitTypeId, 2, abilityId2)
call SaveInteger(whichHashTable, unitTypeId, 3, abilityId3)
call SaveInteger(whichHashTable, unitTypeId, 4, abilityId4)
endfunction
function SupportsHeroTypeForAbilityLevel takes integer unitTypeId returns boolean
return HaveSavedInteger(whichHashTable, unitTypeId, 0)
endfunction
private function GetHeroSkillLevel takes unit hero, integer abilityId returns integer
if (abilityId == 0) then
return 0
endif
return GetUnitAbilityLevelSwapped(abilityId, hero)
endfunction
private function SelectHeroSkillUntilLevel takes unit hero, integer abilityId, integer originalLevel, integer toBeSkilledAbilityId, integer toBeSkilledLevel, real cooldownPercentage returns nothing
local integer i
if (abilityId != 0) then
//call PrintMsg("Skilling hero skill " + GetObjectName(abilityId) + " to level " + I2S(toBeSkilledLevel) + " with cooldown percentage " + R2S(cooldownPercentage))
set i = 0
loop
exitwhen ((i == originalLevel) or (abilityId == toBeSkilledAbilityId and i == toBeSkilledLevel))
call SelectHeroSkill(hero, abilityId)
set i = i + 1
endloop
//call PrintMsg("Setting cooldown to " + R2S(BlzGetUnitAbilityCooldown(hero, abilityId, i - 1) * cooldownPercentage))
call BlzStartUnitAbilityCooldown(hero, abilityId, BlzGetUnitAbilityCooldown(hero, abilityId, i - 1) * cooldownPercentage)
endif
endfunction
private function TimerFunctionReskill takes nothing returns nothing
local integer timerHandleId = GetHandleId(GetExpiredTimer())
local unit hero = LoadUnitHandle(timerHashTable, timerHandleId, 0)
local integer abilityId0 = LoadInteger(timerHashTable, timerHandleId, 1)
local integer abilityId1 = LoadInteger(timerHashTable, timerHandleId, 2)
local integer abilityId2 = LoadInteger(timerHashTable, timerHandleId, 3)
local integer abilityId3 = LoadInteger(timerHashTable, timerHandleId, 4)
local integer abilityId4 = LoadInteger(timerHashTable, timerHandleId, 5)
local integer abilityLevel0 = LoadInteger(timerHashTable, timerHandleId, 6)
local integer abilityLevel1 = LoadInteger(timerHashTable, timerHandleId, 7)
local integer abilityLevel2 = LoadInteger(timerHashTable, timerHandleId, 8)
local integer abilityLevel3 = LoadInteger(timerHashTable, timerHandleId, 9)
local integer abilityLevel4 = LoadInteger(timerHashTable, timerHandleId, 10)
local real abilityCooldownPercentage0 = LoadReal(timerHashTable, timerHandleId, 11)
local real abilityCooldownPercentage1 = LoadReal(timerHashTable, timerHandleId, 12)
local real abilityCooldownPercentage2 = LoadReal(timerHashTable, timerHandleId, 13)
local real abilityCooldownPercentage3 = LoadReal(timerHashTable, timerHandleId, 14)
local real abilityCooldownPercentage4 = LoadReal(timerHashTable, timerHandleId, 15)
local integer abilityId = LoadInteger(timerHashTable, timerHandleId, 16)
local integer level = LoadInteger(timerHashTable, timerHandleId, 17)
// TODO the to be skilled ability has the highest priority in skilling?
if (abilityId0 == abilityId) then
call SelectHeroSkillUntilLevel(hero, abilityId0, abilityLevel0, abilityId, level, abilityCooldownPercentage0)
elseif (abilityId1 == abilityId) then
call SelectHeroSkillUntilLevel(hero, abilityId1, abilityLevel1, abilityId, level, abilityCooldownPercentage1)
elseif (abilityId2 == abilityId) then
call SelectHeroSkillUntilLevel(hero, abilityId2, abilityLevel2, abilityId, level, abilityCooldownPercentage2)
elseif (abilityId3 == abilityId) then
call SelectHeroSkillUntilLevel(hero, abilityId3, abilityLevel3, abilityId, level, abilityCooldownPercentage3)
elseif (abilityId4 == abilityId) then
call SelectHeroSkillUntilLevel(hero, abilityId4, abilityLevel4, abilityId, level, abilityCooldownPercentage4)
endif
if (abilityId0 != abilityId) then
call SelectHeroSkillUntilLevel(hero, abilityId0, abilityLevel0, abilityId, level, abilityCooldownPercentage0)
endif
if (abilityId1 != abilityId) then
call SelectHeroSkillUntilLevel(hero, abilityId1, abilityLevel1, abilityId, level, abilityCooldownPercentage1)
endif
if (abilityId2 != abilityId) then
call SelectHeroSkillUntilLevel(hero, abilityId2, abilityLevel2, abilityId, level, abilityCooldownPercentage2)
endif
if (abilityId3 != abilityId) then
call SelectHeroSkillUntilLevel(hero, abilityId3, abilityLevel3, abilityId, level, abilityCooldownPercentage3)
endif
if (abilityId4 != abilityId) then
call SelectHeroSkillUntilLevel(hero, abilityId4, abilityLevel4, abilityId, level, abilityCooldownPercentage4)
endif
call UnitRemoveAbility(hero, ABILITY_ID_UNLEARN)
call SaveBoolean(whichHashTable, GetHandleId(hero), 0, true)
call PauseTimer(GetExpiredTimer())
call FlushChildHashtable(timerHashTable, timerHandleId)
call DestroyTimer(GetExpiredTimer())
endfunction
private function SetHeroAbilityLevelEx takes unit hero, integer abilityId, integer level returns nothing
local timer whichTimer = CreateTimer()
local integer timerHandleId = GetHandleId(whichTimer)
local integer abilityId0 = LoadInteger(whichHashTable, GetUnitTypeId(hero), 0)
local integer abilityId1 = LoadInteger(whichHashTable, GetUnitTypeId(hero), 1)
local integer abilityId2 = LoadInteger(whichHashTable, GetUnitTypeId(hero), 2)
local integer abilityId3 = LoadInteger(whichHashTable, GetUnitTypeId(hero), 3)
local integer abilityId4 = LoadInteger(whichHashTable, GetUnitTypeId(hero), 4)
local integer abilityLevel0 = GetHeroSkillLevel(hero, abilityId0)
local integer abilityLevel1 = GetHeroSkillLevel(hero, abilityId1)
local integer abilityLevel2 = GetHeroSkillLevel(hero, abilityId2)
local integer abilityLevel3 = GetHeroSkillLevel(hero, abilityId3)
local integer abilityLevel4 = GetHeroSkillLevel(hero, abilityId4)
local real abilityCooldownPercentage0 = 0.0
local real abilityCooldownPercentage1 = 0.0
local real abilityCooldownPercentage2 = 0.0
local real abilityCooldownPercentage3 = 0.0
local real abilityCooldownPercentage4 = 0.0
if (abilityId0 != 0 and BlzGetUnitAbilityCooldown(hero, abilityId0, abilityLevel0) > 0.0) then
set abilityCooldownPercentage0 = BlzGetUnitAbilityCooldownRemaining(hero, abilityId0) / BlzGetUnitAbilityCooldown(hero, abilityId0, abilityLevel0)
endif
if (abilityId1 != 0 and BlzGetUnitAbilityCooldown(hero, abilityId1, abilityLevel1) > 0.0) then
set abilityCooldownPercentage1 = BlzGetUnitAbilityCooldownRemaining(hero, abilityId1) / BlzGetUnitAbilityCooldown(hero, abilityId1, abilityLevel1)
endif
if (abilityId2 != 0 and BlzGetUnitAbilityCooldown(hero, abilityId2, abilityLevel2) > 0.0) then
set abilityCooldownPercentage2 = BlzGetUnitAbilityCooldownRemaining(hero, abilityId2) / BlzGetUnitAbilityCooldown(hero, abilityId2, abilityLevel2)
endif
if (abilityId3 != 0 and BlzGetUnitAbilityCooldown(hero, abilityId3, abilityLevel3) > 0.0) then
set abilityCooldownPercentage3 = BlzGetUnitAbilityCooldownRemaining(hero, abilityId3) / BlzGetUnitAbilityCooldown(hero, abilityId3, abilityLevel3)
endif
if (abilityId4 != 0 and BlzGetUnitAbilityCooldown(hero, abilityId4, abilityLevel4) > 0.0) then
set abilityCooldownPercentage4 = BlzGetUnitAbilityCooldownRemaining(hero, abilityId4) / BlzGetUnitAbilityCooldown(hero, abilityId4, abilityLevel4)
endif
call BlzEndUnitAbilityCooldown(hero, abilityId0)
call BlzEndUnitAbilityCooldown(hero, abilityId1)
call BlzEndUnitAbilityCooldown(hero, abilityId2)
call BlzEndUnitAbilityCooldown(hero, abilityId3)
call BlzEndUnitAbilityCooldown(hero, abilityId4)
//call PrintMsg("Adding ability " + GetObjectName(ABILITY_ID_UNLEARN) + " to unit " + GetUnitName(hero))
call UnitAddAbility(hero, ABILITY_ID_UNLEARN)
call IssueImmediateOrderById(hero, ABILITY_ORDER_ID_UNLEARN)
call SaveUnitHandle(timerHashTable, timerHandleId, 0, hero)
call SaveInteger(timerHashTable, timerHandleId, 1, abilityId0)
call SaveInteger(timerHashTable, timerHandleId, 2, abilityId1)
call SaveInteger(timerHashTable, timerHandleId, 3, abilityId2)
call SaveInteger(timerHashTable, timerHandleId, 4, abilityId3)
call SaveInteger(timerHashTable, timerHandleId, 5, abilityId4)
call SaveInteger(timerHashTable, timerHandleId, 6, abilityLevel0)
call SaveInteger(timerHashTable, timerHandleId, 7, abilityLevel1)
call SaveInteger(timerHashTable, timerHandleId, 8, abilityLevel2)
call SaveInteger(timerHashTable, timerHandleId, 9, abilityLevel3)
call SaveInteger(timerHashTable, timerHandleId, 10, abilityLevel4)
call SaveReal(timerHashTable, timerHandleId, 11, abilityCooldownPercentage0)
call SaveReal(timerHashTable, timerHandleId, 12, abilityCooldownPercentage1)
call SaveReal(timerHashTable, timerHandleId, 13, abilityCooldownPercentage2)
call SaveReal(timerHashTable, timerHandleId, 14, abilityCooldownPercentage3)
call SaveReal(timerHashTable, timerHandleId, 15, abilityCooldownPercentage4)
call SaveInteger(timerHashTable, timerHandleId, 16, abilityId)
call SaveInteger(timerHashTable, timerHandleId, 17, level)
call TimerStart(whichTimer, 1.0, false, function TimerFunctionReskill)
endfunction
// TODO Not only guard calls but queue them?
function SetHeroAbilityLevel takes unit hero, integer abilityId, integer level returns nothing
if (not HaveSavedBoolean(whichHashTable, GetHandleId(hero), 0) or LoadBoolean(whichHashTable, GetHandleId(hero), 0)) then
if (not SupportsHeroTypeForAbilityLevel(GetUnitTypeId(hero))) then
call PrintMsg("Warning: Unit type ID " + GetObjectName(GetUnitTypeId(hero)) + " is not supported for changing the hero ability level.")
endif
call SaveBoolean(whichHashTable, GetHandleId(hero), 0, false)
call SetHeroAbilityLevelEx(hero, abilityId, level)
endif
endfunction
endlibrary
Last edited: