• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Meteor System 1.3b by Adiktuz

A simple meteor system written in vJass. You can use it to create meteor/falling object spells with just one function call. You can change the model, the speed, the initial height, the size, the damage, the number, the aoe, the damage/filter radius, the damage type, the attack type, the acceleration etc. It also supports hitting air units though it does not take size into consideration (I cant think of a way on how to do it.) Even though its written in vJass you do not need to have vJass knowledge since you just need one simple function call to use it.


JASS:
//Version 1.3b
library MeteorSystem initializer MSInit
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//By Adiktuz                                                                                                                                                                                                                           //
//Credits to Vexorian for Dummy.mdx                                                                                                                                                                                                    //    
//                                                                                                                                                                                                                                     //
//How To Import:                                                                                                                                                                                                                       //
//Just copy and paste this library into your map                                                                                                                                                                                       //                                    
//Be sure to export/import the dummy.mdx model and copy the dummy unit                                                                                                                                                                 //                                
//                                                                                                                                                                                                                                     //
//How to use:                                                                                                                                                                                                                          //
//just call the function MSStart(unit caster, real scale,real damage,real x, real y, real radius, real dradius, real speed, real acc, real height, string mfx, string hfx, player owner, attacktype at, damagetype dt, boolean random) //
//Where:                                                                                                                                                                                                                               //
//unit caster = the unit that casted the spell                                                                                                                                                                                         //
//real scale = scale of the unit                                                                                                                                                                                                       //            
//real damage = the damage dealt by each meteor upon contact                                                                                                                                                                           //
//real x = the center of the AOE in the x-axis (SpellTargetX or UnitX)                                                                                                                                                                 //                        
//real y = the center of the AOE in the y-axis (SpellTargetY or UnitY)                                                                                                                                                                 //                
//real radius = the radius of the AOE where the meteors can be created                                                                                                                                                                 //        
//real dradius = the radius of the damage/unitfilter                                                                                                                                                                                   //    
//real speed = the initial distance that will be travelled by the meteor after one timer interval                                                                                                                                      //
//real acc = the increase in speed after one timer interval                                                                                                                                                                            //
//real height = the initial/max height of the meteor                                                                                                                                                                                   //        
//real timedelay = the time before the meteors move, the meteors will hang in the air during this time                                                                                                                                 //                                             //
//string mfx = the path to the model to be used as the meteor                                                                                                                                                                          //    
//string hfx = the path to the effect to be played when the meteor hits the ground or an air unit                                                                                                                                      //        
//player owner = owner of the meteor                                                                                                                                                                                                   //
//attacktype at = the attacktype of the meteor                                                                                                                                                                                         //
//damagetype dt = the damagetype of the meteor                                                                                                                                                                                         //
//boolean random = whether the meteors will all start at max height or can have some discrepancies                                                                                                                                     //    
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//How to get an instance: method GetInstance takes unit u returns integer
//call Meteor.GetInstance(unit u)
//where unit u is the meteor unit whose instance you want to get.


    globals
        private constant integer MSDUMMY = 'h000' //The rawcode of the dummy unit
        private constant real TICK = 0.03 //The periodic loop time
        //DO NOT EDIT BELOW THIS LINE
        //Unless you are sure of what you're doing
        private real xx = 0
        private real yy = 0
        private timer MSTIME = CreateTimer()
        private group MSFILTER = CreateGroup()
        private group MSFILTERED = CreateGroup()
        private group MSFILTERS = CreateGroup()
        private unit MSU = null
        private integer TOTAL = 0
        private integer array METEORS
        private real MAX_X
        private real MAX_Y
        private real MIN_X
        private real MIN_Y
        private integer INSTANCE
    endglobals
    
    //Methods for setting timedelay during flight
    //The first two are instance methods
    //method SetTimeDelay takes real delay returns nothing
    //method AddTimeDelay takes real delay returns nothing
    //The next two are non-instance methods and take the unit as a parameter
    //method AddTimeDelayUnit takes unit u, real delay returns nothing
    //method SetTimeDelayUnit takes unit u, real delay returns nothing
    
    interface MeteorI
        method onHit takes nothing returns nothing
        method onHitFilter takes unit u returns boolean defaults true
        method onLoop takes nothing returns nothing defaults nothing
    endinterface
    
    struct Meteor extends MeteorI
        real x
        real y
        real height
        real radius
        unit caster
        unit meteor
        player owner
        real damage
        damagetype dt
        attacktype at
        real speed
        real acc
        string mfx
        effect sfx
        boolean air
        real timedelay
        static thistype data
        
        method onHitFilter takes unit u returns boolean
            return IsUnitEnemy(u, this.owner) and GetWidgetLife(u) >= .405
        endmethod
        
        method SetTimeDelay takes real delay returns nothing
            set this.timedelay = delay
        endmethod
        
        method AddTimeDelay takes real delay returns nothing
            set this.timedelay = this.timedelay + delay
        endmethod
        
        static method SetTimeDelayUnit takes unit u, real delay returns nothing
            set data = GetInstance(u)
            set data.timedelay = delay
        endmethod
        
        static method AddTimeDelayUnit takes unit u, real delay returns nothing
            set data = GetInstance(u)
            set data.timedelay = data.timedelay + delay
        endmethod
        
        static method GetInstance takes unit u returns integer
            local integer i = 0
            local integer a = 0
            loop
                exitwhen i == TOTAL
                set data = METEORS[i]
                if data.meteor == u then
                    set a = i
                    set i = TOTAL
                else
                    set i = 1 + 1
                endif
            endloop
            return METEORS[a]
        endmethod
        
        method onDestroy takes nothing returns nothing
            call DestroyEffect(AddSpecialEffect(this.mfx, this.x, this.y))
            call DestroyEffect(this.sfx)
            call RemoveUnit(this.meteor)
            set this.sfx = null
            set this.meteor = null
            set this.owner = null
            set this.caster = null
            set this.at = null
            set this.dt = null
        endmethod
        
        static method GLoopAir takes nothing returns nothing
            set data = INSTANCE
            set MSU = GetEnumUnit()
            if data.onHitFilter(MSU) then
                call UnitDamageTarget(data.caster, MSU, data.damage, false, false, data.at, data.dt, WEAPON_TYPE_WHOKNOWS)
                call DestroyEffect(AddSpecialEffectTarget(data.mfx, MSU, "origin"))
            endif
            call GroupRemoveUnit(MSFILTERED, MSU)
        endmethod
        
        static method GLoop takes nothing returns nothing
            set data = INSTANCE
            set MSU = GetEnumUnit()
            if IsUnitEnemy(MSU, data.owner) and GetWidgetLife(MSU) >= .405 then
                call UnitDamageTarget(data.caster, MSU, data.damage, false, false, data.at, data.dt, WEAPON_TYPE_WHOKNOWS)
            endif
            call GroupRemoveUnit(MSFILTERS, MSU)
        endmethod
        
        method onHit takes nothing returns nothing
            set data = this
            set INSTANCE = data
            if data.air then
                call ForGroup(MSFILTERED, function Meteor.GLoopAir)
            else
                call GroupEnumUnitsInRange(MSFILTERS, data.x, data.y, data.radius, null)
                call ForGroup(MSFILTERS, function Meteor.GLoop)
            endif
            call data.destroy()
        endmethod
        
        static method MeteorLoop takes nothing returns nothing
            local integer i = 0
            local real fly = 0
            loop
                 exitwhen i == TOTAL
                 set data = METEORS[i]
                 set data.timedelay = data.timedelay - TICK
                 call data.onLoop()
                 if data.timedelay <= 0 then
                    set data.height = data.height - data.speed
                    call SetUnitFlyHeight(data.meteor, data.height, 0.00)
                    set data.speed = data.speed + data.acc
                    //The following lines until the next comment are for hitting air units
                    call GroupEnumUnitsInRange(MSFILTER, data.x, data.y, data.radius, null)
                    loop
                        set MSU = FirstOfGroup(MSFILTER)
                        exitwhen MSU == null
                        set fly = GetUnitFlyHeight(MSU)
                        if  (fly >= data.height - 50) and (fly <= data.height + 50) and IsUnitEnemy(MSU, data.owner) then
                            call GroupAddUnit(MSFILTERED, MSU)
                        endif
                        call GroupRemoveUnit(MSFILTER, MSU)
                    endloop
                    if FirstOfGroup(MSFILTERED) != null then
                        set data.height = 0
                        set data.air = true
                    endif
                    //End
                    if data.height <= 0 then
                        call data.onHit()
                        set TOTAL = TOTAL - 1
                        set METEORS[i] = METEORS[TOTAL]
                        set i = i - 1
                    endif
                endif
                call GroupClear(MSFILTERED)
                set i = i + 1
            endloop
            if TOTAL == 0 then
                call PauseTimer(MSTIME)
            endif
        endmethod
    endstruct
    
    function MSStart takes unit caster, real scale, real damage, real x, real y, real radius,  real dradius, real speed , real acc, real height, real timedelay, string mfx, string hfx, player owner, attacktype at, damagetype dt, boolean random returns nothing
        local Meteor dat = Meteor.create()
        //These loops is to prevent fatal error due to unit creation outside of map bounds
        //I separated it so that when x is already inside the map bounds it will not be reset anymore 
        loop
            exitwhen (xx == 1)
            set dat.x = x + GetRandomReal(-radius, radius)
            set xx = 1
            if dat.x <= MIN_X or dat.x >= MAX_X then
                set xx = 0
            endif
        endloop
        loop
            exitwhen (yy == 1)
            set dat.y = y + GetRandomReal(-radius, radius)
            set yy = 1
            if dat.y <= MIN_Y or dat.y >= MAX_Y then
                set yy = 0
            endif
        endloop
        set dat.timedelay = timedelay
        set xx = 0
        set yy = 0
        set dat.caster = caster
        set dat.damage = damage
        set dat.meteor = CreateUnit(owner, MSDUMMY, dat.x, dat.y, GetRandomReal(0, 360))
        call SetUnitScale(dat.meteor, scale, scale, scale)
        set dat.air = false
        set dat.radius = dradius
        set dat.speed = speed
        set dat.mfx = hfx
        set dat.sfx = AddSpecialEffectTarget(mfx, dat.meteor, "origin")
        set dat.at = at
        set dat.dt = dt
        set dat.acc = acc
        set dat.owner = owner
        call UnitAddAbility(dat.meteor, 'Amrf')
        call UnitRemoveAbility(dat.meteor, 'Amrf')
        if random then
            set dat.height = height + GetRandomReal(-height*.1, height*.1)
        else
            set dat.height = height
        endif
        call SetUnitFlyHeight(dat.meteor, dat.height, 0.00)
        set METEORS[TOTAL] = dat
        set TOTAL = TOTAL + 1
        if TOTAL == 1 then
            call TimerStart(MSTIME, TICK, true, function Meteor.MeteorLoop)
        endif
    endfunction
    
    function MSInit takes nothing returns nothing
        set MAX_X = GetRectMaxX(bj_mapInitialPlayableArea)
        set MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea)
        set MIN_X = GetRectMinX(bj_mapInitialPlayableArea)
        set MIN_Y = GetRectMinY(bj_mapInitialPlayableArea)
    endfunction
