• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Zephyr Challenge #7 - Nature

Status
Not open for further replies.
Level 17
Joined
Jun 17, 2010
Messages
2,275
Eccho, I don't care tbh.
It looks fine IMO. Not the best, but oh well. :)

InfinateAnswers,
...And do you need me to google it for you?
Reconciliation - an act of reconciling or the state of being reconciled.
Reconcile - to compose or settle (a quarrel, dispute, etc.).
It's not that hard to google it. Most browsers have a little box in a corner where you can instantly use google anyways.

oh nvm i was pronouncing it wrong... haha i know what that word means
 
Level 6
Joined
Oct 10, 2009
Messages
1,425
My Final Submission (updated)

Nature's Reconciliation
A JASS spell by CWeener
MUI & Leakless
icons_10785_btn.jpg

(NOTE: they have some grammar/spelling/spacing errors, that are changed in actual submission)
Learn Tooltip:
WC3ScrnShot_071910_235121_01.jpg

Normal Tooltip:
WC3ScrnShot_071910_235125_02.jpg

View attachment Contest Submission.w3x

JASS:
//This is my (constant ABSOLUTE FINAL) submission to the Zephyr Contest#7 
//All of this was by me(except the icon and effect models) and completely my idea. 
//I used JNPG for the coding.
//          Credits:
//          Vexorian: for this awesome program(JNPG).
//          -BerZeKeR-: for his awesome icon.
//          WILL THE ALMIGHTY: for his awesome explosion model.
//          Blizzard: for the other model effects, and war3 of course.

constant function RAWCODEABILITY takes nothing returns integer
    return 'XYYY'//Raw code of the casting spell
endfunction
constant function RAWCODEENT takes nothing returns integer
    return 'e000'//Rawcode of the ancient protector
endfunction
constant function DUMMYABILITY takes nothing returns integer
    return 'AEer'//Rawcode of entangling roots
endfunction 
constant function DUMMYRAW takes nothing returns integer
    return 'yyyy'//Rawcode of dummy unit (who casts entangling roots)
endfunction

function Damage_Tree takes integer level returns integer
    return level *110//Damage per level.
endfunction

function Damage_Splash takes integer level returns real
    return Damage_Tree(level)/3.000//Splash damage based on 1/3 of the  target damage.
endfunction
   
function Conditions_Tree takes nothing returns boolean
    return GetSpellAbilityId() == RAWCODEABILITY()//Conditions.
endfunction

function Targets_S takes unit target returns boolean//Defines the targets                                                                                                                                                                       
        return (GetWidgetLife(target) > 0.405) and (IsUnitType(target, UNIT_TYPE_STRUCTURE) == false) and (IsUnit(target,GetTriggerUnit()) == false) and (IsUnitAlly(target,GetOwningPlayer(GetTriggerUnit())) == false)  and (IsUnit(target,GetSpellTargetUnit()) == false)
//Splash damage doesn't affect: dead units, buildings, the caster, allies, or the original targeted unit. 
endfunction

function Pick takes nothing returns boolean//Picks the units filtered by function Targets_S
    return Targets_S(GetFilterUnit())
endfunction

//The spells main code.
function Trig_Tree_Attack_Actions takes nothing returns nothing
    local unit U = GetTriggerUnit()
    local unit target = GetSpellTargetUnit()
    local real Y = GetSpellTargetY()
    local real X = GetSpellTargetX()
    local integer level = GetUnitAbilityLevel(U,RAWCODEABILITY())
    local unit Dummy
    local unit Tree
    local group SplashT = CreateGroup()
    local boolexpr b = Condition(function Pick) 
    local string EntEff1 = "Objects\\Spawnmodels\\NightElf\\EntBirthTarget\\EntBirthTarget.mdl"//Effect made on the ent when spawned.
    local string TarEff1 = "notnamed.mdl"//Damaging effect by -BeRsErKeR-
    local string SplashEff1 = "Units\\NightElf\\Wisp\\WispExplode.mdl"//Effect made on the splash targets.
    call GroupEnumUnitsInRange(SplashT,X,Y,200.,b)//Creates the splash target group for later use
    set Tree = CreateUnit(GetOwningPlayer(U),RAWCODEENT(),X,(Y+250),0.00)//Creates the tree.
        call DestroyEffect(AddSpecialEffect(EntEff1,GetUnitX(Tree),GetUnitY(Tree)))
        call UnitApplyTimedLife(Tree,'BTLF',3)
        call IssueTargetOrder(Tree,"attack",target)
    set Dummy = CreateUnit(GetOwningPlayer(U),DUMMYRAW(),X,(Y-50),0.00)//Creates the dummy unit to cast entangling roots
        call UnitAddAbility(Dummy,DUMMYABILITY())
        call SetUnitAbilityLevel(Dummy,DUMMYABILITY(),GetUnitAbilityLevel(U,RAWCODEABILITY()))
        call IssueTargetOrder(Dummy,"entanglingroots",target)
        call UnitApplyTimedLife(Dummy,'BTLF',2)
    set Dummy = null
        call TriggerSleepAction(.82)
    call UnitDamageTarget(U,target,Damage_Tree(level),true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)//makes sure that the killing unit == the casting unit.
    call DestroyEffect(AddSpecialEffect(TarEff1,GetUnitX(target),GetUnitY(target)))
    call RemoveUnit(Tree)
    set target = null
        loop
            set target = FirstOfGroup(SplashT)
            exitwhen target == null
                call UnitDamageTarget(U,target,Damage_Splash(level),true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,WEAPON_TYPE_WHOKNOWS)//makes sure that the killing unit == the casting unit.
                call DestroyEffect(AddSpecialEffectTarget(SplashEff1,target,"origin"))
                call GroupRemoveUnit(SplashT,target)
        endloop
    set Tree = null
    set U = null
    set target = null
    call DestroyGroup(SplashT)
endfunction

