| 02-10-2009, 01:59 PM | #1 |
Hi guys, I am now working in a spell called Chaotic Raise. This spell will be the counter-part for the Ranger's Golem Invocation and it is also an ultimate spell. I also intend to submit it here, although it summons units it will be slightly different. It will be divided into a few stages: 1 - Create a circle with a David star in the center 2 - start spamming orc skelies every cycle 3 - when the caster stops everything stops I don't know if I should make this spell JESP, since 2D array change a lot from last time I checked and it will increase the complexity of the spell considerably. So far I have no problems, I am working on the Star with Circle effect (which will bring me problems), so I am just creating this thread to get an opinion from the user. I will try to make this spell in this forum, it is the first time I will try this,maybe I will get some nice suggestions. Anyway, I would like some opinions in: 1 - When an enemy unit is under a raising skeleton it will be damaged. Do you guys think the damage should differ from skely to skely? (Example, stronger skelies cause more damage) 2 - I use a small fire model for the star and the circle. I think it is pretty simple, anyone has a better idea for a model? Anyway, here is the spell of the code so far: JASS://=========================================================================== //A spell that creates a symbol on the casting position and that channels a //powerful magic. Every cycle an undead Chaos Orc Skeleton will raise from the //ground to fight the enemies of the caster. If an enemy unit is under a raising //skeleton it will take damage. // //Requires TimerUtils and Table // //@author Flame_Phoenix // //@credits //-Veev for helping me optimizing the CreateStarCircle function // //@version 1.0 //=========================================================================== scope ChaoticRaise initializer Init //=========================================================================== //=============================SETUP START=================================== //=========================================================================== globals private constant integer AID = 'A000' //the rawcode of the ability of the caster private constant integer FIRE_ID = 'h000' //the id of teh fire that will create the circle and the star private constant boolean CHANNEL_SKELIES = true //if true, all skelies die when the caster stops channel. If false each skelie will have SpawnLife time of life private constant real TIMER_CYCLE = 0.1 endglobals private constant function SpawnInterval takes integer level returns real //the interval that separates each spawn return 1. //+ (level * 0) endfunction private constant function SpawnNum takes integer level returns integer //the number of units spawned per SpawnInterval return 3 //+ (level * 0) endfunction private constant function SpawnLife takes integer level returns real //the amount of life each spawn will have. This will only work if variable //CHANNEL_SKELIES is set to false return 30. * level endfunction //=========================================================================== //=============================SETUP END===================================== //=========================================================================== globals private group ChaoticRaiseCasters private HandleTable activeTable endglobals private struct SpellData unit caster integer level group fires //this group will have all fires that make the circle and the star group skelies timer t real spellX real spellY static method create takes unit caster, real locX, real locY returns SpellData local SpellData data = SpellData.allocate() //set variables about the caster set data.caster = caster set data.level = GetUnitAbilityLevel(data.caster, AID) //variables about the location set data.spellX = locX set data.spellY = locY //the timer which will determine when we create skelies //creates a skelie everytime it expires set data.t = NewTimer() //This groups will save the dumy fires, so we can kill them //when the caster stops the channeling. We also recycle the group if data.fires == null then set data.fires = CreateGroup() endif //if we want the skelies to die when the caster stops channel //then we create this group so we can add all skelies to it //then we kill the skelies when the caster stops the channel if CHANNEL_SKELIES then //again we recycle the skely group! if data.skelies == null then set data.skelies = CreateGroup() endif endif return data endmethod method onDestroy takes nothing returns nothing //here we select all units from the fires group and we kill them all ! =P //thus meaning that the fire effects will disappear ! local unit f loop set f = FirstOfGroup(.fires) exitwhen(f == null) call GroupRemoveUnit(.fires, f) call KillUnit(f) endloop //cleaning the group for us to use one day later =P call GroupClear(.fires) //if the variable is true, then skelies group was created and it has //units, and so now we kill them all. if CHANNEL_SKELIES then loop set f = FirstOfGroup(.skelies) exitwhen(f == null) call GroupRemoveUnit(.skelies, f) call KillUnit(f) endloop //cleaning the group for us to use one day later =P call GroupClear(.skelies) 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(ChaoticRaiseCasters, .caster) //releasing the timer for TimerUitls to use one day later =D call ReleaseTimer(.t) endmethod endstruct //=========================================================================== private function CreateStarCircle takes integer aStruct returns nothing endfunction //=========================================================================== private function onStop takes nothing returns boolean return false endfunction //=========================================================================== private function Conditions takes nothing returns boolean return true endfunction //=========================================================================== private function Init takes nothing returns nothing //Creates the trigger for when the unit starts casting the spell local trigger ChaoticRaiseTrg = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ(ChaoticRaiseTrg, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition(ChaoticRaiseTrg, Condition( function Conditions ) ) //Creates the trigger for when the unit ceases the channel set ChaoticRaiseTrg = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(ChaoticRaiseTrg, EVENT_PLAYER_UNIT_SPELL_ENDCAST) call TriggerAddCondition(ChaoticRaiseTrg, Condition(function onStop)) //setting out globals set ChaoticRaiseCasters = CreateGroup() set activeTable = HandleTable.create() endfunction endscope If you guys read the header, you will see the credits section is empty. Well, if you help me, you will get +rep and your name will be there =P |
| 02-11-2009, 07:37 AM | #2 |
There is no JESP anymore. Just common sense and good coding practices. |
| 02-11-2009, 12:48 PM | #3 | |
Quote:
EDIT EDIT EDIT Ok guys, I finished up the cleaning. If anyone has ideas on how to optimize the creation of the star within the circle please be my guest. I decided to use bj_variables, this way instead of have 1000 variables I have 999 (you get the point). Enjoy and despair =) JASS:scope StarWithCircle initializer Init globals private constant real RADIUS = 400. private constant integer FIRE_ID = 'h000' private constant real FIRE_SIZE = 10. endglobals //=========================================================================== private function Actions takes nothing returns nothing local unit caster = GetTriggerUnit() local player owner = GetOwningPlayer(caster) local real casterX = GetUnitX(caster) local real casterY = GetUnitY(caster) local real x1 local real y1 local real x2 local real y2 local real x3 local real y3 local real dx local real dy local real angle local real dist local integer fireNum //here we create the circle set bj_forLoopAIndex = 1 set bj_forLoopAIndexEnd = R2I(RADIUS / FIRE_SIZE) loop exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd //polar projection stuff set x1 = casterX + RADIUS * Cos(bj_forLoopAIndex * ( 360.00 / (RADIUS / FIRE_SIZE )) * bj_DEGTORAD) set y1 = casterY + RADIUS * Sin(bj_forLoopAIndex * ( 360.00 / (RADIUS / FIRE_SIZE )) * bj_DEGTORAD) set bj_lastCreatedUnit = CreateUnit(owner, FIRE_ID, x1, y1, 0) call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', GetRandomReal(8.00, 10.00)) set bj_forLoopAIndex = bj_forLoopAIndex + 1 endloop //all this stuff creates the first line of the start ... set x1 = casterX + RADIUS * Cos(234.0 * bj_DEGTORAD) set y1 = casterY + RADIUS * Sin(234.0 * bj_DEGTORAD) set x2 = casterX + RADIUS * Cos(90. * bj_DEGTORAD) set y2 = casterY + RADIUS * Sin(90. * bj_DEGTORAD) set dx = x2 - x1 set dy = y2 - y1 set dist = SquareRoot(dx * dx + dy * dy) set angle = Atan2(y2-y1, x2-x1) set fireNum = R2I(dist) / 40 set bj_forLoopAIndex = 1 set bj_forLoopAIndexEnd = fireNum loop exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd set x3 = x1 + (bj_forLoopAIndex * (dist / fireNum)) * Cos(angle) set y3 = y1 + (bj_forLoopAIndex * (dist / fireNum)) * Sin(angle) set bj_lastCreatedUnit = CreateUnit(owner, FIRE_ID, x3, y3, 0) call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', GetRandomReal(8.00, 10.00)) set bj_forLoopAIndex = bj_forLoopAIndex + 1 endloop //now prepare for the second line of the start lol... don't worry, it //only has 5 lines xD set x1 = casterX + RADIUS * Cos(90. * bj_DEGTORAD) set y1 = casterY + RADIUS * Sin(90. * bj_DEGTORAD) set x2 = casterX + RADIUS * Cos(306. * bj_DEGTORAD) set y2 = casterY + RADIUS * Sin(306. * bj_DEGTORAD) set dx = x2 - x1 set dy = y2 - y1 set dist = SquareRoot(dx * dx + dy * dy) set angle = Atan2(y2-y1, x2-x1) set fireNum = R2I(dist) / 40 set bj_forLoopAIndex = 1 set bj_forLoopAIndexEnd = fireNum loop exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd set x3 = x1 + (bj_forLoopAIndex * (dist / fireNum)) * Cos(angle) set y3 = y1 + (bj_forLoopAIndex * (dist / fireNum)) * Sin(angle) set bj_lastCreatedUnit = CreateUnit(owner, FIRE_ID, x3, y3, 0) call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', GetRandomReal(8.00, 10.00)) set bj_forLoopAIndex = bj_forLoopAIndex + 1 endloop //now for the 3rd line set x1 = casterX + RADIUS * Cos(306. * bj_DEGTORAD) set y1 = casterY + RADIUS * Sin(306. * bj_DEGTORAD) set x2 = casterX + RADIUS * Cos(162. * bj_DEGTORAD) set y2 = casterY + RADIUS * Sin(162. * bj_DEGTORAD) set dx = x2 - x1 set dy = y2 - y1 set dist = SquareRoot(dx * dx + dy * dy) set angle = Atan2(y2-y1, x2-x1) set fireNum = R2I(dist) / 40 set bj_forLoopAIndex = 1 set bj_forLoopAIndexEnd = fireNum loop exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd set x3 = x1 + (bj_forLoopAIndex * (dist / fireNum)) * Cos(angle) set y3 = y1 + (bj_forLoopAIndex * (dist / fireNum)) * Sin(angle) set bj_lastCreatedUnit = CreateUnit(owner, FIRE_ID, x3, y3, 0) call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', GetRandomReal(8.00, 10.00)) set bj_forLoopAIndex = bj_forLoopAIndex + 1 endloop //now for the 4th line, don't worry, we are almost there set x1 = casterX + RADIUS * Cos(162. * bj_DEGTORAD) set y1 = casterY + RADIUS * Sin(162. * bj_DEGTORAD) set x2 = casterX + RADIUS * Cos(19. * bj_DEGTORAD) set y2 = casterY + RADIUS * Sin(19. * bj_DEGTORAD) set dx = x2 - x1 set dy = y2 - y1 set dist = SquareRoot(dx * dx + dy * dy) set angle = Atan2(y2-y1, x2-x1) set fireNum = R2I(dist) / 40 set bj_forLoopAIndex = 1 set bj_forLoopAIndexEnd = fireNum loop exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd set x3 = x1 + (bj_forLoopAIndex * (dist / fireNum)) * Cos(angle) set y3 = y1 + (bj_forLoopAIndex * (dist / fireNum)) * Sin(angle) set bj_lastCreatedUnit = CreateUnit(owner, FIRE_ID, x3, y3, 0) call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', GetRandomReal(8.00, 10.00)) set bj_forLoopAIndex = bj_forLoopAIndex + 1 endloop //at last the last line of our David star! set x1 = casterX + RADIUS * Cos(19.0 * bj_DEGTORAD) set y1 = casterY + RADIUS * Sin(19.0 * bj_DEGTORAD) set x2 = casterX + RADIUS * Cos(234. * bj_DEGTORAD) set y2 = casterY + RADIUS * Sin(234. * bj_DEGTORAD) set dx = x2 - x1 set dy = y2 - y1 set dist = SquareRoot(dx * dx + dy * dy) set angle = Atan2(y2-y1, x2-x1) set fireNum = R2I(dist) / 40 set bj_forLoopAIndex = 1 set bj_forLoopAIndexEnd = fireNum loop exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd set x3 = x1 + (bj_forLoopAIndex * (dist / fireNum)) * Cos(angle) set y3 = y1 + (bj_forLoopAIndex * (dist / fireNum)) * Sin(angle) set bj_lastCreatedUnit = CreateUnit(owner, FIRE_ID, x3, y3, 0) call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', GetRandomReal(8.00, 10.00)) set bj_forLoopAIndex = bj_forLoopAIndex + 1 endloop //cleaning the mess set caster = null set owner = null endfunction //=========================================================================== private function Init takes nothing returns nothing local trigger StarWithCircleTrg = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( StarWithCircleTrg, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddAction( StarWithCircleTrg, function Actions ) endfunction endscope |
| 02-11-2009, 02:45 PM | #4 |
There are a couple calculations that get repeated in the loop but never change... SquareRoot(dx * dx + dy * dy) appears a lot of times. Although it changes in each section you can still create a variable and only calculate it once per section (by section I mean "first line," "second line," and so on). You can do the same for the Atan2 calculations. Also, due to the GUI, you're multiplaying bj_DEGTORAD and bj_RADTODEG together so... Remove that, that's really unnecessary. So... JASS://all this stuff creates the first line of the start ... set x1 = casterX + RADIUS * Cos(234.0 * bj_DEGTORAD) set y1 = casterY + RADIUS * Sin(234.0 * bj_DEGTORAD) set x2 = casterX + RADIUS * Cos(90. * bj_DEGTORAD) set y2 = casterY + RADIUS * Sin(90. * bj_DEGTORAD) set dx = x2 - x1 set dy = y2 - y1 set dist = SquareRoot(dx * dx + dy * dy) set angle = Atan2(y2-y1, x2-x1) set fireNum = R2I(dist / 40) set bj_forLoopAIndex = 1 set bj_forLoopAIndexEnd = fireNum loop exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd set x3 = x1 + I2R(bj_forLoopAIndex) * (dist / I2R(fireNum)) * cos(angle) //These I2R's might be excessive set y3 = y1 + I2R(bj_forLoopAIndex) * (dist / I2R(fireNum)) * Sin(angle) //Maybe someone knows set bj_lastCreatedUnit = CreateUnit(owner, FIRE_ID, x3, y3, 0) call UnitApplyTimedLife(bj_lastCreatedUnit, 'BTLF', GetRandomReal(8.00, 10.00)) set bj_forLoopAIndex = bj_forLoopAIndex + 1 endloop |
| 02-11-2009, 03:33 PM | #5 |
Mmm I will try your code in this precise instant! btw, if "dist" is a real, then there is no need to make I2R(fireNum) because the result of an equation between an integer and a real, is a real. I2R can be removed I think. If it works, You will definitely get credits. I was so focused in that GUI thing I couldn't see the real loop behind it. EDIT EDIT EDIT Ok, about the systems, I want the spell to be channeling, so I will use Table for this. Also, I want to created a sequence of events, timed events, so I will also use TimerUtils. I don't have much ideas for the effects, but if the opportunity arises to use a cool effect with long animation time I will use this system too: http://www.wc3campaigns.net/showthre...11#post1063811 I think this is be all I will need. If any one has suggestions or cool ideas, go ahead and shoot them =P EDIT EDIT EDIT Ok the Circle with the david start on the center was updated. I would post the initial code if people want to make a comparison =P Veev was added to credits. |
