Skip to main content

Constants Reference

This page documents all game constants used throughout Hyperscape. These values are defined in packages/shared/src/constants/.

Combat Constants

// From CombatConstants.ts
export const COMBAT_CONSTANTS = {
  // === TICK SYSTEM ===
  TICK_DURATION_MS: 600,              // 0.6 seconds per tick (OSRS standard)

  // === ATTACK RANGES (tiles) ===
  MELEE_RANGE: 2,                     // General melee range
  MELEE_RANGE_STANDARD: 1,            // Cardinal only (N/S/E/W)
  MELEE_RANGE_HALBERD: 2,             // Can attack diagonally
  RANGED_RANGE: 10,                   // Maximum ranged attack distance
  PICKUP_RANGE: 2.5,                  // Item pickup range

  // === ATTACK SPEEDS (ticks) ===
  DEFAULT_ATTACK_SPEED_TICKS: 4,      // 2.4 seconds (standard sword)

  // === COMBAT TIMING (ticks) ===
  COMBAT_TIMEOUT_TICKS: 17,           // 10.2 seconds (OSRS-accurate)
  LOGOUT_PREVENTION_TICKS: 16,
  HEALTH_REGEN_COOLDOWN_TICKS: 17,
  HEALTH_REGEN_INTERVAL_TICKS: 100,   // 60 seconds between HP regen
  AFK_DISABLE_RETALIATE_TICKS: 2000,

  // === FOOD CONSUMPTION (OSRS-accurate) ===
  EAT_DELAY_TICKS: 3,                 // 1.8s cooldown between eating foods
  EAT_ATTACK_DELAY_TICKS: 3,          // Added to attack cooldown when eating mid-combat
  MAX_HEAL_AMOUNT: 99,                // Security cap on healing (prevents manifest exploits)

  // === DAMAGE FORMULAS (OSRS) ===
  BASE_CONSTANT: 64,
  EFFECTIVE_LEVEL_CONSTANT: 8,
  DAMAGE_DIVISOR: 640,
  MIN_DAMAGE: 0,
  MAX_DAMAGE: 200,

  // === XP RATES ===
  XP: {
    COMBAT_XP_PER_DAMAGE: 4,          // 4 XP per damage for main skill
    HITPOINTS_XP_PER_DAMAGE: 1.33,    // 1.33 XP for Constitution
    CONTROLLED_XP_PER_DAMAGE: 1.33,   // Split across all combat skills
  },

  // === DEATH MECHANICS (ticks) ===
  DEATH: {
    ANIMATION_TICKS: 8,               // 4.8 seconds death animation
    COOLDOWN_TICKS: 17,               // 10.2 seconds respawn cooldown
    RECONNECT_RESPAWN_DELAY_TICKS: 1,
    STALE_LOCK_AGE_TICKS: 6000,
    DEFAULT_RESPAWN_TOWN: "Central Haven",
  },

  // === LOOT TIMING (ticks) ===
  RESPAWN_TICKS_RANDOMNESS: 8,
  GRAVESTONE_TICKS: 1500,             // 15 minutes (items on ground)
  GROUND_ITEM_DESPAWN_TICKS: 300,
  LOOT_PROTECTION_TICKS: 100,
  CORPSE_DESPAWN_TICKS: 200,

  // === NPC DEFAULTS ===
  DEFAULTS: {
    NPC: {
      ATTACK_SPEED_TICKS: 4,
      AGGRO_RANGE: 4,
      COMBAT_RANGE: 1,
      LEASH_RANGE: 7,
      RESPAWN_TICKS: 25,
      WANDER_RADIUS: 5,
    },
    ITEM: {
      ATTACK_SPEED: 4,
      ATTACK_RANGE: 1,
    },
  },
} as const;

Aggro Constants

export const AGGRO_CONSTANTS = {
  DEFAULT_BEHAVIOR: "passive",
  AGGRO_UPDATE_INTERVAL_MS: 100,
  ALWAYS_AGGRESSIVE_LEVEL: 999,       // Ignores level difference
} as const;

Level Constants

