• 🏆 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] My codes crashing WC3

Status
Not open for further replies.
Level 10
Joined
Mar 31, 2009
Messages
732
I've narrowed it down to this somewhere:

JASS:
function Trig_CTF_Flag_Dropped_Actions takes nothing returns nothing
    local item droppedItem = GetManipulatedItem()
    local integer playerID = 0
    loop
        exitwhen playerID == bj_MAX_PLAYERS
        if (droppedItem == playerFlags[playerID]) then
            call BJDebugMsg("DEBUG. droppedItem = " + GetItemName(droppedItem))
            call SetItemPosition(droppedItem, 1, 1)//GetUnitX(playerCops[playerID]), GetUnitY(playerCops[playerID]))
            //call UnitShareVision(GetTriggerUnit(), Player(playerID), false)
        endif
        set playerID = playerID + 1
    endloop
endfunction
Specificaly this line: call SetItemPosition(droppedItem, 1, 1)
I comment that line out, the trigger doesn't do what I want of course, but it doesnt crash. I uncomment it, and it crashes WC3... I've confirmed with the debug line that the variable does indeed have the right thing stored when it hits that line.
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
The problem was you cannot use SetItemPosition on either item events, since both of them involve the item being "possessed" by a unit. If you do try to use SetItemPosition under these circumstances, it will crash WarCraft III without an error message even.

The fix was to use both CreateItem and RemoveItem instead.

This is the first reason I've had to recommend someone to using ItemUtils. It seems that more-than-basic vJass knowledge is required to use it though.
 
Level 10
Joined
Mar 31, 2009
Messages
732
I think it has something to do with the item not having a position while the unit still carries it.
The unitdropitem function is like an issue order I believe, so it takes time for the order to respond, so the item will still be in the units inventory when my trigger hits the next line trying to move it?
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
Its a strange bug. It would seem that using SetItemPosition on the event response of EVENT_UNIT_DROP_ITEM crashes WarCraft III without an error. If you use SetItemPosition on the EVENT_UNIT_PICKUP_ITEM callback, the game responds fine (and moves the item from the unit's inventory to the terrain).

In other words:
JASS:
scope Init initializer init

globals
    public trigger      flagDropTrig        = CreateTrigger()
endglobals

public function onDrop takes nothing returns nothing
    call SetItemPosition(GetManipulatedItem(), 0, 0)
endfunction
public function onDropFilter takes nothing returns boolean
    local integer id=GetItemTypeId(GetManipulatedItem())
    return (id=='flag') or (id=='nflg') or (id=='oflg') or (id=='uflg')
endfunction
public function init takes nothing returns nothing
    call TriggerRegisterAnyUnitEventBJ(flagDropTrig, EVENT_PLAYER_UNIT_PICKUP_ITEM)
    call TriggerAddCondition(flagDropTrig, Filter(function onDropFilter))
    call TriggerAddAction(flagDropTrig, function onDrop)
endfunction
    
endscope

This will not crash WarCraft III.

[jass=Crash]scope Init initializer init

globals
public trigger flagDropTrig = CreateTrigger()
endglobals

public function onDrop takes nothing returns nothing
call SetItemPosition(GetManipulatedItem(), 0, 0)
endfunction
public function onDropFilter takes nothing returns boolean
local integer id=GetItemTypeId(GetManipulatedItem())
return (id=='flag') or (id=='nflg') or (id=='oflg') or (id=='uflg')
endfunction
public function init takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(flagDropTrig, EVENT_PLAYER_UNIT_DROP_ITEM)
call TriggerAddCondition(flagDropTrig, Filter(function onDropFilter))
call TriggerAddAction(flagDropTrig, function onDrop)
endfunction

endscope[/code]

This will.
 
You've got the principal right, but the theory wrong. SetItemPosition triggers a DropItem event, which creates an infinite loop and crashes the game if used in response to a DropItem event. For example, in this code, I use SetItemPosition in a DropItem event, but avoid the crash by limiting the number of times the trigger can fire in one actual drop. Change MAX_COUNT to whatever you want, and that's how many times the trigger will fire.
JASS:
//! zinc
library Test
{
    constant integer MAX_COUNT = 2;
    integer count = 0;
    
    function Actions () -> boolean
    {
        boolean b;
        trigger tt;
        
        count += 1;
        b = count >= MAX_COUNT; if (b)
        {
            tt = GetTriggeringTrigger();
            DisableTrigger(tt);
        }
        
        BJDebugMsg("Drop event, count " + I2S(count));
        SetItemPosition(GetManipulatedItem(), 0., 0.);
        
        if (b)
        {
            BJDebugMsg(" ");
            count = 0;
            EnableTrigger(tt);
        }
        
        return false;
    }
    
    function onInit ()
    {
        trigger t = CreateTrigger();
        TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DROP_ITEM);
        TriggerAddCondition(t, function Actions);
    }
}
//! endzinc
 
Level 18
Joined
Jan 21, 2006
Messages
2,552
I can't believe I never put that together, seems my reasoning was off. Thanks for the tip.

That also means that you'll probably want to do something similar in your code, [b[Teelo[/b]. It would be quite easy to avoid the crash in this case and it would also avoid the hassle of creating/removing an item (which can act strangely when passing off items). Instead of using dynamic items, you should definitely use static ones. If you need help doing this just say so.
 
Status
Not open for further replies.
Top