• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[vJASS] Creating localized items (again)

Status
Not open for further replies.
Level 19
Joined
Aug 8, 2007
Messages
2,765
JASS:
    globals
        hashtable ItemDropHash = InitHashtable()
        hashtable ItemChanceHash = InitHashtable()
        integer MaxItemsInt = 2938439
    endglobals
struct ItemDrops
    private static method onKill takes nothing returns nothing
        local unit u = GetDyingUnit()
        local integer i = 0
        local integer i2 = 0
        local integer i3 = 0
        local boolean array b
        local integer array itemTypes
        local integer max = 0
        loop
            call print("Started Loop 1")
            exitwhen i == 12
            if GetLocalPlayer() == Player(i) then
                loop
                    call print("Started Loop 2")
                    exitwhen i2 == LoadInteger(ItemDropHash, GetUnitTypeId(u), MaxItemsInt)
                    if GetRandomReal(0, 100) < LoadReal(ItemChanceHash, GetUnitTypeId(u), i2) then
                       set b[i2] = true
                    endif
                    set i2 = i2 + 1
                endloop
            endif
        endloop
        loop
            exitwhen i3 == LoadInteger(ItemDropHash, GetUnitTypeId(u), MaxItemsInt)
            set bj_lastCreatedItem = CreateItemLoc(LoadInteger(ItemDropHash, GetUnitTypeId(u), i3), GetUnitLoc(u))
            if b[13] == false then
                call SetItemVisible(GetLastCreatedItem(), false)
            endif
            set i3 = i3 + 1
        endloop
    endmethod
    private static method addUnitType takes integer unitType, integer itemType, real chance returns nothing
        local boolean b = false
        local integer i = 0
        loop
            exitwhen b == true
            if LoadInteger(ItemDropHash, unitType, i) < 50 then
            call SaveInteger(ItemDropHash, unitType, i, itemType)
            call SaveReal(ItemChanceHash, unitType, i, chance)
            call SaveInteger(ItemDropHash, unitType, MaxItemsInt, i)
            call print("Successful")
            set b = true
            endif
            set i = i + 1
        endloop
    endmethod
    private static method onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerAddAction(t, function thistype.onKill)
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
        call addUnitType('N001', 'I01E', 100)
        call print("Good")
    endmethod
endstruct


Current trigger. 2 problems

1) It spawns the item and hides it per per player. If no players can see, than the item sits there. Forever.

2) Im not 100% sure this will work

3) If 2 players get the same item, than both will see the same item rather than them seeing seperate iteems
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Because the other thread was changing into other things....

and "the killer gets the drop" yeah cuz thats encouraging teamplay. Only units within x of the dying unit will get the drop chance, not implemented yet
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Because the other thread was changing into other things....

That's quite the same subject ...

and "the killer gets the drop" yeah cuz thats encouraging teamplay. Only units within x of the dying unit will get the drop chance, not implemented yet

Ok, but being able to create X items just for one unit kill seems overkill for me, but you're the boss.

1) It spawns the item and hides it per per player. If no players can see, than the item sits there. Forever.

2) Im not 100% sure this will work

3) If 2 players get the same item, than both will see the same item rather than them seeing seperate iteems

1) You could sync local data through game cache, if for all players the item is invisible, then destroy it.
Or you could also use a timer to destroy the item if it isn't picked before X seconds.

2) I'm not neither, because an hidden item would take 0 collision on the map, and then an item placed next to it could have a different position, according if the item is visible or not on the computer X.

3) Then you have to create one item per player.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
1) How would one go on about doing this, perhaps sample code? ive never touched game caches and have not an idea how they work. About the timer, im doing one every 5 minutes but still if x mob drops 50 items on possibility, than thats 2000 items on 40 kills

2) Hm? I meant just my coding might slip somewhere.. as i said im not the best coder

3) Probably, but it leads to 1) where i have to check GLOBALLY, not locally, wether the player that has that item was able to see it and if not destroy it for all players
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Ok,

3) yeah that tutorial you gave me will fidx

2) Really? ive never succesfully done anything with hashes

1) I'll play with this, but can u explain this to me

