- Joined
- Jun 17, 2007
- Messages
- 3,828
Never heard of it. I'll check it out.
Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature may not be available in some browsers.

We had thought about making him a ranged champion where he just threw balls of paint, but the idea of Mr Gobo smacking people with a giant paint brush sounded more intriguing.

Thats FANTASTIQUE WORK!Trying to find spell names and correct the theme with my team, this is going to be the result if they're ok;
View attachment 287891
View attachment 287889
View attachment 287890
How about a Hero Glow to differ him from other units?The Hero model is done.
![]()
Ok.it isn't shown in that gif. He has a hero glow.
The scourge may be lacking, but it still has the passion for destruction.
Similarly, the team may lack a modeler, but we are one in creating the model.
![]()
![]()
SPaint Cast

Events


Unit - A unit Starts the effect of an ability

Conditions


(Ability being cast) Equal to SPaint_ABILITY

Actions


-------- SPaint Cast --------


-------- this trigger will switch the "color mode" for the unit --------


-------- if the unit reaches the end of the color palette, it will moved back to color #1 --------


-------- --------


-------- --------


Set SPaint_TempUnit = (Triggering unit)


Custom script: set udg_SPaint_UnitId = GetHandleId(udg_SPaint_TempUnit)


Set SPaint_CurrentColor = (Load PBomb_KEY_CURRENT_COLOR of SPaint_UnitId from PBomb_Hash)


Unit - Remove SPaint_SFX_ABILITY[SPaint_CurrentColor] from SPaint_TempUnit


Unit - Remove SPaint_SFX_BUFF[SPaint_CurrentColor] buff from SPaint_TempUnit


-------- --------


-------- checking which color the unit will now have --------


If (All Conditions are True) then do (Then Actions) else do (Else Actions)



If - Conditions




SPaint_CurrentColor Not equal to SPaint_TOTAL_COLORS



Then - Actions




-------- unit is not at the end of the color palette; move up one --------




Set SPaint_CurrentColor = (SPaint_CurrentColor + 1)



Else - Actions




-------- unit is at the end of the color palette; move back to the beginning --------




Set SPaint_CurrentColor = 1


-------- --------


Unit - Add SPaint_SFX_ABILITY[SPaint_CurrentColor] to SPaint_TempUnit


-------- --------


Hashtable - Save SPaint_CurrentColor as PBomb_KEY_CURRENT_COLOR of SPaint_UnitId in PBomb_Hash
Welp I guess it's my turn to post WIPs.
Our Hero basically has a sub-ability that lets them switch the color of their paint. The color of the paint will decide the mechanic of the primary ability. As you can see below, when they learn the ability, they start off a default color.
![]()
This shouldn't have been the case, but the Switch Paint mechanic took forever to make ._.
SPaint Cast
Events
Unit - A unit Starts the effect of an ability
Conditions
(Ability being cast) Equal to SPaint_ABILITY
Actions
-------- SPaint Cast --------
-------- this trigger will switch the "color mode" for the unit --------
-------- if the unit reaches the end of the color palette, it will moved back to color #1 --------
-------- --------
-------- --------
Set SPaint_TempUnit = (Triggering unit)
Custom script: set udg_SPaint_UnitId = GetHandleId(udg_SPaint_TempUnit)
Set SPaint_CurrentColor = (Load PBomb_KEY_CURRENT_COLOR of SPaint_UnitId from PBomb_Hash)
Unit - Remove SPaint_SFX_ABILITY[SPaint_CurrentColor] from SPaint_TempUnit
Unit - Remove SPaint_SFX_BUFF[SPaint_CurrentColor] buff from SPaint_TempUnit
-------- --------
-------- checking which color the unit will now have --------
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
SPaint_CurrentColor Not equal to SPaint_TOTAL_COLORS
Then - Actions
-------- unit is not at the end of the color palette; move up one --------
Set SPaint_CurrentColor = (SPaint_CurrentColor + 1)
Else - Actions
-------- unit is at the end of the color palette; move back to the beginning --------
Set SPaint_CurrentColor = 1
-------- --------
Unit - Add SPaint_SFX_ABILITY[SPaint_CurrentColor] to SPaint_TempUnit
-------- --------
Hashtable - Save SPaint_CurrentColor as PBomb_KEY_CURRENT_COLOR of SPaint_UnitId in PBomb_Hash
Thank you, but I only finished the switch xD I haven't started on the primary ability yet. Although, I do already have something in mind that should make it really easy.It would have been difficult to maintain the overall idea in creating such a behaviour (spell mechanic, not the switch) in vJASS alone, even more so in JASS, but you did it in GUI, which is another level altogether.
Out of curiousity, why wouldJust a suggestion, you could use less than as a comparison instead of not equal to just to be safe.
a < b be safer than a != b?Total=4
Current_color=5
If Current_color != Total
Current_color++
else
Current_color = 1
Ahh okay. CurrentColor acts as a private member basically. The user would have to physically go into the code to change the current color.I think that somewhere out there, there will be a user who would not understand enough of the spell to change the current colour to something higher than the total.
Literally no interaction happened from your side after any of these ...Would the image above suffice as a WIP on the model?
Now:
I would be showing the second WIP here
@MyPad it's cool you code, but... do you even have a team concept and a modeler? ;s
... nor any attempt or statement to solve the issue anyhow, or to talk with Murloc, or me.Your ignorance is welcome as always.
Literally no interaction happened from your side after any of these ...
... nor any attempt or statement to solve the issue anyhow, or to talk with Murloc, or me.
I don't believe it's valid WIP for model.
Defining only yourself as team is not allowed.
A team is defined by 3 members, respectively responsible for: Model, Icons, Code
OK, so that's a Rule that would generally preclude going *into* a situation like this, that way.
It is what I had done, freely choosing not to discuss with either of you about the modeller problem because I had thought that the problem would be easily resolved, (assuming that a modeller will be available).
PBomb Config

Events


Map initialization

Conditions

Actions


-------- --------


-------- CONFIG START --------


-------- --------


-------- --------


-------- imported object editor data --------


Set PBomb_ABILITY = Paint Bomb


-------- --------


-------- imported triggers --------


Set PBomb_TRIGGER_LOOP = PBomb Loop <gen>


Set PBomb_TRIGGER_PLAY_ERROR = PBomb Error Msg <gen>


-------- --------


-------- order string for PBomb_ABILITY --------


Set PBomb_ORDER_ID = channel


-------- --------


-------- minimum cast range PBomb_ABILITY can be casted at (NEVER make this value 0) --------


Set PBomb_MIN_CAST_RANGE = 200.00


-------- --------


-------- maximum height the missile can reach --------


Set PBomb_MaxHeight = 275.00


-------- time (in seconds) it will take for the missile to reach the target location --------


Set PBomb_TRAVEL_TIME = 0.75


Set PBomb_TRAVEL_TIME_PER_LEVEL = 0.00


-------- --------


-------- other --------


Set PBomb_PERIODIC_TIMER = 0.03


-------- error message that will display to the player if they cast PBomb_ABILITY inside PBomb_MIN_CAST_RANGE --------


Set PBomb_ERROR_MSG1 = Target is inside minimum cast range.


-------- error message that will display if the player tries to cast more puddles than they are allowed to --------


Set PBomb_ERROR_MSG2 = You cannot create any more puddles of that color.


-------- --------


-------- --------


-------- CONFIG END --------


-------- --------


Trigger - Add to PBomb_TRIGGER_LOOP the event (Time - Every PBomb_PERIODIC_TIMER seconds of game time)


Custom script: set udg_PBomb_ERROR_SOUND = CreateSoundFromLabel("InterfaceError", false, false, false, 10, 10)


Hashtable - Create a hashtable


Set PBomb_Hash = (Last created hashtable)


Set PBomb_KEY_CURRENT_COLOR = 0


-------- child keys for active puddle count in CPalete Config --------


Set PBomb_LocZ = (Center of (Playable map area))


-------- preload --------


Custom script: set udg_PBomb_TempUnit = GetRecycledDummyAnyAngle(0.00, 0.00, 0.00)


For each (Integer PBomb_TempInt) from 1 to SPaint_TOTAL_COLORS, do (Actions)



Loop - Actions




Special Effect - Create a special effect attached to the PBomb_SFX_MISSILE_AP[PBomb_TempInt] of PBomb_TempUnit using PBomb_SFX_MISSILE[PBomb_TempInt]




Special Effect - Destroy (Last created special effect)


Custom script: call RecycleDummy(udg_PBomb_TempUnit)
PBomb Order

Events


Unit - A unit Is issued an order targeting a point

Conditions


(Issued order) Equal to (Order(PBomb_ORDER_ID))

Actions


-------- PBomb Order --------


-------- this trigger will ensure that the caster does not cast the spell inside PBomb_MIN_CAST_RANGE --------


-------- and that they cant create another puddle if they reached the MAX_PUDDLES for that color --------


-------- if the caster casts the spell too close, the order will be interrupted --------


-------- --------


-------- --------


-------- there can be multiple spells in a map with the same order id. to ensure it's the one we are looking for, check for the level of the PBomb_ABILITY on the triggering unit --------


Set PBomb_TempUnit = (Triggering unit)


If (All Conditions are True) then do (Then Actions) else do (Else Actions)



If - Conditions




(Level of PBomb_ABILITY for PBomb_TempUnit) Greater than or equal to 1



Then - Actions




-------- PBomb_ABILITY was casted; check if the distance meets the minimum requirement --------




-------- --------




Set PBomb_TempLoc1 = (Position of PBomb_TempUnit)




Set PBomb_TempLoc2 = (Target point of issued order)




If (All Conditions are True) then do (Then Actions) else do (Else Actions)





If - Conditions






(Distance between PBomb_TempLoc1 and PBomb_TempLoc2) Less than PBomb_MIN_CAST_RANGE





Then - Actions






-------- PBomb_ABILITY was casted too close; interrupt cast order --------






-------- --------






Unit - Pause PBomb_TempUnit






Unit - Order PBomb_TempUnit to Stop






Unit - Unpause PBomb_TempUnit






-------- play error message --------






Set PBomb_TempPlayer = (Triggering player)






Set PBomb_ErrorMsg = PBomb_ERROR_MSG1






Trigger - Run PBomb_TRIGGER_PLAY_ERROR (ignoring conditions)





Else - Actions






-------- PBomb_ABILITY met the minimum cast range requirement; check to make sure that caster hasn't reached MAX_PUDDLES for active color --------






-------- --------






Custom script: set udg_PBomb_UnitId = GetHandleId(udg_PBomb_TempUnit)






Set SPaint_CurrentColor = (Load PBomb_KEY_CURRENT_COLOR of PBomb_UnitId from PBomb_Hash)






Set PBomb_TempInt = (PBomb_MAX_PUDDLES[SPaint_CurrentColor] + (PBomb_MAX_PUDDLES_PER_LEVEL[SPaint_CurrentColor] x (Level of PBomb_ABILITY for PBomb_TempUnit)))






