wc3campaigns
WC3C Homepage - www.wc3c.netUser Control Panel (Requires Log-In)Engage in discussions with other users and join contests in the WC3C forums!Read one of our many tutorials, ranging in difficulty from beginner to advanced!Show off your artistic talents in the WC3C Gallery!Download quality models, textures, spells (vJASS/JASS), systems, and scripts!Download maps that have passed through our rigorous approval process!

Go Back   Wc3C.net > Warcraft III Modding > Developer's Corner > Triggers & Scripts
User Name
Password
Register Rules Get Hosted! Chat Pastebin FAQ and Rules Members List Calendar



Reply
 
Thread Tools Search this Thread
Old 07-14-2008, 11:24 PM   #1
Flame_Phoenix
retired coder | real ilfe
 
Flame_Phoenix's Avatar
 
Join Date: Mar 2007
Posts: 2,208

Submissions (10)

Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)

Send a message via MSN to Flame_Phoenix
Default Golem Invocation

HI guys. Well, here is the third spell I intent to submit for the resources section of this community.
It is Golem Invocation spell, a very cool spell =)
This is again a channeling spell (channeling are my favorites =P).
When the caster starts channeling, it creates dust in the area and the ground starts trembling. During all that, 3 types of golems will emerge from the ground ready to fight. The 3 types of golems are unique, some are stronger than others, and the weaker golems will be spawned more times then the stronger golems.
Each golem lasts for a period of time and after that it will die.
During the channeling, if enemy units get inside the dust they will be affected and will be slowed.

I worked hard on code for the last 3 days (yes I am in a rush with this) and now I think the spell is quite ready, however, i don't dare to submit it without an opinion from you guys.

Collapse JASS:
scope GolemInvocation initializer Init
//===========================================================================
//=============================SETUP START===================================
//===========================================================================

    globals
        private constant integer AID = 'A001'   //the rawcode of the ability
        private constant integer DUSTID = 'h000'    //The rawcode of the dummy dust unit
        private constant string ANIMATION = "birth" //the animation that will be played when the unit is created
        private constant integer DUST = 'h000' //the rawcode of the dummy unit that will be dust
    endglobals
    
//===========================================================================
//===========================IMPORTANT NOTE==================================
//The returned value from golemChance1 + golemChance2 + golemChance3 must be 
//equal to 100. This formula is very important if you want to spawn a golem
//every cicle.
//===========================================================================

    private function weakGolemChance takes integer level returns real 
        //in level 1 we have 90% chance to get Weak Golem
        //in level 2 we have 80% chance to get Weak Golem
        //in level 3 we have 70% chance to get Weak Golem
        return 100. - (level * 10)
    endfunction
    
    private function mediumGolemChance takes integer level returns real 
        //in level 1 we have 6% chance to get Medium Golem
        //in level 2 we have 13% chance to get Medium Golem
        //in level 3 we have 20% chance to get Medium Golem
        local real chance = 0
        
        if (level == 1) then
            set chance = 6.
        elseif (level == 2) then
            set chance = 13.
        elseif (level == 3) then
            set chance = 20.
        endif
        
        return chance 
    endfunction
    
    private function strongGolemChance takes integer level returns real 
        //in level 1 we have 4% chance to get Strong Golem
        //in level 2 we have 7% chance to get Strong Golem
        //in level 3 we have 10% chance to get Strong Golem
        local real chance = 0
        
        if (level == 1) then
            set chance = 4.
        elseif (level == 2) then
            set chance = 7.
        elseif (level == 3) then
            set chance = 10.
        endif
        
        return chance 
    endfunction
    
//===========================================================================
//==============================END NOTE=====================================
//Remember: golemChance1 + golemChance2 + golemChance3 = 100
//If you want to ALWAYS spawn a Golem, you must use this formula
//===========================================================================

    
    private function weakGolemType takes integer level returns integer 
        //the rawcode of the weakGolemType unit. In this case our weak
        //golem is a mud golem level 2
        return 'ngrk'
    endfunction
    
    private function mediumGolemType takes integer level returns integer 
        //the rawcode of the mediumGolemType unit. In this case our medium
        //golem is a rock golem level 6
        return 'ngst'
    endfunction
    
    private function strongGolemType takes integer level returns integer 
        //the rawcode of the strongGolemType unit. In this case our strong
        //golem is a granite golem level 9
        return 'nggr'
    endfunction

    private function golemLife takes integer level returns real
        return level * 20.  //the amount of time each golem will live
    endfunction

    private constant function golemsPerCicle takes integer level returns integer
        //the number of golems that will be created each cicle
        return 1 + (level * 0)
    endfunction
    
    private constant function cicle takes integer level returns real
        //the cicle which will determine when we create golems
        //this means, golemsPerCicle golems are created every cicle
        //in this case, we create 1 golem per second (in this case a second 
        //is a cicle)
        return 1. + (level * 0) 
    endfunction
    
    private constant function minRange takes integer level returns real
        //in this case we dont have a minimum range, which means we can 
        //create units at the center of the circle
        //the minimum range is smaller circle, inside the area of the spell
        //in which golems will not be created
        return 0.
    endfunction
    
    private constant function maxRange takes integer level returns real
        //this ensures golems are not created outside the AOE of the spell
        //this gives the AOE of the spell
        return 200. + (level * 100)
    endfunction
    
    private constant function circleCount takes integer level returns integer
        //the number of circles that will be created to give the illusion of teh dust
        //effect. The more circles the more realistic, but more CPU will be needed.
        return 3 + level 
    endfunction
    
    private constant function innerCircleUnits takes integer level returns integer
        //the number of units that the most inner circle will have
        return level + 5
    endfunction
    
    private constant function innerCircleUnitsIncrease takes integer level returns integer
        //the increment of units per circle
        return level + 2
    endfunction
//===========================================================================
//=============================SETUP END=====================================
//===========================================================================

    globals 
        private group GolemInvocationCasters
        private HandleTable activeTable 
    endglobals
    
    private struct MyStruct 
        unit caster
        integer level
        timer cicleTimer 
        real spellLocX
        real spellLocY
        group dummyEffects
        
        static method create takes unit caster, real locX, real locY returns MyStruct
            local MyStruct data = MyStruct.allocate()
            
            //set variables about the caster
            set data.caster = caster
            set data.level = GetUnitAbilityLevel(data.caster, AID)
            
            //variables about the location
            set data.spellLocX = locX
            set data.spellLocY = locY
            
            //the timer which will determine when we create golems
            //creates a golem everytime it expires
            set data.cicleTimer = NewTimer()   
            
            //This groups will save the dumy dust effects, so we can kill them 
            //when the caster stops the channeling
            set data.dummyEffects = NewGroup()
            
            return data
        endmethod
        
        method onDestroy takes nothing returns nothing
            
            //here we select all units from the group and we kill them all ! =P
            //thus meaning that the dust effects will disappear ! 
            local unit f
            loop
                set f = FirstOfGroup(.dummyEffects)
                exitwhen(f == null)
                call GroupRemoveUnit(.dummyEffects, f)
                call KillUnit(f)
            endloop
            
            //since the spell is not active anymore, we clean the Table     
            call activeTable.flush(.caster) 
            
            //the units are not anymore in the active units group.
            call GroupRemoveUnit(GolemInvocationCasters, .caster) 
            
            //releasing the timer and group for CSSafety to use it one day later =D
            call ReleaseTimer(.cicleTimer)
            call ReleaseGroup(.dummyEffects)
            
        endmethod
    endstruct
    
//===========================================================================
    private function onStop takes nothing returns boolean
        local MyStruct data
        local unit u = GetTriggerUnit()
        
        //when a unit stops the channel, we verify if that unit is inside the
        //catsers group. If so, than it is because it is a caster casting this spell
        //and so we recover information about him and we make the spell end
        if(IsUnitInGroup(u, GolemInvocationCasters)) then
            //recover the data from the caster
            set data = activeTable[u] 
            
            //now, time to clean the mess once again
            call data.destroy() 
        endif

        set u = null
        
        return false
    endfunction
//===========================================================================
    //Function made by Themerion and adapted by Flame_Phoenix
    //Creates circles of dummy units to give the illusion of the dust effect
    private function createDust takes integer aStruct returns nothing
        local MyStruct data = aStruct
        
        // forPlayer     -> Create the units for which player?
        local player forPlayer = GetOwningPlayer(data.caster)
        
        // innerRadius   -> The radius of the innermost circle
        // outerRadius   -> The radius of the outmost circle
        local real innerRadius = minRange(data.level)
        local real outerRadius = maxRange(data.level)
        
        // x and y       -> Center of circles
        local real x = data.spellLocX
        local real y = data.spellLocY

        local real radiusInc = (outerRadius - innerRadius) / I2R(circleCount(data.level)-1)
        
        //see funtions they call
        local integer fxcount = innerCircleUnits(data.level)
        local integer fxcountinc = innerCircleUnitsIncrease(data.level)
        
        local real phi = 0
        local real phiInc

        loop
            exitwhen (innerRadius + 0.001 >= outerRadius)

            set phi = 0
            set phiInc = 2*bj_PI/I2R(fxcount)
            
            loop
                exitwhen (phi + 0.001 >= 2 * bj_PI)
                //we add the units to a group, so we can kill them when we want ! =P
                call GroupAddUnit(data.dummyEffects, CreateUnit(forPlayer, DUST, x + innerRadius * Cos(phi), y + innerRadius * Sin(phi), 180 + Rad2Deg(phi)))
                set phi = phi + phiInc
            endloop
            
        set innerRadius = innerRadius + radiusInc
        set fxcount = fxcount + fxcountinc
        
        endloop
        
        set forPlayer = null
    
    endfunction
//===========================================================================
    //Function made by Vexorian, it selects a random region in a disk. 
    //All regions have the same chance of beeing choosen
    private function GetRandomPointInDisk takes real centerx, real centery, real minradius, real maxradius returns location
        local real d = SquareRoot(GetRandomReal(minradius * minradius, maxradius * maxradius))
        local real a = GetRandomReal(0, 2 * bj_PI)
        return Location(centerx + d * Cos(a), centery + d * Sin(a))
    endfunction
//===========================================================================
    private function createGolems takes nothing returns nothing
        //we get the structure from the timer
        local MyStruct data = MyStruct(GetCSData(GetExpiredTimer())) 
        
        //variables for us to know where the golems will born
        local location point  
        local real randomX  
        local real randomY 
        
        //the chances that each golem will have to be spawned
        local real aChance
        
        //just to keep count about how many golems we created
        local integer loopCounter = 0
        
        //cariables about the golems
        local unit golem
        local real golemFacing = GetUnitFacing(data.caster)
        
        //Here we spawn the golems 
        loop 
            exitwhen(loopCounter >= golemsPerCicle(data.level))
                
            set point = GetRandomPointInDisk(data.spellLocX, data.spellLocY, minRange(data.level), maxRange(data.level))
            set randomX = GetLocationX(point)
            set randomY = GetLocationY(point)
            set aChance = GetRandomReal(0, 100)
            
            if (aChance <= 100 - weakGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), weakGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
            elseif (aChance <= 100 - mediumGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), mediumGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
            elseif (aChance <= 100 - strongGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), strongGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))    
            endif   
            
            call RemoveLocation(point)
            set point = null
                
            set loopCounter = loopCounter + 1
        endloop
    
    set golem = null

    endfunction
//===========================================================================
    private function Conditions takes nothing returns boolean
        local MyStruct data
        local location spellLoc //the location of the spell
        
        if (GetSpellAbilityId() == AID) then
            //setting variables for the struct
            set spellLoc = GetSpellTargetLoc()
            set data = MyStruct.create(GetTriggerUnit(), GetLocationX(spellLoc), GetLocationY(spellLoc))
            
            //put the struct in the Table, we just use the caster's handle adress as 
            //the key which tells us where in the Table the struct is stored
            set activeTable[data.caster] = data 

            //  we add the casting unit to some sort of "pool"
            call GroupAddUnit(GolemInvocationCasters, data.caster)
            
            //now we create the dusty effect
            call createDust(data)
            
            //we attach the struct to the timer
            call SetCSData(data.cicleTimer, integer(data))
            call TimerStart(data.cicleTimer, cicle(data.level), true, function createGolems)
            
            //cleaning up the mess
            call RemoveLocation(spellLoc)
        endif
        
        set spellLoc = null
        
        return false
    endfunction
//===========================================================================
    private function Init takes nothing returns nothing
        local trigger GolemInvocationTrigger = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(GolemInvocationTrigger, Condition( function Conditions ) )
        
        set GolemInvocationTrigger = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        call TriggerAddCondition(GolemInvocationTrigger,  Condition(function onStop))

        set GolemInvocationTrigger = null
        
        //set our globals
        set activeTable = HandleTable.create() 
        set GolemInvocationCasters = NewGroup() 

        set GolemInvocationTrigger = null
    endfunction
endscope 

This code is again very simple, the most complicated part is the circle part and when I spawn golems but those are also not that hard to understand if you catch up with some maths.

Anyway, any suggestions on improving this script ?
Btw, don't whine about the code having a minimal range, it is not needed in this spell, but I just had a great idea where to use it.

Anyway, I also need some opinions and help:
- when the unit are slowed by the earthquake, they have the earthquake buff, instead of the Golem Invocation buff ... can I change that ? I already tried but it doesn't seem to work =S
- What is your opinion guys ? Should the golems have a life time like 20 seconds, or should they all die when the caster stops the channel ?

