HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Trying to create efficient dynamic items

07-27-2008, 09:48 PM#1
crayz
After taking a look at ToadCop's inventory system, I'm clueless as to how he created & stored his item attributes, so I've set out to find an efficient way to do this.

Are there any data types used with items that can't be seen in GUI? Or possibly something I have overlooked, which may work good for this?

I had an idea, which would give an item a semi-random custom value, such as:
6|1|35|1|4|6|21

If you take a look between the separators, those digits would be converted into the bonus damage, bonus armor, bonus health / mana, level requirement, class requirement, etc.

It would be uniform, so the 6 above would be a level 6 required item.
The 1 would be the class that may use it. Ex.: 1 = Ranger; 2 = Barbarian; 3 = Druid; etc.
35 - Bonus Damage or Armor
1, 4, 6 & 21 - Extra (External triggers)

To find each value, I would use substrings to separate each 1-2 digits, to get the bonuses & requirements that I want. After those are acquired, I would trigger items upon pickup & upon drop to check if requirements are met, add bonuses, and then remove the bonuses upon drop.

I could use a leaderboard or game-text to display the item values to the players. I would figure out a decent user-friendly way of doing it.

This was just my simple idea. One problem with this is that the bonuses are limited. The max number of digits for an items custom value is 9, so I am very limited to my item bonuses. It seems like it would also lag upon picking items up, as this would check requirements, take proper actions, then use BonusMod multiple times to add the bonuses, all within 1-2 seconds.
Is there a more efficient & better way of doing this, in either Jass or GUI?
07-27-2008, 10:59 PM#2
Captain Griffen
Parallel arrays / structs. vJASS is basically essential for doing parallel arrays and keeping sanity, and required for structs.
07-28-2008, 03:29 AM#3
TEC_Ghost
I do this with Custom Data Item system I made real fast. Basically make a struct with the item attributes, give it a onpickup and ondrop method. Like so...

Collapse JASS:
struct ClothHood

static integer ID = 'I013'
static integer IntBonus = 2
static real ArmorBonus = .01
static integer HPBonus = 10
static string Slot = "Head"

    static method Pickup takes integer i returns nothing
        set PlayerFighter[i].inteligence = PlayerFighter[i].inteligence + .IntBonus
            set PlayerFighter[i].mana = PlayerFighter[i].mana + (.IntBonus * MANA_PER_INT)
        set PlayerFighter[i].armorbase = PlayerFighter[i].armorbase + .ArmorBonus
        set PlayerFighter[i].lifebase = PlayerFighter[i].lifebase + .HPBonus
            set PlayerFighter[i].life = PlayerFighter[i].life + .HPBonus
    
    endmethod
    
    static method Drop takes integer i returns nothing
        set PlayerFighter[i].inteligence = PlayerFighter[i].inteligence - .IntBonus
            set PlayerFighter[i].mana = PlayerFighter[i].mana - (.IntBonus * MANA_PER_INT)
        set PlayerFighter[i].armor = PlayerFighter[i].armor - .ArmorBonus
        set PlayerFighter[i].lifebase = PlayerFighter[i].lifebase - .HPBonus
            set PlayerFighter[i].life = PlayerFighter[i].life - .HPBonus
    endmethod

endstruct

Then you just have on aquire and on drop triggers to run the methods.

Collapse JASS:
    if GetItemTypeId(Item) == ClothHood.ID then
            call ClothHood.Pickup(i)
    endif

Not the most hardcore of ways to do it, but it's pretty simple and works well!
07-28-2008, 07:53 AM#4
Captain Griffen
TEC_Ghost, that must have the most appalling lack of code reuseability...doing that for more than a couple of items would be...ouch. And it isn't MUI.
07-28-2008, 09:55 AM#5
Ammorth
Thats why you introduce extending structs and define global methods for item-types, but change values and outcomes.
07-28-2008, 03:22 PM#6
Razernok
Why not just store item data(level,bonus, slot id, etc) in a game cache?
Then have functions to set and get that data.
07-28-2008, 07:12 PM#7
Toadcop
Quote:
Why not just store item data(level,bonus, slot id, etc) in a game cache?
Then have functions to set and get that data.
+1 ...

item's don't need to be efficient they must be powerful. (in possibilitys)
07-28-2008, 08:00 PM#8
crayz
I took TEC_Ghost's script, and completely re-wrote it.
Note this is the first time I've done jass scripting, so don't mind any leaks, or anything possibly done inefficient :X

This is how I declare my item bonuses:
Collapse JASS:
function getItemData takes integer i returns nothing
    if ( i == 'ratf' ) then
        set udg_itemData[0] = 50 // Armor Bonus
        set udg_itemData[1] = 50 // Damage Bonus
        set udg_itemData[2] = 60 // Sight Range
        set udg_itemData[3] = 70 // Mana Regeneration
        set udg_itemData[4] = 70 // Health Regeneration
        set udg_itemData[5] = 70 // Strength Bonus
        set udg_itemData[6] = 70 // Agility Bonus
        set udg_itemData[7] = 200 // Intelligence Bonus
        set udg_isItem = true
    endif
    if ( i == 'rej4' ) then
        set udg_itemData[1] = 0
        set udg_itemData[2] = 0
        set udg_itemData[3] = 0
        set udg_itemData[4] = 0
        set udg_itemData[5] = 0
        set udg_itemData[6] = 0
        set udg_itemData[7] = 100
        set udg_isItem = true
    endif