If (All Conditions are True) then do (Then Actions) else do (Else Actions)







If - Conditions








(Load PBomb_KEY_ACTIVE_COUNT[SPaint_CurrentColor] of PBomb_UnitId from PBomb_Hash) Greater than or equal to PBomb_TempInt







Then - Actions








-------- caster is already at maximum puddle count; interrupt cast order --------








-------- --------








Unit - Pause PBomb_TempUnit








Unit - Order PBomb_TempUnit to Stop








Unit - Unpause PBomb_TempUnit








-------- play error message --------








Set PBomb_ErrorMsg = PBomb_ERROR_MSG2








Set PBomb_TempPlayer = (Triggering player)








Trigger - Run PBomb_TRIGGER_PLAY_ERROR (ignoring conditions)







Else - Actions








-------- caster has not reached the maximum puddle count for the color; do nothing --------




-------- --------




Custom script: call RemoveLocation(udg_PBomb_TempLoc1)




Custom script: call RemoveLocation(udg_PBomb_TempLoc2)



Else - Actions




-------- not PBomb_ABILITY; do nothing --------
PBomb Cast

Events


Unit - A unit Starts the effect of an ability

Conditions


(Ability being cast) Equal to PBomb_ABILITY

Actions


-------- PBomb Cast --------


-------- this trigger will create a new instance to move the missile to the targeted location --------


-------- --------


-------- members --------


-------- Caster[] = unit that casted the spell --------


-------- Owner[] = player that owns Caster[] --------


-------- AbilityLvl[] = current ability level of PBomb_ABILITY for Caster[] --------


-------- CurrentColor[] = current color selected for Caster[] --------


-------- MissileUnit[] = dummy unit with special effect --------


-------- Cos[] = cosine of the angle MissileUnit[] will move towards --------


-------- Sin[] = sine of the angle MissileUnit[] will move towards --------


-------- DistanceTraveled[] = total distance moved by MissileUnit[] --------


-------- MoveRate[] = how fast MissileUnit[] will move per iteration --------


-------- --------


-------- --------


Set PBomb_SpellCount = (PBomb_SpellCount + 1)


If (All Conditions are True) then do (Then Actions) else do (Else Actions)



If - Conditions




PBomb_SpellCount Equal to 1



Then - Actions




Trigger - Turn on PBomb_TRIGGER_LOOP



Else - Actions




-------- do nothing --------


-------- --------


If (All Conditions are True) then do (Then Actions) else do (Else Actions)



If - Conditions




PBomb_RecycledSize Equal to 0



Then - Actions




Set PBomb_MaxIndex = (PBomb_MaxIndex + 1)




Set PBomb_SpellId = PBomb_MaxIndex



Else - Actions




Set PBomb_RecycledSize = (PBomb_RecycledSize - 1)




Set PBomb_SpellId = PBomb_RecycledStack[PBomb_RecycledSize]


Set PBomb_NodeNext[PBomb_SpellId] = 0


Set PBomb_NodePrev[PBomb_SpellId] = PBomb_NodePrev[0]


Set PBomb_NodeNext[PBomb_NodePrev[0]] = PBomb_SpellId


Set PBomb_NodePrev[0] = PBomb_SpellId


-------- --------


Set PBomb_Caster[PBomb_SpellId] = (Triggering unit)


Set PBomb_Owner[PBomb_SpellId] = (Triggering player)


Set PBomb_AbilityLvl[PBomb_SpellId] = (Level of PBomb_ABILITY for PBomb_Caster[PBomb_SpellId])


Set PBomb_CurrentColor[PBomb_SpellId] = (Load PBomb_KEY_CURRENT_COLOR of (Key (Triggering unit)) from PBomb_Hash)


-------- --------


Set PBomb_TempLoc1 = (Position of PBomb_Caster[PBomb_SpellId])


Set PBomb_TempLoc2 = (Target point of ability being cast)


Set PBomb_TempReal1 = (Angle from PBomb_TempLoc1 to PBomb_TempLoc2)


Set PBomb_TempReal2 = (Current flying height of PBomb_Caster[PBomb_SpellId])


Custom script: set udg_PBomb_StartZ[udg_PBomb_SpellId] = GetLocationZ(udg_PBomb_TempLoc1) + udg_PBomb_TempReal2


Custom script: set udg_PBomb_EndZ[udg_PBomb_SpellId] = GetLocationZ(udg_PBomb_TempLoc2)


-------- --------


Custom script: set udg_PBomb_MissileUnit[udg_PBomb_SpellId] = GetRecycledDummy(GetLocationX(udg_PBomb_TempLoc1), GetLocationY(udg_PBomb_TempLoc1), udg_PBomb_TempReal2, udg_PBomb_TempReal1)


Special Effect - Create a special effect attached to the PBomb_SFX_MISSILE_AP[PBomb_CurrentColor[PBomb_SpellId]] of PBomb_MissileUnit[PBomb_SpellId] using PBomb_SFX_MISSILE[PBomb_CurrentColor[PBomb_SpellId]]


Set PBomb_MissileSfx[PBomb_SpellId] = (Last created special effect)


-------- --------


Set PBomb_Cos[PBomb_SpellId] = (Cos(PBomb_TempReal1))


Set PBomb_Sin[PBomb_SpellId] = (Sin(PBomb_TempReal1))


Set PBomb_DistanceTraveled[PBomb_SpellId] = 0.00


Set PBomb_TotalDistance[PBomb_SpellId] = (Distance between PBomb_TempLoc1 and PBomb_TempLoc2)


Set PBomb_MoveRate[PBomb_SpellId] = (PBomb_TotalDistance[PBomb_SpellId] / ((PBomb_TRAVEL_TIME + (PBomb_TRAVEL_TIME_PER_LEVEL x (Real(PBomb_AbilityLvl[PBomb_SpellId])))) / PBomb_PERIODIC_TIMER))


-------- --------


Custom script: call RemoveLocation(udg_PBomb_TempLoc1)


Custom script: call RemoveLocation(udg_PBomb_TempLoc2)
PBomb Loop

Events

Conditions

Actions


Custom script: local real newX


Custom script: local real newY


Custom script: local real currentD


Custom script: local real totalD


Custom script: local real originZ


Custom script: local real aimZ


Custom script: local real adjustZ


-------- --------


Set PBomb_SpellId = 0


For each (Integer PBomb_LoopInt) from 1 to PBomb_SpellCount, do (Actions)



Loop - Actions




Set PBomb_SpellId = PBomb_NodeNext[PBomb_SpellId]




-------- --------




-------- xy adjustment --------




Custom script: set newX = GetUnitX(udg_PBomb_MissileUnit[udg_PBomb_SpellId]) + udg_PBomb_MoveRate[udg_PBomb_SpellId] * udg_PBomb_Cos[udg_PBomb_SpellId]




Custom script: set newY = GetUnitY(udg_PBomb_MissileUnit[udg_PBomb_SpellId]) + udg_PBomb_MoveRate[udg_PBomb_SpellId] * udg_PBomb_Sin[udg_PBomb_SpellId]




Set PBomb_DistanceTraveled[PBomb_SpellId] = (PBomb_DistanceTraveled[PBomb_SpellId] + PBomb_MoveRate[PBomb_SpellId])




-------- z adjustment (need to use locals or else editor will crash from lengthy custom script) --------




Custom script: call MoveLocation(udg_PBomb_LocZ, newX, newY)




Custom script: set currentD = udg_PBomb_DistanceTraveled[udg_PBomb_SpellId]




Custom script: set totalD = udg_PBomb_TotalDistance[udg_PBomb_SpellId]




Custom script: set originZ = udg_PBomb_StartZ[udg_PBomb_SpellId]




Custom script: set aimZ = udg_PBomb_EndZ[udg_PBomb_SpellId]




Custom script: set adjustZ = originZ - GetLocationZ(udg_PBomb_LocZ)




Custom script: set udg_PBomb_Height = adjustZ + 4 * udg_PBomb_MaxHeight * currentD * (totalD-currentD) / (totalD*totalD) + currentD * (aimZ-originZ) / totalD




-------- apply adjustment --------




Custom script: call SetUnitX(udg_PBomb_MissileUnit[udg_PBomb_SpellId], newX)




Custom script: call SetUnitY(udg_PBomb_MissileUnit[udg_PBomb_SpellId], newY)




Animation - Change PBomb_MissileUnit[PBomb_SpellId] flying height to PBomb_Height at 0.00




-------- --------




-------- checking if missile reached target location --------




If (All Conditions are True) then do (Then Actions) else do (Else Actions)





If - Conditions






PBomb_DistanceTraveled[PBomb_SpellId] Greater than or equal to PBomb_TotalDistance[PBomb_SpellId]





Then - Actions






-------- missile has reached target location; begin phase 2 --------






Trigger - Run PBomb_TRIGGER_INDEX_COLOR[PBomb_CurrentColor[PBomb_SpellId]] (ignoring conditions)






-------- --------






Special Effect - Destroy PBomb_MissileSfx[PBomb_SpellId]






Custom script: call DummyAddRecycleTimer(udg_PBomb_MissileUnit[udg_PBomb_SpellId], udg_PBomb_SFX_DEATH_TIMER[udg_PBomb_CurrentColor[udg_PBomb_SpellId]])






-------- --------






Set PBomb_RecycledStack[PBomb_RecycledSize] = PBomb_SpellId






Set PBomb_RecycledSize = (PBomb_RecycledSize + 1)






Set PBomb_NodeNext[PBomb_NodePrev[PBomb_SpellId]] = PBomb_NodeNext[PBomb_SpellId]






Set PBomb_NodePrev[PBomb_NodeNext[PBomb_SpellId]] = PBomb_NodePrev[PBomb_SpellId]






-------- --------






Set PBomb_SpellCount = (PBomb_SpellCount - 1)






If (All Conditions are True) then do (Then Actions) else do (Else Actions)







If - Conditions








PBomb_SpellCount Equal to 0







Then - Actions








Trigger - Turn off PBomb_TRIGGER_LOOP







Else - Actions








-------- do nothing --------





Else - Actions






-------- missile has not reached target location; continue moving missile --------
we'll let your team enter the contest with the penalty points for not having three members. IcemanBo will announce how many points will be taken in the poll thread.
Nope.The deadline is 30 November 23:59 GMT right? I want to confirm the time left.
What?.. what's the current state or exact lack? Or there's just absolutly nothing?Speaking of lacking teammates, unfortunately our team won't be able to submit anything (lack of communication) thus we're withdrawing from the contest.
Is there an issue with the info from main post? It's clearly stated 30th Dec GMT (day included) ...The deadline is 30 November 23:59 GMT right? I want to confirm the time left.
GUI always and forever.Thank you for using GUI, I was afraid I'm the old guy here![]()
RPaint Config

Events


Map initialization

Conditions

Actions


-------- --------


-------- CONFIG START --------


-------- --------


-------- --------


-------- imported triggers --------