So help and suggestions plz =S
Attached Files
File Type: w3x Golem Invocation.w3x (33.8 KB, 13 views)
__________________
Check out my tutorials at:
1-Creating a Hero Tavern
2-Complete Icon Tutorial - ALL about Icons
3-Making a spell in vJass - Practice Session 1
Check out all my current spells at here
Finally, check my project:
Castle vs Castle Flame Edition
Flame_Phoenix is offline   Reply With Quote
Sponsored Links - Login to hide this ad!
Old 07-15-2008, 08:19 AM
Flame_Phoenix
This message has been deleted by Flame_Phoenix.
Old 07-15-2008, 04:43 PM   #2
Kyrbi0
AKA Khyrberos
 
Kyrbi0's Avatar
 
Join Date: May 2008
Posts: 2,945

Submissions (1)

Kyrbi0 is a jewel in the rough (170)Kyrbi0 is a jewel in the rough (170)

Send a message via MSN to Kyrbi0
Default

Y'know, I might learn a thing or two about JASS from you... You seem to just be starting out, but with a good basic knowledge.

I was about to say, you could re-create the *basic* effect of your spell with a the Hero casting a modified Dark Portal (which gives you a random number of the units you set), then a dummy caster casting a modified Earthquake for X seconds (with a custom buff that reads "Golem Invocation").

Regardless, props to you for learning JASS; I'm told it's the path to a better future. :P
__________________
My Projects, Resources, + Tutorials: ~Just got back from my mission. Glad to be back. Woot! :P~
=It was brought to my attention recently that the ":P" icon stands for "tongue-sticking out", and not the "smirky half-smile" I was using it for all these years. = Thusly I apologize for any unintentional juvenilization of my messages to anyone so afflicted.=
Kyrbi0 is offline   Reply With Quote
Old 07-15-2008, 04:59 PM   #3
the-thingy
User
 
Join Date: Feb 2006
Posts: 172

the-thingy will become famous soon enough (30)the-thingy will become famous soon enough (30)

Default

1) All these if's aren't needed
[jass] private function mediumGolemChance takes integer level returns real
//in level 1 we have 6% chance to get Medium Golem
//in level 2 we have 13% chance to get Medium Golem
//in level 3 we have 20% chance to get Medium Golem
local real chance = 0

if (level == 1) then
set chance %


EDIT: WTF? How did half this post just... disappear...

Last edited by the-thingy : 07-15-2008 at 07:49 PM.
the-thingy is offline   Reply With Quote
Old 07-15-2008, 06:51 PM   #4
Flame_Phoenix
retired coder | real ilfe
 
Flame_Phoenix's Avatar
 
Join Date: Mar 2007
Posts: 2,208

Submissions (10)

Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)

Send a message via MSN to Flame_Phoenix
Default

Quote:
Y'know, I might learn a thing or two about JASS from you... You seem to just be starting out, but with a good basic knowledge.

I was about to say, you could re-create the *basic* effect of your spell with a the Hero casting a modified Dark Portal (which gives you a random number of the units you set), then a dummy caster casting a modified Earthquake for X seconds (with a custom buff that reads "Golem Invocation").

Regardless, props to you for learning JASS; I'm told it's the path to a better future. :P
Lol, I could use Death and decay for the same purpose, but that would just create dummy units in random points just like portal and I don't want that, I want units in circles =P
Also, I already know JASS a long time ago, but only now I started to learn and understand the true power and coding of vJASS.
About Earthquake, well, I am currently trying your suggestion, but it doesn't work =S
Any way, thx for the post.

Quote:
1) All these if's aren't needed
Good point, I didn't found a formula for those, anyway thx for your help.
I still think I should leave an if, so people can see they are not forced to return stuff in one line ... what do you think ?
I think I will let it as a comment.


Quote:
Why are you taking an argument? It's not being used, so it seems like a waste of space.
NO no no no no. Just because I am not using, it doesn't mean that some one won't use them.
Imagine this scenario, per example an elemental summoning.

Level 1 - creates a mud golem, rock golem and granite golem with dust around them.
Level 2 - creates a weak fire spawn, medium fire spawn and a strong fire spawn with fire dummies around them
Level 3 - so on you get the idea.

This allows people to spawn several different dummy units and golems (or whatever) depending on the level of the spell. I just don't use them because I don't need, but other people may have a good use for them.
Besides, you just gave me an idea for a next spell =) using this same code ! =)


Quote:
I'm guessing it's supposed to be cycle
OOOhhh, that is how we should type it Mmmmm finally I know why I always had an error with firefox dictionary lol... Thx !

Quote:
3 days is a rush?
When you create code an map from zero, with exams in the middle, trust me, it is.

Ok thx for your help thingy. Rep++ for you being helpful.

Btw, can some one help me out with these also??

Quote:
Anyway, I also need some opinions and help:
- when the unit are slowed by the earthquake, they have the earthquake buff, instead of the Golem Invocation buff ... can I change that ? I already tried but it doesn't seem to work =S
- What is your opinion guys ? Should the golems have a life time like 20 seconds, or should they all die when the caster stops the channel ?
Please ??

Map and code will be updated soon.
Any other suggestions regarding code ?

EDIT EDIT EIDT
Ok guys, here is the updated version of the code and map, hope you all like it, and please help me out figuring a solution fr my previous problems =S

Collapse JASS:
scope GolemInvocation initializer Init
//===========================================================================
//=============================SETUP START===================================
//===========================================================================

    globals
        private constant integer AID = 'A001'   //the rawcode of the ability
        private constant string ANIMATION = "birth" //the animation that will be played when the unit is created
    endglobals
    
//===========================================================================
//===========================IMPORTANT NOTE==================================
//The returned value from golemChance1 + golemChance2 + golemChance3 must be 
//equal to 100. This formula is very important if you want to spawn a golem
//every cycle.
//===========================================================================

    private constant function weakGolemChance takes integer level returns real 
        //in level 1 we have 90% chance to get Weak Golem
        //in level 2 we have 80% chance to get Weak Golem
        //in level 3 we have 70% chance to get Weak Golem
        return 100. - (level * 10)
    endfunction
    
    private constant function mediumGolemChance takes integer level returns real 
        //in level 1 we have 6% chance to get Medium Golem
        //in level 2 we have 13% chance to get Medium Golem
        //in level 3 we have 20% chance to get Medium Golem
        
        return -1. + (level * 7.)
        
        //example of usage
        //sometimes it is either difficult or impossible to find a formula
        //for our purposes. However, you can always use an if statement, 
        //like I use in the example
        
//       local real chance = 0    
//       if (level == 1) then
//            set chance = 6.
//        elseif (level == 2) then
//            set chance = 13.
//        elseif (level == 3) then
//            set chance = 20.
//        endif
//        return chance 
        
        //please note, that finding a formula is very efficient
        //note how we compressed this whole if statement into that
        //single line
    endfunction
    
    private constant function strongGolemChance takes integer level returns real 
        //in level 1 we have 4% chance to get Strong Golem
        //in level 2 we have 7% chance to get Strong Golem
        //in level 3 we have 10% chance to get Strong Golem
        return 1. + (3. * level)
    endfunction
    
//===========================================================================
//==============================END NOTE=====================================
//Remember: golemChance1 + golemChance2 + golemChance3 = 100
//If you want to ALWAYS spawn a Golem, you must use this formula
//===========================================================================

    private constant function dummyEffectId takes integer level returns integer
        //the rawcode of the dummy unit that will be dust
        //this is in a function so you can have different effects in different
        //levels
        return 'h000'
    endfunction
    
    private constant function weakGolemType takes integer level returns integer 
        //the rawcode of the weakGolemType unit. In this case our weak
        //golem is a mud golem level 2
        return 'ngrk'
        
        //example of usage
//        local integer aUnit = 0
//        if (level == 1) then
//            set aUnit = 'h001'
//        elseif (level == 2) then
//            set aUnit = 'h002'
//        elseif (level == 3) then
//            set aUnit = 'h003'
//        endif
//        return aUnit 
        //in this example, we spawn a different unit type every level
        //please note, there are not 'h001', 'h002' and 'h003' units in this 
        //demo map
    endfunction
    
    private constant function mediumGolemType takes integer level returns integer 
        //the rawcode of the mediumGolemType unit. In this case our medium
        //golem is a rock golem level 6
        return 'ngst'
    endfunction
    
    private constant function strongGolemType takes integer level returns integer 
        //the rawcode of the strongGolemType unit. In this case our strong
        //golem is a granite golem level 9
        return 'nggr'
    endfunction

    private constant function golemLife takes integer level returns real
        return level * 20.  //the amount of time each golem will live
    endfunction

    private constant function golemsPerCycle takes integer level returns integer
        //the number of golems that will be created each cycle
        return 1 + (level * 0)
    endfunction
    
    private constant function cycle takes integer level returns real
        //the cycle which will determine when we create golems
        //this means, golemsPerCycle golems are created every cycle
        //in this case, we create 1 golem per second (in this case a second 
        //is a cycle)
        return 1. + (level * 0) 
    endfunction
    
    private constant function minRange takes integer level returns real

        //in this case we dont have a minimum range, which means we can 
        //create units at the center of the circle
        //the minimum range is smaller circle, inside the area of the spell
        //in which golems will not be created
        return 0.
    endfunction
    
    private constant function maxRange takes integer level returns real
        //this ensures golems are not created outside the AOE of the spell
        //this gives the AOE of the spell
        return 200. + (level * 100)
    endfunction
    
    private constant function circleCount takes integer level returns integer
        //the number of circles that will be created to give the illusion of teh dust
        //effect. The more circles the more realistic, but more CPU will be needed.
        return 3 + level 
    endfunction
    
    private constant function innerCircleUnits takes integer level returns integer
        //the number of units that the most inner circle will have
        return level + 5
    endfunction
    
    private constant function innerCircleUnitsIncrease takes integer level returns integer
        //the increment of units per circle
        return level + 2
    endfunction
//===========================================================================
//=============================SETUP END=====================================
//===========================================================================

    globals 
        private group GolemInvocationCasters
        private HandleTable activeTable 
    endglobals
    
    private struct MyStruct 
        unit caster
        integer level
        timer cycleTimer 
        real spellLocX
        real spellLocY
        group dummyEffects
        
        static method create takes unit caster, real locX, real locY returns MyStruct
            local MyStruct data = MyStruct.allocate()
            
            //set variables about the caster
            set data.caster = caster
            set data.level = GetUnitAbilityLevel(data.caster, AID)
            
            //variables about the location
            set data.spellLocX = locX
            set data.spellLocY = locY
            
            //the timer which will determine when we create golems
            //creates a golem everytime it expires
            set data.cycleTimer = NewTimer()   
            
            //This groups will save the dumy dust effects, so we can kill them 
            //when the caster stops the channeling
            set data.dummyEffects = NewGroup()
            
            return data
        endmethod
        
        method onDestroy takes nothing returns nothing
            
            //here we select all units from the group and we kill them all ! =P
            //thus meaning that the dust effects will disappear ! 
            local unit f
            loop
                set f = FirstOfGroup(.dummyEffects)
                exitwhen(f == null)
                call GroupRemoveUnit(.dummyEffects, f)
                call KillUnit(f)
            endloop
            
            //since the spell is not active anymore, we clean the Table     
            call activeTable.flush(.caster) 
            
            //the units are not anymore in the active units group.
            call GroupRemoveUnit(GolemInvocationCasters, .caster) 
            
            //releasing the timer and group for CSSafety to use it one day later =D
            call ReleaseTimer(.cycleTimer)
            call ReleaseGroup(.dummyEffects)
            
        endmethod
    endstruct
    
//===========================================================================
    private function onStop takes nothing returns boolean
        local MyStruct data
        local unit u = GetTriggerUnit()
        
        //when a unit stops the channel, we verify if that unit is inside the
        //catsers group. If so, than it is because it is a caster casting this spell
        //and so we recover information about him and we make the spell end
        if(IsUnitInGroup(u, GolemInvocationCasters)) then
            //recover the data from the caster
            set data = activeTable[u] 
            
            //now, time to clean the mess once again
            call data.destroy() 
        endif

        set u = null
        
        return false
    endfunction
//===========================================================================
    //Function made by Themerion and adapted by Flame_Phoenix
    //Creates circles of dummy units to give the illusion of the dust effect
    private function createDust takes integer aStruct returns nothing
        local MyStruct data = aStruct
        
        // forPlayer     -> Create the units for which player?
        local player forPlayer = GetOwningPlayer(data.caster)
        
        // innerRadius   -> The radius of the innermost circle
        // outerRadius   -> The radius of the outmost circle
        local real innerRadius = minRange(data.level)
        local real outerRadius = maxRange(data.level)
        
        // x and y       -> Center of circles
        local real x = data.spellLocX
        local real y = data.spellLocY

        local real radiusInc = (outerRadius - innerRadius) / I2R(circleCount(data.level)-1)
        
        //see funtions they call
        local integer fxcount = innerCircleUnits(data.level)
        local integer fxcountinc = innerCircleUnitsIncrease(data.level)
        
        local real phi = 0
        local real phiInc

        loop
            exitwhen (innerRadius + 0.001 >= outerRadius)

            set phi = 0
            set phiInc = 2*bj_PI/I2R(fxcount)
            
            loop
                exitwhen (phi + 0.001 >= 2 * bj_PI)
                //we add the units to a group, so we can kill them when we want ! =P
                call GroupAddUnit(data.dummyEffects, CreateUnit(forPlayer, dummyEffectId(data.level), x + innerRadius * Cos(phi), y + innerRadius * Sin(phi), 180 + Rad2Deg(phi)))
                set phi = phi + phiInc
            endloop
            
        set innerRadius = innerRadius + radiusInc
        set fxcount = fxcount + fxcountinc
        
        endloop
        
        set forPlayer = null
    
    endfunction
