• 🏆 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!

[JASS] Globals error

Status
Not open for further replies.
Level 6
Joined
Jul 23, 2018
Messages
243
Hello there,
I thank you for taking a look at this thread and help me to solve problems. I am copying a dash spell template made by sniper_zero. When I first tested the map, it works fine. But when I copied to it my map and saved it, I got errors with globals from map header. I already got rid of pathability library in my map. I also used patch 1.29
Here are the triggers in the map which is quite different from when I previewed the triggers

JASS:
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library TerrainPathability initializer Init
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This script can be used to detect the type of pathing at a specific point.
//* It is valuable to do it this way because the IsTerrainPathable is very
//* counterintuitive and returns in odd ways and aren't always as you would
//* expect. This library, however, facilitates detecting those things reliably
//* and easily.
//*
//******************************************************************************
//*
//*    > function IsTerrainDeepWater    takes real x, real y returns boolean
//*    > function IsTerrainShallowWater takes real x, real y returns boolean
//*    > function IsTerrainLand         takes real x, real y returns boolean
//*    > function IsTerrainPlatform     takes real x, real y returns boolean
//*    > function IsTerrainWalkable     takes real x, real y returns boolean
//*
//* These functions return true if the given point is of the type specified
//* in the function's name and false if it is not. For the IsTerrainWalkable
//* function, the MAX_RANGE constant below is the maximum deviation range from
//* the supplied coordinates that will still return true.
//*
//* The IsTerrainPlatform works for any preplaced walkable destructable. It will
//* return true over bridges, destructable ramps, elevators, and invisible
//* platforms. Walkable destructables created at runtime do not create the same
//* pathing hole as preplaced ones do, so this will return false for them. All
//* other functions except IsTerrainWalkable return false for platforms, because
//* the platform itself erases their pathing when the map is saved.
//*
//* After calling IsTerrainWalkable(x, y), the following two global variables
//* gain meaning. They return the X and Y coordinates of the nearest walkable
//* point to the specified coordinates. These will only deviate from the
//* IsTerrainWalkable function arguments if the function returned false.
//*
//* Variables that can be used from the library:
//*     [real]    TerrainPathability_X
//*     [real]    TerrainPathability_Y
//*
globals
    private constant real    MAX_RANGE     = 10.
    private constant integer DUMMY_ITEM_ID = 'wolg'
endglobals

globals 
    private item       Item   = null
    private rect       Find   = null
    private item array Hid
    private integer    HidMax = 0
    public  real       X      = 0.
    public  real       Y      = 0.
endglobals

function IsTerrainDeepWater takes real x, real y returns boolean
    return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction
function IsTerrainShallowWater takes real x, real y returns boolean
    return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction
function IsTerrainLand takes real x, real y returns boolean
    return IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY)
endfunction
function IsTerrainPlatform takes real x, real y returns boolean
    return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY)
endfunction

private function HideItem takes nothing returns nothing
    if IsItemVisible(GetEnumItem()) then
        set Hid[HidMax] = GetEnumItem()
        call SetItemVisible(Hid[HidMax], false)
        set HidMax = HidMax + 1
    endif
endfunction
function IsTerrainWalkable takes real x, real y returns boolean
    //Hide any items in the area to avoid conflicts with our item
    call MoveRectTo(Find, x, y)
    call EnumItemsInRect(Find ,null, function HideItem)
    //Try to move the test item and get its coords
    call SetItemPosition(Item, x, y) //Unhides the item
    set X = GetItemX(Item)
    set Y = GetItemY(Item)
    static if LIBRARY_IsTerrainWalkable then
        //This is for compatibility with the IsTerrainWalkable library
        set IsTerrainWalkable_X = X
        set IsTerrainWalkable_Y = Y
    endif
    call SetItemVisible(Item, false)//Hide it again
    //Unhide any items hidden at the start
    loop
        exitwhen HidMax <= 0
        set HidMax = HidMax - 1
        call SetItemVisible(Hid[HidMax], true)
        set Hid[HidMax] = null
    endloop
    //Return walkability
    return (X-x)*(X-x)+(Y-y)*(Y-y) <= MAX_RANGE*MAX_RANGE and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY)
endfunction

private function Init takes nothing returns nothing
    set Find = Rect(0., 0., 128., 128.)
    set Item = CreateItem(DUMMY_ITEM_ID, 0, 0)
    call SetItemVisible(Item, false)