Set RPaint_TRIGGER_LOOP = RPaint Loop <gen>


-------- --------


-------- damage dealt to nearby enemy units when the bubble explodes --------


Set RPaint_DAMAGE = 50.00


Set RPaint_DAMAGE_PER_LEVEL = 25.00


-------- --------


-------- how close a unit must be to the bubble to take damage --------


Set RPaint_AOE = 250.00


Set RPaint_AOE_PER_LEVEL = 0.00


-------- --------


-------- time (in seconds) it takes for the bubble to pop and deal damage --------


Set RPaint_POP_DELAY = 2.00


Set RPaint_POP_DELAY_PER_LEVEL = 0.00


-------- --------


-------- time (in seconds) it takes for the bubble to pop and deal damage --------


Set RPaint_POP_DELAY = 2.00


Set RPaint_POP_DELAY_PER_LEVEL = 0.00


-------- --------


-------- special effect for puddle --------


Set RPaint_SFX_PUDDLE = PaintBombPuddle_Red.mdl


Set RPaint_SFX_PUDDLE_AP = origin


Set RPaint_SFX_PUDDLE_SIZE = 1.00


Set RPaint_SFX_PUDDLE_DEATH_TIMER = 0.25


-------- ^ how much time (in seconds) is needed for death sfx to play --------


-------- --------


-------- special effect for bubble --------


Set RPaint_SFX_BUBBLE = PaintBombBubble.mdl


Set RPaint_SFX_BUBBLE_AP = origin


Set RPaint_SFX_BUBBLE_START_SIZE = 1.00


Set RPaint_SFX_BUBBLE_FINAL_SIZE = 2.50


Set RPaint_SFX_BUBBLE_DEATH_TIMER = 1.00


-------- ^ how much time (in seconds) is needed for death sfx to play --------


-------- --------


-------- other --------


Set RPaint_ATTACK_TYPE = Spells


Set RPaint_DAMAGE_TYPE = Magic


Set RPaint_PERIODIC_TIMER = 0.03


-------- --------


-------- --------


-------- CONFIG END --------


-------- --------


Trigger - Add to RPaint_TRIGGER_LOOP the event (Time - Every RPaint_PERIODIC_TIMER seconds of game time)


-------- preload --------


Custom script: set udg_RPaint_TempUnit = GetRecycledDummyAnyAngle(0.00, 0.00, 0.00)


Special Effect - Create a special effect attached to the RPaint_SFX_PUDDLE_AP of RPaint_TempUnit using RPaint_SFX_PUDDLE


Special Effect - Destroy (Last created special effect)


Special Effect - Create a special effect attached to the RPaint_SFX_BUBBLE_AP of RPaint_TempUnit using RPaint_SFX_BUBBLE


Special Effect - Destroy (Last created special effect)


Custom script: call RecycleDummy(udg_RPaint_TempUnit)


-------- math calculations --------


Set RPaint_SFX_PUDDLE_SIZE = (RPaint_SFX_PUDDLE_SIZE x 100.00)


Set RPaint_SFX_BUBBLE_START_SIZE = (RPaint_SFX_BUBBLE_START_SIZE x 100.00)


Set RPaint_SFX_BUBBLE_FINAL_SIZE = (RPaint_SFX_BUBBLE_FINAL_SIZE x 100.00)


Set RPaint_BubbleSizeSfx = (RPaint_SFX_BUBBLE_FINAL_SIZE - RPaint_SFX_BUBBLE_START_SIZE)
RPaint Index

Events

Conditions

Actions


-------- PBomb Index Red --------


-------- this trigger will create a new instance for the Red Paint Mechanic --------


-------- --------


-------- members --------


-------- Caster[] - unit that will deal the damage when the paint bubble explodes --------


-------- Owner[] - player who owns Caster[] --------


-------- CurrentColor[] - the color the caster had selected when they threw the paint bomb --------


-------- CurrentSize[] - the current size of the bubble as it grows periodically --------


-------- Damage[] - damage dealt to nearby enemy units when the bubble explodes --------


-------- PuddleLoc[] - center of the explosion --------


-------- Radius[] - distance units must be from PuddleLoc[] to take damage --------


-------- PuddleUnit[] - dummy unit with the puddle special effect --------


-------- PuddleSfx[] - the special effect for the puddle left on the ground --------


-------- BubbleUnit[] - dummy unit with the bubble special effect --------


-------- BubbleSfx[] - the special effect for the bubble --------


-------- GrowRate[] - how fast BubbleUnit[] will change in size per iteration --------


-------- --------


-------- --------


Custom script: local real x


Custom script: local real y


-------- --------


Set RPaint_SpellCount = (RPaint_SpellCount + 1)


If (All Conditions are True) then do (Then Actions) else do (Else Actions)



If - Conditions




RPaint_SpellCount Equal to 1



Then - Actions




Trigger - Turn on RPaint_TRIGGER_LOOP



Else - Actions




-------- do nothing --------


-------- --------


If (All Conditions are True) then do (Then Actions) else do (Else Actions)



If - Conditions




RPaint_RecycledSize Equal to 0



Then - Actions




Set RPaint_MaxIndex = (RPaint_MaxIndex + 1)




Set RPaint_SpellId = RPaint_MaxIndex



Else - Actions




Set RPaint_RecycledSize = (RPaint_RecycledSize - 1)




Set RPaint_SpellId = RPaint_RecycledStack[RPaint_RecycledSize]


Set RPaint_NodeNext[RPaint_SpellId] = 0


Set RPaint_NodePrev[RPaint_SpellId] = RPaint_NodePrev[0]


Set RPaint_NodeNext[RPaint_NodePrev[0]] = RPaint_SpellId


Set RPaint_NodePrev[0] = RPaint_SpellId


-------- --------


Set RPaint_Caster[RPaint_SpellId] = PBomb_Caster[PBomb_SpellId]


Set RPaint_Owner[RPaint_SpellId] = PBomb_Owner[PBomb_SpellId]


Set RPaint_CurrentColor[RPaint_SpellId] = PBomb_CurrentColor[PBomb_SpellId]


Set RPaint_CurrentSize[RPaint_SpellId] = RPaint_SFX_BUBBLE_START_SIZE


-------- --------


Set RPaint_TempReal = (Real(PBomb_AbilityLvl[PBomb_SpellId]))


Set RPaint_Damage[RPaint_SpellId] = (RPaint_DAMAGE + (RPaint_DAMAGE_PER_LEVEL x RPaint_TempReal))


Set RPaint_Radius[RPaint_SpellId] = (RPaint_AOE + (RPaint_AOE_PER_LEVEL x RPaint_TempReal))


Set RPaint_GrowRate[RPaint_SpellId] = (RPaint_BubbleSizeSfx / ((RPaint_POP_DELAY + (RPaint_POP_DELAY_PER_LEVEL x RPaint_TempReal)) / RPaint_PERIODIC_TIMER))


-------- --------


Set RPaint_PuddleLoc[RPaint_SpellId] = (Position of PBomb_MissileUnit[PBomb_SpellId])


Custom script: set x = GetLocationX(udg_RPaint_PuddleLoc[udg_RPaint_SpellId])


Custom script: set y = GetLocationY(udg_RPaint_PuddleLoc[udg_RPaint_SpellId])


Custom script: set udg_RPaint_PuddleUnit[udg_RPaint_SpellId] = GetRecycledDummyAnyAngle(x, y, 0.00)


Animation - Change RPaint_PuddleUnit[RPaint_SpellId]'s size to (RPaint_SFX_PUDDLE_SIZE%, 100.00%, 100.00%) of its original size


Special Effect - Create a special effect attached to the RPaint_SFX_PUDDLE_AP of RPaint_PuddleUnit[RPaint_SpellId] using RPaint_SFX_PUDDLE


Set RPaint_PuddleSfx[RPaint_SpellId] = (Last created special effect)


-------- --------


Custom script: set udg_RPaint_BubbleUnit[udg_RPaint_SpellId] = GetRecycledDummyAnyAngle(x, y, 0.00)


Animation - Change RPaint_BubbleUnit[RPaint_SpellId]'s size to (RPaint_SFX_BUBBLE_START_SIZE%, 100.00%, 100.00%) of its original size


Special Effect - Create a special effect attached to the RPaint_SFX_BUBBLE_AP of RPaint_BubbleUnit[RPaint_SpellId] using RPaint_SFX_BUBBLE


Set RPaint_BubbleSfx[RPaint_SpellId] = (Last created special effect)
RPaint Loop

Events

Conditions

Actions


-------- RPaint Loop --------


-------- this trigger will periodically grow the bubble --------


-------- once the bubble reaches the max size, it will explode, and deal damage to nearby enemy units --------


-------- --------


-------- members --------


-------- Caster[] - unit that will deal the damage when the paint bubble explodes --------


-------- Owner[] - player who owns Caster[] --------


-------- CurrentColor[] - the color the caster had selected when they threw the paint bomb --------


-------- CurrentSize[] - the current size of the bubble as it grows periodically --------


-------- Damage[] - damage dealt to nearby enemy units when the bubble explodes --------


-------- PuddleLoc[] - center of the explosion --------


-------- Radius[] - distance units must be from PuddleLoc[] to take damage --------


-------- PuddleUnit[] - dummy unit with the puddle special effect --------


-------- PuddleSfx[] - the special effect for the puddle left on the ground --------


-------- BubbleUnit[] - dummy unit with the bubble special effect --------


-------- BubbleSfx[] - the special effect for the bubble --------


-------- GrowRate[] - how fast BubbleUnit[] will change in size per iteration --------


-------- --------


-------- --------


Set RPaint_SpellId = 0


For each (Integer RPaint_LoopInt) from 1 to RPaint_SpellCount, do (Actions)



Loop - Actions




Set RPaint_SpellId = RPaint_NodeNext[RPaint_SpellId]




-------- --------




-------- checking if the bubble has reached the max size --------




If (All Conditions are True) then do (Then Actions) else do (Else Actions)





If - Conditions






RPaint_CurrentSize[RPaint_SpellId] Greater than or equal to RPaint_SFX_BUBBLE_FINAL_SIZE





Then - Actions






-------- bubble has reached max size; damage nearby enemy units and deallocate --------






-------- --------






-------- using GroupEnumUnitsInRangeOfLoc because GetUnitsInRangeOfLoc has a reference handle leak --------






Custom script: call GroupEnumUnitsInRangeOfLoc(udg_PBomb_InRangeGroup, udg_RPaint_PuddleLoc[udg_RPaint_SpellId], udg_RPaint_Radius[udg_RPaint_SpellId], null)






Unit Group - Pick every unit in PBomb_InRangeGroup and do (Actions)







Loop - Actions








Set RPaint_TempUnit = (Picked unit)








If (All Conditions are True) then do (Then Actions) else do (Else Actions)









If - Conditions










(RPaint_TempUnit is A structure) Equal to False










(RPaint_TempUnit is Magic Immune) Equal to False










(RPaint_TempUnit is alive) Equal to True










