core/item.js

import { Piece } from "./piece.js";

/**
 * Base class for all item types.
 *
 * Items can be picked up, carried, used, thrown, and fired. They do not block
 * movement into a cell. All callbacks are no-ops by default.
 */
export class Item extends Piece {
  /**
   * The player is about to throw this item.
   * Cancel event to prevent the throw.
   * @param {GameEvent} event
   * @param {Cell} cell - player's current cell
   */
  onThrow(event, cell) {}

  /**
   * The player is firing this item (ranged weapon).
   * Return the ammunition piece to launch, or null if unable to fire.
   * Cancel event to abort firing.
   * @param {GameEvent} event
   * @returns {Item|null}
   */
  onFire(event) {
    return null;
  }

  /**
   * This item has struck an agent (thrown or wielded).
   * @param {GameEvent} event
   * @param {Cell} agentLoc
   * @param {Agent} agent
   */
  onHit(event, agentLoc, agent) {}

  /**
   * This item, having been thrown, has landed at the given cell.
   * Cancel event to make the item disappear instead of landing.
   */
  onThrowEnd(event, cell) {}

  /**
   * The player used this item without specifying a direction.
   * Cancel event with a message if the item requires a direction.
   */
  onUse(event) {}

  /**
   * This item is about to be dropped.
   * Cancel event to prevent the drop.
   */
  onDrop(event, cell) {}

  /**
   * This item was selected in the player's inventory.
   */
  onSelect(event, cell) {}

  /**
   * This item is about to be deselected.
   * Cancel event to prevent deselection.
   */
  onDeselect(event, cell) {}

  /**
   * An agent has stepped onto the same cell as this item.
   */
  onSteppedOn(event, agentLoc, agent) {}

  /**
   * Return a phrase with the item name using a definite article (e.g., "the sword").
   * @param {string} phrase - template string with {0} placeholder
   */
  getDefiniteNoun(phrase) {
    return phrase.replace("{0}", `the ${this.name}`);
  }

  /**
   * Return a phrase with the item name using an indefinite article (e.g., "a sword").
   * @param {string} phrase - template string with {0} placeholder
   */
  getIndefiniteNoun(phrase) {
    const article = /^[aeiou]/i.test(this.name) ? "an" : "a";
    return phrase.replace("{0}", `${article} ${this.name}`);
  }
}