endlibrary

JASS:
library MeteorSystemAutomizer requires MeteorSystem
//Basically this system automizes looped meteor creation for you...
//And gives you the ability to easily create meteors over a period of time
//So instead of making your own loop to create meteors over time you just need to call
//the creation function here which is pretty similar to the Meteor creation
//but takes three additional parameters
//call AutoMeteor.MeteorAutoCreate(unit caster, integer totalmeteors, integer meteorsperloop, real looptime, real scale, real damage, real x, real y, real radius,  real dradius, real speed , real acc, real height, real timedelay, string mfx, string hfx, player owner, attacktype at, damagetype dt, boolean random)
//Where:
//integer totalmeteors = total number of meteors to be created
//integer meteorsperloop = number of meteors created every real looptime
//real looptime = interval in which meteors will be created
//the other parameters are the same as those in the MeteorSystem (see MeteorSystem for details about them)

    globals
        private timer AUTO_M_T = CreateTimer()
        private constant real TICK = .03
        private integer TOTAL = 0
        private integer array AUTO_M
    endglobals

    interface AutoInt
        //This method is called when each meteor is created
        method OnCreateS takes nothing returns nothing defaults nothing
        //This method is called when a set of meteors is created
        method OnCreateG takes nothing returns nothing defaults nothing
    endinterface
    
    struct AutoMeteor extends AutoInt
        real x
        real y
        real height
        real radius
        real dradius
        unit caster
        real scale
        player owner
        real damage
        damagetype dt
        attacktype at
        real speed
        real acc
        string mfx
        string hfx
        real timedelay
        integer mps
        integer tmc
        real looptime
        real ctime
        boolean random
        static thistype data
        
        static method MeteorAutoLoop takes nothing returns nothing
            local integer i = 0
            local integer a = 1
            loop
                exitwhen i == TOTAL
                set data = AUTO_M[i]
                set data.ctime = data.ctime - TICK
                if data.ctime <= 0.00 then
                    set data.ctime = data.looptime
                    call data.OnCreateG()
                    set data.tmc = data.tmc - data.mps
                    loop
                        exitwhen a > data.mps
                        call data.OnCreateS()
                        call MSStart(data.caster, data.scale, data.damage, data.x, data.y, data.radius, data.dradius, data.speed, data.acc, data.height, data.timedelay, data.mfx, data.hfx, data.owner, data.at, data.dt, data.random)
                        set a = a + 1
                    endloop
                    set a = 1
                endif
                if data.tmc <= 0 then
                    set TOTAL = TOTAL - 1
                    set AUTO_M[i] = AUTO_M[TOTAL]
                    set i = i - 1
                    call data.destroy()
                endif
                set i = i + 1
            endloop
            if TOTAL == 0 then
                call PauseTimer(AUTO_M_T)
            endif
        endmethod
        
        static method MeteorAutoCreate takes unit caster, integer totalmeteors, integer meteorsperloop, real looptime, real scale, real damage, real x, real y, real radius,  real dradius, real speed , real acc, real height, real timedelay, string mfx, string hfx, player owner, attacktype at, damagetype dt, boolean random returns nothing
            set data = AutoMeteor.create()
            set AUTO_M[TOTAL] = data
            set TOTAL = TOTAL + 1
            set data.caster = caster
            set data.tmc = totalmeteors
            set data.mps = meteorsperloop
            set data.looptime = looptime
            set data.ctime = looptime
            set data.scale = scale
            set data.damage = damage
            set data.x = x
            set data.y = y
            set data.radius = radius
            set data.dradius = dradius
            set data.speed = speed
            set data.acc = acc
            set data.height = height
            set data.timedelay = timedelay
            set data.owner = owner
            set data.mfx = mfx
            set data.hfx = hfx
            set data.at = at
            set data.dt = dt
            set data.random = random
            if TOTAL == 1 then
                call TimerStart(AUTO_M_T, TICK, true, function AutoMeteor.MeteorAutoLoop)
            endif
        endmethod
        
    endstruct
