import { createItem } from "./create_item.js";
import { logger } from "./utils.js";
import { roll, test } from "./random_utils.js";
import Bag from "./models/bag.js";
/**
* Creates a collection of objects, held in a collection type known as a Bag.
*
* @param [params] {Object}
* @param [params.value=10] {Number | String} the total value of items to add to the bag.
* The method will get as close to this value as possible, but may go over. If the
* value is a string, it is treated as dice notation.
* @param [params.repeat=20] {Number} This is the percentage chance that the last item
* selected will be added again. Can range from 0% (no repeated items) to 100% (only
* one item, as many as are needed to reach the other specified limits).
* @param [params.count=Number.MAX_VALUE] {Number} affects how many items will be added to
* the bag. The bag will not exceed this number of items.
* @param [params.enc=Number.MAX_VALUE] {Number} the maximum encumbrance of the bag.
* The method will get as close to this value as possible, but may go over.
* @param [params.uncountable=false] {Boolean} if true, items in the bag are treated as
* uncountable.
* @param [params.minValue=0] {Number} the minimum value of any items added to the bag (for
* some applications, like store stock, it is desirable to set this number above 0).
* @param [params.tags="*"] {String} tags that will be used to search for items to add to the bag.
* @param [params.name] {String} a name for the bag.
* @param [params.description] {String} a description for the bag.
* @param [params.condition] {String} if the item selected has the “br” tag and thus has
* condition, you can fix it’s condition by passing it in to this method.
*
* @example
* createBag({ count: 3, tags: "house"}).toString()
* => "A television (5/20), a winter jacket (worn; 0.5/10), and a ceramic bowl (3/1)."
*
* @returns {Bag} a bag containing items that meet the specified criteria
*/
export function createBag({
value = 10,
repeat = 5,
enc = Number.MAX_VALUE,
count = Number.MAX_VALUE,
uncountable = false,
minValue = 0,
tags = "*",
name,
description,
condition,
} = {}) {
if (typeof value === "string") {
value = roll(value);
}
logger.start("createBag", {
tags,
value,
repeat,
enc,
count,
uncountable,
name,
description,
condition,
});
const bag = new Bag({ uncountable, name, description });
const visitedItems = new Set();
let currentValue = value;
let currentEnc = enc;
let currentCount = count;
let item = null;
outer: while (currentValue > 0 && currentEnc > 0 && currentCount > 0) {
if (!test(repeat) || item === null) {
let safetyLoops = count === Number.MAX_VALUE ? 200 : count * 50;
do {
item = createItem({
tags,
minValue,
maxEnc: currentEnc,
maxValue: currentValue,
condition,
});
if (item == null) {
break outer; // criteria no longer match
}
} while (visitedItems.has(item.name + item.title) && safetyLoops-- > 0);
}
if (item !== null) {
visitedItems.add(item.name + item.title);
bag.add(item);
currentCount--;
// if item.value == 0 (or enc), decrement by a random value or you'll get as many
// items as there are safety loops (unless count or enc is set).
currentValue -= item.value || roll(5);
currentEnc -= item.enc || roll(5);
}
}
return logger.end(bag);
}