• 🏆 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] Facing the unit and see unit

Level 1
Joined
Jul 21, 2023
Messages
2
main.j
JASS:
globals
    hashtable timerTable = InitHashtable()
endglobals
function killEffect takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer tid = GetHandleId(t)
    local effect eff =LoadEffectHandle(timerTable,tid,1)
    call DestroyEffect(eff)
    call FlushChildHashtable(timerTable,tid)
    call DestroyTimer(t)
endfunction
function makeSafeEffectAtPoint takes string effL,location p,real during returns nothing
    local timer t= CreateTimer()
    local integer tid= GetHandleId(t)
    // call AddSpecialEffectLoc( "Abilities\\Spells\\Human\\Resurrect\\ResurrectCaster.mdl" ,p2)
    local effect eff = AddSpecialEffectLoc(effL,p)
    // 不清掉点,需要自己清除
    call SaveEffectHandle(timerTable,tid,1,eff)
    call TimerStart(t,during,false,function killEffect)
endfunction
function killTag takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer tid = GetHandleId(t)
    local texttag tag =LoadTextTagHandle(timerTable,tid,1)
    call DestroyTextTag(tag)
    call FlushChildHashtable(timerTable,tid)
    call DestroyTimer(t)
endfunction
function makeSafeText takes string text ,location p,real during returns nothing
    local timer t= CreateTimer()
    local integer tid= GetHandleId(t)
 
    local texttag tag =CreateTextTagLocBJ(text,p,300,12,255,0,0,1)
    // 不清掉点,需要自己清除
    call SaveTextTagHandle(timerTable,tid,1,tag)
    call TimerStart(t,during,false,function killTag)
endfunction
QQ截图20230823113418.png

how to select speller see unit
JASS:
function Trig_see_Conditions takes nothing returns boolean
 
    return GetSpellAbilityId() == 'A001' 
endfunction
function Trig_see_Func001A takes nothing returns nothing
    local location p1=GetUnitLoc(GetTriggerUnit())
    local location p2=GetUnitLoc(GetEnumUnit())
    local real faceAngel = AngleBetweenPoints(p1,p2) 
    local real dangerAngel = GetUnitFacing(GetTriggerUnit())
    local real rs 
    if (faceAngel< 0 ) then
        set faceAngel = 360 + faceAngel
    endif
    set rs = faceAngel - dangerAngel 
    if(rs <0 ) then 
       set  rs = - rs
    endif
    if(rs > 180) then
        set rs = 360 - rs
    endif
    if(rs<=70 and  IsUnitEnemy(GetEnumUnit(),GetOwningPlayer(GetTriggerUnit()))) then
        call makeSafeEffectAtPoint("Abilities\\Spells\\Undead\\Darksummoning\\DarkSummonTarget.mdl" ,p2,1)
    elseif (IsUnitEnemy(GetEnumUnit(),GetOwningPlayer(GetTriggerUnit()))) then
        call makeSafeText(  R2S(faceAngel) +"-"+R2S(dangerAngel)+ "=" +R2S(rs),p2,2)
    endif
    call RemoveLocation(p1)
    call RemoveLocation(p2)
endfunction
function Trig_see_Actions takes nothing returns nothing
    call ForGroupBJ( GetUnitsInRectAll(GetPlayableMapRect()), function Trig_see_Func001A )
endfunction
//===========================================================================
function InitTrig_see takes nothing returns nothing
    set gg_trg_see = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_see, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_see, Condition( function Trig_see_Conditions ) )
    call TriggerAddAction( gg_trg_see, function Trig_see_Actions )
endfunction

[ATTACH type="full"]446022[/ATTACH]
how to select enemy see speller
JASS:
function Trig_face_Func001A_Conditions takes nothing returns boolean
    if ( not ( GetSpellAbilityId() == 'A000' ) ) then
        return false
    endif
    return true