//===========================================================================
    //Function made by Vexorian, it selects a random region in a disk. 
    //All regions have the same chance of beeing choosen
    private function GetRandomPointInDisk takes real centerx, real centery, real minradius, real maxradius returns location
        local real d = SquareRoot(GetRandomReal(minradius * minradius, maxradius * maxradius))
        local real a = GetRandomReal(0, 2 * bj_PI)
        return Location(centerx + d * Cos(a), centery + d * Sin(a))
    endfunction
//===========================================================================
    private function createGolems takes nothing returns nothing
        //we get the structure from the timer
        local MyStruct data = MyStruct(GetCSData(GetExpiredTimer())) 
        
        //variables for us to know where the golems will born
        local location point  
        local real randomX  
        local real randomY 
        
        //the chances that each golem will have to be spawned
        local real aChance
        
        //just to keep count about how many golems we created
        local integer loopCounter = 0
        
        //cariables about the golems
        local unit golem
        local real golemFacing = GetUnitFacing(data.caster)
        
        //Here we spawn the golems 
        loop 
            exitwhen(loopCounter >= golemsPerCycle(data.level))
                
            set point = GetRandomPointInDisk(data.spellLocX, data.spellLocY, minRange(data.level), maxRange(data.level))
            set randomX = GetLocationX(point)
            set randomY = GetLocationY(point)
            set aChance = GetRandomReal(0, 100)
            
            if (aChance <= 100 - weakGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), weakGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
            elseif (aChance <= 100 - mediumGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), mediumGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
            elseif (aChance <= 100 - strongGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), strongGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))    
            endif   
            
            call RemoveLocation(point)
            set point = null
                
            set loopCounter = loopCounter + 1
        endloop
    
    set golem = null

    endfunction
//===========================================================================
    private function Conditions takes nothing returns boolean
        local MyStruct data
        local location spellLoc //the location of the spell
        
        if (GetSpellAbilityId() == AID) then
            //setting variables for the struct
            set spellLoc = GetSpellTargetLoc()
            set data = MyStruct.create(GetTriggerUnit(), GetLocationX(spellLoc), GetLocationY(spellLoc))
            
            //put the struct in the Table, we just use the caster's handle adress as 
            //the key which tells us where in the Table the struct is stored
            set activeTable[data.caster] = data 

            //  we add the casting unit to some sort of "pool"
            call GroupAddUnit(GolemInvocationCasters, data.caster)
            
            //now we create the dusty effect
            call createDust(data)
            
            //we attach the struct to the timer
            call SetCSData(data.cycleTimer, integer(data))
            call TimerStart(data.cycleTimer, cycle(data.level), true, function createGolems)
            
            //cleaning up the mess
            call RemoveLocation(spellLoc)
        endif
        
        set spellLoc = null
        
        return false
    endfunction
//===========================================================================
    private function Init takes nothing returns nothing
        local trigger GolemInvocationTrigger = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(GolemInvocationTrigger, Condition( function Conditions ) )
        
        set GolemInvocationTrigger = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        call TriggerAddCondition(GolemInvocationTrigger,  Condition(function onStop))

        set GolemInvocationTrigger = null
        
        //set our globals
        set activeTable = HandleTable.create() 
        set GolemInvocationCasters = NewGroup() 

        set GolemInvocationTrigger = null
    endfunction
endscope 

Here is the map, enjoy =)
Attached Files
File Type: w3x Golem Invocation.w3x (34.3 KB, 4 views)
__________________
Check out my tutorials at:
1-Creating a Hero Tavern
2-Complete Icon Tutorial - ALL about Icons
3-Making a spell in vJass - Practice Session 1
Check out all my current spells at here
Finally, check my project:
Castle vs Castle Flame Edition

Last edited by Flame_Phoenix : 07-15-2008 at 07:18 PM.
Flame_Phoenix is offline   Reply With Quote
Old 07-15-2008, 07:20 PM   #5
Kyrbi0
AKA Khyrberos
 
Kyrbi0's Avatar
 
Join Date: May 2008
Posts: 2,945

Submissions (1)

Kyrbi0 is a jewel in the rough (170)Kyrbi0 is a jewel in the rough (170)

Send a message via MSN to Kyrbi0
Default

Quote:
Lol, I could use Death and decay for the same purpose...
But... DnD isn't a summon, it's a channeled area damage based on percentage health. Heke?

~~~

As to your problem with the buffs... I don't know what using vJASS or JASS involves, and whether that could possibly interact and cause your problem. If not, then all you need is a custom "Golem Invocation" buff, and set the Earthquake's "Earthquake" buffs (usually more than one in this case) to your custom ones.
__________________
My Projects, Resources, + Tutorials: ~Just got back from my mission. Glad to be back. Woot! :P~
=It was brought to my attention recently that the ":P" icon stands for "tongue-sticking out", and not the "smirky half-smile" I was using it for all these years. = Thusly I apologize for any unintentional juvenilization of my messages to anyone so afflicted.=

Last edited by Kyrbi0 : 07-15-2008 at 07:20 PM.
Kyrbi0 is offline   Reply With Quote
Old 07-15-2008, 07:27 PM   #6
Flame_Phoenix
retired coder | real ilfe
 
Flame_Phoenix's Avatar
 
Join Date: Mar 2007
Posts: 2,208

Submissions (10)

Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)

Send a message via MSN to Flame_Phoenix
Default

Quote:
As to your problem with the buffs... I don't know what using vJASS or JASS involves, and whether that could possibly interact and cause your problem. If not, then all you need is a custom "Golem Invocation" buff, and set the Earthquake's "Earthquake" buffs (usually more than one in this case) to your custom ones.
That is what I am doing, and it still doesn't work =(
Please download map, you will see the problem, am using the ability editor for that purpose.

Quote:
But... DnD isn't a summon, it's a channeled area damage based on percentage health. Heke?
Yes, but you can choose the effect. You can have, per example, a unit as an effect in Dnd. That way you have the illusion of having a unit being spawned in a random location inside the AOE.
Attached Files
File Type: w3x Golem Invocation.w3x (34.4 KB, 5 views)
__________________
Check out my tutorials at:
1-Creating a Hero Tavern
2-Complete Icon Tutorial - ALL about Icons
3-Making a spell in vJass - Practice Session 1
Check out all my current spells at here
Finally, check my project:
Castle vs Castle Flame Edition

Last edited by Flame_Phoenix : 07-15-2008 at 07:28 PM.
Flame_Phoenix is offline   Reply With Quote
Old 07-15-2008, 07:47 PM   #7
the-thingy
User
 
Join Date: Feb 2006
Posts: 172

the-thingy will become famous soon enough (30)the-thingy will become famous soon enough (30)

Default

Quote:
Level 1 - creates a mud golem, rock golem and granite golem with dust around them.
Level 2 - creates a weak fire spawn, medium fire spawn and a strong fire spawn with fire dummies around them
Level 3 - so on you get the idea.

Can be done with some arrays :P Going by your example (with 3 types of units), the array indexes for each level would be

((Level - 1)*3) + (value between 1 and 3)
Which would give

((1-1)*3) + (1 to 3) = 0*3 + (1 to 3) = 0 + (1 to 3) = 1 to 3
((2 - 1)*3) + (1 to 3) = 1*3 + (1 to 3) = 3 + (1 to 3) = 4 to 6
((3 - 1)*3) + (1 to 3) = 2*3 + (1 to 3) = 6 + (1 to 3) = 7 to 9

Quote:
I still think I should leave an if, so people can see they are not forced to return stuff in one line ... what do you think ?