(RPaint_TempUnit belongs to an enemy of RPaint_Owner[RPaint_SpellId]) Equal to True









Then - Actions










Unit - Cause RPaint_Caster[RPaint_SpellId] to damage RPaint_TempUnit, dealing RPaint_Damage[RPaint_SpellId] damage of attack type RPaint_ATTACK_TYPE and damage type RPaint_DAMAGE_TYPE









Else - Actions










-------- do nothing --------








Unit Group - Remove RPaint_TempUnit from PBomb_InRangeGroup






-------- --------






Custom script: set udg_SPaint_UnitId = GetHandleId(udg_RPaint_Caster[udg_RPaint_SpellId])






Hashtable - Save ((Load PBomb_KEY_ACTIVE_COUNT[RPaint_CurrentColor[RPaint_SpellId]] of SPaint_UnitId from PBomb_Hash) - 1) as PBomb_KEY_ACTIVE_COUNT[RPaint_CurrentColor[RPaint_SpellId]] of SPaint_UnitId in PBomb_Hash






-------- --------






Custom script: call RemoveLocation(udg_RPaint_PuddleLoc[udg_RPaint_SpellId])






Special Effect - Destroy RPaint_PuddleSfx[RPaint_SpellId]






Special Effect - Destroy RPaint_BubbleSfx[RPaint_SpellId]






Custom script: call DummyAddRecycleTimer(udg_RPaint_PuddleUnit[udg_RPaint_SpellId], udg_RPaint_SFX_PUDDLE_DEATH_TIMER)






Custom script: call DummyAddRecycleTimer(udg_RPaint_BubbleUnit[udg_RPaint_SpellId], udg_RPaint_SFX_BUBBLE_DEATH_TIMER)






Set RPaint_RecycledStack[RPaint_RecycledSize] = RPaint_SpellId






Set RPaint_RecycledSize = (RPaint_RecycledSize + 1)






Set RPaint_NodeNext[RPaint_NodePrev[RPaint_SpellId]] = RPaint_NodeNext[RPaint_SpellId]






Set RPaint_NodePrev[RPaint_NodeNext[RPaint_SpellId]] = RPaint_NodePrev[RPaint_SpellId]






-------- --------






Set RPaint_SpellCount = (RPaint_SpellCount - 1)






If (All Conditions are True) then do (Then Actions) else do (Else Actions)







If - Conditions








RPaint_SpellCount Equal to 0







Then - Actions








Trigger - Turn off RPaint_TRIGGER_LOOP







Else - Actions








-------- do nothing --------





Else - Actions






-------- bubble has not reached max size; continue to grow --------






Set RPaint_CurrentSize[RPaint_SpellId] = (RPaint_CurrentSize[RPaint_SpellId] + RPaint_GrowRate[RPaint_SpellId])