//===========================================================================
function InitTrig_Natures_Reconciliation takes nothing returns nothing
    local trigger T = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(T, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddAction(T, function Trig_Tree_Attack_Actions )
    call TriggerAddCondition(T,Condition(function Conditions_Tree))
endfunction

Credits:
Icon by: -BerZeKeR-
Explosion model by: WILL THE ALMIGHTY
Everything Else by: CWeener


Due to time, this is my ABSOLUTE FINAL submission.
No changes will be made. None.


Added a splash effect that deals 1/3 of the initial damage, to units in 200 range of the target unit.
Fixed 2 leaks.
Added some documentation.
 
Last edited:
Level 23
Joined
Nov 29, 2006
Messages
2,482
Woah well, it's about <<46>> hours left everyone.

Now dammit, I demand you do not judge the spell based on the video. It is only a preview.
[highlight]Try everyone's spells! D:[/code]

Edit: YES I forgot to say. The spell is written in Zinc. It requires JNGP to open, and preferrably the latest jasshelper.
Edit 2: YES, the spell is heavily documentated, but really, if that is going to affect anything, it would be unfair. The documentation is not there entirely for you judges or for all you well experienced users...
Edit 3: YES, I updated my spell abit. Minor stuff edited.

Some small things are changed now, such as a new name.
Here is my submission!


banish.gif
Pollination

Covers the area with sprouts, pollinating nearby organic enemy ground units, dealing damage over time.
If a unit dies under the effect of pollination, new sprouts will appear from its corpse.
Lasts 8 seconds.



Level 1 - 100 area damage, 20 damage/second.
Level 2 - 200 area damage, 30 damage/second.
Level 3 - 300 area damage, 40 damage/second.

Does not stack.

//===========================================================================
//*************************** POLLINATION *********************************
// Zephyr Challenger #7 entry
// http://www.hiveworkshop.com/forums/arena-226/zephyr-challenge-7-a-170461/
//
// Revision 2 (2010-07-21)
//
// 1. Description
// Short speaking, the spell covers a field with the desired plants
// and/or flowers, which will initially damage enemy units. Then,
// those units are becoming pollinated and takes damage over time,
// (if not pollinated already by another cast). If a unit die while
// under the effect, it will cover a smaller area around him and the
// process goes on in a cycle more or less, unless a unit manages to
// survive the pollination, or if it explodes.
//
// 2. Custom resources/code
// This spell requires xebasic, xefx and xepreload, all created by
// Vexorian (and thus credit). However, I had to make a modification in
// xefx, as I needed to get the dummy unit itself. Info is in the top
// of the xefx library.
//
// A dummy unit model is imported at war3mapImported\dummy.mdx
// I think it was made by Vexorian.
//
// Additionally, below is the native UnitAlive declared.
//
// 3. Worth knowing
// Altering the constants to be too high of value (ex. NOVA_END_RADIUS)
// would potentially make the spell to lag. This is, due to the amount
// of flowers that are actually generated during the nova effect.
//
// When units die and still are pollinated by the spell, there is no way
// to remove the blossom buff/ability from the dead unit. Additionally,
// if a unit is being summoned (ex. with the Resurrection spell) it is
// checked if it has the blossom buff, and then removed if that is the
// case. The same matter goes to heroes, but instead, will be checked
// using another event (EVENT_PLAYER_HERO_REVIVE_FINISH).
//
// The primary nova will deal full damage as explained in the tooltip.
// The second and following novas will always deal lesser damage and
// have a smaller radius if not defined something else (Right now they
// seem to work pretty well/balanced having half of the range and half
// of the damage. But ofcourse that could be a matter of taste. It do
// eliminate problems which would be lag, though.
//
// The damage over time does not stack. This means if a unit is
// already pollinated, it wont suffer from a new bufflevel, damage or
// increased duration. However, ofcourse the nova damage still applies.
//
// If a unit explodes, it will not trigger a new nova.
//
// All in all, these should all work as intended and should not cause
// any bugs in the spell.
//
// 4. Importing
// If you want to use this in your map, you need the following:
// Import war3mapImported\dummy.mdx
// Copy the universal dummy found in the object/unit editor
// Copy this trigger to your map
// Copy the xefx, xebasic and the xepreload triggers to your map
// Copy the Pollination ability and the Pollination (Target) passive
// ability, and aswell the Pollination (Target) buff.
// Make sure all constants below and in the external libraries, matches
// your desired ones.
//
// 5. Other
// Thanks to Kael och Ragingspeedhorn for being suggestive and
// supporting.
//
// Signed (2010-07-21)
// By Eccho - Give credits if used!
//===========================================================================

--preview.png
 

Attachments

  • Pollination-Zephyr7-Eccho-rev2.w3x
    54.8 KB · Views: 167
Last edited:
Level 6
Joined
Oct 10, 2009
Messages
1,425
Looks really cool Eccho.
IMO, you'll win based on the entries I've seen. Including mine :p

I'm really eager to know how you did some of the effects. They look really good.

Damn you. and you being able to use VJass.
I wish I could of.

:/
Yeah...you'll win.
I'm voting for you too.
 
Level 7
Joined
Dec 19, 2009
Messages
249
Final Submission

-Mysterious Fruit-

Forest Protector use his mystical power to produce some dangerous "fruit" which are thrown at a random place around the tree when they are ready. When they fall on the ground they release mysterious poisonous juice which give a curse to the misfortuned enemies stand close, 25% to Paralyze, 25% to Blind , 25% to Slow and 25% to heal the enemy . The tree can only make ten fruit then he need to recharge his power.
Level #1:paralyze for 3 seconds / Blind 80 % miss / Heal 25 HP / Slow 50%.
Level #2: Paralyze for 4 seconds / Blind 90 % miss / Heal 50 HP/ Slow 75%.
Level #3:paralyze for 5 seconds / Blind 100 % / Heal 75 HP / Slow 100%.
Cooldown 12/11/10 seconds.


View attachment Klingo's Contest Submission.w3x



  • MF Init
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Mysterious Fruit
    • Actions
      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
        • If - Conditions
          • A[2] Equal to 0
        • Then - Actions
          • Trigger - Turn on MF Periodic 001 <gen>
          • Trigger - Turn on MF Periodic 002 <gen>
        • Else - Actions
      • Set A[1] = (A[1] + 1)
      • Set A[2] = (A[2] + 1)
      • Set MFBlindAbility = Blind
      • Set MFSlowAbility = Slow
      • Set MFParalyzeAbility = Paralizer
      • Set MFMainAbility = Mysterious Fruit
      • Set MFAOE = 250.00
      • Set MFSpeed = 20.00
      • Set MFChances = 0
      • Set MFLevel[A[1]] = (Level of MFMainAbility for MFCaster[A[1]])
      • Set MFCaster[A[1]] = (Triggering unit)
      • Set MFPlayer[A[1]] = (Owner of MFCaster[A[1]])
      • Set MFCount[A[1]] = 0
      • Unit Group - Add MFCaster[A[1]] to MFCasterGroup[A[1]]
      • Special Effect - Create a special effect attached to the chest of MFCaster[A[1]] using Abilities\Spells\Undead\DarkSummoning\DarkSummonMissile.mdl
      • Set MFSpecialEffect[A[1]] = (Last created special effect)
  • MF Periodic 001
    • Events
      • Time - Every 1.50 seconds of game time
    • Conditions
    • Actions
      • For each (Integer A[3]) from 1 to A[1], do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (MFCasterGroup[A[3]] is empty) Equal to False
            • Then - Actions
              • Set MFCount[A[3]] = (MFCount[A[3]] + 1)
              • Unit Group - Pick every unit in MFCasterGroup[A[3]] and do (Actions)
                • Loop - Actions
                  • Set MFRandomAngle = 0.00
                  • Set MFRandomOffset = 0.00
                  • Set MFCaster[A[3]] = (Picked unit)
                  • Set MFCasterPoint[A[3]] = (Position of MFCaster[A[3]])
                  • Set MFCasterPoint2[A[3]] = (MFCasterPoint[A[3]] offset by 100.00 towards (Facing of MFCaster[A[3]]) degrees)
                  • Set MFRandomAngle = (Random angle)
                  • Set MFRandomOffset = (Random real number between 106.00 and 350.00)
                  • Set MFHealing[A[3]] = (25.00 x (Real(MFLevel[A[3]])))
                  • Set MFRandomPoint[A[3]] = (MFCasterPoint2[A[3]] offset by MFRandomOffset towards MFRandomAngle degrees)
                  • Set MFDist[A[3]] = (Distance between MFCasterPoint2[A[3]] and MFRandomPoint[A[3]])
                  • Set MFFlyingHeighMax[A[3]] = ((Square root(MFDist[A[3]])) / (MFDist[A[3]] / 15.00))
                  • Set MFRandomReal[A[3]] = (Distance between MFCasterPoint2[A[3]] and MFRandomPoint[A[3]])
                  • Set MFRandomReal2[A[3]] = (MFFlyingHeighMax[A[3]] x MFRandomReal[A[3]])
                  • Set MFParabolicMovement[A[3]] = 0.00
                  • Unit - Create 1 [Fruit] for MFPlayer[A[3]] at MFCasterPoint[A[3]] facing 0.00 degrees
                  • Set MFFruit[A[3]] = (Last created unit)
                  • Unit Group - Add MFFruit[A[3]] to MFFruitGroup[A[3]]
                  • Animation - Change MFFruit[A[3]]'s size to (200.00%, 200.00%, 200.00%) of its original size
                  • Unit - Add Corbeau to MFFruit[A[3]]
                  • Unit - Remove Corbeau from MFFruit[A[3]]
                  • Animation - Change MFFruit[A[3]] flying height to 75.00 at 0.00
                  • Custom script: call RemoveLocation(udg_MFCasterPoint[udg_A[3]])
                  • Custom script: call RemoveLocation(udg_MFCasterPoint2[udg_A[3]])
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • MFCount[A[3]] Equal to 10
                • Then - Actions
                  • Special Effect - Destroy MFSpecialEffect[A[3]]
                  • Unit Group - Remove MFCaster[A[3]] from MFCasterGroup[A[3]]
                  • Set A[2] = (A[2] - 1)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • A[2] Equal to 0
                    • Then - Actions
                      • Set A[1] = 0
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • ((MFCasterGroup[A[3]] is empty) Equal to True) and ((MFFruitGroup[A[3]] is empty) Equal to True)
                        • Then - Actions
                          • Trigger - Turn off (This trigger)
                          • Trigger - Turn off MF Periodic 002 <gen>
                        • Else - Actions
                    • Else - Actions
                • Else - Actions
            • Else - Actions
  • MF Periodic 002
    • Events
      • Time - Every 0.03 seconds of game time
    • Conditions
    • Actions
      • For each (Integer A[4]) from 1 to A[3], do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (MFFruitGroup[A[4]] is empty) Equal to False
            • Then - Actions
              • Unit Group - Pick every unit in MFFruitGroup[A[4]] and do (Actions)
                • Loop - Actions
                  • Set MFFruit[A[4]] = (Picked unit)
                  • Set MFFruitPoint = (Position of MFFruit[A[4]])
                  • Set MFDist[A[4]] = (MFDist[A[4]] - MFSpeed)
                  • Set MFMovingPoint = (MFFruitPoint offset by MFSpeed towards (Angle from MFFruitPoint to MFRandomPoint[A[4]]) degrees)
                  • Unit - Move MFFruit[A[4]] instantly to MFMovingPoint
                  • Set MFParabolicMovement[A[4]] = (MFParabolicMovement[A[4]] + (180.00 / (MFRandomReal[A[4]] / MFSpeed)))
                  • Set MFFlyingHeigh[A[4]] = ((Sin(MFParabolicMovement[A[4]])) x MFRandomReal2[A[4]])
                  • Animation - Change MFFruit[A[4]] flying height to MFFlyingHeigh[A[4]] at 0.00
                  • Custom script: call RemoveLocation(udg_MFFruitPoint)
                  • Custom script: call RemoveLocation(udg_MFMovingPoint)
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • MFDist[A[4]] Less than or equal to 0.00
                    • Then - Actions
                      • Unit - Kill MFFruit[A[4]]
                      • Unit - Create 1 [Juice] for MFPlayer[A[4]] at MFRandomPoint[A[4]] facing 0.00 degrees
                      • Set MFJuice = (Last created unit)
                      • Unit - Add a 2.00 second Generic expiration timer to MFJuice
                      • Animation - Change MFJuice's size to (100.00%, 100.00%, 100.00%) of its original size
                      • Set MFTargetGroup = (Units within MFAOE of MFRandomPoint[A[4]])
                      • Unit Group - Pick every unit in MFTargetGroup and do (Actions)
                        • Loop - Actions
                          • Set MFTarget = (Picked unit)
                          • Set MFTargetPoint = (Position of MFTarget)
                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                            • If - Conditions
                              • And - All (Conditions) are true
                                • Conditions
                                  • (MFTarget is A structure) Equal to False
                                  • (MFTarget is A flying unit) Equal to False
                                  • (MFTarget is Mechanical) Equal to False
                                  • (MFTarget is An Ancient) Equal to False
                                  • (MFTarget is Magic Immune) Equal to False
                                  • (MFTarget belongs to an enemy of MFPlayer[A[4]]) Equal to True
                            • Then - Actions
                              • Set MFChances = (Random integer number between 0 and 100)
                              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                • If - Conditions
                                  • MFChances Less than or equal to 25
                                • Then - Actions
                                  • Unit - Create 1 [Stunner] for MFPlayer[A[4]] at MFTargetPoint facing MFTargetPoint
                                  • Set MFCurse = (Last created unit)
                                  • Unit - Add MFParalyzeAbility to MFCurse
                                  • Unit - Set level of MFParalyzeAbility for MFCurse to MFLevel[A[4]]
                                  • Unit - Order MFCurse to Human Mountain King - Storm Bolt MFTarget
                                  • Unit - Add a 2.00 second Generic expiration timer to MFCurse
                                • Else - Actions
                                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                    • If - Conditions
                                      • (MFChances Greater than 25) and (MFChances Less than or equal to 50)
                                    • Then - Actions
                                      • Unit - Create 1 [Stunner] for MFPlayer[A[4]] at MFTargetPoint facing MFTargetPoint
                                      • Set MFCurse = (Last created unit)
                                      • Unit - Add MFBlindAbility to MFCurse
                                      • Unit - Set level of MFBlindAbility for MFCurse to MFLevel[A[4]]
                                      • Unit - Order MFCurse to Undead Banshee - Curse MFTarget
                                      • Unit - Add a 2.00 second Generic expiration timer to MFCurse
                                    • Else - Actions
                                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                        • If - Conditions
                                          • (MFChances Greater than 50) and (MFChances Less than or equal to 75)
                                        • Then - Actions
                                          • Unit - Create 1 [Stunner] for MFPlayer[A[4]] at MFTargetPoint facing MFTargetPoint
                                          • Set MFCurse = (Last created unit)
                                          • Unit - Add MFSlowAbility to MFCurse
                                          • Unit - Set level of MFSlowAbility for MFCurse to MFLevel[A[4]]
                                          • Unit - Order MFCurse to Human Sorceress - Slow MFTarget
                                          • Unit - Add a 2.00 second Generic expiration timer to MFCurse
                                        • Else - Actions
                                          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                                            • If - Conditions
                                              • MFChances Greater than 75
                                            • Then - Actions
                                              • Unit - Set life of MFTarget to ((Life of MFTarget) + MFHealing[A[4]])
                                              • Special Effect - Create a special effect attached to the chest of MFTarget using Abilities\Spells\Items\WandOfNeutralization\NeutralizationMissile.mdl
                                              • Special Effect - Destroy (Last created special effect)
                                            • Else - Actions
                              • Custom script: call RemoveLocation(udg_MFTargetPoint)
                              • Custom script: call RemoveLocation(udg_MFRandomPoint[udg_A[4]])
                            • Else - Actions
                      • Unit Group - Remove MFFruit[A[4]] from MFFruitGroup[A[4]]
                    • Else - Actions
            • Else - Actions

 
Last edited:
Level 23
Joined
Nov 29, 2006
Messages
2,482
Beasttrog, like the idea with the terrainchange and such, there I would counter on the MUI-part: Would it really work?

As from what I understood it, you store what terraintype it was before, and then revert it back. There is a potential screwup, that if you first cast the spell at one point, then another unit/player casts it on about the same point, the latter one could find the terraintype to be the terrain of the previous cast, if you get what I mean. So well, it could revert back to what really was the same as the spells terraintype.

Other than that, I would actaually preferr to call the uber tree, terror root all along the way, or terror tree or something like that. I guess I just dont like how uber sounds in the tooltip:p

And InfinateAnswers, relax, yeah, I wish you better luck next time then :)