call FlushGameCache(InitGameCache("pingcache"))

It destroys a new cache?

e/ aite heres my current trigger, building off of gamecaches

JASS:
    globals
        hashtable ItemDropHash = InitHashtable()
        hashtable ItemChanceHash = InitHashtable()
        integer MaxItemsInt = 2938439
        gamecache synctable
    endglobals
struct ItemDrops
    private static method PlayerForceStoredInteger takes player p, gamecache gc, string missionkey, string key returns nothing
    if GetLocalPlayer() == p then
        call SyncStoredInteger(gc, missionkey, key)
    endif
    call TriggerSyncReady()
    endmethod
    private static method killTerms takes nothing returns boolean
        local boolean b = true
        if GetOwningPlayer(GetFilterUnit()) == Player(12) then
        else
            return false
        endif
        if LoadInteger(ItemDropHash, GetUnitTypeId(GetFilterUnit()), 0) > 0 then
        else
            return false
        endif
        return true
    endmethod
    private static method onKill takes nothing returns nothing
        local unit u = GetDyingUnit()
        local integer i = 0
        local integer i2 = 0
        local integer i3 = 0
        local integer i4 = 0
        local boolean array b
        local integer array itemTypes
        local integer max = 0
        loop
            call print("Started Loop 1")
            exitwhen i == 12
            if GetLocalPlayer() == Player(i) then
                loop
                    call print("Started Loop 2")
                    exitwhen i2 == LoadInteger(ItemDropHash, GetUnitTypeId(u), MaxItemsInt)
                    if GetRandomReal(0, 100) < LoadReal(ItemChanceHash, GetUnitTypeId(u), i2) then
                       set b[i2] = true
                       set i4 = 0
                       call StoreInteger(synctable, I2S(GetPlayerId(GetLocalPlayer())), I2S(i2), 1)
                       call thistype.PlayerForceStoredInteger(Player(i), synctable, I2S(GetPlayerId(GetLocalPlayer())), I2S(i2))
                       set i4 = 0
                    endif
                    set i2 = i2 + 1
                endloop
            endif
        endloop
        loop
            exitwhen i4 == 12
            loop
                exitwhen i3 == LoadInteger(ItemDropHash, GetUnitTypeId(u), MaxItemsInt)
                if GetStoredInteger(synctable, I2S(i4), I2S(i3)) == 1 then
                    set bj_lastCreatedItem = CreateItemLoc(LoadInteger(ItemDropHash, GetUnitTypeId(u), i3), GetUnitLoc(u))
                    if b[i3] == false then
                        call SetItemVisible(GetLastCreatedItem(), false)
                    endif
                endif
            set i3 = i3 + 1
            endloop
            set i4 = i4 + 1
        endloop
    endmethod
    private static method addUnitType takes integer unitType, integer itemType, real chance returns nothing
        local boolean b = false
        local integer i = 0
        loop
            exitwhen b == true
            if LoadInteger(ItemDropHash, unitType, i) < 50 then
            call SaveInteger(ItemDropHash, unitType, i, itemType)
            call SaveReal(ItemChanceHash, unitType, i, chance)
            call SaveInteger(ItemDropHash, unitType, MaxItemsInt, i)
            call print("Successful")
            set b = true
            endif
            set i = i + 1
        endloop
    endmethod
    private static method onInit takes nothing returns nothing
        local trigger t = CreateTrigger()
        call TriggerAddAction(t, function thistype.onKill)
        call TriggerAddCondition(t, Condition(function thistype.killTerms))
        call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
        call addUnitType('N001', 'I01E', 100)
        call print("Good")
    endmethod
endstruct

parses aite, i guess its time to test


e/ doesnt work as far as i can tell, ill try to do more debugging
 
Last edited:
Level 17
Joined
Apr 27, 2008
Messages
2,455
1) People say it is to avoid conflit values with an older game cache, but i've just tested and it seems useless, i will make a thread for that, since i'm curious to know why.
Maybe it was necessary in the past, with older wc3 versions.

EDIT : I think it's only for campaigns, as game cache datas are kept when you switch to an other map, that's the main point of the game cache, pass data through maps in a campaign.

