Spell Sacred Circle

Sim

Forum Administrator
Staff member
Reaction score
534
I've been working on this spell for a while and I decided it would make out something great.

So, here it is!

What is it? Here's its description:

"Creates an expanding circle of holy energy, damaging every enemy unit caught."

Simply put, here's a screeny:

spells_230_screenshot.jpg


The spell

- It is MUI
- It is in vJASS
- Leakless
- Very low lag

Steps for implementation are listed, although there are several of them :)

Here's the code!

JASS:
//¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
//¤
//¤ ***************** 
//¤ - Sacred Circle - 
//¤ *****************
//¤ 
//¤ By: Daxtreme
//¤ 
//¤ --> How to implement in your map:
//¤     
//¤     1. Copy the game cache variable named "GameCache" in your map.                         
//¤     2. Copy the spell "Sacred Circle" in your map.
//¤     3. Copy everything found in the "Custom script code" section. To do this, click
//¤        on the name of the map in the top-left corner in the trigger editor.
//¤     4. Make a variable called "GameCache".
//¤     5. Copy this trigger into your map.
//¤     6. Import the HolyStrike.mdx model in your map.
//¤
//¤ --> How to customize it:
//¤
//¤     You can configure the spell using the constant functions just below. Change their values.
//¤
//¤ CREDITS:
//¤
//¤     - JetFangInferno's Holy Strike.
//¤     - kenny! for testing, bug-finding, and updating!
//¤
//¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

scope SacredCircle2

    globals
        private constant integer    ABIL_ID    = 'A000'       // Sacred Circle's ability Id
        private constant integer    ORDER_ID   = 852183
        private constant real       INTERVAL   = 0.04         // Period
        private constant string     EFFECT     = "war3mapImported\\HolyStrike.mdx"      // Spell model art
        private constant attacktype A_TYPE     = ATTACK_TYPE_CHAOS
        private constant damagetype D_TYPE     = DAMAGE_TYPE_UNIVERSAL
        private constant weapontype W_TYPE     = WEAPON_TYPE_WHOKNOWS
        private constant boolean    STOP_FIRST = false
    endglobals
    
    private function Damage_dealt takes integer lvl returns real
        return 100.00 * lvl
    endfunction
    
    private function Damage_radius takes integer lvl returns real
        return 175.00 + (0.00 * lvl)
    endfunction
    
    private function Filter_enemies takes unit filter, unit caster returns boolean
        return GetWidgetLife(filter) > 0.406 and IsUnitEnemy(filter,GetOwningPlayer(caster)) == true and IsUnitType(filter,UNIT_TYPE_MAGIC_IMMUNE) == false
    endfunction
    
    private struct Data
        
        unit    cast = null
        real    time = 0.00
        real    dist = 0.00
        real    ang  = 0.00
        integer lvl  = 0
        boolean stop = false
        
        static Data     array D
        static integer  D_total = 0
        static timer    Timer   = null
        static group    Group   = null
        static boolexpr Filt    = null
        
        static method filt takes nothing returns boolean
            return true
        endmethod
        
        method onDestroy takes nothing returns nothing
            set .cast = null
        endmethod
        
        method search takes nothing returns nothing
            local integer i = 1
            
            loop
                exitwhen i > Data.D_total
                if Data.D<i>.cast == .cast then
                    if STOP_FIRST then
                        set Data.D<i>.stop = true
                    else
                        set .stop = true
                    endif
                endif
                set i = i + 1
            endloop
        endmethod
        
        method periodic takes nothing returns boolean
            local real x = GetUnitX(.cast)
            local real y = GetUnitY(.cast)
            local unit u = null
            
            if GetUnitCurrentOrder(.cast) != ORDER_ID or .time &lt;= 0 then
                return true
            else
                set x = x + (50.00 + .dist * 10.00) * Cos(.ang * bj_DEGTORAD)
                set y = y + (50.00 + .dist * 10.00) * Sin(.ang * bj_DEGTORAD)
                
                call DestroyEffect(AddSpecialEffect(EFFECT,x,y))
                call GroupEnumUnitsInRange(Data.Group,x,y,Damage_radius(.lvl),Data.Filt)
                loop
                    set u = FirstOfGroup(Data.Group)
                    exitwhen u == null
                    call GroupRemoveUnit(Data.Group,u)
                    if Filter_enemies(u,.cast) then
                        call UnitDamageTarget(.cast,u,Damage_dealt(.lvl),false,false,A_TYPE,D_TYPE,W_TYPE)
                    endif
                endloop
                
                set .ang  = (.ang  + 24.00 - .dist / 6.00)
                set .dist = (.dist + 1.00)
                set .time = (.time - INTERVAL)
            endif
            
            set u = null
            
            return false
        endmethod            
        
        static method update takes nothing returns nothing
            local integer i = 1
            
            loop
                exitwhen i &gt; Data.D_total
                
                if Data.D<i>.stop or Data.D<i>.periodic() then
                    call Data.D<i>.destroy()
                    set Data.D<i> = Data.D[Data.D_total]
                    set Data.D_total = Data.D_total - 1
                    set i = i - 1
                endif
                
                set i = i + 1
            endloop
            
            if Data.D_total &lt;= 0 then
                call PauseTimer(Data.Timer)
                set Data.D_total = 0
            endif
        endmethod
        
        static method actions takes nothing returns boolean
            local Data d = Data.create()
            
            set d.cast = GetTriggerUnit()
            set d.lvl  = GetUnitAbilityLevel(d.cast,ABIL_ID)
            set d.time = 100.00 * INTERVAL
            call d.search()
            
            set Data.D_total = Data.D_total + 1
            set Data.D[Data.D_total] = d
            if Data.D_total == 1 then
                call TimerStart(Data.Timer,INTERVAL,true,function Data.update)
            endif
            
            return false
        endmethod
        
        static method conditions takes nothing returns boolean
            return GetSpellAbilityId() == ABIL_ID
        endmethod
            
        static method onInit takes nothing returns nothing
            local trigger trig = CreateTrigger()
            local integer i    = 0
            
            set Data.Timer = CreateTimer()
            set Data.Group = CreateGroup()
            set Data.Filt  = Filter(function Data.filt)
            
            loop
                call TriggerRegisterPlayerUnitEvent(trig,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,Data.Filt)
                set i = i + 1
                exitwhen i == bj_MAX_PLAYER_SLOTS
            endloop
            
            call TriggerAddCondition(trig,Condition(function Data.conditions))
            call TriggerAddAction(trig,function Data.actions)
        endmethod
        
    endstruct