I usually do something like (I'll use a real as an example)
Collapse JASS:
function Get<something> takes unit u returns real
   local real base = 1.
   local real m1 = I2R (GetUnitAbilityLevel (u, ABILID))
   local real m2 = 2.
   return base + m1 * m2
That, in most cases, allows for maximum customizability, and it very easy to alter for testing purposes (since you can just set base to <some value> and m2 to 0, and you have yourself a constant value to test with)

Quote:
- when the unit are slowed by the earthquake, they have the earthquake buff, instead of the Golem Invocation buff ... can I change that ? I already tried but it doesn't seem to work =S
Probably one of those really lame abilities where you have to modify the original spell in order for the change to take effect (I think Stampede is the same, in relation to the blood SFX). You could create a dummy unit with Slow Aura (Tornado), then use terrain deformations (I think they can desyncs though)

Quote:
- What is your opinion guys ? Should the golems have a life time like 20 seconds, or should they all die when the caster stops the channel ?
That's something for your config header - add a constant boolean, and a function/constant for your duration. When (boolean) is true, kill the units when the caster stops, else add an expiration timer to them, using the function/constant value to determine how long they should live. If the possibility of configuration for a specific property exists, you should add something that enables you to configure the property

Quote:
When you create code an map from zero, with exams in the middle, trust me, it is.

I made my first vJASS spell during a week of exams, and it only took me about an hour and a half
Here's a link if you're interested. Seeing as it was my first spell though, there are a few bad things associated with it - firstly, I used triggeractions instead of triggerconditions (and noone thought to tell me -.-' and I never really got around to changing that), and secondly, I didn't recycle timers because I never knew of timer recycling at that time

Last edited by the-thingy : 07-15-2008 at 08:01 PM.
the-thingy is offline   Reply With Quote
Old 07-15-2008, 07:58 PM   #8
Kyrbi0
AKA Khyrberos
 
Kyrbi0's Avatar
 
Join Date: May 2008
Posts: 2,945

Submissions (1)

Kyrbi0 is a jewel in the rough (170)Kyrbi0 is a jewel in the rough (170)

Send a message via MSN to Kyrbi0
Default

Quote:
Originally Posted by Flame_Phoenix
...That way you have the illusion of having a unit being spawned in a random location inside the AOE....

Ah, the illusion. For a second, I thought there was something you could change in the DnD ability to make it summon actual units; that would've been cool.

~~~

And sorry, I can't really download stuff willy-nilly; I'll save it up for when I can get to it... Although I'm not sure it will be of help by then :/
__________________
My Projects, Resources, + Tutorials: ~Just got back from my mission. Glad to be back. Woot! :P~
=It was brought to my attention recently that the ":P" icon stands for "tongue-sticking out", and not the "smirky half-smile" I was using it for all these years. = Thusly I apologize for any unintentional juvenilization of my messages to anyone so afflicted.=
Kyrbi0 is offline   Reply With Quote
Old 07-15-2008, 08:02 PM   #9
Flame_Phoenix
retired coder | real ilfe
 
Flame_Phoenix's Avatar
 
Join Date: Mar 2007
Posts: 2,208

Submissions (10)

Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)

Send a message via MSN to Flame_Phoenix
Default

Quote:
((1-1)*3) + (1 to 3) = 0*3 + (1 to 3) = 0 + (1 to 3) = 1 to 3
((2 - 1)*3) + (1 to 3) = 1*3 + (1 to 3) = 3 + (1 to 3) = 4 to 6
((3 - 1)*3) + (1 to 3) = 2*3 + (1 to 3) = 6 + (1 to 3) = 7 to 9
Using an array for 3 units !? That is really not needed ... the spell is fine how it is... Besides I was not talking about chances but about units ... lol
Quote:
That, in most cases, allows for maximum customizability, and it very easy to alter for testing purposes (since you can just set base to <some value> and m2 to 0, and you have yourself a constant value to test with)
definitely not lol..

Quote:
That's something for your config header - add a constant boolean, and a function/constant for your duration. When (boolean) is true, kill the units when the caster stops, else add an expiration timer to them, using the function/constant value to determine how long they should live
yes I considered that option but I think that can complicate things a little bit =S

Anyway, thx for opinion guys. Any suggestions for the code ??

Collapse JASS:
scope GolemInvocation initializer Init
//===========================================================================
//=============================SETUP START===================================
//===========================================================================

    globals
        private constant integer AID = 'A001'   //the rawcode of the ability
        private constant string ANIMATION = "birth" //the animation that will be played when the unit is created
    endglobals

//===========================================================================
//============================GOLEM SETUP====================================
//===========================================================================

//===========================================================================
//===========================IMPORTANT NOTE==================================
//The returned value from golemChance1 + golemChance2 + golemChance3 must be 
//equal to 100. This formula is very important if you want to spawn a golem
//every cycle.
//===========================================================================

    private constant function weakGolemChance takes integer level returns real 
        //in level 1 we have 90% chance to get Weak Golem
        //in level 2 we have 80% chance to get Weak Golem
        //in level 3 we have 70% chance to get Weak Golem
        return 100. - (level * 10)
    endfunction
    
    private constant function mediumGolemChance takes integer level returns real 
        //in level 1 we have 6% chance to get Medium Golem
        //in level 2 we have 13% chance to get Medium Golem
        //in level 3 we have 20% chance to get Medium Golem
        
        return -1. + (level * 7.)
        
        //example of usage
        //sometimes it is either difficult or impossible to find a formula
        //for our purposes. However, you can always use an if statement, 
        //like I use in the example
        
//       local real chance = 0    
//       if (level == 1) then
//            set chance = 6.
//        elseif (level == 2) then
//            set chance = 13.
//        elseif (level == 3) then
//            set chance = 20.
//        endif
//        return chance 
        
        //please note, that finding a formula is very efficient
        //note how we compressed this whole if statement into that
        //single line
    endfunction
    
    private constant function strongGolemChance takes integer level returns real 
        //in level 1 we have 4% chance to get Strong Golem
        //in level 2 we have 7% chance to get Strong Golem
        //in level 3 we have 10% chance to get Strong Golem
        return 1. + (3. * level)
    endfunction
    
//===========================================================================
//==============================END NOTE=====================================
//Remember: golemChance1 + golemChance2 + golemChance3 = 100
//If you want to ALWAYS spawn a Golem, you must use this formula
//===========================================================================
    
    
    private constant function weakGolemType takes integer level returns integer 
        //the rawcode of the weakGolemType unit. In this case our weak
        //golem is a mud golem level 2
        return 'ngrk'
        
        //example of usage
//        local integer aUnit = 0
//        if (level == 1) then
//            set aUnit = 'h001'
//        elseif (level == 2) then
//            set aUnit = 'h002'
//        elseif (level == 3) then
//            set aUnit = 'h003'
//        endif
//        return aUnit 
        //in this example, we spawn a different unit type every level
        //please note, there are not 'h001', 'h002' and 'h003' units in this 
        //demo map
    endfunction
    
    private constant function mediumGolemType takes integer level returns integer 
        //the rawcode of the mediumGolemType unit. In this case our medium
        //golem is a rock golem level 6
        return 'ngst'
    endfunction
    
    private constant function strongGolemType takes integer level returns integer 
        //the rawcode of the strongGolemType unit. In this case our strong
        //golem is a granite golem level 9
        return 'nggr'
    endfunction

    private constant function golemLife takes integer level returns real
        return level * 20.  //the amount of time each golem will be alive live
    endfunction

    private constant function golemsPerCycle takes integer level returns integer
        //the number of golems that will be created each cycle
        return 1 + (level * 0)
    endfunction
    
    
    private constant function cycle takes integer level returns real
        //the cycle which will determine when we create golems
        //this means, golemsPerCycle golems are created every cycle
        //in this case, we create 1 golem per second (in this case a second 
        //is a cycle)
        return 1. + (level * 0) 
    endfunction
    
//===========================================================================
//============================DUST SETUP=====================================
//===========================================================================
    
    private constant function dummyEffectId takes integer level returns integer
        //the rawcode of the dummy unit that will be dust
        //this is in a function so you can have different effects in different
        //levels
        return 'h000'
    endfunction
    
    private constant function minRange takes integer level returns real
        //in this case we dont have a minimum range, which means we can 
        //create units at the center of the circle
        //the minimum range is smaller circle, inside the area of the spell
        //in which golems will not be created
        return 0.
    endfunction
    
    private constant function maxRange takes integer level returns real
        //this ensures golems are not created outside the AOE of the spell
        //this gives the AOE of the spell
        return 200. + (level * 100)
    endfunction
    
    private constant function circleCount takes integer level returns integer
        //the number of circles that will be created to give the illusion of the dust
        //effect. The more circles the more realistic, but more CPU will be needed.
        return 3 + level 
    endfunction
    
    private constant function innerCircleUnits takes integer level returns integer
        //the number of units that the most inner circle will have
        return level + 5
    endfunction
    
    private constant function innerCircleUnitsIncrease takes integer level returns integer
        //the increment of units per circle
        return level + 2
    endfunction
//===========================================================================
//=============================SETUP END=====================================
//===========================================================================

    globals 
        private group GolemInvocationCasters
        private HandleTable activeTable 
    endglobals
    
    private struct MyStruct 
        unit caster
        integer level
        timer cycleTimer 
        real spellLocX
        real spellLocY
        group dummyEffects
        
        static method create takes unit caster, real locX, real locY returns MyStruct
            local MyStruct data = MyStruct.allocate()
            
            //set variables about the caster
            set data.caster = caster
            set data.level = GetUnitAbilityLevel(data.caster, AID)
            
            //variables about the location
            set data.spellLocX = locX
            set data.spellLocY = locY
            
            //the timer which will determine when we create golems
            //creates a golem everytime it expires
            set data.cycleTimer = NewTimer()   
            
            //This groups will save the dumy dust effects, so we can kill them 
            //when the caster stops the channeling
            set data.dummyEffects = NewGroup()
            
            return data
        endmethod
        
        method onDestroy takes nothing returns nothing
            
            //here we select all units from the group and we kill them all ! =P
            //thus meaning that the dust effects will disappear ! 
            local unit f
            loop
                set f = FirstOfGroup(.dummyEffects)
                exitwhen(f == null)
                call GroupRemoveUnit(.dummyEffects, f)
                call KillUnit(f)
            endloop
            
            //since the spell is not active anymore, we clean the Table     
            call activeTable.flush(.caster) 
            
            //the units are not anymore in the active units group.
            call GroupRemoveUnit(GolemInvocationCasters, .caster) 
            
            //releasing the timer and group for CSSafety to use it one day later =D
            call ReleaseTimer(.cycleTimer)
            call ReleaseGroup(.dummyEffects)
            
        endmethod
    endstruct
    
//===========================================================================
    private function onStop takes nothing returns boolean
        local MyStruct data
        local unit u = GetTriggerUnit()
        
        //when a unit stops the channel, we verify if that unit is inside the
        //catsers group. If so, than it is because it is a caster casting this spell
        //and so we recover information about him and we make the spell end
        if(IsUnitInGroup(u, GolemInvocationCasters)) then
            //recover the data from the caster
            set data = activeTable[u] 
            
            //now, time to clean the mess once again
            call data.destroy() 
        endif

        set u = null
        
        return false
    endfunction
//===========================================================================
    //Function made by Themerion and adapted by Flame_Phoenix
    //Creates circles of dummy units to give the illusion of the dust effect
    private function createDust takes integer aStruct returns nothing
        local MyStruct data = aStruct
        
        // forPlayer     -> Create the units for which player?
        local player forPlayer = GetOwningPlayer(data.caster)
        
        // innerRadius   -> The radius of the innermost circle
        // outerRadius   -> The radius of the outmost circle
        local real innerRadius = minRange(data.level)
        local real outerRadius = maxRange(data.level)
        
        // x and y       -> Center of circles
        local real x = data.spellLocX
        local real y = data.spellLocY

        local real radiusInc = (outerRadius - innerRadius) / I2R(circleCount(data.level)-1)
        
        //see funtions they call
        local integer fxcount = innerCircleUnits(data.level)
        local integer fxcountinc = innerCircleUnitsIncrease(data.level)
        
        local real phi = 0
        local real phiInc

        loop
            exitwhen (innerRadius + 0.001 >= outerRadius)

            set phi = 0
            set phiInc = 2*bj_PI/I2R(fxcount)
            
            loop
                exitwhen (phi + 0.001 >= 2 * bj_PI)
                //we add the units to a group, so we can kill them when we want ! =P
                call GroupAddUnit(data.dummyEffects, CreateUnit(forPlayer, dummyEffectId(data.level), x + innerRadius * Cos(phi), y + innerRadius * Sin(phi), 180 + Rad2Deg(phi)))
                set phi = phi + phiInc
            endloop
            
        set innerRadius = innerRadius + radiusInc
        set fxcount = fxcount + fxcountinc
        
        endloop
        
        set forPlayer = null
    
    endfunction
//===========================================================================
    //Function made by Vexorian, it selects a random region in a disk. 
    //All regions have the same chance of beeing choosen
    private function GetRandomPointInDisk takes real centerx, real centery, real minradius, real maxradius returns location
        local real d = SquareRoot(GetRandomReal(minradius * minradius, maxradius * maxradius))
        local real a = GetRandomReal(0, 2 * bj_PI)
        return Location(centerx + d * Cos(a), centery + d * Sin(a))
    endfunction
//===========================================================================
    private function createGolems takes nothing returns nothing
        //we get the structure from the timer
        local MyStruct data = MyStruct(GetCSData(GetExpiredTimer())) 
        
        //variables for us to know where the golems will born
        local location point  
        local real randomX  
        local real randomY 
        
        //the chances that each golem will have to be spawned
        local real aChance
        
        //just to keep count about how many golems we created
        local integer loopCounter = 0
        
        //cariables about the golems
        local unit golem
        local real golemFacing = GetUnitFacing(data.caster)
        
        //Here we spawn the golems 
        loop 
            exitwhen(loopCounter >= golemsPerCycle(data.level))
                
            set point = GetRandomPointInDisk(data.spellLocX, data.spellLocY, minRange(data.level), maxRange(data.level))
            set randomX = GetLocationX(point)
            set randomY = GetLocationY(point)
            set aChance = GetRandomReal(0, 100)
            
            if (aChance <= 100 - weakGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), weakGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
            elseif (aChance <= 100 - mediumGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), mediumGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
            elseif (aChance <= 100 - strongGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), strongGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))    
            endif   
            
            call RemoveLocation(point)
            set point = null
                
            set loopCounter = loopCounter + 1
        endloop
    
    set golem = null

    endfunction
//===========================================================================
    private function Conditions takes nothing returns boolean
        local MyStruct data
        local location spellLoc //the location of the spell
        
        if (GetSpellAbilityId() == AID) then
            //setting variables for the struct
            set spellLoc = GetSpellTargetLoc()
            set data = MyStruct.create(GetTriggerUnit(), GetLocationX(spellLoc), GetLocationY(spellLoc))
            
            //put the struct in the Table, we just use the caster's handle adress as 
            //the key which tells us where in the Table the struct is stored
            set activeTable[data.caster] = data 

            //  we add the casting unit to some sort of "pool"
            call GroupAddUnit(GolemInvocationCasters, data.caster)
            
            //now we create the dusty effect
            call createDust(data)
            
            //we attach the struct to the timer
            call SetCSData(data.cycleTimer, integer(data))
            call TimerStart(data.cycleTimer, cycle(data.level), true, function createGolems)
            
            //cleaning up the mess
            call RemoveLocation(spellLoc)
        endif
        
        set spellLoc = null
        
        return false
    endfunction
//===========================================================================
    private function Init takes nothing returns nothing
        local trigger GolemInvocationTrigger = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(GolemInvocationTrigger, Condition( function Conditions ) )
        
        set GolemInvocationTrigger = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        call TriggerAddCondition(GolemInvocationTrigger,  Condition(function onStop))

        set GolemInvocationTrigger = null
        
        //set our globals
        set activeTable = HandleTable.create() 
        set GolemInvocationCasters = NewGroup() 

        set GolemInvocationTrigger = null
    endfunction
endscope 

Anyway, This is nearly the last version of the code before submission.
I may add the kill golems when caster stops thing.

About Earthquake... isn't there other solution ??? =S
__________________
Check out my tutorials at:
1-Creating a Hero Tavern
2-Complete Icon Tutorial - ALL about Icons
3-Making a spell in vJass - Practice Session 1
Check out all my current spells at here
Finally, check my project:
Castle vs Castle Flame Edition

Last edited by Flame_Phoenix : 07-15-2008 at 08:02 PM.
Flame_Phoenix is offline   Reply With Quote
Old 07-15-2008, 08:19 PM   #10
the-thingy
User
 
Join Date: Feb 2006
Posts: 172

the-thingy will become famous soon enough (30)the-thingy will become famous soon enough (30)

Default

Quote:
Using an array for 3 units !? That is really not needed ... the spell is fine how it is... Besides I was not talking about chances but about units ... lol

1) I was going by your example (whereby level 1 would create one of three different golems, level 2 would create one of three fire-based units, etc). Anyway, using the array lets you condense those 3 functions into one. Why should you use 3 functions for 3 units?

2) I was talking about the units too

Quote:
definitely not lol..
Definitely not what? Anyway, that was just an example of how you can make stuff very customizable since you all you have to do is change 3 or 4 (assuming you're taking a unit argument, you would probably only need 2 extra values if you took a level argument) clearly labelled values, and you've got new stats for the spell :)

Quote:
yes I considered that option but I think that can complicate things a little bit =S
Well, if you want people to use the spell, you should make it as easy as possible for them to manipulate it to their liking (and the map-type that the spell ends up in). All you have to do is
1) When spawning the golems, check if the boolean is true and do the approriate thing (add them to the group, or apply an expiration timer)
Collapse JASS:
if DEATH_UPON_ENDCAST then
   call GroupAddUnit (golemvar, data.Golems)
else
   call UnitApplyTimedLife (golemvar, timerid, time)
endif

2) When the caster stops casting, just do a ForGroup using the previously mentioned group which will kill them :D
Collapse JASS:
if DEATH_UPON_ENDCAST then
   call ForGroup (data.Golems, function KillGolems)
endif

Anyway, these are only my thoughts on what you can do to improve it, I never said anything about you having to change them