endfunction

TEC_Ghost's base structure, re-written:
Collapse JASS:
struct itemSys

static integer iS_pid = GetConvertedPlayerId(GetOwningPlayer(GetManipulatingUnit()))

    static method Pickup takes nothing returns nothing

    set bj_forLoopAIndex = 0
    set bj_forLoopAIndexEnd = 7
    loop
        exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd

           call findCurBonus()
           call UnitSetBonus(udg_playerHero[itemSys.iS_pid], GetForLoopIndexA(), udg_iS_curBonus[GetForLoopIndexA()] + udg_itemData[GetForLoopIndexA()])
           set udg_iS_curBonus[GetForLoopIndexA()] = udg_iS_curBonus[GetForLoopIndexA()] + udg_itemData[GetForLoopIndexA()]
call DisplayTextToForce( GetPlayersAll(), "Current Bonus: "+I2S(udg_iS_curBonus[GetForLoopIndexA()]) )
        set bj_forLoopAIndex = bj_forLoopAIndex + 1
    endloop
    
    endmethod
    
    static method Drop takes nothing returns nothing

    set bj_forLoopAIndex = 0
    set bj_forLoopAIndexEnd = 7
    loop
        exitwhen bj_forLoopAIndex > bj_forLoopAIndexEnd

           call UnitSetBonus(udg_playerHero[itemSys.iS_pid], GetForLoopIndexA(), udg_iS_curBonus[GetForLoopIndexA()] - udg_itemData[GetForLoopIndexA()])
           set udg_iS_curBonus[GetForLoopIndexA()] = udg_iS_curBonus[GetForLoopIndexA()] - udg_itemData[GetForLoopIndexA()]
        set bj_forLoopAIndex = bj_forLoopAIndex + 1
    endloop

    endmethod

endstruct

Due to the way BonusMod works, I had to include this function:
Collapse JASS:
function findCurBonus takes nothing returns nothing

    if ( GetOwningPlayer(GetManipulatingUnit()) == Player(0) ) then
            set udg_curBonus[GetForLoopIndexA()] = udg_BM_P1[GetForLoopIndexA()]
    endif
    if ( GetOwningPlayer(GetManipulatingUnit()) == Player(1) ) then
            set udg_curBonus[GetForLoopIndexA()] = udg_BM_P2[GetForLoopIndexA()]
    endif
    if ( GetOwningPlayer(GetManipulatingUnit()) == Player(2) ) then
            set udg_curBonus[GetForLoopIndexA()] = udg_BM_P3[GetForLoopIndexA()]
    endif
    if ( GetOwningPlayer(GetManipulatingUnit()) == Player(3) ) then
            set udg_curBonus[GetForLoopIndexA()] = udg_BM_P4[GetForLoopIndexA()]
    endif
    if ( GetOwningPlayer(GetManipulatingUnit()) == Player(4) ) then
            set udg_curBonus[GetForLoopIndexA()] = udg_BM_P5[GetForLoopIndexA()]
    endif
    if ( GetOwningPlayer(GetManipulatingUnit()) == Player(5) ) then
            set udg_curBonus[GetForLoopIndexA()] = udg_BM_P6[GetForLoopIndexA()]
    endif

endfunction

Grab Item:
Collapse JASS:
function Trig_Grab_Item_Actions takes nothing returns nothing

local integer i = GetItemTypeId(GetManipulatedItem())
            call getItemData(i)
     if (udg_isItem == true) then
            call itemSys.Pickup()
            set udg_isItem = false
     endif

endfunction

//===========================================================================
function InitTrig_Grab_Item takes nothing returns nothing
    set gg_trg_Grab_Item = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Grab_Item, EVENT_PLAYER_UNIT_PICKUP_ITEM )
    call TriggerAddAction( gg_trg_Grab_Item, function Trig_Grab_Item_Actions )
endfunction

Drop Item:
Collapse JASS:
function Trig_Drop_Item_Actions takes nothing returns nothing

local integer i = GetItemTypeId(GetManipulatedItem())
            call getItemData(i)
     if (udg_isItem == true) then
            call itemSys.Drop()
            set udg_isItem = false
     endif

endfunction

//===========================================================================
function InitTrig_Drop_Item takes nothing returns nothing
    set gg_trg_Drop_Item = CreateTrigger(  )
    call TriggerRegisterAnyUnitEventBJ( gg_trg_Drop_Item, EVENT_PLAYER_UNIT_DROP_ITEM )
    call TriggerAddAction( gg_trg_Drop_Item, function Trig_Drop_Item_Actions )
endfunction

Any suggestions?
Thanks!

Edit: Fixed a few bugs, made the item drop work properly.
07-29-2008, 12:11 AM#9
TEC_Ghost
Quote:
Originally Posted by Captain Griffen
TEC_Ghost, that must have the most appalling lack of code reuseability...doing that for more than a couple of items would be...ouch. And it isn't MUI.

It is MUI in the sense that the listings only define the base Items properties, dropping and picking up are executed for each unit. The structs aren't made to be attached to a unit, just as an item listing, if you wanted each item to be customizable by the player then it wouldn't be a good idea, but if you want each item to be the same it's fine.

It's not to bad, all the item editing is done right there instead of the object editor which holds only the empty item casing. It's by far not optimized, but it's works :P