Animation - Change RPaint_BubbleUnit[RPaint_SpellId]'s size to (RPaint_CurrentSize[RPaint_SpellId]%, 100.00%, 100.00%) of its original size
//! externalblock extension=lua ObjectMerger $FILENAME$
//! i ID = "e002"
//! i ATTACK_SPEED = 1.0
//! i MOVE_SPEED = 500
//! i NAME = "Fel Spiderling"
//! i function declare_spider(atkSpeed, mvSpeed, paramName)
//! i setobjecttype("units")
//! i createobject("nspd", ID)
//! i makechange(current, "uico", "ReplaceableTextures\CommandButtons\BTNSpiderBlack.blp")
//! i makechange(current, "umdl", "units\creeps\SpiderBlack\SpiderBlack.mdl")
//! i makechange(current, "usca", 0.4)
//! i makechange(current, "ussc", 0.9)
//! i makechange(current, "ushx", 15)
//! i makechange(current, "ushy", 15)
//! i makechange(current, "ushh", 40)
//! i makechange(current, "ushw", 40)
//! i makechange(current, "ua1t", "chaos")
//! i makechange(current, "ua1c", math.min(math.max(atkSpeed, 0.1), 5.0))
//! i makechange(current, "ua1b", 0)
//! i makechange(current, "ua1s", 1)
//! i makechange(current, "ua1d", 1)
//! i makechange(current, "ua1r", 90)
//! i makechange(current, "umvs", math.min(mvSpeed, 522))
//! i makechange(current, "umas", math.min(mvSpeed, 522))
//! i makechange(current, "umis", math.min(mvSpeed - 1, 100))
//! i makechange(current, "uhpm", 250)
//! i makechange(current, "urac", "undead")
//! i makechange(current, "unam", paramName)
//! i makechange(current, "utip", "Summon " .. paramName)
//! i makechange(current, "utub", "Light melee unit. Deals damage based on attribute. |n|n|cffffcc00Attacks land units.|r")
//! i end
//! i declare_spider(ATTACK_SPEED, MOVE_SPEED, NAME)
//! endexternalblock
library OvermindSpellThree initializer Init requires /*
* ----------------------
*/ AllocationAndLinks, /* https://www.hiveworkshop.com/threads/allocation-and-links.293621/
* ----------------------
*
* - Contains the doubly linked list and custom allocation which is preferred by the coder.
* - If you don't want extends array syntax, just change AllocLinkBundle to DoubleLink
*
* ----------------------
*/ TimerUtils, /* http://www.wc3c.net/showthread.php?t=101322
* ----------------------
*
* - Too lazy to create a timer library that allows attachment of data,
* but not too lazy to completely rewrite it.
*
* ----------------------------
*/ CustomFunctions, /*
* ----------------------------
*
* - Allows a nice not-red debug setting, and allows the instant generation of a search function.
* Technically not useless.
*
* --------------------------------
*/ DamageEvent, DamageModify, /* https://www.hiveworkshop.com/threads/damagepackage.287101/
* --------------------------------
*
* - Allows the manipulation of damage
* - DamageModify is the takeaway here. (Modifies the damage dealt by the spiderlings).
*
* --------------------------------
*/ optional TextTag /* https://www.hiveworkshop.com/threads/library-text-tag.290924/post-3138916
* --------------------------------
* - Optionally displays the amount restored to the hive creator.
* - Can be used informationally.
*
*/
/*
* __________________________
*
* OvermindSpellThree
* __________________________
*
* ______________
*
* The Hive
* ______________
*
* - A spell based on Pocket Factory that plants a targeted location with a hive mind.
* - This spell is active, and has a sub-spell component, namely Ravage Hive.
*
* __________________
*
* How it goes
* __________________
*
* - The spell is cast, triggering a spell-effect trigger and creating an associated
* struct instance of type Data.
*
* - The Data struct instance then activates a timer, which is set to expire based on
* the speed of the missile created by the ability and the distance therefrom.
*
* - After expiration, the hive is created with a delay in its' timed life. During this
* time, the hive is rendered invulnerable.
*
* - After the delay, the expiration timer for the hive is started. The hive may or may
* not be harmed based on the data flag section.
*
* - If it dies, its' expiration timer expires, or a Ravage Hive sub-spell has taken effect,
* the hive will execute its' death-related event. This may bug out with certain scripts,
* which remove units on death.
*
* ____________
*
* API
* ____________
*
* native functions:
* - UnitAlive(unit id) returns boolean
*
* external functions:
* - external func:
* exe: ObjectMerger.exe
* type: w3u / units
* base id: 'hfoo' / footman
* new id: '!000' / footman derivative.
*
* model: "dummy.mdx"
*
* globals:
* private constant group ENUM_GROUP
* - Enumerator group
* private unit enum_unit
* - Enumerator unit variable.
*
* configurable functions:
* function SPELL_ID() returns integer
* - Returns the raw code of the spell. (See in Object Editor (Ctrl + D))
* function RAW_ID(int i) returns integer
* - Returns some raw code based on request. (Defaults to 0)
* function DATA(int i, int lev) returns real
* - Returns the necessary soft-coded data field. (Defaults to 0)
*
* External scripts:
* - Used mostly for the generation of the spiderling with the added speed properties.
* Can be modified to a certain extent by script.
*
*/
native UnitAlive takes unit id returns boolean
/* The following scripts are external lua scripts which generate the necessary unit data.
* Since I wanted to make this configurable (to a certain extent), the script for declaring
* a spider is given below.
*
* This line of code has been deemed redundant due to the pathing script being removed.
* ___________________________________________________________
*
* ///! external ObjectMerger w3u hfoo "!000" umdl "dummy.mdx"
* ___________________________________________________________
*
* The code below may be commented out by adding a delimited comment.
* Delimited comments look like this:
*
* /*
* Put some stuff here.
* */
*
* To enable the script again, just remove the delimiters.
*
* ___________
*
* API
* ___________
*
* ID = "char"
* - The rawcode of the spider.
*
* ATTACK_SPEED = float r
* - The attack speed defined as a float.
* MOVE_SPEED = float r
* - The movement speed of the spider defined as an integer.
* NAME = string nam
* - The name of the spider. If you like, you can change it.
*
* function declare_spider(real atkSpeed, int mvSpeed, string paramName)
* - Due to the lack of explicit type definition, the type of the parameters have been
* supplied for you.
*
* - Generates a spider with a certain raw id based on the ID variable (string)
* - The only configurable parts are the attack speed, move speed and name
* Even then, the attack speed is capped off at 5.0 and 0.1.
*
* - Will cause the Typecasting library to fail if the external script is not delimited.
*/
/*
//! externalblock extension=lua ObjectMerger $FILENAME$
//! i ID = "e002"
//! i ATTACK_SPEED = 1.0
//! i MOVE_SPEED = 500
//! i NAME = "Fel Spiderling"
//! i function declare_spider(atkSpeed, mvSpeed, paramName)
//! i setobjecttype("units")
//! i createobject("nspd", ID)
//! i makechange(current, "uico", "ReplaceableTextures\\CommandButtons\\BTNSpiderBlack.blp")
//! i makechange(current, "umdl", "units\\creeps\\SpiderBlack\\SpiderBlack.mdl")
//! i makechange(current, "usca", 0.4)
//! i makechange(current, "ussc", 0.9)
//! i makechange(current, "ushx", 15)
//! i makechange(current, "ushy", 15)
//! i makechange(current, "ushh", 40)
//! i makechange(current, "ushw", 40)
//! i makechange(current, "ua1t", "chaos")
//! i makechange(current, "ua1c", math.min(math.max(atkSpeed, 0.1), 5.0))
//! i makechange(current, "ua1b", 0)
//! i makechange(current, "ua1s", 1)
//! i makechange(current, "ua1d", 1)
//! i makechange(current, "ua1r", 90)
//! i makechange(current, "umvs", math.min(mvSpeed, 522))
//! i makechange(current, "umas", math.min(mvSpeed, 522))
//! i makechange(current, "umis", math.min(mvSpeed - 1, 100))
//! i makechange(current, "uhpm", 250)
//! i makechange(current, "urac", "undead")
//! i makechange(current, "unam", paramName)
//! i makechange(current, "utip", "Summon " .. paramName)
//! i makechange(current, "utub", "Light melee unit. Deals damage based on attribute. |n|n|cffffcc00Attacks land units.|r")
//! i end
//! i declare_spider(ATTACK_SPEED, MOVE_SPEED, NAME)
//! endexternalblock
*/
globals
private constant group ENUM_GROUP = CreateGroup()
private unit enum_unit = null
endglobals
private constant function SPELL_ID takes nothing returns integer
return 'A002'
endfunction
private constant function RAW_ID takes integer request returns integer
if request == 0 then
// Returns the ID of the hatchery.
return 'e001'
elseif request == 1 then
// Returns the ID of the fel spiderlings
return 'e002'
elseif request == 2 then
// Returns the ID of the sub-spell
return '1001'
endif
return 0
endfunction
private constant function DATA takes integer request, integer level returns real
if request == 0 then
// Returns the duration of the hive
if level == 1 then
return 50.
elseif level == 2 then
return 75.
elseif level == 3 then
return 100.
endif
elseif request == 1 then
// Returns the effective detection range.
if level == 1 then
return 150.
elseif level == 2 then
return 250.
elseif level == 3 then
return 350.
endif
elseif request == 2 then
// Returns the tick rate.
// Defaults to 1.
return 1.
elseif request == 3 then
// Returns the amount of mana burned around the hive
if level == 1 then
return 5.
elseif level == 2 then
return 7.
elseif level == 3 then
return 10.
endif
elseif request == 4 then
// Returns the amount of health rejuvenated by ratio.
// Only takes effect when used as a nydus canal.
if level == 1 then
return 0.1
elseif level == 2 then
return 0.12
elseif level == 3 then
return 0.16
endif
elseif request == 5 then
// Returns the range field for allowing mana burn
// Defaults to 500.
return 500.
elseif request == 6 then
// Returns the flag for allowing the hive to be invulnerable.
// Defaults to true (not equal to 0.)
return 0.
elseif request == 7 then
// Returns the damage dealt when hive (simulating death or actually dying)
if level == 1 then
return 85.
elseif level == 2 then
return 150.
elseif level == 3 then
return 220.
endif
elseif request == 8 then
// Returns the amount of spiders that will spawn.
if level == 1 then
return 4.
elseif level == 2 then
return 5.
elseif level == 3 then
return 6.
endif
elseif request == 9 then
// Returns the speed of the missile
// Must correspond to the object data equivalent.
return 1000.
elseif request == 10 then
// Returns the frequency of the global timer
// Cannot be configured to the level of the unit
return 1/32.
elseif request == 11 then
// Returns the fade-in total duration.
// Cannot be configured to the level of the unit
return 2.5
elseif request == 12 then
// Returns the duration of the death animation
// Cannot be configured to the level of the unit
return 5.
elseif request == 13 then
// Returns the main attribute to follow
// Higher values will return modulo of 3.
// Strength: 1
// Agility: 2
// Intelligence: 3
return 3.
elseif request == 14 then
// Returns damage dealt based on percentage
if level == 1 then
return 0.1
elseif level == 2 then
return 0.14
elseif level == 3 then
return 0.18
endif
elseif request == 15 then
// Returns the amount of mana rejuvenated by ratio.
// Only takes effect when used as a nydus canal.
if level == 1 then
return 0.12
elseif level == 2 then
return 0.16
elseif level == 3 then
return 0.2
endif
endif
return 0.
endfunction
/* Generated boolean comparison (inlined) */
globals
private constant boolean REG_11_BOOL = 2.5 <= 0.
endglobals
/* The strings which will be used for projecting certain effects and such */
private constant function MDL_FILE takes integer request returns string
if request == 0 then
return "Abilities\\Weapons\\ChimaeraAcidMissile\\ChimaeraAcidMissile.mdl"
elseif request == 1 then
return "Abilities\\Spells\\NightElf\\ManaBurn\\ManaBurnTarget.mdl"
elseif request == 2 then
return "Abilities\\Weapons\\snapMissile\\snapMissile.mdl"
elseif request == 3 then
return "Units\\NightElf\\Wisp\\WispExplode.mdl"
endif
return ""
endfunction
private function real_GetDist takes real x1, real y1, real x2, real y2 returns real
return SquareRoot((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2))
endfunction
private function echo takes string s returns nothing
static if DEBUG_MODE then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 16, s)
endif
endfunction
// Generates a module with the name DoubleLink_local. It has the property of a private module.
// Same with the next textmacro. A private module DoubleLink_active is generated.
//! runtextmacro link_module("local", "private")
//! runtextmacro link_module("active", "private")
private struct Data extends array
implement AllocLinkBundle
implement DoubleLink_local
implement DoubleLink_active
private static constant timer ACTIVE_TIMER = CreateTimer()
private static constant group STORED_SPIDERS = CreateGroup()
// Assistant to the stored spider group
private static integer stored_spider_count = 0
// Counter for a forGroupEx call
private static integer spider_group_count = 0
// Mode checker
private integer mode
private real mode_data
/* Part One
* - This will store the unit, level, timer, target x, and target y for
* the successful creation of the hive. */
private unit unit
private unit hive
private integer level
private timer timer
private real tx
private real ty
// Part Two
/* - This will be the main part of the spell, the mechanics of which will
* be the main focus and intention of this spell. */
// For speed purposes
private static player feedback_player
private static thistype hive_this
private static thistype spider_this
private real stored
private integer eventtype
private unit target
private trigger detector
private group spider_group
/*
These textmacros can be found at CustomFunctions. It's easy to port them to this library, though.
They generate a searching algorithm for finding a certain instance.
If not fully explained, the parameters are defined as follows:
search_list(encapsulation-keyword, name, searched type, iterator variable, conditional statement)
*/
//! runtextmacro search_list("private", "get", "unit", "next", "unit == id")
//! runtextmacro search_list("private", "get_hive", "unit", "active_next", "hive == id")
//! runtextmacro search_list("private", "get_targ", "unit", "active_next", "target == id")
//! runtextmacro search_list("private", "get_trig", "trigger", "active_next", "detector == id")
//! runtextmacro search_list("private", "get_group", "unit", "active_next", "IsUnitInGroup(id, spider_group)")
// Detaches a certain instance from a global list if it is found and in the local list.
// Pushes the next local instance to the global list if there exists at least one more.
private method detach takes nothing returns nothing
if head != 0 then
if local_next != this then
set local_next.head = 1
call local_next.insert(next)
endif
set head = 0
call pop()
endif
call local_pop()
endmethod
/* Mimics death for the spiders */
private static method spider_preDestroy_enum takes nothing returns nothing
set enum_unit = GetEnumUnit()
call PauseUnit(enum_unit, true)
call SetUnitAnimation(enum_unit, "death")
endmethod
private method spider_preDestroy takes nothing returns nothing
call ForGroup(spider_group, function thistype.spider_preDestroy_enum)
set enum_unit = null
endmethod
/* Resets the animation for the next group */
private static method spider_onDestroy_enum takes nothing returns nothing
set enum_unit = GetEnumUnit()
call QueueUnitAnimation(enum_unit, "stand")
call SetUnitX(enum_unit, 0)
call SetUnitY(enum_unit, 0)
call SetUnitOwner(enum_unit, Player(15), true)
call ShowUnit(enum_unit, false)
endmethod
private method spider_onDestroy takes nothing returns nothing
call ForGroup(spider_group, function thistype.spider_onDestroy_enum)
set enum_unit = null
endmethod
/* Check if the hive is still alive. If not, attempt to nullify hive and prepare a new one. */
private method preDestroy takes nothing returns nothing
if not UnitAlive(hive) then
call RemoveUnit(hive)
set hive = null
else
call PauseUnit(hive, true)
call ShowUnit(hive, false)
call SetUnitX(hive, 0)
call SetUnitY(hive, 0)
call SetWidgetLife(hive, GetUnitState(hive, UNIT_STATE_MAX_LIFE))
call SetUnitOwner(hive, Player(15), false)
if not (DATA(6, level) != 0) then
call echo("Unit is vulnerable")
call UnitRemoveAbility(hive, 'Aloc')
debug else
call echo("Unit is invulnerable")
endif
endif
endmethod
private method destroy takes nothing returns nothing
call spider_onDestroy()
call preDestroy()
call ReleaseTimer(timer)
call DestroyTrigger(detector)
set unit = null
set target = null
set timer = null
set detector = null
set tx = 0.
set ty = 0.
set mode_data = 0.
set stored = 0.
set head = 0
set mode = 0
set eventtype = 0
call active_pop()
set active_head = 0
set thistype(0).active_head = thistype(0).active_head - 1
call deallocate()
endmethod
// Part two
private static method target_attack_enum takes nothing returns nothing
local thistype this = spider_this
set enum_unit = GetEnumUnit()
if target != null then
if GetUnitTypeId(target) != 0 or UnitAlive(target) then
call IssueTargetOrder(enum_unit, "attack", target)
else
call IssuePointOrder(enum_unit, "move", GetUnitX(hive) + GetRandomReal(-DATA(1, level), DATA(1, level)), GetUnitY(spider_this.hive) + GetRandomReal(-DATA(1, level), DATA(1, level)))
endif
else
call IssuePointOrder(enum_unit, "move", GetUnitX(hive) + GetRandomReal(-DATA(1, level), DATA(1, level)), GetUnitY(hive) + GetRandomReal(-DATA(1, level), DATA(1, level)))
endif
endmethod
private method target_attack takes nothing returns nothing
set spider_this = this
call ForGroup(spider_group, function thistype.target_attack_enum)
set spider_this = 0
endmethod
private method target_search takes nothing returns nothing
set feedback_player = GetOwningPlayer(hive)
call GroupEnumUnitsInRange(ENUM_GROUP, GetUnitX(hive), GetUnitY(hive), DATA(1, level), null)
call GroupRemoveUnit(ENUM_GROUP, target)
loop
set enum_unit = FirstOfGroup(ENUM_GROUP)
exitwhen enum_unit == null
if UnitAlive(enum_unit) and IsUnitEnemy(enum_unit, feedback_player) and UnitDamageTarget(enum_unit, enum_unit, 0, true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null) then
set target = enum_unit
exitwhen true
endif
call GroupRemoveUnit(ENUM_GROUP, enum_unit)
endloop
if enum_unit == null then
set target = null
call echo("No valid target found")
else
call echo("Target was discovered: " + GetUnitName(target))
endif
endmethod
private static method target_onDeathEvent takes nothing returns nothing
local thistype this = get_targ(GetTriggerUnit())
if this != 0 then
call target_search()
call target_attack()
endif
endmethod
private static method hive_onDeathProxy takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call destroy()
endmethod
private static method hive_onErupt takes nothing returns nothing
local thistype this = hive_this
set hive_this = 0
set feedback_player = GetOwningPlayer(hive)
call GroupEnumUnitsInRange(ENUM_GROUP, GetUnitX(hive), GetUnitY(hive), DATA(5, level), null)
loop
set enum_unit = FirstOfGroup(ENUM_GROUP)
exitwhen enum_unit == null
if UnitAlive(enum_unit) and IsUnitEnemy(enum_unit, feedback_player) then
if UnitDamageTarget(hive, enum_unit, DATA(7, level), true, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_UNIVERSAL, null) then
call DestroyEffect(AddSpecialEffectTarget(MDL_FILE(1), enum_unit, "chest"))
endif
endif
call GroupRemoveUnit(ENUM_GROUP, enum_unit)
endloop
endmethod
private method hive_onDeath takes nothing returns nothing
call PauseTimer(timer)
call TimerStart(timer, DATA(12, 0), false, function thistype.hive_onDeathProxy)
set mode = 3
if eventtype != 1 then
call SetUnitAnimation(hive, "death")
endif
if local_next == this then
call echo("Last reserved instance!")
call UnitRemoveAbility(unit, RAW_ID(2))
debug else
call echo("Current instance: " + I2S(this))
call echo("Next instance: " + I2S(local_next) + "\n")
call echo("There are some instances left!")
endif
call detach()
set hive_this = this
call ForForce(bj_FORCE_PLAYER[0], function thistype.hive_onErupt)
call spider_preDestroy()
endmethod
private method overmind_onTeleport takes nothing returns nothing
local real rx = GetUnitX(unit)
local real ry = GetUnitX(unit)
local player p = GetOwningPlayer(unit)
if this == 0 then
call echo("thistype.overmind_onTeleport: Invalid instance!")
return
endif
call SetWidgetLife(unit, GetWidgetLife(unit) + stored*DATA(4, level))
call SetUnitState(unit, UNIT_STATE_MANA, GetUnitState(unit, UNIT_STATE_MANA) + stored*DATA(15, level))
static if LIBRARY_TextTag then
call CreateTextTagBJ(p, rx, ry, 75, 0, 255, 255, "+" + I2S(R2I(stored*(DATA(4, level)))) + " health!\n+" + I2S(R2I(stored*(DATA(15, level)))) + " mana!")
set vj_lastCreatedTextTag.duration = 3.0
set vj_lastCreatedTextTag.fade = 2.25
endif
// For boolean consistency
set eventtype = 3
if not (DATA(6, level) != 0) then
call echo("Removing timed life buffs")
call UnitRemoveBuffsEx(hive, true, true, false, false, true, false, false)
endif
call DestroyEffect(AddSpecialEffect(MDL_FILE(3), rx, ry))
call DestroyEffect(AddSpecialEffect(MDL_FILE(0), rx, ry))
call SetUnitX(unit, GetUnitX(hive))
call SetUnitY(unit, GetUnitX(hive))
// Unimportant to deallocate players (hear-say)
endmethod
private static method hive_onDeathEvent takes nothing returns nothing
local thistype this = get_hive(GetTriggerUnit())
if this != 0 then
if eventtype == 0 then
set eventtype = 1
endif
call hive_onDeath()
endif
endmethod
private static method hive_onFeedback_loop takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
set mode_data = mode_data - DATA(2, level)
if mode_data > 0. then
call target_attack()
set feedback_player = GetOwningPlayer(hive)
call GroupEnumUnitsInRange(ENUM_GROUP, GetUnitX(hive), GetUnitY(hive), DATA(5, level), null)
loop
set enum_unit = FirstOfGroup(ENUM_GROUP)
exitwhen enum_unit == null
if UnitAlive(enum_unit) and IsUnitEnemy(enum_unit, feedback_player) then
if GetUnitState(enum_unit, UNIT_STATE_MAX_MANA) != 0 then
call DestroyEffect(AddSpecialEffectTarget(MDL_FILE(1), enum_unit, "chest"))
call SetUnitState(enum_unit, UNIT_STATE_MANA, GetUnitState(enum_unit, UNIT_STATE_MANA) - DATA(3, level))
call UnitDamageTarget(hive, enum_unit, DATA(3, level), true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_UNIVERSAL, null)
set stored = stored + DATA(3, level)
endif
endif
call GroupRemoveUnit(ENUM_GROUP, enum_unit)
endloop
else
set eventtype = 2
call hive_onDeath()
endif
endmethod
private static method hive_onDetectEnemy takes nothing returns nothing
local thistype this = get_trig(GetTriggeringTrigger())
if IsUnitEnemy(GetTriggerUnit(), GetOwningPlayer(hive)) then
if target == null then
set target = GetTriggerUnit()
call target_attack()
endif
endif
endmethod
private static method spider_forGroupEx_enum takes nothing returns nothing
local thistype this = spider_this
set enum_unit = GetEnumUnit()
set spider_group_count = spider_group_count + 1
call SetUnitOwner(enum_unit, feedback_player, true)
call SetUnitPosition(enum_unit, tx, ty)
call SetUnitFacing(enum_unit, GetRandomReal(0, 360))
call PauseUnit(enum_unit, false)
call ShowUnit(enum_unit, true)
call UnitRemoveAbility(enum_unit, 'Aloc')
call UnitAddAbility(enum_unit, 'Aloc')
endmethod
private method spider_forGroupEx takes nothing returns integer
set spider_this = this
set spider_group_count = 0
call ForGroup(spider_group, function thistype.spider_forGroupEx_enum)
set enum_unit = null
return spider_group_count
endmethod
private method hive_spider_init takes nothing returns nothing
local integer int = R2I(DATA(8, level))
set feedback_player = GetOwningPlayer(unit)
if spider_group == null then
set spider_group = CreateGroup()
endif
set int = int - spider_forGroupEx()
if int < 0 then
loop
set enum_unit = FirstOfGroup(spider_group)
exitwhen int >= 0
call SetUnitOwner(enum_unit, Player(15), true)
call SetUnitX(enum_unit, 0)
call SetUnitY(enum_unit, 0)
call PauseUnit(enum_unit, true)
call ShowUnit(enum_unit, false)
call UnitRemoveAbility(enum_unit, 'Aloc')
call UnitAddAbility(enum_unit, 'Aloc')
call GroupRemoveUnit(spider_group, enum_unit)
call GroupAddUnit(STORED_SPIDERS, enum_unit)
set stored_spider_count = stored_spider_count + 1
set int = int + 1
endloop
else
// We check if there are any free spiders in the group.
loop
set enum_unit = FirstOfGroup(STORED_SPIDERS)
exitwhen enum_unit == null or int <= 0 or stored_spider_count <= 0
call SetUnitOwner(enum_unit, feedback_player, true)
call SetUnitPosition(enum_unit, tx, ty)
call SetUnitFacing(enum_unit, GetRandomReal(0, 360))
call PauseUnit(enum_unit, false)
call ShowUnit(enum_unit, true)
call UnitRemoveAbility(enum_unit, 'Aloc')
call UnitAddAbility(enum_unit, 'Aloc')
call GroupRemoveUnit(STORED_SPIDERS, enum_unit)
call GroupAddUnit(spider_group, enum_unit)
set stored_spider_count = stored_spider_count - 1
set int = int - 1
endloop
// If there are none, proceed to the next loop
loop
exitwhen int <= 0
set bj_lastCreatedUnit = CreateUnit(feedback_player, RAW_ID(1), tx, ty, GetRandomReal(0, 360))
call SetUnitAcquireRange(bj_lastCreatedUnit, DATA(1, level))
call UnitAddAbility(bj_lastCreatedUnit, 'Aloc')
call Damage.add(bj_lastCreatedUnit)
call GroupAddUnit(spider_group, bj_lastCreatedUnit)
set int = int - 1
endloop
endif
call echo("Number of spiders: " + I2S(CountUnitsInGroup(spider_group)))
endmethod
private method hive_addDetection takes nothing returns nothing
set detector = CreateTrigger()
call TriggerRegisterUnitInRange(detector, hive, DATA(1, level), null)
call TriggerAddCondition(detector, function thistype.hive_onDetectEnemy)
endmethod
private method hive_addFeedback takes nothing returns nothing
if not (DATA(6, level) != 0) then
call SetUnitInvulnerable(hive, false)
call UnitApplyTimedLife(hive, 'BTLF', mode_data)
call UnitPauseTimedLife(hive, false)
endif
call hive_addDetection()
call hive_spider_init()
call TimerStart(timer, DATA(2, level), true, function thistype.hive_onFeedback_loop)
endmethod
private static method hive_runList takes nothing returns nothing
local thistype this = thistype(0).active_next
if thistype(0).active_head == 0 then
call PauseTimer(ACTIVE_TIMER)
return
endif
loop
exitwhen this == 0
if mode == 1 then
call DestroyEffect(AddSpecialEffect(MDL_FILE(0), GetUnitX(hive), GetUnitY(hive)))
static if REG_11_BOOL then
call SetUnitVertexColor(hive, 255, 255, 255, 255)
set mode = 2
call hive_addFeedback()
else
set mode_data = mode_data + (255)*DATA(10, 0)/DATA(11, 0)
if mode_data >= 255 then
call SetUnitVertexColor(hive, 255, 255, 255, 255)
set mode = 2
set mode_data = DATA(0, level)
call hive_addFeedback()
else
call SetUnitVertexColor(hive, 255, 255, 255, R2I(mode_data))
endif
endif
endif
set this = active_next
endloop
endmethod
private static method hive_spider_onDamage takes nothing returns nothing
local thistype this = get_group(Damage.source)
local real mode = ModuloReal(mode, 3.)
if mode == 0 then
set mode = 3
endif
if this != 0 then
if mode == 1 then
set Damage.amount = DATA(14, level)*GetHeroStr(unit, true)
elseif mode == 2 then
set Damage.amount = DATA(14, level)*GetHeroAgi(unit, true)
elseif mode == 3 then
set Damage.amount = DATA(14, level)*GetHeroInt(unit, true)
endif
endif
endmethod
// Part one
private static method hive_bufferAdd takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call UnitAddAbility(hive, 'Aloc')
call ReleaseTimer(GetExpiredTimer())
endmethod
private method hive_create takes nothing returns nothing
if hive == null then
set hive = CreateUnit(GetOwningPlayer(unit), RAW_ID(0), tx, ty, 0)
set mode = 1
call SetUnitVertexColor(hive, 255, 255, 255, 0)
if DATA(6, level) != 0 then
call TimerStart(NewTimerEx(this), 0., false, function thistype.hive_bufferAdd)
else
call SetUnitInvulnerable(hive, true)
endif
else
call SetUnitAnimation(hive, "stand")
call QueueUnitAnimation(hive, "stand")
call SetUnitInvulnerable(hive, false)
call SetUnitOwner(hive, GetOwningPlayer(unit), true)
call SetUnitPosition(hive, tx, ty)
call PauseUnit(hive, false)
call ShowUnit(hive, true)
if DATA(6, level) != 0 then
call UnitRemoveAbility(hive, 'Aloc')
call UnitAddAbility(hive, 'Aloc')
endif
set mode = 1
call SetUnitVertexColor(hive, 255, 255, 255, 0)
endif
if GetLocalPlayer() == GetOwningPlayer(unit) then
call SelectUnit(hive, true)
call SelectUnit(hive, false)
endif
call active_push()
set active_head = 1
if thistype(0).active_head == 0 then
call TimerStart(ACTIVE_TIMER, DATA(10, 0), true, function thistype.hive_runList)
endif
set thistype(0).active_head = thistype(0).active_head + 1
endmethod
private static method prepare_hive_flag takes nothing returns nothing
local thistype this = GetTimerData(GetExpiredTimer())
call hive_create()
endmethod
private method prepare_hive takes nothing returns nothing
set timer = NewTimerEx(this)
call TimerStart(timer, real_GetDist(GetUnitX(unit), GetUnitY(unit), GetSpellTargetX(), GetSpellTargetY())/DATA(9, 0), false, function thistype.prepare_hive_flag)
endmethod
static method create takes unit u returns thistype
local thistype this = get(u)
local thistype that
if this == 0 then
set this = allocate()
set unit = u
set level = GetUnitAbilityLevel(u, SPELL_ID())
set head = 1
call UnitAddAbility(u, RAW_ID(2))
call UnitMakeAbilityPermanent(u, true, RAW_ID(2))
call push()
call local_insert(this)
set tx = GetSpellTargetX()
set ty = GetSpellTargetY()
call prepare_hive()
return this
endif
set that = allocate()
set that.unit = unit
set that.level = GetUnitAbilityLevel(unit, SPELL_ID())
call that.local_insert(this)
set that.tx = GetSpellTargetX()
set that.ty = GetSpellTargetY()
call UnitAddAbility(u, RAW_ID(2))
call UnitMakeAbilityPermanent(u, true, RAW_ID(2))
call that.prepare_hive()
return that
endmethod
static method teleport takes unit u, real x, real y returns nothing
local thistype this = get(u)
local thistype head = this
local thistype nearest = head
if this == 0 then
call echo("thistype.teleport: Instance of unit does not exist.")
call echo("thistype.teleport: Returning")
return
endif
set this = local_next
loop
exitwhen this == head
if (real_GetDist(x, y, GetUnitX(hive), GetUnitY(hive)) <= real_GetDist(x, y, GetUnitX(nearest.hive), GetUnitY(nearest.hive))) and mode == 2 then
set nearest = this
endif
set this = local_next
endloop
if nearest.mode != 2 then
call DisplayTextToPlayer(GetOwningPlayer(u), 0, 0, "|cffffcc00The hives are not available.|r")
else
call nearest.overmind_onTeleport()
endif
endmethod
// Init method
public static method init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t, function thistype.hive_onDeathEvent)
call TriggerAddCondition(t, function thistype.target_onDeathEvent)
set t = CreateTrigger()
call Damage.registerModifierTrigger(t)
call TriggerAddCondition(t, function thistype.hive_spider_onDamage)
// Located at part two
set t = null
endmethod
endstruct
private function OnSpellEvent takes nothing returns nothing
if GetSpellAbilityId() == SPELL_ID() then
call Data.create(GetTriggerUnit())
elseif GetSpellAbilityId() == RAW_ID(2) then
call Data.teleport(GetTriggerUnit(), GetSpellTargetX(), GetSpellTargetY())
endif
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, function OnSpellEvent)
call ForForce(bj_FORCE_PLAYER[0], function Data.init)
set t = null
endfunction
endlibrary


