Back to Browser Side Quest
SOURCE / PINNED RELEASE

Made of little things.

Browser Side Quest

Release
b9d42f5768e4…
Author-recorded commit
c267690145fa…
License
LICENSE
Author’s source reference
nostr://npub1ye5ptcxfyyxl5vjvdjar2ua3f0hynkjzpx552mu5snj3qmx5pzjscpknpr/wss%3A%2F%2Fgit.shakespeare.diy%2F/browser-side-quest

Archive hash verified: 6d4b90b8a5f328f7…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

src/shared/gametypes.ts
// Port of BrowserQuest shared/js/gametypes.js (MPL-2.0, Little Workshop / Mozilla).
// Message numbers and entity kinds are kept identical to the original protocol.

export const Messages = {
  HELLO: 0,
  WELCOME: 1,
  SPAWN: 2,
  DESPAWN: 3,
  MOVE: 4,
  LOOTMOVE: 5,
  AGGRO: 6,
  ATTACK: 7,
  HIT: 8,
  HURT: 9,
  HEALTH: 10,
  CHAT: 11,
  LOOT: 12,
  EQUIP: 13,
  DROP: 14,
  TELEPORT: 15,
  DAMAGE: 16,
  POPULATION: 17,
  KILL: 18,
  LIST: 19,
  WHO: 20,
  ZONE: 21,
  DESTROY: 22,
  HP: 23,
  BLINK: 24,
  OPEN: 25,
  CHECK: 26,
  // Port extension (world → client only): [PLAYERINFO, playerId, nostrPubkeyHex].
  PLAYERINFO: 27,
} as const;

export const Entities = {
  WARRIOR: 1,

  // Mobs
  RAT: 2,
  SKELETON: 3,
  GOBLIN: 4,
  OGRE: 5,
  SPECTRE: 6,
  CRAB: 7,
  BAT: 8,
  WIZARD: 9,
  EYE: 10,
  SNAKE: 11,
  SKELETON2: 12,
  BOSS: 13,
  DEATHKNIGHT: 14,

  // Armors
  FIREFOX: 20,
  CLOTHARMOR: 21,
  LEATHERARMOR: 22,
  MAILARMOR: 23,
  PLATEARMOR: 24,
  REDARMOR: 25,
  GOLDENARMOR: 26,

  // Objects
  FLASK: 35,
  BURGER: 36,
  CHEST: 37,
  FIREPOTION: 38,
  CAKE: 39,

  // NPCs
  GUARD: 40,
  KING: 41,
  OCTOCAT: 42,
  VILLAGEGIRL: 43,
  VILLAGER: 44,
  PRIEST: 45,
  SCIENTIST: 46,
  AGENT: 47,
  RICK: 48,
  NYAN: 49,
  SORCERER: 50,
  BEACHNPC: 51,
  FORESTNPC: 52,
  DESERTNPC: 53,
  LAVANPC: 54,
  CODER: 55,

  // Weapons
  SWORD1: 60,
  SWORD2: 61,
  REDSWORD: 62,
  GOLDENSWORD: 63,
  MORNINGSTAR: 64,
  AXE: 65,
  BLUESWORD: 66,
} as const;

export const Orientations = {
  UP: 1,
  DOWN: 2,
  LEFT: 3,
  RIGHT: 4,
} as const;

export type Orientation = (typeof Orientations)[keyof typeof Orientations];
export type KindType = 'player' | 'mob' | 'weapon' | 'armor' | 'object' | 'npc';

