library MaxBash initializer Init
globals
// This is the raw code of max bash ability
// Default: 'MBsh'
private constant integer MAX_BASH = 'MBsh'
// Spells frames per second
// Default: 50
private constant integer FPS = 50
// Push model file
// Default: Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl
private constant string PUSH_FILE = "Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl"
// On push file (when ability is triggerd) applay this effect
// Default: Abilities\\Spells\\NightElf\\ThornsAura\\ThornsAuraDamage.mdl
private constant string ON_PUSH_FILE = "Abilities\\Spells\\NightElf\\ThornsAura\\ThornsAuraDamage.mdl"
// On which point of attacker "ON_PUSH_FILE" is added?
// Default: weapon
private constant string ATTACH_POINT = "weapon"
// This is speed in game coordinates, of how fast unit is pushed away
// defined star and end speeds of pushed unit
// Default: 300 / 200
private constant real PUSH_SPEED_START = 300.
private constant real PUSH_SPEED_END = 150.
// This is deacceleration of unit. This value must never be negative
// Default: 250
private constant real PUSH_DEACC = 250.
// Should trees be destroyed?
// Default: true
private constant boolean DESTROY_TREES = true
// Should floating text be created?
// Default: true
private constant boolean ALLOW_FLOATING_TEXT = true
// The duration of floating text in seconds
// Default: 3.5
private constant real FLOATING_TEXT_DURATION = 3.5
// *** Do not edit this vars here, edit them below ***
// {
private integer Levels = 0
private integer array BashChance[8191]
private real array BashDamage[8191]
private boolean array BashAsPerc[8191]
private real array BashPRange[8191]
// }
endglobals
// -------------------------------------------------------------
// *** Level data setup here ***
private function SetupMaxBash takes nothing returns nothing
// *** Max level of the spell ***
// Default: 3
set Levels = 3
// *** The bash chance per level ***
// Default: 15 / 17 / 20
set BashChance[1] = 15
set BashChance[2] = 17
set BashChance[3] = 20
// *** Defines should dealed damage be a percentage of
// dealed damage or should it be extra damage ***
// Default: true / true / true
set BashAsPerc[1] = true
set BashAsPerc[2] = true
set BashAsPerc[3] = true
// *** The bash damage per level ***
// Default: 3, 4.5, 6
set BashDamage[1] = 3.0
set BashDamage[2] = 4.5
set BashDamage[3] = 6.0
// *** This is the push range of unit ***
// Default: 200 / 250 / 310
set BashPRange[1] = 200.
set BashPRange[2] = 250.
set BashPRange[3] = 310.
endfunction
// ======================================================================
// DO NOT EDIT BELOW IF YOU DONT KNOW JASS
// ======================================================================
// *** Main global vars ***
globals
// *** Constants ***
private constant real TIMER_DELAY = 1./FPS
private constant real TREES_PICK_RANGE = 192.
// *** Other globals ***
private code pLoop = null
private real MinX = 0.
private real MinY = 0.
private real MaxX = 0.
private real MaxY = 0.
endglobals
// -------------------------------------------------------------------
// ---> New types define
// -------------------------------------------------------------------
private struct vector
// *** Vector members ***
readonly real x
readonly real y
readonly real dx
readonly real dy
// *** Constructor ***
static method create takes real x, real y, real rad returns vector
local vector this = vector.allocate()
set this.x = x
set this.y = y
set this.dx = Cos(rad)
set this.dy = Sin(rad)
return (this)
endmethod
// *** Destructor ***
public method delete takes nothing returns nothing
set this.x = 0
set this.y = 0
set this.dx = 0
set this.dy = 0
call this.destroy()
endmethod
// *** Offset move method ***
public method OffsetMove takes real dist returns nothing
set this.x = this.x + dist * this.dx
set this.y = this.y + dist * this.dy
endmethod
endstruct
// *** Main bash struct data ***
private struct bash
// *** Bash members ***
readonly unit u
readonly vector v
public real vel
public real dist
public static bash array Bash[8191]
public static integer BashCount = 0
public static timer Countdown = null
// *** Try load timer ***
static method TryLoadTimer takes nothing returns nothing
if (bash.Countdown == null) then
set bash.Countdown = CreateTimer()
call TimerStart(bash.Countdown, TIMER_DELAY, true, pLoop)
endif
endmethod
// *** Try break timer ***
static method TryBreakTimer takes nothing returns nothing
if (bash.BashCount == null) then
call PauseTimer(bash.Countdown)
call DestroyTimer(bash.Countdown)
set bash.Countdown = null
endif
endmethod
// *** Constructor ***
static method create takes unit u, real rad, integer lvl returns bash
local bash this = bash.allocate()
set this.u = u
set this.v = vector.create(GetUnitX(u), GetUnitY(u), rad)
set this.vel = PUSH_SPEED_START
set this.dist = lvl:BashPRange
set bash.Bash[bash.BashCount] = this
set bash.BashCount = bash.BashCount + 1
call bash.TryLoadTimer()
return (this)
endmethod
// *** Destructor ***
public method delete takes nothing returns nothing
set this.u = null
set bash.BashCount = bash.BashCount - 1
set bash.Bash[this] = bash.Bash[bash.BashCount]
call bash.TryBreakTimer()
call this.v.delete()
call this.destroy()
endmethod
endstruct
// -------------------------------------------------------------------
// Spells custom defined functions
// -------------------------------------------------------------------
private function QMod takes integer divid, integer divs returns integer
return divid - (divid/divs) * divs
endfunction
// *** This is random percentage chance to trigger an ability ***
private function GetPercent takes integer chance returns boolean
local integer p = GetRandomInt(1, 100)
//call SetRandomSeed(p/GetRandomInt(1, p)*QMod(GetRandomInt(0, 100000), GetRandomInt(3, 96)))
return 0 == QMod(p, 100/chance) //and chance*(100/chance) >= p
endfunction
// *** Returns angle between 2 widgets ***
private function Ang takes widget w1, widget w2 returns real
return Atan2(GetWidgetY(w2)-GetWidgetY(w1), GetWidgetX(w2)-GetWidgetX(w1))
endfunction
// *** Instant effects add ***
private function AddInstantEffect takes string file, vector v returns nothing
call DestroyEffect(AddSpecialEffect(file, v.x, v.y))
endfunction
// *** This will change unit position ***
private function SetUnitPos takes unit whichUnit, vector v returns nothing
local real x = v.x
local real y = v.y
// *** Limited x ***
if (x < MinX) then
set x = MinX
elseif (x > MaxX) then
set x = MaxX
endif
// *** Limited y ***
if (y < MinY) then
set y = MinY
elseif (y > MaxY) then
set y = MaxY
endif
// *** Move unit ***
call SetUnitPosition(whichUnit, x, y)
endfunction
// *** Clears nerby trees ***
private function FilterDests takes nothing returns nothing
call KillDestructable(GetFilterDestructable())
endfunction
private function TryClearTrees takes vector v returns nothing
// *** Locals ***
local code c = function FilterDests
local rect r
local real rd
local boolexpr bx
// *** If trees can be destroyed ***
if (DESTROY_TREES) then
set rd = TREES_PICK_RANGE*0.5
set r = Rect(v.x-rd, v.y-rd, v.x+rd, v.y+rd)
set bx = Filter(c)
// *** Clear all dests ***
call EnumDestructablesInRect(r, bx, null)
call RemoveRect(r)
call DestroyBoolExpr(bx)
// *** Null a "must" locals ***
set r = null
set bx = null
endif
endfunction
// *** Quick simple timed destroy of text tag ***
private function DestroyTextTagTimed takes texttag tt, real dur returns nothing
call TriggerSleepAction(dur)
call DestroyTextTag(tt)
endfunction
// -------------------------------------------------------------------
// *** Main loop function ***
private function MaxBashPeriod takes nothing returns nothing
local integer i = 0
local bash b = bash(0)
// *** Loop through all casts ***
loop
exitwhen (i >= bash.BashCount)
set b = bash.Bash
// *** Can be move our unit? ***
if (b.dist > 0.) then
// *** Setup values ***
set b.dist = b.dist - (b.vel * TIMER_DELAY)
call b.v.OffsetMove(b.vel*TIMER_DELAY)
if (PUSH_SPEED_START-PUSH_SPEED_END >= 0.) then
set b.vel = RMaxBJ(b.vel-PUSH_DEACC*TIMER_DELAY, PUSH_SPEED_END)
else
set b.vel = RMinBJ(b.vel+PUSH_DEACC*TIMER_DELAY, PUSH_SPEED_START)
endif
// *** Now clear path and move object ***
call TryClearTrees(b.v)
call SetUnitPos(b.u, b.v)
call AddInstantEffect(PUSH_FILE, b.v)
elseif (b.u != null) then
// *** One spell instance ends here ***
call PauseUnit(b.u, false)
call b.delete()
if (bash.BashCount > 0) then
set i = i - 1
endif
endif
set i = i + 1
endloop
endfunction
// ===================================================================
// *** Main spell function (condition / action) ***
private function MaxBash takes nothing returns nothing
local unit u // Damages source unit
local unit v // Victim unit
local integer lvl // Spell level
local real dmg // Spells extra damage
// *** Add periodic unit? ***
if (GetTriggerEventId() != EVENT_UNIT_DAMAGED) then
if not IsUnitType(GetTriggerUnit(), UNIT_TYPE_STRUCTURE) then
call TriggerRegisterUnitEvent(gg_trg_Max_Bash, GetTriggerUnit(), EVENT_UNIT_DAMAGED)
endif
return
endif
// *** Set locals ***
set u = GetEventDamageSource()
set v = GetTriggerUnit()
set lvl = GetUnitAbilityLevel(u, MAX_BASH)
// *** Attacker has MaxBash ability? ***
if (lvl > null) then
// *** if yes then check can he trigger an attack ***
if (GetPercent(lvl:BashChance)) then
// *** No more exec ***
call DisableTrigger(gg_trg_Max_Bash)
// *** Deal extra damage ***
if (lvl:BashAsPerc) then
set dmg = GetEventDamage()*lvl:BashDamage
else
set dmg = lvl:BashDamage
endif
call UnitDamageTarget(u, v, dmg, true, false, ATTACK_TYPE_HERO, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
// *** Apply custom effect ***
call DestroyEffect(AddSpecialEffectTarget(ON_PUSH_FILE, u, ATTACH_POINT))
// *** Floating text add? ***
if (ALLOW_FLOATING_TEXT) then
call CreateTextTagUnitBJ("+"+I2S(R2I(dmg)), v, 0., 10., 100., 100., 100., 0.)
call SetTextTagVelocityBJ(bj_lastCreatedTextTag, 64., 90.)
//call SetTextTagLifespan(bj_lastCreatedTextTag, 5.)
call DestroyTextTagTimed.execute(bj_lastCreatedTextTag, FLOATING_TEXT_DURATION)
endif
// *** Now pause the victim ***
call PauseUnit(v, true)
// *** Load main bash struct ***
call bash.create(v, Ang(u, v), lvl)
// *** Allow future exec ***
call EnableTrigger(gg_trg_Max_Bash)
endif
endif
// *** Null locals ***
set u = null
set v = null
endfunction
// *** Non-leaking filter ***
private constant function DummyBool takes nothing returns boolean
return true
endfunction
// *** On map startup register any loaded unit as taking damage ***
private function FilterRegisterStartUp takes nothing returns nothing
if not IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) then
call TriggerRegisterUnitEvent(gg_trg_Max_Bash, GetFilterUnit(), EVENT_UNIT_DAMAGED)
endif
endfunction
// *** Main init function ***
private function Init takes nothing returns nothing
// *** Load locals ***
local code c = function FilterRegisterStartUp
local group g = CreateGroup()
local region r = CreateRegion()
local filterfunc ff = Filter(c)
// *** Load trigger ***
set gg_trg_Max_Bash = CreateTrigger()
// ---> Register event
call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, ff)
call DestroyFilter(ff)
// ---> Add cond/act
set c = function MaxBash
call TriggerAddCondition(gg_trg_Max_Bash, Condition(c))
// *** Now add periodic events ***
set ff = Filter(function DummyBool)
call RegionAddRect(r, bj_mapInitialPlayableArea)
call TriggerRegisterEnterRegion(gg_trg_Max_Bash, r, ff)
call DestroyFilter(ff)
// *** Now call user setup ***
call SetupMaxBash()
set pLoop = function MaxBashPeriod
// *** Get min, max coords
set MinX = GetRectMinX(bj_mapInitialPlayableArea)
set MinY = GetRectMinY(bj_mapInitialPlayableArea)
set MaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set MaxY = GetRectMaxY(bj_mapInitialPlayableArea)
// *** Null needed locals ***
call DestroyGroup(g)
set ff = null
set g = null
endfunction
endlibrary