YPaint Config

Events


Map initialization

Conditions

Actions


-------- --------


-------- CONFIG START --------


-------- --------


-------- --------


-------- --------


-------- imported object editor data --------


Set YPaint_ABILITY_SLOW = Slow (Yellow Paint)


Set YPaint_BUFF_SLOW = Slow (Yellow Paint)


-------- ^ note: make sure ABILITY_SLOW is giving the corresponding BUFF_SLOW in Object Editor --------


Set YPaint_ABILITY_SNARE = Snare (Yellow Paint)


Set YPaint_BUFF_SNARE = Ensnared (Yellow Paint)


-------- ^ note: make sure ABILITY_SNARE is giving the corresponding BUFF_SNARE in Object Editor --------


-------- --------


-------- imported triggers --------


Set YPaint_TRIGGER_LOOP = YPaint Loop <gen>


Set YPaint_TRIGGER_APPLY_SLOW = YPaint Slow Index <gen>


Set YPaint_TRIGGER_LOOP_SLOW = YPaint Slow Loop <gen>


-------- --------


-------- how long (in seconds) the puddle will last --------


Set YPaint_PUDDLE_DURATION = 5.00


Set YPaint_PUDDLE_DURATION_PER_LVL = 0.00


-------- --------


-------- how close a unit must be to the puddle to be slowed --------


