🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
Description:
Summons Big Apus pet to fight for your hero. You can't control him, he can't attack
Apus follow your hero whenever you move.
Once you are attacked or you attack someone, attacked/attacking unit is added to Apus Targets.
Having the Targets causes Apus to charge into them, slowly increasing his movement speed.
If any unit in Apus Targets come too close to Apus, he stomps Target unit dealing up to 25/37/50 damage depending on Apus current movement speed and stuns target for 0.25 seconds.
Every 3 seconds Apus cast Nova at every unit in Apus Targets dealing 25/50/75 damage and slowing movement speed for 2 seconds.
Every 11/10/9 seconds Apus cast FlameStrike in 3/4/5 directions dealing 50/100/150 damage to units from Apus Targets which are in range.
Apus last 70/80/90 seconds.
Apus Config
Events
Map initialization
Conditions
Actions
-------- Ability Type --------
Set A_Spell = Apus
-------- Distance required to remove target from Apus Targets --------
Set A_Area[1] = 1500.00
Set A_Area[2] = 2000.00
Set A_Area[3] = 2500.00
-------- Damage of Ice --------
Set A_Dmg[1] = 25.00
Set A_Dmg[2] = 50.00
Set A_Dmg[3] = 75.00
-------- Cooldown Damage of Ice (In Seconds) --------
Set A_Cooldown[1] = 3.00
Set A_Cooldown[2] = 3.00
Set A_Cooldown[3] = 3.00
-------- Ice Effect --------
Set A_IceEffectString = Abilities\Spells\Undead\FrostNova\FrostNovaTarget.mdl
-------- Ice Attack Type --------
Set A_FreezeAttackType = Spells
-------- Ice Damage Type --------
Set A_FreezeDamageType = Cold
-------- Stomp Damage --------
Set A_Dmg2[1] = 25.00
Set A_Dmg2[2] = 37.00
Set A_Dmg2[3] = 50.00
-------- Distance required to be damaged by Stomp --------
Set A_Area2[1] = 100.00
Set A_Area2[2] = 100.00
Set A_Area2[3] = 100.00
-------- Stomp Effect --------
Set A_StompEffectString = Abilities\Spells\Orc\WarStomp\WarStompCaster.mdl
-------- Stomp Attack Type --------
Set A_StompAttackType = Spells
-------- Stomp Damage Type --------
Set A_StompDamageType = Universal
-------- FlameStrike Damage --------
Set A_Dmg3[1] = 50.00
Set A_Dmg3[2] = 100.00
Set A_Dmg3[3] = 150.00
-------- Area of FlameStrike effect --------
Set A_Area3[1] = 200.00
Set A_Area3[2] = 200.00
Set A_Area3[3] = 200.00
-------- FlameStrike Effect --------
Set A_FlameStrikeEffectString = Abilities\Spells\Other\Incinerate\FireLordDeathExplode.mdl
-------- FlameStrike Attack Type --------
Set A_FlameStrikeAttackType = Spells
-------- FlameStrike Damage Type --------
Set A_FlameStrikeDamageType = Fire
-------- MaxDist3 defines how many FlameStrikes are gonna be created, calculation MaxDist3/Area3 = 5/6/7 --------
Set A_MaxDist3[1] = 800.00
Set A_MaxDist3[2] = 1000.00
Set A_MaxDist3[3] = 1200.00
-------- In how many directions FlameStrike will be created --------
Set A_Directions3[1] = 3
Set A_Directions3[2] = 4
Set A_Directions3[3] = 5
-------- Cooldown FlameStrike (In Seconds) --------
Set A_Cooldown2[1] = 11.00
Set A_Cooldown2[2] = 10.00
Set A_Cooldown2[3] = 9.00
-------- Does Apus require any time limit? --------
Set A_Limit = True
-------- If True, then how long he last? (In Seconds) --------
Set A_Last[1] = 70.00
Set A_Last[2] = 80.00
Set A_Last[3] = 90.00
-------- Distance between Hero and Apus creation point --------
Set A_SpawnArea[1] = 300.00
Set A_SpawnArea[2] = 300.00
Set A_SpawnArea[3] = 300.00
-------- Apus speed while he is calm and following his hero --------
Set A_ApusSpeed[1] = 300.00
Set A_ApusSpeed[2] = 300.00
Set A_ApusSpeed[3] = 300.00
-------- Set Apus size per level --------
Set A_ApusSize[1] = 200.00
Set A_ApusSize[2] = 250.00
Set A_ApusSize[3] = 300.00
-------- Set Apus color per level. It's a percentage value of 255 RGB coloring --------
Set A_ApusColor[1] = 100.00
Set A_ApusColor[2] = 66.00
Set A_ApusColor[3] = 33.00
-------- Unit type of Dummy which cast Stun and Slow --------
-------- If TRUE then Apus destroy trees in range: --------
Set A_DestTreesRange[1] = 200.00
Set A_DestTreesRange[2] = 200.00
Set A_DestTreesRange[3] = 200.00
-------- Loop Time of Loop Trigger --------
Set A_LoopTime = 0.05
Trigger - Add to Apus Loop <gen> the event (Time - Every A_LoopTime seconds of game time)
-------- Loop Time of Movement and Stomp Trigger --------
Set A_LoopTime2 = 0.03
Trigger - Add to Apus Movement and Stomp <gen> the event (Time - Every A_LoopTime2 seconds of game time)
-------- Loop Time of FlameStrike Trigger --------
Set A_LoopTime3 = 0.20
Trigger - Add to Apus FlameStrike <gen> the event (Time - Every A_LoopTime3 seconds of game time)
Apus Cast
Events
Unit - A unit Finishes casting an ability
Conditions
(Ability being cast) Equal to A_Spell
Actions
Set A_Index = (A_Index + 1)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
A_Index Equal to 1
Then - Actions
Trigger - Turn on Apus Loop <gen>
Trigger - Turn on Apus Attack <gen>
Else - Actions
Set A_Caster[A_Index] = (Triggering unit)
Set A_Level[A_Index] = (Level of A_Spell for A_Caster[A_Index])
Set A_CooldownR[A_Index] = A_Cooldown[A_Level[A_Index]]
Set A_Cooldown2R[A_Index] = A_Cooldown2[A_Level[A_Index]]
Custom script: if udg_A_Group[udg_A_Index] == null then
Custom script: set udg_A_Group[udg_A_Index] = CreateGroup()
Custom script: endif
Set A_TempPoint = (Position of A_Caster[A_Index])
Set A_TempPoint2 = (A_TempPoint offset by A_SpawnArea[A_Level[A_Index]] towards (Facing of A_Caster[A_Index]) degrees)
Unit - Create 1 A_UnitType for (Owner of A_Caster[A_Index]) at A_TempPoint2 facing (Facing of A_Caster[A_Index]) degrees
Set A_Apus[A_Index] = (Last created unit)
Animation - Change A_Apus[A_Index]'s size to (A_ApusSize[A_Level[A_Index]]%, A_ApusSize[A_Level[A_Index]]%, A_ApusSize[A_Level[A_Index]]%) of its original size
Animation - Change A_Apus[A_Index]'s vertex coloring to (A_ApusColor[A_Level[A_Index]]%, A_ApusColor[A_Level[A_Index]]%, A_ApusColor[A_Level[A_Index]]%) with 0.00% transparency
Unit - Create 1 A_DummyType for (Owner of A_Caster[A_Index]) at A_TempPoint2 facing Default building facing degrees
Set A_Dummy[A_Index] = (Last created unit)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
A_Limit Equal to True
Then - Actions
Unit - Add a A_Last[A_Level[A_Index]] second Generic expiration timer to A_Apus[A_Index]
Animation - Change A_Apus[A_LoopIndex]'s animation speed to A_AnimSpeed% of its original speed
Set A_Cooldown2R[A_LoopIndex] = (A_Cooldown2R[A_LoopIndex] - A_LoopTime)
Set A_CooldownR[A_LoopIndex] = (A_CooldownR[A_LoopIndex] - A_LoopTime)
Set A_TempPoint = (Position of A_Caster[A_LoopIndex])
Animation - Change A_Apus[A_LoopIndex]'s vertex coloring to ((A_ApusColor[A_Level[A_LoopIndex]] x (A_CooldownR[A_LoopIndex] / A_Cooldown[A_Level[A_LoopIndex]]))%, (A_ApusColor[A_Level[A_LoopIndex]] x (A_CooldownR[A_LoopIndex] / A_Cooldown[A_Level[A_LoopIndex]]))%, A_ApusColor[A_Level[A_LoopIndex]]%) with 0.00% transparency
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(A_TargetUnit[A_LoopIndex] is dead) Equal to True
Then - Actions
Set A_TargetUnit[A_LoopIndex] = (Random unit from A_Group[A_LoopIndex])
Else - Actions
Unit Group - Pick every unit in A_Group[A_LoopIndex] and do (Actions)
Loop - Actions
Set A_TempUnit = (Picked unit)
Set A_TempPoint2 = (Position of A_TempUnit)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
Or - Any (Conditions) are true
Conditions
(Distance between A_TempPoint and A_TempPoint2) Greater than or equal to A_Area[A_Level[A_LoopIndex]]
(A_TempUnit is dead) Equal to True
Then - Actions
Unit Group - Remove A_TempUnit from A_Group[A_LoopIndex]
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
A_CooldownR[A_LoopIndex] Less than or equal to 0.00
Then - Actions
Special Effect - Create a special effect at A_TempPoint2 using A_IceEffectString
Special Effect - Destroy (Last created special effect)
Unit - Cause A_Apus[A_LoopIndex] to damage A_TempUnit, dealing A_Dmg[A_Level[A_LoopIndex]] damage of attack type A_FreezeAttackType and damage type A_FreezeDamageType
Unit - Order A_Dummy[A_LoopIndex] to Human Sorceress - Slow A_TempUnit
Animation - Play A_Apus[A_LoopIndex]'s walk animation
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
A_CooldownR[A_LoopIndex] Less than or equal to 0.00
Then - Actions
Set A_CooldownR[A_LoopIndex] = A_Cooldown[A_Level[A_LoopIndex]]
Set A_TargetUnit[A_LoopIndex] = (Random unit from A_Group[A_LoopIndex])
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Apus Movement and Stomp <gen> is on) Equal to False
Then - Actions
Trigger - Turn on Apus Movement and Stomp <gen>
Else - Actions
Else - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
A_Cooldown2R[A_LoopIndex] Less than or equal to 0.00
Then - Actions
Set A_Cooldown2R[A_LoopIndex] = A_Cooldown2[A_Level[A_LoopIndex]]
Set A_MaxDist3_2[A_LoopIndex] = 0.00
Set A_FreezePos[A_LoopIndex] = (Position of A_Apus[A_LoopIndex])
Unit - Create 1 A_UnitType for (Owner of A_Caster[A_LoopIndex]) at A_FreezePos[A_LoopIndex] facing (Facing of A_Apus[A_LoopIndex]) degrees
Set A_ApusShadow[A_LoopIndex] = (Last created unit)
Animation - Change A_ApusShadow[A_LoopIndex]'s size to ((A_ApusSize[A_Level[A_LoopIndex]] x 1.50)%, (A_ApusSize[A_Level[A_LoopIndex]] x 1.50)%, (A_ApusSize[A_Level[A_LoopIndex]] x 1.50)%) of its original size
Animation - Change A_ApusShadow[A_LoopIndex]'s vertex coloring to (100.00%, 0.00%, 0.00%) with 50.00% transparency
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
A_DestTreesBool Equal to True
Then - Actions
Destructible - Pick every destructible within A_DestTreesRange[A_Level[A_LoopIndex]] of A_TempPoint3 and do (Actions)
Loop - Actions
Set A_TempDest = (Picked destructible)
Unit - Order A_Peasant to Harvest A_TempDest
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Current order of A_Peasant) Equal to (Order(harvest))
Then - Actions
Destructible - Kill A_TempDest
Else - Actions
Unit - Order A_Peasant to Stop
Else - Actions
Unit Group - Pick every unit in A_Group[A_LoopIndex] and do (Actions)
Loop - Actions
Set A_TempUnit = (Picked unit)
Set A_TempPoint = (Position of A_TempUnit)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Distance between A_TempPoint and A_TempPoint3) Less than or equal to A_Area2[A_Level[A_LoopIndex]]
(A_TempUnit is alive) Equal to True
Then - Actions
Special Effect - Create a special effect attached to the foot of A_TempUnit using A_StompEffectString
Special Effect - Destroy (Last created special effect)
Unit - Cause A_Apus[A_LoopIndex] to damage A_TempUnit, dealing (A_LoopTime2 x (A_Dmg2[A_Level[A_LoopIndex]] x (Square root(((A_ApusXVelo[A_LoopIndex] x A_ApusXVelo[A_LoopIndex]) + (A_ApusYVelo[A_LoopIndex] x A_ApusYVelo[A_LoopIndex])))))) damage of attack type A_StompAttackType and damage type A_StompDamageType
Unit - Order A_Dummy[A_LoopIndex] to Human Mountain King - Storm Bolt A_TempUnit
Unit - Remove A_ApusShadow[A_LoopIndex] from the game
Set A_ApusShadow[A_LoopIndex] = No unit
Else - Actions
Set A_MaxDist3_2[A_LoopIndex] = (A_MaxDist3_2[A_LoopIndex] + A_Area3[A_Level[A_LoopIndex]])
For each (Integer A_TempC) from 1 to A_Directions3[A_Level[A_LoopIndex]], do (Actions)
Loop - Actions
Set A_TempPoint2 = (A_FreezePos[A_LoopIndex] offset by A_MaxDist3_2[A_LoopIndex] towards (((Real(A_TempC)) x (360.00 / (Real(A_Directions3[A_Level[A_LoopIndex]])))) - (360.00 / (2.00 x (Real(A_Directions3[A_Level[A_LoopIndex]]))))) degrees)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
A_DestTreesBool Equal to True
Then - Actions
Destructible - Pick every destructible within A_DestTreesRange[A_Level[A_LoopIndex]] of A_TempPoint2 and do (Actions)
Loop - Actions
Set A_TempDest = (Picked destructible)
Unit - Order A_Peasant to Harvest A_TempDest
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Current order of A_Peasant) Equal to (Order(harvest))
Then - Actions
Destructible - Kill A_TempDest
Else - Actions
Unit - Order A_Peasant to Stop
Else - Actions
Special Effect - Create a special effect at A_TempPoint2 using A_FlameStrikeEffectString
Special Effect - Destroy (Last created special effect)
Set A_TempGroup = (Units within A_Area3[A_Level[A_LoopIndex]] of A_TempPoint2 matching (((Matching unit) is in A_Group[A_LoopIndex]) Equal to True))
Unit Group - Pick every unit in A_TempGroup and do (Actions)
Loop - Actions
Set A_TempUnit = (Picked unit)
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(A_TempUnit is alive) Equal to True
Then - Actions
Unit - Cause A_Apus[A_LoopIndex] to damage A_TempUnit, dealing A_Dmg3[A_Level[A_LoopIndex]] damage of attack type A_FlameStrikeAttackType and damage type A_FlameStrikeDamageType
1.0: Initial realise
1.1:
Changed "Casting unit" into "Triggering unit"
Added Attack and Damage types into configurable variables.
Added Dummy Unit type into configurable variable.
Changed Index variables into variables without arrays
Improved Apus movement
Now there is only 1 Apus Unit type, it's size and color can be configured via Config trigger
Now there is only 1 dummy which cast Slow and Stun per instance instead of creating 1 unit per target
Changed Stomp effect attachment from Apus to target unit. Apus size increasing do not affect its size, no lag possibilities
Some code optimalization.
1.2:
Apus is now able to destroy trees. It's configurable.
More code optimalization
1.3:
Removed imports from test map.
Fixed some code.
1.4:
Small fix.
1.5:
Added prefixes to variable names.
Shadow animation index is configurable.
How to import:
- Make sure to enable "Automatically create unknown variables while pasting trigger data" on the General tab of your World Editor Preferences.
- Copy all abilities and units from Object Editor and paste it into yours.
- Copy the whole Apus folder and paste in onto your Trigger Editor.
- Make sure to configure everything in the Apus Config Trigger.
Give credits if you use it anywhere.
Suggestions:
Ultimate Explosion Model made by WILL THE ALMIGHTY as a FlameStrike effect
TaurenDruidCat model made by AhhFreshWeeD as Apus model
Set A_Group[Index[1]] = (Random 0 units from (Units in (Playable map area)))
^Use custom script and CreateGroup() over this.
The unit's movement looks very unnatural. It should be improved.
It sticks to the hero like a bubble gum, it looks really weird. The following behaviour should be more intuitive.
You should let a tolerance distance for example.
The movement animations looks not smooth.
When the Apus uses spells he should make some animation, that indicates it for example.
At the moment the spell just occurs, but you can't clearly notice that the source is the Apus.
Don't make the Max/Current index variables be an array. It gets unreadable.
Use the normal function in GUI to check if a unit is dead.
Check to turn off loops should be done onDeindex.
A tooltip is needed. Add a decent description.
Reals don't need to be nulled.
It would be cool if the different Apus would have diffent scale/colour for example for each level, so you can differ them.
((Execution count of (This trigger)) mod 20) Equal to 0
^I'm sure you can find a smarter way to solve this.
The idea of such a helper creep is good. But it needs some work to do, for example the weird movement.
Wow I didn't expect to receive any feedback after all this time Thanks for that.
Have you got any idea how to copy triggers translated? I'm using Polish version of world editor and I have to translate every GUI action into english. That makes my update really long.
I made them an arrays because I'm making all spells using only 2 Index variables: Index and Loop Index. Every spell has its own array index in index so i don't have to create new variables for indexes.
If I don't null them, when all instances of spell are finished, then new instance has those reals copied from previous instance. Apus created in new instance might have higher movement speed than expected.
Custom script: set udg_A_Group[udg_A_Index] = CreateGroup()
into this ->
Custom script: if udg_A_Group[udg_A_Index] == null then
Custom script: set udg_A_Group[udg_A_Index] = CreateGroup()
Custom script: endif
to prevent leak.
For deindex in loop, just check "caster[index] is dead == ture Or time < 0". Will be enough. And first check won't be needed then if caster is dead.
Remove Apus onDeindex, or set it's death type to "can't raise, won't decay" in object editor.
onDeindex you forgot about the dummy.
onDeindex you forgot all the spell variable arrays. (flame strike variables, stomp)
onDeindex you have to null all units and the group of MaxIndex.
When Apus is close caster you keep forcing to play the stand animation:
Animation - Play A_Apus[A_LoopIndex]'s stand animation
This makes the stand look a bit unnatural. (at least I think so )
You could try following instead, it might look smoother:
Animation - Queue A_Apus[A_LoopIndex]'s stand animation
Set TempPoint4 = (TempPoint3 offset by (300.00 x A_LoopTime) towards (Angle from TempPoint3 to TempPoint2) degrees)
^Why do you makke the offset depend on the looptime?
onAttack "AttackedUnit" and "AttackingUnit" should be stored into temp variables.
Instead of using modulo, you always could reset the counter? Not?
You should try with looptime 0.03 instead of 0.02. It's the recommended time for movement systems.
Needs Fix
Edit:
If you have to translate each single trigger into english, you don't have to bother to keep the code up to date until approval.
It will be ok for me to check the triggers in map. So it saves you some work.
But once it gets approved, there should be the newest code in description.
If you accept this, then please at least mark that the triggers in description are not up to date.
If you have to translate each single trigger into english, you don't have to bother to keep the code up to date until approval.
It will be ok for me to check the triggers in map. So it saves you some work.
But once it gets approved, there should be the newest code in description.
If you accept this, then please at least mark that the triggers in description are not up to date.
Don't use default peasant as dummy unit. Create a new dummy unit. (You can't ensure user didn't modify the default one.)
Immediatly deindex if caster is dead.
Currently "ApusShadow" must be dead, too. In my understanding this is not wanted, or am I wrong?
If caster is dead, and "ApusShadow" alive, you still want to do further operations?
onDeindex you null now all units and the group. But you use the wrong index.
You have to null the variable[maxIndex] not variable[currentIndex] after you copied the data. Otherwise it doesn't make sense.
Are these imports really needed? It's always better to have as less imports as possible, or none at all.
If you think you can, then you should make them optional. (you still can recommend them here on hive in your description)
I found a bug, when ApusShadow is alive and Apus timer expires. Instance is finished but ApusShadow is still alive, not removed. That's just to prevent that bug. Even if caster is dead, spell will last up to 1.4 more seconds before ApusShadow die. Then he dies and instance is finished. Look that ApusShadow not equal to Apus. ApusShadow is the red one while casting FlameStrike.
Hm, have you changed something with the movement behaviour? It does seem to have problems with followting the hero.
It prefers to fight enemies now, instead of staying close next to caster.
When you change the unit's size only the first only the first argument matters. You can let the others "0": SetSize(size, 0, 0)
In demo map my FPS tempory decreased to ~15 when fighting. Is it only me who has problems/lags with it?
Edit: The tooltip seems too long and is not well structured. You should try to keep only the most important.
I havent noticed and problems with following the hero. Apus now do not go directly towards caster position, it goes to position behind caster. It looks more smooth now. Same as activating, deactivating movement happens while caster is too far from Apus.
I had no FPS drop like you. It was about 60 whole the time.
Have you downloaded the latest version I uploaded?
In main loop don't do any further operations if you deindex.
You get this done by putting the other block into the "Else - Actions" part. (since deindex is in "Then - Actions" part)
Else you do the actions twice for one instance. Though it is possible.
Also in main loop, in your damage part. Only damage, slow, and create the effect above a target if it's not dead and is in range.
Currently you filter these kind of units and remove them from group, but still do named operations to it.
I see your point with casting FlameStrike. So you have to find a solution.
Hm, but definitly ignore further operations that belong to caster or damaging nearby units if caster is dead.
Still you may wait until the shadow unit finished his spell if you want, until you completly deindex.
Better way would to make them more independant from each other, but it would take much more restructering.
I see your point with casting FlameStrike. So you have to find a solution.
Hm, but definitly ignore further operations that belong to caster or damaging nearby units if caster is dead.
Still you may wait until the shadow unit finished his spell if you want, until you completly deindex.
Better way would to make them more independant from each other, but it would take much more restructering.
It might be nitpicking, but if unit type is configurable and animation index is hardcoded it's definitly a mistake in coding.
It's even very quick to fix. Don't be lazy also in small updates.
Well for variables... just use the prefix for all variables that are used by your system. For testmap doesn't matter.
I would work on tooltip if I was you. It's too long, and should be reduced to most important.
Please also note to import dummy unit. I know you will do it.
Edit:
I updated your triggers in description. You don't need to bother with translating. edo494 was so friendly and provided the english bb code for it.
Test map has a tooltip how to import. Added the same tooltip in the first post.
Description is a little shorter. In my opinion these information are the most important so the user knows how this spell works
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.