Edit:

Klingo, the visual effects works nice for your spell (with some minor things Ill suggest now), but I would suggest that the projectiles was moving abit smoother in the parabola, and perhaps that they dont hit the ground at the z-height of 0. It do look less appealing when only half of them is visible, and the rest of the half is dug in the terrain. And well, you know that I personally hate long tooltips:p, but there were at some place(s?) that you might have put double spaces by accident or so.
 
Level 17
Joined
Jun 17, 2010
Messages
2,275
Beasttrog, like the idea with the terrainchange and such, there I would counter on the MUI-part: Would it really work?

As from what I understood it, you store what terraintype it was before, and then revert it back. There is a potential screwup, that if you first cast the spell at one point, then another unit/player casts it on about the same point, the latter one could find the terraintype to be the terrain of the previous cast, if you get what I mean. So well, it could revert back to what really was the same as the spells terraintype.

Other than that, I would actaually preferr to call the uber tree, terror root all along the way, or terror tree or something like that. I guess I just dont like how uber sounds in the tooltip:p

And InfinateAnswers, relax, yeah, I wish you better luck next time then :)

Edit:

Klingo, the visual effects works nice for your spell (with some minor things Ill suggest now), but I would suggest that the projectiles was moving abit smoother in the parabola, and perhaps that they dont hit the ground at the z-height of 0. It do look less appealing when only half of them is visible, and the rest of the half is dug in the terrain. And well, you know that I personally hate long tooltips:p, but there were at some place(s?) that you might have put double spaces by accident or so.
In german uber means over, so Over Tree?
 
