Spell Shiva's Guard(Artic Blast)vJass

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Yea, it works, but you need to adjust the animation time of dummy to 0.000.
 

Romek

Super Moderator
Reaction score
963
JASS:
    private constant integer abil_id = 'A000'
    private constant real AoE = 600.
    private constant real speed = 25.
    private constant integer slideDummyId = 'e001'
    private constant integer CasterDummyId = 'n000'

Please use a non-retarded naming convention.
All small + underscore, small/capital, all small, start small, sentence case... All for constant globals..?

JASS:
library SomeNamingConvention

    globals
        constant integer CONSTANT_GLOBAL = 0 // All Caps
        
        integer OtherGlobal // Capital on first letter of each word
    endglobals
    
    struct StructName // Capital on first letter of each word
        
        integer structmember // All small
        
        method methodName takes nothing returns nothing // First word small, then capital on first letter of each word.
        
        endmethod
        
    endstruct

    // Function Names: Capital on first letter of each word
    // Arguments: either a single, small letter. Or same as struct methods.
    function SomeOtherFunction takes integer i, unit whichUnit returns nothing
        // Locals are all small. They're usually not longer than 3 letters though.
        local integer somelocal
    endfunction

endlibrary


You should probably clear the ABC struct before destroying the timer.
In fact, you shouldn't even destroy timers.
 

Viikuna

No Marlo no game.
Reaction score
265
Have you tried it?

Yep. And I have decided to start kind of "Use only one dummy" - educational project, which means that I will appear to suggest it to every thread where someone creates dummies during the spellcast when its not needed.

Actually, I just realized that it is possible in GUI too ( Sometimes I forget what GUI can&cant do ), so I guess I need to advertise it to GUI users too..

edit. Or maybe I should write a tutorial, but meh.. I dont like writing tutorials..
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Revamped the code, v2.0!!

What's new?
Use T32, use one dummy for whole spell, use linked list instead of struct array, uses radian instead of angle.
 

Laiev

Hey Listen!!
Reaction score
188
Push'd save button then...

shivas.jpg



(?)
 

Kenny

Back for now.
Reaction score
202
@ Laiev:

What JassHelper do you have? There was a problem with module onInit methods conflicting with struct onInit methods a while ago. That is probably the cause of the error.

As for the spell itself, and the update...

I'd probably like to see some constant functions for area of effect, wave speed, damage and possibly number of effects.

JASS:
private constant integer NUMBER_OF_BEAMS = 36// In v2.0, this constant is flexible, since linked list is introduced.


Why is it only flexible once you introduced a linked list implementation? Arrays should do just fine for this spell.

As for the linked list implementation, are you serious? I think you are over doing it a bit. As I said, a unit array will be just fine. You don't even have a need to detach links from the list, or do anything that linked list functionality actually provides. What you use works just like an array at the moment.

Your naming convention in the Data struct is a little whack. And there are a few struct members that aren't even needed, like [ljass]private integer loopz[/ljass] and of course the LinkedList members.

[ljass]implement T32[/ljass] Should be put BELOW the periodic method. And it seems like you are using the deprecated version of T32. Try using T32x. Also, you can then use T32_Tick and make your tick counting simpler.

Now that I look at it again, your linked list implementation just got worse. Why a static list and a non-static list? And you switch between the two for some reason.

You should be using Dummy Caster by Jesus4Lyf. That is exactly what this needs.

Your spell conditions and actions can be combined to save a trigger action call as well.

There should also be some kind of filter function that users can modify so that they can choose who to target.

Also, to make this even more configurable, you should use vexorian's dummy model. Then users can specify what their nova should look like.

That is just from first glance at your code. But I do believe there is a lot of stuff that needs to be fixed before this can get approved.
 

Laiev

Hey Listen!!
Reaction score
188
@ Laiev:

What JassHelper do you have? There was a problem with module onInit methods conflicting with struct onInit methods a while ago. That is probably the cause of the error.
EDIT [2]: Thx, no problem anymore.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Yeah, kenny! already nailed it, but...

>implement T32
This needs to always be directly below .periodic, as it says in the documentation. It makes a substantial difference to efficiency. :)

>You should be using Dummy Caster by Jesus4Lyf. That is exactly what this needs.
Yep. Just make sure you always do:
JASS:
call UnitAddAbility(DUMMY,'abil')
call SetUnitAbilityLevel(DUMMY,'abil',level)
call IssueTargetOrderById(...)
call UnitRemoveAbility(DUMMY,'abil') // important, else this can conflict with other abilities.
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Yay, updated to v2.1

