0
\$\begingroup\$

I'm having trouble figuring out how to spawn more than one item in to a container with a weight limit. What I'm having trouble with is the understanding, rather than what statements to write;

My items are composed of weight, type and foundIn, among other things. My containers are items, with some minor changes. foundIn is an array of strings which match "container" items, and should be either "world", "container-name", or empty ([]). "container" items follow a similar structure, with slight deviance.


Whenever I want to drop an item, I get a pool of items in a foundIn location, make a Math.random check against the commonRate, and if that item is a type = "container", I try to fill the container.

Here is where I have my problem; I can not figure out how to decide if multiple items of the same type should be dropped inside the container, and if so, how many. If I can figure this out, I can have monsters carry their own drops, instead of having to write a whole monster drop-table with levels and oddities.


The following is my code. The last method, dropItem, glues the displayed methods together.

placeExists(place) {
    return this._itemPlaces.indexOf(place) > -1;
}

getItemsOfType(arrayOfTypes, inList) {
    if (!Array.isArray(arrayOfTypes)) throw new Error('Index must be string');
    let pool = this.list;
    if (inList) pool = inList;

    return pool.map((item => {
        if (arrayOfTypes.indexOf(item.type) > -1) {
            return item;
        }
    }));

}

populateContainer(container, pool) {
    let chance = Math.random();
    pool = pool.map(item => {
        let canBeFound = item.foundIn.indexOf(container.name) > -1 
                || item.foundIn.indexOf('world') > -1;
        if (item.commonRate >= chance && canBeFound) return item;
    });

    this.getItemsOfType(container.availableTypePool, pool).some(item => {
        if (container.capacity.freeSpace <= 0) return true;
        if (item.commonRate >= Math.random() 
                && item.weight <= container.capacity.freeSpace) {
            container.addItem(item);
        }
    });

    return container;
}

getItemsOfPlace(place) {
    return this._LIST.map(item => {
        if (item.isFoundIn(place)) {
            return item;
        }
    })
}

dropItem(fromPlace) {
    if (this.placeExists(fromPlace)) return [];
    let foundItem = [];

    let pool = this.getItemsOfPlace(fromPlace);
    pool.some(item => {
        let chance = Math.random();
        if (chance > item.commonRate) {
            if (item.type == 'container') 
                foundItem.push(this.populateContainer(item, pool));
            else 
                foundItem.push(item);
            return true;
        }
    });

    return foundItem;
}


// container abstracted method of adding an item

container.addItem = (item = new Item()) {
    if (item instanceof Item === false) throw Error('item needs to be of type Item');
    if (item.type == 'container') throw Error('Yo dawg, I heard you like containers...');

    this._contained.push(item.code);
    this.carryingWeight = +item.weight;
}

How do I decide if I should drop multiple items, and how do I randomly select that amount?

Note that this.list and this._LIST are the same list. For some reason, WebStorm seems to lose track of one or the other when inside certain callbacks, so I switch to avoid losing autocomplete. For reference, this.list is get list() { return this._LIST }, and is obtained from extending a custom List class.

\$\endgroup\$
0
\$\begingroup\$

I wasn't thinking correctly: The action of the user should control how much items can fall (so we can later apply modifiers to this value without having to change how the Item class works) not the place where the user picks the item from. as such, now an Item has dropInfo = { chance: 0~1, maxQty: 0, dropsFrom: [''] };

Whenever I want to drop an item I all dropEvent with "item", "variety" and "modifier" as its arguments, for the "how much" the maxQty is used (with a modifier) - this also controls how much of this item can be bundled together.

dropEvent(fromPlace, variety, modifier) {
    let dropped = [];
    this.byDropPlace(fromPlace).some((item = new Item()) => {
        if (variety === 0) return true;
        if (variety > 0) variety--;
        if (item.drop.tryDrop) {
            let quantity = Math.floor(Math.random() * (item.drop.maxQty + modifier) + 1);
            dropped.push(this.makeBundleReference(item, quantity))
        }
    });
    return dropped;
}

A bunldeReference is a reference to the item, containing the item name, code, description and weight for basic informational proposes.

I still have to figure out a way of not following a ordered list, so I can avoid the first items getting to drop more often than the last items of the list - but dropEvent solves the original question.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.