Last edited by the-thingy : 07-15-2008 at 08:30 PM.
the-thingy is offline   Reply With Quote
Old 07-15-2008, 10:29 PM   #11
Flame_Phoenix
retired coder | real ilfe
 
Flame_Phoenix's Avatar
 
Join Date: Mar 2007
Posts: 2,208

Submissions (10)

Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)

Send a message via MSN to Flame_Phoenix
Default

I am not using an array for three values. Three values are perfectly easy to manage, it's like having an array for 3 integers =P

About the other thing, I may do it =)
__________________
Check out my tutorials at:
1-Creating a Hero Tavern
2-Complete Icon Tutorial - ALL about Icons
3-Making a spell in vJass - Practice Session 1
Check out all my current spells at here
Finally, check my project:
Castle vs Castle Flame Edition
Flame_Phoenix is offline   Reply With Quote
Old 07-15-2008, 11:17 PM   #12
the-thingy
User
 
Join Date: Feb 2006
Posts: 172

the-thingy will become famous soon enough (30)the-thingy will become famous soon enough (30)

Default

Quote:
Originally Posted by Flame_Phoenix
I am not using an array for three values. Three values are perfectly easy to manage
You aren't willing to use a single array for 3 values, but you are willing to use 3 functions instead? Your logic confuses me...

1) With arrays, everything can go into one function
2) Said function only needs to be called once, for initialization - slight improvement to code speed
3) The idea behind arrays is for storing multiple similar values - seems sensible to use it since you are referring to multiple similar values
4) The random chance could be solved pretty easily

Collapse JASS:
function GetGolemArrayIndex takes integer level returns integer
  local integer rnd = GetRandomInt (1, 100)
  local integer low = weakGoleChance (level)
  local integer med = mediumGolemChance (level)
  local integer index

  if rnd <= low then
    set index = 1
  elseif rnd >= low and rnd <= med + low then
    set index = 2
  elseif rnd >= med + low then
    set index = 3
  endif

  return index
endfunction

Then you've got the array index for the unit which should be summoned

Quote:
it's like having an array for 3 integers =P
Well, if the 3 integers are being used for a similar purpose (say you want to store caster's hero level and target's hero level, an array would be suitable since you are storing two similar values OR if you want to store multiple unit ID's ), why shouldn't you use arrays?

Last edited by the-thingy : 07-15-2008 at 11:18 PM.
the-thingy is offline   Reply With Quote
Old 07-15-2008, 11:57 PM   #13
Flame_Phoenix
retired coder | real ilfe
 
Flame_Phoenix's Avatar
 
Join Date: Mar 2007
Posts: 2,208

Submissions (10)

Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)

Send a message via MSN to Flame_Phoenix
Default

Well, last time Vexorian almost killed me because I was using an array for 2 values ... I won't risk it again because of an array of 3 values.
Besides the functions are all constant, meaning they are faster.

Anyway, I improved the code, this is most likely to be the final version.
Hope you people like it. Add the boolean for the channel thing =P

Collapse JASS:
scope GolemInvocation initializer Init
//===========================================================================
//=============================SETUP START===================================
//===========================================================================

    globals
        private constant integer AID = 'A001'   //the rawcode of the ability
        private constant string ANIMATION = "birth" //the animation that will be played when the unit is created
    endglobals

//===========================================================================
//============================GOLEM SETUP====================================
//===========================================================================

//===========================================================================
//===========================IMPORTANT NOTE==================================
//The returned value from golemChance1 + golemChance2 + golemChance3 must be 
//equal to 100. This formula is very important if you want to spawn a golem
//every cycle.
//===========================================================================

    private constant function weakGolemChance takes integer level returns real 
        //in level 1 we have 90% chance to get Weak Golem
        //in level 2 we have 80% chance to get Weak Golem
        //in level 3 we have 70% chance to get Weak Golem
        return 100. - (level * 10)
    endfunction
    
    private constant function mediumGolemChance takes integer level returns real 
        //in level 1 we have 6% chance to get Medium Golem
        //in level 2 we have 13% chance to get Medium Golem
        //in level 3 we have 20% chance to get Medium Golem
        
        return -1. + (level * 7.)
        
        //example of usage
        //sometimes it is either difficult or impossible to find a formula
        //for our purposes. However, you can always use an if statement, 
        //like I use in the example
        
//       local real chance = 0    
//       if (level == 1) then
//            set chance = 6.
//        elseif (level == 2) then
//            set chance = 13.
//        elseif (level == 3) then
//            set chance = 20.
//        endif
//        return chance 
        
        //please note, that finding a formula is very efficient
        //note how we compressed this whole if statement into that
        //single line
    endfunction
    
    private constant function strongGolemChance takes integer level returns real 
        //in level 1 we have 4% chance to get Strong Golem
        //in level 2 we have 7% chance to get Strong Golem
        //in level 3 we have 10% chance to get Strong Golem
        return 1. + (3. * level)
    endfunction
    
//===========================================================================
//==============================END NOTE=====================================
//Remember: golemChance1 + golemChance2 + golemChance3 = 100
//If you want to ALWAYS spawn a Golem, you must use this formula
//===========================================================================
    
    
    private constant function weakGolemType takes integer level returns integer 
        //the rawcode of the weakGolemType unit. In this case our weak
        //golem is a mud golem level 2
        return 'ngrk'
        
        //example of usage
//        local integer aUnit = 0
//        if (level == 1) then
//            set aUnit = 'h001'
//        elseif (level == 2) then
//            set aUnit = 'h002'
//        elseif (level == 3) then
//            set aUnit = 'h003'
//        endif
//        return aUnit 
        //in this example, we spawn a different unit type every level
        //please note, there are not 'h001', 'h002' and 'h003' units in this 
        //demo map
    endfunction
    
    private constant function mediumGolemType takes integer level returns integer 
        //the rawcode of the mediumGolemType unit. In this case our medium
        //golem is a rock golem level 6
        return 'ngst'
    endfunction
    
    private constant function strongGolemType takes integer level returns integer 
        //the rawcode of the strongGolemType unit. In this case our strong
        //golem is a granite golem level 9
        return 'nggr'
    endfunction

    private constant function golemLife takes integer level returns real
        return level * 20.  //the amount of time each golem will be alive live
    endfunction

    private constant function channelGolems takes integer level returns boolean
        //if true it will make all spawned golems die when the caster stops the channel
        //if false, it allows the golems to have golemLife seconds of life and they
        //will not die when the caster stops the channel
        //in this case my golems 20, 40 and 60 seconds of life for each leavel.
        return false
        
        //example of usage
//        local boolean result = true
//        if (level == 3) then
//            set result = false
//        endif
//        return result
        //in this example the golems will die when the channel ends in level 1 and 2
        //in level 3, the golems will live 60 seconds of life
    endfunction
    
    private constant function golemsPerCycle takes integer level returns integer
        //the number of golems that will be created each cycle
        return 1 + (level * 0)
    endfunction
    
    
    private constant function cycle takes integer level returns real
        //the cycle which will determine when we create golems
        //this means, golemsPerCycle golems are created every cycle
        //in this case, we create 1 golem per second (in this case a second 
        //is a cycle)
        return 1. + (level * 0) 
    endfunction
    
//===========================================================================
//============================DUST SETUP=====================================
//===========================================================================
    
    private constant function dummyEffectId takes integer level returns integer
        //the rawcode of the dummy unit that will be dust
        //this is in a function so you can have different effects in different
        //levels
        return 'h000'
    endfunction
    
    private constant function minRange takes integer level returns real
        //in this case we dont have a minimum range, which means we can 
        //create units at the center of the circle
        //the minimum range is smaller circle, inside the area of the spell
        //in which golems will not be created
        return 0.
    endfunction
    
    private constant function maxRange takes integer level returns real
        //this ensures golems are not created outside the AOE of the spell
        //this gives the AOE of the spell
        return 200. + (level * 100)
    endfunction
    
    private constant function circleCount takes integer level returns integer
        //the number of circles that will be created to give the illusion of the dust
        //effect. The more circles the more realistic, but more CPU will be needed.
        return 3 + level 
    endfunction
    
    private constant function innerCircleUnits takes integer level returns integer
        //the number of units that the most inner circle will have
        return level + 5
    endfunction
    
    private constant function innerCircleUnitsIncrease takes integer level returns integer
        //the increment of units per circle
        return level + 2
    endfunction
//===========================================================================
//=============================SETUP END=====================================
//===========================================================================

    globals 
        private group GolemInvocationCasters
        private HandleTable activeTable 
    endglobals
    
    private struct MyStruct 
        unit caster
        integer level
        timer cycleTimer 
        real spellLocX
        real spellLocY
        group dummyEffects
        group golems
        
        static method create takes unit caster, real locX, real locY returns MyStruct
            local MyStruct data = MyStruct.allocate()
            
            //set variables about the caster
            set data.caster = caster
            set data.level = GetUnitAbilityLevel(data.caster, AID)
            
            //variables about the location
            set data.spellLocX = locX
            set data.spellLocY = locY
            
            //the timer which will determine when we create golems
            //creates a golem everytime it expires
            set data.cycleTimer = NewTimer()   
            
            //This groups will save the dumy dust effects, so we can kill them 
            //when the caster stops the channeling
            set data.dummyEffects = NewGroup()
            
            //if we want the golems to die when the caster stops channel
            //then we create this group so we can add all golems to it
            //then we kill the golems when the caster stops the channel
            if (channelGolems(data.level)) then
                set data.golems = NewGroup()
            endif
            
            return data
        endmethod
        
        method onDestroy takes nothing returns nothing
            
            //here we select all units from the group and we kill them all ! =P
            //thus meaning that the dust effects will disappear ! 
            local unit f
            loop
                set f = FirstOfGroup(.dummyEffects)
                exitwhen(f == null)
                call GroupRemoveUnit(.dummyEffects, f)
                call KillUnit(f)
            endloop
            
            //if the variable is true, then golems group was created and it has
            //units. Now we just kill all units it has and we release the group
            //for CSSafety to use one day later
            if (channelGolems(.level)) then
                loop
                    set f = FirstOfGroup(.golems)
                    exitwhen(f == null)
                    call GroupRemoveUnit(.golems, f)
                    call KillUnit(f)
            endloop
            
            call ReleaseGroup(.golems)
            endif
            
            //since the spell is not active anymore, we clean the Table     
            call activeTable.flush(.caster) 
            
            //the units are not anymore in the active units group.
            call GroupRemoveUnit(GolemInvocationCasters, .caster) 
            
            //releasing the timer and group for CSSafety to use it one day later =D
            call ReleaseTimer(.cycleTimer)
            call ReleaseGroup(.dummyEffects)
            
        endmethod
    endstruct
    
//===========================================================================
    private function onStop takes nothing returns boolean
        local MyStruct data
        local unit u = GetTriggerUnit()
        
        //when a unit stops the channel, we verify if that unit is inside the
        //catsers group. If so, than it is because it is a caster casting this spell
        //and so we recover information about him and we make the spell end
        if(IsUnitInGroup(u, GolemInvocationCasters)) then
            //recover the data from the caster
            set data = activeTable[u] 
            
            //now, time to clean the mess once again
            call data.destroy() 
        endif

        set u = null
        
        return false
    endfunction
//===========================================================================
    //Function made by Themerion and adapted by Flame_Phoenix
    //Creates circles of dummy units to give the illusion of the dust effect
    private function createDust takes integer aStruct returns nothing
        local MyStruct data = aStruct
        
        // forPlayer     -> Create the units for which player?
        local player forPlayer = GetOwningPlayer(data.caster)
        
        // innerRadius   -> The radius of the innermost circle
        // outerRadius   -> The radius of the outmost circle
        local real innerRadius = minRange(data.level)
        local real outerRadius = maxRange(data.level)
        
        // x and y       -> Center of circles
        local real x = data.spellLocX
        local real y = data.spellLocY

        local real radiusInc = (outerRadius - innerRadius) / I2R(circleCount(data.level)-1)
        
        //see funtions they call
        local integer fxcount = innerCircleUnits(data.level)
        local integer fxcountinc = innerCircleUnitsIncrease(data.level)
        
        local real phi = 0
        local real phiInc

        loop
            exitwhen (innerRadius + 0.001 >= outerRadius)

            set phi = 0
            set phiInc = 2*bj_PI/I2R(fxcount)
            
            loop
                exitwhen (phi + 0.001 >= 2 * bj_PI)
                //we add the units to a group, so we can kill them when we want ! =P
                call GroupAddUnit(data.dummyEffects, CreateUnit(forPlayer, dummyEffectId(data.level), x + innerRadius * Cos(phi), y + innerRadius * Sin(phi), 180 + Rad2Deg(phi)))
                set phi = phi + phiInc
            endloop
            
        set innerRadius = innerRadius + radiusInc
        set fxcount = fxcount + fxcountinc
        
        endloop
        
        set forPlayer = null
    
    endfunction
//===========================================================================
    //Function made by Vexorian, it selects a random region in a disk. 
    //All regions have the same chance of beeing choosen
    private function GetRandomPointInDisk takes real centerx, real centery, real minradius, real maxradius returns location
        local real d = SquareRoot(GetRandomReal(minradius * minradius, maxradius * maxradius))
        local real a = GetRandomReal(0, 2 * bj_PI)
        return Location(centerx + d * Cos(a), centery + d * Sin(a))
    endfunction