endfunction
function Trig_face_Func001A takes nothing returns nothing
    local location p1=GetUnitLoc(GetTriggerUnit())
    local location p2=GetUnitLoc(GetEnumUnit())
    local real faceAngel = GetUnitFacing(GetEnumUnit())
    local real dangerAngel = AngleBetweenPoints(p2,p1)
    local real rs 
    if (dangerAngel< 0 ) then
        // call makeSafeEffectAtPoint("Abilities\\Spells\\NightElf\\Blink\\BlinkCaster.mdl" ,p2,1)
        set dangerAngel = 360 + dangerAngel
    endif
    set rs = faceAngel - dangerAngel 
    if(rs <0 ) then 
       set  rs = - rs
    endif
    if(rs > 180) then
        set rs = 360 - rs
    endif
    if(rs<=30 and  IsUnitEnemy(GetEnumUnit(),GetOwningPlayer(GetTriggerUnit()))) then
        call makeSafeEffectAtPoint("Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl" ,p2,1)
    elseif (IsUnitEnemy(GetEnumUnit(),GetOwningPlayer(GetTriggerUnit()))) then
        call makeSafeText(  R2S(faceAngel) +"-"+R2S(dangerAngel)+ "=" +R2S(rs),p2,2)
    endif
    call RemoveLocation(p1)
    call RemoveLocation(p2)
    
endfunction
function Trig_face_Actions takes nothing returns nothing
    call ForGroupBJ( GetUnitsInRectAll(GetPlayableMapRect()), function Trig_face_Func001A )
endfunction
//===========================================================================
function InitTrig_face takes nothing returns nothing
    set gg_trg_face = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_face, EVENT_PLAYER_UNIT_SPELL_EFFECT )
    call TriggerAddCondition( gg_trg_face, Condition( function Trig_face_Func001A_Conditions ) )
    call TriggerAddAction( gg_trg_face, function Trig_face_Actions )
endfunction
 

Attachments

  • index.w3m
    17.9 KB · Views: 1
  • QQ图片20230823113425.png
    QQ图片20230823113425.png
    1.4 MB · Views: 3
Hi @version, thank you for your submission.

I am not sure what this script is meant to be used for. Is this supposed to be a 'backstab' detection mechanic?

It looks like this is two submissions, rather than one. One submission you have a special effect cleaner, and in the other one you have a backstab-level cleaner.

I will take this opportunity to show a few different approaches on how your special effect code can be improved:

1) Null locals/use english descriptions (as this is mainly an English community):

JASS:
globals
    hashtable timerTable = InitHashtable()
endglobals

function killEffect takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer tid = GetHandleId(t)
    local effect eff =LoadEffectHandle(timerTable,tid,1)
    call DestroyEffect(eff)
    call FlushChildHashtable(timerTable,tid)
    call DestroyTimer(t)
    //locals also have to be nullified in JASS.
    set t = null
    set eff = null
endfunction

function makeSafeEffectAtPoint takes string effL,location p,real during returns nothing
    local timer t= CreateTimer()
    local integer tid= GetHandleId(t)
    // call AddSpecialEffectLoc( "Abilities\\Spells\\Human\\Resurrect\\ResurrectCaster.mdl" ,p2)
    local effect eff = AddSpecialEffectLoc(effL,p)
    // Can't be cleared within this thread, so delay the text tag destruction.
    call SaveEffectHandle(timerTable,tid,1,eff)
    call TimerStart(t,during,false,function killEffect)
endfunction

function killTag takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer tid = GetHandleId(t)
    local texttag tag =LoadTextTagHandle(timerTable,tid,1)
    call DestroyTextTag(tag)
    call FlushChildHashtable(timerTable,tid)
    call DestroyTimer(t)
    //locals also have to be nullified in JASS
    set t = null
    set tag = null
endfunction

