HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

item stock manipulation

12-28-2007, 09:59 PM#1
crazedcougar
I have set up a system for item stocking. Basically, there is no automatic restock. When an item is bought the stock decreases by one, when it is sold it increases by one at the shop where it was sold. I prevent buying from allied shops and use a two dimensional array to keep track of 45 items of 6 different players.

This almost works perfectly. When selling, half the time it will predictably remove a seeminly random item from stock, and only update the pawned item's stock to one less than it should be. This is odd behavior, similar to what you might see if you take out either annoted waits. (The waits are mentioned on other posts on this forum also)

The last strange thing is that on the pawn items trigger I needed to remove the item before adding it again with a differnet stock, or it would glitch every time. With the sell items this was completely unnecessary.

So with that data, I have three questions: Whats going on, how can i fix it, and can I replace the waits wtih anything else to make it more rugged?

Here are the two triggers, and thanks!

The perfectly working buy item trig:
Collapse JASS:
function Trig_item_bought_Actions takes nothing returns nothing
    local integer playerNum = GetPlayerId(GetOwningPlayer(GetSellingUnit()))  //most of these vars for 2d array
    local integer itemId = GetItemTypeId(GetSoldItem())
    local integer arraySpot = get_item_spot(itemId)+ playerNum *45
    if (Player(playerNum) == GetOwningPlayer(GetBuyingUnit())) then //no buying from allied shops
        call DisplayTextToForce(GetPlayersAll(), I2S(udg_itemStock[arraySpot]))
        set udg_itemStock[arraySpot] = udg_itemStock[arraySpot] -1
        if (udg_itemStock[arraySpot] > 0) then
            call DisplayTextToForce(GetPlayersAll(), I2S(udg_itemStock[arraySpot]))
            call TriggerSleepAction(0.27)  //this is necessary for some reason
            if (udg_itemStock[arraySpot] > 0) then  //check again in case user bought another item
                call DisplayTextToForce(GetPlayersAll(), I2S(udg_itemStock[arraySpot]))
                call AddItemToStock(GetSellingUnit(), itemId, udg_itemStock[arraySpot], udg_itemStock[arraySpot])
                //for some reason, stock can be manipulated here with no RemoveItemFromStock.  That is required when selling an item.
            else //remove if 0, prevent restock
                call RemoveItemFromStock(GetSellingUnit(), itemId)
            endif
        else //remove if 0, prevent restock
            call RemoveItemFromStock(GetSellingUnit(), itemId)
        endif
        call DisplayTextToForce(GetPlayersAll(), I2S(udg_itemStock[arraySpot]))
    else  //illegal buy
        call RemoveItem( GetSoldItem() )
        call DisplayTextToForce(GetPlayersAll(), "|cffFFFF00You cannot buy from allied shops.  Have your ally buy it for you|r")
        call PlayLocalSound(gg_snd_error, playerNum)
        call TriggerSleepAction(0.27)
        if (udg_itemStock[arraySpot] > 0) then
            call AddItemToStock(GetSellingUnit(), itemId, udg_itemStock[arraySpot], udg_itemStock[arraySpot])
        endif
    endif
endfunction

//===========================================================================
function InitTrig_item_bought takes nothing returns nothing
    set gg_trg_item_bought = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_item_bought, EVENT_PLAYER_UNIT_SELL_ITEM )
    call TriggerAddAction( gg_trg_item_bought, function Trig_item_bought_Actions )
endfunction


And the unusably glitchy sell trigger (oh and how do I better the conditions?):
Collapse JASS:
function is_Filter_hvlt takes nothing returns boolean
    return ( GetUnitTypeId(GetFilterUnit()) == 'hvlt' )
endfunction

function is_Filter_ovln takes nothing returns boolean
    return ( GetUnitTypeId(GetFilterUnit()) == 'ovln' )
endfunction

function is_Filter_utom takes nothing returns boolean
    return ( GetUnitTypeId(GetFilterUnit()) == 'utom' )
endfunction

function is_Filter_eden takes nothing returns boolean
    return ( GetUnitTypeId(GetFilterUnit()) == 'eden' )
endfunction

function is_Filter_ngme takes nothing returns boolean
    return ( GetUnitTypeId(GetFilterUnit()) == 'ngme' )
endfunction