//===========================================================================
    private function createGolems takes nothing returns nothing
        //we get the structure from the timer
        local MyStruct data = MyStruct(GetCSData(GetExpiredTimer())) 
        
        //variables for us to know where the golems will born
        local location point  
        local real randomX  
        local real randomY 
        
        //the chances that each golem will have to be spawned
        local real aChance
        
        //just to keep count about how many golems we created
        local integer loopCounter = 0
        
        //cariables about the golems
        local unit golem
        local real golemFacing = GetUnitFacing(data.caster)
        
        //Here we spawn the golems 
        loop 
            exitwhen(loopCounter >= golemsPerCycle(data.level))
                
            set point = GetRandomPointInDisk(data.spellLocX, data.spellLocY, minRange(data.level), maxRange(data.level))
            set randomX = GetLocationX(point)
            set randomY = GetLocationY(point)
            set aChance = GetRandomReal(0, 100)
            
            if (aChance <= 100 - weakGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), weakGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                
                //if channelGolems(data.level) is true we add the golem to it 
                //so we can keep track of it and kill it later in the "onDestroy"
                //method
                //else if the variable is false, it means that the group was not
                //created, and we ant the units to have a LifeTime
                if (channelGolems(data.level)) then
                    call GroupAddUnit(data.golems, golem)
                else
                    call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
                endif
            elseif (aChance <= 100 - mediumGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), mediumGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                
                //if channelGolems(data.level) is true we add the golem to it 
                //so we can keep track of it and kill it later in the "onDestroy"
                //method
                //else if the variable is false, it means that the group was not
                //created, and we ant the units to have a LifeTime
                if (channelGolems(data.level)) then
                    call GroupAddUnit(data.golems, golem)
                else
                    call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
                endif
            elseif (aChance <= 100 - strongGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), strongGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                
                //if channelGolems(data.level) is true we add the golem to it 
                //so we can keep track of it and kill it later in the "onDestroy"
                //method
                //else if the variable is false, it means that the group was not
                //created, and we ant the units to have a LifeTime
                if (channelGolems(data.level)) then
                    call GroupAddUnit(data.golems, golem)
                else
                    call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
                endif
            endif   
            
            call RemoveLocation(point)
            set point = null
                
            set loopCounter = loopCounter + 1
        endloop
    
    set golem = null

    endfunction
//===========================================================================
    private function Conditions takes nothing returns boolean
        local MyStruct data
        local location spellLoc //the location of the spell
        
        if (GetSpellAbilityId() == AID) then
            //setting variables for the struct
            set spellLoc = GetSpellTargetLoc()
            set data = MyStruct.create(GetTriggerUnit(), GetLocationX(spellLoc), GetLocationY(spellLoc))
            
            //put the struct in the Table, we just use the caster's handle adress as 
            //the key which tells us where in the Table the struct is stored
            set activeTable[data.caster] = data 

            //  we add the casting unit to some sort of "pool"
            call GroupAddUnit(GolemInvocationCasters, data.caster)
            
            //now we create the dusty effect
            call createDust(data)
            
            //we attach the struct to the timer
            call SetCSData(data.cycleTimer, integer(data))
            call TimerStart(data.cycleTimer, cycle(data.level), true, function createGolems)
            
            //cleaning up the mess
            call RemoveLocation(spellLoc)
        endif
        
        set spellLoc = null
        
        return false
    endfunction
//===========================================================================
    private function Init takes nothing returns nothing
        local trigger GolemInvocationTrigger = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(GolemInvocationTrigger, Condition( function Conditions ) )
        
        set GolemInvocationTrigger = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        call TriggerAddCondition(GolemInvocationTrigger,  Condition(function onStop))

        set GolemInvocationTrigger = null
        
        //set our globals
        set activeTable = HandleTable.create() 
        set GolemInvocationCasters = NewGroup() 

        set GolemInvocationTrigger = null
    endfunction
endscope 

Also have the map for you all to have fun with the spell.
However I still have the problem of the buff ... Earthquake =(
Attached Files
File Type: w3x Golem Invocation.w3x (36.5 KB, 2 views)
__________________
Check out my tutorials at:
1-Creating a Hero Tavern
2-Complete Icon Tutorial - ALL about Icons
3-Making a spell in vJass - Practice Session 1
Check out all my current spells at here
Finally, check my project:
Castle vs Castle Flame Edition

Last edited by Flame_Phoenix : 07-15-2008 at 11:57 PM.
Flame_Phoenix is offline   Reply With Quote
Old 07-18-2008, 12:49 PM   #14
Flame_Phoenix
retired coder | real ilfe
 
Flame_Phoenix's Avatar
 
Join Date: Mar 2007
Posts: 2,208

Submissions (10)

Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)Flame_Phoenix has a spectacular aura about (90)

Send a message via MSN to Flame_Phoenix
Default

Hi guys here is probably the final version of the spell. I am on hollidays, so I do not have access to internet, and so, I am inside a cyber shop.
I didn't see your suggestions, although I will try to approve the code as soon as possible. Nonless for those of you who wish to see the spell here is it.
I also added another demo spell, called Fire Cataclism. I like the somke effects in level 3, but they can be changed. Anyway this new spell allows people to see the great potential of the structure of the spell, and I hope they all like it.
Without any other stuff to say, and because I only have 30 minutes use interner and must leave soon, here are the spell codes:
About Golem Invocation, I just took advantage of not being able to change the buff. After all, creating dust only makes sense if we have an earthquake going on, and if wc3 already has it, why not use it ? =P

Golem Invocation
Collapse JASS:
//===========================================================================
//A spell that creates an Earthquake. This earthquake creates dust and spawns 
//golems inside the target area. Each golem has a period of life, and weaker
//golems have more chances to be spawned.
//
//Requires CSData, CSSafety and Table
//
//@author Flame_Phoenix 
//
//@credits
//- the-thingy, Kyrbi0
//- My first teacher of vJASS: Blue_Jeans
//- All other people I forgot or ignored
//
//@version 1.0
//===========================================================================
scope GolemInvocation initializer Init
//===========================================================================
//=============================SETUP START===================================
//===========================================================================

    globals
        private constant integer AID = 'A001'   //the rawcode of the ability
        private constant string ANIMATION = "birth" //the animation that will be played when the unit is created
    endglobals

//===========================================================================
//============================GOLEM SETUP====================================
//===========================================================================

//===========================================================================
//===========================IMPORTANT NOTE==================================
//The returned value from golemChance1 + golemChance2 + golemChance3 must be 
//equal to 100. This formula is very important if you want to spawn a golem
//every cycle.
//===========================================================================

    private constant function weakGolemChance takes integer level returns real 
        //in level 1 we have 90% chance to get Weak Golem
        //in level 2 we have 80% chance to get Weak Golem
        //in level 3 we have 70% chance to get Weak Golem
        return 100. - (level * 10)
    endfunction
    
    private constant function mediumGolemChance takes integer level returns real 
        //in level 1 we have 6% chance to get Medium Golem
        //in level 2 we have 13% chance to get Medium Golem
        //in level 3 we have 20% chance to get Medium Golem
        
        return (level * 7.) - 1.
        
        //example of usage
        //sometimes it is either difficult or impossible to find a formula
        //for our purposes. However, you can always use an if statement, 
        //like I use in the example
        
//       local real chance = 0    
//       if (level == 1) then
//            set chance = 6.
//        elseif (level == 2) then
//            set chance = 13.
//        elseif (level == 3) then
//            set chance = 20.
//        endif
//        return chance 
        
        //please note, that finding a formula is very efficient
        //note how we compressed this whole if statement into that
        //single line
    endfunction
    
    private constant function strongGolemChance takes integer level returns real 
        //in level 1 we have 4% chance to get Strong Golem
        //in level 2 we have 7% chance to get Strong Golem
        //in level 3 we have 10% chance to get Strong Golem
        return 1. + (3. * level)
    endfunction
    
//===========================================================================
//==============================END NOTE=====================================
//Remember: golemChance1 + golemChance2 + golemChance3 = 100
//If you want to ALWAYS spawn a Golem, you must use this formula
//===========================================================================
    
    
    private constant function weakGolemType takes integer level returns integer 
        //the rawcode of the weakGolemType unit. In this case our weak
        //golem is a mud golem level 2
        return 'ngrk'
        
        //example of usage
//        local integer aUnit = 0
//        if (level == 1) then
//            set aUnit = 'h001'
//        elseif (level == 2) then
//            set aUnit = 'h002'
//        elseif (level == 3) then
//            set aUnit = 'h003'
//        endif
//        return aUnit 
        //in this example, we spawn a different unit type every level
        //please note, there are not 'h001', 'h002' and 'h003' units in this 
        //demo map
    endfunction
    
    private constant function mediumGolemType takes integer level returns integer 
        //the rawcode of the mediumGolemType unit. In this case our medium
        //golem is a rock golem level 6
        return 'ngst'
    endfunction
    
    private constant function strongGolemType takes integer level returns integer 
        //the rawcode of the strongGolemType unit. In this case our strong
        //golem is a granite golem level 9
        return 'nggr'
    endfunction

    private constant function golemLife takes integer level returns real
        return level * 20.  //the amount of time each golem will be alive live
    endfunction

    private constant function channelGolems takes integer level returns boolean
        //if true it will make all spawned golems die when the caster stops the channel
        //if false, it allows the golems to have golemLife seconds of life and they
        //will not die when the caster stops the channel
        //in this case my golems 20, 40 and 60 seconds of life for each leavel.
        return false
        
        //example of usage
//        local boolean result = true
//        if (level == 3) then
//            set result = false
//        endif
//        return result
        //in this example the golems will die when the channel ends in level 1 and 2
        //in level 3, the golems will live 60 seconds of life
    endfunction
    
    private constant function golemsPerCycle takes integer level returns integer
        //the number of golems that will be created each cycle
        return 1 + (level * 0)
    endfunction
    
    
    private constant function cycle takes integer level returns real
        //the cycle which will determine when we create golems
        //this means, golemsPerCycle golems are created every cycle
        //in this case, we create 1 golem per second (in this case a second 
        //is a cycle)
        return 1. + (level * 0) 
    endfunction
    
//===========================================================================
//============================DUST SETUP=====================================
//===========================================================================
    
    private constant function dummyEffectId takes integer level returns integer
        //the rawcode of the dummy unit that will be dust
        //this is in a function so you can have different effects in different
        //levels
        return 'h000'
    endfunction
    
    private constant function minRange takes integer level returns real
        //in this case we dont have a minimum range, which means we can 
        //create units at the center of the circle
        //the minimum range is smaller circle, inside the area of the spell
        //in which golems will not be created
        return 0.
    endfunction
    
    private constant function maxRange takes integer level returns real
        //this ensures golems are not created outside the AOE of the spell
        //this gives the AOE of the spell
        return 200. + (level * 100)
    endfunction
    
    private constant function circleCount takes integer level returns integer
        //the number of circles that will be created to give the illusion of the dust
        //effect. The more circles the more realistic, but more CPU will be needed.
        return 3 + level 
    endfunction
    
    private constant function innerCircleUnits takes integer level returns integer
        //the number of units that the most inner circle will have
        return level + 5
    endfunction
    
    private constant function innerCircleUnitsIncrease takes integer level returns integer
        //the increment of units per circle
        return level + 2
    endfunction
//===========================================================================
//=============================SETUP END=====================================
//===========================================================================

    globals 
        private group GolemInvocationCasters
        private HandleTable activeTable 
    endglobals
    
    private struct MyStruct 
        unit caster
        integer level
        timer cycleTimer 
        real spellLocX
        real spellLocY
        group dummyEffects
        group golems
        
        static method create takes unit caster, real locX, real locY returns MyStruct
            local MyStruct data = MyStruct.allocate()
            
            //set variables about the caster
            set data.caster = caster
            set data.level = GetUnitAbilityLevel(data.caster, AID)
            
            //variables about the location
            set data.spellLocX = locX
            set data.spellLocY = locY
            
            //the timer which will determine when we create golems
            //creates a golem everytime it expires
            set data.cycleTimer = NewTimer()   
            
            //This groups will save the dumy dust effects, so we can kill them 
            //when the caster stops the channeling
            set data.dummyEffects = NewGroup()
            
            //if we want the golems to die when the caster stops channel
            //then we create this group so we can add all golems to it
            //then we kill the golems when the caster stops the channel
            if (channelGolems(data.level)) then
                set data.golems = NewGroup()
            endif
            
            return data
        endmethod
        
        method onDestroy takes nothing returns nothing
            
            //here we select all units from the group and we kill them all ! =P
            //thus meaning that the dust effects will disappear ! 
            local unit f
            loop
                set f = FirstOfGroup(.dummyEffects)
                exitwhen(f == null)
                call GroupRemoveUnit(.dummyEffects, f)
                call KillUnit(f)
            endloop
            
            //if the variable is true, then golems group was created and it has
            //units. Now we just kill all units it has and we release the group
            //for CSSafety to use one day later
            if (channelGolems(.level)) then
                loop
                    set f = FirstOfGroup(.golems)
                    exitwhen(f == null)
                    call GroupRemoveUnit(.golems, f)
                    call KillUnit(f)
            endloop
            
            call ReleaseGroup(.golems)
            endif
            
            //since the spell is not active anymore, we clean the Table     
            call activeTable.flush(.caster) 
            
            //the units are not anymore in the active units group.
            call GroupRemoveUnit(GolemInvocationCasters, .caster) 
            
            //releasing the timer and group for CSSafety to use it one day later =D
            call ReleaseTimer(.cycleTimer)
            call ReleaseGroup(.dummyEffects)
            
        endmethod
    endstruct
    
