HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

get item owning unit in a periodic even

03-27-2010, 06:26 PM#1
mystafox
Hi,

I am trying to have an item cause some action every X seconds when carried by a unit. I have figured out how to do this, sort of, but it isn't MUI and it is very ugly. The code so far:

Collapse JASS:
function Trig_Silmaril_Enticement_FilterIsEnemy takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), bj_groupEnumOwningPlayer) and GetWidgetLife(GetFilterUnit()) > 0.405
endfunction

function Trig_Silmaril_Enticement_Filter takes nothing returns boolean 
    local group g
    local unit t
    local boolean b = false
    
    set g = GetUnitsOfPlayerAll(Player(0))
    loop
        set t = FirstOfGroup(g)
        exitwhen t == null
        call GroupRemoveUnit(g,t)
        if UnitHasItemOfTypeBJ(t, 'ratf') then
            set b = true
        endif
    endloop
    
    call DestroyGroup(g)
    set g = null
    
    return b
endfunction

function Trig_Silmaril_Enticement_Conditions takes nothing returns boolean
    return Trig_Silmaril_Enticement_Filter()
endfunction

function Trig_Silmaril_Enticement_Actions takes nothing returns nothing
    local unit U
    local player P
    local location L
    local group g = CreateGroup()
    local boolexpr b = Condition(function Trig_Silmaril_Enticement_FilterIsEnemy)
    local unit t
    local integer i = 1
    
    set g = GetUnitsOfPlayerAll(Player(0))
    loop
        set t = FirstOfGroup(g)
        exitwhen t == null
        call GroupRemoveUnit(g,t)
        if  UnitHasItemOfTypeBJ(t, 'ratf') then
            set U = t
        endif
    endloop
    
    set P = GetOwningPlayer( U )
    set L = GetUnitLoc( U )
    call DestroyGroup(g)
    set g = CreateGroup()
    
    call DisplayTimedTextToPlayer( P, 0, 0, 5. ,"TAUNT " + GetPlayerName(P) )
    call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\Taunt\\TauntCaster.mdl", U, "origin" ) )
    set bj_groupEnumOwningPlayer = P
    call GroupEnumUnitsInRangeOfLoc(g, L, 1000, b)
    call DestroyBoolExpr(b)
    loop
        set t = FirstOfGroup(g)
        exitwhen t == null
        call GroupRemoveUnit(g,t)
        call IssueTargetOrder( t, "attack", U )
    endloop
    
    call DestroyGroup(g)
    call RemoveLocation(L)
    set g = null
    set b = null
    set t = null
    set P = null
    set U = null
    set L = null
endfunction

function InitTrig_Silmaril_taunt takes nothing returns nothing
    set gg_trg_Silmaril_taunt = CreateTrigger(  )
    call TriggerRegisterTimerEvent( gg_trg_Silmaril_taunt, 5., true )
    call TriggerAddCondition( gg_trg_Silmaril_taunt , Condition(function Trig_Silmaril_Enticement_Conditions))
    call TriggerAddAction( gg_trg_Silmaril_taunt, function Trig_Silmaril_Enticement_Actions )
endfunction

The condition here goes through all of player(0)'s units and checks for the item, if found, it runs the action that searches for the unit again, and then will cast the taunt effect every 5 seconds.

Note that I am wishing to use something like this for any type of spell, not just taunt. Is there an easier way to grab the item-owning unit than this? And make it work for any number of players who may have it?

Thank you
03-27-2010, 06:43 PM#2
Tot
I assume you make some middleearth-map...

If there is only one silmaril in your map:
save the current holder upon item-pickup into a global, everytime the item is picked, removed

If there are more slimaril in your map:
save all current holders into a global group and remove/add everyone who drops/picks a silmaril
03-27-2010, 06:49 PM#3
mystafox
The middle-earth stories are fun, aren't they?

Is there an easier way to finding the current item holders than iterating through the owning units of every player?
03-27-2010, 06:59 PM#4
Tot
have you read my post??

you've simply to store the current holder(s) when they pickup, drop an item or die
03-27-2010, 07:12 PM#5
mystafox
Hi,

Yes. I read your post, thank you. I am currently implementing multiple triggers to try and do as you suggest.

I would like to clarify my question, (please humor me): Is there a simpler way to grab the current owning unit within the one trigger. Such as by using GetTriggerUnit() or GetManipulatingUnit() - both of which don't work of course...

There may not be a simpler way, in which case your method might be the best and I will use that.

Thanks
03-27-2010, 07:27 PM#6
Tot
Collapse your code:
function Trig_Silmaril_Enticement_FilterIsEnemy takes nothing returns boolean
    return IsUnitEnemy(GetFilterUnit(), bj_groupEnumOwningPlayer) and GetWidgetLife(GetFilterUnit()) > 0.405
endfunction

function Trig_Silmaril_Enticement_Filter takes nothing returns boolean 
    local group g
    local unit t
    local boolean b = false
    
    set g = GetUnitsOfPlayerAll(Player(0))
    loop
        set t = FirstOfGroup(g)
        exitwhen t == null
        call GroupRemoveUnit(g,t)
        if UnitHasItemOfTypeBJ(t, 'ratf') then
            set b = true
        endif
    endloop
    
    call DestroyGroup(g)
    set g = null
    
    return b
endfunction

function Trig_Silmaril_Enticement_Conditions takes nothing returns boolean
    return Trig_Silmaril_Enticement_Filter()
endfunction

