Spell Ice Wall

Ghan

Administrator - Servers are fun
Staff member
Reaction score
889
JASS - Yes - vJASS Required
MUI - Yes
Works - Yes
Leaks - I find your lack of leaklessness disturbing.

Ice Wall

This spell summons a wall of ice behind the caster, blocking advancing enemy units.

IceWallScreenshot.jpg


Code:

JASS:
//**************************ICE WALL by GHAN_04***********************
//******************************DESCRIPTION*****************************
//**Creates a wall of ice behind the caster that blocks enemy advance.**
//**********************************************************************
//**********************************************************************


scope IceWall initializer Init
    
    globals
        private trigger t = CreateTrigger()
        private integer ICE_WALL_CODE = 'A000'               //The raw code of the Ice Wall ability.
        private integer ICE_WALL_SECTION_CODE = 'h000'       //The raw code of the Ice Wall unit.
        private integer ICE_WALL_DURATION = 15               //The duration of the ice wall.
        private integer ICE_WALL_DURATION_FACTOR = 5         //The amount that the duration increases each level.
        private real ICE_WALL_DISTANCE = 500                 //The initial distance back from the caster that the wall appears.
        private real ICE_WALL_DISTANCE_FACTOR = 25           //The amount that the distance decreases with each level.
        private real ICE_WALL_WIDTH = 600                    //The distance sideways that the wall will expand.
        private real ICE_WALL_WIDTH_FACTOR = 25              //The amount that the width increases with each level.
        private real ICE_WALL_SIZE = 80                      //This is the distance between each wall section. CHANGE WITH CAUTION
        private real PLAYABLE_MAX_X
        private real PLAYABLE_MIN_X
        private real PLAYABLE_MAX_Y
        private real PLAYABLE_MIN_Y
    endglobals

    private function Conditions takes nothing returns boolean
        return GetSpellAbilityId() == ICE_WALL_CODE
    endfunction
    
    private function checkPoint takes real X1, real Y1, real X2, real Y2 returns boolean
        local real height1 = GetLocationZ(Location(X1, Y1))
        local real height2 = GetLocationZ(Location(X2, Y2))
        local real offset = height1 - height2
        if (offset < 0) then
            set offset = -offset
        endif
        return (PLAYABLE_MIN_X <= X2) and (X2 <= PLAYABLE_MAX_X) and (PLAYABLE_MIN_Y <= Y2) and (Y2 <= PLAYABLE_MAX_Y) and offset < 10
    endfunction
    
    private function Actions takes nothing returns nothing
        local unit caster = GetTriggerUnit()
        local real abilitylevel = GetUnitAbilityLevel(caster, ICE_WALL_CODE)
        local real X = GetUnitX(caster)
        local real Y = GetUnitY(caster)
        local real facing = GetUnitFacing(caster)
        local real left = facing - 90
        local real right = facing + 90
        local real wallstartX = X + (ICE_WALL_DISTANCE - ICE_WALL_DISTANCE_FACTOR * GetUnitAbilityLevel(caster, ICE_WALL_CODE)) * Cos((facing + 180) * bj_DEGTORAD)
        local real wallstartY = Y + (ICE_WALL_DISTANCE - ICE_WALL_DISTANCE_FACTOR * abilitylevel) * Sin((facing + 180) * bj_DEGTORAD)
        local unit start = CreateUnit(Player(15), ICE_WALL_SECTION_CODE, wallstartX, wallstartY, 0.00)
        local real count = 0
        local real currentwallX
        local real currentwallY
        local real oldX = wallstartX
        local real oldY = wallstartY
        call UnitApplyTimedLife(start, 'BTLF', ICE_WALL_DURATION + ICE_WALL_DURATION_FACTOR * abilitylevel)
        loop
            exitwhen count >= (ICE_WALL_WIDTH + ICE_WALL_WIDTH_FACTOR * abilitylevel)/2
            set count = count + ICE_WALL_SIZE
            if(not checkPoint(oldX, oldY, wallstartX + count * Cos((left) * bj_DEGTORAD), wallstartY + count * Sin((left) * bj_DEGTORAD))) then
                exitwhen true
            endif
            set currentwallX = wallstartX + count * Cos(left * bj_DEGTORAD)
            set currentwallY = wallstartY + count * Sin(left * bj_DEGTORAD)
            set oldX = currentwallX
            set oldY = currentwallY
            call UnitApplyTimedLife(CreateUnit(Player(15), ICE_WALL_SECTION_CODE, currentwallX, currentwallY, 0.00), 'BTLF', ICE_WALL_DURATION + ICE_WALL_DURATION_FACTOR * abilitylevel)
        endloop
        set count = 0
        loop
            exitwhen count >= (ICE_WALL_WIDTH + ICE_WALL_WIDTH_FACTOR * abilitylevel)/2
            set count = count + ICE_WALL_SIZE
            if(not checkPoint(oldX, oldY, wallstartX + count * Cos(right * bj_DEGTORAD), wallstartY + count * Sin((right) * bj_DEGTORAD))) then
                exitwhen true
            endif
            set currentwallX = wallstartX + count * Cos(right * bj_DEGTORAD)
            set currentwallY = wallstartY + count * Sin(right * bj_DEGTORAD)
            set oldX = currentwallX
            set oldY = currentwallY
            call UnitApplyTimedLife(CreateUnit(Player(15), ICE_WALL_SECTION_CODE, currentwallX, currentwallY, 0.00), 'BTLF', ICE_WALL_DURATION + ICE_WALL_DURATION_FACTOR * abilitylevel)
        endloop
        set caster = null
        set start = null
    endfunction
    
    private function Init takes nothing returns nothing
        local integer index = 0
        set PLAYABLE_MAX_X = GetRectMaxX(bj_mapInitialPlayableArea)
        set PLAYABLE_MIN_X = GetRectMinX(bj_mapInitialPlayableArea)
        set PLAYABLE_MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea)
        set PLAYABLE_MIN_Y = GetRectMinY(bj_mapInitialPlayableArea)
        loop
            call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)

            set index = index + 1
            exitwhen index == bj_MAX_PLAYER_SLOTS
        endloop
        call TriggerAddCondition(t, Condition(function Conditions))
        call TriggerAddAction(t, function Actions)
    endfunction