//===========================================================================
    private function onStop takes nothing returns boolean
        local MyStruct data
        local unit u = GetTriggerUnit()
        
        //when a unit stops the channel, we verify if that unit is inside the
        //catsers group. If so, than it is because it is a caster casting this spell
        //and so we recover information about him and we make the spell end
        if(IsUnitInGroup(u, GolemInvocationCasters)) then
            //recover the data from the caster
            set data = activeTable[u] 
            
            //now, time to clean the mess once again
            call data.destroy() 
        endif

        set u = null
        
        return false
    endfunction
//===========================================================================
    //Function made by Themerion and adapted by Flame_Phoenix
    //Creates circles of dummy units to give the illusion of the dust effect
    private function createDust takes integer aStruct returns nothing
        local MyStruct data = aStruct
        
        // forPlayer     -> Create the units for which player?
        local player forPlayer = GetOwningPlayer(data.caster)
        
        // innerRadius   -> The radius of the innermost circle
        // outerRadius   -> The radius of the outmost circle
        local real innerRadius = minRange(data.level)
        local real outerRadius = maxRange(data.level)
        
        // x and y       -> Center of circles
        local real x = data.spellLocX
        local real y = data.spellLocY

        local real radiusInc = (outerRadius - innerRadius) / I2R(circleCount(data.level)-1)
        
        //see funtions they call
        local integer fxcount = innerCircleUnits(data.level)
        local integer fxcountinc = innerCircleUnitsIncrease(data.level)
        
        local real phi = 0
        local real phiInc

        loop
            exitwhen (innerRadius + 0.001 >= outerRadius)

            set phi = 0
            set phiInc = 2*bj_PI/I2R(fxcount)
            
            loop
                exitwhen (phi + 0.001 >= 2 * bj_PI)
                //we add the units to a group, so we can kill them when we want ! =P
                call GroupAddUnit(data.dummyEffects, CreateUnit(forPlayer, dummyEffectId(data.level), x + innerRadius * Cos(phi), y + innerRadius * Sin(phi), 180 + Rad2Deg(phi)))
                set phi = phi + phiInc
            endloop
            
        set innerRadius = innerRadius + radiusInc
        set fxcount = fxcount + fxcountinc
        
        endloop
        
        set forPlayer = null
    
    endfunction
//===========================================================================
    //Function made by Vexorian, it selects a random region in a disk. 
    //All regions have the same chance of beeing choosen
    private function GetRandomPointInDisk takes real centerx, real centery, real minradius, real maxradius returns location
        local real d = SquareRoot(GetRandomReal(minradius * minradius, maxradius * maxradius))
        local real a = GetRandomReal(0, 2 * bj_PI)
        return Location(centerx + d * Cos(a), centery + d * Sin(a))
    endfunction
//===========================================================================
    private function createGolems takes nothing returns nothing
        //we get the structure from the timer
        local MyStruct data = MyStruct(GetCSData(GetExpiredTimer())) 
        
        //variables for us to know where the golems will born
        local location point  
        local real randomX  
        local real randomY 
        
        //the chances that each golem will have to be spawned
        local real aChance
        
        //just to keep count about how many golems we created
        local integer loopCounter = 0
        
        //cariables about the golems
        local unit golem
        local real golemFacing = GetUnitFacing(data.caster)
        
        //Here we spawn the golems 
        loop 
            exitwhen(loopCounter >= golemsPerCycle(data.level))
                
            set point = GetRandomPointInDisk(data.spellLocX, data.spellLocY, minRange(data.level), maxRange(data.level))
            set randomX = GetLocationX(point)
            set randomY = GetLocationY(point)
            set aChance = GetRandomReal(0, 100)
            
            if (aChance <= 100 - weakGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), weakGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                
                //if channelGolems(data.level) is true we add the golem to it 
                //so we can keep track of it and kill it later in the "onDestroy"
                //method
                //else if the variable is false, it means that the group was not
                //created, and we ant the units to have a LifeTime
                if (channelGolems(data.level)) then
                    call GroupAddUnit(data.golems, golem)
                else
                    call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
                endif
            elseif (aChance <= 100 - mediumGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), mediumGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                
                //if channelGolems(data.level) is true we add the golem to it 
                //so we can keep track of it and kill it later in the "onDestroy"
                //method
                //else if the variable is false, it means that the group was not
                //created, and we ant the units to have a LifeTime
                if (channelGolems(data.level)) then
                    call GroupAddUnit(data.golems, golem)
                else
                    call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
                endif
            elseif (aChance <= 100 - strongGolemChance(data.level)) then
                set golem =  CreateUnit(GetOwningPlayer(data.caster), strongGolemType(data.level), randomX, randomY, golemFacing)
                call SetUnitAnimation( golem, ANIMATION )
                
                //if channelGolems(data.level) is true we add the golem to it 
                //so we can keep track of it and kill it later in the "onDestroy"
                //method
                //else if the variable is false, it means that the group was not
                //created, and we ant the units to have a LifeTime
                if (channelGolems(data.level)) then
                    call GroupAddUnit(data.golems, golem)
                else
                    call UnitApplyTimedLife(golem, 'BTLF', golemLife(data.level))
                endif
            endif   
            
            call RemoveLocation(point)
            set point = null
                
            set loopCounter = loopCounter + 1
        endloop
    
    set golem = null

    endfunction
//===========================================================================
    private function Conditions takes nothing returns boolean
        local MyStruct data
        local location spellLoc //the location of the spell
        
        if (GetSpellAbilityId() == AID) then
            //setting variables for the struct
            set spellLoc = GetSpellTargetLoc()
            set data = MyStruct.create(GetTriggerUnit(), GetLocationX(spellLoc), GetLocationY(spellLoc))
            
            //put the struct in the Table, we just use the caster's handle adress as 
            //the key which tells us where in the Table the struct is stored
            set activeTable[data.caster] = data 

            //  we add the casting unit to some sort of "pool"
            call GroupAddUnit(GolemInvocationCasters, data.caster)
            
            //now we create the dusty effect
            call createDust(data)
            
            //we attach the struct to the timer
            call SetCSData(data.cycleTimer, integer(data))
            call TimerStart(data.cycleTimer, cycle(data.level), true, function createGolems)
            
            //cleaning up the mess
            call RemoveLocation(spellLoc)
        endif
        
        set spellLoc = null
        
        return false
    endfunction
