models/location.js

import { createCharacter } from "../create_character.js";
import Model from "./model.js";

/**
 * Template for creating location instances. Defines the blueprint for creating location
 * instances, including their properties, sub-divisions, material contents, and behavior patterns.
 *
 * @extends Model
 */
export class LocationTemplate extends Model {
  /**
   * Creates a new LocationTemplate instance.
   *
   * @constructor
   * @param {Object} [params={}] - Configuration parameters
   * @param {String} [params.type] - Unambiguous and unique, human-readable label for the location type. Either `type` or `room` must be provided and they are mutually exclusive.
   * @param {String} [params.room] - If present, supplies the type of the location, and also indicates that is a room, which will not be not included in the list of locations from which you can start to build a top-down representation of a location. Either `type` or `room` must be provided and they are mutually exclusive.
   * @param {String} [params.name=params.type] - The display name of a location. Can contain alternatives in the string form "{A|B}"
   * @param {String[]} [params.tags] - Array of tags to categorize this location template
   * @param {Boolean} [params.abstract=false] - Whether this is an abstract template that cannot be instantiated directly
   * @param {Object} [params.contents] - Contents configuration to create content of this location in the format defined by the `selectElements` function.
   * @param {Object} [params.inventory] - An array of configurations for the inventory of this location, each in the format defined by the `bagSpecParser` function.
   * @param {Array|Object} [params.ch] - The child nodes of this location template, either as an array of types, or as an object in the format defined by the `selectElements` function.
   * @param {String} [params.descr] - Description of the location
   * @param {String} [params.policy] - A free-text description of the sales policies of a store
   * @param {String} [params.owner] - The profession to use when generating an owner of a store
   */
  constructor({
    type,
    name,
    tags = [],
    abstract = false,
    room = false,
    contents = {},
    inventory = {},
    ch = [],
    descr,
    policy,
    owner,
  } = {}) {
    super({ tags });
    this.type = type ?? room;
    this.name = name ?? type ?? room;
    this.room = room;
    this.abstract = abstract;
    this.description = descr;
    this.contents = Object.freeze(contents);
    this.inventory = Object.freeze(inventory);
    this.ch = Object.freeze(ch);
    this.policy = policy;
    this.owner = owner;
  }
}

/**
 * Represents an actual location instance created from a LocationTemplate.
 * Contains the runtime state and hierarchical relationships between locations.
 *
 * @extends Model
 */
export class Location extends Model {
  /**
   * Creates a new Location instance from a template.
   *
   * @constructor
   * @param {LocationTemplate} template - The template to create this location from
   * @param {Location} [parent] - The parent location in the hierarchy
   */
  constructor(template, parent) {
    super({ tags: template.tags });
    this.name = template.name;
    this.seqValue = "";
    this.type = template.type;
    this.description = template.description;
    this.contents = [];
    this.inventory = [];
    this.children = [];
    this.parent = parent;
  }
  /**
   * Adds a child location to this location's hierarchy.
   *
   * @param {Location} child - The child location to add
   * @throws {Error} If the child is not a Location instance
   */
  addChild(child) {
    if (!(child instanceof Location)) {
      throw new Error("Cannot add a template to a location: " + child);
    }
    child.parent = this;
    this.children.push(child);
  }
}

/**
 * Represents a store location with ownership, policies, and commercial properties.
 * Extends Location with store-specific features like owners and business policies.
 *
 * @extends Location
 */
export class Store extends Location {
  /**
   * Creates a new Store instance from a template.
   *
   * @constructor
   * @param {LocationTemplate} template - The template to create this store from
   * @param {Location} [parent] - The parent location in the hierarchy
   */
  constructor(template, parent) {
    super(template, parent);
    this.policy = template.policy;
    this.owner = createCharacter({ profession: template.owner });
  }
}