endlibrary


I have included two sample spells that can show how this system is used.

Needs JNGP to save

Credits to Vexorian for dummy.mdl




Version 1.3b - Added two OnCreate interface methods on the AutoMeteor. I did not update the map itself, just the code, so just copy the AutoMeteor library from this post into your map.
Version 1.3b - added onHitFilter interface method to allow easy changes to the damage filter per spell which uses this system.

Version 1.3 - Added a new library MeteorSystemAutomizer which enables easy meteor
creation loops and meteor creation over time

Version 1.2c - fixed the GetInstance method
- added two non-instance timedelay setting methods.
- Removed the two instance timedelay methods from interface coz they really
shouldnt be there
-added the onHit on the interface...
-added an onLoop interface method which is called during the MeteorLoop
-replaced all local Meteor dat with a static thistype data...

Version 1.2b - added filter to the FG loops on the onhit method to only damage enemies and living units

Version 1.2 - changed the onHit group loop rom an FoG into a FG loop. Added GetInstance(please check the code for this one...) Also added a new parameter timedelay which can make the meteor "hang" in the air for timedelay and only move after that... Added also two methods to set or add timedelay to a meteor during its flight...

Version 1.1 - changed the attachement point of the meteor effect to origin instead of chest since it causes the meteor to be offset by a bit