export const LEVEL_CONSTANTS = {
  DEFAULT_COMBAT_LEVEL: 3,
  MIN_COMBAT_LEVEL: 3,
  MAX_LEVEL: 99,

  // XP formula constants
  XP_BASE: 50,
  XP_GROWTH_FACTOR: 8,

  // Combat level calculation weights (OSRS formula)
  COMBAT_LEVEL_WEIGHTS: {
    DEFENSE_WEIGHT: 0.25,
    OFFENSE_WEIGHT: 0.325,
    RANGED_MULTIPLIER: 1.5,
  },
} as const;

Player Constants

export const PLAYER_CONSTANTS = {
  DEFAULT_HEALTH: 100,
  DEFAULT_MAX_HEALTH: 100,
  DEFAULT_STAMINA: 100,
  DEFAULT_MAX_STAMINA: 100,
  BASE_MOVEMENT_SPEED: 1.0,
  RUNNING_SPEED_MULTIPLIER: 1.5,
  HEALTH_REGEN_RATE: 1,               // HP restored per regen tick
  STAMINA_REGEN_RATE: 2.0,
  STAMINA_DRAIN_RATE: 5.0,
} as const;

Stamina Mechanics (Client-Side)

Stamina is calculated client-side in PlayerLocal.ts with the following rates:
// Base rates (per second)
staminaDrainPerSecond = 2;              // While running
staminaRegenWhileWalkingPerSecond = 2;  // While walking
staminaRegenPerSecond = 4;              // While idle

// Weight modifier (affects drain)
weightDrainModifier = 0.005;            // +0.5% drain per kg carried

// Agility modifier (affects regen)
agilityRegenModifier = 0.01;            // +1% regen per agility level
Drain Formula:
drainRate = staminaDrainPerSecond × (1 + totalWeight × 0.005)
Regen Formula:
regenRate = baseRegenRate × (1 + agilityLevel × 0.01)
Examples:
WeightAgilityRunning DrainIdle RegenWalking Regen
0 kg12.0/sec4.04/sec2.02/sec
20 kg12.2/sec4.04/sec2.02/sec
50 kg502.5/sec6.0/sec3.0/sec
100 kg993.0/sec7.96/sec3.98/sec
Weight is calculated server-side and synced to the client via PLAYER_WEIGHT_CHANGED events. This ensures stamina calculations use accurate, server-authoritative weight values.

Inventory Constants

export const INVENTORY_CONSTANTS = {
  MAX_INVENTORY_SLOTS: 28,
  MAX_BANK_SLOTS: 480,
  MAX_STACK_SIZE: 1000,
  DEFAULT_ITEM_VALUE: 1,
} as const;

Network Constants

export const NETWORK_CONSTANTS = {
  UPDATE_RATE: 20,                    // 20 Hz
  INTERPOLATION_DELAY: 100,           // milliseconds
  MAX_PACKET_SIZE: 1024,
  POSITION_SYNC_THRESHOLD: 0.1,
  ROTATION_SYNC_THRESHOLD: 0.1,
} as const;

Gathering Constants

export const GATHERING_CONSTANTS = {
  WOODCUTTING_BASE_TIME: 3000,        // 3 seconds
  FISHING_BASE_TIME: 4000,            // 4 seconds
  GATHER_RANGE: 2.0,
  RESOURCE_RESPAWN_TIME: 60000,       // 1 minute
  SUCCESS_RATE_BASE: 0.8,
  LEVEL_SUCCESS_BONUS: 0.01,          // 1% per level
} as const;

XP Constants

export const XP_CONSTANTS = {
  BASE_XP_MULTIPLIER: 83,
  MAX_LEVEL: 99,
  XP_TABLE_LENGTH: 99,
  DEFAULT_XP_GAIN: {
    COMBAT: 10,
    WOODCUTTING: 25,
    FISHING: 20,
    FIREMAKING: 40,
    COOKING: 30,
  },
} as const;

Style Bonuses