endscope
</i></i></i></i></i></i>


--------------------------------------

I made this at first for myself but then I realized the whole community could use it, because I feel it is good.

Tell me what you think!

*Credits to JetFangInferno for the Holy Strike model and KaTTaNa for the Local Handle Vars system!*

EDIT: First update.

EDIT: 2nd update.

EDIT: 3rd update.

EDIT: 4th update.

EDIT: 5th update.

EDIT: (After a while) Update! Credits to kenny! for the whole changes. :)
 

Attachments

  • Sacred Circle.w3x
    39.8 KB · Views: 580

waaaks!

Zinctified
Reaction score
256
wow, real great....

its made in jass
leakless

did you wrote to your trigger that how to import this spell?
its for people who do not know jass

well its great...+rep
 

SFilip

Gone but not forgotten
Reaction score
634
SC_RawCode, SC_StrikeDmg, SC_CheckMagicImmune and SC_CheckAlly can (and should) all be constants.
IsUnitType tends to cause an unusual bug if not compared to something...so only in this case you should use "return IsUnitType(targ, UNIT_TYPE_MAGIC_IMMUNE) == false" instead of "return not IsUnitType(targ, UNIT_TYPE_MAGIC_IMMUNE)".

Code:
    loop
        exitwhen GetTriggerEvalCount(trig)>0
        call TriggerSleepAction( 0.10 )
    endloop
Bad idea.
You can check the exec/eval count in the trigger itself (from Trig_Sacred_Circle_Actions_Loop) and disable/clean it there.

Oh and you might wanna use the native instead of AddSpecialEffectLocBJ, this seems to be the only BJ you used (except for PolarProjection).
 
I

IKilledKEnny

Guest
Looks great, those are imported models, right (or am I wrong? Screeny bit small)? Anyway if there are imported any chance you could attach them?
 

Sim

Forum Administrator
Staff member
Reaction score
534
You can export those models once you open the map.

> Bad idea.
> You can check the exec/eval count in the trigger itself (from Trig_Sacred_Circle_Actions_Loop) and disable/clean it there.

Will do.

> Oh and you might wanna use the native instead of AddSpecialEffectLocBJ, this seems to be the only BJ you used (except for PolarProjection).

Well, the effect thingy bugged when I used the native, don't know why -_- I will try again though.