const kinds: Record<string, [number, KindType]> = {
  warrior: [Entities.WARRIOR, 'player'],

  rat: [Entities.RAT, 'mob'],
  skeleton: [Entities.SKELETON, 'mob'],
  goblin: [Entities.GOBLIN, 'mob'],
  ogre: [Entities.OGRE, 'mob'],
  spectre: [Entities.SPECTRE, 'mob'],
  deathknight: [Entities.DEATHKNIGHT, 'mob'],
  crab: [Entities.CRAB, 'mob'],
  snake: [Entities.SNAKE, 'mob'],
  bat: [Entities.BAT, 'mob'],
  wizard: [Entities.WIZARD, 'mob'],
  eye: [Entities.EYE, 'mob'],
  skeleton2: [Entities.SKELETON2, 'mob'],
  boss: [Entities.BOSS, 'mob'],

  sword1: [Entities.SWORD1, 'weapon'],
  sword2: [Entities.SWORD2, 'weapon'],
  axe: [Entities.AXE, 'weapon'],
  redsword: [Entities.REDSWORD, 'weapon'],
  bluesword: [Entities.BLUESWORD, 'weapon'],
  goldensword: [Entities.GOLDENSWORD, 'weapon'],
  morningstar: [Entities.MORNINGSTAR, 'weapon'],

  firefox: [Entities.FIREFOX, 'armor'],
  clotharmor: [Entities.CLOTHARMOR, 'armor'],
  leatherarmor: [Entities.LEATHERARMOR, 'armor'],
  mailarmor: [Entities.MAILARMOR, 'armor'],
  platearmor: [Entities.PLATEARMOR, 'armor'],
  redarmor: [Entities.REDARMOR, 'armor'],
  goldenarmor: [Entities.GOLDENARMOR, 'armor'],

  flask: [Entities.FLASK, 'object'],
  cake: [Entities.CAKE, 'object'],
  burger: [Entities.BURGER, 'object'],
  chest: [Entities.CHEST, 'object'],
  firepotion: [Entities.FIREPOTION, 'object'],

  guard: [Entities.GUARD, 'npc'],
  villagegirl: [Entities.VILLAGEGIRL, 'npc'],
  villager: [Entities.VILLAGER, 'npc'],
  coder: [Entities.CODER, 'npc'],
  scientist: [Entities.SCIENTIST, 'npc'],
  priest: [Entities.PRIEST, 'npc'],
  king: [Entities.KING, 'npc'],
  rick: [Entities.RICK, 'npc'],
  nyan: [Entities.NYAN, 'npc'],
  sorcerer: [Entities.SORCERER, 'npc'],
  agent: [Entities.AGENT, 'npc'],
  octocat: [Entities.OCTOCAT, 'npc'],
  beachnpc: [Entities.BEACHNPC, 'npc'],
  forestnpc: [Entities.FORESTNPC, 'npc'],
  desertnpc: [Entities.DESERTNPC, 'npc'],
  lavanpc: [Entities.LAVANPC, 'npc'],
};

const kindNames = new Map<number, string>();
for (const [name, [kind]] of Object.entries(kinds)) kindNames.set(kind, name);

export const rankedWeapons: number[] = [
  Entities.SWORD1,
  Entities.SWORD2,
  Entities.AXE,
  Entities.MORNINGSTAR,
  Entities.BLUESWORD,
  Entities.REDSWORD,
  Entities.GOLDENSWORD,
];

export const rankedArmors: number[] = [
  Entities.CLOTHARMOR,
  Entities.LEATHERARMOR,
  Entities.MAILARMOR,
  Entities.PLATEARMOR,
  Entities.REDARMOR,
  Entities.GOLDENARMOR,
];

function getType(kind: number): KindType | undefined {
  const name = kindNames.get(kind);
  return name ? kinds[name][1] : undefined;
}

export const getWeaponRank = (kind: number): number => rankedWeapons.indexOf(kind);
export const getArmorRank = (kind: number): number => rankedArmors.indexOf(kind);

export const isPlayer = (kind: number): boolean => getType(kind) === 'player';
export const isMob = (kind: number): boolean => getType(kind) === 'mob';
export const isNpc = (kind: number): boolean => getType(kind) === 'npc';
export const isCharacter = (kind: number): boolean => isMob(kind) || isNpc(kind) || isPlayer(kind);
export const isArmor = (kind: number): boolean => getType(kind) === 'armor';
export const isWeapon = (kind: number): boolean => getType(kind) === 'weapon';
export const isObject = (kind: number): boolean => getType(kind) === 'object';
export const isChest = (kind: number): boolean => kind === Entities.CHEST;
export const isItem = (kind: number): boolean =>
  isWeapon(kind) || isArmor(kind) || (isObject(kind) && !isChest(kind));
export const isHealingItem = (kind: number): boolean =>
  kind === Entities.FLASK || kind === Entities.BURGER;
export const isExpendableItem = (kind: number): boolean =>
  isHealingItem(kind) || kind === Entities.FIREPOTION || kind === Entities.CAKE;

export function getKindFromString(name: string): number | undefined {
  return name in kinds ? kinds[name][0] : undefined;
}

export function getKindAsString(kind: number): string | undefined {
  return kindNames.get(kind);
}

export function forEachKind(callback: (kind: number, name: string) => void): void {
  for (const [name, [kind]] of Object.entries(kinds)) callback(kind, name);
}

export function forEachArmorKind(callback: (kind: number, name: string) => void): void {
  forEachKind((kind, name) => {
    if (isArmor(kind)) callback(kind, name);
  });
}

export function forEachMobOrNpcKind(callback: (kind: number, name: string) => void): void {
  forEachKind((kind, name) => {
    if (isMob(kind) || isNpc(kind)) callback(kind, name);
  });
}

export function getOrientationAsString(orientation: number): string {
  switch (orientation) {
    case Orientations.LEFT:
      return 'left';
    case Orientations.RIGHT:
      return 'right';
    case Orientations.UP:
      return 'up';
    default:
      return 'down';
  }
}

export function getMessageTypeAsString(type: number): string {
  for (const [name, value] of Object.entries(Messages)) {
    if (value === type) return name;
  }
  return 'UNKNOWN';
}