Set YPaint_AOE = 150.00


Set YPaint_AOE_PER_LEVEL = 0.00


-------- --------


-------- duration of the slow --------


Set YPaint_SLOW_DURATION = 5.00


Set YPaint_SLOW_DURATION_PER_LVL = 0.00


-------- --------


-------- special effect for puddle --------


Set YPaint_SFX_PUDDLE = PaintBombPuddle_Yellow.mdl


Set YPaint_SFX_PUDDLE_AP = origin


Set YPaint_SFX_PUDDLE_SIZE = 1.75


Set YPaint_SFX_PUDDLE_DEATH_TIMER = 0.25


-------- ^ how much time (in seconds) is needed for death sfx to play --------


-------- --------


-------- special effect applied to the target when they are slowed --------


Set YPaint_SFX_SLOW = Abilities\Spells\Human\slow\slowtarget.mdl


Set YPaint_SFX_SLOW_AP = origin


-------- --------


-------- other --------


Set YPaint_PERIODIC_TIMER = 0.03


-------- --------


-------- --------


-------- CONFIG END --------


-------- --------


Trigger - Add to YPaint_TRIGGER_LOOP the event (Time - Every YPaint_PERIODIC_TIMER seconds of game time)


Trigger - Add to YPaint_TRIGGER_LOOP_SLOW the event (Time - Every YPaint_PERIODIC_TIMER seconds of game time)


Set YPaint_KEY_ABILITY_LVL = 4


Set YPaint_KEY_DURATION = 5


Set YPaint_KEY_SFX = 6


-------- preload --------


Custom script: set udg_YPaint_DummyCaster = GetRecycledDummyAnyAngle(GetRectMaxX(bj_mapInitialPlayableArea), GetRectMaxY(bj_mapInitialPlayableArea), 0.00)


Special Effect - Create a special effect attached to the YPaint_SFX_PUDDLE_AP of YPaint_DummyCaster using YPaint_SFX_PUDDLE


Special Effect - Destroy (Last created special effect)


-------- turning dummy unit into dummy caster --------


Unit - Unpause YPaint_DummyCaster


Unit - Add YPaint_ABILITY_SLOW to YPaint_DummyCaster


Unit - Add YPaint_ABILITY_SNARE to YPaint_DummyCaster


-------- unpausing because dummy units are paused by DummyRecycler --------


Custom script: call UnitRemoveAbility(udg_YPaint_DummyCaster, 'Amov')


-------- math calculations --------


Set YPaint_SFX_PUDDLE_SIZE = (YPaint_SFX_PUDDLE_SIZE x 100.00)
YPaint Index

Events

Conditions

Actions


-------- YPaint Index --------


-------- this trigger will create a new instance for the yellow paint mechanic --------


-------- --------


-------- members --------


-------- Caster[] = unit who casted PBomb_ABILITY --------


-------- Owner[] = player who owns Caster[] that threw the paint bucket --------


-------- AbilityLvl[] = level of PBomb_ABILITY when the caster initially casted the ability --------


-------- CurrentColor[] - the color the caster had selected when they casted PBomb_ABILITY --------


-------- Counter[] = duration of puddle --------


-------- PuddleX[] - x coordinate for the puddle --------


-------- PuddleY[] - y coordinate for the puddle --------


-------- --------


-------- --------


Set YPaint_SpellCount = (YPaint_SpellCount + 1)


If (All Conditions are True) then do (Then Actions) else do (Else Actions)



If - Conditions




YPaint_SpellCount Equal to 1



Then - Actions




Trigger - Turn on YPaint_TRIGGER_LOOP



Else - Actions




-------- do nothing --------


-------- --------


If (All Conditions are True) then do (Then Actions) else do (Else Actions)



If - Conditions




YPaint_RecycledSize Equal to 0



Then - Actions




Set YPaint_MaxIndex = (YPaint_MaxIndex + 1)




Set YPaint_SpellId = YPaint_MaxIndex



Else - Actions




Set YPaint_RecycledSize = (YPaint_RecycledSize - 1)




Set YPaint_SpellId = YPaint_RecycledStack[YPaint_RecycledSize]


Set YPaint_NodeNext[YPaint_SpellId] = 0


Set YPaint_NodePrev[YPaint_SpellId] = YPaint_NodePrev[0]


Set YPaint_NodeNext[YPaint_NodePrev[0]] = YPaint_SpellId


Set YPaint_NodePrev[0] = YPaint_SpellId


-------- --------


Set YPaint_Caster[YPaint_SpellId] = PBomb_Caster[PBomb_SpellId]


Set YPaint_Owner[YPaint_SpellId] = PBomb_Owner[PBomb_SpellId]


Set YPaint_AbilityLvl[YPaint_SpellId] = PBomb_AbilityLvl[PBomb_SpellId]


Set YPaint_CurrentColor[YPaint_SpellId] = PBomb_CurrentColor[PBomb_SpellId]


-------- --------


Set YPaint_TempReal = (Real(YPaint_AbilityLvl[YPaint_SpellId]))


Set YPaint_Counter[YPaint_SpellId] = (YPaint_PUDDLE_DURATION + (YPaint_PUDDLE_DURATION_PER_LVL x YPaint_TempReal))


Set YPaint_Radius[YPaint_SpellId] = (YPaint_AOE + (YPaint_AOE_PER_LEVEL x YPaint_TempReal))


-------- --------


Custom script: set udg_YPaint_PuddleX[udg_YPaint_SpellId] = GetUnitX(udg_PBomb_MissileUnit[udg_PBomb_SpellId])


Custom script: set udg_YPaint_PuddleY[udg_YPaint_SpellId] = GetUnitY(udg_PBomb_MissileUnit[udg_PBomb_SpellId])


Custom script: set udg_YPaint_PuddleUnit[udg_YPaint_SpellId] = GetRecycledDummyAnyAngle(udg_YPaint_PuddleX[udg_YPaint_SpellId], udg_YPaint_PuddleY[udg_YPaint_SpellId], 0.00)


Animation - Change YPaint_PuddleUnit[YPaint_SpellId]'s size to (YPaint_SFX_PUDDLE_SIZE%, 100.00%, 100.00%) of its original size


Special Effect - Create a special effect attached to the YPaint_SFX_PUDDLE_AP of YPaint_PuddleUnit[YPaint_SpellId] using YPaint_SFX_PUDDLE