Keywords:
meteor, jass, vjass, spell, system, falling, blades, shower, blizzard, magic
Contents

MeteorSystem 1.3 (Map)

Reviews
15:18, 19th Aug 2010 hvo-busterkomo: The system is good enough to be approved. Use xexf and xebasic. Use BoundSentinel. The use of acceleration (users could obviously set it to 0 for no acceleration). Use GroupUtils, and also improving the...

Moderator

M

Moderator

15:18, 19th Aug 2010
hvo-busterkomo: The system is good enough to be approved.

  • Use xexf and xebasic.
  • Use BoundSentinel.
  • The use of acceleration (users could obviously set it to 0 for no acceleration).
  • Use GroupUtils, and also improving the way groups are handled in the system (needlessly complicated).
 
Oops, forgot to change the attachment point to origin instead of chest... I'll be updating it tomorrow. Please comment. Thanks!

Note: you may notice that the damage radius is a little bit off in-game, that is because I had forgot to set the attachment point of the meteor model/effect to the origin, instead I had placed it in the chest and the dummy is tilted so the points are off by a little bit. That will be fixed tomorrow...
 
Level 7
Joined
Jun 6, 2010
Messages
224
use an indexing method to find your struct instance so you can make your group loop work on the Enumeration.

Also you could make this more configurable with more constants?
Give the user the ability to choose which units are affected by the damage?