Level 7
Joined
Dec 19, 2009
Messages
249
Klingo, the visual effects works nice for your spell (with some minor things Ill suggest now), but I would suggest that the projectiles was moving abit smoother in the parabola, and perhaps that they dont hit the ground at the z-height of 0. It do look less appealing when only half of them is visible, and the rest of the half is dug in the terrain. And well, you know that I personally hate long tooltips:p, but there were at some place(s?) that you might have put double spaces by accident or so.

Well , I think same for the parabola but don't know how to make it smoother , I'll try to improve (Maybe).

It don't hit when the flying height is 0? I'll change the Speed ^^.

What about the tooltips ? I don't understand.
 
Level 23
Joined
Nov 29, 2006
Messages
2,482
I usually spend about 20-40 hours planning/doing my spell. So for me, it would be very restricted:p I think I usually waste most of my time debugging and by designing the code wrong in the beginning.
 
Level 6
Joined
Oct 10, 2009
Messages
1,425
I usually spend about 20-40 hours planning/doing my spell. So for me, it would be very restricted:p I think I usually waste most of my time debugging and by designing the code wrong in the beginning.

Exact same here.
Except I don't plan.
Usually I'll make a boring spell based on a generic theme and spice it up.
And if I don't do that, then I just have an idea to start, and just do that the best I can.
 
Level 16
Joined
Feb 22, 2006
Messages
960
So here we go my submission, it's fully written in vJass.

Credits go to:
SkriK - Icon
Vexorian - JassHelper/TimerUtils/Tabel
Rising_Dusk - IntuitiveDamageSystem



JASS:
//*******************************************************************************************************************
//* Touch of Nature by xD.Schurke (Zephyr Contest #7 entry)
//* -------------------------------------------------------
//*
//* Requires:
//*          - JassHelper (Latest Version)
//*          - Table 3.0 By Vexorian
//*          - TimerUtils (Blue Flavour) by Vexorian
//*          - IntuitiveDamageSystem 1.13 by Rising_Dusk
//*          - Basis Jass-Knowledge to setup the spell
//*         
//*
//* Other Credits:
//*          - SkriK for the icon
//*
//*
//* About the spell:
//*          Touches an allied unit with the power of nature. The unit regenerates life 
//*          and takes 5% less physical damage. In addition blossoms are spawned for 
//*          5 seconds which can be consumed by anyone. Those blossoms increase the armor 
//*          by 3 and heal the unit over 7.5 seconds for 65 hitpoints.
//*          Level 1 - The touched unit regenerates 100 health points over 10 seconds.
//*          Level 2 - The touched unit regenerates 175 health points over 11 seconds.
//*          Level 3 - The touched unit regenerates 250 health points over 12 seconds.
//*
//*          Cooldown: 15 seconds
//*
//*
//*          - The spell requires some micro to have the optimal use in a battle. 
//*          - The spell is balanced for melee games, only issue is that it uses Inner-Fire buff
//*
//*
//*
//*******************************************************************************************************************
scope TouchOfNature
globals
    //************************************************************************************************
    //* You can change the following variables to fit your needs, or to copy this spell to your map 
    //************************************************************************************************
    
    //*Rawcodes*\\
    private constant    integer         DUMMY_ID                    =   'n001' //Dummy
    private constant    integer         SPELL_ID                    =   'A000' //Spell
    private constant    integer         SPELL_BUFF_ID               =   'B000' //Touch of Nature buff
    private constant    integer         DUMMY_SPELL_ID              =   'A001' //Dummy Spell (Blossoms Gift)
    private constant    integer         DUMMY_SPELL_BUFF_ID         =   'B001' //Blossoms Gift buff
    
    //*Time-related variables*\\
    private constant    real            INTERVAL                    =    0.03125 //Standard timer interval of 32 FPS
    private constant    real            DURATION_BASIS              =   10.00000 //The basis duration of the Touch of Nature buff
    private constant    real            DURATION_BASIS_INC          =    1.00000 //Level duration increase of touch of nature
    private constant    real            DURATION_FLOWER_BASIS       =    5.00000 //Duration of the blossoms (flowers)
    private constant    real            DURATION_FLOWER_BASIS_INC   =    0.00000 //Actually this variable is not needed, but if you want an increase per level, you can change this variable
    private constant    real            GROWTH_DURATION             =    2.00000 //The time in which the flower should grow
    private constant    real            BLOSSOM_DURATION            =    7.50000 //Blossoms Gift buff duration
    
    //*Spell effect variables*\\
    private constant    real            LIFE_REGENERATION           =  100.00000 //The basis life healed of Touch of nature
    private constant    real            LIFE_REGENERATION_INC       =   75.00000 //The level increase of life healed by the spell
    private constant    real            DAMAGE_REDUCE               =    5.00000 //The damage reduction of the spell in percent
    private constant    real            BLOSSOM_HEAL                =   65.00000 //The hitpoints healed by the blossom buff
    
    //*Flower growth stuff*\\
    private constant    real            GROWTH_MAX_SIZE             =    1.00000 //Maximal size of the flower
    private constant    real            GROWTH_START_SIZE           =    0.00 //The start size of the flower
    //!!DO NOT CHANGE!!\\
    private constant    real            GROWTH_VALUE                =   GROWTH_MAX_SIZE/(GROWTH_DURATION/INTERVAL) //How much the flower should grow per interval
    //!!!!!!!!!!!!!!!!!\\
    
    //*Range check variables*\\
    private constant    real            GROWTH_CHECK_RANGE          =   50.00000 //Is used to check if other flowers are grown near the spot
    private constant    real            FLOWER_CHECK_RANGE          =   50.00000 //Is used to find the unit which should be buffed    
    
    private constant    real            GROWTH_ANGLE_RADIUS         =  360.00000 //0 - this angle is used to spawn new flowsers
    
    //*Effect Strings'\\
    private constant    string          FLOWER_DEATH_EFFECT         =   "Abilities\\Spells\\NightElf\\FaerieDragonInvis\\FaerieDragon_Invis.mdl"
    private constant    string          FLOWER_PICK_UP_EFFECT       =   "Abilities\\Spells\\Human\\DispelMagic\\DispelMagicTarget.mdl"
    
    private             string  array   FLOWER_VARIATION                   //This array contains the flower model strings , for more information see setupModelStrings
    private constant    integer         VARIATION_COUNT             =    5 //If u want to add any flower model, or remove any change this variable to the count
    
    //DO NOT change anything bellow this line without any knowledge!
    //Those variables are used for group issues, so the whole spell uses just one group which is only temporaly used
    private             player          tmpP 
    private             unit            tmpU
    private             group           tmpG
    private             boolexpr        FILTER_FLOWER
    private             boolexpr        FILTER_CHECK_FLOWER
