// This is the main Orianna module which contains most of the code
// that handles Orianna's abilities. We depend on DamageType because
// Shield depends on DamageType, and is necessary to implement
// Command: Protect.
// Note: This library contains four (4) customizable sections
library Orianna requires DamageType
// InitShim is a small adapter used to prevent a specific
// instantiation issue.
private module InitShim
//The only implemented method necessary for the adapter
private static method onInit takes nothing returns nothing
call i()
endmethod
endmodule
// Throw handler is a private module used to throw units with
// a specific pattern which we desire to behave like Command:
// Shockwave in League of Legends. Hence it is only used by
// Command: Shockwave
private struct ThrowHandler
private unit u
private real dX
private real dY
private real dZ
private static thistype array DB
private static integer dbIndex=-1
private static timer time=CreateTimer()
//*********************************************************
// This section to be modified by the user
//*********************************************************
// The clock period determines the frame rate of the
// throwing algorithm. A value between 1./20. and 1./60. is
// recommended.
private static constant real CLOCK_PERIOD =1./30.
// The rate in units per second at which thrown units
// accelerate towards the ground.
private static constant real GRAVITY =200.
// Below this height, units are considered back on the
// ground. Choose something below 10. or you'll have visual
// abnormalities.
private static constant real GROUND_HEIGHT_MAX=5.
//*********************************************************
// End customizable section
//*********************************************************
// ThrowHandler.p is the periodic function ThrowHandler
// uses to handle multiple units simultaneously.
private static method p takes nothing returns nothing
local thistype t
local integer i=0
loop
exitwhen i>dbIndex
set t=DB[i]
call SetUnitFlyHeight(t.u,GetUnitFlyHeight(t.u)+t.dZ,0.)
set t.dZ=t.dZ-GRAVITY*CLOCK_PERIOD
call SetUnitX(t.u,GetUnitX(t.u)+t.dX)
call SetUnitY(t.u,GetUnitY(t.u)+t.dY)
if GetUnitFlyHeight(t.u)<GROUND_HEIGHT_MAX and t.dZ<0. then
call t.destroy()
set DB[i]=DB[dbIndex]
set dbIndex=dbIndex-1
set i=i-1
if dbIndex==-1 then
call PauseTimer(time)
endif
endif
set i=i+1
endloop
endmethod
// This is the public method used for imparting a throw vector on
// a unit. This is the only public interface with the struct.
public static method add takes unit u, real dx, real dy, real dz returns nothing
local thistype tempDat=thistype.create()
set tempDat.u=u
set tempDat.dX=dx*CLOCK_PERIOD
set tempDat.dY=dy*CLOCK_PERIOD
set tempDat.dZ=dz*CLOCK_PERIOD
set dbIndex=dbIndex+1
set DB[dbIndex]=tempDat
if UnitAddAbility(u,'Arav') then
call UnitRemoveAbility(u,'Arav')
endif
if dbIndex==0 then
call TimerStart(time,CLOCK_PERIOD,true,function thistype.p)
endif
endmethod
endstruct
// HasteHandler is a private struct used to increase the speed of
// allied units in a specific fashion implemented by Command:
// Distortion.
private struct HasteHandler
//**********************************************************
// Customizable Section
//**********************************************************
// The full haste duration units are imparted after leaving
// the distortion field in seconds.
private static constant real HASTE_DURATION=2.
// The clock period allows the user to control how accurate
// the slowing effect is. Recommend a value between 1./2. and
// 1./60.
private static constant real CLOCK_PERIOD=1./5.
// The rawcode ID of the dummy caster unit
private static constant integer DUMMY_CASTER_ID='h004'
// The rawcode ID of the haste ability
private static constant integer HASTE_ABILITY_ID='A007'
// The raw string order ID of the haste ability
private static constant string HASTE_STRING="bloodlust"
//**********************************************************
// End Customizable Section
//**********************************************************
private static thistype array DB
private static integer dbIndex=-1
private static HandleTable fromU
private static group grp=CreateGroup()
private static timer clock=CreateTimer()
private static unit caster
private unit who
private integer level=0
private real timeLeft=HASTE_DURATION
// The periodic method used to control the hasting of all
// units simultaneously
private static method periodic takes nothing returns nothing
local thistype tempDat
local integer index=0
loop
exitwhen index>dbIndex
set tempDat=DB[index]
set tempDat.timeLeft=tempDat.timeLeft-CLOCK_PERIOD
call SetUnitAbilityLevel(thistype.caster,thistype.HASTE_ABILITY_ID,R2I(tempDat.level*tempDat.timeLeft/thistype.HASTE_DURATION)+1)
call IssueTargetOrder(thistype.caster,HASTE_STRING,tempDat.who)
if tempDat.timeLeft<=0. then
call fromU.flush(tempDat.who)
call tempDat.destroy()
set DB[index]=DB[dbIndex]
set thistype.dbIndex=thistype.dbIndex-1
if dbIndex==-1 then
call PauseTimer(thistype.clock)
endif
endif
set index=index+1
endloop
endmethod
// This is the public method used to *set* a unit's haste
// value. This is important because we need to be able to
// over-write a unit's existing haste value if it steps
// back onto the distortion ring.
public static method setUnit takes unit u, integer z returns nothing
local thistype tempDat
if fromU.exists(u) then
set tempDat=fromU[u]
set tempDat.level=z
set tempDat.timeLeft=HASTE_DURATION
else
set tempDat=thistype.create()
set tempDat.who=u
set tempDat.level=z
set fromU[u]=tempDat
set dbIndex=dbIndex+1
set DB[dbIndex]=tempDat
if dbIndex==0 then
call TimerStart(clock,CLOCK_PERIOD,true,function thistype.periodic)
endif
endif
call SetUnitAbilityLevel(thistype.caster,HASTE_ABILITY_ID,z)
call IssueTargetOrder(thistype.caster,HASTE_STRING,tempDat.who)
endmethod
// The initialization function called in the InitShim which
// creates a static dummy
private static method i takes nothing returns nothing
set thistype.fromU=HandleTable.create()
set thistype.caster=CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),DUMMY_CASTER_ID,0.,0.,0.)
call UnitAddAbility(thistype.caster,HASTE_ABILITY_ID)
endmethod
//calls i() on initialization
implement InitShim
endstruct
// SlowHandler is a private interface for handling the specific
// slow procedure used in Command: Distortion
private struct SlowHandler
//***********************************************************
// Customizable Section
//***********************************************************
// The duration of slows after leaving the distortion field
private static constant real SLOW_DURATION=2.
// The clock period for handling the slow timings. I suggest
// a value between 1./2. and 1./30.
private static constant real CLOCK_PERIOD=1./5.
// The unit ID of the dummy caster
private static constant integer DUMMY_CASTER_ID='h004'
// The ability ID of slow
private static constant integer SLOW_ABILITY_ID='A006'
// The order ID for the slow ability
private static constant string SLOW_ORDER="slow"
//***********************************************************
// End Customizable Section
//***********************************************************
private static thistype array DB
private static integer dbIndex=-1
private static HandleTable fromU
private static group grp=CreateGroup()
private static timer clock=CreateTimer()
private static unit caster
private unit who
private integer level=0
private real timeLeft=SLOW_DURATION
// Periodic function used to handle all the slow effects
// simultaneously.
private static method periodic takes nothing returns nothing
local thistype tempDat
local integer index=0
loop
exitwhen index>dbIndex
set tempDat=DB[index]
set tempDat.timeLeft=tempDat.timeLeft-CLOCK_PERIOD
call SetUnitAbilityLevel(thistype.caster,thistype.SLOW_ABILITY_ID,R2I(tempDat.level*tempDat.timeLeft/thistype.SLOW_DURATION)+1)
call IssueTargetOrder(thistype.caster,SLOW_ORDER,tempDat.who)
if tempDat.timeLeft<=0. then
call fromU.flush(tempDat.who)
call tempDat.destroy()
set DB[index]=DB[dbIndex]
set thistype.dbIndex=thistype.dbIndex-1
if dbIndex==-1 then
call PauseTimer(thistype.clock)
endif
endif
set index=index+1
endloop
endmethod
// The only public interface available for the SlowHandler.
// Allows us to set the slow level of a unit arbitrarily.
public static method setUnit takes unit u, integer z returns nothing
local thistype tempDat
if fromU.exists(u) then
set tempDat=fromU[u]
set tempDat.level=z
set tempDat.timeLeft=SLOW_DURATION
else
set tempDat=thistype.create()
set tempDat.who=u
set tempDat.level=z
set fromU[u]=tempDat
set dbIndex=dbIndex+1
set DB[dbIndex]=tempDat
if dbIndex==0 then
call TimerStart(clock,CLOCK_PERIOD,true,function thistype.periodic)
endif
endif
call SetUnitAbilityLevel(thistype.caster,SLOW_ABILITY_ID,z)
call IssueTargetOrder(thistype.caster,"slow",tempDat.who)
endmethod
// Initialization function called by InitShim
private static method i takes nothing returns nothing
set thistype.fromU=HandleTable.create()
set thistype.caster=CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),DUMMY_CASTER_ID,0.,0.,0.)
call UnitAddAbility(thistype.caster,SLOW_ABILITY_ID)
endmethod
implement InitShim
endstruct
// Essentially a sound in stuct form - necessary due
// to the implementation specifics
private struct soundShim
sound s
endstruct
// Struct which overrides the library title. Here is
// the real contents of Orianna.
struct Orianna
private static group grp=CreateGroup()
private static integer dbIndex=-1
private static timer clock=CreateTimer()
private static thistype array DB
private static HandleTable fromOri
private static HandleTable preloadTable
//**************************************************************
// Customizable Section
//**************************************************************
// The unit rawcode for the dummy which points to an Orianna
// instance's ball
private static constant integer ARROW_ID='h001'
// Unit rawcode for a ball
private static constant integer BALL_ID='h000'
// Unit rawcode for the Command: Disonnance indicator
private static constant integer DISONNANCE_INDICATOR_ID='h003'
// Unit rawcode for the small stand below an immobile ball
private static constant integer STAND_INDICATOR_ID='h002'
// Unit rawcode for the circle that appears while Command:
// Shockwave is charging
private static constant integer SHOCKWAVE_INDICATOR_ID='h005'
// Unit rawcode for the dummy electric balls that appear
// while casting Command: Shockwave
private static constant integer SHOCKWAVE_ORB_ID='h006'
// Opacity value for the ball (Out of 255)
private static constant integer BALL_OPACITY=200
// Opacity value for the disonnance indicator (Out of 255)
private static constant integer DISONNANCE_INDICATOR_OPACITY=155
// Disonnance indicator Red concentration (Out of 255)
private static constant integer DISONNANCE_INDICATOR_RED=55
// Disonnance indicator Green concentration (Out of 255)
private static constant integer DISONNANCE_INDICATOR_GREEN=165
// Disonnance indicator Blue concentration (Out of 255)
private static constant integer DISONNANCE_INDICATOR_BLUE=55
// How far away should Orianna's ball pointer be from here
// in game units
private static constant real ARROW_HOVER_DISTANCE=100.
// Model scale of the ball pointer
private static constant real ARROW_SCALE=.5
// Fly height of the ball pointer
private static constant real ARROW_FLY_HEIGHT=50.
// Distance to the ball at which the ball pointer is hidden
private static constant real ARROW_MIN_RANGE=150.
// Maximum distance at which the arrow is green (close)
private static constant real ARROW_GREEN_RANGE=650.
// Maximum distance at which the arrow is yellow (far)
private static constant real ARROW_YELLOW_RANGE=925.
// The radius around the ball which damages enemies while moving
private static constant real BALL_ATTACK_DAMAGE_RADIUS=100.
// The sound pitch of the ball's begin move sound
private static constant real BALL_MOVE_START_SOUND_PITCH=1.25
// The sound pitch of the ball's hit sound
private static constant real BALL_MOVE_HIT_SOUND_PITCH=.5
// The sound pitch of the ball's end move sound
private static constant real BALL_MOVE_END_SOUND_PITCH=.75
// The flying height a ball rests at while on a unit
private static constant real BALL_OVERHEAD_HEIGHT=150.
// The flyight height a ball rests at while on the ground
private static constant real BALL_GROUND_HEIGHT=50.
// The animation scale (speed) used by a ball by default
private static constant real BALL_TIME_SCALE=1./10.
// The animation scale (speed) used by a ball on the ground
private static constant real BALL_TIME_SCALE_GROUND=1./5.
// The maximum range a ball can be away from Orianna while
// on the ground
private static constant real BALL_LEASH_RANGE_GROUND=1125.
// The maximum range a ball can be away from Orianna while
// attached to another unit
private static constant real BALL_LEASH_RANGE_ONUNIT=1225.
// How close must Orianna get to the ball to pick it up
private static constant real BALL_PICKUP_RANGE=64.
// How fast should the ball move while under the effects of
// Command: Attack or Command: Shockwave
private static constant real BALL_VELOCITY=1200.
// How accurate should the timing clock be for Orianna?
// Recommend value between 1./27. and 1./80.
private static constant real CLOCK_PERIOD=1./90.
// How long is too long between attacks to retain Orianna's
// innate?
private static constant real CLOCKWORK_WINDUP_TIMEOUT=4.
// How much flat damage should Command: Attack deal?
private static constant real COMMAND_ATTACK_FLAT_DAMAGE=30.
// How much damage per level should Command: Attack deal?
private static constant real COMMAND_ATTACK_DAMAGE_PER_LEVEL=30.
// What multiplier should be used for Command: Attack
private static constant real COMMAND_ATTACK_INTELLIGENCE_MULTIPLIER=.5
// What is the minimum damage multiplier a unit can take from
// Command: Attack?
private static constant real COMMAND_ATTACK_MINIMUM_DAMAGE_MULTIPLIER=.4
// How much should Command: Attack's damage be reduced on
// subsequent hit?
private static constant real COMMAND_ATTACK_DAMAGE_REDUCTION=.1
// Modle scale of the disonnance indicator
private static constant real DISONNANCE_INDICATOR_SCALE=2.5
// Fly height of the active disonnance indicator
private static constant real DISONNANCE_INDICATOR_HEIGHT=25.
// Radius of the active disonnance effect
private static constant real DISONNANCE_RADIUS=190.
// Flat damage of Command: Disonnance
private static constant real DISONNANCE_FLAT_DAMAGE=25.
// Additional damage per level of Command: Disonnance
private static constant real DISONNANCE_DAMAGE_PER_LEVEL=45.
// Multiplier for intelligence based damage on Command:
// Disonnance
private static constant real DISONNANCE_INTELLIGENCE_MULTIPLIER=.7
// Duration of Command: Disonnance's Active Effect
private static constant real DISONNANCE_ACTIVE_DURATION=3.
// The duration at the end of Disonnance's effect during which
// the Disonnance indicator should fade away
private static constant real DISONNANCE_INDICATOR_FADE_PERIOD=.25
// Fly height off the ball when attached to an allied unit
private static constant real PROTECT_ATTACH_RANGE=100.
// Flying height given to units who are "hidden" in the top
// left of the map
private static constant real DUMMY_HIDDEN_HEIGHT=2000.
// Model scale of "hidden" units
private static constant real DUMMY_HIDDEN_SCALE=1./100.
// X value of the map's top left corner (should be inside the
// map boundary)
private static constant real MAP_TOP_LEFT_X=-7680.
// Y value
private static constant real MAP_TOP_LEFT_Y=5630.
// model scale of the dummy indicator for a ball on the ground
private static constant real STAND_INDICATOR_SCALE=.4
// Duration in seconds of the shield imparted by Command:
// Protect
private static constant real SHIELD_DURATION=4.
// Flat shield value of Command: Protect
private static constant real SHIELD_FLAT_AMOUNT=40.
// Flat damage value of Command: Protect
private static constant real SHIELD_FLAT_DAMAGE=30.
// Damage per level of Command: Protect
private static constant real SHIELD_DAMAGE_PER_LEVEL=30.
// Additional intelligence based damage multiplier for
// Command: Protect
private static constant real SHIELD_BONUS_DAMAGE_MULTIPLIER=.3
// Shield value per level of Command: Protect
private static constant real SHIELD_AMOUNT_PER_LEVEL=40.
// Bonus Shield per intelligence of Command: Protect
private static constant real SHIELD_BONUS_MULTIPLIER=.4
// Model scale of the Command: Shockwave indicator
private static constant real SHOCK_INDIC_SCALE=8.
// Radius of Command: Shockwave's effect
private static constant real SHOCK_RADIUS=300.
// Flying height of the Shockwave Indicator
private static constant real SHOCK_INDIC_HEIGHT=-100.
// Duration of Command: Shockwave's windup animation
private static constant real SHOCK_WINDUP_DURATION=.5
// Rotational velocity of shockwave orbs during the
// windup animation
private static constant real SHOCK_WINDUP_ORB_SPEED=3.*bj_PI
// The phase difference between the shockwave orbs
private static constant real SHOCK_ORB_PHASE_DIFFERENCE=2.*bj_PI/3.
// Model scale of shockwave orbs
private static constant real SHOCK_ORB_SCALE=1.25
// XY velocity at which units are thrown under the
// effect of Command: Shockwave
private static constant real THROW_VELOCITY=500.
// Multiplier for the initial vertical velocity
private static constant real THROW_VERT_MULTIPLIER=3.
// Spawned effect when an ability hits a unit
private static constant string ABILITY_HIT_EFFECT="Abilities\\Weapons\\LordofFlameMissile\\LordofFlameMissile.mdl"
// Model file for the dummy that rests on the ball while it
// remains on the ground
private static constant string BALL_GROUND_EFFECT="buildings\\other\\CircleOfPower\\CircleOfPower.mdl"
// Sound played when the ball begins moving
private static constant string BALL_MOVE_START_SOUND="Abilities\\Spells\\Orc\\Ensnare\\EnsnareMissile.wav"
// Sound played when the ball finishes moving
private static constant string BALL_MOVE_END_SOUND="Abilities\\Weapons\\ShadowHunterMissile\\HeroShadowhunterMissileHit1.wav"
// Model displayed when disonnance occurs
private static constant string DISONNANCE_EFFECT="Abilities\\Spells\\Human\\Thunderclap\\ThunderClapCaster.mdl"
// Model displayed when disonnacne hits a unit
private static constant string DISONNANCE_HIT_EFFECT="Objects\\Spawnmodels\\Human\\HumanBlood\\HumanBloodFootman.mdl"
// Attachment point for the effect that occurs when a unit
// is hit by Command: Dissonance
private static constant string DISONNANCE_EFFECT_TARGET="chest"
// Model used when Command: Protect shields a unit
private static constant string SHIELD_FX="Abilities\\Spells\\Human\\ManaShield\\ManaShieldCaster.mdl"
// Orianna Raw ID
public static constant integer ID='E000'
// Volume passed for max volume (sounds)
public static constant integer SOUND_MAX_VOLUME=127
// Fade rate passed for max fade rate (sounds)
public static constant integer SOUND_MAX_FADERATE=12700
// Ball state values (change this if you want to avoid
// using identical values within other interfaces... I guess)
public static constant integer BALL_STATE_DEAD='d'
public static constant integer BALL_STATE_HOME='h'
public static constant integer BALL_STATE_ATTACK='a'
public static constant integer BALL_STATE_GROUND='g'
public static constant integer BALL_STATE_TARGET='t'
public static constant integer BALL_STATE_ONUNIT='o'
public static constant integer BALL_STATE_SHOCKWAVE='s'
// Ability raw ID for command: attack
public static constant integer COMMAND_ATTACK_ID='A002'
// Ability raw ID for the PASSIVE (disabled) Command: attack
public static constant integer COMMAND_ATTACK_DIS_ID='A004'
// Ability IDs for the active and passive Command: Disonnance
public static constant integer COMMAND_DISONNANCE_ID='A005'
public static constant integer COMMAND_DISSONANCE_DIS_ID='A008'
// Ability IDs for the active and passive Command: Protect
public static constant integer COMMAND_PROTECT_ID='A009'
public static constant integer COMMAND_PROTECT_DIS_ID='A00A'
// Ability ID for Command: Protect's passive effect
public static constant integer PROTECT_PASSIVE_ID='A00D'
// Ability IDs for the active and passiev Command: Shockwave
public static constant integer COMMAND_SHOCKWAVE_ID='A00B'
public static constant integer COMMAND_SHOCKWAVE_DIS_ID='A00C'
// Method ID passed. This probably won't have much use unless
// you decide to implement a second, different version of
// Orianna's innate (why?)
public static constant integer METHOD_INCREMENT_AND_COUNT='a'
//**************************************************************
// End Customizable Section
//**************************************************************
private group alreadyHit
private unit ori
private unit ball
private unit arrow
private unit shockwaveIndicator
private unit shockwaveOrb1
private unit shockwaveOrb2
private unit shockwaveOrb3
private unit standIndicator
private unit disonnanceIndicator
private unit target
private unit pTarget
private unit protectBonusUnit=null
private integer attackCount=0
private integer state=0
private integer steps=0
private integer attackRevertLevel=0
private integer dissonanceRevertLevel=0
private integer protectRevertLevel=0
private integer shockwaveRevertLevel=0
private real counterTimeout=0.
private real targetX=0.
private real targetY=0.
private real damage=0.
private real disonnanceTimeLeft=0.
private real delX=0.
private real delY=0.
private real delZ=0.
private real minDamage=0.
private real shieldAmount=0.
// Method used to passify (disable) Orianna's abilities - occurs
// when the ball already has some action.
private method passifyAbilities takes nothing returns nothing
set this.attackRevertLevel=GetUnitAbilityLevel(ori,COMMAND_ATTACK_ID)
set this.dissonanceRevertLevel=GetUnitAbilityLevel(ori,COMMAND_DISONNANCE_ID)
set this.protectRevertLevel=GetUnitAbilityLevel(ori,COMMAND_PROTECT_ID)
set this.shockwaveRevertLevel=GetUnitAbilityLevel(ori,COMMAND_SHOCKWAVE_ID)
if GetUnitAbilityLevel(this.ori,COMMAND_ATTACK_DIS_ID)>0 then
call SetUnitAbilityLevel(this.ori,COMMAND_ATTACK_ID,5)
call IncUnitAbilityLevel(this.ori,COMMAND_ATTACK_ID)
call UnitAddAbility(this.ori,COMMAND_ATTACK_DIS_ID)
endif
if GetUnitAbilityLevel(this.ori,COMMAND_DISONNANCE_ID)>0 then
call SetUnitAbilityLevel(this.ori,COMMAND_DISONNANCE_ID,5)
call IncUnitAbilityLevel(this.ori,COMMAND_DISONNANCE_ID)
call UnitAddAbility(this.ori,COMMAND_DISSONANCE_DIS_ID)
endif
if GetUnitAbilityLevel(this.ori,COMMAND_PROTECT_ID)>0 then
call SetUnitAbilityLevel(this.ori,COMMAND_PROTECT_ID,5)
call IncUnitAbilityLevel(this.ori,COMMAND_PROTECT_ID)
call UnitAddAbility(this.ori,COMMAND_PROTECT_DIS_ID)
endif
if GetUnitAbilityLevel(this.ori,COMMAND_SHOCKWAVE_ID)>0 then
call SetUnitAbilityLevel(this.ori,COMMAND_SHOCKWAVE_ID,3)
call IncUnitAbilityLevel(this.ori,COMMAND_SHOCKWAVE_ID)
call UnitAddAbility(this.ori,COMMAND_SHOCKWAVE_DIS_ID)
endif
endmethod
// Method used to re-activate Orianna's active abilities
private method actifyAbilities takes nothing returns nothing
call UnitRemoveAbility(this.ori,COMMAND_ATTACK_DIS_ID)
call SetUnitAbilityLevel(this.ori,COMMAND_ATTACK_ID,this.attackRevertLevel)
call UnitRemoveAbility(this.ori,COMMAND_DISSONANCE_DIS_ID)
call SetUnitAbilityLevel(this.ori,COMMAND_DISONNANCE_ID,this.dissonanceRevertLevel)
call UnitRemoveAbility(this.ori,COMMAND_PROTECT_DIS_ID)
call SetUnitAbilityLevel(this.ori,COMMAND_PROTECT_ID,this.protectRevertLevel)
call UnitRemoveAbility(this.ori,COMMAND_SHOCKWAVE_DIS_ID)
call SetUnitAbilityLevel(this.ori,COMMAND_SHOCKWAVE_ID,this.shockwaveRevertLevel)
endmethod
// Public method called when a client wants to Command: Attack a location
public static method attack takes unit ori, real x, real y returns nothing
local thistype tempDat=fromOri[ori]
local real dist
local real bx=GetUnitX(tempDat.ball)
local real by=GetUnitY(tempDat.ball)
local real theta=Atan2(y-by,x-bx)
local sound snd=CreateSound(BALL_MOVE_START_SOUND,false,true,true,SOUND_MAX_FADERATE,SOUND_MAX_FADERATE,"")
call SetSoundVolume(snd,SOUND_MAX_VOLUME)
call SetSoundPosition(snd,bx,by,BALL_GROUND_HEIGHT)
call SetSoundPitch(snd,BALL_MOVE_START_SOUND_PITCH)
call StartSound(snd)
call KillSoundWhenDone(snd)
call GroupClear(tempDat.alreadyHit)
if tempDat.state==BALL_STATE_GROUND then
call SetUnitX(tempDat.standIndicator,MAP_TOP_LEFT_X)
call SetUnitY(tempDat.standIndicator,MAP_TOP_LEFT_Y)
call SetUnitScale(tempDat.standIndicator,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE)
endif
set tempDat.state=BALL_STATE_ATTACK
set tempDat.targetX=x
set tempDat.targetY=y
set dist=SquareRoot((x-bx)*(x-bx)+(y-by)*(y-by))
set tempDat.steps=R2I(dist/(BALL_VELOCITY*CLOCK_PERIOD))
set tempDat.delX=BALL_VELOCITY*CLOCK_PERIOD*Cos(theta)
set tempDat.delY=BALL_VELOCITY*CLOCK_PERIOD*Sin(theta)
set tempDat.delZ=(BALL_GROUND_HEIGHT-GetUnitFlyHeight(tempDat.ball))/tempDat.steps
set tempDat.damage=COMMAND_ATTACK_FLAT_DAMAGE + COMMAND_ATTACK_DAMAGE_PER_LEVEL*tempDat.attackRevertLevel + COMMAND_ATTACK_INTELLIGENCE_MULTIPLIER*GetHeroInt(ori,true)
set tempDat.minDamage=tempDat.damage*COMMAND_ATTACK_MINIMUM_DAMAGE_MULTIPLIER
if tempDat.protectBonusUnit!=null then
call UnitRemoveAbility(tempDat.protectBonusUnit,PROTECT_PASSIVE_ID)
set tempDat.protectBonusUnit=null
endif
call tempDat.passifyAbilities()
set snd=null
endmethod
// Public method used when an Orianna should cast Command: Disonnance
public static method disonnance takes unit ori returns nothing
local thistype tempDat=fromOri[ori]
local real cX=GetUnitX(tempDat.ball)
local real cY=GetUnitY(tempDat.ball)
local real damage=DISONNANCE_FLAT_DAMAGE+DISONNANCE_DAMAGE_PER_LEVEL*GetUnitAbilityLevel(tempDat.ori,COMMAND_DISONNANCE_ID)+GetHeroInt(tempDat.ori,true)*DISONNANCE_INTELLIGENCE_MULTIPLIER
local unit FoG
set tempDat.disonnanceTimeLeft=DISONNANCE_ACTIVE_DURATION
call SetUnitX(tempDat.disonnanceIndicator,cX)
call SetUnitY(tempDat.disonnanceIndicator,cY)
call SetUnitScale(tempDat.disonnanceIndicator,DISONNANCE_INDICATOR_SCALE,DISONNANCE_INDICATOR_SCALE,DISONNANCE_INDICATOR_SCALE)
call DestroyEffect(AddSpecialEffect(DISONNANCE_EFFECT,cX,cY))
call GroupEnumUnitsInRange(thistype.grp,cX,cY,DISONNANCE_RADIUS,null)
loop
set FoG=FirstOfGroup(thistype.grp)
exitwhen FoG==null
if IsUnitEnemy(tempDat.ori,GetOwningPlayer(FoG)) and UnitAlive(FoG) then
call DamageType.dealCodeDamage(tempDat.ori,FoG,damage)
call DestroyEffect(AddSpecialEffectTarget(DISONNANCE_HIT_EFFECT,FoG,DISONNANCE_EFFECT_TARGET))
endif
call GroupRemoveUnit(thistype.grp,FoG)
endloop
endmethod
// Public method used when an orianna should Command: Protect an allied unit
public static method protect takes unit ori, unit target returns nothing
local thistype tempDat=fromOri[ori]
local real int=GetHeroInt(ori,true)
set tempDat.pTarget=target
call SetUnitTimeScale(tempDat.ball,BALL_TIME_SCALE)
call SetUnitFlyHeight(tempDat.ball,BALL_OVERHEAD_HEIGHT,0.)
call SetUnitX(tempDat.standIndicator,MAP_TOP_LEFT_X)
call SetUnitY(tempDat.standIndicator,MAP_TOP_LEFT_Y)
call SetUnitScale(tempDat.standIndicator,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE)
call GroupClear(tempDat.alreadyHit)
set tempDat.state=BALL_STATE_TARGET
set tempDat.shieldAmount=SHIELD_FLAT_AMOUNT+SHIELD_AMOUNT_PER_LEVEL*tempDat.protectRevertLevel+SHIELD_BONUS_MULTIPLIER*int
set tempDat.damage=SHIELD_FLAT_DAMAGE+SHIELD_DAMAGE_PER_LEVEL*tempDat.protectRevertLevel+SHIELD_BONUS_DAMAGE_MULTIPLIER*int
if tempDat.protectBonusUnit!=null then
call UnitRemoveAbility(tempDat.protectBonusUnit,PROTECT_PASSIVE_ID)
set tempDat.protectBonusUnit=null
endif
call tempDat.passifyAbilities()
endmethod
// Public method used when an Orianna should Command: Shockwave
public static method shockwave takes unit ori returns nothing
local thistype tempDat=fromOri[ori]
local real bX=GetUnitX(tempDat.ball)
local real bY=GetUnitY(tempDat.ball)
call SetUnitTimeScale(tempDat.ball,BALL_TIME_SCALE)
call SetUnitFlyHeight(tempDat.ball,BALL_GROUND_HEIGHT,0.)
set tempDat.steps=0
set tempDat.state=BALL_STATE_SHOCKWAVE
call SetUnitX(tempDat.shockwaveIndicator,bX)
call SetUnitY(tempDat.shockwaveIndicator,bY)
call SetUnitScale(tempDat.shockwaveIndicator,SHOCK_INDIC_SCALE,SHOCK_INDIC_SCALE,SHOCK_INDIC_SCALE)
call SetUnitFlyHeight(tempDat.shockwaveIndicator,SHOCK_INDIC_HEIGHT,0.)
call SetUnitX(tempDat.shockwaveOrb1,bX+SHOCK_RADIUS*Cos(0.*SHOCK_ORB_PHASE_DIFFERENCE))
call SetUnitY(tempDat.shockwaveOrb1,bY+SHOCK_RADIUS*Sin(0.*SHOCK_ORB_PHASE_DIFFERENCE))
call SetUnitScale(tempDat.shockwaveOrb1,SHOCK_ORB_SCALE,SHOCK_ORB_SCALE,SHOCK_ORB_SCALE)
call SetUnitX(tempDat.shockwaveOrb2,bX+SHOCK_RADIUS*Cos(1.*SHOCK_ORB_PHASE_DIFFERENCE))
call SetUnitY(tempDat.shockwaveOrb2,bY+SHOCK_RADIUS*Sin(1.*SHOCK_ORB_PHASE_DIFFERENCE))
call SetUnitScale(tempDat.shockwaveOrb2,SHOCK_ORB_SCALE,SHOCK_ORB_SCALE,SHOCK_ORB_SCALE)
call SetUnitX(tempDat.shockwaveOrb3,bX+SHOCK_RADIUS*Cos(2.*SHOCK_ORB_PHASE_DIFFERENCE))
call SetUnitY(tempDat.shockwaveOrb3,bY+SHOCK_RADIUS*Sin(2.*SHOCK_ORB_PHASE_DIFFERENCE))
call SetUnitScale(tempDat.shockwaveOrb3,SHOCK_ORB_SCALE,SHOCK_ORB_SCALE,SHOCK_ORB_SCALE)
if tempDat.protectBonusUnit!=null then
call UnitRemoveAbility(tempDat.protectBonusUnit,PROTECT_PASSIVE_ID)
set tempDat.protectBonusUnit=null
endif
endmethod
// Method used to get and increment the hitcount for an Orianna;
// used by her innate
public static method hitCount takes unit ori, unit targ, integer meth returns integer
local thistype tempDat
if meth==METHOD_INCREMENT_AND_COUNT then
set tempDat=thistype.fromOri[ori]
if tempDat.target==targ then
set tempDat.attackCount=tempDat.attackCount+1
else
set tempDat.target=targ
set tempDat.attackCount=1
endif
set tempDat.counterTimeout=CLOCKWORK_WINDUP_TIMEOUT
return tempDat.attackCount
endif
return 0
endmethod
// Method used for preloading sounds after a timer
private static method preloadSoundAfter takes nothing returns nothing
local timer time=GetExpiredTimer()
local soundShim shim=thistype.preloadTable[time]
call StartSound(shim.s)
call KillSoundWhenDone(shim.s)
call shim.destroy()
set time=null
endmethod
// Method used to preload sounds
private static method preloadSound takes string s returns nothing
local timer time=CreateTimer()
local sound snd=CreateSound(s,false,false,true,SOUND_MAX_FADERATE,SOUND_MAX_FADERATE,"")
local soundShim shim=soundShim.create()
set shim.s=snd
set thistype.preloadTable[time]=shim
call SetSoundVolume(snd,1)
call TimerStart(time,0.,false,function thistype.preloadSoundAfter)
set time=null
set snd=null
endmethod
// Periodic method that handles all the dynamic movement and timings
// of Orianna's basic effects... take a deep breath.
private static method periodic takes nothing returns nothing
local integer index=0
local thistype tempDat
local real ballX
local real ballY
local real dx
local real dy
local real pX
local real pY
local real pAng
local real sid
local real phase
local real uX
local real uY
local real dist2
local real theta
local sound snd
local unit FoG
loop
exitwhen index>dbIndex
set tempDat=DB[index]
set ballX=GetUnitX(tempDat.ball)
set ballY=GetUnitY(tempDat.ball)
set dx=ballX-GetUnitX(tempDat.ori)
set dy=ballY-GetUnitY(tempDat.ori)
set dist2=dx*dx+dy*dy
// Some logic for Clockwork Windup
if tempDat.counterTimeout>0. then
set tempDat.counterTimeout=tempDat.counterTimeout-CLOCK_PERIOD
if tempDat.counterTimeout<=0. then
set tempDat.target=null
endif
endif
// Some logic for disonnance's effect
if tempDat.disonnanceTimeLeft>0. then
set tempDat.disonnanceTimeLeft=tempDat.disonnanceTimeLeft-CLOCK_PERIOD
// 36 is between an arbitrary value and a constant. It's just a
// tenth of a circle.
call SetUnitFacingTimed(tempDat.disonnanceIndicator,GetUnitFacing(tempDat.disonnanceIndicator)-36.,2.)
if tempDat.disonnanceTimeLeft<DISONNANCE_INDICATOR_FADE_PERIOD then
call SetUnitVertexColor(tempDat.disonnanceIndicator,DISONNANCE_INDICATOR_RED,DISONNANCE_INDICATOR_GREEN,DISONNANCE_INDICATOR_BLUE,R2I(DISONNANCE_INDICATOR_OPACITY*tempDat.disonnanceTimeLeft/DISONNANCE_INDICATOR_FADE_PERIOD))
endif
call GroupEnumUnitsInRange(thistype.grp,GetUnitX(tempDat.disonnanceIndicator),GetUnitY(tempDat.disonnanceIndicator),thistype.DISONNANCE_RADIUS,null)
loop
set FoG=FirstOfGroup(grp)
exitwhen FoG==null
if IsUnitEnemy(FoG,GetOwningPlayer(tempDat.ori)) then
call SlowHandler.setUnit(FoG,GetUnitAbilityLevel(tempDat.ori,thistype.COMMAND_DISONNANCE_ID)+3)
else
call HasteHandler.setUnit(FoG,GetUnitAbilityLevel(tempDat.ori,thistype.COMMAND_DISONNANCE_ID)+3)
endif
call GroupRemoveUnit(grp,FoG)
endloop
if tempDat.disonnanceTimeLeft<=0. then
set tempDat.disonnanceTimeLeft=0.
call SetUnitVertexColor(tempDat.disonnanceIndicator,DISONNANCE_INDICATOR_RED,DISONNANCE_INDICATOR_GREEN,DISONNANCE_INDICATOR_BLUE,DISONNANCE_INDICATOR_OPACITY)
call SetUnitX(tempDat.disonnanceIndicator,MAP_TOP_LEFT_X)
call SetUnitY(tempDat.disonnanceIndicator,MAP_TOP_LEFT_Y)
call SetUnitScale(tempDat.disonnanceIndicator,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE)
endif
endif
// Some logic for when a ball is attached to a unit
if tempDat.state==BALL_STATE_ONUNIT then
call SetUnitX(tempDat.ball,GetUnitX(tempDat.pTarget))
call SetUnitY(tempDat.ball,GetUnitY(tempDat.pTarget))
if dist2>BALL_LEASH_RANGE_ONUNIT*BALL_LEASH_RANGE_ONUNIT then
set tempDat.state=BALL_STATE_HOME
call UnitRemoveAbility(tempDat.protectBonusUnit,PROTECT_PASSIVE_ID)
set tempDat.protectBonusUnit=tempDat.ori
call UnitAddAbility(tempDat.ori,PROTECT_PASSIVE_ID)
endif
endif
// Some logic while the the ball has been issued Command:
// Attack
if tempDat.state==BALL_STATE_ATTACK then
set uX=GetUnitX(tempDat.ball)+tempDat.delX
set uY=GetUnitY(tempDat.ball)+tempDat.delY
call SetUnitX(tempDat.ball,uX)
call SetUnitY(tempDat.ball,uY)
call SetUnitFlyHeight(tempDat.ball,GetUnitFlyHeight(tempDat.ball)+tempDat.delZ,0.)
set tempDat.steps=tempDat.steps-1
call GroupEnumUnitsInRange(grp,uX,uY,BALL_ATTACK_DAMAGE_RADIUS,null)
loop
set FoG=FirstOfGroup(grp)
exitwhen FoG==null
if IsUnitEnemy(tempDat.ori,GetOwningPlayer(FoG)) and (not IsUnitInGroup(FoG,tempDat.alreadyHit)) then
call DamageType.dealCodeDamage(tempDat.ori,FoG,tempDat.damage)
call DestroyEffect(AddSpecialEffectTarget(ABILITY_HIT_EFFECT,FoG,"chest"))
set tempDat.damage=tempDat.damage*(1.-COMMAND_ATTACK_DAMAGE_REDUCTION)
call GroupAddUnit(tempDat.alreadyHit,FoG)
if tempDat.damage<tempDat.minDamage then
set tempDat.damage=tempDat.minDamage
endif
endif
call GroupRemoveUnit(grp,FoG)
endloop
if tempDat.steps<1 then
call SetUnitX(tempDat.ball,tempDat.targetX)
call SetUnitY(tempDat.ball,tempDat.targetY)
call SetUnitFlyHeight(tempDat.ball,BALL_GROUND_HEIGHT,0.)
call SetUnitTimeScale(tempDat.ball,BALL_TIME_SCALE_GROUND)
call SetUnitX(tempDat.standIndicator,tempDat.targetX)
call SetUnitY(tempDat.standIndicator,tempDat.targetY)
call SetUnitScale(tempDat.standIndicator,STAND_INDICATOR_SCALE,STAND_INDICATOR_SCALE,STAND_INDICATOR_SCALE)
set snd=CreateSound(BALL_MOVE_END_SOUND,false,true,true,12700,12700,"")
call tempDat.actifyAbilities()
call SetSoundVolume(snd,127)
call SetSoundPitch(snd,BALL_MOVE_END_SOUND_PITCH)
call SetSoundPosition(snd,tempDat.targetX,tempDat.targetY,BALL_GROUND_HEIGHT)
call StartSound(snd)
call KillSoundWhenDone(snd)
set tempDat.state=BALL_STATE_GROUND
endif
// Some logic while the ball has been issued Command:
// Shockwave
elseif tempDat.state==BALL_STATE_SHOCKWAVE then
set tempDat.steps=tempDat.steps+1
set sid=SHOCK_RADIUS*(-1.*CLOCK_PERIOD*tempDat.steps/SHOCK_WINDUP_DURATION+1)
set phase=tempDat.steps*CLOCK_PERIOD*SHOCK_WINDUP_ORB_SPEED
if GetUnitAbilityLevel(tempDat.ori,COMMAND_SHOCKWAVE_DIS_ID)==0 then
call tempDat.passifyAbilities()
endif
call SetUnitX(tempDat.shockwaveOrb1,ballX+sid*Cos(2*bj_PI+phase))
call SetUnitY(tempDat.shockwaveOrb1,ballY+sid*Sin(2*bj_PI+phase))
call SetUnitX(tempDat.shockwaveOrb2,ballX+sid*Cos(2.*bj_PI/3.+phase))
call SetUnitY(tempDat.shockwaveOrb2,ballY+sid*Sin(2.*bj_PI/3.+phase))
call SetUnitX(tempDat.shockwaveOrb3,ballX+sid*Cos(4.*bj_PI/3.+phase))
call SetUnitY(tempDat.shockwaveOrb3,ballY+sid*Sin(4.*bj_PI/3.+phase))
if tempDat.steps>SHOCK_WINDUP_DURATION/CLOCK_PERIOD then
set tempDat.state=BALL_STATE_GROUND
call GroupEnumUnitsInRange(grp,GetUnitX(tempDat.shockwaveIndicator),GetUnitY(tempDat.shockwaveIndicator),250.,null)
call tempDat.actifyAbilities()
loop
set FoG=FirstOfGroup(grp)
exitwhen FoG==null
set pY=75.+75.*GetUnitAbilityLevel(tempDat.ori,COMMAND_SHOCKWAVE_ID)+0.7*GetHeroInt(tempDat.ori,true)
if IsUnitEnemy(tempDat.ball,GetOwningPlayer(FoG)) and UnitAlive(FoG) then
set pX=Atan2(GetUnitY(tempDat.ball)-GetUnitY(FoG),GetUnitX(tempDat.ball)-GetUnitX(FoG))
call DamageType.dealCodeDamage(tempDat.ori,FoG,pY)
call ThrowHandler.add(FoG,THROW_VELOCITY*Cos(pX),THROW_VELOCITY*Sin(pX),THROW_VELOCITY*THROW_VERT_MULTIPLIER)
endif
call GroupRemoveUnit(grp,FoG)
endloop
call SetUnitX(tempDat.shockwaveOrb1,MAP_TOP_LEFT_X)
call SetUnitY(tempDat.shockwaveOrb1,MAP_TOP_LEFT_Y)
call SetUnitX(tempDat.shockwaveOrb2,MAP_TOP_LEFT_X)
call SetUnitY(tempDat.shockwaveOrb2,MAP_TOP_LEFT_Y)
call SetUnitX(tempDat.shockwaveOrb3,MAP_TOP_LEFT_X)
call SetUnitY(tempDat.shockwaveOrb3,MAP_TOP_LEFT_Y)
call SetUnitX(tempDat.shockwaveIndicator,MAP_TOP_LEFT_X)
call SetUnitY(tempDat.shockwaveIndicator,MAP_TOP_LEFT_Y)
endif
// Some logic while the ball has been issued Command:
// Protect
elseif tempDat.state==BALL_STATE_TARGET then
set pX=GetUnitX(tempDat.pTarget)-ballX
set pY=GetUnitY(tempDat.pTarget)-ballY
set pAng=Atan2(pY,pX)
set uX=ballX+thistype.BALL_VELOCITY*thistype.CLOCK_PERIOD*Cos(pAng)
set uY=ballY+thistype.BALL_VELOCITY*thistype.CLOCK_PERIOD*Sin(pAng)
call SetUnitX(tempDat.ball,uX)
call SetUnitY(tempDat.ball,uY)
call GroupEnumUnitsInRange(grp,uX,uY,BALL_ATTACK_DAMAGE_RADIUS,null)
loop
set FoG=FirstOfGroup(grp)
exitwhen FoG==null
if IsUnitEnemy(tempDat.ori,GetOwningPlayer(FoG)) and (not IsUnitInGroup(FoG,tempDat.alreadyHit)) then
call DamageType.dealCodeDamage(tempDat.ori,FoG,tempDat.damage)
call DestroyEffect(AddSpecialEffectTarget(ABILITY_HIT_EFFECT,FoG,"chest"))
call GroupAddUnit(tempDat.alreadyHit,FoG)
endif
call GroupRemoveUnit(grp,FoG)
endloop
if (pX*pX+pY*pY)<PROTECT_ATTACH_RANGE*PROTECT_ATTACH_RANGE then
set tempDat.state=BALL_STATE_ONUNIT
call UnitRemoveAbility(tempDat.protectBonusUnit,PROTECT_PASSIVE_ID)
set tempDat.protectBonusUnit=tempDat.pTarget
call UnitAddAbility(tempDat.pTarget,PROTECT_PASSIVE_ID)
call Shield.add(tempDat.pTarget,tempDat.shieldAmount,SHIELD_DURATION,SHIELD_FX,"origin")
call tempDat.actifyAbilities()
endif
// Other stuff for when Orianna is alive
elseif UnitAlive(tempDat.ori) then
if tempDat.state==BALL_STATE_DEAD then
set tempDat.state=BALL_STATE_HOME
call UnitRemoveAbility(tempDat.protectBonusUnit,PROTECT_PASSIVE_ID)
set tempDat.protectBonusUnit=tempDat.ori
call UnitAddAbility(tempDat.ori,PROTECT_PASSIVE_ID)
call SetUnitFlyHeight(tempDat.ball,BALL_OVERHEAD_HEIGHT,0.)
call SetUnitVertexColor(tempDat.ball,255,255,255,255)
call SetUnitOwner(tempDat.ball,GetOwningPlayer(tempDat.ori),false)
call SetUnitPosition(tempDat.ball,GetUnitX(tempDat.ori),GetUnitY(tempDat.ori))
elseif tempDat.state==BALL_STATE_GROUND then
if dist2>BALL_LEASH_RANGE_GROUND*BALL_LEASH_RANGE_GROUND or dist2<BALL_PICKUP_RANGE*BALL_PICKUP_RANGE then
call SetUnitTimeScale(tempDat.ball,BALL_TIME_SCALE)
call SetUnitFlyHeight(tempDat.ball,BALL_OVERHEAD_HEIGHT,0.)
call SetUnitX(tempDat.standIndicator,MAP_TOP_LEFT_X)
call SetUnitY(tempDat.standIndicator,MAP_TOP_LEFT_Y)
call SetUnitScale(tempDat.standIndicator,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE)
set tempDat.state=BALL_STATE_HOME
call UnitRemoveAbility(tempDat.protectBonusUnit,PROTECT_PASSIVE_ID)
set tempDat.protectBonusUnit=tempDat.ori
call UnitAddAbility(tempDat.ori,PROTECT_PASSIVE_ID)
endif
elseif tempDat.state==BALL_STATE_HOME then
call SetUnitX(tempDat.ball,GetUnitX(tempDat.ori))
call SetUnitY(tempDat.ball,GetUnitY(tempDat.ori))
endif
// ... and when she's dead
elseif not UnitAlive(tempDat.ori) then
call SetUnitX(tempDat.ball,MAP_TOP_LEFT_X)
call SetUnitY(tempDat.ball,MAP_TOP_LEFT_Y)
call SetUnitFlyHeight(tempDat.ball,DUMMY_HIDDEN_HEIGHT,0.)
call SetUnitVertexColor(tempDat.ball,255,255,255,0)
call SetUnitOwner(tempDat.ball,Player(PLAYER_NEUTRAL_PASSIVE),false)
if tempDat.state==BALL_STATE_GROUND then
call SetUnitX(tempDat.standIndicator,MAP_TOP_LEFT_X)
call SetUnitY(tempDat.standIndicator,MAP_TOP_LEFT_Y)
call SetUnitScale(tempDat.standIndicator,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE)
endif
set tempDat.state=BALL_STATE_DEAD
call UnitRemoveAbility(tempDat.protectBonusUnit,PROTECT_PASSIVE_ID)
set tempDat.protectBonusUnit=null
endif
// When to hide the indicator
if tempDat.state==BALL_STATE_HOME or tempDat.state==BALL_STATE_DEAD or dist2<ARROW_MIN_RANGE*ARROW_MIN_RANGE then
call SetUnitX(tempDat.arrow,MAP_TOP_LEFT_X)
call SetUnitY(tempDat.arrow,MAP_TOP_LEFT_Y)
call SetUnitFlyHeight(tempDat.arrow,DUMMY_HIDDEN_HEIGHT,0.)
call SetUnitScale(tempDat.arrow,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE)
// When to move the indicator
else
set theta=Atan2(dy,dx)
call SetUnitX(tempDat.arrow,GetUnitX(tempDat.ori)+ARROW_HOVER_DISTANCE*Cos(theta))
call SetUnitY(tempDat.arrow,GetUnitY(tempDat.ori)+ARROW_HOVER_DISTANCE*Sin(theta))
if GetLocalPlayer()==GetOwningPlayer(tempDat.ori) then
call SetUnitFlyHeight(tempDat.arrow,ARROW_FLY_HEIGHT,0.)
call SetUnitScale(tempDat.arrow,ARROW_SCALE,ARROW_SCALE,ARROW_SCALE)
endif
if dist2<ARROW_GREEN_RANGE*ARROW_GREEN_RANGE then
call SetUnitColor(tempDat.arrow,PLAYER_COLOR_GREEN)
elseif dist2<ARROW_YELLOW_RANGE*ARROW_YELLOW_RANGE then
call SetUnitColor(tempDat.arrow,PLAYER_COLOR_YELLOW)
else
call SetUnitColor(tempDat.arrow,PLAYER_COLOR_RED)
endif
endif
//Last check if Orianna exists so we can properly destroy her otherwise
if GetUnitTypeId(tempDat.ori)==0 then
call DestroyGroup(tempDat.alreadyHit)
call RemoveUnit(tempDat.ball)
call RemoveUnit(tempDat.arrow)
call RemoveUnit(tempDat.shockwaveIndicator)
call RemoveUnit(tempDat.shockwaveOrb1)
call RemoveUnit(tempDat.shockwaveOrb2)
call RemoveUnit(tempDat.shockwaveOrb3)
call RemoveUnit(tempDat.standIndicator)
call RemoveUnit(tempDat.disonnanceIndicator)
if tempDat.protectBonusUnit!=null then
call UnitRemoveAbility(tempDat.protectBonusUnit,PROTECT_PASSIVE_ID)
set tempDat.protectBonusUnit=null
endif
call tempDat.destroy()
set DB[index]=DB[dbIndex]
set dbIndex=dbIndex-1
set index=index-1
endif
set index=index+1
endloop
set snd=null
endmethod
// Initialization function for an Orianna instance
private static method initialize takes unit u returns nothing
local player owner=GetOwningPlayer(u)
local thistype tempDat=thistype.create()
set tempDat.ori=u
set tempDat.ball=CreateUnit(owner,BALL_ID,0.,0.,270.)
set tempDat.arrow=CreateUnit(owner,ARROW_ID,MAP_TOP_LEFT_X,MAP_TOP_LEFT_Y,270.)
set tempDat.standIndicator=CreateUnit(owner,STAND_INDICATOR_ID,MAP_TOP_LEFT_X,MAP_TOP_LEFT_Y,270.)
set tempDat.disonnanceIndicator=CreateUnit(owner,DISONNANCE_INDICATOR_ID,MAP_TOP_LEFT_X,MAP_TOP_LEFT_Y,270.)
set tempDat.shockwaveIndicator=CreateUnit(owner,SHOCKWAVE_INDICATOR_ID,MAP_TOP_LEFT_X,MAP_TOP_LEFT_Y,270.)
set tempDat.shockwaveOrb1=CreateUnit(owner,SHOCKWAVE_ORB_ID,MAP_TOP_LEFT_X,MAP_TOP_LEFT_Y,270.)
set tempDat.shockwaveOrb2=CreateUnit(owner,SHOCKWAVE_ORB_ID,MAP_TOP_LEFT_X,MAP_TOP_LEFT_Y,270.)
set tempDat.shockwaveOrb3=CreateUnit(owner,SHOCKWAVE_ORB_ID,MAP_TOP_LEFT_X,MAP_TOP_LEFT_Y,270.)
call SetUnitScale(tempDat.shockwaveIndicator,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE)
call SetUnitScale(tempDat.shockwaveOrb1,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE)
call SetUnitScale(tempDat.shockwaveOrb2,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE)
call SetUnitScale(tempDat.shockwaveOrb3,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE)
call SetUnitScale(tempDat.disonnanceIndicator,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE)
call SetUnitVertexColor(tempDat.disonnanceIndicator,DISONNANCE_INDICATOR_RED,DISONNANCE_INDICATOR_GREEN,DISONNANCE_INDICATOR_BLUE,DISONNANCE_INDICATOR_OPACITY)
call SetUnitScale(tempDat.standIndicator,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE)
call SetUnitColor(tempDat.arrow,PLAYER_COLOR_GREEN)
call SetUnitScale(tempDat.arrow,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE,DUMMY_HIDDEN_SCALE)
set thistype.fromOri[u]=tempDat
set tempDat.target=null
set tempDat.alreadyHit=CreateGroup()
call UnitAddAbility(tempDat.ball,'Arav')
call UnitRemoveAbility(tempDat.ball,'Arav')
call UnitAddAbility(tempDat.disonnanceIndicator,'Arav')
call UnitRemoveAbility(tempDat.disonnanceIndicator,'Arav')
call UnitAddAbility(tempDat.shockwaveIndicator,'Arav')
call UnitRemoveAbility(tempDat.shockwaveIndicator,'Arav')
call SetUnitFlyHeight(tempDat.disonnanceIndicator,DISONNANCE_INDICATOR_HEIGHT,0.)
call SetUnitX(tempDat.ball,GetUnitX(u))
call SetUnitY(tempDat.ball,GetUnitY(u))
call SetUnitTimeScale(tempDat.ball,BALL_TIME_SCALE)
call SetUnitFlyHeight(tempDat.ball,BALL_OVERHEAD_HEIGHT,0.)
call SetUnitVertexColor(tempDat.ball,255,255,255,BALL_OPACITY)
set dbIndex=dbIndex+1
set DB[dbIndex]=tempDat
if dbIndex==0 then
call TimerStart(clock,CLOCK_PERIOD,true,function thistype.periodic)
endif
set tempDat.state=BALL_STATE_HOME
endmethod
// Auxillary function used for getting new Orianna
// instances
private static method c takes nothing returns boolean
local unit tU=GetTriggerUnit()
if GetUnitTypeId(tU)==ID then
call thistype.initialize(tU)
endif
set tU=null
return false
endmethod
// Initialization method called by the InitShim
private static method i takes nothing returns nothing
local unit FoG
local region reg=CreateRegion()
local trigger t=CreateTrigger()
set thistype.fromOri=HandleTable.create()
set thistype.preloadTable=HandleTable.create()
call thistype.preloadSound(BALL_MOVE_START_SOUND)
call thistype.preloadSound(BALL_MOVE_END_SOUND)
call RegionAddRect(reg,bj_mapInitialPlayableArea)
call TriggerRegisterEnterRegion(t,reg,null)
call TriggerAddCondition(t,Condition(function thistype.c))
set reg=null
set t=null
call GroupEnumUnitsInRect(grp,bj_mapInitialPlayableArea,null)
loop
set FoG=FirstOfGroup(grp)
exitwhen FoG==null
if GetUnitTypeId(FoG)==thistype.ID then
call thistype.initialize(FoG)
endif
call GroupRemoveUnit(grp,FoG)
endloop
endmethod
implement InitShim
endstruct
endlibrary