function makeSafeText takes string text ,location p,real during returns nothing
    local timer t= CreateTimer()
    local integer tid= GetHandleId(t)
 
    local texttag tag =CreateTextTagLocBJ(text,p,300,12,255,0,0,1)
    // Can't be cleared within this thread, so delay the text tag destruction.
    call SaveTextTagHandle(timerTable,tid,1,tag)
    call TimerStart(t,during,false,function killTag)
endfunction
Use more advanced vJass/NewTable library and use 'SetTextTagLifespan:

JASS:
library TimedEffectAndTextTag initializer Init requires Table

globals
    private Table tab
endglobals

private function KillEffect takes nothing returns nothing
    local timer t = GetExpiredTimer()
    local integer tid = GetHandleId(t)
    local effect eff = tab.effect[tid]
    call DestroyEffect(eff)
    call tab.handle.remove(tid)
    call DestroyTimer(t)
    //locals also have to be nullified in JASS.
    set t = null
    set eff = null
endfunction

//Capitalize function name to maintain continuity with Blizzard.j/Common.j API:
function MakeSafeEffectAtPoint takes string effL,location p,real during returns nothing
    local timer t= CreateTimer()
    local integer tid= GetHandleId(t)
    // call AddSpecialEffectLoc( "Abilities\\Spells\\Human\\Resurrect\\ResurrectCaster.mdl" ,p2)
    local effect eff = AddSpecialEffectLoc(effL,p)
    // Some special effects need to wait before being removed, so we can't clear them within this thread, so delay the effect tag destruction.
    set tab.effect[tid] = eff
    call TimerStart(t,during,false,function KillEffect)
    set t = null
    set eff = null
endfunction

function MakeSafeText takes string text ,location p,real during returns nothing
    local texttag tag =CreateTextTagLocBJ(text,p,300,12,255,0,0,1)
 
    //This is already an automatic text tag destroyer.
    call SetTextTagLifespan(tag, during)
    call SetTextTagPermanent(tag, false)
 
    //technically, text tags do not need to be nulled, because they are not agents.
endfunction

private function Init takes nothing returns nothing
    set tab = Table.create()
endfunction

endlibrary

Alternatively, using Lua + PreciseWait to make this whole process much cleaner:

Lua:
do
    ---@param effL string
    ---@param p location
    ---@param during real
    function MakeSafeEffectAtPoint(effL, p, during)
        local eff = AddSpecialEffectLoc(effL, p)
        TriggerSleepAction(during)
        DestroyEffect(eff)
        -- Agents do not need to be set to 'nil' in Lua as the are treated the same way as handles.
    end
    ---@param text string
    ---@param p location
    ---@param during real
    function MakeSafeText(text, p, during)
        local tag = CreateTextTagLocBJ(text, p, 300, 12, 255, 0, 0, 1)
        SetTextTagLifespan(tag, during)
    end
end

So then, we can take the spell that you've made, and apply further cleanup and improve the logic to get rid of magic numbers wherever possible:

JASS:
library BackstabInfoDisplayer initializer Init requires TimedEffectAndTextTag

globals
    private player ownerOfTriggeringUnit
    private location triggerUnitLoc
endglobals

private function HandleBackstabLogic takes unit pickedUnit returns nothing
    local location pickedUnitLoc = GetUnitLoc(pickedUnit)
    local real faceAngle = GetUnitFacing(pickedUnit)
    local real angleBetweenUnits = AngleBetweenPoints(pickedUnitLoc, triggerUnitLoc)
    local real backstabAngle = ModuloReal(faceAngle - angleBetweenUnits, 360)
 
    if (backstabAngle > 180) then
        set backstabAngle = 360 - backstabAngle
    endif
    if (backstabAngle <= 30) then
        call MakeSafeEffectAtPoint("Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl", pickedUnitLoc, 1)
    else
        //Use I2S(R2I()) to avoid very long and unnecessary decimal values being printed.
        call MakeSafeText(I2S(R2I(faceAngle)) + " - " + I2S(R2I(angleBetweenUnits)) + " = " + I2S(R2I(backstabAngle)), pickedUnitLoc, 2)
    endif
 
    //clear dynamic handles manually:
    call RemoveLocation(pickedUnitLoc)
 
    //null local agents:
    set pickedUnitLoc = null
 
    //set pickedUnit = null <- not needed. parameter agents do not need to be set to 'null'