function Trig_item_returned_Actions takes nothing returns nothing
    local integer itemId = GetItemTypeId(GetSoldItem())  //most of these vars are for 2d array
    local integer shopNum = get_item_spot(itemId)
    local integer playerNum = GetPlayerId(GetOwningPlayer(GetSellingUnit()))
    local integer arraySpot = shopNum + playerNum *45
    local unit shop
    call DisplayTextToForce(GetPlayersAll(), I2S(udg_itemStock[arraySpot]))
    set udg_itemStock[arraySpot] = udg_itemStock[arraySpot] +1 //array works fine
    set bj_wantDestroyGroup = true
    call DisplayTextToForce(GetPlayersAll(), "shopnum: " + I2S(shopNum))
    if (shopNum < 9) then //figure out which shop the item came from
        set shop = GroupPickRandomUnit(GetUnitsOfPlayerMatching(Player(playerNum), Condition(function is_Filter_hvlt)))
    elseif (shopNum < 17) then
        set shop = GroupPickRandomUnit(GetUnitsOfPlayerMatching(Player(playerNum), Condition(function is_Filter_ovln)))
    elseif (shopNum < 25) then
        set shop = GroupPickRandomUnit(GetUnitsOfPlayerMatching(Player(playerNum), Condition(function is_Filter_utom)))
    elseif (shopNum < 34) then
        set shop = GroupPickRandomUnit(GetUnitsOfPlayerMatching(Player(playerNum), Condition(function is_Filter_eden)))
    else
        set shop = GroupPickRandomUnit(GetUnitsOfPlayerMatching(Player(playerNum), Condition(function is_Filter_ngme)))
    endif
    call DisplayTextToForce(GetPlayersAll(), I2S(udg_itemStock[arraySpot]))
    call RemoveItemFromStock(shop, itemId) //this is necessary or the stock will not change.
    call TriggerSleepAction(0.27)  //I dont know why, but this is necessary or odd things happen
    call AddItemToStock(shop, itemId, udg_itemStock[arraySpot], udg_itemStock[arraySpot]) 
endfunction

//===========================================================================
function InitTrig_item_returned takes nothing returns nothing
    set gg_trg_item_returned = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_item_returned, EVENT_PLAYER_UNIT_PAWN_ITEM )
    call TriggerAddAction( gg_trg_item_returned, function Trig_item_returned_Actions )
endfunction


Collapse JASS:
function get_item_spot takes integer ID returns integer
if (ID == 'sreg') then
    return 0
elseif (ID == 'plcl') then
    return 1
//this repeats 43 more times
endif
return 0 //prevent crash
endfunction
12-30-2007, 10:40 PM#2
crazedcougar
Ok, so I figured it out. At least I know exactly whats going on and a suitable workaround.

The neutral building add item triggers are more complex than at first seems. The AddItemToStock seems to, unintuitively, change the current stock and then the max stock. This means that it behaves as one would assume when lowering the stock of an item below the last set maximum. When you raise the stock and the stock max both to above the old max, however, the stock will be at the old maximum until the item replenishes more.

The best workaround I know for this is to simply call the function twice with the same parameters when you know the new stock will be above the old stock max.

However, I did not discover this right away (due in inexperience in bugtesting) and found another workaround, which is, however, flawed. (Blizzards fault!)

You can call RemoveItemFromStock before adding your item again, and it will be at the correct stock. However, this will cause the first item which the shop is selling to be removed, I assume because its AddITemFromStock is trying to remove the item first, but its not there. It works like this:

Collapse JASS:
    call RemoveItemFromStock(shop, itemId)  //comment this line and all is normal
    call TriggerSleepAction(1)  //added this line to see which func was removing the incorrect item.
    call AddItemToStock(shop, itemId, 3, 3) //without the RemoveItem commented, 
        //this will remove the first item for sale in a shop.

Because I was working on two or three things at the same time for this system, this bug cause me lots of trouble. Perhaps this info should be added to some giant stickied thread of "Weird things about the editor that don't work quite exactly as one might assume"?

Adios


PS: A "0" second wait ir required between buying the item and manipulating the stock. Why? Of course this comes out to 0.27 seconds, is there a way to speed this up?
12-30-2007, 11:05 PM#3
Ammorth
Use a 0 second timer. The events actually fire right before the transaction takes place (in-case you want to prevent it all together).

To do so, use an attach method to attach your locals to a timer, start it for 0 seconds and make it execute a function which does the remainder of the actions. I know it seems stupid to have to do so much, but thats what I have used in the past.

(I think you could get away with globals instead of attaching, but attaching is fool-proof and I've never done any serious testing with globals).
12-30-2007, 11:51 PM#4
crazedcougar
That sounds good, like it would be instant. I've never used handle vars before, how would that work?

*burys head in tutorials*

Edit: Would I use something large like HSAS? It says it is the fastest way to attach thins to timers.

Edit2: HSAS or ABC? Maybe ABC because its smaller, and speed is not a huge concern here?
12-31-2007, 12:39 AM#5
Ammorth
Yes, you can use that, CSCache or even SmartTimers

Each has a different approach, so you would have to learn how.

If you are using vJass, I recommend making a struct to save all your locals to and then saving the struct to the timer.