endfunction
endlibrary
JASS:
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//This part is where you can configure the spell.
globals
    //Configurables
    integer Rush = 'A000' //This is the ability id the spell uses. Change it after copying the trigger.
    real Speed = 1150 //This is the speed of the caster when he uses the spell.
    real Interval = .03 //How often you want the timer to run.
    real Range = 175 //How close units should be to be damaged by the spell.
    boolean UnitOrSfx = false //This decides if you want to use a dummy unit or sfx as the well...sfx of the spell. False for sfx, true for dummy unit.
    integer Transparency = 80 //How transparent you want the dummy to be.
    integer RushDummy = 'e001' // This is the id of the dummy unit created.
    real Lifespan = 0.5 // Life span of the dummy.
    string Sfx = "Abilities\\Spells\\Orc\\MirrorImage\\MirrorImageCaster.mdl" //The sfx that appears when the caster dashes.
    string Animation = "stand ready" //What animation plays when the caster dashes.
    real DamageBase = 75 //This is the base damage which will be multiplied by the ability level.
    integer R = 255 //This is the red value for the dummy unit.
    integer G = 255 //This is the blue value for the dummy unit.
    integer B = 255 //This is the green value for the dummy unit.
    real AbilDist = 200 //This is the distance that scales per level of ability. Set BonusDist to 0 if you want a pure level based distance.
    real BonusDist = 200 // This is the bonus distance. Set AbilDist to 0 if you want constant distant.
    attacktype AttackType = ATTACK_TYPE_CHAOS //The attack type.
    damagetype DamageType = DAMAGE_TYPE_UNIVERSAL //The damage type. They're both currently set to these configurations to allow easy testing.
 
    //Non-configurables
    group RushGroup = CreateGroup() //Don't touch this. Don't null or destroy this.
    real Offset = Speed * Interval //How far the caster moves per interval.
endglobals

//------Configurable functions------//

//Configure the conditions for group check here
function UnitCheck takes unit caster, unit u returns boolean
    return IsUnitEnemy(u, GetOwningPlayer(caster)) and not (IsUnitType(u, UNIT_TYPE_DEAD) and GetUnitTypeId(u) != 0) and IsUnitType(u, UNIT_TYPE_GROUND) and not IsUnitType(u, UNIT_TYPE_STRUCTURE)
endfunction

//The Damage formula for the ability.
function Damage takes unit caster, integer Rush, real BaseDamage returns real
    return GetUnitAbilityLevel(caster, Rush) * BaseDamage
endfunction

//Formula for the maximum distance. If you only want the ability to affect distance, set BonusDist to 0.
function MaximumDistance takes unit caster, integer Rush, real AbilDist, real BonusDist returns real
    return GetUnitAbilityLevel(caster, Rush) * AbilDist + BonusDist
endfunction
//---End of Configurable functions---//


function Rush_Periodic takes nothing returns nothing
    //Local Variable Setup
    local timer t = GetExpiredTimer()
    local integer id = GetHandleId(t)
    local unit caster = LoadUnitHandle(udg_Rush_Hash, id, 0)
    local real facing = LoadReal(udg_Rush_Hash, id, 1)
    local real cur_dist = LoadReal(udg_Rush_Hash, id, 2)
    local group g = LoadGroupHandle(udg_Rush_Hash, id, 3)
    local real x = GetUnitX(caster)
    local real y = GetUnitY(caster)
    local real x1 = x + Offset * Cos(facing)
    local real y1 = y + Offset * Sin(facing)
    local player owner = GetOwningPlayer(caster)
    local unit dummy
    local unit u
    local real damage = Damage(caster, Rush, DamageBase) //You can change this to whatever you want.
    local real MaxDistance = MaximumDistance(caster, Rush, AbilDist, BonusDist) //This makes the distance you dash scale with the level.
 
 
    if cur_dist < MaxDistance then
        call SetUnitAnimation(caster, Animation)
        if not UnitOrSfx then
            call DestroyEffect(AddSpecialEffect(Sfx, x, y))
        else
            set dummy = CreateUnit(owner, RushDummy, x, y, facing)
            call SetUnitAnimation(dummy, Animation)
            call SetUnitVertexColor(dummy, R, G, B, Transparency)
            call UnitApplyTimedLife(dummy, 'BTLF', Lifespan)
            set dummy = null
        endif
        call GroupEnumUnitsInRange(RushGroup, x, y, Range, null)
        loop //What we do here is check if the target is in g. If not, then we damage it and add it to g to prevent it from being damaged again.
            set u = FirstOfGroup(RushGroup)
            exitwhen u == null
            if not IsUnitInGroup(u, g) and UnitCheck(caster, u) then
                call UnitDamageTarget(caster, u, damage, false, false, AttackType, DamageType, null)
                call GroupAddUnit(g, u)
            endif
            call GroupRemoveUnit(RushGroup, u)
        endloop
        if IsTerrainWalkable(x1, y1) then //If the terrain is passable the you'll dash, if not then trigger ends.
            call SetUnitX(caster, x1)
            call SetUnitY(caster, y1)
            set cur_dist = cur_dist + Offset //This counts how many times you've moved.
            call SaveReal(udg_Rush_Hash, id, 2, cur_dist)
        else
            call PauseTimer(t)
            call DestroyTimer(t)
            call DestroyGroup(g)
            call SetUnitAnimation(caster, "stand") //Resets the animation.
            call FlushChildHashtable(udg_Rush_Hash, id)
        endif
    else
        call PauseTimer(t)
        call DestroyTimer(t)
        call DestroyGroup(g)
        call SetUnitAnimation(caster, "stand") //Resets the animation.
        call FlushChildHashtable(udg_Rush_Hash, id)
    endif
 
    //Nulling
    set t = null
    set caster = null
    set g = null
