mbkarle / mind-the-fog

Roguelike JavaScript game--mind the fog!
2 stars 1 forks source link

Inventory Refactor #119

Closed akarle closed 6 years ago

akarle commented 6 years ago

What if we consider any collection of items an "inventory", one that can be interacted with. Inventories that the hero can take items from include:

1) mob drops (a "one shot" inventory) 2) chest (a "one shot" inventory) 3) the dog (a "permanent" inventory)

All of these inventories will have the same code for populating the HTML (currently theres a good bit of duplicate code between mob drop items and openChest, etc). This makes sense, as the hero interaction of taking items is the same.

A HeroInventory is different, as we concern ourselves with what is equipped/carried, etc. Also the look is different.

akarle commented 6 years ago

Schema schemin:


class inventory {
    constructor(items)
          //list of items in inv
          this.items = items

    transfer_item(target_inv)
           //splice and add to other inv

    isEmpty()
}

class HeroInv extends Inv
akarle commented 6 years ago

Planning Notes

User Stories

Users

  1. random mob drops
  2. custom combat drops
  3. Chest
  4. hero inventory
  5. dog inventory (future)

Current User Stories

  1. Currently mobs only drop one item from the mobDrops item list. 1.1 The mob is assigned a random index from mobDrops 1.2 Upon defeat, there is a certain chance the mob will drop it! 1.3 Custom function is used to display the items exactly the same as chest (Pain Point)

  2. Custom combat mobs only drop one custom weapon, and it is consistent 2.1 Instantiated with their own custom weapon 2.2 Upon defeat, 100% chance of getting weapon 2.3 Same custom function as 1.3 used to display like a chest (Pain Point)

  3. Chest is a random selection of items given upon initialization 3.1 Chests are created at random in Room.js's makeNormalRoom() 3.2 Upon initialization, they are given an itemList to choose from and then are filled using their own chest.fillChest function. Filling essentially picks the items from the list to put in the chest 3.3 When interacted with, a complicated hero_interact function (Pain Point) runs and runs a similar drop_items function as 1.3 (Pain Point).

  4. Hero inventory is just a JSON object 4.1 take_item is currently used to push an item into the proper spot in hero inventory. 4.2 take_item removes items from chests! (Pain Point). This should not happen! (make separate "remove item" function, as adding a check for mobs and custom mobs and dogs, etc into take_item is not appropriate!

Proposed Workflows

  1. Mobs 1.1 Add inv property and add generateInv() function to Enemy so that upon entering combat, we simply pick an enemy and generate a new inventory. This function should create a new Inventory([item1, item2,...]) where the list of items given is simply the items picked at random from mobDrops 1.2 Upon defeating the enemy, chance of drop. This will activate txtmd.showInventory(target.inv) which will show and allow the hero to collect from the mob

  2. Custom combat: Same as mobs

  3. Chests 3.1 Add inv property and make fillChest create a new Inventory() which fills from the itemList already given to chest 3.2 Use txtmd to display the inventory

  4. Hero 4.1 Create a custom inventory for the hero which extends the general inventory OR Make "carried" and "equipped" two inventory's! but carried must have different constraints (special subclass?)

  5. Dog 5.1 Dog should have its own inventory with a capacity (set by dog trainer) 5.2 Hero should be allowed to transfer to & from dog using inventory functions

Why?

  1. Standardize code: no need to have mobs and chests and dog and all that use different functions to display items!
  2. Organize code: By putting collections of items into inventories, we can allow for high level functions that involve the interactions between inventories (transfer, display, etc). The only way to ensure these functions is to standardize the inventories themselves

Requirements

Classes:

  1. Inventory 1.1 Should allow duplicate items 1.2 Planned implementation as a JSON object with unique itemID's 1.3 itemID's planned to be ITEMCONSTRUCTOR_i where i is for the i'th occurence in the inv.

Functions

  1. Inventory 1.1 Transfer itemID from source -> target inventory (will need to re-id)

  2. TextModule 1.1 Display Inventory view: ex:

    {
    "msgs":
    ["trans", "You've defeated the monster!"], 
    ["inv", target.inv]
    }
  3. Enemy 3.1 genInv to generate inventory from mobDrops (or other given list)

  4. HeroInventoryModule 4.1 Need to change refreshInventoryHTML: simply change the "carried" / "equipped" sections to be displays of the items in the hero's inventory

akarle commented 6 years ago

As of 4b39459058e29085bce2df8efb76219a6c3e0578 the enemys, bosses, chests, and hero all have functioning inventorys...

The next big issue is that I need a standardized way to display these inventorys. As of the commit, only the inventorys displayed in the text module (chests/mobs/bosses) have working visual representations, and as such their working transfer to the hero inventory does nothing to actually change the hero's visualized inventory.

Need for a Unified Visualization

Inventories Visualized

The following are all inventories if we take the loose definition of an inventory being a collection of items we transfer between.

  1. Mob drops / Boss drops --> in text mod
  2. Chests --> in text mod
  3. Hero --> in info mod
  4. Dog (future) --> in text mod? separate mod? need to give/take (future work)
  5. Merchant --> vendor mod
  6. NPC --> vendor mod

Problem: They all should have similar displays of the inventory (a div for each item, a button for an action, a hover info)

Solution: Create a modular standardized function (or set of functions) to visualize any inventory within any module (text mod, vendor mod, dog mod, info mod).

Plans

All items (non torch/gold) should have some kind of display like so:

-------------------------------------------------------------------------------------
| |x (drop btn)|                      item name                     | function btn| |
-------------------------------------------------------------------------------------

Where:

Schema

  1. Any module that is visualizing an inventory must pass certain information about its html elements to be populated (specifically their ids). This can be passed as a JSON object:

    var mod_ids = {
    "hoverID": "txtmd_hover",
    "textBoxID": "txtmd_textBox",
    "uniqueID": "txtmd" // for drop btn, item div, and cb btn id's
    }
  2. The module must also pass in whether or not it wants drop buttons, and what the text of the cb button and the cb called by the cb button should be:

    var mod_cbs = {
    "drop_cb": inv.remove(id), //dont add it no drop
    "cb_txt": "Equip",
    "cb": inv.equip(id),
    "consumable_cb_txt": "Use", //separate for consumables if desire separate cb
    "consumable_cb": useConsumable(id)
    }
  3. Using these two objects, the inv.generateHTML(mod_ids, mod_cbs) function should in turn generate the inner html to show (with proper IDs and labels such that CSS styling works as intended) AND return a function that will set the click listeners appropriately (they cannot be set until inner html is created I believe).

    function generateHTML(mod_ids, mod_cbs) {
     // gen html
    ...
    // gen onclick function
    var onclick = function() { ... }
    // return
    return {"innerhtml": html, "setClicks": onclick}
    }
  4. Lastly, any module that wants to display an inventory can take that returned object and display the inner html and then call the onclick. In this way, each module can have their own showInventory function and actually perform the showing, but the Inventory.generateHTML function is the one that does all the lifting in the setup. For example:

    (TextMod class...)
    ...
    showInventory(inv){
    var mod_ids = {
        "hoverID": "txtmd_hover",
        "textBoxID": "txtmd_textBox",
        "uniqueID": "txtmd_" // for drop btn, item div, and cb btn id's
    }
    var mod_cbs = {
        "cb_txt": "Take",
        "cb": transfer_item(hero.inv, id),
        // no consumable or drop stuff...
    }
    
    invhtmlobj = inv.generateHTML()
    
    //show the html first
    this.setTextBox(invhtmlobj["innerhtml"])
    
    //then set callbacks
    invhtmlobj["setClicks"]()
    
    //set close btn etc... (non inventory related/specific to this mod)
    ....
    }
akarle commented 6 years ago

Fixed by #128