endscope


I created this spell on a request, so now I'm submitting it for review.
Enjoy!
 

Attachments

  • Ice Wall.w3x
    20.2 KB · Views: 265

Romek

Super Moderator
Reaction score
964
Why does this require UMSWE?

> set offset = -1 * offset
set offset = -offset

The map Max/Min[X/Y] could be stored into globals

There's no point in inlining TriggerRegisterAnyUnitEventBJ, especially if you're not going to change it in any way.

I'll look through it in more detail later. The spell seems useful though. I had someone asking me about a spell like this just a few minutes ago. So I'm sure a lot of people will be happy to see this. :)
 

Ghan

Administrator - Servers are fun
Staff member
Reaction score
889
Thanks for the suggestions. I updated those things.
 

Kenny

Back for now.
Reaction score
202
JASS:
private real ICE_WALL_WIDTH_FACTOR = 25              //The amount that the width decreases with each level.


Why does the wall width decrease per level, or am I not understanding correctly.

JASS:
private real PLAYABLE_MAX_X = GetRectMaxX(bj_mapInitialPlayableArea)
private real PLAYABLE_MIN_X = GetRectMinX(bj_mapInitialPlayableArea)
private real PLAYABLE_MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea)
private real PLAYABLE_MIN_Y = GetRectMinY(bj_mapInitialPlayableArea)


I'm not sure if GetRectMaxX and all that can be initialized in the globals block. At least last time I checked it didn't work. You should initialize them in the Init function.

It is also more accurate to +/- 64 to the max and min values, so:

JASS:
// Done in the Init function.
set PLAYABLE_MAX_X = GetRectMaxX(bj_mapInitialPlayableArea) - 64.00
set PLAYABLE_MIN_X = GetRectMinX(bj_mapInitialPlayableArea) + 64.00
set PLAYABLE_MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea) - 64.00
set PLAYABLE_MIN_Y = GetRectMinY(bj_mapInitialPlayableArea) + 64.00


You should probably add GetTriggerUnit() to a local variable, as you are using it like 10 times in the function, so that can be cleaned up. You will need to null it too.

You also don't null start (the unit variable).

You could also probably set GetUnitAbilityLevel(GetTriggerUnit(),ICE_WALL_CODE) to a variable, as you use it a fair bit.

And although it doesn't matter, you dont need the parenthesis around (left) and (right).

You could also make this use GTrigger by Jesus4Lyf. It would shorten the script quite a bit.

And maybe add some function for distance, width and duration to make it a bit easier to read and understand.

JASS:
private function Duration takes integer level returns real
    return 15.00 + (5.00 * level) // something like that.
endfunction


This is a pretty mad spell, and it will definately come in handy for a lot of people. Well done.
 