Set YPaint_PuddleSfx[YPaint_SpellId] = (Last created special effect)
YPaint Loop

Events

Conditions

Actions


-------- YPaint Loop --------


-------- this trigger will periodically check if there are units within the radius of the puddle --------


-------- if there is an enemy unit within the puddle, the dummy caster will apply the slow effect on them --------


-------- if the enemy unit is already affected by the slow or snare, the dummy caster will do nothing --------


-------- --------


-------- members --------


-------- Caster[] = unit who casted PBomb_ABILITY --------


-------- Owner[] = player who owns Caster[] that threw the paint bucket --------


-------- AbilityLvl[] = level of PBomb_ABILITY when the caster initially casted the ability --------


-------- CurrentColor[] - the color the caster had selected when they casted PBomb_ABILITY --------


-------- Counter[] = duration of puddle --------


-------- PuddleX[] - x coordinate for the puddle --------


-------- PuddleY[] - y coordinate for the puddle --------


-------- --------


-------- --------


Set YPaint_SpellId = 0


For each (Integer YPaint_LoopInt) from 1 to YPaint_SpellCount, do (Actions)



Loop - Actions




Set YPaint_SpellId = YPaint_NodeNext[YPaint_SpellId]




-------- --------




-------- checking if the puddle reached the end of its life span --------




If (All Conditions are True) then do (Then Actions) else do (Else Actions)





If - Conditions






YPaint_Counter[YPaint_SpellId] Less than or equal to 0.00





Then - Actions






-------- puddle has reached the end of its life span; deallocate instance --------






-------- --------






-------- decreasing number of active puddles for this color --------






Custom script: set udg_SPaint_UnitId = GetHandleId(udg_YPaint_Caster[udg_YPaint_SpellId])






Hashtable - Save ((Load PBomb_KEY_ACTIVE_COLOR_COUNT[YPaint_CurrentColor[YPaint_SpellId]] of SPaint_UnitId from PBomb_Hash) - 1) as PBomb_KEY_ACTIVE_COLOR_COUNT[YPaint_CurrentColor[YPaint_SpellId]] of SPaint_UnitId in PBomb_Hash






-------- --------






Special Effect - Destroy YPaint_PuddleSfx[YPaint_SpellId]






Custom script: call DummyAddRecycleTimer(udg_YPaint_PuddleUnit[udg_YPaint_SpellId], udg_YPaint_SFX_PUDDLE_DEATH_TIMER)






Set YPaint_RecycledStack[YPaint_RecycledSize] = YPaint_SpellId






Set YPaint_RecycledSize = (YPaint_RecycledSize + 1)






Set YPaint_NodeNext[YPaint_NodePrev[YPaint_SpellId]] = YPaint_NodeNext[YPaint_SpellId]






Set YPaint_NodePrev[YPaint_NodeNext[YPaint_SpellId]] = YPaint_NodePrev[YPaint_SpellId]






-------- --------






Set YPaint_SpellCount = (YPaint_SpellCount - 1)






If (All Conditions are True) then do (Then Actions) else do (Else Actions)







If - Conditions








YPaint_SpellCount Equal to 0







Then - Actions








Trigger - Turn off YPaint_TRIGGER_LOOP







Else - Actions








-------- do nothing --------





Else - Actions






-------- puddle has not reached the end of its life span; continue slowing nearby enemy units --------






Set YPaint_Counter[YPaint_SpellId] = (YPaint_Counter[YPaint_SpellId] - YPaint_PERIODIC_TIMER)






-------- --------






Custom script: call SetUnitX(udg_YPaint_DummyCaster, udg_YPaint_PuddleX[udg_YPaint_SpellId])






Custom script: call SetUnitY(udg_YPaint_DummyCaster, udg_YPaint_PuddleY[udg_YPaint_SpellId])






-------- using GroupEnumUnitsInRange because GetUnitsInRangeOfLoc has a reference handle leak --------






Custom script: call GroupEnumUnitsInRange(udg_PBomb_InRangeGroup, udg_YPaint_PuddleX[udg_YPaint_SpellId], udg_YPaint_PuddleY[udg_YPaint_SpellId], udg_YPaint_Radius[udg_YPaint_SpellId], null)






Unit Group - Pick every unit in PBomb_InRangeGroup and do (Actions)







Loop - Actions








Set YPaint_TempUnit = (Picked unit)








If (All Conditions are True) then do (Then Actions) else do (Else Actions)









If - Conditions










(YPaint_TempUnit is A structure) Equal to False










(YPaint_TempUnit is A flying unit) Equal to False










(YPaint_TempUnit is Magic Immune) Equal to False










(YPaint_TempUnit is alive) Equal to True










(YPaint_TempUnit belongs to an enemy of YPaint_Owner[YPaint_SpellId]) Equal to True










(YPaint_TempUnit has buff YPaint_BUFF_SLOW) Equal to False










(YPaint_TempUnit has buff YPaint_BUFF_SNARE) Equal to False









Then - Actions










Trigger - Run YPaint_TRIGGER_APPLY_SLOW (ignoring conditions)









Else - Actions










-------- do nothing --------








Unit Group - Remove YPaint_TempUnit from PBomb_InRangeGroup
YPaint Slow Index

Events

Conditions

Actions


-------- YPaint Slow Index --------


-------- this trigger will create an instance that slows the affected unit --------


-------- --------


-------- --------


Custom script: set udg_YPaint_UnitId = GetHandleId(udg_YPaint_TempUnit)


-------- --------


Unit Group - Add YPaint_TempUnit to YPaint_SlowedGroup


Set YPaint_GroupCount = (YPaint_GroupCount + 1)


If (All Conditions are True) then do (Then Actions) else do (Else Actions)



If - Conditions




YPaint_GroupCount Equal to 1



Then - Actions




Trigger - Turn on YPaint_TRIGGER_LOOP_SLOW



Else - Actions




-------- do nothing --------


-------- --------


Set YPaint_SlowCounter = (YPaint_SLOW_DURATION + (YPaint_SLOW_DURATION_PER_LVL x (Real(YPaint_AbilityLvl[YPaint_SpellId]))))


Unit - Order YPaint_DummyCaster to Human Sorceress - Slow YPaint_TempUnit


Special Effect - Create a special effect attached to the YPaint_SFX_SLOW_AP of YPaint_TempUnit using YPaint_SFX_SLOW


-------- --------


Hashtable - Save YPaint_AbilityLvl[YPaint_SpellId] as YPaint_KEY_ABILITY_LVL of YPaint_UnitId in PBomb_Hash


Hashtable - Save YPaint_SlowCounter as YPaint_KEY_DURATION of YPaint_UnitId in PBomb_Hash


Hashtable - Save Handle Of(Last created special effect) as YPaint_KEY_SFX of YPaint_UnitId in PBomb_Hash
YPaint Slow Loop

Events

Conditions

Actions


-------- YPaint Slow Loop --------


-------- this trigger will keep track of the duration of the slow on affected units --------


-------- if the unit still has the buff at the end of the duration, they will be snared --------


-------- --------


-------- --------


Unit Group - Pick every unit in YPaint_SlowedGroup and do (Actions)



Loop - Actions




Set YPaint_Target = (Picked unit)




Custom script: set udg_YPaint_UnitId = GetHandleId(udg_YPaint_Target)




-------- --------




Set YPaint_SlowCounter = ((Load YPaint_KEY_DURATION of YPaint_UnitId from PBomb_Hash) - YPaint_PERIODIC_TIMER)




-------- checking if the target loss the buff or if the duration is over --------




If (All Conditions are True) then do (Then Actions) else do (Else Actions)





If - Conditions






Or - Any (Conditions) are true







Conditions








(YPaint_Target is dead) Equal to True








(YPaint_Target has buff YPaint_BUFF_SLOW) Equal to False








YPaint_SlowCounter Less than or equal to 0.00





Then - Actions






-------- --------






-------- checking if target still has buff --------






If (All Conditions are True) then do (Then Actions) else do (Else Actions)







If - Conditions








(YPaint_Target has buff YPaint_BUFF_SLOW) Equal to True







Then - Actions








-------- target still had buff at the end of the duration; manually remove slow and snare the target --------








Unit - Remove YPaint_BUFF_SLOW buff from YPaint_Target








-------- --------








Custom script: call SetUnitX(udg_YPaint_DummyCaster, GetUnitX(udg_YPaint_Target))








Custom script: call SetUnitY(udg_YPaint_DummyCaster, GetUnitY(udg_YPaint_Target))








Unit - Set level of YPaint_ABILITY_SNARE for YPaint_DummyCaster to (Load YPaint_KEY_ABILITY_LVL of YPaint_UnitId from PBomb_Hash)








Unit - Order YPaint_DummyCaster to Night Elf Keeper Of The Grove - Entangling Roots YPaint_Target







Else - Actions








-------- target loss the debuff; do nothing --------






-------- --------






Special Effect - Destroy (Load YPaint_KEY_SFX of YPaint_UnitId in PBomb_Hash)






-------- manually removing child keys because other child keys still might be in use --------






Custom script: call RemoveSavedInteger(udg_PBomb_Hash, udg_YPaint_UnitId, udg_YPaint_KEY_ABILITY_LVL)






Custom script: call RemoveSavedReal(udg_PBomb_Hash, udg_YPaint_UnitId, udg_YPaint_KEY_DURATION)






Custom script: call RemoveSavedHandle(udg_PBomb_Hash, udg_YPaint_UnitId, udg_YPaint_KEY_SFX)






-------- --------






Unit Group - Remove YPaint_Target from YPaint_SlowedGroup






Set YPaint_GroupCount = (YPaint_GroupCount - 1)






If (All Conditions are True) then do (Then Actions) else do (Else Actions)







If - Conditions








YPaint_GroupCount Equal to 0







Then - Actions








Trigger - Turn off YPaint_TRIGGER_LOOP_SLOW







Else - Actions








-------- do nothing --------





Else - Actions






-------- target still has the debuff with time left; save duration left --------






Hashtable - Save YPaint_SlowCounter as YPaint_KEY_DURATION of YPaint_UnitId in PBomb_Hash
As far as I know, entries whether written in GUI, JASS, vJASS or Wurst are all judged equally and does not affect the scoring so I think Cokemonkey will give you a fair review.Side note: @Cokemonkey11 is going to hate me after this contest. Give me a fair review and I promise to consider Wurst next year!
This way it is unequivocal which day, date, month & year are being talked about, and most importantly both the time frame & the time zone. (if we use/assume midnight (generally considered the 'end of the day' but technically the beginning of the next), people might assume the 31st is part of it. Or move back from 12 & be a minute late, etc).Saturday, December 30th, 2017, @ 11:59:59PM (GMT 0)
For the record, I didn't start on my entry until the 16th of December because I had school, so I had a lot less time. With that in mind, I agree with the extension. I start school again on the 2nd, but the extra few days will allow me to debug and review my code more thoroughly.say Tuesday, January 2nd, 2018 @ 11:59:59PM (GMT 0) or somesuch