endglobals

//This function is used to setup the flower model strings
private function setupModelStrings takes nothing returns nothing
    set FLOWER_VARIATION[0]       =   "Doodads\\Ruins\\Plants\\Ruins_Flower\\Ruins_Flower0.mdl"
    set FLOWER_VARIATION[1]       =   "Doodads\\Ruins\\Plants\\Ruins_Flower\\Ruins_Flower1.mdl"
    set FLOWER_VARIATION[2]       =   "Doodads\\Ruins\\Plants\\Ruins_Flower\\Ruins_Flower2.mdl"
    set FLOWER_VARIATION[3]       =   "Doodads\\Ruins\\Plants\\Ruins_Flower\\Ruins_Flower3.mdl"
    set FLOWER_VARIATION[4]       =   "Doodads\\Ruins\\Plants\\Ruins_Flower\\Ruins_Flower4.mdl"
endfunction

//Function for getting the duration of the spell
private function getDuration takes integer lvl returns real
    return DURATION_BASIS+(DURATION_BASIS_INC*(lvl-1))
endfunction
//Function for getting the duration of the flowers
private function getFlowerDuration takes integer lvl returns real
    return DURATION_FLOWER_BASIS+(DURATION_FLOWER_BASIS_INC*(lvl-1))
endfunction
//Function for calculating the healed amount of the main spell
private function getHealMain takes integer lvl returns real
    return (LIFE_REGENERATION+(LIFE_REGENERATION_INC*(lvl-1)))/(getDuration(lvl)/INTERVAL)
endfunction
//Function for calculating the healed amount of the blossoms
private function getHealBlossom takes nothing returns real
    return BLOSSOM_HEAL/(BLOSSOM_DURATION/INTERVAL)
endfunction
//Filter function used to find a unit which can be buffed
private function GroupFilterFlower takes nothing returns boolean
    return GetUnitAbilityLevel(GetFilterUnit(),DUMMY_SPELL_BUFF_ID) == 0 and (GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE)>0) and IsUnitType(GetFilterUnit(),UNIT_TYPE_GROUND) and (GetUnitTypeId(GetFilterUnit())!= DUMMY_ID) and GetFilterUnit() != tmpU
endfunction
//Filter Function used to check if other flowers are arround
private function GroupFilterFlowerCheck takes nothing returns boolean
    local real dx = GetUnitX(GetFilterUnit()) - GetUnitX(tmpU)
    local real dy = GetUnitY(GetFilterUnit()) - GetUnitY(tmpU)
    return GetUnitState(GetFilterUnit(),UNIT_STATE_LIFE) > 0 and GetUnitTypeId(GetFilterUnit())== DUMMY_ID and SquareRoot(dx * dx + dy * dy) < GROWTH_CHECK_RANGE
endfunction
//Keyword since I decided to declare the FlowerStruct after the MainStruct
private keyword FlowerStruct

//This struct is the one handeling the main part, also this struct contains the initializer method (onInit)
private struct MainStruct
    private         unit        caster      =   null 
    private         unit        target      =   null
    private         real        duration    =   0.0
    //method to check the surrounding area for other flowers
    private method checkFlowers takes nothing returns boolean
        local real x = GetUnitX(this.caster)
        local real y = GetUnitY(this.caster)
        set tmpP = GetOwningPlayer(this.target)
        set tmpU = this.target
        call GroupEnumUnitsOfPlayer(tmpG,tmpP,FILTER_CHECK_FLOWER)
        if FirstOfGroup(tmpG) != null then
            call GroupClear(tmpG)
            return false
        endif
        return true
    endmethod
    //The callback method which is called each interval, heals the target of the spell and copes the flower growth
    private static method callback takes nothing returns nothing
        local timer         tim  = GetExpiredTimer()
        local thistype      this = GetTimerData(tim)
        local real          x    = 0.0
        local real          y    = 0.0
        local real          life = GetUnitState(this.target,UNIT_STATE_LIFE)
        set this.duration    = this.duration + INTERVAL
        call SetUnitState(this.target,UNIT_STATE_LIFE,life+getHealMain(GetUnitAbilityLevel(this.caster,SPELL_ID)))
        if this.checkFlowers() then
            set x = GetUnitX(this.target) + GetRandomReal(0.0,GROWTH_CHECK_RANGE) * Cos(GetRandomReal(0.0,GROWTH_ANGLE_RADIUS) * bj_DEGTORAD)
            set y = GetUnitY(this.target) + GetRandomReal(0.0,GROWTH_CHECK_RANGE) * Sin(GetRandomReal(0.0,GROWTH_ANGLE_RADIUS) * bj_DEGTORAD)
            call FlowerStruct.create(this.caster,this.target,x,y)
        endif
        if this.duration >= getDuration(GetUnitAbilityLevel(this.caster,SPELL_ID)) or GetUnitAbilityLevel(this.target,SPELL_BUFF_ID) == 0 then
            call ReleaseTimer(tim)
            call this.destroy()
        endif
        set tim = null
    endmethod
    
    static method create takes unit caster ,unit target returns thistype
        local thistype this = thistype.allocate()
        local timer tim = NewTimer()
        set this.caster = caster
        set this.target = target
        call SetTimerData(tim,this)
        call TimerStart(tim,INTERVAL,true,function thistype.callback)
        return this
    endmethod
    
    private method onDestroy takes nothing returns nothing
        set this.caster = null
        set this.target = null
    endmethod
    //The following part is used to setup stuff like damage reduction and general struct creation on spell cast
    private static method condition takes nothing returns boolean
        if GetSpellAbilityId() == SPELL_ID then
            call thistype.create(GetTriggerUnit(),GetSpellTargetUnit())
        endif
        return false
    endmethod
    
    private static method damageCondition takes nothing returns boolean
        if GetUnitAbilityLevel(GetTriggerDamageTarget(),SPELL_BUFF_ID) > 0 and GetTriggerDamageType() == DAMAGE_TYPE_ATTACK then
            call SetUnitState(GetTriggerDamageTarget(),UNIT_STATE_LIFE,GetUnitState(GetTriggerDamageTarget(),UNIT_STATE_LIFE)+GetTriggerDamage()*DAMAGE_REDUCE)
        endif
        return false
    endmethod
    
    private static method onInit takes nothing returns nothing
        local trigger trig = CreateTrigger()
        local trigger damageTrig = CreateTrigger()
        call setupModelStrings()
        set  tmpG                =  CreateGroup()
        set  FILTER_FLOWER       =  Condition(function GroupFilterFlower)
        set  FILTER_CHECK_FLOWER =  Condition(function GroupFilterFlowerCheck)
        
        call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(trig,Condition(function thistype.condition))
        
        call TriggerAddCondition(damageTrig,Condition(function thistype.damageCondition))        
        call TriggerRegisterDamageEvent(damageTrig,0)
        set trig = null
    endmethod