endfunction

private function RoundupAllUnits takes nothing returns boolean
    local unit pickedUnit = GetFilterUnit()
    if IsUnitEnemy(pickedUnit, ownerOfTriggeringUnit) then
        call HandleBackstabLogic(pickedUnit)
    endif
    set pickedUnit = null
    return false
endfunction

private function TrigActions takes nothing returns boolean
    if GetSpellAbilityId() == 'A000' then
        // GetTriggerPlayer is already the same value as GetOwningPlayer(GetTriggerUnit()) because this is a playerunitevent, so it has a triggering unit and a triggering player alike.
        set ownerOfTriggeringUnit = GetTriggerPlayer()
  
        // store it before entering the loop so it doesn't have to be created and removed a bunch of times
        set triggerUnitLoc = GetUnitLoc(GetTriggerUnit())
  
        call GroupEnumUnitsInRect(bj_lastCreatedGroup, bj_mapInitialPlayableArea, Filter(function RoundupAllUnits))
  
        call RemoveLocation(triggerUnitLoc)
    endif
    return false
endfunction

//===========================================================================
private function Init takes nothing returns nothing
    local trigger trig = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_EFFECT)
 
    // In JASS, we can combine trigger actions and trigger conditions into one. It is fine to use a TriggerAction instead,
    // but it is also common to wrap everything in a condition as the thread executes slightly more efficiently.
    call TriggerAddCondition(trig, Condition(function TrigActions))
 
    //Since this trigger is never destroyed, nulling it is not technically relevant.
    //set trig = null
endfunction

endlibrary

The Lua version would look something like this (using Global Initialization and Lua-Infused GUI):
Lua:
OnInit(function()
    RegisterAnyPlayerUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT, function()
        if GetSpellAbilityId() == FourCC('A000') then
            local ownerOfTriggeringUnit = GetTriggerPlayer()
            local triggerUnitLoc = GetUnitLoc(GetTriggerUnit())
   
            ---@param pickedUnit unit
            local function handleBackstabLogic(pickedUnit)
                local pickedUnitLoc = GetUnitLoc(pickedUnit)
                local faceAngle = GetUnitFacing(pickedUnit)
                local angleBetweenUnits = AngleBetweenPoints(pickedUnitLoc, triggerUnitLoc)
                local backstabAngle = ModuloReal(faceAngle - angleBetweenUnits, 360)
   
                if (backstabAngle > 180) then
                    backstabAngle = 360 - backstabAngle
                end
                if (backstabAngle <= 30) then
                    MakeSafeEffectAtPoint("Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl", pickedUnitLoc, 1)
                else
                    --Use math.floor to avoid very long and unnecessary decimal values being printed.
                    MakeSafeText(math.floor(faceAngle) .. " - " .. math.floor(angleBetweenUnits) .. " = " .. math.floor(backstabAngle), pickedUnitLoc, 2)
                end
   
                --Lua-infused GUI eliminates the need to remove the locations manually, as it transforms locations and unit groups into garbage-collectible tables..
            end
   
            GUI.enumUnitsInRect(
                function(pickedUnit)
                    if IsUnitEnemy(pickedUnit, ownerOfTriggeringUnit) then
                        handleBackstabLogic(pickedUnit)
                    end
                end,
                bj_mapInitialPlayableArea
            )
        end
    end)
end)

I hope this has been instructive, as I don't really want to vote on the poll you created. I want to encourage you to learn and develop in your coding skills.
 

Attachments

  • index.w3m
    30.3 KB · Views: 0
Last edited:
Top