- Joined
- Jun 5, 2008
- Messages
- 2,573
Im making skills for my hero, the Artisan of War.
After that, we will see.
After that, we will see.
//==========================================================================================
//Soul Harvest (Xerex) v1.02 by watermelon_1234
//__________________________________________________________________________________________
//Description:
// Corpses within 500 range of Dark Lord will bolster his offensive power.
//******************************************************************************************
//Libraries required:
// - BonusMod
// - GroupUtils
// - TimedLoop
//##########################################################################################
//Importing:
// 1. Copy the ability, Soul Harvest, and its buff.
// 2. Copy this trigger.
// 3. Implement required libraries.
// 4. Configure the spell.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//Notes:
// The level check may be inefficient as it always update to that manually. The nice thing
// is that this spell supports Tome of Retraining.
//$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
//Changelog:
// v1.02: Made it reduce the time it would check, adds a special effect if the hero has a
// bonus.
// v1.01: Made it use TimedLoop
//==========================================================================================
scope SoulHarvest
native UnitAlive takes unit id returns boolean //A better way to check if a unit is alive.
globals
private constant integer SPELL_ID = 'A005' //Raw id of the Soul Harvest ability.
private constant real TIMER_LOOP = 0.5 //How often the timer would check the corpses
private constant string BONUS_SFX = "Abilities\\Weapons\\IllidanMissile\\IllidanMissile.mdl" //The SFX that would be attached to the hero if it has a damage bonus
private constant string BONUS_SFX_ATTACH = "hand,left" //The attachment point for the BONUS_SFX
endglobals
//The range of the ability which enumerates corpses.
private constant function Range takes integer lvl returns real
return 500. + 0*lvl
endfunction
//The damage bonus gained for each corpse.
private constant function DamageBonus takes integer lvl returns integer
return 2 + 2*lvl
endfunction
//The max damage bonus that one can get from this ability.
private constant function MaxDamageBonus takes integer lvl returns integer
return 70 + 0*lvl
endfunction
//-------------END OF CONFIGURATION-------------------
globals
private boolexpr e //Used for counting corpses
endglobals
private struct Data
unit hero //The hero that learned the ability.
integer lvl = 1 //The level of the ability for the hero. Is updated at the end of every loop as it stores the past level.
integer count //Counts how many corpses there are near the hero.
integer oldCount = 0 //Stores the count from the previous time the loop was run. Used to update the attack damage bonus correctly.
integer totalBonus = 0 //The total attack damage bonus the hero has from this ability.
real timeCounter = 0 //Counts how often the struct should be looped.
effect sfx = null //The effect for the bonus.
private static thistype temp //Used for the group filter so that we can set count of a struct instance correctly.
static method create takes unit h returns thistype
local thistype this = thistype.allocate()
set .hero = h
call .startTimedLoop()
return this
endmethod
//Note that this is a filter. Used only to count dead units for the bonus.
static method countCorpses takes nothing returns boolean
if not UnitAlive(GetFilterUnit()) then //Corpses count as units that are dead.
set temp.count = temp.count + 1
endif
return false
endmethod
//Used so many times that I just made a method for this. Basically removes any bonus the hero gained from this spell.
method resetBonus takes nothing returns nothing
call AddUnitBonus(.hero,BONUS_DAMAGE,-.totalBonus)
endmethod
method removeEffect takes nothing returns nothing
call DestroyEffect(.sfx)
set .sfx = null
endmethod
method onTimedLoop takes nothing returns boolean
local integer add //Considers what attack damage bonus the spell needs to add
local integer curLvl = GetUnitAbilityLevel(.hero,SPELL_ID)
//If the level is 0 that means the hero no longer has the ability. That means the spell should stop.
if curLvl == 0 then
//Only reset the bonus if .totalBonus is greater than 0.
if .totalBonus > 0 then
call .resetBonus()
call .removeEffect()
endif
return false
endif
if .timeCounter == 0 then
if UnitAlive(.hero) then
set .count = 0 //Set to 0 first or else counting the corpses will be messed up.
set temp = this
call GroupEnumUnitsInArea(ENUM_GROUP,GetUnitX(.hero),GetUnitY(.hero),Range(.lvl),e)
//No corpses but oldCount has a different number. Remove any bonus given to the hero and correctly set oldCount to 0.
if .count == 0 and .oldCount != 0 then
call .resetBonus()
call .removeEffect()
set .totalBonus = 0
set .oldCount = 0
//Previous level is not updated with the current level.
//In this case, ignore any bonus the hero has received from last loop by resetting it and manually give the correct bonus.
elseif .lvl != curLvl then
call .resetBonus()
//Make sure the bonus will not exceed MaxDamageBonus.
//Remember: The bonus given to the hero is the # of corpses times the damage bonus each corpse gives but the bonus is capped.
if .count*DamageBonus(curLvl) > MaxDamageBonus(curLvl) then
set .totalBonus = MaxDamageBonus(curLvl)
else
set .totalBonus = .count*DamageBonus(curLvl)
endif
call AddUnitBonus(.hero,BONUS_DAMAGE,.totalBonus)
set .lvl = curLvl
elseif .count != .oldCount then //The counts of the corpses aren't the same so change the bonus. Otherwise, don't do anything after this as all is well.
//If the supposed bonus is bigger than MaxDamageBonus, limit it.
//add is the difference between the bonus the hero should have from the spell and the current bonus it has.
if .count*DamageBonus(.lvl) > MaxDamageBonus(.lvl) then
set add = MaxDamageBonus(.lvl) - .totalBonus
else
set add = .count*DamageBonus(.lvl) - .totalBonus
endif
call AddUnitBonus(.hero,BONUS_DAMAGE,add)
//Update some variables to work for the next loop
set .oldCount = .count
set .totalBonus = .totalBonus + add
endif
if .totalBonus > 0 and .sfx == null then
set .sfx = AddSpecialEffectTarget(BONUS_SFX,.hero,BONUS_SFX_ATTACH)
endif
endif
endif
set .timeCounter = .timeCounter + TimedLoop_PERIOD
if .timeCounter >= TIMER_LOOP then
set .timeCounter = 0
endif
return true
endmethod
implement TimedLoop
static method learnSkill takes nothing returns boolean
if GetLearnedSkill() == SPELL_ID and GetUnitAbilityLevel(GetTriggerUnit(),SPELL_ID) == 1 then
call thistype.create(GetTriggerUnit())
endif
return false
endmethod
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t,EVENT_PLAYER_HERO_SKILL)
call TriggerAddCondition(t,Condition(function thistype.learnSkill))
set e = Filter(function thistype.countCorpses)
endmethod
endstruct
endscope
I'm pretty sure only vJass is accepted, sorry. However, things may change if there's a serious lack of coders which appears to be happening right now...I want to create the spells for Dentothor, is that OK?
I use GUI if that is alright.