>Your spell conditions and actions can be combined to save a trigger action call as well.

>There should also be some kind of filter function that users can modify so that they can choose who to target.
Oh ya, v2.1 added these.

>Also, to make this even more configurable, you should use vexorian's dummy model. Then users can specify what their nova should look like.
This lowers the fps, I tested.

JASS:
    call UnitAddAbility(DUMMY,'abil')
    call SetUnitAbilityLevel(DUMMY,'abil',level)
    call IssueTargetOrderById(...)
    call UnitRemoveAbility(DUMMY,'abil') // important, else this can conflict with other abilities.
It costs more function calls. ><

Maybe I will use xeCast.
 

Kenny

Back for now.
Reaction score
202
o_O

What did you do!?!

JASS:
.
            set thistype.enumGroup = CreateGroup()
            set thistype.cf = Condition(function thistype.Effects)
            set thistype.radianOfCircle = (2 * bj_PI) / NUMBER_OF_BEAMS
            set thistype.dummyOwner = Player(15)
            set thistype.spellTicks = R2I(AOE / WAVE_SPEED)
            set thistype.dummy = CreateUnit(thistype.dummyOwner,DUMMY_ID,0.,0.,0.)
            call UnitAddAbility(thistype.dummy,DUMMY_SLOW_ID)
            
            set thistype.loopz = NUMBER_OF_BEAMS
            loop
            exitwhen thistype.loopz == 0
                set thistype.radianOfBeams[thistype.loopz] = thistype.radianOfCircle * thistype.loopz
                set thistype.angleOfBeams[thistype.loopz] = thistype.radianOfBeams[thistype.loopz] * 57.2958
                set thistype.cosine[thistype.loopz] = Cos(thistype.radianOfBeams[thistype.loopz])
                set thistype.sine[thistype.loopz] = Sin(thistype.radianOfBeams[thistype.loopz])
                set thistype.loopz = thistype.loopz - 1
            endloop


That basically just ruins this for those who want a different amount of 'beams' per level, amongst other things.

Please just follow some of the standards you see for most spells submitted here.

JASS:
private static method Filter takes unit whichUnit returns boolean
    return GetWidgetLife(whichUnit) &gt; .405 and IsUnitEnemy(whichUnit,thistype.this.p) and not IsUnitInGroup(whichUnit,thistype.this.damaged) and IsUnitType(whichUnit,UNIT_TYPE_STRUCTURE) == false 
endmethod


I find that function name tacky. Just pick a name that isn't already a function name?

Please, for the love of God, just use Dummy Caster. :p

xeCast is overkill, and is more complex then just using Dummy Caster. The only thing different with dummy caster is that you have to remove the spell from the dummy afterwards. It wont be that much of a strain on people's computers.

Your naming convention is still weird. At least be consistent. You have [ljass]unit cs[/ljass] for the caster, while you have [ljass]group damaged[/ljass] for the unit group. Either spell them all out and shorten them all of something.

I still think your static integer loopz is unneeded, and I think you can use T32_Tick better.

And some constant functions would be nice for configurability. :)

Honestly, it would take around 5-10 minutes for many members of this community to write this and follow proper conventions, as it isn't that complicated. So just putting in a bit of effort will definately go a long way, and stop people from submitting the same thing but better (I have thought about doing it for many submissions).
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
JASS:
            set thistype.enumGroup = CreateGroup()
            set thistype.cf = Condition(function thistype.Effects)
            set thistype.radianOfCircle = (2 * bj_PI) / NUMBER_OF_BEAMS
            set thistype.dummyOwner = Player(15)
            set thistype.spellTicks = R2I(AOE / WAVE_SPEED)
            set thistype.dummy = CreateUnit(thistype.dummyOwner,DUMMY_ID,0.,0.,0.)
            call UnitAddAbility(thistype.dummy,DUMMY_SLOW_ID)
            
            set thistype.loopz = NUMBER_OF_BEAMS
            loop
            exitwhen thistype.loopz == 0
                set thistype.radianOfBeams[thistype.loopz] = thistype.radianOfCircle * thistype.loopz
                set thistype.angleOfBeams[thistype.loopz] = thistype.radianOfBeams[thistype.loopz] * 57.2958
                set thistype.cosine[thistype.loopz] = Cos(thistype.radianOfBeams[thistype.loopz])
                set thistype.sine[thistype.loopz] = Sin(thistype.radianOfBeams[thistype.loopz])
                set thistype.loopz = thistype.loopz - 1
            endloop

