import * as _ from "lodash" ; import { GetDEBUG } from "../app" ; import { Encounter } from "./combat" ; import { Entity } from "./entity" ; import { GAME } from "./GAME" ; import { Gui } from "./gui" ; import { compareItemByProp , IItemQuantity , Item , ItemIds , ItemSubtype , ItemType } from "./item" ; import { CombatItem } from "./items/combatitems" ; import { ItemToy } from "./items/toy-item" ; import { IChoice } from "./link" ; import { Text } from "./text" ; export class Inventory { public static ItemByType ( inv , itemsByType ? , usableItemsByType ? , combatItemsByType ? ) { _ . forIn ( ItemType , ( value , key ) => { if ( itemsByType ) { itemsByType [ value ] = [ ] ; } if ( usableItemsByType ) { usableItemsByType [ value ] = [ ] ; } if ( combatItemsByType ) { combatItemsByType [ value ] = [ ] ; } } ) ; for ( const item of inv ) { const it = item . it ; if ( itemsByType ) { itemsByType [ it . type ] . push ( item ) ; } if ( usableItemsByType && it . Use ) { usableItemsByType [ it . type ] . push ( item ) ; } const itC = it as CombatItem ; if ( combatItemsByType && itC . combat ) { combatItemsByType [ it . type ] . push ( item ) ; } } _ . forIn ( ItemType , ( value , key ) => { if ( itemsByType && itemsByType [ value ] . length === 0 ) { delete itemsByType [ value ] ; } if ( usableItemsByType && usableItemsByType [ value ] . length === 0 ) { delete usableItemsByType [ value ] ; } if ( combatItemsByType && combatItemsByType [ value ] . length === 0 ) { delete combatItemsByType [ value ] ; } } ) ; } public static ItemByBothTypes ( inv , itemsByType = { } , usableItemsByType ? , combatItemsByType ? ) { _ . forIn ( ItemType , ( value , key ) => { if ( itemsByType ) { itemsByType [ value ] = { } ; } if ( usableItemsByType ) { usableItemsByType [ value ] = { } ; } if ( combatItemsByType ) { combatItemsByType [ value ] = { } ; } _ . forIn ( ItemSubtype , ( value2 , key2 ) => { if ( itemsByType ) { itemsByType [ value ] [ value2 ] = [ ] ; } if ( usableItemsByType ) { usableItemsByType [ value ] [ value2 ] = [ ] ; } if ( combatItemsByType ) { combatItemsByType [ value ] [ value2 ] = [ ] ; } } ) ; } ) ; for ( const item of inv ) { const it = item . it as CombatItem ; if ( itemsByType ) { itemsByType [ it . type ] [ it . subtype ] . push ( item ) ; } if ( usableItemsByType && it . Use ) { usableItemsByType [ it . type ] [ it . subtype ] . push ( item ) ; } if ( combatItemsByType && it . combat ) { combatItemsByType [ it . type ] [ it . subtype ] . push ( item ) ; } } _ . forIn ( ItemType , ( itType , key ) => { const items = itemsByType [ itType ] ; _ . forIn ( ItemSubtype , ( subType , key2 ) => { if ( itemsByType && items [ subType ] . length === 0 ) { delete items [ subType ] ; } if ( usableItemsByType && usableItemsByType [ itType ] [ subType ] . length === 0 ) { delete usableItemsByType [ itType ] [ subType ] ; } if ( combatItemsByType && combatItemsByType [ itType ] [ subType ] . length === 0 ) { delete combatItemsByType [ itType ] [ subType ] ; } } ) ; if ( itemsByType && _ . keys ( items ) . length === 0 ) { delete itemsByType [ itType ] ; } if ( usableItemsByType && _ . keys ( usableItemsByType [ itType ] ) . length === 0 ) { delete usableItemsByType [ itType ] ; } if ( combatItemsByType && _ . keys ( combatItemsByType [ itType ] ) . length === 0 ) { delete combatItemsByType [ itType ] ; } } ) ; } public items : IItemQuantity [ ] ; constructor ( ) { this . items = [ ] ; } public ToStorage ( ) { const storage = [ ] ; _ . each ( this . items , ( item ) => { storage . push ( { it : item . it . id , num : item . num , } ) ; } ) ; return storage ; } public FromStorage ( storage ) { const list = [ ] ; _ . each ( storage , ( s ) => { const item = { it : ItemIds [ s . it ] , num : parseInt ( s . num , 10 ) , } ; if ( item . it ) { list . push ( item ) ; } } ) ; this . items = list ; } public QueryNum ( item ) { for ( const it of this . items ) { if ( it . it === item ) { return it . num ; } } return undefined ; } public AddItem ( item , num = 1 ) { if ( GetDEBUG ( ) ) { Text . NL ( ) ; Text . Add ( `DEBUG: Added ${ num } ${ item . name } (ID: ${ item . id })` , undefined , "bold" ) ; Text . NL ( ) ; Text . Flush ( ) ; } for ( const it of this . items ) { if ( it . it === item ) { it . num += num ; return ; } } this . items . push ( { it : item , num } ) ; } public RemoveItem ( item , num = 1 ) { if ( GetDEBUG ( ) ) { Text . NL ( ) ; Text . Add ( `DEBUG: Removed ${ num } ${ item . name } (ID: ${ item . id })` , undefined , "bold" ) ; Text . NL ( ) ; Text . Flush ( ) ; } let i = 0 ; for ( const it of this . items ) { if ( it . it === item ) { it . num -= num ; if ( it . num <= 0 ) { this . items . splice ( i , 1 ) ; } return ; } i ++ ; } } public Print ( ) { for ( const item of this . items ) { Text . Add ( item . num + "x " + item . it . name + " - " + item . it . Short ( ) + "<br>" ) ; } Text . Flush ( ) ; } public ShowInventory ( SetExploreButtons , preventClear ? ) { const inv = this ; inv . items . sort ( compareItemByProp ( "name" ) ) ; const backPrompt = ( ) => { inv . ShowInventory ( SetExploreButtons ) ; } ; if ( ! preventClear ) { Text . Clear ( ) ; } const itemsByType = { } ; const usableItemsByType = { } ; Inventory . ItemByBothTypes ( this . items , itemsByType , usableItemsByType ) ; for ( const typeKey of _ . keys ( itemsByType ) ) { Text . AddDiv ( "<hr>" ) ; Text . AddDiv ( typeKey , undefined , "itemTypeHeader" ) ; Text . AddDiv ( "<hr>" ) ; for ( const subtypeKey of _ . keys ( itemsByType [ typeKey ] ) ) { if ( subtypeKey !== ItemSubtype . None ) { Text . AddDiv ( subtypeKey , undefined , "itemSubtypeHeader" ) ; } const items = itemsByType [ typeKey ] [ subtypeKey ] ; if ( items ) { for ( const item of items ) { Text . AddDiv ( item . it . name + " x" + item . num , undefined , "itemName" ) ; } } } Text . NL ( ) ; } let usable = [ ] ; for ( const key of _ . keys ( usableItemsByType ) ) { for ( const subtypeKey of _ . keys ( usableItemsByType [ key ] ) ) { const items = usableItemsByType [ key ] [ subtypeKey ] ; if ( items ) { usable = usable . concat ( items ) ; } } } const options = [ ] ; for ( const u of usable ) { const it = u . it ; const num = u . num ; options . push ( { nameStr : it . name + " x" + num , enabled : true , obj : it , func ( item ) { Text . Clear ( ) ; Text . Add ( item . Long ( ) ) ; Text . NL ( ) ; Text . Add ( "Use [it] on which partymember?" , { it : item . name } ) ; Text . Flush ( ) ; const target = new Array ( ) ; _ . each ( GAME ( ) . party . members , ( t ) => { target . push ( { nameStr : t . name , func ( t ) { Text . Clear ( ) ; const use = t . ItemUse ( item , backPrompt ) ; if ( use . grab ) { if ( use . consume ) { inv . RemoveItem ( item ) ; } } else { if ( item . Use ( t ) . consume ) { inv . RemoveItem ( item ) ; } Gui . NextPrompt ( backPrompt ) ; } Text . Flush ( ) ; } , enabled : t . ItemUsable ( item ) , obj : t , } ) ; } ) ; Gui . SetButtonsFromList ( target , true , backPrompt ) ; } , } ) ; } Gui . SetButtonsFromList ( options ) ; if ( this . items . length === 0 ) { Text . Add ( "You are not carrying anything at the moment." ) ; } Text . Flush ( ) ; SetExploreButtons ( ) ; } public CombatInventory ( encounter , entity , back ? ) { const inv = this ; Text . Clear ( ) ; const backPrompt = ( ) => { inv . CombatInventory ( encounter , entity , back ) ; } ; const combatItemsByType = { } ; Inventory . ItemByBothTypes ( this . items , undefined , undefined , combatItemsByType ) ; let usable = [ ] ; for ( const key of _ . keys ( combatItemsByType ) ) { for ( const subtypeKey of _ . keys ( combatItemsByType [ key ] ) ) { const items = combatItemsByType [ key ] [ subtypeKey ] ; if ( items ) { usable = usable . concat ( items ) ; } } } for ( const typeKey of _ . keys ( combatItemsByType ) ) { Text . AddDiv ( "<hr>" ) ; Text . AddDiv ( typeKey , undefined , "itemTypeHeader" ) ; Text . AddDiv ( "<hr>" ) ; for ( const subtypeKey of _ . keys ( combatItemsByType [ typeKey ] ) ) { if ( subtypeKey !== ItemSubtype . None ) { Text . AddDiv ( subtypeKey , undefined , "itemSubtypeHeader" ) ; } const items = combatItemsByType [ typeKey ] [ subtypeKey ] ; if ( items ) { for ( const item of items ) { Text . AddDiv ( item . it . name + " x" + item . num , undefined , "itemName" ) ; } } } Text . NL ( ) ; } const options = [ ] ; for ( const u of usable ) { const it = u . it ; const num = u . num ; options . push ( { nameStr : it . name , enabled : it . combat ? it . combat . enabledCondition ( encounter , entity ) : true , obj : it , func ( item ) { if ( item . combat . OnSelect ( encounter , entity , backPrompt , inv ) ) { Text . Clear ( ) ; Text . Add ( item . Long ( ) ) ; Text . NL ( ) ; Text . Add ( "Use [it] on whom?" , { it : item . name } ) ; Text . Flush ( ) ; } } , } ) ; } Gui . SetButtonsFromList ( options , true , back ) ; if ( options . length === 0 ) { Text . Add ( "You are not carrying any items usable in combat at the moment." ) ; } Text . Flush ( ) ; } public ShowEquippable ( entity , type , backPrompt ? ) { const inv = this ; const items = [ ] ; _ . each ( this . items , ( it ) => { const item = it . it ; switch ( type ) { case ItemType . Weapon : if ( item . type === ItemType . Weapon ) { items . push ( item ) ; } break ; case ItemSubtype . TopArmor : if ( item . subtype === ItemSubtype . TopArmor ) { items . push ( item ) ; } else if ( item . subtype === ItemSubtype . FullArmor ) { items . push ( item ) ; } break ; case ItemSubtype . BotArmor : if ( item . subtype === ItemSubtype . BotArmor ) { items . push ( item ) ; } break ; case ItemSubtype . Acc1 : case ItemSubtype . Acc2 : if ( item . type === ItemType . Accessory ) { items . push ( item ) ; } break ; case ItemSubtype . StrapOn : if ( item . subtype === ItemSubtype . StrapOn ) { items . push ( item ) ; } break ; } } ) ; let hasEquip = false ; switch ( type ) { case ItemType . Weapon : if ( entity . weaponSlot ) { hasEquip = true ; } break ; case ItemSubtype . TopArmor : if ( entity . topArmorSlot ) { hasEquip = true ; } break ; case ItemSubtype . BotArmor : if ( entity . botArmorSlot ) { hasEquip = true ; } break ; case ItemSubtype . Acc1 : if ( entity . acc1Slot ) { hasEquip = true ; } break ; case ItemSubtype . Acc2 : if ( entity . acc2Slot ) { hasEquip = true ; } break ; case ItemSubtype . StrapOn : if ( entity . strapOn ) { hasEquip = true ; } break ; } const list = [ ] ; list . push ( { nameStr : "Dequip" , func ( ) { switch ( type ) { case ItemType . Weapon : if ( entity . weaponSlot ) { inv . AddItem ( entity . weaponSlot ) ; } entity . weaponSlot = undefined ; break ; case ItemSubtype . TopArmor : if ( entity . topArmorSlot ) { inv . AddItem ( entity . topArmorSlot ) ; } entity . topArmorSlot = undefined ; break ; case ItemSubtype . BotArmor : if ( entity . botArmorSlot ) { inv . AddItem ( entity . botArmorSlot ) ; } entity . botArmorSlot = undefined ; break ; case ItemSubtype . Acc1 : if ( entity . acc1Slot ) { inv . AddItem ( entity . acc1Slot ) ; } entity . acc1Slot = undefined ; break ; case ItemSubtype . Acc2 : if ( entity . acc2Slot ) { inv . AddItem ( entity . acc2Slot ) ; } entity . acc2Slot = undefined ; break ; case ItemSubtype . StrapOn : if ( entity . strapOn ) { inv . AddItem ( entity . strapOn ) ; } entity . strapOn = undefined ; break ; } entity . Equip ( ) ; backPrompt ( ) ; } , enabled : hasEquip , } ) ; _ . each ( items , ( it ) => { it . ShowEquipStats ( ) ; Text . AddDiv ( "<hr>" ) ; list . push ( { nameStr : it . name , func ( t ) { inv . RemoveItem ( t ) ; const switchType = ( t . subtype !== ItemSubtype . None ) ? t . subtype : t . type ; switch ( switchType ) { case ItemType . Weapon : if ( entity . weaponSlot ) { inv . AddItem ( entity . weaponSlot ) ; } entity . weaponSlot = t ; break ; case ItemSubtype . FullArmor : if ( entity . topArmorSlot ) { inv . AddItem ( entity . topArmorSlot ) ; } if ( entity . botArmorSlot ) { inv . AddItem ( entity . botArmorSlot ) ; } entity . topArmorSlot = t ; entity . botArmorSlot = undefined ; break ; case ItemSubtype . TopArmor : if ( entity . topArmorSlot ) { inv . AddItem ( entity . topArmorSlot ) ; } entity . topArmorSlot = t ; break ; case ItemSubtype . BotArmor : if ( entity . botArmorSlot ) { inv . AddItem ( entity . botArmorSlot ) ; } entity . botArmorSlot = t ; break ; case ItemType . Accessory : if ( type === ItemSubtype . Acc1 ) { if ( entity . acc1Slot ) { inv . AddItem ( entity . acc1Slot ) ; } entity . acc1Slot = t ; } else if ( type === ItemSubtype . Acc2 ) { if ( entity . acc2Slot ) { inv . AddItem ( entity . acc2Slot ) ; } entity . acc2Slot = t ; } break ; case ItemSubtype . StrapOn : if ( entity . strapOn ) { inv . AddItem ( entity . strapOn ) ; } entity . strapOn = t as ItemToy ; break ; } entity . Equip ( ) ; backPrompt ( ) ; } , enabled : true , obj : it , tooltip : it . Long ( ) , } ) ; } ) ; Text . Flush ( ) ; Gui . SetButtonsFromList ( list , true , backPrompt ) ; } }