ever considered using XE for your dummy?

If you can't manage to do the group method i stated above,
use temp groups (prolly make them static) and use them for each instance


JASS:
private real xx = 0
        private real yy = 0
        private timer MSTIME = CreateTimer()
        private group MSFILTER = CreateGroup()
        private group MSFILTERED = CreateGroup()
        private group MSFILTERS = CreateGroup()
        private unit MSU = null
        private integer TOTAL = 0
        private integer array METEOR
        private real MAX_X
        private real MAX_Y
        private real MIN_X
        private real MIN_Y
since these are not configurable, i suggest you declare them as static in your struct declaring .

I'll rate 3/5 because this needs a little bit of work...
I also beleive that dummy.mdl has a "chest" attachment ;P
The eye candy was good enough for my simplicity.
 

use an indexing method to find your struct instance so you can make your group loop work on the Enumeration.

Also you could make this more configurable with more constants?
Give the user the ability to choose which units are affected by the damage?

ever considered using XE for your dummy?

If you can't manage to do the group method i stated above,
use temp groups (prolly make them static) and use them for each instance


JASS:
private real xx = 0
        private real yy = 0
        private timer MSTIME = CreateTimer()
        private group MSFILTER = CreateGroup()
        private group MSFILTERED = CreateGroup()
        private group MSFILTERS = CreateGroup()
        private unit MSU = null
        private integer TOTAL = 0
        private integer array METEOR
        private real MAX_X
        private real MAX_Y
        private real MIN_X
        private real MIN_Y
since these are not configurable, i suggest you declare them as static in your struct declaring .

I'll rate 3/5 because this needs a little bit of work...
I also beleive that dummy.mdl has a "chest" attachment ;P
The eye candy was good enough for my simplicity.

of course it has "chest" but the problem is that the radius is filtered from the origin I think and the unit is tilted so the chest is a little bit off from the x,y position. IDK if its really off but that is what I have observed, I'M NOT SURE ABOUT IT THOUGH. ^^

hmm... about adding the ability to check the units that get damaged, not sure if I can do it... about indexing, IDK how to use indexing...

for the eye candy, it depends on what the user wants to use since you can change it for every spell that will use this sytem...

for XE, I really do not use it, IDK why...

and what do you mean with more constants? every configurables are reallt in the function parameters and I'm still thinking If I can add more...

and for those uneditables, I'm used to adding them as globals... anyway is there any difference if I put them as statics?

Thanks for the comment. ^^
 
Level 7
Joined
Jun 6, 2010
Messages
224
which units are affected by the effect
How to do?

Declare some constant booleans
like

JASS:
private constant boolean HIT_ANCIENTS = true

then in your group filtering

JASS:
local boolean b = IsUnitType(GetEnumUnit(), UNIT_TYPE_ANCIENT) == false
static if HIT_ANCIENTS then
    set b = true
endif

this will always make your effect to hit ancients

stating : static if
makes the preprocessor delete any statements inside that block if your boolean flag is false.

example : if HIT_ANCIENTS is true
the block will become

set b = true

else it will just erase the whole block
this happens on compilation

a way to index an instance through the struct (may be slow if we got a shitload of instances running) is this
DEMO:
JASS:
static method GetInstance takes unit u returns integer
    local thistype data
    local integer i = 0
    loop
    exitwhen i > INTEGER_TOTAL
        set data = INTEGER_ARRAY[i]
        if IsUnit(u, data.u) then
            return data
        endif
        set i = i + 1
    endloop
    return 0
endmethod

It's not the best method, but still it's one

and for those uneditables, I'm used to adding them as globals... anyway is there any difference if I put them as statics?
There is no difference...
You can just do it imo so your global block (that users will read first) will look cleaner, lol. You can add constants there instead of the uneditable globals.
 