Ghan

Administrator - Servers are fun
Staff member
Reaction score
889
> Why does the wall width decrease per level, or am I not understanding correctly.

That should be increases. Fixed.

> You should initialize them in the Init function.

Done.

> It is also more accurate to +/- 64 to the max and min values

Why? Are there known errors that can occur to make stuff happen outside the playable map area with that restriction?

> GetTriggerUnit() to a local variable

Done.

> You also don't null start (the unit variable).

Thanks for that catch. Fixed.

> You could also probably set GetUnitAbilityLevel(GetTriggerUnit(),ICE_WALL_CODE) to a variable

Done.

> you dont need the parenthesis around (left) and (right).

In development, I had some extra stuff there; I just didn't take them out. Thanks.

> You could also make this use GTrigger by Jesus4Lyf. It would shorten the script quite a bit.

I'm not really even sure what that system does - it seems like an incredible amount of code to add here. o_O

> And maybe add some function for distance, width and duration to make it a bit easier to read and understand.

Considering that most of the customizable stuff is done in the globals, wouldn't that just add unneeded function calls?
 

Kenny

Back for now.
Reaction score
202
> Why? Are there known errors that can occur to make stuff happen outside the playable map area with that restriction?

I've just heard that it can be inaccurate, and that adding the +/- 64.00 ensures that no errors may occur, so I've just used it since then.

> I'm not really even sure what that system does - it seems like an incredible amount of code to add here. o_O

It makes it much easier to register events for single event spells, and all spells in general. It turns:

JASS:
private function Conditions takes nothing returns boolean
    return GetSpellAbilityId() == ICE_WALL_CODE
endfunction

private function Init takes nothing returns nothing
    local integer index
    set PLAYABLE_MAX_X = GetRectMaxX(bj_mapInitialPlayableArea)
    set PLAYABLE_MIN_X = GetRectMinX(bj_mapInitialPlayableArea)
    set PLAYABLE_MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea)
    set PLAYABLE_MIN_Y = GetRectMinY(bj_mapInitialPlayableArea)
    set index = 0
    loop
        call TriggerRegisterPlayerUnitEvent(t, Player(index), EVENT_PLAYER_UNIT_SPELL_EFFECT, null)

        set index = index + 1
        exitwhen index == bj_MAX_PLAYER_SLOTS
    endloop
    call TriggerAddCondition(t, Condition(function Conditions))
    call TriggerAddAction(t, function Actions)
endfunction


Into:

JASS:
private function Init takes nothing returns nothing
    set PLAYABLE_MAX_X = GetRectMaxX(bj_mapInitialPlayableArea)
    set PLAYABLE_MIN_X = GetRectMinX(bj_mapInitialPlayableArea)
    set PLAYABLE_MAX_Y = GetRectMaxY(bj_mapInitialPlayableArea)
    set PLAYABLE_MIN_Y = GetRectMinY(bj_mapInitialPlayableArea)

    call GT_AddStartsEffectEvent(function Actions,ICE_WALL_CODE)
endfunction

//  However, your actions function will need to return boolean,
//  so just add return false to the end, and make sure it returns boolean.


However it is not needed, I just think the system makes things much easier to read, and makes coding easier as well.

> Considering that most of the customizable stuff is done in the globals, wouldn't that just add unneeded function calls?

There is no reason at all to change it. I guess its just personal preference, I'd rather look at the function and be able to do whatever i want with it rather than changing the two globals and stuff getting done for me.

Keep it as is if you want, its perfectly fine.

Also if you arent going to use GTrigger, you should just initialize index (in the Init function) in the local block up the top. Theres no reason to initialize it afterwards. Oh and if you use GTrigger you can get rid of the private trigger t in the globals block.

And again, this isn't needed, but you should make the globals that are actually constant have the constant keyword prefix. Its currently a little deceiving :p.

EDIT:

You should make the local variable for the ability level an integer instead of a real.
 

Romek

Super Moderator
Reaction score
964
> Oh and if you use GTrigger you can get rid of the private trigger t in the globals block.
You can get rid of it anyway, without GTrigger.
Just make it a local. :)

GTrigger only shortens code by about 2 lines anyway. It seems more here because Ghan inlined TriggerRegisterAnyUnitEventBJ.
 

Ghan

Administrator - Servers are fun
Staff member
Reaction score
889
Updated.
I don't really want to introduce a bunch more code here where it really isn't needed. :/ I have a feeling it would confuse me and the user downloading the spell.
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top