//===========================================================================
    private function Init takes nothing returns nothing
        local trigger GolemInvocationTrigger = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(GolemInvocationTrigger, Condition( function Conditions ) )
        
        set GolemInvocationTrigger = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(GolemInvocationTrigger, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        call TriggerAddCondition(GolemInvocationTrigger,  Condition(function onStop))

        set GolemInvocationTrigger = null
        
        //set our globals
        set activeTable = HandleTable.create() 
        set GolemInvocationCasters = NewGroup() 

        set GolemInvocationTrigger = null
    endfunction
endscope 

And now Fire Cataclism
Collapse JASS:
/===========================================================================
//A spell that erupts a vulcano from the ground. The volcano will create small
//fires around it depending on level and will spawn fire creatures, that will 
//be stronger with levels. The weaker the unit, the more chances it has to be 
//spawned. All creates die when the spell caster stops the channel, except in 
//the last level, when die have a period of time.
//
//Requires CSData, CSSafety and Table
//
//@author Flame_Phoenix 
//
//@credits
//- the-thingy, Kyrbi0
//- My first teacher of vJASS: Blue_Jeans
//- All other people I forgot or ignored
//
//@version 1.0
//===========================================================================
scope FireCataclism initializer Init
//===========================================================================
//=============================SETUP START===================================
//===========================================================================

    globals
        private constant integer AID = 'A000'   //the rawcode of the ability
        private constant string ANIMATION = "birth" //the animation that will be played when the unit is created
    endglobals

//===========================================================================
//============================GOLEM SETUP====================================
//===========================================================================

//===========================================================================
//===========================IMPORTANT NOTE==================================
//The returned value from fireSpawnChance1 + fireSpawnChance2 + fireSpawnChance3 must be 
//equal to 100. This formula is very important if you want to spawn a fireSpawn
//every cycle.
//===========================================================================

    private constant function weakFireSpawnChance takes integer level returns real 
        //in level 1 we have 90% chance to get Weak FireSpawn
        //in level 2 we have 80% chance to get Weak FireSpawn
        //in level 3 we have 70% chance to get Weak FireSpawn
        return 100. - (level * 10)
    endfunction
    
    private constant function mediumFireSpawnChance takes integer level returns real 
        //in level 1 we have 6% chance to get Medium FireSpawn
        //in level 2 we have 13% chance to get Medium FireSpawn
        //in level 3 we have 20% chance to get Medium FireSpawn
        
        return (level * 7.) - 1.
        
        //example of usage
        //sometimes it is either difficult or impossible to find a formula
        //for our purposes. However, you can always use an if statement, 
        //like I use in the example
        
//       local real chance = 0    
//       if (level == 1) then
//            set chance = 6.
//        elseif (level == 2) then
//            set chance = 13.
//        elseif (level == 3) then
//            set chance = 20.
//        endif
//        return chance 
        
        //please note, that finding a formula is very efficient
        //note how we compressed this whole if statement into that
        //single line
    endfunction
    
    private constant function strongFireSpawnChance takes integer level returns real 
        //in level 1 we have 4% chance to get Strong FireSpawn
        //in level 2 we have 7% chance to get Strong FireSpawn
        //in level 3 we have 10% chance to get Strong FireSpawn
        return 1. + (3. * level)
    endfunction
    
//===========================================================================
//==============================END NOTE=====================================
//Remember: fireSpawnChance1 + fireSpawnChance2 + fireSpawnChance3 = 100
//If you want to ALWAYS spawn a FireSpawn, you must use this formula
//===========================================================================
    
    
    private constant function weakFireSpawnType takes integer level returns integer 
        //the rawcode of the weakFireSpawnType unit. In this case our weak
        //fireSpawn is a lava spawn, from the Firelord's ability
        //if we have level equal to 1, our weak unit will be lava spawn lv3
        //if we have level equal to 2, our weak unit will be lava spawn lv4
        //if we have level equal to 3, our weak unit will be lava spawn lv5
        //this way our weak unit get stronger and stronger with levels
        
        local integer spawn = 0 
        
        if (level == 1) then
            set spawn = 'nlv1'
        elseif (level == 2) then
            set spawn = 'nlv2'
        elseif (level == 3) then 
            set spawn = 'nlv3'
        endif
        
        return spawn
    endfunction
    
    private constant function mediumFireSpawnType takes integer level returns integer 
        //the rawcode of the mediumFireSpawnType unit. In this case our medium
        //fireSpawn is a modified water elemental (blue really lookd ugly, but
        //this is just a demonstration of what you can do xD)
        //if we have level equal to 1, our medium unit will be red elemental lv1
        //if we have level equal to 2, our medium unit will be red elemental lv2
        //if we have level equal to 3, our medium unit will be red elemental lv3
        //this way our medium unit get stronger and stronger with levels
        local integer spawn = 0 
        
        if (level == 1) then
            set spawn = 'h001'
        elseif (level == 2) then
            set spawn = 'h002'
        elseif (level == 3) then 
            set spawn = 'h003'
        endif
        
        return spawn
    endfunction
    
    private constant function strongFireSpawnType takes integer level returns integer 
        //the rawcode of the strongFireSpawnType unit. In this case our strong
        //fireSpawn is a modified Fire Hero, which I think it is appropriate.
        //if we have level equal to 1, our strong unit will be fire Hero lv1
        //if wehave level equal to 2, our strong unit will be fire Hero lv2
        //if wehave level equal to 3, our strong unit will be fire Hero lv3
        //this way our strong unit get stronger and stronger with levels
        local integer spawn = 0 
        
        if (level == 1) then
            set spawn = 'h004'
        elseif (level == 2) then
            set spawn = 'h005'
        elseif (level == 3) then 
            set spawn = 'h006'
        endif
        
        return spawn
    endfunction

    private constant function fireSpawnLife takes integer level returns real
        return level * 20.  //the amount of time each fireSpawn will be alive live
    endfunction

    private constant function channelFireSpawns takes integer level returns boolean
        //if true it will make all spawned fireSpawns die when the caster stops the channel
        //if false, it allows the fireSpawns to have fireSpawnLife seconds of life and they
        //will not die when the caster stops the channel
        //in this case my fireSpawns will die when the caster stops the channel in levels
        //1 and 2, but in level 3, each spawn will have 60 seconds of life
        
        local boolean result = true
        
        if (level == 3) then
            set result = false
        endif
        
        return result
    endfunction
    
    private constant function fireSpawnsPerCycle takes integer level returns integer
        //the number of fireSpawns that will be created each cycle
        return level
    endfunction
    
    
    private constant function cycle takes integer level returns real
        //the cycle which will determine when we create fireSpawns
        //this means, fireSpawnsPerCycle fireSpawns are created every cycle
        //in this case, we create 1 fireSpawn per 3 seconds (in this case a 3 seconds 
        //is a cycle)
        return 3.
    endfunction
    
//===========================================================================
//============================DUST SETUP=====================================
//===========================================================================
    
    private constant function dummyEffectId takes integer level returns integer
        //the rawcode of the dummy unit that will be fire
        //this is in a function so you can have different effects in different
        //levels
        local integer dumEffect = 0
        
        if (level == 1) then
            set dumEffect = 'h007'
        elseif (level == 2) then
            set dumEffect = 'h008'
        elseif (level == 3) then
            set dumEffect = 'h009'
        endif
        
        return dumEffect
    endfunction
    
    private constant function minRange takes integer level returns real
        //in this case we have a minimum range. We don't want to spawn unit inside
        //the vulcano =P
        //the minimum range is smaller circle, inside the area of the spell
        //in which fireSpawns will not be created
        return 250.
    endfunction
    
    private constant function maxRange takes integer level returns real
        //this ensures fireSpawns are not created outside the AOE of the spell
        //this gives the AOE of the spell
        return 300. + (level * 200.)
    endfunction
    
    private constant function circleCount takes integer level returns integer
        //the number of circles that will be created to give the illusion of the fire
        //effects. The more circles the more realistic, but more CPU will be needed.
        local integer number = 0
        
        if (level == 1) then
            set number = 13
        elseif (level == 2) then
            set number = 10
        elseif (level == 3) then
            set number = 10
        endif
        
        return number
    endfunction
    
    private constant function innerCircleUnits takes integer level returns integer
        //the number of units that the most inner circle will have
        local integer number = 0
        
        if (level == 1) then
            set number = 20
        elseif (level == 2) then
            set number = 10
        elseif (level == 3) then
            set number = 10
        endif
        
        return number
    endfunction
    
    private constant function innerCircleUnitsIncrease takes integer level returns integer
        //the increment of units per circle
        return 10
    endfunction
//===========================================================================
//=============================SETUP END=====================================
//===========================================================================

    globals 
        private group FireCataclismCasters
        private HandleTable activeTable 
    endglobals
    
    private struct MyStruct 
        unit caster
        integer level
        timer cycleTimer 
        real spellLocX
        real spellLocY
        group dummyEffects
        group fireSpawns
        
        static method create takes unit caster, real locX, real locY returns MyStruct
            local MyStruct data = MyStruct.allocate()
            
            //set variables about the caster
            set data.caster = caster
            set data.level = GetUnitAbilityLevel(data.caster, AID)
            
            //variables about the location
            set data.spellLocX = locX
            set data.spellLocY = locY
            
            //the timer which will determine when we create fireSpawns
            //creates a fireSpawn everytime it expires
            set data.cycleTimer = NewTimer()   
            
            //This groups will save the dumy fire effects, so we can kill them 
            //when the caster stops the channeling
            set data.dummyEffects = NewGroup()
            
            //if we want the fireSpawns to die when the caster stops channel
            //then we create this group so we can add all fireSpawns to it
            //then we kill the fireSpawns when the caster stops the channel
            if (channelFireSpawns(data.level)) then
                set data.fireSpawns = NewGroup()
            endif
            
            return data
        endmethod
        
        method onDestroy takes nothing returns nothing
            
            //here we select all units from the group and we kill them all ! =P
            //thus meaning that the fire effects will disappear ! 
            local unit f
            loop
                set f = FirstOfGroup(.dummyEffects)
                exitwhen(f == null)
                call GroupRemoveUnit(.dummyEffects, f)
                call KillUnit(f)
            endloop
            
            //if the variable is true, then fireSpawns group was created and it has
            //units. Now we just kill all units it has and we release the group
            //for CSSafety to use one day later
            if (channelFireSpawns(.level)) then
                loop
                    set f = FirstOfGroup(.fireSpawns)
                    exitwhen(f == null)
                    call GroupRemoveUnit(.fireSpawns, f)
                    call KillUnit(f)
            endloop
            
            call ReleaseGroup(.fireSpawns)
            endif
            
            //since the spell is not active anymore, we clean the Table     
            call activeTable.flush(.caster) 
            
            //the units are not anymore in the active units group.
            call GroupRemoveUnit(FireCataclismCasters, .caster) 
            
            //releasing the timer and group for CSSafety to use it one day later =D
            call ReleaseTimer(.cycleTimer)
            call ReleaseGroup(.dummyEffects)
            
        endmethod
    endstruct
    
//===========================================================================
    private function onStop takes nothing returns boolean
        local MyStruct data
        local unit u = GetTriggerUnit()
        
        //when a unit stops the channel, we verify if that unit is inside the
        //catsers group. If so, than it is because it is a caster casting this spell
        //and so we recover information about him and we make the spell end
        if(IsUnitInGroup(u, FireCataclismCasters)) then
            //recover the data from the caster
            set data = activeTable[u] 
            
            //now, time to clean the mess once again
            call data.destroy() 
        endif

        set u = null
        
        return false
    endfunction
//===========================================================================
    //Function made by Themerion and adapted by Flame_Phoenix
    //Creates circles of dummy units to give the illusion of the fire effects
    private function createDust takes integer aStruct returns nothing
        local MyStruct data = aStruct
        
        // forPlayer     -> Create the units for which player?
        local player forPlayer = GetOwningPlayer(data.caster)
        
        // innerRadius   -> The radius of the innermost circle
        // outerRadius   -> The radius of the outmost circle
        local real innerRadius = minRange(data.level)
        local real outerRadius = maxRange(data.level)
        
        // x and y       -> Center of circles
        local real x = data.spellLocX
        local real y = data.spellLocY

        local real radiusInc = (outerRadius - innerRadius) / I2R(circleCount(data.level)-1)
        
        //see funtions they call
        local integer fxcount = innerCircleUnits(data.level)
        local integer fxcountinc = innerCircleUnitsIncrease(data.level)
        
        local real phi = 0
        local real phiInc

        loop
            exitwhen (innerRadius + 0.001 >= outerRadius)

            set phi = 0
            set phiInc = 2*bj_PI/I2R(fxcount)
            
            loop
                exitwhen (phi + 0.001 >= 2 * bj_PI)
                //we add the units to a group, so we can kill them when we want ! =P
                call GroupAddUnit(data.dummyEffects, CreateUnit(forPlayer, dummyEffectId(data.level), x + innerRadius * Cos(phi), y + innerRadius * Sin(phi), 180 + Rad2Deg(phi)))
                set phi = phi + phiInc
            endloop
            
        set innerRadius = innerRadius + radiusInc
        set fxcount = fxcount + fxcountinc
        
        endloop
        
        set forPlayer = null
    
    endfunction
//===========================================================================
    //Function made by Vexorian, it selects a random region in a disk. 
    //All regions have the same chance of beeing choosen
    private function GetRandomPointInDisk takes real centerx, real centery, real minradius, real maxradius returns location
        local real d = SquareRoot(GetRandomReal(minradius * minradius, maxradius * maxradius))
        local real a = GetRandomReal(0, 2 * bj_PI)
        return Location(centerx + d * Cos(a), centery + d * Sin(a))
    endfunction
//===========================================================================
    private function createFireSpawns takes nothing returns nothing
        //we get the structure from the timer
        local MyStruct data = MyStruct(GetCSData(GetExpiredTimer())) 
        
        //variables for us to know where the fireSpawns will born
        local location point  
        local real randomX  
        local real randomY 
        
        //the chances that each fireSpawn will have to be spawned
        local real aChance
        
        //just to keep count about how many fireSpawns we created
        local integer loopCounter = 0
        
        //cariables about the fireSpawns
        local unit fireSpawn
        local real fireSpawnFacing = GetUnitFacing(data.caster)
        
        //Here we spawn the fireSpawns 
        loop 
            exitwhen(loopCounter >= fireSpawnsPerCycle(data.level))
                
            set point = GetRandomPointInDisk(data.spellLocX, data.spellLocY, minRange(data.level), maxRange(data.level))
            set randomX = GetLocationX(point)
            set randomY = GetLocationY(point)
            set aChance = GetRandomReal(0, 100)
            
            if (aChance <= 100 - weakFireSpawnChance(data.level)) then
                set fireSpawn =  CreateUnit(GetOwningPlayer(data.caster), weakFireSpawnType(data.level), randomX, randomY, fireSpawnFacing)
                call SetUnitAnimation( fireSpawn, ANIMATION )
                
                //if channelFireSpawns(data.level) is true we add the fireSpawn to it 
                //so we can keep track of it and kill it later in the "onDestroy"
                //method
                //else if the variable is false, it means that the group was not
                //created, and we ant the units to have a LifeTime
                if (channelFireSpawns(data.level)) then
                    call GroupAddUnit(data.fireSpawns, fireSpawn)
                else
                    call UnitApplyTimedLife(fireSpawn, 'BTLF', fireSpawnLife(data.level))
                endif
            elseif (aChance <= 100 - mediumFireSpawnChance(data.level)) then
                set fireSpawn =  CreateUnit(GetOwningPlayer(data.caster), mediumFireSpawnType(data.level), randomX, randomY, fireSpawnFacing)
                call SetUnitAnimation( fireSpawn, ANIMATION )
                
                //if channelFireSpawns(data.level) is true we add the fireSpawn to it 
                //so we can keep track of it and kill it later in the "onDestroy"
                //method
                //else if the variable is false, it means that the group was not
                //created, and we ant the units to have a LifeTime
                if (channelFireSpawns(data.level)) then
                    call GroupAddUnit(data.fireSpawns, fireSpawn)
                else
                    call UnitApplyTimedLife(fireSpawn, 'BTLF', fireSpawnLife(data.level))
                endif
            elseif (aChance <= 100 - strongFireSpawnChance(data.level)) then
                set fireSpawn =  CreateUnit(GetOwningPlayer(data.caster), strongFireSpawnType(data.level), randomX, randomY, fireSpawnFacing)
                call SetUnitAnimation( fireSpawn, ANIMATION )
                
                //if channelFireSpawns(data.level) is true we add the fireSpawn to it 
                //so we can keep track of it and kill it later in the "onDestroy"
                //method
                //else if the variable is false, it means that the group was not
                //created, and we ant the units to have a LifeTime
                if (channelFireSpawns(data.level)) then
                    call GroupAddUnit(data.fireSpawns, fireSpawn)
                else
                    call UnitApplyTimedLife(fireSpawn, 'BTLF', fireSpawnLife(data.level))
                endif
            endif   
            
            call RemoveLocation(point)
            set point = null
                
            set loopCounter = loopCounter + 1
        endloop
    
    set fireSpawn = null

    endfunction
//===========================================================================
    private function Conditions takes nothing returns boolean
        local MyStruct data
        local location spellLoc //the location of the spell
        
        if (GetSpellAbilityId() == AID) then
            //setting variables for the struct
            set spellLoc = GetSpellTargetLoc()
            set data = MyStruct.create(GetTriggerUnit(), GetLocationX(spellLoc), GetLocationY(spellLoc))
            
            //put the struct in the Table, we just use the caster's handle adress as 
            //the key which tells us where in the Table the struct is stored
            set activeTable[data.caster] = data 

            //  we add the casting unit to some sort of "pool"
            call GroupAddUnit(FireCataclismCasters, data.caster)
            
            //now we create the fire effects
            call createDust(data)
            
            //we attach the struct to the timer
            call SetCSData(data.cycleTimer, integer(data))
            call TimerStart(data.cycleTimer, cycle(data.level), true, function createFireSpawns)
            
            //cleaning up the mess
            call RemoveLocation(spellLoc)
        endif
        
        set spellLoc = null
        
        return false
    endfunction
//===========================================================================
    private function Init takes nothing returns nothing
        local trigger FireCataclismTrigger = CreateTrigger(  )
        call TriggerRegisterAnyUnitEventBJ(FireCataclismTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
        call TriggerAddCondition(FireCataclismTrigger, Condition( function Conditions ) )
        
        set FireCataclismTrigger = CreateTrigger()
        call TriggerRegisterAnyUnitEventBJ(FireCataclismTrigger, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
        call TriggerAddCondition(FireCataclismTrigger,  Condition(function onStop))

        set FireCataclismTrigger = null
        
        //set our globals
        set activeTable = HandleTable.create() 
        set FireCataclismCasters = NewGroup() 

        set FireCataclismTrigger = null
    endfunction
endscope 

And now for those who like, here is an imba, unbalanced demo map, where 1 hero will pawn a army with no effort at all =P
Hope you all like it, and please give suggestions.
I am now submiting this spell to resources.

Btw, credits will be awarded. Thx for your help guys.
Attached Files
File Type: w3x Golem Invocation.w3x (60.3 KB, 4 views)
__________________
Check out my tutorials at:
1-Creating a Hero Tavern
2-Complete Icon Tutorial - ALL about Icons
3-Making a spell in vJass - Practice Session 1
Check out all my current spells at here
Finally, check my project:
Castle vs Castle Flame Edition

Last edited by Flame_Phoenix : 07-18-2008 at 12:52 PM.
Flame_Phoenix is offline   Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off


All times are GMT. The time now is 09:11 AM.


Affiliates
The Hubb The JASS Vault Clan WEnW Campaign Creations Clan CBS GamesModding Flixreel Videos

Powered by vBulletin (Copyright ©2000 - 2019, Jelsoft Enterprises Ltd).
Hosted by www.OICcam.com
IT Support and Services provided by Executive IT Services