well, I need everything changeable to be set in the function parameter instead of a global constant since it is a system and not a single spell... if I use a global constant then that can cause problems if you want one spell that uses this system to hit ancients while you want another one to ignore ancients...

for the indexing, hmmm... I'd prefer to use this FOGloop rather than that since it will still use many lines...
 
Level 7
Joined
Jun 6, 2010
Messages
224
Well since it's a system for meteor showering you can point some directions to users on what to change on their functions to make more meteors, to deal more damage, to apply effect on meteor hit on ground.

In that case declare an interface with methods like, onLoop and onGround so people can extend your systems to their structs (if they use any)

JASS:
interface Demo
    method onGround takes nothing returns nothing defaults nothing
    method onLoop takes nothing returns nothing defaults nothing
endinterface
 
Well since it's a system for meteor showering you can point some directions to users on what to change on their functions to make more meteors, to deal more damage, to apply effect on meteor hit on ground.

In that case declare an interface with methods like, onLoop and onGround so people can extend your systems to their structs (if they use any)

details on how to use the system is at the top of the library...

and that's my problem until now, I dont seem to understand how interfaces work and how to use them... I'm so dumb... ^^
 
Level 7
Joined
Jun 6, 2010
Messages
224
Ah well i'm dumb as well for not reading the FAQ :p

ok... Let me explain a little bit

interfaces allow us to extend a parent struct
meaning we create a child struct anywhere (if parent struct is accesable ofcourse)
and we access it's methods that have been declared on the interface.
These methods are called within other methods inside the parent struct.
for instance:

JASS:
interface Handler
    method onGround takes nothing returns nothing defaults nothing
endinterface

struct Rain
    
     static method RainDrop takes nothing returns nothing
          local Rain drop
          call drop.onGround() //The method onGround will be executed whenever this method is called
     endmethod
endstruct

//That was our parent struct

struct Thunder extends Rain
    method onRain takes nothing returns nothing
        call DoSome(SeriousShit_Here)
    endmethod
endstruct

I hope i enlighted you
 
Ah well i'm dumb as well for not reading the FAQ :p

ok... Let me explain a little bit

interfaces allow us to extend a parent struct
meaning we create a child struct anywhere (if parent struct is accesable ofcourse)
and we access it's methods that have been declared on the interface.
These methods are called within other methods inside the parent struct.
for instance:

JASS:
interface Handler
    method onGround takes nothing returns nothing defaults nothing
endinterface

struct Rain
    
     static method RainDrop takes nothing returns nothing
          local Rain drop
          call drop.onGround() //The method onGround will be executed whenever this method is called
     endmethod
endstruct

//That was our parent struct

struct Thunder extends Rain
    method onRain takes nothing returns nothing
        call DoSome(SeriousShit_Here)
    endmethod
endstruct

I hope i enlighted you

well, thanks for the effort but I really cant seem to get it... I think its because I cannot see how it works or how to make it work, because its not existent in those lines... I'm really dumb...

ex. I cannot seem to understand how or what onGround does because I do not see any action under it... this is mostly the case when I look on lines with interfaces...
 
the stupid heat of 41 celsius is really killing me thats why its taking so long xD
I think i'm gonna make hundreds of mistakes at the end of the day

well, the heat is really giving us a lot of stress and lots of tolls to our bodies...

PS: right now I'm working on TAS:TGA, it got removed from the maps section due to rejection which I guess is due to the fact that I havent made a good description...

Edit: checked the code for the meteor spell in one of my spellpacks and yeah, it should really be origin rather than chest... so the meteors are really a little bit position off right now...
 
Level 7
Joined
Jun 6, 2010
Messages
224
what the fuck? Are you insulting me? I never wanted to offend him. I would do this to help him understanding interfaces and so on. Please use your brain befor you talk....

You could help him with an example not by making his own system, that's what i meant. What good would it be for him if you did his homework?
 
Last edited by a moderator:
Level 22
Joined
Dec 31, 2006
Messages
2,216
Here's a simple example of how you can use interfaces.

JASS:
interface Sound
    method MakeSound takes nothing returns nothing
endinterface

struct Animal extends Sound

    method Lol takes nothing returns nothing
        call this.MakeSound()
    endmethod
    
    //Any child struct which define their own MakeSound
    //method will overwrite this one.
    //If no MakeSound method is created in the child struct
    //then this method will be called instead.
    method MakeSound takes nothing returns nothing
        //As there's no code inside here nothing will happen
        //if this "default" method runs.
    endmethod