endstruct
//This is just a small struct healing the target of a blossom buff, does nothing else
private struct BlossomStruct
    private unit    target      =   null
    private real    duration    =   0.0     
    
    private static method callback takes nothing returns nothing
        local timer         tim  = GetExpiredTimer()
        local thistype      this = GetTimerData(tim)
        local real          life = GetUnitState(this.target,UNIT_STATE_LIFE)
        set this.duration    = this.duration + INTERVAL
        call SetUnitState(this.target,UNIT_STATE_LIFE,life+getHealBlossom())
        if this.duration >= BLOSSOM_DURATION or GetUnitAbilityLevel(this.target,DUMMY_SPELL_BUFF_ID) == 0 then
            call ReleaseTimer(tim)
            call this.destroy()
        endif
        set tim = null
    endmethod
    
    private method onDestroy takes nothing returns nothing
        set this.target = null
    endmethod

    static method create takes unit target returns thistype
        local thistype this = thistype.allocate()
        local timer tim = NewTimer()
        set this.target = target
        call SetTimerData(tim,this)
        call TimerStart(tim,INTERVAL,true,function thistype.callback)
        return this
    endmethod    
endstruct

//The FlowerStruct represents Flower/Blossom objects, it actually checks in the callback method for units arround which can be buffed, and then
//applies the buff to them, look a bit more into it to get a basic knowledge of what I am doing here
private struct FlowerStruct
    private unit    caster      =   null
    private unit    target      =   null
    private unit    dummy       =   null
    private effect  attachement =   null
    private real    duration    =   0.0
    private real    actualSize  =   GROWTH_START_SIZE    
    
    private method checkRange takes nothing returns boolean
        local real x = GetUnitX(this.dummy)
        local real y = GetUnitY(this.dummy)
        local unit pickedUnit = null
        set tmpU = this.target
        set tmpP = GetOwningPlayer(this.target)
        call GroupEnumUnitsInRange(tmpG,x,y,FLOWER_CHECK_RANGE,FILTER_FLOWER)
        if FirstOfGroup(tmpG) != null then
            set pickedUnit = FirstOfGroup(tmpG)
            call UnitAddAbility(this.dummy,DUMMY_SPELL_ID)
            call IssueTargetOrder(this.dummy,"innerfire",pickedUnit)
            call BlossomStruct.create(pickedUnit)
            call GroupClear(tmpG)
            return true
        endif
        call GroupClear(tmpG)
        return false
    endmethod
    
    private static method callback takes nothing returns nothing
        local timer         tim  = GetExpiredTimer()
        local thistype      this = GetTimerData(tim)
        set this.duration = this.duration + INTERVAL
        if this.duration < GROWTH_DURATION then
            set this.actualSize = this.actualSize + GROWTH_VALUE
            call SetUnitScale(this.dummy,this.actualSize,this.actualSize,this.actualSize)
        endif
        if this.checkRange() then
            call DestroyEffect(AddSpecialEffect(FLOWER_PICK_UP_EFFECT,GetUnitX(this.dummy),GetUnitY(this.dummy)))
            call ReleaseTimer(tim)
            call this.destroy()
        elseif this.duration >= getFlowerDuration(GetUnitAbilityLevel(this.caster,SPELL_ID)) then
            call DestroyEffect(AddSpecialEffect(FLOWER_DEATH_EFFECT,GetUnitX(this.dummy),GetUnitY(this.dummy)))
            call ReleaseTimer(tim)
            call this.destroy()
        endif
        set tim = null
    endmethod
    
    static method create takes unit caster, unit target, real x, real y returns thistype
        local thistype this = thistype.allocate()
        local timer tim = NewTimer()
        set this.caster = caster
        set this.target = target
        set this.dummy = CreateUnit(GetOwningPlayer(this.target),DUMMY_ID,x,y,0.0)
        call SetUnitTimeScale(this.dummy,0.0)
        call SetUnitScale(this.dummy,GROWTH_START_SIZE,GROWTH_START_SIZE,GROWTH_START_SIZE)
        call AddSpecialEffectTarget(FLOWER_VARIATION[GetRandomInt(0,VARIATION_COUNT-1)],this.dummy,"origin")
        call SetTimerData(tim,this)
        call TimerStart(tim,INTERVAL,true,function thistype.callback)
        return this
    endmethod
    
    private method onDestroy takes nothing returns nothing
        call DestroyEffect(this.attachement)
        call RemoveUnit(this.dummy)
        set this.attachement = null
        set this.dummy = null
        set this.caster = null
        set this.target = null
    endmethod
endstruct
endscope


Touch of Nature
attachment.php

Touches an allied unit with the power of nature. The unit regenerates life and takes 5% less physical damage.
In addition blossoms are spawned for 5 seconds which can be consumed by anyone. Those blossoms increase the
armor by 3 and heal the unit over 7.5 seconds for 65 hitpoints.

Level 1 - The touched unit regenerates 100 health points over 10 seconds.
Level 2 - The touched unit regenerates 175 health points over 11 seconds.
Level 3 - The touched unit regenerates 250 health points over 12 seconds.

Cooldown: 15 seconds
 

Attachments

  • Nature.png
    Nature.png
    12.7 KB · Views: 575
  • Zephyr Contest #7 xD.Schurke.w3x
    65.8 KB · Views: 92
Last edited:
Level 23
Joined
Nov 29, 2006
Messages
2,482
Don't forget about this.
Balance may result in several points of score.

Atm Eccho, your submission is awfully imbalanced :p

25 mana cost, huge AoE carnage and low cooldown.

