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

Weird AddUnitToStockBJ function behaviour

Status
Not open for further replies.
Level 5
Joined
Jun 12, 2018
Messages
148
Hi ! I'm currently trying to implement a dynamic random unit sell system and I've ran into a strange problem using the native function which adds unit to a shop (AddUnitToStockBJ).

Problem

Sometimes the function is adding the correct amount of unit slots to the shop and sometimes it just doesn't. I'm sure the integer variable for slots is ok as I check it just before the function call (check picture provided)

Context

This function is called each time the Roll ability is casted and this is happening before :
- udg_hashDraftedUnits saves the 5 random unit-types as follows -> INDEX of PLAYER_NUMBER
- udg_hashCurrentDrafterUnits saves the number of occurences by drafted unit-type-> UNIT_TYPE_ID of PLAYER_NUMBER
- Previous drafted units and both hashtables are flushed with the following code

  • Flushing Tables
    • Events
    • Conditions
    • Actions
      • For each (Integer iteratorInt[(Player number of (Triggering player))]) from 1 to 5, do (Actions)
        • Loop - Actions
          • -------- Cleaning the drafter for the new roll --------
          • Custom script: set unitTypeId = LoadIntegerBJ(udg_iteratorInt[playerIndex], playerIndex, udg_hashDraftedUnits)
          • Custom script: set udg_utUnitLoaded[playerIndex] = unitTypeId
          • Neutral Building - Remove utUnitLoaded[(Player number of (Triggering player))] from DRAFTERS[(Player number of (Triggering player))]
      • -------- Cleaning the old draft hashtables --------
      • Hashtable - Clear all child hashtables of child (Player number of (Triggering player)) in hashCurrentDrafterUnits
      • Hashtable - Clear all child hashtables of child (Player number of (Triggering player)) in hashDraftedUnits
      • -------- Shit Happening --------
      • Custom script: call AddUnitsToDrafter(playerIndex)

Code

JASS:
function AddUnitsToDrafter takes integer playerIndex returns nothing
    local integer unitTypeId
    local integer unitCount
    local Stack unitTypeList = Stack.create()
    set udg_iteratorInt[playerIndex] = 1
    loop
        exitwhen udg_iteratorInt[playerIndex] > 5
        set unitTypeId = LoadIntegerBJ(udg_iteratorInt[playerIndex], playerIndex, udg_hashDraftedUnits)
        set unitCount = LoadIntegerBJ(unitTypeId, playerIndex, udg_hashCurrentDrafterUnits)
        call SaveIntegerBJ(( unitCount + 1 ), unitTypeId, playerIndex, udg_hashCurrentDrafterUnits)
        if ( not unitTypeList.has(unitTypeId) ) then
           call unitTypeList.add(unitTypeId)
        endif
        set udg_iteratorInt[playerIndex] = udg_iteratorInt[playerIndex] + 1
    endloop
    call DisplayTextToForce( GetPlayersAll(), "List size : " + I2S(unitTypeList.count) )
    loop
        exitwhen not unitTypeList.hasNext()
        set unitTypeId = unitTypeList.getNext()
        set unitCount = LoadIntegerBJ(unitTypeId, playerIndex, udg_hashCurrentDrafterUnits)
        call DisplayTextToForce( GetPlayersAll(), "Unit ID " + I2S(unitTypeId) + " : " + I2S(unitCount) )
        call AddUnitToStockBJ(unitTypeId, udg_DRAFTERS[playerIndex], unitCount, unitCount)
    endloop
endfunction

Thanks for your help :)
 

Attachments

  • bug1.png
    bug1.png
    3.1 MB · Views: 50
Level 39
Joined
Feb 27, 2007
Messages
5,013
Is it the same unit types that have this error every time? If so perhaps something about its stock refresh interval/max in stock OE data is at fault. I see another potential issue, though I'm not sure it's actually important. "Player number of <player>" in GUI returns in the range 1-24 because it uses GetConvertedPlayerId(), but in JASS GetPlayerId() returns in the 0-23 range. I don't see where you're defining playerIndex in the Flushing Tables trigger, but that might cause some headaches if it interferes.
 
Level 5
Joined
Jun 12, 2018
Messages
148
It seems to happen when a unit-type has already been rolled in the drafter, first time is ok but then unit-type will be limited to 1 max unit slot.
playerIndex is just a local used in custom scripts call to get rid of the painful redundant use in GUI.
I'll refactor this trigger in full vJass in the future, I'm learning it atm.