// Combat style bonuses (OSRS-accurate)
export const ATTACK_STYLES = {
  AGGRESSIVE: "aggressive",           // +3 STR XP per damage
  CONTROLLED: "controlled",           // +1 ATK, +1 STR, +1 DEF XP per damage
  DEFENSIVE: "defensive",             // +3 DEF XP per damage
  ACCURATE: "accurate",               // +3 ATK XP per damage
} as const;

Skills

export const SKILLS = {
  ATTACK: "attack",
  STRENGTH: "strength",
  DEFENSE: "defense",
  CONSTITUTION: "constitution",
  RANGE: "range",
  WOODCUTTING: "woodcutting",
  MINING: "mining",
  FISHING: "fishing",
  FIREMAKING: "firemaking",
  COOKING: "cooking",
  SMITHING: "smithing",
} as const;

Smithing Constants

// From SmithingConstants.ts
export const SMITHING_CONSTANTS = {
  // Item IDs
  HAMMER_ITEM_ID: "hammer",
  COAL_ITEM_ID: "coal",

  // Tick-based timing (OSRS-accurate)
  DEFAULT_SMELTING_TICKS: 4,          // 2.4 seconds per bar
  DEFAULT_SMITHING_TICKS: 4,          // 2.4 seconds per item
  TICK_DURATION_MS: 600,

  // Input validation limits
  MAX_QUANTITY: 10000,
  MIN_QUANTITY: 1,
  MAX_ITEM_ID_LENGTH: 64,

  // Messages
  MESSAGES: {
    ALREADY_SMELTING: "You are already smelting.",
    NO_ORES: "You don't have the ores to smelt anything.",
    LEVEL_TOO_LOW_SMELT: "You need level {level} Smithing to smelt that.",
    SMELT_SUCCESS: "You smelt a {item}.",
    IRON_SMELT_FAIL: "The ore is too impure and you fail to smelt it.",
    
    ALREADY_SMITHING: "You are already smithing.",
    NO_HAMMER: "You need a hammer to work the metal on this anvil.",
    NO_BARS: "You don't have the bars to smith anything.",
    LEVEL_TOO_LOW_SMITH: "You need level {level} Smithing to make that.",
    SMITH_SUCCESS: "You hammer the {metal} and make a {item}.",
  },
} as const;

Context Menu Colors

// From GameConstants.ts
export const CONTEXT_MENU_COLORS = {
  ITEM: "#ff9040",      // Orange - for items (OSRS-accurate)
  NPC: "#ffff00",       // Yellow - for NPCs and mobs
  OBJECT: "#00ffff",    // Cyan - for scenery/objects
  PLAYER: "#ffffff",    // White - for players
} as const;
All context menu handlers now use these centralized constants instead of hardcoded values. This ensures consistency across all interaction types.

Raycast Proxy Constants

// From interaction/constants.ts
export const RAYCAST_PROXY = {
  BASE_RADIUS: 0.4,         // Base radius for humanoid proxies (meters)
  BASE_HEIGHT: 1.2,         // Base height for humanoid proxies (meters)
  Y_OFFSET: 0.8,            // Y-offset to center proxy on entity body (meters)
  TALL_HEIGHT: 1.6,         // Height for taller mob proxies (meters)
  CAP_SEGMENTS: 4,          // Capsule geometry segments (radial)
  HEIGHT_SEGMENTS: 8,       // Capsule geometry segments (height)
} as const;
Performance: VRM SkinnedMesh raycast is extremely slow (~700-1800ms) because THREE.js must transform every vertex by bone weights. Invisible capsule proxies provide instant click detection.

Equipment Slots

export const EQUIPMENT_SLOTS = {
  WEAPON: "weapon",
  SHIELD: "shield",
  HELMET: "helmet",
  BODY: "body",
  LEGS: "legs",
  ARROWS: "arrows",
} as const;

XP Table Reference

LevelTotal XPXP to Next
1083
101,154229
204,470899
3013,3632,673
4037,2247,195
50101,33318,389
60273,74246,236
70737,627115,590
801,986,068287,883
905,346,332716,427
926,517,253(~50% of 99)
9913,034,431MAX