Oh bleff, Ghouls are weak units, a level 3 spell is usually very affecting against them, as Ghouls do take extra damage from magic. I guess I should fix the mana cost and cooldown then, and add an extra trigger to reset cooldown/mana for those who are lazy to wait for it while testing.
 
Level 6
Joined
Oct 10, 2009
Messages
1,425
Oh bleff, Ghouls are weak units, a level 3 spell is usually very affecting against them, as Ghouls do take extra damage from magic. I guess I should fix the mana cost and cooldown then, and add an extra trigger to reset cooldown/mana for those who are lazy to wait for it while testing.

Exactly what I did.
Klingo said:
I have a question , Can we loose points if we don't do documentation?
I forgot where, but I'm fairly certain I saw that we needed documentation.
That's why I went back and added some, to be on the safe side.
 
Level 23
Joined
Nov 29, 2006
Messages
2,482
Indeed, funny and creative, but I found a bug. If the caster is in the area of cast, he gets a green effect like the rest of the units, but since he is not slowed, the green effect never disappear.

Also, remove those "goo off", "owls off" messages:p
 
Level 23
Joined
Nov 29, 2006
Messages
2,482
GMT or GMT+0 is London-time. If it is 3AM now GMT+1, then it is 2AM GMT there. Thus, 22 hours left now. Also, don't rely on the time at the bottom of THW. It clearly says GMT+2 for me while it in fact is displaying the time for GMT+1.
 
Level 17
Joined
Jun 17, 2007
Messages
1,433
Here's a WIP (just need to make a few changes) of my spell, 'The Circle of Life'. I haven't finished the tooltip, but a group of missiles move towards a target point and then come back. If they collide with a tree on the way, they will absorb some of the trees energy. Once the spell is finished, all allies within the circle are healed, and all enemies are damaged.
Sorry about the bad video quality.
 
Level 37
Joined
Mar 6, 2006
Messages
9,240
Thanks for the comments. I came from work and improved some things.

*The owls now "dive" to drop the raccoon
*The raccoons now do melee damage
*Documentation
*Made it optional to increase the number of owls/raccoons spawned per target
*Replaced some hashtable thingies with custom scripts - not as many BJ's
*Slow now supports levels
*Only enemies are affected by sap
*Tooltip adjustment
*Owls now faster, over the max of 522
And some things I forgot

Lol maker that idea will get a 100% for creativity xD it would be sick if the owls could dive bomb.

They do now
smoker.gif


But it's 7:50 in the morning, I should get some sleep. I have an away game (football) in another city and work today so this might be my final version.

EDIT: Another update.
 

Attachments

  • Zephyr Challenge #7 - Maker.w3x
    72 KB · Views: 95
Last edited:
Level 23
Joined
Nov 29, 2006
Messages
2,482
Here's a WIP (just need to make a few changes) of my spell, 'The Circle of Life'. I haven't finished the tooltip, but a group of missiles move towards a target point and then come back. If they collide with a tree on the way, they will absorb some of the trees energy. Once the spell is finished, all allies within the circle are healed, and all enemies are damaged.

Bring it on :>

Edit: I took the time to update mine abit. Very minor stuff but still. You can find it here
 
Last edited:
Level 17
Joined
Jun 17, 2007
Messages
1,433
Here is my submission, 'The Circle of Life'.
Creates a circle of missiles that revolve and move towards the target point, and then back. If the missiles collide with any trees on the way there or back, they will absorb some of the trees energy. Upon returning, allied units within the circle will be healed, and enemy units will be damaged equal to the amount of life taken from the trees. Must remain channeling. Missiles revolve once every second. The radius of the circle is 225. The circle moves at a speed of 300.
Level 1 - 4 missiles, 10 life absorbed per second.
Level 2 - 5 missiles, 15 life absorbed per second.
Level 3 - 6 missiles, 20 life absorbed per second.