2) I just meant that i had understood what you've said, not really checked your code.
And i've tested, an hidden item have 0 collision, so even if it doesn't desync on drop (not tested), it is likely to will on picking up in some cases.

Indeed, imagine a square full of visible items, an item is droped inside, it will be moved outside it, on the edges.
Now imagine this same square of items, but this time they are invisibles, the item droped inside won't be moved.
So the item will have different positions on different computers, then the pickup won't be done at the same time -> desync.
Note that's only theoric, but that makes sense.

3) Since an item is supposed to be visible only for one player, you even don't need to sync data, all you need is eventually create the item, and then display it only for the right player.
Since a code is better than any other explanations :

JASS:
library CustomDrop initializer init

    globals
        private hashtable Hash_t = InitHashtable()
    endglobals
    
    private function OnDeath takes nothing returns nothing
        local unit u = GetDyingUnit()
        local integer unitId = GetUnitTypeId(u)
        local integer count = LoadInteger(Hash_t,unitId,0) // if the unit type was not registred for drop it will be equal to 0, else it will be > 0
        local real random
        local integer i
        local item drop
        
        loop // loop on all dropable item for unitID
        exitwhen count == 0 
            
            set i = 0
            loop // player loop
            exitwhen i == 11
                set random = GetRandomReal(0,100)
                if random < LoadReal(Hash_t,unitId,count) then
                    set drop = CreateItem(LoadInteger(Hash_t,unitId,count),GetUnitX(u),GetUnitY(u))
                    call SetItemVisible(drop,GetLocalPlayer()==Player(i)) // the item will be visible only for Player(i)
                    // or just  : call SetItemVisible(CreateItem(LoadInteger(Hash_t,unitId,count),GetUnitX(u),GetUnitY(u)),GetLocalPlayer()==Player(i))
                endif
            set i = i+1
            endloop
     
        set count = count-1
        endloop
        set u = null
        set drop = null
    endfunction
    
    private function RegisterDrop takes integer unitId , integer itemId, real chanceToDrop returns nothing // chanceToDrop in percent
        local integer n = LoadInteger(Hash_t,unitId,0)
        /* integer : unitId ; 0 -> number of possible item drop for the unit type unitId
           integer : unitId ; x -> rawcode of the item to drop ; x > 0
           real : unitId ; x -> chance of the item x to drop
        */
        set n = n+1
        call SaveInteger(Hash_t,unitId,0,n)
        call SaveInteger(Hash_t,unitId,n,itemId)
        call SaveReal(Hash_t,unitId,n,chanceToDrop)
    endfunction

    private function init takes nothing returns nothing
        local trigger trig = CreateTrigger()
        
        call TriggerRegisterAnyUnitEventBJ(trig,EVENT_PLAYER_UNIT_DEATH)
        call TriggerAddAction(trig,function OnDeath)
        call RegisterDrop('hfoo','spsh',50)
        
    endfunction
    
endlibrary

Because of 2) it still should desync in the mentionned cases.
 
Level 19
Joined
Aug 8, 2007
Messages
2,765
Interesting, SetItemVisible has quite a delay (0.25sec maybe?) although this can be overwritten by spawning the item at a corner, setting it hidden, than moving to where you want it to go.

Anyway, i cant seem to get your code to work. It will flash the item for (above delay) than hide it.
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
You could use TimerUtils or whatever else.

Have you tried to use :

JASS:
call SetItemVisible(CreateItem(LoadInteger(Hash_t,unitId,count),GetUnitX(u),GetUnitY(u)),GetLocalPlayer()==Player(i))

Instead of :

JASS:
set drop = CreateItem(LoadInteger(Hash_t,unitId,count),GetUnitX(u),GetUnitY(u))
call SetItemVisible(drop,GetLocalPlayer()==Player(i))

That should be the same though.

Apparently you don't care about the possible desync :p
 
Level 17
Joined
Apr 27, 2008
Messages
2,455
Alternatively instead of delay the position of the items after creating, you could handle a queue of needed items.
Basically, you create X items of each type on map init, hide them, and when you need one, you just pick the older of them, recreate one and hide it.
 
Status
Not open for further replies.
Top