endstruct

struct Cat extends Animal
    static method create takes nothing returns Cat
        local Cat c = Cat.allocate()
        call c.Lol() //Here we call the parent method "Lol"
        return c
    endmethod

    method MakeSound takes nothing returns nothing
        call BJDebugMsg("MEOW")
    endmethod
endstruct

What happens is that when you create the cat it will call the parent function "Lol" which again calls the "MakeSound" function. This will output "MEOW" when the cat is created. No text will be displayed if you create the Animal instead.
 
Last edited:
Here's a simple example of how you can use interfaces.

JASS:
interface Sound
    method MakeSound takes nothing returns nothing
endinterface

struct Animal extends Sound

    method Lol takes nothing returns nothing
        call this.MakeSound()
    endmethod
    
    //Any child struct which define their own MakeSound
    //method will overwrite this one.
    //If no MakeSound method is created in the child struct
    //then this method will be called instead.
    method MakeSound takes nothing returns nothing
        //As there's code inside here nothing will happen
        //if this "default" method runs.
    endmethod
endstruct

struct Cat extends Animal
    static method create takes nothing returns Cat
        local Cat c = Cat.allocate()
        call c.Lol() //Here we call the parent method "Lol"
        return c
    endmethod

    method MakeSound takes nothing returns nothing
        call BJDebugMsg("MEOW")
    endmethod
endstruct

What happens is that when you create the cat it will call the parent function "Lol" which again calls the "MakeSound" function. This will output "MEOW" when the cat is created. No text will be displayed if you create the Animal instead.

thanks, I kinda get it but why would I need to have the interface? I mean you define the method in the other structs so why use the interface?

I have an idea, I use an interface so that I can have a function call that can have multiple outputs depending on the child struct that calls that function? and so that I can call a method(from struct A) from another struct(B) and attach/call a method inside the struct(B) where I called (A)?
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
(Lol, forgot a "no" in my previous example xD)

Interfaces aren't needed, but they are pretty nice. It's much clearer if you have a list of methods in an interface than having a ton of methods inside a struct together with a bunch of other things. For example; let's say you find this awesome system on the hive which is written in vJASS. Whenever you want to make a spell with this system you must create your own struct which extends some other struct in the system. If this system got a bunch of methods it's much neater to have an interface where all the functions are listed than having to go through the whole script to find them. Here's an example:

(Using interface)
JASS:
interface Example
    method A takes nothing returns nothing
    method B takes nothing returns nothing
    method C takes nothing returns nothing
    method D takes nothing returns nothing
    method E takes nothing returns nothing
    method F takes nothing returns nothing
    method G takes nothing returns nothing
    method H takes nothing returns nothing
endinterface

struct Example2 extends Example
    //<blabla>
endstruct

struct Example3 extends Example2
    //<blabla>
endstruct

(Not using interface)
JASS:
struct Example
    //Insert bunch of members
    
    stub method A takes nothing returns nothing
    endmethod
    
    stub method B takes nothing returns nothing
    endmethod
    
    stub method C takes nothing returns nothing
    endmethod
    
    stub method D takes nothing returns nothing
    endmethod
    
    stub method E takes nothing returns nothing
    endmethod
    
    stub method F takes nothing returns nothing
    endmethod
    
    stub method G takes nothing returns nothing
    endmethod
    
    stub method H takes nothing returns nothing
    endmethod
    
    //Add a shitload of other internal methods the system uses
endstruct

struct Example2 extends Example
    //<blabla>
endstruct

As you can see, it's both shorter and easier to read. It's also important to remember to have the interface almost at the top of the script to increase visibility.
 
so I can just add the interface/endinterface without defining any actions for those methods listed right?

or, I'll add the interface and then make my struct extend that interface and use the methods in the interface as the method names inside my struct?

example of what I think based on the comments...

I'll add this line
JASS:
interface meteorint
    method onHit takes nothing returns nothing
endinterface

and then make the struct extend this
JASS:
struct Meteor extends meteorint

