| 07-14-2008, 10:24 PM | #1 |
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. 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 |
| 07-15-2008, 03:43 PM | #2 |
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 |
| 07-15-2008, 03:59 PM | #3 |
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... |
| 07-15-2008, 05:51 PM | #4 | ||||||
Quote:
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:
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:
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:
Quote:
Ok thx for your help thingy. Rep++ for you being helpful. Btw, can some one help me out with these also?? Quote:
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 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 =) |
| 07-15-2008, 06:20 PM | #5 | |
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. |
| 07-15-2008, 06:27 PM | #6 | ||
Quote:
Please download map, you will see the problem, am using the ability editor for that purpose. Quote:
|
| 07-15-2008, 06:47 PM | #7 | |||||
Quote:
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 usually do something like (I'll use a real as an example) 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 Quote:
Quote:
Quote:
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 |
| 07-15-2008, 06:58 PM | #8 | |
Quote:
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 :/ |
| 07-15-2008, 07:02 PM | #9 | |||
Quote:
Quote:
Quote:
Anyway, thx for opinion guys. Any suggestions for the code ?? 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 |
| 07-15-2008, 07:19 PM | #10 | |||
Quote:
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:
Quote:
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) 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 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 |
| 07-15-2008, 09:29 PM | #11 |
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 =) |
| 07-15-2008, 10:17 PM | #12 | ||
Quote:
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 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:
), why shouldn't you use arrays? |
| 07-15-2008, 10:57 PM | #13 |
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 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 =( |
| 07-18-2008, 11:49 AM | #14 |
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 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 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. |