function Trig_Silmaril_Enticement_Actions takes nothing returns nothing
    local unit U
    local player P
    local location L
    local group g = CreateGroup()
    local boolexpr b = Condition(function Trig_Silmaril_Enticement_FilterIsEnemy)
    local unit t
    local integer i = 1
    
    set g = GetUnitsOfPlayerAll(Player(0))
    loop
        set t = FirstOfGroup(g)
        exitwhen t == null
        call GroupRemoveUnit(g,t)
        if  UnitHasItemOfTypeBJ(t, 'ratf') then
            set U = t
        endif
    endloop
    
    set P = GetOwningPlayer( U )
    set L = GetUnitLoc( U )
    call DestroyGroup(g)
    set g = CreateGroup()
    
    call DisplayTimedTextToPlayer( P, 0, 0, 5. ,"TAUNT " + GetPlayerName(P) )
    call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\Taunt\\TauntCaster.mdl", U, "origin" ) )
    set bj_groupEnumOwningPlayer = P
    call GroupEnumUnitsInRangeOfLoc(g, L, 1000, b)
    call DestroyBoolExpr(b)
    loop
        set t = FirstOfGroup(g)
        exitwhen t == null
        call GroupRemoveUnit(g,t)
        call IssueTargetOrder( t, "attack", U )
    endloop
    
    call DestroyGroup(g)
    call RemoveLocation(L)
    set g = null
    set b = null
    set t = null
    set P = null
    set U = null
    set L = null
endfunction

function InitTrig_Silmaril_taunt takes nothing returns nothing
    set gg_trg_Silmaril_taunt = CreateTrigger(  )
    call TriggerRegisterTimerEvent( gg_trg_Silmaril_taunt, 5., true )
    call TriggerAddCondition( gg_trg_Silmaril_taunt , Condition(function Trig_Silmaril_Enticement_Conditions))
    call TriggerAddAction( gg_trg_Silmaril_taunt, function Trig_Silmaril_Enticement_Actions )
endfunction

Collapse optimized code:
function Trig_Silmaril_Enticement_FilterIsEnemy takes nothing returns boolean
    local unit u=GetFilterUnit()
    local boolean b=(u!=null and IsUnitEnemy(u, bj_groupEnumOwningPlayer) and GetWidgetLife(u) > 0.405)
    set u=null
    return b
endfunction

globals
group tempGroup=CreateGroup()
boolexpr enemyFilter=Condition(function Trig_Silmaril_Enticement_FilterIsEnemy)
endglobals

function Trig_Silmaril_Enticement_Filter takes nothing returns boolean 
    local unit t
    call GroupClear(tempGroup)
    call GroupEnumUnitsOfPlayer(tempGroup,p,null)
    loop
        set t = FirstOfGroup(tempGroup)
        exitwhen t == null
        call GroupRemoveUnit(tempGroup,t)
        if UnitHasItemOfTypeBJ(t, 'ratf') then
            return true
        endif
    endloop
    return false
endfunction

function Trig_Silmaril_Enticement_Actions takes nothing returns nothing
    local player P
    local unit t
    local unit U
    local integer i = 1
    call GroupClear(tempGroup)
    call GroupEnumUnitsOfPlayer(tempGroup,P,null)
    loop
        set t = FirstOfGroup(tempGroup)
        exitwhen t == null
        call GroupRemoveUnit(tempGroup,t)
        exitwhen UnitHasItemOfTypeBJ(t, 'ratf')
    endloop
   if t==null then
       return //no one holds the item
   endif
    set U=t
    set P = GetOwningPlayer( U )
    call DisplayTimedTextToPlayer( P, 0, 0, 5. ,"TAUNT " + GetPlayerName(P) )
    call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\NightElf\\Taunt\\TauntCaster.mdl", U, "origin" ) )
    set bj_groupEnumOwningPlayer = P
      call ClearGroup(tempGroup)
    call GroupEnumUnitsInRange(tempGroupo, GetUnitX(U),GetUnitY(U), 1000, enemyFilter)
    loop
        set t = FirstOfGroup(tempGroup)
        exitwhen t == null
        call GroupRemoveUnit(tempGroup,t)
        call IssueTargetOrder( t, "attack", U )
    endloop
    set t = null
    set P = null
    set U = null
endfunction

function InitTrig_Silmaril_taunt takes nothing returns nothing
    set gg_trg_Silmaril_taunt = CreateTrigger(  )
    call TimerStart(CreateTimer(),5.0,true, function gg_trg_Silmaril_taunt)
    call TriggerAddCondition( gg_trg_Silmaril_taunt , Condition(function Trig_Silmaril_Enticement_Filter))
    call TriggerAddAction( gg_trg_Silmaril_taunt, function Trig_Silmaril_Enticement_Actions )
endfunction

if you're using plain JASS, simply create variables for each var in the golbals-block and replace them with udg_<name> within the trigger
03-27-2010, 08:44 PM#7
Kueken
Quote:
Originally Posted by mystafox
Hi,

Yes. I read your post, thank you. I am currently implementing multiple triggers to try and do as you suggest.

I would like to clarify my question, (please humor me): Is there a simpler way to grab the current owning unit within the one trigger. Such as by using GetTriggerUnit() or GetManipulatingUnit() - both of which don't work of course...

There may not be a simpler way, in which case your method might be the best and I will use that.

Thanks

There is no native, which leads to your desired unit. You need to do some kind of workaround. You can use ToTs method. There are other methods, though. You could, for example, use Item Indexing (as Items got a Custom Value afaik) or Hashtables to store the current owner for every item. However, this is probably too complicated, if you only need this check for one item.
03-28-2010, 09:05 AM#8
Anitarf
ItemUtils comes with the function GetItemOwningUnit() which can give you the unit currently carrying the item. The library itself uses the method Tot mentioned internally.