I'm posting the full trigger so you can see clearer :)

  • Roll
    • Events
      • Unit - A unit Starts the effect of an ability
    • Conditions
      • (Ability being cast) Equal to Roll
      • ((Triggering player) Current gold) Greater than or equal to 2
    • Actions
      • Custom script: local integer playerIndex = GetConvertedPlayerId(GetTriggerPlayer())
      • Custom script: local integer unitTypeId
      • Player - Set (GetTriggerPlayer()) Current gold to (((Triggering player) Current gold) - 2)
      • -------- Getting the player draw chances according to his level --------
      • Set PlayerTier1Chances[(Player number of (Triggering player))] = (Load (Hero level of COURIERS[(Player number of (Triggering player))]) of TIER_1 from CHANCES_DRAW_BY_XP)
      • Set PlayerTier2Chances[(Player number of (Triggering player))] = (Load (Hero level of COURIERS[(Player number of (Triggering player))]) of TIER_2 from CHANCES_DRAW_BY_XP)
      • Set PlayerTier3Chances[(Player number of (Triggering player))] = (Load (Hero level of COURIERS[(Player number of (Triggering player))]) of TIER_3 from CHANCES_DRAW_BY_XP)
      • Set PlayerTier4Chances[(Player number of (Triggering player))] = (Load (Hero level of COURIERS[(Player number of (Triggering player))]) of TIER_4 from CHANCES_DRAW_BY_XP)
      • -------- Drafting random units from the pool and saving them to a hashtable --------
      • For each (Integer iteratorInt[(Player number of (Triggering player))]) from 1 to 5, do (Actions)
        • Loop - Actions
          • -------- Cleaning the drafter for the new roll --------
          • Custom script: set unitTypeId = LoadIntegerBJ(udg_iteratorInt[playerIndex], playerIndex, udg_hashDraftedUnits)
          • Custom script: set udg_utUnitLoaded[playerIndex] = unitTypeId
          • Neutral Building - Remove utUnitLoaded[(Player number of (Triggering player))] from DRAFTERS[(Player number of (Triggering player))]
      • -------- Cleaning the old draft hashtables --------
      • Hashtable - Clear all child hashtables of child (Player number of (Triggering player)) in hashCurrentDrafterUnits
      • Hashtable - Clear all child hashtables of child (Player number of (Triggering player)) in hashDraftedUnits
      • For each (Integer iteratorInt[(Player number of (Triggering player))]) from 1 to 5, do (Actions)
        • Loop - Actions
          • -------- Getting a random unit that will be available at the current slot --------
          • Set randomInt[(Player number of (Triggering player))] = (Random integer number between 1 and 100)
          • Set currentChance[(Player number of (Triggering player))] = PlayerTier1Chances[(Player number of (Triggering player))]
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • randomInt[(Player number of (Triggering player))] Less than or equal to currentChance[(Player number of (Triggering player))]
            • Then - Actions
              • Set utUnitLoaded[(Player number of (Triggering player))] = UnitPool_Tier_1[(Random integer number between 1 and TOTAL_TIER_1_UNITS)]
            • Else - Actions
              • Set currentChance[(Player number of (Triggering player))] = (currentChance[(Player number of (Triggering player))] + PlayerTier2Chances[(Player number of (Triggering player))])
              • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                • If - Conditions
                  • randomInt[(Player number of (Triggering player))] Less than or equal to currentChance[(Player number of (Triggering player))]
                • Then - Actions
                  • Set utUnitLoaded[(Player number of (Triggering player))] = UnitPool_Tier_2[(Random integer number between 1 and TOTAL_TIER_2_UNITS)]
                • Else - Actions
                  • Set currentChance[(Player number of (Triggering player))] = (currentChance[(Player number of (Triggering player))] + PlayerTier3Chances[(Player number of (Triggering player))])
                  • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                    • If - Conditions
                      • randomInt[(Player number of (Triggering player))] Less than or equal to currentChance[(Player number of (Triggering player))]
                    • Then - Actions
                      • Set utUnitLoaded[(Player number of (Triggering player))] = UnitPool_Tier_3[(Random integer number between 1 and TOTAL_TIER_3_UNITS)]
                    • Else - Actions
                      • Set currentChance[(Player number of (Triggering player))] = (currentChance[(Player number of (Triggering player))] + PlayerTier4Chances[(Player number of (Triggering player))])
                      • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
                        • If - Conditions
                          • randomInt[(Player number of (Triggering player))] Less than or equal to currentChance[(Player number of (Triggering player))]
                        • Then - Actions
                          • Set utUnitLoaded[(Player number of (Triggering player))] = UnitPool_Tier_4[(Random integer number between 1 and TOTAL_TIER_4_UNITS)]
                        • Else - Actions
          • Custom script: set unitTypeId = udg_utUnitLoaded[playerIndex]
          • Custom script: call SaveIntegerBJ(unitTypeId, udg_iteratorInt[playerIndex], playerIndex, udg_hashDraftedUnits)
      • -------- Add the saved units to the drafter with the according slots --------
      • Custom script: call AddUnitsToDrafter(playerIndex)
The potential issue may come from
  • Neutral Building - Remove utUnitLoaded[(Player number of (Triggering player))] from DRAFTERS[(Player number of (Triggering player))]
which can be called several times even if there is no unit in the drafter or if the unit-type has already been removed. I thought this was bug free so I didn't adjust the code yet.
 
Last edited:
Level 8
Joined
Mar 19, 2017
Messages
248
Whenever you sell a unit from a marketplace or other unit that has the unit sell unit ability, the sold unit is removed, no matter the stock count, by a "hidden" init trigger that is loaded by Blizzard. This is a good old hardcoded trigger that could (not sure how) be the root of the problem you're facing.

To halt that code from running you must, as custom script on a map init trigger, do this:

Code:
call PauseTimer(bj_stockUpdateTimer)
call DisableTrigger(bj_stockItemPurchased)
 
Level 5
Joined
Jun 12, 2018
Messages
148
@disruptive_ Thanks for the input, I did not know about this. I tried what you've suggested but the result was still the same so I copied this code at the beginning of my Roll trigger (re-enabling the variables at the end) : results were a bit better I could get up to 3 max slots for a unit after several rolls.

However, the results are still random and don't seem linked to the unit-types.

World Editor, I'm not done yet !! :ogre_rage:
 
Level 5
Joined
Jun 12, 2018
Messages
148
I've ended up by removing the drafter building and make a new one to add the new units, the workaround is working and the animations reset are not that bad.
 
Status
Not open for further replies.
Top