HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Opinion about code

06-24-2008, 08:35 AM#1
Flame_Phoenix
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.

Collapse 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
Attached Files
File type: w3xApocalypse 1.7.w3x (51.5 KB)
06-24-2008, 12:35 PM#2
tamisrah
Collapse JASS:
   private struct Mystruct
        unit caster = GetTriggerUnit()
        timer repeator = CreateTimer()
        timer expirer = CreateTimer()
        trigger end = CreateTrigger()
        triggeraction endAction
        triggercondition endCondition
    endstruct
This should probably be something like this:
Collapse 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)
Collapse JASS:
unit array dummy
06-24-2008, 12:37 PM#3
Anitarf
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
Vexorian
local unit array dummy[] Don't make false syntax up.

Quote:
Can you guys tell me, if the mods will approve it ?? I did a lot of effort in this please =S
It is using a dynamic trigger for do reason.


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:
Collapse JASS:
    private struct Mystruct
        unit caster = GetTriggerUnit()
        timer repeator = CreateTimer()
        timer expirer = CreateTimer()
        trigger end = CreateTrigger()
        triggeraction endAction
        triggercondition endCondition
    endstruct
i don't think that's a good idea.

Quote:
Collapse JASS:
        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)
    
I am quite sure this will generate a lot of points that would be outside the circle, or is it a fancy way to generate random points in a square?
06-24-2008, 03:52 PM#5
Flame_Phoenix
Collapse 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:
Another thing is that you use an array for 2 dummy units, which is total overkill
Lol, o like the expression "overkill".
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:
What do I do if I want to change the number of meteors, number of infernals etc? Your calibration section is lacking.

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:
local unit array dummy[] Don't make false syntax up.
I don't understand what you mean =(

Quote:
It is using a dynamic trigger for do reason.
Also, didn't understand your point =(

Quote:
I am quite sure this will generate a lot of points that would be outside the circle, or is it a fancy way to generate random points in a square?
No NO NO, those lines are one of my greatest discoveries =)
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
Captain Griffen
Quote:
Originally Posted by Flame_Phoenix
No NO NO, those lines are one of my greatest discoveries =)
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

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:

Collapse 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
Anitarf
Quote:
Also, didn't understand your point =(
Seems vex made a typo, I'm pretty sure he meant "no reason", not "do reason".
06-24-2008, 04:16 PM#8
Themerion
Quote:
Originally Posted by Flame_phoenix
The meteors won't ago beyond the circle, and it is not a square, but a circle.

Quote:
Originally Posted by Captain Griffen
Vex is, however, correct in that your code for that is wrong.

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
Anitarf
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
Flame_Phoenix
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:

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:
Seems vex made a typo, I'm pretty sure he meant "no reason", not "do reason".
Meh, I still don't get the point =S
Quote:
Vexorian ( and thus Griffen (and thus Earth-Fury)) is just wrong
Oh boy, is good to have some1 who actually agrees with us for a change =D.

Quote:
(R and THETA)
Meh, "H" decided to run from me =P, i little typo, thx saying.
Quote:
he is getting different random values for distance and angle
Antiarf, that is exactly what I want, and exactly what Polar Coordinate with R and THETA =p are all about (in this case).

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

Collapse 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
Anitarf
Quote:
Meh, I still don't get the point =S
You're using dynamic triggers when you don't need to, and that's a bad idea due to many reasons I don't feel like listing here.

Quote:
Antiarf, that is exactly what I want, and exactly what Polar Coordinate with R and THETA =p are all about (in this case).
Seriously, re-read what I said, not just the part you quoted.

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
Themerion
Dynamic Triggers:
Somewhat simplified: A trigger is called dynamic if you do not create it at map initialization.

Quote:
Originally Posted by Anitarf
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.

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:
Originally Posted by Fmale_Phoenix
Antiarf, that is exactly what I want, and exactly what Polar Coordinate with R and THETA =p are all about (in this case).

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...

Collapse 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
Flame_Phoenix
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
Themerion
Nah, Anitarf is right.

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?

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:
Originally Posted by Vexorian
[ Don't make up your own syntax ]

Collapse 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
Flame_Phoenix
Quote:
local unit array dummy[]
.... riiiit ... Is that so important ?? ... Bah I'll change it anyways ...
Ok, so, anything else for me to fix ?

Collapse 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