The condition functions will be constants.

Thanks guys :)

EDIT:

>did you wrote to your trigger that how to import this spell?
>its for people who do not know jass

Look for yourself! :p
 

Dismembered

New Member
Reaction score
1
Wow Very very nice spell man

I might use it so i give u all credit for this spell ! Very nice again
 

Sim

Forum Administrator
Staff member
Reaction score
534
The spell has been updated according to SFilip's comments.
 

emjlr3

Change can be a good thing
Reaction score
395
have not looked myself, however if you fixed what he said I will move this over, gj
 

SFilip

Gone but not forgotten
Reaction score
634
Something I forgot last time...
Code:
function LocalVars takes nothing returns gamecache  
    return InitGameCache("jasslocalvars.w3v") 
endfunction   

function GameCache takes nothing returns gamecache
    return udg_GameCache
endfunction
This isn't right, should be something like this
Code:
function LocalVars takes nothing returns gamecache  
    if udg_GameCache == null then
        set udg_GameCache = InitGameCache("jasslocalvars.w3v")
    endif
    return udg_GameCache
endfunction
 

Tom Jones

N/A
Reaction score
437
It does look really great ingame, and it certainly deals some serious damage :)

For future consideration, there are somethings that seems unnecessary. At first I simply couldn't figure out what in the world you were using the local trigger for, when I suddenly realized it was a channeling ability. You could have added the END_CAST event to the main trigger, and then had a if statement in your actions trigger like this:
Code:
if GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_EFFECT then
*Turn on timer, store handle locals*
elseif GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_ENDCAST then
*turn of timer, flush handle locals, destroy the timer*
endif
The condition will work for both events. Another thing that seemed abit strange, was that your using a region. You could acheive the same result with xypoints.
 

Sim

Forum Administrator
Staff member
Reaction score
534
It does look really great ingame, and it certainly deals some serious damage :)

For future consideration, there are somethings that seems unnecessary. At first I simply couldn't figure out what in the world you were using the local trigger for, when I suddenly realized it was a channeling ability. You could have added the END_CAST event to the main trigger, and then had a if statement in your actions trigger like this:
Code:
if GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_EFFECT then
*Turn on timer, store handle locals*
elseif GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_ENDCAST then
*turn of timer, flush handle locals, destroy the timer*
endif
The condition will work for both events. Another thing that seemed abit strange, was that your using a region. You could acheive the same result with xypoints.

Well, I had other ideas in mind for this spell, and it needed Handle vars. Once I decided to change it, the handle vars still worked good and everything was already settled so I kept them. I noticed they were only half useful ;)

But I'm lazy.

Also, regions are easy to handle :p

Something I forgot last time...
Code:
function LocalVars takes nothing returns gamecache  
    return InitGameCache("jasslocalvars.w3v") 
endfunction   

function GameCache takes nothing returns gamecache
    return udg_GameCache
endfunction
This isn't right, should be something like this
Code:
function LocalVars takes nothing returns gamecache  
    if udg_GameCache == null then
        set udg_GameCache = InitGameCache("jasslocalvars.w3v")
    endif
    return udg_GameCache
endfunction

Are you sure? In both my maps I use the 2 above functions instead of what you said and... it always worked. Maybe I got a false version of the Handle Vars? :eek:
 

SFilip

Gone but not forgotten
Reaction score
634
> it always worked
The original works as well without any changes...
Though it causes a memory leak and is much slower as the game cache gets reloaded every time you use it.
 

Tom Jones

N/A
Reaction score
437
The original should be:
Code:
function LocalVars takes nothing returns gameache
    return udg_*VariableName*
endfunction
Or SFilips method, which is safer, since it'll automatically create the gamecache if it isn't created by the user.

>Also, regions are easy to handle

Then create a local region and move it around with handle locals. Implementation of a jass spell using a handle vars system should only include copying of triggers, abilities, custom script, and the game cache variable in my opinion
 

emjlr3

Change can be a good thing
Reaction score
395
alternatively, you could create your gc variable at map init, and always just return it, therefore saving some lines of code every time you get it, or not use a function call in the first place, and wherever you need it just use the gc variable, like I do, which would save even more time
 

Sim

Forum Administrator
Staff member
Reaction score
534
I'll use local region good idea *thumbs up*

EDIT: *rect

This isn't right, should be something like this
Code:
function LocalVars takes nothing returns gamecache  
    if udg_GameCache == null then
        set udg_GameCache = InitGameCache("jasslocalvars.w3v")
    endif
    return udg_GameCache