JASS:
//Requires TimedLoop, DestructableLib, GroupUtils, xefx, xebasic, xedamage, TimedHandles, TimerUtils
//xepreload can be used optionally.
//Special thanks to Vexorian, Pitzermike, Rising_Dusk, and TriggerHappy.
scope TheCircleOfLife initializer Init

    //Configuration.
    globals
        private constant integer SPELL_ID = 'A001'
        //The raw id of the spell. Hit CTRL + D in the object editor to find this.
        private constant integer MAX_MISSILES = 15
        //The maximum number of missiles created by an instance of this spell.
        private constant attacktype ATTACK_TYPE = ATTACK_TYPE_NORMAL
        //The attacktype of the damage dealt.
        private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_NORMAL
        //The damagetype of the damage dealt.
        private constant real    HEIGHT       = 65
        //The height of the missile.
        private constant string  ORDER        = "channel"
        //The order string used for the ability.
        private constant string MISSILE = "Abilities\\Weapons\\ChimaeraAcidMissile\\ChimaeraAcidMissile.mdl"
        //The model used by the missile(s).
        private constant string  HEAL_EFFECT  = "Abilities\\Spells\\Items\\AIma\\AImaTarget.mdl"
        //The special effect displayed when a unit is healed.
        private constant string DAMAGE_EFFECT = "Abilities\\Spells\\Undead\\AnimateDead\\AnimateDeadTarget.mdl"
        //The special effect displayed when a unit is damaged.
        private constant boolean CHANNELING   = true
        //A boolean deciding whether the spell is interrupted if the caster stops channeling.
        private constant boolean DAMAGE_TREES = true
        //A boolean deciding whether the spell damages trees.
        private constant string LIGHTNING_HEAL = "DRAL"
        //The integer of the lightning effect shown when a unit is healed.
        private constant string LIGHTNING_DAMAGE = "AFOD"
        //The integer of the lightning effect shown when a unit is damaged.
        private constant real LIGHTNING_DURATION = .5
        //The duration of the lightning when a unit is healed or damaged.
    endglobals

    private function RevolutionTime takes integer level returns real
        return 1.5
    endfunction
    //The time taken for a missile to make a complete revolution (seconds).

    private function MissileCount takes integer level returns integer
        return level + 3
    endfunction
    //The number of missiles.

    private function Offset takes integer level returns real
        return 220.
    endfunction
    //The radius of the circle created by the missiles.

    private function Speed takes integer level returns real
        return 250.
    endfunction
    //The speed at which the circle travels (not neccesarely the missiles).

    private function TreeRadius takes integer level returns real
        return 100.
    endfunction
    //The radius at which a missile is considered to have collided with a tree.

    private function AbsorbPerSecond takes integer level returns real
        return level * 5. + 5.
    endfunction    
    //The amount of 'energy' absorbed from a tree per second.

    //End configuration.    
           
    globals    
        private constant real PI2 = bj_PI * 2
        //The constant equal to the amount of radians in a circle. You can change this, but it's not recommended as the circle will look weird.
        private location Loc = Location(0,0)
        private integer Order
        private rect    R = Rect(0,0,0,0)
        private boolexpr filter
        private boolexpr filter2
        private keyword Instance
        private Instance D
    endglobals
    
    private function Heal takes nothing returns boolean
        local unit u = GetFilterUnit()
        local integer i = 0
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local string s = LIGHTNING_HEAL
        if IsUnitAlly(D.caster, GetOwningPlayer(u)) then
            //Checks if the unit is an ally of the caster. 
            call SetWidgetLife(u, GetWidgetLife(u) + D.absorbed)
            call DestroyEffect(AddSpecialEffect(HEAL_EFFECT, x, y))
        else
            set s = LIGHTNING_DAMAGE
            call DestroyEffect(AddSpecialEffect(DAMAGE_EFFECT, x, y))
            call UnitDamageTarget(D.caster, u, D.absorbed, true, false, ATTACK_TYPE, DAMAGE_TYPE, WEAPON_TYPE_WHOKNOWS)
        endif
        loop
            exitwhen i > D.number
            call DestroyLightningTimed(AddLightning(s, false, x, y, D.missile[i].x, D.missile[i].y), LIGHTNING_DURATION)
            set i = i + 1
        endloop
        set u = null
        return true
    endfunction

    private function DestructableFilter takes nothing returns boolean
       return IsDestructableTree(GetFilterDestructable())
       //Checks if the destructable is a tree (so it doesn't affect crates, barricades, etc..).
    endfunction

    private function DestructableEnum takes nothing returns nothing
        local destructable d = GetEnumDestructable()
        if DAMAGE_TREES then
        //Checks if the spell is set to damage trees.
            call SetWidgetLife(d, GetWidgetLife(d)-D.absorbAmount)
            //"Damages" the tree.
        endif
        set D.absorbed=D.absorbed+D.absorbAmount
        set d = null
    endfunction

    private struct Instance
        boolean onReturn = false
        //a boolean used to determine if the circle is on its way back or not.
        unit caster
        real x
        real y
        real cos
        real sin
        real inc
        real max
        real offset
        real radius
        real absorbed
        real absorbAmount
        integer number
        real array angle[MAX_MISSILES]
        xefx array missile[MAX_MISSILES]

        implement TimedLoop
        //Implements the struct indexing system.

        private method onTimedLoop takes nothing returns boolean
            local integer i = 0
            set this.x = this.x + this.cos
            set this.y = this.y + this.sin
            if CHANNELING then
                if GetUnitCurrentOrder(this.caster) != Order then
                    return TimedLoop_STOP
                endif
            endif
            
            loop
                exitwhen i > this.number
                set D = this
                set this.missile[i].x = this.x + Cos(this.angle[i]) * this.offset
                set this.missile[i].y = this.y + Sin(this.angle[i]) * this.offset
                //Moves the missile in a different angle away from the center of the circle.
                
                call SetRect(R,this.missile[i].x-this.radius,this.missile[i].y-this.radius,this.missile[i].x+this.radius,this.missile[i].y+this.radius)
                //Moves the global rect to enumerate destructables.
                call EnumDestructablesInRect(R, filter, function DestructableEnum)
                set this.angle[i] = this.angle[i] + this.inc
                set this.missile[i].xyangle = this.angle[i]*bj_RADTODEG
                
                call MoveLocation(Loc, this.missile[i].x,  this.missile[i].y)
                set this.missile[i].z = HEIGHT - GetLocationZ(Loc)
                set this = D
                set i = i + 1
            endloop
            
            if this.angle[0] >= this.max then
                set this.max = this.max*2
                set this.cos = this.cos*-1
                set this.sin = this.sin*-1
                //Inverts the direction of the circle.
                
                if this.onReturn then
                //Checks if the circle is on its way back.
                    call IssueImmediateOrder(this.caster, "stop")
                    //Stops the caster from channeling.
                    set D = this
                    call GroupEnumUnitsInRange(ENUM_GROUP, this.x, this.y, Offset(GetUnitAbilityLevel(this.caster, SPELL_ID)),  filter2)
                        
                    return TimedLoop_STOP
                endif
                
                set this.onReturn = true
                //Sets the boolean to true, meaning the missile is on its way back.
                
            endif

            return TimedLoop_CONTINUE
            //Returns true, meaning the loop will continue.
        endmethod

        static method create takes unit caster, real x, real y, real direction, real distance returns thistype
            local thistype d = thistype.allocate()
            local integer i = 0
            local xefx fx
            local integer level = GetUnitAbilityLevel(caster, SPELL_ID)
            local real r = PI2/MissileCount(level)
            local real r2 = Speed(level)*TimedLoop_PERIOD
            local real r3 = RevolutionTime(level)
            set d.inc = PI2*TimedLoop_PERIOD/r3
            set d.cos = Cos(direction) * r2
            set d.sin = Sin(direction) * r2
            set d.x = x
            set d.y = y
            set d.number = MissileCount(level)
            set d.max = distance / Speed(level) * PI2 / r3
            set d.offset = Offset(level)
            set d.radius = TreeRadius(level)
            set d.caster = caster
            set d.absorbAmount = AbsorbPerSecond(level)*TimedLoop_PERIOD
            //Performs a few calculations and then stores everything in the struct.
            call d.startTimedLoop()
            //Starts the struct indexing.
            
            loop
                exitwhen i > d.number
                set d.missile[i] = xefx.create(x + d.offset * Cos(r), y + d.offset * Sin(r), r * bj_RADTODEG)
                set d.missile[i].fxpath = MISSILE
                set d.angle[i] = r * i
                set i = i + 1
            endloop
            //Creates the missiles in a circle.
            
            return d
        endmethod

        method onDestroy takes nothing returns nothing
            local integer i = 0
            loop
                exitwhen i > this.number
                call this.missile[i].destroy()
                set i = i + 1
            endloop
            //Loops through the xefx array and destroys every missile.
        endmethod

    endstruct

    private function Conditions takes nothing returns boolean
        return true// GetSpellAbilityId() == SPELL_ID
        //Checks if the spell being cast matches this code.
    endfunction

    private function Actions takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local real x = GetUnitX(u)
        local real y = GetUnitY(u)
        local real dx = GetSpellTargetX() - x
        local real dy = GetSpellTargetY() - y
        local Instance d = Instance.create(GetTriggerUnit(), x, y, Atan2(dy,dx), SquareRoot(dx*dx+dy*dy))
        set u = null
        //Calculates the distance between the target point and the caster and then creates the struct.
    endfunction

    function Init takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
        call TriggerAddCondition(t, Condition(function Conditions))
        call TriggerAddAction(t, function Actions)
        if CHANNELING then
            set Order = OrderId(ORDER)
        endif
        //Stores the order id if CHANNELING is set to true (avoids a function call otherwise).
        set filter = Filter(function DestructableFilter)
        set filter2 = Filter(function Heal)
        call Preload(HEAL_EFFECT)
        call Preload(MISSILE)
        call Preload(DAMAGE_EFFECT)
        //Preloads the models. 
        static if LIBRARY_xepreload then
            call XE_PreloadAbility(SPELL_ID)
        endif
        //If the xepreload library is found it will preload the ability.
    endfunction

endscope
attachment.php


I used Jass NewGen: http://www.wc3c.net/showthread.php?t=90999

Credits:
Vexorian: xefx, xe, xepreload, TimedLoop, TimerUtils
Rising_Dusk: GroupUtils
TriggerHappy: TimedHandles
 

Attachments

  • Screenshot.jpg
    Screenshot.jpg
    108.9 KB · Views: 329
  • Zephyr Challenge - The Circle of Life.w3x
    69.7 KB · Views: 81
Last edited:
Status
Not open for further replies.
Top