endfunction

function Rush_Actions takes nothing returns nothing
    //Local Variable Setup
    local timer t = CreateTimer()
    local integer id = GetHandleId(t)
    local unit caster = GetTriggerUnit()
    local real dx = GetSpellTargetX() - GetUnitX(caster)
    local real dy = GetSpellTargetY() - GetUnitY(caster)
    local real dist_check = (dx*dx) + (dy*dy)
    local real facing
 
    //A little distance check to avoid bugs when you cast the spell in your current position.
    if dist_check <= 100 * 100 then
        set facing = GetUnitFacing(caster) * bj_DEGTORAD
    else
        set facing = (Atan2(dy, dx))
    endif
 
    //Hashtable Setup
    call SaveUnitHandle(udg_Rush_Hash, id, 0, caster)
    call SaveReal(udg_Rush_Hash, id, 1, facing)
    call SaveReal(udg_Rush_Hash, id, 2, 0)
    call SaveGroupHandle(udg_Rush_Hash, id, 3, CreateGroup())
    //End Hashtable Setup
 
    call TimerStart(t, Interval, true, function Rush_Periodic)
 
    //Nulling
    set t = null
    set caster = null
endfunction

function Rush_Conditions takes nothing returns boolean
    if GetSpellAbilityId() == Rush then
        call Rush_Actions()
    endif
    return false
endfunction

//===========================================================================
function InitTrig_Rush takes nothing returns nothing
    local trigger t = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( t, Condition( function Rush_Conditions) )
    set udg_Rush_Hash = InitHashtable()
    set t = null
endfunction
 
Level 22
Joined
Feb 26, 2008
Messages
891
Well, if I take your code and just add a global hashtable variable called Rush_Hash, it compiles fine, other than the issue with terrain library. You can probably either do that or add the variable in the globals section of the code and change the name.
 
Level 22
Joined
Feb 26, 2008
Messages
891
The variables editor works as well. Or you can right-click in the navigation tree and select the New Global Variable option.

Ghan-08-27-20_16:24:03.png


Ghan-08-27-20_16:24:47.png


Ghan-08-27-20_16:26:15.png
 
Level 6
Joined
Jul 23, 2018
Messages
243
The globals worked fine because I used 1.31 instead. Turns out I need JassHelper. However I got another error "Error: Identifier already in used: Damage." Perhaps there's a trigger that interferes with the triggers. Could it be Bribe's Damage Engine?
 
Last edited:
Level 6
Joined
Jul 23, 2018
Messages
243
I think I did not clarify enough. It's these lines right here. And error showed, "Identifier already in use: Damage". It's strange that this trigger with test map works fine but with my map, it's getting error. Not sure what's interfering with the trigger.
JASS:
//The Damage formula for the ability.
function Damage takes unit caster, integer Rush, real BaseDamage returns real
    return GetUnitAbilityLevel(caster, Rush) * BaseDamage
endfunction
 
Last edited:
Level 22
Joined
Feb 26, 2008
Messages
891
Yeah, that's the function called Damage that I mentioned might be a candidate. It sounds like there may be another such function somewhere which is causing the error. You'll need to find where the duplicate is, or you can rename this one to something else - just make sure to update all calls to it as well.
 
Level 6
Joined
Jul 23, 2018
Messages
243
After renaming Damage, I got these errors as they did not happen in the test map
upload_2020-9-1_13-47-10.png

Edit: Nevermind, one line was not changed due to the first change
 
Status
Not open for further replies.
Top