endfunction

Is it the exact code? :p

Anyways, I'll test it as it is.

EDIT: I'd need to change all the handle vars functions because they call the function "GameCache" >_<

I don't really know if my changes would work... Anyone here knows exactly how those functions work and can mess around with them?

Or do I just need to change every "GameCache" call to a "LocalVars" call?

EDIT again (omg): It worked by changing every "GameCache" call to a "LocalVars" call.

pretty cool man...the divine revenant also looks so nice

It isn't made by me though! :p
 

Tom Jones

N/A
Reaction score
437
You could add the code from the LocalVars function to your GameCache function. You could also copy paste the LocalVars function, change the function name to GameCache, and then delete the old GameCache function.

Changing all instances of GameCache is a bit complex way to do it :)
 
General chit-chat
Help Users
  • No one is chatting at the moment.
  • The Helper The Helper:
    What is up Old Mountain Shadow?
  • The Helper The Helper:
    Happy Thursday!
    +1
  • Varine Varine:
    Crazy how much 3d printing has come in the last few years. Sad that it's not as easily modifiable though
  • Varine Varine:
    I bought an Ender 3 during the pandemic and tinkered with it all the time. Just bought a Sovol, not as easy. I'm trying to make it use a different nozzle because I have a fuck ton of Volcanos, and they use what is basically a modified volcano that is just a smidge longer, and almost every part on this thing needs to be redone to make it work
  • Varine Varine:
    Luckily I have a 3d printer for that, I guess. But it's ridiculous. The regular volcanos are 21mm, these Sovol versions are about 23.5mm
  • Varine Varine:
    So, 2.5mm longer. But the thing that measures the bed is about 1.5mm above the nozzle, so if I swap it with a volcano then I'm 1mm behind it. So cool, new bracket to swap that, but THEN the fan shroud to direct air at the part is ALSO going to be .5mm to low, and so I need to redo that, but by doing that it is a little bit off where it should be blowing and it's throwing it at the heating block instead of the part, and fuck man
  • Varine Varine:
    I didn't realize they designed this entire thing to NOT be modded. I would have just got a fucking Bambu if I knew that, the whole point was I could fuck with this. And no one else makes shit for Sovol so I have to go through them, and they have... interesting pricing models. So I have a new extruder altogether that I'm taking apart and going to just design a whole new one to use my nozzles. Dumb design.
  • Varine Varine:
    Can't just buy a new heatblock, you need to get a whole hotend - so block, heater cartridge, thermistor, heatbreak, and nozzle. And they put this fucking paste in there so I can't take the thermistor or cartridge out with any ease, that's 30 dollars. Or you can get the whole extrudor with the direct driver AND that heatblock for like 50, but you still can't get any of it to come apart
  • Varine Varine:
    Partsbuilt has individual parts I found but they're expensive. I think I can get bits swapped around and make this work with generic shit though
  • Ghan Ghan:
    Heard Houston got hit pretty bad by storms last night. Hope all is well with TH.
  • The Helper The Helper:
    Power back on finally - all is good here no damage
    +2
  • V-SNES V-SNES:
    Happy Friday!
    +1
  • The Helper The Helper:
    New recipe is another summer dessert Berry and Peach Cheesecake - https://www.thehelper.net/threads/recipe-berry-and-peach-cheesecake.194169/
  • The Helper The Helper:
    I think we need to add something to the bottom of the front page that shows the Headline News forum that has a link to go to the News Forum Index so people can see there is more news. Do you guys see what I am saying, lets say you read all the articles on the front page and you get to the end and it just ends, no kind of link for MOAR!
  • The Helper The Helper:
    Happy Wednesday!
    +1
  • V-SNES V-SNES:
    Happy Friday!
    +1
  • The Helper The Helper:
    Sticking with the desserts for now the latest recipe is Fried Apple Pies - https://www.thehelper.net/threads/recipe-fried-apple-pies.194297/
  • The Helper The Helper:
    Finally finding about some of the bots that are flooding the users online - bytespider apparently is a huge offender here - ignores robots.txt and comes in from a ton of different IPs
  • Monovertex Monovertex:
    @The Helper I'm really not seeing the "Signature" link in the sidebar on that page. Here's a screenshot:
  • The Helper The Helper:
    I have reported it - I was wondering why nobody I have given sigs to over the last few years have used them

      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