| 06-24-2008, 08:35 AM | #1 |
Hi guys, Recently I made a code. It was my first code using vJAss and I tried to follow the JESP standards, although I am not sure i did the last one correctly. The main reason I am posting this here, is to ask fro an opinion. Do you guys think this spell has a chance of getting approved for the spells section here ? Btw, It uses ABC. Comments like: "I don't read Cohadars shit" or, "this spell is shit" are NOT necessary and I will even thank you if you don't post them. Also, for those winners who can optimize every little line of code, well, i appreciate optimization, but I value code easy to understand a lot more, because I never know who will be reading it tomorrow. Anyway, the spell has a cool idea (in my opinion) but I decided to make the code very simple, as usual. Hope you guys enjoy the spell, and please, give nice feedback =S Remember, this is my first vJASS spell after all. JASS://=========================================================================== //A spell that makes meteors fall randomly in the map, damaging enemy units //and summoning powerfull infernals // //@author Flame_Phoenix //@version 1.7 //=========================================================================== scope Apocalypse // globals // private constant integer AID = 'A000' // ->The rawcode of the Apocalypse hero ability // // private constant integer INFERNAL = 'A002' // ->Rawcode of the dreadlords dummy infernal spell. // This will be used to spawn an ifernal or any other unit you may like. To change the summoned // unit, just go to the dummy spell, and change it // // private constant integer SPAWN = 'A003' // ->Rawcode of the special dummy ability Flame Strike. When an infernal falls we can // not show 2 meteors. So this is a special ability, without the meteor falling ability // It is only used when the infernal is spawned // // private constant integer NO_SPAWN = 'A001' // ->Rawcode of the Flame Strike ability, when no infernal is spwaned. It is an ability // with the falling meteor animation. // // private constant integer DUMMY_RAW = 'h000' // ->The rawcode of the dummy unit that will cast all spells needed for this trigger // to work. For more information, ee the dummy unit i created in object editor. // // private constant real MIN_RANGE = 300.00 // ->The minimal range. Meteors will not fall behind this number. It was made to protect // the caster from being hurt. You can change the minimum range, but it must be ALWAYS // lower the the MAX_RANGE real. // // private constant real MAX_RANGE = 600.00 // ->The maximal range. Meteors will not fall after the number.This is the area of // effect of the spell. You can change this value, but it must be BIGGER than the // MIN_RANGE real. // // endglobals //=========================================================================================== //To change the time the spell will last, or the wait between each meteor see "function Actions" //To change damage and AOE of meteors, change the abilities: // - Flame Strike NO Infernal // - Flame Strike Infernal // - Inferno // in the ability object editor //=========================================================================================== globals private constant integer AID = 'A000' //The rawcode of the Apocalypse hero ability private constant integer INFERNAL = 'A002' //rawcode of the dreadlords dummy infernal spell. This will be used to spawn an ifernal or any private constant integer SPAWN = 'A003' private constant integer NO_SPAWN = 'A001' private constant integer DUMMY_RAW = 'h000' private constant real MIN_RANGE = 300.00 private constant real MAX_RANGE = 600.00 endglobals private struct Mystruct unit caster = GetTriggerUnit() timer repeator = CreateTimer() timer expirer = CreateTimer() trigger end = CreateTrigger() triggeraction endAction triggercondition endCondition endstruct //========================================================================== private function endConds takes nothing returns boolean local Mystruct data = GetTriggerStructB(GetTriggeringTrigger()) if GetTriggerEventId() == EVENT_GAME_TIMER_EXPIRED then return true else return GetTriggerUnit() == data.caster endif endfunction //========================================================================== private function endActs takes nothing returns nothing //catches the trigger and runs this function local Mystruct data = GetTriggerStructB(GetTriggeringTrigger()) //removes the created trigger in the Actions function call TriggerRemoveCondition(data.end,data.endCondition) call TriggerRemoveAction(data.end,data.endAction) call DestroyTrigger(data.end) call ClearTriggerStructB(data.end) //stops the repeator timer and ends the spell once and for all call PauseTimer(data.repeator) call DestroyTimer(data.repeator) call PauseTimer(data.expirer) call DestroyTimer(data.expirer) call ClearTimerStructA(data.repeator) call ClearTimerStructB(data.expirer) call data.destroy() endfunction //========================================================================== private function Effect takes nothing returns nothing //catches the expired timer and runs this function local Mystruct data = GetTimerStructA(GetExpiredTimer()) //local variables local integer infernal = GetRandomInt(0, 100) local unit array dummy[] //This uses polar projection. Formula: Center + r * trigfunction(angle teta); //where Center is the center coordinate X or Y //r is the distance (in the case rabdom between 300 and 600) //trigfunction is Sin if using Y and Cos if using X //angle teta is the angle formed between r and the axis (in this case random, can be all circle) local real randomX = GetUnitX(data.caster) + GetRandomReal(MIN_RANGE, MAX_RANGE) * Cos(GetRandomReal(0.0, 360.0) * bj_DEGTORAD) local real randomY = GetUnitY(data.caster) + GetRandomReal(MIN_RANGE, MAX_RANGE) * Sin(GetRandomReal(0.0, 360.0) * bj_DEGTORAD) if (infernal <= 3 * GetUnitAbilityLevel(data.caster, AID) + 1) then set dummy[0] = CreateUnit(GetOwningPlayer(data.caster), DUMMY_RAW, GetUnitX(data.caster), GetUnitY(data.caster), 0) call UnitAddAbility(dummy[0], INFERNAL) call SetUnitAbilityLevel(dummy[0], INFERNAL, GetUnitAbilityLevel(data.caster, AID)) call IssuePointOrder(dummy[0], "dreadlordinferno", randomX, randomY) call UnitApplyTimedLife(dummy[0], 'BTLF', 3) set dummy[1] = CreateUnit(GetOwningPlayer(data.caster), DUMMY_RAW, GetUnitX(data.caster), GetUnitY(data.caster), 0) call UnitAddAbility(dummy[1], SPAWN) call SetUnitAbilityLevel(dummy[1], SPAWN, GetUnitAbilityLevel(data.caster, AID)) call IssuePointOrder(dummy[1], "flamestrike", randomX, randomY) call UnitApplyTimedLife(dummy[1], 'BTLF', 3) else set dummy[0] = CreateUnit(GetOwningPlayer(data.caster), DUMMY_RAW, GetUnitX(data.caster), GetUnitY(data.caster), 0) call UnitAddAbility(dummy[0], NO_SPAWN) call SetUnitAbilityLevel(dummy[0], NO_SPAWN, GetUnitAbilityLevel(data.caster, AID)) call IssuePointOrder(dummy[0], "flamestrike", randomX, randomY) call UnitApplyTimedLife(dummy[0], 'BTLF', 3) endif set dummy[0] = null set dummy[1] = null endfunction //========================================================================== private function Conditions takes nothing returns boolean return GetSpellAbilityId() == AID endfunction //========================================================================== private function Actions takes nothing returns nothing local Mystruct data = Mystruct.create() //starts the effect of the spell, meteors start falling from sky call SetTimerStructA(data.repeator, data) call TimerStart(data.repeator, 6 / GetUnitAbilityLevel(data.caster, AID), true, function Effect) //creates the timer that ends the spell when expired call SetTimerStructB(data.expirer, data) call TimerStart(data.expirer, 5 * GetUnitAbilityLevel(data.caster, AID) + 15, false, null) //creates the trigger that will end the spell when the timer expires or the hero dies call SetTriggerStructB(data.end, data) call TriggerRegisterTimerExpireEvent( data.end, data.expirer ) call TriggerRegisterAnyUnitEventBJ(data.end, EVENT_PLAYER_UNIT_DEATH ) set data.endCondition = TriggerAddCondition( data.end, Condition( function endConds ) ) set data.endAction = TriggerAddAction( data.end, function endActs ) endfunction //=========================================================================== public function InitTrig takes nothing returns nothing set gg_trg_Apocalypse = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( gg_trg_Apocalypse, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( gg_trg_Apocalypse, Condition( function Conditions ) ) call TriggerAddAction( gg_trg_Apocalypse, function Actions ) endfunction endscope I read some codes from Rising_dusk, but I dunno if i messed up in something. Anyway, here is the map. Apocalypse 1.7.w3x Can you guys tell me, if the mods will approve it ?? I did a lot of effort in this please =S |
| 06-24-2008, 12:35 PM | #2 |
JASS:private struct Mystruct unit caster = GetTriggerUnit() timer repeator = CreateTimer() timer expirer = CreateTimer() trigger end = CreateTrigger() triggeraction endAction triggercondition endCondition endstruct JASS:private struct Mystruct unit caster timer repeator timer expirer trigger end triggeraction endAction triggercondition endCondition static method create takes nothing returns MyStruct+ local MyStruct this = MyStruct.allocate() set caster = GetTriggerUnit() set repeator = CreateTimer() set expirer = CreateTimer() set end = CreateTrigger() return this endstruct endstruct Another thing is that you use an array for 2 dummy units, which is total overkill. So I suggest rather using two unit variables. But if you want to use an array you create it without the [] (exceptions are struct arrays and oversized arrays) JASS:unit array dummy |
| 06-24-2008, 12:37 PM | #3 |
What do I do if I want to change the number of meteors, number of infernals etc? Your calibration section is lacking. |
| 06-24-2008, 12:38 PM | #4 | |||
local unit array dummy[]
Don't make false syntax up. Quote:
You say you want the code to be readable, yet you are using an array and things like dummy[0], dummy[1], please use two variables. Quote:
Quote:
|
| 06-24-2008, 03:52 PM | #5 | |||||
JASS:private struct Mystruct unit caster = GetTriggerUnit() timer repeator = CreateTimer() timer expirer = CreateTimer() trigger end = CreateTrigger() triggeraction endAction triggercondition endCondition endstruct private struct Mystruct unit caster timer repeator timer expirer trigger end triggeraction endAction triggercondition endCondition static method create takes nothing returns MyStruct+ local MyStruct this = MyStruct.allocate() set caster = GetTriggerUnit() set repeator = CreateTimer() set expirer = CreateTimer() set end = CreateTrigger() return this endstruct endstruct Meh !?, i don't understand, they do the same stuff, what is the big difference ? Quote:
Well, truth is i considered using two variables. But then I though: what if the guy next to me wants to use many dummies ? Well, It could be hard for that guy to change the whole code to add an array, so I decided to so it myself =) Quote:
If you want to change the infernals falling, you must go into the object editor and change the ability yourself, there is nothing i can do. If you want to change the number of meteors falling you must change the timers. Mmm, Maybe I should add a constant function ? Quote:
Quote:
Quote:
The meteors won't ago beyond the circle, and it is not a square, but a circle. I am using Polar projection, and I am not using the regular X, Y scheme most people use, but I am using R and TETA. I convert them into X and Y later, but I assure those two lines were heavily tested by me, and they work properly =D Ok, so, I will probably add a few more functions to customize the spell. Wermm, i didn't get the "bad idea thing". Anything else you guys want me to change? |
| 06-24-2008, 04:04 PM | #6 | |
Quote:
It's not really a discovery. It just isn't normally used because it results in points near the centre being more likely than those at the edge. Each ring has a fixed probably, rather than each point. This may or may not be what you want. Vex is, however, correct in that your code for that is wrong. You need: JASS:local real angle = GetRandomReal(0., 360.) * bj_DEGTORAD local real distance = GetRandomReal(MIN_RANGE, MAX_RANGE) local real randomX = GetUnitX(data.caster) + distance * Cos(angle) local real randomY = GetUnitY(data.caster) + distance * Sin(angle) |
| 06-24-2008, 04:12 PM | #7 | |
Quote:
|
| 06-24-2008, 04:16 PM | #8 | ||
Quote:
Quote:
Vexorian ( and thus Griffen (and thus Earth-Fury)) is just wrong. Vexorian stated that the code would probably not work for creating units within a circle. Well, it will. It won't spawn them outside the outmost circle; the code will work perfectly for what he intends, and therefore it is not wrong.If his intention is to use plane polear coordinates (R and THETA), then yeah, he should be using the method stated by Griffen above. He doesn't really need to do that for this application though. And also, you could replace GetRandomReal(0.0, 360.0) * bj_DEGTORAD with GetRandomReal(0, 2*bj_PI) |
| 06-24-2008, 05:22 PM | #9 |
Themerion, there's no need to jump on the stupid bandwagon, think for a moment. That code is wrong. The idea behind it is right, but he's doing it wrong because he is getting different random values for distance and angle when doing y calculation than he got when he was doing x. |
| 06-24-2008, 06:20 PM | #10 | |||||
Quote:
So much for "i don't see codes that use ABC". Anyway, The code is correct. Did you try to play the mini-map ? =P You should. Also, your code is equal to mine =S You just added a variable called distance ... that is a personal optimization, it depends on our styles when making code ... I think i won't change that. Quote:
Quote:
Quote:
Quote:
So, I really don't think the code is wrong ... it does everything as it should ... I don't understand you guys saying it is no correct .. i think the main issue here is that you are not used to think "Polar like", but i may never know. I am updating the code soon adding some functions to make it easier to customize. Can any1 explain me that "create" thing ? I really don't see a use for it =S EDIT EDIT EDIT Hey, here is the new version. I made more changes, and fixed a little random thingy many people wouldn't like. Anyway, here is the new version. Know that it is probably to be changed soon because there are so many people saying bad stuff about the code ='( Hope you guys like the modifications and enjoy it =D JASS://=========================================================================== //A spell that makes meteors fall randomly in the map, damaging enemy units //and summoning powerfull infernals // //@author Flame_Phoenix //@version 1.8 //=========================================================================== scope Apocalypse // globals // private constant integer AID = 'A000' // ->The rawcode of the Apocalypse hero ability // // private constant integer INFERNAL = 'A002' // ->Rawcode of the dreadlords dummy infernal spell. // This will be used to spawn an ifernal or any other unit you may like. To change the summoned // unit, just go to the dummy spell, and change it // // private constant integer SPAWN = 'A003' // ->Rawcode of the special dummy ability Flame Strike. When an infernal falls we can // not show 2 meteors. So this is a special ability, without the meteor falling ability // It is only used when the infernal is spawned // // private constant integer NO_SPAWN = 'A001' // ->Rawcode of the Flame Strike ability, when no infernal is spwaned. It is an ability // with the falling meteor animation. // // private constant integer DUMMY_RAW = 'h000' // ->The rawcode of the dummy unit that will cast all spells needed for this trigger // to work. For more information, ee the dummy unit i created in object editor. // // private constant real MIN_RANGE = 300.00 // ->The minimal range. Meteors will not fall behind this number. It was made to protect // the caster from being hurt. You can change the minimum range, but it must be ALWAYS // lower the the MAX_RANGE real. // // private constant real MAX_RANGE = 600.00 // ->The maximal range. Meteors will not fall after the number.This is the area of // effect of the spell. You can change this value, but it must be BIGGER than the // MIN_RANGE real. // // endglobals //=========================================================================================== //To change the time the spell will last, or the wait between each meteor see "function Actions" //To change damage and AOE of meteors, change the abilities: // - Flame Strike NO Infernal // - Flame Strike Infernal // - Inferno // in the ability object editor //=========================================================================================== globals private constant integer AID = 'A000' private constant integer INFERNAL = 'A002' private constant string INFERNALORDER = "dreadlordinferno" private constant integer SPAWN = 'A003' private constant string SPAWNORDER = "flamestrike" private constant integer NO_SPAWN = 'A001' private constant string NO_SPAWNORDER = "flamestrike" private constant integer DUMMY_RAW = 'h000' private constant real MIN_RANGE = 300.00 private constant real MAX_RANGE = 600.00 private constant integer METEORS = 2 endglobals private constant function meteorFall takes integer level returns integer interval return 6 / level //the time interval that separates each meteor endfunction private constant function meteorEnd takes integer level returns integer end return 5 * level + 15 //the duration of the spell endfunction private constant function infernalChance takes integer level returns integer chance return 3 * level + 1 endfunction private struct Mystruct unit caster = GetTriggerUnit() timer repeator = CreateTimer() timer expirer = CreateTimer() trigger end = CreateTrigger() triggeraction endAction triggercondition endCondition endstruct //========================================================================== private function endConds takes nothing returns boolean local Mystruct data = GetTriggerStructB(GetTriggeringTrigger()) if GetTriggerEventId() == EVENT_GAME_TIMER_EXPIRED then return true else return GetTriggerUnit() == data.caster endif endfunction //========================================================================== private function endActs takes nothing returns nothing //catches the trigger and runs this function local Mystruct data = GetTriggerStructB(GetTriggeringTrigger()) //removes the created trigger in the Actions function call TriggerRemoveCondition(data.end,data.endCondition) call TriggerRemoveAction(data.end,data.endAction) call DestroyTrigger(data.end) call ClearTriggerStructB(data.end) //stops the repeator timer and ends the spell once and for all call PauseTimer(data.repeator) call DestroyTimer(data.repeator) call PauseTimer(data.expirer) call DestroyTimer(data.expirer) call ClearTimerStructA(data.repeator) call ClearTimerStructB(data.expirer) call data.destroy() endfunction //========================================================================== private function Effect takes nothing returns nothing //catches the expired timer and runs this function local Mystruct data = GetTimerStructA(GetExpiredTimer()) //local variables local integer infernal local unit array dummy[] local integer level = GetUnitAbilityLevel(data.caster, AID) local integer counter = 0 //This uses polar projection. Formula: Center + r * trigfunction(angle teta); //where Center is the center coordinate X or Y //r is the distance (in the case rabdom between 300 and 600) //trigfunction is Sin if using Y and Cos if using X //angle teta is the angle formed between r and the axis (in this case random, can be all circle) local real randomX local real randomY loop exitwhen(counter >= METEORS) set randomX = GetUnitX(data.caster) + GetRandomReal(MIN_RANGE, MAX_RANGE) * Cos(GetRandomReal(0.0, 360.0) * bj_DEGTORAD) set randomY = GetUnitY(data.caster) + GetRandomReal(MIN_RANGE, MAX_RANGE) * Sin(GetRandomReal(0.0, 360.0) * bj_DEGTORAD) set infernal = GetRandomInt(0, 100) if (infernal <= infernalChance(level)) then set dummy[0] = CreateUnit(GetOwningPlayer(data.caster), DUMMY_RAW, GetUnitX(data.caster), GetUnitY(data.caster), 0) call UnitAddAbility(dummy[0], INFERNAL) call SetUnitAbilityLevel(dummy[0], INFERNAL, GetUnitAbilityLevel(data.caster, AID)) call IssuePointOrder(dummy[0], INFERNALORDER, randomX, randomY) call UnitApplyTimedLife(dummy[0], 'BTLF', 3) set dummy[1] = CreateUnit(GetOwningPlayer(data.caster), DUMMY_RAW, GetUnitX(data.caster), GetUnitY(data.caster), 0) call UnitAddAbility(dummy[1], SPAWN) call SetUnitAbilityLevel(dummy[1], SPAWN, GetUnitAbilityLevel(data.caster, AID)) call IssuePointOrder(dummy[1], SPAWNORDER, randomX, randomY) call UnitApplyTimedLife(dummy[1], 'BTLF', 3) else set dummy[0] = CreateUnit(GetOwningPlayer(data.caster), DUMMY_RAW, GetUnitX(data.caster), GetUnitY(data.caster), 0) call UnitAddAbility(dummy[0], NO_SPAWN) call SetUnitAbilityLevel(dummy[0], NO_SPAWN, GetUnitAbilityLevel(data.caster, AID)) call IssuePointOrder(dummy[0], NO_SPAWNORDER, randomX, randomY) call UnitApplyTimedLife(dummy[0], 'BTLF', 3) endif set dummy[0] = null set dummy[1] = null set counter = counter + 1 endloop endfunction //========================================================================== private function Conditions takes nothing returns boolean return GetSpellAbilityId() == AID endfunction //========================================================================== private function Actions takes nothing returns nothing local Mystruct data = Mystruct.create() local integer level = GetUnitAbilityLevel(data.caster, AID) //starts the effect of the spell, meteors start falling from sky call SetTimerStructA(data.repeator, data) call TimerStart(data.repeator, meteorFall(level), true, function Effect) //creates the timer that ends the spell when expired call SetTimerStructB(data.expirer, data) call TimerStart(data.expirer, meteorEnd(level), false, null) //creates the trigger that will end the spell when the timer expires or the hero dies call SetTriggerStructB(data.end, data) call TriggerRegisterTimerExpireEvent( data.end, data.expirer ) call TriggerRegisterAnyUnitEventBJ(data.end, EVENT_PLAYER_UNIT_DEATH ) set data.endCondition = TriggerAddCondition( data.end, Condition( function endConds ) ) set data.endAction = TriggerAddAction( data.end, function endActs ) endfunction //=========================================================================== public function InitTrig takes nothing returns nothing set gg_trg_Apocalypse = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( gg_trg_Apocalypse, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( gg_trg_Apocalypse, Condition( function Conditions ) ) call TriggerAddAction( gg_trg_Apocalypse, function Actions ) endfunction endscope Btw, the documentation and the comments were not improved !! I will do that later. |
| 06-24-2008, 07:01 PM | #11 | ||
Quote:
Quote:
The point is you can get different distance and angle values for each individual coordinate. You can, for example, get a distance of 375 and an angle of 90 when calculating the x offset and a distance of 450 and an angle of 180 when calculating the y offset. Now tell me, with those values, where is the meteor going to land? |
| 06-24-2008, 07:29 PM | #12 | ||
Dynamic Triggers: Somewhat simplified: A trigger is called dynamic if you do not create it at map initialization. Quote:
I am wrong. I thought he used the same angle but different distances. Aw... I badly wanted Griffen to be wrong for once... Ah, well... Quote:
Actually, as I mentioned in my first post, if you are trying to use plane polar coordinates, you are wrong. :) Instead of using x and y, you can use THETA and R. It is a map from 2 integers (x,y) into 2 integers (THETA, R). However, you are using four values to represent THETA and R... JASS:set randomX = GetUnitX(data.caster) + GetRandomReal(MIN_RANGE, MAX_RANGE) * Cos(GetRandomReal(0.0, 360.0) * bj_DEGTORAD) set randomY = GetUnitY(data.caster) + GetRandomReal(MIN_RANGE, MAX_RANGE) * Sin(GetRandomReal(0.0, 360.0) * bj_DEGTORAD) // is equal to: local real distanceX = GetRandomReal(MIN_RANGE, MAX_RANGE) local real distanceY = GetRandomReal(MIN_RANGE, MAX_RANGE) local real thetaX = GetRandomReal(0.0, 360.0) * bj_DEGTORAD local real thetaY = GetRandomReal(0.0, 360.0) * bj_DEGTORAD set randomX = GetUnitX(data.caster) + distanceX * Cos(thetaX) set randomY = GetUnitY(data.caster) + distanceY * Sin(thetaY) You use 4 random calls, and therefore you get 4 different values. 2 for THETA and 2 for R. You are currently not using plane polar coordinates. Your method would work the same if you kept the angles the same and used a different distance. |
| 06-24-2008, 07:41 PM | #13 |
Meh, so the polar coordinates thing is not that much important, since it works fine rit ? Anyway, any more suggestions ??? Btw, don't forget to see the updated code ! |
| 06-24-2008, 07:45 PM | #14 | ||
Nah, Anitarf is right. Quote:
Let's make it even more obvious: What if you get the MAX_DISTANCE for both x and y? Angle for x = 0 Angle for y = 90 x = MAX_DISTANCE * Cos(0) = MAX_DISTANCE y = MAX_DISTANCE * Sin(90) = MAX_DISTANCE You will end up at the point (MAX_DISTANCE,MAX_DISTANCE) which is clearly outside your circle (it's the corner of a square surrounding actually). Quote:
JASS:// This is wrong local unit array dummy[] // This is how to do it in jass local unit array dummy |
| 06-24-2008, 09:03 PM | #15 | |
Quote:
Ok, so, anything else for me to fix ? JASS://=========================================================================== //A spell that makes meteors fall randomly in the map, damaging enemy units //and summoning powerfull infernals // //@author Flame_Phoenix //@version 1.8 //=========================================================================== scope Apocalypse // globals // private constant integer AID = 'A000' // ->The rawcode of the Apocalypse hero ability // // private constant integer INFERNAL = 'A002' // ->Rawcode of the dreadlords dummy infernal spell. // This will be used to spawn an ifernal or any other unit you may like. To change the summoned // unit, just go to the dummy spell, and change it // // private constant integer SPAWN = 'A003' // ->Rawcode of the special dummy ability Flame Strike. When an infernal falls we can // not show 2 meteors. So this is a special ability, without the meteor falling ability // It is only used when the infernal is spawned // // private constant integer NO_SPAWN = 'A001' // ->Rawcode of the Flame Strike ability, when no infernal is spwaned. It is an ability // with the falling meteor animation. // // private constant integer DUMMY_RAW = 'h000' // ->The rawcode of the dummy unit that will cast all spells needed for this trigger // to work. For more information, ee the dummy unit i created in object editor. // // private constant real MIN_RANGE = 300.00 // ->The minimal range. Meteors will not fall behind this number. It was made to protect // the caster from being hurt. You can change the minimum range, but it must be ALWAYS // lower the the MAX_RANGE real. // // private constant real MAX_RANGE = 600.00 // ->The maximal range. Meteors will not fall after the number.This is the area of // effect of the spell. You can change this value, but it must be BIGGER than the // MIN_RANGE real. // // endglobals //=========================================================================================== //To change the time the spell will last, or the wait between each meteor see "function Actions" //To change damage and AOE of meteors, change the abilities: // - Flame Strike NO Infernal // - Flame Strike Infernal // - Inferno // in the ability object editor //=========================================================================================== globals private constant integer AID = 'A000' private constant integer INFERNAL = 'A002' private constant string INFERNALORDER = "dreadlordinferno" private constant integer SPAWN = 'A003' private constant string SPAWNORDER = "flamestrike" private constant integer NO_SPAWN = 'A001' private constant string NO_SPAWNORDER = "flamestrike" private constant integer DUMMY_RAW = 'h000' private constant real MIN_RANGE = 300.00 private constant real MAX_RANGE = 600.00 private constant integer METEORS = 1 endglobals private constant function meteorFall takes integer level returns integer interval return 6 / level //the time interval that separates each meteor endfunction private constant function meteorEnd takes integer level returns integer end return 5 * level + 15 //the duration of the spell endfunction private constant function infernalChance takes integer level returns integer chance return 3 * level + 1 endfunction private struct Mystruct unit caster = GetTriggerUnit() timer repeator = CreateTimer() timer expirer = CreateTimer() trigger end = CreateTrigger() triggeraction endAction triggercondition endCondition endstruct //========================================================================== private function endConds takes nothing returns boolean local Mystruct data = GetTriggerStructB(GetTriggeringTrigger()) if GetTriggerEventId() == EVENT_GAME_TIMER_EXPIRED then return true else return GetTriggerUnit() == data.caster endif endfunction //========================================================================== private function endActs takes nothing returns nothing //catches the trigger and runs this function local Mystruct data = GetTriggerStructB(GetTriggeringTrigger()) //removes the created trigger in the Actions function call TriggerRemoveCondition(data.end,data.endCondition) call TriggerRemoveAction(data.end,data.endAction) call DestroyTrigger(data.end) call ClearTriggerStructB(data.end) //stops the repeator timer and ends the spell once and for all call PauseTimer(data.repeator) call DestroyTimer(data.repeator) call PauseTimer(data.expirer) call DestroyTimer(data.expirer) call ClearTimerStructA(data.repeator) call ClearTimerStructB(data.expirer) call data.destroy() endfunction //========================================================================== private function Effect takes nothing returns nothing //catches the expired timer and runs this function local Mystruct data = GetTimerStructA(GetExpiredTimer()) //local variables local integer infernal local unit array dummy local integer level = GetUnitAbilityLevel(data.caster, AID) local integer counter = 0 //This uses polar projection. Formula: Center + r * trigfunction(angle teta); //where Center is the center coordinate X or Y //r is the distance (in the case rabdom between 300 and 600) //trigfunction is Sin if using Y and Cos if using X //angle teta is the angle formed between r and the axis (in this case random, can be all circle) local real randomX local real randomY loop exitwhen(counter >= METEORS) set randomX = GetUnitX(data.caster) + GetRandomReal(MIN_RANGE, MAX_RANGE) * Cos(GetRandomReal(0.0, 360.0) * bj_DEGTORAD) set randomY = GetUnitY(data.caster) + GetRandomReal(MIN_RANGE, MAX_RANGE) * Sin(GetRandomReal(0.0, 360.0) * bj_DEGTORAD) set infernal = GetRandomInt(0, 100) if (infernal <= infernalChance(level)) then set dummy[0] = CreateUnit(GetOwningPlayer(data.caster), DUMMY_RAW, GetUnitX(data.caster), GetUnitY(data.caster), 0) call UnitAddAbility(dummy[0], INFERNAL) call SetUnitAbilityLevel(dummy[0], INFERNAL, GetUnitAbilityLevel(data.caster, AID)) call IssuePointOrder(dummy[0], INFERNALORDER, randomX, randomY) call UnitApplyTimedLife(dummy[0], 'BTLF', 3) set dummy[1] = CreateUnit(GetOwningPlayer(data.caster), DUMMY_RAW, GetUnitX(data.caster), GetUnitY(data.caster), 0) call UnitAddAbility(dummy[1], SPAWN) call SetUnitAbilityLevel(dummy[1], SPAWN, GetUnitAbilityLevel(data.caster, AID)) call IssuePointOrder(dummy[1], SPAWNORDER, randomX, randomY) call UnitApplyTimedLife(dummy[1], 'BTLF', 3) else set dummy[0] = CreateUnit(GetOwningPlayer(data.caster), DUMMY_RAW, GetUnitX(data.caster), GetUnitY(data.caster), 0) call UnitAddAbility(dummy[0], NO_SPAWN) call SetUnitAbilityLevel(dummy[0], NO_SPAWN, GetUnitAbilityLevel(data.caster, AID)) call IssuePointOrder(dummy[0], NO_SPAWNORDER, randomX, randomY) call UnitApplyTimedLife(dummy[0], 'BTLF', 3) endif set dummy[0] = null set dummy[1] = null set counter = counter + 1 endloop endfunction //========================================================================== private function Conditions takes nothing returns boolean return GetSpellAbilityId() == AID endfunction //========================================================================== private function Actions takes nothing returns nothing local Mystruct data = Mystruct.create() local integer level = GetUnitAbilityLevel(data.caster, AID) //starts the effect of the spell, meteors start falling from sky call SetTimerStructA(data.repeator, data) call TimerStart(data.repeator, meteorFall(level), true, function Effect) //creates the timer that ends the spell when expired call SetTimerStructB(data.expirer, data) call TimerStart(data.expirer, meteorEnd(level), false, null) //creates the trigger that will end the spell when the timer expires or the hero dies call SetTriggerStructB(data.end, data) call TriggerRegisterTimerExpireEvent( data.end, data.expirer ) call TriggerRegisterAnyUnitEventBJ(data.end, EVENT_PLAYER_UNIT_DEATH ) set data.endCondition = TriggerAddCondition( data.end, Condition( function endConds ) ) set data.endAction = TriggerAddAction( data.end, function endActs ) endfunction //=========================================================================== public function InitTrig takes nothing returns nothing set gg_trg_Apocalypse = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ( gg_trg_Apocalypse, EVENT_PLAYER_UNIT_SPELL_EFFECT ) call TriggerAddCondition( gg_trg_Apocalypse, Condition( function Conditions ) ) call TriggerAddAction( gg_trg_Apocalypse, function Actions ) endfunction endscope |