then create a method in the struct call onHit and move the damaging actions from onDestroy to the onHit and call this onHit before I call .destroy()
JASS:
     method onHit takes nothing returns nothing
        if this.air then
                loop
                    set MSU = FirstOfGroup(MSFILTERED)
                    exitwhen MSU == null
                    call UnitDamageTarget(this.caster, MSU, this.damage, false, false, this.at, this.dt, WEAPON_TYPE_WHOKNOWS)
                    call GroupRemoveUnit(MSFILTERED, MSU)
                    call DestroyEffect(AddSpecialEffectTarget(this.mfx, MSU, "origin"))
                endloop
            else
                call GroupEnumUnitsInRange(MSFILTERS, this.x, this.y, this.radius, null)
                loop
                    set MSU = FirstOfGroup(MSFILTERS)
                    exitwhen MSU == null
                    if IsUnitEnemy(MSU, this.owner) then
                        call UnitDamageTarget(this.caster, MSU, this.damage, false, false, this.at, this.dt, WEAPON_TYPE_WHOKNOWS)
                    endif
                    call GroupRemoveUnit(MSFILTERS, MSU)
                endloop
                call DestroyEffect(AddSpecialEffect(this.mfx, this.x, this.y))
            endif
     endmethod

please comment and check if I'm getting the right idea about using interfaces...
 
Last edited:
Level 14
Joined
Nov 18, 2007
Messages
1,084
Really short code pointers:

  • You're allowing dead units to be damaged.
  • The initializer function should be private.
  • boolean air could be initially set to false when declared as a struct member.
Anyway, I don't know how the others would want you to use inheritance to make this system more customizable, but I would think this system would have been better done if a) it took the form of a struct that can be extended, similar to xecollider, or b) it allowed functions to be passed into MSStart function that get called when the meteor falls. The first method is probably better than the second one I mentioned.
 
Level 22
Joined
Dec 31, 2006
Messages
2,216
so I can just add the interface/endinterface without defining any actions for those methods listed right?

or, I'll add the interface and then make my struct extend that interface and use the methods in the interface as the method names inside my struct?

example of what I think based on the comments...

I'll add this line
JASS:
interface meteorint
    method onHit takes nothing returns nothing
endinterface

and then make the struct extend this
JASS:
struct Meteor extends meteorint

then create a method in the struct call onHit and move the damaging actions from onDestroy to the onHit and call this onHit before I call .destroy()
JASS:
     method onHit takes nothing returns nothing
        if this.air then
                loop
                    set MSU = FirstOfGroup(MSFILTERED)
                    exitwhen MSU == null
                    call UnitDamageTarget(this.caster, MSU, this.damage, false, false, this.at, this.dt, WEAPON_TYPE_WHOKNOWS)
                    call GroupRemoveUnit(MSFILTERED, MSU)
                    call DestroyEffect(AddSpecialEffectTarget(this.mfx, MSU, "origin"))
                endloop
            else
                call GroupEnumUnitsInRange(MSFILTERS, this.x, this.y, this.radius, null)
                loop
                    set MSU = FirstOfGroup(MSFILTERS)
                    exitwhen MSU == null
                    if IsUnitEnemy(MSU, this.owner) then
                        call UnitDamageTarget(this.caster, MSU, this.damage, false, false, this.at, this.dt, WEAPON_TYPE_WHOKNOWS)
                    endif
                    call GroupRemoveUnit(MSFILTERS, MSU)
                endloop
                call DestroyEffect(AddSpecialEffect(this.mfx, this.x, this.y))
            endif
     endmethod

please comment and check if I'm getting the right idea about using interfaces...

Ye, that looks good to me.
 
Ye, that looks good to me.

so basically interfaces just contain all the methods you can use?

EDIT: might update next week coz I think I got an idea on how to pass the instance to the ForGroup Loop... maybe this will require a GroupRecycler after the update, I'll also add a method to get the struct instance based on an individual meteor...

EDIT2: updated to version 1.2c... see changelogs... please comment on the setting of the onHit and onLoop interface methods...

EDIT3: updated to version 1.3 - added a new library which enables Over Time creation...
 
Last edited:
How do you get the spell to work because i always have to put it on another spell:vw_wtf:

oh, sorry for the late reply (it didn't show a notice on my usercp)... this is not a spell, this is a system which means, it is used by a spell so you need to make your own spell and make it use the system, just like what I did on the sample spells...

UPDATE!:while I was thinking, I realized a major flaw in my systems, that is the fact that its hard to modify the damage filter per spell that uses the system, so I added a new interface method (onHitFilter) which is used as the filter that checks if a unit will be damaged or not... now users just need to extend the struct and make their own onHitFilter method to modify the damage filter... ^_^
__________________
 
Top