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.
*
* @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 = 20,
enc = Number.MAX_VALUE,
count = Number.MAX_VALUE,
uncountable = false,
minValue = 0,
tags = "*",
} = {}) {
if (typeof value === "string") {
value = roll(value);
}
logger.start("createBag", { tags, value, repeat, enc, count, uncountable });
const bag = new Bag({ uncountable });
const visitedItems = new Map();
let currentValue = value;
let currentEnc = enc;
let currentCount = count;
let safetyLoops = count === Number.MAX_VALUE ? 70 : count * 10;
let item = null;
outer: while (currentValue > 0 && currentEnc > 0 && currentCount > 0 && safetyLoops-- > 0) {
if (!test(repeat) || item === null) {
do {
item = createItem({ tags, minValue, maxEnc: currentEnc, maxValue: currentValue });
if (item == null) {
break outer; // criteria no longer match
}
} while (visitedItems.get(item.name) && safetyLoops-- > 0);
}
if (item !== null) {
visitedItems.set(item.name, true);
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);
}