This is used to preload.

>That basically just ruins this for those who want a different amount of 'beams' per level, amongst other things.
Hmm, the number of beams is a constant.

Your naming convention is still weird. At least be consistent. You have unit cs for the caster, while you have group damaged for the unit group. Either spell them all out and shorten them all of something.
:p

And some constant functions would be nice for configurability
I listed them already. o_O
 

Kenny

Back for now.
Reaction score
202
>This is used to preload.

You shouldn't need to.

>Hmm, the number of beams is a constant.

The maximum number of projectiles should be a constant, the number per level shouldn't be.

>I listed them already. o_O

Notice the word functions. You have configurable globals.

I think something like this is a lot easier to understand, and far more configurable:

JASS:
scope ArticBlast

    globals
        private constant integer    ABIL_ID     = &#039;A000&#039; // Hero ability.
        private constant integer    PROJ_ID     = &#039;h000&#039; // The projectile for the nova.
        private constant integer    SLOW_ID     = &#039;A001&#039; // The dummy slow ability.
        private constant integer    MAX_PROJS   = 36     // Maximum number of projectiles allowed at any level.
        private constant string     ORDER_ID    = &quot;slow&quot; // Order string for the dummy ability.
        private constant string     SLOW_EFFECT = &quot;Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl&quot;
        private constant string     SLOW_ATTACH = &quot;origin&quot;
        private constant attacktype ATTACK_TYPE = ATTACK_TYPE_MAGIC
        private constant damagetype DAMAGE_TYPE = DAMAGE_TYPE_MAGIC
        private constant weapontype WEAPON_TYPE = WEAPON_TYPE_WHOKNOWS
        private constant boolean    PRELOAD     = true
    endglobals
    
    private constant function Damage takes integer level returns real
        return 100.00 * level // Damage dealt per level.
    endfunction
    
    private constant function Speed takes integer level returns real
        return 600.00 + (0.00 * level) // Speed the projectiles move in units per second.
    endfunction
    
    private constant function Radius takes integer level returns real
        return 600.00 + (0.00 * level) // The radius of the nova.
    endfunction
    
    private constant function Projectiles takes integer level returns integer
        return 20 + (4 * level) // How many projectiles there are per level. Cannot be over MAX_PROJS.
    endfunction
    
    private function FilterUnits takes unit filter, unit caster returns boolean
        return GetWidgetLife(filter) &gt; 0.405 and IsUnitEnemy(filter,GetOwningPlayer(caster)) and IsUnitType(filter,UNIT_TYPE_STRUCTURE) == false
    endfunction
    
    private struct Data
    
        unit    caster  = null
        player  owner   = null
        group   damaged = null
        real    castx   = 0.00
        real    casty   = 0.00
        real    damage  = 0.00
        real    speed   = 0.00
        real    total   = 0.00
        integer level   = 0
        integer projs   = 0
        integer ticks   = 0
         
        unit array proj[MAX_PROJS]
        real array pcos[MAX_PROJS]
        real array psin[MAX_PROJS]
        
        static thistype tempData  = 0
        static group    enumGroup = null
        static boolexpr enumBool  = null
        
        method onDestroy takes nothing returns nothing
            local integer i = 0
            
            loop
                exitwhen i == this.projs
                call KillUnit(this.proj<i>)
                set this.proj<i> = null
                set i = i + 1
            endloop
            
            call Group.release(this.damaged)
            
            set this.caster  = null
            set this.owner   = null
            set this.damaged = null
        endmethod
        
        static method filterUnits takes nothing returns boolean
            local thistype this = thistype.tempData
            local unit     filt = GetFilterUnit()
            
            if FilterUnits(filt,this.caster) == true and IsUnitInGroup(filt,this.damaged) == false then
                call UnitDamageTarget(this.caster,filt,this.damage,false,false,ATTACK_TYPE,DAMAGE_TYPE,WEAPON_TYPE)
                call DestroyEffect(AddSpecialEffectTarget(SLOW_EFFECT,filt,SLOW_ATTACH))
                call UnitAddAbility(DUMMY,SLOW_ID)
                call SetUnitAbilityLevel(DUMMY,SLOW_ID,this.level)
                call IssueTargetOrder(DUMMY,ORDER_ID,filt)
                call UnitRemoveAbility(DUMMY,SLOW_ID)
                call GroupAddUnit(this.damaged,filt)
            endif
            
            set filt = null
            
            return false
        endmethod
        
        method periodic takes nothing returns nothing
            local integer i = 0
            
            if T32_Tick == this.ticks then
                call this.stopPeriodic()
                call this.destroy()
            else
                set this.total = this.total + this.speed
                set this.castx = GetUnitX(this.caster)
                set this.casty = GetUnitY(this.caster)
                
                loop
                    exitwhen i == this.projs
                    call SetUnitX(this.proj<i>,this.castx + this.total * this.pcos<i>)
                    call SetUnitY(this.proj<i>,this.casty + this.total * this.psin<i>)
                    set i = i + 1
                endloop
                
                set thistype.tempData = this
                call GroupEnumUnitsInRange(thistype.enumGroup,this.castx,this.casty,this.total,thistype.enumBool)
            endif
        endmethod                
        
        implement T32x
    
        static method create takes nothing returns thistype
            local thistype this = thistype.allocate()
            local integer  i    = 0
            local real     r    = 0.00
            
            set this.caster  = GetTriggerUnit()
            set this.owner   = GetOwningPlayer(this.caster)
            set this.castx   = GetUnitX(this.caster)
            set this.casty   = GetUnitY(this.caster)
            set this.level   = GetUnitAbilityLevel(this.caster,ABIL_ID)
            set this.damage  = Damage(this.level)
            set this.speed   = Speed(this.level) * T32_PERIOD
            set this.projs   = Projectiles(this.level)
            set this.damaged = Group.get()
            
            if this.projs &gt; MAX_PROJS then
                set this.projs = MAX_PROJS
            endif
            
            set this.ticks   = T32_Tick + R2I(Radius(this.level) / this.speed)
            set r            = (2.00 * bj_PI) / this.projs
            
            loop
                exitwhen i == this.projs
                set this.proj<i> = CreateUnit(this.owner,PROJ_ID,this.castx,this.casty,(r * i) * bj_RADTODEG)
                set this.pcos<i> = Cos(r * i)
                set this.psin<i> = Sin(r * i)
                set i = i + 1
            endloop                
                
            call this.startPeriodic()
            
            return this
        endmethod
        
        static method conditions takes nothing returns boolean
            if GetSpellAbilityId() == ABIL_ID then
                call thistype.create()
            endif
            return false
        endmethod
        
        static method onInit takes nothing returns nothing
            local trigger trig = CreateTrigger()
            local unit    dumm = null
            
            set thistype.enumGroup = CreateGroup()
            set thistype.enumBool  = Filter(function thistype.filterUnits)
            
            call GT_AddStartsEffectAction(function thistype.conditions,ABIL_ID)
            
            if PRELOAD then
                set dumm = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),PROJ_ID,0.00,0.00,0.00)
                call DestroyEffect(AddSpecialEffect(SLOW_EFFECT,0.00,0.00))
                call UnitAddAbility(dumm,SLOW_ID)
                call RemoveUnit(dumm)
                
                set dumm = null
            endif
        endmethod
        
    endstruct
    
endscope
</i></i></i></i></i></i></i></i></i>


It requires:

- GTrigger
- T32
- DummyCaster
- Recycle
- BoundSentinel (optional)

All of which are solid, standard resources, which are efficient and make things a lot simple.

I suggest you implement something similar. That reminds me, you should add some type of border safety to the spell as well.

(The above is untested, but it should work as far as I can see)
 

INCINERATE

New Member
Reaction score
12
hey , so is this spell usable for my map consisting of 12 players? i wanna use this, + rep/cred to maker, just wanna know if its safe to do so :p ?
 

Laiev

Hey Listen!!
Reaction score
188
You want know if spell is mui?

not 100% sure but 99% of me think is.....

try yourself... create 2 units :) and cast it..
 

kingkingyyk3

Visitor (Welcome to the Jungle, Baby!)
Reaction score
216
Oh, download my demo map. There are 5 invokers casting it simultaneously.

Update : v2.2.
 

INCINERATE

New Member
Reaction score
12
thanks kingking .. i tested new map

i like this spell, its pretty sweet, but most of all, i love how it hardly gives any performance decrease considering its effect :)

thanks dude :thup:
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top