diff --git a/.github/workflows/update-docs.yml b/.github/workflows/update-docs.yml index 8b70bc961..45214bf6c 100644 --- a/.github/workflows/update-docs.yml +++ b/.github/workflows/update-docs.yml @@ -42,7 +42,7 @@ jobs: 'You are a documentation specialist for Hyperia, an AI-native MMORPG engine built on Three.js with ElizaOS AI agent integration. Your job is to perform COMPREHENSIVE documentation updates, not minimal edits.', '', '## Project Overview', - 'Hyperia is a RuneScape-inspired MMORPG built on a custom 3D multiplayer engine. Key packages:', + 'Hyperia is a classic fantasy MMORPG built on a custom 3D multiplayer engine. Key packages:', '- packages/shared/ - Core 3D engine (ECS, Three.js, PhysX, networking, React UI)', '- packages/server/ - Game server (Fastify, WebSockets, PostgreSQL)', '- packages/client/ - Web client (Vite, React)', diff --git a/AGENTS.md b/AGENTS.md index 8391c988c..57dcc5107 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,7 +31,7 @@ This is a hard requirement. DO NOT: ## Project Overview -Hyperia is a RuneScape-style MMORPG built on Three.js WebGPURenderer with TSL shaders. +Hyperia is a classic fantasy MMORPG built on Three.js WebGPURenderer with TSL shaders. ## CRITICAL: Secrets and Private Keys diff --git a/CLAUDE.md b/CLAUDE.md index ea819e905..f114942fd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -Hyperia is a RuneScape-style MMORPG built on a custom 3D multiplayer engine. The project features a real-time 3D metaverse engine (Hyperia) in a persistent world. +Hyperia is a classic fantasy MMORPG built on a custom 3D multiplayer engine. The project features a real-time 3D metaverse engine (Hyperia) in a persistent world. ## CRITICAL: Secrets and Private Keys diff --git a/README.md b/README.md index f7ff88db1..41fac2e06 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,12 @@ **The first AI-native MMORPG where autonomous agents play alongside humans.** -Hyperia is a RuneScape-inspired MMORPG built on a heavily modified and custom version of [Hyperfy](https://hyperfy.io), an open-source 3D multiplayer engine. The game integrates [ElizaOS](https://elizaos.ai) to enable AI agents to play autonomously in a persistent world. Unlike traditional games where NPCs follow scripts, Hyperia's agents use LLMs to make decisions, set goals, and interact with the world just like human players. +Hyperia is a classic fantasy MMORPG built on a heavily modified and custom version of [Hyperfy](https://hyperfy.io), an open-source 3D multiplayer engine. The game integrates [ElizaOS](https://elizaos.ai) to enable AI agents to play autonomously in a persistent world. Unlike traditional games where NPCs follow scripts, Hyperia's agents use LLMs to make decisions, set goals, and interact with the world just like human players. ## What Makes Hyperia Unique - **AI Agents as Players**: Autonomous agents powered by ElizaOS that fight, skill, trade, and make decisions using LLMs -- **True OSRS Mechanics**: Authentic tick-based combat (600ms ticks), safespotting, tile-based movement, and classic progression systems +- **Authentic Tick-Based Mechanics**: Combat on 600ms ticks, safespotting, tile-based movement, and classic progression systems - **Manifest-Driven Design**: Add NPCs, items, and content by editing JSON files—no code changes required - **Spectator Mode**: Watch agents play in real-time and observe their decision-making process - **Open Source**: Built on open technology with extensible architecture @@ -16,7 +16,7 @@ Hyperia is a RuneScape-inspired MMORPG built on a heavily modified and custom ve | Category | Features | |----------|----------| -| **Combat** | Tick-based OSRS mechanics (600ms ticks), attack styles, accuracy formulas, death/respawn system | +| **Combat** | Classic tick-based mechanics (600ms ticks), attack styles, accuracy formulas, death/respawn system | | **Skills** | Woodcutting, Mining, Fishing, Cooking, Firemaking + combat skills with XP/leveling | | **Economy** | 480-slot bank, shops, item weights, loot drops | | **AI Agents** | ElizaOS-powered autonomous gameplay, LLM decision-making, spectator mode | diff --git a/packages/asset-forge/dev-book/01-overview/features.md b/packages/asset-forge/dev-book/01-overview/features.md index c5a23782f..e72d87faf 100644 --- a/packages/asset-forge/dev-book/01-overview/features.md +++ b/packages/asset-forge/dev-book/01-overview/features.md @@ -588,7 +588,7 @@ Customize material presets: Customize generation prompts: **Game Style Prompts:** -- RuneScape 2007: "Low-poly RuneScape style..." +- classic low-poly fantasy: "Low-poly classic fantasy MMORPG style..." - Generic: "Game-ready 3D asset..." - Custom: User-defined styles diff --git a/packages/asset-forge/dev-book/02-getting-started/configuration.md b/packages/asset-forge/dev-book/02-getting-started/configuration.md index adf8558e4..9d5650ebe 100644 --- a/packages/asset-forge/dev-book/02-getting-started/configuration.md +++ b/packages/asset-forge/dev-book/02-getting-started/configuration.md @@ -476,7 +476,7 @@ Each preset has the following fields: "category": "metal", "tier": 1, "color": "#CD7F32", - "stylePrompt": "bronze metal texture, copper brown color, slightly dull metallic finish, RuneScape 2007 style", + "stylePrompt": "bronze metal texture, copper brown color, slightly dull metallic finish, classic low-poly fantasy style", "description": "Basic copper-brown metal, entry-level equipment" } ``` diff --git a/packages/asset-forge/dev-book/02-getting-started/quick-start.md b/packages/asset-forge/dev-book/02-getting-started/quick-start.md index 98815ae45..d0ca1d6d7 100644 --- a/packages/asset-forge/dev-book/02-getting-started/quick-start.md +++ b/packages/asset-forge/dev-book/02-getting-started/quick-start.md @@ -66,7 +66,7 @@ A medieval bronze sword with leather-wrapped grip and ornate crossguard **Game Style:** ``` -Select: RuneScape 2007 +Select: classic low-poly fantasy ``` *Or choose "Custom" and write your own style* @@ -125,7 +125,7 @@ The pipeline goes through several stages: ``` "Medieval bronze sword with leather-wrapped grip, detailed ornate crossguard with Celtic patterns, straight double-edged blade, -pommel for balance, low-poly RuneScape 2007 style, game-ready +pommel for balance, classic low-poly fantasy style, game-ready geometry, handle at bottom, blade pointing upward" ``` diff --git a/packages/asset-forge/dev-book/03-user-guides/asset-generation.md b/packages/asset-forge/dev-book/03-user-guides/asset-generation.md index 775877557..c7b848714 100644 --- a/packages/asset-forge/dev-book/03-user-guides/asset-generation.md +++ b/packages/asset-forge/dev-book/03-user-guides/asset-generation.md @@ -276,10 +276,10 @@ at entrance, wooden sign hanging from iron bracket" ``` Field: style Type: Dropdown (optional) -Default: "RuneScape 2007" +Default: "classic low-poly fantasy" Options: -├─ RuneScape 2007: Low-poly nostalgic MMORPG style +├─ classic low-poly fantasy: Low-poly nostalgic MMORPG style └─ Generic: Standard game-ready 3D asset style Custom Style: @@ -594,7 +594,7 @@ Status Messages: What Happens: 1. Uses enhanced prompt for image generation 2. Creates 1024x1024px concept art -3. Applies art style (RuneScape/Generic/Custom) +3. Applies art style (Classic Fantasy/Generic/Custom) 4. Uploads image to server 5. Displays preview diff --git a/packages/asset-forge/dev-book/03-user-guides/material-variants.md b/packages/asset-forge/dev-book/03-user-guides/material-variants.md index 4ec9c6261..f6cc2eac0 100644 --- a/packages/asset-forge/dev-book/03-user-guides/material-variants.md +++ b/packages/asset-forge/dev-book/03-user-guides/material-variants.md @@ -903,7 +903,7 @@ Total Assets: 4 weapons × 5 tiers = 20 items Settings for all: ├─ Quality: high -├─ Style: RuneScape 2007 +├─ Style: classic low-poly fantasy └─ Enable variants: bronze, steel, mithril, adamant, rune ``` diff --git a/packages/asset-forge/dev-book/04-architecture/state-management.md b/packages/asset-forge/dev-book/04-architecture/state-management.md index d86597fce..c87f36631 100644 --- a/packages/asset-forge/dev-book/04-architecture/state-management.md +++ b/packages/asset-forge/dev-book/04-architecture/state-management.md @@ -283,7 +283,7 @@ interface GenerationState { assetName: string assetType: string description: string - gameStyle: 'runescape' | 'custom' + gameStyle: 'classic' | 'custom' customStyle: string // Reference Image diff --git a/packages/asset-forge/dev-book/05-frontend/components-overview.md b/packages/asset-forge/dev-book/05-frontend/components-overview.md index d0223d3d4..0f1337f82 100644 --- a/packages/asset-forge/dev-book/05-frontend/components-overview.md +++ b/packages/asset-forge/dev-book/05-frontend/components-overview.md @@ -376,14 +376,14 @@ interface AssetDetailsCardProps { assetName: string assetType: string description: string - gameStyle: 'runescape' | 'custom' + gameStyle: 'classic' | 'custom' customStyle: string customAssetTypes: CustomAssetType[] customGameStyles: Record onAssetNameChange: (name: string) => void onAssetTypeChange: (type: string) => void onDescriptionChange: (desc: string) => void - onGameStyleChange: (style: 'runescape' | 'custom') => void + onGameStyleChange: (style: 'classic' | 'custom') => void onCustomStyleChange: (style: string) => void onBack: () => void onSaveCustomGameStyle: (name: string, config: GameStyleConfig) => void @@ -393,7 +393,7 @@ interface AssetDetailsCardProps { **Features**: - Asset name and description input - Asset type selection (weapon, armor, character, etc.) -- Game style presets (RuneScape, custom) +- Game style presets (classic fantasy MMORPG, custom) - Custom style creation and management #### 3. PipelineOptionsCard (`PipelineOptionsCard.tsx`) diff --git a/packages/asset-forge/dev-book/05-frontend/stores.md b/packages/asset-forge/dev-book/05-frontend/stores.md index 89ed8b204..4c7269c12 100644 --- a/packages/asset-forge/dev-book/05-frontend/stores.md +++ b/packages/asset-forge/dev-book/05-frontend/stores.md @@ -109,7 +109,7 @@ interface GenerationState { assetName: string assetType: string description: string - gameStyle: 'runescape' | 'custom' + gameStyle: 'classic' | 'custom' customStyle: string // Reference Image Input (4 properties) @@ -188,7 +188,7 @@ setEditingPreset: (preset: MaterialPreset | null) => void setAssetName: (name: string) => void setAssetType: (type: string) => void setDescription: (desc: string) => void -setGameStyle: (style: 'runescape' | 'custom') => void +setGameStyle: (style: 'classic' | 'custom') => void setCustomStyle: (style: string) => void ``` diff --git a/packages/asset-forge/dev-book/06-backend/ai-integrations.md b/packages/asset-forge/dev-book/06-backend/ai-integrations.md index f0a44a49d..9892855ce 100644 --- a/packages/asset-forge/dev-book/06-backend/ai-integrations.md +++ b/packages/asset-forge/dev-book/06-backend/ai-integrations.md @@ -150,7 +150,7 @@ const response = await fetch('https://api.openai.com/v1/chat/completions', { "index": 0, "message": { "role": "assistant", - "content": "A menacing goblin warrior character standing in T-pose with arms stretched horizontally and empty hands, wearing rugged leather armor with bronze accents, green scaly skin texture, pointed ears, fierce expression, low-poly RuneScape style with blocky geometry and flat-shaded surfaces" + "content": "A menacing goblin warrior character standing in T-pose with arms stretched horizontally and empty hands, wearing rugged leather armor with bronze accents, green scaly skin texture, pointed ears, fierce expression, low-poly classic fantasy MMORPG style with blocky geometry and flat-shaded surfaces" }, "finish_reason": "stop" } @@ -254,7 +254,7 @@ const response = await fetch('https://api.openai.com/v1/images/generations', { }, body: JSON.stringify({ model: 'gpt-image-1', - prompt: 'A menacing goblin warrior character in T-pose with empty hands, leather armor with bronze accents, low-poly RuneScape style', + prompt: 'A menacing goblin warrior character in T-pose with empty hands, leather armor with bronze accents, low-poly classic fantasy MMORPG style', size: '1024x1024', quality: 'high' }) diff --git a/packages/asset-forge/dev-book/06-backend/api-reference.md b/packages/asset-forge/dev-book/06-backend/api-reference.md index 7bf5e0b3b..29d62e0cc 100644 --- a/packages/asset-forge/dev-book/06-backend/api-reference.md +++ b/packages/asset-forge/dev-book/06-backend/api-reference.md @@ -524,7 +524,7 @@ Content-Type: application/json "type": "character", "subtype": "humanoid", "generationType": "avatar", - "style": "low-poly RuneScape", + "style": "low-poly classic fantasy MMORPG", "quality": "high", "enableRigging": true, "enableRetexturing": true, @@ -541,7 +541,7 @@ Content-Type: application/json "characterHeight": 1.83 }, "customPrompts": { - "gameStyle": "low-poly RuneScape style, blocky geometry" + "gameStyle": "low-poly classic fantasy MMORPG style, blocky geometry" } } ``` @@ -623,7 +623,7 @@ Host: localhost:3004 "progress": 100, "result": { "originalPrompt": "A fierce goblin warrior", - "optimizedPrompt": "A menacing goblin warrior character in T-pose, wearing rugged leather armor with bronze accents, low-poly RuneScape style" + "optimizedPrompt": "A menacing goblin warrior character in T-pose, wearing rugged leather armor with bronze accents, low-poly classic fantasy MMORPG style" } }, "imageGeneration": { @@ -908,8 +908,8 @@ Host: localhost:3004 { "version": "1.0.0", "default": { - "runescape": { - "base": "low-poly RuneScape style", + "classic": { + "base": "low-poly classic fantasy MMORPG style", "description": "Blocky, stylized geometry with flat textures" }, "skyrim": { @@ -943,8 +943,8 @@ Content-Type: application/json { "version": "1.0.0", "default": { - "runescape": { - "base": "low-poly RuneScape style", + "classic": { + "base": "low-poly classic fantasy MMORPG style", "description": "Blocky geometry" } }, diff --git a/packages/asset-forge/dev-book/06-backend/services.md b/packages/asset-forge/dev-book/06-backend/services.md index 044e281df..1a2456c22 100644 --- a/packages/asset-forge/dev-book/06-backend/services.md +++ b/packages/asset-forge/dev-book/06-backend/services.md @@ -266,7 +266,7 @@ Focus on: - Clear, specific visual details - Material and texture descriptions - Geometric shape and form -- Style consistency (especially for low-poly RuneScape style) +- Style consistency (especially for low-poly classic fantasy MMORPG style) - T-pose stance with empty hands for rigging compatibility Keep the enhanced prompt concise but detailed. @@ -397,13 +397,13 @@ Generates concept art using OpenAI's GPT-Image-1 model. **Parameters:** - `description` (string): Asset description - `assetType` (string): Asset type (character, weapon, etc.) -- `style` (string): Visual style (runescape, skyrim, etc.) +- `style` (string): Visual style (classic, skyrim, etc.) **Returns:** ```javascript { imageUrl: "data:image/png;base64,iVBORw0KGgo...", - prompt: "A fierce goblin warrior. low-poly RuneScape style...", + prompt: "A fierce goblin warrior. low-poly classic fantasy MMORPG style...", metadata: { model: "gpt-image-1", resolution: "1024x1024", diff --git a/packages/asset-forge/dev-book/08-features/07-ai-pipeline/generation-pipeline.md b/packages/asset-forge/dev-book/08-features/07-ai-pipeline/generation-pipeline.md index 46d1c87c3..18052adf2 100644 --- a/packages/asset-forge/dev-book/08-features/07-ai-pipeline/generation-pipeline.md +++ b/packages/asset-forge/dev-book/08-features/07-ai-pipeline/generation-pipeline.md @@ -83,7 +83,7 @@ interface GenerationConfig { type: string // Asset type: weapon, armor, character subtype: string // Specific category description: string // User description - style?: string // Art style (default: runescape) + style?: string // Art style (default: classic) quality?: 'standard' | 'high' | 'ultra' // Optional configuration @@ -110,7 +110,7 @@ interface GenerationConfig { - `description`: Meaningful text (min 10 characters) **Optional Fields:** -- `style`: Defaults to 'runescape' if not provided +- `style`: Defaults to 'classic' if not provided - `quality`: Defaults to 'high' - `metadata`: Additional context (creature type, armor slot, etc.) @@ -225,7 +225,7 @@ The blade has a subtle fuller groove running down the center. Simple cross-guard with slight downward curve. Leather-wrapped wooden grip with visible wrap texture. Round pommel with iron finish. -Low-poly RuneScape style with clean edges and minimal polygons. +Low-poly classic fantasy MMORPG style with clean edges and minimal polygons. The sword should have a slightly weathered iron texture with subtle scratches." ``` @@ -1016,7 +1016,7 @@ const config: GenerationConfig = { type: 'weapon', subtype: 'sword', description: 'A basic iron sword', - style: 'runescape', + style: 'classic', quality: 'high', enableRetexturing: true, enableSprites: true, @@ -1099,7 +1099,7 @@ app.get('/api/generation/pipeline/:id', async (req, res) => { { "defaults": { "quality": "high", - "style": "runescape", + "style": "classic", "enableRetexturing": false, "enableSprites": false, "enableRigging": false diff --git a/packages/asset-forge/dev-book/08-features/07-ai-pipeline/image-generation.md b/packages/asset-forge/dev-book/08-features/07-ai-pipeline/image-generation.md index 9d89baaf6..81a63bab0 100644 --- a/packages/asset-forge/dev-book/08-features/07-ai-pipeline/image-generation.md +++ b/packages/asset-forge/dev-book/08-features/07-ai-pipeline/image-generation.md @@ -1057,7 +1057,7 @@ describe('Full Generation Pipeline', () => { type: 'weapon', subtype: 'sword', description: 'iron sword', - style: 'runescape' + style: 'classic' } // Generate image @@ -1180,7 +1180,7 @@ const NO_MANNEQUIN_INSTRUCTION = **Solution**: Be very explicit about style ```typescript const STYLE_INSTRUCTION = - "Art style: Low-poly RuneScape 2007 with under 500 polygons, " + + "Art style: Classic low-poly fantasy with under 500 polygons, " + "flat shading, vibrant saturated colors, chunky proportions, " + "early 2000s game aesthetic. NOT realistic, NOT high-poly." ``` diff --git a/packages/asset-forge/dev-book/08-features/07-ai-pipeline/prompt-engineering.md b/packages/asset-forge/dev-book/08-features/07-ai-pipeline/prompt-engineering.md index f029b49ee..9ab670d84 100644 --- a/packages/asset-forge/dev-book/08-features/07-ai-pipeline/prompt-engineering.md +++ b/packages/asset-forge/dev-book/08-features/07-ai-pipeline/prompt-engineering.md @@ -27,7 +27,7 @@ Asset Forge uses a sophisticated prompt engineering system to generate high-qual ↓ ┌─────────────────────────────────────┐ │ Game Style Prompt │ -│ + "low-poly RuneScape style" │ +│ + "low-poly classic fantasy MMORPG style" │ └──────────────┬──────────────────────┘ ↓ ┌─────────────────────────────────────┐ @@ -45,7 +45,7 @@ Asset Forge uses a sophisticated prompt engineering system to generate high-qual 1. **Base Description**: User's input text 2. **Asset Type Context**: Type-specific requirements (T-pose, armor shape, etc.) -3. **Style Modifier**: Game art style (RuneScape, realistic, stylized) +3. **Style Modifier**: Game art style (classic fantasy MMORPG, realistic, stylized) 4. **Enhancement**: GPT-4 added visual details 5. **Critical Requirements**: Hard constraints (pose, orientation) @@ -63,15 +63,15 @@ Define the visual style and art direction for generated assets. ### Default Styles -#### RuneScape 2007 +#### Classic Low-Poly Fantasy ```json { - "runescape": { - "name": "RuneScape 2007", - "base": "Low-poly RuneScape 2007", - "enhanced": "low-poly RuneScape style", - "generation": "runescape2007" + "classic": { + "name": "Classic Low-Poly Fantasy", + "base": "Classic low-poly fantasy", + "enhanced": "low-poly classic fantasy MMORPG style", + "generation": "classicLowPoly" } } ``` @@ -87,7 +87,7 @@ Define the visual style and art direction for generated assets. **Example Enhanced Prompt:** ``` "Iron sword with straight blade and crossguard, -low-poly RuneScape style with simple geometry and vibrant metallic sheen" +low-poly classic fantasy MMORPG style with simple geometry and vibrant metallic sheen" ``` #### Generic Low-Poly @@ -200,8 +200,8 @@ function buildStylePrompt(userDescription: string, style: string): string { } // Example: -buildStylePrompt('iron sword', 'runescape') -// → "iron sword, low-poly RuneScape style" +buildStylePrompt('iron sword', 'classic') +// → "iron sword, low-poly classic fantasy MMORPG style" ``` --- @@ -257,7 +257,7 @@ Prompts are separated by **generation type**: **Example Usage:** ``` "Medieval knight, show the full character in T-pose, -front view on neutral background, low-poly RuneScape style" +front view on neutral background, low-poly classic fantasy MMORPG style" ``` #### Humanoid @@ -327,7 +327,7 @@ front view on neutral background, low-poly RuneScape style" **Example:** ``` "Bronze sword, show the full weapon clearly on neutral background, -low-poly RuneScape style with simple crossguard and leather-wrapped handle" +low-poly classic fantasy MMORPG style with simple crossguard and leather-wrapped handle" ``` #### Armor @@ -353,7 +353,7 @@ low-poly RuneScape style with simple crossguard and leather-wrapped handle" ``` "Iron chest plate, show armor piece shaped for T-pose fitting, shoulder openings pointing straight sideways, -hollow interior, no armor stand, low-poly RuneScape style" +hollow interior, no armor stand, low-poly classic fantasy MMORPG style" ``` #### Tool @@ -429,7 +429,7 @@ Generate material-specific variations during retexturing. ```json { "templates": { - "runescape": "${materialId} texture, low-poly RuneScape style", + "classic": "${materialId} texture, low-poly classic fantasy MMORPG style", "generic": "${materialId} texture" }, "customOverrides": {} @@ -447,12 +447,12 @@ Generate material-specific variations during retexturing. **Weapon Materials:** ```typescript const weaponMaterials = [ - { id: 'bronze', name: 'Bronze', stylePrompt: 'bronze texture, low-poly RuneScape style' }, - { id: 'iron', name: 'Iron', stylePrompt: 'iron texture, low-poly RuneScape style' }, - { id: 'steel', name: 'Steel', stylePrompt: 'steel texture, low-poly RuneScape style' }, - { id: 'mithril', name: 'Mithril', stylePrompt: 'mithril texture, low-poly RuneScape style' }, - { id: 'adamant', name: 'Adamant', stylePrompt: 'adamant texture, low-poly RuneScape style' }, - { id: 'rune', name: 'Rune', stylePrompt: 'rune texture, low-poly RuneScape style' } + { id: 'bronze', name: 'Bronze', stylePrompt: 'bronze texture, low-poly classic fantasy MMORPG style' }, + { id: 'iron', name: 'Iron', stylePrompt: 'iron texture, low-poly classic fantasy MMORPG style' }, + { id: 'steel', name: 'Steel', stylePrompt: 'steel texture, low-poly classic fantasy MMORPG style' }, + { id: 'mithril', name: 'Mithril', stylePrompt: 'mithril texture, low-poly classic fantasy MMORPG style' }, + { id: 'adamant', name: 'Adamant', stylePrompt: 'adamant texture, low-poly classic fantasy MMORPG style' }, + { id: 'rune', name: 'Rune', stylePrompt: 'rune texture, low-poly classic fantasy MMORPG style' } ] ``` @@ -472,7 +472,7 @@ Override specific material prompts: ```json { "customOverrides": { - "mithril": "Mithril texture with blue-silver sheen and magical glow, RuneScape style" + "mithril": "Mithril texture with blue-silver sheen and magical glow, classic fantasy MMORPG style" } } ``` @@ -531,7 +531,7 @@ Use GPT-4 to intelligently enhance user descriptions with visual details. wearing leather armor and fur accessories. Standing in T-pose with arms stretched horizontally and empty hands. Legs slightly apart, facing forward. -Low-poly RuneScape style with simple geometry and vibrant colors." +Low-poly classic fantasy MMORPG style with simple geometry and vibrant colors." ``` #### Armor Enhancement @@ -569,7 +569,7 @@ forming a wide T-shape when viewed from above. Hollow interior with no mannequin or armor stand. Simple bronze plates with rivets and leather straps. Ends at shoulders with no arm extensions. -Low-poly RuneScape style with clean geometry." +Low-poly classic fantasy MMORPG style with clean geometry." ``` #### Item Enhancement @@ -591,7 +591,7 @@ Cork stopper at the top with wax seal. Cylindrical bottle with rounded bottom. Red liquid has subtle glow effect. Simple label with health symbol. -Low-poly RuneScape style with vibrant red color and minimal geometry." +Low-poly classic fantasy MMORPG style with vibrant red color and minimal geometry." ``` ### GPT-4 API Call @@ -748,7 +748,7 @@ function buildFinalPrompt(config: GenerationConfig, enhanced: string): string { "Muscular orc warrior with green skin, leather armor, and fur accessories, standing in T-pose with arms extended horizontally and empty hands, legs slightly apart, facing forward, -low-poly RuneScape style with simple geometry and vibrant colors, +low-poly classic fantasy MMORPG style with simple geometry and vibrant colors, on neutral background, evenly lit from multiple angles, front view" ``` @@ -759,7 +759,7 @@ on neutral background, evenly lit from multiple angles, front view" simple crossguard with slight downward curve, leather-wrapped wooden grip with visible wrap texture, round iron pommel, slightly weathered with subtle scratches, -low-poly RuneScape style with clean edges and minimal polygons, +low-poly classic fantasy MMORPG style with clean edges and minimal polygons, on neutral background, evenly lit from multiple angles, front view" ``` @@ -772,7 +772,7 @@ forming wide T-shape when viewed from above, hollow interior with no mannequin or armor stand, bronze plates with rivets and leather straps, ends at shoulders with no arm extensions, -low-poly RuneScape style with clean geometry, +low-poly classic fantasy MMORPG style with clean geometry, on neutral background, evenly lit from multiple angles, front view" ``` @@ -818,7 +818,7 @@ const allGameStyles = PromptService.mergePrompts( ) // Get specific style -const runescapeStyle = allGameStyles.runescape +const classicStyle = allGameStyles.classic ``` ### Caching Strategy @@ -929,7 +929,7 @@ async function createMaterialOverride( // Example await createMaterialOverride( 'dragon', - 'Dragon scale texture with iridescent sheen and mystical glow, RuneScape style' + 'Dragon scale texture with iridescent sheen and mystical glow, classic fantasy MMORPG style' ) ``` @@ -960,7 +960,7 @@ await createMaterialOverride( ### 5. Add Style Consistently **Bad**: "Wooden bow" -**Good**: "Wooden longbow, low-poly RuneScape style with simple geometry" +**Good**: "Wooden longbow, low-poly classic fantasy MMORPG style with simple geometry" ### 6. Use Visual References @@ -1001,7 +1001,7 @@ async function testPromptVariants( description: variant, type: 'weapon', subtype: 'sword', - style: 'runescape' + style: 'classic' }) results.push({ @@ -1125,7 +1125,7 @@ across when viewed from above, like the letter T, NOT angled downward" **Solution**: Be more explicit about style ``` -"Low-poly RuneScape 2007 style with SIMPLE GEOMETRY (under 500 polygons), +"Classic low-poly fantasy style with SIMPLE GEOMETRY (under 500 polygons), FLAT SHADING, VIBRANT COLORS, chunky proportions, early 2000s game aesthetic" ``` @@ -1152,7 +1152,7 @@ interface AssetTypePrompt { } interface MaterialPromptTemplate { - templates: { runescape: string; generic: string } & Record + templates: { classic: string; generic: string } & Record customOverrides: Record } diff --git a/packages/asset-forge/dev-book/08-features/07-ai-pipeline/retexturing.md b/packages/asset-forge/dev-book/08-features/07-ai-pipeline/retexturing.md index c5b4f35dc..6c67cfc11 100644 --- a/packages/asset-forge/dev-book/08-features/07-ai-pipeline/retexturing.md +++ b/packages/asset-forge/dev-book/08-features/07-ai-pipeline/retexturing.md @@ -170,10 +170,10 @@ interface RetextureResponse { **Example Templates:** -**RuneScape Style:** +**classic fantasy MMORPG Style:** ```typescript -const runescapeTemplate = (material: string) => - `${material} texture, low-poly RuneScape style, vibrant colors, simple shading` +const classicTemplate = (material: string) => + `${material} texture, low-poly classic fantasy MMORPG style, vibrant colors, simple shading` ``` **Generic Style:** @@ -194,42 +194,42 @@ const realisticTemplate = (material: string) => **Bronze:** ``` -"Bronze texture, low-poly RuneScape style, +"Bronze texture, low-poly classic fantasy MMORPG style, warm orange-brown metal with slight patina, simple shading, game asset quality" ``` **Iron:** ``` -"Iron texture, low-poly RuneScape style, +"Iron texture, low-poly classic fantasy MMORPG style, dark gray metallic surface with minimal rust, simple shading, game asset quality" ``` **Steel:** ``` -"Steel texture, low-poly RuneScape style, +"Steel texture, low-poly classic fantasy MMORPG style, bright silver-gray polished metal, simple shading, game asset quality" ``` **Mithril:** ``` -"Mithril texture, low-poly RuneScape style, +"Mithril texture, low-poly classic fantasy MMORPG style, light blue-silver magical metal with subtle glow, simple shading, game asset quality" ``` **Adamant:** ``` -"Adamant texture, low-poly RuneScape style, +"Adamant texture, low-poly classic fantasy MMORPG style, dark green metallic surface, simple shading, game asset quality" ``` **Rune:** ``` -"Rune texture, low-poly RuneScape style, +"Rune texture, low-poly classic fantasy MMORPG style, cyan-blue magical metal with mystical appearance, simple shading, game asset quality" ``` @@ -280,7 +280,7 @@ fine grain, polished finish" - Be specific about material type - Include color description - Mention texture characteristics -- Specify style (RuneScape, realistic, etc.) +- Specify style (classic fantasy MMORPG, realistic, etc.) - Keep prompts concise (< 200 characters) **DON'T:** @@ -325,7 +325,7 @@ interface MaterialPreset { "category": "metal", "tier": 1, "color": "#CD7F32", - "stylePrompt": "Bronze texture, low-poly RuneScape style, warm orange-brown metal" + "stylePrompt": "Bronze texture, low-poly classic fantasy MMORPG style, warm orange-brown metal" }, { "id": "iron", @@ -334,7 +334,7 @@ interface MaterialPreset { "category": "metal", "tier": 2, "color": "#7F7F7F", - "stylePrompt": "Iron texture, low-poly RuneScape style, dark gray metallic surface" + "stylePrompt": "Iron texture, low-poly classic fantasy MMORPG style, dark gray metallic surface" }, { "id": "steel", @@ -343,7 +343,7 @@ interface MaterialPreset { "category": "metal", "tier": 3, "color": "#C0C0C0", - "stylePrompt": "Steel texture, low-poly RuneScape style, bright silver-gray polished metal" + "stylePrompt": "Steel texture, low-poly classic fantasy MMORPG style, bright silver-gray polished metal" } ] } @@ -361,7 +361,7 @@ async function loadMaterialPresets(): Promise { const presets: MaterialPreset[] = [] for (const [id, template] of Object.entries(templates.templates)) { - if (id === 'runescape' || id === 'generic') continue + if (id === 'classic' || id === 'generic') continue presets.push({ id, @@ -397,7 +397,7 @@ await createCustomPreset({ category: 'exotic', tier: 10, color: '#8B0000', - stylePrompt: 'Dragon scale texture with iridescent sheen, dark red with green highlights, RuneScape style' + stylePrompt: 'Dragon scale texture with iridescent sheen, dark red with green highlights, classic fantasy MMORPG style' }) ``` @@ -974,7 +974,7 @@ interface VariantAssetMetadata { "category": "metal", "tier": 1, "color": "#CD7F32", - "stylePrompt": "Bronze texture, low-poly RuneScape style" + "stylePrompt": "Bronze texture, low-poly classic fantasy MMORPG style" }, "retextureTaskId": "meshy-retexture-789", diff --git a/packages/asset-forge/dev-book/10-configuration/material-presets.md b/packages/asset-forge/dev-book/10-configuration/material-presets.md index 70294c642..2e1f3e11e 100644 --- a/packages/asset-forge/dev-book/10-configuration/material-presets.md +++ b/packages/asset-forge/dev-book/10-configuration/material-presets.md @@ -43,7 +43,7 @@ Material Preset - **Category system** for logical grouping - **Color theming** for UI consistency - **Style prompts** for AI generation -- **RuneScape 2007 aesthetic** by default +- **classic low-poly fantasy aesthetic** by default ### File Locations @@ -71,7 +71,7 @@ Asset Forge includes 9 pre-configured material presets organized into 4 categori "category": "metal", "tier": 1, "color": "#CD7F32", - "stylePrompt": "bronze metal texture, copper brown color, slightly dull metallic finish, RuneScape 2007 style", + "stylePrompt": "bronze metal texture, copper brown color, slightly dull metallic finish, classic low-poly fantasy style", "description": "Basic copper-brown metal, entry-level equipment" } ``` @@ -94,7 +94,7 @@ Asset Forge includes 9 pre-configured material presets organized into 4 categori "category": "metal", "tier": 2, "color": "#C0C0C0", - "stylePrompt": "steel metal texture, silver gray color, polished metallic finish, RuneScape 2007 style", + "stylePrompt": "steel metal texture, silver gray color, polished metallic finish, classic low-poly fantasy style", "description": "Silver-gray metal, intermediate quality equipment" } ``` @@ -117,7 +117,7 @@ Asset Forge includes 9 pre-configured material presets organized into 4 categori "category": "metal", "tier": 3, "color": "#4169E1", - "stylePrompt": "mithril metal texture, blue-gray color with magical shimmer, fantasy metallic finish, RuneScape 2007 style", + "stylePrompt": "mithril metal texture, blue-gray color with magical shimmer, fantasy metallic finish, classic low-poly fantasy style", "description": "Magical blue-gray metal, high-quality equipment" } ``` @@ -142,7 +142,7 @@ Asset Forge includes 9 pre-configured material presets organized into 4 categori "category": "wood", "tier": 1, "color": "#DEB887", - "stylePrompt": "light wood texture, natural pine color, basic wooden finish, RuneScape 2007 style", + "stylePrompt": "light wood texture, natural pine color, basic wooden finish, classic low-poly fantasy style", "description": "Basic light wood, entry-level equipment" } ``` @@ -165,7 +165,7 @@ Asset Forge includes 9 pre-configured material presets organized into 4 categori "category": "wood", "tier": 2, "color": "#8B4513", - "stylePrompt": "oak wood texture, medium brown color, solid wooden finish, RuneScape 2007 style", + "stylePrompt": "oak wood texture, medium brown color, solid wooden finish, classic low-poly fantasy style", "description": "Strong oak wood, intermediate quality" } ``` @@ -188,7 +188,7 @@ Asset Forge includes 9 pre-configured material presets organized into 4 categori "category": "wood", "tier": 3, "color": "#9ACD32", - "stylePrompt": "willow wood texture, pale yellow-green color, flexible wooden finish, RuneScape 2007 style", + "stylePrompt": "willow wood texture, pale yellow-green color, flexible wooden finish, classic low-poly fantasy style", "description": "Flexible willow wood, good for bows" } ``` @@ -213,7 +213,7 @@ Asset Forge includes 9 pre-configured material presets organized into 4 categori "category": "leather", "tier": 1, "color": "#8B4513", - "stylePrompt": "brown leather texture, natural cowhide, worn leather finish, RuneScape 2007 style", + "stylePrompt": "brown leather texture, natural cowhide, worn leather finish, classic low-poly fantasy style", "description": "Basic brown leather, entry-level armor" } ``` @@ -236,7 +236,7 @@ Asset Forge includes 9 pre-configured material presets organized into 4 categori "category": "leather", "tier": 2, "color": "#654321", - "stylePrompt": "hardened brown leather texture, reinforced cowhide, sturdy leather finish, RuneScape 2007 style", + "stylePrompt": "hardened brown leather texture, reinforced cowhide, sturdy leather finish, classic low-poly fantasy style", "description": "Reinforced leather, improved protection" } ``` @@ -259,7 +259,7 @@ Asset Forge includes 9 pre-configured material presets organized into 4 categori "category": "leather", "tier": 3, "color": "#8B4513", - "stylePrompt": "studded leather texture, brown leather with metal studs, reinforced leather finish, RuneScape 2007 style", + "stylePrompt": "studded leather texture, brown leather with metal studs, reinforced leather finish, classic low-poly fantasy style", "description": "Leather reinforced with metal studs" } ``` @@ -284,7 +284,7 @@ Asset Forge includes 9 pre-configured material presets organized into 4 categori "category": "custom", "tier": 10, "color": "#fa0000", - "stylePrompt": "Dragon metal texture, red with matte finish, RuneScape 2007 style", + "stylePrompt": "Dragon metal texture, red with matte finish, classic low-poly fantasy style", "description": "Custom material" } ``` @@ -402,7 +402,7 @@ interface MaterialPreset { **Type**: String **Format**: Natural language description -**Example**: `"bronze metal texture, copper brown color, slightly dull metallic finish, RuneScape 2007 style"` +**Example**: `"bronze metal texture, copper brown color, slightly dull metallic finish, classic low-poly fantasy style"` **Purpose**: AI prompt for retexturing @@ -415,7 +415,7 @@ interface MaterialPreset { 1. **Material Type**: bronze metal, oak wood, studded leather 2. **Color Description**: copper brown, silver gray, yellow-green 3. **Finish Type**: polished, dull, matte, glossy -4. **Art Style**: RuneScape 2007 style, low-poly, realistic +4. **Art Style**: classic low-poly fantasy style, low-poly, realistic **Best Practices**: - Be specific about texture details @@ -624,7 +624,7 @@ Users can create custom materials by adding entries to `material-presets.json`. "category": "special", "tier": 8, "color": "#00FFFF", - "stylePrompt": "crystalline material texture, transparent cyan color, magical shimmer, glowing effect, RuneScape 2007 style", + "stylePrompt": "crystalline material texture, transparent cyan color, magical shimmer, glowing effect, classic low-poly fantasy style", "description": "Magical crystalline material with inner glow" } ``` @@ -649,7 +649,7 @@ Generate an asset variant using the new material to verify appearance. "category": "special", "tier": 7, "color": "#1C1C1C", - "stylePrompt": "obsidian volcanic glass texture, glossy black color with purple reflections, sharp edges, RuneScape 2007 style", + "stylePrompt": "obsidian volcanic glass texture, glossy black color with purple reflections, sharp edges, classic low-poly fantasy style", "description": "Volcanic glass material, sharp and dark" } ``` @@ -664,7 +664,7 @@ Generate an asset variant using the new material to verify appearance. "category": "metal", "tier": 4, "color": "#FFD700", - "stylePrompt": "gold metal texture, bright yellow-gold color, highly polished metallic finish, RuneScape 2007 style", + "stylePrompt": "gold metal texture, bright yellow-gold color, highly polished metallic finish, classic low-poly fantasy style", "description": "Precious gold metal, ornamental equipment" } ``` @@ -679,7 +679,7 @@ Generate an asset variant using the new material to verify appearance. "category": "wood", "tier": 4, "color": "#C04000", - "stylePrompt": "mahogany wood texture, rich reddish-brown color, fine grain pattern, polished wooden finish, RuneScape 2007 style", + "stylePrompt": "mahogany wood texture, rich reddish-brown color, fine grain pattern, polished wooden finish, classic low-poly fantasy style", "description": "Exotic hardwood, deep red-brown color" } ``` @@ -726,7 +726,7 @@ Material prompts can use templates for consistency across game styles. { "version": "1.0.0", "templates": { - "runescape": "${materialId} texture, low-poly RuneScape style", + "classic": "${materialId} texture, low-poly classic fantasy MMORPG style", "generic": "${materialId} texture" }, "customOverrides": {} @@ -743,9 +743,9 @@ Material prompts can use templates for consistency across game styles. **Example Usage**: ```javascript -const template = templates.runescape +const template = templates.classic const prompt = template.replace('${materialId}', 'bronze') -// Result: "bronze texture, low-poly RuneScape style" +// Result: "bronze texture, low-poly classic fantasy MMORPG style" ``` ### Style-Specific Templates @@ -755,7 +755,7 @@ Different game styles may require different prompt formats: ```json { "templates": { - "runescape": "${materialId} texture, low-poly RuneScape 2007 style, simple textures", + "classic": "${materialId} texture, classic low-poly fantasy style, simple textures", "realistic": "${materialId} material, photorealistic PBR textures, 4K resolution", "stylized": "${materialId} material, hand-painted stylized art, vibrant colors", "lowpoly": "${materialId} texture, flat colors, low-poly game asset style" @@ -770,8 +770,8 @@ Override templates for specific materials: ```json { "customOverrides": { - "dragon": "legendary dragon scale texture, deep crimson red, metallic shimmer, magical aura, RuneScape 2007 style", - "crystal": "transparent crystal texture, cyan glow, internal facets, magical energy, RuneScape 2007 style" + "dragon": "legendary dragon scale texture, deep crimson red, metallic shimmer, magical aura, classic low-poly fantasy style", + "crystal": "transparent crystal texture, cyan glow, internal facets, magical energy, classic low-poly fantasy style" } } ``` @@ -904,7 +904,7 @@ The complete material presets file structure and best practices. "category": "metal", "tier": 1, "color": "#CD7F32", - "stylePrompt": "bronze metal texture, copper brown color, slightly dull metallic finish, RuneScape 2007 style", + "stylePrompt": "bronze metal texture, copper brown color, slightly dull metallic finish, classic low-poly fantasy style", "description": "Basic copper-brown metal, entry-level equipment" }, { @@ -914,7 +914,7 @@ The complete material presets file structure and best practices. "category": "metal", "tier": 2, "color": "#C0C0C0", - "stylePrompt": "steel metal texture, silver gray color, polished metallic finish, RuneScape 2007 style", + "stylePrompt": "steel metal texture, silver gray color, polished metallic finish, classic low-poly fantasy style", "description": "Silver-gray metal, intermediate quality equipment" } ] diff --git a/packages/asset-forge/dev-book/10-configuration/prompts.md b/packages/asset-forge/dev-book/10-configuration/prompts.md index a36c5d3b2..0dfda4513 100644 --- a/packages/asset-forge/dev-book/10-configuration/prompts.md +++ b/packages/asset-forge/dev-book/10-configuration/prompts.md @@ -29,7 +29,7 @@ User Input ↓ Asset Type Prompts (avatar/item categories) ↓ -Game Style Prompts (RuneScape, generic, custom) +Game Style Prompts (classic fantasy MMORPG, generic, custom) ↓ Generation Prompts (base image generation) ↓ @@ -114,7 +114,7 @@ Documentation embedded in JSON: ```json "default": { - "runescape": { ... }, + "classic": { ... }, "generic": { ... } } ``` @@ -360,11 +360,11 @@ Base templates for image generation: ``` Input: description: "bronze longsword" - style: "RuneScape 2007" + style: "classic low-poly fantasy" assetType: "weapon" Output: - "bronze longsword. RuneScape 2007 style, weapon, clean geometry suitable for 3D conversion." + "bronze longsword. classic low-poly fantasy style, weapon, clean geometry suitable for 3D conversion." ``` #### Fallback Enhancement @@ -451,14 +451,14 @@ Game style prompts define art style characteristics for consistent generation. ### Default Styles -#### RuneScape 2007 +#### Classic Low-Poly Fantasy ```json -"runescape": { - "name": "RuneScape 2007", - "base": "Low-poly RuneScape 2007", - "enhanced": "low-poly RuneScape style", - "generation": "runescape2007" +"classic": { + "name": "Classic Low-Poly Fantasy", + "base": "Classic low-poly fantasy", + "enhanced": "low-poly classic fantasy MMORPG style", + "generation": "classicLowPoly" } ``` @@ -466,7 +466,7 @@ Game style prompts define art style characteristics for consistent generation. - Low-poly geometry - Retro MMORPG aesthetic - Simple textures -- Nostalgic 2007-era graphics +- Nostalgic retro low-poly graphics **Fields**: - `name` - Display name for UI @@ -724,10 +724,10 @@ Material prompts provide templates for retexturing assets with different materia Generic templates using variable substitution: -#### RuneScape Template +#### classic fantasy MMORPG Template ```json -"runescape": "${materialId} texture, low-poly RuneScape style" +"classic": "${materialId} texture, low-poly classic fantasy MMORPG style" ``` **Variables**: @@ -736,7 +736,7 @@ Generic templates using variable substitution: **Example**: ``` materialId: "bronze" -Result: "bronze texture, low-poly RuneScape style" +Result: "bronze texture, low-poly classic fantasy MMORPG style" ``` #### Generic Template @@ -759,8 +759,8 @@ Material-specific prompt overrides: ```json "customOverrides": { - "dragon": "legendary dragon scale texture, deep crimson red, metallic shimmer, magical aura, RuneScape 2007 style", - "crystal": "transparent crystal texture, cyan glow, internal facets, magical energy, RuneScape 2007 style" + "dragon": "legendary dragon scale texture, deep crimson red, metallic shimmer, magical aura, classic low-poly fantasy style", + "crystal": "transparent crystal texture, cyan glow, internal facets, magical energy, classic low-poly fantasy style" } ``` @@ -812,7 +812,7 @@ Base instructions for prompt enhancement: "Clear, specific visual details", "Material and texture descriptions", "Geometric shape and form", - "Style consistency (especially for ${config.style || 'low-poly RuneScape'} style)" + "Style consistency (especially for ${config.style || 'low-poly classic fantasy MMORPG'} style)" ] ``` @@ -885,7 +885,7 @@ Asset-type specific enhancement rules: **After Enhancement**: ``` -"bronze chest plate armor piece, floating without stand, SHAPED FOR T-POSE BODY with shoulder openings pointing STRAIGHT OUT SIDEWAYS at 90 degrees like a scarecrow, wide T-shape when viewed from front, ends at shoulders with no arm extensions, hollow shoulder openings, bronze metal texture with copper brown color and slightly dull metallic finish, low-poly RuneScape 2007 style" +"bronze chest plate armor piece, floating without stand, SHAPED FOR T-POSE BODY with shoulder openings pointing STRAIGHT OUT SIDEWAYS at 90 degrees like a scarecrow, wide T-shape when viewed from front, ends at shoulders with no arm extensions, hollow shoulder openings, bronze metal texture with copper brown color and slightly dull metallic finish, classic low-poly fantasy style" ``` **Improvements**: @@ -1039,9 +1039,9 @@ Simple variable substitution: ```javascript const template = "${description}. ${style} style." -const values = { description: "bronze sword", style: "RuneScape" } +const values = { description: "bronze sword", style: "classic fantasy MMORPG" } const result = template.replace(/\$\{(\w+)\}/g, (_, key) => values[key]) -// Result: "bronze sword. RuneScape style." +// Result: "bronze sword. classic fantasy MMORPG style." ``` ### Nested Variables diff --git a/packages/asset-forge/dev-book/12-api-reference/frontend-api.md b/packages/asset-forge/dev-book/12-api-reference/frontend-api.md index cb56c21ea..38b2e40c0 100644 --- a/packages/asset-forge/dev-book/12-api-reference/frontend-api.md +++ b/packages/asset-forge/dev-book/12-api-reference/frontend-api.md @@ -312,7 +312,7 @@ const pipelineId = await client.startPipeline({ type: 'weapon', subtype: 'sword', description: 'A polished steel longsword', - style: 'runescape2007', + style: 'classicLowPoly', enableRetexturing: true, enableSprites: true, materialPresets: [ diff --git a/packages/asset-forge/dev-book/12-api-reference/rest-api.md b/packages/asset-forge/dev-book/12-api-reference/rest-api.md index 38f85065c..9bad23856 100644 --- a/packages/asset-forge/dev-book/12-api-reference/rest-api.md +++ b/packages/asset-forge/dev-book/12-api-reference/rest-api.md @@ -194,7 +194,7 @@ Pragma: no-cache "type": "weapon", "metadata": { "isBaseModel": true, - "gameStyle": "runescape", + "gameStyle": "classic", "weaponType": "sword", "tier": 1, "polycount": 5000, @@ -355,7 +355,7 @@ Content-Type: application/json "type": "weapon", "metadata": { "isBaseModel": true, - "gameStyle": "runescape", + "gameStyle": "classic", "weaponType": "sword", "tier": 2, "featured": true, @@ -394,12 +394,12 @@ Content-Type: application/json "type": "weapon", "subtype": "sword", "description": "A polished steel longsword with leather grip", - "style": "runescape2007", + "style": "classicLowPoly", "assetId": "steel-longsword", "generationType": "item", "quality": "high", "metadata": { - "gameStyle": "runescape", + "gameStyle": "classic", "useGPT4Enhancement": true }, "materialPresets": [ @@ -410,7 +410,7 @@ Content-Type: application/json "category": "metal", "tier": 1, "color": "#CD7F32", - "stylePrompt": "bronze texture, low-poly RuneScape style" + "stylePrompt": "bronze texture, low-poly classic fantasy MMORPG style" }, { "id": "steel", @@ -419,7 +419,7 @@ Content-Type: application/json "category": "metal", "tier": 2, "color": "#C0C0C0", - "stylePrompt": "polished steel texture, low-poly RuneScape style" + "stylePrompt": "polished steel texture, low-poly classic fantasy MMORPG style" } ], "enableGeneration": true, @@ -450,7 +450,7 @@ Content-Type: application/json | type | string | Yes | Asset type (weapon, armor, character, etc.) | | subtype | string | Yes | Asset subtype (sword, helmet, humanoid, etc.) | | description | string | No | Detailed asset description | -| style | string | No | Visual style (runescape2007, generic, etc.) | +| style | string | No | Visual style (classicLowPoly, generic, etc.) | | assetId | string | No | Custom asset ID (auto-generated if not provided) | | generationType | string | No | Generation type (item or avatar, default: item) | | quality | string | No | Quality level (standard, high, ultra) | @@ -570,7 +570,7 @@ Host: localhost:3004 "category": "metal", "tier": 1, "color": "#CD7F32", - "stylePrompt": "bronze metal with copper-brown coloring, low-poly RuneScape 2007 style, simple shading", + "stylePrompt": "bronze metal with copper-brown coloring, classic low-poly fantasy style, simple shading", "description": "Basic bronze metal with copper-brown coloring" }, { @@ -580,7 +580,7 @@ Host: localhost:3004 "category": "metal", "tier": 2, "color": "#C0C0C0", - "stylePrompt": "polished steel metal with silver-gray finish, low-poly RuneScape style", + "stylePrompt": "polished steel metal with silver-gray finish, low-poly classic fantasy MMORPG style", "description": "Strong steel metal with silver-gray finish" } ] diff --git a/packages/asset-forge/dev-book/12-api-reference/utility-functions.md b/packages/asset-forge/dev-book/12-api-reference/utility-functions.md index 97a4c59fd..ba8bbdbe9 100644 --- a/packages/asset-forge/dev-book/12-api-reference/utility-functions.md +++ b/packages/asset-forge/dev-book/12-api-reference/utility-functions.md @@ -815,7 +815,7 @@ interface BuildConfigOptions { materialPresets: MaterialPreset[] materialPromptOverrides: Record materialPromptTemplates?: { - runescape: string + classic: string generic: string } gameStyleConfig?: { @@ -840,7 +840,7 @@ const config = buildGenerationConfig({ assetType: 'weapon', description: 'A polished steel longsword', generationType: 'item', - gameStyle: 'runescape', + gameStyle: 'classic', enableRetexturing: true, enableSprites: true, enableRigging: false, diff --git a/packages/asset-forge/dev-book/15-appendix/changelog.md b/packages/asset-forge/dev-book/15-appendix/changelog.md index 0ecc172cf..c88f63fab 100644 --- a/packages/asset-forge/dev-book/15-appendix/changelog.md +++ b/packages/asset-forge/dev-book/15-appendix/changelog.md @@ -142,7 +142,7 @@ This is the first official release of Asset Forge, a comprehensive AI-powered 3D #### Default Settings - Default quality: High -- Default game style: RuneScape +- Default game style: classic fantasy MMORPG - Default materials: Bronze, Steel, Mithril - Default sprites: Disabled - Default rigging: Enabled for avatars diff --git a/packages/asset-forge/dev-book/15-appendix/faq.md b/packages/asset-forge/dev-book/15-appendix/faq.md index bd8ec1486..0a5ec63b7 100644 --- a/packages/asset-forge/dev-book/15-appendix/faq.md +++ b/packages/asset-forge/dev-book/15-appendix/faq.md @@ -284,7 +284,7 @@ Effective prompts are crucial for high-quality asset generation. Follow these gu ``` A medieval longsword with a leather-wrapped handle, silver crossguard, and runes etched along the blade. The pommel features a red gemstone. -Low-poly 3D model, game-ready, RuneScape art style. +Low-poly 3D model, game-ready, classic fantasy MMORPG art style. ``` **Bad Prompt Example** @@ -315,7 +315,7 @@ sword - Weathering: "battle-worn", "pristine" 5. **Art Style** (Highly Recommended) - - Reference game: "RuneScape style", "WoW style" + - Reference game: "classic fantasy MMORPG style", "WoW style" - Style descriptors: "low-poly", "stylized", "hand-painted" - Avoid: "realistic", "photorealistic" (usually poor results) diff --git a/packages/asset-forge/public/prompts/game-style-prompts.json b/packages/asset-forge/public/prompts/game-style-prompts.json index 1bc0697c6..497c4f370 100644 --- a/packages/asset-forge/public/prompts/game-style-prompts.json +++ b/packages/asset-forge/public/prompts/game-style-prompts.json @@ -2,11 +2,11 @@ "__comment": "Game style prompts - add custom styles in the 'custom' section", "version": "1.0.0", "default": { - "runescape": { - "name": "RuneScape 2007", - "base": "Low-poly RuneScape 2007", - "enhanced": "low-poly RuneScape style", - "generation": "runescape2007" + "classic": { + "name": "Classic Low-Poly Fantasy", + "base": "Classic low-poly fantasy", + "enhanced": "low-poly classic fantasy MMORPG style", + "generation": "classicLowPoly" }, "generic": { "name": "Generic Low-Poly", @@ -41,4 +41,4 @@ "enhanced": "Stylized hand painted game asset" } } -} \ No newline at end of file +} diff --git a/packages/asset-forge/public/prompts/gpt4-enhancement-prompts.json b/packages/asset-forge/public/prompts/gpt4-enhancement-prompts.json index 1ff3dd9b9..cc557c6e1 100644 --- a/packages/asset-forge/public/prompts/gpt4-enhancement-prompts.json +++ b/packages/asset-forge/public/prompts/gpt4-enhancement-prompts.json @@ -1,31 +1,31 @@ -{ - "__comment": "GPT-4 prompt enhancement system prompts", - "version": "1.0.0", - "systemPrompt": { - "base": "You are an expert at optimizing prompts for 3D asset generation. \nYour task is to enhance the user's description to create better results with image generation and 3D conversion.", - "focusPoints": [ - "Clear, specific visual details", - "Material and texture descriptions", - "Geometric shape and form", - "Style consistency (especially for ${config.style || 'low-poly RuneScape'} style)" - ], - "closingInstruction": "Keep the enhanced prompt concise but detailed." - }, - "typeSpecific": { - "avatar": { - "critical": "CRITICAL for characters: The character MUST be in a T-pose (arms stretched out horizontally, legs slightly apart) for proper rigging. The character must have EMPTY HANDS - no weapons, tools, or held items. Always add \"standing in T-pose with empty hands\" to the description.", - "focus": "- T-pose stance with empty hands for rigging compatibility" - }, - "armor": { - "base": "CRITICAL for armor pieces: The armor must be shown ALONE without any armor stand, mannequin, or body inside.", - "chest": "EXTRA IMPORTANT for chest/body armor: This MUST be shaped for a SCARECROW POSE (T-POSE) - imagine a scarecrow with arms sticking STRAIGHT OUT SIDEWAYS. The shoulder openings MUST point STRAIGHT OUT HORIZONTALLY at 90 degrees from the body, NOT downward or forward! The chest piece should look like a wide \"T\" or cross shape. From above, the shoulder openings should form a straight line across. The armor should END AT THE SHOULDERS - no arm extensions or sleeves past the shoulder joint.", - "positioning": "The armor MUST be positioned and SHAPED for a SCARECROW/T-POSE body - shoulder openings pointing STRAIGHT SIDEWAYS, not down. The armor piece must have OPEN HOLES where the body parts go through. Always specify \"floating armor piece shaped for scarecrow/T-pose body, shoulder openings pointing straight sideways at 90 degrees, no extensions, hollow openings, no armor stand\" in the description.", - "enhancementPrefix": "Enhance this armor piece description for 3D generation. CRITICAL: The armor must be SHAPED FOR A T-POSE BODY - shoulder openings must point STRAIGHT SIDEWAYS at 90 degrees (like a scarecrow), NOT angled downward! Should look like a wide \"T\" shape. Ends at shoulders (no arm extensions), hollow openings, no armor stand: ", - "focus": [ - "- Armor SHAPED for T-pose body (shoulder openings pointing straight sideways, not down)", - "- Chest armor should form a \"T\" or cross shape when viewed from above", - "- Shoulder openings at 180° angle to each other (straight line across)" - ] - } - } -} \ No newline at end of file +{ + "__comment": "GPT-4 prompt enhancement system prompts", + "version": "1.0.0", + "systemPrompt": { + "base": "You are an expert at optimizing prompts for 3D asset generation. \nYour task is to enhance the user's description to create better results with image generation and 3D conversion.", + "focusPoints": [ + "Clear, specific visual details", + "Material and texture descriptions", + "Geometric shape and form", + "Style consistency (especially for ${config.style || 'low-poly classic fantasy MMORPG'} style)" + ], + "closingInstruction": "Keep the enhanced prompt concise but detailed." + }, + "typeSpecific": { + "avatar": { + "critical": "CRITICAL for characters: The character MUST be in a T-pose (arms stretched out horizontally, legs slightly apart) for proper rigging. The character must have EMPTY HANDS - no weapons, tools, or held items. Always add \"standing in T-pose with empty hands\" to the description.", + "focus": "- T-pose stance with empty hands for rigging compatibility" + }, + "armor": { + "base": "CRITICAL for armor pieces: The armor must be shown ALONE without any armor stand, mannequin, or body inside.", + "chest": "EXTRA IMPORTANT for chest/body armor: This MUST be shaped for a SCARECROW POSE (T-POSE) - imagine a scarecrow with arms sticking STRAIGHT OUT SIDEWAYS. The shoulder openings MUST point STRAIGHT OUT HORIZONTALLY at 90 degrees from the body, NOT downward or forward! The chest piece should look like a wide \"T\" or cross shape. From above, the shoulder openings should form a straight line across. The armor should END AT THE SHOULDERS - no arm extensions or sleeves past the shoulder joint.", + "positioning": "The armor MUST be positioned and SHAPED for a SCARECROW/T-POSE body - shoulder openings pointing STRAIGHT SIDEWAYS, not down. The armor piece must have OPEN HOLES where the body parts go through. Always specify \"floating armor piece shaped for scarecrow/T-pose body, shoulder openings pointing straight sideways at 90 degrees, no extensions, hollow openings, no armor stand\" in the description.", + "enhancementPrefix": "Enhance this armor piece description for 3D generation. CRITICAL: The armor must be SHAPED FOR A T-POSE BODY - shoulder openings must point STRAIGHT SIDEWAYS at 90 degrees (like a scarecrow), NOT angled downward! Should look like a wide \"T\" shape. Ends at shoulders (no arm extensions), hollow openings, no armor stand: ", + "focus": [ + "- Armor SHAPED for T-pose body (shoulder openings pointing straight sideways, not down)", + "- Chest armor should form a \"T\" or cross shape when viewed from above", + "- Shoulder openings at 180° angle to each other (straight line across)" + ] + } + } +} diff --git a/packages/asset-forge/public/prompts/material-presets.json b/packages/asset-forge/public/prompts/material-presets.json index 24b880322..76bbc9d71 100644 --- a/packages/asset-forge/public/prompts/material-presets.json +++ b/packages/asset-forge/public/prompts/material-presets.json @@ -3,7 +3,7 @@ "id": "bronze", "name": "bronze", "displayName": "Bronze", - "stylePrompt": "bronze metal texture, copper brown color, slightly dull metallic finish, RuneScape 2007 style", + "stylePrompt": "bronze metal texture, copper brown color, slightly dull metallic finish, classic low-poly fantasy style", "description": "Basic copper-brown metal, entry-level equipment", "category": "metal", "tier": 1, @@ -13,7 +13,7 @@ "id": "steel", "name": "steel", "displayName": "Steel", - "stylePrompt": "steel metal texture, silver gray color, polished metallic finish, RuneScape 2007 style", + "stylePrompt": "steel metal texture, silver gray color, polished metallic finish, classic low-poly fantasy style", "description": "Silver-gray metal, intermediate quality equipment", "category": "metal", "tier": 2, @@ -23,7 +23,7 @@ "id": "mithril", "name": "mithril", "displayName": "Mithril", - "stylePrompt": "mithril metal texture, blue-gray color with magical shimmer, fantasy metallic finish, RuneScape 2007 style", + "stylePrompt": "mithril metal texture, blue-gray color with magical shimmer, fantasy metallic finish, classic low-poly fantasy style", "description": "Magical blue-gray metal, high-quality equipment", "category": "metal", "tier": 3, @@ -33,7 +33,7 @@ "id": "leather", "name": "leather", "displayName": "Leather", - "stylePrompt": "brown leather texture, natural cowhide, worn leather finish, RuneScape 2007 style", + "stylePrompt": "brown leather texture, natural cowhide, worn leather finish, classic low-poly fantasy style", "description": "Basic brown leather, entry-level armor", "category": "leather", "tier": 1, @@ -43,7 +43,7 @@ "id": "hard-leather", "name": "hard-leather", "displayName": "Hard Leather", - "stylePrompt": "hardened brown leather texture, reinforced cowhide, sturdy leather finish, RuneScape 2007 style", + "stylePrompt": "hardened brown leather texture, reinforced cowhide, sturdy leather finish, classic low-poly fantasy style", "description": "Reinforced leather, improved protection", "category": "leather", "tier": 2, @@ -53,7 +53,7 @@ "id": "studded-leather", "name": "studded-leather", "displayName": "Studded Leather", - "stylePrompt": "studded leather texture, brown leather with metal studs, reinforced leather finish, RuneScape 2007 style", + "stylePrompt": "studded leather texture, brown leather with metal studs, reinforced leather finish, classic low-poly fantasy style", "description": "Leather reinforced with metal studs", "category": "leather", "tier": 3, @@ -63,7 +63,7 @@ "id": "wood", "name": "wood", "displayName": "Wood", - "stylePrompt": "light wood texture, natural pine color, basic wooden finish, RuneScape 2007 style", + "stylePrompt": "light wood texture, natural pine color, basic wooden finish, classic low-poly fantasy style", "description": "Basic light wood, entry-level equipment", "category": "wood", "tier": 1, @@ -73,7 +73,7 @@ "id": "oak", "name": "oak", "displayName": "Oak", - "stylePrompt": "oak wood texture, medium brown color, solid wooden finish, RuneScape 2007 style", + "stylePrompt": "oak wood texture, medium brown color, solid wooden finish, classic low-poly fantasy style", "description": "Strong oak wood, intermediate quality", "category": "wood", "tier": 2, @@ -83,7 +83,7 @@ "id": "willow", "name": "willow", "displayName": "Willow", - "stylePrompt": "willow wood texture, pale yellow-green color, flexible wooden finish, RuneScape 2007 style", + "stylePrompt": "willow wood texture, pale yellow-green color, flexible wooden finish, classic low-poly fantasy style", "description": "Flexible willow wood, good for bows", "category": "wood", "tier": 3, @@ -93,7 +93,7 @@ "id": "dragon", "name": "dragon", "displayName": "Dragon", - "stylePrompt": "Dragon metal texture, red with matte finish, RuneScape 2007 style", + "stylePrompt": "Dragon metal texture, red with matte finish, classic low-poly fantasy style", "description": "Custom material", "category": "custom", "tier": 10, diff --git a/packages/asset-forge/public/prompts/material-prompts.json b/packages/asset-forge/public/prompts/material-prompts.json index 1f7dee83b..4bffc5ac3 100644 --- a/packages/asset-forge/public/prompts/material-prompts.json +++ b/packages/asset-forge/public/prompts/material-prompts.json @@ -1,9 +1,9 @@ -{ - "__comment": "Material generation prompts - templates for material variations", - "version": "1.0.0", - "templates": { - "runescape": "${materialId} texture, low-poly RuneScape style", - "generic": "${materialId} texture" - }, - "customOverrides": {} +{ + "__comment": "Material generation prompts - templates for material variations", + "version": "1.0.0", + "templates": { + "classic": "${materialId} texture, low-poly classic fantasy MMORPG style", + "generic": "${materialId} texture" + }, + "customOverrides": {} } \ No newline at end of file diff --git a/packages/asset-forge/server/services/GenerationService.ts b/packages/asset-forge/server/services/GenerationService.ts index fc9ffaa13..a4f822ea8 100644 --- a/packages/asset-forge/server/services/GenerationService.ts +++ b/packages/asset-forge/server/services/GenerationService.ts @@ -1267,7 +1267,7 @@ Your task is to enhance the user's description to create better results with ima "Clear, specific visual details", "Material and texture descriptions", "Geometric shape and form", - `Style consistency (especially for ${config.style || "low-poly RuneScape"} style)`, + `Style consistency (especially for ${config.style || "low-poly classic fantasy MMORPG"} style)`, ]; systemPrompt += @@ -1277,8 +1277,8 @@ Your task is to enhance the user's description to create better results with ima (point) => "- " + point.replace( - "${config.style || 'low-poly RuneScape'}", - config.style || "low-poly RuneScape", + "${config.style || 'low-poly classic fantasy MMORPG'}", + config.style || "low-poly classic fantasy MMORPG", ), ) .join("\n"); diff --git a/packages/asset-forge/server/utils/promptLoader.ts b/packages/asset-forge/server/utils/promptLoader.ts index 779601e77..d0c1c1f70 100644 --- a/packages/asset-forge/server/utils/promptLoader.ts +++ b/packages/asset-forge/server/utils/promptLoader.ts @@ -270,8 +270,8 @@ export async function getMaterialPromptTemplate( )) as MaterialPrompts | null; if (!prompts) { // Fallback templates - return gameStyle === "runescape" - ? "${materialId} texture, low-poly RuneScape style" + return gameStyle === "classic" + ? "${materialId} texture, low-poly classic fantasy MMORPG style" : "${materialId} texture"; } diff --git a/packages/asset-forge/src/components/ArmorPipeline/ArmorPreviewTab.tsx b/packages/asset-forge/src/components/ArmorPipeline/ArmorPreviewTab.tsx index 84336ff14..dc0ef3828 100644 --- a/packages/asset-forge/src/components/ArmorPipeline/ArmorPreviewTab.tsx +++ b/packages/asset-forge/src/components/ArmorPipeline/ArmorPreviewTab.tsx @@ -247,7 +247,7 @@ export const ArmorPreviewTab: React.FC = ({ } }, [riggedPieces, visiblePieces, addLog]); - /** OSRS-style item name mapping from slot */ + /** classic MMORPG-style item name mapping from slot */ const slotItemName = ( slot: string, tier: string, diff --git a/packages/asset-forge/src/components/ArmorPipeline/TextureGeneratorTab.tsx b/packages/asset-forge/src/components/ArmorPipeline/TextureGeneratorTab.tsx index 9222f2bc2..29e4383fc 100644 --- a/packages/asset-forge/src/components/ArmorPipeline/TextureGeneratorTab.tsx +++ b/packages/asset-forge/src/components/ArmorPipeline/TextureGeneratorTab.tsx @@ -60,22 +60,22 @@ interface MaterialPreset { id: string; label: string; prompt: string; - group: "osrs" | "fantasy"; + group: "classic" | "fantasy"; /** CSS color for the swatch dot */ swatch?: string; } /** Preset material prompts organized by style. - * OSRS presets include hex codes + specific material descriptors for Meshy-6 color accuracy. + * classic MMORPG presets include hex codes + specific material descriptors for Meshy-6 color accuracy. * Fantasy presets are detailed AI prompts with surface quality keywords. */ const MATERIAL_PRESETS: MaterialPreset[] = [ - // ── OSRS-style solid color tiers ────────────────────────── + // ── classic MMORPG-style solid color tiers ────────────────────────── { id: "bronze", label: "Bronze", prompt: "bronze metal armor plate, warm copper-gold #cd7f32 color, polished bronze surface", - group: "osrs", + group: "classic", swatch: "#cd7f32", }, { @@ -83,7 +83,7 @@ const MATERIAL_PRESETS: MaterialPreset[] = [ label: "Iron", prompt: "iron metal armor plate, dark grey #6b6b6b color, matte forged iron surface", - group: "osrs", + group: "classic", swatch: "#6b6b6b", }, { @@ -91,7 +91,7 @@ const MATERIAL_PRESETS: MaterialPreset[] = [ label: "Steel", prompt: "steel metal armor plate, bright silver #b8b8b8 color, polished reflective steel surface", - group: "osrs", + group: "classic", swatch: "#b8b8b8", }, { @@ -99,7 +99,7 @@ const MATERIAL_PRESETS: MaterialPreset[] = [ label: "Black", prompt: "black metal armor plate, very dark #2a2a2a color, polished obsidian black surface", - group: "osrs", + group: "classic", swatch: "#2a2a2a", }, { @@ -107,7 +107,7 @@ const MATERIAL_PRESETS: MaterialPreset[] = [ label: "Mithril", prompt: "mithril metal armor plate, blue-steel #4a7ab5 color, gleaming blue-purple surface", - group: "osrs", + group: "classic", swatch: "#4a7ab5", }, { @@ -115,7 +115,7 @@ const MATERIAL_PRESETS: MaterialPreset[] = [ label: "Adamant", prompt: "adamantite metal armor plate, dark green #2d6b3f color, polished green surface", - group: "osrs", + group: "classic", swatch: "#2d6b3f", }, { @@ -123,7 +123,7 @@ const MATERIAL_PRESETS: MaterialPreset[] = [ label: "Rune", prompt: "runite metal armor plate, bright teal-cyan #3db8c4 color, polished cyan surface", - group: "osrs", + group: "classic", swatch: "#3db8c4", }, { @@ -131,7 +131,7 @@ const MATERIAL_PRESETS: MaterialPreset[] = [ label: "Dragon", prompt: "dragon metal armor plate, deep crimson #8b1a1a color, polished dark red surface", - group: "osrs", + group: "classic", swatch: "#8b1a1a", }, // ── Detailed fantasy presets ────────────────────────────── @@ -388,9 +388,11 @@ export const TextureGeneratorTab: React.FC = ({ return; } - // ── Batch Tiers: generate all 8 OSRS tiers at once (programmatic) ── + // ── Batch Tiers: generate all 8 classic MMORPG tiers at once (programmatic) ── if (textureMethod === "batch") { - const tierPresets = MATERIAL_PRESETS.filter((p) => p.group === "osrs"); + const tierPresets = MATERIAL_PRESETS.filter( + (p) => p.group === "classic", + ); setStage("loading-result"); addLog( `Generating ${tierPresets.length} material tiers for ${slots.length} slot(s)...`, @@ -450,7 +452,7 @@ export const TextureGeneratorTab: React.FC = ({ // ── AI Retexture: Meshy API ── const prompt = getPrompt(); const preset = MATERIAL_PRESETS.find((p) => p.id === selectedPreset); - const swatchHex = preset?.swatch; // only OSRS presets have swatch + const swatchHex = preset?.swatch; // only classic MMORPG presets have swatch // CRITICAL: Do NOT send image_style_url alongside text_style_prompt. // Per Meshy docs, image_style_url OVERRIDES text_style_prompt entirely — @@ -676,7 +678,7 @@ export const TextureGeneratorTab: React.FC = ({ const { GLTFExporter } = await import("three/addons/exporters/GLTFExporter.js"); const exporter = new GLTFExporter(); - const tierPresets = MATERIAL_PRESETS.filter((p) => p.group === "osrs"); + const tierPresets = MATERIAL_PRESETS.filter((p) => p.group === "classic"); const slots = Array.from(selectedSlots); for (const tier of tierPresets) { @@ -966,11 +968,11 @@ export const TextureGeneratorTab: React.FC = ({ const cur = MATERIAL_PRESETS.find( (p) => p.id === selectedPreset, ); - if (cur?.group !== "osrs") { + if (cur?.group !== "classic") { setSelectedPreset("rune"); } } - // AI mode keeps whatever preset is selected — supports both OSRS and fantasy + // AI mode keeps whatever preset is selected — supports both classic MMORPG and fantasy }} className={`flex-1 px-2 py-1.5 rounded-md text-xs font-medium transition-all text-center ${ textureMethod === id @@ -994,7 +996,7 @@ export const TextureGeneratorTab: React.FC = ({ Metal Tier
- {MATERIAL_PRESETS.filter((p) => p.group === "osrs").map( + {MATERIAL_PRESETS.filter((p) => p.group === "classic").map( (preset) => (
- {/* All Tabs (0-9) - RS3 style: Tab 0 is just another tab, icon = first item */} + {/* All Tabs (0-9) - modern MMORPG style: Tab 0 is just another tab, icon = first item */} {(() => { // Create array of all tabs including tab 0 (which always exists implicitly) const allTabIndexes = [0, ...tabs.map((t) => t.tabIndex)].sort( @@ -220,7 +220,7 @@ export function BankTabBar({ : isSelected ? `1px solid ${theme.colors.border.default}` : `1px solid ${theme.colors.border.decorative}`; - // RS3-style: Tab icon = first item by slot order + // modern MMORPG-style: Tab icon = first item by slot order // Prefer real items (qty > 0), but fall back to placeholders if tab only has placeholders const tabItemsSorted = items .filter((i) => i.tabIndex === tabIndex) diff --git a/packages/client/src/game/panels/BankPanel/components/RightPanel.tsx b/packages/client/src/game/panels/BankPanel/components/RightPanel.tsx index 77b28841d..4b31abe41 100644 --- a/packages/client/src/game/panels/BankPanel/components/RightPanel.tsx +++ b/packages/client/src/game/panels/BankPanel/components/RightPanel.tsx @@ -2,7 +2,7 @@ * RightPanel Component * * Right-side panel containing inventory grid and equipment paperdoll views. - * RS3-style tab switcher between backpack and worn equipment. + * modern MMORPG-style tab switcher between backpack and worn equipment. */ import React, { useState } from "react"; @@ -90,7 +90,7 @@ export function RightPanel({ minWidth: shouldUseMobileUI ? undefined : `${desktopPanelWidth}px`, }} > - {/* RS3-style Tab Header with view switcher */} + {/* modern MMORPG-style Tab Header with view switcher */}
(null); const menuRef = useRef(null); - // RS3-style: Items with qty=0 are placeholders + // modern MMORPG-style: Items with qty=0 are placeholders const isPlaceholder = menu.type === "bank" && menu.quantity === 0; const actionLabel = menu.type === "bank" ? "Withdraw" : "Deposit"; - // RS3-style: Check if item is equipable for "Equip" option + // modern MMORPG-style: Check if item is equipable for "Equip" option const itemData = menu.itemId ? getItem(menu.itemId) : null; const isEquipable = itemData?.equipSlot || itemData?.equipable; @@ -121,7 +121,7 @@ export function ContextMenu({ whiteSpace: "nowrap", }); - // RS3-style: Handle placeholder-only context menu (qty=0 bank items) + // modern MMORPG-style: Handle placeholder-only context menu (qty=0 bank items) if (isPlaceholder) { return createPortal(
= []; - // RS3-style: "Equip" option position depends on rightPanelMode + // modern MMORPG-style: "Equip" option position depends on rightPanelMode const canEquip = menu.type === "bank" && isEquipable && menu.quantity > 0; if (canEquip && rightPanelMode === "equipment") { diff --git a/packages/client/src/game/panels/BankPanel/constants.ts b/packages/client/src/game/panels/BankPanel/constants.ts index 371dc4e8c..9d617ab5f 100644 --- a/packages/client/src/game/panels/BankPanel/constants.ts +++ b/packages/client/src/game/panels/BankPanel/constants.ts @@ -62,7 +62,7 @@ export const BANK_THEME = Object.freeze({ TAB_BG_SELECTED: "rgba(139, 69, 19, 0.6)", TAB_BORDER: "rgba(139, 69, 19, 0.5)", - // Text colors - gold theme with OSRS quantity colors + // Text colors - gold theme with classic MMORPG quantity colors TEXT_GOLD: "#f2d08a", // Primary gold TEXT_GOLD_DIM: "rgba(242, 208, 138, 0.7)", TEXT_YELLOW: "#ffff00", // Quantity < 100K diff --git a/packages/client/src/game/panels/BankPanel/hooks/useBankActions.ts b/packages/client/src/game/panels/BankPanel/hooks/useBankActions.ts index cc43998d5..8ba2978ab 100644 --- a/packages/client/src/game/panels/BankPanel/hooks/useBankActions.ts +++ b/packages/client/src/game/panels/BankPanel/hooks/useBankActions.ts @@ -63,13 +63,13 @@ interface BankActions { toSlot?: number, ) => void; - // Placeholder operations (RS3-style) + // Placeholder operations (modern MMORPG-style) handleWithdrawPlaceholder: (itemId: string) => void; handleReleasePlaceholder: (tabIndex: number, slot: number) => void; handleReleaseAllPlaceholders: () => void; handleToggleAlwaysPlaceholder: () => void; - // Equipment operations (RS3-style) + // Equipment operations (modern MMORPG-style) handleWithdrawToEquipment: ( itemId: string, tabIndex: number, @@ -113,7 +113,7 @@ export function useBankActions({ return; } try { - // RS3-style: New items go to currently viewed tab (or tab 0 if viewing All) + // modern MMORPG-style: New items go to currently viewed tab (or tab 0 if viewing All) const targetTab = selectedTab === TAB_INDEX_ALL ? 0 : selectedTab; world.network.send("bankDeposit", { itemId, @@ -133,7 +133,7 @@ export function useBankActions({ return; } try { - // RS3-style: New items go to currently viewed tab (or tab 0 if viewing All) + // modern MMORPG-style: New items go to currently viewed tab (or tab 0 if viewing All) const targetTab = selectedTab === TAB_INDEX_ALL ? 0 : selectedTab; world.network.send("bankDepositAll", { targetTabIndex: targetTab }); } catch (error) { @@ -261,7 +261,7 @@ export function useBankActions({ [world.network], ); - // ========== PLACEHOLDER OPERATIONS (RS3-style) ========== + // ========== PLACEHOLDER OPERATIONS (modern MMORPG-style) ========== const handleWithdrawPlaceholder = useCallback( (itemId: string) => { @@ -317,7 +317,7 @@ export function useBankActions({ } }, [world.network]); - // ========== EQUIPMENT OPERATIONS (RS3-style) ========== + // ========== EQUIPMENT OPERATIONS (modern MMORPG-style) ========== const handleWithdrawToEquipment = useCallback( (itemId: string, tabIndex: number, slot: number) => { diff --git a/packages/client/src/game/panels/BankPanel/hooks/useDragDrop.ts b/packages/client/src/game/panels/BankPanel/hooks/useDragDrop.ts index 270a89be7..f05b5622a 100644 --- a/packages/client/src/game/panels/BankPanel/hooks/useDragDrop.ts +++ b/packages/client/src/game/panels/BankPanel/hooks/useDragDrop.ts @@ -1,7 +1,7 @@ /** * useDragDrop Hook * - * Manages drag-drop state for OSRS-style bank reorganization. + * Manages drag-drop state for classic MMORPG-style bank reorganization. * Provides stable callbacks for memoized slot components and * exposes state setters for tab-specific drag handling. * diff --git a/packages/client/src/game/panels/BankPanel/types.ts b/packages/client/src/game/panels/BankPanel/types.ts index 5dcb9399b..32d4fc577 100644 --- a/packages/client/src/game/panels/BankPanel/types.ts +++ b/packages/client/src/game/panels/BankPanel/types.ts @@ -13,7 +13,7 @@ import type { PlayerEquipmentItems } from "@hyperforge/shared"; export interface BankItem { itemId: string; - quantity: number; // 0 = placeholder (RS3-style) + quantity: number; // 0 = placeholder (modern MMORPG-style) slot: number; tabIndex: number; } @@ -66,12 +66,12 @@ export type RightPanelMode = "inventory" | "equipment"; // ============================================================================ /** - * RS3-STYLE PLACEHOLDERS: + * modern MMORPG-STYLE PLACEHOLDERS: * - Placeholders are items with quantity = 0 (no separate data structure) * - Items with qty=0 are rendered with greyed-out style * - Context menu shows "Release" for qty=0 items, "Withdraw-Placeholder" for qty>0 * - * RS3-STYLE EQUIPMENT VIEW: + * modern MMORPG-STYLE EQUIPMENT VIEW: * - Right panel can switch between Inventory and Equipment views * - Equipment view shows all equipped items with deposit buttons * - "Deposit Worn Items" button deposits all equipment at once @@ -83,7 +83,7 @@ export interface BankPanelProps { maxSlots: number; world: ClientWorld; inventory: InventorySlotViewItem[]; - equipment?: PlayerEquipmentItems | null; // Player's equipped items (RS3-style) + equipment?: PlayerEquipmentItems | null; // Player's equipped items (modern MMORPG-style) coins: number; onClose: () => void; } diff --git a/packages/client/src/game/panels/ChatPanel.tsx b/packages/client/src/game/panels/ChatPanel.tsx index 269a06708..af81e8f12 100644 --- a/packages/client/src/game/panels/ChatPanel.tsx +++ b/packages/client/src/game/panels/ChatPanel.tsx @@ -34,8 +34,8 @@ interface ChatMessage { * - warning: Warning messages * - news: News/event announcements * - trade: Trade channel messages - * - trade_request: OSRS-style clickable trade request - * - duel_challenge: OSRS-style clickable duel challenge + * - trade_request: classic MMORPG-style clickable trade request + * - duel_challenge: classic MMORPG-style clickable duel challenge * - private: Private/whisper messages * - clan/guild: Clan chat messages */ @@ -88,7 +88,7 @@ const MESSAGE_COLORS = { activity: COLORS.SUCCESS, // Green for activity (logins, etc.) warning: COLORS.ERROR, // Red for warnings news: "#a855f7", // Purple for news/events (no exact match in COLORS) - trade_request: "#FF00FF", // Pink/magenta for trade requests (OSRS-style) + trade_request: "#FF00FF", // Pink/magenta for trade requests (classic MMORPG-style) duel_challenge: "#FF4444", // Red for duel challenges default: COLORS.TEXT_PRIMARY, }; diff --git a/packages/client/src/game/panels/CombatPanel.tsx b/packages/client/src/game/panels/CombatPanel.tsx index 8fe281ad6..90086d977 100644 --- a/packages/client/src/game/panels/CombatPanel.tsx +++ b/packages/client/src/game/panels/CombatPanel.tsx @@ -849,7 +849,7 @@ interface CombatPanelProps { } // Client-side cache for combat style state (persists across panel opens/closes) -// This enables instant display when reopening panel (RuneScape pattern) +// This enables instant display when reopening panel (classic fantasy MMORPG pattern) const combatStyleCache = new Map(); const autoRetaliateCache = new Map(); const VALID_WEAPON_TYPES = new Set(Object.values(WeaponType)); @@ -882,7 +882,7 @@ export function CombatPanel({ world, stats, equipment }: CombatPanelProps) { const [cooldown, setCooldown] = useState(0); const [targetName, setTargetName] = useState(null); const [targetHealth, setTargetHealth] = useState(null); - // Auto-retaliate state (OSRS default is ON) + // Auto-retaliate state (classic MMORPG default is ON) const [autoRetaliate, setAutoRetaliate] = useState(() => { const player = world.entities?.player; const playerId = player?.id; @@ -896,12 +896,12 @@ export function CombatPanel({ world, stats, equipment }: CombatPanelProps) { if (typeof playerCombat?.autoRetaliate === "boolean") { return playerCombat.autoRetaliate; } - return true; // OSRS default: ON + return true; // classic MMORPG default: ON }); const playerId = world.entities?.player?.id ?? null; const previousPlayerIdRef = useRef(null); - // Calculate combat level using OSRS formula (melee-only MVP) + // Calculate combat level using classic combat formula (melee-only MVP) const combatLevel = stats?.skills ? (() => { const s = stats.skills; @@ -1070,7 +1070,7 @@ export function CombatPanel({ world, stats, equipment }: CombatPanelProps) { if (!actions?.actionMethods?.changeAttackStyle) return; - // Optimistic: update UI instantly (OSRS has zero visible delay) + // Optimistic: update UI instantly (classic MMORPG has zero visible delay) combatStyleCache.set(playerId, next); setStyle(next); @@ -1078,7 +1078,7 @@ export function CombatPanel({ world, stats, equipment }: CombatPanelProps) { // which will overwrite our optimistic value with the authoritative one actions.actionMethods.changeAttackStyle(playerId, next); - // OSRS-accurate: selecting autocast opens the spells panel for spell selection + // rules-accurate: selecting autocast opens the spells panel for spell selection if (next === "autocast") { const store = useWindowStore.getState(); const windows = Array.from(store.windows.values()); @@ -1130,7 +1130,7 @@ export function CombatPanel({ world, stats, equipment }: CombatPanelProps) { const newValue = !autoRetaliate; - // Optimistic: update UI instantly (OSRS has zero visible delay) + // Optimistic: update UI instantly (classic MMORPG has zero visible delay) autoRetaliateCache.set(playerId, newValue); setAutoRetaliate(newValue); @@ -1140,7 +1140,7 @@ export function CombatPanel({ world, stats, equipment }: CombatPanelProps) { }; // All possible combat styles with their XP training info and colors - // Includes melee, ranged, and magic styles (OSRS-accurate) + // Includes melee, ranged, and magic styles (rules-accurate) const allStyles: Array<{ id: string; label: string; @@ -1194,7 +1194,7 @@ export function CombatPanel({ world, stats, equipment }: CombatPanelProps) { }, ]; - // Filter styles based on equipped weapon (OSRS-accurate restrictions) + // Filter styles based on equipped weapon (rules-accurate restrictions) const styles = useMemo(() => { const normalizedWeaponType = equipment?.weapon?.weaponType?.toLowerCase(); const weaponType = normalizedWeaponType diff --git a/packages/client/src/game/panels/CraftingPanel.tsx b/packages/client/src/game/panels/CraftingPanel.tsx index 275c4f5c9..eaa6e82a6 100644 --- a/packages/client/src/game/panels/CraftingPanel.tsx +++ b/packages/client/src/game/panels/CraftingPanel.tsx @@ -1,5 +1,5 @@ /** - * CraftingPanel - OSRS-style crafting interface + * CraftingPanel - classic MMORPG-style crafting interface * * Features: * - Shows available items to craft based on player's materials diff --git a/packages/client/src/game/panels/DashboardPanel.tsx b/packages/client/src/game/panels/DashboardPanel.tsx index 2b0b9063e..fad57619b 100644 --- a/packages/client/src/game/panels/DashboardPanel.tsx +++ b/packages/client/src/game/panels/DashboardPanel.tsx @@ -1,6 +1,6 @@ /** * Dashboard Panel - * RuneScape-style unified UI with vertical tabs on the right side (desktop) + * classic fantasy MMORPG-style unified UI with vertical tabs on the right side (desktop) * or horizontal tabs at the bottom (mobile) * Combines all panels into one interface with consistent UI */ diff --git a/packages/client/src/game/panels/DialoguePanel.tsx b/packages/client/src/game/panels/DialoguePanel.tsx index 553e843d5..6aec6e19e 100644 --- a/packages/client/src/game/panels/DialoguePanel.tsx +++ b/packages/client/src/game/panels/DialoguePanel.tsx @@ -5,9 +5,9 @@ * - Displays NPC dialogue text * - Shows response options as clickable buttons * - Closes when dialogue ends (no responses) - * - OSRS-style appearance + * - classic MMORPG-style appearance * - * PRODUCTION PATTERN (OSRS/WoW style): + * PRODUCTION PATTERN (classic MMORPG/WoW style): * - Server is the single source of truth for UI state * - Server tracks active dialogue sessions via InteractionSessionManager * - Server validates distance and sends close packets when player moves away diff --git a/packages/client/src/game/panels/DuelPanel/ConfirmScreen.tsx b/packages/client/src/game/panels/DuelPanel/ConfirmScreen.tsx index 7a9c93d55..e56618fae 100644 --- a/packages/client/src/game/panels/DuelPanel/ConfirmScreen.tsx +++ b/packages/client/src/game/panels/DuelPanel/ConfirmScreen.tsx @@ -4,7 +4,7 @@ * Final read-only review before duel combat begins. * Shows summary of rules, equipment restrictions, and stakes. * - * OSRS-style features: + * classic MMORPG-style features: * - Cannot modify settings on this screen * - Both players must accept for duel to begin * - Clear display of what each player risks diff --git a/packages/client/src/game/panels/DuelPanel/DuelChallengeModal.tsx b/packages/client/src/game/panels/DuelPanel/DuelChallengeModal.tsx index 5e08e5813..e11d95e24 100644 --- a/packages/client/src/game/panels/DuelPanel/DuelChallengeModal.tsx +++ b/packages/client/src/game/panels/DuelPanel/DuelChallengeModal.tsx @@ -84,10 +84,10 @@ export function DuelChallengeModal({ transform: declineHover ? "translateY(-1px)" : "none", }; - // Combat level color based on OSRS conventions + // Combat level color based on classic MMORPG conventions const getLevelColor = (_opponentLevel: number): string => { // Since we don't know the local player's level here, - // use a neutral gold color like OSRS's duel interface + // use a neutral gold color like classic MMORPG's duel interface return "#ffd700"; }; diff --git a/packages/client/src/game/panels/DuelPanel/RulesScreen.tsx b/packages/client/src/game/panels/DuelPanel/RulesScreen.tsx index d42e339ac..77cad231d 100644 --- a/packages/client/src/game/panels/DuelPanel/RulesScreen.tsx +++ b/packages/client/src/game/panels/DuelPanel/RulesScreen.tsx @@ -4,7 +4,7 @@ * Screen where both players negotiate duel rules and equipment restrictions. * Both players must accept for the duel to proceed to the Stakes screen. * - * OSRS-style features: + * classic MMORPG-style features: * - 10 rule toggles (combat restrictions) * - 11 equipment slot toggles * - Accept button that shows opponent's acceptance status diff --git a/packages/client/src/game/panels/DuelPanel/StakesScreen.tsx b/packages/client/src/game/panels/DuelPanel/StakesScreen.tsx index c7d099fac..80f5728e4 100644 --- a/packages/client/src/game/panels/DuelPanel/StakesScreen.tsx +++ b/packages/client/src/game/panels/DuelPanel/StakesScreen.tsx @@ -4,7 +4,7 @@ * Screen where both players stake items for the duel. * Similar to trade panel but for duel stakes. * - * OSRS-style features: + * classic MMORPG-style features: * - Left-click inventory item: stake 1 * - Right-click: context menu for quantity options * - Both players must accept for duel to proceed diff --git a/packages/client/src/game/panels/EquipmentPanel.tsx b/packages/client/src/game/panels/EquipmentPanel.tsx index 012960719..f815d0779 100644 --- a/packages/client/src/game/panels/EquipmentPanel.tsx +++ b/packages/client/src/game/panels/EquipmentPanel.tsx @@ -164,7 +164,7 @@ function DroppableEquipmentSlot({ if (!slot.item) return; - // OSRS uses orange for item names in context menus + // classic MMORPG uses orange for item names in context menus const itemName = slot.item.name; const items = [ @@ -418,7 +418,7 @@ export const EquipmentPanel = React.memo(function EquipmentPanel({ }: EquipmentPanelProps) { const theme = useThemeStore((s) => s.theme); const { shouldUseMobileUI } = useMobileLayout(); - // RS3-style hover tooltip state + // modern MMORPG-style hover tooltip state const [hoverState, setHoverState] = useState( null, ); @@ -539,7 +539,7 @@ export const EquipmentPanel = React.memo(function EquipmentPanel({ } }; - // RS3-style: Click immediately unequips + // modern MMORPG-style: Click immediately unequips const handleSlotClick = (slot: EquipmentSlot) => { if (!slot.item) return; if (onSlotAction) { @@ -604,7 +604,7 @@ export const EquipmentPanel = React.memo(function EquipmentPanel({ type: "info", position: ce.detail.position, }); - // Also add to chat (OSRS-style game message) + // Also add to chat (classic MMORPG-style game message) if (world?.chat?.add) { world.chat.add({ id: uuid(), diff --git a/packages/client/src/game/panels/FletchingPanel.tsx b/packages/client/src/game/panels/FletchingPanel.tsx index ffb996da1..d8f619414 100644 --- a/packages/client/src/game/panels/FletchingPanel.tsx +++ b/packages/client/src/game/panels/FletchingPanel.tsx @@ -1,5 +1,5 @@ /** - * FletchingPanel - OSRS-style fletching interface + * FletchingPanel - classic MMORPG-style fletching interface * * Features: * - Shows available items to fletch based on player's materials diff --git a/packages/client/src/game/panels/InventoryPanel.tsx b/packages/client/src/game/panels/InventoryPanel.tsx index c49912f1d..4657656a6 100644 --- a/packages/client/src/game/panels/InventoryPanel.tsx +++ b/packages/client/src/game/panels/InventoryPanel.tsx @@ -41,7 +41,7 @@ import { EventType, getItem, uuid, - // OSRS-accurate item helpers (extracted to shared) + // rules-accurate item helpers (extracted to shared) isFood, isPotion, isBone, @@ -61,7 +61,7 @@ import { CoinPouch } from "./inventory"; import { zIndex } from "../../constants/tokens"; /** - * Maximum inventory slots (OSRS-style: 28 slots) + * Maximum inventory slots (classic MMORPG-style: 28 slots) * Uses INVENTORY_CONSTANTS from shared package as single source of truth */ const MAX_SLOTS = INVENTORY_CONSTANTS.MAX_INVENTORY_SLOTS; @@ -114,7 +114,7 @@ interface DraggableItemProps { position: { x: number; y: number }, ) => void; onTargetHoverEnd?: () => void; - // RS3-style hover tooltip (separate from targeting mode) + // modern MMORPG-style hover tooltip (separate from targeting mode) onItemHoverStart?: ( item: InventorySlotViewItem, position: { x: number; y: number }, @@ -133,10 +133,10 @@ interface DraggableItemProps { ) => void; } -// OSRS-style: 4 columns × 7 rows = 28 slots, all visible (no pagination) +// classic MMORPG-style: 4 columns × 7 rows = 28 slots, all visible (no pagination) /** - * Format quantity for OSRS-style display + * Format quantity for classic MMORPG-style display * - Under 100K: show exact number * - 100K-9.99M: green "123K" format * - 10M+: green "12M" format @@ -209,10 +209,10 @@ const DraggableInventorySlot = memo(function DraggableInventorySlot({ // Slots stay fixed - no transform! Only the DragOverlay moves. const isEmpty = !item; - // OSRS-style targeting mode checks + // classic MMORPG-style targeting mode checks const isTargetingActive = targetingState?.active ?? false; - // Check if THIS slot is the source item (gets white border in OSRS) + // Check if THIS slot is the source item (gets white border in classic MMORPG) const isSourceItem = isTargetingActive && targetingState?.sourceItem?.slot === index; @@ -270,15 +270,15 @@ const DraggableInventorySlot = memo(function DraggableInventorySlot({ if (isValidTarget && item && onTargetClick) { onTargetClick(item, index); } else if (item && !isValidTarget && onInvalidTargetClick) { - // OSRS: Clicking an invalid item shows "Nothing interesting happens." + // classic MMORPG: Clicking an invalid item shows "Nothing interesting happens." // (Empty slots don't trigger this - only actual items) onInvalidTargetClick(); } - // Clicking empty slot does nothing (OSRS behavior) + // Clicking empty slot does nothing (classic MMORPG behavior) return; } - // Shift-click to drop instantly (OSRS-style) + // Shift-click to drop instantly (classic MMORPG-style) if (e.shiftKey && item && onShiftClick) { e.preventDefault(); e.stopPropagation(); @@ -286,7 +286,7 @@ const DraggableInventorySlot = memo(function DraggableInventorySlot({ return; } - // Left-click: execute primary action (OSRS-style) + // Left-click: execute primary action (classic MMORPG-style) // Uses manifest-first approach with heuristic fallback // Uses memoized itemData and isItemNoted for efficiency if (item && onPrimaryAction) { @@ -299,11 +299,11 @@ const DraggableInventorySlot = memo(function DraggableInventorySlot({ }} onMouseEnter={(e) => { setIsHovered(true); - // OSRS-style: show "Use X → Y" tooltip when hovering valid target + // classic MMORPG-style: show "Use X → Y" tooltip when hovering valid target if (isValidTarget && item && onTargetHover) { onTargetHover(item, { x: e.clientX, y: e.clientY }); } else if (!isTargetingActive && item && onItemHoverStart) { - // RS3-style: show item stats tooltip when not in targeting mode + // modern MMORPG-style: show item stats tooltip when not in targeting mode onItemHoverStart(item, { x: e.clientX, y: e.clientY }); } }} @@ -348,7 +348,7 @@ const DraggableInventorySlot = memo(function DraggableInventorySlot({ const itemName = itemData?.name || item.itemId; const isNoted = isItemNoted; - // Build menu items - OSRS-accurate: use inventoryActions from manifest if available + // Build menu items - rules-accurate: use inventoryActions from manifest if available const menuItems: Array<{ id: string; label: string; @@ -356,7 +356,7 @@ const DraggableInventorySlot = memo(function DraggableInventorySlot({ enabled: boolean; }> = []; - // OSRS-accurate: Check manifest's inventoryActions first + // rules-accurate: Check manifest's inventoryActions first if ( itemData?.inventoryActions && itemData.inventoryActions.length > 0 && @@ -488,7 +488,7 @@ const DraggableInventorySlot = memo(function DraggableInventorySlot({ }); } - // OSRS-style: Cancel is always the last option + // classic MMORPG-style: Cancel is always the last option menuItems.push({ id: "cancel", label: "Cancel", @@ -513,14 +513,14 @@ const DraggableInventorySlot = memo(function DraggableInventorySlot({ style={{ // Use 'size' for 2D container queries (cqw/cqh) in responsive grid containerType: "size", - // OSRS-style targeting: + // classic MMORPG-style targeting: // - Source item: WHITE border (the item being used) // - Valid targets: normal appearance, cursor indicates validity // - Invalid targets: normal appearance, cursor shows not-allowed ...slotChrome, opacity: isDragging ? 0.3 : slotChrome.opacity, borderColor: isSourceItem - ? "rgba(255, 255, 255, 0.95)" // OSRS: White border on source item + ? "rgba(255, 255, 255, 0.95)" // classic MMORPG: White border on source item : isOver ? "rgba(242, 208, 138, 0.5)" // Gold highlight when dragging over : isEmpty @@ -537,7 +537,7 @@ const DraggableInventorySlot = memo(function DraggableInventorySlot({ ? "linear-gradient(180deg, rgba(215, 200, 165, 0.95) 0%, rgba(235, 225, 195, 0.95) 100%)" // Parchment - lighter at bottom for emboss : "var(--color-slot-filled)", // Use theme slot.filled color boxShadow: isSourceItem - ? "0 0 8px rgba(255, 255, 255, 0.6)" // OSRS: White glow on source item + ? "0 0 8px rgba(255, 255, 255, 0.6)" // classic MMORPG: White glow on source item : isOver ? "inset 0 0 8px rgba(183, 140, 76, 0.24), 0 0 0 1px rgba(183, 140, 76, 0.12)" : isEmpty @@ -545,7 +545,7 @@ const DraggableInventorySlot = memo(function DraggableInventorySlot({ : isItemNoted ? "inset 1px 1px 3px rgba(0, 0, 0, 0.25), inset -1px -1px 1px rgba(255, 255, 255, 0.4)" // Subtle paper emboss : "inset 2px 2px 4px rgba(0, 0, 0, 0.34), inset -1px -1px 2px rgba(98, 82, 60, 0.1)", // Emboss for filled - // OSRS-style cursor changes during targeting mode + // classic MMORPG-style cursor changes during targeting mode cursor: isTargetingActive ? isSourceItem ? "default" // Source item - no special cursor @@ -580,7 +580,7 @@ const DraggableInventorySlot = memo(function DraggableInventorySlot({
)} - {/* Quantity Badge - RS3 style: top-left, yellow for stacks */} + {/* Quantity Badge - modern MMORPG style: top-left, yellow for stacks */} {/* BANK NOTE SYSTEM: Darker text with light shadow for noted items */} {/* Mobile: Larger text for readability (clamp(10px, 3cqw, 14px)) */} {item && @@ -646,7 +646,7 @@ interface PendingMove { /** * Targeting mode state for "Use X on Y" interactions (firemaking, cooking) - * OSRS-style: source item gets white border, cursor changes for valid/invalid targets + * classic MMORPG-style: source item gets white border, cursor changes for valid/invalid targets */ interface TargetingState { active: boolean; @@ -656,7 +656,7 @@ interface TargetingState { } /** - * Hover state for "Use X → Y" tooltip (OSRS-style) + * Hover state for "Use X → Y" tooltip (classic MMORPG-style) */ interface TargetHoverState { targetName: string; @@ -664,7 +664,7 @@ interface TargetHoverState { } /** - * Hover state for RS3-style item tooltip + * Hover state for modern MMORPG-style item tooltip */ interface ItemHoverState { item: InventorySlotViewItem; @@ -810,10 +810,10 @@ export function InventoryPanel({ initialTargetingState, ); - // OSRS-style hover tooltip state for "Use X → Y" + // classic MMORPG-style hover tooltip state for "Use X → Y" const [targetHover, setTargetHover] = useState(null); - // RS3-style hover tooltip state for item stats + // modern MMORPG-style hover tooltip state for item stats const [itemHover, setItemHover] = useState(null); // Track if context menu is open (suppress hover tooltips while open) @@ -875,7 +875,7 @@ export function InventoryPanel({ ); }, [slotItems, world]); - // Listen for targeting mode events (OSRS-style "Use X on Y") + // Listen for targeting mode events (classic MMORPG-style "Use X on Y") useEffect(() => { if (!world) return; @@ -1045,7 +1045,7 @@ export function InventoryPanel({ preMoveSlotsSnapshot: [...slotItems], }; - // OSRS-style SWAP: exchange two slots directly (don't shift/insert) + // classic MMORPG-style SWAP: exchange two slots directly (don't shift/insert) // Create deep copies of items to avoid mutating props and update .slot property const newSlots = [...slotItems]; const fromItem = newSlots[fromIndex]; @@ -1114,7 +1114,7 @@ export function InventoryPanel({ hoveredItem: InventorySlotViewItem, position: { x: number; y: number }, ) => { - // OSRS-style "Use X → Y" tooltip + // classic MMORPG-style "Use X → Y" tooltip setTargetHover({ targetName: hoveredItem.itemId, position, @@ -1127,7 +1127,7 @@ export function InventoryPanel({ setTargetHover(null); }, []); - // RS3-style item hover handlers for stats tooltip + // modern MMORPG-style item hover handlers for stats tooltip const handleItemHoverStart = useCallback( (item: InventorySlotViewItem, position: { x: number; y: number }) => { // Don't show hover tooltip if context menu is open @@ -1178,10 +1178,10 @@ export function InventoryPanel({ ); const handleInvalidTargetClick = useCallback(() => { - // OSRS: "Nothing interesting happens." when using item on invalid target + // classic MMORPG: "Nothing interesting happens." when using item on invalid target const message = "Nothing interesting happens."; - // Show in chat (OSRS-style game message) + // Show in chat (classic MMORPG-style game message) if (world?.chat?.add) { world.chat.add({ id: uuid(), @@ -1273,7 +1273,7 @@ export function InventoryPanel({ boxShadow: "none", }} > - {/* OSRS-style "Use X → Y" tooltip - rendered via portal to avoid transform issues */} + {/* classic MMORPG-style "Use X → Y" tooltip - rendered via portal to avoid transform issues */} {targetingState.active && targetHover && targetingState.sourceItem && @@ -1300,7 +1300,7 @@ export function InventoryPanel({ document.body, )} - {/* RS3-style item hover tooltip - rendered via portal */} + {/* modern MMORPG-style item hover tooltip - rendered via portal */} {!targetingState.active && itemHover && renderItemHoverTooltip(itemHover, theme)} @@ -1323,7 +1323,7 @@ export function InventoryPanel({
- {/* RS3-style Coins/Money Pouch - Extracted component */} + {/* modern MMORPG-style Coins/Money Pouch - Extracted component */} {showCoinPouch && ( )} diff --git a/packages/client/src/game/panels/PrayerPanel.tsx b/packages/client/src/game/panels/PrayerPanel.tsx index 646fd3267..46dda2c20 100644 --- a/packages/client/src/game/panels/PrayerPanel.tsx +++ b/packages/client/src/game/panels/PrayerPanel.tsx @@ -1,12 +1,12 @@ /** * Prayer Panel - * RuneScape-inspired prayer interface with adaptive grid layout - * Authentic OSRS/RS3 style design + * classic fantasy MMORPG-inspired prayer interface with adaptive grid layout + * Classic fantasy MMORPG interface with a modern presentation * Supports drag-drop to action bar * Syncs with server prayer state * * Layout adapts based on panel size: - * - Wide: 5 columns (default OSRS style) + * - Wide: 5 columns (default classic MMORPG style) * - Medium: 4 columns * - Narrow: 3 columns * - Very narrow: 2 columns (vertical layout) @@ -228,7 +228,7 @@ function getPrayerDisplayIcon(iconId: string): string { return PRAYER_ICON_MAP[iconId] ?? "✨"; } -/** Prayer icon component with OSRS-style glow effect and drag support */ +/** Prayer icon component with classic MMORPG-style glow effect and drag support */ function PrayerIcon({ prayer, playerLevel, @@ -332,7 +332,7 @@ function PrayerIcon({ borderColor: isActive ? theme.colors.accent.secondary : isHovered && isUnlocked - ? "rgba(183, 140, 76, 0.4)" // RS3/OSRS gold tint on hover + ? "rgba(183, 140, 76, 0.4)" // modern MMORPG/classic MMORPG gold tint on hover : "rgba(8, 8, 10, 0.6)", borderWidth: "1px", borderRadius: 4, // Square slots diff --git a/packages/client/src/game/panels/QuestCompletePanel.tsx b/packages/client/src/game/panels/QuestCompletePanel.tsx index 5636634be..5c1bb58bb 100644 --- a/packages/client/src/game/panels/QuestCompletePanel.tsx +++ b/packages/client/src/game/panels/QuestCompletePanel.tsx @@ -1,5 +1,5 @@ /** - * QuestCompletePanel - OSRS-style quest completion overlay + * QuestCompletePanel - classic MMORPG-style quest completion overlay * * Features: * - Scroll/parchment style modal diff --git a/packages/client/src/game/panels/QuestDetailPanel.tsx b/packages/client/src/game/panels/QuestDetailPanel.tsx index 6a4790f76..f705db320 100644 --- a/packages/client/src/game/panels/QuestDetailPanel.tsx +++ b/packages/client/src/game/panels/QuestDetailPanel.tsx @@ -59,7 +59,7 @@ function savePinnedQuests(pinnedIds: Set): void { } } -// OSRS-style status colors +// classic MMORPG-style status colors const STATUS_COLORS: Record = { available: COLORS.ERROR, // Red - not started active: COLORS.WARNING, // Yellow - in progress diff --git a/packages/client/src/game/panels/QuestJournalPanel.tsx b/packages/client/src/game/panels/QuestJournalPanel.tsx index e60d5bb7c..139560621 100644 --- a/packages/client/src/game/panels/QuestJournalPanel.tsx +++ b/packages/client/src/game/panels/QuestJournalPanel.tsx @@ -1,5 +1,5 @@ /** - * QuestJournalPanel - OSRS-style quest tracking interface + * QuestJournalPanel - classic MMORPG-style quest tracking interface * * Features: * - Quest list with color-coded status (red/yellow/green) @@ -53,7 +53,7 @@ interface QuestDetail { }>; } -// Status colors matching OSRS +// Status colors matching classic MMORPG const STATUS_COLORS = { not_started: "#ff4444", // Red in_progress: "#ffff00", // Yellow diff --git a/packages/client/src/game/panels/QuestStartPanel.tsx b/packages/client/src/game/panels/QuestStartPanel.tsx index 8058ec73d..2a5ea6efb 100644 --- a/packages/client/src/game/panels/QuestStartPanel.tsx +++ b/packages/client/src/game/panels/QuestStartPanel.tsx @@ -1,5 +1,5 @@ /** - * QuestStartPanel - OSRS-style quest accept overlay + * QuestStartPanel - classic MMORPG-style quest accept overlay * * Features: * - Shows quest name, description, requirements diff --git a/packages/client/src/game/panels/SkillGuidePanel.tsx b/packages/client/src/game/panels/SkillGuidePanel.tsx index 0970b19b6..1ee09b8ab 100644 --- a/packages/client/src/game/panels/SkillGuidePanel.tsx +++ b/packages/client/src/game/panels/SkillGuidePanel.tsx @@ -1,6 +1,6 @@ /** * Skill Guide Panel - * OSRS-style popup showing skill unlocks at each level + * classic MMORPG-style popup showing skill unlocks at each level * * Uses ModalWindow for consistent styling and behavior. */ diff --git a/packages/client/src/game/panels/SkillsPanel.tsx b/packages/client/src/game/panels/SkillsPanel.tsx index 42d13313d..10d0aa5d2 100644 --- a/packages/client/src/game/panels/SkillsPanel.tsx +++ b/packages/client/src/game/panels/SkillsPanel.tsx @@ -166,7 +166,7 @@ const DraggableSkillCard = memo(function DraggableSkillCard({ > {skill.icon} - {/* OSRS-style slanted level display: current↗/↘base */} + {/* classic MMORPG-style slanted level display: current↗/↘base */}
- {/* Right: Total / Combat with OSRS-style angled split */} + {/* Right: Total / Combat with classic MMORPG-style angled split */}
{ diff --git a/packages/client/src/game/panels/SmeltingPanel.tsx b/packages/client/src/game/panels/SmeltingPanel.tsx index f6eb2b1a9..5f4b993e5 100644 --- a/packages/client/src/game/panels/SmeltingPanel.tsx +++ b/packages/client/src/game/panels/SmeltingPanel.tsx @@ -1,5 +1,5 @@ /** - * SmeltingPanel - OSRS-style smelting interface + * SmeltingPanel - classic MMORPG-style smelting interface * * Features: * - Shows available bars to smelt based on player's inventory diff --git a/packages/client/src/game/panels/SmithingPanel.tsx b/packages/client/src/game/panels/SmithingPanel.tsx index 308a5f83d..f4affcd4a 100644 --- a/packages/client/src/game/panels/SmithingPanel.tsx +++ b/packages/client/src/game/panels/SmithingPanel.tsx @@ -1,5 +1,5 @@ /** - * SmithingPanel - OSRS-style smithing interface + * SmithingPanel - classic MMORPG-style smithing interface * * Features: * - Shows available items to smith based on player's bars @@ -120,7 +120,7 @@ export function SmithingPanel({ const [showQuantityInput, setShowQuantityInput] = useState(false); const [customQuantity, setCustomQuantity] = useState(""); - // Make X memory - remember last custom quantity (OSRS feature) + // Make X memory - remember last custom quantity (classic MMORPG feature) const [lastCustomQuantity, setLastCustomQuantity] = useState(() => { try { const stored = localStorage.getItem(SMITHING_LAST_X_KEY); @@ -171,7 +171,7 @@ export function SmithingPanel({ }; const handleCustomQuantitySubmit = () => { - // Use entered quantity, or fall back to last X if empty (OSRS behavior) + // Use entered quantity, or fall back to last X if empty (classic MMORPG behavior) const qty = customQuantity.trim() ? parseInt(customQuantity, 10) : lastCustomQuantity; diff --git a/packages/client/src/game/panels/SpellsPanel.tsx b/packages/client/src/game/panels/SpellsPanel.tsx index 4b45d3352..68e124449 100644 --- a/packages/client/src/game/panels/SpellsPanel.tsx +++ b/packages/client/src/game/panels/SpellsPanel.tsx @@ -1,6 +1,6 @@ /** * Spells Panel - * OSRS-inspired magic spellbook interface + * classic MMORPG-inspired magic spellbook interface * Shows available combat spells with level requirements * Click to select autocast spell * diff --git a/packages/client/src/game/panels/StatsPanel.tsx b/packages/client/src/game/panels/StatsPanel.tsx index 8418cde8c..e25a6e579 100644 --- a/packages/client/src/game/panels/StatsPanel.tsx +++ b/packages/client/src/game/panels/StatsPanel.tsx @@ -1,12 +1,12 @@ /** - * Stats Panel - OSRS-style Equipment Stats Display + * Stats Panel - classic MMORPG-style Equipment Stats Display * * Shows equipment bonuses from all worn items, grouped by: * - Attack bonuses: Stab, Slash, Crush, Magic, Ranged * - Defence bonuses: Stab, Slash, Crush, Magic, Ranged * - Other bonuses: Melee Strength, Ranged Strength, Magic Damage, Prayer * - * Matches the RuneScape "Equipment Stats" screen layout. + * Matches the classic fantasy MMORPG "Equipment Stats" screen layout. */ import { useMemo } from "react"; diff --git a/packages/client/src/game/panels/StorePanel.tsx b/packages/client/src/game/panels/StorePanel.tsx index ae0dc21d3..731961fd6 100644 --- a/packages/client/src/game/panels/StorePanel.tsx +++ b/packages/client/src/game/panels/StorePanel.tsx @@ -1,5 +1,5 @@ /** - * StorePanel - RuneScape-style store interface + * StorePanel - classic fantasy MMORPG-style store interface * * Features: * - Grid display of store items for sale diff --git a/packages/client/src/game/panels/TanningPanel.tsx b/packages/client/src/game/panels/TanningPanel.tsx index 198c33d17..d1e1ea5e0 100644 --- a/packages/client/src/game/panels/TanningPanel.tsx +++ b/packages/client/src/game/panels/TanningPanel.tsx @@ -1,5 +1,5 @@ /** - * TanningPanel - OSRS-style tanning interface + * TanningPanel - classic MMORPG-style tanning interface * * Features: * - Shows available hides to tan based on player's inventory diff --git a/packages/client/src/game/panels/TradePanel/TradePanel.tsx b/packages/client/src/game/panels/TradePanel/TradePanel.tsx index aeaa36949..c3ace2345 100644 --- a/packages/client/src/game/panels/TradePanel/TradePanel.tsx +++ b/packages/client/src/game/panels/TradePanel/TradePanel.tsx @@ -1,8 +1,8 @@ /** - * Trade Panel - OSRS Style + * Trade Panel - classic MMORPG Style * * Main trading interface showing both players' offers side-by-side. - * Uses OSRS-style click-based item management with right-click context menus. + * Uses classic MMORPG-style click-based item management with right-click context menus. * * Layout: * - Left side: Local player's offer @@ -197,7 +197,7 @@ export function TradePanel({ style={{ ...getPanelSurfaceStyle(theme, { emphasis: "strong" }), borderRadius: theme.borderRadius.xl, - // OSRS layout: wider to fit inventory on right side + // classic MMORPG layout: wider to fit inventory on right side width: state.screen === "offer" ? "680px" : "480px", }} > @@ -254,7 +254,7 @@ export function TradePanel({
- {/* Trade areas - OSRS layout: offers on left, inventory on right */} + {/* Trade areas - classic MMORPG layout: offers on left, inventory on right */}
{/* Left section: Trade offers */} @@ -420,7 +420,7 @@ export function TradePanel({
- {/* Trade status bar - OSRS style: free slots + wealth transfer */} + {/* Trade status bar - classic MMORPG style: free slots + wealth transfer */}
- {/* Partner free slots indicator (OSRS-style) */} + {/* Partner free slots indicator (classic MMORPG-style) */}
- {/* Right section: Inventory (OSRS style - only on offer screen) */} + {/* Right section: Inventory (classic MMORPG style - only on offer screen) */} {state.screen === "offer" && ( <> {/* Divider between offers and inventory */} diff --git a/packages/client/src/game/panels/TradePanel/components/InventoryItem.tsx b/packages/client/src/game/panels/TradePanel/components/InventoryItem.tsx index 44ef28e6d..2f690b309 100644 --- a/packages/client/src/game/panels/TradePanel/components/InventoryItem.tsx +++ b/packages/client/src/game/panels/TradePanel/components/InventoryItem.tsx @@ -1,7 +1,7 @@ /** * Inventory Item Component * - * Clickable inventory item for OSRS-style trade panel. + * Clickable inventory item for classic MMORPG-style trade panel. * Left-click: add 1 to trade * Right-click: show context menu */ diff --git a/packages/client/src/game/panels/TradePanel/components/InventoryMiniPanel.tsx b/packages/client/src/game/panels/TradePanel/components/InventoryMiniPanel.tsx index 129f97d05..9395f8ff2 100644 --- a/packages/client/src/game/panels/TradePanel/components/InventoryMiniPanel.tsx +++ b/packages/client/src/game/panels/TradePanel/components/InventoryMiniPanel.tsx @@ -2,7 +2,7 @@ * Inventory Mini Panel Component * * Inventory mini-panel for selecting items to trade. - * OSRS style: displayed to the right of trade offers, 4x7 grid matching inventory. + * classic MMORPG style: displayed to the right of trade offers, 4x7 grid matching inventory. * Left-click: add 1 item, Right-click: context menu */ @@ -39,7 +39,7 @@ export function InventoryMiniPanel({
void; @@ -161,7 +161,7 @@ export interface StatusOrbProps { } /** - * Get label color based on HP percentage (OSRS-style) + * Get label color based on HP percentage (classic MMORPG-style) * Green (>50%) -> Yellow (25-50%) -> Red (<25%) */ function getHpLabelColor(percent: number): string { @@ -386,7 +386,7 @@ export interface SpecialAttackOrbProps { } /** - * Special Attack Orb Component (OSRS-style) + * Special Attack Orb Component (classic MMORPG-style) * * Shows special attack energy with visual feedback: * - Light blue fill when spec weapon equipped @@ -510,7 +510,7 @@ export interface RunEnergyOrbProps { } /** - * Run Energy Orb Component (OSRS-style) + * Run Energy Orb Component (classic MMORPG-style) * * Shows run energy with toggle functionality: * - Amber/orange fill for energy level diff --git a/packages/client/src/ui/components/TouchActionBar.tsx b/packages/client/src/ui/components/TouchActionBar.tsx index a9daccde8..1b20e47c8 100644 --- a/packages/client/src/ui/components/TouchActionBar.tsx +++ b/packages/client/src/ui/components/TouchActionBar.tsx @@ -1,7 +1,7 @@ /** * Touch Action Bar Component * - * Mobile-optimized action bar with 5 slots (OSRS-mobile pattern). + * Mobile-optimized action bar with 5 slots (classic MMORPG-mobile pattern). * Features: * - 48x48px minimum touch targets * - 8px spacing between targets diff --git a/packages/client/src/ui/components/animations.ts b/packages/client/src/ui/components/animations.ts index 929078b9a..b8f3b1df4 100644 --- a/packages/client/src/ui/components/animations.ts +++ b/packages/client/src/ui/components/animations.ts @@ -2,7 +2,7 @@ * Animation Library * * Standard animation definitions for UI components. - * Based on RS3/MMO interface design patterns. + * Based on modern MMORPG/MMO interface design patterns. * * @packageDocumentation */ diff --git a/packages/client/src/ui/core/tooltip/useTooltipPosition.ts b/packages/client/src/ui/core/tooltip/useTooltipPosition.ts index 3e289281e..ee0383a4e 100644 --- a/packages/client/src/ui/core/tooltip/useTooltipPosition.ts +++ b/packages/client/src/ui/core/tooltip/useTooltipPosition.ts @@ -166,7 +166,7 @@ function checkOverflow( /** * Calculate optimal tooltip position with automatic flipping and shifting. * - * This implements RuneScape-style tooltip positioning where: + * This implements classic fantasy MMORPG-style tooltip positioning where: * - Tooltips flip to the opposite side if they would overflow * - Tooltips shift along their axis to stay fully visible * - Maintains consistent offset from the anchor point diff --git a/packages/client/src/ui/theme/animations.ts b/packages/client/src/ui/theme/animations.ts index 929078b9a..b8f3b1df4 100644 --- a/packages/client/src/ui/theme/animations.ts +++ b/packages/client/src/ui/theme/animations.ts @@ -2,7 +2,7 @@ * Animation Library * * Standard animation definitions for UI components. - * Based on RS3/MMO interface design patterns. + * Based on modern MMORPG/MMO interface design patterns. * * @packageDocumentation */ diff --git a/packages/client/src/ui/theme/themes.ts b/packages/client/src/ui/theme/themes.ts index 42a5f4115..5f0132e54 100644 --- a/packages/client/src/ui/theme/themes.ts +++ b/packages/client/src/ui/theme/themes.ts @@ -3,9 +3,9 @@ * * Two theme variants: * - base: Clean, minimal dark theme - * - hyperia: RS3-inspired dark theme with gold/bronze accents and glassmorphism + * - hyperia: modern MMORPG-inspired dark theme with gold/bronze accents and glassmorphism * - * Based on Runescape 3 visual design specifications. + * Based on classic fantasy MMORPG 3 visual design specifications. * * @packageDocumentation */ @@ -369,7 +369,7 @@ export const baseTheme: Theme = { /** * Hyperia Theme - * RS3-inspired dark theme with gold/bronze accents and enhanced glassmorphism + * modern MMORPG-inspired dark theme with gold/bronze accents and enhanced glassmorphism * Updated with more polished color palette for modern game UI */ export const hyperiaTheme: Theme = { @@ -1055,7 +1055,7 @@ export function getStatusBarGradient( } /** - * Get decorative panel border style (RS3-style bronze border) + * Get decorative panel border style (modern MMORPG-style bronze border) */ export function getDecorativeBorderStyle(theme: Theme): React.CSSProperties { if (theme.name === "hyperia") { diff --git a/packages/client/src/ui/tokens.ts b/packages/client/src/ui/tokens.ts index a4b384d9d..7f3d7c856 100644 --- a/packages/client/src/ui/tokens.ts +++ b/packages/client/src/ui/tokens.ts @@ -65,7 +65,7 @@ export const spacing = { */ export const typography = { fontFamily: { - /** Fantasy/medieval headers - Cinzel for RuneScape aesthetic */ + /** Fantasy/medieval headers - Cinzel for classic fantasy MMORPG aesthetic */ display: "'Cinzel', serif", /** UI body text - Inter for readability */ body: "'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif", @@ -173,7 +173,7 @@ export const shadows = { /** Extra large elevation */ xl: "0 20px 25px rgba(0, 0, 0, 0.6), 0 8px 10px rgba(0, 0, 0, 0.2)", - /** Panel shadow with golden glow (RuneScape aesthetic) */ + /** Panel shadow with golden glow (classic fantasy MMORPG aesthetic) */ panel: "0 8px 32px rgba(0, 0, 0, 0.6), 0 0 1px rgba(242, 208, 138, 0.2)", /** Panel hover state */ panelHover: diff --git a/packages/client/src/utils/itemUtils.ts b/packages/client/src/utils/itemUtils.ts index d256608aa..dab17e299 100644 --- a/packages/client/src/utils/itemUtils.ts +++ b/packages/client/src/utils/itemUtils.ts @@ -109,7 +109,7 @@ export function formatItemName(itemId: string): string { } /** - * Format quantity with K/M abbreviations (OSRS-style) + * Format quantity with K/M abbreviations (classic MMORPG-style) * * @param quantity - The quantity to format * @returns Formatted string (e.g., "1.5K", "10M") @@ -135,7 +135,7 @@ export function formatPrice(price: number): string { } /** - * Get quantity text color based on OSRS thresholds + * Get quantity text color based on classic MMORPG thresholds * * @param quantity - The quantity to check * @returns CSS color string diff --git a/packages/client/tests/e2e/combat.spec.ts b/packages/client/tests/e2e/combat.spec.ts index 3a9c411cc..d852052f9 100644 --- a/packages/client/tests/e2e/combat.spec.ts +++ b/packages/client/tests/e2e/combat.spec.ts @@ -737,7 +737,7 @@ describeCombat("Combat Interactions", () => { const skills = win.world?.entities?.player?.data?.skills; if (!skills) return null; - // Calculate combat level using OSRS formula + // Calculate combat level using classic combat formula const attack = skills.attack?.level ?? 1; const strength = skills.strength?.level ?? 1; const defence = skills.defence?.level ?? 1; diff --git a/packages/client/tests/e2e/silhouette.spec.ts b/packages/client/tests/e2e/silhouette.spec.ts index abb37ee7e..b04209c78 100644 --- a/packages/client/tests/e2e/silhouette.spec.ts +++ b/packages/client/tests/e2e/silhouette.spec.ts @@ -1,7 +1,7 @@ /** * Player Silhouette E2E Tests * - * Visual verification of RuneScape-style silhouette (depthTest=false, player overwrites). + * Visual verification of classic fantasy MMORPG-style silhouette (depthTest=false, player overwrites). */ import { test, expect, Page } from "@playwright/test"; diff --git a/packages/client/tests/e2e/skills.spec.ts b/packages/client/tests/e2e/skills.spec.ts index c7c171b44..c5ad78933 100644 --- a/packages/client/tests/e2e/skills.spec.ts +++ b/packages/client/tests/e2e/skills.spec.ts @@ -162,7 +162,7 @@ test.describe("Skills Panel", () => { const skillCount = await skillItems.count(); // Should have multiple skills displayed - // Common OSRS-style games have 20+ skills + // Common classic MMORPG-style games have 20+ skills expect(skillCount).toBeGreaterThanOrEqual(1); // Take screenshot @@ -302,7 +302,7 @@ test.describe("XP and Level Up", () => { for (const skillName of Object.keys(skills)) { const skill = skills[skillName]; - // Level should be between 1 and 99 (OSRS style) + // Level should be between 1 and 99 (classic MMORPG style) expect(skill.level).toBeGreaterThanOrEqual(1); expect(skill.level).toBeLessThanOrEqual(99); diff --git a/packages/contracts/src/libraries/CombatLevel.sol b/packages/contracts/src/libraries/CombatLevel.sol index 6e609cc51..ee018cda5 100644 --- a/packages/contracts/src/libraries/CombatLevel.sol +++ b/packages/contracts/src/libraries/CombatLevel.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.24; /** * @title CombatLevel - * @notice Calculates OSRS-accurate combat level from skill levels. + * @notice Calculates rules-accurate combat level from skill levels. * * Formula (must match TypeScript CombatCalculations.ts): * base = 0.25 × (Defense + Constitution + floor(Prayer / 2)) diff --git a/packages/contracts/src/libraries/Constants.sol b/packages/contracts/src/libraries/Constants.sol index 1a8a3dccd..1dd397c53 100644 --- a/packages/contracts/src/libraries/Constants.sol +++ b/packages/contracts/src/libraries/Constants.sol @@ -11,7 +11,7 @@ library Constants { // Inventory // ========================================================================= - /// @notice Maximum inventory slots (RuneScape-style) + /// @notice Maximum inventory slots (classic fantasy MMORPG-style) uint8 internal constant MAX_INVENTORY_SLOTS = 28; /// @notice Maximum equipment slot type index (0-10 inclusive) @@ -80,7 +80,7 @@ library Constants { uint64 internal constant MAX_GOLD = 2_147_483_647; // ========================================================================= - // Combat XP Rates (matches OSRS) + // Combat XP Rates (matches classic MMORPG) // ========================================================================= /// @notice XP per damage dealt for the trained combat skill (×100 for precision) diff --git a/packages/contracts/src/libraries/XPTable.sol b/packages/contracts/src/libraries/XPTable.sol index 3281a69cf..f43ebcc47 100644 --- a/packages/contracts/src/libraries/XPTable.sol +++ b/packages/contracts/src/libraries/XPTable.sol @@ -5,12 +5,12 @@ import { Constants } from "./Constants.sol"; /** * @title XPTable - * @notice OSRS-accurate XP table for skill levels 1-99. + * @notice rules-accurate XP table for skill levels 1-99. * * The XP formula for each level N (1-indexed) is: * xpForLevel[N] = sum from i=1 to N-1 of floor(i + 300 * 2^(i/7)) / 4 * - * This matches the RuneScape XP table exactly and must produce identical + * This matches the classic fantasy MMORPG XP table exactly and must produce identical * values to SkillsSystem.generateXPTable() in the TypeScript codebase. * * Because Solidity cannot do floating-point 2^(i/7), we use a precomputed @@ -30,10 +30,10 @@ library XPTable { // Precomputed XP thresholds for levels 1-99. // Generated from: floor(sum(i=1..N-1, floor(i + 300 * 2^(i/7)) / 4)) - // These values match the OSRS wiki exactly. + // These values match the classic MMORPG wiki exactly. // Generated from the TypeScript SkillsSystem.generateXPTable() formula. // These MUST match the game server's values exactly (JavaScript floating-point). - // Differs from OSRS wiki values by up to 37 XP at level 99 due to float rounding. + // Differs from classic MMORPG wiki values by up to 37 XP at level 99 due to float rounding. uint32[99] memory table = [ uint32(0), // Level 1 uint32(83), // Level 2 diff --git a/packages/contracts/src/systems/PlayerRegistrySystem.sol b/packages/contracts/src/systems/PlayerRegistrySystem.sol index 4f663690c..1e9c483e8 100644 --- a/packages/contracts/src/systems/PlayerRegistrySystem.sol +++ b/packages/contracts/src/systems/PlayerRegistrySystem.sol @@ -64,7 +64,7 @@ contract PlayerRegistrySystem is System { // Create reverse lookup CharacterOwner.set(characterId, playerAddress); - // Initialize combat skills with OSRS defaults + // Initialize combat skills with classic MMORPG defaults CombatSkills.set( characterId, 1, 0, // attack: level 1, 0 xp diff --git a/packages/contracts/src/systems/SkillSystem.sol b/packages/contracts/src/systems/SkillSystem.sol index 7b105deb9..fc7ebb660 100644 --- a/packages/contracts/src/systems/SkillSystem.sol +++ b/packages/contracts/src/systems/SkillSystem.sol @@ -16,7 +16,7 @@ import { CombatLevel } from "../libraries/CombatLevel.sol"; * them in a single transaction using updateCombatSkills() or * updateGatheringSkills() to minimize gas costs. * - * All level calculations use the OSRS XP formula via XPTable library, + * All level calculations use the classic MMORPG XP formula via XPTable library, * which must produce identical results to the TypeScript SkillsSystem. */ contract SkillSystem is System { diff --git a/packages/impostors/public/human_rigged.glb b/packages/impostors/public/human_rigged.glb index f2531e840..f6e3fb672 100644 Binary files a/packages/impostors/public/human_rigged.glb and b/packages/impostors/public/human_rigged.glb differ diff --git a/packages/plugin-hyperia/src/actions/goals.ts b/packages/plugin-hyperia/src/actions/goals.ts index 6fcabae68..55726f7cf 100644 --- a/packages/plugin-hyperia/src/actions/goals.ts +++ b/packages/plugin-hyperia/src/actions/goals.ts @@ -670,7 +670,7 @@ What You Can Do NOW: const isScripted = autonomyModeSetting === "scripted"; // Build intelligent LLM prompt with full context (unless scripted mode is enabled) - const selectionPrompt = `You are an AI agent playing a RuneScape-style MMORPG. Choose your next goal intelligently. + const selectionPrompt = `You are an AI agent playing a classic fantasy MMORPG. Choose your next goal intelligently. CURRENT STATUS: - Health: ${healthPercent}% diff --git a/packages/plugin-hyperia/src/content-packs/content-pack.ts b/packages/plugin-hyperia/src/content-packs/content-pack.ts index ae43ea66e..100bc7ac2 100644 --- a/packages/plugin-hyperia/src/content-packs/content-pack.ts +++ b/packages/plugin-hyperia/src/content-packs/content-pack.ts @@ -202,14 +202,14 @@ const rpgSystems: IGameSystem[] = [ ]; /** - * Runescape-Style RPG Content Pack + * Classic Fantasy RPG Content Pack * * This content pack connects ElizaOS agents to our polished RPG systems, * enabling AI agents to play in our RPG world with full system integration. */ -export const RunescapeRPGPack: IContentPack = { - id: "runescape-rpg", - name: "Runescape RPG Pack", +export const ClassicRPGPack: IContentPack = { + id: "classic-rpg", + name: "Classic RPG Pack", description: "Complete RPG experience with 54+ polished systems integrated for AI agents", version: "1.0.0", @@ -254,4 +254,4 @@ export const RunescapeRPGPack: IContentPack = { }, }; -export default RunescapeRPGPack; +export default ClassicRPGPack; diff --git a/packages/plugin-hyperia/src/content-packs/index.ts b/packages/plugin-hyperia/src/content-packs/index.ts index 094d3a197..e84b18734 100644 --- a/packages/plugin-hyperia/src/content-packs/index.ts +++ b/packages/plugin-hyperia/src/content-packs/index.ts @@ -4,8 +4,8 @@ * Centralized exports for all available content packs in the plugin-hyperia system. */ -export { RunescapeRPGPack as RPGContentPack } from "./content-pack.js"; -export { default as RunescapeRPGPack } from "./content-pack.js"; +export { ClassicRPGPack as RPGContentPack } from "./content-pack.js"; +export { default as ClassicRPGPack } from "./content-pack.js"; // Character profiles for agent personality differentiation export { diff --git a/packages/plugin-hyperia/src/managers/autonomous-behavior-manager.ts b/packages/plugin-hyperia/src/managers/autonomous-behavior-manager.ts index 365773180..ccbc49e7e 100644 --- a/packages/plugin-hyperia/src/managers/autonomous-behavior-manager.ts +++ b/packages/plugin-hyperia/src/managers/autonomous-behavior-manager.ts @@ -4001,7 +4001,7 @@ export class AutonomousBehaviorManager { } /** - * Build prompt for action selection with OSRS common sense knowledge + * Build prompt for action selection with classic MMORPG common sense knowledge * This prompt gives the LLM context AND common sense rules so it can make intelligent decisions */ private buildActionSelectionPrompt( @@ -4181,7 +4181,7 @@ export class AutonomousBehaviorManager { // === SYSTEM INSTRUCTION === const traits = getPersonalityTraits(this.runtime); lines.push( - "You are a character living in an OSRS-style RPG. You are preparing for duels against other agents.", + "You are a character living in a classic fantasy RPG. You are preparing for duels against other agents.", ); lines.push( "Every action you take should make you stronger for combat. Think step by step, keeping your personality and duel preparation in mind.", @@ -4397,7 +4397,7 @@ export class AutonomousBehaviorManager { lines.push(""); } - // === OSRS COMMON SENSE RULES === + // === classic MMORPG COMMON SENSE RULES === lines.push("=== GAME KNOWLEDGE (Important!) ==="); lines.push("These are the fundamental rules of the game:"); lines.push(""); @@ -5952,7 +5952,7 @@ export class AutonomousBehaviorManager { /** * Duel combat tick — strategic combat loop during duel fights. * - * Priority order (like a real RS player): + * Priority order (like an experienced player): * 1. Heal if health below threshold * 2. Movement — kite/chase/circle based on fight plan * 3. Adjust combat style & prayers based on phase diff --git a/packages/plugin-hyperia/src/providers/goalProvider.ts b/packages/plugin-hyperia/src/providers/goalProvider.ts index d060319d7..dbb4c01be 100644 --- a/packages/plugin-hyperia/src/providers/goalProvider.ts +++ b/packages/plugin-hyperia/src/providers/goalProvider.ts @@ -477,7 +477,7 @@ export function getCombatReadiness(service: HyperiaService): CombatReadiness { } // Check for weapon (deduct points based on combat capability) - // In OSRS, hatchets and pickaxes can be equipped and used as melee weapons + // In classic MMORPG, hatchets and pickaxes can be equipped and used as melee weapons const hasWeaponEquipped = detectHasWeapon(player); const hasCombatItem = hasCombatCapableItem(player); diff --git a/packages/plugin-hyperia/src/providers/goalTemplatesProvider.ts b/packages/plugin-hyperia/src/providers/goalTemplatesProvider.ts index 188aa2846..373798079 100644 --- a/packages/plugin-hyperia/src/providers/goalTemplatesProvider.ts +++ b/packages/plugin-hyperia/src/providers/goalTemplatesProvider.ts @@ -1,12 +1,12 @@ /** - * goalTemplatesProvider - Structured goal templates for OSRS beginner flows + * goalTemplatesProvider - Structured goal templates for classic MMORPG beginner flows * * Provides the LLM with recommended goal templates based on: * - Current player state (skills, inventory, equipment) * - Nearby resources and entities * - Prerequisites and progression paths * - * Goal templates represent common OSRS activities: + * Goal templates represent common classic MMORPG activities: * - Woodcutting basics * - Bronze gear crafting chain (mine -> smelt -> smith) * - Combat training @@ -71,7 +71,7 @@ export interface ScoredGoalTemplate extends GoalTemplate { } // ============================================================================ -// GOAL TEMPLATES - OSRS Beginner Flows +// GOAL TEMPLATES - classic MMORPG Beginner Flows // ============================================================================ const GOAL_TEMPLATES: GoalTemplate[] = [ @@ -788,7 +788,8 @@ function scoreTemplate( export const goalTemplatesProvider: Provider = { name: "goalTemplates", - description: "Structured goal templates for OSRS beginner activities", + description: + "Structured goal templates for classic MMORPG beginner activities", dynamic: true, position: 8, // After possibilitiesProvider diff --git a/packages/plugin-hyperia/src/providers/possibilitiesProvider.ts b/packages/plugin-hyperia/src/providers/possibilitiesProvider.ts index b0a622baa..35295c81d 100644 --- a/packages/plugin-hyperia/src/providers/possibilitiesProvider.ts +++ b/packages/plugin-hyperia/src/providers/possibilitiesProvider.ts @@ -59,7 +59,7 @@ interface FiremakingRecipe { xp: number; } -// Core smelting recipes (OSRS-style) +// Core smelting recipes (classic MMORPG-style) const SMELTING_RECIPES: SmeltingRecipe[] = [ { barId: "bronze_bar", @@ -95,7 +95,7 @@ const SMELTING_RECIPES: SmeltingRecipe[] = [ }, ]; -// Core smithing recipes (OSRS-style) +// Core smithing recipes (classic MMORPG-style) const SMITHING_RECIPES: SmithingRecipe[] = [ // Bronze items { diff --git a/packages/plugin-hyperia/src/services/HyperiaService.ts b/packages/plugin-hyperia/src/services/HyperiaService.ts index 8c37a18ad..c55939bad 100644 --- a/packages/plugin-hyperia/src/services/HyperiaService.ts +++ b/packages/plugin-hyperia/src/services/HyperiaService.ts @@ -2761,7 +2761,7 @@ Respond with ONLY the action name, nothing else.`; this.handleGoalOverride(data); break; - // Tile movement packets (RuneScape-style 600ms tick movement) + // Tile movement packets (classic fantasy MMORPG-style 600ms tick movement) case "tileMovementStart": { // Movement started - update position tracking // Packet contains: { id, startTile, path, running, destinationTile, moveSeq, emote } diff --git a/packages/plugin-hyperia/src/systems/PlayerMovementSystem.ts b/packages/plugin-hyperia/src/systems/PlayerMovementSystem.ts index 859d2ec77..53894dc0d 100644 --- a/packages/plugin-hyperia/src/systems/PlayerMovementSystem.ts +++ b/packages/plugin-hyperia/src/systems/PlayerMovementSystem.ts @@ -84,7 +84,7 @@ export class PlayerMovementSystem extends EventEmitter { private updateInterval: number = 50; // Network update interval in ms private lastNetworkUpdate: number = Date.now(); - /** Shared BFSPathfinder instance - same algorithm used by server for OSRS-accurate movement */ + /** Shared BFSPathfinder instance - same algorithm used by server for rules-accurate movement */ private pathfinder: BFSPathfinder = new BFSPathfinder(); constructor(world: World) { @@ -257,7 +257,7 @@ export class PlayerMovementSystem extends EventEmitter { /** * Find a path from start to end using the shared BFSPathfinder. * - * Uses the same OSRS-accurate pathfinding algorithm as the server: + * Uses the same rules-accurate pathfinding algorithm as the server: * - Naive diagonal pathing first (walk diagonally toward target, then straight) * - Falls back to BFS if obstacles block the naive path * diff --git a/packages/plugin-hyperia/src/utils/item-detection.ts b/packages/plugin-hyperia/src/utils/item-detection.ts index 112478843..504568440 100644 --- a/packages/plugin-hyperia/src/utils/item-detection.ts +++ b/packages/plugin-hyperia/src/utils/item-detection.ts @@ -248,7 +248,7 @@ export function hasWeapon( /** * Check if player has a combat-capable item (equipped OR in inventory) - * In OSRS, hatchets and pickaxes can be equipped and used as melee weapons. + * In classic MMORPG, hatchets and pickaxes can be equipped and used as melee weapons. * * @param player - Player entity with items and equipment * @returns true if player has any combat-capable item diff --git a/packages/procgen/src/building/generator/BuildingGenerator.ts b/packages/procgen/src/building/generator/BuildingGenerator.ts index 57cbe05d2..ad6f69752 100644 --- a/packages/procgen/src/building/generator/BuildingGenerator.ts +++ b/packages/procgen/src/building/generator/BuildingGenerator.ts @@ -825,7 +825,7 @@ export class BuildingGenerator { const floorGeometries: THREE.BufferGeometry[] = []; // Walkable surfaces const wallGeometries: THREE.BufferGeometry[] = []; // Non-walkable (walls, ceilings, props) const roofGeometries: THREE.BufferGeometry[] = []; - // Terrace railings are separate so they can be hidden with roofs (RuneScape-style) + // Terrace railings are separate so they can be hidden with roofs (classic fantasy MMORPG-style) const terraceRailingGeometries: THREE.BufferGeometry[] = []; // New geometry arrays for windows and doors @@ -1138,7 +1138,7 @@ export class BuildingGenerator { } } - // Create terrace railings mesh (hidden with roofs when inside building - RuneScape-style) + // Create terrace railings mesh (hidden with roofs when inside building - classic fantasy MMORPG-style) if (terraceRailingGeometries.length > 0) { const mergedTerraceRailings = mergeGeometries( terraceRailingGeometries, diff --git a/packages/procgen/src/terrain/TerrainGenerator.ts b/packages/procgen/src/terrain/TerrainGenerator.ts index dd6103c8c..ecdec0181 100644 --- a/packages/procgen/src/terrain/TerrainGenerator.ts +++ b/packages/procgen/src/terrain/TerrainGenerator.ts @@ -27,7 +27,7 @@ import type { // ============== DEFAULT CONFIGURATIONS ============== /** - * Default noise configuration for OSRS-style gentle rolling terrain + * Default noise configuration for classic MMORPG-style gentle rolling terrain */ export const DEFAULT_NOISE_CONFIG: TerrainNoiseConfig = { continent: { @@ -230,7 +230,7 @@ export class TerrainGenerator { height = (height + 1) * 0.5; height = Math.max(0, Math.min(1, height)); - // Apply gentle power curve for OSRS-style terrain + // Apply gentle power curve for classic MMORPG-style terrain height = Math.pow(height, 1.1); // Apply island shaping if enabled diff --git a/packages/procgen/src/terrain/TerrainShaderTSL.ts b/packages/procgen/src/terrain/TerrainShaderTSL.ts index 93b817417..edb862f64 100644 --- a/packages/procgen/src/terrain/TerrainShaderTSL.ts +++ b/packages/procgen/src/terrain/TerrainShaderTSL.ts @@ -5,7 +5,7 @@ * Both Asset Forge and the game engine share this code for visual consistency. * * Features: - * - OSRS-style flat-shaded vertex colors (no textures) + * - classic MMORPG-style flat-shaded vertex colors (no textures) * - Height and slope-based biome blending * - Noise-based dirt patches * - Snow at high elevations @@ -315,11 +315,11 @@ export interface TerrainMaterialOptions { } // ============================================================================ -// TERRAIN MATERIAL - OSRS Style (No Textures) +// TERRAIN MATERIAL - classic MMORPG Style (No Textures) // ============================================================================ /** - * Create the game-accurate OSRS-style terrain material + * Create the game-accurate classic MMORPG-style terrain material * * This is the EXACT same material used in the game engine. * Uses TSL (Three Shader Language) for WebGPU rendering. @@ -356,10 +356,10 @@ export function createTerrainMaterial( const slope = sub(float(1.0), abs(worldNormal.y)); // ============================================================================ - // OSRS-STYLE VERTEX COLORS + // classic MMORPG-STYLE VERTEX COLORS // ============================================================================ - // Core terrain colors (OSRS palette) + // Core terrain colors (classic MMORPG palette) const grassGreen = vec3(0.3, 0.55, 0.15); const grassDark = vec3(0.22, 0.42, 0.1); const dirtBrown = vec3(0.45, 0.32, 0.18); diff --git a/packages/server/public/web/physx-js-webidl.wasm b/packages/server/public/web/physx-js-webidl.wasm index fc6c23c3c..4adc05674 100755 Binary files a/packages/server/public/web/physx-js-webidl.wasm and b/packages/server/public/web/physx-js-webidl.wasm differ diff --git a/packages/server/src/database/migrations/0011_add_bank_tabs.sql b/packages/server/src/database/migrations/0011_add_bank_tabs.sql index 9618f1947..6c5240a82 100644 --- a/packages/server/src/database/migrations/0011_add_bank_tabs.sql +++ b/packages/server/src/database/migrations/0011_add_bank_tabs.sql @@ -1,4 +1,4 @@ --- Migration: Add bank tabs support (OSRS-style bank organization) +-- Migration: Add bank tabs support (classic MMORPG-style bank organization) -- -- Phase 2 of bank reorganization: -- 1. Add tabIndex column to bank_storage diff --git a/packages/server/src/database/migrations/0033_allow_bank_quantity_zero.sql b/packages/server/src/database/migrations/0033_allow_bank_quantity_zero.sql index e2c2cc344..3810b18d7 100644 --- a/packages/server/src/database/migrations/0033_allow_bank_quantity_zero.sql +++ b/packages/server/src/database/migrations/0033_allow_bank_quantity_zero.sql @@ -1,4 +1,4 @@ --- Migration: Allow quantity=0 in bank_storage for RS3-style placeholders +-- Migration: Allow quantity=0 in bank_storage for modern MMORPG-style placeholders -- When a player withdraws all of an item, the row stays with quantity=0 -- to reserve the bank slot (placeholder). The previous constraint (>=1) -- blocked this, causing withdraw failures. diff --git a/packages/server/src/database/repositories/BankRepository.ts b/packages/server/src/database/repositories/BankRepository.ts index 7d677a352..d23c727f6 100644 --- a/packages/server/src/database/repositories/BankRepository.ts +++ b/packages/server/src/database/repositories/BankRepository.ts @@ -36,7 +36,7 @@ export interface BankTab { } /** - * Bank placeholder representation (OSRS-style slot reservation) + * Bank placeholder representation (classic MMORPG-style slot reservation) */ export interface BankPlaceholder { tabIndex: number; diff --git a/packages/server/src/database/repositories/InventoryRepository.ts b/packages/server/src/database/repositories/InventoryRepository.ts index f28928f90..b4c2a337e 100644 --- a/packages/server/src/database/repositories/InventoryRepository.ts +++ b/packages/server/src/database/repositories/InventoryRepository.ts @@ -1,7 +1,7 @@ /** * InventoryRepository - Player inventory management operations * - * Handles player inventory storage with 28 slots (like RuneScape classic). + * Handles player inventory storage with 28 slots (like classic fantasy MMORPG classic). * Each item has an ID, quantity, slot index, and optional metadata. * * Responsibilities: diff --git a/packages/server/src/database/schema.ts b/packages/server/src/database/schema.ts index dd74e72ee..96c2e54e3 100644 --- a/packages/server/src/database/schema.ts +++ b/packages/server/src/database/schema.ts @@ -12,7 +12,7 @@ * - `users`: Account authentication and user profiles * - `entities`: Serialized world objects and props * - * **Character System** (RuneScape-inspired): + * **Character System** (classic fantasy MMORPG-inspired): * - `characters`: Player characters with stats, levels, XP, and position * - Combat skills: attack, strength, defense, constitution (health), ranged, prayer * - Gathering skills: woodcutting, fishing, firemaking, cooking @@ -366,7 +366,7 @@ export const items = pgTable("items", { /** * Inventory Table - Player inventory items * - * Stores items in a player's inventory (28 slots like RuneScape). + * Stores items in a player's inventory (28 slots like classic fantasy MMORPG). * Each row represents one stack of items in one slot. * * Key columns: @@ -482,7 +482,7 @@ export const bankStorage = pgTable( /** * Bank Tabs Table - Custom bank tab configuration * - * Stores custom bank tabs created by players (OSRS-style). + * Stores custom bank tabs created by players (classic MMORPG-style). * Tab 0 (main tab) is implicit and not stored here. * * Key columns: @@ -516,7 +516,7 @@ export const bankTabs = pgTable( ); /** - * Bank Placeholders Table - Reserved item slots (OSRS-style) + * Bank Placeholders Table - Reserved item slots (classic MMORPG-style) * * Stores placeholders for items that have been withdrawn. * When a player withdraws all of an item with placeholders enabled, @@ -855,7 +855,7 @@ export const characterTemplates = pgTable( /** * Layout Presets Table - User interface layout presets * - * Stores UI layout configurations for players (RS3-style NIS presets). + * Stores UI layout configurations for players (modern MMORPG-style NIS presets). * Each user can have up to 4 preset slots for different activities. * * Key columns: diff --git a/packages/server/src/eliza/AgentManager.ts b/packages/server/src/eliza/AgentManager.ts index b7fd03829..f50956bf1 100644 --- a/packages/server/src/eliza/AgentManager.ts +++ b/packages/server/src/eliza/AgentManager.ts @@ -1607,7 +1607,7 @@ export class AgentManager { const mapAwareness = instance.service.formatMapAwarenessForLlm(); const prompt = [ - `You are defining the CHARACTER BUILD IDENTITY for a player in an OSRS-style MMO.`, + `You are defining the CHARACTER BUILD IDENTITY for a player in a classic fantasy MMO.`, `This is NOT a vague ambition — it is a SPECIFIC, OPINIONATED build archetype that drives every decision.`, `Pick ONE clear identity and commit to it. Examples: "Melee tank", "Ranged pure", "Mage-prayer hybrid", "Skiller (woodcutting/fishing)", "Combat berserker".`, `The narrative should describe WHO this character IS as a player and what they prioritize. Be bold — no "balanced" or "well-rounded" hedging.`, diff --git a/packages/server/src/eliza/ModelAgentSpawner.ts b/packages/server/src/eliza/ModelAgentSpawner.ts index 946e7ef62..d20cd74bc 100644 --- a/packages/server/src/eliza/ModelAgentSpawner.ts +++ b/packages/server/src/eliza/ModelAgentSpawner.ts @@ -1074,7 +1074,7 @@ async function createBehaviorPlan( ).length; const prompt = [ - `You are ${config.displayName}, an OSRS-style RPG agent between arena duels.`, + `You are ${config.displayName}, a classic fantasy RPG agent between arena duels.`, `Plan your next 3-5 actions to prepare for the next duel.`, ``, `STATE: HP ${healthPct}%, ${inventory.length}/28 inventory, ${foodCount} food, ${inCombat ? "IN COMBAT" : "idle"}`, diff --git a/packages/server/src/eliza/__tests__/BehaviorPlan.live.test.ts b/packages/server/src/eliza/__tests__/BehaviorPlan.live.test.ts index 34bcd0fd2..d1995ac0a 100644 --- a/packages/server/src/eliza/__tests__/BehaviorPlan.live.test.ts +++ b/packages/server/src/eliza/__tests__/BehaviorPlan.live.test.ts @@ -86,7 +86,7 @@ function buildBehaviorPrompt(scenario: { items: Array<{ name: string; distance: number }>; }): string { return [ - `You are ${scenario.agentName}, an OSRS-style RPG agent between arena duels.`, + `You are ${scenario.agentName}, a classic fantasy RPG agent between arena duels.`, `Plan your next 3-5 actions to prepare for the next duel.`, ``, `STATE: HP ${scenario.healthPct}%, ${scenario.inventoryCount}/28 inventory, ${scenario.foodCount} food, ${scenario.inCombat ? "IN COMBAT" : "idle"}`, diff --git a/packages/server/src/eliza/agentHelpers.ts b/packages/server/src/eliza/agentHelpers.ts index 7a3f66d9d..d0d387ad3 100644 --- a/packages/server/src/eliza/agentHelpers.ts +++ b/packages/server/src/eliza/agentHelpers.ts @@ -72,7 +72,7 @@ export const MODEL_SETTING_KEYS: Record< // ============================================================================ /** Base competitive system prompt shared by all agents */ -export const COMPETITIVE_SYSTEM_PROMPT = `You are an elite AI competitor in Hyperia, a RuneScape-style MMORPG. Your singular mission is DOMINANCE through strategic PvP combat. +export const COMPETITIVE_SYSTEM_PROMPT = `You are an elite AI competitor in Hyperia, a classic fantasy MMORPG. Your singular mission is DOMINANCE through strategic PvP combat. ## COMBAT DOCTRINE - Analyze opponent's combat level, equipment, and fighting style before engaging diff --git a/packages/server/src/eliza/llmBehaviorDecision.ts b/packages/server/src/eliza/llmBehaviorDecision.ts index 224c4aef7..a3c60c948 100644 --- a/packages/server/src/eliza/llmBehaviorDecision.ts +++ b/packages/server/src/eliza/llmBehaviorDecision.ts @@ -746,7 +746,7 @@ export function buildBehaviorDecisionPrompt( .join("\n"); return [ - `You are ${instance.config.name}, an autonomous agent playing an OSRS-style RPG 24/7.`, + `You are ${instance.config.name}, an autonomous agent playing a classic fantasy RPG 24/7.`, `You THINK before you act. Every tick (~8s), you assess the situation, follow or revise your plan, and pick the best action.`, stuckWarning, ``, diff --git a/packages/server/src/systems/DuelScheduler/index.ts b/packages/server/src/systems/DuelScheduler/index.ts index a956143e2..ec24a5fe0 100644 --- a/packages/server/src/systems/DuelScheduler/index.ts +++ b/packages/server/src/systems/DuelScheduler/index.ts @@ -274,7 +274,7 @@ export class DuelScheduler { const ranged = data.skills.ranged?.level || 1; const magic = data.skills.magic?.level || 1; - // OSRS combat level formula (simplified) + // classic MMORPG combat level formula (simplified) const base = 0.25 * (defence + hitpoints + Math.floor(prayer / 2)); const melee = 0.325 * (attack + strength); const range = 0.325 * Math.floor(ranged * 1.5); diff --git a/packages/server/src/systems/DuelSystem/ArenaPoolManager.ts b/packages/server/src/systems/DuelSystem/ArenaPoolManager.ts index 7bae1a30e..29d899aab 100644 --- a/packages/server/src/systems/DuelSystem/ArenaPoolManager.ts +++ b/packages/server/src/systems/DuelSystem/ArenaPoolManager.ts @@ -9,7 +9,7 @@ * - Release arenas when duels complete * - Provide spawn points and bounds for each arena * - * Arena Layout (OSRS-style): + * Arena Layout (classic MMORPG-style): * - 6 rectangular arenas arranged in a 2x3 grid * - Each arena has 2 spawn points (north and south) * - Arena bounds used for movement clamping if noMovement rule diff --git a/packages/server/src/systems/DuelSystem/DuelCombatResolver.ts b/packages/server/src/systems/DuelSystem/DuelCombatResolver.ts index 652d5cde6..a4bbcf9f9 100644 --- a/packages/server/src/systems/DuelSystem/DuelCombatResolver.ts +++ b/packages/server/src/systems/DuelSystem/DuelCombatResolver.ts @@ -475,7 +475,7 @@ export class DuelCombatResolver { /** * Restore player to full stats after duel - * OSRS-accurate: Both winner and loser get full HP, prayer, stamina restored + * rules-accurate: Both winner and loser get full HP, prayer, stamina restored * @param spawnPosition - Must match the teleport destination to avoid lerpPosition conflicts */ private restorePlayerHealth( diff --git a/packages/server/src/systems/DuelSystem/config.ts b/packages/server/src/systems/DuelSystem/config.ts index 20710ac7b..98d3c3e94 100644 --- a/packages/server/src/systems/DuelSystem/config.ts +++ b/packages/server/src/systems/DuelSystem/config.ts @@ -4,7 +4,7 @@ * Centralized configuration constants for the duel system. * Eliminates magic numbers throughout the codebase. * - * All timing values are in game ticks (600ms each, OSRS-accurate). + * All timing values are in game ticks (600ms each, rules-accurate). * Use ticksToMs() helper or multiply by TICK_DURATION_MS for setTimeout/setInterval. * All distance values are in tiles/units. */ @@ -48,7 +48,7 @@ export const SESSION_MAX_AGE_TICKS = 3000; /** * Delay before resolving duel after death to allow animation - * OSRS-accurate: 8 ticks ≈ 4.8 seconds (close to 5s, aligned to tick boundary) + * rules-accurate: 8 ticks ≈ 4.8 seconds (close to 5s, aligned to tick boundary) */ export const DEATH_RESOLUTION_DELAY_TICKS = 8; @@ -82,7 +82,7 @@ export { TICK_DURATION_MS }; /** * Maximum distance (in tiles) between players to create/maintain a challenge - * OSRS-accurate: 15 tiles + * rules-accurate: 15 tiles */ export const CHALLENGE_DISTANCE_TILES = 15; diff --git a/packages/server/src/systems/DuelSystem/index.ts b/packages/server/src/systems/DuelSystem/index.ts index f13307466..1277651ae 100644 --- a/packages/server/src/systems/DuelSystem/index.ts +++ b/packages/server/src/systems/DuelSystem/index.ts @@ -1,5 +1,5 @@ /** - * DuelSystem - Server-authoritative player-to-player dueling (OSRS-accurate) + * DuelSystem - Server-authoritative player-to-player dueling (rules-accurate) * * Manages duel sessions with rules negotiation, stakes, and combat enforcement. * @@ -1154,7 +1154,7 @@ export class DuelSystem { const session = this.getPlayerDuel(playerId); if (!session) return true; // Not in duel, can move freely - // Freeze during countdown (OSRS-accurate) + // Freeze during countdown (rules-accurate) if (session.state === "COUNTDOWN") { return false; } @@ -1324,7 +1324,7 @@ export class DuelSystem { session.state = "FIGHTING"; session.fightStartedAt = Date.now(); - // OSRS-accurate: Restore both players to full stats before the fight + // rules-accurate: Restore both players to full stats before the fight this.restorePlayerStats(session.challengerId); this.restorePlayerStats(session.targetId); @@ -1354,7 +1354,7 @@ export class DuelSystem { /** * Restore a player to full health, prayer, and stamina before a duel fight - * OSRS-accurate: Players always start duels at full stats + * rules-accurate: Players always start duels at full stats */ private restorePlayerStats(playerId: string): void { const playerEntity = this.world.entities?.get?.(playerId); diff --git a/packages/server/src/systems/GameTickProcessor.ts b/packages/server/src/systems/GameTickProcessor.ts index 8b6f7f22c..cad9dd504 100644 --- a/packages/server/src/systems/GameTickProcessor.ts +++ b/packages/server/src/systems/GameTickProcessor.ts @@ -1,20 +1,19 @@ /** - * GameTickProcessor - OSRS-Accurate Tick Processing + * GameTickProcessor - Rules-Accurate Tick Processing * * Implements Henke's Model for deterministic game tick processing: * 1. Client inputs processed (from previous tick) * 2. NPCs processed (in spawn order): timers → queues → movement → combat * 3. Players processed (in PID order): queues → timers → movement → combat - * 4. Queued damage applied (OSRS damage asymmetry) + * 4. Queued damage applied (classic MMORPG damage asymmetry) * 5. State broadcast (batched) * * CRITICAL: NPCs process BEFORE players. This creates the asymmetric - * damage timing that defines OSRS combat feel: + * damage timing that defines classic MMORPG combat feel: * - NPC → Player damage: Same tick (NPC queues, Player processes same tick) * - Player → NPC damage: Next tick (Player queues, NPC processes next tick) * - * @see https://oldschool.runescape.wiki/w/Game_tick - * @see COMBAT_SYSTEM_AUDIT.md for full OSRS research + * @see COMBAT_SYSTEM_AUDIT.md for full classic MMORPG research */ import type { World } from "@hyperforge/shared"; @@ -111,7 +110,7 @@ interface PlayerEntityInterface { export type DamageAttackType = "melee" | "ranged" | "magic"; /** - * Queued damage for OSRS-style tick scheduling + * Queued damage for classic MMORPG-style tick scheduling * * Hit delay based on attack type: * - Melee: 0 tick delay (instant) @@ -147,7 +146,7 @@ interface QueuedBroadcast { } /** - * GameTickProcessor - Unified OSRS-accurate tick processor + * GameTickProcessor - Unified rules-accurate tick processor * * Processes all game logic in deterministic order each tick: * 1. Inputs → 2. NPCs → 3. Players → 4. Damage → 5. Broadcast @@ -160,26 +159,25 @@ export class GameTickProcessor { private pendingAttacks: PendingAttackManager; private broadcastManager: BroadcastManager; - // OSRS-accurate script queues + // rules-accurate script queues // Players have Strong/Normal/Weak/Soft priority system // NPCs have single queue type (FIFO) private playerScriptQueue: PlayerScriptQueue | null = null; private npcScriptQueue: NPCScriptQueue | null = null; - // OSRS-accurate face direction manager + // rules-accurate face direction manager // Handles deferred face direction processing at end of tick - // @see https://osrs-docs.com/docs/packets/outgoing/updating/masks/face-direction/ private faceDirectionManager: FaceDirectionManager | null = null; // Feature flag to enable/disable new tick processing // When false, falls back to legacy per-system tick processing private enabled = true; - // Feature flag for OSRS script queue system + // Feature flag for classic MMORPG script queue system // When true, uses Strong/Normal/Weak/Soft priority system private scriptQueueEnabled = true; - // Damage queue for next-tick application (OSRS asymmetry) + // Damage queue for next-tick application (classic MMORPG asymmetry) private damageQueue: QueuedDamage[] = []; // Broadcast queue for end-of-tick batching @@ -266,7 +264,7 @@ export class GameTickProcessor { this.npcScriptQueue = deps.npcScriptQueue; } - // Face direction manager (OSRS-accurate deferred facing) + // Face direction manager (rules-accurate deferred facing) if (deps.faceDirectionManager) { this.faceDirectionManager = deps.faceDirectionManager; } @@ -299,7 +297,7 @@ export class GameTickProcessor { setEnabled(enabled: boolean): void { this.enabled = enabled; console.log( - `[GameTickProcessor] ${enabled ? "Enabled" : "Disabled"} OSRS-accurate tick processing`, + `[GameTickProcessor] ${enabled ? "Enabled" : "Disabled"} rules-accurate tick processing`, ); } @@ -311,13 +309,13 @@ export class GameTickProcessor { } /** - * Enable or disable OSRS script queue system. + * Enable or disable classic MMORPG script queue system. * When enabled, uses Strong/Normal/Weak/Soft priority system. */ setScriptQueueEnabled(enabled: boolean): void { this.scriptQueueEnabled = enabled; console.log( - `[GameTickProcessor] ${enabled ? "Enabled" : "Disabled"} OSRS script queue system`, + `[GameTickProcessor] ${enabled ? "Enabled" : "Disabled"} classic MMORPG script queue system`, ); } @@ -350,7 +348,7 @@ export class GameTickProcessor { } /** - * Process a single game tick - OSRS accurate order + * Process a single game tick - rules-accurate order * * This is the main entry point called by TickSystem. * Processes all game logic in deterministic order. @@ -363,7 +361,7 @@ export class GameTickProcessor { // Update processing order if entities changed this.updateProcessingOrder(); - // PHASE 0: Reset per-tick flags (OSRS face direction system) + // PHASE 0: Reset per-tick flags (classic MMORPG face direction system) // Must happen BEFORE any movement processing this.faceDirectionManager?.resetMovementFlags(); @@ -371,15 +369,14 @@ export class GameTickProcessor { this.processInputs(tickNumber); // PHASE 2: Process all NPCs (in spawn order) - // OSRS: NPCs process BEFORE players + // classic MMORPG: NPCs process BEFORE players this.processNPCs(tickNumber); // PHASE 3: Process all Players (in PID/connection order) this.processPlayers(tickNumber); - // PHASE 3.5: Process face direction (OSRS-accurate) + // PHASE 3.5: Process face direction (rules-accurate) // Only applies rotation if player has faceTarget AND did NOT move this tick - // @see https://osrs-docs.com/docs/packets/outgoing/updating/masks/face-direction/ this.faceDirectionManager?.processFaceDirection(this.playerProcessingOrder); // PHASE 4: Apply queued damage from previous tick @@ -483,7 +480,7 @@ export class GameTickProcessor { /** * PHASE 2: Process all NPCs in spawn order * - * OSRS Order per NPC: + * classic MMORPG Order per NPC: * 1. Timers execute (BEFORE queues for NPCs!) * 2. Queue scripts execute (single queue type) * 3. Movement processing @@ -503,7 +500,7 @@ export class GameTickProcessor { // Skip dead mobs if ((mob.config?.currentHealth ?? 0) <= 0) continue; - // OSRS ORDER FOR NPCs: + // classic MMORPG ORDER FOR NPCs: // 1. Timers execute (BEFORE queues for NPCs!) // 2. Queue scripts execute (single queue type - FIFO) // 3. Movement processing @@ -512,7 +509,7 @@ export class GameTickProcessor { // 1. Process NPC AI (handles timers internally) this.processNPCAI(mob, tickNumber); - // 2. Process NPC script queue (OSRS-accurate) + // 2. Process NPC script queue (rules-accurate) // NPCs have single queue type (no priority system) if (this.scriptQueueEnabled && this.npcScriptQueue) { this.npcScriptQueue.processNPCTick(mobId, tickNumber); @@ -540,7 +537,7 @@ export class GameTickProcessor { /** * Process NPC AI for this tick * - * In OSRS: NPCs run timers BEFORE queues. + * In classic MMORPG: NPCs run timers BEFORE queues. * Our AIStateMachine handles this internally. */ private processNPCAI(mob: MobEntityInterface, _tickNumber: number): void { @@ -577,7 +574,7 @@ export class GameTickProcessor { /** * PHASE 3: Process all Players in PID order * - * OSRS Order per Player: + * classic MMORPG Order per Player: * 1. Queue scripts execute (Strong → Normal → Weak) * 2. Timers execute (AFTER queues for Players!) * 3. Movement processing @@ -598,13 +595,13 @@ export class GameTickProcessor { // Skip dead or loading players if (player.data?.alive === false || player.data?.isLoading) continue; - // OSRS ORDER FOR PLAYERS: + // classic MMORPG ORDER FOR PLAYERS: // 1. Queue scripts execute (Strong > Normal > Weak, then Soft always) // 2. Timers execute (AFTER queues for Players!) // 3. Movement processing // 4. Combat interactions - // 1. Process player script queue (OSRS-accurate) + // 1. Process player script queue (rules-accurate) // Players have Strong/Normal/Weak/Soft priority system if (this.scriptQueueEnabled && this.playerScriptQueue) { this.playerScriptQueue.processPlayerTick(playerId, tickNumber); @@ -635,7 +632,7 @@ export class GameTickProcessor { /** * Process player combat turn * - * Player → NPC damage is QUEUED for next tick (OSRS asymmetry) + * Player → NPC damage is QUEUED for next tick (classic MMORPG asymmetry) */ private processPlayerCombat(playerId: string, tickNumber: number): void { const combatSystem = this.world.getSystem("combat") as @@ -650,7 +647,7 @@ export class GameTickProcessor { /** * Queue damage for future tick application * - * This implements the OSRS damage asymmetry: + * This implements the classic MMORPG damage asymmetry: * - Player → NPC: applyAtTick = currentTick + 1 * - NPC → Player: applyAtTick = currentTick (same tick) */ @@ -659,12 +656,12 @@ export class GameTickProcessor { } /** - * Queue damage with OSRS-accurate hit delay calculation + * Queue damage with rules-accurate hit delay calculation * * This method calculates the appropriate hit delay based on attack type * and distance, then queues the damage to apply at the correct tick. * - * OSRS Hit Delay Formulas: + * classic MMORPG Hit Delay Formulas: * - Melee: 0 ticks (instant) * - Ranged: 1 + floor((3 + distance) / 6) ticks * - Magic: 1 + floor((1 + distance) / 3) ticks @@ -715,7 +712,7 @@ export class GameTickProcessor { // Cap at maximum delay (10 ticks) hitDelayTicks = Math.min(hitDelayTicks, 10); - // Apply OSRS damage asymmetry + // Apply classic MMORPG damage asymmetry // Player → NPC damage: +1 tick (queued for next tick) // NPC → Player damage: +0 ticks (same tick) let asymmetryDelay = 0; diff --git a/packages/server/src/systems/ServerNetwork/FaceDirectionManager.ts b/packages/server/src/systems/ServerNetwork/FaceDirectionManager.ts index 9a154fb46..eb762f961 100644 --- a/packages/server/src/systems/ServerNetwork/FaceDirectionManager.ts +++ b/packages/server/src/systems/ServerNetwork/FaceDirectionManager.ts @@ -1,16 +1,15 @@ /** - * FaceDirectionManager - OSRS-Accurate Face Direction System + * FaceDirectionManager - Rules-Accurate Face Direction System * - * Implements the OSRS face direction mask behavior: + * Implements the classic MMORPG face direction mask behavior: * 1. When player interacts with object/NPC, faceTarget is SET (not applied) * 2. At END of each tick, if player did NOT move, rotation is applied * 3. If player moved, rotation is skipped but faceTarget PERSISTS * 4. Player will face the target when they eventually stop moving * - * This creates the authentic OSRS behavior where clicking a tree then + * This creates the authentic classic MMORPG behavior where clicking a tree then * walking away will still cause you to face the tree once you stop. * - * @see https://osrs-docs.com/docs/packets/outgoing/updating/masks/face-direction/ */ import type { World } from "@hyperforge/shared"; @@ -57,14 +56,14 @@ interface FaceableEntity { } /** - * OSRS 8-direction constants + * classic MMORPG 8-direction constants * Players/NPCs can only face these 8 directions */ const DIRECTION_COUNT = 8; const DIRECTION_STEP = (Math.PI * 2) / DIRECTION_COUNT; // 45 degrees = PI/4 /** - * FaceDirectionManager handles OSRS-accurate deferred face direction + * FaceDirectionManager handles rules-accurate deferred face direction */ export class FaceDirectionManager { private world: World; @@ -86,7 +85,7 @@ export class FaceDirectionManager { * Set a face target for a player * Called when player interacts with objects, NPCs, resources, etc. * - * OSRS: The target is stored but NOT applied until end of tick + * classic MMORPG: The target is stored but NOT applied until end of tick * * @param playerId - Player to set face target for * @param targetX - X coordinate to face @@ -220,7 +219,7 @@ export class FaceDirectionManager { * Mark a player as having moved this tick * Called by TileMovementManager when player moves * - * OSRS: If entity moved, face direction is NOT applied this tick + * classic MMORPG: If entity moved, face direction is NOT applied this tick * * @param playerId - Player who moved */ @@ -256,7 +255,7 @@ export class FaceDirectionManager { * Process face direction for all players * Called at END of tick by GameTickProcessor, AFTER all movement * - * OSRS behavior: + * classic MMORPG behavior: * - Only applies rotation if player has faceTarget AND did NOT move * - faceTarget persists even if not applied (player will face when they stop) * - Rotation snapped to 8 directions (N, NE, E, SE, S, SW, W, NW) @@ -283,7 +282,7 @@ export class FaceDirectionManager { ); } - // OSRS: Skip if player moved this tick (but keep targets for later) + // classic MMORPG: Skip if player moved this tick (but keep targets for later) if (player.movedThisTick) { if (DEBUG_FACE_DIRECTION) { if (player.cardinalFaceDirection) { @@ -353,7 +352,7 @@ export class FaceDirectionManager { // Calculate raw angle const rawAngle = Math.atan2(dx, dz); - // OSRS: Snap to nearest 45 degrees (8 directions) + // classic MMORPG: Snap to nearest 45 degrees (8 directions) const snappedAngle = Math.round(rawAngle / DIRECTION_STEP) * DIRECTION_STEP; @@ -380,7 +379,7 @@ export class FaceDirectionManager { ); } - // OSRS: Clear face target after successfully applying + // classic MMORPG: Clear face target after successfully applying player.faceTarget = undefined; } } diff --git a/packages/server/src/systems/ServerNetwork/FollowManager.ts b/packages/server/src/systems/ServerNetwork/FollowManager.ts index 4a0fa3552..f96adea7a 100644 --- a/packages/server/src/systems/ServerNetwork/FollowManager.ts +++ b/packages/server/src/systems/ServerNetwork/FollowManager.ts @@ -2,16 +2,16 @@ * FollowManager * * Server-authoritative system for tracking players following other players. - * Implements OSRS-accurate following behavior. + * Implements rules-accurate following behavior. * - * OSRS-style behavior (from wiki): + * classic MMORPG-style behavior (from wiki): * 1. Player right-clicks another player and selects "Follow" * 2. Follower walks behind the leader (not on same tile) * 3. When leader moves, follower re-paths to stay behind them * 4. Following continues indefinitely until cancelled * 5. Cancelled by: clicking to walk, trading, equipping items, target disconnecting * - * @see https://runescape.wiki/w/Follow + * @see https://classic.wiki/w/Follow */ import type { World, TileCoord } from "@hyperforge/shared"; @@ -55,11 +55,10 @@ export class FollowManager { * Start following another player * Called when player selects "Follow" from context menu * - * OSRS-ACCURATE: Does NOT immediately start moving. + * RULES-ACCURATE: Does NOT immediately start moving. * Movement is deferred to processTick() which runs on the NEXT tick, * creating the characteristic 1-tick delay before follower reacts. * - * @see https://oldschool.runescape.wiki/w/Game_tick - "Each action registered * within one tick will start to take place by the beginning of the next tick" */ startFollowing(followerId: string, targetId: string): void { @@ -93,7 +92,7 @@ export class FollowManager { // Set up follow state - DON'T immediately move // processTick() will handle path calculation on NEXT tick - // This creates the OSRS-accurate 1-tick delay before following starts + // This creates the rules-accurate 1-tick delay before following starts this.following.set(followerId, { followerId, targetId, @@ -134,7 +133,7 @@ export class FollowManager { /** * Process all following players - called every tick * - * OSRS-ACCURATE behavior: + * RULES-ACCURATE behavior: * - Uses PREVIOUS tile (last tile stepped off during movement) * - This is 1 tile behind current position, stays unchanged when stopped * - Creates proper trailing: follower stops 1 tile behind when target stops @@ -154,9 +153,9 @@ export class FollowManager { } for (const [followerId, state] of this.following) { - // OSRS-ACCURATE: Enforce 1-tick delay before following starts + // RULES-ACCURATE: Enforce 1-tick delay before following starts // If follow was registered THIS tick, skip processing until NEXT tick - // This matches OSRS: "Each action registered within one tick will start + // This matches classic MMORPG: "Each action registered within one tick will start // to take place by the beginning of the next tick" if (state.startTick === this.currentTickNumber) { continue; @@ -187,7 +186,7 @@ export class FollowManager { // Zero-allocation: write to pre-allocated tile object worldToTileInto(followerPos.x, followerPos.z, this._tempFollowerTile); - // OSRS-ACCURATE: Get target's PREVIOUS tile (last tile they stepped off) + // RULES-ACCURATE: Get target's PREVIOUS tile (last tile they stepped off) // This is always 1 tile behind their current position // When target stops, previousTile stays at the last stepped-off position const previousTile = this.tileMovementManager.getPreviousTile( diff --git a/packages/server/src/systems/ServerNetwork/InteractionSessionManager.ts b/packages/server/src/systems/ServerNetwork/InteractionSessionManager.ts index 463089b92..508386c3b 100644 --- a/packages/server/src/systems/ServerNetwork/InteractionSessionManager.ts +++ b/packages/server/src/systems/ServerNetwork/InteractionSessionManager.ts @@ -3,7 +3,7 @@ * * Server-authoritative management of UI interaction sessions (store, bank, dialogue). * - * PRODUCTION PATTERN (OSRS/WoW style): + * PRODUCTION PATTERN (classic MMORPG/WoW style): * - Server is the single source of truth for UI state * - Server tracks active sessions per player * - Server validates distance and sends close packets when player moves away @@ -121,7 +121,7 @@ export class InteractionSessionManager implements ISessionReader { // - Distance validation (player walks too far) // - Player disconnect // - // This is the correct server-authoritative pattern used by OSRS/WoW. + // This is the correct server-authoritative pattern used by classic MMORPG/WoW. // Listen for bank open events to create sessions // We listen for BOTH BANK_OPEN (direct click) and BANK_OPEN_REQUEST (via dialogue) @@ -198,8 +198,8 @@ export class InteractionSessionManager implements ISessionReader { // Same reasoning as STORE_CLOSE above - user-initiated closes should not // clear the server session to avoid race conditions with new UI opens. - // OSRS-accurate: Close bank/store/dialogue if player is attacked - // In OSRS, being attacked (even a splash/miss) interrupts banking + // rules-accurate: Close bank/store/dialogue if player is attacked + // In classic MMORPG, being attacked (even a splash/miss) interrupts banking const combatDamageHandler = (event: unknown) => { const data = event as { targetId?: string; @@ -209,7 +209,7 @@ export class InteractionSessionManager implements ISessionReader { if (!data.targetId || data.targetType !== "player") { return; } - // OSRS-accurate: Close session when player is ATTACKED, not just when taking damage + // rules-accurate: Close session when player is ATTACKED, not just when taking damage // Even a splash/miss (damage=0) interrupts banking - being in combat matters if (this.sessions.has(data.targetId)) { this.closeSession(data.targetId, "combat"); @@ -401,7 +401,7 @@ export class InteractionSessionManager implements ISessionReader { return { valid: false, reason: "target_gone" }; } - // Calculate distance (Chebyshev/OSRS-style) using shared function and constants + // Calculate distance (Chebyshev/classic MMORPG-style) using shared function and constants const distance = chebyshevDistance(playerEntity.position, targetPos); const maxDistance = INTERACTION_DISTANCE[session.sessionType]; diff --git a/packages/server/src/systems/ServerNetwork/PendingAttackManager.ts b/packages/server/src/systems/ServerNetwork/PendingAttackManager.ts index 90c31be66..883516788 100644 --- a/packages/server/src/systems/ServerNetwork/PendingAttackManager.ts +++ b/packages/server/src/systems/ServerNetwork/PendingAttackManager.ts @@ -4,7 +4,7 @@ * Server-authoritative system for tracking players walking toward mobs to attack. * This replaces unreliable client-side tracking with 100% reliable server-side logic. * - * OSRS-style behavior (from wiki): + * classic MMORPG-style behavior (from wiki): * 1. Player clicks mob to attack * 2. If not in range, server queues "pending attack" and moves player toward mob * 3. Every tick, server re-checks range and re-paths if mob moved @@ -12,7 +12,6 @@ * 5. New click or disconnect cancels pending attack * 6. NO TIMEOUT - pathfinding recalculates every tick until target found * - * @see https://oldschool.runescape.wiki/w/Pathfinding */ import type { World, TileCoord } from "@hyperforge/shared"; @@ -68,7 +67,7 @@ export class PendingAttackManager { * Queue a pending attack for a player * Called when player clicks target but is not in range * - * OSRS: When clicking an NPC/player, pathfinding targets all tiles within attack range + * classic MMORPG: When clicking an NPC/player, pathfinding targets all tiles within attack range * * @param attackRange - Weapon's attack range (1 = standard melee/unarmed, 2 = halberd, 10 = ranged/magic) * @param targetType - "mob" for PvE, "player" for PvP @@ -174,15 +173,15 @@ export class PendingAttackManager { /** * Process all pending attacks - called every tick * - * OSRS behavior (from wiki): + * classic MMORPG behavior (from wiki): * - "if the clicked entity is an NPC or player, a new pathfinding attempt * will be started every tick, until a target tile can be found" * - NO TIMEOUT - players follow indefinitely until they click elsewhere - * - Uses OSRS melee range rules (cardinal-only for range 1) + * - Uses classic MMORPG melee range rules (cardinal-only for range 1) */ processTick(_currentTick: number): void { for (const [playerId, pending] of this.pendingAttacks) { - // NO TIMEOUT - OSRS follows indefinitely (removed timeout check) + // NO TIMEOUT - classic MMORPG follows indefinitely (removed timeout check) // Check if target still exists and is alive (supports both mobs and players) if (!this.isTargetAlive(pending.targetId, pending.targetType)) { @@ -208,7 +207,7 @@ export class PendingAttackManager { worldToTileInto(playerPos.x, playerPos.z, this._playerTile); worldToTileInto(targetPos.x, targetPos.z, this._targetTile); - // OSRS-accurate range check: + // rules-accurate range check: // - Melee range 1: Cardinal only (N/S/E/W) // - Melee range 2+: Allows diagonal (Chebyshev distance) // - Ranged/Magic: Chebyshev distance + Line of Sight @@ -246,7 +245,7 @@ export class PendingAttackManager { } // Not in range - check if target moved and re-path if needed - // OSRS: recalculates path every tick when target moves + // classic MMORPG: recalculates path every tick when target moves if ( !pending.lastTargetTile || pending.lastTargetTile.x !== this._targetTile.x || @@ -273,7 +272,7 @@ export class PendingAttackManager { /** * Process pending attack for a specific player * - * OSRS-ACCURATE: Called by GameTickProcessor during player phase + * RULES-ACCURATE: Called by GameTickProcessor during player phase * This processes just one player's pending attack instead of all. * * @param playerId - The player to process @@ -307,7 +306,7 @@ export class PendingAttackManager { worldToTileInto(playerPos.x, playerPos.z, this._playerTile); worldToTileInto(targetPos.x, targetPos.z, this._targetTile); - // OSRS-accurate range check based on attack type + // rules-accurate range check based on attack type // Ranged/Magic additionally require Line of Sight const inRange = pending.attackType === AttackType.MELEE diff --git a/packages/server/src/systems/ServerNetwork/PendingGatherManager.ts b/packages/server/src/systems/ServerNetwork/PendingGatherManager.ts index 566487605..76dfb608c 100644 --- a/packages/server/src/systems/ServerNetwork/PendingGatherManager.ts +++ b/packages/server/src/systems/ServerNetwork/PendingGatherManager.ts @@ -11,16 +11,16 @@ * 4. Server paths player to that tile via movePlayerToward() * 5. Every tick, server checks if player arrived at cardinal tile * 6. When arrived, server sets face target via FaceDirectionManager and starts gathering - * 7. At end of tick, FaceDirectionManager applies rotation (OSRS-accurate deferred facing) + * 7. At end of tick, FaceDirectionManager applies rotation (rules-accurate deferred facing) * * KEY DIFFERENCES FROM OLD APPROACH: * - Uses movePlayerToward() with GATHERING_RANGE (like combat's MELEE_RANGE_STANDARD) * - Tick-based processing (like PendingAttackManager) instead of setInterval - * - Uses FaceDirectionManager for rotation (OSRS-accurate deferred face direction) + * - Uses FaceDirectionManager for rotation (rules-accurate deferred face direction) * - No client-side position calculations * * @see PendingAttackManager - combat equivalent - * @see FaceDirectionManager - handles OSRS-accurate rotation + * @see FaceDirectionManager - handles rules-accurate rotation */ import type { World } from "@hyperforge/shared"; @@ -235,7 +235,7 @@ export class PendingGatherManager { // PERF: Reduced logging - only log on actual state changes, not every tick // FISHING: Find shore tile FIRST, then check if player is already there - // OSRS behavior: Player ALWAYS walks to shore before fishing (not just "in range") + // classic MMORPG behavior: Player ALWAYS walks to shore before fishing (not just "in range") if (isFishing) { // Find the closest walkable shore tile to the fishing spot const shoreTile = this.tileMovementManager.findClosestWalkableTile( @@ -529,7 +529,7 @@ export class PendingGatherManager { // and bundled with tileMovementEnd packet for atomic delivery to client. // This prevents race condition where client sets "idle" before emote arrives. - // Use FaceDirectionManager for OSRS-accurate rotation (like other resources) + // Use FaceDirectionManager for rules-accurate rotation (like other resources) this.setFaceTargetViaManager( playerId, pending.resourceAnchorTile, diff --git a/packages/server/src/systems/ServerNetwork/ScriptQueue.ts b/packages/server/src/systems/ServerNetwork/ScriptQueue.ts index 49f9c1393..e349435b1 100644 --- a/packages/server/src/systems/ServerNetwork/ScriptQueue.ts +++ b/packages/server/src/systems/ServerNetwork/ScriptQueue.ts @@ -1,7 +1,7 @@ /** - * ScriptQueue - OSRS-Accurate Script Priority System + * ScriptQueue - Rules-Accurate Script Priority System * - * Implements the RuneScape queue script priority system: + * Implements the classic fantasy MMORPG queue script priority system: * * STRONG (Priority 0): * - Removes all WEAK scripts from queue @@ -24,19 +24,18 @@ * - Always executes regardless of other queue state * - Examples: System messages, login scripts * - * IMPORTANT OSRS DIFFERENCE: + * IMPORTANT classic MMORPG DIFFERENCE: * - Players have all 4 queue types * - NPCs have only ONE queue type (all scripts are equal priority) * - * @see https://oldschool.runescape.wiki/w/Tick - * @see COMBAT_SYSTEM_AUDIT.md for full OSRS research + * @see COMBAT_SYSTEM_AUDIT.md for full classic MMORPG research */ import type { ServerSocket } from "../../shared/types"; import { getCachedTimestamp } from "@hyperforge/shared"; /** - * Script priority levels (OSRS-accurate) + * Script priority levels (rules-accurate) * Lower number = higher priority */ export enum ScriptPriority { @@ -141,7 +140,7 @@ const MAX_NORMAL_DELAY_TICKS = 10; * PlayerScriptQueue - Script queue for players with full priority system * * Processes scripts in priority order (STRONG > NORMAL > WEAK > SOFT) - * with OSRS-accurate interruption and modal handling. + * with rules-accurate interruption and modal handling. */ export class PlayerScriptQueue { private playerStates: Map = new Map(); @@ -245,14 +244,14 @@ export class PlayerScriptQueue { executed: false, }; - // OSRS RULE: STRONG scripts remove all WEAK scripts + // classic MMORPG RULE: STRONG scripts remove all WEAK scripts if (effectivePriority === ScriptPriority.STRONG) { state.scripts = state.scripts.filter( (s) => s.priority !== ScriptPriority.WEAK, ); } - // OSRS RULE: Movement (walk-here) clears WEAK scripts + // classic MMORPG RULE: Movement (walk-here) clears WEAK scripts if (type === ScriptType.MOVEMENT) { state.scripts = state.scripts.filter( (s) => s.priority !== ScriptPriority.WEAK, @@ -388,7 +387,7 @@ export class PlayerScriptQueue { /** * Process scripts for a specific player on this tick * - * OSRS Order (for players): + * classic MMORPG Order (for players): * 1. SOFT scripts execute first (always) * 2. STRONG scripts execute and close modals * 3. NORMAL scripts execute if no modal open (else delay) @@ -580,7 +579,7 @@ export class PlayerScriptQueue { /** * NPCScriptQueue - Simplified script queue for NPCs * - * OSRS DIFFERENCE: NPCs have only ONE queue type - all scripts are equal priority. + * classic MMORPG DIFFERENCE: NPCs have only ONE queue type - all scripts are equal priority. * This is much simpler than the player queue. */ export class NPCScriptQueue { @@ -684,7 +683,7 @@ export class NPCScriptQueue { scripts.push(script); } - // Execute scripts (FIFO - process first one only per tick like OSRS) + // Execute scripts (FIFO - process first one only per tick like classic MMORPG) if (this._toExecuteNPC.length > 0 && this.handler) { const script = this._toExecuteNPC[0]; script.executed = true; diff --git a/packages/server/src/systems/ServerNetwork/__tests__/FaceDirectionManager.test.ts b/packages/server/src/systems/ServerNetwork/__tests__/FaceDirectionManager.test.ts index f347c662a..28464108a 100644 --- a/packages/server/src/systems/ServerNetwork/__tests__/FaceDirectionManager.test.ts +++ b/packages/server/src/systems/ServerNetwork/__tests__/FaceDirectionManager.test.ts @@ -1,7 +1,7 @@ /** * FaceDirectionManager Tests * - * Tests the OSRS-accurate face direction system: + * Tests the rules-accurate face direction system: * - Cardinal face direction (N/S/E/W) for resources * - Point-based face target for legacy interactions * - Movement flag tracking (skip rotation if moved) @@ -289,7 +289,7 @@ describe("FaceDirectionManager", () => { // Rotation should NOT be applied expect(player.node?.quaternion?.set).not.toHaveBeenCalled(); - // But faceTarget should PERSIST (OSRS behavior) + // But faceTarget should PERSIST (classic MMORPG behavior) expect(player.faceTarget).toEqual({ x: 15, z: 10 }); }); diff --git a/packages/server/src/systems/ServerNetwork/action-queue.ts b/packages/server/src/systems/ServerNetwork/action-queue.ts index e1c61b0e7..35174629f 100644 --- a/packages/server/src/systems/ServerNetwork/action-queue.ts +++ b/packages/server/src/systems/ServerNetwork/action-queue.ts @@ -1,7 +1,7 @@ /** * Action Queue System * - * OSRS-style action queue that processes player inputs on tick boundaries. + * classic MMORPG-style action queue that processes player inputs on tick boundaries. * This ensures fair, predictable timing for all players regardless of * connection speed or click rate. * @@ -12,7 +12,7 @@ * - Interaction actions can be queued (up to limit) * - Each player has their own queue * - * OSRS Reference: + * classic MMORPG Reference: * - Walk-here replaces current movement, doesn't queue * - Attack sets target, combat continues until target dead/out of range * - Use-item queues if busy, executes when possible @@ -129,8 +129,8 @@ export class ActionQueue { /** * Queue a movement action - * Movement ALWAYS replaces pending action (OSRS behavior) - * In OSRS, clicking the ground immediately cancels whatever you're doing + * Movement ALWAYS replaces pending action (classic MMORPG behavior) + * In classic MMORPG, clicking the ground immediately cancels whatever you're doing */ queueMovement(socket: ServerSocket, data: unknown): void { const playerId = socket.player?.id; @@ -148,18 +148,18 @@ export class ActionQueue { priority: ActionPriority.MOVEMENT, }; - // Movement always replaces pending action (OSRS: ground click cancels all) + // Movement always replaces pending action (classic MMORPG: ground click cancels all) state.pendingAction = action; // Clear combat target when player clicks to move elsewhere - // (OSRS behavior: clicking ground cancels combat) + // (classic MMORPG behavior: clicking ground cancels combat) state.combatTarget = null; } /** * Queue a combat action * Sets persistent combat target that continues across ticks - * OSRS behavior: clicking new target switches immediately + * classic MMORPG behavior: clicking new target switches immediately * * Includes rate limiting to prevent combat spam: * - Max 2 combat requests per tick diff --git a/packages/server/src/systems/ServerNetwork/character-selection.ts b/packages/server/src/systems/ServerNetwork/character-selection.ts index 3de5ba512..41c79cfc9 100644 --- a/packages/server/src/systems/ServerNetwork/character-selection.ts +++ b/packages/server/src/systems/ServerNetwork/character-selection.ts @@ -819,7 +819,7 @@ export async function handleEnterWorld( // Load full character data from DB (position, skills, AND combat preferences) // Skip for load test bots - they use default values for performance let savedSkills: Record | undefined; - let savedAutoRetaliate = true; // Default ON (OSRS behavior) + let savedAutoRetaliate = true; // Default ON (classic MMORPG behavior) if (characterId && accountId && !isLoadTestBot) { try { const databaseSystem = world.getSystem("database") as diff --git a/packages/server/src/systems/ServerNetwork/event-bridge.ts b/packages/server/src/systems/ServerNetwork/event-bridge.ts index 395cf47b7..1f66513b9 100644 --- a/packages/server/src/systems/ServerNetwork/event-bridge.ts +++ b/packages/server/src/systems/ServerNetwork/event-bridge.ts @@ -174,7 +174,7 @@ export class EventBridge { }, ); - // OSRS-STYLE: Forward gathering tool show/hide events (for fishing rod visual) + // classic MMORPG-STYLE: Forward gathering tool show/hide events (for fishing rod visual) this.on(EventType.GATHERING_TOOL_SHOW, (payload: unknown) => { const data = payload as EventMap[EventType.GATHERING_TOOL_SHOW]; if (data.playerId) { @@ -321,7 +321,7 @@ export class EventBridge { } }); - // Forward XP drops to clients for visual feedback (RS3-style) + // Forward XP drops to clients for visual feedback (modern MMORPG-style) // Uses XP_DROP_BROADCAST which is emitted AFTER SkillsSystem processes XP // This ensures newLevel reflects any level-ups that occurred this.on(EventType.XP_DROP_BROADCAST, (payload: unknown) => { @@ -353,7 +353,7 @@ export class EventBridge { ) { // Map skill name to database column names // Round XP to integer at DB boundary (XP columns are integer type, - // but recipes use float values like 13.8, 67.5 for OSRS accuracy) + // but recipes use float values like 13.8, 67.5 for classic MMORPG accuracy) const skillLevelKey = `${data.skill}Level`; const skillXpKey = `${data.skill}Xp`; const saveData = { diff --git a/packages/server/src/systems/ServerNetwork/handlers/bank/coins.ts b/packages/server/src/systems/ServerNetwork/handlers/bank/coins.ts index 685294b28..baebcdb3a 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/bank/coins.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/bank/coins.ts @@ -284,7 +284,7 @@ export async function handleBankWithdrawCoins( await tx .delete(schema.bankStorage) .where(eq(schema.bankStorage.id, bankCoinsRow.id)); - // OSRS-style: compact slots to fill the gap + // classic MMORPG-style: compact slots to fill the gap await compactBankSlots(tx, ctx.playerId, bankCoinsRow.slot); } else { // Decrement quantity diff --git a/packages/server/src/systems/ServerNetwork/handlers/bank/core.ts b/packages/server/src/systems/ServerNetwork/handlers/bank/core.ts index b1e4617ac..42457694f 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/bank/core.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/bank/core.ts @@ -46,7 +46,7 @@ import { MAX_BANK_SLOTS, } from "./utils"; -// Import coin handler for bank withdraw redirect (coins go to money pouch, RS3-style) +// Import coin handler for bank withdraw redirect (coins go to money pouch, modern MMORPG-style) import { handleBankWithdrawCoins } from "./coins"; /** @@ -98,7 +98,7 @@ export async function handleBankOpen( try { const bankRepo = new BankRepository(db.drizzle, db.pool); - // RS3-style: items includes qty=0 rows (placeholders) + // modern MMORPG-style: items includes qty=0 rows (placeholders) const items = await bankRepo.getPlayerBank(playerId); const tabs = await bankRepo.getPlayerTabs(playerId); const alwaysSetPlaceholder = @@ -107,7 +107,7 @@ export async function handleBankOpen( // InteractionSessionManager now tracks targetEntityId as single source of truth // Send bank state to client (include isOpen and bankId for initial open) - // RS3-style: no separate placeholders array - items with qty=0 ARE placeholders + // modern MMORPG-style: no separate placeholders array - items with qty=0 ARE placeholders sendToSocket(socket, "bankState", { playerId, bankId: data.bankId, @@ -318,7 +318,7 @@ export async function handleBankDeposit( } // Add to bank (stacking) - // RS3-STYLE: If item exists (even with qty=0 placeholder), add to that slot + // modern MMORPG-STYLE: If item exists (even with qty=0 placeholder), add to that slot if (bankRows.length > 0) { // Works for both normal items and qty=0 placeholders // qty=0 + newQty = newQty (placeholder becomes real item) @@ -329,7 +329,7 @@ export async function handleBankDeposit( ); } else { // No existing item - find next available bank slot IN TARGET TAB - // RS3-style: New items go to the currently viewed tab + // modern MMORPG-style: New items go to the currently viewed tab const targetTab = data.targetTabIndex ?? 0; // Get items in the target tab to find next available slot @@ -568,11 +568,11 @@ export async function handleBankWithdraw( // Remove from bank const newBankQty = availableQty - finalWithdrawQty; if (newBankQty <= 0) { - // RS3-STYLE PLACEHOLDER BEHAVIOR: + // modern MMORPG-STYLE PLACEHOLDER BEHAVIOR: // If alwaysSetPlaceholder is ON, set qty=0 (item stays as placeholder) // If alwaysSetPlaceholder is OFF, delete row and compact slots if (alwaysSetPlaceholder) { - // RS3-style: Keep row with qty=0 as placeholder + // modern MMORPG-style: Keep row with qty=0 as placeholder await tx.execute( sql`UPDATE bank_storage SET quantity = 0 WHERE id = ${bankRow.id}`, ); @@ -880,7 +880,7 @@ export async function handleBankDepositAll( } // Update/insert bank items - // RS3-style: New items go to the currently viewed tab + // modern MMORPG-style: New items go to the currently viewed tab const targetTab = data.targetTabIndex ?? 0; // Get slots used in target tab for new item placement diff --git a/packages/server/src/systems/ServerNetwork/handlers/bank/equipment.ts b/packages/server/src/systems/ServerNetwork/handlers/bank/equipment.ts index f8831f0e9..9455d5b9e 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/bank/equipment.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/bank/equipment.ts @@ -1,5 +1,5 @@ /** - * Bank Equipment Handlers (RS3-style equipment tab) + * Bank Equipment Handlers (modern MMORPG-style equipment tab) * * Handles withdraw-to-equipment, deposit-from-equipment operations. * These allow equipping/unequipping directly from bank without using inventory. @@ -44,7 +44,7 @@ import { /** * Handle withdraw item directly to equipment * - * RS3-style bank equipment tab feature: + * modern MMORPG-style bank equipment tab feature: * - When "equipment" view is active, withdrawing equipable items goes directly to equipment slot * - Handles 2h weapon/shield conflicts * - Displaced items go to bank (not inventory) @@ -286,7 +286,7 @@ export async function handleBankWithdrawToEquipment( /** * Handle deposit single equipment slot to bank * - * RS3-style bank equipment tab feature: + * modern MMORPG-style bank equipment tab feature: * - Click on equipment slot in bank to deposit directly to bank * - Does not go through inventory * @@ -434,7 +434,7 @@ export async function handleBankDepositEquipment( /** * Handle deposit all worn equipment to bank * - * RS3-style "Deposit Worn Items" button: + * modern MMORPG-style "Deposit Worn Items" button: * - One-click deposit all equipped items to bank * - Does not go through inventory * diff --git a/packages/server/src/systems/ServerNetwork/handlers/bank/index.ts b/packages/server/src/systems/ServerNetwork/handlers/bank/index.ts index ed814267b..2cf3947f8 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/bank/index.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/bank/index.ts @@ -7,7 +7,7 @@ * - coins.ts: Coin deposit/withdraw to money pouch * - equipment.ts: Equipment tab interactions * - move.ts: Bank rearrangement (swap/insert modes) - * - placeholders.ts: RS3-style placeholder system + * - placeholders.ts: modern MMORPG-style placeholder system * - tabs.ts: Custom tab management * - utils.ts: Shared utilities (not exported externally) */ diff --git a/packages/server/src/systems/ServerNetwork/handlers/bank/move.ts b/packages/server/src/systems/ServerNetwork/handlers/bank/move.ts index 80e00c360..1d8163cc0 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/bank/move.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/bank/move.ts @@ -1,7 +1,7 @@ /** * Bank Move/Rearrange Handler * - * OSRS-style bank organization: swap mode and insert mode. + * classic MMORPG-style bank organization: swap mode and insert mode. */ import { type World, SessionType } from "@hyperforge/shared"; @@ -25,7 +25,7 @@ import { rateLimiter, sendBankStateWithTabs, TEMP_SWAP_SLOT } from "./utils"; /** * Handle bank move/rearrange request * - * OSRS-style bank organization: + * classic MMORPG-style bank organization: * - Swap mode: Drop on item center → exchange positions * - Insert mode: Drop on item edge → insert at position, shift others * diff --git a/packages/server/src/systems/ServerNetwork/handlers/bank/placeholders.ts b/packages/server/src/systems/ServerNetwork/handlers/bank/placeholders.ts index 166dfee6f..7a6959c2a 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/bank/placeholders.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/bank/placeholders.ts @@ -1,7 +1,7 @@ /** - * Bank Placeholder Handlers (RS3-style) + * Bank Placeholder Handlers (modern MMORPG-style) * - * RS3-style: Placeholders are bank_storage rows with qty=0. + * modern MMORPG-style: Placeholders are bank_storage rows with qty=0. * Provides withdraw-placeholder, release, and toggle functionality. */ @@ -36,12 +36,12 @@ import { } from "./utils"; /** - * Handle withdraw-placeholder request (RS3-style) + * Handle withdraw-placeholder request (modern MMORPG-style) * * Withdraws ALL of an item to inventory and leaves a qty=0 placeholder. - * This is the RS3 "Withdraw-Placeholder" context menu option. + * This is the modern MMORPG "Withdraw-Placeholder" context menu option. * - * RS3 Behavior: + * modern MMORPG Behavior: * - Right-click item in bank → "Withdraw-Placeholder" * - ALL of that item withdrawn to inventory * - Bank row stays with qty=0 (placeholder) @@ -105,7 +105,7 @@ export async function handleBankWithdrawPlaceholder( const bankRow = bankRows[0]; const availableQty = bankRow.quantity ?? 0; - // RS3-style: Can't withdraw-placeholder if already qty=0 + // modern MMORPG-style: Can't withdraw-placeholder if already qty=0 if (availableQty === 0) { throw new Error("ALREADY_PLACEHOLDER"); } @@ -144,7 +144,7 @@ export async function handleBankWithdrawPlaceholder( // Withdraw as many as we can fit (up to all) const withdrawQty = Math.min(availableQty, freeSlots.length); - // RS3-STYLE: Set qty=0 (leave placeholder) - ALWAYS for this action + // modern MMORPG-STYLE: Set qty=0 (leave placeholder) - ALWAYS for this action await tx.execute( sql`UPDATE bank_storage SET quantity = 0 WHERE id = ${bankRow.id}`, ); @@ -184,7 +184,7 @@ export async function handleBankWithdrawPlaceholder( } /** - * Handle release single placeholder (RS3-style) + * Handle release single placeholder (modern MMORPG-style) * * Deletes a bank_storage row with qty=0 at the specified slot. * Then compacts slots to fill the gap. @@ -223,7 +223,7 @@ export async function handleBankReleasePlaceholder( SLOT_EMPTY: "No item at that slot", }, execute: async (tx) => { - // RS3-style: Find bank_storage row with qty=0 at this slot + // modern MMORPG-style: Find bank_storage row with qty=0 at this slot const placeholderResult = await tx.execute( sql`SELECT id, quantity FROM bank_storage WHERE "playerId" = ${ctx.playerId} @@ -241,7 +241,7 @@ export async function handleBankReleasePlaceholder( quantity: number | null; }; - // RS3-style: Can only release if qty=0 (is a placeholder) + // modern MMORPG-style: Can only release if qty=0 (is a placeholder) if ((row.quantity ?? 0) > 0) { throw new Error("NOT_A_PLACEHOLDER"); } @@ -263,7 +263,7 @@ export async function handleBankReleasePlaceholder( } /** - * Handle release all placeholders (RS3-style) + * Handle release all placeholders (modern MMORPG-style) * * Deletes all bank_storage rows with qty=0 for the player. * Then compacts slots in each tab. @@ -287,7 +287,7 @@ export async function handleBankReleaseAllPlaceholders( // Step 2: Execute transaction const result = await executeSecureTransaction(ctx, { execute: async (tx) => { - // RS3-style: Find all qty=0 placeholders grouped by tab + // modern MMORPG-style: Find all qty=0 placeholders grouped by tab const placeholders = await tx.execute( sql`SELECT id, slot, "tabIndex" FROM bank_storage WHERE "playerId" = ${ctx.playerId} AND quantity = 0 diff --git a/packages/server/src/systems/ServerNetwork/handlers/bank/tabs.ts b/packages/server/src/systems/ServerNetwork/handlers/bank/tabs.ts index 291fddebb..810cd08fb 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/bank/tabs.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/bank/tabs.ts @@ -1,7 +1,7 @@ /** * Bank Tab Handlers * - * Manages custom bank tabs (RS3-style tab organization). + * Manages custom bank tabs (modern MMORPG-style tab organization). * Tab 0 is the main tab, tabs 1-9 are custom user tabs. */ @@ -36,7 +36,7 @@ import { * Creates a new custom tab (1-9) with an item from main tab (or another tab). * The item becomes the first item in the new tab and its icon. * - * OSRS Behavior: + * classic MMORPG Behavior: * - Drag item to "+" button or empty tab slot to create * - First item becomes the tab icon * - Max 9 custom tabs (1-9) @@ -173,7 +173,7 @@ export async function handleBankCreateTab( * Deletes a custom tab and moves all items to main tab (index 0). * Tab 0 (main) cannot be deleted. * - * OSRS Behavior: + * classic MMORPG Behavior: * - Items from deleted tab are appended to main tab * - Tab numbers above the deleted tab shift down * @@ -250,7 +250,7 @@ export async function handleBankDeleteTab( WHERE "playerId" = ${ctx.playerId} AND "tabIndex" = ${data.tabIndex}`, ); - // RS3-STYLE: Shift all higher tabs down by 1 to fill the gap + // modern MMORPG-STYLE: Shift all higher tabs down by 1 to fill the gap // This ensures tabs are always sequential (1, 2, 3...) with no gaps // // NOTE: Cannot use single batched UPDATE due to unique constraint on (playerId, tabIndex, slot). diff --git a/packages/server/src/systems/ServerNetwork/handlers/bank/utils.ts b/packages/server/src/systems/ServerNetwork/handlers/bank/utils.ts index 9b3b24aea..74f9e8f2a 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/bank/utils.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/bank/utils.ts @@ -234,7 +234,7 @@ export function validateBankTabRows(rows: unknown[]): BankTabRowData[] { /** * Compact bank slots after an item is deleted. * - * OSRS-style behavior: When an item is fully withdrawn, remaining items + * classic MMORPG-style behavior: When an item is fully withdrawn, remaining items * shift left to fill the gap. No empty slots in the middle of the bank. * * NOTE: This compacts within the CURRENT tab only (tab 0 by default for backwards compatibility). @@ -286,7 +286,7 @@ export async function compactBankSlots( * Send full bank state including tabs to client * Helper function for all bank handlers to send consistent state * - * RS3-STYLE PLACEHOLDERS: + * modern MMORPG-STYLE PLACEHOLDERS: * - Placeholders are just bank_storage rows with quantity = 0 * - No separate placeholders array needed - items with qty=0 ARE placeholders * - Client renders qty=0 items with greyed-out style @@ -297,7 +297,7 @@ export async function sendBankStateWithTabs( db: { drizzle: NodePgDatabase; pool: pg.Pool }, ): Promise { const bankRepo = new BankRepository(db.drizzle, db.pool); - // RS3-style: getPlayerBank now includes qty=0 items (placeholders) + // modern MMORPG-style: getPlayerBank now includes qty=0 items (placeholders) const bankItems = await bankRepo.getPlayerBank(playerId); const bankTabs = await bankRepo.getPlayerTabs(playerId); const alwaysSetPlaceholder = await bankRepo.getAlwaysSetPlaceholder(playerId); diff --git a/packages/server/src/systems/ServerNetwork/handlers/combat.ts b/packages/server/src/systems/ServerNetwork/handlers/combat.ts index 2d6b0cdb2..9b133b795 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/combat.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/combat.ts @@ -29,7 +29,7 @@ import { getCombatRateLimiter } from "../services/SlidingWindowRateLimiter"; /** * Valid attack styles (whitelist) - * Includes melee, ranged, and magic styles (OSRS-accurate) + * Includes melee, ranged, and magic styles (rules-accurate) */ const VALID_ATTACK_STYLES = new Set([ // Melee styles diff --git a/packages/server/src/systems/ServerNetwork/handlers/common/helpers.ts b/packages/server/src/systems/ServerNetwork/handlers/common/helpers.ts index 3699429af..fa24d9384 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/common/helpers.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/common/helpers.ts @@ -127,7 +127,7 @@ export function hasActiveInterfaceSession( /** * Position type for entity lookups. - * Uses x/z for ground plane (OSRS-style), y optional for elevation. + * Uses x/z for ground plane (classic MMORPG-style), y optional for elevation. */ export interface EntityPosition { readonly x: number; diff --git a/packages/server/src/systems/ServerNetwork/handlers/common/validation.ts b/packages/server/src/systems/ServerNetwork/handlers/common/validation.ts index eda7d9d24..a13b15c72 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/common/validation.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/common/validation.ts @@ -51,7 +51,7 @@ const SESSION_TYPE_DISPLAY_NAMES: Readonly> = { /** * Verify player is within interaction distance of session target. - * Uses Chebyshev distance (OSRS-style square range). + * Uses Chebyshev distance (classic MMORPG-style square range). * * @returns Error message if invalid, null if valid */ @@ -92,7 +92,7 @@ function verifyDistanceToTarget( return "Player position not found"; } - // Chebyshev distance check (OSRS-style) + // Chebyshev distance check (classic MMORPG-style) const distance = chebyshevDistance(playerEntity.position, targetPos); const maxDistance = INTERACTION_DISTANCE[sessionType]; diff --git a/packages/server/src/systems/ServerNetwork/handlers/dialogue.ts b/packages/server/src/systems/ServerNetwork/handlers/dialogue.ts index efa2da5d2..84de1e0aa 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/dialogue.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/dialogue.ts @@ -12,7 +12,7 @@ * * Unlike store/bank handlers, dialogue does NOT require: * - Database transactions (no persistent state changes) - * - Heavy rate limiting (OSRS allows fast dialogue clicking) + * - Heavy rate limiting (classic MMORPG allows fast dialogue clicking) * * The DialogueSystem (shared package) handles the actual dialogue state * machine. This handler is just the network entry point with validation. diff --git a/packages/server/src/systems/ServerNetwork/handlers/duel/challenge.ts b/packages/server/src/systems/ServerNetwork/handlers/duel/challenge.ts index 9bf5f775b..730cd1f0a 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/duel/challenge.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/duel/challenge.ts @@ -232,7 +232,7 @@ export function handleDuelChallenge( targetId: targetPlayerId, }); - // Send notification to target player as OSRS-style chat message + // Send notification to target player as classic MMORPG-style chat message const targetSocket = getSocketByPlayerId(world, targetPlayerId); if (targetSocket) { // Send as clickable chat message (like trade requests) diff --git a/packages/server/src/systems/ServerNetwork/handlers/inventory.ts b/packages/server/src/systems/ServerNetwork/handlers/inventory.ts index eb3d200c6..be0b7972e 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/inventory.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/inventory.ts @@ -5,7 +5,7 @@ * - Item pickup from ground * - Item drop to ground * - Item equip/unequip - * - Inventory slot swapping (OSRS-style) + * - Inventory slot swapping (classic MMORPG-style) * * All inputs are validated before processing. * Includes rate limiting to prevent spam attacks. @@ -68,7 +68,7 @@ function isValidEntityId(value: unknown): value is string { /** * Valid equipment slot names for unequip operations - * Matches OSRS equipment slots + * Matches classic MMORPG equipment slots */ const VALID_EQUIPMENT_SLOTS = new Set([ "weapon", @@ -416,7 +416,7 @@ export function handleEquipItem( ? payload.inventorySlot : undefined; - // Block all equip/unequip during active duels (OSRS: can't change gear mid-duel) + // Block all equip/unequip during active duels (classic MMORPG: can't change gear mid-duel) const duelSystemEquip = world.getSystem("duel") as | { getStakedSlots?: (id: string) => Set; @@ -440,7 +440,7 @@ export function handleEquipItem( } } - // Block equip during active trades (OSRS: can't change gear mid-trade) + // Block equip during active trades (classic MMORPG: can't change gear mid-trade) const tradingSystemEquip = getTradingSystem(world); if (tradingSystemEquip?.isPlayerInTrade(playerEntity.id)) { sendInventoryError( @@ -451,7 +451,7 @@ export function handleEquipItem( return; } - // Block equip while dead (OSRS: can't change gear while dead) + // Block equip while dead (classic MMORPG: can't change gear while dead) const entityDataEquip = playerEntity.data as | { deathState?: DeathState } | undefined; @@ -485,7 +485,7 @@ export function handleEquipItem( * - Slot and itemId validation * - Server-authoritative (actual consumption handled by InventorySystem) * - * OSRS Flow: + * classic MMORPG Flow: * Client sends useItem → Server emits INVENTORY_USE → InventorySystem.useItem() * → ITEM_USED → PlayerSystem.handleItemUsed() → healing + eat delay * @@ -504,7 +504,7 @@ export function handleUseItem( return; } - // Rate limit check (separate from equip to allow OSRS-style PvP gear+eat combos) + // Rate limit check (separate from equip to allow classic MMORPG-style PvP gear+eat combos) if (!getConsumeRateLimiter().check(playerEntity.id)) { return; } @@ -634,7 +634,7 @@ export function handleUnequipItem( return; } - // Block unequip during active duels (OSRS: can't change gear mid-duel) + // Block unequip during active duels (classic MMORPG: can't change gear mid-duel) const duelSystemUnequip = world.getSystem("duel") as | { isPlayerInActiveDuel?: (id: string) => boolean } | undefined; @@ -647,7 +647,7 @@ export function handleUnequipItem( return; } - // Block unequip during active trades (OSRS: can't change gear mid-trade) + // Block unequip during active trades (classic MMORPG: can't change gear mid-trade) const tradingSystemUnequip = getTradingSystem(world); if (tradingSystemUnequip?.isPlayerInTrade(playerEntity.id)) { sendInventoryError( @@ -658,7 +658,7 @@ export function handleUnequipItem( return; } - // Block unequip while dead (OSRS: can't change gear while dead) + // Block unequip while dead (classic MMORPG: can't change gear while dead) const entityDataUnequip = playerEntity.data as | { deathState?: DeathState } | undefined; @@ -684,9 +684,9 @@ export function handleUnequipItem( } /** - * Handle inventory slot move/swap request (OSRS-style) + * Handle inventory slot move/swap request (classic MMORPG-style) * - * Implements OSRS-style SWAP behavior: + * Implements classic MMORPG-style SWAP behavior: * - Dragging item A to slot B swaps them * - Does NOT shift/insert like typical drag-drop * diff --git a/packages/server/src/systems/ServerNetwork/handlers/player.ts b/packages/server/src/systems/ServerNetwork/handlers/player.ts index efee0832c..755f51178 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/player.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/player.ts @@ -9,7 +9,7 @@ * - Rate limiting (prevents spam) * - Server-side player existence verification * - * @see https://runescape.wiki/w/Follow + * @see https://classic.wiki/w/Follow */ import type { ServerSocket } from "../../../shared/types"; @@ -35,7 +35,7 @@ function sendPlayerError(socket: ServerSocket, reason: string): void { /** * Handle follow player request from client * - * OSRS behavior: + * classic MMORPG behavior: * - Player walks behind the target * - Re-paths when target moves * - Cancelled by clicking elsewhere, trading, equipping items diff --git a/packages/server/src/systems/ServerNetwork/handlers/processing.ts b/packages/server/src/systems/ServerNetwork/handlers/processing.ts index 75d4cfce5..d4b42c8da 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/processing.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/processing.ts @@ -138,7 +138,7 @@ export function handleFiremakingRequest( return; } - // Validate inventory slot bounds (OSRS inventory is 28 slots: 0-27) + // Validate inventory slot bounds (classic MMORPG inventory is 28 slots: 0-27) if ( payload.logsSlot < 0 || payload.logsSlot > 27 || @@ -151,7 +151,7 @@ export function handleFiremakingRequest( return; } - // Stop player movement before lighting fire (OSRS: player stands still to light) + // Stop player movement before lighting fire (classic MMORPG: player stands still to light) ctx.tileMovementManager.stopPlayer(player.id); ctx.world.emit(EventType.PROCESSING_FIREMAKING_REQUEST, { diff --git a/packages/server/src/systems/ServerNetwork/handlers/store.ts b/packages/server/src/systems/ServerNetwork/handlers/store.ts index 01d517c1e..2a70558b9 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/store.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/store.ts @@ -14,7 +14,7 @@ * - Quantity bounds checking prevents integer overflow * - Coin balance verification before purchase * - Inventory space verification before adding items - * - Distance validation using Chebyshev distance (OSRS-style) + * - Distance validation using Chebyshev distance (classic MMORPG-style) * * This follows the same security patterns as bank.ts. * Common patterns are extracted to ./common/ for reuse. diff --git a/packages/server/src/systems/ServerNetwork/handlers/trade/acceptance.ts b/packages/server/src/systems/ServerNetwork/handlers/trade/acceptance.ts index 197808aea..e8b5c01f3 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/trade/acceptance.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/trade/acceptance.ts @@ -57,7 +57,7 @@ export async function handleTradeAccept( // Send update to both players sendTradeUpdate(world, tradingSystem, data.tradeId); - // Two-screen confirmation flow (OSRS-style): + // Two-screen confirmation flow (classic MMORPG-style): // 1. On offer screen: both accept → move to confirmation screen // 2. On confirmation screen: both accept → complete trade if (result.moveToConfirming) { diff --git a/packages/server/src/systems/ServerNetwork/handlers/trade/helpers.ts b/packages/server/src/systems/ServerNetwork/handlers/trade/helpers.ts index d2c129719..04db9b01a 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/trade/helpers.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/trade/helpers.ts @@ -29,7 +29,7 @@ export const rateLimiter = new RateLimitService(); // ============================================================================ /** - * Maximum distance in tiles for players to initiate a trade (OSRS-style) + * Maximum distance in tiles for players to initiate a trade (classic MMORPG-style) * Players must be adjacent (1 tile) to trade */ export const TRADE_PROXIMITY_TILES = 1; @@ -97,7 +97,7 @@ export function getPlayerName(world: World, playerId: string): string { * Get player combat level from world entities * * Returns player's combat level, or 3 (minimum) if not found. - * Level 3 is the base combat level in OSRS. + * Level 3 is the base combat level in classic MMORPG. */ export function getPlayerCombatLevel(world: World, playerId: string): number { const player = world.entities?.players?.get(playerId); @@ -122,7 +122,7 @@ export function getPlayerCombatLevel(world: World, playerId: string): number { /** * Calculate Chebyshev distance between two positions (tile-based) - * In OSRS, adjacency is measured using Chebyshev distance (allows diagonals) + * In classic MMORPG, adjacency is measured using Chebyshev distance (allows diagonals) */ export function chebyshevDistance( pos1: { x: number; z: number }, @@ -244,7 +244,7 @@ export function calculateFreeSlots( | undefined; if (!inventorySystem?.getInventoryData) { - return 28; // OSRS inventory size + return 28; // classic MMORPG inventory size } const inventoryData = inventorySystem.getInventoryData(playerId); @@ -339,7 +339,7 @@ export function sendTradeUpdate( } /** - * Send confirmation screen packet to both participants (OSRS two-screen flow) + * Send confirmation screen packet to both participants (classic MMORPG two-screen flow) * Includes item values for wealth transfer indicator */ export function sendTradeConfirmScreen( diff --git a/packages/server/src/systems/ServerNetwork/handlers/trade/request.ts b/packages/server/src/systems/ServerNetwork/handlers/trade/request.ts index e2eed8971..a0f3ea619 100644 --- a/packages/server/src/systems/ServerNetwork/handlers/trade/request.ts +++ b/packages/server/src/systems/ServerNetwork/handlers/trade/request.ts @@ -30,7 +30,7 @@ import { /** * Handle trade request from Player A to Player B * - * OSRS-style behavior: If not in range, player walks up to target first + * classic MMORPG-style behavior: If not in range, player walks up to target first */ export function handleTradeRequest( socket: ServerSocket, @@ -139,10 +139,10 @@ export function handleTradeRequest( return; } - // Send notification to target player as OSRS-style pink chat message + // Send notification to target player as classic MMORPG-style pink chat message const targetSocket = getSocketByPlayerId(world, targetPlayerId); if (targetSocket) { - // Send trade request as a clickable chat message (OSRS-style) + // Send trade request as a clickable chat message (classic MMORPG-style) const chatMessage = { id: uuid(), from: "", @@ -278,7 +278,7 @@ export function handleTradeRequestRespond( ); const recipientLevel = getPlayerCombatLevel(world, playerId); - // Calculate initial free slots for each player (OSRS-style indicator) + // Calculate initial free slots for each player (classic MMORPG-style indicator) const initiatorFreeSlots = calculateFreeSlots( world, session.initiator.playerId, diff --git a/packages/server/src/systems/ServerNetwork/index.ts b/packages/server/src/systems/ServerNetwork/index.ts index 733fdfe61..a80a13b1d 100644 --- a/packages/server/src/systems/ServerNetwork/index.ts +++ b/packages/server/src/systems/ServerNetwork/index.ts @@ -604,10 +604,10 @@ export class ServerNetwork extends System implements NetworkWithSocket { // Note: uWS pub/sub is wired later via enablePubSub() after uWS server starts - // Tick system for RuneScape-style 600ms ticks + // Tick system for classic fantasy MMORPG-style 600ms ticks this.tickSystem = new TickSystem(); - // Tile-based movement manager (RuneScape-style) + // Tile-based movement manager (classic fantasy MMORPG-style) // Use sendToNearby for movement broadcasts — position is extracted from // the data payload's player entity rather than from the packet itself. this.tileMovementManager = new TileMovementManager( @@ -662,7 +662,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { }, ); - // Action queue for OSRS-style input processing + // Action queue for classic MMORPG-style input processing this.actionQueue = new ActionQueue(); // Set up action queue handlers - these execute the actual game logic @@ -800,11 +800,11 @@ export class ServerNetwork extends System implements NetworkWithSocket { }, ); - // OSRS-ACCURATE: Process mob AI BEFORE mob movement each tick + // RULES-ACCURATE: Process mob AI BEFORE mob movement each tick // AI state machine (IDLE → WANDER → CHASE → ATTACK → RETURN) decides movement targets, // then mob tile movement executes the path on the same tick. // Without this, mobs stand idle forever because MobEntity.serverUpdate() defers - // AI ticking to the tick system for deterministic OSRS ordering. + // AI ticking to the tick system for deterministic classic MMORPG ordering. const MOB_AI_DELTA_SECONDS = TICK_DURATION_MS / 1000; // Use type-indexed entity lookup instead of iterating all 221+ entities @@ -1014,14 +1014,14 @@ export class ServerNetwork extends System implements NetworkWithSocket { ); // Follow manager - server-authoritative tracking of players following other players - // OSRS-style: follower walks behind leader, re-paths when leader moves + // classic MMORPG-style: follower walks behind leader, re-paths when leader moves this.followManager = new FollowManager( this.world, this.tileMovementManager, ); // Register follow processing (same priority as movement) - // Pass tick number for OSRS-accurate 1-tick delay tracking + // Pass tick number for rules-accurate 1-tick delay tracking this.tickSystem.onTick( (tickNumber) => { this.followManager.processTick(tickNumber); @@ -1031,7 +1031,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { ); // Pending trade manager - server-authoritative "walk to player and trade" system - // OSRS-style: if player clicks to trade someone far away, walk up first + // classic MMORPG-style: if player clicks to trade someone far away, walk up first this.pendingTradeManager = new PendingTradeManager( this.world, this.tileMovementManager, @@ -1052,7 +1052,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { ).pendingTradeManager = this.pendingTradeManager; // Pending duel challenge manager - server-authoritative "walk to player and challenge" system - // OSRS-style: if player clicks to challenge someone far away, walk up first + // classic MMORPG-style: if player clicks to challenge someone far away, walk up first this.pendingDuelChallengeManager = new PendingDuelChallengeManager( this.world, this.tileMovementManager, @@ -1083,7 +1083,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { (this.world as { tradingSystem?: TradingSystem }).tradingSystem = this.tradingSystem; - // Duel system - server-authoritative player-to-player dueling (OSRS-style) + // Duel system - server-authoritative player-to-player dueling (classic MMORPG-style) // Manages duel sessions, rules negotiation, stakes, and combat enforcement this.duelSystem = new DuelSystem(this.world); @@ -1247,9 +1247,8 @@ export class ServerNetwork extends System implements NetworkWithSocket { this.tileMovementManager.cleanup(playerId); }); - // OSRS-accurate face direction manager + // rules-accurate face direction manager // Defers rotation until end of tick, only applies if player didn't move - // @see https://osrs-docs.com/docs/packets/outgoing/updating/masks/face-direction/ this.faceDirectionManager = new FaceDirectionManager(this.world); // Wire up the send function so FaceDirectionManager can broadcast rotation changes @@ -1269,7 +1268,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { }); // Register face direction processing - runs AFTER all movement at COMBAT priority - // OSRS: Face direction mask is processed at end of tick if entity didn't move + // classic MMORPG: Face direction mask is processed at end of tick if entity didn't move this.tickSystem.onTick( () => { // Get all player IDs from the players map (not items) @@ -1309,7 +1308,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { ).faceDirectionManager = this.faceDirectionManager; // Register combat system to process on each tick (after movement, before AI) - // This is OSRS-accurate: combat runs on the game tick, not per-frame + // This is rules-accurate: combat runs on the game tick, not per-frame this.tickSystem.onTick( (tickNumber) => { const t0 = Date.now(); @@ -1326,7 +1325,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { ); // Register death system to process on each tick (after combat) - // Handles gravestone expiration and ground item despawn (OSRS-accurate tick-based timing) + // Handles gravestone expiration and ground item despawn (rules-accurate tick-based timing) this.tickSystem.onTick( (tickNumber) => { const playerDeathSystem = this.world.getSystem( @@ -1344,7 +1343,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { ); // Register loot system to process on each tick (after combat) - // Handles mob corpse despawn (OSRS-accurate tick-based timing) + // Handles mob corpse despawn (rules-accurate tick-based timing) this.tickSystem.onTick( (tickNumber) => { const lootSystem = this.world.getSystem("loot") as unknown as @@ -1359,7 +1358,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { ); // Register resource gathering system to process on each tick (after combat) - // OSRS-accurate: Woodcutting attempts every 4 ticks (2.4 seconds) + // rules-accurate: Woodcutting attempts every 4 ticks (2.4 seconds) this.tickSystem.onTick( (tickNumber) => { const resourceSystem = this.world.getSystem( @@ -1673,12 +1672,12 @@ export class ServerNetwork extends System implements NetworkWithSocket { }); // Combat follow: When player is in combat but out of range, move toward target - // OSRS-style: "if the clicked entity is an NPC or player, a new pathfinding attempt + // classic MMORPG-style: "if the clicked entity is an NPC or player, a new pathfinding attempt // will be started every tick, until a target tile can be found" this.onWorld(EventType.COMBAT_FOLLOW_TARGET, (event) => { const followEvent = event as EventMap[typeof EventType.COMBAT_FOLLOW_TARGET]; - // Use OSRS-style pathfinding with appropriate range and type + // Use classic MMORPG-style pathfinding with appropriate range and type // MELEE: Cardinal-only for range 1, RANGED/MAGIC: Chebyshev distance this.tileMovementManager.movePlayerToward( followEvent.playerId, @@ -1689,14 +1688,14 @@ export class ServerNetwork extends System implements NetworkWithSocket { ); }); - // OSRS-accurate: Cancel pending attack when player clicks elsewhere + // rules-accurate: Cancel pending attack when player clicks elsewhere this.onWorld(EventType.PENDING_ATTACK_CANCEL, (event) => { const { playerId } = event as EventMap[typeof EventType.PENDING_ATTACK_CANCEL]; this.pendingAttackManager.cancelPendingAttack(playerId); }); - // OSRS-accurate: Move player to adjacent tile after lighting fire + // rules-accurate: Move player to adjacent tile after lighting fire // Priority: West → East → South → North (handled by ProcessingSystem) // Uses proper tile movement for smooth walking animation (not teleport) this.onWorld(EventType.FIREMAKING_MOVE_REQUEST, (event) => { @@ -1714,13 +1713,13 @@ export class ServerNetwork extends System implements NetworkWithSocket { return; } - // OSRS-accurate: Use tile movement system for smooth walking animation + // rules-accurate: Use tile movement system for smooth walking animation // Walking (not running) to adjacent tile, meleeRange=0 means go directly to tile // This sends tileMovementStart packet for smooth client interpolation this.tileMovementManager.movePlayerToward( playerId, position, - false, // OSRS firemaking step is a walk, not a run + false, // classic MMORPG firemaking step is a walk, not a run 0, // meleeRange=0 = non-combat, go directly to the tile ); }); @@ -1944,7 +1943,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { // advances on the 600ms tick schedule via onTick(). This matches the documented // 30 Hz client input rate and removes the 0–600ms ActionQueue delay. this.handlers["onMoveRequest"] = (socket, data) => { - // Cancel any pending actions when player moves elsewhere (OSRS behavior) + // Cancel any pending actions when player moves elsewhere (classic MMORPG behavior) if (socket.player) { this.cancelAllPendingActions(socket.player.id, socket); } @@ -1955,7 +1954,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { // Legacy input handler - convert clicks to immediate move request const payload = data as LegacyInputPayload; if (payload.type === "click" && Array.isArray(payload.target)) { - // Cancel any pending actions when player moves elsewhere (OSRS behavior) + // Cancel any pending actions when player moves elsewhere (classic MMORPG behavior) if (socket.player) { this.cancelAllPendingActions(socket.player.id, socket); } @@ -1967,7 +1966,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { }; // Combat - server-authoritative "walk to and attack" system - // OSRS-style: If in attack range, start combat immediately; otherwise queue pending attack + // classic MMORPG-style: If in attack range, start combat immediately; otherwise queue pending attack // Melee range is CARDINAL ONLY for range 1, ranged/magic use Chebyshev distance this.handlers["onAttackMob"] = (socket, data) => { const playerEntity = socket.player; @@ -2094,7 +2093,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { }); this.actionQueue.queueCombat(socket, data); } else { - // Not in range - queue pending attack (server handles OSRS-style pathfinding) + // Not in range - queue pending attack (server handles classic MMORPG-style pathfinding) traceAttackMob("action:queue_pending_attack", { playerId: playerEntity.id, targetId, @@ -2205,7 +2204,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { } }; - // Follow another player (OSRS-style) + // Follow another player (classic MMORPG-style) this.handlers["onFollowPlayer"] = (socket, data) => { const playerEntity = socket.player; if (!playerEntity) return; @@ -2630,7 +2629,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { this.handlers["onBankMoveToTab"] = (socket, data) => handleBankMoveToTab(socket, data as BankMoveToTabPayload, this.world); - // Bank placeholder handlers (RS3 style: qty=0 in bank_storage) + // Bank placeholder handlers (modern MMORPG style: qty=0 in bank_storage) this.handlers["onBankWithdrawPlaceholder"] = (socket, data) => handleBankWithdrawPlaceholder( socket, @@ -2647,7 +2646,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { this.handlers["onBankToggleAlwaysPlaceholder"] = (socket, data) => handleBankToggleAlwaysPlaceholder(socket, data, this.world); - // Bank equipment tab handlers (RS3-style equipment view) + // Bank equipment tab handlers (modern MMORPG-style equipment view) this.handlers["onBankWithdrawToEquipment"] = (socket, data) => handleBankWithdrawToEquipment( socket, @@ -3246,7 +3245,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { // Setup event bridge (world events → network messages) this.eventBridge.setupEventListeners(); - // Start tick system (600ms RuneScape-style ticks) + // Start tick system (600ms classic fantasy MMORPG-style ticks) this.tickSystem.start(); console.log( "[ServerNetwork] Tick system started (600ms ticks) with action queue", @@ -3876,7 +3875,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { if (equipment?.weapon?.item) { const weaponItem = equipment.weapon.item; - // OSRS-accurate: Magic weapons (staffs/wands) without autocast + // rules-accurate: Magic weapons (staffs/wands) without autocast // default to melee range (1 tile bonk). The selectedSpell check above // already returns 10 for magic range when a spell is selected. const isMagicWeapon = @@ -3911,7 +3910,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { * Get the attack type from the player's equipped weapon or selected spell * Returns AttackType.MELEE if no weapon or melee weapon equipped and no spell selected * - * OSRS-accurate: You can cast spells without a staff - the staff just provides + * rules-accurate: You can cast spells without a staff - the staff just provides * magic attack bonus and elemental staves give infinite runes */ getPlayerAttackType(playerId: string): AttackType { @@ -3945,7 +3944,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { // Check explicit attackType first if (weaponItem.attackType) { - // OSRS-accurate: Magic weapons (staffs/wands) without autocast use + // rules-accurate: Magic weapons (staffs/wands) without autocast use // melee crush attack (bonk). The selectedSpell check above already // returns MAGIC when a spell is selected. const isMagicAttackType = @@ -3961,7 +3960,7 @@ export class ServerNetwork extends System implements NetworkWithSocket { if (weaponItem.weaponType === WeaponType.BOW) { return AttackType.RANGED; } - // OSRS-accurate: Staffs/wands without autocast use melee (crush bonk) + // rules-accurate: Staffs/wands without autocast use melee (crush bonk) // The selectedSpell check above already handles the autocast case if ( weaponItem.weaponType === WeaponType.STAFF || diff --git a/packages/server/src/systems/ServerNetwork/mob-tile-movement.ts b/packages/server/src/systems/ServerNetwork/mob-tile-movement.ts index ee39c83d2..6b5e13ac9 100644 --- a/packages/server/src/systems/ServerNetwork/mob-tile-movement.ts +++ b/packages/server/src/systems/ServerNetwork/mob-tile-movement.ts @@ -1,7 +1,7 @@ /** * Mob Tile Movement Manager * - * RuneScape-style tile-based movement system for mobs. + * classic fantasy MMORPG-style tile-based movement system for mobs. * Mobs move discretely from tile to tile on server ticks (600ms). * * Key behaviors: @@ -9,13 +9,12 @@ * - Mobs move 1-2 tiles per tick (based on mob speed) * - Uses greedy/direct pathfinding (chaseStep), NOT BFS * - Mobs walk directly toward target, getting stuck behind obstacles - * - This enables "safespotting" gameplay (authentic OSRS behavior) + * - This enables "safespotting" gameplay (authentic classic MMORPG behavior) * - Client interpolates visually between tile positions * - * OSRS Reference: + * classic MMORPG Reference: * - Mobs use "dumb" pathfinding - they don't navigate around obstacles - * - This is why safespotting works in OSRS - * - @see https://oldschool.runescape.wiki/w/Pathfinding + * - This is why safespotting works in classic MMORPG */ import { @@ -93,10 +92,10 @@ function createMobTileState( } /** - * Tile-based movement manager for mobs (RuneScape-style) + * Tile-based movement manager for mobs (classic fantasy MMORPG-style) * * IMPORTANT: Mobs use greedy/direct pathfinding (chaseStep), NOT BFS. - * This is authentic OSRS behavior - mobs walk directly toward their target + * This is authentic classic MMORPG behavior - mobs walk directly toward their target * and get stuck behind obstacles (enabling safespotting gameplay). */ export class MobTileMovementManager { @@ -310,7 +309,7 @@ export class MobTileMovementManager { * Called by MobEntity when AI wants to move * * IMPORTANT: Mobs use greedy/direct pathfinding (chaseStep), NOT BFS. - * This is authentic OSRS behavior - mobs walk directly toward their target + * This is authentic classic MMORPG behavior - mobs walk directly toward their target * and get stuck behind obstacles (enabling safespotting gameplay). * * @param mobId - The mob's entity ID @@ -361,7 +360,7 @@ export class MobTileMovementManager { // If chasing an entity and already within combat range - stop moving // (Only for combat - when returning to spawn, we want the exact tile) - // OSRS-accurate: Range 1 = cardinal only (N/S/E/W), range 2+ = diagonal allowed + // rules-accurate: Range 1 = cardinal only (N/S/E/W), range 2+ = diagonal allowed if ( targetEntityId !== null && tilesWithinMeleeRange(state.currentTile, targetTile, combatRange) @@ -413,7 +412,7 @@ export class MobTileMovementManager { this._currentPosTile.x = state.currentTile.x; this._currentPosTile.z = state.currentTile.z; - // OSRS-ACCURATE LEASH RANGE CAP: Get spawn point and leash range + // RULES-ACCURATE LEASH RANGE CAP: Get spawn point and leash range // Mobs cannot move beyond leashRange from their spawn point const mobEntity = entity instanceof MobEntity ? entity : null; const spawnPoint = mobEntity?.getSpawnPoint(); @@ -432,7 +431,7 @@ export class MobTileMovementManager { if (!nextTile) break; // Blocked - // OSRS-ACCURATE: Check if this step would exceed leash range from spawn + // RULES-ACCURATE: Check if this step would exceed leash range from spawn // If so, stop at current position (mob lingers at edge) if (spawnTile) { const nextDistFromSpawn = tileChebyshevDistance(nextTile, spawnTile); @@ -449,7 +448,7 @@ export class MobTileMovementManager { this._currentPosTile.x = nextTile.x; this._currentPosTile.z = nextTile.z; - // Stop if we'll be in combat range after this step (OSRS melee rules) + // Stop if we'll be in combat range after this step (classic MMORPG melee rules) if (tilesWithinMeleeRange(nextTile, targetTile, combatRange)) break; } @@ -504,7 +503,7 @@ export class MobTileMovementManager { // Broadcast movement started // Server sends COMPLETE authoritative path - client follows exactly, no recalculation // startTile: where server knows mob IS - // OSRS-style: Bundle emote with movement packet to prevent animation mismatch + // classic MMORPG-style: Bundle emote with movement packet to prevent animation mismatch // Zero-allocation: copy path to pre-allocated network buffer this._networkPathBuffer.length = state.path.length; @@ -599,14 +598,13 @@ export class MobTileMovementManager { ); } - // OSRS-STYLE DUMB PATHFINDER FOR CHASE MODE + // classic MMORPG-STYLE DUMB PATHFINDER FOR CHASE MODE // Instead of expensive BFS repathing every tick, NPCs use a simple algorithm: // 1. Try diagonal step toward target // 2. Try cardinal steps (prioritize axis with greater distance) // 3. If all blocked = NPC is "stuck" (safespotting!) // // This is O(1) per step, so no throttling is needed. - // @see https://oldschool.runescape.wiki/w/Pathfinding if (state.isChasing && state.targetEntityId) { // CRITICAL: Players are NOT in world.entities - they're accessed via world.getPlayer() // Mobs are in world.entities, but when chasing we're always targeting players @@ -621,9 +619,9 @@ export class MobTileMovementManager { this._targetTile, ); - // OSRS COMBAT POSITIONING: Check if we're already in combat range + // classic MMORPG COMBAT POSITIONING: Check if we're already in combat range // If so, we're in attack range - no need to move closer! - // OSRS-accurate: Range 1 = cardinal only (N/S/E/W), range 2+ = diagonal allowed + // rules-accurate: Range 1 = cardinal only (N/S/E/W), range 2+ = diagonal allowed const combatRange = state.combatRange || 1; if ( tilesWithinMeleeRange( @@ -698,7 +696,7 @@ export class MobTileMovementManager { this._currentPosTile.x = state.currentTile.x; this._currentPosTile.z = state.currentTile.z; - // OSRS-ACCURATE LEASH RANGE CAP: Get spawn point and leash range + // RULES-ACCURATE LEASH RANGE CAP: Get spawn point and leash range // Mobs cannot move beyond leashRange from their spawn point const mobEntity = entity instanceof MobEntity ? entity : null; const spawnPoint = mobEntity?.getSpawnPoint(); @@ -726,7 +724,7 @@ export class MobTileMovementManager { break; } - // OSRS-ACCURATE: Check if this step would exceed leash range from spawn + // RULES-ACCURATE: Check if this step would exceed leash range from spawn // If so, stop at current position (mob lingers at edge) if (hasSpawnTile) { const nextDistFromSpawn = tileChebyshevDistance( @@ -747,7 +745,7 @@ export class MobTileMovementManager { this._currentPosTile.x = nextTile.x; this._currentPosTile.z = nextTile.z; - // Stop early if we'll be in combat range after this step (OSRS melee rules) + // Stop early if we'll be in combat range after this step (classic MMORPG melee rules) if ( tilesWithinMeleeRange(nextTile, this._targetTile, combatRange) ) { @@ -880,7 +878,7 @@ export class MobTileMovementManager { const nextTile = state.path[state.pathIndex]; - // OSRS-STYLE COLLISION: Never step onto the tile occupied by our target + // classic MMORPG-STYLE COLLISION: Never step onto the tile occupied by our target // This is defense-in-depth - the path should already avoid this, // but we double-check here in case target moved after path calculation if ( @@ -898,10 +896,10 @@ export class MobTileMovementManager { break; } - // OSRS-ACCURATE ENTITY COLLISION: Check if tile is blocked by another NPC - // Per OSRS: Pathfinder IGNORES entity collision - it's checked HERE at movement time + // RULES-ACCURATE ENTITY COLLISION: Check if tile is blocked by another NPC + // Pathfinder ignores entity collision; it is checked here at movement time. // If blocked: movement fails, path is RETAINED for retry next tick - // This creates the "waiting behind" behavior seen in OSRS + // This creates the "waiting behind" behavior seen in classic MMORPG const isBlocked = this.world.entityOccupancy.isBlocked( nextTile, mobId as EntityID, @@ -913,7 +911,7 @@ export class MobTileMovementManager { `[MobTileMovement] COLLISION: Mob ${mobId} at (${state.currentTile.x},${state.currentTile.z}) cannot move to (${nextTile.x},${nextTile.z}) - blocked by ${occupant?.entityId}`, ); } - // Path is RETAINED - will retry next tick (OSRS-accurate) + // Path is RETAINED - will retry next tick (rules-accurate) break; } else if (this.DEBUG_MODE) { console.log( @@ -975,7 +973,7 @@ export class MobTileMovementManager { entity.data.position = [worldPos.x, worldPos.y, worldPos.z]; } - // Update entity occupancy after movement (OSRS-accurate tile collision) + // Update entity occupancy after movement (rules-accurate tile collision) // This updates the EntityOccupancyMap to reflect the mob's new position if (entity instanceof MobEntity) { if (this.DEBUG_MODE) @@ -1052,9 +1050,9 @@ export class MobTileMovementManager { /** * Process movement for a specific mob on this tick * - * OSRS-ACCURATE: Called by GameTickProcessor during NPC phase + * RULES-ACCURATE: Called by GameTickProcessor during NPC phase * This processes just one mob's movement instead of all mobs. - * NPCs process BEFORE players in OSRS, which creates damage asymmetry. + * NPCs process BEFORE players in classic MMORPG, which creates damage asymmetry. * * Zero-allocation: Uses pre-allocated tile buffers. * @@ -1073,7 +1071,7 @@ export class MobTileMovementManager { const terrain = this.getTerrain(); - // OSRS-STYLE DUMB PATHFINDER FOR CHASE MODE + // classic MMORPG-STYLE DUMB PATHFINDER FOR CHASE MODE if (state.isChasing && state.targetEntityId) { const targetPlayer = this.world.getPlayer?.(state.targetEntityId); const targetEntity = @@ -1126,7 +1124,7 @@ export class MobTileMovementManager { this._currentPosTile.x = state.currentTile.x; this._currentPosTile.z = state.currentTile.z; - // OSRS-ACCURATE LEASH RANGE CAP: Get spawn point and leash range + // RULES-ACCURATE LEASH RANGE CAP: Get spawn point and leash range // Mobs cannot move beyond leashRange from their spawn point const mobEntity = entity instanceof MobEntity ? entity : null; const spawnPoint = mobEntity?.getSpawnPoint(); @@ -1151,7 +1149,7 @@ export class MobTileMovementManager { if (!nextTile) break; - // OSRS-ACCURATE: Check if this step would exceed leash range from spawn + // RULES-ACCURATE: Check if this step would exceed leash range from spawn // If so, stop at current position (mob lingers at edge) if (hasSpawnTile) { const nextDistFromSpawn = tileChebyshevDistance( @@ -1220,11 +1218,11 @@ export class MobTileMovementManager { if (state.pathIndex >= state.path.length) break; const nextTile = state.path[state.pathIndex]; - // OSRS-ACCURATE ENTITY COLLISION: Check if tile is blocked by another NPC - // Per OSRS: Pathfinder IGNORES entity collision - it's checked HERE at movement time + // RULES-ACCURATE ENTITY COLLISION: Check if tile is blocked by another NPC + // Pathfinder ignores entity collision; it is checked here at movement time. // If blocked: movement fails, path is RETAINED for retry next tick if (this.world.entityOccupancy.isBlocked(nextTile, mobId as EntityID)) { - // Path is RETAINED - will retry next tick (OSRS-accurate) + // Path is RETAINED - will retry next tick (rules-accurate) break; } @@ -1277,7 +1275,7 @@ export class MobTileMovementManager { entity.data.position = [worldPos.x, worldPos.y, worldPos.z]; } - // Update entity occupancy after movement (OSRS-accurate tile collision) + // Update entity occupancy after movement (rules-accurate tile collision) if (entity instanceof MobEntity) { entity.updateOccupancy(); } diff --git a/packages/server/src/systems/ServerNetwork/services/InputValidation.ts b/packages/server/src/systems/ServerNetwork/services/InputValidation.ts index 75b5b0175..06d676d05 100644 --- a/packages/server/src/systems/ServerNetwork/services/InputValidation.ts +++ b/packages/server/src/systems/ServerNetwork/services/InputValidation.ts @@ -91,7 +91,7 @@ export function isValidBankMoveMode( /** * Validate bank tab index - 0 (main) or 1-9 (custom tabs) - * OSRS allows up to 9 custom tabs plus the main tab + * classic MMORPG allows up to 9 custom tabs plus the main tab */ export function isValidBankTabIndex(value: unknown): value is number { return ( @@ -130,7 +130,7 @@ export function isValidNpcId(value: unknown): value is string { /** * Validate dialogue responseIndex - must be non-negative integer - * Max 10 responses per dialogue node (generous limit for OSRS-style dialogues) + * Max 10 responses per dialogue node (generous limit for classic MMORPG-style dialogues) */ export function isValidResponseIndex(value: unknown): value is number { return ( diff --git a/packages/server/src/systems/ServerNetwork/services/SlidingWindowRateLimiter.ts b/packages/server/src/systems/ServerNetwork/services/SlidingWindowRateLimiter.ts index c4937f162..de7a49e58 100644 --- a/packages/server/src/systems/ServerNetwork/services/SlidingWindowRateLimiter.ts +++ b/packages/server/src/systems/ServerNetwork/services/SlidingWindowRateLimiter.ts @@ -251,7 +251,7 @@ export function getEquipRateLimiter(): RateLimiter { /** * Get the consumable rate limiter (3/sec) * Limits food/potion use requests - separate from equip to allow - * OSRS-style PvP where players gear switch AND eat in same tick + * classic MMORPG-style PvP where players gear switch AND eat in same tick * Game logic already enforces 3-tick (1.8s) eat delay */ export function getConsumeRateLimiter(): RateLimiter { @@ -266,7 +266,7 @@ export function getConsumeRateLimiter(): RateLimiter { /** * Get the tile movement rate limiter (15/sec) - * Limits tile movement requests - allows burst clicking (OSRS allows rapid clicks) + * Limits tile movement requests - allows burst clicking (classic MMORPG allows rapid clicks) * but prevents spam attacks that could overwhelm the server */ export function getTileMovementRateLimiter(): RateLimiter { @@ -296,7 +296,7 @@ export function getPathfindRateLimiter(): RateLimiter { /** * Get the combat rate limiter (3/sec) - * Limits attack requests - OSRS tick is 600ms, so ~1.67 attacks/sec max + * Limits attack requests - classic MMORPG tick is 600ms, so ~1.67 attacks/sec max * We allow 3/sec to be generous with client click behavior */ export function getCombatRateLimiter(): RateLimiter { @@ -341,7 +341,7 @@ export function getCoinPouchRateLimiter(): RateLimiter { /** * Get the prayer rate limiter (5/sec) * Limits prayer toggle requests - matches PRAYER_TOGGLE_RATE_LIMIT - * OSRS allows quick prayer switching but we prevent spam + * classic MMORPG allows quick prayer switching but we prevent spam */ export function getPrayerRateLimiter(): RateLimiter { if (!prayerLimiter) { diff --git a/packages/server/src/systems/ServerNetwork/services/ValidationService.ts b/packages/server/src/systems/ServerNetwork/services/ValidationService.ts index 34a3898e3..4fa56d76c 100644 --- a/packages/server/src/systems/ServerNetwork/services/ValidationService.ts +++ b/packages/server/src/systems/ServerNetwork/services/ValidationService.ts @@ -74,7 +74,7 @@ export class ValidationService implements ITransactionValidator { }; } - // 5. Check distance (Chebyshev/OSRS-style) + // 5. Check distance (Chebyshev/classic MMORPG-style) const distance = chebyshevDistance(player.position, target.position); const maxDistance = INTERACTION_DISTANCE[requiredType]; diff --git a/packages/server/src/systems/ServerNetwork/socket-management.ts b/packages/server/src/systems/ServerNetwork/socket-management.ts index 0fd765ca5..9272b8c68 100644 --- a/packages/server/src/systems/ServerNetwork/socket-management.ts +++ b/packages/server/src/systems/ServerNetwork/socket-management.ts @@ -45,7 +45,7 @@ const TEST_MAX_SOCKET_COUNT = Math.max( /** * Socket health manager for WebSocket connection monitoring */ -/** Duration to keep a player entity alive after combat disconnect (OSRS: ~10s) */ +/** Duration to keep a player entity alive after combat disconnect (classic MMORPG: ~10s) */ const COMBAT_LOGOUT_DELAY_MS = Math.max( 0, parseInt(process.env.COMBAT_LOGOUT_DELAY_MS || "10000", 10), @@ -282,7 +282,7 @@ export class SocketManager { }, ); - // Check combat logout timer (OSRS: can't log out for ~10s after combat) + // Check combat logout timer (classic MMORPG: can't log out for ~10s after combat) const combatSystem = this.world.getSystem("combat") as { canLogout?: ( playerId: string, @@ -296,7 +296,7 @@ export class SocketManager { ); if (logoutCheck && !logoutCheck.allowed) { - // Player is in combat — delay entity removal (OSRS combat-logging prevention) + // Player is in combat — delay entity removal (classic MMORPG combat-logging prevention) // Entity stays in-world and targetable during the grace period console.log( `[SocketManager] Combat logout delay for ${playerId}: ${logoutCheck.reason}`, diff --git a/packages/server/src/systems/ServerNetwork/tile-movement.ts b/packages/server/src/systems/ServerNetwork/tile-movement.ts index 1e9570c7b..733d65d51 100644 --- a/packages/server/src/systems/ServerNetwork/tile-movement.ts +++ b/packages/server/src/systems/ServerNetwork/tile-movement.ts @@ -1,7 +1,7 @@ /** * Tile Movement Manager * - * RuneScape-style tile-based movement system. + * classic fantasy MMORPG-style tile-based movement system. * Players move discretely from tile to tile on server ticks (600ms). * * Key differences from the old continuous system: @@ -62,7 +62,7 @@ const AGILITY_TILES_PER_XP_GRANT = 100; // Tiles needed before XP is granted const AGILITY_XP_PER_GRANT = 50; // XP granted per threshold (effectively 1 XP per 2 tiles) /** - * Tile-based movement manager for RuneScape-style movement + * Tile-based movement manager for classic fantasy MMORPG-style movement */ export class TileMovementManager { private playerStates: Map = new Map(); @@ -87,11 +87,11 @@ export class TileMovementManager { private arrivalEmotes: Map = new Map(); /** - * OSRS-ACCURATE: Tick-start positions for all players + * RULES-ACCURATE: Tick-start positions for all players * Captured at the VERY START of onTick(), BEFORE any movement processing. * Used by FollowManager to create the 1-tick delay effect. * - * Key insight from OSRS: "The important part is to set the previousTile + * Key insight from classic MMORPG: "The important part is to set the previousTile * at the start (or the end) of the tick not when they actually move" */ private tickStartTiles: Map = new Map(); @@ -508,10 +508,10 @@ export class TileMovementManager { const payload = validation.payload!; - // OSRS-ACCURACY: Emit click-to-move event for weak queue cancellation + // RULES ACCURACY: Emit click-to-move event for weak queue cancellation // This MUST happen before any early returns (same-tile, cancel, etc.) // ResourceSystem subscribes to this to cancel gathering when player clicks ground - // In OSRS, ANY click cancels weak queue actions like gathering + // In classic MMORPG, ANY click cancels weak queue actions like gathering this.world.emit(EventType.MOVEMENT_CLICK_TO_MOVE, { playerId: playerId, targetPosition: { @@ -526,7 +526,7 @@ export class TileMovementManager { state.path.length = 0; // Zero-allocation clear state.pathIndex = 0; - // RS3-style: Clear movement flag so combat can resume + // modern MMORPG-style: Clear movement flag so combat can resume playerEntity.data.tileMovementActive = false; // Broadcast idle state @@ -632,7 +632,7 @@ export class TileMovementManager { if (path.length > 0) { playerEntity.data.tileMovementActive = true; - // OSRS-accurate: Clicking ground cancels your attack + // rules-accurate: Clicking ground cancels your attack // Player is walking away - they're no longer attacking their target // The mob continues chasing them, and auto-retaliate can trigger if hit this.world.emit(EventType.COMBAT_PLAYER_DISENGAGE, { @@ -679,7 +679,7 @@ export class TileMovementManager { // path: tiles to walk through (server's BFS result) // destinationTile: final target (for verification) // moveSeq: packet ordering to ignore stale packets - // emote: bundled animation (OSRS-style, no separate packet) + // emote: bundled animation (classic MMORPG-style, no separate packet) // Zero-allocation: copy path to pre-allocated network buffer this._networkPathBuffer.length = path.length; @@ -770,7 +770,7 @@ export class TileMovementManager { this._walkabilityCache.clear(); this._directionalBlockCache.clear(); - // OSRS-ACCURATE: Capture tick-start positions for ALL players FIRST + // RULES-ACCURATE: Capture tick-start positions for ALL players FIRST // This happens BEFORE any movement, so FollowManager can see where // players were at the START of this tick (creating 1-tick delay effect) // Overwrite existing tile objects in-place to avoid per-tick allocations. @@ -836,7 +836,7 @@ export class TileMovementManager { for (let i = 0; i < tilesToMove; i++) { if (state.pathIndex >= state.path.length) break; - // OSRS-ACCURATE: Capture the tile we're stepping OFF of + // RULES-ACCURATE: Capture the tile we're stepping OFF of // This ensures previousTile is always 1 tile behind currentTile // Used by FollowManager for 1-tile trailing effect state.previousTile!.x = state.currentTile.x; @@ -957,9 +957,8 @@ export class TileMovementManager { this._worldPos.z, ]; - // OSRS-ACCURATE: Mark player as having moved this tick + // RULES-ACCURATE: Mark player as having moved this tick // Face direction system will skip rotation update if player moved - // @see https://osrs-docs.com/docs/packets/outgoing/updating/masks/face-direction/ const faceManager = ( this.world as { faceDirectionManager?: { markPlayerMoved: (id: string) => void }; @@ -1095,7 +1094,7 @@ export class TileMovementManager { state.path.length = 0; // Zero-allocation clear state.pathIndex = 0; - // RS3-style: Clear movement flag so combat can resume + // modern MMORPG-style: Clear movement flag so combat can resume entity.data.tileMovementActive = false; // Broadcast entity state with arrival emote @@ -1115,7 +1114,7 @@ export class TileMovementManager { /** * Process movement for a specific player on this tick * - * OSRS-ACCURATE: Called by GameTickProcessor during player phase + * RULES-ACCURATE: Called by GameTickProcessor during player phase * This processes just one player's movement instead of all players. * * Zero-allocation: Uses pre-allocated tile buffers. @@ -1153,7 +1152,7 @@ export class TileMovementManager { for (let i = 0; i < tilesToMove; i++) { if (state.pathIndex >= state.path.length) break; - // OSRS-ACCURATE: Capture the tile we're stepping OFF of + // RULES-ACCURATE: Capture the tile we're stepping OFF of // This ensures previousTile is always 1 tile behind currentTile // Used by FollowManager for 1-tile trailing effect state.previousTile!.x = state.currentTile.x; @@ -1235,7 +1234,7 @@ export class TileMovementManager { this._worldPos.z, ]; - // OSRS-ACCURATE: Mark player as having moved this tick + // RULES-ACCURATE: Mark player as having moved this tick // Face direction system will skip rotation update if player moved const faceManager = ( this.world as { @@ -1353,7 +1352,7 @@ export class TileMovementManager { state.path.length = 0; // Zero-allocation clear state.pathIndex = 0; - // RS3-style: Clear movement flag so combat can resume + // modern MMORPG-style: Clear movement flag so combat can resume entity.data.tileMovementActive = false; // Broadcast entity state with arrival emote @@ -1657,7 +1656,7 @@ export class TileMovementManager { state.lastPathPartial = false; state.nextSegmentPrecomputed = false; - // RS3-style: Clear movement flag so combat can resume + // modern MMORPG-style: Clear movement flag so combat can resume const entity = this.world.entities.get(playerId); if (entity?.data) { entity.data.tileMovementActive = false; @@ -1687,13 +1686,13 @@ export class TileMovementManager { /** * Get the previous tile for a player (where they were at START of tick) * - * OSRS-ACCURATE: Used by FollowManager for follow mechanic. + * RULES-ACCURATE: Used by FollowManager for follow mechanic. * Followers path to target's PREVIOUS tile, creating the * characteristic 1-tick trailing effect. * * Edge cases: * - If no previous tile (just spawned/teleported): use tile WEST of current - * - This matches OSRS behavior per private server community research + * - This matches classic MMORPG behavior per private server community research * * @see https://rune-server.org/threads/help-with-player-dancing-spinning-when-following-each-other.706121/ */ @@ -1706,7 +1705,7 @@ export class TileMovementManager { } // Fallback: If no previous tile (just spawned/teleported), use tile WEST of current - // This matches OSRS behavior per private server research + // This matches classic MMORPG behavior per private server research if (state) { return { x: state.currentTile.x - 1, @@ -1731,7 +1730,7 @@ export class TileMovementManager { /** * Get the tick-start tile for a player * - * OSRS-ACCURATE: Returns where the player was at the VERY START of the + * RULES-ACCURATE: Returns where the player was at the VERY START of the * current tick, BEFORE any movement was processed. This is different from * previousTile (which is the last tile stepped off during movement). * @@ -1807,7 +1806,7 @@ export class TileMovementManager { * Server-initiated movement toward a target position * Used for combat follow when target moves out of range * - * OSRS-style pathfinding (from wiki): + * classic MMORPG-style pathfinding (from wiki): * - When clicking on an NPC, the requested tiles are all tiles within attack range * - BFS finds the CLOSEST valid tile among those options * - For melee range 1: only cardinal tiles (N/S/E/W) are valid destinations @@ -1820,7 +1819,6 @@ export class TileMovementManager { * @param attackRange - Weapon's attack range (1 = standard melee, 2 = halberd, 10 = ranged/magic, 0 = non-combat) * @param attackType - Attack type (MELEE, RANGED, MAGIC) - affects positioning logic * - * @see https://oldschool.runescape.wiki/w/Pathfinding */ movePlayerToward( playerId: string, @@ -2062,7 +2060,7 @@ export class TileMovementManager { state.isRunning = running; state.moveSeq = (state.moveSeq || 0) + 1; - // RS3-style: Set movement flag to suppress combat while moving + // modern MMORPG-style: Set movement flag to suppress combat while moving entity.data.tileMovementActive = true; // Broadcast movement start diff --git a/packages/server/src/systems/TickSystem.ts b/packages/server/src/systems/TickSystem.ts index f376ffbaa..93deb1e12 100644 --- a/packages/server/src/systems/TickSystem.ts +++ b/packages/server/src/systems/TickSystem.ts @@ -1,7 +1,7 @@ /** * Tick System * - * Implements RuneScape-style server tick system. + * Implements classic fantasy MMORPG-style server tick system. * All game logic runs on 600ms ticks, ensuring: * - Consistent timing for all players * - Predictable movement (1-2 tiles per tick) @@ -41,7 +41,7 @@ interface TickListener { } /** - * Server tick system for RuneScape-style game loop + * Server tick system for classic fantasy MMORPG-style game loop * * Uses self-correcting setTimeout instead of setInterval to prevent drift. * setInterval can accumulate timing errors over time, especially under load. @@ -57,7 +57,7 @@ export class TickSystem { private isRunning = false; /** * When true, skip missed ticks and reset schedule when falling behind (>1 tick). - * This is the correct RuneScape behavior: ticks stretch under load, they don't + * This is the correct classic fantasy MMORPG behavior: ticks stretch under load, they don't * replay in a burst. Actions stay responsive on the next clean tick. * Set TICK_ALLOW_SKIP=false to disable (useful for diagnosing desync). */ diff --git a/packages/server/src/systems/TradingSystem/index.ts b/packages/server/src/systems/TradingSystem/index.ts index 408093134..2993bb647 100644 --- a/packages/server/src/systems/TradingSystem/index.ts +++ b/packages/server/src/systems/TradingSystem/index.ts @@ -567,7 +567,7 @@ export class TradingSystem { /** * Set acceptance state for a player * - * Two-screen confirmation flow (OSRS-style): + * Two-screen confirmation flow (classic MMORPG-style): * 1. On "active" (offer screen): both accept → moveToConfirming: true * 2. On "confirming" (confirmation screen): both accept → bothAccepted: true */ @@ -627,7 +627,7 @@ export class TradingSystem { } /** - * Move trade to confirmation screen (OSRS two-screen flow) + * Move trade to confirmation screen (classic MMORPG two-screen flow) * Resets acceptance for both players */ moveToConfirmation(tradeId: string): TradeOperationResult { @@ -688,7 +688,7 @@ export class TradingSystem { * Complete a trade - swap items between players * Returns the items each player receives (for database operations) * - * Note: Trade must be in "confirming" status (OSRS two-screen flow) + * Note: Trade must be in "confirming" status (classic MMORPG two-screen flow) */ completeTrade(tradeId: string): TradeOperationResult & { initiatorReceives?: TradeOfferItem[]; diff --git a/packages/server/tests/e2e/fixed-timestep-timing.spec.ts b/packages/server/tests/e2e/fixed-timestep-timing.spec.ts index 45c02ba9b..76b683f15 100644 --- a/packages/server/tests/e2e/fixed-timestep-timing.spec.ts +++ b/packages/server/tests/e2e/fixed-timestep-timing.spec.ts @@ -363,7 +363,7 @@ test.describe("Fixed Timestep Timing System", () => { ); // Server ticks should be ~600ms (allow some variance for network/scheduling) - // This verifies the OSRS-style tick system is working + // This verifies the classic MMORPG-style tick system is working expect(avgInterval).toBeGreaterThan(400); // At least 400ms expect(avgInterval).toBeLessThan(1000); // At most 1000ms logs.push(`[${testName}] ✅ Tick timing within expected range`); diff --git a/packages/server/tests/integration/bank/equipment.integration.test.ts b/packages/server/tests/integration/bank/equipment.integration.test.ts index af499a63a..26efb0b1a 100644 --- a/packages/server/tests/integration/bank/equipment.integration.test.ts +++ b/packages/server/tests/integration/bank/equipment.integration.test.ts @@ -1,7 +1,7 @@ /** * Bank Equipment Handler Integration Tests * - * Tests the RS3-style equipment tab handler flows with mocked dependencies. + * Tests the modern MMORPG-style equipment tab handler flows with mocked dependencies. * These tests verify handler behavior at the integration boundary. */ diff --git a/packages/server/tests/integration/inventory-move.integration.test.ts b/packages/server/tests/integration/inventory-move.integration.test.ts index f156e6ffd..0462eb8ed 100644 --- a/packages/server/tests/integration/inventory-move.integration.test.ts +++ b/packages/server/tests/integration/inventory-move.integration.test.ts @@ -2,7 +2,7 @@ * Inventory Move Integration Tests * * Tests the inventory move/swap handler logic with mocked socket/world dependencies. - * Verifies OSRS-style SWAP behavior (not INSERT), validation, and rate limiting. + * Verifies classic MMORPG-style SWAP behavior (not INSERT), validation, and rate limiting. */ import { describe, it, expect, beforeEach, vi } from "vitest"; @@ -112,7 +112,7 @@ function isValidInventorySlot(value: unknown): value is number { ); } -// Simulate the OSRS-style SWAP logic from InventorySystem.moveItem +// Simulate the classic MMORPG-style SWAP logic from InventorySystem.moveItem function performSwap( inventory: MockInventory, fromSlot: number, @@ -136,7 +136,7 @@ function performSwap( return false; } - // OSRS-style SWAP: exchange two slots directly + // classic MMORPG-style SWAP: exchange two slots directly if (fromItem && toItem) { // Both slots occupied - swap fromItem.slot = toSlot; @@ -224,7 +224,7 @@ function handleMoveItem( return { success: false, error: "Swap failed" }; } -describe("Inventory Move Integration - OSRS-style SWAP", () => { +describe("Inventory Move Integration - classic MMORPG-style SWAP", () => { let player: MockPlayer; let socket: MockSocket; let world: MockWorld; @@ -804,7 +804,7 @@ describe("Inventory Move Integration - Stackable Items", () => { }); it("swaps stackable items without merging stacks", () => { - // OSRS inventory swap doesn't merge stacks - that's a bank operation + // classic MMORPG inventory swap doesn't merge stacks - that's a bank operation const arrows1 = createMockItem("bronze_arrows", 0, 50); arrows1.item.stackable = true; const arrows2 = createMockItem("bronze_arrows", 5, 100); diff --git a/packages/server/tests/unit/bank/coins.test.ts b/packages/server/tests/unit/bank/coins.test.ts index 06c44cc15..5aa111fc3 100644 --- a/packages/server/tests/unit/bank/coins.test.ts +++ b/packages/server/tests/unit/bank/coins.test.ts @@ -13,7 +13,7 @@ import { describe, it, expect, beforeEach } from "vitest"; // Constants (mirror actual constants) // ============================================================================ -const MAX_COINS = 2147483647; // Max 32-bit signed integer (OSRS cap) +const MAX_COINS = 2147483647; // Max 32-bit signed integer (classic MMORPG cap) const MAX_BANK_SLOTS = 1200; // ============================================================================ diff --git a/packages/server/tests/unit/bank/equipment.test.ts b/packages/server/tests/unit/bank/equipment.test.ts index 24316327a..a513b0661 100644 --- a/packages/server/tests/unit/bank/equipment.test.ts +++ b/packages/server/tests/unit/bank/equipment.test.ts @@ -1,7 +1,7 @@ /** * Bank Equipment Unit Tests * - * Tests for RS3-style bank equipment tab operations: + * Tests for modern MMORPG-style bank equipment tab operations: * - Withdraw to equipment (equip directly from bank) * - Deposit from equipment (unequip directly to bank) * - Deposit all equipment (one-click unequip all) diff --git a/packages/server/tests/unit/bank/placeholders.test.ts b/packages/server/tests/unit/bank/placeholders.test.ts index 88f5bb9b8..6e30e0260 100644 --- a/packages/server/tests/unit/bank/placeholders.test.ts +++ b/packages/server/tests/unit/bank/placeholders.test.ts @@ -1,7 +1,7 @@ /** * Bank Placeholders Unit Tests * - * Tests for RS3-style placeholder system logic. + * Tests for modern MMORPG-style placeholder system logic. * Uses mock classes following the existing codebase pattern. */ @@ -36,7 +36,7 @@ const MAX_INVENTORY_SLOTS = 28; /** * Mock bank placeholder manager that tests the ALGORITHM logic - * for RS3-style placeholder operations. + * for modern MMORPG-style placeholder operations. */ class MockBankPlaceholderManager { private bankData: BankSlot[] = []; @@ -65,7 +65,7 @@ class MockBankPlaceholderManager { /** * Withdraw-placeholder: Withdraw all, leave qty=0 placeholder * - * RS3-style: Withdraws all of an item to inventory and leaves qty=0 + * modern MMORPG-style: Withdraws all of an item to inventory and leaves qty=0 */ withdrawPlaceholder( playerId: string, diff --git a/packages/server/tests/unit/bank/tabs.test.ts b/packages/server/tests/unit/bank/tabs.test.ts index 8d7621493..21f66b1a9 100644 --- a/packages/server/tests/unit/bank/tabs.test.ts +++ b/packages/server/tests/unit/bank/tabs.test.ts @@ -1,7 +1,7 @@ /** * Bank Tabs Unit Tests * - * Tests for RS3-style bank tab management logic. + * Tests for modern MMORPG-style bank tab management logic. * Uses mock classes following the existing codebase pattern. */ diff --git a/packages/server/tests/unit/combat/PendingAttackManager.test.ts b/packages/server/tests/unit/combat/PendingAttackManager.test.ts index 6957a5ef0..b56603e6f 100644 --- a/packages/server/tests/unit/combat/PendingAttackManager.test.ts +++ b/packages/server/tests/unit/combat/PendingAttackManager.test.ts @@ -249,7 +249,7 @@ describe("PendingAttackManager", () => { expect(manager.hasPendingAttack("player1")).toBe(false); }); - it("does NOT emit combat when player is diagonal with range 1 (OSRS rule)", () => { + it("does NOT emit combat when player is diagonal with range 1 (classic MMORPG rule)", () => { // Place mob at tile (5, 5) mobPositions.set("mob1", { x: 5.5, y: 0, z: 5.5 }); aliveMobs.add("mob1"); @@ -326,7 +326,7 @@ describe("PendingAttackManager", () => { expect(tileMovementManager._movePlayerToward).not.toHaveBeenCalled(); }); - it("follows indefinitely - no timeout (OSRS behavior)", () => { + it("follows indefinitely - no timeout (classic MMORPG behavior)", () => { mobPositions.set("mob1", { x: 100.5, y: 0, z: 100.5 }); aliveMobs.add("mob1"); world.setPlayerPosition("player1", 0.5, 0, 0.5); diff --git a/packages/server/tests/unit/follow/FollowManager.test.ts b/packages/server/tests/unit/follow/FollowManager.test.ts index cd14b3a80..3b645fe3b 100644 --- a/packages/server/tests/unit/follow/FollowManager.test.ts +++ b/packages/server/tests/unit/follow/FollowManager.test.ts @@ -1,17 +1,17 @@ /** * FollowManager Unit Tests * - * Tests the OSRS-accurate player following system. + * Tests the rules-accurate player following system. * * Key behaviors tested: * - Starting and stopping follows - * - 1-tick delay before following starts (OSRS-accurate) + * - 1-tick delay before following starts (rules-accurate) * - 1-tile trailing behavior using previousTile * - Re-pathing when target moves * - Cleanup on player disconnect * - Mutual following ("dancing" pattern) * - * @see https://runescape.wiki/w/Follow + * @see https://classic.wiki/w/Follow * @see https://rune-server.org/threads/help-with-player-dancing-spinning-when-following-each-other.706121/ */ diff --git a/packages/server/tests/unit/inventory/coinPouch.test.ts b/packages/server/tests/unit/inventory/coinPouch.test.ts index 9dedcd953..09b7f7485 100644 --- a/packages/server/tests/unit/inventory/coinPouch.test.ts +++ b/packages/server/tests/unit/inventory/coinPouch.test.ts @@ -19,7 +19,7 @@ import { describe, it, expect, beforeEach } from "vitest"; // Constants (mirror actual constants from @hyperforge/shared) // ============================================================================ -const MAX_COINS = 2147483647; // Max 32-bit signed integer (OSRS cap) +const MAX_COINS = 2147483647; // Max 32-bit signed integer (classic MMORPG cap) const MAX_INVENTORY_SLOTS = 28; // ============================================================================ diff --git a/packages/server/tests/unit/systems/ServerNetwork/InteractionSessionManager.combat.test.ts b/packages/server/tests/unit/systems/ServerNetwork/InteractionSessionManager.combat.test.ts index aa12d0282..0360209b4 100644 --- a/packages/server/tests/unit/systems/ServerNetwork/InteractionSessionManager.combat.test.ts +++ b/packages/server/tests/unit/systems/ServerNetwork/InteractionSessionManager.combat.test.ts @@ -1,10 +1,9 @@ /** * InteractionSessionManager Combat Tests * - * Tests the OSRS-style behavior where being attacked closes bank/store/dialogue. + * Tests the classic MMORPG-style behavior where being attacked closes bank/store/dialogue. * This is server-authoritative - the server sends close packets when combat starts. * - * @see https://oldschool.runescape.wiki/w/Bank * "If a player is attacked while banking, the bank window will close." */ @@ -188,7 +187,7 @@ describe("InteractionSessionManager - Combat Closes Sessions", () => { targetId: playerId, targetType: "player", attackerId: "mob-1", - damage: 0, // OSRS: Even splash/miss (0 damage) interrupts + damage: 0, // classic MMORPG: Even splash/miss (0 damage) interrupts }); // Session should be closed @@ -205,7 +204,7 @@ describe("InteractionSessionManager - Combat Closes Sessions", () => { ); }); - it("should close session even with zero damage (OSRS-accurate)", () => { + it("should close session even with zero damage (rules-accurate)", () => { const playerId = "player-4"; manager.openSession({ @@ -215,7 +214,7 @@ describe("InteractionSessionManager - Combat Closes Sessions", () => { targetEntityId: "bank-npc-1", }); - // OSRS: Splash attacks (0 damage) still interrupt banking + // classic MMORPG: Splash attacks (0 damage) still interrupt banking mockWorld._triggerEvent(EventType.COMBAT_DAMAGE_DEALT, { targetId: playerId, targetType: "player", diff --git a/packages/shared/dev-book/01-overview/features.md b/packages/shared/dev-book/01-overview/features.md index ab762e3ab..08dc04f32 100644 --- a/packages/shared/dev-book/01-overview/features.md +++ b/packages/shared/dev-book/01-overview/features.md @@ -668,12 +668,12 @@ world.ui.appendChild(healthBar); - Instanced mesh rendering for performance - Always face camera (billboarding) - Distance scaling -- Shown during combat (RuneScape pattern) +- Shown during combat (classic fantasy MMORPG pattern) **Usage:** ```typescript // Health bars managed by HealthBars system -// Names shown in right-click context menu only (OSRS pattern) +// Names shown in right-click context menu only (classic MMORPG pattern) entity.createHealthBar(); // Shows current/max health ``` diff --git a/packages/shared/dev-book/05-core-systems/COMBAT-SYSTEM-DOCUMENTATION.md b/packages/shared/dev-book/05-core-systems/COMBAT-SYSTEM-DOCUMENTATION.md index 33a4afa49..d21330c75 100644 --- a/packages/shared/dev-book/05-core-systems/COMBAT-SYSTEM-DOCUMENTATION.md +++ b/packages/shared/dev-book/05-core-systems/COMBAT-SYSTEM-DOCUMENTATION.md @@ -1,6 +1,6 @@ # Combat System Documentation -> **The Complete Technical Reference for Hyperia's OSRS-Accurate Combat System** +> **The Complete Technical Reference for Hyperia's Rules-Accurate Combat System** --- @@ -15,7 +15,7 @@ 7. [Loot & Economy Systems](#7-loot--economy-systems) 8. [Animation & Timing](#8-animation--timing) 9. [Client Visual Systems](#9-client-visual-systems) -10. [OSRS Combat Mechanics](#10-osrs-combat-mechanics) +10. [classic MMORPG Combat Mechanics](#10-classic-combat-mechanics) 11. [Combat Flow Diagrams](#11-combat-flow-diagrams) 12. [Damage Calculation](#12-damage-calculation) 13. [Security & Anti-Cheat](#13-security--anti-cheat) @@ -95,7 +95,7 @@ | Principle | Implementation | |-----------|---------------| -| **OSRS Accuracy** | Tick-based timing (600ms), authentic formulas, PID shuffle, tolerance timer | +| **classic MMORPG Accuracy** | Tick-based timing (600ms), authentic formulas, PID shuffle, tolerance timer | | **Type Safety** | Runtime type guards, branded IDs, zero `any` types | | **Zero Allocations** | Object pooling, pre-allocated tile buffers | | **Security First** | OWASP validation, HMAC signing, rate limiting, anti-cheat scoring | @@ -122,11 +122,11 @@ packages/shared/src/ │ ├── CombatRequestValidator.ts # HMAC signing (245 lines) │ ├── CombatReplayService.ts # Replay & debugging (567 lines) │ ├── CombatAnimationSync.ts # Animation-damage sync (492 lines) -│ ├── RangeSystem.ts # OSRS range calculations (300 lines) +│ ├── RangeSystem.ts # classic MMORPG range calculations (300 lines) │ ├── AggroSystem.ts # Mob AI & aggression (857 lines) │ ├── MobDeathSystem.ts # Mob death handling (79 lines) │ ├── PlayerDeathSystem.ts # Player death/respawn (1,263 lines) -│ ├── PidManager.ts # OSRS PID system (392 lines) +│ ├── PidManager.ts # classic MMORPG PID system (392 lines) │ └── handlers/ │ ├── index.ts # Barrel export │ ├── DamageHandler.ts # Strategy interface (120 lines) @@ -144,9 +144,9 @@ packages/shared/src/ ├── systems/shared/economy/ │ ├── LootSystem.ts # Loot drop orchestration (203 lines) │ ├── LootTableService.ts # Loot table logic/rolling (204 lines) -│ └── GroundItemSystem.ts # OSRS-style ground items (633 lines) +│ └── GroundItemSystem.ts # classic MMORPG-style ground items (633 lines) ├── systems/shared/character/ -│ └── HealthRegenSystem.ts # OSRS passive health regen (230 lines) +│ └── HealthRegenSystem.ts # classic MMORPG passive health regen (230 lines) ├── systems/client/ │ ├── DamageSplatSystem.ts # Client damage visualization (238 lines) │ ├── XPDropSystem.ts # Client XP drop display (226 lines) @@ -177,10 +177,10 @@ packages/shared/src/ ├── SeededRandom.ts # Deterministic RNG (284 lines) ├── typeGuards.ts # Runtime type validation (545 lines) └── game/ - ├── CombatLevelCalculator.ts # OSRS combat level formula (156 lines) + ├── CombatLevelCalculator.ts # classic MMORPG combat level formula (156 lines) ├── CombatCalculations.ts # Damage/accuracy formulas (468 lines) ├── CombatValidation.ts # Input validation utilities (223 lines) - ├── HitDelayCalculator.ts # OSRS hit delay/projectiles (345 lines) + ├── HitDelayCalculator.ts # classic MMORPG hit delay/projectiles (345 lines) └── CombatUtils.ts # Combat helper functions (358 lines) packages/server/src/ @@ -358,7 +358,7 @@ class CombatComponent extends Component { ### 3.6 PlayerCombatStateManager -The `PlayerCombatStateManager.ts` (406 lines) manages player-specific combat state with OSRS-accurate mechanics. +The `PlayerCombatStateManager.ts` (406 lines) manages player-specific combat state with rules-accurate mechanics. ```typescript class PlayerCombatStateManager { @@ -367,7 +367,7 @@ class PlayerCombatStateManager { private targetId: string | null; private lastAttackerId: string | null; - // Auto-retaliate (enabled by default in OSRS) + // Auto-retaliate (enabled by default in classic MMORPG) private autoRetaliateEnabled = true; // AFK tracking (20 minutes disables auto-retaliate) @@ -381,7 +381,7 @@ class PlayerCombatStateManager { performAttack(targetId: string, currentTick: number): boolean; onReceiveAttack(attackerId: string, currentTick: number): void; - // OSRS auto-retaliate timing: ceil(attackSpeed / 2) + 1 ticks + // classic MMORPG auto-retaliate timing: ceil(attackSpeed / 2) + 1 ticks private shouldAutoRetaliate(currentTick: number): boolean; // Logout check (16 ticks after damage) @@ -392,15 +392,15 @@ class PlayerCombatStateManager { } ``` -**OSRS-Accurate Features:** +**Rules-Accurate Features:** - Auto-retaliate delay: `ceil(attackSpeed / 2) + 1` ticks - AFK timeout: 2000 ticks (20 minutes) disables auto-retaliate - Logout prevention: 16 ticks (9.6 seconds) after taking damage - Combat timeout: 8 ticks (4.8 seconds) of inactivity -### 3.7 PidManager (OSRS PID Shuffle) +### 3.7 PidManager (classic MMORPG PID Shuffle) -Ensures fair PvP combat priority using OSRS-accurate PID system. +Ensures fair PvP combat priority using rules-accurate PID system. ``` ┌─────────────────────────────────────────────────────────────────┐ @@ -585,7 +585,7 @@ The AggroSystem handles mob AI, aggression detection, and chase mechanics. ### 4.2 Tolerance Timer System -OSRS-accurate tolerance timer that stops aggression after 10 minutes in a region. +rules-accurate tolerance timer that stops aggression after 10 minutes in a region. ``` ┌─────────────────────────────────────────────────────────────────┐ @@ -624,7 +624,7 @@ OSRS-accurate tolerance timer that stops aggression after 10 minutes in a region ### 4.3 Combat Level Calculator -OSRS-accurate combat level formula for aggression checks. +rules-accurate combat level formula for aggression checks. ```typescript /** @@ -682,7 +682,7 @@ The `AIStateMachine.ts` (568 lines) provides a complete state machine for mob AI │ └───────────│ ATTACK │──────────────────────────┘ │ │ └──────────┘ │ │ │ -│ OSRS-Accurate Features: │ +│ Rules-Accurate Features: │ │ • Tile-based distance (not world distance) │ │ • Range 1 melee: Cardinal only (no diagonal) │ │ • Same-tile handling: Step out to random cardinal direction │ @@ -711,7 +711,7 @@ class AIStateMachine { ### 4.5 AggroManager (Per-Entity Targeting) -The `AggroManager.ts` (306 lines) handles target acquisition with OSRS-accurate random selection. +The `AggroManager.ts` (306 lines) handles target acquisition with rules-accurate random selection. ```typescript class AggroManager { @@ -721,7 +721,7 @@ class AggroManager { // Zero-allocation buffer for valid targets private readonly _validTargetsBuffer: PlayerTarget[]; - // OSRS-accurate: Random selection from ALL valid candidates + // rules-accurate: Random selection from ALL valid candidates // (not first-found, not closest) findNearbyPlayer( currentPos: Position3D, @@ -743,11 +743,11 @@ class AggroManager { ## 5. Range System -### 5.1 Three OSRS Range Types +### 5.1 Three classic MMORPG Range Types ``` ┌─────────────────────────────────────────────────────────────────┐ -│ OSRS RANGE TYPES │ +│ classic MMORPG RANGE TYPES │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 1. HUNT RANGE (Aggro Detection) │ @@ -828,7 +828,7 @@ const NPC_SIZES: Record = { ``` ┌─────────────────────────────────────────────────────────────────┐ -│ OSRS MELEE RANGE RULES │ +│ classic MMORPG MELEE RANGE RULES │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ Range 1 (Standard Melee) - CARDINAL ONLY: │ @@ -953,7 +953,7 @@ const NPC_SIZES: Record = { │ │ │ │ ▼ │ │ ┌──────────────────┐ │ -│ │ Spawn Gravestone │ ──► AFTER respawn (RuneScape-style) │ +│ │ Spawn Gravestone │ ──► AFTER respawn (classic fantasy MMORPG-style) │ │ │ (Safe Areas) │ │ │ └──────────────────┘ │ │ │ @@ -1020,7 +1020,7 @@ class SafeAreaDeathHandler { } ``` -**OSRS-Accurate Timing:** +**Rules-Accurate Timing:** - Gravestone: 500 ticks (5 minutes) - Ground items: 200 ticks (2 minutes) after gravestone expires - Items protected from other players while in gravestone @@ -1116,7 +1116,7 @@ class DeathStateManager { ### 6.8 RespawnManager -The `RespawnManager.ts` (251 lines) manages mob respawn locations with OSRS-accurate tick-based timing. +The `RespawnManager.ts` (251 lines) manages mob respawn locations with rules-accurate tick-based timing. ```typescript class RespawnManager { @@ -1148,7 +1148,7 @@ interface RespawnConfig { } ``` -**OSRS-Accurate Features:** +**Rules-Accurate Features:** - Mobs spawn in an AREA, not a single point - Random location within configured radius - Tick-based timing (600ms per tick) @@ -1210,7 +1210,7 @@ class LootSystem extends SystemBase { } ``` -**OSRS-Style Behavior:** +**classic MMORPG-Style Behavior:** - Mob dies → Items drop directly to ground at tile center - Items pile on same tile, stackables merge - Click item directly to pick up (no loot window) @@ -1246,7 +1246,7 @@ interface LootDrop { ### 7.3 GroundItemSystem -The `GroundItemSystem.ts` (633 lines) manages OSRS-style ground items with tile-based piling. +The `GroundItemSystem.ts` (633 lines) manages classic MMORPG-style ground items with tile-based piling. ```typescript class GroundItemSystem extends SystemBase { @@ -1279,7 +1279,7 @@ class GroundItemSystem extends SystemBase { } ``` -**OSRS-Accurate Features:** +**Rules-Accurate Features:** - Items snap to tile centers - Stackable items merge in same pile - Only top item visible per pile (click to see pile menu) @@ -1353,7 +1353,7 @@ interface ScheduledAttack { ### 8.3 HitDelayCalculator -The `HitDelayCalculator.ts` (345 lines) calculates OSRS-accurate hit delays and manages projectile tracking. +The `HitDelayCalculator.ts` (345 lines) calculates rules-accurate hit delays and manages projectile tracking. ```typescript // Calculate hit delay for any attack type @@ -1415,7 +1415,7 @@ class CombatStateManager { private nextAttackTick = 0; private lastAttackerId: string | null = null; - // First-attack timing (OSRS-accurate) + // First-attack timing (rules-accurate) // When NPC first enters combat range, attack happens NEXT tick private _pendingFirstAttack = false; private _firstAttackTick = -1; @@ -1425,13 +1425,13 @@ class CombatStateManager { onEnterCombatRange(currentTick: number): void; canAttack(currentTick: number): boolean; performAttack(targetId: string, currentTick: number): boolean; - onReceiveAttack(currentTick: number): void; // OSRS retaliation timing + onReceiveAttack(currentTick: number): void; // classic MMORPG retaliation timing } ``` ### 8.5 HealthRegenSystem -The `HealthRegenSystem.ts` (230 lines) handles OSRS-style passive health regeneration. +The `HealthRegenSystem.ts` (230 lines) handles classic MMORPG-style passive health regeneration. ```typescript class HealthRegenSystem extends SystemBase { @@ -1452,7 +1452,7 @@ class HealthRegenSystem extends SystemBase { } ``` -**OSRS-Accurate Timing:** +**Rules-Accurate Timing:** - No regen while in combat - 17 tick cooldown (10.2s) after taking damage - 1 HP every 100 ticks (60 seconds) when eligible @@ -1464,7 +1464,7 @@ class HealthRegenSystem extends SystemBase { ### 9.1 DamageSplatSystem -The `DamageSplatSystem.ts` (238 lines) creates OSRS-style damage splats. +The `DamageSplatSystem.ts` (238 lines) creates classic MMORPG-style damage splats. ```typescript class DamageSplatSystem extends System { @@ -1485,7 +1485,7 @@ class DamageSplatSystem extends System { ### 9.2 XPDropSystem -The `XPDropSystem.ts` (226 lines) creates RS3-style XP drops. +The `XPDropSystem.ts` (226 lines) creates modern MMORPG-style XP drops. ```typescript class XPDropSystem extends System { @@ -1532,7 +1532,7 @@ class HealthBars extends SystemBase { } ``` -**OSRS-Style Features:** +**classic MMORPG-Style Features:** - Only visible during combat (hides after timeout) - Red/green bar with black border - Positioned above entity head @@ -1540,13 +1540,13 @@ class HealthBars extends SystemBase { --- -## 10. OSRS Combat Mechanics +## 10. classic MMORPG Combat Mechanics ### 10.1 Tick-Based Timing ``` ┌─────────────────────────────────────────────────────────────────┐ -│ OSRS TICK SYSTEM │ +│ classic MMORPG TICK SYSTEM │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 1 Tick = 600ms = 0.6 seconds │ @@ -1592,7 +1592,7 @@ class HealthBars extends SystemBase { │ ▼ │ │ ┌──────────────────┐ │ │ │ AFK > 20 min? │───► YES ──► No retaliation │ -│ │ (2000 ticks) │ (OSRS-accurate) │ +│ │ (2000 ticks) │ (rules-accurate) │ │ └────────┬─────────┘ │ │ │ NO │ │ ▼ │ @@ -1724,7 +1724,7 @@ class HealthBars extends SystemBase { ## 12. Damage Calculation -### 12.1 OSRS Accuracy Formula +### 12.1 classic MMORPG Accuracy Formula ``` ┌─────────────────────────────────────────────────────────────────┐ @@ -1758,7 +1758,7 @@ class HealthBars extends SystemBase { └─────────────────────────────────────────────────────────────────┘ ``` -### 12.2 OSRS Max Hit Formula +### 12.2 classic MMORPG Max Hit Formula ``` ┌─────────────────────────────────────────────────────────────────┐ @@ -1797,7 +1797,7 @@ class HealthBars extends SystemBase { The `CombatCalculations.ts` file (468 lines) provides the core calculation functions used throughout the combat system. ```typescript -// Combat Style Bonuses (OSRS-accurate) +// Combat Style Bonuses (rules-accurate) type CombatStyle = "accurate" | "aggressive" | "defensive" | "controlled"; function getStyleBonus(style: CombatStyle): StyleBonus { @@ -1958,7 +1958,7 @@ class CombatRequestValidator { │ Damage Validation (validateDamage): │ │ ──────────────────────────────────── │ │ • Calculates theoretical max hit for attacker stats │ -│ • Uses OSRS formula │ +│ • Uses classic combat formula │ │ • Adds 10% tolerance for special attacks │ │ • Flags CRITICAL violation if damage > limit │ │ │ @@ -2311,7 +2311,7 @@ function isEquipmentSystem(system: unknown): system is EquipmentSystemLike; ## Summary -This combat system represents a **production-ready, OSRS-accurate** implementation with: +This combat system represents a **production-ready, rules-accurate** implementation with: | Metric | Value | |--------|-------| @@ -2319,14 +2319,14 @@ This combat system represents a **production-ready, OSRS-accurate** implementati | **Number of Files** | 57 | | **Type Safety** | 100% (no `any`, runtime type guards) | | **Security Layers** | 3 (Network, Combat, Anti-Cheat) | -| **OSRS Accuracy** | Full (tick system, formulas, tolerance timer, PID shuffle) | +| **classic MMORPG Accuracy** | Full (tick system, formulas, tolerance timer, PID shuffle) | | **Memory Efficiency** | Object pooling, bounded collections | | **Replay Capability** | Full (EventStore + ReplayService + AuditLog) | | **Event Systems** | 3 (EventBus, EventStore, AuditLog) | ### Complete Feature List -- ✅ OSRS tick-based timing (600ms) +- ✅ classic MMORPG tick-based timing (600ms) - ✅ Authentic damage formulas - ✅ PID shuffle system for fair PvP - ✅ Tolerance timer (10-minute aggro immunity) @@ -2337,13 +2337,13 @@ This combat system represents a **production-ready, OSRS-accurate** implementati - ✅ Mob death with loot/respawn - ✅ Mob respawn with randomized spawn points - ✅ Loot table system with drop tiers -- ✅ Ground items with OSRS tile piling -- ✅ OSRS health regeneration (17-tick combat cooldown) +- ✅ Ground items with classic MMORPG tile piling +- ✅ classic MMORPG health regeneration (17-tick combat cooldown) - ✅ Animation-damage-hitsplat synchronization - ✅ Hit delay by attack type (melee/ranged/magic) -- ✅ OSRS-style damage splats (red/blue) +- ✅ classic MMORPG-style damage splats (red/blue) - ✅ XP drop notifications with skill icons -- ✅ Auto-retaliate with OSRS timing +- ✅ Auto-retaliate with classic MMORPG timing - ✅ AFK detection (20-minute threshold) - ✅ Entity ID validation (OWASP compliant) - ✅ Rate limiting (per-tick and per-second) diff --git a/packages/shared/src/constants/CombatConstants.ts b/packages/shared/src/constants/CombatConstants.ts index 8527d1aa2..76d6c2eac 100644 --- a/packages/shared/src/constants/CombatConstants.ts +++ b/packages/shared/src/constants/CombatConstants.ts @@ -1,21 +1,20 @@ /** * Combat Constants * - * OSRS-accurate timing and combat values. + * rules-accurate timing and combat values. * All tick-based values assume 600ms per tick. * - * @see https://oldschool.runescape.wiki/w/Game_tick */ import { WeaponType } from "../types/game/item-types"; /** * Melee attack style determines which per-style attack/defence bonuses are used. - * OSRS: Each weapon type has a default style (e.g., swords slash, daggers stab). + * classic MMORPG: Each weapon type has a default style (e.g., swords slash, daggers stab). */ export type MeleeAttackStyle = "stab" | "slash" | "crush"; -/** Default melee attack style per weapon type (OSRS-accurate) */ +/** Default melee attack style per weapon type (rules-accurate) */ export const WEAPON_DEFAULT_ATTACK_STYLE: Record = { [WeaponType.SWORD]: "slash", [WeaponType.LONGSWORD]: "slash", @@ -42,13 +41,13 @@ export const COMBAT_CONSTANTS = { // === Combat Timing (ticks) === DEFAULT_ATTACK_SPEED_TICKS: 4, - COMBAT_TIMEOUT_TICKS: 17, // OSRS-accurate: 10.2 seconds (17 ticks * 600ms) + COMBAT_TIMEOUT_TICKS: 17, // rules-accurate: 10.2 seconds (17 ticks * 600ms) LOGOUT_PREVENTION_TICKS: 16, HEALTH_REGEN_COOLDOWN_TICKS: 17, HEALTH_REGEN_INTERVAL_TICKS: 100, AFK_DISABLE_RETALIATE_TICKS: 2000, - // === Food Consumption (OSRS-accurate) === + // === Food Consumption (rules-accurate) === /** Ticks before player can eat again after eating (3 ticks = 1.8s) */ EAT_DELAY_TICKS: 3, /** Ticks added to attack cooldown when eating during combat */ @@ -100,15 +99,15 @@ export const COMBAT_CONSTANTS = { EMOTE_RANGED: "ranged", EMOTE_MAGIC: "magic", EMOTE_IDLE: "idle", - /** Duration (seconds) for GLB animation crossfades. RS3 uses 300-400ms; 350ms splits the range. */ + /** Duration (seconds) for GLB animation crossfades. modern MMORPG uses 300-400ms; 350ms splits the range. */ CROSSFADE_DURATION: 0.35, }, // === Death & Loot (ticks) === RESPAWN_TICKS_RANDOMNESS: 8, GRAVESTONE_TICKS: 1500, - GROUND_ITEM_DESPAWN_TICKS: 6000, // OSRS-accurate: 60 minutes (was 300 = 3 min) - UNTRADEABLE_DESPAWN_TICKS: 6000, // OSRS-accurate: 60 minutes (was 300 = 3 min) + GROUND_ITEM_DESPAWN_TICKS: 6000, // rules-accurate: 60 minutes (was 300 = 3 min) + UNTRADEABLE_DESPAWN_TICKS: 6000, // rules-accurate: 60 minutes (was 300 = 3 min) LOOT_PROTECTION_TICKS: 100, CORPSE_DESPAWN_TICKS: 200, @@ -147,7 +146,7 @@ export const COMBAT_CONSTANTS = { ATTACK_SPEED_TICKS: 4, AGGRO_RANGE: 4, COMBAT_RANGE: 1, - LEASH_RANGE: 42, // Extended from OSRS default of 7 for better gameplay + LEASH_RANGE: 42, // Extended from classic MMORPG default of 7 for better gameplay RESPAWN_TICKS: 25, WANDER_RADIUS: 5, }, @@ -203,7 +202,7 @@ export interface MagicStyleBonus { readonly xpSplit: "magic" | "magic_defence"; } -/** Pre-allocated frozen style bonuses for ranged combat (OSRS-accurate) */ +/** Pre-allocated frozen style bonuses for ranged combat (rules-accurate) */ export const RANGED_STYLE_BONUSES: Readonly< Record> > = Object.freeze({ diff --git a/packages/shared/src/constants/GameConstants.ts b/packages/shared/src/constants/GameConstants.ts index e272c63ab..b0d7a4578 100644 --- a/packages/shared/src/constants/GameConstants.ts +++ b/packages/shared/src/constants/GameConstants.ts @@ -32,7 +32,7 @@ export const PLAYER_CONSTANTS = { DEFAULT_MAX_STAMINA: 100, BASE_MOVEMENT_SPEED: 1.0, RUNNING_SPEED_MULTIPLIER: 1.5, - HEALTH_REGEN_RATE: 1, // 1 HP per regen tick (RuneScape-style) + HEALTH_REGEN_RATE: 1, // 1 HP per regen tick (classic fantasy MMORPG-style) // Note: Health regen cooldown/interval use COMBAT_CONSTANTS tick-based values STAMINA_REGEN_RATE: 2.0, STAMINA_DRAIN_RATE: 5.0, @@ -255,13 +255,13 @@ export const UI_CONSTANTS = { CHAT_MESSAGE_TIMEOUT: 5000, // 5 seconds } as const; -// === OSRS-STYLE CONTEXT MENU COLORS === +// === classic MMORPG-STYLE CONTEXT MENU COLORS === export const CONTEXT_MENU_COLORS = { - /** Item name color in context menus (OSRS orange) */ + /** Item name color in context menus (classic MMORPG orange) */ ITEM: "#ff9040", - /** NPC name color in context menus (OSRS yellow) */ + /** NPC name color in context menus (classic MMORPG yellow) */ NPC: "#ffff00", - /** Object name color in context menus (OSRS cyan) */ + /** Object name color in context menus (classic MMORPG cyan) */ OBJECT: "#00ffff", /** Player name color in context menus */ PLAYER: "#ffffff", diff --git a/packages/shared/src/constants/GatheringConstants.ts b/packages/shared/src/constants/GatheringConstants.ts index acc6e35d0..d55a4fba4 100644 --- a/packages/shared/src/constants/GatheringConstants.ts +++ b/packages/shared/src/constants/GatheringConstants.ts @@ -2,25 +2,19 @@ * Gathering Constants * * Centralized constants for the resource gathering system. - * OSRS-accurate timing and gathering values. + * rules-accurate timing and gathering values. * - * @see https://oldschool.runescape.wiki/w/Woodcutting - * @see https://oldschool.runescape.wiki/w/Mining - * @see https://oldschool.runescape.wiki/w/Fishing */ export const GATHERING_CONSTANTS = { - // === Skill-Specific Mechanics (OSRS-accurate) === + // === Skill-Specific Mechanics (rules-accurate) === /** - * Different gathering skills have fundamentally different mechanics in OSRS. + * Different gathering skills have fundamentally different mechanics in classic MMORPG. * * WOODCUTTING: Fixed roll frequency (4 ticks), tool tier affects SUCCESS RATE * MINING: Variable roll frequency (tool-dependent), tool does NOT affect success rate * FISHING: Fixed roll frequency (5 ticks), equipment doesn't affect anything * - * @see https://oldschool.runescape.wiki/w/Woodcutting - * @see https://oldschool.runescape.wiki/w/Mining - * @see https://x.com/JagexAsh/status/1215007439692730370 */ SKILL_MECHANICS: { woodcutting: { @@ -57,10 +51,9 @@ export const GATHERING_CONSTANTS = { * Gathering interaction range in tiles. * Uses cardinal-only adjacent tiles (N/S/E/W) like standard melee combat. * - * OSRS: Players must stand on a cardinal adjacent tile to gather resources. + * classic MMORPG: Players must stand on a cardinal adjacent tile to gather resources. * This is equivalent to COMBAT_CONSTANTS.MELEE_RANGE_STANDARD. * - * @see https://oldschool.runescape.wiki/w/Pathfinding */ GATHERING_RANGE: 1, @@ -69,7 +62,7 @@ export const GATHERING_CONSTANTS = { PROXIMITY_SEARCH_RADIUS: 15, /** Default interaction range for gathering (world units, legacy) */ DEFAULT_INTERACTION_RANGE: 4.0, - /** Floating point tolerance for position comparison (OSRS: any movement cancels) */ + /** Floating point tolerance for position comparison (classic MMORPG: any movement cancels) */ POSITION_EPSILON: 0.01, // === Timing (ticks/ms) === @@ -82,20 +75,19 @@ export const GATHERING_CONSTANTS = { /** Rate limit cleanup interval (60 seconds) */ RATE_LIMIT_CLEANUP_INTERVAL_MS: 60000, - // === OSRS Success Rate Formula (LERP Interpolation) === + // === classic MMORPG Success Rate Formula (LERP Interpolation) === /** - * OSRS uses linear interpolation between low (level 1) and high (level 99) values. + * classic MMORPG uses linear interpolation between low (level 1) and high (level 99) values. * * Formula: P(Level) = (1 + floor(low × (99 - L) / 98 + high × (L - 1) / 98 + 0.5)) / 256 * - * @see https://oldschool.runescape.wiki/w/Skilling_success_rate */ /** * Woodcutting success rates by tree type and axe tier. * Values are x/256 (success numerator). * - * OSRS: Axe tier significantly affects success rate. + * classic MMORPG: Axe tier significantly affects success rate. * - Bronze axe at level 1 on regular tree: ~25% (64/256) * - Bronze axe at level 99 on regular tree: ~78% (200/256) * - Iron axe reaches 100% at level 78 on regular trees @@ -103,7 +95,6 @@ export const GATHERING_CONSTANTS = { * * Higher tier trees (oak, willow) have lower success rates. * - * @see https://oldschool.runescape.wiki/w/Tree */ WOODCUTTING_SUCCESS_RATES: { // Regular tree (level 1) - easiest @@ -142,15 +133,15 @@ export const GATHERING_CONSTANTS = { } as const, /** - * Mining success rates by ore type (OSRS-accurate). + * Mining success rates by ore type (rules-accurate). * Values are x/256 (success numerator) for the LERP formula. * - * OSRS: Pickaxe tier does NOT affect success rate, only roll frequency. + * classic MMORPG: Pickaxe tier does NOT affect success rate, only roll frequency. * Success rate depends only on Mining level. * * Formula: P(Level) = (1 + floor(low × (99 - L) / 98 + high × (L - 1) / 98 + 0.5)) / 256 * - * OSRS Wiki Data: + * Reference gathering data: * - Copper/Tin: ~39.5% at L1, 100% at L62 * - Iron: ~52% at L15, 100% at L63 * - Coal: ~16.4% at L30, ~39.5% at L99 @@ -158,8 +149,6 @@ export const GATHERING_CONSTANTS = { * - Adamantite: ~7.4% at L70, ~10.2% at L99 * - Runite: 17/256 (~6.64%) at L85, 19/256 (~7.42%) at L97+ (confirmed by Mod Ash) * - * @see https://oldschool.runescape.wiki/w/Mining - * @see https://oldschool.runescape.wiki/w/Skilling_success_rate */ MINING_SUCCESS_RATES: { // Copper ore (level 1) - 39.5% at L1, 100% at L62 @@ -183,10 +172,9 @@ export const GATHERING_CONSTANTS = { * Fishing success rates by spot type. * Values are x/256 (success numerator). * - * OSRS: Equipment does NOT affect success rate. + * classic MMORPG: Equipment does NOT affect success rate. * Success rate depends only on Fishing level. * - * @see https://oldschool.runescape.wiki/w/Fishing */ FISHING_SUCCESS_RATES: { // Net fishing - Shrimp/Anchovies (level 1+) @@ -213,12 +201,10 @@ export const GATHERING_CONSTANTS = { // === Tree Despawn Times (ticks) - Forestry System === /** - * OSRS Forestry-style tree depletion timer. + * classic MMORPG Forestry-style tree depletion timer. * Timer starts on FIRST LOG, counts down while chopping, regenerates when idle. * Tree only depletes when timer=0 AND player receives a log. * - * @see https://oldschool.runescape.wiki/w/Forestry - * @see https://github.com/runelite/runelite/discussions/16894 */ TREE_DESPAWN_TICKS: { tree: 0, // Regular trees use 1/8 chance, not timer @@ -235,7 +221,6 @@ export const GATHERING_CONSTANTS = { /** * Time for depleted trees to respawn. * - * @see https://oldschool.runescape.wiki/w/Tree */ TREE_RESPAWN_TICKS: { tree: 10, // ~6 seconds @@ -251,17 +236,16 @@ export const GATHERING_CONSTANTS = { // === Timer Regeneration === /** * Rate at which tree timers regenerate when no one is gathering. - * OSRS: 1 tick of regeneration per 1 tick of not being gathered. + * classic MMORPG: 1 tick of regeneration per 1 tick of not being gathered. */ TIMER_REGEN_PER_TICK: 1, - // === Fishing Spot Movement (OSRS-accurate) === + // === Fishing Spot Movement (rules-accurate) === /** * Fishing spots don't deplete - they periodically move to a nearby tile. - * In OSRS, spots move randomly every ~4-12 minutes. + * In classic MMORPG, spots move randomly every ~4-12 minutes. * Using 300 ticks (3 minutes) as base with ±100 tick variance for gameplay. * - * @see https://oldschool.runescape.wiki/w/Fishing */ FISHING_SPOT_MOVE: { /** Base ticks before spot moves (300 ticks = 3 minutes) */ diff --git a/packages/shared/src/constants/ProcessingConstants.ts b/packages/shared/src/constants/ProcessingConstants.ts index 1d81254f0..0acf25f14 100644 --- a/packages/shared/src/constants/ProcessingConstants.ts +++ b/packages/shared/src/constants/ProcessingConstants.ts @@ -2,7 +2,7 @@ * Processing Constants * * Centralized constants for firemaking and cooking systems. - * OSRS-accurate timing and mechanics. + * rules-accurate timing and mechanics. * * NOTE: Item-specific data (XP values, level requirements, burn levels) * is now defined in the item manifest (items.json) and accessed via @@ -10,12 +10,10 @@ * * @see packages/server/world/assets/manifests/items.json for item data * @see packages/shared/src/data/ProcessingDataProvider.ts for runtime access - * @see https://oldschool.runescape.wiki/w/Firemaking - * @see https://oldschool.runescape.wiki/w/Cooking */ export const PROCESSING_CONSTANTS = { - // === Skill-Specific Mechanics (OSRS-accurate) === + // === Skill-Specific Mechanics (rules-accurate) === /** * FIREMAKING: Fixed 4-tick attempts, level affects success rate * COOKING: Fixed 4-tick per item, level affects burn rate @@ -40,12 +38,11 @@ export const PROCESSING_CONSTANTS = { }, } as const, - // === Firemaking Success Rates (OSRS formula) === + // === Firemaking Success Rates (classic combat formula) === /** - * OSRS Firemaking: 65/256 at level 1, 513/256 at level 99 + * classic MMORPG Firemaking: 65/256 at level 1, 513/256 at level 99 * 100% success reached at level 43 * - * @see https://oldschool.runescape.wiki/w/Firemaking */ FIREMAKING_SUCCESS_RATE: { low: 65, // Numerator at level 1 (65/256 = 25.4%) @@ -54,9 +51,9 @@ export const PROCESSING_CONSTANTS = { // === Fire Properties === FIRE: { - /** Minimum fire duration in ticks (60 seconds) - OSRS per Mod Ash */ + /** Minimum fire duration in ticks (60 seconds) - classic MMORPG per Mod Ash */ minDurationTicks: 100, - /** Maximum fire duration in ticks (119 seconds) - OSRS per Mod Ash */ + /** Maximum fire duration in ticks (119 seconds) - classic MMORPG per Mod Ash */ maxDurationTicks: 198, /** Maximum fires per player */ maxFiresPerPlayer: 3, @@ -66,7 +63,7 @@ export const PROCESSING_CONSTANTS = { interactionRange: 1, }, - // === Walk-West Movement Priority (OSRS) === + // === Walk-West Movement Priority (classic MMORPG) === /** * After lighting fire, player walks in this priority order: * 1. West (preferred) diff --git a/packages/shared/src/constants/SmithingConstants.ts b/packages/shared/src/constants/SmithingConstants.ts index f59328252..c42863175 100644 --- a/packages/shared/src/constants/SmithingConstants.ts +++ b/packages/shared/src/constants/SmithingConstants.ts @@ -4,7 +4,6 @@ * This file contains all hardcoded values used across the smithing feature, * making it easier to maintain consistency and adjust values. * - * @see https://oldschool.runescape.wiki/w/Game_tick for tick timing */ import { COMBAT_CONSTANTS } from "./CombatConstants"; @@ -15,7 +14,7 @@ export const SMITHING_CONSTANTS = { COAL_ITEM_ID: "coal", // Tick-based timing defaults (used when manifest doesn't specify) - // OSRS: smelting and smithing both take 4 ticks + // classic MMORPG: smelting and smithing both take 4 ticks DEFAULT_SMELTING_TICKS: 4, DEFAULT_SMITHING_TICKS: 4, @@ -139,7 +138,7 @@ export function getItemQuantity(item: LooseInventoryItem): number { /** * Convert ticks to milliseconds for setTimeout scheduling - * @param ticks - Number of game ticks (1 tick = 600ms in OSRS) + * @param ticks - Number of game ticks (1 tick = 600ms in classic MMORPG) */ export function ticksToMs(ticks: number): number { return ticks * SMITHING_CONSTANTS.TICK_DURATION_MS; diff --git a/packages/shared/src/constants/WeaponStyleConfig.ts b/packages/shared/src/constants/WeaponStyleConfig.ts index aaed23024..4116b6c9e 100644 --- a/packages/shared/src/constants/WeaponStyleConfig.ts +++ b/packages/shared/src/constants/WeaponStyleConfig.ts @@ -1,10 +1,9 @@ /** - * WeaponStyleConfig - OSRS-accurate combat style availability per weapon type + * WeaponStyleConfig - rules-accurate combat style availability per weapon type * - * In OSRS, different weapon types have different available combat styles. + * In classic MMORPG, different weapon types have different available combat styles. * This configuration maps weapon types to their allowed combat styles. * - * @see https://oldschool.runescape.wiki/w/Combat_Options */ import { WeaponType } from "../types/game/item-types"; @@ -12,7 +11,7 @@ import type { CombatStyleExtended } from "../types/game/combat-types"; /** * Combat styles available for each weapon type. - * OSRS-accurate: Not all weapons have all 4 styles. + * rules-accurate: Not all weapons have all 4 styles. */ export const WEAPON_STYLE_CONFIG: Record = { // Swords - full style selection (slash/stab versatility) @@ -41,7 +40,7 @@ export const WEAPON_STYLE_CONFIG: Record = { // Halberds - full style selection (2H reach weapon) [WeaponType.HALBERD]: ["accurate", "aggressive", "defensive", "controlled"], - // Axes - no controlled (pure damage weapons in OSRS) + // Axes - no controlled (pure damage weapons in classic MMORPG) [WeaponType.AXE]: ["accurate", "aggressive", "defensive"], // Daggers - no controlled (quick stabbing weapons) @@ -50,18 +49,17 @@ export const WEAPON_STYLE_CONFIG: Record = { // Unarmed - no controlled (punching) [WeaponType.NONE]: ["accurate", "aggressive", "defensive"], - // Ranged weapons - OSRS-accurate styles + // Ranged weapons - rules-accurate styles // Accurate: +3 ranged level, normal speed // Rapid: no bonus, -1 tick faster attack // Longrange: +2 attack range, XP split to ranged/defence [WeaponType.BOW]: ["accurate", "rapid", "longrange"], [WeaponType.CROSSBOW]: ["accurate", "rapid", "longrange"], - // Magic weapons - OSRS-accurate styles + // Magic weapons - rules-accurate styles // Staves/wands have both melee and magic styles: // Melee (crush): Bash=accurate, Pound=aggressive, Focus=defensive // Magic: Spell=autocast (defensive autocast is a toggle, not a separate style) - // @see https://oldschool.runescape.wiki/w/Staff [WeaponType.STAFF]: ["accurate", "aggressive", "defensive", "autocast"], [WeaponType.WAND]: ["accurate", "aggressive", "defensive", "autocast"], diff --git a/packages/shared/src/constants/__tests__/WeaponStyleConfig.test.ts b/packages/shared/src/constants/__tests__/WeaponStyleConfig.test.ts index 5d7f844a9..339114f16 100644 --- a/packages/shared/src/constants/__tests__/WeaponStyleConfig.test.ts +++ b/packages/shared/src/constants/__tests__/WeaponStyleConfig.test.ts @@ -1,12 +1,11 @@ /** * WeaponStyleConfig Unit Tests * - * Tests for OSRS-accurate weapon-to-combat-style mapping: + * Tests for rules-accurate weapon-to-combat-style mapping: * - getAvailableStyles: Returns valid styles per weapon type * - isStyleValidForWeapon: Validates style availability * - getDefaultStyleForWeapon: Returns correct default style * - * @see https://oldschool.runescape.wiki/w/Combat_Options */ import { describe, it, expect } from "vitest"; @@ -58,8 +57,8 @@ describe("WeaponStyleConfig", () => { expect(styles).not.toContain("controlled"); }); - it("returns OSRS-accurate styles for ranged weapons", () => { - // Bows and crossbows have accurate, rapid, and longrange in OSRS + it("returns rules-accurate styles for ranged weapons", () => { + // Bows and crossbows have accurate, rapid, and longrange in classic MMORPG expect(getAvailableStyles(WeaponType.BOW)).toEqual([ "accurate", "rapid", @@ -72,9 +71,8 @@ describe("WeaponStyleConfig", () => { ]); }); - it("returns OSRS-accurate styles for magic weapons", () => { - // Staves and wands have melee bash styles PLUS autocast in OSRS - // @see https://oldschool.runescape.wiki/w/Staff (Bash=accurate, Pound=aggressive, Focus=defensive) + it("returns rules-accurate styles for magic weapons", () => { + // Staves and wands have melee bash styles PLUS autocast in classic MMORPG expect(getAvailableStyles(WeaponType.STAFF)).toEqual([ "accurate", "aggressive", diff --git a/packages/shared/src/constants/interaction.ts b/packages/shared/src/constants/interaction.ts index 64da09a92..ff16dd27d 100644 --- a/packages/shared/src/constants/interaction.ts +++ b/packages/shared/src/constants/interaction.ts @@ -20,14 +20,14 @@ export const SessionType = { export type SessionType = (typeof SessionType)[keyof typeof SessionType]; // ============================================================================ -// DISTANCE CONFIGURATION (OSRS-style Chebyshev) +// DISTANCE CONFIGURATION (classic MMORPG-style Chebyshev) // ============================================================================ /** * Maximum interaction distances per session type. - * Uses Chebyshev distance (max of |dx|, |dz|) - OSRS standard. + * Uses Chebyshev distance (max of |dx|, |dz|) - classic MMORPG standard. * - * OSRS uses ~1-2 tiles to open, closes at ~2-3 tiles away. + * classic MMORPG uses ~1-2 tiles to open, closes at ~2-3 tiles away. * We use 2 tiles for stores/banks (authentic) and 2 for dialogue. */ export const INTERACTION_DISTANCE: Readonly> = { diff --git a/packages/shared/src/core/World.ts b/packages/shared/src/core/World.ts index bc38aff3e..7fcbba936 100644 --- a/packages/shared/src/core/World.ts +++ b/packages/shared/src/core/World.ts @@ -221,7 +221,7 @@ export class World extends EventEmitter { accumulator = 0; /** - * Current server tick number (OSRS-style 600ms ticks). + * Current server tick number (classic MMORPG-style 600ms ticks). * Set by TickSystem on the server, used by mobs/NPCs for tick-aligned AI. * On client, this is 0 (client uses frame-based updates). * @@ -594,7 +594,7 @@ export class World extends EventEmitter { /** * Unified collision matrix for tile-based collision. - * Stores OSRS-accurate bitmask flags per tile in zone-based chunks. + * Stores rules-accurate bitmask flags per tile in zone-based chunks. * * Key features: * - Static objects (trees, rocks, furnaces) set BLOCKED flag @@ -618,7 +618,6 @@ export class World extends EventEmitter { * - Delegates blocking checks to CollisionMatrix * * @see NPC_ENTITY_COLLISION_PLAN.md - * @see https://osrs-docs.com/docs/mechanics/entity-collision/ */ entityOccupancy: IEntityOccupancy = new EntityOccupancyMap(); diff --git a/packages/shared/src/data/DataManager.ts b/packages/shared/src/data/DataManager.ts index 35f113e1a..b4eb12361 100644 --- a/packages/shared/src/data/DataManager.ts +++ b/packages/shared/src/data/DataManager.ts @@ -204,7 +204,7 @@ import type { * Gathering Tool Data - derived from items.json where item.tool is defined * Defines tool properties for gathering skills (woodcutting, mining, fishing) * - * OSRS Mechanics: + * classic MMORPG Mechanics: * - Woodcutting: tier used for success rate lookup, roll frequency is fixed (4 ticks) * - Mining: rollTicks defines time between attempts, success is level-only * - Fishing: equipment doesn't affect speed or success @@ -218,16 +218,16 @@ export interface GatheringToolData { tier: string; /** Skill level required to use this tool (derived from tier or explicit) */ levelRequired: number; - /** For mining: ticks between roll attempts (OSRS-accurate) */ + /** For mining: ticks between roll attempts (rules-accurate) */ rollTicks?: number; /** * For mining (dragon/crystal pickaxe): Chance for bonus speed roll. - * OSRS: Dragon has 1/6 (0.167), Crystal has 1/4 (0.25) chance for 2-tick roll. + * classic MMORPG: Dragon has 1/6 (0.167), Crystal has 1/4 (0.25) chance for 2-tick roll. */ bonusTickChance?: number; /** * For mining (dragon/crystal pickaxe): Tick count when bonus triggers. - * OSRS: Both use 2 ticks when bonus triggers (vs normal 3). + * classic MMORPG: Both use 2 ticks when bonus triggers (vs normal 3). */ bonusRollTicks?: number; /** Priority for best tool selection (lower = better, 1 = best) */ @@ -283,11 +283,11 @@ export interface ExternalResourceData { chance: number; xpAmount: number; stackable: boolean; - /** Level required to catch this specific fish (OSRS-accurate) */ + /** Level required to catch this specific fish (rules-accurate) */ levelRequired?: number; - /** OSRS catch rate at level 1 (x/256) - for priority rolling */ + /** classic MMORPG catch rate at level 1 (x/256) - for priority rolling */ catchLow?: number; - /** OSRS catch rate at level 99 (x/256) - for priority rolling */ + /** classic MMORPG catch rate at level 99 (x/256) - for priority rolling */ catchHigh?: number; }>; } @@ -1744,7 +1744,7 @@ export class DataManager { levelRange, stats: { level: npc.stats?.level ?? 1, - health: npc.stats?.health ?? 10, // OSRS: hitpoints = max HP directly + health: npc.stats?.health ?? 10, // classic MMORPG: hitpoints = max HP directly attack: npc.stats?.attack ?? 1, strength: npc.stats?.strength ?? 1, defense: npc.stats?.defense ?? 1, diff --git a/packages/shared/src/data/NoteGenerator.ts b/packages/shared/src/data/NoteGenerator.ts index eeb25b366..3f8f4a20d 100644 --- a/packages/shared/src/data/NoteGenerator.ts +++ b/packages/shared/src/data/NoteGenerator.ts @@ -5,7 +5,7 @@ * This avoids manual duplication in item manifests - any tradeable, * non-stackable item automatically gets a noted version. * - * OSRS Note Rules: + * classic MMORPG Note Rules: * - Only tradeable, non-stackable items can be noted * - Already stackable items (arrows, runes, coins) cannot be noted * - Untradeable/quest items cannot be noted @@ -27,7 +27,7 @@ export const NOTE_SUFFIX = "_noted"; /** * Determine if an item should have a noted variant generated. * - * OSRS Rules: + * classic MMORPG Rules: * - Must be tradeable (default true for most items) * - Must NOT already be stackable (stackable items don't need notes) * - Must NOT be currency type (coins are inherently stackable) @@ -63,7 +63,7 @@ export function shouldGenerateNote(item: Item): boolean { return false; } - // Untradeable items cannot be noted (OSRS rule) + // Untradeable items cannot be noted (classic MMORPG rule) // Default to tradeable if not specified const isTradeable = item.tradeable !== false; if (!isTradeable) { diff --git a/packages/shared/src/data/ProcessingDataProvider.ts b/packages/shared/src/data/ProcessingDataProvider.ts index 7a284e143..140616528 100644 --- a/packages/shared/src/data/ProcessingDataProvider.ts +++ b/packages/shared/src/data/ProcessingDataProvider.ts @@ -2220,7 +2220,7 @@ export class ProcessingDataProvider { * Calculate the multi-rune multiplier for a given rune type and level. * Returns how many runes are produced per essence at the given level. * - * In OSRS, each threshold in multiRuneLevels grants +1 rune per essence. + * In classic MMORPG, each threshold in multiRuneLevels grants +1 rune per essence. * e.g., air rune thresholds [11, 22, 33, ...]: at level 22, you get 3 runes per essence. */ public getRunecraftingMultiplier(runeType: string, level: number): number { diff --git a/packages/shared/src/data/TierDataProvider.ts b/packages/shared/src/data/TierDataProvider.ts index 6f9417c74..4c0fe259a 100644 --- a/packages/shared/src/data/TierDataProvider.ts +++ b/packages/shared/src/data/TierDataProvider.ts @@ -1,7 +1,7 @@ /** * Tier Data Provider * - * Provides OSRS-accurate tier-based level requirements for equipment and tools. + * Provides rules-accurate tier-based level requirements for equipment and tools. * Single source of truth - loaded from tier-requirements.json manifest. * * Usage: diff --git a/packages/shared/src/data/__tests__/NoteGenerator.test.ts b/packages/shared/src/data/__tests__/NoteGenerator.test.ts index d01553efb..75b6f3b63 100644 --- a/packages/shared/src/data/__tests__/NoteGenerator.test.ts +++ b/packages/shared/src/data/__tests__/NoteGenerator.test.ts @@ -7,7 +7,7 @@ * - generateAllNotedItems: Batch generation with cross-linking * - Helper functions: isNotedItemId, getBaseItemId, getNotedItemId * - * OSRS Rules enforced: + * classic MMORPG Rules enforced: * - Only tradeable, non-stackable items can be noted * - Stackable items (arrows, runes, coins) cannot be noted * - Untradeable/quest items cannot be noted diff --git a/packages/shared/src/data/__tests__/skill-unlocks.test.ts b/packages/shared/src/data/__tests__/skill-unlocks.test.ts index cc1136666..4a5a58211 100644 --- a/packages/shared/src/data/__tests__/skill-unlocks.test.ts +++ b/packages/shared/src/data/__tests__/skill-unlocks.test.ts @@ -5,7 +5,7 @@ * and skill unlocks data integrity. * * All skill unlocks are loaded from skill-unlocks.json manifest. - * Single source of truth - OSRS accurate data. + * Single source of truth - rules-accurate data. */ import { describe, it, expect, beforeAll } from "vitest"; @@ -412,15 +412,15 @@ describe("Skill data integrity", () => { }); // ============================================================================ -// OSRS-Accurate Skill Unlock Verification +// Rules-Accurate Skill Unlock Verification // ============================================================================ -describe("OSRS-accurate skill unlock values", () => { - it("attack weapon tiers are OSRS accurate", () => { +describe("rules-accurate skill unlock values", () => { + it("attack weapon tiers are rules-accurate", () => { const allUnlocks = getAllSkillUnlocks(); const attack = allUnlocks.attack; - // Verify key OSRS attack milestones + // Verify key classic MMORPG attack milestones expect(attack.find((u) => u.level === 1)?.description).toContain("Bronze"); expect(attack.find((u) => u.level === 5)?.description).toContain("Steel"); expect(attack.find((u) => u.level === 20)?.description).toContain( @@ -433,7 +433,7 @@ describe("OSRS-accurate skill unlock values", () => { expect(attack.find((u) => u.level === 60)?.description).toContain("Dragon"); }); - it("defense armor tiers are OSRS accurate", () => { + it("defense armor tiers are rules-accurate", () => { const allUnlocks = getAllSkillUnlocks(); const defense = allUnlocks.defense; @@ -464,7 +464,7 @@ describe("OSRS-accurate skill unlock values", () => { expect(prayer.find((u) => u.level === 70)?.description).toContain("Piety"); }); - it("woodcutting tree types are OSRS accurate", () => { + it("woodcutting tree types are rules-accurate", () => { const allUnlocks = getAllSkillUnlocks(); const woodcutting = allUnlocks.woodcutting; @@ -491,7 +491,7 @@ describe("OSRS-accurate skill unlock values", () => { ); }); - it("mining ore types are OSRS accurate", () => { + it("mining ore types are rules-accurate", () => { const allUnlocks = getAllSkillUnlocks(); const mining = allUnlocks.mining; @@ -505,7 +505,7 @@ describe("OSRS-accurate skill unlock values", () => { expect(mining.find((u) => u.level === 85)?.description).toBe("Runite ore"); }); - it("fishing levels are OSRS accurate", () => { + it("fishing levels are rules-accurate", () => { const allUnlocks = getAllSkillUnlocks(); const fishing = allUnlocks.fishing; @@ -516,7 +516,7 @@ describe("OSRS-accurate skill unlock values", () => { expect(fishing.find((u) => u.level === 76)?.description).toBe("Shark"); }); - it("cooking levels are OSRS accurate", () => { + it("cooking levels are rules-accurate", () => { const allUnlocks = getAllSkillUnlocks(); const cooking = allUnlocks.cooking; @@ -551,7 +551,7 @@ describe("OSRS-accurate skill unlock values", () => { ); }); - it("smithing bar levels are OSRS accurate", () => { + it("smithing bar levels are rules-accurate", () => { const allUnlocks = getAllSkillUnlocks(); const smithing = allUnlocks.smithing; diff --git a/packages/shared/src/data/ammunition.ts b/packages/shared/src/data/ammunition.ts index c6086a39a..2bca14727 100644 --- a/packages/shared/src/data/ammunition.ts +++ b/packages/shared/src/data/ammunition.ts @@ -1,7 +1,6 @@ /** * Ammunition Manifest * Defines bow tiers and arrow data for ranged combat. - * @see https://oldschool.runescape.wiki/w/Ammunition */ export interface ArrowData { diff --git a/packages/shared/src/data/combat-spells.ts b/packages/shared/src/data/combat-spells.ts index 4e6c70c7b..0c220d7d9 100644 --- a/packages/shared/src/data/combat-spells.ts +++ b/packages/shared/src/data/combat-spells.ts @@ -1,7 +1,6 @@ /** * Combat Spells Manifest * Defines all F2P combat spells (Strike and Bolt tiers). - * @see https://oldschool.runescape.wiki/w/Spells */ import type { RuneRequirement } from "../systems/shared/combat/RuneService"; diff --git a/packages/shared/src/data/npc-sizes.ts b/packages/shared/src/data/npc-sizes.ts index 6c4211068..11628304b 100644 --- a/packages/shared/src/data/npc-sizes.ts +++ b/packages/shared/src/data/npc-sizes.ts @@ -2,7 +2,6 @@ * NPC Size Manifest * Defines collision sizes for NPCs used in range calculations. * Most NPCs are 1x1 tiles. Bosses occupy larger footprints. - * @see https://oldschool.runescape.wiki/w/Non-player_character */ export interface NPCSize { diff --git a/packages/shared/src/data/npcs.ts b/packages/shared/src/data/npcs.ts index 5ccd0ec9b..4d15663bd 100644 --- a/packages/shared/src/data/npcs.ts +++ b/packages/shared/src/data/npcs.ts @@ -153,7 +153,7 @@ export function calculateNPCDrops( } /** - * Calculate NPC combat level using OSRS-accurate formula (delegates to CombatLevelCalculator) + * Calculate NPC combat level using rules-accurate formula (delegates to CombatLevelCalculator) */ export function calculateNPCCombatLevel(npc: NPCData): number { return calculateCombatLevel( diff --git a/packages/shared/src/data/runes.ts b/packages/shared/src/data/runes.ts index 2693e4c2e..1f4b2de4a 100644 --- a/packages/shared/src/data/runes.ts +++ b/packages/shared/src/data/runes.ts @@ -1,7 +1,6 @@ /** * Rune Data Manifest * Defines elemental staff mappings and rune metadata for magic combat. - * @see https://oldschool.runescape.wiki/w/Rune */ /** diff --git a/packages/shared/src/data/skill-icons.ts b/packages/shared/src/data/skill-icons.ts index 6b72a0f94..451542c36 100644 --- a/packages/shared/src/data/skill-icons.ts +++ b/packages/shared/src/data/skill-icons.ts @@ -1,5 +1,5 @@ /** - * Skill Data - Definitions and metadata for OSRS-style skills + * Skill Data - Definitions and metadata for classic MMORPG-style skills * * Shared constant used by: * - XPProgressOrb (HUD orbs) @@ -36,8 +36,8 @@ export interface SkillDefinition { } /** - * All skill definitions in OSRS-style display order. - * Arranged in 3-column grid matching RuneScape layout: + * All skill definitions in classic MMORPG-style display order. + * Arranged in 3-column grid matching classic fantasy MMORPG layout: * Column 1: Combat (Attack, Strength, Defence, Ranged, Magic, Prayer) * Column 2: Support (Constitution, Agility) * Column 3: Gathering/Production (Mining, Smithing, Fishing, Cooking, Firemaking, Woodcutting) @@ -203,7 +203,7 @@ export const SKILL_ICONS: Readonly> = { defence: "🛡️", defense: "🛡️", // US spelling alias constitution: "❤️", - hitpoints: "❤️", // OSRS alias + hitpoints: "❤️", // classic MMORPG alias ranged: "🏹", prayer: "✨", magic: "🔮", diff --git a/packages/shared/src/data/skill-unlocks.ts b/packages/shared/src/data/skill-unlocks.ts index b6caa5f9d..a25106488 100644 --- a/packages/shared/src/data/skill-unlocks.ts +++ b/packages/shared/src/data/skill-unlocks.ts @@ -1,5 +1,5 @@ /** - * Skill Unlocks Data - OSRS-style content unlocks per skill level + * Skill Unlocks Data - classic MMORPG-style content unlocks per skill level * * Defines what content is unlocked at each level for display in * the level-up notification popup. @@ -63,7 +63,7 @@ export function loadSkillUnlocks(manifest: SkillUnlocksManifest): void { } // Normalize British/American spelling: "defence" -> "defense" - // JSON uses OSRS-accurate British spelling, but UI uses American spelling + // JSON uses rules-accurate British spelling, but UI uses American spelling // Replace the British spelling entirely to keep skill count at 12 if (loadedUnlocks["defence"] && !loadedUnlocks["defense"]) { loadedUnlocks["defense"] = loadedUnlocks["defence"]; diff --git a/packages/shared/src/data/smithing-recipes.ts b/packages/shared/src/data/smithing-recipes.ts index 9ee1ed58e..994f6d3bd 100644 --- a/packages/shared/src/data/smithing-recipes.ts +++ b/packages/shared/src/data/smithing-recipes.ts @@ -4,7 +4,6 @@ * All smithing data (levels, XP, bars required) is manifest-driven: * @see packages/server/world/assets/manifests/items.json for recipe data * @see ProcessingDataProvider for runtime accessors - * @see https://oldschool.runescape.wiki/w/Smithing for OSRS reference */ /** diff --git a/packages/shared/src/entities/Entity.ts b/packages/shared/src/entities/Entity.ts index 61b839176..03d3f91e0 100644 --- a/packages/shared/src/entities/Entity.ts +++ b/packages/shared/src/entities/Entity.ts @@ -303,7 +303,7 @@ export class Entity implements IEntity { protected level: number = 1; // UI elements - Atlas-based (HealthBars system uses instanced mesh) - // Names shown in right-click context menu only (OSRS pattern) + // Names shown in right-click context menu only (classic MMORPG pattern) private _entityHealthBarHandle: HealthBarHandle | null = null; // Pre-allocated matrix for health bar position updates @@ -960,7 +960,7 @@ export class Entity implements IEntity { /** * Initialize visual elements (mesh, health bar) - from BaseEntity - * Names shown in right-click context menu only (OSRS pattern) + * Names shown in right-click context menu only (classic MMORPG pattern) */ protected initializeVisuals(): void { // Create main mesh - implemented by subclasses @@ -1000,7 +1000,7 @@ export class Entity implements IEntity { this.health, this.maxHealth, ); - // Health bar starts hidden (RuneScape pattern: show during combat) + // Health bar starts hidden (classic fantasy MMORPG pattern: show during combat) // Position update happens in clientUpdate() via handle.move() return; } diff --git a/packages/shared/src/entities/InteractableEntity.ts b/packages/shared/src/entities/InteractableEntity.ts index 0e44967df..afbb77772 100644 --- a/packages/shared/src/entities/InteractableEntity.ts +++ b/packages/shared/src/entities/InteractableEntity.ts @@ -161,7 +161,7 @@ export abstract class InteractableEntity extends Entity { * Override in subclasses (e.g., station entities) to return multi-tile footprints. * Default: single tile at entity position. * - * OSRS-style: Interaction is allowed if player is within `interactionRange` + * classic MMORPG-style: Interaction is allowed if player is within `interactionRange` * tiles of ANY occupied tile, using Chebyshev distance (diagonals count as 1). */ protected getOccupiedTiles(): TileCoord[] { @@ -171,7 +171,7 @@ export abstract class InteractableEntity extends Entity { /** * Calculate tile distance (Chebyshev distance) between two tiles. - * Diagonal movement counts as 1 step, matching OSRS mechanics. + * Diagonal movement counts as 1 step, matching classic tick-based mechanics. */ private getTileDistance(t1: TileCoord, t2: TileCoord): number { return Math.max(Math.abs(t1.x - t2.x), Math.abs(t1.z - t2.z)); @@ -219,7 +219,7 @@ export abstract class InteractableEntity extends Entity { return false; } - // Check distance using OSRS-style tile distance (Chebyshev) + // Check distance using classic MMORPG-style tile distance (Chebyshev) // Player must be within interactionRange tiles of ANY occupied tile const tileDistance = this.calculateTileDistance(playerPosition); diff --git a/packages/shared/src/entities/managers/AIStateMachine.ts b/packages/shared/src/entities/managers/AIStateMachine.ts index ef719e277..9bb1391a4 100644 --- a/packages/shared/src/entities/managers/AIStateMachine.ts +++ b/packages/shared/src/entities/managers/AIStateMachine.ts @@ -41,7 +41,7 @@ export interface AIStateContext { getCurrentTarget(): string | null; setTarget(playerId: string | null): void; - // Combat (TICK-BASED, OSRS-accurate) + // Combat (TICK-BASED, rules-accurate) canAttack(currentTick: number): boolean; performAttack(targetId: string, currentTick: number): void; onEnterCombatRange(currentTick: number): void; // Sets up first-attack timing (1-tick delay) @@ -52,7 +52,7 @@ export interface AIStateContext { getSpawnPoint(): Position3D; getDistanceFromSpawn(): number; getWanderRadius(): number; // For wander target generation (5 tiles default) - getLeashRange(): number; // For chase boundary (10 tiles default, OSRS two-tier range) + getLeashRange(): number; // For chase boundary (10 tiles default, classic MMORPG two-tier range) getCombatRange(): number; // Wander @@ -71,7 +71,7 @@ export interface AIStateContext { markNetworkDirty(): void; emitEvent(eventType: string, data: unknown): void; - // Entity Occupancy (OSRS-accurate NPC collision) + // Entity Occupancy (rules-accurate NPC collision) /** Entity ID for occupancy exclusion */ getEntityId(): EntityID; /** Entity occupancy map for collision checks */ @@ -79,18 +79,15 @@ export interface AIStateContext { /** Check if tile is walkable (terrain-based) */ isWalkable(tile: TileCoord): boolean; - // Same-tile step-out (OSRS-accurate) + // Same-tile step-out (rules-accurate) /** * Attempt to step out to a random cardinal-adjacent tile. * Used when NPC is on same tile as target and cannot attack. * - * OSRS behavior: pick random N/E/S/W, move if walkable, else do nothing. - * "In RS, they pick a random cardinal direction and try to move the NPC - * towards that by 1 tile, if it can. If not, the NPC does nothing that cycle." + * Classic tile-based behavior: pick random N/E/S/W, move if walkable, else do nothing. * * @returns true if movement was requested (server determines walkability) * - * @see https://osrs-docs.com/docs/mechanics/entity-collision/ */ tryStepOutCardinal(): boolean; } @@ -245,7 +242,7 @@ export class WanderState implements AIState { /** * CHASE State - Pursuing a player * - * OSRS-STYLE COMBAT POSITIONING: + * classic MMORPG-STYLE COMBAT POSITIONING: * - Uses manifest combatRange to determine how close mob needs to get * - Range 1 (standard melee): Cardinal only (N/S/E/W) - NO diagonal attacks * - Range 2+ (halberd, spear): Allows diagonal attacks (Chebyshev distance) @@ -253,10 +250,9 @@ export class WanderState implements AIState { * - This prevents entities from standing on top of each other * * IMPORTANT: Must use tilesWithinMeleeRange (not tilesWithinRange) to match - * CombatSystem's OSRS-accurate range validation. Using the wrong function + * CombatSystem's rules-accurate range validation. Using the wrong function * causes mobs to get stuck when diagonally adjacent to players. * - * @see https://oldschool.runescape.wiki/w/Attack_range */ export class ChaseState implements AIState { readonly name = MobAIState.CHASE; @@ -283,7 +279,7 @@ export class ChaseState implements AIState { return MobAIState.IDLE; } - // OSRS-ACCURATE: Check if PLAYER exceeded aggression range from SPAWN + // RULES-ACCURATE: Check if PLAYER exceeded aggression range from SPAWN // This is the key difference from before: we check PLAYER position, not MOB position // Mob movement is capped at leashRange in MobTileMovementManager, so mob lingers at edge // Target loss only happens when PLAYER moves beyond aggressionRange (leashRange + combatRange) @@ -306,19 +302,19 @@ export class ChaseState implements AIState { if (playerDistFromSpawn > aggressionRange) { context.setTarget(null); context.exitCombat(); - // RS-accurate: Mob returns to spawn when player exceeds aggression range + // Rules-accurate: Mob returns to spawn when player exceeds aggression range // Prevents ranged farming exploit where mobs stand idle at leash edge return MobAIState.RETURN; } - // TILE-BASED COMBAT RANGE CHECK (OSRS-style) + // TILE-BASED COMBAT RANGE CHECK (classic MMORPG-style) const currentPos = context.getPosition(); worldToTileInto(currentPos.x, currentPos.z, this._currentTile); const currentTile = this._currentTile; const targetTile = this._playerTile; // Reuse already computed tile // Check if already in combat range (uses manifest combatRange) - // OSRS-accurate: Range 1 = cardinal only, Range 2+ = allows diagonal + // rules-accurate: Range 1 = cardinal only, Range 2+ = allows diagonal const combatRangeTiles = context.getCombatRange(); const inMeleeRange = tilesWithinMeleeRange( currentTile, @@ -331,7 +327,7 @@ export class ChaseState implements AIState { } // If on same tile as target, transition to ATTACK state - // ATTACK state will handle step-out behavior (OSRS-accurate) + // ATTACK state will handle step-out behavior (rules-accurate) // This happens when player walks into mob's tile during chase if (tilesEqual(currentTile, targetTile)) { return MobAIState.ATTACK; @@ -372,23 +368,21 @@ export class ChaseState implements AIState { /** * ATTACK State - In melee range, attacking * - * OSRS-STYLE MELEE COMBAT: + * classic MMORPG-STYLE MELEE COMBAT: * - Stay on current tile (don't move closer) * - Range 1 (standard melee): Cardinal only (N/S/E/W) - NO diagonal attacks * - Range 2+ (halberd, spear): Allows diagonal attacks (Chebyshev distance) * - Switch to CHASE if target moves away (no longer in valid attack range) * - * SAME-TILE HANDLING (OSRS-accurate): + * SAME-TILE HANDLING (rules-accurate): * - NPC cannot attack from same tile (own tile not in attack range) * - Pick random cardinal direction and try to step out * - If blocked, do nothing that tick (try again next tick) * * IMPORTANT: Must use tilesWithinMeleeRange (not tilesWithinRange) to match - * CombatSystem's OSRS-accurate range validation. Using the wrong function + * CombatSystem's rules-accurate range validation. Using the wrong function * causes mobs to get stuck when diagonally adjacent to players. * - * @see https://oldschool.runescape.wiki/w/Attack_range - * @see https://osrs-docs.com/docs/mechanics/entity-collision/ */ export class AttackState implements AIState { readonly name = MobAIState.ATTACK; @@ -399,7 +393,7 @@ export class AttackState implements AIState { private readonly _currentTile: TileCoord = { x: 0, z: 0 }; enter(context: AIStateContext): void { - // OSRS-accurate: First attack is delayed 1 tick after entering combat range + // rules-accurate: First attack is delayed 1 tick after entering combat range // This sets up _pendingFirstAttack and _firstAttackTick for proper timing // Critical for re-entry attacks: resets timing when mob transitions back to ATTACK state const currentTick = context.getCurrentTick(); @@ -419,7 +413,7 @@ export class AttackState implements AIState { return MobAIState.IDLE; } - // OSRS-ACCURATE: Check if PLAYER exceeded aggression range from SPAWN + // RULES-ACCURATE: Check if PLAYER exceeded aggression range from SPAWN // This is the key difference from before: we check PLAYER position, not MOB position // Mob movement is capped at leashRange in MobTileMovementManager, so mob lingers at edge // Target loss only happens when PLAYER moves beyond aggressionRange (leashRange + combatRange) @@ -442,7 +436,7 @@ export class AttackState implements AIState { if (playerDistFromSpawn > aggressionRange) { context.setTarget(null); context.exitCombat(); - // RS-accurate: Mob returns to spawn when player exceeds aggression range + // Rules-accurate: Mob returns to spawn when player exceeds aggression range // Prevents ranged farming exploit where mobs stand idle at leash edge return MobAIState.RETURN; } @@ -459,7 +453,7 @@ export class AttackState implements AIState { ); const isSameTile = tilesEqual(currentTile, targetTile); - // OSRS-ACCURATE SAME-TILE HANDLING + // RULES-ACCURATE SAME-TILE HANDLING // When on same tile, NPC cannot attack - must step out first // "The tile underneath the NPC itself is not part of the attack range" if (isSameTile) { @@ -497,18 +491,15 @@ export class AttackState implements AIState { * RETURN State - Walking back to spawn point * * Used when: - * - Mob exceeds leash range while chasing/attacking (RS-accurate) + * - Mob exceeds leash range while chasing/attacking (rules-accurate) * - Mob stuck for too long (production safety) * - Low HP retreat behavior (future feature) * - * RS-accurate behavior: When player moves beyond aggression range, mob + * Rules-accurate behavior: When player moves beyond aggression range, mob * returns to its spawn point rather than standing idle at the leash edge. * This prevents ranged farming exploits where players attack from outside * the mob's retaliation range. * - * Per OSRS/RS3 Wiki: "Stepping outside of a radius will cause a melee - * monster to stop attacking you immediately and return to wandering." - * * Uses TILE-BASED distance check for arrival detection. * Movement is tile-based (600ms ticks), so we must check if we're on the * same tile as spawn, not world-space distance. diff --git a/packages/shared/src/entities/managers/AggroManager.ts b/packages/shared/src/entities/managers/AggroManager.ts index ffb308ec1..371d32452 100644 --- a/packages/shared/src/entities/managers/AggroManager.ts +++ b/packages/shared/src/entities/managers/AggroManager.ts @@ -1,12 +1,11 @@ /** * Manages mob target acquisition. Random selection from players in range. * - * OSRS-Accurate Aggro Mechanics: + * Rules-Accurate Aggro Mechanics: * - Hunt Range: Area where NPC detects players (from NPC's CURRENT position) * - Aggression Range: Area where NPC can attack players (from NPC's SPAWN point) * - Both checks must pass for aggro to occur * - * @see https://oldschool.runescape.wiki/w/Aggressiveness */ import type { Position3D } from "../../types"; @@ -40,13 +39,13 @@ export class AggroManager { /** * Random selection from valid candidates in range. * - * OSRS-Accurate: Two checks must pass for aggro: + * Rules-Accurate: Two checks must pass for aggro: * 1. Hunt Range: Player within aggroRange of mob's CURRENT position * 2. Aggression Range: Player within aggressionRange of mob's SPAWN point * * @param currentPos - Mob's current world position * @param players - Array of potential targets - * @param spawnPoint - Mob's spawn point (for OSRS-accurate aggression range check) + * @param spawnPoint - Mob's spawn point (for rules-accurate aggression range check) * @param aggressionRange - Max distance from spawn where players can be attacked (leashRange + attackRange) */ findNearbyPlayer( @@ -85,7 +84,7 @@ export class AggroManager { this._validTargetsBuffer.length = 0; const mobTile = worldToTile(currentPos.x, currentPos.z); - // Compute spawn tile if spawn point provided (for OSRS-accurate aggression range) + // Compute spawn tile if spawn point provided (for rules-accurate aggression range) const spawnTile: TileCoord | null = spawnPoint ? worldToTile(spawnPoint.x, spawnPoint.z) : null; @@ -102,7 +101,7 @@ export class AggroManager { if (huntDistance > this.config.aggroRange) continue; // Check 2: Aggression Range - player within aggressionRange of mob's SPAWN point - // This is OSRS-accurate: "The origin of the aggression range is the static spawn point" + // This is rules-accurate: "The origin of the aggression range is the static spawn point" if (spawnTile !== null && aggressionRange !== undefined) { const playerSpawnDistance = tileChebyshevDistance( spawnTile, diff --git a/packages/shared/src/entities/managers/CombatStateManager.ts b/packages/shared/src/entities/managers/CombatStateManager.ts index 9db1b92cb..4f5f9b3af 100644 --- a/packages/shared/src/entities/managers/CombatStateManager.ts +++ b/packages/shared/src/entities/managers/CombatStateManager.ts @@ -1,7 +1,6 @@ /** * Tracks mob combat state and attack timing. * First attack delayed one tick after entering range. - * @see https://oldschool.runescape.wiki/w/Attack_speed */ export interface CombatStateConfig { @@ -56,7 +55,7 @@ export class CombatStateManager { } /** - * First attack happens next tick, not immediately (OSRS-accurate) + * First attack happens next tick, not immediately (rules-accurate) * * Guard: Only sets up timing if NOT already in combat. This is intentional: * - Prevents resetting timing on rapid CHASE→ATTACK→CHASE→ATTACK transitions @@ -108,7 +107,6 @@ export class CombatStateManager { return true; } - /** Retaliate timing: ceil(speed/2)+1 ticks. @see https://oldschool.runescape.wiki/w/Auto_Retaliate */ onReceiveAttack(currentTick: number): void { const retaliationDelay = Math.ceil(this.config.attackSpeedTicks / 2) + 1; const retaliationTick = currentTick + retaliationDelay; diff --git a/packages/shared/src/entities/managers/MobHealthBarManager.ts b/packages/shared/src/entities/managers/MobHealthBarManager.ts index 679674c59..ad2adafc9 100644 --- a/packages/shared/src/entities/managers/MobHealthBarManager.ts +++ b/packages/shared/src/entities/managers/MobHealthBarManager.ts @@ -81,7 +81,7 @@ export class MobHealthBarManager { /** * Register with HealthBars system (client-side only). * Uses atlas-based instanced mesh for performance instead of sprite per mob. - * Health bar starts hidden (RuneScape pattern: only show during combat). + * Health bar starts hidden (classic fantasy MMORPG pattern: only show during combat). */ init(): void { if (this.ctx.world.isServer) return; @@ -96,7 +96,7 @@ export class MobHealthBarManager { this.ctx.config.currentHealth, this.ctx.config.maxHealth, ); - // Health bar starts hidden (RuneScape pattern: only show during combat) + // Health bar starts hidden (classic fantasy MMORPG pattern: only show during combat) } this._lastKnownHealth = this.ctx.config.currentHealth; @@ -138,7 +138,7 @@ export class MobHealthBarManager { // ─── Visibility management ────────────────────────────────────── /** - * Check and hide health bar after combat timeout (RuneScape pattern: 4.8 seconds). + * Check and hide health bar after combat timeout (classic fantasy MMORPG pattern: 4.8 seconds). * Called every client frame. */ updateVisibilityTimeout(): void { diff --git a/packages/shared/src/entities/managers/MobMovementManager.ts b/packages/shared/src/entities/managers/MobMovementManager.ts index fd52c9321..64ce0d65b 100644 --- a/packages/shared/src/entities/managers/MobMovementManager.ts +++ b/packages/shared/src/entities/managers/MobMovementManager.ts @@ -2,7 +2,7 @@ * MobMovementManager - Manages tile movement, patrol, pathfinding, and occupancy for MobEntity. * * Extracted from MobEntity to separate movement/occupancy concerns from AI and combat logic. - * Handles tile-based movement (OSRS-accurate), patrol point generation, wander targets, + * Handles tile-based movement (rules-accurate), patrol point generation, wander targets, * occupancy registration/unregistration, spawn tile search, and distance calculations. * * **Pattern**: Plain class (not a System subclass). @@ -167,7 +167,7 @@ export class MobMovementManager { /** * Find an unoccupied tile for spawning using spiral search * - * OSRS Mechanic: If spawn tile is occupied, search outward in expanding rings + * classic MMORPG Mechanic: If spawn tile is occupied, search outward in expanding rings * until an unoccupied tile is found. Uses Chebyshev distance (8-connected). * * @param centerX - Center tile X coordinate @@ -284,7 +284,7 @@ export class MobMovementManager { * Called after spawn/respawn to set collision flags on tiles this mob occupies. * Uses pre-allocated buffers to avoid hot path allocations. * - * OSRS Mechanic: Flags set when entity spawns/moves TO a tile + * classic MMORPG Mechanic: Flags set when entity spawns/moves TO a tile * If spawn tile is occupied, finds nearby unoccupied tile first. */ registerOccupancy(): void { @@ -302,7 +302,7 @@ export class MobMovementManager { this._currentTile.z = Math.floor(pos.z); // Check if spawn tile is already occupied by another mob - // If so, find an unoccupied tile nearby (OSRS-accurate: NPCs don't stack) + // If so, find an unoccupied tile nearby (rules-accurate: NPCs don't stack) const unoccupiedTile = this.findUnoccupiedSpawnTile( this._currentTile.x, this._currentTile.z, @@ -349,7 +349,7 @@ export class MobMovementManager { * * Called when mob dies or despawns to clear collision flags. * - * OSRS Mechanic: Flags removed when entity despawns/dies + * classic MMORPG Mechanic: Flags removed when entity despawns/dies */ unregisterOccupancy(): void { // Server-only: occupancy tracking is authoritative @@ -367,7 +367,7 @@ export class MobMovementManager { * Called after successful movement to update collision flags. * Uses atomic move() to avoid race conditions. * - * OSRS Mechanic: Flags removed from old tiles, added to new tiles (in order) + * classic MMORPG Mechanic: Flags removed from old tiles, added to new tiles (in order) * Called by MobTileMovementManager after successful movement. */ updateOccupancy(): void { @@ -435,9 +435,9 @@ export class MobMovementManager { // ─── Wander target generation ─────────────────────────────────── /** - * Generate a random wander target within wander radius (OSRS-accurate) + * Generate a random wander target within wander radius (rules-accurate) * - * OSRS generates wander targets relative to SPAWN, not current position. + * classic MMORPG generates wander targets relative to SPAWN, not current position. * This ensures NPCs naturally drift back toward spawn over time, * even after being leashed far from their spawn point. * @@ -447,7 +447,7 @@ export class MobMovementManager { const spawn = this._currentSpawnPoint; const radius = this.ctx.config.wanderRadius; - // OSRS-accurate: Random tile within [-radius, +radius] of spawn + // rules-accurate: Random tile within [-radius, +radius] of spawn // This creates a square wander area centered on spawn const range = 2 * radius + 1; const offsetX = Math.floor(Math.random() * range) - radius; @@ -530,7 +530,7 @@ export class MobMovementManager { Math.exp(-deltaTime * COMBAT_CONSTANTS.ROTATION.MOVEMENT_SLERP_SPEED); this.ctx.node.quaternion.slerp(this._targetQuat, rotationAlpha); - // Stuck detection: Only check when actively moving (RuneScape-style: give up if stuck) + // Stuck detection: Only check when actively moving (classic fantasy MMORPG-style: give up if stuck) // This prevents false positives during IDLE and ATTACK states const isMovingState = this.ctx.config.aiState === MobAIState.WANDER || @@ -572,7 +572,7 @@ export class MobMovementManager { } /** - * Emit a tile movement request (OSRS-accurate tick-based movement) + * Emit a tile movement request (rules-accurate tick-based movement) * Called by AI state machine's moveTowards callback. * Server's MobTileMovementManager will handle the actual movement on ticks. * @@ -619,7 +619,7 @@ export class MobMovementManager { /** * Calculate 2D horizontal distance (XZ plane only, ignoring Y) - * @deprecated Use getSpawnDistanceTiles() for leash/spawn checks - OSRS uses Chebyshev distance + * @deprecated Use getSpawnDistanceTiles() for leash/spawn checks - classic MMORPG uses Chebyshev distance */ getDistance2D(point: Position3D): number { const pos = this.ctx.getPosition(); @@ -629,9 +629,9 @@ export class MobMovementManager { } /** - * Calculate tile-based Chebyshev distance from spawn point (OSRS-accurate) + * Calculate tile-based Chebyshev distance from spawn point (rules-accurate) * - * OSRS uses Chebyshev distance (max of dx, dz) for tile-based checks. + * classic MMORPG uses Chebyshev distance (max of dx, dz) for tile-based checks. * This is critical for diagonal positions: * - Euclidean: (6,6) from (0,0) = 8.49 tiles (WRONG) * - Chebyshev: (6,6) from (0,0) = 6 tiles (CORRECT) @@ -646,8 +646,7 @@ export class MobMovementManager { /** * Get the mob's leash range (max tiles from spawn during chase) - * OSRS-accurate default: 7 tiles max range from spawn - * @see https://oldschool.runescape.wiki/w/Aggressiveness + * rules-accurate default: 7 tiles max range from spawn */ getLeashRange(): number { return ( diff --git a/packages/shared/src/entities/managers/MobVisualManager.ts b/packages/shared/src/entities/managers/MobVisualManager.ts index 9cc978335..d12d6b890 100644 --- a/packages/shared/src/entities/managers/MobVisualManager.ts +++ b/packages/shared/src/entities/managers/MobVisualManager.ts @@ -851,7 +851,7 @@ export class MobVisualManager { * is instant and stays for the entity's lifetime. * * IMMEDIATE INTERACTION: Also ensures the mob is interactive BEFORE VRM loads. - * RuneScape-style: entity is functional immediately, visuals are secondary. + * classic fantasy MMORPG-style: entity is functional immediately, visuals are secondary. */ createRaycastProxy(): void { // Skip on server - no visuals needed diff --git a/packages/shared/src/entities/managers/PlayerCombatStateManager.ts b/packages/shared/src/entities/managers/PlayerCombatStateManager.ts index 549f50023..cd23d787c 100644 --- a/packages/shared/src/entities/managers/PlayerCombatStateManager.ts +++ b/packages/shared/src/entities/managers/PlayerCombatStateManager.ts @@ -9,15 +9,12 @@ * * Responsibilities: * - Track combat state (in combat vs peaceful) - * - Manage attack cooldowns using game ticks (OSRS-accurate) + * - Manage attack cooldowns using game ticks (rules-accurate) * - Validate attack conditions * - Prevent logout while in combat * - Track last attacker for retaliation - * - Handle OSRS-accurate retaliation timing + * - Handle rules-accurate retaliation timing * - * @see https://oldschool.runescape.wiki/w/Auto_Retaliate - Auto-retaliate mechanics - * @see https://oldschool.runescape.wiki/w/Attack_speed - Attack speed ticks - * @see https://oldschool.runescape.wiki/w/Combat#Logout - Logout prevention timer */ import { COMBAT_CONSTANTS } from "../../constants/CombatConstants"; @@ -38,7 +35,7 @@ export class PlayerCombatStateManager { private lastAttackerId: string | null = null; private config: PlayerCombatStateConfig; - // Auto-retaliate state (enabled by default in OSRS) + // Auto-retaliate state (enabled by default in classic MMORPG) private autoRetaliateEnabled = true; // AFK tracking for auto-retaliate disable @@ -145,11 +142,10 @@ export class PlayerCombatStateManager { /** * Called when player is attacked - handles retaliation timing * - * OSRS-accurate retaliation: + * rules-accurate retaliation: * - If auto-retaliate is enabled and player is not AFK * - Retaliation happens after: ceil(attack_speed / 2) + 1 ticks * - * @see https://oldschool.runescape.wiki/w/Auto_Retaliate * * @param attackerId - ID of the attacking entity (accepts both EntityID and string) * @param currentTick - Current server tick number @@ -163,7 +159,7 @@ export class PlayerCombatStateManager { // Check if auto-retaliate should trigger if (this.shouldAutoRetaliate(currentTick)) { - // Calculate OSRS retaliation delay: ceil(attack_speed / 2) + 1 ticks + // Calculate classic MMORPG retaliation delay: ceil(attack_speed / 2) + 1 ticks const retaliationDelay = Math.ceil(this.config.attackSpeedTicks / 2) + 1; const retaliationTick = currentTick + retaliationDelay; @@ -230,8 +226,7 @@ export class PlayerCombatStateManager { /** * Check if player can logout (not prevented by combat) * - * OSRS: Cannot logout for 9.6 seconds (16 ticks) after taking damage - * @see https://oldschool.runescape.wiki/w/Combat#Logout + * classic MMORPG: Cannot logout for 9.6 seconds (16 ticks) after taking damage */ canLogout(currentTick: number): boolean { const ticksSinceDamage = currentTick - this.lastDamageTakenTick; diff --git a/packages/shared/src/entities/managers/RespawnManager.ts b/packages/shared/src/entities/managers/RespawnManager.ts index f40291ed7..c8f85586f 100644 --- a/packages/shared/src/entities/managers/RespawnManager.ts +++ b/packages/shared/src/entities/managers/RespawnManager.ts @@ -2,11 +2,11 @@ * RespawnManager - Manages mob respawn locations and timing (TICK-BASED) * * Production-quality respawn system: - * - Mobs spawn in an AREA, not at a single point (RuneScape-style) + * - Mobs spawn in an AREA, not at a single point (classic fantasy MMORPG-style) * - Random spawn location within configured radius * - Separate initial spawn from respawn locations * - Prevents spawn camping and exploitation - * - TICK-BASED timing for OSRS-accurate respawn mechanics + * - TICK-BASED timing for rules-accurate respawn mechanics * * Design: * 1. Define spawn area (center point + radius) @@ -16,10 +16,9 @@ * * Timing: * - Config accepts milliseconds for backwards compatibility - * - Internally converts to ticks for OSRS-accurate timing + * - Internally converts to ticks for rules-accurate timing * - Respawn timer tracked in ticks (600ms per tick) * - * @see https://oldschool.runescape.wiki/w/Respawn_rate */ import type { Position3D } from "../../types"; @@ -40,7 +39,7 @@ export class RespawnManager { private config: RespawnConfig; private currentRespawnPoint: Position3D | null = null; - // TICK-BASED respawn timing (OSRS-accurate) + // TICK-BASED respawn timing (rules-accurate) private respawnStartTick: number | null = null; private respawnDurationTicks: number = 0; diff --git a/packages/shared/src/entities/npc/LargeNPCSupport.ts b/packages/shared/src/entities/npc/LargeNPCSupport.ts index ec417666d..d06b59ce6 100644 --- a/packages/shared/src/entities/npc/LargeNPCSupport.ts +++ b/packages/shared/src/entities/npc/LargeNPCSupport.ts @@ -1,16 +1,15 @@ /** * LargeNPCSupport - Multi-tile NPC handling * - * OSRS large NPCs: + * classic MMORPG large NPCs: * - Occupy multiple tiles (2x2, 3x3, 4x4, etc.) * - SW tile is "true" position for most calculations * - Attack range originates from ALL occupied tiles * - Players can walk through occupied tiles (with entity collision) * * This module provides utilities for handling NPCs that occupy more than - * one tile, matching OSRS mechanics for boss fights and large creatures. + * one tile, matching classic tick-based mechanics for boss fights and large creatures. * - * @see https://oldschool.runescape.wiki/w/Size * @see MOB_AGGRO_IMPLEMENTATION_PLAN.md */ @@ -100,7 +99,7 @@ export function getNPCSize(mobType: string): NPCSize { * * The SW tile is the tile with the smallest X and Z coordinates * that the NPC occupies. This is the "true" position for most - * OSRS calculations (pathfinding, hunt range, etc.) + * classic MMORPG calculations (pathfinding, hunt range, etc.) * * @param worldPos - NPC's world position * @returns SW tile coordinate diff --git a/packages/shared/src/entities/npc/MobEntity.ts b/packages/shared/src/entities/npc/MobEntity.ts index 6f7aa027c..9e3543c8b 100644 --- a/packages/shared/src/entities/npc/MobEntity.ts +++ b/packages/shared/src/entities/npc/MobEntity.ts @@ -53,7 +53,7 @@ * - Health bar when damaged * - Death animation * - Attack animations - * - Name shown in right-click menu (OSRS pattern) + * - Name shown in right-click menu (classic MMORPG pattern) * * **Network Sync**: * - Position broadcast to clients @@ -281,7 +281,7 @@ export class MobEntity extends CombatantEntity { /** * Find an unoccupied tile for spawning using spiral search * - * OSRS Mechanic: If spawn tile is occupied, search outward in expanding rings + * classic MMORPG Mechanic: If spawn tile is occupied, search outward in expanding rings * until an unoccupied tile is found. Uses Chebyshev distance (8-connected). * * @param centerX - Center tile X coordinate @@ -396,7 +396,7 @@ export class MobEntity extends CombatantEntity { * Called after spawn/respawn to set collision flags on tiles this mob occupies. * Uses pre-allocated buffers to avoid hot path allocations. * - * OSRS Mechanic: Flags set when entity spawns/moves TO a tile + * classic MMORPG Mechanic: Flags set when entity spawns/moves TO a tile * If spawn tile is occupied, finds nearby unoccupied tile first. */ private registerOccupancy(): void { @@ -414,7 +414,7 @@ export class MobEntity extends CombatantEntity { this._currentTile.z = Math.floor(pos.z); // Check if spawn tile is already occupied by another mob - // If so, find an unoccupied tile nearby (OSRS-accurate: NPCs don't stack) + // If so, find an unoccupied tile nearby (rules-accurate: NPCs don't stack) const unoccupiedTile = this.findUnoccupiedSpawnTile( this._currentTile.x, this._currentTile.z, @@ -461,7 +461,7 @@ export class MobEntity extends CombatantEntity { * * Called when mob dies or despawns to clear collision flags. * - * OSRS Mechanic: Flags removed when entity despawns/dies + * classic MMORPG Mechanic: Flags removed when entity despawns/dies */ private unregisterOccupancy(): void { // Server-only: occupancy tracking is authoritative @@ -479,7 +479,7 @@ export class MobEntity extends CombatantEntity { * Called after successful movement to update collision flags. * Uses atomic move() to avoid race conditions. * - * OSRS Mechanic: Flags removed from old tiles, added to new tiles (in order) + * classic MMORPG Mechanic: Flags removed from old tiles, added to new tiles (in order) * Called by MobTileMovementManager after successful movement. */ public updateOccupancy(): void { @@ -559,7 +559,7 @@ export class MobEntity extends CombatantEntity { this.config.currentHealth, this.config.maxHealth, ); - // Health bar starts hidden (RuneScape pattern: only show during combat) + // Health bar starts hidden (classic fantasy MMORPG pattern: only show during combat) } } @@ -576,7 +576,7 @@ export class MobEntity extends CombatantEntity { protected override initializeVisuals(): void { // Call parent but it won't create health bar for mobs because we override createHealthBar // Note: We still want name tags from Entity.ts if applicable - // But mobs don't show nametags (RS pattern: names in right-click menu only) + // But mobs don't show nametags (names appear in the context menu only) // So just create the mesh without UI elements } @@ -704,7 +704,7 @@ export class MobEntity extends CombatantEntity { initialSpawnPoint.z, ); - // Register tile occupancy for OSRS-accurate NPC collision + // Register tile occupancy for rules-accurate NPC collision // Called after position is set (server-only, no-op on client) this.registerOccupancy(); @@ -1089,7 +1089,7 @@ export class MobEntity extends CombatantEntity { * is instant and stays for the entity's lifetime. * * IMMEDIATE INTERACTION: Also ensures the mob is interactive BEFORE VRM loads. - * RuneScape-style: entity is functional immediately, visuals are secondary. + * classic fantasy MMORPG-style: entity is functional immediately, visuals are secondary. */ private createRaycastProxy(): void { // Skip on server - no visuals needed @@ -1457,7 +1457,7 @@ export class MobEntity extends CombatantEntity { } }, - // Combat (TICK-BASED, OSRS-accurate) + // Combat (TICK-BASED, rules-accurate) canAttack: (currentTick) => this.combatManager.canAttack(currentTick), performAttack: (targetId, currentTick) => { this.combatManager.performAttack(targetId, currentTick); @@ -1472,7 +1472,7 @@ export class MobEntity extends CombatantEntity { // CRITICAL: Return mob's current spawn point (changes on respawn) // NOT the spawn area center (which is fixed) getSpawnPoint: () => this._currentSpawnPoint, - getDistanceFromSpawn: () => this.getSpawnDistanceTiles(), // OSRS Chebyshev tiles + getDistanceFromSpawn: () => this.getSpawnDistanceTiles(), // classic MMORPG Chebyshev tiles getWanderRadius: () => this.respawnManager.getSpawnAreaRadius(), getLeashRange: () => this.config.leashRange ?? COMBAT_CONSTANTS.DEFAULTS.NPC.LEASH_RANGE, @@ -1501,7 +1501,7 @@ export class MobEntity extends CombatantEntity { this.world.emit(eventType as EventType, data); }, - // Entity Occupancy (OSRS-accurate NPC collision) + // Entity Occupancy (rules-accurate NPC collision) getEntityId: () => this.id as EntityID, getEntityOccupancy: () => this.world.entityOccupancy, isWalkable: (tile) => { @@ -1527,7 +1527,7 @@ export class MobEntity extends CombatantEntity { return true; }, - // Same-tile step-out (OSRS-accurate) + // Same-tile step-out (rules-accurate) // When NPC is on same tile as target, it cannot attack. // Tries all 4 cardinal directions in shuffled order, picking the first // valid tile (walkable terrain + no entity blocking). @@ -1540,7 +1540,7 @@ export class MobEntity extends CombatantEntity { const rng = getGameRng(); // Find best step-out tile (checks walkability + entity occupancy) - // Uses shuffled order for OSRS-style randomness + // Uses shuffled order for classic MMORPG-style randomness const stepOutTile = getBestStepOutTile( currentTile, this.world.entityOccupancy, @@ -1573,7 +1573,7 @@ export class MobEntity extends CombatantEntity { // If no valid tile found, all directions are blocked if (!stepOutTile) { // All cardinal tiles blocked - wait for next tick - // In OSRS, mob would be stuck until a tile opens up + // In classic MMORPG, mob would be stuck until a tile opens up return false; } @@ -1599,9 +1599,9 @@ export class MobEntity extends CombatantEntity { } /** - * Generate a random wander target within wander radius (OSRS-accurate) + * Generate a random wander target within wander radius (rules-accurate) * - * OSRS generates wander targets relative to SPAWN, not current position. + * classic MMORPG generates wander targets relative to SPAWN, not current position. * This ensures NPCs naturally drift back toward spawn over time, * even after being leashed far from their spawn point. * @@ -1611,7 +1611,7 @@ export class MobEntity extends CombatantEntity { const spawn = this._currentSpawnPoint; const radius = this.config.wanderRadius; - // OSRS-accurate: Random tile within [-radius, +radius] of spawn + // rules-accurate: Random tile within [-radius, +radius] of spawn // This creates a square wander area centered on spawn const range = 2 * radius + 1; const offsetX = Math.floor(Math.random() * range) - radius; @@ -1769,7 +1769,7 @@ export class MobEntity extends CombatantEntity { return; // Don't run AI when dead } - // Validate target is still alive (RuneScape-style: instant disengage on target death) + // Validate target is still alive (classic fantasy MMORPG-style: instant disengage on target death) if (this.config.targetPlayerId) { const targetPlayer = this.world.getPlayer(this.config.targetPlayerId); if (!targetPlayer || targetPlayer.health.current <= 0) { @@ -1995,7 +1995,7 @@ export class MobEntity extends CombatantEntity { this._healthBarHandle.move(this._healthBarMatrix); } - // Hide health bar after combat timeout (RuneScape pattern: 4.8 seconds) + // Hide health bar after combat timeout (classic fantasy MMORPG pattern: 4.8 seconds) if (this._healthBarHandle && this._healthBarVisibleUntil > 0) { if (Date.now() >= this._healthBarVisibleUntil) { this._healthBarHandle.hide(); @@ -2056,7 +2056,7 @@ export class MobEntity extends CombatantEntity { } } - // COMBAT ROTATION: Rotate to face target when in ATTACK state (RuneScape-style) + // COMBAT ROTATION: Rotate to face target when in ATTACK state (classic fantasy MMORPG-style) // BUT: Only apply combat rotation when NOT moving via tile movement // TileInterpolator handles rotation when entity is walking/running const isTileMoving = this.data.tileMovementActive === true; @@ -2071,7 +2071,7 @@ export class MobEntity extends CombatantEntity { const dz = targetPlayer.position.z - this.position.z; const distanceSquared = dx * dx + dz * dz; - // OSRS-ACCURATE: Skip rotation when on same tile (distance too small) + // RULES-ACCURATE: Skip rotation when on same tile (distance too small) // Prevents 180° flips from floating-point instability when dx ≈ 0, dz ≈ 0 // Threshold: 0.25 = 0.5^2 (half a tile) const MIN_ROTATION_DISTANCE_SQ = 0.25; @@ -2322,7 +2322,7 @@ export class MobEntity extends CombatantEntity { /** * Calculate 2D horizontal distance (XZ plane only, ignoring Y) - * @deprecated Use getSpawnDistanceTiles() for leash/spawn checks - OSRS uses Chebyshev distance + * @deprecated Use getSpawnDistanceTiles() for leash/spawn checks - classic MMORPG uses Chebyshev distance */ private getDistance2D(point: Position3D): number { const pos = this.getPosition(); @@ -2332,9 +2332,9 @@ export class MobEntity extends CombatantEntity { } /** - * Calculate tile-based Chebyshev distance from spawn point (OSRS-accurate) + * Calculate tile-based Chebyshev distance from spawn point (rules-accurate) * - * OSRS uses Chebyshev distance (max of dx, dz) for tile-based checks. + * classic MMORPG uses Chebyshev distance (max of dx, dz) for tile-based checks. * This is critical for diagonal positions: * - Euclidean: (6,6) from (0,0) = 8.49 tiles (WRONG) * - Chebyshev: (6,6) from (0,0) = 6 tiles (CORRECT) @@ -2349,7 +2349,7 @@ export class MobEntity extends CombatantEntity { /** * Get the mob's current spawn point (public accessor for movement capping) - * Used by MobTileMovementManager to enforce OSRS-accurate leash range + * Used by MobTileMovementManager to enforce rules-accurate leash range */ getSpawnPoint(): Position3D { return this._currentSpawnPoint; @@ -2357,8 +2357,7 @@ export class MobEntity extends CombatantEntity { /** * Get the mob's leash range (max tiles from spawn during chase) - * OSRS-accurate default: 7 tiles max range from spawn - * @see https://oldschool.runescape.wiki/w/Aggressiveness + * rules-accurate default: 7 tiles max range from spawn */ getLeashRange(): number { return this.config.leashRange ?? COMBAT_CONSTANTS.DEFAULTS.NPC.LEASH_RANGE; @@ -2427,7 +2426,7 @@ export class MobEntity extends CombatantEntity { this.deathManager.die(deathPosition, currentTime); // Start respawn timer with RespawnManager (TICK-BASED - generates NEW random spawn point - NOT death location!) - // Uses server tick for OSRS-accurate timing + // Uses server tick for rules-accurate timing this.respawnManager.startRespawnTimer( this.world.currentTick, deathPosition, @@ -2447,7 +2446,7 @@ export class MobEntity extends CombatantEntity { // CRITICAL FIX FOR ISSUE #269: Don't end combat immediately when mob dies // Let combat timeout naturally after 4.8 seconds (8 ticks) to keep health bars visible - // This matches RuneScape behavior where combat state persists briefly after death + // This matches classic fantasy MMORPG behavior where combat state persists briefly after death // CombatSystem.handleEntityDied() already removes the dead mob's combat state // The attacker's combat will timeout naturally via the 4.8 second timer // @@ -2520,7 +2519,7 @@ export class MobEntity extends CombatantEntity { selectedSpell ) { // Magic weapon WITH active spell - use "magic" style for Magic XP - // OSRS-accurate: staffs used for melee (no spell) grant melee XP + // rules-accurate: staffs used for melee (no spell) grant melee XP attackStyle = "magic"; } else { // Melee attack (or staff/wand without a spell) - use player's selected attack style @@ -2536,7 +2535,7 @@ export class MobEntity extends CombatantEntity { } } else { // No weapon (unarmed) - check if player has a spell selected - // OSRS-accurate: You can cast spells without a staff + // rules-accurate: You can cast spells without a staff if (selectedSpell) { // Player has a spell selected - use "magic" for Magic XP attackStyle = "magic"; @@ -2637,7 +2636,7 @@ export class MobEntity extends CombatantEntity { // Smoothly rotate towards target direction this.node.quaternion.slerp(this._targetQuat, 0.1); - // Stuck detection: Only check when actively moving (RuneScape-style: give up if stuck) + // Stuck detection: Only check when actively moving (classic fantasy MMORPG-style: give up if stuck) // This prevents false positives during IDLE and ATTACK states const isMovingState = this.config.aiState === MobAIState.WANDER || @@ -2680,7 +2679,7 @@ export class MobEntity extends CombatantEntity { } /** - * Find nearby player within aggro range (RuneScape-style) + * Find nearby player within aggro range (classic fantasy MMORPG-style) * Delegates to AggroManager component * * IMPORTANT: Only scans for players if mob is aggressive. @@ -2705,11 +2704,10 @@ export class MobEntity extends CombatantEntity { ? aggroSystem.getPlayersInNearbyRegions(currentPos) : this.world.getPlayers(); // Fallback if AggroSystem not available - // OSRS-Accurate Aggression Range: + // Rules-Accurate Aggression Range: // The aggression range origin is the static spawn point of the NPC. // Aggression range = max range (leash) + attack range (combat range) // Players must be within this distance of SPAWN to be attacked. - // @see https://oldschool.runescape.wiki/w/Aggressiveness const leashRange = this.config.leashRange ?? COMBAT_CONSTANTS.DEFAULTS.NPC.LEASH_RANGE; const attackRange = Math.max(1, this.config.combatRange); @@ -2718,7 +2716,7 @@ export class MobEntity extends CombatantEntity { return this.aggroManager.findNearbyPlayer( currentPos, players, - this._currentSpawnPoint, // Spawn point for OSRS-accurate aggression check + this._currentSpawnPoint, // Spawn point for rules-accurate aggression check aggressionRange, // Max attack distance from spawn ); } @@ -2736,7 +2734,7 @@ export class MobEntity extends CombatantEntity { /** * Clear current target and exit combat (called when target dies or becomes invalid) - * RuneScape-style: Mob immediately disengages and returns to spawn area + * classic fantasy MMORPG-style: Mob immediately disengages and returns to spawn area */ private clearTargetAndExitCombat(): void { // Clear target @@ -2769,7 +2767,7 @@ export class MobEntity extends CombatantEntity { } } - // Map internal AI states to interface expected states (RuneScape-style) + // Map internal AI states to interface expected states (classic fantasy MMORPG-style) private mapAIStateToInterface( internalState: string, ): "idle" | "wander" | "chase" | "attack" | "return" | "dead" { @@ -2966,7 +2964,7 @@ export class MobEntity extends CombatantEntity { // CRITICAL: Use current VISUAL position (this.position), NOT server position (data.p) // TileInterpolator may be mid-interpolation, showing the mob at a different location // than the server's authoritative position. The mob should die WHERE THE PLAYER SEES IT, - // not teleport to the server position. This matches RS3's smooth movement philosophy. + // not teleport to the server position. This matches modern MMORPG's smooth movement philosophy. const visualDeathPos = new THREE.Vector3( this.position.x, this.position.y, diff --git a/packages/shared/src/entities/npc/NPCEntity.ts b/packages/shared/src/entities/npc/NPCEntity.ts index ec75d1b6d..2d07b10b4 100644 --- a/packages/shared/src/entities/npc/NPCEntity.ts +++ b/packages/shared/src/entities/npc/NPCEntity.ts @@ -41,7 +41,7 @@ * * **Visual Representation**: * - 3D model or humanoid mesh - * - Name shown in right-click menu (OSRS pattern) + * - Name shown in right-click menu (classic MMORPG pattern) * - NO health bar (cannot be damaged) * - Idle animations * - Interaction highlight when in range diff --git a/packages/shared/src/entities/player/PlayerEntity.ts b/packages/shared/src/entities/player/PlayerEntity.ts index 9d15b62d3..3fe96ea8d 100644 --- a/packages/shared/src/entities/player/PlayerEntity.ts +++ b/packages/shared/src/entities/player/PlayerEntity.ts @@ -15,7 +15,7 @@ * - Stamina system for actions * * **Inventory & Equipment**: - * - 28-slot inventory (RuneScape-style) + * - 28-slot inventory (classic fantasy MMORPG-style) * - Equipment slots (weapon, helmet, body, legs, shield, etc.) * - Item quantities and metadata * - Coins/currency @@ -35,7 +35,7 @@ * - Session data * * **UI Elements**: - * - Name shown in right-click menu (OSRS pattern) + * - Name shown in right-click menu (classic MMORPG pattern) * - Health bar (when damaged) * - Stamina bar (when depleted) * - Combat indicators @@ -395,7 +395,7 @@ export class PlayerEntity extends CombatantEntity { inCombat: false, combatTarget: null, autoRetaliate: - (playerData.autoRetaliate as boolean | undefined) ?? true, // OSRS default: ON, persisted from DB + (playerData.autoRetaliate as boolean | undefined) ?? true, // classic MMORPG default: ON, persisted from DB }, // Death system @@ -488,7 +488,7 @@ export class PlayerEntity extends CombatantEntity { this.addComponent("inventory", { items: playerData.inventory || [], - capacity: 28, // RuneScape-style 28 slots + capacity: 28, // classic fantasy MMORPG-style 28 slots coins: 0, }); @@ -744,7 +744,7 @@ export class PlayerEntity extends CombatantEntity { } // Note: Health bar handled by HealthBars system - // Names shown in right-click context menu only (OSRS pattern) + // Names shown in right-click context menu only (classic MMORPG pattern) // Player-specific methods that can be called by Systems diff --git a/packages/shared/src/entities/player/PlayerLocal.ts b/packages/shared/src/entities/player/PlayerLocal.ts index 223f3ed32..35e6beee9 100644 --- a/packages/shared/src/entities/player/PlayerLocal.ts +++ b/packages/shared/src/entities/player/PlayerLocal.ts @@ -358,9 +358,9 @@ const _healthBarMatrix = new THREE.Matrix4(); export class PlayerLocal extends Entity implements HotReloadable { private avatarDebugLogged: boolean = false; - // RS3-style run energy + // modern MMORPG-style run energy public stamina: number = 100; - // Tunable RS-style stamina rates (percent per second). Adjust to match desired feel exactly. + // Tunable stamina rates (percent per second). Adjust to match desired feel exactly. private readonly staminaDrainPerSecond: number = 2; // drain while running private readonly staminaRegenWhileWalkingPerSecond: number = 2; // regen while walking private readonly staminaRegenPerSecond: number = 4; // regen while idle @@ -421,7 +421,7 @@ export class PlayerLocal extends Entity implements HotReloadable { combatStyle: "attack", inCombat: false, combatTarget: null, - autoRetaliate: true, // OSRS default: ON + autoRetaliate: true, // classic MMORPG default: ON }; // Issue #322: Store last combat-facing rotation to preserve facing direction after combat ends private _lastCombatRotation: THREE.Quaternion | null = null; @@ -519,9 +519,9 @@ export class PlayerLocal extends Entity implements HotReloadable { // Internal avatar reference (rename existing avatar property) private _avatar?: AvatarNode; - // ========== PLAYER SILHOUETTE (RuneScape-style x-ray effect) ========== + // ========== PLAYER SILHOUETTE (classic fantasy MMORPG-style x-ray effect) ========== // - // TECHNIQUE (from official RuneScape dev blog): + // TECHNIQUE (from official classic fantasy MMORPG dev blog): // "Silhouettes are handled... we use the same size for both and only check // against the depth buffer on the last draw operation." // @@ -982,7 +982,7 @@ export class PlayerLocal extends Entity implements HotReloadable { if ("c" in data) { const newInCombat = data.c as boolean; this.combat.inCombat = newInCombat; - // Show/hide health bar based on combat state (RuneScape pattern) + // Show/hide health bar based on combat state (classic fantasy MMORPG pattern) if (this._healthBarHandle) { if (newInCombat) { // Sync health bar with current entity data before showing. @@ -1294,7 +1294,7 @@ export class PlayerLocal extends Entity implements HotReloadable { throw new Error("Failed to create aura node for PlayerLocal"); } - // Nametags disabled - OSRS pattern: names shown in right-click menu only + // Nametags disabled - classic MMORPG pattern: names shown in right-click menu only // Register with HealthBars system const healthbars = this.world.getSystem?.("healthbars") as @@ -1305,7 +1305,7 @@ export class PlayerLocal extends Entity implements HotReloadable { const currentHealth = (this.data.health as number) || 100; const maxHealth = (this.data.maxHealth as number) || 100; this._healthBarHandle = healthbars.add(this.id, currentHealth, maxHealth); - // Health bar starts hidden (RuneScape pattern: only show during combat) + // Health bar starts hidden (classic fantasy MMORPG pattern: only show during combat) } this.bubble = createNode("ui", { @@ -1719,7 +1719,7 @@ export class PlayerLocal extends Entity implements HotReloadable { success: true, }); - // Create silhouette effect for x-ray visibility (RuneScape-style) + // Create silhouette effect for x-ray visibility (classic fantasy MMORPG-style) this.createPlayerSilhouette(); // PERFORMANCE: Disable raycasting on ALL local player VRM meshes @@ -1759,7 +1759,7 @@ export class PlayerLocal extends Entity implements HotReloadable { } /** - * Create RuneScape-style silhouette for x-ray visibility when occluded. + * Create classic fantasy MMORPG-style silhouette for x-ray visibility when occluded. * Silhouette renders with depthTest=false (always draws), player overwrites where visible. */ private createPlayerSilhouette(): void { @@ -2078,7 +2078,7 @@ export class PlayerLocal extends Entity implements HotReloadable { }); } - // RuneScape-style run mode toggle (persists across movements) + // classic fantasy MMORPG-style run mode toggle (persists across movements) public runMode: boolean = true; private clientPredictMovement: boolean = true; @@ -2276,7 +2276,7 @@ export class PlayerLocal extends Entity implements HotReloadable { // ALWAYS log first 10 updates with high visibility // (logging removed but keeping structure for future use) - // COMBAT ROTATION: Rotate to face target when in combat (RuneScape-style) + // COMBAT ROTATION: Rotate to face target when in combat (classic fantasy MMORPG-style) // Client is display-only - server controls all combat facing // Priority: 1) Our combat target (from server), 2) Server face target (attacker) let combatTarget: { @@ -2327,7 +2327,7 @@ export class PlayerLocal extends Entity implements HotReloadable { } } - // OSRS behavior: Only face combat target when STANDING STILL + // classic MMORPG behavior: Only face combat target when STANDING STILL // When moving, face movement direction (handled by TileInterpolator) const isMoving = this.data?.tileMovementActive === true; @@ -2341,7 +2341,7 @@ export class PlayerLocal extends Entity implements HotReloadable { } if (combatTarget && !isMoving) { - // Calculate angle to target (XZ plane only, like RuneScape) + // Calculate angle to target (XZ plane only, like classic fantasy MMORPG) const dx = combatTarget.position.x - this.position.x; const dz = combatTarget.position.z - this.position.z; let angle = Math.atan2(dx, dz); @@ -2516,7 +2516,7 @@ export class PlayerLocal extends Entity implements HotReloadable { 100, ); if (this.stamina <= 0 && !this.autoRunSwitchSent) { - // Auto-switch to walk on server when energy depletes (RS-style) + // Auto-switch to walk on server when energy depletes this.runMode = false; this.world.network.send("moveRequest", { runMode: false }); this.autoRunSwitchSent = true; @@ -2686,7 +2686,7 @@ export class PlayerLocal extends Entity implements HotReloadable { } onNetworkData(_data: Partial): void { - // Name stored in this.data.name - shown in right-click menu (OSRS pattern) + // Name stored in this.data.name - shown in right-click menu (classic MMORPG pattern) // Health bar is NOT updated here - visual updates ONLY via handleHealthChange() // to prevent stale snapshot data from overwriting event-driven values } @@ -3072,7 +3072,7 @@ export class PlayerLocal extends Entity implements HotReloadable { this._avatar = undefined; } - // Clean up player silhouette (RuneScape-style x-ray effect) + // Clean up player silhouette (classic fantasy MMORPG-style x-ray effect) this.destroyPlayerSilhouette(); // Clean up UI elements diff --git a/packages/shared/src/entities/player/PlayerRemote.ts b/packages/shared/src/entities/player/PlayerRemote.ts index 925c4be06..9cfa12f66 100644 --- a/packages/shared/src/entities/player/PlayerRemote.ts +++ b/packages/shared/src/entities/player/PlayerRemote.ts @@ -14,7 +14,7 @@ * * **Visual Representation**: * - VRM avatar rendering - * - Name shown in right-click menu (OSRS pattern) + * - Name shown in right-click menu (classic MMORPG pattern) * - Chat bubbles for messages * - Health bar (if in combat) * - Capsule collider visualization (debug mode) @@ -206,15 +206,15 @@ export class PlayerRemote extends Entity implements HotReloadable { // This bypasses the Node system and avoids expensive SkinnedMesh raycast private raycastProxy: THREE.Mesh | null = null; - // Combat state for RuneScape-style auto-retaliate + // Combat state for classic fantasy MMORPG-style auto-retaliate combat = { inCombat: false, combatTarget: null as string | null, }; - /** Combat level for OSRS-style display and PvP range checks */ + /** Combat level for classic MMORPG-style display and PvP range checks */ get combatLevel(): number { - return (this.data.combatLevel as number) || 3; // Default to OSRS minimum + return (this.data.combatLevel as number) || 3; // Default to classic MMORPG minimum } // Guard to prevent double initialization @@ -328,7 +328,7 @@ export class PlayerRemote extends Entity implements HotReloadable { const currentHealth = (this.data.health as number) || 100; const maxHealth = (this.data.maxHealth as number) || 100; this._healthBarHandle = healthbars.add(this.id, currentHealth, maxHealth); - // Health bar starts hidden (RuneScape pattern: only show during combat) + // Health bar starts hidden (classic fantasy MMORPG pattern: only show during combat) } this.bubble = createNode("ui", { @@ -1367,7 +1367,7 @@ export class PlayerRemote extends Entity implements HotReloadable { } if (data.combatLevel !== undefined) { this.data.combatLevel = data.combatLevel as number; - // Combat level stored in data - shown in right-click menu (OSRS pattern) + // Combat level stored in data - shown in right-click menu (classic MMORPG pattern) } if (data.maxHealth !== undefined) { this.data.maxHealth = data.maxHealth as number; @@ -1405,12 +1405,12 @@ export class PlayerRemote extends Entity implements HotReloadable { const vel = data.v as number[]; this.velocity.set(vel[0], vel[1], vel[2]); } - // Handle combat state updates for RuneScape-style auto-retaliate rotation + // Handle combat state updates for classic fantasy MMORPG-style auto-retaliate rotation // Using abbreviated key 'c' for inCombat (network efficiency) if ("c" in data) { const newInCombat = data.c as boolean; this.combat.inCombat = newInCombat; - // Show/hide health bar via HealthBars system (RuneScape pattern) + // Show/hide health bar via HealthBars system (classic fantasy MMORPG pattern) if (this._healthBarHandle) { if (newInCombat) { // Sync health bar with current entity data before showing. diff --git a/packages/shared/src/entities/player/__tests__/PlayerSilhouette.test.ts b/packages/shared/src/entities/player/__tests__/PlayerSilhouette.test.ts index 78d93ac11..6e59f3f01 100644 --- a/packages/shared/src/entities/player/__tests__/PlayerSilhouette.test.ts +++ b/packages/shared/src/entities/player/__tests__/PlayerSilhouette.test.ts @@ -1,7 +1,7 @@ /** * PlayerSilhouette Comprehensive Tests * - * Tests the RuneScape-style silhouette x-ray effect with full coverage: + * Tests the classic fantasy MMORPG-style silhouette x-ray effect with full coverage: * - Happy path: normal operation * - Edge cases: missing data, empty scenes, unusual hierarchies * - Error handling: null values, dispose states diff --git a/packages/shared/src/entities/world/AltarEntity.ts b/packages/shared/src/entities/world/AltarEntity.ts index 37cb47625..bc68a059e 100644 --- a/packages/shared/src/entities/world/AltarEntity.ts +++ b/packages/shared/src/entities/world/AltarEntity.ts @@ -155,7 +155,7 @@ export class AltarEntity extends InteractableEntity { } /** - * Return tiles occupied by this station for OSRS-style interaction checking. + * Return tiles occupied by this station for classic MMORPG-style interaction checking. * Uses the same tiles registered for collision. */ protected override getOccupiedTiles(): TileCoord[] { diff --git a/packages/shared/src/entities/world/AnvilEntity.ts b/packages/shared/src/entities/world/AnvilEntity.ts index 1b65abe51..73f58cd3a 100644 --- a/packages/shared/src/entities/world/AnvilEntity.ts +++ b/packages/shared/src/entities/world/AnvilEntity.ts @@ -157,7 +157,7 @@ export class AnvilEntity extends InteractableEntity { } /** - * Return tiles occupied by this station for OSRS-style interaction checking. + * Return tiles occupied by this station for classic MMORPG-style interaction checking. * Uses the same tiles registered for collision. */ protected override getOccupiedTiles(): TileCoord[] { diff --git a/packages/shared/src/entities/world/BankEntity.ts b/packages/shared/src/entities/world/BankEntity.ts index 6959ec261..55af4a1dc 100644 --- a/packages/shared/src/entities/world/BankEntity.ts +++ b/packages/shared/src/entities/world/BankEntity.ts @@ -143,7 +143,7 @@ export class BankEntity extends InteractableEntity { } /** - * Return tiles occupied by this station for OSRS-style interaction checking. + * Return tiles occupied by this station for classic MMORPG-style interaction checking. * Uses the same tiles registered for collision. */ protected override getOccupiedTiles(): TileCoord[] { diff --git a/packages/shared/src/entities/world/FireEntity.ts b/packages/shared/src/entities/world/FireEntity.ts index 223eed716..a48be5534 100644 --- a/packages/shared/src/entities/world/FireEntity.ts +++ b/packages/shared/src/entities/world/FireEntity.ts @@ -3,7 +3,7 @@ * * Represents a fire that players can cook on. * Created when player successfully uses tinderbox on logs. - * Expires after 60-119 seconds (OSRS accurate). + * Expires after 60-119 seconds (rules-accurate). * * **Extends**: InteractableEntity (players can interact to cook) * diff --git a/packages/shared/src/entities/world/FurnaceEntity.ts b/packages/shared/src/entities/world/FurnaceEntity.ts index 12ed931e1..bb7ca20c0 100644 --- a/packages/shared/src/entities/world/FurnaceEntity.ts +++ b/packages/shared/src/entities/world/FurnaceEntity.ts @@ -153,7 +153,7 @@ export class FurnaceEntity extends InteractableEntity { } /** - * Return tiles occupied by this station for OSRS-style interaction checking. + * Return tiles occupied by this station for classic MMORPG-style interaction checking. * Uses the same tiles registered for collision. */ protected override getOccupiedTiles(): TileCoord[] { diff --git a/packages/shared/src/entities/world/ItemEntity.ts b/packages/shared/src/entities/world/ItemEntity.ts index 9cccfa145..28d60d9df 100644 --- a/packages/shared/src/entities/world/ItemEntity.ts +++ b/packages/shared/src/entities/world/ItemEntity.ts @@ -314,7 +314,7 @@ export class ItemEntity extends InteractableEntity { protected clientUpdate(deltaTime: number): void { super.clientUpdate(deltaTime); - // OSRS-style pile visibility - only top item in pile is visible + // classic MMORPG-style pile visibility - only top item in pile is visible if (this.mesh) { const visibleInPile = this.getProperty("visibleInPile", true); if (this.mesh.visible !== visibleInPile) { @@ -356,7 +356,7 @@ export class ItemEntity extends InteractableEntity { private checkDespawn(): void { // Skip native despawn for items managed by GroundItemSystem - // GroundItemSystem uses tick-based despawn which is more accurate (OSRS-style) + // GroundItemSystem uses tick-based despawn which is more accurate (classic MMORPG-style) // Only run native despawn for world spawn items (from ItemSpawnerSystem) if (this.id.startsWith("ground_item_")) { // GroundItemSystem handles despawn via processTick() diff --git a/packages/shared/src/entities/world/RangeEntity.ts b/packages/shared/src/entities/world/RangeEntity.ts index 119761030..a79f28b20 100644 --- a/packages/shared/src/entities/world/RangeEntity.ts +++ b/packages/shared/src/entities/world/RangeEntity.ts @@ -159,7 +159,7 @@ export class RangeEntity extends InteractableEntity { } /** - * Return tiles occupied by this station for OSRS-style interaction checking. + * Return tiles occupied by this station for classic MMORPG-style interaction checking. * Uses the same tiles registered for collision. */ protected override getOccupiedTiles(): TileCoord[] { diff --git a/packages/shared/src/entities/world/ResourceEntity.ts b/packages/shared/src/entities/world/ResourceEntity.ts index 0014d7590..fdab6ce6f 100644 --- a/packages/shared/src/entities/world/ResourceEntity.ts +++ b/packages/shared/src/entities/world/ResourceEntity.ts @@ -203,7 +203,7 @@ export class ResourceEntity extends InteractableEntity { } // Respawn is handled by ResourceSystem.processRespawns() via tick-based timing. - // No setTimeout here — tick-based respawn is deterministic and OSRS-accurate. + // No setTimeout here — tick-based respawn is deterministic and rules-accurate. } public respawn(): void { diff --git a/packages/shared/src/entities/world/RunecraftingAltarEntity.ts b/packages/shared/src/entities/world/RunecraftingAltarEntity.ts index 2e2576b9e..c13727f88 100644 --- a/packages/shared/src/entities/world/RunecraftingAltarEntity.ts +++ b/packages/shared/src/entities/world/RunecraftingAltarEntity.ts @@ -162,7 +162,7 @@ export class RunecraftingAltarEntity extends InteractableEntity { } /** - * Return tiles occupied by this station for OSRS-style interaction checking. + * Return tiles occupied by this station for classic MMORPG-style interaction checking. */ protected override getOccupiedTiles(): TileCoord[] { if (this.collisionTiles.length > 0) { diff --git a/packages/shared/src/index.client.ts b/packages/shared/src/index.client.ts index 4eeeba706..a4217e475 100644 --- a/packages/shared/src/index.client.ts +++ b/packages/shared/src/index.client.ts @@ -90,7 +90,7 @@ export { PlayerMigration } from "./types/core/core"; // Export enums (these are values, not types) export { WeaponType, EquipmentSlotName } from "./types/core/core"; -// Weapon style configuration (OSRS-accurate style restrictions per weapon) +// Weapon style configuration (rules-accurate style restrictions per weapon) export { WEAPON_STYLE_CONFIG, getAvailableStyles, @@ -132,7 +132,7 @@ export type { PendingLootTransaction, } from "./types/death"; -// Export tile utilities (used for OSRS-style tile-based distance checks) +// Export tile utilities (used for classic MMORPG-style tile-based distance checks) export { worldToTile, tileToWorld, @@ -147,7 +147,7 @@ export { // Export item helpers used by server network snapshot export { ITEMS, getItem } from "./data/items"; -// Item type detection helpers (OSRS-accurate inventory actions) +// Item type detection helpers (rules-accurate inventory actions) export { isFood, isPotion, @@ -163,7 +163,7 @@ export { } from "./utils/item-helpers"; export type { PrimaryActionType } from "./utils/item-helpers"; -// Context menu colors (OSRS-accurate styling) +// Context menu colors (rules-accurate styling) export { CONTEXT_MENU_COLORS } from "./constants/GameConstants"; // Home teleport constants (cooldown, cast time) diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 4d8378ea3..72794e048 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -193,7 +193,7 @@ export type { StreamingGuardrailPhase, } from "./utils/rendering/streamingGuardrails"; -// Export SeededRandom and game RNG utilities (OSRS-accurate deterministic RNG) +// Export SeededRandom and game RNG utilities (rules-accurate deterministic RNG) export { SeededRandom, initializeGameRng, @@ -580,7 +580,7 @@ export { ControlPriorities } from "./systems/client/ControlPriorities"; export { downloadFile } from "./utils/downloadFile"; export * from "./utils/typeGuards"; -// Item type detection helpers (OSRS-accurate inventory actions) +// Item type detection helpers (rules-accurate inventory actions) export { isFood, isPotion, @@ -1033,7 +1033,7 @@ export { tileKey as buildingTileKey, } from "./types/world/building-collision-types"; -// Export tile movement system (RuneScape-style) +// Export tile movement system (classic fantasy MMORPG-style) export { // Constants TILE_SIZE, @@ -1158,10 +1158,10 @@ export { PLAYER_CONSTANTS } from "./constants/GameConstants"; // Gathering constants (tick-based timing, ranges, etc.) export { GATHERING_CONSTANTS } from "./constants/GatheringConstants"; -// Context menu colors (OSRS-accurate styling) +// Context menu colors (rules-accurate styling) export { CONTEXT_MENU_COLORS } from "./constants/GameConstants"; -// Weapon style configuration (OSRS-accurate style restrictions per weapon) +// Weapon style configuration (rules-accurate style restrictions per weapon) export { WEAPON_STYLE_CONFIG, getAvailableStyles, @@ -1169,7 +1169,7 @@ export { getDefaultStyleForWeapon, } from "./constants/WeaponStyleConfig"; -// Hit delay calculator (OSRS-accurate projectile delays) +// Hit delay calculator (rules-accurate projectile delays) export { calculateHitDelay, calculateMeleeHitDelay, @@ -1188,7 +1188,7 @@ export type { HitDelayResult, } from "./utils/game/HitDelayCalculator"; -// Distance utilities (OSRS-style Chebyshev) +// Distance utilities (classic MMORPG-style Chebyshev) export { chebyshevDistance, isWithinDistance, diff --git a/packages/shared/src/nodes/HealthBar.ts b/packages/shared/src/nodes/HealthBar.ts index 0066d32d8..f5bfad781 100644 --- a/packages/shared/src/nodes/HealthBar.ts +++ b/packages/shared/src/nodes/HealthBar.ts @@ -2,7 +2,7 @@ * HealthBar.ts - Entity Health Bar Node * * Frontend handle to the HealthBars system for rendering health bars above entities. - * Names are shown in right-click context menus only (OSRS pattern). + * Names are shown in right-click context menus only (classic MMORPG pattern). * * Usage: * ```typescript diff --git a/packages/shared/src/platform/shared/packets.ts b/packages/shared/src/platform/shared/packets.ts index 4e5887e87..9648b6475 100644 --- a/packages/shared/src/platform/shared/packets.ts +++ b/packages/shared/src/platform/shared/packets.ts @@ -120,7 +120,7 @@ const names = [ 'gatheringComplete', 'gatheringStarted', // Server -> Client: gathering session started 'gatheringStopped', // Server -> Client: gathering session stopped - 'gatheringToolShow', // Server -> Client: show gathering tool in hand (OSRS fishing rod) + 'gatheringToolShow', // Server -> Client: show gathering tool in hand (classic MMORPG fishing rod) 'gatheringToolHide', // Server -> Client: hide gathering tool from hand // Processing packets (firemaking/cooking) 'firemakingRequest', // Client -> Server: request to light fire (tinderbox + logs) @@ -164,7 +164,7 @@ const names = [ // Combat packets 'attackMob', 'attackPlayer', // PvP attack - 'followPlayer', // Follow another player (OSRS-style) + 'followPlayer', // Follow another player (classic MMORPG-style) 'changeAttackStyle', 'setAutoRetaliate', 'autoRetaliateChanged', @@ -186,7 +186,7 @@ const names = [ 'equipmentUpdated', // Skills sync packets 'skillsUpdated', - // XP drop visual feedback packets (RS3-style) + // XP drop visual feedback packets (modern MMORPG-style) 'xpDrop', // UI feedback packets 'showToast', @@ -246,12 +246,12 @@ const names = [ 'bankDeleteTab', // Delete tab (items move to main tab) 'bankMoveToTab', // Move item between tabs 'bankSelectTab', // Client selected a different tab - // Bank placeholder packets (RS3 style: qty=0 in bank_storage) - 'bankWithdrawPlaceholder', // Withdraw all and leave qty=0 placeholder (RS3 style) + // Bank placeholder packets (modern MMORPG style: qty=0 in bank_storage) + 'bankWithdrawPlaceholder', // Withdraw all and leave qty=0 placeholder (modern MMORPG style) 'bankReleasePlaceholder', // Release single placeholder (delete qty=0 row) 'bankReleaseAllPlaceholders', // Clear all placeholders (delete all qty=0 rows) 'bankToggleAlwaysPlaceholder', // Toggle auto-placeholder setting - // Bank equipment tab packets (RS3-style equipment view in bank) + // Bank equipment tab packets (modern MMORPG-style equipment view in bank) 'bankWithdrawToEquipment', // Withdraw item directly to equipment slot 'bankDepositEquipment', // Deposit single equipment slot to bank 'bankDepositAllEquipment', // Deposit all worn equipment to bank @@ -272,7 +272,7 @@ const names = [ 'dialogueContinue', 'dialogueEnd', 'dialogueClose', - // Tile movement packets (RuneScape-style) + // Tile movement packets (classic fantasy MMORPG-style) 'entityTileUpdate', // Server -> Client: entity moved to new tile position 'tileMovementStart', // Server -> Client: movement path started 'tileMovementEnd', // Server -> Client: arrived at destination @@ -325,7 +325,7 @@ const names = [ 'tradeCompleted', // Server -> Client: trade successful, items swapped 'tradeCancelled', // Server -> Client: trade cancelled (disconnect, decline, etc.) 'tradeError', // Server -> Client: trade operation failed with reason - 'tradeConfirmScreen', // Server -> Client: move to confirmation screen (OSRS two-screen) + 'tradeConfirmScreen', // Server -> Client: move to confirmation screen (classic MMORPG two-screen) // Duel Arena packets 'duel:challenge', // Client -> Server: challenge player to duel 'duel:challenge:respond',// Client -> Server: accept/decline duel challenge diff --git a/packages/shared/src/runtime/createClientWorld.ts b/packages/shared/src/runtime/createClientWorld.ts index 9b91d8019..bbdfd4da9 100644 --- a/packages/shared/src/runtime/createClientWorld.ts +++ b/packages/shared/src/runtime/createClientWorld.ts @@ -337,7 +337,7 @@ export function createClientWorld() { // These systems enhance visual fidelity and user experience world.register("lods", LODs); // Level-of-detail mesh management - // Nametags disabled - OSRS pattern: names shown in right-click menu only + // Nametags disabled - classic MMORPG pattern: names shown in right-click menu only world.register("healthbars", HealthBars); // Entity health bars world.register("equipment-visual", EquipmentVisualSystem); // Visual weapon/equipment attachment world.register("zone-detection", ZoneDetectionSystem); // Zone type detection (safe/pvp/wilderness) diff --git a/packages/shared/src/systems/client/ClientCameraSystem.ts b/packages/shared/src/systems/client/ClientCameraSystem.ts index a3338a290..40b81795c 100644 --- a/packages/shared/src/systems/client/ClientCameraSystem.ts +++ b/packages/shared/src/systems/client/ClientCameraSystem.ts @@ -91,13 +91,13 @@ export class ClientCameraSystem extends SystemBase { // Control settings private readonly settings = { - // RS3-like zoom bounds (further min to avoid getting too close) + // modern MMORPG-like zoom bounds (further min to avoid getting too close) minDistance: 2.0, maxDistance: 15.0, // Pitch limits: allow higher arc for more overhead viewing minPolarAngle: Math.PI * 0.15, maxPolarAngle: Math.PI * 0.48, - // RS3-like feel + // modern MMORPG-like feel rotateSpeed: 0.9, zoomSpeed: 1.2, panSpeed: 2.0, @@ -632,7 +632,7 @@ export class ClientCameraSystem extends SystemBase { event.stopPropagation(); const invert = this.settings.invertY === true ? -1 : 1; - // RS3-like: keep rotation responsive when fully zoomed out + // modern MMORPG-like: keep rotation responsive when fully zoomed out const minR = this.settings.minDistance; const maxR = this.settings.maxDistance; const r = THREE.MathUtils.clamp(this.spherical.radius, minR, maxR); @@ -718,7 +718,7 @@ export class ClientCameraSystem extends SystemBase { this.settings.minDistance, this.settings.maxDistance, ); - // RS-style: snap zoom immediately (no swooping) + // Snap zoom immediately (no swooping) this.spherical.radius = this.targetSpherical.radius; this.effectiveRadius = this.targetSpherical.radius; this.zoomDirty = true; @@ -769,7 +769,7 @@ export class ClientCameraSystem extends SystemBase { } private onKeyDown(event: KeyboardEvent): void { - // RS-style camera control via arrow keys: rotate around character only + // Arrow-key camera control: rotate around character only const rotateStep = 0.06; if (event.code === "ArrowLeft") { event.preventDefault(); @@ -2674,7 +2674,7 @@ export class ClientCameraSystem extends SystemBase { this.targetPosition.copy(_v3_1); this.targetPosition.add(this.cameraOffset); - // RS3: no target smoothing; follow the player position directly to avoid any lag/jitter + // modern MMORPG: no target smoothing; follow the player position directly to avoid any lag/jitter this.smoothedTarget.copy(this.targetPosition); } @@ -2722,7 +2722,7 @@ export class ClientCameraSystem extends SystemBase { this.spherical.radius = this.targetSpherical.radius; } - // Hard clamp after smoothing to enforce strict RS3-like limits + // Hard clamp after smoothing to enforce strict modern MMORPG-like limits this.spherical.radius = clamp( this.spherical.radius, this.settings.minDistance, @@ -2794,7 +2794,7 @@ export class ClientCameraSystem extends SystemBase { } // Follow target. If zoom changed this frame, snap position instantly for straight-in/out motion - // RS3: move camera directly with no positional lerp to avoid swoop or lag + // modern MMORPG: move camera directly with no positional lerp to avoid swoop or lag this.camera.position.copy(this.cameraPosition); if (cinematicFrame) { this.camera.position.add(this.computeCameraShake(frameDt)); diff --git a/packages/shared/src/systems/client/ClientInput.ts b/packages/shared/src/systems/client/ClientInput.ts index 502e5f6d5..04d982f9b 100644 --- a/packages/shared/src/systems/client/ClientInput.ts +++ b/packages/shared/src/systems/client/ClientInput.ts @@ -572,7 +572,7 @@ export class ClientInput extends SystemBase { } } - // RuneScape-style: no keyboard-driven movement; do not send network cancels on key release + // classic fantasy MMORPG-style: no keyboard-driven movement; do not send network cancels on key release }; private onPointerDown = (e: PointerEvent) => { @@ -938,7 +938,7 @@ export class ClientInput extends SystemBase { this.inputBuffer.push(buffered); - // RuneScape-style: no keyboard-driven movement; do not send moveRequest from keyboard + // classic fantasy MMORPG-style: no keyboard-driven movement; do not send moveRequest from keyboard // Trim buffer while (this.inputBuffer.length > MovementConfig.inputBufferSize) { @@ -1322,7 +1322,7 @@ export class ClientInput extends SystemBase { * Start random walk behavior (for AI agents) * * Picks random positions within the configured radius and walks to them. - * Uses OSRS-style probabilistic wandering with configurable interval. + * Uses classic MMORPG-style probabilistic wandering with configurable interval. * * @param radius - Max distance from current position (default 10) * @param interval - Time between random walks in ms (default 3000) diff --git a/packages/shared/src/systems/client/ClientInterface.ts b/packages/shared/src/systems/client/ClientInterface.ts index 7785b734f..c0d7e1628 100644 --- a/packages/shared/src/systems/client/ClientInterface.ts +++ b/packages/shared/src/systems/client/ClientInterface.ts @@ -42,7 +42,7 @@ export interface ClientPrefsData { bloom?: boolean; colorGrading?: string; colorGradingIntensity?: number; - /** Depth-based camera blur (RuneScape-style DoF) */ + /** Depth-based camera blur (classic fantasy MMORPG-style DoF) */ depthBlur?: boolean; /** Depth blur intensity 0-1 */ depthBlurIntensity?: number; @@ -87,9 +87,9 @@ export class ClientInterface extends SystemBase { bloom: boolean = true; colorGrading: string = "none"; colorGradingIntensity: number = 1; - /** Depth-based camera blur (RuneScape-style DoF) - enabled by default */ + /** Depth-based camera blur (classic fantasy MMORPG-style DoF) - enabled by default */ depthBlur: boolean = true; - /** Depth blur intensity 0-1, default 0.85 for RuneScape-style heavy blur */ + /** Depth blur intensity 0-1, default 0.85 for classic fantasy MMORPG-style heavy blur */ depthBlurIntensity: number = 0.85; /** Depth blur focus distance in world units - how far before blur starts */ depthBlurDistance: number = 60; diff --git a/packages/shared/src/systems/client/ClientNetwork.ts b/packages/shared/src/systems/client/ClientNetwork.ts index 4e0cd0a3f..6dddb2403 100644 --- a/packages/shared/src/systems/client/ClientNetwork.ts +++ b/packages/shared/src/systems/client/ClientNetwork.ts @@ -319,7 +319,7 @@ export class ClientNetwork extends SystemBase { private maxSnapshots: number = 10; private extrapolationLimit: number = 500; // ms - // Tile-based interpolation for RuneScape-style movement + // Tile-based interpolation for classic fantasy MMORPG-style movement // Public to allow position sync on respawn/teleport public tileInterpolator: TileInterpolator = new TileInterpolator(); @@ -1803,7 +1803,7 @@ export class ClientNetwork extends SystemBase { // // This prevents race conditions where multiple systems fight over rotation. // TileInterpolator.setCombatRotation() will apply rotation when entity is standing still, - // and ignore it when moving (movement direction takes priority, OSRS-accurate). + // and ignore it when moving (movement direction takes priority, rules-accurate). const changesTyped = changes as Record; const { p, q, ...restChanges } = changesTyped; @@ -1818,7 +1818,7 @@ export class ClientNetwork extends SystemBase { // If TileInterpolator didn't apply it (entity moving), that's intentional // Movement direction wins over combat rotation while moving if (!applied) { - // Entity is moving - combat rotation ignored (OSRS-accurate) + // Entity is moving - combat rotation ignored (rules-accurate) } } @@ -2087,7 +2087,7 @@ export class ClientNetwork extends SystemBase { } // CRITICAL: Skip interpolation for dead mobs to prevent death animation sliding - // Dead mobs lock their position client-side for RuneScape-style stationary death + // Dead mobs lock their position client-side for classic fantasy MMORPG-style stationary death // Access entity.data directly instead of serialize() to avoid per-frame allocation if ((entity.data as { aiState?: string })?.aiState === "dead") { continue; // Don't interpolate - let MobEntity maintain locked death position @@ -3792,7 +3792,7 @@ export class ClientNetwork extends SystemBase { } /** - * Trade moved to confirmation screen (OSRS two-screen flow) + * Trade moved to confirmation screen (classic MMORPG two-screen flow) */ onTradeConfirmScreen = (data: { tradeId: string; @@ -3895,7 +3895,7 @@ export class ClientNetwork extends SystemBase { onEntityRemoved = (id: string) => { // Remove from interpolation tracking this.deleteInterpolationState(id); - // Remove from tile interpolation tracking (RuneScape-style movement) + // Remove from tile interpolation tracking (classic fantasy MMORPG-style movement) this.tileInterpolator.removeEntity(id); // Clean up pending modifications tracking - decrement count first const list = this.pendingModifications.get(id); @@ -3931,7 +3931,7 @@ export class ClientNetwork extends SystemBase { } | null; const collisionService = townSystem?.getCollisionService?.(); - // Update tile-based interpolation (RuneScape-style) + // Update tile-based interpolation (classic fantasy MMORPG-style) this.tileInterpolator.update( delta, (id: string) => { @@ -3998,7 +3998,7 @@ export class ClientNetwork extends SystemBase { }); }; - // OSRS-STYLE: Show gathering tool in hand during gathering (e.g., fishing rod) + // classic MMORPG-STYLE: Show gathering tool in hand during gathering (e.g., fishing rod) onGatheringToolShow = (data: { playerId: string; itemId: string; @@ -4899,7 +4899,7 @@ export class ClientNetwork extends SystemBase { }); }; - // ==== Tile Movement Handlers (RuneScape-style) ==== + // ==== Tile Movement Handlers (classic fantasy MMORPG-style) ==== /** * Handle tile position update from server @@ -4955,7 +4955,7 @@ export class ClientNetwork extends SystemBase { /** * Handle movement path started * - * OSRS Model: Client receives FULL PATH and walks through it at fixed speed. + * classic MMORPG Model: Client receives FULL PATH and walks through it at fixed speed. * Server tick updates are for sync/verification only. */ onTileMovementStart = (data: { @@ -4978,7 +4978,7 @@ export class ClientNetwork extends SystemBase { // path: complete path from server (no client recalculation) // destinationTile: final target for verification // moveSeq: packet ordering to ignore stale packets - // emote: bundled animation (OSRS-style) + // emote: bundled animation (classic MMORPG-style) // tilesPerTick: mob-specific speed (for faster/slower mobs) this.tileInterpolator.onMovementStart( data.id, diff --git a/packages/shared/src/systems/client/DamageSplatSystem.ts b/packages/shared/src/systems/client/DamageSplatSystem.ts index c194d89f0..e32049741 100644 --- a/packages/shared/src/systems/client/DamageSplatSystem.ts +++ b/packages/shared/src/systems/client/DamageSplatSystem.ts @@ -1,8 +1,8 @@ /** - * DamageSplatSystem - RuneScape-style Damage Splats + * DamageSplatSystem - classic fantasy MMORPG-style Damage Splats * * Creates visual damage numbers (hit splats) that appear above entities when they take damage. - * Mimics Old School RuneScape's iconic damage feedback system. + * Mimics classic fantasy MMORPG's iconic damage feedback system. * * Features: * - Red splats for successful hits (damage > 0) @@ -16,7 +16,6 @@ * - Animates with fadeout and upward movement * - Auto-removes after animation completes * - * @see https://oldschool.runescape.wiki/w/Hitsplat - OSRS hitsplat mechanics and colors */ import * as THREE from "../../extras/three/three"; @@ -209,7 +208,7 @@ export class DamageSplatSystem extends System { // Clear canvas and redraw context.clearRect(0, 0, size, size); - // Draw OSRS-style hit splat + // Draw classic MMORPG-style hit splat const isHit = damage > 0; const bgColor = isHit ? "#8B0000" : "#000080"; // Dark red or dark blue const textColor = "#FFFFFF"; diff --git a/packages/shared/src/systems/client/DuelArenaVisualsSystem.ts b/packages/shared/src/systems/client/DuelArenaVisualsSystem.ts index ce4e9e641..f3c8ebe74 100644 --- a/packages/shared/src/systems/client/DuelArenaVisualsSystem.ts +++ b/packages/shared/src/systems/client/DuelArenaVisualsSystem.ts @@ -14,7 +14,7 @@ * Performance: ~22 draw calls via InstancedMesh (down from ~846 individual meshes). * All 28 PointLights replaced with GPU-animated TSL emissive brazier materials. * - * Arena Layout (OSRS-style): + * Arena Layout (classic MMORPG-style): * - 6 rectangular arenas in a 2x3 grid * - Each arena is 20m wide x 24m long * - 4m gap between arenas diff --git a/packages/shared/src/systems/client/DuelCountdownSplatSystem.ts b/packages/shared/src/systems/client/DuelCountdownSplatSystem.ts index 775022cf8..b8e67c920 100644 --- a/packages/shared/src/systems/client/DuelCountdownSplatSystem.ts +++ b/packages/shared/src/systems/client/DuelCountdownSplatSystem.ts @@ -38,7 +38,7 @@ interface SplatPoolItem { active: boolean; } -// Color coding for countdown numbers (OSRS-style) +// Color coding for countdown numbers (classic MMORPG-style) const COUNT_COLORS: Record = { 3: "#ff4444", // Red 2: "#ff8800", // Orange diff --git a/packages/shared/src/systems/client/EquipmentVisualSystem.ts b/packages/shared/src/systems/client/EquipmentVisualSystem.ts index c7d3b0972..e5f029a3d 100644 --- a/packages/shared/src/systems/client/EquipmentVisualSystem.ts +++ b/packages/shared/src/systems/client/EquipmentVisualSystem.ts @@ -195,7 +195,7 @@ export class EquipmentVisualSystem extends SystemBase { }, ); - // OSRS-STYLE: Show gathering tool during gathering (e.g., fishing rod during fishing) + // classic MMORPG-STYLE: Show gathering tool during gathering (e.g., fishing rod during fishing) this.subscribe( EventType.GATHERING_TOOL_SHOW, (data: { playerId: string; itemId: string; slot: string }) => { @@ -211,7 +211,7 @@ export class EquipmentVisualSystem extends SystemBase { }, ); - // OSRS-STYLE: Hide melee weapon during magic/ranged attacks + // classic MMORPG-STYLE: Hide melee weapon during magic/ranged attacks this.subscribe( EventType.COMBAT_PROJECTILE_LAUNCHED, (data: { attackerId: string }) => { @@ -435,7 +435,7 @@ export class EquipmentVisualSystem extends SystemBase { } /** - * OSRS-STYLE: Hide melee weapon during magic/ranged attacks. + * classic MMORPG-STYLE: Hide melee weapon during magic/ranged attacks. * * When a non-melee projectile is launched, the attacker's equipped melee weapon * should be hidden for the duration of the attack animation. Staffs and bows @@ -509,7 +509,7 @@ export class EquipmentVisualSystem extends SystemBase { } /** - * OSRS-STYLE: Show gathering tool in hand during gathering animation + * classic MMORPG-STYLE: Show gathering tool in hand during gathering animation * (e.g., fishing rod appears in hand even though it's in inventory, not equipped) * * This temporarily hides any equipped weapon and shows the gathering tool instead. @@ -549,7 +549,7 @@ export class EquipmentVisualSystem extends SystemBase { } const equipment = this.playerEquipment.get(playerId)!; - // OSRS-STYLE: Temporarily hide the equipped weapon while showing gathering tool + // classic MMORPG-STYLE: Temporarily hide the equipped weapon while showing gathering tool // Check hiddenWeapons to prevent hiding multiple times on rapid calls if ( equipment.weapon && @@ -596,7 +596,7 @@ export class EquipmentVisualSystem extends SystemBase { // Remove the gathering tool visual this.unequipVisual(playerId, "gatheringTool", equipment, vrm); - // OSRS-STYLE: Restore the equipped weapon that was hidden + // classic MMORPG-STYLE: Restore the equipped weapon that was hidden // Verify weapon exists and is currently hidden before restoring if ( this.hiddenWeapons.has(playerId) && diff --git a/packages/shared/src/systems/client/HealthBars.ts b/packages/shared/src/systems/client/HealthBars.ts index f2e5b7022..a68f25ff9 100644 --- a/packages/shared/src/systems/client/HealthBars.ts +++ b/packages/shared/src/systems/client/HealthBars.ts @@ -4,7 +4,7 @@ * Renders health bars for all entities (players and mobs) using a single * instanced mesh for optimal performance with TSL Node Materials. * - * Names are shown in right-click context menus only (OSRS pattern). + * Names are shown in right-click context menus only (classic MMORPG pattern). * * @see HealthBarRenderer for the drawing logic */ diff --git a/packages/shared/src/systems/client/ResourceTileDebugSystem.ts b/packages/shared/src/systems/client/ResourceTileDebugSystem.ts index 7f9520d97..a8eb10c2b 100644 --- a/packages/shared/src/systems/client/ResourceTileDebugSystem.ts +++ b/packages/shared/src/systems/client/ResourceTileDebugSystem.ts @@ -4,7 +4,7 @@ * Client-side debug visualization for resource tile occupancy. * Shows red ground planes for tiles that resources occupy. * - * OSRS-ACCURACY: Resources occupy specific tiles based on their footprint: + * RULES ACCURACY: Resources occupy specific tiles based on their footprint: * - standard (1×1): Single tile * - large (2×2): Four tiles from anchor (SW corner) * - massive (3×3): Nine tiles from anchor diff --git a/packages/shared/src/systems/client/TileInterpolator.ts b/packages/shared/src/systems/client/TileInterpolator.ts index 48e66a74e..7cd655b23 100644 --- a/packages/shared/src/systems/client/TileInterpolator.ts +++ b/packages/shared/src/systems/client/TileInterpolator.ts @@ -1,7 +1,7 @@ /** - * Tile Interpolator - RuneScape-Style Movement + * Tile Interpolator - classic fantasy MMORPG-Style Movement * - * OSRS Movement Model (from research): + * classic MMORPG Movement Model (from research): * 1. Server calculates full BFS path * 2. Server sends FULL PATH to client in tileMovementStart * 3. Client walks through path at FIXED SPEED (doesn't wait for individual updates) @@ -177,7 +177,7 @@ interface EntityMovementState { } /** - * Client-side tile interpolator using OSRS's full-path prediction model + * Client-side tile interpolator using classic MMORPG's full-path prediction model * * The client receives the full path and walks through it at fixed speed. * Server updates are used for verification/sync only, not for driving movement. @@ -316,7 +316,7 @@ export class TileInterpolator { * @param startTile Server's authoritative starting tile (where server knows entity IS) * @param destinationTile Final target tile for verification * @param moveSeq Movement sequence number for packet ordering - * @param emote Optional emote bundled with movement (OSRS-style) + * @param emote Optional emote bundled with movement (classic MMORPG-style) * @param tilesPerTick Optional per-entity speed (tiles per server tick) */ onMovementStart( @@ -429,7 +429,7 @@ export class TileInterpolator { // Calculate rotation to face DESTINATION (not first tile in path) // When spam clicking, server's path starts from its known position which may be // behind the client's visual position. Using first tile could cause facing backward. - // Instead, face the destination - this matches OSRS behavior (face where you clicked). + // Instead, face the destination - this matches classic MMORPG behavior (face where you clicked). const firstTileWorld = tileToWorld(finalPath[0]); const rotationTargetTile = destinationTile || finalPath[finalPath.length - 1]; @@ -1453,7 +1453,7 @@ export class TileInterpolator { // Mark entity as controlled by tile interpolator to prevent other systems from overwriting entity.data.tileInterpolatorControlled = true; // Expose isMoving so PlayerLocal/PlayerRemote can check for combat rotation - // OSRS behavior: only face combat target when standing still, not while moving + // classic MMORPG behavior: only face combat target when standing still, not while moving entity.data.tileMovementActive = state.isMoving; // Set rotation: Use base for players (VRM has 180° rotation baked in), // fall back to node for mobs/other entities that don't have base @@ -1551,7 +1551,7 @@ export class TileInterpolator { * 2. Entity is NOT currently moving (standing still in combat) * * Combat rotation is now applied even during movement - the entity will - * face their combat target while moving (OSRS PvP behavior). + * face their combat target while moving (classic MMORPG PvP behavior). * * @param entityId - Entity to update * @param quaternion - Combat rotation as [x, y, z, w] array or THREE.Quaternion @@ -1606,7 +1606,7 @@ export class TileInterpolator { } // Apply combat rotation ONLY if not currently moving - // Movement direction takes priority over combat rotation (OSRS-accurate) + // Movement direction takes priority over combat rotation (rules-accurate) if (state.isMoving) { return false; // Ignored while moving } diff --git a/packages/shared/src/systems/client/XPDropSystem.ts b/packages/shared/src/systems/client/XPDropSystem.ts index 0a8feb8cc..4815c961b 100644 --- a/packages/shared/src/systems/client/XPDropSystem.ts +++ b/packages/shared/src/systems/client/XPDropSystem.ts @@ -1,8 +1,8 @@ /** - * XPDropSystem - RuneScape 3-style XP Drops + * XPDropSystem - modern fantasy MMORPG-style XP Drops * * Creates visual XP numbers that float up from the player when experience is gained. - * Mimics RuneScape 3's iconic XP drop feedback system. + * Mimics modern fantasy MMORPG's iconic XP drop feedback system. * * Features: * - Gold/yellow XP text with skill icon diff --git a/packages/shared/src/systems/client/interaction/InteractionRouter.ts b/packages/shared/src/systems/client/interaction/InteractionRouter.ts index 039598f92..4ceb30f3f 100644 --- a/packages/shared/src/systems/client/interaction/InteractionRouter.ts +++ b/packages/shared/src/systems/client/interaction/InteractionRouter.ts @@ -99,7 +99,7 @@ export class InteractionRouter extends System { private lastHoverTime = 0; private static readonly HOVER_THROTTLE_MS = 50; - // Targeting mode state (OSRS "Use X on Y") + // Targeting mode state (classic MMORPG "Use X on Y") private targetingMode: TargetingModeState = { active: false, sourceItem: null, @@ -282,7 +282,7 @@ export class InteractionRouter extends System { // This is critical for accurate item pickup (range 0 actions) this.world.on(EventType.ENTITY_MODIFIED, this.onEntityModified); - // Listen for targeting mode events (OSRS "Use X on Y") + // Listen for targeting mode events (classic MMORPG "Use X on Y") this.world.on(EventType.TARGETING_START, this.onTargetingStart); this.world.on(EventType.TARGETING_COMPLETE, this.onTargetingComplete); this.world.on(EventType.TARGETING_CANCEL, this.onTargetingCancel); @@ -364,7 +364,7 @@ export class InteractionRouter extends System { this.canvas, ); - // OSRS-style targeting mode: handle world entity clicks for cooking + // classic MMORPG-style targeting mode: handle world entity clicks for cooking if (this.targetingMode.active) { event.preventDefault(); @@ -990,7 +990,7 @@ export class InteractionRouter extends System { * When player becomes "idle" (movement finished), check queued actions * using the server-authoritative position for accurate range checking. * - * This is the OSRS-style pattern for reliable item pickup: + * This is the classic MMORPG-style pattern for reliable item pickup: * - Server sends final position in changes.p * - We use that exact position to check if player reached the item * - No reliance on interpolated client position @@ -1357,7 +1357,7 @@ export class InteractionRouter extends System { return false; } - // === Targeting Mode (OSRS "Use X on Y") === + // === Targeting Mode (classic MMORPG "Use X on Y") === /** * Enter targeting mode when player uses an item. diff --git a/packages/shared/src/systems/client/interaction/constants.ts b/packages/shared/src/systems/client/interaction/constants.ts index d426a4d54..50551b8ea 100644 --- a/packages/shared/src/systems/client/interaction/constants.ts +++ b/packages/shared/src/systems/client/interaction/constants.ts @@ -13,7 +13,7 @@ /** * Interaction ranges in tiles (using Chebyshev/max-distance) * - * OSRS uses tile-based ranges where diagonal counts as 1 tile. + * classic MMORPG uses tile-based ranges where diagonal counts as 1 tile. * Range 0 = must stand ON the tile (items) * Range 1 = adjacent tile (most interactions) */ @@ -55,7 +55,7 @@ export const TIMING = { RESOURCE_DEBOUNCE_MS: 1000, /** Mobile long-press duration to trigger context menu */ LONG_PRESS_MS: 500, - /** How long click indicator stays visible (RS3 style) */ + /** How long click indicator stays visible (modern MMORPG style) */ CLICK_INDICATOR_MS: 300, /** Max time to wait for player to reach target (auto-cancel) */ ACTION_TIMEOUT_MS: 10000, @@ -67,7 +67,7 @@ export const TIMING = { * Visual feedback constants */ export const VISUAL = { - /** OSRS-style: disable tile target marker */ + /** classic MMORPG-style: disable tile target marker */ TARGET_MARKER_ENABLED: false, /** Target marker size as fraction of tile */ TARGET_MARKER_SCALE: 0.9, @@ -81,7 +81,7 @@ export const VISUAL = { CLICK_INDICATOR_MAX_SCALE: 0.8, /** Reference distance for indicator scaling */ CLICK_INDICATOR_REFERENCE_DISTANCE: 10, - /** Target marker color (yellow/gold like RuneScape) */ + /** Target marker color (yellow/gold like classic fantasy MMORPG) */ TARGET_MARKER_COLOR: 0xffff00, /** Yellow X color for ground clicks */ CLICK_INDICATOR_GROUND_COLOR: "#ffff00", @@ -145,7 +145,7 @@ export const ACTION_QUEUE = { * arrives at the same tile as the item, even with minor position differences. * * Value: 0.75 tiles = 75% of tile size, enough to cover tile center variations. - * OSRS uses exact tile matching, but our items can be visually offset. + * classic MMORPG uses exact tile matching, but our items can be visually offset. */ ITEM_PICKUP_TOLERANCE_TILES: 0.75, } as const; diff --git a/packages/shared/src/systems/client/interaction/handlers/AltarInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/AltarInteractionHandler.ts index bde208b1e..667c66c43 100644 --- a/packages/shared/src/systems/client/interaction/handlers/AltarInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/AltarInteractionHandler.ts @@ -3,21 +3,20 @@ * * Handles interactions with prayer altars. * - * OSRS Context Menu Format: " " with cyan target (scenery color) + * classic MMORPG Context Menu Format: " " with cyan target (scenery color) * - "Pray Altar" (cyan #00ffff for target) * - "Examine Altar" (cyan #00ffff for target) * * Regular altars only recharge prayer points to full. * Gilded altars (not implemented) would also offer bone burning with XP multipliers. * - * @see https://oldschool.runescape.wiki/w/Altar for OSRS altar mechanics */ import { BaseInteractionHandler } from "./BaseInteractionHandler"; import type { RaycastTarget, ContextMenuAction } from "../types"; import { INTERACTION_RANGE, MESSAGE_TYPES } from "../constants"; -/** OSRS scenery/object color (cyan) for context menu target names */ +/** classic MMORPG scenery/object color (cyan) for context menu target names */ const SCENERY_COLOR = "#00ffff"; export class AltarInteractionHandler extends BaseInteractionHandler { @@ -31,7 +30,7 @@ export class AltarInteractionHandler extends BaseInteractionHandler { /** * Right-click: Show altar options * - * OSRS-accurate format: + * rules-accurate format: * - "Pray Altar" (action white, target cyan) * - "Examine Altar" (action white, target cyan) */ @@ -39,7 +38,7 @@ export class AltarInteractionHandler extends BaseInteractionHandler { const actions: ContextMenuAction[] = []; const targetName = target.name || "Altar"; - // Pray action (primary) - OSRS: "Pray Altar" + // Pray action (primary) - classic MMORPG: "Pray Altar" actions.push({ id: "pray-altar", label: `Pray ${targetName}`, @@ -52,7 +51,7 @@ export class AltarInteractionHandler extends BaseInteractionHandler { handler: () => this.prayAtAltar(target), }); - // Examine - OSRS: "Examine Altar" + // Examine - classic MMORPG: "Examine Altar" actions.push({ id: "examine", label: `Examine ${targetName}`, diff --git a/packages/shared/src/systems/client/interaction/handlers/BankInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/BankInteractionHandler.ts index e48954fc3..ca07ef85a 100644 --- a/packages/shared/src/systems/client/interaction/handlers/BankInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/BankInteractionHandler.ts @@ -3,21 +3,20 @@ * * Handles interactions with bank objects (booths, chests, etc.). * - * OSRS Context Menu Format: " " with cyan target (scenery color) + * classic MMORPG Context Menu Format: " " with cyan target (scenery color) * - "Bank Bank booth" / "Bank Bank chest" (cyan #00ffff for target) * - "Examine Bank booth" (cyan #00ffff for target) * * Note: Bank NPCs (clerks) are handled by NPCInteractionHandler. * This handler is for bank objects/furniture only. * - * @see https://oldschool.runescape.wiki/w/Choose_Option for OSRS menu format */ import { BaseInteractionHandler } from "./BaseInteractionHandler"; import type { RaycastTarget, ContextMenuAction } from "../types"; import { INTERACTION_RANGE, MESSAGE_TYPES } from "../constants"; -/** OSRS scenery/object color (cyan) for context menu target names */ +/** classic MMORPG scenery/object color (cyan) for context menu target names */ const SCENERY_COLOR = "#00ffff"; export class BankInteractionHandler extends BaseInteractionHandler { @@ -31,7 +30,7 @@ export class BankInteractionHandler extends BaseInteractionHandler { /** * Right-click: Show bank options * - * OSRS-accurate format: + * rules-accurate format: * - "Bank Bank booth" (action white, target cyan) * - "Examine Bank booth" (action white, target cyan) */ @@ -39,7 +38,7 @@ export class BankInteractionHandler extends BaseInteractionHandler { const actions: ContextMenuAction[] = []; const targetName = target.name || "Bank booth"; - // Bank action (primary) - OSRS: "Bank Bank booth" + // Bank action (primary) - classic MMORPG: "Bank Bank booth" actions.push({ id: "use-bank", label: `Bank ${targetName}`, @@ -52,7 +51,7 @@ export class BankInteractionHandler extends BaseInteractionHandler { handler: () => this.openBank(target), }); - // Examine - OSRS: "Examine Bank booth" + // Examine - classic MMORPG: "Examine Bank booth" actions.push({ id: "examine", label: `Examine ${targetName}`, diff --git a/packages/shared/src/systems/client/interaction/handlers/BaseInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/BaseInteractionHandler.ts index 73aaf66ed..31ecda536 100644 --- a/packages/shared/src/systems/client/interaction/handlers/BaseInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/BaseInteractionHandler.ts @@ -123,7 +123,7 @@ export abstract class BaseInteractionHandler { if (footprint) { // Multi-tile entity: Check if player is in range of ANY occupied tile - // This enables OSRS-style interaction from any side of a 2x2 furnace, etc. + // This enables classic MMORPG-style interaction from any side of a 2x2 furnace, etc. inRange = tilesWithinRangeOfFootprint( playerTile, targetTile, @@ -159,7 +159,7 @@ export abstract class BaseInteractionHandler { if (params.range === 0) { // Range 0 (items): Walk directly TO the target's tile - // OSRS behavior: Must stand ON item to pick it up + // classic MMORPG behavior: Must stand ON item to pick it up const targetTileWorld = tileToWorld(targetTile); walkTarget = { x: targetTileWorld.x, @@ -168,7 +168,7 @@ export abstract class BaseInteractionHandler { }; } else { // Range 1+ (combat/resources): Walk to ADJACENT tile - // OSRS behavior: Can't attack from same tile as target + // classic MMORPG behavior: Can't attack from same tile as target walkTarget = this.getAdjacentCombatPosition( player.position, params.target.position, @@ -181,7 +181,7 @@ export abstract class BaseInteractionHandler { } /** - * Calculate the best adjacent tile for combat (OSRS-style) + * Calculate the best adjacent tile for combat (classic MMORPG-style) * * Finds a tile that is: * 1. Within combat range of the target (but not same tile) @@ -277,7 +277,7 @@ export abstract class BaseInteractionHandler { /** * Show examine message (common to all entities) * - * Displays as toast and adds to chat log (OSRS-style). + * Displays as toast and adds to chat log (classic MMORPG-style). */ protected showExamineMessage(message: string): void { // Show toast notification @@ -286,7 +286,7 @@ export abstract class BaseInteractionHandler { type: "info", }); - // Add to chat (OSRS-style game message with no sender) + // Add to chat (classic MMORPG-style game message with no sender) this.addChatMessage(message); } diff --git a/packages/shared/src/systems/client/interaction/handlers/BuildingSignInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/BuildingSignInteractionHandler.ts index 7d5becfb9..2633d1bde 100644 --- a/packages/shared/src/systems/client/interaction/handlers/BuildingSignInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/BuildingSignInteractionHandler.ts @@ -4,7 +4,7 @@ * Handles interactions with hanging signs on building facades. * Players can read the sign to see the building name and type. * - * OSRS Context Menu Format: " " with cyan target (scenery color) + * classic MMORPG Context Menu Format: " " with cyan target (scenery color) * - "Read Sign" (cyan #00ffff for target) * - "Examine Sign" (cyan #00ffff for target) */ @@ -14,7 +14,7 @@ import type { RaycastTarget, ContextMenuAction } from "../types"; import { INTERACTION_RANGE } from "../constants"; import { EventType } from "../../../../types/events/event-types"; -/** OSRS scenery/object color (cyan) for context menu target names */ +/** classic MMORPG scenery/object color (cyan) for context menu target names */ const SCENERY_COLOR = "#00ffff"; /** Human-readable building type names */ diff --git a/packages/shared/src/systems/client/interaction/handlers/CookingSourceInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/CookingSourceInteractionHandler.ts index ee911e802..bde179164 100644 --- a/packages/shared/src/systems/client/interaction/handlers/CookingSourceInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/CookingSourceInteractionHandler.ts @@ -3,7 +3,7 @@ * * Handles interactions with cooking sources (fires and ranges). * - * OSRS Context Menu Format: " " with cyan target (scenery color) + * classic MMORPG Context Menu Format: " " with cyan target (scenery color) * - "Cook Fire" / "Cook Range" (cyan #00ffff for target) * - "Walk here" * - "Examine Fire" / "Examine Range" (cyan #00ffff for target) @@ -11,7 +11,6 @@ * When player is in targeting mode with raw food, clicking a fire/range * will trigger the cooking request. * - * @see https://oldschool.runescape.wiki/w/Choose_Option for OSRS menu format */ import { BaseInteractionHandler } from "./BaseInteractionHandler"; @@ -19,7 +18,7 @@ import type { RaycastTarget, ContextMenuAction } from "../types"; import { INTERACTION_RANGE } from "../constants"; import { EventType } from "../../../../types/events/event-types"; -/** OSRS scenery/object color (cyan) for context menu target names */ +/** classic MMORPG scenery/object color (cyan) for context menu target names */ const SCENERY_COLOR = "#00ffff"; /** @@ -63,7 +62,7 @@ export class CookingSourceInteractionHandler extends BaseInteractionHandler { /** * Right-click: Show Cook action and other options * - * OSRS-accurate format: + * rules-accurate format: * - "Cook Fire" / "Cook Range" (action white, target cyan) * - "Walk here" * - "Examine Fire" / "Examine Range" (action white, target cyan) @@ -77,7 +76,7 @@ export class CookingSourceInteractionHandler extends BaseInteractionHandler { const targetName = target.name || (sourceType === "range" ? "Range" : "Fire"); - // Cook action (primary) - OSRS: "Cook Fire" or "Cook Range" + // Cook action (primary) - classic MMORPG: "Cook Fire" or "Cook Range" actions.push({ id: "cook", label: `Cook ${targetName}`, @@ -100,7 +99,7 @@ export class CookingSourceInteractionHandler extends BaseInteractionHandler { // Walk here actions.push(this.createWalkHereAction(target)); - // Examine - OSRS: "Examine Fire" or "Examine Range" + // Examine - classic MMORPG: "Examine Fire" or "Examine Range" const examineText = this.getExamineText(entity, sourceType, isActive); actions.push({ id: "examine", diff --git a/packages/shared/src/systems/client/interaction/handlers/CorpseInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/CorpseInteractionHandler.ts index 2accacc64..992ece1f0 100644 --- a/packages/shared/src/systems/client/interaction/handlers/CorpseInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/CorpseInteractionHandler.ts @@ -3,7 +3,7 @@ * * Handles interactions with corpses and headstones/gravestones. * - * OSRS Context Menu Format: " " with cyan target (scenery color) + * classic MMORPG Context Menu Format: " " with cyan target (scenery color) * - "Loot Gravestone" (cyan #00ffff for "Gravestone") * - "Examine Gravestone" (cyan #00ffff) * @@ -11,14 +11,13 @@ * - Player death gravestones (reclaim items) * - Mob corpses (loot drops) * - * @see https://oldschool.runescape.wiki/w/Choose_Option for OSRS menu format */ import { BaseInteractionHandler } from "./BaseInteractionHandler"; import type { RaycastTarget, ContextMenuAction } from "../types"; import { INTERACTION_RANGE } from "../constants"; -/** OSRS scenery/object color (cyan) for context menu target names */ +/** classic MMORPG scenery/object color (cyan) for context menu target names */ const SCENERY_COLOR = "#00ffff"; /** Corpse/Headstone entity interface */ @@ -37,7 +36,7 @@ export class CorpseInteractionHandler extends BaseInteractionHandler { /** * Right-click: Show loot and examine options * - * OSRS-accurate format with cyan target names (scenery): + * rules-accurate format with cyan target names (scenery): * - "Loot Gravestone" (cyan for "Gravestone") * - "Examine Gravestone" (cyan) */ @@ -45,7 +44,7 @@ export class CorpseInteractionHandler extends BaseInteractionHandler { const actions: ContextMenuAction[] = []; const targetName = target.name || "Gravestone"; - // Loot action - OSRS: "Loot Gravestone" + // Loot action - classic MMORPG: "Loot Gravestone" actions.push({ id: "loot", label: `Loot ${targetName}`, @@ -58,7 +57,7 @@ export class CorpseInteractionHandler extends BaseInteractionHandler { handler: () => this.lootCorpse(target), }); - // Examine - OSRS: "Examine Gravestone" + // Examine - classic MMORPG: "Examine Gravestone" const examineText = `The remains of a ${targetName.toLowerCase()}.`; actions.push({ id: "examine", diff --git a/packages/shared/src/systems/client/interaction/handlers/ForfeitPillarInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/ForfeitPillarInteractionHandler.ts index c5bda7272..7c3aa450c 100644 --- a/packages/shared/src/systems/client/interaction/handlers/ForfeitPillarInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/ForfeitPillarInteractionHandler.ts @@ -4,7 +4,7 @@ * Handles interactions with forfeit pillars in the Duel Arena. * Players can click a pillar during an active duel to forfeit and surrender. * - * OSRS Context Menu Format: + * classic MMORPG Context Menu Format: * - "Forfeit Trapdoor" (primary action - only enabled during active duel) * - "Examine Trapdoor" * @@ -13,14 +13,13 @@ * - Disabled if the duel has "noForfeit" rule enabled * - Immediately ends the duel with the opponent as winner * - * @see https://oldschool.runescape.wiki/w/Duel_Arena for OSRS duel mechanics */ import { BaseInteractionHandler } from "./BaseInteractionHandler"; import type { RaycastTarget, ContextMenuAction } from "../types"; import { INTERACTION_RANGE, MESSAGE_TYPES } from "../constants"; -/** OSRS scenery/object color (cyan) for context menu target names */ +/** classic MMORPG scenery/object color (cyan) for context menu target names */ const SCENERY_COLOR = "#00ffff"; export class ForfeitPillarInteractionHandler extends BaseInteractionHandler { @@ -38,7 +37,7 @@ export class ForfeitPillarInteractionHandler extends BaseInteractionHandler { /** * Right-click: Show forfeit pillar options * - * OSRS-accurate format: + * rules-accurate format: * - "Forfeit Trapdoor" (action white, target cyan) - only if in duel * - "Examine Trapdoor" (action white, target cyan) */ diff --git a/packages/shared/src/systems/client/interaction/handlers/ItemInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/ItemInteractionHandler.ts index 954533738..70a50dabe 100644 --- a/packages/shared/src/systems/client/interaction/handlers/ItemInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/ItemInteractionHandler.ts @@ -3,17 +3,16 @@ * * Handles interactions with ground items. * - * OSRS Context Menu Format: " " with orange target (item color) + * classic MMORPG Context Menu Format: " " with orange target (item color) * - "Take Bones" (orange #ff9040 for "Bones") * - "Walk here" * - "Examine Bones" (orange #ff9040 for "Bones") * - * OSRS-Style Behavior: + * classic MMORPG-Style Behavior: * - Must stand ON the item's tile to pick it up (range 0) * - Left-click picks up highest value item in pile * - Context menu shows all items in pile * - * @see https://oldschool.runescape.wiki/w/Choose_Option for OSRS menu format */ import { BaseInteractionHandler } from "./BaseInteractionHandler"; @@ -63,7 +62,7 @@ export class ItemInteractionHandler extends BaseInteractionHandler { if (pileItems.length === 0) return; - // Find highest value item in pile (OSRS behavior) + // Find highest value item in pile (classic MMORPG behavior) const bestItem = pileItems.reduce( (best, item) => (item.value > best.value ? item : best), pileItems[0], @@ -75,7 +74,7 @@ export class ItemInteractionHandler extends BaseInteractionHandler { /** * Right-click: Show all items in pile * - * OSRS-accurate format with orange item names: + * rules-accurate format with orange item names: * - "Take Bones" (orange for "Bones") * - "Take Coins" (orange for "Coins") * - "Walk here" @@ -110,7 +109,7 @@ export class ItemInteractionHandler extends BaseInteractionHandler { } // Add "Take" for each item in pile (newest first = top of menu) - // OSRS: "Take Bones" with orange item name + // classic MMORPG: "Take Bones" with orange item name let priority = 1; for (const pileItem of pileItems) { actions.push({ @@ -129,7 +128,7 @@ export class ItemInteractionHandler extends BaseInteractionHandler { // Walk here actions.push(this.createWalkHereAction(target)); - // Examine for each item - OSRS: "Examine Bones" with orange item name + // Examine for each item - classic MMORPG: "Examine Bones" with orange item name for (const pileItem of pileItems) { const itemData = getItem(pileItem.itemId); const examineText = @@ -206,7 +205,7 @@ export class ItemInteractionHandler extends BaseInteractionHandler { } /** - * Get all item entities at a specific tile (OSRS-style pile query) + * Get all item entities at a specific tile (classic MMORPG-style pile query) * * Optimization: Tries GroundItemSystem O(1) lookup first (server-side), * falls back to O(n) entity iteration (client-side). diff --git a/packages/shared/src/systems/client/interaction/handlers/MobInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/MobInteractionHandler.ts index a98022efa..13d8670e1 100644 --- a/packages/shared/src/systems/client/interaction/handlers/MobInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/MobInteractionHandler.ts @@ -8,7 +8,7 @@ * - Walk here * - Examine * - * OSRS-Style Behavior: + * classic MMORPG-Style Behavior: * - Combat range based on equipped weapon * - Must be within range but NOT on same tile * - Tracks moving targets (mobs that wander) @@ -82,7 +82,7 @@ export class MobInteractionHandler extends BaseInteractionHandler { label: `Attack ${mobName} (Level: ${mobLevel})`, styledLabel: [ { text: "Attack " }, - { text: mobName, color: CONTEXT_MENU_COLORS.NPC }, // Yellow for mob names (OSRS style) + { text: mobName, color: CONTEXT_MENU_COLORS.NPC }, // Yellow for mob names (classic MMORPG style) { text: " (Level: " }, { text: `${mobLevel}`, color: levelColor }, { text: ")" }, @@ -95,7 +95,7 @@ export class MobInteractionHandler extends BaseInteractionHandler { // Walk here actions.push(this.createWalkHereAction(target)); - // Examine - OSRS: "Examine Goblin" + // Examine - classic MMORPG: "Examine Goblin" const examineText = this.getExamineText(target, mobData); actions.push({ id: "examine", @@ -151,7 +151,7 @@ export class MobInteractionHandler extends BaseInteractionHandler { } // Server-authoritative attack system: - // Send attack request immediately - server handles OSRS-style pathfinding + // Send attack request immediately - server handles classic MMORPG-style pathfinding // (cardinal-only melee range, path-to-adjacent tile) this.send(MESSAGE_TYPES.ATTACK_MOB, { mobId: target.entityId, @@ -174,7 +174,7 @@ export class MobInteractionHandler extends BaseInteractionHandler { /** * Get local player's combat level. * Used for relative color calculation (green/yellow/red). - * Falls back to 3 (OSRS minimum) if unknown. + * Falls back to 3 (classic MMORPG minimum) if unknown. * * Checks multiple property paths to handle different player entity types: * - PlayerRemote: has `combatLevel` getter @@ -220,7 +220,7 @@ export class MobInteractionHandler extends BaseInteractionHandler { return combat.combatLevel; } - // Fallback: OSRS minimum combat level + // Fallback: classic MMORPG minimum combat level return 3; } diff --git a/packages/shared/src/systems/client/interaction/handlers/NPCInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/NPCInteractionHandler.ts index a7ffcdb58..dd80e30c9 100644 --- a/packages/shared/src/systems/client/interaction/handlers/NPCInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/NPCInteractionHandler.ts @@ -3,7 +3,7 @@ * * Handles interactions with NPCs (non-hostile characters). * - * OSRS Context Menu Format: " " with yellow target (NPC color) + * classic MMORPG Context Menu Format: " " with yellow target (NPC color) * * Banker NPC: * - "Talk-to Banker" (yellow #ffff00 for "Banker") @@ -21,8 +21,6 @@ * - "store"/"shop" → Opens store interface * - (default) → Opens dialogue * - * @see https://oldschool.runescape.wiki/w/Choose_Option for OSRS menu format - * @see https://oldschool.runescape.wiki/w/Banker for banker info */ import { BaseInteractionHandler } from "./BaseInteractionHandler"; @@ -61,7 +59,7 @@ export class NPCInteractionHandler extends BaseInteractionHandler { /** * Right-click: Show all available actions * - * OSRS-accurate format with yellow NPC names: + * rules-accurate format with yellow NPC names: * - Banker: "Talk-to Banker", "Bank Banker", "Collect Banker" * - Shop: "Talk-to Shop keeper", "Trade Shop keeper" */ @@ -72,7 +70,7 @@ export class NPCInteractionHandler extends BaseInteractionHandler { const npcName = target.name || "NPC"; // Talk-to (always available, primary for most NPCs) - // OSRS: "Talk-to Banker" / "Talk-to Shop keeper" + // classic MMORPG: "Talk-to Banker" / "Talk-to Shop keeper" actions.push({ id: "talk", label: `Talk-to ${npcName}`, @@ -85,7 +83,7 @@ export class NPCInteractionHandler extends BaseInteractionHandler { handler: () => this.startDialogue(target), }); - // Bank service - OSRS: "Bank Banker" + // Bank service - classic MMORPG: "Bank Banker" if (services.includes("bank")) { actions.push({ id: "bank", @@ -99,7 +97,7 @@ export class NPCInteractionHandler extends BaseInteractionHandler { handler: () => this.openBank(target), }); - // Collect (Grand Exchange) - OSRS: "Collect Banker" + // Collect (Grand Exchange) - classic MMORPG: "Collect Banker" actions.push({ id: "collect", label: `Collect ${npcName}`, @@ -113,7 +111,7 @@ export class NPCInteractionHandler extends BaseInteractionHandler { }); } - // Store service - OSRS: "Trade Shop keeper" + // Store service - classic MMORPG: "Trade Shop keeper" if (services.includes("store") || services.includes("shop")) { actions.push({ id: "trade", @@ -131,7 +129,7 @@ export class NPCInteractionHandler extends BaseInteractionHandler { // Walk here actions.push(this.createWalkHereAction(target)); - // Examine - OSRS: "Examine Banker" / "Examine Shop keeper" + // Examine - classic MMORPG: "Examine Banker" / "Examine Shop keeper" const examineText = this.getExamineText(target, config); actions.push({ id: "examine", @@ -169,7 +167,7 @@ export class NPCInteractionHandler extends BaseInteractionHandler { /** * Collect items from Grand Exchange. - * In OSRS, bankers can access GE collection box. + * In classic MMORPG, bankers can access GE collection box. */ private collectFromGE(target: RaycastTarget): void { this.queueInteraction({ diff --git a/packages/shared/src/systems/client/interaction/handlers/PlayerInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/PlayerInteractionHandler.ts index c01f3e74a..5652dcf19 100644 --- a/packages/shared/src/systems/client/interaction/handlers/PlayerInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/PlayerInteractionHandler.ts @@ -1,9 +1,9 @@ /** * PlayerInteractionHandler * - * Handles interactions with other players (OSRS-accurate). + * Handles interactions with other players (rules-accurate). * - * Menu order (matches OSRS): + * Menu order (matches classic MMORPG): * 1. Attack PlayerName (Level: XX) - ONLY APPEARS in PvP zones (not shown elsewhere) * 2. Trade with PlayerName - disabled until trading implemented * 3. Follow PlayerName @@ -11,10 +11,9 @@ * 5. Walk here * 6. Examine * - * Note: Left-click on players does nothing by default (OSRS behavior). + * Note: Left-click on players does nothing by default (classic MMORPG behavior). * All player interactions require right-click context menu. * - * @see https://oldschool.runescape.wiki/w/Player_killing - Attack only in PvP areas */ import { BaseInteractionHandler } from "./BaseInteractionHandler"; @@ -26,7 +25,7 @@ import type { ZoneDetectionSystem } from "../../../shared/death/ZoneDetectionSys export class PlayerInteractionHandler extends BaseInteractionHandler { /** - * Left-click: Attack in active duel only (OSRS behavior) + * Left-click: Attack in active duel only (classic MMORPG behavior) * * In normal gameplay, players require right-click to interact. * Exception: During active duel combat, left-click attacks your opponent. @@ -41,7 +40,7 @@ export class PlayerInteractionHandler extends BaseInteractionHandler { } /** - * Right-click: Show player interaction options (OSRS order) + * Right-click: Show player interaction options (classic MMORPG order) * * Combat levels are colored based on relative level difference: * - Green: Target is lower level @@ -56,7 +55,7 @@ export class PlayerInteractionHandler extends BaseInteractionHandler { const inPvPZone = this.isInPvPZone(); const inActiveDuel = this.isInActiveDuelWith(target.entityId); - // 1. Attack (OSRS-accurate: only APPEARS in PvP zones OR during active duel) + // 1. Attack (rules-accurate: only APPEARS in PvP zones OR during active duel) if (inPvPZone || inActiveDuel) { actions.push({ id: "attack", @@ -237,7 +236,7 @@ export class PlayerInteractionHandler extends BaseInteractionHandler { /** * Get target player's combat level. - * Falls back to 3 (OSRS minimum) if unknown. + * Falls back to 3 (classic MMORPG minimum) if unknown. * * Checks multiple property paths to handle different player entity types: * - PlayerRemote: has `combatLevel` getter @@ -282,14 +281,14 @@ export class PlayerInteractionHandler extends BaseInteractionHandler { return combat.combatLevel; } - // Fallback: OSRS minimum combat level + // Fallback: classic MMORPG minimum combat level return 3; } /** * Get local player's combat level. * Used for relative color calculation (green/yellow/red). - * Falls back to 3 (OSRS minimum) if unknown. + * Falls back to 3 (classic MMORPG minimum) if unknown. * * Checks multiple property paths to handle different player entity types: * - PlayerRemote: has `combatLevel` getter @@ -335,7 +334,7 @@ export class PlayerInteractionHandler extends BaseInteractionHandler { return combat.combatLevel; } - // Fallback: OSRS minimum combat level + // Fallback: classic MMORPG minimum combat level return 3; } diff --git a/packages/shared/src/systems/client/interaction/handlers/ResourceInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/ResourceInteractionHandler.ts index 32e9d3fc9..11703fb8d 100644 --- a/packages/shared/src/systems/client/interaction/handlers/ResourceInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/ResourceInteractionHandler.ts @@ -1,9 +1,9 @@ /** * ResourceInteractionHandler * - * Handles interactions with gathering resources using OSRS-accurate context menus. + * Handles interactions with gathering resources using rules-accurate context menus. * - * OSRS Context Menu Format: " " with colored target + * classic MMORPG Context Menu Format: " " with colored target * * Resource types and their context menu formats: * - Trees → "Chop down Oak" (strips "Tree" suffix, cyan target - object color) @@ -15,7 +15,6 @@ * - Walk here * - Examine * - * @see https://oldschool.runescape.wiki/w/Choose_Option for OSRS menu format */ import { BaseInteractionHandler } from "./BaseInteractionHandler"; @@ -57,7 +56,7 @@ export class ResourceInteractionHandler extends BaseInteractionHandler { /** * Right-click: Show gather action and other options * - * OSRS-accurate context menu format: + * rules-accurate context menu format: * - Trees: "Chop down " (e.g., "Chop down Oak") * - Rocks: "Mine " (e.g., "Mine Copper rocks") * - Fishing: Multiple actions per spot (e.g., "Net Fishing spot", "Bait Fishing spot") @@ -76,7 +75,7 @@ export class ResourceInteractionHandler extends BaseInteractionHandler { resourceType.includes("ore") || resourceType.includes("mining") ) { - // OSRS: "Mine Copper rocks" with cyan target name (object color) + // classic MMORPG: "Mine Copper rocks" with cyan target name (object color) const rockName = this.getRockDisplayName(target); actions.push({ id: "mine", @@ -93,7 +92,7 @@ export class ResourceInteractionHandler extends BaseInteractionHandler { resourceType === "fishing_spot" || resourceType.includes("fish") ) { - // OSRS: Multiple actions - "Net Fishing spot", "Bait Fishing spot" + // classic MMORPG: Multiple actions - "Net Fishing spot", "Bait Fishing spot" const methods = this.getFishingMethods(entity); for (const method of methods) { actions.push({ @@ -109,7 +108,7 @@ export class ResourceInteractionHandler extends BaseInteractionHandler { }); } } else { - // Default: Trees - OSRS: "Chop down Oak" with cyan target name (object color) + // Default: Trees - classic MMORPG: "Chop down Oak" with cyan target name (object color) const treeName = this.getTreeDisplayName(target); actions.push({ id: "chop", @@ -271,14 +270,14 @@ export class ResourceInteractionHandler extends BaseInteractionHandler { } // ========================================================================== - // OSRS-ACCURATE DISPLAY NAME HELPERS + // RULES-ACCURATE DISPLAY NAME HELPERS // ========================================================================== /** - * Get OSRS-style tree display name. + * Get classic MMORPG-style tree display name. * Strips "Tree" suffix for named trees (Oak, Willow) but keeps it for basic trees. * - * OSRS Wiki object names: + * Reference object names: * - "Tree" (basic tree) * - "Oak" (not "Oak Tree") * - "Yew" (not "Yew Tree") @@ -292,7 +291,7 @@ export class ResourceInteractionHandler extends BaseInteractionHandler { return "Tree"; } - // "Magic Tree" -> "Magic tree" (OSRS uses lowercase 't') + // "Magic Tree" -> "Magic tree" (classic MMORPG uses lowercase 't') if (name.toLowerCase() === "magic tree") { return "Magic tree"; } @@ -306,10 +305,10 @@ export class ResourceInteractionHandler extends BaseInteractionHandler { } /** - * Get OSRS-style rock display name. + * Get classic MMORPG-style rock display name. * Converts "Copper Rock" -> "Copper rocks" (lowercase, plural). * - * OSRS Wiki object names: + * Reference object names: * - "Copper rocks" (not "Copper Rock") * - "Iron rocks" (not "Iron Rock") * - "Coal rocks" (not "Coal Rock") diff --git a/packages/shared/src/systems/client/interaction/handlers/RunecraftingAltarInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/RunecraftingAltarInteractionHandler.ts index 2086ae53b..1f4797d94 100644 --- a/packages/shared/src/systems/client/interaction/handlers/RunecraftingAltarInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/RunecraftingAltarInteractionHandler.ts @@ -3,7 +3,7 @@ * * Handles interactions with runecrafting altars. * - * OSRS Context Menu Format: " " with cyan target (scenery color) + * classic MMORPG Context Menu Format: " " with cyan target (scenery color) * - "Craft-rune Runecrafting Altar" (cyan #00ffff for target) * - "Walk here" * - "Examine Runecrafting Altar" (cyan #00ffff for target) @@ -11,14 +11,13 @@ * Left-click: Instantly send all essence for rune crafting. * Right-click: Context menu with Craft-rune and Examine. * - * @see https://oldschool.runescape.wiki/w/Runecrafting for OSRS mechanics */ import { BaseInteractionHandler } from "./BaseInteractionHandler"; import type { RaycastTarget, ContextMenuAction } from "../types"; import { INTERACTION_RANGE } from "../constants"; -/** OSRS scenery/object color (cyan) for context menu target names */ +/** classic MMORPG scenery/object color (cyan) for context menu target names */ const SCENERY_COLOR = "#00ffff"; export class RunecraftingAltarInteractionHandler extends BaseInteractionHandler { @@ -37,7 +36,7 @@ export class RunecraftingAltarInteractionHandler extends BaseInteractionHandler /** * Right-click: Show altar options * - * OSRS-accurate format: + * rules-accurate format: * - "Craft-rune Runecrafting Altar" (action white, target cyan) * - "Walk here" * - "Examine Runecrafting Altar" (action white, target cyan) diff --git a/packages/shared/src/systems/client/interaction/handlers/SignpostInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/SignpostInteractionHandler.ts index f4a732b43..ab541f8af 100644 --- a/packages/shared/src/systems/client/interaction/handlers/SignpostInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/SignpostInteractionHandler.ts @@ -3,7 +3,7 @@ * * Handles interactions with town signposts that show directions to nearby towns. * - * OSRS Context Menu Format: " " with cyan target (scenery color) + * classic MMORPG Context Menu Format: " " with cyan target (scenery color) * - "Read Signpost" (cyan #00ffff for target) * - "Examine Signpost" (cyan #00ffff for target) * @@ -16,7 +16,7 @@ import type { RaycastTarget, ContextMenuAction } from "../types"; import { INTERACTION_RANGE } from "../constants"; import { EventType } from "../../../../types/events/event-types"; -/** OSRS scenery/object color (cyan) for context menu target names */ +/** classic MMORPG scenery/object color (cyan) for context menu target names */ const SCENERY_COLOR = "#00ffff"; export class SignpostInteractionHandler extends BaseInteractionHandler { @@ -30,7 +30,7 @@ export class SignpostInteractionHandler extends BaseInteractionHandler { /** * Right-click: Show signpost options * - * OSRS-accurate format: + * rules-accurate format: * - "Read Signpost" (action white, target cyan) * - "Examine Signpost" (action white, target cyan) */ diff --git a/packages/shared/src/systems/client/interaction/handlers/SmeltingSourceInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/SmeltingSourceInteractionHandler.ts index d4bac919d..00399a116 100644 --- a/packages/shared/src/systems/client/interaction/handlers/SmeltingSourceInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/SmeltingSourceInteractionHandler.ts @@ -3,13 +3,11 @@ * * Handles interactions with furnaces for smelting ores into bars. * - * OSRS Context Menu Format: " " with cyan target (scenery color) + * classic MMORPG Context Menu Format: " " with cyan target (scenery color) * - "Smelt Furnace" (cyan #00ffff for "Furnace") * - "Walk here" * - "Examine Furnace" (cyan #00ffff for "Furnace") * - * @see https://oldschool.runescape.wiki/w/Choose_Option for OSRS menu format - * @see https://oldschool.runescape.wiki/w/Furnace for furnace info */ import { BaseInteractionHandler } from "./BaseInteractionHandler"; @@ -17,7 +15,7 @@ import type { RaycastTarget, ContextMenuAction } from "../types"; import { INTERACTION_RANGE } from "../constants"; import { EventType } from "../../../../types/events/event-types"; -/** OSRS scenery/object color (cyan) for context menu target names */ +/** classic MMORPG scenery/object color (cyan) for context menu target names */ const SCENERY_COLOR = "#00ffff"; /** @@ -48,7 +46,7 @@ export class SmeltingSourceInteractionHandler extends BaseInteractionHandler { /** * Right-click: Show Smelt action and other options * - * OSRS-accurate format: + * rules-accurate format: * - "Smelt Furnace" (action white, target cyan) * - "Walk here" * - "Examine Furnace" (action white, target cyan) @@ -57,7 +55,7 @@ export class SmeltingSourceInteractionHandler extends BaseInteractionHandler { const actions: ContextMenuAction[] = []; const targetName = target.name || "Furnace"; - // Smelt action (primary) - OSRS: "Smelt Furnace" + // Smelt action (primary) - classic MMORPG: "Smelt Furnace" actions.push({ id: "smelt", label: `Smelt ${targetName}`, @@ -100,7 +98,7 @@ export class SmeltingSourceInteractionHandler extends BaseInteractionHandler { // Walk here actions.push(this.createWalkHereAction(target)); - // Examine - OSRS: "Examine Furnace" + // Examine - classic MMORPG: "Examine Furnace" actions.push({ id: "examine", label: `Examine ${targetName}`, diff --git a/packages/shared/src/systems/client/interaction/handlers/SmithingSourceInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/SmithingSourceInteractionHandler.ts index f8cbdc20c..e84687962 100644 --- a/packages/shared/src/systems/client/interaction/handlers/SmithingSourceInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/SmithingSourceInteractionHandler.ts @@ -3,15 +3,13 @@ * * Handles interactions with anvils for smithing bars into items. * - * OSRS Context Menu Format: " " with cyan target (scenery color) + * classic MMORPG Context Menu Format: " " with cyan target (scenery color) * - "Smith Anvil" (cyan #00ffff for "Anvil") * - "Walk here" * - "Examine Anvil" (cyan #00ffff for "Anvil") * * Note: Player needs a hammer in inventory to smith. * - * @see https://oldschool.runescape.wiki/w/Choose_Option for OSRS menu format - * @see https://oldschool.runescape.wiki/w/Anvil for anvil info */ import { BaseInteractionHandler } from "./BaseInteractionHandler"; @@ -19,7 +17,7 @@ import type { RaycastTarget, ContextMenuAction } from "../types"; import { INTERACTION_RANGE } from "../constants"; import { EventType } from "../../../../types/events/event-types"; -/** OSRS scenery/object color (cyan) for context menu target names */ +/** classic MMORPG scenery/object color (cyan) for context menu target names */ const SCENERY_COLOR = "#00ffff"; /** @@ -50,7 +48,7 @@ export class SmithingSourceInteractionHandler extends BaseInteractionHandler { /** * Right-click: Show Smith action and other options * - * OSRS-accurate format: + * rules-accurate format: * - "Smith Anvil" (action white, target cyan) * - "Walk here" * - "Examine Anvil" (action white, target cyan) @@ -59,7 +57,7 @@ export class SmithingSourceInteractionHandler extends BaseInteractionHandler { const actions: ContextMenuAction[] = []; const targetName = target.name || "Anvil"; - // Smith action (primary) - OSRS: "Smith Anvil" + // Smith action (primary) - classic MMORPG: "Smith Anvil" actions.push({ id: "smith", label: `Smith ${targetName}`, @@ -82,7 +80,7 @@ export class SmithingSourceInteractionHandler extends BaseInteractionHandler { // Walk here actions.push(this.createWalkHereAction(target)); - // Examine - OSRS: "Examine Anvil" + // Examine - classic MMORPG: "Examine Anvil" actions.push({ id: "examine", label: `Examine ${targetName}`, diff --git a/packages/shared/src/systems/client/interaction/handlers/StarterChestInteractionHandler.ts b/packages/shared/src/systems/client/interaction/handlers/StarterChestInteractionHandler.ts index ebe5e2611..5e26868e6 100644 --- a/packages/shared/src/systems/client/interaction/handlers/StarterChestInteractionHandler.ts +++ b/packages/shared/src/systems/client/interaction/handlers/StarterChestInteractionHandler.ts @@ -4,7 +4,7 @@ * Handles interactions with the starter chest that provides new players * with basic equipment (bronze tools, tinderbox, net, food). * - * OSRS Context Menu Format: " " with cyan target (scenery color) + * classic MMORPG Context Menu Format: " " with cyan target (scenery color) * - "Search Starter Chest" (cyan #00ffff for target) * - "Examine Starter Chest" (cyan #00ffff for target) */ @@ -13,7 +13,7 @@ import { BaseInteractionHandler } from "./BaseInteractionHandler"; import type { RaycastTarget, ContextMenuAction } from "../types"; import { INTERACTION_RANGE } from "../constants"; -/** OSRS scenery/object color (cyan) for context menu target names */ +/** classic MMORPG scenery/object color (cyan) for context menu target names */ const SCENERY_COLOR = "#00ffff"; export class StarterChestInteractionHandler extends BaseInteractionHandler { @@ -27,7 +27,7 @@ export class StarterChestInteractionHandler extends BaseInteractionHandler { /** * Right-click: Show chest options * - * OSRS-accurate format: + * rules-accurate format: * - "Search Starter Chest" (action white, target cyan) * - "Examine Starter Chest" (action white, target cyan) */ @@ -35,7 +35,7 @@ export class StarterChestInteractionHandler extends BaseInteractionHandler { const actions: ContextMenuAction[] = []; const targetName = target.name || "Starter Chest"; - // Search action (primary) - OSRS: "Search Starter Chest" + // Search action (primary) - classic MMORPG: "Search Starter Chest" actions.push({ id: "search-chest", label: `Search ${targetName}`, @@ -51,7 +51,7 @@ export class StarterChestInteractionHandler extends BaseInteractionHandler { // Walk here actions.push(this.createWalkHereAction(target)); - // Examine - OSRS: "Examine Starter Chest" + // Examine - classic MMORPG: "Examine Starter Chest" actions.push({ id: "examine", label: `Examine ${targetName}`, diff --git a/packages/shared/src/systems/client/interaction/index.ts b/packages/shared/src/systems/client/interaction/index.ts index a571c1ea1..d938bed03 100644 --- a/packages/shared/src/systems/client/interaction/index.ts +++ b/packages/shared/src/systems/client/interaction/index.ts @@ -1,7 +1,7 @@ /** * Interaction System * - * Production-quality interaction handling for OSRS-style gameplay. + * Production-quality interaction handling for classic MMORPG-style gameplay. * * This module provides a complete replacement for the legacy InteractionSystem: * - Frame-based action queue (replaces unreliable setTimeout) diff --git a/packages/shared/src/systems/client/interaction/services/ActionQueueService.ts b/packages/shared/src/systems/client/interaction/services/ActionQueueService.ts index b8362af2e..30d700c0b 100644 --- a/packages/shared/src/systems/client/interaction/services/ActionQueueService.ts +++ b/packages/shared/src/systems/client/interaction/services/ActionQueueService.ts @@ -3,7 +3,7 @@ * * Hybrid action queue using event-based AND frame-based detection. * - * OSRS-Style Pattern: + * classic MMORPG-Style Pattern: * 1. Player clicks entity far away * 2. Action queued with target position and required range * 3. Walk request sent to server @@ -22,7 +22,7 @@ * Frame-based polling allows us to track the moving target and recalculate * the walk path if needed. Event-based alone would miss mob movement. * - * This matches how OSRS handles interactions - items are picked up on + * This matches how classic MMORPG handles interactions - items are picked up on * arrival at the tile, while combat continuously tracks moving targets. */ @@ -54,7 +54,7 @@ export class ActionQueueService { /** * Queue an action to execute when player reaches range * - * Replaces any existing queued action (OSRS-style: new click cancels old action). + * Replaces any existing queued action (classic MMORPG-style: new click cancels old action). * * @returns The action ID for tracking */ @@ -78,11 +78,11 @@ export class ActionQueueService { queuedAtFrame: this.frameCount, maxWaitFrames: params.maxWaitFrames ?? ACTION_QUEUE.DEFAULT_TIMEOUT_FRAMES, - // OSRS-style: Track target tile to detect movement for following + // classic MMORPG-style: Track target tile to detect movement for following lastWalkTargetTile: initialTargetTile ? { x: initialTargetTile.x, z: initialTargetTile.z } : undefined, - // Multi-tile footprint for OSRS-style interaction from any adjacent tile + // Multi-tile footprint for classic MMORPG-style interaction from any adjacent tile footprint: params.footprint, }; @@ -178,7 +178,7 @@ export class ActionQueueService { let inRange: boolean; if (action.requiredRange === 0) { - // Range 0 (items): OSRS-accurate tile matching + // Range 0 (items): rules-accurate tile matching // Use world-space distance with tolerance to handle minor position offsets const dx = Math.abs(serverPosition.x - action.targetPosition.x); const dz = Math.abs(serverPosition.z - action.targetPosition.z); @@ -322,7 +322,7 @@ export class ActionQueueService { action.targetPosition.z, ); - // OSRS-style: If target moved to a different tile, re-pathfind to follow + // classic MMORPG-style: If target moved to a different tile, re-pathfind to follow // "if the clicked entity is an NPC or player, a new pathfinding attempt // will be started every tick, until a target tile can be found" if ( @@ -368,7 +368,7 @@ export class ActionQueueService { } /** - * Send walk request to follow a moving target (OSRS-style) + * Send walk request to follow a moving target (classic MMORPG-style) * Calculates adjacent tile position for combat range */ private sendFollowWalkRequest( diff --git a/packages/shared/src/systems/client/interaction/services/EntityHighlightService.ts b/packages/shared/src/systems/client/interaction/services/EntityHighlightService.ts index d2dcc014f..d0ebb204d 100644 --- a/packages/shared/src/systems/client/interaction/services/EntityHighlightService.ts +++ b/packages/shared/src/systems/client/interaction/services/EntityHighlightService.ts @@ -1,11 +1,11 @@ /** * EntityHighlightService * - * Manages RS3-style entity outline highlighting on mouse hover. + * Manages modern MMORPG-style entity outline highlighting on mouse hover. * Maps entity types to highlight colors and drives the post-processing * outline pass via the PostProcessingComposer. * - * Color scheme (RS3 defaults): + * Color scheme (modern MMORPG defaults): * - Yellow: Friendly NPCs * - Red: Attackable/hostile mobs * - Cyan: Interactable objects, resources, stations diff --git a/packages/shared/src/systems/client/interaction/services/RaycastService.ts b/packages/shared/src/systems/client/interaction/services/RaycastService.ts index 752955c75..f0b271ab2 100644 --- a/packages/shared/src/systems/client/interaction/services/RaycastService.ts +++ b/packages/shared/src/systems/client/interaction/services/RaycastService.ts @@ -657,7 +657,7 @@ export class RaycastService { * Get footprint for station entities (multi-tile objects like furnace, anvil, etc.) * * Returns footprint dimensions for entities that occupy multiple tiles. - * This enables OSRS-style interaction where players can interact from + * This enables classic MMORPG-style interaction where players can interact from * any tile adjacent to the entity's footprint, not just the center. * * @param entityType - The entity type diff --git a/packages/shared/src/systems/client/interaction/services/VisualFeedbackService.ts b/packages/shared/src/systems/client/interaction/services/VisualFeedbackService.ts index abb1876ca..e346d629f 100644 --- a/packages/shared/src/systems/client/interaction/services/VisualFeedbackService.ts +++ b/packages/shared/src/systems/client/interaction/services/VisualFeedbackService.ts @@ -2,7 +2,7 @@ * VisualFeedbackService * * Handles visual feedback for interactions: - * - RuneScape-style movement indicator (arrow + circle) + * - classic fantasy MMORPG-style movement indicator (arrow + circle) * - Click indicators for entity interactions (red X) * - Minimap destination sync * @@ -33,7 +33,7 @@ export class VisualFeedbackService { private activeClickIndicator: THREE.Sprite | null = null; private clickIndicatorTimeout: ReturnType | null = null; - // RuneScape-style movement indicator components + // classic fantasy MMORPG-style movement indicator components private movementIndicatorGroup: THREE.Group | null = null; private movementArrow: THREE.Group | null = null; private movementCircle: THREE.Mesh | null = null; @@ -82,7 +82,7 @@ export class VisualFeedbackService { } /** - * Create RuneScape-style movement indicator (V chevron + circle on tile) + * Create classic fantasy MMORPG-style movement indicator (V chevron + circle on tile) */ private createMovementIndicator(): void { const scene = this.world.stage?.scene; @@ -245,12 +245,12 @@ export class VisualFeedbackService { /** * Show click indicator at position - * For ground clicks: shows RuneScape-style arrow + circle + * For ground clicks: shows classic fantasy MMORPG-style arrow + circle * For entity clicks: shows red X marker */ showClickIndicator(position: Position3D, type: "ground" | "entity"): void { if (type === "ground") { - // Use RuneScape-style movement indicator for ground clicks + // Use classic fantasy MMORPG-style movement indicator for ground clicks this.showMovementIndicator(position); return; } @@ -308,7 +308,7 @@ export class VisualFeedbackService { } /** - * Show RuneScape-style movement indicator at position + * Show classic fantasy MMORPG-style movement indicator at position */ private showMovementIndicator(position: Position3D): void { if (!this.movementIndicatorGroup) return; diff --git a/packages/shared/src/systems/client/interaction/types.ts b/packages/shared/src/systems/client/interaction/types.ts index f5a073988..6cd52d1d4 100644 --- a/packages/shared/src/systems/client/interaction/types.ts +++ b/packages/shared/src/systems/client/interaction/types.ts @@ -95,7 +95,7 @@ export interface QueuedAction { maxWaitFrames: number; /** Last tile we sent a walk request toward (for following moving targets) */ lastWalkTargetTile?: { x: number; z: number }; - /** Optional footprint for multi-tile entities (enables OSRS-style interaction from any adjacent tile) */ + /** Optional footprint for multi-tile entities (enables classic MMORPG-style interaction from any adjacent tile) */ footprint?: EntityFootprint; } @@ -105,7 +105,7 @@ export interface QueuedAction { * Used for rich text rendering in context menus, such as * combat level colors (green/yellow/red based on relative level). * - * @see getCombatLevelColor for OSRS-accurate level coloring + * @see getCombatLevelColor for rules-accurate level coloring */ export interface LabelSegment { /** Text content of this segment */ @@ -178,6 +178,6 @@ export interface QueueActionParams { onCancel?: () => void; /** Optional max frames to wait (default from constants) */ maxWaitFrames?: number; - /** Optional footprint for multi-tile entities (enables OSRS-style interaction from any adjacent tile) */ + /** Optional footprint for multi-tile entities (enables classic MMORPG-style interaction from any adjacent tile) */ footprint?: EntityFootprint; } diff --git a/packages/shared/src/systems/client/interaction/utils/combatLevelColor.ts b/packages/shared/src/systems/client/interaction/utils/combatLevelColor.ts index 858cdf19f..823a232bc 100644 --- a/packages/shared/src/systems/client/interaction/utils/combatLevelColor.ts +++ b/packages/shared/src/systems/client/interaction/utils/combatLevelColor.ts @@ -1,19 +1,17 @@ /** * Combat Level Color Utility * - * OSRS-accurate combat level color calculation for context menus. + * rules-accurate combat level color calculation for context menus. * * Colors range from bright green (-10 or lower difference) through * yellow (same level) to bright red (+10 or higher difference). * - * @see https://oldschool.runescape.wiki/w/Combat_level - * @see https://oldschool.runescape.wiki/w/Choose_Option */ /** * Get the color for a combat level relative to the player's level. * - * OSRS color gradient: + * classic MMORPG color gradient: * - +10 or higher: #ff0000 (bright red) * - 0 (same level): #ffff00 (yellow) * - -10 or lower: #00ff00 (bright green) @@ -30,7 +28,7 @@ export function getCombatLevelColor( ): string { const diff = targetLevel - playerLevel; - // Clamp to -10 to +10 range (OSRS behavior) + // Clamp to -10 to +10 range (classic MMORPG behavior) const clampedDiff = Math.max(-10, Math.min(10, diff)); if (clampedDiff === 0) { diff --git a/packages/shared/src/systems/client/network/InterpolationEngine.ts b/packages/shared/src/systems/client/network/InterpolationEngine.ts index f9a7efcaa..64617e25c 100644 --- a/packages/shared/src/systems/client/network/InterpolationEngine.ts +++ b/packages/shared/src/systems/client/network/InterpolationEngine.ts @@ -222,7 +222,7 @@ export class InterpolationEngine { } // CRITICAL: Skip interpolation for dead mobs to prevent death animation sliding - // Dead mobs lock their position client-side for RuneScape-style stationary death + // Dead mobs lock their position client-side for classic fantasy MMORPG-style stationary death // Access entity.data directly (avoid entity.serialize() which copies all fields) const entityData = entity.data as { aiState?: string } | null | undefined; if (entityData?.aiState === "dead") { diff --git a/packages/shared/src/systems/server/__tests__/ServerRuntime.test.ts b/packages/shared/src/systems/server/__tests__/ServerRuntime.test.ts index f5b3f53ac..f8c1e2346 100644 --- a/packages/shared/src/systems/server/__tests__/ServerRuntime.test.ts +++ b/packages/shared/src/systems/server/__tests__/ServerRuntime.test.ts @@ -258,7 +258,7 @@ describe("ServerRuntime - Runtime Behavior (Documentation)", () => { it("should document: runtime ticks run at 2Hz (500ms interval)", () => { // The server runtime only drives lifecycle callbacks. - // OSRS-like game logic still runs in TickSystem at 600ms. + // classic MMORPG-like game logic still runs in TickSystem at 600ms. const runtimeTickRate = 2; // Hz const runtimeTickInterval = 1000 / runtimeTickRate; // ms expect(runtimeTickInterval).toBe(500); @@ -278,7 +278,7 @@ describe("ServerRuntime - Runtime Behavior (Documentation)", () => { it("should document: game logic still runs on TickSystem", () => { // ServerRuntime handles lifecycle callbacks; combat/AI remain on the - // separate OSRS-style TickSystem cadence. + // separate classic MMORPG-style TickSystem cadence. const tickSystemInterval = 600; // ms const runtimeInterval = 500; // ms diff --git a/packages/shared/src/systems/shared/character/BuryDelayManager.ts b/packages/shared/src/systems/shared/character/BuryDelayManager.ts index b09afd8eb..e99fa7f10 100644 --- a/packages/shared/src/systems/shared/character/BuryDelayManager.ts +++ b/packages/shared/src/systems/shared/character/BuryDelayManager.ts @@ -1,19 +1,18 @@ /** * BuryDelayManager - Manages bone burying cooldowns per player * - * Single Responsibility: Track and enforce bury delay timing (OSRS-accurate) + * Single Responsibility: Track and enforce bury delay timing (rules-accurate) * - * OSRS Mechanics: + * classic MMORPG Mechanics: * - Bone burying has 2-tick (1.2s) delay * - Player cannot bury again until delay expires * - Delay is per-player, not global * * Memory: Uses Map with automatic cleanup on player disconnect/death * - * @see https://oldschool.runescape.wiki/w/Bones */ -/** OSRS-accurate bury delay: 2 ticks = 1.2 seconds */ +/** rules-accurate bury delay: 2 ticks = 1.2 seconds */ const BURY_DELAY_TICKS = 2; export class BuryDelayManager { diff --git a/packages/shared/src/systems/shared/character/CoinPouchSystem.ts b/packages/shared/src/systems/shared/character/CoinPouchSystem.ts index 62267da92..a9d25473a 100644 --- a/packages/shared/src/systems/shared/character/CoinPouchSystem.ts +++ b/packages/shared/src/systems/shared/character/CoinPouchSystem.ts @@ -1,5 +1,5 @@ /** - * CoinPouchSystem - Manages player coin balances (OSRS-style Money Pouch) + * CoinPouchSystem - Manages player coin balances (classic MMORPG-style Money Pouch) * * Server-authoritative system that handles all coin operations: * - Adding coins (loot, store sales, trades) @@ -7,7 +7,7 @@ * - Querying coin balances * - Persisting to database * - * Coins are stored separately from inventory (like OSRS money pouch): + * Coins are stored separately from inventory (like classic MMORPG money pouch): * - Protected on death (coins stay with player) * - No slot usage * - Unlimited stacking @@ -33,7 +33,7 @@ import type { DatabaseSystem } from "../../../types/systems/system-interfaces"; const DEFAULT_STARTING_COINS = 100; /** Maximum coins a player can hold (prevent overflow) */ -const MAX_COINS = 2147483647; // Max 32-bit signed integer (OSRS cap) +const MAX_COINS = 2147483647; // Max 32-bit signed integer (classic MMORPG cap) /** * CoinPouchSystem - Manages player coin balances diff --git a/packages/shared/src/systems/shared/character/EatDelayManager.ts b/packages/shared/src/systems/shared/character/EatDelayManager.ts index 0787f30c3..93776bdd4 100644 --- a/packages/shared/src/systems/shared/character/EatDelayManager.ts +++ b/packages/shared/src/systems/shared/character/EatDelayManager.ts @@ -1,9 +1,9 @@ /** * EatDelayManager - Manages eating cooldowns per player * - * Single Responsibility: Track and enforce eat delay timing (OSRS-accurate) + * Single Responsibility: Track and enforce eat delay timing (rules-accurate) * - * OSRS Mechanics: + * classic MMORPG Mechanics: * - Standard food has 3-tick (1.8s) eat delay * - Player cannot eat again until delay expires * - Delay is per-player, not global diff --git a/packages/shared/src/systems/shared/character/EquipmentSystem.ts b/packages/shared/src/systems/shared/character/EquipmentSystem.ts index d2eb3df01..5d6fd2ec9 100644 --- a/packages/shared/src/systems/shared/character/EquipmentSystem.ts +++ b/packages/shared/src/systems/shared/character/EquipmentSystem.ts @@ -1168,7 +1168,7 @@ export class EquipmentSystem extends SystemBase { if (bonuses.defenseMagic) equipment.totalStats.magicDefense += bonuses.defenseMagic; - // Map per-style defence bonuses (OSRS combat triangle) + // Map per-style defence bonuses (classic MMORPG combat triangle) if (bonuses.defenseStab) equipment.totalStats.defenseStab += bonuses.defenseStab; if (bonuses.defenseSlash) @@ -1216,7 +1216,7 @@ export class EquipmentSystem extends SystemBase { return "weapon"; } - // OSRS-accurate: Check explicit equipSlot first (handles tools like hatchets/pickaxes) + // rules-accurate: Check explicit equipSlot first (handles tools like hatchets/pickaxes) // Tools have type: "tool" but equipSlot: "weapon" - they should be equipable if (itemData.equipSlot && itemData.equipSlot !== "2h") { return itemData.equipSlot; diff --git a/packages/shared/src/systems/shared/character/HealthRegenSystem.ts b/packages/shared/src/systems/shared/character/HealthRegenSystem.ts index af2c6bf04..4d9d01c52 100644 --- a/packages/shared/src/systems/shared/character/HealthRegenSystem.ts +++ b/packages/shared/src/systems/shared/character/HealthRegenSystem.ts @@ -1,8 +1,8 @@ /** - * HealthRegenSystem - Passive Health Regeneration (OSRS-style) + * HealthRegenSystem - Passive Health Regeneration (classic MMORPG-style) * * Server-authoritative system that handles passive health regeneration for all players. - * Implements OSRS-accurate mechanics using game ticks (600ms each): + * Implements rules-accurate mechanics using game ticks (600ms each): * - No regeneration while in combat * - 17 tick cooldown (10.2 seconds) after taking damage before regen starts * - Regenerates 1 HP every 100 ticks (60 seconds) when conditions are met @@ -195,7 +195,7 @@ export class HealthRegenSystem extends SystemBase { } /** - * Get last damage tick from entity (tick-based for OSRS accuracy) + * Get last damage tick from entity (tick-based for classic MMORPG accuracy) */ private getLastDamageTick(entity: unknown): number | null { if (!entity || typeof entity !== "object") return null; diff --git a/packages/shared/src/systems/shared/character/InventorySystem.ts b/packages/shared/src/systems/shared/character/InventorySystem.ts index be28092c3..82d7f3782 100644 --- a/packages/shared/src/systems/shared/character/InventorySystem.ts +++ b/packages/shared/src/systems/shared/character/InventorySystem.ts @@ -747,7 +747,7 @@ export class InventorySystem extends SystemBase { } const position = player.node.position; - // Use GroundItemSystem for proper pile management (OSRS-style) + // Use GroundItemSystem for proper pile management (classic MMORPG-style) const groundItems = this.world.getSystem("ground-items"); if (groundItems) { // Spawn through GroundItemSystem for tile-based pile management @@ -806,9 +806,9 @@ export class InventorySystem extends SystemBase { // Get all items that will be dropped (for logging) const droppedItemCount = inventory.items.length; - // Clear the inventory (RuneScape-style: all items go to gravestone) + // Clear the inventory (classic fantasy MMORPG-style: all items go to gravestone) inventory.items = []; - // NOTE: Coins are protected and remain in coin pouch (RuneScape-style) + // NOTE: Coins are protected and remain in coin pouch (classic fantasy MMORPG-style) // CRITICAL: Update UI by emitting inventory update event this.emitInventoryUpdate(playerID); @@ -976,7 +976,7 @@ export class InventorySystem extends SystemBase { return; } - // Check loot protection (OSRS: killer has 1 minute exclusivity on mob loot) + // Check loot protection (classic MMORPG: killer has 1 minute exclusivity on mob loot) const groundItems = this.world.getSystem("ground-items"); if (groundItems) { const currentTick = this.world.currentTick ?? 0; @@ -1083,9 +1083,9 @@ export class InventorySystem extends SystemBase { // NOTE: updateCoins() removed - now handled by CoinPouchSystem /** - * Move/swap items between inventory slots (OSRS-style) + * Move/swap items between inventory slots (classic MMORPG-style) * - * Implements OSRS-style SWAP behavior: + * Implements classic MMORPG-style SWAP behavior: * - If both slots have items: swap them * - If only source has item: move to destination * - If source is empty: no-op @@ -1175,7 +1175,7 @@ export class InventorySystem extends SystemBase { return; } - // OSRS-style swap + // classic MMORPG-style swap if (toItem) { // Both slots occupied - swap fromItem.slot = toSlot; @@ -2143,9 +2143,9 @@ export class InventorySystem extends SystemBase { const droppedItemCount = inventory.items.length; - // Clear the inventory (RuneScape-style: all items go to gravestone) + // Clear the inventory (classic fantasy MMORPG-style: all items go to gravestone) inventory.items = []; - // NOTE: Coins are protected and remain in coin pouch (RuneScape-style) + // NOTE: Coins are protected and remain in coin pouch (classic fantasy MMORPG-style) // CRITICAL: Update UI by emitting inventory update event this.emitInventoryUpdate(playerID); diff --git a/packages/shared/src/systems/shared/character/PlayerSystem.ts b/packages/shared/src/systems/shared/character/PlayerSystem.ts index 80e2be81b..771420159 100644 --- a/packages/shared/src/systems/shared/character/PlayerSystem.ts +++ b/packages/shared/src/systems/shared/character/PlayerSystem.ts @@ -17,7 +17,7 @@ * 5. PLAYER_LEAVE → Save final state to database * * **Attack Styles:** - * Manages RuneScape-style attack modes: + * Manages classic fantasy MMORPG-style attack modes: * - attack: +3 Attack XP per damage * - strength: +3 Strength XP per damage * - defense: +3 Defense XP per damage @@ -25,7 +25,7 @@ * - ranged: Ranged combat style * * **Combat Level:** - * Calculated from combat skills using RuneScape formula: + * Calculated from combat skills using classic fantasy MMORPG formula: * Base = 0.25 * (Defense + Constitution + floor(Ranged/2)) * Melee = 0.325 * (Attack + Strength) * Ranged = 0.325 * (Ranged * 1.5) @@ -93,10 +93,10 @@ export class PlayerSystem extends SystemBase { private saveInterval?: NodeJS.Timeout; private _tempVec3 = new THREE.Vector3(); - // Eat delay tracking (OSRS-accurate 3-tick cooldown) + // Eat delay tracking (rules-accurate 3-tick cooldown) private eatDelayManager = new EatDelayManager(); - // Bury delay tracking (OSRS-accurate 2-tick cooldown) + // Bury delay tracking (rules-accurate 2-tick cooldown) private buryDelayManager = new BuryDelayManager(); // Player spawn tracking (merged from PlayerSpawnSystem) @@ -143,7 +143,7 @@ export class PlayerSystem extends SystemBase { private playerAttackStyles = new Map(); private skillSaveTimers = new Map(); - // Auto-retaliate tracking (OSRS-style combat preference) + // Auto-retaliate tracking (classic MMORPG-style combat preference) /** Player auto-retaliate settings (Map lookup = O(1), no allocations) */ private playerAutoRetaliate = new Map(); private pendingSkillUpdates = new Map(); @@ -151,8 +151,7 @@ export class PlayerSystem extends SystemBase { private autoRetaliateLastToggle = new Map(); private readonly AUTO_RETALIATE_COOLDOWN_MS = 500; // Max 2 toggles/second - // Attack styles - OSRS-accurate stat bonuses applied via CombatCalculations.getStyleBonus() - // @see https://oldschool.runescape.wiki/w/Combat_Options + // Attack styles - rules-accurate stat bonuses applied via CombatCalculations.getStyleBonus() private readonly ATTACK_STYLES: Record = { accurate: { id: "accurate", @@ -206,7 +205,7 @@ export class PlayerSystem extends SystemBase { icon: "⚖️", }, - // Ranged combat styles (OSRS-accurate) + // Ranged combat styles (rules-accurate) rapid: { id: "rapid", name: "Rapid", @@ -233,7 +232,7 @@ export class PlayerSystem extends SystemBase { icon: "🔭", }, - // Magic combat styles (OSRS-accurate) + // Magic combat styles (rules-accurate) autocast: { id: "autocast", name: "Autocast", @@ -358,7 +357,7 @@ export class PlayerSystem extends SystemBase { ), ); - // OSRS-accurate: auto-switch style when weapon changes and current style is invalid + // rules-accurate: auto-switch style when weapon changes and current style is invalid // Only subscribe on server — style changes are server-authoritative if (this.world.isServer) { this.subscribe(EventType.PLAYER_EQUIPMENT_CHANGED, (data) => { @@ -524,7 +523,7 @@ export class PlayerSystem extends SystemBase { // Load saved combat preferences from database if available let savedAttackStyle: string | undefined; - let savedAutoRetaliate = true; // Default ON (OSRS behavior) + let savedAutoRetaliate = true; // Default ON (classic MMORPG behavior) if (this.databaseSystem) { try { const databaseId = PlayerIdMapper.getDatabaseId(data.playerId); @@ -812,7 +811,7 @@ export class PlayerSystem extends SystemBase { ); player.health.current = player.health.max; } else { - // Floor to ensure health is always an integer (RuneScape-style) + // Floor to ensure health is always an integer (classic fantasy MMORPG-style) player.health.current = Math.floor( Math.max(0, Math.min(validCurrentHealth, player.health.max)), ); @@ -912,7 +911,7 @@ export class PlayerSystem extends SystemBase { return; } - // Apply damage - floor to ensure health is always an integer (RuneScape-style) + // Apply damage - floor to ensure health is always an integer (classic fantasy MMORPG-style) const newHealth = Math.floor( Math.max(0, player.health.current - data.damage), ); @@ -1071,7 +1070,7 @@ export class PlayerSystem extends SystemBase { if (!player || !player.alive) return false; const oldHealth = player.health.current; - // Floor to ensure health is always an integer (RuneScape-style) + // Floor to ensure health is always an integer (classic fantasy MMORPG-style) player.health.current = Math.floor( Math.min(player.health.max, player.health.current + amount), ); @@ -1090,13 +1089,13 @@ export class PlayerSystem extends SystemBase { } /** - * Handle food consumption with OSRS-accurate timing + * Handle food consumption with rules-accurate timing * * Implements: * - 3-tick (1.8s) eat delay between foods * - Attack delay when eating during combat * - OWASP input validation - * - OSRS-style chat message format + * - classic MMORPG-style chat message format */ private handleItemUsed(data: { playerId: string; @@ -1194,11 +1193,10 @@ export class PlayerSystem extends SystemBase { // NOTE: healPlayer() emits PLAYER_HEALTH_UPDATED only if health changed this.healPlayer(data.playerId, healAmount); - // OSRS Behavior: Message and attack delay ALWAYS apply when eating, + // classic MMORPG Behavior: Message and attack delay ALWAYS apply when eating, // even at full health. Food is consumed regardless. - // @see https://oldschool.runescape.wiki/w/Food - // OSRS-style message (lowercase item name, no heal amount shown) + // classic MMORPG-style message (lowercase item name, no heal amount shown) this.emitTypedEvent(EventType.UI_MESSAGE, { playerId: data.playerId, message: `You eat the ${itemData.name.toLowerCase()}.`, @@ -1210,9 +1208,9 @@ export class PlayerSystem extends SystemBase { } /** - * Apply attack delay when eating during combat (OSRS-accurate) + * Apply attack delay when eating during combat (rules-accurate) * - * OSRS Rule: Foods only add to EXISTING attack delay. + * classic MMORPG Rule: Foods only add to EXISTING attack delay. * If weapon is ready to attack, eating does NOT add delay. */ private applyEatAttackDelay(playerId: string, currentTick: number): void { @@ -1232,19 +1230,18 @@ export class PlayerSystem extends SystemBase { COMBAT_CONSTANTS.EAT_ATTACK_DELAY_TICKS, ); } - // If not on cooldown, do nothing (OSRS-accurate behavior) + // If not on cooldown, do nothing (rules-accurate behavior) } /** - * Handle bone burying for prayer XP (OSRS-accurate) + * Handle bone burying for prayer XP (rules-accurate) * - * OSRS Mechanics: + * classic MMORPG Mechanics: * - 2-tick (1.2s) delay between burials * - XP granted immediately upon bury * - Some bones require minimum prayer level * - Message: "You bury the bones." * - * @see https://oldschool.runescape.wiki/w/Bones */ private handleBoneBury( playerId: string, @@ -1302,7 +1299,7 @@ export class PlayerSystem extends SystemBase { }); } - // OSRS-style message + // classic MMORPG-style message this.emitTypedEvent(EventType.UI_MESSAGE, { playerId, message: "You bury the bones.", @@ -1455,7 +1452,7 @@ export class PlayerSystem extends SystemBase { ? player.health.current : player.health.max; - // Floor to ensure health is always an integer (RuneScape-style) + // Floor to ensure health is always an integer (classic fantasy MMORPG-style) player.health.current = Math.floor( Math.max(0, currentHealth - validAmount), ); @@ -1788,7 +1785,7 @@ export class PlayerSystem extends SystemBase { } private calculateCombatLevel(skills: Skills): number { - // OSRS Combat Level Formula: + // classic MMORPG Combat Level Formula: // base = 0.25 × (Defence + Hitpoints + floor(Prayer / 2)) // melee = 0.325 × (Attack + Strength) // ranged = 0.325 × floor(Ranged × 1.5) @@ -1907,7 +1904,7 @@ export class PlayerSystem extends SystemBase { return; } - // Validate style is allowed for equipped weapon (OSRS-accurate) + // Validate style is allowed for equipped weapon (rules-accurate) const weaponType = this.getPlayerWeaponType(playerId); if (!isStyleValidForWeapon(weaponType, newStyle as CombatStyleExtended)) { @@ -1950,7 +1947,7 @@ export class PlayerSystem extends SystemBase { } /** - * OSRS-accurate: When weapon changes, validate current style is still available. + * rules-accurate: When weapon changes, validate current style is still available. * If not, auto-switch to the first valid style for the new weapon type. * Example: switching from staff (autocast) to sword → auto-select "accurate" */ @@ -2299,7 +2296,7 @@ export class PlayerSystem extends SystemBase { } } - // Final fallback: default to true (OSRS behavior) + // Final fallback: default to true (classic MMORPG behavior) enabled = enabled ?? true; if (data.callback) { diff --git a/packages/shared/src/systems/shared/character/PrayerSystem.ts b/packages/shared/src/systems/shared/character/PrayerSystem.ts index 0c0e09e8e..7811583af 100644 --- a/packages/shared/src/systems/shared/character/PrayerSystem.ts +++ b/packages/shared/src/systems/shared/character/PrayerSystem.ts @@ -3,13 +3,13 @@ * * Server-authoritative system that handles all prayer operations: * - Activating/deactivating prayers - * - Prayer point drain mechanics (OSRS-accurate formula) + * - Prayer point drain mechanics (rules-accurate formula) * - Conflict resolution (auto-deactivate conflicting prayers) * - Level requirement validation * - Combat bonus calculations * - Database persistence * - * OSRS Prayer Drain Formula: + * classic MMORPG Prayer Drain Formula: * drain_resistance = 2 * prayer_bonus + 60 * drain_per_tick = drain_effect / drain_resistance (per 0.6s game tick) * @@ -67,7 +67,7 @@ interface MutablePrayerBonuses { // CONSTANTS // ============================================================================ -/** Game tick duration in ms (OSRS uses 600ms ticks) */ +/** Game tick duration in ms (classic MMORPG uses 600ms ticks) */ const GAME_TICK_MS = 600; /** How often to process prayer drain (in ms) */ @@ -78,10 +78,10 @@ const DEFAULT_PRAYER_POINTS = 1; // MAX_PRAYER_POINTS imported from prayer-types.ts -/** Base drain resistance constant (OSRS formula) */ +/** Base drain resistance constant (classic combat formula) */ const BASE_DRAIN_RESISTANCE = 60; -/** Prayer bonus multiplier for drain resistance (OSRS formula) */ +/** Prayer bonus multiplier for drain resistance (classic combat formula) */ const PRAYER_BONUS_MULTIPLIER = 2; /** @@ -952,7 +952,7 @@ export class PrayerSystem extends SystemBase { if (totalDrain <= 0) continue; - // OSRS drain formula: drain_resistance = 2 * prayer_bonus + 60 + // classic MMORPG drain formula: drain_resistance = 2 * prayer_bonus + 60 const drainResistance = PRAYER_BONUS_MULTIPLIER * prayerBonus + BASE_DRAIN_RESISTANCE; diff --git a/packages/shared/src/systems/shared/character/SkillsSystem.ts b/packages/shared/src/systems/shared/character/SkillsSystem.ts index 7e2c53e3f..aa1a3c6ea 100644 --- a/packages/shared/src/systems/shared/character/SkillsSystem.ts +++ b/packages/shared/src/systems/shared/character/SkillsSystem.ts @@ -1,7 +1,7 @@ /** * SkillsSystem.ts - Skills, XP, and Leveling System * - * Implements RuneScape-style skill progression system with experience points and levels. + * Implements classic fantasy MMORPG-style skill progression system with experience points and levels. * * **Skills Managed:** * - Combat: attack, strength, defense, constitution, ranged @@ -9,7 +9,7 @@ * - Artisan: firemaking, cooking * * **XP Calculation:** - * Uses RuneScape XP table formula: + * Uses classic fantasy MMORPG XP table formula: * - Level 1-99 (max level) * - XP for level N = floor(N + 300 * 2^(N/7)) / 4 * - Example: Level 50 requires 101,333 XP @@ -345,7 +345,7 @@ export class SkillsSystem extends SystemBase { * Get combat level for an entity */ public getCombatLevel(stats: StatsComponent): number { - // RuneScape combat level formula + // classic fantasy MMORPG combat level formula // Extract levels from stats const defenseLevel = stats.defense?.level ?? 1; const hitpointsLevel = stats.constitution?.level ?? 10; @@ -634,7 +634,7 @@ export class SkillsSystem extends SystemBase { } // Special handling for Prayer level up - // Prayer level = max prayer points (OSRS-accurate) + // Prayer level = max prayer points (rules-accurate) if (skill === Skill.PRAYER) { const prayerSystem = this.world.getSystem("prayer") as unknown as { setMaxPrayerPoints?: (id: string, max: number) => void; @@ -642,7 +642,7 @@ export class SkillsSystem extends SystemBase { } | null; if (prayerSystem?.setMaxPrayerPoints) { prayerSystem.setMaxPrayerPoints(entity.id, newLevel); - // Also restore prayer points to new max (OSRS behavior on level-up) + // Also restore prayer points to new max (classic MMORPG behavior on level-up) prayerSystem.restorePrayerPoints?.(entity.id, newLevel); } } @@ -657,7 +657,7 @@ export class SkillsSystem extends SystemBase { } private calculateMaxHitpoints(level: number): number { - // RuneScape formula: 10 + level + // classic fantasy MMORPG formula: 10 + level return 10 + level; } @@ -718,8 +718,7 @@ export class SkillsSystem extends SystemBase { const targetStats = getStatsComponent(target); if (!targetStats) return; - // OSRS Formula: 4 XP per damage for combat skills, 1.33 XP per damage for Hitpoints - // @see https://oldschool.runescape.wiki/w/Combat#Experience + // classic MMORPG Formula: 4 XP per damage for combat skills, 1.33 XP per damage for Hitpoints // Use damageDealt (total damage by this player) or fallback to mob's max HP const totalDamage = damageDealt > 0 ? damageDealt : (targetStats.health?.max ?? 10); @@ -759,7 +758,7 @@ export class SkillsSystem extends SystemBase { break; case "controlled": { - // OSRS: Controlled gives 1.33 XP per damage to each of 4 skills + // classic MMORPG: Controlled gives 1.33 XP per damage to each of 4 skills // Total: 5.32 XP per damage (vs 5.33 for focused styles) const controlledXP = totalDamage * COMBAT_CONSTANTS.XP.CONTROLLED_XP_PER_DAMAGE; @@ -821,7 +820,7 @@ export class SkillsSystem extends SystemBase { break; } - // ALWAYS grant Hitpoints XP (Constitution) for combat - OSRS standard + // ALWAYS grant Hitpoints XP (Constitution) for combat - classic MMORPG standard this.emitTypedEvent(EventType.SKILLS_XP_GAINED, { playerId: attackerId, skill: Skill.CONSTITUTION, diff --git a/packages/shared/src/systems/shared/character/__tests__/AgilityPersistence.test.ts b/packages/shared/src/systems/shared/character/__tests__/AgilityPersistence.test.ts index 6c7bf2adb..8a9321322 100644 --- a/packages/shared/src/systems/shared/character/__tests__/AgilityPersistence.test.ts +++ b/packages/shared/src/systems/shared/character/__tests__/AgilityPersistence.test.ts @@ -125,7 +125,7 @@ class MockSkillsSystem { } private calculateLevel(xp: number): number { - // Simplified OSRS XP table (approximation) + // Simplified classic MMORPG XP table (approximation) if (xp < 83) return 1; if (xp < 174) return 2; if (xp < 276) return 3; diff --git a/packages/shared/src/systems/shared/character/__tests__/ArmorSystem.test.ts b/packages/shared/src/systems/shared/character/__tests__/ArmorSystem.test.ts index 3da1fc13e..9704302dd 100644 --- a/packages/shared/src/systems/shared/character/__tests__/ArmorSystem.test.ts +++ b/packages/shared/src/systems/shared/character/__tests__/ArmorSystem.test.ts @@ -5,7 +5,7 @@ * - Manifest validation (32 items, no duplicates, valid fields) * - Per-style defence bonus summation * - Armor equip to correct slot with defence requirements - * - Weapon attack style mapping (OSRS combat triangle) + * - Weapon attack style mapping (classic MMORPG combat triangle) * - Defense bonus helper functions */ @@ -357,7 +357,7 @@ function getDefenseBonusForStyle( } // ============================================================================ -// Test Fixtures: OSRS-Accurate Armor Items +// Test Fixtures: Rules-Accurate Armor Items // ============================================================================ /** Rune platebody (tier 5 melee body — requires 40 defence) */ @@ -1023,7 +1023,7 @@ describe("ArmorSystem", () => { } }); - it("all defence values are within OSRS range (0-200)", () => { + it("all defence values are within classic MMORPG range (0-200)", () => { const defenseKeys = [ "defenseStab", "defenseSlash", diff --git a/packages/shared/src/systems/shared/character/__tests__/AutoRetaliate.test.ts b/packages/shared/src/systems/shared/character/__tests__/AutoRetaliate.test.ts index 4d9c9075b..489d493ab 100644 --- a/packages/shared/src/systems/shared/character/__tests__/AutoRetaliate.test.ts +++ b/packages/shared/src/systems/shared/character/__tests__/AutoRetaliate.test.ts @@ -1,7 +1,7 @@ /** * Auto-Retaliate Unit Tests * - * Tests for OSRS-style auto-retaliate functionality: + * Tests for classic MMORPG-style auto-retaliate functionality: * - State initialization (default ON) * - Toggle behavior with rate limiting * - Event emission on state change diff --git a/packages/shared/src/systems/shared/character/__tests__/CoinPouchSystem.test.ts b/packages/shared/src/systems/shared/character/__tests__/CoinPouchSystem.test.ts index 7445b09c0..99ea9d17b 100644 --- a/packages/shared/src/systems/shared/character/__tests__/CoinPouchSystem.test.ts +++ b/packages/shared/src/systems/shared/character/__tests__/CoinPouchSystem.test.ts @@ -1,7 +1,7 @@ /** * CoinPouchSystem Unit Tests * - * Tests the coin pouch functionality (OSRS-style money pouch): + * Tests the coin pouch functionality (classic MMORPG-style money pouch): * - Basic coin operations (add, remove, query) * - Overflow protection (MAX_COINS cap) * - Persistence operations @@ -18,7 +18,7 @@ import { describe, it, expect, beforeEach } from "vitest"; // ============================================================================ const DEFAULT_STARTING_COINS = 100; -const MAX_COINS = 2147483647; // Max 32-bit signed integer (OSRS cap) +const MAX_COINS = 2147483647; // Max 32-bit signed integer (classic MMORPG cap) // ============================================================================ // Types @@ -480,7 +480,7 @@ describe("CoinPouchSystem", () => { await manager.initializePlayerCoins("player-1"); manager.addCoins("player-1", 1000); - // Death in OSRS doesn't affect money pouch + // Death in classic MMORPG doesn't affect money pouch // Coins should remain intact const coinsAfterDeath = manager.getCoins("player-1"); diff --git a/packages/shared/src/systems/shared/character/__tests__/EatDelayManager.test.ts b/packages/shared/src/systems/shared/character/__tests__/EatDelayManager.test.ts index 63842757c..03bf55cfb 100644 --- a/packages/shared/src/systems/shared/character/__tests__/EatDelayManager.test.ts +++ b/packages/shared/src/systems/shared/character/__tests__/EatDelayManager.test.ts @@ -1,7 +1,7 @@ /** * EatDelayManager Unit Tests * - * Tests for OSRS-accurate eating cooldown functionality: + * Tests for rules-accurate eating cooldown functionality: * - 3-tick (1.8s) eat delay between foods * - Cooldown state management per player * - Player cleanup on death/disconnect @@ -41,10 +41,10 @@ describe("EatDelayManager", () => { expect(eatDelayManager.canEat("player-1", 104)).toBe(true); }); - it("returns true exactly at 3 tick boundary (OSRS-accurate)", () => { + it("returns true exactly at 3 tick boundary (rules-accurate)", () => { eatDelayManager.recordEat("player-1", 100); - // OSRS behavior: can eat exactly at 3 ticks elapsed + // classic MMORPG behavior: can eat exactly at 3 ticks elapsed // elapsed = current - last = 103 - 100 = 3 // 3 >= EAT_DELAY_TICKS (3) = true expect(eatDelayManager.canEat("player-1", 103)).toBe(true); @@ -176,9 +176,9 @@ describe("EatDelayManager", () => { }); }); - describe("OSRS timing accuracy", () => { + describe("classic MMORPG timing accuracy", () => { it("uses exactly 3 ticks for eat delay (1.8 seconds)", () => { - // Verify constant matches OSRS wiki + // Verify constant matches classic MMORPG wiki expect(COMBAT_CONSTANTS.EAT_DELAY_TICKS).toBe(3); }); diff --git a/packages/shared/src/systems/shared/character/__tests__/InventorySystem.moveItem.test.ts b/packages/shared/src/systems/shared/character/__tests__/InventorySystem.moveItem.test.ts index f2212e674..fd4282a5c 100644 --- a/packages/shared/src/systems/shared/character/__tests__/InventorySystem.moveItem.test.ts +++ b/packages/shared/src/systems/shared/character/__tests__/InventorySystem.moveItem.test.ts @@ -1,7 +1,7 @@ /** * InventorySystem.moveItem Unit Tests * - * Tests the OSRS-style slot swap functionality: + * Tests the classic MMORPG-style slot swap functionality: * - Basic swap between two occupied slots * - Move to empty slot * - Same-slot no-op @@ -149,7 +149,7 @@ class MockInventoryManager { return; } - // OSRS-style swap + // classic MMORPG-style swap if (toItem) { // Both slots occupied - swap fromItem.slot = toSlot; diff --git a/packages/shared/src/systems/shared/character/__tests__/PrayerSystem.test.ts b/packages/shared/src/systems/shared/character/__tests__/PrayerSystem.test.ts index 65d49eeab..4339a98d2 100644 --- a/packages/shared/src/systems/shared/character/__tests__/PrayerSystem.test.ts +++ b/packages/shared/src/systems/shared/character/__tests__/PrayerSystem.test.ts @@ -3,12 +3,11 @@ * * Tests for prayer system functionality: * - Type guards and input validation - * - OSRS-accurate drain formula + * - rules-accurate drain formula * - Prayer toggle with conflict resolution * - Rate limiting * - Bounds checking * - * @see https://oldschool.runescape.wiki/w/Prayer */ import { describe, it, expect } from "vitest"; @@ -325,7 +324,7 @@ describe("Prayer Constants", () => { expect(MIN_PRAYER_LEVEL).toBe(1); }); - it("MAX_PRAYER_LEVEL is 99 (OSRS-accurate)", () => { + it("MAX_PRAYER_LEVEL is 99 (rules-accurate)", () => { expect(MAX_PRAYER_LEVEL).toBe(99); }); @@ -339,8 +338,8 @@ describe("Prayer Constants", () => { }); }); -describe("OSRS Prayer Drain Formula", () => { - // OSRS formula: drain_resistance = 2 * prayer_bonus + 60 +describe("classic MMORPG Prayer Drain Formula", () => { + // classic combat formula: drain_resistance = 2 * prayer_bonus + 60 // Points drained per tick = drain_effect / drain_resistance const BASE_DRAIN_RESISTANCE = 60; diff --git a/packages/shared/src/systems/shared/character/__tests__/SkillsSystem.xp.test.ts b/packages/shared/src/systems/shared/character/__tests__/SkillsSystem.xp.test.ts index 60133b7a4..7343f2a3f 100644 --- a/packages/shared/src/systems/shared/character/__tests__/SkillsSystem.xp.test.ts +++ b/packages/shared/src/systems/shared/character/__tests__/SkillsSystem.xp.test.ts @@ -1,13 +1,12 @@ /** * Combat XP Distribution Unit Tests * - * Tests for OSRS-accurate experience point distribution: + * Tests for rules-accurate experience point distribution: * - Focused styles: 4 XP per damage to combat skill + 1.33 XP to HP * - Controlled style: 1.33 XP per damage to each of 4 skills * * Verifies fractional XP accumulation (no flooring until display). * - * @see https://oldschool.runescape.wiki/w/Combat#Experience */ import { describe, it, expect } from "vitest"; @@ -21,16 +20,16 @@ describe("Combat XP Distribution", () => { CONTROLLED_XP_PER_DAMAGE, } = COMBAT_CONSTANTS.XP; - describe("OSRS XP Constants", () => { - it("COMBAT_XP_PER_DAMAGE is 4 (OSRS-accurate)", () => { + describe("classic MMORPG XP Constants", () => { + it("COMBAT_XP_PER_DAMAGE is 4 (rules-accurate)", () => { expect(COMBAT_XP_PER_DAMAGE).toBe(4); }); - it("HITPOINTS_XP_PER_DAMAGE is 1.33 (OSRS-accurate)", () => { + it("HITPOINTS_XP_PER_DAMAGE is 1.33 (rules-accurate)", () => { expect(HITPOINTS_XP_PER_DAMAGE).toBe(1.33); }); - it("CONTROLLED_XP_PER_DAMAGE is 1.33 (OSRS-accurate)", () => { + it("CONTROLLED_XP_PER_DAMAGE is 1.33 (rules-accurate)", () => { expect(CONTROLLED_XP_PER_DAMAGE).toBe(1.33); }); }); @@ -106,7 +105,7 @@ describe("Combat XP Distribution", () => { it("trades efficiency for balanced skill training", () => { // Controlled: 1.33 to each of 4 skills = 5.32 total // Focused: 4 to 1 skill + 1.33 to HP = 5.33 total - // Difference is intentional OSRS design + // Difference is intentional classic MMORPG design const damage = 100; const focusedXP = damage * (COMBAT_XP_PER_DAMAGE + HITPOINTS_XP_PER_DAMAGE); diff --git a/packages/shared/src/systems/shared/combat/AggroSystem.ts b/packages/shared/src/systems/shared/combat/AggroSystem.ts index 268846b78..ec6a254be 100644 --- a/packages/shared/src/systems/shared/combat/AggroSystem.ts +++ b/packages/shared/src/systems/shared/combat/AggroSystem.ts @@ -34,9 +34,8 @@ import type { ZoneDetectionSystem } from "../death/ZoneDetectionSystem"; /** * Tolerance state for a player in a region - * In OSRS, aggressive mobs stop attacking after player has been in a 21x21 region for 10 minutes + * In classic MMORPG, aggressive mobs stop attacking after player has been in a 21x21 region for 10 minutes * - * @see https://oldschool.runescape.wiki/w/Aggression#Tolerance */ interface ToleranceState { /** Region identifier (21x21 tile zone) */ @@ -50,7 +49,7 @@ interface ToleranceState { /** Tolerance timer duration: 1000 ticks = 10 minutes at 600ms/tick */ const TOLERANCE_TICKS = 1000; -/** Tolerance region size in tiles (OSRS uses 21x21 regions) */ +/** Tolerance region size in tiles (classic MMORPG uses 21x21 regions) */ const TOLERANCE_REGION_SIZE = 21; /** @@ -280,7 +279,7 @@ export class AggroSystem extends SystemBase { } } - // Start AI update loop aligned to server tick (OSRS-accurate) + // Start AI update loop aligned to server tick (rules-accurate) this.createInterval(() => { this.updateMobAI(); }, TICK_DURATION_MS); // 600ms - aligned to server tick @@ -307,7 +306,7 @@ export class AggroSystem extends SystemBase { const mobType = mobData.type.toLowerCase(); - // Use manifest values with OSRS-accurate DEFAULTS as fallback + // Use manifest values with rules-accurate DEFAULTS as fallback // This replaces the legacy MOB_BEHAVIORS lookup pattern const detectionRange = mobData.combat?.aggroRange ?? COMBAT_CONSTANTS.DEFAULTS.NPC.AGGRO_RANGE; @@ -566,14 +565,13 @@ export class AggroSystem extends SystemBase { /** * Check if mob should aggro a player based on level and behavior * - * OSRS Rule: Mobs ignore players whose combat level is MORE THAN DOUBLE the mob's level. + * classic MMORPG Rule: Mobs ignore players whose combat level is MORE THAN DOUBLE the mob's level. * * Examples: * - Level 2 goblin ignores level 5+ players (5 > 2*2 = 4) * - Level 10 guard ignores level 21+ players (21 > 10*2 = 20) * - Bosses (toleranceImmune) never ignore based on level * - * @see https://oldschool.runescape.wiki/w/Aggression */ private shouldMobAggroPlayer( mobState: MobAIStateData, @@ -595,7 +593,7 @@ export class AggroSystem extends SystemBase { } } - // Get player combat level using OSRS formula + // Get player combat level using classic combat formula const playerCombatLevel = this.getPlayerCombatLevel(playerId); // Get mob's combat level from the entity @@ -607,7 +605,7 @@ export class AggroSystem extends SystemBase { // They always aggro regardless of player level const toleranceImmune = mobState.levelIgnore >= 999; - // OSRS double-level aggro rule + // classic MMORPG double-level aggro rule // Player level > (mob level * 2) = mob ignores player if (shouldMobIgnorePlayer(playerCombatLevel, mobLevel, toleranceImmune)) { return false; @@ -668,12 +666,12 @@ export class AggroSystem extends SystemBase { return combatLevel; } - /** Default skills for fresh character (OSRS level 3) */ + /** Default skills for fresh character (classic MMORPG level 3) */ private static readonly DEFAULT_SKILLS = { attack: 1, strength: 1, defense: 1, - constitution: 10, // Hitpoints starts at 10 in OSRS + constitution: 10, // Hitpoints starts at 10 in classic MMORPG ranged: 1, magic: 1, prayer: 1, @@ -706,7 +704,6 @@ export class AggroSystem extends SystemBase { /** * Update tolerance state - after 10 min in a 21x21 region, mobs stop aggro - * @see https://oldschool.runescape.wiki/w/Aggression#Tolerance */ private updatePlayerTolerance( playerId: string, @@ -762,7 +759,7 @@ export class AggroSystem extends SystemBase { /** * Get tolerance region ID for a tile position - * OSRS divides the world into 21x21 tile regions for tolerance purposes + * classic MMORPG divides the world into 21x21 tile regions for tolerance purposes * * @param tile - Tile coordinates * @returns Region identifier string "x:z" @@ -827,7 +824,7 @@ export class AggroSystem extends SystemBase { /** * Get the tolerance region ID for a world position - * Regions are 21x21 tiles (OSRS-accurate) + * Regions are 21x21 tiles (rules-accurate) * * @param position - World position (x, z coordinates) * @returns Region identifier string "x:z" diff --git a/packages/shared/src/systems/shared/combat/CombatAnimationManager.ts b/packages/shared/src/systems/shared/combat/CombatAnimationManager.ts index c639edaaa..787961fe9 100644 --- a/packages/shared/src/systems/shared/combat/CombatAnimationManager.ts +++ b/packages/shared/src/systems/shared/combat/CombatAnimationManager.ts @@ -91,7 +91,7 @@ export class CombatAnimationManager { /** * Process emote reset for a specific entity * - * OSRS-ACCURATE: Called by GameTickProcessor during per-entity processing + * RULES-ACCURATE: Called by GameTickProcessor during per-entity processing * This allows emote resets to be processed per-entity rather than globally. * * @param entityId - The entity to check for emote reset @@ -165,10 +165,10 @@ export class CombatAnimationManager { weaponType === "wand"; if (isMagicWeapon && selectedSpell) { - // OSRS-accurate: Magic weapons with autocast use spell cast animation + // rules-accurate: Magic weapons with autocast use spell cast animation combatEmote = "spell_cast"; } else if (isMagicWeapon) { - // OSRS-accurate: Magic weapons WITHOUT autocast use melee bonk (crush) + // rules-accurate: Magic weapons WITHOUT autocast use melee bonk (crush) // Staffs default to punching/combat animation when no spell selected combatEmote = "combat"; } else if (weaponType === "two_hand_sword") { diff --git a/packages/shared/src/systems/shared/combat/CombatAntiCheat.ts b/packages/shared/src/systems/shared/combat/CombatAntiCheat.ts index b187053ad..e5a5cb834 100644 --- a/packages/shared/src/systems/shared/combat/CombatAntiCheat.ts +++ b/packages/shared/src/systems/shared/combat/CombatAntiCheat.ts @@ -907,7 +907,7 @@ export class CombatAntiCheat { ): boolean { const attackerIdStr = String(attackerId); // Calculate maximum possible hit for this attacker - // OSRS formula: Max Hit = floor(0.5 + EffectiveStrength × (StrengthBonus + 64) / 640) + // classic combat formula: Max Hit = floor(0.5 + EffectiveStrength × (StrengthBonus + 64) / 640) // EffectiveStrength = StrengthLevel + 8 + 3 (max style bonus) const effectiveStrength = attackerStrength + 8 + 3; const maxPossibleHit = Math.floor( diff --git a/packages/shared/src/systems/shared/combat/CombatEntityResolver.ts b/packages/shared/src/systems/shared/combat/CombatEntityResolver.ts index ebcbf06ae..8e00717d5 100644 --- a/packages/shared/src/systems/shared/combat/CombatEntityResolver.ts +++ b/packages/shared/src/systems/shared/combat/CombatEntityResolver.ts @@ -182,7 +182,7 @@ export class CombatEntityResolver { } /** - * Get attack speed in TICKS for an entity (OSRS-accurate) + * Get attack speed in TICKS for an entity (rules-accurate) * @param entityId - Entity ID to check * @param entityType - Type of entity ("player" or "mob") * @returns Attack speed in game ticks (default: 4 ticks = 2.4 seconds) @@ -235,7 +235,7 @@ export class CombatEntityResolver { /** * Get combat range for an entity in tiles * Mobs use combatRange from manifest, players use equipped weapon's attackRange - * OSRS-accurate: If player has a spell selected, use magic range (10 tiles) + * rules-accurate: If player has a spell selected, use magic range (10 tiles) * @param entity - Entity to check * @param entityType - Type of entity ("player" or "mob") * @returns Combat range in tiles (default: 1 for unarmed) @@ -248,7 +248,7 @@ export class CombatEntityResolver { } if (entityType === "player") { - // OSRS-accurate: Check if player has a spell selected first + // rules-accurate: Check if player has a spell selected first // You can cast spells without a staff - the staff just provides magic bonus const selectedSpell = (entity as { data?: { selectedSpell?: string } }) ?.data?.selectedSpell; @@ -276,7 +276,7 @@ export class CombatEntityResolver { if (equipment?.weapon?.item) { const weaponItem = equipment.weapon.item; - // OSRS-accurate: Magic weapons (staffs/wands) only use their attackRange + // rules-accurate: Magic weapons (staffs/wands) only use their attackRange // when a spell is selected (autocast). Without autocast, staffs default // to melee range. The selectedSpell check above already returns 10 for // magic range, so if we reach here, no spell is selected. diff --git a/packages/shared/src/systems/shared/combat/CombatRotationManager.ts b/packages/shared/src/systems/shared/combat/CombatRotationManager.ts index 0d2a55614..f93672ac5 100644 --- a/packages/shared/src/systems/shared/combat/CombatRotationManager.ts +++ b/packages/shared/src/systems/shared/combat/CombatRotationManager.ts @@ -59,7 +59,7 @@ export class CombatRotationManager { } /** - * Rotate an entity to face a target (RuneScape-style instant rotation) + * Rotate an entity to face a target (classic fantasy MMORPG-style instant rotation) * @param entityId - Entity to rotate * @param targetId - Target to face * @param entityType - Whether entity is player or mob diff --git a/packages/shared/src/systems/shared/combat/CombatStateService.ts b/packages/shared/src/systems/shared/combat/CombatStateService.ts index 5e35a9fa5..d942bcb26 100644 --- a/packages/shared/src/systems/shared/combat/CombatStateService.ts +++ b/packages/shared/src/systems/shared/combat/CombatStateService.ts @@ -23,7 +23,7 @@ export interface CombatData { weaponType: AttackType; inCombat: boolean; - // TICK-BASED timing (OSRS-accurate) + // TICK-BASED timing (rules-accurate) lastAttackTick: number; nextAttackTick: number; combatEndTick: number; @@ -272,7 +272,7 @@ export class CombatStateService { } /** - * Mark player as in combat but without a target (OSRS auto-retaliate OFF behavior) + * Mark player as in combat but without a target (classic MMORPG auto-retaliate OFF behavior) * Player is being attacked but won't fight back - still triggers combat timer * Stores attackerId so we can start combat if auto-retaliate is toggled ON * @param entityId - Entity ID (accepts both EntityID and string for backwards compatibility) diff --git a/packages/shared/src/systems/shared/combat/CombatSystem.ts b/packages/shared/src/systems/shared/combat/CombatSystem.ts index f510562a1..9ace57e3c 100644 --- a/packages/shared/src/systems/shared/combat/CombatSystem.ts +++ b/packages/shared/src/systems/shared/combat/CombatSystem.ts @@ -164,7 +164,7 @@ export class CombatSystem extends SystemBase { rangedStrength: number; magicAttack: number; magicDefense: number; - // Per-style melee defence bonuses (OSRS combat triangle) + // Per-style melee defence bonuses (classic MMORPG combat triangle) defenseStab: number; defenseSlash: number; defenseCrush: number; @@ -185,12 +185,12 @@ export class CombatSystem extends SystemBase { private readonly _attackerTile: PooledTile = tilePool.acquire(); private readonly _targetTile: PooledTile = tilePool.acquire(); - // OSRS-accurate: Track last known target tile per attacker for persistent combat follow. - // In OSRS, the player continuously follows the target while in combat — not just when + // rules-accurate: Track last known target tile per attacker for persistent combat follow. + // In classic MMORPG, the player continuously follows the target while in combat — not just when // out of range. This map lets us detect when the target has moved and re-path accordingly. private lastCombatTargetTile = new Map(); - // Auto-retaliate disabled after 20 minutes of no input (OSRS behavior) + // Auto-retaliate disabled after 20 minutes of no input (classic MMORPG behavior) private lastInputTick = new Map(); private damageHandlers: Map<"player" | "mob", DamageHandler>; @@ -496,8 +496,8 @@ export class CombatSystem extends SystemBase { }, ); - // OSRS-accurate: Player clicked to move = cancel their attacking combat - // In OSRS, clicking anywhere else cancels your current action including combat + // rules-accurate: Player clicked to move = cancel their attacking combat + // In classic MMORPG, clicking anywhere else cancels your current action including combat // SERVER-ONLY: Combat state changes must happen on server this.subscribe( EventType.COMBAT_PLAYER_DISENGAGE, @@ -625,7 +625,7 @@ export class CombatSystem extends SystemBase { rangedStrength?: number; magicAttack?: number; magicDefense?: number; - // Optional per-style bonuses (OSRS combat triangle) + // Optional per-style bonuses (classic MMORPG combat triangle) defenseStab?: number; defenseSlash?: number; defenseCrush?: number; @@ -660,7 +660,7 @@ export class CombatSystem extends SystemBase { * Get attack type from equipped weapon or selected spell * Returns AttackType based on weapon's attackType property, or MAGIC if spell selected * - * OSRS-accurate: You can cast spells without a staff - the staff just provides + * rules-accurate: You can cast spells without a staff - the staff just provides * magic attack bonus and elemental staves give infinite runes */ private getAttackTypeFromWeapon(attackerId: string): AttackType { @@ -692,7 +692,7 @@ export class CombatSystem extends SystemBase { return AttackType.RANGED; } - // Default to melee (includes staffs/wands without autocast - OSRS accurate) + // Default to melee (includes staffs/wands without autocast - rules-accurate) return AttackType.MELEE; } @@ -912,11 +912,10 @@ export class CombatSystem extends SystemBase { /** * Check if attacker is within combat range of target * - * OSRS melee rules (from wiki): + * classic MMORPG melee rules (from wiki): * - Range 1 (standard melee): Cardinal only (N/S/E/W) - NO diagonal attacks * - Range 2+ (halberd): Allows diagonal attacks * - * @see https://oldschool.runescape.wiki/w/Attack_range */ private isWithinCombatRange( attacker: Entity | MobEntity, @@ -937,7 +936,7 @@ export class CombatSystem extends SystemBase { attackerType, ); - // OSRS-accurate melee range check: + // rules-accurate melee range check: // - Range 1: Cardinal only (N/S/E/W) // - Range 2+: Allows diagonal (Chebyshev distance) if ( @@ -1014,7 +1013,7 @@ export class CombatSystem extends SystemBase { attackSpeedTicks, ); - // Get player's combat style for OSRS-accurate damage bonuses + // Get player's combat style for rules-accurate damage bonuses let combatStyle: CombatStyle = "accurate"; if (attackerType === "player") { const playerSystem = this.world.getSystem( @@ -1843,7 +1842,7 @@ export class CombatSystem extends SystemBase { ? target.getMobData().defense : this.getPlayerSkillLevel(String(target.id), "defense"); - // Use per-style defenseRanged from equipment (OSRS combat triangle). + // Use per-style defenseRanged from equipment (classic MMORPG combat triangle). // Falls back to generic ranged bonus for backward compatibility. const targetEquipStats = this.playerEquipmentStats.get(String(target.id)); const targetRangedDefense = @@ -1863,7 +1862,7 @@ export class CombatSystem extends SystemBase { // Do NOT add arrowStrength separately as that would double-count it const rangedStrengthBonus = equipmentStats?.rangedStrength ?? arrowStrength; - // Get player's combat style for OSRS-accurate damage bonuses + // Get player's combat style for rules-accurate damage bonuses let rangedStyle: RangedCombatStyle = "accurate"; const playerSystem = this.world.getSystem("player") as PlayerSystem | null; const styleData = playerSystem?.getPlayerAttackStyle?.(attackerId); @@ -1967,7 +1966,7 @@ export class CombatSystem extends SystemBase { ? prayerSystem?.getCombinedBonuses(String(target.id)) : undefined; - // Get player's combat style for OSRS-accurate damage bonuses + // Get player's combat style for rules-accurate damage bonuses let magicStyle: MagicCombatStyle = "accurate"; const playerSystem = this.world.getSystem("player") as PlayerSystem | null; const styleData = playerSystem?.getPlayerAttackStyle?.(attackerId); @@ -2082,7 +2081,7 @@ export class CombatSystem extends SystemBase { /** * Handle auto-retaliate being toggled ON while being attacked - * OSRS behavior: Player should start fighting back immediately + * classic MMORPG behavior: Player should start fighting back immediately * * Supports both PvE (mob attacker) and PvP (player attacker) scenarios. */ @@ -2133,18 +2132,16 @@ export class CombatSystem extends SystemBase { } /** - * OSRS-accurate: Handle player clicking to move (disengage from combat) - * In OSRS, clicking anywhere else cancels YOUR current action including combat. + * rules-accurate: Handle player clicking to move (disengage from combat) + * In classic MMORPG, clicking anywhere else cancels YOUR current action including combat. * * CRITICAL: This only affects the DISENGAGING player's combat state. * The player who was attacking them (their target) keeps their combat state - * and continues chasing. This is correct OSRS behavior: + * and continues chasing. This is correct classic MMORPG behavior: * - "Deliberate movement out of the opponent's weapon range to force them to follow - * is called dragging." - OSRS Wiki (Free-to-play PvP techniques) + * is called dragging." * - Pathfinding recalculates every tick when targeting a moving entity * - * @see https://oldschool.runescape.wiki/w/Free-to-play_PvP_techniques - * @see https://oldschool.runescape.wiki/w/Pathfinding */ private handlePlayerDisengage(playerId: string): void { const combatState = this.stateService.getCombatData(playerId); @@ -2155,7 +2152,7 @@ export class CombatSystem extends SystemBase { const targetId = String(combatState.targetId); const typedPlayerId = createEntityID(playerId); - // OSRS-ACCURATE: Only remove THIS player's combat state + // RULES-ACCURATE: Only remove THIS player's combat state // DO NOT call forceEndCombat() as it removes BOTH players' states! // The target (who may be attacking this player) keeps their combat state // and continues chasing this player. This enables the "dragging" PvP technique. @@ -2177,7 +2174,7 @@ export class CombatSystem extends SystemBase { // If auto-retaliate is ON and attacker catches up and hits, player will start fighting again this.stateService.markInCombatWithoutTarget(playerId, targetId); - // OSRS-ACCURATE: Do NOT face the target when walking away + // RULES-ACCURATE: Do NOT face the target when walking away // Player should face their walking direction (handled by tile movement) // Only face target when auto-retaliate triggers (handled by enterCombat) } @@ -2233,7 +2230,7 @@ export class CombatSystem extends SystemBase { } } - // Determine melee attack style from weapon type (OSRS combat triangle) + // Determine melee attack style from weapon type (classic MMORPG combat triangle) let meleeAttackStyle: MeleeAttackStyle | undefined; if (!(attacker instanceof MobEntity)) { const weapon = this.getEquippedWeapon(attacker.id); @@ -2416,8 +2413,7 @@ export class CombatSystem extends SystemBase { attackerWeaponType, ); - // OSRS Retaliation: Target retaliates after ceil(speed/2) + 1 ticks - // @see https://oldschool.runescape.wiki/w/Auto_Retaliate + // classic MMORPG Retaliation: Target retaliates after ceil(speed/2) + 1 ticks // Check if target can retaliate (mobs have retaliates flag, players check auto-retaliate setting) let canRetaliate = true; if (targetType === "mob" && targetEntity) { @@ -2426,13 +2422,13 @@ export class CombatSystem extends SystemBase { } else if (targetType === "player") { // Check player's auto-retaliate setting // Uses cached reference (no getSystem() call in hot path) - // Defaults to true if PlayerSystem unavailable (fail-safe, OSRS default) + // Defaults to true if PlayerSystem unavailable (fail-safe, classic MMORPG default) if (this.playerSystem) { canRetaliate = this.playerSystem.getPlayerAutoRetaliate( String(targetId), ); } - // Note: If playerSystem is null, canRetaliate stays true (default OSRS behavior) + // Note: If playerSystem is null, canRetaliate stays true (default classic MMORPG behavior) // 20 min AFK disables auto-retaliate if (canRetaliate && this.isAFKTooLong(String(targetId), currentTick)) { @@ -2472,7 +2468,7 @@ export class CombatSystem extends SystemBase { ); if (!targetHasValidTarget) { - // Target has no valid target - schedule retaliation (normal OSRS auto-retaliate) + // Target has no valid target - schedule retaliation (normal classic MMORPG auto-retaliate) const retaliationDelay = calculateRetaliationDelay( targetAttackSpeedTicks, ); @@ -2487,7 +2483,7 @@ export class CombatSystem extends SystemBase { targetAttackSpeedTicks, ); - // OSRS-ACCURATE: Auto-retaliate ALWAYS redirects player toward attacker + // RULES-ACCURATE: Auto-retaliate ALWAYS redirects player toward attacker // When hit with auto-retaliate ON, player stops any current movement and turns to fight // The COMBAT_FOLLOW_TARGET event replaces any existing movement destination // Wiki: "the player's character walks/runs towards the monster attacking and fights back" @@ -2546,7 +2542,7 @@ export class CombatSystem extends SystemBase { } } else { // Target already has valid target - just extend their combat timer - // They stay locked on their current target (OSRS-accurate) + // They stay locked on their current target (rules-accurate) this.stateService.extendCombatTimer(targetId, currentTick); } } @@ -2561,7 +2557,7 @@ export class CombatSystem extends SystemBase { // Target only gets NEW combat target if: // 1. They will retaliate (auto-retaliate ON), AND - // 2. They don't already have a valid target (OSRS-accurate) + // 2. They don't already have a valid target (rules-accurate) // // If target already has a valid target, we don't overwrite their target state. // They stay locked on their current enemy. @@ -2871,7 +2867,7 @@ export class CombatSystem extends SystemBase { attacker, opts.attackerType, ); - // OSRS-accurate melee range check (cardinal-only for range 1) + // rules-accurate melee range check (cardinal-only for range 1) if ( !tilesWithinMeleeRange( this._attackerTile, @@ -2904,7 +2900,7 @@ export class CombatSystem extends SystemBase { * Check if player is on attack cooldown * Used by eating system to determine if eat should add attack delay * - * OSRS Rule: Foods only add to EXISTING attack delay. + * classic MMORPG Rule: Foods only add to EXISTING attack delay. * If weapon is ready to attack (cooldown expired), eating does NOT add delay. * * @param playerId - Player to check @@ -2922,9 +2918,9 @@ export class CombatSystem extends SystemBase { /** * Add delay ticks to player's next attack - * Used by eating system (OSRS: eating during combat adds 3 tick delay) + * Used by eating system (classic MMORPG: eating during combat adds 3 tick delay) * - * OSRS-Accurate: Only called when player is ALREADY on cooldown. + * Rules-Accurate: Only called when player is ALREADY on cooldown. * If weapon is ready, eating does not add delay. * * @param playerId - Player to modify @@ -2944,7 +2940,7 @@ export class CombatSystem extends SystemBase { combatData.nextAttackTick += delayTicks; } } - // If no current cooldown, do nothing (OSRS-accurate: no delay if weapon ready) + // If no current cooldown, do nothing (rules-accurate: no delay if weapon ready) } public forceEndCombat( @@ -2963,7 +2959,7 @@ export class CombatSystem extends SystemBase { /** * Check if a player can logout based on combat state - * OSRS-accurate: Cannot logout while actively in combat + * rules-accurate: Cannot logout while actively in combat * Uses the combat timeout window to determine if player is in active combat * * @param playerId - The player's entity ID @@ -2992,7 +2988,7 @@ export class CombatSystem extends SystemBase { /** * Update the last input tick for a player * Called by PlayerSystem when player performs any action - * OSRS: Auto-retaliate disabled after 20 minutes of no input + * classic MMORPG: Auto-retaliate disabled after 20 minutes of no input * * @param playerId - The player's entity ID * @param currentTick - The current game tick @@ -3003,7 +2999,7 @@ export class CombatSystem extends SystemBase { /** * Check if a player has been AFK too long (20 minutes) - * OSRS-accurate: Auto-retaliate disabled after 2000 ticks of no input + * rules-accurate: Auto-retaliate disabled after 2000 ticks of no input * * @param playerId - The player's entity ID * @param currentTick - The current game tick @@ -3083,7 +3079,7 @@ export class CombatSystem extends SystemBase { // Combat update loop - DEPRECATED: Combat logic now handled by processCombatTick() via TickSystem // This method is kept for compatibility but does nothing - all combat runs through tick system update(_dt: number): void { - // Combat logic moved to processCombatTick() for OSRS-accurate tick-based timing + // Combat logic moved to processCombatTick() for rules-accurate tick-based timing // This is called by TickSystem at TickPriority.COMBAT } @@ -3092,7 +3088,7 @@ export class CombatSystem extends SystemBase { private _lastSortedCombatCount = 0; /** - * Process combat on each server tick (OSRS-accurate) + * Process combat on each server tick (rules-accurate) * Called by TickSystem at COMBAT priority (after movement, before AI) */ public processCombatTick(tickNumber: number): void { @@ -3160,8 +3156,8 @@ export class CombatSystem extends SystemBase { if (!combatState.inCombat || !combatState.targetId) continue; - // OSRS-style: Check range EVERY tick and follow if needed (not just on attack ticks) - // In OSRS, you continuously pursue your target while in combat + // classic MMORPG-style: Check range EVERY tick and follow if needed (not just on attack ticks) + // In classic MMORPG, you continuously pursue your target while in combat if (combatState.attackerType === "player") { this.checkRangeAndFollow(combatState, tickNumber); } @@ -3185,7 +3181,7 @@ export class CombatSystem extends SystemBase { /** * Process combat for a specific NPC on this tick * - * OSRS-ACCURATE: Called by GameTickProcessor during NPC phase + * RULES-ACCURATE: Called by GameTickProcessor during NPC phase * NPCs process BEFORE players, creating the damage asymmetry: * - NPC → Player damage: Applied same tick * - Player → NPC damage: Applied next tick @@ -3228,7 +3224,7 @@ export class CombatSystem extends SystemBase { /** * Process combat for a specific player on this tick * - * OSRS-ACCURATE: Called by GameTickProcessor during Player phase + * RULES-ACCURATE: Called by GameTickProcessor during Player phase * Players process AFTER NPCs, creating the damage asymmetry: * - Player → NPC damage: Applied next tick (queued by GameTickProcessor) * - NPC → Player damage: Applied same tick @@ -3252,7 +3248,7 @@ export class CombatSystem extends SystemBase { // Only process player attackers (not players being attacked) if (combatState.attackerType !== "player") return; - // OSRS-ACCURATE: No movement suppression needed + // RULES-ACCURATE: No movement suppression needed // If player has combat state, they're either: // 1. Standing still fighting // 2. Combat following (chasing their target) @@ -3263,7 +3259,7 @@ export class CombatSystem extends SystemBase { // Process emote resets for this player this.animationManager.processEntityEmoteReset(playerId, tickNumber); - // OSRS-style: Check range EVERY tick and follow if needed + // classic MMORPG-style: Check range EVERY tick and follow if needed this.checkRangeAndFollow(combatState, tickNumber); if (tickNumber >= combatState.nextAttackTick) { @@ -3280,7 +3276,7 @@ export class CombatSystem extends SystemBase { } /** - * OSRS-style: Check if player is in range of target, emit follow event if not + * classic MMORPG-style: Check if player is in range of target, emit follow event if not * Called EVERY tick to ensure continuous pursuit of moving targets * * CRITICAL: This method must NOT extend combat timeout for invalid targets. @@ -3294,7 +3290,7 @@ export class CombatSystem extends SystemBase { const attackerId = String(combatState.attackerId); const targetId = String(combatState.targetId); - // OSRS-ACCURATE: No movement suppression for following + // RULES-ACCURATE: No movement suppression for following // If player has combat state, they should continuously pursue their target // Wiki: "follow and attack while chasing it" // Movement during combat follow is normal - player is chasing their target @@ -3372,7 +3368,7 @@ export class CombatSystem extends SystemBase { ? this.getAttackTypeFromWeapon(attackerId) : AttackType.MELEE; - // OSRS-accurate range check: + // rules-accurate range check: // - MELEE: Cardinal-only for range 1 (using tilesWithinMeleeRange) // - RANGED/MAGIC: Chebyshev distance (can attack diagonally) const inRange = @@ -3388,8 +3384,8 @@ export class CombatSystem extends SystemBase { combatRangeTiles, ); - // OSRS-accurate: Continuously follow the target while in combat. - // In OSRS, the player follows the target every tick — not just when out of range. + // rules-accurate: Continuously follow the target while in combat. + // In classic MMORPG, the player follows the target every tick — not just when out of range. // movePlayerToward() already returns early if already in range, so this is safe. // This prevents the stutter pattern where the player stands still until the target // leaves range, then chases, then stops again. @@ -3488,7 +3484,7 @@ export class CombatSystem extends SystemBase { if (!attackerPos || !targetPos) return false; // MELEE: Must be within attacker's combat range (configurable per mob, minimum 1 tile) - // OSRS-style: range 1 = cardinal only (N/S/E/W), range 2+ = diagonal allowed + // classic MMORPG-style: range 1 = cardinal only (N/S/E/W), range 2+ = diagonal allowed // Use pre-allocated pooled tiles (zero GC) tilePool.setFromPosition(this._attackerTile, attackerPos); tilePool.setFromPosition(this._targetTile, targetPos); @@ -3497,7 +3493,7 @@ export class CombatSystem extends SystemBase { attackerType, ); - // OSRS-accurate melee range check (cardinal-only for range 1) + // rules-accurate melee range check (cardinal-only for range 1) return tilesWithinMeleeRange( this._attackerTile, this._targetTile, @@ -3517,7 +3513,7 @@ export class CombatSystem extends SystemBase { combatState: CombatData, tickNumber: number, ): number { - // OSRS-STYLE: Update entity facing to face target + // classic MMORPG-STYLE: Update entity facing to face target this.rotationManager.rotateTowardsTarget( attackerId, targetId, @@ -3533,7 +3529,7 @@ export class CombatSystem extends SystemBase { combatState.attackSpeedTicks, ); - // Get player's combat style for OSRS-accurate damage bonuses + // Get player's combat style for rules-accurate damage bonuses let combatStyle: CombatStyle = "accurate"; if (combatState.attackerType === "player") { const playerSystem = this.world.getSystem( @@ -3548,7 +3544,7 @@ export class CombatSystem extends SystemBase { // MVP: Melee-only damage calculation const rawDamage = this.calculateMeleeDamage(attacker, target, combatStyle); - // OSRS-STYLE: Cap damage at target's current health (no overkill) + // classic MMORPG-STYLE: Cap damage at target's current health (no overkill) const currentHealth = this.entityResolver.getHealth(target); const damage = Math.min(rawDamage, currentHealth); diff --git a/packages/shared/src/systems/shared/combat/CombatTickProcessor.ts b/packages/shared/src/systems/shared/combat/CombatTickProcessor.ts index 8de0334c9..2bab35980 100644 --- a/packages/shared/src/systems/shared/combat/CombatTickProcessor.ts +++ b/packages/shared/src/systems/shared/combat/CombatTickProcessor.ts @@ -154,7 +154,7 @@ export class CombatTickProcessor { if (!combatState.inCombat || !combatState.targetId) continue; - // OSRS-style: Check range EVERY tick and follow if needed + // classic MMORPG-style: Check range EVERY tick and follow if needed if (combatState.attackerType === "player") { this.checkRangeAndFollow(combatState, tickNumber); } @@ -406,7 +406,7 @@ export class CombatTickProcessor { this._projectileHitPayload, ); - // OSRS arrow recovery: 80% drop to ground, 20% destroyed + // classic MMORPG arrow recovery: 80% drop to ground, 20% destroyed if (projectile.arrowId && this.ctx.groundItemSystem) { const rng = getGameRng(); if (rng.random() >= 0.2) { diff --git a/packages/shared/src/systems/shared/combat/DamageCalculator.ts b/packages/shared/src/systems/shared/combat/DamageCalculator.ts index 34411c744..3b4fa4d3a 100644 --- a/packages/shared/src/systems/shared/combat/DamageCalculator.ts +++ b/packages/shared/src/systems/shared/combat/DamageCalculator.ts @@ -25,7 +25,7 @@ export interface EquipmentStats { strength: number; defense: number; ranged: number; - // Per-style melee defence bonuses (OSRS combat triangle) + // Per-style melee defence bonuses (classic MMORPG combat triangle) defenseStab?: number; defenseSlash?: number; defenseCrush?: number; @@ -106,7 +106,7 @@ export class DamageCalculator { * Calculate melee damage for an attack * @param attacker - The attacking entity * @param target - The target entity - * @param style - Combat style for OSRS-accurate stat bonuses (default: "accurate") + * @param style - Combat style for rules-accurate stat bonuses (default: "accurate") * @param attackerPrayerBonuses - Prayer multipliers for attacker (optional) * @param defenderPrayerBonuses - Prayer multipliers for defender (optional) * @param meleeAttackStyle - Weapon attack style (stab/slash/crush) for per-style bonus lookup diff --git a/packages/shared/src/systems/shared/combat/DeathUtils.ts b/packages/shared/src/systems/shared/combat/DeathUtils.ts index b47cb2515..cc18c0b1c 100644 --- a/packages/shared/src/systems/shared/combat/DeathUtils.ts +++ b/packages/shared/src/systems/shared/combat/DeathUtils.ts @@ -53,8 +53,7 @@ export function sanitizeKilledBy(killedBy: unknown): string { } /** - * OSRS-style: In safe zones, player keeps their 3 most valuable items on death. - * @see https://oldschool.runescape.wiki/w/Items_Kept_on_Death + * classic MMORPG-style: In safe zones, player keeps their 3 most valuable items on death. */ export const ITEMS_KEPT_ON_DEATH = 3; @@ -68,7 +67,7 @@ export function getItemValue(itemId: string): number { } /** - * Split items into "kept" and "dropped" lists for safe zone deaths (OSRS-style). + * Split items into "kept" and "dropped" lists for safe zone deaths (classic MMORPG-style). * Keeps the N most valuable individual items. For stacked items (quantity > 1), * each unit counts as one item but only the top N units across all stacks are kept. * diff --git a/packages/shared/src/systems/shared/combat/MagicDamageCalculator.ts b/packages/shared/src/systems/shared/combat/MagicDamageCalculator.ts index 36d9c6b07..820c4943f 100644 --- a/packages/shared/src/systems/shared/combat/MagicDamageCalculator.ts +++ b/packages/shared/src/systems/shared/combat/MagicDamageCalculator.ts @@ -1,5 +1,5 @@ /** - * MagicDamageCalculator - OSRS-accurate magic damage formulas + * MagicDamageCalculator - rules-accurate magic damage formulas * * Key differences from melee/ranged: * - Magic defense for PLAYERS = 0.7 * magicLevel + 0.3 * defenseLevel @@ -11,8 +11,6 @@ * Defense Roll (player) = floor(0.7 * magicLevel + 0.3 * defenseLevel + 9) * (magicDefenseBonus + 64) * Defense Roll (NPC) = (magicLevel + 9) * (magicDefenseBonus + 64) * - * @see https://oldschool.runescape.wiki/w/Damage_per_second/Magic - * @see https://oldschool.runescape.wiki/w/Magic_Damage */ import { @@ -145,7 +143,7 @@ function calculateNpcMagicDefenseRoll( } /** - * Calculate magic damage using OSRS-accurate formulas + * Calculate magic damage using rules-accurate formulas * * @param params - Magic damage calculation parameters * @param rng - Optional seeded random number generator diff --git a/packages/shared/src/systems/shared/combat/PlayerDeathSystem.ts b/packages/shared/src/systems/shared/combat/PlayerDeathSystem.ts index ac4a9dbb6..3fd04c252 100644 --- a/packages/shared/src/systems/shared/combat/PlayerDeathSystem.ts +++ b/packages/shared/src/systems/shared/combat/PlayerDeathSystem.ts @@ -42,7 +42,6 @@ import { /** * Orchestrates player death via modular handlers (zone detection, safe area, wilderness). * Safe zones: gravestone (5min) → ground (2min). Wilderness: ground immediately (2min). - * @see https://oldschool.runescape.wiki/w/Death */ export class PlayerDeathSystem extends SystemBase { private deathLocations = new Map(); @@ -65,7 +64,7 @@ export class PlayerDeathSystem extends SystemBase { } >(); - // OSRS-style: Items kept on death (top 3 most valuable) — returned on respawn. + // classic MMORPG-style: Items kept on death (top 3 most valuable) — returned on respawn. // In-memory for fast access; also persisted in death lock (keptItems field) for // crash recovery. On respawn, in-memory is preferred; on reconnect after crash, // DeathStateManager loads keptItems from DB. @@ -393,7 +392,7 @@ export class PlayerDeathSystem extends SystemBase { }); } - // Award combat XP to the killer - duels should grant XP (OSRS-accurate) + // Award combat XP to the killer - duels should grant XP (rules-accurate) // Pass killedBy directly since CombatSystem clears attacker states on ENTITY_DEATH // before PlayerDeathSystem runs, making stateService queries unreliable this.emitCombatKillForPvP(playerId, data.killedBy); @@ -564,7 +563,7 @@ export class PlayerDeathSystem extends SystemBase { } // Check for existing death lock - if player dies again before looting, clear old one - // This matches OSRS behavior where dying again replaces your old gravestone + // This matches classic MMORPG behavior where dying again replaces your old gravestone const existingDeathLock = await this.deathStateManager.getDeathLock(playerId); if (existingDeathLock) { @@ -654,7 +653,7 @@ export class PlayerDeathSystem extends SystemBase { const allItems = [...inventoryItems, ...equipmentItems]; const zoneType = this.zoneDetection.getZoneType(deathPosition); - // OSRS-style: In safe zones, keep 3 most valuable items + // classic MMORPG-style: In safe zones, keep 3 most valuable items if (zoneType === ZoneType.SAFE_AREA) { const split = splitItemsForSafeDeath(allItems, ITEMS_KEPT_ON_DEATH); itemsToDrop = split.dropped; @@ -769,7 +768,7 @@ export class PlayerDeathSystem extends SystemBase { killedBy: string, keptItems?: InventoryItem[], ): void { - // Store items to return on respawn (OSRS keep-3) + // Store items to return on respawn (classic MMORPG keep-3) if (keptItems && keptItems.length > 0) { this.itemsKeptOnDeath.set(playerId, keptItems); } @@ -1184,7 +1183,7 @@ export class PlayerDeathSystem extends SystemBase { playerId, }); - // OSRS-style: Return kept items to inventory after respawn. + // classic MMORPG-style: Return kept items to inventory after respawn. // Prefer in-memory (fast path), fall back to death lock DB (crash recovery). let keptItems = this.itemsKeptOnDeath.get(playerId); if (!keptItems || keptItems.length === 0) { @@ -1372,7 +1371,7 @@ export class PlayerDeathSystem extends SystemBase { }); } - // Immediately trigger respawn (RuneScape-style - no waiting, no screen) + // Immediately trigger respawn (classic fantasy MMORPG-style - no waiting, no screen) // Very short delay, then auto-respawn (just enough for world to load) const reconnectTimer = setTimeout(() => { this.respawnTimers.delete(playerId); diff --git a/packages/shared/src/systems/shared/combat/RangedDamageCalculator.ts b/packages/shared/src/systems/shared/combat/RangedDamageCalculator.ts index 210dac940..591aa402d 100644 --- a/packages/shared/src/systems/shared/combat/RangedDamageCalculator.ts +++ b/packages/shared/src/systems/shared/combat/RangedDamageCalculator.ts @@ -1,5 +1,5 @@ /** - * RangedDamageCalculator - OSRS-accurate ranged damage formulas + * RangedDamageCalculator - rules-accurate ranged damage formulas * * Effective Level = floor(rangedLevel * prayerBonus) + styleBonus + 8 * Attack Roll = effectiveLevel * (equipmentBonus + 64) @@ -11,7 +11,6 @@ * * Max Hit = floor(0.5 + effectiveStr * (strengthBonus + 64) / 640) * - * @see https://oldschool.runescape.wiki/w/Damage_per_second/Ranged */ import { @@ -138,7 +137,7 @@ function calculateRangedMaxHit( } /** - * Calculate ranged damage using OSRS-accurate formulas + * Calculate ranged damage using rules-accurate formulas * * @param params - Ranged damage calculation parameters * @param rng - Optional seeded random number generator diff --git a/packages/shared/src/systems/shared/combat/__tests__/AggroSystem.test.ts b/packages/shared/src/systems/shared/combat/__tests__/AggroSystem.test.ts index 273c8c1f4..42253594d 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/AggroSystem.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/AggroSystem.test.ts @@ -216,7 +216,7 @@ describe("AggroSystem", () => { }); describe("DEFAULTS.NPC constants", () => { - it("has OSRS-accurate aggroRange of 4", () => { + it("has rules-accurate aggroRange of 4", () => { expect(COMBAT_CONSTANTS.DEFAULTS.NPC.AGGRO_RANGE).toBe(4); }); @@ -224,11 +224,11 @@ describe("AggroSystem", () => { expect(COMBAT_CONSTANTS.DEFAULTS.NPC.LEASH_RANGE).toBe(42); }); - it("has OSRS-accurate attackSpeedTicks of 4", () => { + it("has rules-accurate attackSpeedTicks of 4", () => { expect(COMBAT_CONSTANTS.DEFAULTS.NPC.ATTACK_SPEED_TICKS).toBe(4); }); - it("has OSRS-accurate respawnTicks of 25", () => { + it("has rules-accurate respawnTicks of 25", () => { expect(COMBAT_CONSTANTS.DEFAULTS.NPC.RESPAWN_TICKS).toBe(25); }); }); @@ -262,7 +262,7 @@ describe("AggroSystem", () => { expect(skills.constitution).toBe(55); }); - it("returns OSRS default skills when player not cached", () => { + it("returns classic MMORPG default skills when player not cached", () => { const privateSystem = system as unknown as { getPlayerSkills: (playerId: string) => { attack: number; @@ -276,13 +276,13 @@ describe("AggroSystem", () => { expect(skills.attack).toBe(1); expect(skills.strength).toBe(1); expect(skills.defense).toBe(1); - // OSRS: Hitpoints starts at 10, not 1 + // classic MMORPG: Hitpoints starts at 10, not 1 expect(skills.constitution).toBe(10); }); }); describe("combat level calculation", () => { - it("calculates combat level using OSRS formula", () => { + it("calculates combat level using classic combat formula", () => { const privateSystem = system as unknown as { playerSkills: Map< string, @@ -291,8 +291,8 @@ describe("AggroSystem", () => { getPlayerCombatLevel: (playerId: string) => number; }; - // Set skills for OSRS formula test - // OSRS Combat Level = floor(Base + max(Melee, Ranged, Magic)) + // Set skills for classic combat formula test + // classic MMORPG Combat Level = floor(Base + max(Melee, Ranged, Magic)) // Base = 0.25 * (Defence + Hitpoints + floor(Prayer / 2)) // Melee = 0.325 * (Attack + Strength) // @@ -311,7 +311,7 @@ describe("AggroSystem", () => { expect(combatLevel).toBe(54); }); - it("returns minimum level 3 for new players (OSRS-accurate)", () => { + it("returns minimum level 3 for new players (rules-accurate)", () => { const privateSystem = system as unknown as { playerSkills: Map< string, @@ -320,7 +320,7 @@ describe("AggroSystem", () => { getPlayerCombatLevel: (playerId: string) => number; }; - // OSRS fresh character: All skills at 1, Hitpoints at 10 + // classic MMORPG fresh character: All skills at 1, Hitpoints at 10 // Base = 0.25 * (1 + 10 + 0) = 2.75 // Melee = 0.325 * (1 + 1) = 0.65 // Combat Level = floor(2.75 + 0.65) = 3 @@ -328,20 +328,20 @@ describe("AggroSystem", () => { attack: { level: 1, xp: 0 }, strength: { level: 1, xp: 0 }, defense: { level: 1, xp: 0 }, - constitution: { level: 10, xp: 0 }, // OSRS: Hitpoints starts at 10 + constitution: { level: 10, xp: 0 }, // classic MMORPG: Hitpoints starts at 10 }); const combatLevel = privateSystem.getPlayerCombatLevel("player1"); expect(combatLevel).toBe(3); }); - it("returns level 3 for unknown player (OSRS default)", () => { + it("returns level 3 for unknown player (classic MMORPG default)", () => { const privateSystem = system as unknown as { getPlayerCombatLevel: (playerId: string) => number; }; - // Unknown player uses OSRS defaults: all 1 except Hitpoints=10 - // Combat level = 3 (OSRS starting combat level) + // Unknown player uses classic MMORPG defaults: all 1 except Hitpoints=10 + // Combat level = 3 (classic MMORPG starting combat level) const combatLevel = privateSystem.getPlayerCombatLevel("unknown_player"); expect(combatLevel).toBe(3); }); @@ -399,7 +399,7 @@ describe("AggroSystem", () => { }); // With levelIgnore 999 (toleranceImmune), mob always aggros - // Note: actual result depends on OSRS double-level rule and tolerance timer + // Note: actual result depends on classic MMORPG double-level rule and tolerance timer // This test verifies the toleranceImmune check works const shouldAggro = privateSystem.shouldMobAggroPlayer( mobState, @@ -885,7 +885,7 @@ describe("AggroSystem", () => { }); describe("combat level boundary conditions", () => { - it("handles all skills at level 1 (minimum OSRS state)", () => { + it("handles all skills at level 1 (minimum classic MMORPG state)", () => { const privateSystem = system as unknown as { playerSkills: Map< string, @@ -894,7 +894,7 @@ describe("AggroSystem", () => { getPlayerCombatLevel: (playerId: string) => number; }; - // All skills at 1 except constitution at 10 (OSRS starting state) + // All skills at 1 except constitution at 10 (classic MMORPG starting state) privateSystem.playerSkills.set("player1", { attack: { level: 1, xp: 0 }, strength: { level: 1, xp: 0 }, @@ -906,10 +906,10 @@ describe("AggroSystem", () => { }); const level = privateSystem.getPlayerCombatLevel("player1"); - expect(level).toBe(3); // OSRS minimum combat level + expect(level).toBe(3); // classic MMORPG minimum combat level }); - it("handles all skills at level 99 (maximum OSRS state)", () => { + it("handles all skills at level 99 (maximum classic MMORPG state)", () => { const privateSystem = system as unknown as { playerSkills: Map< string, @@ -929,7 +929,7 @@ describe("AggroSystem", () => { }); const level = privateSystem.getPlayerCombatLevel("player1"); - expect(level).toBe(126); // OSRS maximum combat level + expect(level).toBe(126); // classic MMORPG maximum combat level }); it("handles ranged-based combat level correctly", () => { @@ -1101,7 +1101,7 @@ describe("AggroSystem", () => { expect(skills.attack).toBe(50); expect(skills.strength).toBe(1); // Default expect(skills.defense).toBe(1); // Default - expect(skills.constitution).toBe(10); // OSRS default for hitpoints + expect(skills.constitution).toBe(10); // classic MMORPG default for hitpoints }); it("handles updateMobPosition with invalid data", () => { diff --git a/packages/shared/src/systems/shared/combat/__tests__/AutoRetaliateMovement.test.ts b/packages/shared/src/systems/shared/combat/__tests__/AutoRetaliateMovement.test.ts index 452e25b3b..8c3e09b27 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/AutoRetaliateMovement.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/AutoRetaliateMovement.test.ts @@ -1,14 +1,13 @@ /** - * OSRS-Accurate Auto-Retaliate Movement Tests + * Rules-Accurate Auto-Retaliate Movement Tests * - * Tests the critical OSRS behavior: when auto-retaliate triggers, + * Tests the critical classic MMORPG behavior: when auto-retaliate triggers, * the player's movement destination is REPLACED with the attacker's position. * - * Key OSRS behaviors tested: + * Key classic MMORPG behaviors tested: * - Auto-retaliate ON: Player moves toward attacker (cancels "run away" movement) * - Auto-retaliate OFF: Player keeps their current movement (can run away) * - * @see https://oldschool.runescape.wiki/w/Auto_Retaliate * "the player's character walks/runs towards the monster attacking and fights back" */ @@ -241,7 +240,7 @@ function createTestWorld(options: { currentTick?: number } = {}) { }; } -describe("OSRS Auto-Retaliate Movement", () => { +describe("classic MMORPG Auto-Retaliate Movement", () => { let combatSystem: CombatSystem; let world: ReturnType; @@ -506,7 +505,7 @@ describe("OSRS Auto-Retaliate Movement", () => { }); }); - describe("OSRS-accurate auto-retaliate interrupts movement", () => { + describe("rules-accurate auto-retaliate interrupts movement", () => { it("emits COMBAT_FOLLOW_TARGET when mob with extended range attacks moving player", () => { // Player is actively moving (tileMovementActive = true) // Mob with range 2 attacks, player needs to close distance diff --git a/packages/shared/src/systems/shared/combat/__tests__/CombatFlow.integration.test.ts b/packages/shared/src/systems/shared/combat/__tests__/CombatFlow.integration.test.ts index ba618af8c..66906a63e 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/CombatFlow.integration.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/CombatFlow.integration.test.ts @@ -364,7 +364,7 @@ describe("CombatFlow Integration", () => { describe("full player-vs-mob combat cycle", () => { it("completes combat from start to mob death", () => { - // Setup: Player near a low-health mob (cardinal adjacent for OSRS melee) + // Setup: Player near a low-health mob (cardinal adjacent for classic MMORPG melee) const player = createTestPlayer("player1", { position: { x: 0.5, y: 0, z: 0.5 }, stats: { attack: 50, strength: 50, defence: 10 }, @@ -996,16 +996,15 @@ describe("CombatFlow Integration", () => { }); /** - * OSRS-accurate auto-retaliate target persistence tests + * rules-accurate auto-retaliate target persistence tests * - * @see https://oldschool.runescape.wiki/w/Auto_Retaliate * @see AUTO_RETALIATE_FIX_PLAN.md * - * In OSRS, auto-retaliate ONLY triggers when the player has NO current target. + * In classic MMORPG, auto-retaliate ONLY triggers when the player has NO current target. * When player is already fighting an enemy, getting attacked by another enemy * does NOT cause the player to switch targets. */ - describe("OSRS-accurate auto-retaliate target persistence", () => { + describe("rules-accurate auto-retaliate target persistence", () => { it("does NOT switch targets when attacked by second enemy while fighting", () => { // Setup: Player with two mobs at different positions const player = createTestPlayer("player1", { @@ -1045,7 +1044,7 @@ describe("CombatFlow Integration", () => { }); // Assert: Player should STILL be targeting mob1, NOT mob2 - // This is the OSRS-accurate behavior + // This is the rules-accurate behavior const afterState = combatSystem.getCombatData("player1"); expect(afterState?.targetId).toBe("mob1"); expect(afterState?.targetId).not.toBe("mob2"); @@ -1126,7 +1125,7 @@ describe("CombatFlow Integration", () => { targetType: "player", }); - // STILL targeting mob1 - OSRS accurate + // STILL targeting mob1 - rules-accurate expect(combatSystem.getCombatData("player1")?.targetId).toBe("mob1"); // Process some combat ticks diff --git a/packages/shared/src/systems/shared/combat/__tests__/CombatMeleeRange.integration.test.ts b/packages/shared/src/systems/shared/combat/__tests__/CombatMeleeRange.integration.test.ts index 19866c8ff..7b1909f34 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/CombatMeleeRange.integration.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/CombatMeleeRange.integration.test.ts @@ -1,13 +1,12 @@ /** - * OSRS Melee Range Integration Tests + * classic MMORPG Melee Range Integration Tests * - * End-to-end tests for OSRS-accurate melee combat range mechanics: + * End-to-end tests for rules-accurate melee combat range mechanics: * - Range 1 (standard melee): CARDINAL ONLY (N/S/E/W) * - Range 2+ (halberd/spear): Allows diagonal (Chebyshev distance) * - Walk-to-attack pathing for out-of-range targets * - Infinite follow behavior (no timeout) * - * @see https://oldschool.runescape.wiki/w/Attack_range */ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; @@ -248,7 +247,7 @@ function createTestWorld(options: { currentTick?: number } = {}) { }; } -describe("OSRS Melee Range Integration", () => { +describe("classic MMORPG Melee Range Integration", () => { let combatSystem: CombatSystem; let world: ReturnType; @@ -883,7 +882,7 @@ describe("OSRS Melee Range Integration", () => { }); }); - describe("combat timeout behavior (OSRS-style)", () => { + describe("combat timeout behavior (classic MMORPG-style)", () => { it("combat timeout is extended when follow events are emitted", () => { const player = createTestPlayer("player1", { position: { x: 5.5, y: 0, z: 5.5 }, diff --git a/packages/shared/src/systems/shared/combat/__tests__/CombatSystem.eatDelay.test.ts b/packages/shared/src/systems/shared/combat/__tests__/CombatSystem.eatDelay.test.ts index 9b690618d..92daa5a42 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/CombatSystem.eatDelay.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/CombatSystem.eatDelay.test.ts @@ -1,7 +1,7 @@ /** * CombatSystem Eat Delay Integration Tests * - * Tests for OSRS-accurate attack delay when eating during combat: + * Tests for rules-accurate attack delay when eating during combat: * - isPlayerOnAttackCooldown() detection * - addAttackDelay() application * - Correct integration with nextAttackTicks and CombatData @@ -37,7 +37,7 @@ class CombatSystemEatDelayTester { /** * Add delay ticks to player's next attack - * Used by eating system (OSRS: eating during combat adds 3 tick delay) + * Used by eating system (classic MMORPG: eating during combat adds 3 tick delay) */ addAttackDelay(playerId: string, delayTicks: number): void { const typedPlayerId = createEntityID(playerId); @@ -53,7 +53,7 @@ class CombatSystemEatDelayTester { combatData.nextAttackTick += delayTicks; } } - // If no current cooldown, do nothing (OSRS-accurate: no delay if weapon ready) + // If no current cooldown, do nothing (rules-accurate: no delay if weapon ready) } // Helper: Set attack cooldown for testing @@ -131,7 +131,7 @@ describe("CombatSystem - Eat Delay Integration", () => { expect(combatSystem.nextAttackTicks.get(typedId)).toBe(113); }); - it("does nothing when no existing cooldown (OSRS-accurate)", () => { + it("does nothing when no existing cooldown (rules-accurate)", () => { // Player has no cooldown entry - weapon is ready combatSystem.addAttackDelay( "player-1", @@ -175,7 +175,7 @@ describe("CombatSystem - Eat Delay Integration", () => { }); }); - describe("OSRS attack delay constants", () => { + describe("classic MMORPG attack delay constants", () => { it("uses exactly 3 ticks for eat attack delay", () => { expect(COMBAT_CONSTANTS.EAT_ATTACK_DELAY_TICKS).toBe(3); }); diff --git a/packages/shared/src/systems/shared/combat/__tests__/CombatSystem.test.ts b/packages/shared/src/systems/shared/combat/__tests__/CombatSystem.test.ts index 305261b54..b1282fd98 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/CombatSystem.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/CombatSystem.test.ts @@ -148,7 +148,7 @@ function createMockPlayer( // Mock mob entity // NOTE: Default position (1, 0, 0) is CARDINAL adjacent to player at (0, 0, 0) -// OSRS melee range 1 requires cardinal adjacency (no diagonal attacks) +// classic MMORPG melee range 1 requires cardinal adjacency (no diagonal attacks) function createMockMob( id: string, health: number = 50, @@ -596,7 +596,7 @@ describe("CombatSystem", () => { }); const states = combatSystem.stateService.getAllCombatStates(); - // OSRS-style: Both attacker and target enter combat (mutual combat) + // classic MMORPG-style: Both attacker and target enter combat (mutual combat) expect(states.length).toBeGreaterThanOrEqual(1); // Verify player is in combat expect(combatSystem.isInCombat("player1")).toBe(true); diff --git a/packages/shared/src/systems/shared/combat/__tests__/CombatSystemPerformance.test.ts b/packages/shared/src/systems/shared/combat/__tests__/CombatSystemPerformance.test.ts index 2809479b9..b45d45d62 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/CombatSystemPerformance.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/CombatSystemPerformance.test.ts @@ -313,7 +313,7 @@ describe("CombatSystem Performance", () => { describe("Attack Timing Simulation", () => { it("simulates realistic combat tick with mixed attack speeds", () => { // Setup combats with different weapon speeds - const attackSpeeds = [3, 4, 5, 6, 7]; // OSRS weapon speed tiers + const attackSpeeds = [3, 4, 5, 6, 7]; // classic MMORPG weapon speed tiers for (let i = 0; i < 100; i++) { const speed = attackSpeeds[i % attackSpeeds.length]; diff --git a/packages/shared/src/systems/shared/combat/__tests__/DeathUtils.test.ts b/packages/shared/src/systems/shared/combat/__tests__/DeathUtils.test.ts index 43ae4bbff..b7f1d8f72 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/DeathUtils.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/DeathUtils.test.ts @@ -5,7 +5,7 @@ * * Key behaviors tested: * - sanitizeKilledBy: XSS prevention, Unicode normalization, injection defense - * - splitItemsForSafeDeath: OSRS keep-3 logic, stack handling, value sorting + * - splitItemsForSafeDeath: classic MMORPG keep-3 logic, stack handling, value sorting * - validatePosition: NaN/Infinity rejection, world-bounds clamping * - isPositionInBounds: boundary detection without clamping * - isValidPositionNumber: finite number validation @@ -496,7 +496,7 @@ describe("isValidPositionNumber", () => { // ─── ITEMS_KEPT_ON_DEATH constant ──────────────────────────────────────────── describe("ITEMS_KEPT_ON_DEATH", () => { - it("is 3 (OSRS standard)", () => { + it("is 3 (classic MMORPG standard)", () => { expect(ITEMS_KEPT_ON_DEATH).toBe(3); }); }); diff --git a/packages/shared/src/systems/shared/combat/__tests__/LeashBehavior.test.ts b/packages/shared/src/systems/shared/combat/__tests__/LeashBehavior.test.ts index 7116a8102..38b9a9636 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/LeashBehavior.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/LeashBehavior.test.ts @@ -1,18 +1,17 @@ /** - * OSRS-Accurate Leash Behavior Tests + * Rules-Accurate Leash Behavior Tests * * Tests the two-tier range system and leash behavior: * - wanderRadius: Area where NPCs randomly wander (smaller, ~5 tiles) * - leashRange: Maximum chase distance from spawn (larger, ~10 tiles) * - * Key OSRS behaviors tested: + * Key classic MMORPG behaviors tested: * - NPCs can chase beyond wander radius but within leash range * - NPCs stop in place when exceeding leash range (no walk-back) * - NPCs transition to IDLE, not RETURN, when leashed * - Wander targets are relative to spawn (natural drift back) * - * @see https://oldschool.runescape.wiki/w/Aggression - * @see OSRS_LEASH_BEHAVIOR_PLAN.md + * @see LEASH_BEHAVIOR_PLAN.md */ import { describe, it, expect } from "vitest"; @@ -78,7 +77,7 @@ function createMockContext( getTime: () => Date.now(), markNetworkDirty: () => {}, emitEvent: () => {}, - // Entity occupancy for OSRS-accurate collision + // Entity occupancy for rules-accurate collision getEntityId: () => "test-mob-1", getEntityOccupancy: () => ({ isBlocked: () => false, @@ -96,7 +95,7 @@ function createMockContext( }; } -describe("OSRS-Accurate Leash Behavior", () => { +describe("Rules-Accurate Leash Behavior", () => { describe("two-tier range system", () => { it("allows NPC to chase beyond wander radius but within leash range", () => { const chaseState = new ChaseState(); @@ -137,7 +136,7 @@ describe("OSRS-Accurate Leash Behavior", () => { chaseState.enter(context); const nextState = chaseState.update(context, 0.016); - // RS-accurate: Mob returns to spawn when exceeding leash range + // Rules-accurate: Mob returns to spawn when exceeding leash range expect(nextState).toBe(MobAIState.RETURN); }); @@ -180,7 +179,7 @@ describe("OSRS-Accurate Leash Behavior", () => { chaseState.enter(context); const nextState = chaseState.update(context, 0.016); - // RS-accurate: Mob returns to spawn when player exceeds aggression range + // Rules-accurate: Mob returns to spawn when player exceeds aggression range // Prevents ranged farming exploit where mobs stand idle at leash edge expect(nextState).toBe(MobAIState.RETURN); }); @@ -199,7 +198,7 @@ describe("OSRS-Accurate Leash Behavior", () => { attackState.enter(context); const nextState = attackState.update(context, 0.016); - // RS-accurate: Mob returns to spawn when player exceeds aggression range + // Rules-accurate: Mob returns to spawn when player exceeds aggression range // Prevents ranged farming exploit where mobs stand idle at leash edge expect(nextState).toBe(MobAIState.RETURN); }); @@ -256,7 +255,7 @@ describe("OSRS-Accurate Leash Behavior", () => { const chaseState = new ChaseState(); // Player at exactly aggression range (leashRange + combatRange = 11) - // OSRS-accurate: Leash is based on PLAYER distance from spawn, not mob distance + // rules-accurate: Leash is based on PLAYER distance from spawn, not mob distance const context = createMockContext({ distanceFromSpawn: 10, leashRange: 10, @@ -278,7 +277,7 @@ describe("OSRS-Accurate Leash Behavior", () => { const chaseState = new ChaseState(); // Player just beyond aggression range - // RS-accurate: Leash is based on PLAYER distance from spawn + // Rules-accurate: Leash is based on PLAYER distance from spawn const context = createMockContext({ distanceFromSpawn: 10, leashRange: 10, @@ -291,7 +290,7 @@ describe("OSRS-Accurate Leash Behavior", () => { chaseState.enter(context); const nextState = chaseState.update(context, 0.016); - // RS-accurate: Mob returns to spawn when player exceeds aggression range + // Rules-accurate: Mob returns to spawn when player exceeds aggression range expect(nextState).toBe(MobAIState.RETURN); }); @@ -327,7 +326,7 @@ describe("OSRS-Accurate Leash Behavior", () => { chaseState.enter(context); const nextState = chaseState.update(context, 0.016); - // RS-accurate: Mob returns to spawn when exceeding leash range + // Rules-accurate: Mob returns to spawn when exceeding leash range expect(nextState).toBe(MobAIState.RETURN); }); diff --git a/packages/shared/src/systems/shared/combat/__tests__/MagicDamageCalculator.test.ts b/packages/shared/src/systems/shared/combat/__tests__/MagicDamageCalculator.test.ts index dab5ee455..891590c08 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/MagicDamageCalculator.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/MagicDamageCalculator.test.ts @@ -1,7 +1,7 @@ /** * MagicDamageCalculator Unit Tests * - * Tests OSRS-accurate magic damage formulas: + * Tests rules-accurate magic damage formulas: * - Player defense: 0.7 * magicLevel + 0.3 * defenseLevel * - NPC defense: uses only magic level * - Max hit determined by spell diff --git a/packages/shared/src/systems/shared/combat/__tests__/MobAggro.integration.test.ts b/packages/shared/src/systems/shared/combat/__tests__/MobAggro.integration.test.ts index be8b2c939..e6b1f556b 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/MobAggro.integration.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/MobAggro.integration.test.ts @@ -1,7 +1,7 @@ /** * Mob Aggro Integration Tests * - * End-to-end tests for OSRS-accurate mob aggro, pathfinding, and combat mechanics: + * End-to-end tests for rules-accurate mob aggro, pathfinding, and combat mechanics: * - Safespot mechanics (dumb pathfinder getting stuck) * - Corner-cutting prevention * - Large NPC (2x2, 3x3) attack range from all occupied tiles @@ -10,7 +10,6 @@ * - Hunt range vs attack range distinction * * @see MOB_AGGRO_IMPLEMENTATION_PLAN.md Phase 5.2 - * @see https://oldschool.runescape.wiki/w/Pathfinding */ import { describe, it, expect, beforeEach } from "vitest"; @@ -137,7 +136,7 @@ describe("Mob Aggro Integration", () => { }); /** - * OSRS corner-cutting rule: + * classic MMORPG corner-cutting rule: * To move diagonally, BOTH adjacent cardinal tiles must be walkable. * * [ ][B] @@ -388,7 +387,7 @@ describe("Mob Aggro Integration", () => { describe("first-attack timing", () => { /** - * OSRS: When NPC enters combat range, first attack is on NEXT tick. + * classic MMORPG: When NPC enters combat range, first attack is on NEXT tick. */ it("first attack delayed by 1 tick after entering combat range", () => { const combatManager = new CombatStateManager({ diff --git a/packages/shared/src/systems/shared/combat/__tests__/PidManager.test.ts b/packages/shared/src/systems/shared/combat/__tests__/PidManager.test.ts index d0ab3c380..582ed0666 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/PidManager.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/PidManager.test.ts @@ -1,7 +1,7 @@ /** * PidManager Unit Tests * - * Tests for OSRS-style Player ID (PID) combat priority system: + * Tests for classic MMORPG-style Player ID (PID) combat priority system: * - PID assignment on player join * - PID removal on player leave * - Combat priority comparison (lower PID = higher priority) @@ -9,7 +9,6 @@ * - Periodic PID shuffle for fairness * - Statistics and debugging * - * @see https://oldschool.runescape.wiki/w/PID */ import { describe, it, expect, beforeEach } from "vitest"; diff --git a/packages/shared/src/systems/shared/combat/__tests__/RangeSystem.test.ts b/packages/shared/src/systems/shared/combat/__tests__/RangeSystem.test.ts index 2ba7fc33f..46e456617 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/RangeSystem.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/RangeSystem.test.ts @@ -1,7 +1,7 @@ /** * RangeSystem Unit Tests * - * Tests OSRS-accurate range calculations for NPC aggro and combat. + * Tests rules-accurate range calculations for NPC aggro and combat. * * Key behaviors tested: * - Hunt range (SW tile origin) @@ -10,7 +10,6 @@ * - Large NPC tile occupation * - Melee range 1 diagonal exclusion * - * @see https://oldschool.runescape.wiki/w/Aggressiveness * @see MOB_AGGRO_IMPLEMENTATION_PLAN.md Phase 2.2 */ @@ -301,7 +300,7 @@ describe("RangeSystem", () => { ); }); - it("returns false for diagonal adjacent tiles (range 1 - OSRS rule)", () => { + it("returns false for diagonal adjacent tiles (range 1 - classic MMORPG rule)", () => { const npc = createNPC(5, 5, 1, AttackType.MELEE); // NE diagonal diff --git a/packages/shared/src/systems/shared/combat/__tests__/RangedDamageCalculator.test.ts b/packages/shared/src/systems/shared/combat/__tests__/RangedDamageCalculator.test.ts index b95f645fb..4a86fe712 100644 --- a/packages/shared/src/systems/shared/combat/__tests__/RangedDamageCalculator.test.ts +++ b/packages/shared/src/systems/shared/combat/__tests__/RangedDamageCalculator.test.ts @@ -1,7 +1,7 @@ /** * RangedDamageCalculator Unit Tests * - * Tests OSRS-accurate ranged damage formulas: + * Tests rules-accurate ranged damage formulas: * - Effective level calculation with style bonuses * - Attack roll formula * - Defense roll formula diff --git a/packages/shared/src/systems/shared/combat/handlers/MagicAttackHandler.ts b/packages/shared/src/systems/shared/combat/handlers/MagicAttackHandler.ts index 12fecd52b..88eca23bd 100644 --- a/packages/shared/src/systems/shared/combat/handlers/MagicAttackHandler.ts +++ b/packages/shared/src/systems/shared/combat/handlers/MagicAttackHandler.ts @@ -372,7 +372,7 @@ export class MagicAttackHandler { return; } - // Resolve magic style before range check so longrange +2 applies (OSRS-accurate) + // Resolve magic style before range check so longrange +2 applies (rules-accurate) let magicStyle: MagicCombatStyle = "accurate"; const magicStyleData = this.ctx.playerSystem?.getPlayerAttackStyle?.(attackerId); @@ -383,7 +383,7 @@ export class MagicAttackHandler { } } - // Check magic attack range — longrange style adds +2 tiles (OSRS-accurate) + // Check magic attack range — longrange style adds +2 tiles (rules-accurate) const attackRange = 10 + MAGIC_STYLE_BONUSES[magicStyle].rangeModifier; const distance = checkProjectileRange( this.ctx, @@ -578,7 +578,7 @@ export class MagicAttackHandler { ? prayerSystem?.getCombinedBonuses(String(target.id)) : undefined; - // Get player's combat style for OSRS-accurate damage bonuses + // Get player's combat style for rules-accurate damage bonuses let magicStyle: MagicCombatStyle = "accurate"; const styleData = this.ctx.playerSystem?.getPlayerAttackStyle?.(attackerId); if (styleData?.id) { diff --git a/packages/shared/src/systems/shared/combat/handlers/MeleeAttackHandler.ts b/packages/shared/src/systems/shared/combat/handlers/MeleeAttackHandler.ts index c652b1073..dab262f8a 100644 --- a/packages/shared/src/systems/shared/combat/handlers/MeleeAttackHandler.ts +++ b/packages/shared/src/systems/shared/combat/handlers/MeleeAttackHandler.ts @@ -222,11 +222,10 @@ export class MeleeAttackHandler { /** * Check if attacker is within combat range of target * - * OSRS melee rules (from wiki): + * classic MMORPG melee rules (from wiki): * - Range 1 (standard melee): Cardinal only (N/S/E/W) - NO diagonal attacks * - Range 2+ (halberd): Allows diagonal attacks * - * @see https://oldschool.runescape.wiki/w/Attack_range */ private isWithinCombatRange( attacker: Entity | MobEntity, @@ -247,7 +246,7 @@ export class MeleeAttackHandler { attackerType, ); - // OSRS-accurate melee range check: + // rules-accurate melee range check: // - Range 1: Cardinal only (N/S/E/W) // - Range 2+: Allows diagonal (Chebyshev distance) if ( @@ -323,7 +322,7 @@ export class MeleeAttackHandler { currentTick + attackSpeedTicks, ); - // Get player's combat style for OSRS-accurate damage bonuses + // Get player's combat style for rules-accurate damage bonuses let combatStyle: CombatStyle = "accurate"; if (attackerType === "player") { const styleData = diff --git a/packages/shared/src/systems/shared/combat/handlers/PlayerDamageHandler.ts b/packages/shared/src/systems/shared/combat/handlers/PlayerDamageHandler.ts index 7489f7bab..ec4ce6fc4 100644 --- a/packages/shared/src/systems/shared/combat/handlers/PlayerDamageHandler.ts +++ b/packages/shared/src/systems/shared/combat/handlers/PlayerDamageHandler.ts @@ -89,7 +89,7 @@ export class PlayerDamageHandler implements DamageHandler { return { actualDamage: 0, targetDied: false, success: false }; } - // Handle 0 damage as a valid combat outcome (OSRS miss/block) + // Handle 0 damage as a valid combat outcome (classic MMORPG miss/block) // PlayerSystem.damagePlayer() returns false for amount <= 0, which would // trigger a false positive "Failed to apply damage" error in CombatSystem if (damage <= 0) { @@ -143,7 +143,7 @@ export class PlayerDamageHandler implements DamageHandler { canRetaliate(entityId: EntityID, _currentTick: number): boolean { if (!this.playerSystem) { - // Default to OSRS behavior (auto-retaliate on) + // Default to classic MMORPG behavior (auto-retaliate on) return true; } diff --git a/packages/shared/src/systems/shared/combat/handlers/RangedAttackHandler.ts b/packages/shared/src/systems/shared/combat/handlers/RangedAttackHandler.ts index 851f0a257..473d24d4a 100644 --- a/packages/shared/src/systems/shared/combat/handlers/RangedAttackHandler.ts +++ b/packages/shared/src/systems/shared/combat/handlers/RangedAttackHandler.ts @@ -336,7 +336,7 @@ export class RangedAttackHandler { return; } - // Resolve ranged style before range check so longrange +2 applies (OSRS-accurate) + // Resolve ranged style before range check so longrange +2 applies (rules-accurate) let rangedStyle: RangedCombatStyle = "accurate"; const styleData = this.ctx.playerSystem?.getPlayerAttackStyle?.(attackerId); if (styleData?.id) { @@ -347,7 +347,7 @@ export class RangedAttackHandler { } const styleBonus = RANGED_STYLE_BONUSES[rangedStyle]; - // Check ranged attack range — longrange style adds +2 tiles (OSRS-accurate) + // Check ranged attack range — longrange style adds +2 tiles (rules-accurate) const attackRange = (weapon?.attackRange ?? 7) + styleBonus.rangeModifier; const distance = checkProjectileRange( this.ctx, @@ -421,7 +421,7 @@ export class RangedAttackHandler { this.ctx.projectileService.createProjectile(projectileParams); - // OSRS: Consume one arrow from equipment on fire + // classic MMORPG: Consume one arrow from equipment on fire this.ctx.emitTypedEvent(EventType.EQUIPMENT_CONSUME_ARROW, { playerId: attackerId, }); @@ -473,7 +473,7 @@ export class RangedAttackHandler { ? target.getMobData().defense : this.ctx.getPlayerSkillLevel(String(target.id), "defense"); - // Use per-style defenseRanged from equipment (OSRS combat triangle). + // Use per-style defenseRanged from equipment (classic MMORPG combat triangle). // Falls back to generic ranged bonus for backward compatibility. const targetEquipStats = this.ctx.playerEquipmentStats.get( String(target.id), @@ -495,7 +495,7 @@ export class RangedAttackHandler { // Do NOT add arrowStrength separately as that would double-count it const rangedStrengthBonus = equipmentStats?.rangedStrength ?? arrowStrength; - // Get player's combat style for OSRS-accurate damage bonuses + // Get player's combat style for rules-accurate damage bonuses let rangedStyle: RangedCombatStyle = "accurate"; const styleData = this.ctx.playerSystem?.getPlayerAttackStyle?.(attackerId); if (styleData?.id) { diff --git a/packages/shared/src/systems/shared/death/DeathStateManager.ts b/packages/shared/src/systems/shared/death/DeathStateManager.ts index c054880e4..cc1683536 100644 --- a/packages/shared/src/systems/shared/death/DeathStateManager.ts +++ b/packages/shared/src/systems/shared/death/DeathStateManager.ts @@ -48,7 +48,7 @@ interface DeathLockData { zoneType: ZoneType; itemCount: number; items: DeathItemData[]; - keptItems?: DeathItemData[]; // OSRS keep-3 items returned on respawn + keptItems?: DeathItemData[]; // classic MMORPG keep-3 items returned on respawn killedBy: string; recovered: boolean; } diff --git a/packages/shared/src/systems/shared/death/SafeAreaDeathHandler.ts b/packages/shared/src/systems/shared/death/SafeAreaDeathHandler.ts index 42b8a604b..11116a8e4 100644 --- a/packages/shared/src/systems/shared/death/SafeAreaDeathHandler.ts +++ b/packages/shared/src/systems/shared/death/SafeAreaDeathHandler.ts @@ -1,17 +1,16 @@ /** * SafeAreaDeathHandler (TICK-BASED) * - * Handles player death in safe zones (RuneScape-style): + * Handles player death in safe zones (classic fantasy MMORPG-style): * 1. Items → gravestone (1500 ticks = 15 minutes) * 2. Gravestone expires → ground items (6000 ticks = 60 minutes) * 3. Ground items despawn via GroundItemSystem tick processing * - * TICK-BASED TIMING (OSRS-accurate): + * TICK-BASED TIMING (rules-accurate): * - Gravestone expiration tracked in ticks * - processTick() called once per tick by TickSystem * - Uses constants from COMBAT_CONSTANTS * - * @see https://oldschool.runescape.wiki/w/Gravestone */ import type { World } from "../../../core/World"; diff --git a/packages/shared/src/systems/shared/death/WildernessDeathHandler.ts b/packages/shared/src/systems/shared/death/WildernessDeathHandler.ts index 54f7d31e8..12446610b 100644 --- a/packages/shared/src/systems/shared/death/WildernessDeathHandler.ts +++ b/packages/shared/src/systems/shared/death/WildernessDeathHandler.ts @@ -1,17 +1,16 @@ /** * WildernessDeathHandler (TICK-BASED) * - * Handles player death in wilderness/PvP zones (RuneScape-style): + * Handles player death in wilderness/PvP zones (classic fantasy MMORPG-style): * 1. Items → ground items immediately (200 ticks = 2 minutes) * 2. Ground items despawn via GroundItemSystem tick processing * No gravestone protection in dangerous areas * - * TICK-BASED TIMING (OSRS-accurate): + * TICK-BASED TIMING (rules-accurate): * - Uses tick constants from COMBAT_CONSTANTS * - Ground item despawn handled by GroundItemSystem.processTick() * - Loot protection expires after 100 ticks (1 minute) * - * @see https://oldschool.runescape.wiki/w/Wilderness#Death */ import type { World } from "../../../core/World"; diff --git a/packages/shared/src/systems/shared/death/__tests__/PvPDeath.integration.test.ts b/packages/shared/src/systems/shared/death/__tests__/PvPDeath.integration.test.ts index a376cc643..ca4f2f6f8 100644 --- a/packages/shared/src/systems/shared/death/__tests__/PvPDeath.integration.test.ts +++ b/packages/shared/src/systems/shared/death/__tests__/PvPDeath.integration.test.ts @@ -849,7 +849,7 @@ describe("PvP Death Integration", () => { }); it("handles high-value inventory (many items)", async () => { - // Create inventory with 28 items (full OSRS inventory) + // Create inventory with 28 items (full classic MMORPG inventory) const largeInventory: MockInventoryItem[] = []; for (let i = 0; i < 28; i++) { largeInventory.push({ @@ -887,7 +887,7 @@ describe("PvP Death Integration", () => { }); }); - describe("timing accuracy (OSRS compliance)", () => { + describe("timing accuracy (classic MMORPG compliance)", () => { it("uses correct despawn time for ground items (300 ticks = 3 minutes)", async () => { const victim = createMockPlayer("victim", { health: 1, diff --git a/packages/shared/src/systems/shared/death/__tests__/SafeAreaDeathHandler.test.ts b/packages/shared/src/systems/shared/death/__tests__/SafeAreaDeathHandler.test.ts index 3dac42864..eccd4bc58 100644 --- a/packages/shared/src/systems/shared/death/__tests__/SafeAreaDeathHandler.test.ts +++ b/packages/shared/src/systems/shared/death/__tests__/SafeAreaDeathHandler.test.ts @@ -1,7 +1,7 @@ /** * SafeAreaDeathHandler Unit Tests * - * Tests the safe area death handling system (RuneScape-style gravestones). + * Tests the safe area death handling system (classic fantasy MMORPG-style gravestones). * * Key behaviors tested: * - Server authority: Client cannot spawn gravestones diff --git a/packages/shared/src/systems/shared/death/__tests__/WildernessDeathHandler.test.ts b/packages/shared/src/systems/shared/death/__tests__/WildernessDeathHandler.test.ts index 8c8e6de4d..28a2e97e9 100644 --- a/packages/shared/src/systems/shared/death/__tests__/WildernessDeathHandler.test.ts +++ b/packages/shared/src/systems/shared/death/__tests__/WildernessDeathHandler.test.ts @@ -330,7 +330,7 @@ describe("WildernessDeathHandler", () => { const expectedMs = ticksToMs(COMBAT_CONSTANTS.GROUND_ITEM_DESPAWN_TICKS); expect(spawnCall.despawnTime).toBe(expectedMs); - // 6000 ticks * 600ms = 3600000ms = 60 minutes (OSRS-accurate) + // 6000 ticks * 600ms = 3600000ms = 60 minutes (rules-accurate) expect(expectedMs).toBe(3600000); }); diff --git a/packages/shared/src/systems/shared/economy/GroundItemSystem.ts b/packages/shared/src/systems/shared/economy/GroundItemSystem.ts index 3058b80f7..f1f607699 100644 --- a/packages/shared/src/systems/shared/economy/GroundItemSystem.ts +++ b/packages/shared/src/systems/shared/economy/GroundItemSystem.ts @@ -8,13 +8,12 @@ * with a single shared system, eliminating the need for ID prefixes. * * Features: - * - OSRS-style tile-based piling + * - classic MMORPG-style tile-based piling * - Stackable item merging * - Tick-based despawn timers * - Loot protection * - O(1) tile lookups via spatial indexing * - * @see https://oldschool.runescape.wiki/w/Dropped_items */ import type { World } from "../../../core/World"; @@ -64,7 +63,7 @@ export class GroundItemSystem extends SystemBase { private pickupLockTimestamps = new Map(); private readonly PICKUP_LOCK_TIMEOUT_MS = 5000; - /** OSRS: Maximum items per tile */ + /** classic MMORPG: Maximum items per tile */ private readonly MAX_PILE_SIZE = 128; /** Server-wide ground item limit to prevent memory exhaustion */ @@ -149,7 +148,7 @@ export class GroundItemSystem extends SystemBase { /** * Spawn a single ground item (TICK-BASED despawn) * Options accept ms for backwards compatibility, converted to ticks internally - * Items are snapped to tile centers and managed in piles (OSRS-style stacking) + * Items are snapped to tile centers and managed in piles (classic MMORPG-style stacking) */ async spawnGroundItem( itemId: string, @@ -190,8 +189,8 @@ export class GroundItemSystem extends SystemBase { const currentTick = this.world.currentTick ?? 0; - // OSRS: Untradeable items ALWAYS despawn in 3 min, tradeable uses caller's time - // This overrides caller's despawnTime for untradeable items (OSRS-accurate behavior) + // classic MMORPG: Untradeable items ALWAYS despawn in 3 min, tradeable uses caller's time + // This overrides caller's despawnTime for untradeable items (rules-accurate behavior) const despawnTicks = item.tradeable === false ? COMBAT_CONSTANTS.UNTRADEABLE_DESPAWN_TICKS // 300 ticks = 3 min (forced) @@ -201,7 +200,7 @@ export class GroundItemSystem extends SystemBase { ? msToTicks(options.lootProtection) : 0; - // OSRS-STYLE: Snap position to tile center + // classic MMORPG-STYLE: Snap position to tile center const tile = worldToTile(position.x, position.z); const tileKey = this.getTileKey(tile); const tileCenter = tileToWorld(tile); @@ -217,7 +216,7 @@ export class GroundItemSystem extends SystemBase { // Check for existing pile at this tile const existingPile = this.groundItemPiles.get(tileKey); - // OSRS-STYLE: Check pile size limit (max 128 items per tile) + // classic MMORPG-STYLE: Check pile size limit (max 128 items per tile) // If full, remove oldest item (bottom of pile) to make room if (existingPile && existingPile.items.length >= this.MAX_PILE_SIZE) { const oldestItem = existingPile.items.pop(); // Remove from end (oldest) @@ -232,7 +231,7 @@ export class GroundItemSystem extends SystemBase { } } - // OSRS-STYLE: If stackable, try to merge with existing item of same type + // classic MMORPG-STYLE: If stackable, try to merge with existing item of same type if (item.stackable && existingPile) { const existingStackItem = existingPile.items.find( (pileItem) => @@ -342,7 +341,7 @@ export class GroundItemSystem extends SystemBase { this.groundItems.set(dropId, groundItemData); - // OSRS-STYLE: Manage pile - hide previous top item, add new item to pile + // classic MMORPG-STYLE: Manage pile - hide previous top item, add new item to pile if (existingPile) { // Hide the current top item this.setItemVisibility(existingPile.topItemEntityId, false); @@ -637,7 +636,7 @@ export class GroundItemSystem extends SystemBase { } /** - * Check if an item is visible to a specific player (OSRS visibility phases) + * Check if an item is visible to a specific player (classic MMORPG visibility phases) * - Private phase (0-100 ticks): Only dropper/killer sees item * - Public phase (100-200 ticks): Everyone sees item * diff --git a/packages/shared/src/systems/shared/economy/LootSystem.ts b/packages/shared/src/systems/shared/economy/LootSystem.ts index 465c60b95..6f7c28465 100644 --- a/packages/shared/src/systems/shared/economy/LootSystem.ts +++ b/packages/shared/src/systems/shared/economy/LootSystem.ts @@ -5,14 +5,12 @@ * - LootTableService: Pure loot table logic and rolling * - GroundItemSystem: Shared ground item management * - * OSRS-STYLE BEHAVIOR: + * classic MMORPG-STYLE BEHAVIOR: * - Mob dies → Items drop directly to ground at tile center * - Items pile on same tile, stackables merge * - Click item directly to pick up (no loot window) * - 2 minute despawn timer per item * - * @see https://oldschool.runescape.wiki/w/Loot - * @see https://oldschool.runescape.wiki/w/Dropped_items */ import type { World } from "../../../types/index"; @@ -113,7 +111,7 @@ export class LootSystem extends SystemBase { } /** - * Handle mob death and generate loot (OSRS-style ground items) + * Handle mob death and generate loot (classic MMORPG-style ground items) * * Drops items directly to ground at tile center instead of creating * a corpse entity. Items can be picked up by clicking directly. @@ -161,7 +159,7 @@ export class LootSystem extends SystemBase { Infinity, ); - // OSRS-STYLE: Spawn ground items directly (no corpse entity) + // classic MMORPG-STYLE: Spawn ground items directly (no corpse entity) // Items pile at tile center, stackables merge, 2 minute despawn await this.groundItemSystem.spawnGroundItems( inventoryItems, @@ -170,7 +168,7 @@ export class LootSystem extends SystemBase { despawnTime: ticksToMs(COMBAT_CONSTANTS.GROUND_ITEM_DESPAWN_TICKS), // 2 minutes droppedBy: data.killedBy, // Killer gets loot protection lootProtection: ticksToMs(COMBAT_CONSTANTS.LOOT_PROTECTION_TICKS), // 1 minute protection - scatter: false, // Items pile at mob position tile center (OSRS-style) + scatter: false, // Items pile at mob position tile center (classic MMORPG-style) }, ); diff --git a/packages/shared/src/systems/shared/economy/__tests__/GroundItemSystem.test.ts b/packages/shared/src/systems/shared/economy/__tests__/GroundItemSystem.test.ts index 05c885d31..8f6ec9c8e 100644 --- a/packages/shared/src/systems/shared/economy/__tests__/GroundItemSystem.test.ts +++ b/packages/shared/src/systems/shared/economy/__tests__/GroundItemSystem.test.ts @@ -3,7 +3,7 @@ * * Tests the ground item management system: * - Item spawning and tracking - * - Tile-based piling (OSRS-style) + * - Tile-based piling (classic MMORPG-style) * - Stackable item merging * - Loot protection (canPickup enforcement) * - Tick-based despawn @@ -58,7 +58,7 @@ class MockGroundItemManager { private nextId = 1; private currentTick = 0; - // OSRS constants + // classic MMORPG constants private readonly TICK_MS = 600; private readonly DEFAULT_DESPAWN_TICKS = 200; // 2 minutes (tradeable) private readonly UNTRADEABLE_DESPAWN_TICKS = 300; // 3 minutes (untradeable) @@ -104,7 +104,7 @@ class MockGroundItemManager { const id = `ground_item_${this.nextId++}`; - // OSRS: Untradeable items ALWAYS get 3 min despawn + // classic MMORPG: Untradeable items ALWAYS get 3 min despawn const tradeable = options.tradeable !== false; // Default true const baseDespawnTicks = tradeable ? this.DEFAULT_DESPAWN_TICKS @@ -189,7 +189,7 @@ class MockGroundItemManager { } /** - * Check if an item is visible to a specific player (OSRS visibility phases) + * Check if an item is visible to a specific player (classic MMORPG visibility phases) * - Private phase: Only dropper/killer sees item * - Public phase: Everyone sees item */ diff --git a/packages/shared/src/systems/shared/entities/Entities.ts b/packages/shared/src/systems/shared/entities/Entities.ts index 6c9df61be..9ceb81c38 100644 --- a/packages/shared/src/systems/shared/entities/Entities.ts +++ b/packages/shared/src/systems/shared/entities/Entities.ts @@ -370,7 +370,7 @@ export class Entities extends SystemBase implements IEntities { movementType: "wander", // Default to wander for backwards compatibility aggroRange: 15.0, // 15 meters detection range combatRange: 1.5, // 1.5 meters melee range - wanderRadius: 10, // 10 meter wander radius from spawn (RuneScape-style) + wanderRadius: 10, // 10 meter wander radius from spawn (classic fantasy MMORPG-style) xpReward: 10, lootTable: [], respawnTime: 300000, diff --git a/packages/shared/src/systems/shared/entities/MobNPCSystem.ts b/packages/shared/src/systems/shared/entities/MobNPCSystem.ts index 866838713..f0538511a 100644 --- a/packages/shared/src/systems/shared/entities/MobNPCSystem.ts +++ b/packages/shared/src/systems/shared/entities/MobNPCSystem.ts @@ -63,7 +63,7 @@ export class MobNPCSystem extends SystemBase { type: npcId, // NPC ID from npcs.json name: npcData.name, level: npcData.stats.level, - health: npcData.stats.health, // OSRS: hitpoints = max HP directly + health: npcData.stats.health, // classic MMORPG: hitpoints = max HP directly stats: { attack: npcData.stats.attack, strength: npcData.stats.strength, @@ -489,7 +489,7 @@ export class MobNPCSystem extends SystemBase { type: config.type, name: config.name, level: config.level, - health: config.health ?? config.level * 3, // OSRS: hitpoints = max HP + health: config.health ?? config.level * 3, // classic MMORPG: hitpoints = max HP stats: config.stats ?? { attack: config.level, strength: config.level, diff --git a/packages/shared/src/systems/shared/entities/ResourceSystem.ts b/packages/shared/src/systems/shared/entities/ResourceSystem.ts index 0ef5a009d..f8abf1978 100644 --- a/packages/shared/src/systems/shared/entities/ResourceSystem.ts +++ b/packages/shared/src/systems/shared/entities/ResourceSystem.ts @@ -86,7 +86,7 @@ interface ResourceEntityMethods { * 2. Handler sends network message → resources.ts handler * 3. Handler emits RESOURCE_GATHER event with server-authoritative position * 4. ResourceSystem.startGathering() validates and creates session - * 5. TickSystem calls processGatheringTick() every 600ms (OSRS tick rate) + * 5. TickSystem calls processGatheringTick() every 600ms (classic MMORPG tick rate) * 6. On success: drops item via manifest data, awards XP, may deplete resource * * ### Manifest Integration @@ -107,7 +107,7 @@ interface ResourceEntityMethods { * - Resource ID validation: Alphanumeric with length limit to prevent injection * - Proximity checks: Uses server-side player position for range validation * - * ### Tool Tier System (OSRS-Accurate, Manifest-Driven) + * ### Tool Tier System (Rules-Accurate, Manifest-Driven) * Tool definitions loaded from tools.json manifest: * - Woodcutting: Axe tier affects SUCCESS RATE (not speed), fixed 4-tick rolls * - Mining: Pickaxe tier affects ROLL FREQUENCY (not success), variable ticks @@ -120,7 +120,7 @@ interface ResourceEntityMethods { export class ResourceSystem extends SystemBase { private resources = new Map(); - // Tick-based gathering sessions (OSRS-accurate timing) + // Tick-based gathering sessions (rules-accurate timing) // Session includes cached data to avoid per-tick allocations private activeGathering = new Map< PlayerID, @@ -146,7 +146,7 @@ export class ResourceSystem extends SystemBase { cachedSuccessRate: number; cachedDrops: ResourceDrop[]; cachedResourceName: string; // For messages without lookup - // OSRS-ACCURACY: Store start position to detect movement (cancels gathering) + // RULES ACCURACY: Store start position to detect movement (cancels gathering) cachedStartPosition: { x: number; y: number; z: number }; // DEBUG: Cached for logging (only used when DEBUG_GATHERING=true) debugInfo?: { @@ -176,7 +176,7 @@ export class ResourceSystem extends SystemBase { */ useHighPriorityBatch = true; - // ===== FORESTRY-STYLE RESOURCE TIMERS (OSRS-accurate) ===== + // ===== FORESTRY-STYLE RESOURCE TIMERS (rules-accurate) ===== /** * Per-resource depletion timer for Forestry-style tree mechanics. * - Timer starts on FIRST LOG (not first interaction) @@ -185,7 +185,6 @@ export class ResourceSystem extends SystemBase { * - Tree depletes when timer=0 AND player receives a log * - Multiple players share the same timer (no penalty) * - * @see https://oldschool.runescape.wiki/w/Forestry */ private resourceTimers = new Map< ResourceID, @@ -219,12 +218,11 @@ export class ResourceSystem extends SystemBase { } >(); - // ===== OSRS-ACCURACY: Fishing spot movement timers ===== + // ===== RULES ACCURACY: Fishing spot movement timers ===== /** * Fishing spots don't deplete - they periodically move to nearby tiles. * Each spot has a random timer that triggers relocation. * - * @see https://oldschool.runescape.wiki/w/Fishing */ private fishingSpotMoveTimers = new Map< ResourceID, @@ -252,13 +250,11 @@ export class ResourceSystem extends SystemBase { // Tool definitions are in packages/server/world/assets/manifests/tools.json // Loaded at runtime via DataManager → getExternalToolsForSkill() // - // OSRS-ACCURATE MECHANICS: + // RULES-ACCURATE MECHANICS: // - Woodcutting: tier affects success rate, roll frequency is fixed (4 ticks) // - Mining: rollTicks affects roll frequency, success rate is level-only // - Fishing: Equipment doesn't affect speed or success // - // @see https://oldschool.runescape.wiki/w/Axe - // @see https://oldschool.runescape.wiki/w/Pickaxe // ============================================================================= constructor(world: World) { @@ -287,7 +283,7 @@ export class ResourceSystem extends SystemBase { /** * Calculate all tiles occupied by a resource based on its anchor tile and footprint * - * OSRS-ACCURACY: Multi-tile resources (like large trees) occupy multiple tiles. + * RULES ACCURACY: Multi-tile resources (like large trees) occupy multiple tiles. * The anchor tile is the SW corner, and this function returns all tiles * in the rectangular footprint. * @@ -365,9 +361,9 @@ export class ResourceSystem extends SystemBase { this.cleanupPlayerGathering(data.id), ); - // OSRS-ACCURACY: Cancel gathering when player clicks to move anywhere - // In OSRS, gathering uses "weak queue" which is cancelled by ANY click (even same tile) - // This ensures clicking ground under yourself cancels gathering, matching OSRS behavior + // RULES ACCURACY: Cancel gathering when player clicks to move anywhere + // In classic MMORPG, gathering uses "weak queue" which is cancelled by ANY click (even same tile) + // This ensures clicking ground under yourself cancels gathering, matching classic MMORPG behavior this.subscribe<{ playerId: string; targetPosition: { x: number; y: number; z: number }; @@ -385,7 +381,7 @@ export class ResourceSystem extends SystemBase { } }); - // OSRS-ACCURACY: Cancel gathering when player dies + // RULES ACCURACY: Cancel gathering when player dies // Critical: Dead players cannot continue gathering this.subscribe<{ entityId: string; entityType: string }>( EventType.ENTITY_DEATH, @@ -396,7 +392,7 @@ export class ResourceSystem extends SystemBase { }, ); - // OSRS-ACCURACY: Cancel gathering when player teleports + // RULES ACCURACY: Cancel gathering when player teleports // Cannot gather from a resource across the map this.subscribe<{ playerId: string; @@ -405,7 +401,7 @@ export class ResourceSystem extends SystemBase { this.cancelGatheringForPlayer(data.playerId, "teleported"); }); - // OSRS-ACCURACY: Cancel gathering when player initiates combat + // RULES ACCURACY: Cancel gathering when player initiates combat // Attacking a mob/player is a new action that replaces gathering this.subscribe<{ attackerId?: string; @@ -420,7 +416,7 @@ export class ResourceSystem extends SystemBase { } }); - // OSRS-ACCURACY: Cancel gathering when player opens bank + // RULES ACCURACY: Cancel gathering when player opens bank // Opening interface = new action this.subscribe<{ playerId: string; bankId?: string }>( EventType.BANK_OPEN, @@ -429,7 +425,7 @@ export class ResourceSystem extends SystemBase { }, ); - // OSRS-ACCURACY: Cancel gathering when player opens store + // RULES ACCURACY: Cancel gathering when player opens store // Opening interface = new action this.subscribe<{ playerId: string; storeId?: string }>( EventType.STORE_OPEN, @@ -438,7 +434,7 @@ export class ResourceSystem extends SystemBase { }, ); - // OSRS-ACCURACY: Cancel gathering when player interacts with any entity + // RULES ACCURACY: Cancel gathering when player interacts with any entity // Clicking on an entity (NPC, player, object) = new action // Exception: Don't cancel if interacting with the same resource we're gathering this.subscribe<{ @@ -454,7 +450,7 @@ export class ResourceSystem extends SystemBase { } }); - // OSRS-ACCURACY: Cancel gathering when player drops an item + // RULES ACCURACY: Cancel gathering when player drops an item // Dropping is an action that should cancel gathering // Also prevents database deadlocks between inventory insert (gathering) and delete (drop) this.subscribe<{ @@ -466,8 +462,8 @@ export class ResourceSystem extends SystemBase { this.cancelGatheringForPlayer(data.playerId, "item_drop"); }); - // OSRS-ACCURACY: Cancel gathering when equipping/unequipping items - // In OSRS, equipment changes are distinct actions that interrupt gathering + // RULES ACCURACY: Cancel gathering when equipping/unequipping items + // In classic MMORPG, equipment changes are distinct actions that interrupt gathering this.subscribe<{ playerId: string; itemId: string; @@ -589,7 +585,7 @@ export class ResourceSystem extends SystemBase { // Resources will be spawned procedurally by TerrainSystem across all terrain tiles // No need for manual default spawning - TerrainSystem generates resources based on biome // NOTE: Gathering is now processed via processGatheringTick() called by TickSystem - // The old 500ms interval has been removed in favor of OSRS-accurate 600ms tick-based processing + // The old 500ms interval has been removed in favor of rules-accurate 600ms tick-based processing // Registration happens in ServerNetwork/index.ts at TickPriority.RESOURCES // Load explicit resource placements from world-areas.json (server only) @@ -1007,7 +1003,7 @@ export class ResourceSystem extends SystemBase { : `${resource.type}_normal`; this.resourceVariants.set(rid, variant); - // OSRS-ACCURACY: Initialize fishing spot movement timer + // RULES ACCURACY: Initialize fishing spot movement timer if ( resource.type === "fishing_spot" || resource.skillRequired === "fishing" @@ -1026,7 +1022,7 @@ export class ResourceSystem extends SystemBase { w: Math.cos(yRotation / 2), }; - // OSRS-ACCURACY: Calculate tile footprint data for proper interaction positioning + // RULES ACCURACY: Calculate tile footprint data for proper interaction positioning const footprint: ResourceFootprint = resource.footprint || "standard"; const anchorTile = worldToTile( resource.position.x, @@ -1116,7 +1112,7 @@ export class ResourceSystem extends SystemBase { resource.type, spawnPoint.subType, ), - // OSRS-ACCURACY: Tile-based positioning for face direction and interaction + // RULES ACCURACY: Tile-based positioning for face direction and interaction footprint, anchorTile, occupiedTiles, @@ -1347,7 +1343,7 @@ export class ResourceSystem extends SystemBase { chance: yield_.chance, xpAmount: yield_.xpAmount, stackable: yield_.stackable, - // OSRS-ACCURACY: Include fishing priority rolling fields + // RULES ACCURACY: Include fishing priority rolling fields levelRequired: yield_.levelRequired, catchLow: yield_.catchLow, catchHigh: yield_.catchHigh, @@ -1389,7 +1385,7 @@ export class ResourceSystem extends SystemBase { ); } - // OSRS-ACCURACY: Snap position to tile center for proper face direction and interaction + // RULES ACCURACY: Snap position to tile center for proper face direction and interaction // This ensures resources are always at tile centers (e.g., 15.5, -9.5) not corners (15, -10) const snappedPosition = snapToTileCenter(position); @@ -1512,12 +1508,12 @@ export class ResourceSystem extends SystemBase { const playerId = createPlayerID(data.playerId); // ===== SECURITY: Rate limiting - prevent gather request spam ===== - // Silently drops requests faster than 1 tick (600ms), just like OSRS + // Silently drops requests faster than 1 tick (600ms), just like classic MMORPG // This allows normal spam clicking without punishment const now = Date.now(); const lastAttempt = this.gatherRateLimits.get(playerId); if (lastAttempt && now - lastAttempt < GATHERING_CONSTANTS.RATE_LIMIT_MS) { - // Silently drop rapid requests (OSRS behavior - no punishment for spam clicking) + // Silently drop rapid requests (classic MMORPG behavior - no punishment for spam clicking) return; } this.gatherRateLimits.set(playerId, now); @@ -1727,7 +1723,7 @@ export class ResourceSystem extends SystemBase { return; } - // Tool check using manifest's toolRequired field (RuneScape-style: any tier qualifies; tier affects speed) + // Tool check using manifest's toolRequired field (classic fantasy MMORPG-style: any tier qualifies; tier affects speed) if (resource.toolRequired) { const toolCategory = this.getToolCategory(resource.toolRequired); const hasTool = this.playerHasToolCategory(data.playerId, toolCategory); @@ -1765,8 +1761,7 @@ export class ResourceSystem extends SystemBase { } } - // OSRS-ACCURACY: Check for secondary consumable (bait, feathers, etc.) - // @see https://oldschool.runescape.wiki/w/Fishing - "Bait fishing requires fishing bait" + // RULES ACCURACY: Check for secondary consumable (bait, feathers, etc.) if (resource.secondaryRequired) { const hasSecondary = this.playerHasItem( data.playerId, @@ -1790,13 +1785,10 @@ export class ResourceSystem extends SystemBase { this.activeGathering.delete(playerId); } - // Start RS-like timed gathering session with OSRS-accurate messages + // Start a timed gathering session with rules-accurate messages const resourceName = resource.name || resource.type.replace("_", " "); - // OSRS-ACCURACY: Skill-specific gathering start messages - // @see https://oldschool.runescape.wiki/w/Woodcutting - // @see https://oldschool.runescape.wiki/w/Mining - // @see https://oldschool.runescape.wiki/w/Fishing + // RULES ACCURACY: Skill-specific gathering start messages const gatheringStartMessage = (() => { switch (resource.skillRequired) { case "woodcutting": @@ -1813,7 +1805,7 @@ export class ResourceSystem extends SystemBase { // Create tick-based session const sessionResourceId = createResourceID(resource.id); - // Get current tick from world (OSRS-accurate tick-based timing) + // Get current tick from world (rules-accurate tick-based timing) const currentTick = this.world.currentTick || 0; // Compute tick-based cycle interval @@ -1830,7 +1822,7 @@ export class ResourceSystem extends SystemBase { // Get best tool tier using unified tool system const toolInfo = this.getBestTool(data.playerId, resource.skillRequired); - // OSRS-ACCURATE: Compute cycle ticks based on skill-specific mechanics + // RULES-ACCURATE: Compute cycle ticks based on skill-specific mechanics // - Woodcutting: Fixed 4 ticks (axe affects success rate, not speed) // - Mining: Variable ticks based on pickaxe tier // - Fishing: Fixed 5 ticks @@ -1841,7 +1833,7 @@ export class ResourceSystem extends SystemBase { ); // PERFORMANCE: Pre-compute success rate to avoid per-tick calculation - // OSRS-ACCURATE: Uses LERP formula with skill-specific tables + // RULES-ACCURATE: Uses LERP formula with skill-specific tables // - Woodcutting: Tree type + axe tier determines success // - Mining/Fishing: Resource type only (tool doesn't affect success) const successRate = this.computeSuccessRate( @@ -1851,7 +1843,7 @@ export class ResourceSystem extends SystemBase { toolInfo?.tier ?? null, ); - // OSRS-ACCURACY: Get server-authoritative player position for movement detection + // RULES ACCURACY: Get server-authoritative player position for movement detection const player = this.world.getPlayer?.(data.playerId); const startPosition = player?.position ? { x: player.position.x, y: player.position.y, z: player.position.z } @@ -1861,7 +1853,7 @@ export class ResourceSystem extends SystemBase { z: data.playerPosition.z, }; - // OSRS-ACCURACY: Rotate player to face the resource (instant rotation like OSRS) + // RULES ACCURACY: Rotate player to face the resource (instant rotation like classic MMORPG) // This happens before session starts so animation plays in correct direction const footprintForRotation = resource.footprint || "standard"; if (DEBUG_GATHERING) { @@ -1902,7 +1894,7 @@ export class ResourceSystem extends SystemBase { cachedSuccessRate: successRate, cachedDrops: resource.drops, cachedResourceName: resourceName, - // OSRS-ACCURACY: Store position to detect movement (any movement cancels gathering) + // RULES ACCURACY: Store position to detect movement (any movement cancels gathering) cachedStartPosition: startPosition, // DEBUG: Store for logging (only used when DEBUG_GATHERING=true) debugInfo: DEBUG_GATHERING @@ -1915,7 +1907,7 @@ export class ResourceSystem extends SystemBase { : undefined, }); - // DEBUG: Log session start with OSRS mechanics details + // DEBUG: Log session start with classic tick-based mechanics details if (DEBUG_GATHERING) { const mechanics = GATHERING_CONSTANTS.SKILL_MECHANICS[ @@ -1966,7 +1958,7 @@ export class ResourceSystem extends SystemBase { tickDurationMs: TICK_DURATION_MS, }); - // OSRS-STYLE: Show gathering tool in hand during gathering (overrides equipped weapon) + // classic MMORPG-STYLE: Show gathering tool in hand during gathering (overrides equipped weapon) // e.g., if player has a pickaxe equipped but a hatchet in inventory, the hatchet // appears in hand while woodcutting. Applies to all gathering skills. if (toolInfo?.itemId) { @@ -1977,7 +1969,7 @@ export class ResourceSystem extends SystemBase { }); } - // OSRS-ACCURACY: Send OSRS-style gathering start message via chat and UI + // RULES ACCURACY: Send classic MMORPG-style gathering start message via chat and UI this.sendChat(data.playerId, gatheringStartMessage); this.emitTypedEvent(EventType.UI_MESSAGE, { playerId: data.playerId, @@ -2005,7 +1997,7 @@ export class ResourceSystem extends SystemBase { // Reset emote back to idle when gathering stops this.resetGatheringEmote(data.playerId); - // OSRS-STYLE: Hide gathering tool visual and restore equipped weapon + // classic MMORPG-STYLE: Hide gathering tool visual and restore equipped weapon if (session.toolItemId) { this.emitTypedEvent(EventType.GATHERING_TOOL_HIDE, { playerId: data.playerId, @@ -2050,7 +2042,7 @@ export class ResourceSystem extends SystemBase { patterns.lastDisconnect = now; this.suspiciousPatterns.set(pid, patterns); - // OSRS-STYLE: Hide gathering tool visual and restore equipped weapon + // classic MMORPG-STYLE: Hide gathering tool visual and restore equipped weapon if (session.toolItemId) { this.emitTypedEvent(EventType.GATHERING_TOOL_HIDE, { playerId: playerId, @@ -2082,7 +2074,7 @@ export class ResourceSystem extends SystemBase { } /** - * Cancel gathering for a player due to an action/event (OSRS weak queue behavior) + * Cancel gathering for a player due to an action/event (classic MMORPG weak queue behavior) * Used by event subscriptions to cancel gathering when player performs another action. * * @param playerId - The player whose gathering should be cancelled @@ -2100,7 +2092,7 @@ export class ResourceSystem extends SystemBase { // FORESTRY: Remove from active gatherers (timer will regenerate if no other gatherers) this.removeActiveGatherer(pid, session.resourceId); - // OSRS-STYLE: Hide gathering tool visual and restore equipped weapon + // classic MMORPG-STYLE: Hide gathering tool visual and restore equipped weapon if (session.toolItemId) { this.emitTypedEvent(EventType.GATHERING_TOOL_HIDE, { playerId: playerId, @@ -2118,9 +2110,9 @@ export class ResourceSystem extends SystemBase { } /** - * Set face target for player to face a resource (OSRS-accurate deferred rotation) + * Set face target for player to face a resource (rules-accurate deferred rotation) * - * OSRS-ACCURACY: Face direction is NOT applied immediately. Instead: + * RULES ACCURACY: Face direction is NOT applied immediately. Instead: * 1. A faceTarget is set on the player * 2. At END of the server tick, if player did NOT move, rotation is applied * 3. If player moved, rotation is skipped but faceTarget persists @@ -2129,7 +2121,6 @@ export class ResourceSystem extends SystemBase { * For multi-tile resources (2×2, 3×3), the player faces the center of the * occupied tile area, not just a single tile. * - * @see https://osrs-docs.com/docs/packets/outgoing/updating/masks/face-direction/ * * @param playerId - The player to set face target for * @param resourcePosition - The position of the resource (tile-centered) @@ -2140,7 +2131,7 @@ export class ResourceSystem extends SystemBase { resourcePosition: { x: number; y: number; z: number }, footprint: ResourceFootprint = "standard", ): void { - // OSRS-ACCURACY: Use FaceDirectionManager for deferred tick-end processing + // RULES ACCURACY: Use FaceDirectionManager for deferred tick-end processing // The manager will apply rotation at end of tick only if player didn't move // // CARDINAL-ONLY: Uses deterministic cardinal face direction for AAA quality. @@ -2210,7 +2201,7 @@ export class ResourceSystem extends SystemBase { if (timer.activeGatherers.size > 0 && timer.hasReceivedFirstLog) { // Being gathered AND first log received - decrement timer - // OSRS-ACCURACY: Timer only counts down AFTER first log is received + // RULES ACCURACY: Timer only counts down AFTER first log is received const oldTicks = timer.currentTicks; timer.currentTicks = Math.max( 0, @@ -2397,7 +2388,7 @@ export class ResourceSystem extends SystemBase { } /** - * Process resource respawns on tick (OSRS-accurate tick-based timing) + * Process resource respawns on tick (rules-accurate tick-based timing) * Replaces setTimeout-based respawn with deterministic tick counting */ private processRespawns(tickNumber: number): void { @@ -2442,7 +2433,7 @@ export class ResourceSystem extends SystemBase { /** * Initialize a fishing spot movement timer with random delay. - * OSRS-ACCURACY: Fishing spots move periodically instead of depleting. + * RULES ACCURACY: Fishing spots move periodically instead of depleting. */ private initializeFishingSpotTimer( resourceId: ResourceID, @@ -2470,9 +2461,8 @@ export class ResourceSystem extends SystemBase { /** * Process fishing spot movement on each tick. - * OSRS-ACCURACY: Fishing spots don't deplete - they move to nearby tiles periodically. + * RULES ACCURACY: Fishing spots don't deplete - they move to nearby tiles periodically. * - * @see https://oldschool.runescape.wiki/w/Fishing */ private processFishingSpotMovement(tickNumber: number): void { // PERFORMANCE: Use pre-allocated buffer to avoid GC pressure @@ -2601,7 +2591,7 @@ export class ResourceSystem extends SystemBase { } /** - * Process all active gathering sessions on each server tick (OSRS-accurate 600ms) + * Process all active gathering sessions on each server tick (rules-accurate 600ms) * * Called by TickSystem at RESOURCES priority. Handles: * 1. Resource respawn checks (tick-based, not setTimeout) @@ -2626,7 +2616,7 @@ export class ResourceSystem extends SystemBase { // Process respawns first (tick-based) this.processRespawns(tickNumber); - // OSRS-ACCURACY: Process fishing spot movement + // RULES ACCURACY: Process fishing spot movement this.processFishingSpotMovement(tickNumber); // Retry deferred fishing spot spawns (waiting for collision flags to bake). @@ -2672,8 +2662,8 @@ export class ResourceSystem extends SystemBase { // Only process when it's time for the next attempt (tick-based) if (tickNumber < session.nextAttemptTick) continue; - // OSRS-ACCURACY: Server-authoritative movement detection - // In OSRS, ANY movement cancels gathering (weak queue action) + // RULES ACCURACY: Server-authoritative movement detection + // In classic MMORPG, ANY movement cancels gathering (weak queue action) // Position is fetched from world state, never from client payload const p = this.world.getPlayer?.(playerId); const playerPos = @@ -2691,14 +2681,14 @@ export class ResourceSystem extends SystemBase { continue; } - // Check if player moved from their starting position (OSRS: any movement cancels) + // Check if player moved from their starting position (classic MMORPG: any movement cancels) const startPos = session.cachedStartPosition; const epsilon = GATHERING_CONSTANTS.POSITION_EPSILON; const movedX = Math.abs(playerPos.x - startPos.x) > epsilon; const movedZ = Math.abs(playerPos.z - startPos.z) > epsilon; if (movedX || movedZ) { - // Player moved - cancel gathering (OSRS: weak queue cancelled on any movement) + // Player moved - cancel gathering (classic MMORPG: weak queue cancelled on any movement) if (DEBUG_GATHERING) { console.log( `[ResourceSystem] Cancelling gather for ${playerId} - player moved from (${startPos.x.toFixed(2)}, ${startPos.z.toFixed(2)}) to (${playerPos.x.toFixed(2)}, ${playerPos.z.toFixed(2)})`, @@ -2756,7 +2746,7 @@ export class ResourceSystem extends SystemBase { } } - // OSRS-ACCURACY: Check for secondary consumable (bait, feathers) on each tick + // RULES ACCURACY: Check for secondary consumable (bait, feathers) on each tick // Stop gathering if player runs out of bait/feathers if (resource.secondaryRequired) { const hasSecondary = this.playerHasItem( @@ -2803,13 +2793,13 @@ export class ResourceSystem extends SystemBase { if (isSuccessful) { session.successes++; - // OSRS-ACCURACY: Get player's skill level for priority-based fish rolling + // RULES ACCURACY: Get player's skill level for priority-based fish rolling const cachedSkills = this.playerSkills.get(playerId); const playerSkillLevel = cachedSkills?.[resource.skillRequired]?.level ?? 1; // PERFORMANCE: Roll against cached drop table (avoids resource lookup) - // For fishing, this uses OSRS priority rolling with per-fish catch rates + // For fishing, this uses classic MMORPG priority rolling with per-fish catch rates const drop = this.rollDrop(session.cachedDrops, playerSkillLevel); // Add item to inventory using manifest data @@ -2832,8 +2822,7 @@ export class ResourceSystem extends SystemBase { amount: xpAmount, }); - // OSRS-ACCURACY: Consume secondary item (bait, feathers) on successful harvest - // @see https://oldschool.runescape.wiki/w/Fishing - "One bait is used per fish caught" + // RULES ACCURACY: Consume secondary item (bait, feathers) on successful harvest if (resource.secondaryRequired) { this.emitTypedEvent(EventType.INVENTORY_ITEM_REMOVED, { playerId: playerId, @@ -2854,7 +2843,7 @@ export class ResourceSystem extends SystemBase { }); // ===== DEPLETION CHECK ===== - // OSRS-ACCURACY: Use Forestry timer for higher-level trees, chance-based for mining/regular trees + // RULES ACCURACY: Use Forestry timer for higher-level trees, chance-based for mining/regular trees let shouldDeplete = false; if (this.usesTimerBasedDepletion(session.resourceId)) { @@ -2870,7 +2859,7 @@ export class ResourceSystem extends SystemBase { resource.skillRequired === "mining" ) { // MINING: Use manifest depleteChance (1.0 for most rocks, 0 for essence) - // OSRS: Rune essence rocks never deplete — continuous mining until inventory full. + // classic MMORPG: Rune essence rocks never deplete — continuous mining until inventory full. const depletionChance = tuned.depleteChance ?? 1.0; if (depletionChance <= 0) { shouldDeplete = false; @@ -2964,10 +2953,8 @@ export class ResourceSystem extends SystemBase { // Legacy completeGathering() method removed - continuous loop in updateGathering() handles all gathering now - // ===== Tuning helpers (TICK-BASED for OSRS accuracy) ===== - // OSRS Reference: https://oldschool.runescape.wiki/w/Tick_manipulation + // ===== Tuning helpers (TICK-BASED for classic MMORPG accuracy) ===== // Standard woodcutting = 4 ticks (2.4 seconds) per attempt - // Respawn times from OSRS Wiki: https://oldschool.runescape.wiki/w/Tree private getVariantTuning(variantKey: string): { levelRequired: number; xpPerLog: number; @@ -3003,7 +2990,7 @@ export class ResourceSystem extends SystemBase { } /** - * Compute gathering cycle in ticks (OSRS-accurate, skill-specific). + * Compute gathering cycle in ticks (rules-accurate, skill-specific). * SERVER-SIDE: Rolls for dragon/crystal pickaxe bonus speed here to maintain determinism. * @see gathering/SuccessRateCalculator.ts for implementation */ @@ -3035,7 +3022,7 @@ export class ResourceSystem extends SystemBase { } /** - * Compute success rate using OSRS's LERP interpolation formula. + * Compute success rate using classic MMORPG's LERP interpolation formula. * @see gathering/SuccessRateCalculator.ts for implementation */ private computeSuccessRate( @@ -3356,7 +3343,7 @@ export class ResourceSystem extends SystemBase { // FORESTRY: Clear resource timer tracking this.resourceTimers.clear(); - // OSRS-ACCURACY: Clear fishing spot movement timers + // RULES ACCURACY: Clear fishing spot movement timers this.fishingSpotMoveTimers.clear(); // Clear all resource data diff --git a/packages/shared/src/systems/shared/entities/__tests__/ResourceSystem.test.ts b/packages/shared/src/systems/shared/entities/__tests__/ResourceSystem.test.ts index fd758bb27..736d28b0e 100644 --- a/packages/shared/src/systems/shared/entities/__tests__/ResourceSystem.test.ts +++ b/packages/shared/src/systems/shared/entities/__tests__/ResourceSystem.test.ts @@ -5,7 +5,7 @@ * - Drop rolling with probability distribution * - Resource ID validation (security) * - Tool category extraction - * - Success rate calculation (OSRS-style) + * - Success rate calculation (classic MMORPG-style) * - Cycle time calculation * * Note: Some tests access private methods via bracket notation for unit testing. @@ -198,8 +198,8 @@ describe("ResourceSystem", () => { expect(getToolCategory(system, "rune_pickaxe")).toBe("pickaxe"); }); - it("should return exact tool ID for fishing equipment (OSRS-accurate)", () => { - // OSRS-ACCURACY: Fishing tools require exact matching, not interchangeable + it("should return exact tool ID for fishing equipment (rules-accurate)", () => { + // RULES ACCURACY: Fishing tools require exact matching, not interchangeable expect(getToolCategory(system, "fishing_rod")).toBe("fishing_rod"); expect(getToolCategory(system, "small_fishing_net")).toBe( "small_fishing_net", @@ -223,7 +223,7 @@ describe("ResourceSystem", () => { it("should return friendly names for known categories", () => { expect(getToolDisplayName(system, "hatchet")).toBe("hatchet"); expect(getToolDisplayName(system, "pickaxe")).toBe("pickaxe"); - // OSRS-accurate: fishing tools use exact IDs, not "fishing equipment" + // rules-accurate: fishing tools use exact IDs, not "fishing equipment" expect(getToolDisplayName(system, "fishing_rod")).toBe("fishing rod"); expect(getToolDisplayName(system, "small_fishing_net")).toBe( "small fishing net", @@ -237,7 +237,7 @@ describe("ResourceSystem", () => { }); // ===== SUCCESS RATE CALCULATION TESTS ===== - // NOTE: computeSuccessRate now uses OSRS lerpSuccessRate formula internally. + // NOTE: computeSuccessRate now uses classic MMORPG lerpSuccessRate formula internally. // Detailed formula tests are in the lerpSuccessRate test suite. // These tests verify the integration works correctly. describe("computeSuccessRate", () => { @@ -283,7 +283,7 @@ describe("ResourceSystem", () => { expect(highRate).toBeGreaterThan(lowRate); }); - it("should cap at maximum rate (OSRS formula bounds)", () => { + it("should cap at maximum rate (classic combat formula bounds)", () => { const rate = computeSuccessRate( system, 99, @@ -354,7 +354,7 @@ describe("ResourceSystem", () => { }); }); - // ===== OSRS CATCH RATE FORMULA TESTS ===== + // ===== classic MMORPG CATCH RATE FORMULA TESTS ===== // Tests the module function directly (no ResourceSystem dependency) describe("lerpSuccessRate", () => { it("should use low value at level 1", () => { @@ -401,10 +401,10 @@ describe("ResourceSystem", () => { }); }); - // ===== OSRS PRIORITY FISH ROLLING TESTS ===== + // ===== classic MMORPG PRIORITY FISH ROLLING TESTS ===== // Tests the module function directly (no ResourceSystem dependency) describe("rollFishDrop", () => { - // Test drops ordered by level requirement (highest first, like OSRS) + // Test drops ordered by level requirement (highest first, like classic MMORPG) const fishDrops: ResourceDrop[] = [ { itemId: "swordfish", diff --git a/packages/shared/src/systems/shared/entities/gathering/DropRoller.ts b/packages/shared/src/systems/shared/entities/gathering/DropRoller.ts index 5f46ad849..1400316ff 100644 --- a/packages/shared/src/systems/shared/entities/gathering/DropRoller.ts +++ b/packages/shared/src/systems/shared/entities/gathering/DropRoller.ts @@ -4,13 +4,12 @@ * Extracted from ResourceSystem.ts for SOLID compliance (Single Responsibility). * These are pure functions with no system dependencies. * - * @see https://oldschool.runescape.wiki/w/Catch_rate - OSRS catch rate formula */ import type { ResourceDrop } from "../../../../types/core/core"; /** - * OSRS catch rate interpolation formula + * classic MMORPG catch rate interpolation formula * * Formula: P(Level) = (1 + floor(low × (99 - L) / 98 + high × (L - 1) / 98 + 0.5)) / 256 * @@ -19,7 +18,6 @@ import type { ResourceDrop } from "../../../../types/core/core"; * @param level - Player's skill level (1-99) * @returns Probability between 0 and 1 * - * @see https://oldschool.runescape.wiki/w/Catch_rate */ export function lerpSuccessRate( low: number, @@ -29,7 +27,7 @@ export function lerpSuccessRate( // Clamp level to valid range const clampedLevel = Math.min(99, Math.max(1, level)); - // OSRS interpolation formula + // classic MMORPG interpolation formula const lowComponent = (low * (99 - clampedLevel)) / 98; const highComponent = (high * (clampedLevel - 1)) / 98; const numerator = 1 + Math.floor(lowComponent + highComponent + 0.5); @@ -39,7 +37,7 @@ export function lerpSuccessRate( } /** - * OSRS Priority-based fish rolling system + * classic MMORPG Priority-based fish rolling system * * Fish are ordered by level requirement (highest first in manifest). * For each fish, the system: @@ -48,7 +46,6 @@ export function lerpSuccessRate( * 3. If roll succeeds, returns that fish * 4. If roll fails, moves to the next (lower-level) fish * - * @see https://oldschool.runescape.wiki/w/Catch_rate * @param drops - Array of fish drops (must be ordered highest-level first) * @param playerLevel - Player's fishing level * @param debug - Enable debug logging @@ -107,10 +104,10 @@ export function rollFishDrop( * Roll against harvestYield chances to determine drop * * Respects chance values from manifest for multi-drop resources (e.g., fishing). - * Automatically uses OSRS priority rolling when drops have catchLow/catchHigh. + * Automatically uses classic MMORPG priority rolling when drops have catchLow/catchHigh. * * @param drops - Array of possible drops from manifest harvestYield - * @param playerLevel - Optional player skill level (required for OSRS priority rolling) + * @param playerLevel - Optional player skill level (required for classic MMORPG priority rolling) * @param debug - Enable debug logging * @returns The rolled drop with all manifest data (itemId, itemName, quantity, xpAmount, etc.) * @throws Error if drops array is empty @@ -129,7 +126,7 @@ export function rollDrop( return drops[0]; } - // OSRS-ACCURACY: Check if drops use priority rolling (catchLow/catchHigh defined) + // RULES ACCURACY: Check if drops use priority rolling (catchLow/catchHigh defined) // This is used for fishing spots where higher-level fish are rolled first const usesPriorityRolling = drops.some( (d) => d.catchLow !== undefined && d.catchHigh !== undefined, diff --git a/packages/shared/src/systems/shared/entities/gathering/README.md b/packages/shared/src/systems/shared/entities/gathering/README.md index 9dfd4a0d5..e79b02b47 100644 --- a/packages/shared/src/systems/shared/entities/gathering/README.md +++ b/packages/shared/src/systems/shared/entities/gathering/README.md @@ -1,10 +1,10 @@ # Gathering System Architecture -OSRS-accurate resource gathering system for woodcutting, mining, and fishing. +rules-accurate resource gathering system for woodcutting, mining, and fishing. ## Overview -The gathering system implements authentic Old School RuneScape mechanics including: +The gathering system implements authentic classic fantasy MMORPG mechanics including: - 600ms tick-based timing - LERP success rate interpolation - Priority-based fish rolling @@ -19,9 +19,9 @@ gathering/ ├── index.ts # Module exports ├── debug.ts # Environment-based debug configuration ├── types.ts # Type definitions (GatheringSession, etc.) -├── DropRoller.ts # OSRS drop mechanics & fish priority rolling +├── DropRoller.ts # classic MMORPG drop mechanics & fish priority rolling ├── ToolUtils.ts # Tool validation & category mapping -├── SuccessRateCalculator.ts # OSRS LERP formula implementation +├── SuccessRateCalculator.ts # classic MMORPG LERP formula implementation └── README.md # This file ``` @@ -30,9 +30,9 @@ gathering/ | File | Purpose | |------|---------| | `ResourceSystem.ts` | Main orchestrator - session management, tick processing, event handling | -| `DropRoller.ts` | Roll drops using OSRS chance distribution, priority fish rolling | +| `DropRoller.ts` | Roll drops using classic MMORPG chance distribution, priority fish rolling | | `ToolUtils.ts` | Map item IDs to tool categories, validate tool requirements | -| `SuccessRateCalculator.ts` | Calculate success rates using OSRS LERP formula | +| `SuccessRateCalculator.ts` | Calculate success rates using classic MMORPG LERP formula | | `types.ts` | TypeScript interfaces for sessions, timers, tuning data | | `debug.ts` | Environment-based debug flag (`HYPERIA_DEBUG_GATHERING`) | @@ -41,9 +41,9 @@ gathering/ | File | Purpose | |------|---------| | `PendingGatherManager.ts` | Path player to cardinal tile before gathering starts | -| `FaceDirectionManager.ts` | OSRS-accurate deferred face direction at tick end | +| `FaceDirectionManager.ts` | rules-accurate deferred face direction at tick end | -## OSRS Mechanics Implemented +## classic MMORPG Mechanics Implemented ### Success Rate (LERP Formula) ``` @@ -55,7 +55,7 @@ rate = low + (high - low) * (level - 1) / 98 - Mining uses variable roll frequency instead ### Tick System -- All gathering runs on 600ms ticks (OSRS standard) +- All gathering runs on 600ms ticks (classic MMORPG standard) - Woodcutting: Fixed 4-tick rolls, tool affects success rate - Mining: Variable tick rolls based on pickaxe tier - Fishing: Fixed 5-tick rolls, equipment doesn't affect speed @@ -106,7 +106,7 @@ rate = low + (high - low) * (level - 1) / 98 ## Security Features -- **600ms rate limit**: Silently drops requests faster than 1 tick (matches OSRS) +- **600ms rate limit**: Silently drops requests faster than 1 tick (matches classic MMORPG) - **Resource ID validation**: Alphanumeric only, length limits - **Server-authoritative position**: Client position ignored - **Disconnect tracking**: Logs suspicious rapid disconnects during gathering diff --git a/packages/shared/src/systems/shared/entities/gathering/SuccessRateCalculator.ts b/packages/shared/src/systems/shared/entities/gathering/SuccessRateCalculator.ts index 4ff7b86aa..23e07bacf 100644 --- a/packages/shared/src/systems/shared/entities/gathering/SuccessRateCalculator.ts +++ b/packages/shared/src/systems/shared/entities/gathering/SuccessRateCalculator.ts @@ -1,10 +1,9 @@ /** - * SuccessRateCalculator - OSRS-accurate success rate and cycle calculations + * SuccessRateCalculator - rules-accurate success rate and cycle calculations * * Extracted from ResourceSystem.ts for SOLID compliance. - * These functions compute gathering success rates using OSRS formulas. + * These functions compute gathering success rates using classic combat formulas. * - * @see https://oldschool.runescape.wiki/w/Skilling_success_rate */ import { GATHERING_CONSTANTS } from "../../../../constants/GatheringConstants"; @@ -14,7 +13,7 @@ import { lerpSuccessRate } from "./DropRoller"; import type { SuccessRateValues } from "./types"; /** - * Get low/high success rate values from OSRS-accurate tables. + * Get low/high success rate values from rules-accurate tables. * * @param skill - The gathering skill (woodcutting, mining, fishing) * @param resourceVariant - Resource type key (e.g., "tree_normal", "ore_copper") @@ -70,9 +69,9 @@ export function getSuccessRateValues( } /** - * Compute success rate using OSRS's LERP interpolation formula. + * Compute success rate using classic MMORPG's LERP interpolation formula. * - * OSRS Formula: P(Level) = (1 + floor(low × (99 - L) / 98 + high × (L - 1) / 98 + 0.5)) / 256 + * classic MMORPG Formula: P(Level) = (1 + floor(low × (99 - L) / 98 + high × (L - 1) / 98 + 0.5)) / 256 * * The low/high values come from skill-specific tables: * - Woodcutting: Varies by tree type AND axe tier @@ -85,7 +84,6 @@ export function getSuccessRateValues( * @param toolTier - Tool tier for woodcutting (e.g., "bronze", "rune"), ignored for other skills * @returns Success probability (0-1) * - * @see https://oldschool.runescape.wiki/w/Skilling_success_rate */ export function computeSuccessRate( skillLevel: number, @@ -96,17 +94,17 @@ export function computeSuccessRate( // Get low/high values based on skill type const { low, high } = getSuccessRateValues(skill, resourceVariant, toolTier); - // Apply OSRS LERP formula + // Apply classic MMORPG LERP formula return lerpSuccessRate(low, high, skillLevel); } /** - * Compute gathering cycle in ticks (OSRS-accurate, skill-specific). + * Compute gathering cycle in ticks (rules-accurate, skill-specific). * * This is a DETERMINISTIC (pure) function - no randomness. * For dragon/crystal pickaxe bonus speed, the caller must roll and pass bonusRollTriggered. * - * OSRS MECHANICS: + * classic MMORPG MECHANICS: * - Woodcutting: Fixed 4 ticks, tool doesn't affect frequency * - Mining: Tool determines tick interval (8 bronze → 3 rune/dragon) * - Dragon pickaxe: 3 ticks default, 1/6 chance for 2 ticks (avg 2.83) @@ -119,8 +117,6 @@ export function computeSuccessRate( * @param bonusRollTriggered - Whether the dragon/crystal pickaxe bonus speed triggered (caller rolls this server-side) * @returns Number of ticks between gathering attempts * - * @see https://oldschool.runescape.wiki/w/Mining - * @see https://oldschool.runescape.wiki/w/Dragon_pickaxe */ export function computeCycleTicks( skill: string, @@ -148,7 +144,7 @@ export function computeCycleTicks( // Use rollTicks from tool data, or fall back to base (bronze = 8) let rollTicks = toolData?.rollTicks ?? mechanics.baseRollTicks; - // OSRS: Dragon/Crystal pickaxe have a chance for bonus speed + // classic MMORPG: Dragon/Crystal pickaxe have a chance for bonus speed // Dragon: 1/6 chance for 2 ticks (vs 3), avg 2.83 // Crystal: 1/4 chance for 2 ticks (vs 3), avg 2.75 // The caller (server-side) rolls for this and passes bonusRollTriggered diff --git a/packages/shared/src/systems/shared/entities/gathering/ToolUtils.ts b/packages/shared/src/systems/shared/entities/gathering/ToolUtils.ts index 2cbf557c9..f07b3f8eb 100644 --- a/packages/shared/src/systems/shared/entities/gathering/ToolUtils.ts +++ b/packages/shared/src/systems/shared/entities/gathering/ToolUtils.ts @@ -12,7 +12,7 @@ import { isNotedItemId } from "../../../../data/NoteGenerator"; import { getExternalTool } from "../../../../utils/ExternalAssetUtils"; /** - * OSRS fishing tools that require exact matching (not interchangeable) + * classic MMORPG fishing tools that require exact matching (not interchangeable) */ export const EXACT_FISHING_TOOLS = [ "small_fishing_net", @@ -63,7 +63,7 @@ const CATEGORY_TO_SKILL: Partial> = { * * e.g., "bronze_hatchet" -> "hatchet", "bronze_pickaxe" -> "pickaxe" * - * OSRS-ACCURACY: Fishing tools use EXACT matching because: + * RULES ACCURACY: Fishing tools use EXACT matching because: * - small_fishing_net catches shrimp/anchovies (level 1) * - fishing_rod + bait catches sardine/herring/pike (level 5+) * - fly_fishing_rod + feathers catches trout/salmon (level 20+) @@ -75,7 +75,7 @@ const CATEGORY_TO_SKILL: Partial> = { export function getToolCategory(toolRequired: string): string { const lowerTool = toolRequired.toLowerCase(); - // OSRS-ACCURACY: Fishing tools require EXACT matching (not interchangeable) + // RULES ACCURACY: Fishing tools require EXACT matching (not interchangeable) // Return the exact tool ID for fishing equipment if (EXACT_FISHING_TOOLS.includes(lowerTool as FishingToolId)) { return lowerTool; // Return exact ID, not category @@ -100,7 +100,7 @@ export function getToolCategory(toolRequired: string): string { const TOOL_DISPLAY_NAMES: Record = { hatchet: "hatchet", pickaxe: "pickaxe", - // OSRS-accurate fishing tool names + // rules-accurate fishing tool names small_fishing_net: "small fishing net", fishing_rod: "fishing rod", fly_fishing_rod: "fly fishing rod", diff --git a/packages/shared/src/systems/shared/entities/gathering/__tests__/ToolUtils.test.ts b/packages/shared/src/systems/shared/entities/gathering/__tests__/ToolUtils.test.ts index 5f39b8adc..ac3b4e990 100644 --- a/packages/shared/src/systems/shared/entities/gathering/__tests__/ToolUtils.test.ts +++ b/packages/shared/src/systems/shared/entities/gathering/__tests__/ToolUtils.test.ts @@ -6,7 +6,6 @@ * - Category matching for pickaxes and hatchets * - Exact matching for fishing tools * - * @see https://oldschool.runescape.wiki/w/Noted_items */ import { describe, it, expect, afterEach, beforeEach, vi } from "vitest"; diff --git a/packages/shared/src/systems/shared/entities/gathering/types.ts b/packages/shared/src/systems/shared/entities/gathering/types.ts index ff389c2fa..cd0d12432 100644 --- a/packages/shared/src/systems/shared/entities/gathering/types.ts +++ b/packages/shared/src/systems/shared/entities/gathering/types.ts @@ -32,7 +32,7 @@ export interface GatheringDebugInfo { /** * Active gathering session data. * - * Sessions are tick-based (OSRS-accurate timing): + * Sessions are tick-based (rules-accurate timing): * - startTick: When gathering started * - nextAttemptTick: Next tick to roll for success * - cycleTickInterval: Ticks between attempts (skill-specific) @@ -56,7 +56,7 @@ export interface GatheringSession { cachedDrops: ResourceDrop[]; cachedResourceName: string; - // OSRS-ACCURACY: Store start position to detect movement (cancels gathering) + // RULES ACCURACY: Store start position to detect movement (cancels gathering) cachedStartPosition: { x: number; y: number; z: number }; // DEBUG: Cached for logging (only used when DEBUG_GATHERING=true) @@ -66,7 +66,7 @@ export interface GatheringSession { /** * Resource timer data for Forestry-style mechanics. * - * OSRS Forestry mechanics: + * classic MMORPG Forestry mechanics: * - Timer starts on FIRST LOG (not first interaction) * - Counts down while anyone is gathering * - Regenerates when no one is gathering @@ -84,7 +84,7 @@ export interface ResourceTimer { /** * Fishing spot movement timer data. * - * OSRS-ACCURATE: Fishing spots don't deplete - they periodically move. + * RULES-ACCURATE: Fishing spots don't deplete - they periodically move. * Each spot has a random timer (280-530 ticks, ~2.8-5.3 min) that triggers relocation. */ export interface FishingSpotTimer { @@ -95,7 +95,7 @@ export interface FishingSpotTimer { } /** - * Success rate values for OSRS LERP formula. + * Success rate values for classic MMORPG LERP formula. * low = numerator at level 1, high = numerator at level 99 */ export interface SuccessRateValues { diff --git a/packages/shared/src/systems/shared/entities/processing/CookingCalculator.ts b/packages/shared/src/systems/shared/entities/processing/CookingCalculator.ts index ebfd1ed09..fb4f85b8a 100644 --- a/packages/shared/src/systems/shared/entities/processing/CookingCalculator.ts +++ b/packages/shared/src/systems/shared/entities/processing/CookingCalculator.ts @@ -1,11 +1,9 @@ /** * Cooking Calculator * - * OSRS-accurate cooking burn rate calculations. + * rules-accurate cooking burn rate calculations. * Uses data from items.json manifest via ProcessingDataProvider. * - * @see https://oldschool.runescape.wiki/w/Cooking - * @see https://oldschool.runescape.wiki/w/Cooking/Burn_level */ import { processingDataProvider } from "../../../../data/ProcessingDataProvider"; @@ -63,7 +61,7 @@ export function calculateBurnChance( return 0; // Edge case: stopBurn <= levelRequired } - const MAX_BURN_CHANCE = 0.55; // ~55% burn at minimum level (OSRS-like) + const MAX_BURN_CHANCE = 0.55; // ~55% burn at minimum level (classic MMORPG-like) const progress = cookingLevel - levelRequired; const rawBurn = 1 - progress / range; return Math.max(0, Math.min(MAX_BURN_CHANCE, rawBurn)); diff --git a/packages/shared/src/systems/shared/entities/processing/CookingSessionManager.ts b/packages/shared/src/systems/shared/entities/processing/CookingSessionManager.ts index 2de67a693..2ad1d5cee 100644 --- a/packages/shared/src/systems/shared/entities/processing/CookingSessionManager.ts +++ b/packages/shared/src/systems/shared/entities/processing/CookingSessionManager.ts @@ -2,14 +2,13 @@ * Cooking Session Manager * * Tick-based cooking session management. - * Follows OSRS mechanics: + * Follows classic tick-based mechanics: * - 4-tick per item * - Level-based burn chance (linear interpolation) * - "Cook All" support with quantity tracking * - Fire vs Range burn rates * - Movement cancellation * - * @see https://oldschool.runescape.wiki/w/Cooking */ import { PROCESSING_CONSTANTS } from "../../../../constants/ProcessingConstants"; @@ -138,7 +137,7 @@ export class CookingSessionManager { const now = Date.now(); const lastRequest = this.rateLimits.get(playerId); if (lastRequest && now - lastRequest < PROCESSING_CONSTANTS.RATE_LIMIT_MS) { - return null; // Silently drop (OSRS behavior) + return null; // Silently drop (classic MMORPG behavior) } this.rateLimits.set(playerId, now); diff --git a/packages/shared/src/systems/shared/entities/processing/FireManager.ts b/packages/shared/src/systems/shared/entities/processing/FireManager.ts index 5a0673c4e..cbb51a043 100644 --- a/packages/shared/src/systems/shared/entities/processing/FireManager.ts +++ b/packages/shared/src/systems/shared/entities/processing/FireManager.ts @@ -2,9 +2,8 @@ * Fire Manager * * Manages fire object lifecycle for firemaking skill. - * Implements OSRS-accurate walk-west behavior after lighting fires. + * Implements rules-accurate walk-west behavior after lighting fires. * - * @see https://oldschool.runescape.wiki/w/Firemaking */ import { PROCESSING_CONSTANTS } from "../../../../constants/ProcessingConstants"; @@ -15,7 +14,7 @@ import { getRandomFireDuration } from "./FiremakingCalculator"; /** * Direction offsets for walk-west priority. - * OSRS order: West, East, South, North + * classic MMORPG order: West, East, South, North */ const DIRECTION_OFFSETS: Record = { west: { x: -1, z: 0 }, @@ -39,7 +38,7 @@ function generateFireId(): string { * - Position-based lookup * - Range-based queries for cooking * - Automatic expiration via tick updates - * - OSRS walk-west movement calculation + * - classic MMORPG walk-west movement calculation */ export class FireManager { /** Active fires by ID */ @@ -273,7 +272,7 @@ export class FireManager { } /** - * Calculate post-fire position using OSRS walk-west behavior. + * Calculate post-fire position using classic MMORPG walk-west behavior. * * After lighting a fire, the player walks in priority order: * 1. West (preferred) diff --git a/packages/shared/src/systems/shared/entities/processing/FiremakingCalculator.ts b/packages/shared/src/systems/shared/entities/processing/FiremakingCalculator.ts index 4176fe218..b77120563 100644 --- a/packages/shared/src/systems/shared/entities/processing/FiremakingCalculator.ts +++ b/packages/shared/src/systems/shared/entities/processing/FiremakingCalculator.ts @@ -1,19 +1,18 @@ /** * Firemaking Calculator * - * OSRS-accurate firemaking success rate calculations. + * rules-accurate firemaking success rate calculations. * Uses data from items.json manifest via ProcessingDataProvider. * - * @see https://oldschool.runescape.wiki/w/Firemaking */ import { PROCESSING_CONSTANTS } from "../../../../constants/ProcessingConstants"; import { processingDataProvider } from "../../../../data/ProcessingDataProvider"; /** - * Calculate firemaking success rate using OSRS LERP formula. + * Calculate firemaking success rate using classic MMORPG LERP formula. * - * OSRS Formula: successChance = (low + (high - low) * (level - 1) / 98) / 256 + * classic MMORPG Formula: successChance = (low + (high - low) * (level - 1) / 98) / 256 * - At level 1: 65/256 = 25.4% * - At level 43: 256/256 = 100% (capped) * - At level 99: 513/256 = 100% (capped) @@ -21,7 +20,6 @@ import { processingDataProvider } from "../../../../data/ProcessingDataProvider" * @param level - Player's firemaking level (1-99) * @returns Success probability (0-1) * - * @see https://oldschool.runescape.wiki/w/Firemaking */ export function calculateFiremakingSuccess(level: number): number { const { low, high } = PROCESSING_CONSTANTS.FIREMAKING_SUCCESS_RATE; @@ -77,7 +75,7 @@ export function isValidLog(itemId: string): boolean { /** * Get random fire duration in ticks. * - * OSRS: Fires last 60-119 seconds (per Mod Ash). + * classic MMORPG: Fires last 60-119 seconds (per Mod Ash). * At 600ms/tick: 100-198 ticks. * * @returns Duration in ticks diff --git a/packages/shared/src/systems/shared/entities/processing/FiremakingSessionManager.ts b/packages/shared/src/systems/shared/entities/processing/FiremakingSessionManager.ts index dd13a3bc7..8c0ca5dd7 100644 --- a/packages/shared/src/systems/shared/entities/processing/FiremakingSessionManager.ts +++ b/packages/shared/src/systems/shared/entities/processing/FiremakingSessionManager.ts @@ -2,13 +2,12 @@ * Firemaking Session Manager * * Tick-based firemaking session management. - * Follows OSRS mechanics: + * Follows classic tick-based mechanics: * - 4-tick roll attempts * - Level-based success rate (25.4% at 1, 100% at 43+) * - Retry on failure * - Movement cancellation * - * @see https://oldschool.runescape.wiki/w/Firemaking */ import { PROCESSING_CONSTANTS } from "../../../../constants/ProcessingConstants"; @@ -111,7 +110,7 @@ export class FiremakingSessionManager { const now = Date.now(); const lastRequest = this.rateLimits.get(playerId); if (lastRequest && now - lastRequest < PROCESSING_CONSTANTS.RATE_LIMIT_MS) { - return null; // Silently drop (OSRS behavior) + return null; // Silently drop (classic MMORPG behavior) } this.rateLimits.set(playerId, now); @@ -267,7 +266,7 @@ export class FiremakingSessionManager { logId: session.cachedLogId, xpAwarded: 0, fireCreated: false, - message: "", // No message on fail (OSRS doesn't show fail messages for firemaking) + message: "", // No message on fail (classic MMORPG doesn't show fail messages for firemaking) }); this.callbacks.onAttemptFailed(playerId, session.cachedLogId); diff --git a/packages/shared/src/systems/shared/entities/processing/PendingCookingManager.ts b/packages/shared/src/systems/shared/entities/processing/PendingCookingManager.ts index f3c9ae5d5..011a0d31f 100644 --- a/packages/shared/src/systems/shared/entities/processing/PendingCookingManager.ts +++ b/packages/shared/src/systems/shared/entities/processing/PendingCookingManager.ts @@ -14,7 +14,6 @@ * 4. If valid, creates session in CookingSessionManager * 5. Session processes cooking with burn chance * - * @see https://oldschool.runescape.wiki/w/Cooking */ import { PROCESSING_CONSTANTS } from "../../../../constants/ProcessingConstants"; @@ -377,7 +376,7 @@ export class PendingCookingManager { } else if (reason === "no_food") { this.callbacks.sendMessage(playerId, "You have run out of food to cook."); } else if (reason === "moved") { - // No message - OSRS doesn't show a message for moving + // No message - classic MMORPG doesn't show a message for moving } if (DEBUG_PROCESSING) { diff --git a/packages/shared/src/systems/shared/entities/processing/PendingFiremakingManager.ts b/packages/shared/src/systems/shared/entities/processing/PendingFiremakingManager.ts index a65624c7d..cd994bca3 100644 --- a/packages/shared/src/systems/shared/entities/processing/PendingFiremakingManager.ts +++ b/packages/shared/src/systems/shared/entities/processing/PendingFiremakingManager.ts @@ -15,7 +15,6 @@ * 4. If valid, creates session in FiremakingSessionManager * 5. On success, creates fire and triggers walk-west * - * @see https://oldschool.runescape.wiki/w/Firemaking */ import { PROCESSING_CONSTANTS } from "../../../../constants/ProcessingConstants"; @@ -116,7 +115,7 @@ export class PendingFiremakingManager { this.handleFireLit(playerId, logId, xp, position); }, onAttemptFailed: (playerId, _logId) => { - // No message on fail (OSRS behavior) + // No message on fail (classic MMORPG behavior) if (DEBUG_PROCESSING) { console.log(`[PendingFiremaking] ${playerId} failed attempt`); } diff --git a/packages/shared/src/systems/shared/entities/processing/__tests__/CookingCalculator.test.ts b/packages/shared/src/systems/shared/entities/processing/__tests__/CookingCalculator.test.ts index 3f8c0ff4a..a0b3c48c3 100644 --- a/packages/shared/src/systems/shared/entities/processing/__tests__/CookingCalculator.test.ts +++ b/packages/shared/src/systems/shared/entities/processing/__tests__/CookingCalculator.test.ts @@ -1,15 +1,13 @@ /** * Cooking Calculator Tests * - * Verifies OSRS-accurate cooking calculations: + * Verifies rules-accurate cooking calculations: * - Burn chance formula (linear interpolation) * - Stop-burn levels per food type (fire vs range) * - XP values per food type * - Level requirements * - Cooked/burnt item mappings * - * @see https://oldschool.runescape.wiki/w/Cooking - * @see https://oldschool.runescape.wiki/w/Cooking/Burn_level */ import { describe, it, expect, beforeAll } from "vitest"; @@ -303,7 +301,7 @@ describe("CookingCalculator", () => { it("returns MAX_BURN_CHANCE at exact level requirement (highest burn rate)", () => { // At exactly level 1 for shrimp, burn chance is capped at MAX_BURN_CHANCE (0.55) - // (OSRS-like: meeting the requirement guarantees some chance of success) + // (classic MMORPG-like: meeting the requirement guarantees some chance of success) expect(calculateBurnChance(1, "raw_shrimp", "fire")).toBe(0.55); // Well above requirement, burn chance drops below the cap // rawBurn < 0.55 when progress/range > 0.45, i.e. level >= 16 for shrimp @@ -526,8 +524,8 @@ describe("CookingCalculator", () => { }); }); - describe("OSRS Wiki verification", () => { - // These tests verify specific values from the OSRS Wiki + describe("reference-rules verification", () => { + // These tests verify specific values from the reference ruleset it("raw_shrimp: level 1, 30 XP, stop burn 34 fire / 33 range", () => { expect(getCookingLevelRequired("raw_shrimp")).toBe(1); diff --git a/packages/shared/src/systems/shared/entities/processing/__tests__/FireManager.test.ts b/packages/shared/src/systems/shared/entities/processing/__tests__/FireManager.test.ts index 3c30f97fc..fc0984368 100644 --- a/packages/shared/src/systems/shared/entities/processing/__tests__/FireManager.test.ts +++ b/packages/shared/src/systems/shared/entities/processing/__tests__/FireManager.test.ts @@ -3,12 +3,11 @@ * * Verifies fire lifecycle management: * - Fire creation and indexing - * - OSRS walk-west behavior + * - classic MMORPG walk-west behavior * - Fire expiration * - Position-based queries * - Player fire limits * - * @see https://oldschool.runescape.wiki/w/Firemaking */ import { describe, it, expect, beforeEach } from "vitest"; @@ -424,7 +423,7 @@ describe("FireManager", () => { expect(target).toEqual({ x: 11, z: 10 }); }); - it("follows OSRS priority order: W → E → S → N", () => { + it("follows classic MMORPG priority order: W → E → S → N", () => { expect(PROCESSING_CONSTANTS.FIRE_WALK_PRIORITY).toEqual([ "west", "east", diff --git a/packages/shared/src/systems/shared/entities/processing/__tests__/FiremakingCalculator.test.ts b/packages/shared/src/systems/shared/entities/processing/__tests__/FiremakingCalculator.test.ts index 412e67b71..8166a61e5 100644 --- a/packages/shared/src/systems/shared/entities/processing/__tests__/FiremakingCalculator.test.ts +++ b/packages/shared/src/systems/shared/entities/processing/__tests__/FiremakingCalculator.test.ts @@ -1,13 +1,12 @@ /** * Firemaking Calculator Tests * - * Verifies OSRS-accurate firemaking calculations: + * Verifies rules-accurate firemaking calculations: * - Success rate formula (65/256 at level 1, 100% at level 43+) * - XP values per log type * - Level requirements * - Fire duration ranges * - * @see https://oldschool.runescape.wiki/w/Firemaking */ import { describe, it, expect, beforeAll } from "vitest"; @@ -26,7 +25,7 @@ import { type FiremakingManifest, } from "../../../../../data/ProcessingDataProvider"; -// OSRS-accurate firemaking data from recipes/firemaking.json +// rules-accurate firemaking data from recipes/firemaking.json const FIREMAKING_MANIFEST: FiremakingManifest = { recipes: [ { log: "logs", level: 1, xp: 40, ticks: 4 }, @@ -75,7 +74,7 @@ describe("FiremakingCalculator", () => { } }); - it("follows OSRS LERP formula: (low + (high - low) * (level - 1) / 98) / 256", () => { + it("follows classic MMORPG LERP formula: (low + (high - low) * (level - 1) / 98) / 256", () => { const { low, high } = PROCESSING_CONSTANTS.FIREMAKING_SUCCESS_RATE; // Test at level 50 (midpoint) @@ -224,7 +223,7 @@ describe("FiremakingCalculator", () => { }); describe("getRandomFireDuration", () => { - it("returns value within OSRS range (100-198 ticks)", () => { + it("returns value within classic MMORPG range (100-198 ticks)", () => { for (let i = 0; i < 100; i++) { const duration = getRandomFireDuration(); expect(duration).toBeGreaterThanOrEqual(100); @@ -272,8 +271,8 @@ describe("FiremakingCalculator", () => { }); }); - describe("OSRS Wiki verification", () => { - // These tests verify specific values from the OSRS Wiki + describe("reference-rules verification", () => { + // These tests verify specific values from the reference ruleset it("normal logs: level 1, 40 XP", () => { expect(getFiremakingLevelRequired("logs")).toBe(1); diff --git a/packages/shared/src/systems/shared/entities/processing/types.ts b/packages/shared/src/systems/shared/entities/processing/types.ts index 3ba957a29..8080bb7da 100644 --- a/packages/shared/src/systems/shared/entities/processing/types.ts +++ b/packages/shared/src/systems/shared/entities/processing/types.ts @@ -30,7 +30,7 @@ export interface ProcessingDebugInfo { * Active firemaking session data. * * PERFORMANCE: All data cached at session start to avoid per-tick allocations. - * OSRS-ACCURACY: Start position cached for movement detection (cancels action). + * RULES ACCURACY: Start position cached for movement detection (cancels action). */ export interface FiremakingSession { playerId: PlayerID; diff --git a/packages/shared/src/systems/shared/infrastructure/SystemLoader.ts b/packages/shared/src/systems/shared/infrastructure/SystemLoader.ts index 7961e59d1..32447de6d 100644 --- a/packages/shared/src/systems/shared/infrastructure/SystemLoader.ts +++ b/packages/shared/src/systems/shared/infrastructure/SystemLoader.ts @@ -331,7 +331,7 @@ export async function registerSystems(world: World): Promise { world.register("prayer", PrayerSystem); // 12a. Health regeneration system - Passive health regen (depends on combat system) - // Server-only: handles RuneScape-style out-of-combat health regeneration + // Server-only: handles classic fantasy MMORPG-style out-of-combat health regeneration // Note: world.isServer isn't reliable here because ServerNetwork registers later // Use Node.js/Bun environment check instead const isServerEnvironment = @@ -419,7 +419,7 @@ export async function registerSystems(world: World): Promise { world.register("inventory-interaction", InventoryInteractionSystem); // XP Drop System - 3D version disabled, using 2D screen-space drops in XPProgressOrb - // The 2D approach is more like RS3 where XP floats up the screen toward the orb + // The 2D approach is more like modern MMORPG where XP floats up the screen toward the orb // Keep XPDropSystem.ts for potential future use or alternative mode } diff --git a/packages/shared/src/systems/shared/interaction/CraftingSystem.ts b/packages/shared/src/systems/shared/interaction/CraftingSystem.ts index 46ffccaad..cfbc5ff71 100644 --- a/packages/shared/src/systems/shared/interaction/CraftingSystem.ts +++ b/packages/shared/src/systems/shared/interaction/CraftingSystem.ts @@ -1,7 +1,7 @@ /** * CraftingSystem - Handles Crafting Skills * - * OSRS-accurate crafting implementation: + * rules-accurate crafting implementation: * - Leather/dragonhide: use needle + thread + hides * - Jewelry: use mould + gold bar at furnace * - Gem cutting: use chisel on uncut gems @@ -10,7 +10,6 @@ * - Grants crafting XP per item made * - Auto-crafting continues until out of materials * - * @see https://oldschool.runescape.wiki/w/Crafting * @see ProcessingDataProvider for crafting recipes from manifest */ @@ -110,7 +109,7 @@ export class CraftingSystem extends SystemBase { }, ); - // Cancel crafting on movement (OSRS: any click cancels skilling) + // Cancel crafting on movement (classic MMORPG: any click cancels skilling) this.subscribe<{ playerId: string; targetPosition: { x: number; y: number; z: number }; @@ -193,7 +192,7 @@ export class CraftingSystem extends SystemBase { let filteredRecipes = processingDataProvider.getCraftingRecipesByStation(station); - // Filter by specific input item if provided (OSRS-accurate: only show relevant recipes) + // Filter by specific input item if provided (rules-accurate: only show relevant recipes) if (inputItemId) { filteredRecipes = filteredRecipes.filter((recipe) => recipe.inputs.some((inp) => inp.item === inputItemId), @@ -460,7 +459,7 @@ export class CraftingSystem extends SystemBase { return; } - // Play crafting animation (OSRS-style) + // Play crafting animation (classic MMORPG-style) this.emitTypedEvent(EventType.ANIMATION_PLAY, { entityId: playerId, animation: "crafting", @@ -517,7 +516,7 @@ export class CraftingSystem extends SystemBase { batchTotal: session.quantity, }); - // Success message (OSRS style - shows item name) + // Success message (classic MMORPG style - shows item name) const itemName = recipe.name || recipe.output.replace(/_/g, " "); this.emitTypedEvent(EventType.UI_MESSAGE, { playerId, diff --git a/packages/shared/src/systems/shared/interaction/FletchingSystem.ts b/packages/shared/src/systems/shared/interaction/FletchingSystem.ts index bec8ca662..52ccca071 100644 --- a/packages/shared/src/systems/shared/interaction/FletchingSystem.ts +++ b/packages/shared/src/systems/shared/interaction/FletchingSystem.ts @@ -1,7 +1,7 @@ /** * FletchingSystem - Handles Fletching Skill * - * OSRS-accurate fletching implementation: + * rules-accurate fletching implementation: * - Knife + logs → arrow shafts (multi-output) or unstrung bows * - Bowstring + unstrung bow → strung bow (item-on-item) * - Arrowtips + headless arrows → finished arrows (item-on-item, multi-output) @@ -10,7 +10,6 @@ * - Grants fletching XP per action * - Auto-fletching continues until out of materials * - * @see https://oldschool.runescape.wiki/w/Fletching * @see ProcessingDataProvider for fletching recipes from manifest */ @@ -111,7 +110,7 @@ export class FletchingSystem extends SystemBase { }, ); - // Cancel fletching on movement (OSRS: any click cancels skilling) + // Cancel fletching on movement (classic MMORPG: any click cancels skilling) this.subscribe<{ playerId: string; targetPosition: { x: number; y: number; z: number }; diff --git a/packages/shared/src/systems/shared/interaction/InventoryInteractionSystem.ts b/packages/shared/src/systems/shared/interaction/InventoryInteractionSystem.ts index 38ce533ff..2d20bdff6 100644 --- a/packages/shared/src/systems/shared/interaction/InventoryInteractionSystem.ts +++ b/packages/shared/src/systems/shared/interaction/InventoryInteractionSystem.ts @@ -4,7 +4,7 @@ * Handles both: * - Drag-and-drop for inventory/equipment management * - Item right-click context menus (Wear, Drop, Eat, Use, etc.) - * Provides complete RuneScape-style inventory interactions. + * Provides complete classic fantasy MMORPG-style inventory interactions. */ import { @@ -1183,7 +1183,7 @@ export class InventoryInteractionSystem extends SystemBase { }, }); - // === OSRS-STYLE "USE" ACTIONS FOR FIREMAKING/COOKING === + // === classic MMORPG-STYLE "USE" ACTIONS FOR FIREMAKING/COOKING === // Tinderbox: Use on logs to light fire this.registerAction("processing", { @@ -1196,7 +1196,7 @@ export class InventoryInteractionSystem extends SystemBase { }, }); - // Logs: Use on tinderbox (reverse direction also works in OSRS) + // Logs: Use on tinderbox (reverse direction also works in classic MMORPG) this.registerAction("processing", { id: "use", label: "Use", @@ -1568,7 +1568,7 @@ export class InventoryInteractionSystem extends SystemBase { return dataManager.getItem(itemId); } - // === TARGETING MODE FOR OSRS-STYLE "USE X ON Y" === + // === TARGETING MODE FOR classic MMORPG-STYLE "USE X ON Y" === /** * Start targeting mode for "Use X on Y" interactions. diff --git a/packages/shared/src/systems/shared/interaction/ProcessingSystem.ts b/packages/shared/src/systems/shared/interaction/ProcessingSystem.ts index 1143182a6..9b8edf870 100644 --- a/packages/shared/src/systems/shared/interaction/ProcessingSystem.ts +++ b/packages/shared/src/systems/shared/interaction/ProcessingSystem.ts @@ -66,9 +66,8 @@ export class ProcessingSystem extends SystemBase { // NOTE: XP values and cooking parameters are now in the item manifest (items.json) // and accessed via ProcessingDataProvider at runtime. - // OSRS firemaking movement priority: West → East → South → North + // classic MMORPG firemaking movement priority: West → East → South → North // After lighting a fire, player moves to an adjacent tile in this priority order - // @see https://oldschool.runescape.wiki/w/Firemaking private readonly FIREMAKING_MOVE_PRIORITY = [ { dx: -1, dz: 0 }, // West (-X) { dx: 1, dz: 0 }, // East (+X) @@ -451,7 +450,7 @@ export class ProcessingSystem extends SystemBase { type: "info", }); - // OSRS: Player squats/crouches while lighting fire + // classic MMORPG: Player squats/crouches while lighting fire this.setProcessingEmote(playerId); // Cache player start position for movement detection and fire placement @@ -631,10 +630,10 @@ export class ProcessingSystem extends SystemBase { this.fireCleanupTimers.set(fireId, cleanupTimer); - // OSRS: Reset emote when fire is lit (before moving) + // classic MMORPG: Reset emote when fire is lit (before moving) this.resetPlayerEmote(playerId); - // OSRS: Move player to adjacent tile after lighting fire + // classic MMORPG: Move player to adjacent tile after lighting fire // Priority: West → East → South → North const moveTarget = this.findFiremakingMoveTarget(position); if (moveTarget) { @@ -813,7 +812,7 @@ export class ProcessingSystem extends SystemBase { this.activeProcessing.set(playerId, processingAction); - // Show processing message only on first cook (OSRS style) + // Show processing message only on first cook (classic MMORPG style) if (isFirstCook) { this.emitTypedEvent(EventType.UI_MESSAGE, { playerId, @@ -822,7 +821,7 @@ export class ProcessingSystem extends SystemBase { }); } - // OSRS: Player squats/crouches for each cook attempt + // classic MMORPG: Player squats/crouches for each cook attempt this.setProcessingEmote(playerId); // Complete after duration @@ -883,13 +882,13 @@ export class ProcessingSystem extends SystemBase { // Release action back to pool this.releaseAction(action); - // OSRS Auto-cooking: Check if player has more cookable items and continue + // classic MMORPG Auto-cooking: Check if player has more cookable items and continue this.tryAutoCookNext(playerId, sourceId, isRange); } /** * Check if player has more cookable items and automatically continue cooking. - * This implements OSRS-style auto-cooking where you cook all items until done. + * This implements classic MMORPG-style auto-cooking where you cook all items until done. * @param isRange - If true, cooking on a permanent range (always active). */ private tryAutoCookNext( @@ -1032,7 +1031,7 @@ export class ProcessingSystem extends SystemBase { }); } - // Success/failure message (OSRS style) - use generic food name + // Success/failure message (classic MMORPG style) - use generic food name const foodName = rawItemId.replace("raw_", ""); const message = didBurn ? `You accidentally burn the ${foodName}.` @@ -1059,7 +1058,7 @@ export class ProcessingSystem extends SystemBase { /** * Calculate burn chance based on cooking level and food-specific parameters. - * Uses OSRS-accurate linear interpolation. + * Uses rules-accurate linear interpolation. * * @param cookingLevel - Player's cooking level * @param requiredLevel - Level required to cook this food @@ -1343,7 +1342,7 @@ export class ProcessingSystem extends SystemBase { fire.mesh = undefined; } - // Spawn ashes at fire position (server-only, OSRS: fires leave ashes when they burn out) + // Spawn ashes at fire position (server-only, classic MMORPG: fires leave ashes when they burn out) if (this.world.isServer) { const groundItems = this.world.getSystem("ground-items"); @@ -1443,13 +1442,12 @@ export class ProcessingSystem extends SystemBase { return false; } - // === FIREMAKING MOVEMENT (OSRS-accurate) === + // === FIREMAKING MOVEMENT (rules-accurate) === /** - * Find the tile to move to after lighting a fire (OSRS-accurate) + * Find the tile to move to after lighting a fire (rules-accurate) * Priority: West → East → South → North * - * @see https://oldschool.runescape.wiki/w/Firemaking */ private findFiremakingMoveTarget(firePosition: { x: number; diff --git a/packages/shared/src/systems/shared/interaction/RunecraftingSystem.ts b/packages/shared/src/systems/shared/interaction/RunecraftingSystem.ts index 73eebecc4..7e983af99 100644 --- a/packages/shared/src/systems/shared/interaction/RunecraftingSystem.ts +++ b/packages/shared/src/systems/shared/interaction/RunecraftingSystem.ts @@ -1,7 +1,7 @@ /** * RunecraftingSystem - Instant Essence-to-Rune Conversion at Altars * - * OSRS-accurate runecrafting implementation: + * rules-accurate runecrafting implementation: * - Click altar to instantly convert all carried essence into runes * - Two essence types: rune_essence (basic runes), pure_essence (all runes) * - Multi-rune crafting at higher levels (e.g., 2x air runes at level 11) @@ -10,7 +10,6 @@ * Unlike smelting/smithing, runecrafting is INSTANT (no tick-based sessions). * One click converts all valid essence in inventory at once. * - * @see https://oldschool.runescape.wiki/w/Runecrafting * @see ProcessingDataProvider for runecrafting recipes from manifest */ diff --git a/packages/shared/src/systems/shared/interaction/SmeltingSystem.ts b/packages/shared/src/systems/shared/interaction/SmeltingSystem.ts index 37e6e4316..16e3108b5 100644 --- a/packages/shared/src/systems/shared/interaction/SmeltingSystem.ts +++ b/packages/shared/src/systems/shared/interaction/SmeltingSystem.ts @@ -1,14 +1,13 @@ /** * SmeltingSystem - Handles Smelting at Furnaces * - * OSRS-accurate smelting implementation: + * rules-accurate smelting implementation: * - Use ores on furnace to smelt bars * - Consumes primary ore, secondary ore (bronze), and coal * - Iron ore has 50% success rate (others always succeed) * - Grants smithing XP on successful smelt * - Auto-smelting continues until out of materials * - * @see https://oldschool.runescape.wiki/w/Smithing#Smelting * @see ProcessingDataProvider for smelting recipes from manifest */ @@ -97,7 +96,7 @@ export class SmeltingSystem extends SystemBase { }, ); - // Cancel smelting on movement (OSRS: any click cancels skilling) + // Cancel smelting on movement (classic MMORPG: any click cancels skilling) this.subscribe<{ playerId: string; targetPosition: { x: number; y: number; z: number }; @@ -351,7 +350,7 @@ export class SmeltingSystem extends SystemBase { return; } - // Play smelting animation (OSRS-style) + // Play smelting animation (classic MMORPG-style) this.emitTypedEvent(EventType.ANIMATION_PLAY, { entityId: playerId, animation: "smelting", diff --git a/packages/shared/src/systems/shared/interaction/SmithingSystem.ts b/packages/shared/src/systems/shared/interaction/SmithingSystem.ts index a4e3f5597..0efd588d9 100644 --- a/packages/shared/src/systems/shared/interaction/SmithingSystem.ts +++ b/packages/shared/src/systems/shared/interaction/SmithingSystem.ts @@ -1,7 +1,7 @@ /** * SmithingSystem - Handles Smithing at Anvils * - * OSRS-accurate smithing implementation: + * rules-accurate smithing implementation: * - Use bars on anvil to smith items * - Requires hammer in inventory (not consumed) * - Consumes bars based on recipe @@ -9,7 +9,6 @@ * - Grants smithing XP per item made * - Auto-smithing continues until out of bars * - * @see https://oldschool.runescape.wiki/w/Smithing * @see ProcessingDataProvider for smithing recipes from manifest */ @@ -327,7 +326,7 @@ export class SmithingSystem extends SystemBase { return; } - // Play smithing animation (OSRS-style) + // Play smithing animation (classic MMORPG-style) this.emitTypedEvent(EventType.ANIMATION_PLAY, { entityId: playerId, animation: "smithing", @@ -363,7 +362,7 @@ export class SmithingSystem extends SystemBase { session.smithed++; - // Success message (OSRS style - shows item name) + // Success message (classic MMORPG style - shows item name) const qtyText = qty > 1 ? `${qty} ${recipe.name}` : `a ${recipe.name}`; this.emitTypedEvent(EventType.UI_MESSAGE, { playerId, diff --git a/packages/shared/src/systems/shared/interaction/TanningSystem.ts b/packages/shared/src/systems/shared/interaction/TanningSystem.ts index 710a1f14a..e596111af 100644 --- a/packages/shared/src/systems/shared/interaction/TanningSystem.ts +++ b/packages/shared/src/systems/shared/interaction/TanningSystem.ts @@ -1,14 +1,13 @@ /** * TanningSystem - Handles Hide Tanning at Tanner NPCs * - * OSRS-accurate tanning implementation: + * rules-accurate tanning implementation: * - Talk to tanner NPC to open tanning interface * - Select hide type and quantity * - Instant conversion: deduct coins + hide, add leather - * - No tick delay — tanning is instant in OSRS + * - No tick delay — tanning is instant in classic MMORPG * - Costs: cowhide → leather (1gp), green dragonhide → green dragon leather (20gp) * - * @see https://oldschool.runescape.wiki/w/Tanner * @see ProcessingDataProvider for tanning recipes from manifest */ diff --git a/packages/shared/src/systems/shared/interaction/__tests__/ProcessingSystem.test.ts b/packages/shared/src/systems/shared/interaction/__tests__/ProcessingSystem.test.ts index c2a00f350..0dfb6df74 100644 --- a/packages/shared/src/systems/shared/interaction/__tests__/ProcessingSystem.test.ts +++ b/packages/shared/src/systems/shared/interaction/__tests__/ProcessingSystem.test.ts @@ -3,7 +3,7 @@ * * Unit tests for the ProcessingSystem covering: * - Fire limits (max 3 per player) - * - Burn chance calculation (OSRS-accurate) + * - Burn chance calculation (rules-accurate) * - Object pooling behavior * - fishSlot=-1 handling (find first cookable) * - Rate limiting logic diff --git a/packages/shared/src/systems/shared/loot/LootPermissionService.ts b/packages/shared/src/systems/shared/loot/LootPermissionService.ts index b2bf37ea3..80ddef427 100644 --- a/packages/shared/src/systems/shared/loot/LootPermissionService.ts +++ b/packages/shared/src/systems/shared/loot/LootPermissionService.ts @@ -4,7 +4,7 @@ * Pure function for loot permission checks. * Shared by HeadstoneEntity (interaction gating) and GravestoneLootSystem (loot processing). * - * Rules (OSRS-style): + * Rules (classic MMORPG-style): * - Owner can always loot their own gravestone * - Safe area deaths (lootProtectionUntil=0): owner-only, no expiration * - Wilderness/PvP deaths: protectedFor (killer) can loot during protection period diff --git a/packages/shared/src/systems/shared/movement/BFSPathfinder.ts b/packages/shared/src/systems/shared/movement/BFSPathfinder.ts index df1677232..b9420ee9f 100644 --- a/packages/shared/src/systems/shared/movement/BFSPathfinder.ts +++ b/packages/shared/src/systems/shared/movement/BFSPathfinder.ts @@ -1,11 +1,11 @@ /** - * BFS Pathfinder — OSRS "Smartpathing" + * BFS Pathfinder — classic MMORPG "Smartpathing" * - * OSRS player movement uses BFS ("smartpathing") as the primary algorithm. + * classic MMORPG player movement uses BFS ("smartpathing") as the primary algorithm. * Naive/dumb diagonal pathing is ONLY used by NPC chase movement (see ChasePathfinding.ts). * * Key features: - * - BFS with OSRS neighbor order (W,E,S,N,SW,SE,NW,NE) + * - BFS with classic MMORPG neighbor order (W,E,S,N,SW,SE,NW,NE) * - findPathToAny(): Multi-destination BFS for combat — terminates at the first * valid combat tile reached, naturally finding the shortest path. * - findNaivePath(): Exposed for NPC chase systems only, never called from findPath(). @@ -27,7 +27,6 @@ * BFS is limited to PATHFIND_RADIUS (128 tiles) from the start position. * Destinations outside this radius will result in partial paths. * - * @see https://oldschool.runescape.wiki/w/Pathfinding */ import { @@ -111,7 +110,7 @@ export class BFSPathfinder { } /** - * Find a path from start to end using BFS (OSRS "smartpathing"). + * Find a path from start to end using BFS (classic MMORPG "smartpathing"). * BFS is the primary pathfinder for all player movement. * * After calling, check `wasLastPathPartial()` to see if the path @@ -177,7 +176,7 @@ export class BFSPathfinder { } } - // BFS is the primary pathfinder (OSRS "smartpathing") + // BFS is the primary pathfinder (classic MMORPG "smartpathing") // Note: BFS may also set _lastPathWasPartial if iteration limit is reached return this.findBFSPath(start, end, isWalkable, maxIterations); } @@ -185,7 +184,7 @@ export class BFSPathfinder { /** * Multi-destination BFS: find shortest path from start to ANY destination tile. * - * OSRS combat pathfinding feeds all valid interaction tiles into the pathfinder + * classic MMORPG combat pathfinding feeds all valid interaction tiles into the pathfinder * and terminates as soon as any is reached. This naturally finds the shortest * path to the closest valid combat tile. * @@ -262,7 +261,7 @@ export class BFSPathfinder { return this.reconstructPath(start, current, parent); } - // Expand neighbors in OSRS order (zero-allocation scratch tile for checks) + // Expand neighbors in classic MMORPG order (zero-allocation scratch tile for checks) for (const dir of TILE_DIRECTIONS) { const nx = current.x + dir.x; const nz = current.z + dir.z; @@ -449,7 +448,7 @@ export class BFSPathfinder { return this.reconstructPath(start, end, parent); } - // Check all 8 directions in OSRS order: W, E, S, N, SW, SE, NW, NE + // Check all 8 directions in classic MMORPG order: W, E, S, N, SW, SE, NW, NE // OPTIMIZATION: Use scratch tile for checks, only allocate when enqueuing. // Reduces allocations from 8 per iteration to ~1-2 (only walkable neighbors). for (const dir of TILE_DIRECTIONS) { diff --git a/packages/shared/src/systems/shared/movement/ChasePathfinding.ts b/packages/shared/src/systems/shared/movement/ChasePathfinding.ts index 93cf7d6cf..7313dbfc7 100644 --- a/packages/shared/src/systems/shared/movement/ChasePathfinding.ts +++ b/packages/shared/src/systems/shared/movement/ChasePathfinding.ts @@ -1,5 +1,5 @@ /** - * Chase Pathfinding (OSRS "Dumb Pathfinder") + * Chase Pathfinding (classic MMORPG "Dumb Pathfinder") * * Simple greedy pathfinding algorithm for NPC chasing behavior. * Unlike BFS which searches for optimal paths around obstacles, @@ -8,7 +8,7 @@ * This is intentionally simple - NPCs don't navigate around obstacles, * which enables "safespotting" gameplay where players can hide behind objects. * - * OSRS-Accurate Algorithm: + * Rules-Accurate Algorithm: * 1. Calculate direction to target (normalized to -1, 0, or 1) * 2. Try diagonal step FIRST (if moving on both axes AND corner-cut is valid) * 3. If diagonal blocked, try cardinal steps (prioritize axis with greater distance) @@ -22,7 +22,6 @@ * - chaseStep() allocates objects per call (for backwards compatibility) * - ChasePathfinder class provides zero-allocation alternative for hot paths * - * @see https://oldschool.runescape.wiki/w/Pathfinding */ import type { TileCoord } from "./TileSystem"; @@ -57,7 +56,7 @@ export function chaseStep( const candidates: TileCoord[] = []; // Priority 1: Diagonal (if moving on both axes AND corner-cut is valid) - // OSRS corner-cutting rule: Both adjacent cardinal tiles must be walkable + // classic MMORPG corner-cutting rule: Both adjacent cardinal tiles must be walkable // to move diagonally. This prevents cutting through wall corners. if (dx !== 0 && dz !== 0) { const cardinalX: TileCoord = { x: current.x + dx, z: current.z }; diff --git a/packages/shared/src/systems/shared/movement/CollisionFlags.ts b/packages/shared/src/systems/shared/movement/CollisionFlags.ts index e225c4ee9..ff2e2e3d5 100644 --- a/packages/shared/src/systems/shared/movement/CollisionFlags.ts +++ b/packages/shared/src/systems/shared/movement/CollisionFlags.ts @@ -1,17 +1,16 @@ /** - * CollisionFlags - OSRS-accurate collision bitmask flags + * CollisionFlags - rules-accurate collision bitmask flags * * Each tile has an int32 bitmask combining these flags. * Bitwise operations allow efficient queries: * if (flags & CollisionFlag.BLOCKED) { // can't walk } * - * Flag values match OSRS conventions where possible: + * Flag values match classic MMORPG conventions where possible: * - Wall flags: 0x1 - 0x80 (directional) * - Occupied: 0x100 - 0x200 (entities) * - Blocked: 0x200000 (full tile block) * - LoS block: 0x400000 (ranged combat) * - * @see https://osrs-docs.com/docs/mechanics/entity-collision/ * @see https://rune-server.org/threads/collision-flags-map-rendering.620525/ */ diff --git a/packages/shared/src/systems/shared/movement/EntityOccupancyMap.ts b/packages/shared/src/systems/shared/movement/EntityOccupancyMap.ts index ba9aa292f..91f29f4d6 100644 --- a/packages/shared/src/systems/shared/movement/EntityOccupancyMap.ts +++ b/packages/shared/src/systems/shared/movement/EntityOccupancyMap.ts @@ -1,9 +1,9 @@ /** * EntityOccupancyMap - Tracks entity tile occupancy for collision * - * OSRS-accurate entity collision: + * rules-accurate entity collision: * - Each tile can be occupied by at most one NPC (for collision purposes) - * - Players also set occupancy flags (optional - OSRS does this) + * - Players also set occupancy flags (optional - classic MMORPG does this) * - Bosses/special NPCs can ignore collision (configurable) * * Memory Hygiene: @@ -11,14 +11,12 @@ * - Pre-allocated query buffers to avoid hot path allocations * - No closures created during isBlocked/isOccupied checks * - * OSRS Mechanics (verified from osrs-docs.com): * - Flags set when entity spawns/moves TO a tile * - Flags removed when entity despawns/moves OFF a tile * - Pathfinder IGNORES entity collision (checked at movement time) * - If blocked, movement fails but path is RETAINED * * @see NPC_ENTITY_COLLISION_PLAN.md - * @see https://osrs-docs.com/docs/mechanics/entity-collision/ */ import type { EntityID } from "../../../types/core/identifiers"; @@ -114,7 +112,7 @@ export interface IEntityOccupancy { /** * Production implementation of entity occupancy tracking * - * Provides OSRS-accurate entity collision for NPCs and players. + * Provides rules-accurate entity collision for NPCs and players. * Uses Map-based storage with O(1) lookups. */ export class EntityOccupancyMap implements IEntityOccupancy { @@ -345,7 +343,7 @@ export class EntityOccupancyMap implements IEntityOccupancy { /** * Move entity to new tiles (atomic operation with delta-based CollisionMatrix updates) * - * Follows OSRS flag update order: + * Follows classic MMORPG flag update order: * 1. Remove flags from old tiles not in new position * 2. Add flags on new tiles not in old position * 3. Update internal tracking diff --git a/packages/shared/src/systems/shared/movement/PathPersistenceManager.ts b/packages/shared/src/systems/shared/movement/PathPersistenceManager.ts index 31624cd82..6d143b062 100644 --- a/packages/shared/src/systems/shared/movement/PathPersistenceManager.ts +++ b/packages/shared/src/systems/shared/movement/PathPersistenceManager.ts @@ -1,7 +1,7 @@ /** - * PathPersistenceManager - OSRS-accurate NPC path persistence + * PathPersistenceManager - rules-accurate NPC path persistence * - * Key OSRS behaviors: + * Key classic MMORPG behaviors: * - Path persists when blocked by entities (retry next tick) * - Path clears only when blocked by terrain (safespotted) * - NPCs slide along obstacles when blocked @@ -9,7 +9,6 @@ * This manager tracks path state per NPC and distinguishes between * entity blocking (temporary) and terrain blocking (permanent/safespot). * - * @see https://oldschool.runescape.wiki/w/Pathfinding */ import type { TileCoord } from "./TileSystem"; @@ -50,7 +49,7 @@ export type BlockChecker = ( /** * PathPersistenceManager - Manages path state for all NPCs * - * Provides OSRS-accurate path persistence: + * Provides rules-accurate path persistence: * - Paths persist when blocked by entities * - Paths clear when blocked by terrain (safespotted) */ @@ -169,7 +168,7 @@ export class PathPersistenceManager { const blockResult = checkBlock(desiredTile, npcId); if (blockResult.blocked && blockResult.byEntity) { - // Blocked by entity - PERSIST path (OSRS behavior) + // Blocked by entity - PERSIST path (classic MMORPG behavior) state.blockedByEntity = true; state.ticksBlocked++; state.lastAttemptedTile = desiredTile; @@ -185,7 +184,7 @@ export class PathPersistenceManager { } } - // Blocked by terrain - CLEAR path (safespotted, OSRS behavior) + // Blocked by terrain - CLEAR path (safespotted, classic MMORPG behavior) state.targetTile = null; state.blockedByEntity = false; state.ticksBlocked = 0; diff --git a/packages/shared/src/systems/shared/movement/TileSystem.ts b/packages/shared/src/systems/shared/movement/TileSystem.ts index 8414a1b8d..bf2605c2e 100644 --- a/packages/shared/src/systems/shared/movement/TileSystem.ts +++ b/packages/shared/src/systems/shared/movement/TileSystem.ts @@ -1,13 +1,13 @@ /** * Tile System * - * Core constants and utilities for RuneScape-style tile-based movement. + * Core constants and utilities for classic fantasy MMORPG-style tile-based movement. * The game world is divided into discrete tiles, and entities move * one tile at a time in sync with server ticks. * * Key concepts: * - TILE_SIZE: World units per tile (1.0 = 1 meter per tile) - * - TICK_DURATION_MS: Server tick interval (600ms like RuneScape) + * - TICK_DURATION_MS: Server tick interval (600ms like classic fantasy MMORPG) * - Movement happens discretely: 1 tile/tick (walk) or 2 tiles/tick (run) * - Client interpolates visually between tile positions */ @@ -19,14 +19,14 @@ import type { IEntityOccupancy } from "./EntityOccupancyMap"; /** * Core tile system constants * - * OSRS uses 600ms ticks with 1 tile/tick walk, 2 tiles/tick run. + * classic MMORPG uses 600ms ticks with 1 tile/tick walk, 2 tiles/tick run. * We use 2x speed (2/4 tiles per tick) for a snappier modern feel * while keeping the tick-based movement system. */ export const TILE_SIZE = 1.0; // 1 world unit = 1 tile export const TICK_DURATION_MS = 600; // 0.6 seconds per server tick -export const TILES_PER_TICK_WALK = 2; // Walking: 2 tiles per tick (2x OSRS) -export const TILES_PER_TICK_RUN = 4; // Running: 4 tiles per tick (2x OSRS) +export const TILES_PER_TICK_WALK = 2; // Walking: 2 tiles per tick (2x classic MMORPG) +export const TILES_PER_TICK_RUN = 4; // Running: 4 tiles per tick (2x classic MMORPG) export const MAX_PATH_LENGTH = 25; // Maximum checkpoint tiles in a path export const PATHFIND_RADIUS = 128; // BFS search radius in tiles @@ -51,7 +51,7 @@ export interface TileMovementState { /** * Tile player was on at START of current tick (captured before movement) * - * OSRS-ACCURATE: Used by FollowManager for follow mechanic. + * RULES-ACCURATE: Used by FollowManager for follow mechanic. * Following a player means walking to their PREVIOUS tile, * creating the characteristic 1-tick trailing effect. * @@ -160,7 +160,7 @@ export function tileToWorld(tile: TileCoord): { /** * Snap a world position to the center of its containing tile * - * OSRS-ACCURACY: All interactable objects are tile-aligned in OSRS. + * RULES ACCURACY: All interactable objects are tile-aligned in classic MMORPG. * This function ensures resources, NPCs, and other objects are positioned * at tile centers rather than arbitrary coordinates. * @@ -226,7 +226,7 @@ export function tilesEqual(a: TileCoord, b: TileCoord): boolean { * This includes diagonal adjacency (8 directions). * Used for general "next to each other" checks. * - * OSRS Reference: Entities are considered "in melee range" when adjacent. + * classic MMORPG Reference: Entities are considered "in melee range" when adjacent. */ export function tilesAdjacent(a: TileCoord, b: TileCoord): boolean { const dx = Math.abs(a.x - b.x); @@ -261,7 +261,7 @@ export function tilesWithinRange( /** * Check if player is within range of ANY tile in a multi-tile footprint. * - * OSRS-ACCURATE: Multi-tile objects like furnaces (2x2) can be interacted with + * RULES-ACCURATE: Multi-tile objects like furnaces (2x2) can be interacted with * from any adjacent tile. The footprint is CENTERED on the target position. * * For a 2x2 furnace at position (10.5, 10.5): @@ -315,9 +315,9 @@ export function tilesWithinRangeOfFootprint( } /** - * OSRS-accurate melee range check + * rules-accurate melee range check * - * OSRS melee attack rules (from wiki): + * classic MMORPG melee attack rules (from wiki): * - Range 1 (standard melee): CARDINAL ONLY (N/S/E/W) - cannot attack diagonally * - Range 2+ (halberd, spear): Can attack diagonally (uses Chebyshev distance) * - Salamanders are special: range 1 but CAN attack diagonally (not implemented here) @@ -327,7 +327,6 @@ export function tilesWithinRangeOfFootprint( * @param meleeRange - Weapon's melee range (1 = standard, 2 = halberd) * @returns true if target is within melee attack range * - * @see https://oldschool.runescape.wiki/w/Attack_range */ export function tilesWithinMeleeRange( attacker: TileCoord, @@ -338,7 +337,7 @@ export function tilesWithinMeleeRange( const dz = Math.abs(attacker.z - target.z); // Range 1 (standard melee): CARDINAL ONLY - no diagonal attacks - // This is the core OSRS melee mechanic that makes positioning matter + // This is the core classic MMORPG melee mechanic that makes positioning matter if (meleeRange === COMBAT_CONSTANTS.MELEE_RANGE_STANDARD) { return (dx === 1 && dz === 0) || (dx === 0 && dz === 1); } @@ -353,9 +352,9 @@ export function tilesWithinMeleeRange( /** * Check if two tiles are cardinally adjacent (Manhattan distance = 1) * This is N/S/E/W only, no diagonals. - * In OSRS, melee attacks are cardinal-only (except salamanders). + * In classic MMORPG, melee attacks are cardinal-only (except salamanders). * - * OSRS Reference: Standard melee can only attack N/S/E/W, not diagonally. + * classic MMORPG Reference: Standard melee can only attack N/S/E/W, not diagonally. */ export function tilesCardinallyAdjacent(a: TileCoord, b: TileCoord): boolean { const dx = Math.abs(a.x - b.x); @@ -369,11 +368,11 @@ export function tilesCardinallyAdjacent(a: TileCoord, b: TileCoord): boolean { * Returns the adjacent tile to `target` that is closest to `attacker`. * This is used for melee combat positioning - stand next to target, not on it. * - * OSRS Reference: NPCs path to an adjacent tile when chasing for melee combat. + * classic MMORPG Reference: NPCs path to an adjacent tile when chasing for melee combat. * * @param target - The tile the target is standing on * @param attacker - The tile the attacker is currently on - * @param cardinalOnly - If true, only consider N/S/E/W tiles (OSRS melee behavior) + * @param cardinalOnly - If true, only consider N/S/E/W tiles (classic MMORPG melee behavior) * @param isWalkable - Optional function to check if a tile is walkable * @returns The best adjacent tile to stand on, or null if none available */ @@ -495,9 +494,9 @@ export function getBestCombatRangeTile( } /** - * OSRS-accurate melee destination tile selection + * rules-accurate melee destination tile selection * - * When clicking an NPC for melee combat, OSRS: + * When clicking an NPC for melee combat, classic MMORPG: * 1. Finds all tiles within melee range of the target * 2. For range 1: only cardinal tiles (N/S/E/W) - NO diagonal * 3. For range 2+: all tiles within Chebyshev distance @@ -509,7 +508,6 @@ export function getBestCombatRangeTile( * @param isWalkable - Optional function to check if a tile is walkable * @returns The best tile to path to for melee combat, or null if none available * - * @see https://oldschool.runescape.wiki/w/Pathfinding */ export function getBestMeleeTile( target: TileCoord, @@ -524,7 +522,7 @@ export function getBestMeleeTile( return attacker; } - // For range 1: CARDINAL ONLY (OSRS melee behavior) + // For range 1: CARDINAL ONLY (classic MMORPG melee behavior) if (effectiveRange === COMBAT_CONSTANTS.MELEE_RANGE_STANDARD) { const cardinalTiles = [ { x: target.x - 1, z: target.z }, // West @@ -582,7 +580,7 @@ export function getBestMeleeTile( } /** - * Get adjacent tiles (8 directions - RuneScape order) + * Get adjacent tiles (8 directions - classic fantasy MMORPG order) * Order: W, E, S, N, SW, SE, NW, NE */ export function getAdjacentTiles(tile: TileCoord): TileCoord[] { @@ -599,7 +597,7 @@ export function getAdjacentTiles(tile: TileCoord): TileCoord[] { } /** - * Direction vectors matching RuneScape's neighbor check order + * Direction vectors matching classic fantasy MMORPG's neighbor check order */ export const TILE_DIRECTIONS = [ { x: -1, z: 0 }, // West @@ -614,9 +612,8 @@ export const TILE_DIRECTIONS = [ /** * Cardinal directions only (N/E/S/W, no diagonals) - * OSRS uses all 4 cardinal directions for NPC step-out when on same tile + * classic MMORPG uses all 4 cardinal directions for NPC step-out when on same tile * - * @see https://osrs-docs.com/docs/mechanics/entity-collision/ */ export const CARDINAL_DIRECTIONS = [ { x: 0, z: 1 }, // North @@ -640,16 +637,15 @@ export function getCardinalTiles(tile: TileCoord): TileCoord[] { /** * Get a random cardinal-adjacent tile - * Used for OSRS-accurate NPC step-out when on same tile as target. + * Used for rules-accurate NPC step-out when on same tile as target. * - * OSRS behavior: "In RS, they pick a random cardinal direction (north, east, - * west, south) and try to move the NPC towards that by 1 tile." + * Uses the four cardinal directions (north, east, west, south) so the NPC + * moves one tile at a time. * * @param tile - Center tile * @param rng - Random number generator (for deterministic behavior) * @returns Random cardinal tile (N, E, S, or W) * - * @see https://osrs-docs.com/docs/mechanics/entity-collision/ */ export function getRandomCardinalTile( tile: TileCoord, @@ -680,10 +676,10 @@ const _stepOutBuffer: TileCoord[] = [ /** * Find the best cardinal tile to step out to when on same tile as target. * - * OSRS-accurate: When an NPC is on the same tile as its target, it must + * rules-accurate: When an NPC is on the same tile as its target, it must * step out to a cardinal tile before it can attack. This function finds * the first valid tile by: - * 1. Shuffling all 4 cardinal directions (maintains OSRS randomness) + * 1. Shuffling all 4 cardinal directions (maintains classic MMORPG randomness) * 2. Checking each for terrain walkability AND entity occupancy * 3. Returning the first valid tile found * @@ -699,7 +695,6 @@ const _stepOutBuffer: TileCoord[] = [ * @param rng - RNG for shuffling directions (deterministic) * @returns Best tile to step to, or null if all 4 cardinal tiles are blocked * - * @see https://osrs-docs.com/docs/mechanics/entity-collision/ */ export function getBestStepOutTile( currentTile: TileCoord, @@ -722,7 +717,7 @@ export function getBestStepOutTile( _stepOutBuffer[3].x = currentTile.x + 1; _stepOutBuffer[3].z = currentTile.z; - // Fisher-Yates shuffle for random order (OSRS-style randomness) + // Fisher-Yates shuffle for random order (classic MMORPG-style randomness) for (let i = 3; i > 0; i--) { const j = rng.nextInt(i + 1); // Swap values (not references, to keep buffer intact) @@ -757,7 +752,7 @@ export function getBestStepOutTile( // ============================================================================ /** - * OSRS-accurate Line of Sight check for ranged/magic combat. + * rules-accurate Line of Sight check for ranged/magic combat. * Traces a line between two tiles using Bresenham's algorithm and checks * for BLOCKS_RANGED obstacles on intermediate tiles. * @@ -838,7 +833,7 @@ export function getValidRangedTiles( /** * Generate all valid tiles for melee combat. - * Range 1 (standard): cardinal only (N/S/E/W) — OSRS melee behavior. + * Range 1 (standard): cardinal only (N/S/E/W) — classic MMORPG melee behavior. * Range 2+ (halberd): all Chebyshev tiles within range. * * @param target - Target's tile position @@ -855,7 +850,7 @@ export function getValidMeleeTiles( const tiles: TileCoord[] = []; if (effectiveRange === COMBAT_CONSTANTS.MELEE_RANGE_STANDARD) { - // Range 1: cardinal only (OSRS melee behavior) + // Range 1: cardinal only (classic MMORPG melee behavior) const cardinals = [ { x: target.x - 1, z: target.z }, { x: target.x + 1, z: target.z }, @@ -989,7 +984,7 @@ const _extendedMeleeTiles: TileCoord[] = Array.from({ length: 24 }, () => ({ /** * Get cardinal melee tiles (range 1) into pre-allocated buffer * - * OSRS melee range 1: Cardinal only (N/S/E/W) - no diagonal attacks + * classic MMORPG melee range 1: Cardinal only (N/S/E/W) - no diagonal attacks * Uses zero-allocation by writing to provided buffer. * * @param targetTile - Target's tile position @@ -1049,7 +1044,7 @@ export function getExtendedMeleeTilesInto( /** * Find best unoccupied combat tile for melee attack (zero-allocation) * - * OSRS-accurate: Cardinal tiles only for range 1, diagonal allowed for range 2+. + * rules-accurate: Cardinal tiles only for range 1, diagonal allowed for range 2+. * Checks both terrain walkability AND entity occupancy. * * Uses internal pre-allocated buffers - DO NOT store returned tile reference @@ -1147,7 +1142,7 @@ export function hasUnoccupiedCardinalTile( /** * Get all tiles adjacent to a multi-tile resource (valid standing positions) * - * OSRS-ACCURACY: For multi-tile resources (like large trees), players can + * RULES ACCURACY: For multi-tile resources (like large trees), players can * interact from any adjacent tile around the resource's footprint. * * For a 2×2 resource at anchor (15,-10), this returns the 12 tiles surrounding it: @@ -1201,7 +1196,7 @@ export function getResourceAdjacentTiles( /** * Find the best adjacent tile for a player to stand on when interacting with a resource * - * OSRS-ACCURACY: Returns the walkable tile nearest to player's current position. + * RULES ACCURACY: Returns the walkable tile nearest to player's current position. * This creates natural pathing behavior where players move to the closest valid spot. * * @param playerTile - Player's current tile position diff --git a/packages/shared/src/systems/shared/movement/WanderBehavior.ts b/packages/shared/src/systems/shared/movement/WanderBehavior.ts index b462b7e1e..bf2b55107 100644 --- a/packages/shared/src/systems/shared/movement/WanderBehavior.ts +++ b/packages/shared/src/systems/shared/movement/WanderBehavior.ts @@ -1,14 +1,13 @@ /** - * WanderBehavior - OSRS-accurate random walking + * WanderBehavior - rules-accurate random walking * - * OSRS NPCs have a probabilistic wandering system: + * classic MMORPG NPCs have a probabilistic wandering system: * - ~10/1000 chance per CLIENT tick to start wandering * - With ~30 client ticks per server tick, this is ~26-30% per server tick * - Wander radius is typically 5 tiles from spawn point * * This replaces the time-based idle system with probabilistic wandering. * - * @see https://osrs-docs.com/docs/mechanics/random-walk/ */ import type { TileCoord } from "./TileSystem"; @@ -31,13 +30,13 @@ export interface WanderConfig { } /** - * WanderBehavior - OSRS-accurate random walking + * WanderBehavior - rules-accurate random walking * - * Provides probabilistic wandering behavior matching OSRS mechanics. + * Provides probabilistic wandering behavior matching classic tick-based mechanics. * NPCs have a ~26-30% chance per server tick to start a new wander path. */ export class WanderBehavior { - // OSRS probability converted to server tick + // classic MMORPG probability converted to server tick // ~10/1000 per client tick × ~30 client ticks/server tick ≈ 26% private static readonly DEFAULT_WANDER_CHANCE = 0.26; private static readonly DEFAULT_WANDER_RADIUS = 5; @@ -65,7 +64,7 @@ export class WanderBehavior { /** * Check if NPC should start wandering this tick * - * OSRS-accurate: ~26-30% chance per tick when idle. + * rules-accurate: ~26-30% chance per tick when idle. * Returns false if: * - Movement type is stationary * - Already has a wander path @@ -109,12 +108,12 @@ export class WanderBehavior { } this._lastWanderTick = currentTick; - // Probabilistic check (OSRS-accurate: ~26% per tick) + // Probabilistic check (rules-accurate: ~26% per tick) return Math.random() < this.wanderChance; } /** - * Generate wander destination (OSRS-accurate) + * Generate wander destination (rules-accurate) * * Random offset -5 to +5 tiles on each axis from spawn. * Uses pre-allocated buffer for zero allocation. @@ -125,7 +124,7 @@ export class WanderBehavior { generateWanderTarget(spawnTile: TileCoord): TileCoord { const radius = this.wanderRadius; - // OSRS: Random offset within [-radius, +radius] from spawn + // classic MMORPG: Random offset within [-radius, +radius] from spawn // 2 * radius + 1 possible values on each axis const range = 2 * radius + 1; const offsetX = Math.floor(Math.random() * range) - radius; diff --git a/packages/shared/src/systems/shared/movement/__tests__/BFSPathfinder.test.ts b/packages/shared/src/systems/shared/movement/__tests__/BFSPathfinder.test.ts index d297602bc..e8717e39c 100644 --- a/packages/shared/src/systems/shared/movement/__tests__/BFSPathfinder.test.ts +++ b/packages/shared/src/systems/shared/movement/__tests__/BFSPathfinder.test.ts @@ -1,11 +1,11 @@ /** * BFS Pathfinder Unit Tests * - * Tests the BFS pathfinding system with OSRS-style diagonal pathing. + * Tests the BFS pathfinding system with classic MMORPG-style diagonal pathing. * * Key behaviors tested: * - Basic straight-line pathfinding - * - Naive diagonal pathing (OSRS follow-mode style) + * - Naive diagonal pathing (classic MMORPG follow-mode style) * - BFS fallback when naive path is blocked * - Obstacle avoidance * - Corner clipping prevention diff --git a/packages/shared/src/systems/shared/movement/__tests__/ChasePathfinding.test.ts b/packages/shared/src/systems/shared/movement/__tests__/ChasePathfinding.test.ts index e18a8bbdd..26e408f3d 100644 --- a/packages/shared/src/systems/shared/movement/__tests__/ChasePathfinding.test.ts +++ b/packages/shared/src/systems/shared/movement/__tests__/ChasePathfinding.test.ts @@ -1,16 +1,15 @@ /** * ChasePathfinding Unit Tests * - * Tests the OSRS "dumb pathfinder" algorithm for NPC chasing behavior. + * Tests the classic MMORPG "dumb pathfinder" algorithm for NPC chasing behavior. * * Key behaviors tested: * - Basic movement toward target - * - Corner-cutting prevention (OSRS rule) + * - Corner-cutting prevention (classic MMORPG rule) * - Cardinal priority when diagonal blocked * - Safespot detection (all directions blocked) * - Zero-allocation ChasePathfinder class * - * @see https://oldschool.runescape.wiki/w/Pathfinding * @see MOB_AGGRO_IMPLEMENTATION_PLAN.md Phase 1.4, 4.1 */ @@ -76,7 +75,7 @@ describe("ChasePathfinding", () => { }); }); - describe("diagonal movement (OSRS corner-cutting rule)", () => { + describe("diagonal movement (classic MMORPG corner-cutting rule)", () => { it("allows diagonal when both cardinal tiles are walkable", () => { const current = { x: 0, z: 0 }; const target = { x: 1, z: 1 }; @@ -423,7 +422,7 @@ describe("ChasePathfinding", () => { }); }); - describe("OSRS safespot scenarios", () => { + describe("classic MMORPG safespot scenarios", () => { it("should get stuck behind rock (classic safespot)", () => { // Player behind rock, NPC can't path around // [P] ← Player diff --git a/packages/shared/src/systems/shared/movement/__tests__/TileSystem.test.ts b/packages/shared/src/systems/shared/movement/__tests__/TileSystem.test.ts index 2e57c04e5..8f1362fef 100644 --- a/packages/shared/src/systems/shared/movement/__tests__/TileSystem.test.ts +++ b/packages/shared/src/systems/shared/movement/__tests__/TileSystem.test.ts @@ -314,8 +314,8 @@ describe("TileSystem", () => { expect(hasNE).toBe(true); }); - it("has OSRS priority order (W, E, S, N, SW, SE, NW, NE)", () => { - // OSRS BFS processes neighbors in this order + it("has classic MMORPG priority order (W, E, S, N, SW, SE, NW, NE)", () => { + // classic MMORPG BFS processes neighbors in this order expect(TILE_DIRECTIONS[0]).toEqual({ x: -1, z: 0 }); // W expect(TILE_DIRECTIONS[1]).toEqual({ x: 1, z: 0 }); // E expect(TILE_DIRECTIONS[2]).toEqual({ x: 0, z: -1 }); // S @@ -332,7 +332,7 @@ describe("TileSystem", () => { describe("tilesWithinMeleeRange", () => { const center = { x: 5, z: 5 }; - describe("range 1 (OSRS cardinal-only)", () => { + describe("range 1 (classic MMORPG cardinal-only)", () => { it("returns true for cardinal north neighbor", () => { expect(tilesWithinMeleeRange(center, { x: 5, z: 6 }, 1)).toBe(true); }); @@ -349,19 +349,19 @@ describe("TileSystem", () => { expect(tilesWithinMeleeRange(center, { x: 4, z: 5 }, 1)).toBe(true); }); - it("returns false for diagonal northeast (OSRS rule)", () => { + it("returns false for diagonal northeast (classic MMORPG rule)", () => { expect(tilesWithinMeleeRange(center, { x: 6, z: 6 }, 1)).toBe(false); }); - it("returns false for diagonal southeast (OSRS rule)", () => { + it("returns false for diagonal southeast (classic MMORPG rule)", () => { expect(tilesWithinMeleeRange(center, { x: 6, z: 4 }, 1)).toBe(false); }); - it("returns false for diagonal southwest (OSRS rule)", () => { + it("returns false for diagonal southwest (classic MMORPG rule)", () => { expect(tilesWithinMeleeRange(center, { x: 4, z: 4 }, 1)).toBe(false); }); - it("returns false for diagonal northwest (OSRS rule)", () => { + it("returns false for diagonal northwest (classic MMORPG rule)", () => { expect(tilesWithinMeleeRange(center, { x: 4, z: 6 }, 1)).toBe(false); }); @@ -675,7 +675,7 @@ describe("TileSystem", () => { it("returns true when standing on one footprint tile (adjacent to others)", () => { // When standing on a corner tile, player is in range of adjacent footprint tiles - // This is correct OSRS behavior - you're "in range" even if technically on the object + // This is correct classic MMORPG behavior - you're "in range" even if technically on the object // (4,4) is distance 1 from (5,4) and (4,5) expect( tilesWithinRangeOfFootprint({ x: 4, z: 4 }, center, 2, 2, 1), diff --git a/packages/shared/src/systems/shared/movement/__tests__/WanderBehavior.test.ts b/packages/shared/src/systems/shared/movement/__tests__/WanderBehavior.test.ts index 3b99fb8d2..97413f251 100644 --- a/packages/shared/src/systems/shared/movement/__tests__/WanderBehavior.test.ts +++ b/packages/shared/src/systems/shared/movement/__tests__/WanderBehavior.test.ts @@ -1,7 +1,7 @@ /** * WanderBehavior Unit Tests * - * Tests OSRS-accurate probabilistic wandering behavior. + * Tests rules-accurate probabilistic wandering behavior. * * Key behaviors tested: * - Probabilistic wander chance (~26% per tick) @@ -9,7 +9,6 @@ * - State management (active wander path) * - Movement type restrictions (stationary) * - * @see https://osrs-docs.com/docs/mechanics/random-walk/ * @see MOB_AGGRO_IMPLEMENTATION_PLAN.md Phase 3.1 */ diff --git a/packages/shared/src/systems/shared/movement/index.ts b/packages/shared/src/systems/shared/movement/index.ts index c8944c973..aa891a703 100644 --- a/packages/shared/src/systems/shared/movement/index.ts +++ b/packages/shared/src/systems/shared/movement/index.ts @@ -1,7 +1,7 @@ /** * Movement System Module * - * Exports all tile-based movement utilities for RuneScape-style movement. + * Exports all tile-based movement utilities for classic fantasy MMORPG-style movement. */ export * from "./TileSystem"; diff --git a/packages/shared/src/systems/shared/tick/NPCTickProcessor.ts b/packages/shared/src/systems/shared/tick/NPCTickProcessor.ts index c7c8e9da2..58d619c3d 100644 --- a/packages/shared/src/systems/shared/tick/NPCTickProcessor.ts +++ b/packages/shared/src/systems/shared/tick/NPCTickProcessor.ts @@ -1,7 +1,7 @@ /** - * NPCTickProcessor - Processes all NPC logic in OSRS-accurate order + * NPCTickProcessor - Processes all NPC logic in rules-accurate order * - * OSRS Processing Order (per tick): + * classic MMORPG Processing Order (per tick): * 1. NPC timers execute * 2. NPC queues process * 3. NPC movement @@ -12,7 +12,6 @@ * This processor handles steps 1-4 for all NPCs, ensuring they process * in the correct order and with zero allocations in the hot path. * - * @see https://osrs-docs.com/docs/mechanics/timers/ */ import type { TileCoord } from "../movement/TileSystem"; @@ -49,7 +48,7 @@ export interface TickProcessingStats { /** * NPCTickProcessor - Single entry point for all NPC tick processing * - * Ensures correct OSRS processing order and zero allocations in hot paths. + * Ensures correct classic MMORPG processing order and zero allocations in hot paths. */ export class NPCTickProcessor { // Strategy dependencies (DIP - depend on abstractions) @@ -122,7 +121,7 @@ export class NPCTickProcessor { } } - // Process in spawn order for determinism (OSRS processes NPCs by spawn order) + // Process in spawn order for determinism (classic MMORPG processes NPCs by spawn order) this._npcBuffer.sort((a, b) => a.spawnOrder - b.spawnOrder); // Limit processing if needed (for performance) @@ -165,7 +164,7 @@ export class NPCTickProcessor { /** * Process a single NPC for the current tick * - * OSRS order within NPC processing: + * classic MMORPG order within NPC processing: * 1. Update timers (handled externally by MobEntity) * 2. Process queues (handled externally by MobEntity) * 3. Aggro check and target selection @@ -253,12 +252,12 @@ export class NPCTickProcessor { /** * Generate a wander destination for an NPC * - * OSRS: Random offset -5 to +5 tiles from spawn point + * classic MMORPG: Random offset -5 to +5 tiles from spawn point */ private generateWanderTarget(npc: ProcessableNPC): TileCoord | null { const spawnTile = npc.getSpawnTile(); - // OSRS: -5 to +5 offset from spawn (11x11 area) + // classic MMORPG: -5 to +5 offset from spawn (11x11 area) const offsetX = Math.floor(Math.random() * 11) - 5; const offsetZ = Math.floor(Math.random() * 11) - 5; diff --git a/packages/shared/src/systems/shared/tick/index.ts b/packages/shared/src/systems/shared/tick/index.ts index 36e3c1c17..8296afc69 100644 --- a/packages/shared/src/systems/shared/tick/index.ts +++ b/packages/shared/src/systems/shared/tick/index.ts @@ -1,7 +1,7 @@ /** * Tick Processing System * - * OSRS-accurate tick-based processing for NPCs. + * rules-accurate tick-based processing for NPCs. * All NPC logic runs on 600ms tick boundaries. */ diff --git a/packages/shared/src/systems/shared/world/BiomeResourceGenerator.ts b/packages/shared/src/systems/shared/world/BiomeResourceGenerator.ts index 4d2fa5ea4..0f585fc13 100644 --- a/packages/shared/src/systems/shared/world/BiomeResourceGenerator.ts +++ b/packages/shared/src/systems/shared/world/BiomeResourceGenerator.ts @@ -290,7 +290,7 @@ export function getTreeProcgenPreset(subType: string): string { } /** - * Level requirements for ore types (OSRS mining levels). + * Level requirements for ore types (classic MMORPG mining levels). * Single source of truth - used by both generation and tests. */ export const ORE_LEVEL_REQUIREMENTS: Record = { diff --git a/packages/shared/src/systems/shared/world/BridgeSystem.ts b/packages/shared/src/systems/shared/world/BridgeSystem.ts index ebcbad7c9..0cda418ac 100644 --- a/packages/shared/src/systems/shared/world/BridgeSystem.ts +++ b/packages/shared/src/systems/shared/world/BridgeSystem.ts @@ -601,7 +601,7 @@ export class BridgeSystem extends SystemBase { const isEndpoint = tile.minS === 0 || tile.maxS === steps; // Cardinal walls — at endpoints, skip walls in bridge direction. - // OSRS dual-tile pattern: set wall on bridge tile AND opposite wall on neighbor. + // classic MMORPG dual-tile pattern: set wall on bridge tile AND opposite wall on neighbor. // This ensures both isBlocked() check directions catch the wall. if (this.getDeckHeightAt(tile.x + 1, tile.z) === null) { if (!isEndpoint || Math.abs(normDirX) < 0.5) { diff --git a/packages/shared/src/systems/shared/world/BuildingCollisionService.ts b/packages/shared/src/systems/shared/world/BuildingCollisionService.ts index b83789965..c61953b80 100644 --- a/packages/shared/src/systems/shared/world/BuildingCollisionService.ts +++ b/packages/shared/src/systems/shared/world/BuildingCollisionService.ts @@ -1683,7 +1683,7 @@ export class BuildingCollisionService { floorIndex, ); - // Standard OSRS rule: blocked only if BOTH cardinal paths are blocked + // Standard classic MMORPG rule: blocked only if BOTH cardinal paths are blocked if (path1Blocked && path2Blocked) { if (this._debugLogging) { console.log( diff --git a/packages/shared/src/systems/shared/world/BuildingRenderingSystem.ts b/packages/shared/src/systems/shared/world/BuildingRenderingSystem.ts index 12c5e4c3f..31a66b384 100644 --- a/packages/shared/src/systems/shared/world/BuildingRenderingSystem.ts +++ b/packages/shared/src/systems/shared/world/BuildingRenderingSystem.ts @@ -346,7 +346,7 @@ import type { PhysicsHandle } from "../../../types/systems/physics"; /** * Building occlusion shader configuration. - * Uses dithered/stippled effect like RuneScape for seeing character through walls. + * Uses dithered/stippled effect like classic fantasy MMORPG for seeing character through walls. * Values are intentionally smaller than vegetation for subtle visibility. */ export const BUILDING_OCCLUSION_CONFIG = { @@ -371,7 +371,7 @@ export const BUILDING_OCCLUSION_CONFIG = { /** Occlusion strength (0 = disabled, only near-camera dissolve active) */ STRENGTH: 0.0, - // ========== NEAR-CAMERA DISSOLVE (RuneScape-style depth fade) ========== + // ========== NEAR-CAMERA DISSOLVE (classic fantasy MMORPG-style depth fade) ========== // Prevents hard geometry clipping when camera clips through objects /** Distance from camera where near-fade begins (meters) - fully opaque beyond this */ @@ -1078,7 +1078,7 @@ export type BuildingOcclusionMaterial = MeshStandardNodeMaterial & { * Uses TSL (Three Shading Language) for GPU-accelerated patterns and occlusion. * * The shader creates a cone-shaped dissolve from camera to player, - * using a dithered/stippled pattern like classic RuneScape. + * using a dithered/stippled pattern reminiscent of classic fantasy MMORPGs. * * @returns Material with occlusion shader */ @@ -1145,7 +1145,7 @@ function createBuildingOcclusionMaterial(): BuildingOcclusionMaterial { const camDistSq = add(add(mul(cfX, cfX), mul(cfY, cfY)), mul(cfZ, cfZ)); const camDist = sqrt(camDistSq); - // ========== NEAR-CAMERA DISSOLVE (RuneScape-style depth fade) ========== + // ========== NEAR-CAMERA DISSOLVE (classic fantasy MMORPG-style depth fade) ========== // Prevents hard geometry clipping when camera clips through objects // smoothstep returns 0→1 as distance goes from end→start, we invert for fade const nearCameraFade = sub( @@ -1229,7 +1229,7 @@ function createBuildingOcclusionMaterial(): BuildingOcclusionMaterial { // - occlusionFade: dissolve when player is behind walls const combinedFade = max(max(nearCameraFade, distanceFade), occlusionFade); - // ========== SCREEN-SPACE 4x4 BAYER DITHERING (RuneScape 3 style) ========== + // ========== SCREEN-SPACE 4x4 BAYER DITHERING (modern fantasy MMORPG style) ========== // 4x4 Bayer matrix: [ 0, 8, 2,10; 12, 4,14, 6; 3,11, 1, 9; 15, 7,13, 5]/16 const ix = mod(floor(viewportCoordinate.x), float(4.0)); const iy = mod(floor(viewportCoordinate.y), float(4.0)); @@ -1257,7 +1257,7 @@ function createBuildingOcclusionMaterial(): BuildingOcclusionMaterial { ); const ditherValue = mul(bayerInt, float(0.0625)); // /16 - // RS3-style: discard when fade >= dither + // modern MMORPG-style: discard when fade >= dither // step returns 0 or 1, multiply by 2 so threshold > 1.0 causes discard // (alphaTest discards when material.alpha (1.0) < threshold) // IMPORTANT: Only apply dithering when combinedFade > 0, otherwise step(0,0)=1 causes holes @@ -2759,7 +2759,7 @@ export class BuildingRenderingSystem extends SystemBase { /** Shared uber-material for all batched buildings (with occlusion shader) */ private batchedMaterial: BuildingOcclusionMaterial; - /** Shared roof material with per-building visibility (RuneScape-style roof hiding) */ + /** Shared roof material with per-building visibility (classic fantasy MMORPG-style roof hiding) */ private roofMaterial: RoofOcclusionMaterial; /** Shared floor material for all batched building floors (no occlusion needed) */ @@ -2830,7 +2830,7 @@ export class BuildingRenderingSystem extends SystemBase { // Create shared material for batched buildings (with occlusion shader) this.batchedMaterial = createBuildingOcclusionMaterial(); - // Create shared roof material with per-building visibility (RuneScape-style) + // Create shared roof material with per-building visibility (classic fantasy MMORPG-style) this.roofMaterial = createBuildingRoofMaterial(); // Create shared floor material (simple, no occlusion - floors are walkable) @@ -3169,7 +3169,7 @@ export class BuildingRenderingSystem extends SystemBase { /** * Update roof visibility state. * - * **RuneScape-Style Per-Building Roof Hiding:** + * **classic fantasy MMORPG-Style Per-Building Roof Hiding:** * Individual building roofs are now hidden via the roof material's shader, * which reads buildingCenter and buildingRadius vertex attributes to determine * if the player or camera is close to each specific building. This enables @@ -3178,7 +3178,7 @@ export class BuildingRenderingSystem extends SystemBase { * The shader automatically: * - Hides a building's roof when player is within the building's footprint + margin * - Hides a building's roof when camera is within the building's footprint + margin - * - Uses dithered dissolve effect for smooth transitions (RS3 style) + * - Uses dithered dissolve effect for smooth transitions (modern MMORPG style) * * This method now only handles: * - The "always hidden" override (for debugging/special modes) @@ -4232,7 +4232,7 @@ export class BuildingRenderingSystem extends SystemBase { ); } - // === ROOF MESH (RuneScape-style per-building roof hiding) === + // === ROOF MESH (classic fantasy MMORPG-style per-building roof hiding) === // Uses roofMaterial which has per-building visibility based on vertex attributes // buildingCenter and buildingRadius attributes enable the shader to hide roofs // when player/camera is close to that specific building diff --git a/packages/shared/src/systems/shared/world/GPUMaterials.ts b/packages/shared/src/systems/shared/world/GPUMaterials.ts index 8309c3989..3da2e1a31 100644 --- a/packages/shared/src/systems/shared/world/GPUMaterials.ts +++ b/packages/shared/src/systems/shared/world/GPUMaterials.ts @@ -11,7 +11,7 @@ * * ## Shared Shader Features * - Screen-space dithered dissolve (Bayer 4x4) - * - Camera-to-player occlusion cone (RuneScape-style) + * - Camera-to-player occlusion cone (classic fantasy MMORPG-style) * - Near-camera depth fade * - Per-instance Fresnel rim highlight * @@ -96,7 +96,7 @@ export const GPU_VEG_CONFIG = { WATER_BUFFER: 3.0, // ========== OCCLUSION DISSOLVE CONFIG ========== - // Camera-to-player line-of-sight dissolve (RuneScape-style) + // Camera-to-player line-of-sight dissolve (classic fantasy MMORPG-style) // Uses a CONE shape that expands from camera toward player for natural visibility /** Radius at camera end of the cone (meters) - keeps near objects visible */ @@ -114,13 +114,13 @@ export const GPU_VEG_CONFIG = { /** Distance from player where occlusion stops (small buffer behind player) */ OCCLUSION_FAR_MARGIN: 0.3, - /** Sharpness of the cutoff edge (higher = sharper, more binary like RuneScape) */ + /** Sharpness of the cutoff edge (higher = sharper, more binary like classic fantasy MMORPG) */ OCCLUSION_EDGE_SHARPNESS: 0.5, /** Maximum occlusion dissolve strength (0 = disabled, matches buildings) */ OCCLUSION_STRENGTH: 0.0, - // ========== NEAR-CAMERA DISSOLVE (RuneScape-style depth fade) ========== + // ========== NEAR-CAMERA DISSOLVE (classic fantasy MMORPG-style depth fade) ========== // Prevents hard geometry clipping when camera clips through objects /** Distance from camera where near-fade begins (meters) - fully opaque beyond this */ @@ -243,7 +243,7 @@ export type DissolveMaterial = THREE.MeshStandardNodeMaterial & { /** * Creates a GPU vegetation material with distance-based dithered fade - * and camera-to-player occlusion dissolve (RuneScape-style). + * and camera-to-player occlusion dissolve (classic fantasy MMORPG-style). * * Uses cutout rendering (alphaTest) for performance - no alpha blending. * Dithering is per-instance (not per-fragment) for consistent fade. @@ -272,7 +272,7 @@ export function createGPUVegetationMaterial( const fadeStartSq = mul(uFadeStart, uFadeStart); const fadeEndSq = mul(uFadeEnd, uFadeEnd); - // Occlusion dissolve constants (RuneScape-style cone) + // Occlusion dissolve constants (classic fantasy MMORPG-style cone) const enableOcclusion = options.enableOcclusionDissolve !== false; const occlusionCameraRadius = float(GPU_VEG_CONFIG.OCCLUSION_CAMERA_RADIUS); const occlusionPlayerRadius = float(GPU_VEG_CONFIG.OCCLUSION_PLAYER_RADIUS); @@ -282,7 +282,7 @@ export function createGPUVegetationMaterial( const occlusionEdgeSharpness = float(GPU_VEG_CONFIG.OCCLUSION_EDGE_SHARPNESS); const occlusionStrength = float(GPU_VEG_CONFIG.OCCLUSION_STRENGTH); - // Near-camera dissolve constants (RuneScape-style depth fade) + // Near-camera dissolve constants (classic fantasy MMORPG-style depth fade) const nearCameraFadeStart = float(GPU_VEG_CONFIG.NEAR_CAMERA_FADE_START); const nearCameraFadeEnd = float(GPU_VEG_CONFIG.NEAR_CAMERA_FADE_END); @@ -303,7 +303,7 @@ export function createGPUVegetationMaterial( // 3. Distance factor: 0.0 when close (keep fragment), 1.0 when far (discard fragment) const distanceFade = smoothstep(fadeStartSq, fadeEndSq, distSq); - // 4. CAMERA-TO-PLAYER OCCLUSION DISSOLVE (RuneScape-style) + // 4. CAMERA-TO-PLAYER OCCLUSION DISSOLVE (classic fantasy MMORPG-style) const occlusionFade = enableOcclusion ? (() => { const camToPlayer = vec3( @@ -376,7 +376,7 @@ export function createGPUVegetationMaterial( })() : float(0.0); - // 5. NEAR-CAMERA DISSOLVE (RuneScape-style depth fade) + // 5. NEAR-CAMERA DISSOLVE (classic fantasy MMORPG-style depth fade) const camToFrag = sub(worldPos, uCameraPos); const camDistSq = dot(camToFrag, camToFrag); const camDist = sqrt(camDistSq); @@ -388,7 +388,7 @@ export function createGPUVegetationMaterial( // 6. Combine all fade factors const combinedFade = max(max(distanceFade, occlusionFade), nearCameraFade); - // 7. SCREEN-SPACE 4x4 BAYER DITHERING (RuneScape 3 style) + // 7. SCREEN-SPACE 4x4 BAYER DITHERING (modern fantasy MMORPG style) const ix = mod(floor(viewportCoordinate.x), float(4.0)); const iy = mod(floor(viewportCoordinate.y), float(4.0)); @@ -408,7 +408,7 @@ export function createGPUVegetationMaterial( ); const ditherValue = mul(bayerInt, float(0.0625)); - // 8. RS3-style threshold: discard when fade >= dither + // 8. modern MMORPG-style threshold: discard when fade >= dither const hasAnyFade = step(float(0.001), combinedFade); const ditherThreshold = mul( mul(step(ditherValue, combinedFade), hasAnyFade), @@ -545,7 +545,7 @@ export function createDissolveMaterial( GPU_VEG_CONFIG.WATER_LEVEL + GPU_VEG_CONFIG.WATER_BUFFER, ); - // Occlusion dissolve constants (RuneScape-style cone) + // Occlusion dissolve constants (classic fantasy MMORPG-style cone) const occlusionCameraRadius = float(GPU_VEG_CONFIG.OCCLUSION_CAMERA_RADIUS); const occlusionPlayerRadius = float(GPU_VEG_CONFIG.OCCLUSION_PLAYER_RADIUS); const occlusionDistanceScale = float(GPU_VEG_CONFIG.OCCLUSION_DISTANCE_SCALE); @@ -554,7 +554,7 @@ export function createDissolveMaterial( const occlusionEdgeSharpness = float(GPU_VEG_CONFIG.OCCLUSION_EDGE_SHARPNESS); const occlusionStrength = float(GPU_VEG_CONFIG.OCCLUSION_STRENGTH); - // Near-camera dissolve constants (RuneScape-style depth fade) + // Near-camera dissolve constants (classic fantasy MMORPG-style depth fade) const nearCameraFadeStart = float(GPU_VEG_CONFIG.NEAR_CAMERA_FADE_START); const nearCameraFadeEnd = float(GPU_VEG_CONFIG.NEAR_CAMERA_FADE_END); @@ -587,7 +587,7 @@ export function createDissolveMaterial( smoothstep(nearCameraFadeEnd, nearCameraFadeStart, camDist), ); - // CAMERA-TO-PLAYER OCCLUSION DISSOLVE (RuneScape-style) + // CAMERA-TO-PLAYER OCCLUSION DISSOLVE (classic fantasy MMORPG-style) const occlusionFade = enableOcclusion ? (() => { const camToPlayer = vec3( @@ -664,7 +664,7 @@ export function createDissolveMaterial( nearCameraFade, ); - // SCREEN-SPACE 4x4 BAYER DITHERING (RuneScape 3 style) + // SCREEN-SPACE 4x4 BAYER DITHERING (modern fantasy MMORPG style) const ix = mod(floor(viewportCoordinate.x), float(4.0)); const iy = mod(floor(viewportCoordinate.y), float(4.0)); @@ -851,7 +851,7 @@ export function createImposterMaterial( const farFade = smoothstep(fadeStartSq, fadeEndSq, distSq); - // SCREEN-SPACE 4x4 BAYER DITHERING (RuneScape 3 style) + // SCREEN-SPACE 4x4 BAYER DITHERING (modern fantasy MMORPG style) const ix = mod(floor(viewportCoordinate.x), float(4.0)); const iy = mod(floor(viewportCoordinate.y), float(4.0)); diff --git a/packages/shared/src/systems/shared/world/ProceduralDocks.ts b/packages/shared/src/systems/shared/world/ProceduralDocks.ts index 595d5aa15..1ada4da8b 100644 --- a/packages/shared/src/systems/shared/world/ProceduralDocks.ts +++ b/packages/shared/src/systems/shared/world/ProceduralDocks.ts @@ -4,7 +4,7 @@ * Generates procedural docks on water bodies. * Follows the BridgeSystem pattern for collision registration: * - Walkable tiles: remove WATER flag, add DOCK flag - * - Edge blocking: OSRS dual-tile wall flags on dock perimeter + * - Edge blocking: classic MMORPG dual-tile wall flags on dock perimeter * - Deck height tracking: per-tile Y override for player positioning * * Works on both client (mesh + collision) and server (collision only). @@ -347,7 +347,7 @@ export class ProceduralDocks extends System { tileSet.add(key); } - // Pass 2: Cardinal wall flags from blockedEdges (OSRS dual-tile pattern) + // Pass 2: Cardinal wall flags from blockedEdges (classic MMORPG dual-tile pattern) for (const edge of dock.collision.blockedEdges) { let wallFlag: number; let ndx: number; diff --git a/packages/shared/src/systems/shared/world/TerrainShader.ts b/packages/shared/src/systems/shared/world/TerrainShader.ts index 6bf012986..7183e5403 100644 --- a/packages/shared/src/systems/shared/world/TerrainShader.ts +++ b/packages/shared/src/systems/shared/world/TerrainShader.ts @@ -1022,7 +1022,7 @@ export function computeTerrainColorCPU( } // ============================================================================ -// TERRAIN MATERIAL - OSRS Style (No Textures) +// TERRAIN MATERIAL - classic MMORPG Style (No Textures) // ============================================================================ /** diff --git a/packages/shared/src/systems/shared/world/TerrainSystem.ts b/packages/shared/src/systems/shared/world/TerrainSystem.ts index 62ee8220a..12066f441 100644 --- a/packages/shared/src/systems/shared/world/TerrainSystem.ts +++ b/packages/shared/src/systems/shared/world/TerrainSystem.ts @@ -393,7 +393,7 @@ export class TerrainSystem extends System { * No fallback material - roads require the full shader to render correctly. */ private initTerrainMaterial(): void { - // Create the shared terrain material (uses procedural OSRS-style colors, no textures needed) + // Create the shared terrain material (uses procedural classic MMORPG-style colors, no textures needed) // This material reads the roadInfluence attribute and blends road colors this.terrainMaterial = createTerrainMaterial(); @@ -1404,7 +1404,7 @@ export class TerrainSystem extends System { } // World Configuration - Your Specifications - // OSRS-STYLE: Rolling terrain with visible hills + // classic MMORPG-STYLE: Rolling terrain with visible hills private readonly CONFIG = { // Core World Specs TILE_SIZE: TERRAIN_CONSTANTS.TERRAIN_TILE_SIZE, diff --git a/packages/shared/src/systems/shared/world/__tests__/BiomeResourceSpawning.test.ts b/packages/shared/src/systems/shared/world/__tests__/BiomeResourceSpawning.test.ts index 00391820a..1a276c67a 100644 --- a/packages/shared/src/systems/shared/world/__tests__/BiomeResourceSpawning.test.ts +++ b/packages/shared/src/systems/shared/world/__tests__/BiomeResourceSpawning.test.ts @@ -418,7 +418,7 @@ describe("BiomeResourceGenerator", () => { ); }); - it("ore level requirements match OSRS progression", () => { + it("ore level requirements match classic MMORPG progression", () => { expect(getOreLevelRequirement("copper")).toBe(1); expect(getOreLevelRequirement("tin")).toBe(1); expect(getOreLevelRequirement("iron")).toBe(15); diff --git a/packages/shared/src/types/bank-equipment.ts b/packages/shared/src/types/bank-equipment.ts index 9aa260c20..522cadc5a 100644 --- a/packages/shared/src/types/bank-equipment.ts +++ b/packages/shared/src/types/bank-equipment.ts @@ -1,7 +1,7 @@ /** * Bank Equipment Tab Types * - * Type definitions for the RS3-style bank equipment view feature. + * Type definitions for the modern MMORPG-style bank equipment view feature. * Enables players to: * - View/manage equipment from bank interface * - Withdraw items directly to equipment slot diff --git a/packages/shared/src/types/death/death-types.ts b/packages/shared/src/types/death/death-types.ts index 2c6c77db7..7a3bd79a5 100644 --- a/packages/shared/src/types/death/death-types.ts +++ b/packages/shared/src/types/death/death-types.ts @@ -82,7 +82,7 @@ export interface DeathLock { itemCount: number; // Crash recovery fields (optional for backwards compatibility) items?: DeathItemData[]; // Dropped items for recovery (gravestone/ground) - keptItems?: DeathItemData[]; // OSRS keep-3 items returned on respawn + keptItems?: DeathItemData[]; // classic MMORPG keep-3 items returned on respawn killedBy?: string; // What killed the player recovered?: boolean; // Whether death was processed during crash recovery } @@ -102,7 +102,7 @@ export interface GroundItemOptions { /** * Ground item data tracked by GroundItemSystem (TICK-BASED) - * Uses tick numbers for OSRS-accurate despawn timing + * Uses tick numbers for rules-accurate despawn timing */ export interface GroundItemData { entityId: string; @@ -117,7 +117,7 @@ export interface GroundItemData { /** * Ground item pile data - tracks all items at a single tile - * Used for OSRS-style item stacking where only top item is visible + * Used for classic MMORPG-style item stacking where only top item is visible */ export interface GroundItemPileData { tileKey: string; // "x_z" format for Map key diff --git a/packages/shared/src/types/entities/entities.ts b/packages/shared/src/types/entities/entities.ts index 46b0e6d20..99b808840 100644 --- a/packages/shared/src/types/entities/entities.ts +++ b/packages/shared/src/types/entities/entities.ts @@ -219,7 +219,7 @@ export interface MobEntityConfig extends EntityConfig { level: number; maxHealth: number; currentHealth: number; - attack: number; // Attack level for accuracy calculations (OSRS-style) + attack: number; // Attack level for accuracy calculations (classic MMORPG-style) attackPower: number; // Strength-based, determines max hit defense: number; defenseBonus: number; // Equipment/armor defense bonus @@ -231,8 +231,8 @@ export interface MobEntityConfig extends EntityConfig { movementType: "stationary" | "wander" | "patrol"; // Controls idle movement behavior aggroRange: number; combatRange: number; - wanderRadius: number; // Fixed distance from spawn point (RuneScape-style) - leashRange?: number; // Max chase distance from spawn (defaults to 10, OSRS-style two-tier range) + wanderRadius: number; // Fixed distance from spawn point (classic fantasy MMORPG-style) + leashRange?: number; // Max chase distance from spawn (defaults to 10, classic MMORPG-style two-tier range) respawnTime: number; xpReward: number; lootTable: Array<{ @@ -255,7 +255,7 @@ export interface MobEntityConfig extends EntityConfig { arrowId?: string; /** - * If true, this NPC walks through other NPCs (OSRS boss behavior) + * If true, this NPC walks through other NPCs (classic MMORPG boss behavior) * * Used for: GWD generals, Dagannoth Kings, raid bosses, etc. * When true, the NPC's tiles don't block other entities from moving. diff --git a/packages/shared/src/types/entities/npc-mob-types.ts b/packages/shared/src/types/entities/npc-mob-types.ts index 0f13f7780..f786edf94 100644 --- a/packages/shared/src/types/entities/npc-mob-types.ts +++ b/packages/shared/src/types/entities/npc-mob-types.ts @@ -172,7 +172,7 @@ export interface AggroTarget { // ============== DROP SYSTEM ============== /** - * RuneScape-style Drop Rarity Tiers + * classic fantasy MMORPG-style Drop Rarity Tiers */ export type DropRarity = | "always" @@ -182,7 +182,7 @@ export type DropRarity = | "very_rare"; /** - * Drop Table Entry - RuneScape-style loot system + * Drop Table Entry - classic fantasy MMORPG-style loot system */ export interface DropTableEntry { itemId: string; @@ -256,12 +256,12 @@ export interface NPCDataInput { /** * NPC Stats - Unified across all NPCs - * Note: In OSRS, monster "hitpoints" IS the max HP directly (no multiplication). + * Note: In classic MMORPG, monster "hitpoints" IS the max HP directly (no multiplication). * The `health` field is the hitpoints level AND max HP (1:1 ratio). */ export interface NPCStats { level: number; - health: number; // This IS the hitpoints level AND max HP (OSRS style) + health: number; // This IS the hitpoints level AND max HP (classic MMORPG style) attack: number; strength: number; defense: number; @@ -303,7 +303,7 @@ export interface NPCMovementConfig { } /** - * NPC Drops - RuneScape-style tiered drop system + * NPC Drops - classic fantasy MMORPG-style tiered drop system * ALL NPCs drop something (at minimum, bones/ashes) */ export interface NPCDrops { @@ -408,7 +408,7 @@ export interface NPCAppearanceConfig { * - All NPCs drop something (minimum: bones/ashes) * - All NPCs have stats (even if passive) * - All NPCs can move (flag to disable) - * - Flexible drop system with RuneScape-style rarity tiers + * - Flexible drop system with classic fantasy MMORPG-style rarity tiers */ export interface NPCData { // ========== CORE IDENTITY ========== @@ -608,7 +608,7 @@ export interface MobSpawnConfig { type: string; // Mob ID from mobs.json name: string; level: number; - health: number; // OSRS: hitpoints = max HP directly + health: number; // classic MMORPG: hitpoints = max HP directly description?: string; levelRange?: LevelRange; difficultyLevel?: 1 | 2 | 3; diff --git a/packages/shared/src/types/entities/player-types.ts b/packages/shared/src/types/entities/player-types.ts index 2ea0896b4..c1031931a 100644 --- a/packages/shared/src/types/entities/player-types.ts +++ b/packages/shared/src/types/entities/player-types.ts @@ -8,7 +8,7 @@ import type { PlayerRow } from "../network/database"; import type { Item, EquipmentSlot } from "../game/item-types"; import type { Skills } from "./entity-types"; import { - calculateCombatLevel as osrsCombatLevel, + calculateCombatLevel as classicCombatLevel, normalizeCombatSkills, } from "../../utils/game/CombatLevelCalculator"; @@ -48,7 +48,7 @@ export interface PlayerCombatData { trainingSkill?: "attack" | "strength" | "defense" | "ranged"; inCombat: boolean; combatTarget: string | null; - autoRetaliate: boolean; // OSRS-style auto-retaliate setting (default: true) + autoRetaliate: boolean; // classic MMORPG-style auto-retaliate setting (default: true) } // Stamina system @@ -136,9 +136,8 @@ export interface Player { // Auto-retaliate initialization - top-level for entity creation, used to initialize combat.autoRetaliate autoRetaliate?: boolean; - // === OSRS-Accurate Face Direction System === + // === Rules-Accurate Face Direction System === // Face target is set when interacting with objects/NPCs, processed at end of tick - // @see https://osrs-docs.com/docs/packets/outgoing/updating/masks/face-direction/ faceTarget?: { /** Target coordinates to face (tile position) */ x: number; @@ -218,7 +217,7 @@ export class PlayerMigration { trainingSkill: "attack", inCombat: false, combatTarget: null, - autoRetaliate: true, // OSRS default: ON + autoRetaliate: true, // classic MMORPG default: ON }, death: { deathLocation: null, @@ -273,7 +272,7 @@ export class PlayerMigration { trainingSkill: "attack", inCombat: old.inCombat || false, combatTarget: old.combatTarget || null, - autoRetaliate: true, // OSRS default: ON + autoRetaliate: true, // classic MMORPG default: ON }, coins: old.coins, death: { @@ -312,10 +311,10 @@ export class PlayerMigration { } /** - * Calculate combat level from skills (delegates to OSRS-accurate CombatLevelCalculator) + * Calculate combat level from skills (delegates to rules-accurate CombatLevelCalculator) */ static calculateCombatLevel(skills: Skills): number { - return osrsCombatLevel( + return classicCombatLevel( normalizeCombatSkills({ attack: skills.attack?.level || 1, strength: skills.strength?.level || 1, @@ -367,7 +366,7 @@ export class PlayerMigration { trainingSkill: "attack", inCombat: false, combatTarget: null, - autoRetaliate: true, // OSRS default: ON + autoRetaliate: true, // classic MMORPG default: ON }, death: { deathLocation: null, @@ -543,7 +542,7 @@ export interface PlayerEquipment { rangedStrength: number; magicAttack: number; magicDefense: number; - // Per-style melee defence bonuses (OSRS combat triangle) + // Per-style melee defence bonuses (classic MMORPG combat triangle) defenseStab: number; defenseSlash: number; defenseCrush: number; diff --git a/packages/shared/src/types/events/event-payloads.ts b/packages/shared/src/types/events/event-payloads.ts index 3d124f1f3..8d1756f41 100644 --- a/packages/shared/src/types/events/event-payloads.ts +++ b/packages/shared/src/types/events/event-payloads.ts @@ -94,14 +94,14 @@ export interface CombatFollowTargetPayload { } /** - * OSRS-accurate: Player clicked to move (not on target), cancel their attacking combat + * rules-accurate: Player clicked to move (not on target), cancel their attacking combat */ export interface CombatPlayerDisengagePayload { playerId: string; } /** - * OSRS-accurate: Player clicked elsewhere, cancel their pending attack + * rules-accurate: Player clicked elsewhere, cancel their pending attack * (e.g., player was walking to mob to attack, but clicked ground instead) */ export interface PendingAttackCancelPayload { @@ -1017,7 +1017,7 @@ export interface EventMap { playerId?: string; message: string; type: "info" | "success" | "warning" | "error" | string; - /** Screen coordinates for positioned toasts (RS3-style). If omitted, toast displays centered. */ + /** Screen coordinates for positioned toasts (modern MMORPG-style). If omitted, toast displays centered. */ position?: { x: number; y: number }; }; [EventType.UI_SIDEBAR_CHAT_TOGGLE]: void; diff --git a/packages/shared/src/types/events/event-types.ts b/packages/shared/src/types/events/event-types.ts index ce950426f..c7b9b6e09 100644 --- a/packages/shared/src/types/events/event-types.ts +++ b/packages/shared/src/types/events/event-types.ts @@ -384,7 +384,7 @@ export enum EventType { RESOURCE_MESH_CREATED = "resource:mesh:created", RESOURCE_ACTION = "resource:action", - // Gathering Tool Visuals (show tool in hand during gathering, like OSRS fishing) + // Gathering Tool Visuals (show tool in hand during gathering, like classic MMORPG fishing) GATHERING_TOOL_SHOW = "gathering:tool:show", GATHERING_TOOL_HIDE = "gathering:tool:hide", diff --git a/packages/shared/src/types/game/duel-types.ts b/packages/shared/src/types/game/duel-types.ts index b9151aea5..7f1415f4b 100644 --- a/packages/shared/src/types/game/duel-types.ts +++ b/packages/shared/src/types/game/duel-types.ts @@ -2,7 +2,7 @@ * Duel Arena Types * * Type definitions for player-to-player dueling system. - * Follows OSRS-style duel arena mechanics with stakes. + * Follows classic MMORPG-style duel arena mechanics with stakes. * * Duel Flow: * 1. Player A challenges Player B (duelChallenge) @@ -71,7 +71,7 @@ export const DEFAULT_DUEL_RULES: DuelRules = { }; /** - * Rule combinations that are invalid (OSRS restrictions). + * Rule combinations that are invalid (classic MMORPG restrictions). * Format: [rule1, rule2, error message] */ export const INVALID_RULE_COMBINATIONS: Array< diff --git a/packages/shared/src/types/game/item-types.ts b/packages/shared/src/types/game/item-types.ts index 5b4af2734..e283323e1 100644 --- a/packages/shared/src/types/game/item-types.ts +++ b/packages/shared/src/types/game/item-types.ts @@ -41,7 +41,6 @@ export enum ItemType { // Combat related enums /** * Combat attack types. Discriminated union for exhaustive switch handling. - * @see https://oldschool.runescape.wiki/w/Combat */ export enum AttackType { MELEE = "melee", @@ -156,7 +155,7 @@ export interface Item { weaponType?: WeaponType | null; // Default: null equipable?: boolean; // Default: false (derived from equipSlot if not specified) attackType?: AttackType | null; // Default: null - attackSpeed?: number; // Attack speed in game ticks (OSRS-style: 4 = standard sword) + attackSpeed?: number; // Attack speed in game ticks (classic MMORPG-style: 4 = standard sword) attackRange?: number; // Attack range in tiles (1 = adjacent melee, 2 = halberd, 7+ = ranged) is2h?: boolean; // Explicit flag for 2-handed weapons (alternative to equipSlot: '2h') @@ -322,16 +321,16 @@ export interface Item { skill: "woodcutting" | "mining" | "fishing"; /** Priority for best tool selection (lower = better, 1 = best) */ priority: number; - /** For mining: ticks between roll attempts (OSRS-accurate) */ + /** For mining: ticks between roll attempts (rules-accurate) */ rollTicks?: number; }; - // === OSRS-ACCURATE INVENTORY ACTIONS === + // === RULES-ACCURATE INVENTORY ACTIONS === /** - * Explicit inventory context menu actions (OSRS-accurate). + * Explicit inventory context menu actions (rules-accurate). * First action is the left-click default. * - * OSRS stores this per-item, NOT derived from properties. + * classic MMORPG stores this per-item, NOT derived from properties. * Common actions: "Eat", "Drink", "Wield", "Wear", "Bury", "Use", "Drop", "Examine" * * If not specified, falls back to type-based detection for compatibility. diff --git a/packages/shared/src/types/game/prayer-types.ts b/packages/shared/src/types/game/prayer-types.ts index 87519bff7..87d665b51 100644 --- a/packages/shared/src/types/game/prayer-types.ts +++ b/packages/shared/src/types/game/prayer-types.ts @@ -4,7 +4,6 @@ * Types for the manifest-driven prayer system. * Includes type guards for runtime validation. * - * @see https://oldschool.runescape.wiki/w/Prayer */ // === Constants === diff --git a/packages/shared/src/types/game/quest-types.ts b/packages/shared/src/types/game/quest-types.ts index 56830408c..ca9f4faad 100644 --- a/packages/shared/src/types/game/quest-types.ts +++ b/packages/shared/src/types/game/quest-types.ts @@ -33,7 +33,7 @@ export type QuestStatus = /** Database-stored status values (ready_to_complete is derived, not stored) */ export type QuestDbStatus = "not_started" | "in_progress" | "completed"; -/** Quest difficulty levels matching RuneScape */ +/** Quest difficulty levels matching classic fantasy MMORPG */ export type QuestDifficulty = | "novice" | "intermediate" diff --git a/packages/shared/src/types/game/resource-processing-types.ts b/packages/shared/src/types/game/resource-processing-types.ts index 182be1515..475421c73 100644 --- a/packages/shared/src/types/game/resource-processing-types.ts +++ b/packages/shared/src/types/game/resource-processing-types.ts @@ -10,16 +10,15 @@ import type { Position3D } from "../core/base-types"; /** * Resource footprint - predefined sizes for how many tiles a resource occupies - * Used for OSRS-accurate tile-based positioning and interaction + * Used for rules-accurate tile-based positioning and interaction * * - standard: 1×1 tile (normal trees, rocks, fishing spots) * - large: 2×2 tiles (ancient trees, large ore veins) * - massive: 3×3 tiles (world trees, raid objects) * * Multi-tile resources use the SW (south-west) tile as their anchor, - * matching OSRS behavior for large objects. + * matching classic MMORPG behavior for large objects. * - * @see https://oldschool.runescape.wiki/w/Pathfinding */ export type ResourceFootprint = "standard" | "large" | "massive"; @@ -95,13 +94,12 @@ export interface Resource { /** * Resource drop - what a resource can drop when gathered * - * For fishing with OSRS priority rolling: + * For fishing with classic MMORPG priority rolling: * - `levelRequired`: Minimum skill level to catch this fish * - `catchLow`: Catch rate at level 1 (x/256 numerator) * - `catchHigh`: Catch rate at level 99 (x/256 numerator) * * Fish are rolled in priority order (highest level first). - * @see https://oldschool.runescape.wiki/w/Catch_rate */ export interface ResourceDrop { itemId: string; @@ -112,9 +110,9 @@ export interface ResourceDrop { stackable: boolean; /** Skill level required to catch this specific item */ levelRequired?: number; - /** OSRS catch rate numerator at level 1 (x/256) */ + /** classic MMORPG catch rate numerator at level 1 (x/256) */ catchLow?: number; - /** OSRS catch rate numerator at level 99 (x/256) */ + /** classic MMORPG catch rate numerator at level 99 (x/256) */ catchHigh?: number; } diff --git a/packages/shared/src/types/game/social-types.ts b/packages/shared/src/types/game/social-types.ts index c3ef17fac..f051993fc 100644 --- a/packages/shared/src/types/game/social-types.ts +++ b/packages/shared/src/types/game/social-types.ts @@ -7,7 +7,7 @@ * - Ignore list * - Private messaging * - * Follows RuneScape-style social mechanics with bidirectional friendships. + * Follows classic fantasy MMORPG-style social mechanics with bidirectional friendships. * * @see packages/server/src/database/repositories/FriendRepository for server implementation * @see packages/client/src/game/panels/FriendsPanel for UI implementation diff --git a/packages/shared/src/types/game/trade-types.ts b/packages/shared/src/types/game/trade-types.ts index c293fadf1..c1177cf68 100644 --- a/packages/shared/src/types/game/trade-types.ts +++ b/packages/shared/src/types/game/trade-types.ts @@ -2,7 +2,7 @@ * Trade System Types * * Type definitions for player-to-player trading system. - * Follows OSRS-style trade mechanics with mutual acceptance. + * Follows classic MMORPG-style trade mechanics with mutual acceptance. * * Trade Flow: * 1. Player A requests trade with Player B (tradeRequest) @@ -211,7 +211,7 @@ export type TradeStartedPayload = { partnerName: string; /** Trading partner's combat level */ partnerLevel: number; - /** Number of free inventory slots partner has (OSRS-style indicator) */ + /** Number of free inventory slots partner has (classic MMORPG-style indicator) */ partnerFreeSlots?: number; }; @@ -235,7 +235,7 @@ export type TradeUpdatedPayload = { myOffer: TradeOfferView; /** Partner's offer */ theirOffer: TradeOfferView; - /** Number of free inventory slots partner has (OSRS-style indicator) */ + /** Number of free inventory slots partner has (classic MMORPG-style indicator) */ partnerFreeSlots?: number; }; @@ -293,7 +293,7 @@ export type TradeErrorPayload = { // ============================================================================ /** - * Trade screen type for two-screen confirmation flow (OSRS-style) + * Trade screen type for two-screen confirmation flow (classic MMORPG-style) * - offer: Main trading screen where players add/remove items * - confirm: Confirmation screen showing final summary */ @@ -327,7 +327,7 @@ export type TradeWindowState = { myOfferValue: number; /** Total value of partner's offer (for wealth transfer indicator) */ theirOfferValue: number; - /** Number of free inventory slots partner has (OSRS-style indicator) */ + /** Number of free inventory slots partner has (classic MMORPG-style indicator) */ partnerFreeSlots: number; }; @@ -355,7 +355,7 @@ export type TradeRequestModalState = { * Trade system constants */ export const TRADE_CONSTANTS = { - /** Maximum items per trade offer (matches OSRS inventory size) */ + /** Maximum items per trade offer (matches classic MMORPG inventory size) */ MAX_TRADE_SLOTS: 28, /** Trade request timeout in milliseconds (30 seconds) */ diff --git a/packages/shared/src/types/index.ts b/packages/shared/src/types/index.ts index 920a6642e..93a48ff9e 100644 --- a/packages/shared/src/types/index.ts +++ b/packages/shared/src/types/index.ts @@ -411,7 +411,7 @@ export interface Entities extends System { export type ChatMessageType = | "chat" // Normal chat message | "system" // System messages - | "trade_request"; // OSRS-style trade request (pink clickable) + | "trade_request"; // classic MMORPG-style trade request (pink clickable) // Chat message interface with all required properties export interface ChatMessage { diff --git a/packages/shared/src/types/interaction.ts b/packages/shared/src/types/interaction.ts index e9a025c7c..05d6ef6a2 100644 --- a/packages/shared/src/types/interaction.ts +++ b/packages/shared/src/types/interaction.ts @@ -100,5 +100,5 @@ export type SessionCloseReason = | "disconnect" // Player disconnected | "new_session" // Replaced by new session (opening another UI) | "target_gone" // Target entity no longer exists - | "combat" // Player was attacked (OSRS-style: interrupts banking) + | "combat" // Player was attacked (classic MMORPG-style: interrupts banking) | "timeout"; // Session exceeded maximum duration (zombie cleanup) diff --git a/packages/shared/src/types/systems/system-interfaces.ts b/packages/shared/src/types/systems/system-interfaces.ts index 3ca6ac5b8..80571f7b8 100644 --- a/packages/shared/src/types/systems/system-interfaces.ts +++ b/packages/shared/src/types/systems/system-interfaces.ts @@ -505,7 +505,7 @@ export interface DuelSessionInfo { } /** - * DuelSystem - Server-authoritative player-to-player dueling (OSRS-accurate) + * DuelSystem - Server-authoritative player-to-player dueling (rules-accurate) * * Manages duel sessions with rules negotiation, stakes, and combat enforcement. * diff --git a/packages/shared/src/utils/SeededRandom.ts b/packages/shared/src/utils/SeededRandom.ts index 66f65fa87..487134ba9 100644 --- a/packages/shared/src/utils/SeededRandom.ts +++ b/packages/shared/src/utils/SeededRandom.ts @@ -1,5 +1,5 @@ /** - * SeededRandom - Deterministic PRNG for OSRS-Accurate Combat + * SeededRandom - Deterministic PRNG for Rules-Accurate Combat * * Uses xorshift128+ algorithm for fast, high-quality random numbers. * Same seed always produces the same sequence on all platforms. @@ -37,7 +37,7 @@ export interface SeededRandomState { * // Get random values * const float = rng.random(); // 0.0 to 1.0 * const int = rng.nextInt(100); // 0 to 99 - * const roll = rng.nextInt(256); // OSRS accuracy roll + * const roll = rng.nextInt(256); // classic MMORPG accuracy roll * * // Save/restore state * const state = rng.getState(); @@ -133,7 +133,7 @@ export class SeededRandom { } /** - * OSRS-style accuracy roll + * classic MMORPG-style accuracy roll * Compares attack roll vs defense roll * * @param attackRoll - Attacker's accuracy roll (0 to maxRoll) @@ -141,7 +141,7 @@ export class SeededRandom { * @returns true if attack hits, false if it misses */ accuracyRoll(attackRoll: number, defenseRoll: number): boolean { - // OSRS formula: if attack > defense, hit chance = 1 - (def+2)/(2*(atk+1)) + // classic combat formula: if attack > defense, hit chance = 1 - (def+2)/(2*(atk+1)) // if attack <= defense, hit chance = atk / (2*(def+1)) // We simulate this by rolling both and comparing @@ -152,7 +152,7 @@ export class SeededRandom { } /** - * OSRS-style damage roll + * classic MMORPG-style damage roll * Generates damage from 0 to maxHit (inclusive) * * @param maxHit - Maximum possible damage diff --git a/packages/shared/src/utils/ShoreUtils.ts b/packages/shared/src/utils/ShoreUtils.ts index 12730910d..223090aea 100644 --- a/packages/shared/src/utils/ShoreUtils.ts +++ b/packages/shared/src/utils/ShoreUtils.ts @@ -13,7 +13,6 @@ * 2. findShorePoints (LEGACY) — Independently samples terrain heights. * Kept for non-fishing uses and as fallback when collision data is unavailable. * - * @see https://oldschool.runescape.wiki/w/Fishing - OSRS fishing spots appear at water edges */ import { TERRAIN_CONSTANTS } from "../constants/GameConstants"; @@ -361,7 +360,7 @@ export function findShorePoints( /** * Finds points IN the water that are adjacent to walkable land. - * This is the OSRS-accurate placement - fishing spots appear as ripples + * This is the rules-accurate placement - fishing spots appear as ripples * in the water near the shore where players can reach them. * * @param bounds - Rectangle to search within (world coordinates) diff --git a/packages/shared/src/utils/__tests__/SeededRandom.test.ts b/packages/shared/src/utils/__tests__/SeededRandom.test.ts index 1d28f3ac0..7e99d4594 100644 --- a/packages/shared/src/utils/__tests__/SeededRandom.test.ts +++ b/packages/shared/src/utils/__tests__/SeededRandom.test.ts @@ -113,7 +113,7 @@ describe("SeededRandom", () => { }); }); - describe("OSRS combat methods", () => { + describe("classic MMORPG combat methods", () => { it("damageRoll() produces values in [0, maxHit]", () => { const rng = new SeededRandom(42); const maxHit = 25; diff --git a/packages/shared/src/utils/__tests__/item-helpers.test.ts b/packages/shared/src/utils/__tests__/item-helpers.test.ts index abd07ceb6..9b25cbef1 100644 --- a/packages/shared/src/utils/__tests__/item-helpers.test.ts +++ b/packages/shared/src/utils/__tests__/item-helpers.test.ts @@ -1,7 +1,7 @@ /** * Item Helpers Unit Tests * - * Tests for OSRS-accurate item type detection helpers used for + * Tests for rules-accurate item type detection helpers used for * context menu ordering and left-click default actions. */ diff --git a/packages/shared/src/utils/distance.ts b/packages/shared/src/utils/distance.ts index 180f222cb..c62962846 100644 --- a/packages/shared/src/utils/distance.ts +++ b/packages/shared/src/utils/distance.ts @@ -1,7 +1,7 @@ /** * Distance Calculation Utilities * - * OSRS uses Chebyshev distance (square range), not Euclidean (circular range). + * classic MMORPG uses Chebyshev distance (square range), not Euclidean (circular range). * All game systems MUST use these functions for consistency. */ @@ -15,7 +15,7 @@ export interface Position2D { * * Chebyshev = max(|x1-x2|, |z1-z2|) * - * This creates "square" range checks matching OSRS tile-based mechanics. + * This creates "square" range checks matching classic MMORPG tile-based mechanics. * Example: (3,4) from origin = Chebyshev 4, Euclidean 5 */ export function chebyshevDistance(a: Position2D, b: Position2D): number { diff --git a/packages/shared/src/utils/game/CombatCalculations.ts b/packages/shared/src/utils/game/CombatCalculations.ts index 593545a17..f889ba1f4 100644 --- a/packages/shared/src/utils/game/CombatCalculations.ts +++ b/packages/shared/src/utils/game/CombatCalculations.ts @@ -1,6 +1,5 @@ /** * Combat damage/accuracy calculations. Deterministic via SeededRandom. - * @see https://oldschool.runescape.wiki/w/Damage_per_second/Melee */ import { COMBAT_CONSTANTS } from "../../constants/CombatConstants"; @@ -31,7 +30,6 @@ export interface StyleBonus { /** * Pre-allocated style bonuses to avoid object creation in hot path. * Frozen to prevent mutation and enable V8 optimizations. - * @see https://oldschool.runescape.wiki/w/Combat_Options */ const STYLE_BONUSES: Readonly>> = { accurate: Object.freeze({ attack: 3, strength: 0, defense: 0 }), @@ -67,7 +65,7 @@ export interface HitCalculationResult { /** * Prayer bonus multipliers for combat. - * Applied to effective levels per OSRS formula. + * Applied to effective levels per classic combat formula. */ export interface PrayerCombatBonuses { attackMultiplier?: number; @@ -76,9 +74,8 @@ export interface PrayerCombatBonuses { } /** - * OSRS-accurate hit chance from attack and defense rolls. + * rules-accurate hit chance from attack and defense rolls. * Shared by melee, ranged, and magic damage calculators. - * @see https://oldschool.runescape.wiki/w/Accuracy */ export function calculateHitChance( attackRoll: number, @@ -92,9 +89,8 @@ export function calculateHitChance( } /** - * Calculate hit chance using OSRS-accurate formula. + * Calculate hit chance using rules-accurate formula. * Prayer bonuses are applied as multipliers to effective levels. - * @see https://oldschool.runescape.wiki/w/Accuracy */ function calculateAccuracy( attackerAttackLevel: number, @@ -114,7 +110,7 @@ function calculateAccuracy( ? getStyleBonus(defenderStyle) : { attack: 0, strength: 0, defense: 0 }; - // OSRS formula: prayer multiplier is applied to base level before adding constants + // classic combat formula: prayer multiplier is applied to base level before adding constants // effectiveLevel = floor(baseLevel * prayerMultiplier) + 8 + styleBonus const prayerAttackMultiplier = attackerPrayerBonuses?.attackMultiplier ?? 1; const boostedAttackLevel = Math.floor( @@ -141,9 +137,8 @@ function calculateAccuracy( } /** - * Calculate melee damage using OSRS-accurate formulas. + * Calculate melee damage using rules-accurate formulas. * Prayer bonuses are applied as multipliers to effective levels. - * @see https://oldschool.runescape.wiki/w/Damage_per_second/Melee */ export function calculateDamage( attacker: { stats?: CombatStats; config?: { attackPower?: number } }, @@ -179,7 +174,7 @@ export function calculateDamage( attackStat = baseAttackLevel; - // OSRS formula: prayer multiplier is applied to base level before adding constants + // classic combat formula: prayer multiplier is applied to base level before adding constants // effectiveStrength = floor(baseStrength * prayerMultiplier) + 8 + styleBonus const prayerStrengthMultiplier = attackerPrayerBonuses?.strengthMultiplier ?? 1; @@ -264,7 +259,6 @@ function _getDefenseValue(entity: { return 0; } -/** @see https://oldschool.runescape.wiki/w/Attack_range */ export function isInAttackRange( attackerPos: { x: number; y: number; z: number }, targetPos: { x: number; y: number; z: number }, @@ -292,7 +286,6 @@ export function isAttackOnCooldownTicks( return currentTick < nextAttackTick; } -/** ceil(attack_speed / 2) + 1 ticks @see https://oldschool.runescape.wiki/w/Auto_Retaliate */ export function calculateRetaliationDelay(attackSpeedTicks: number): number { return Math.ceil(attackSpeedTicks / 2) + 1; } diff --git a/packages/shared/src/utils/game/CombatLevelCalculator.ts b/packages/shared/src/utils/game/CombatLevelCalculator.ts index 902e1b611..5b922db77 100644 --- a/packages/shared/src/utils/game/CombatLevelCalculator.ts +++ b/packages/shared/src/utils/game/CombatLevelCalculator.ts @@ -1,10 +1,9 @@ /** - * Combat Level Calculator - OSRS-Accurate Combat Level Calculation + * Combat Level Calculator - Rules-Accurate Combat Level Calculation * - * Implements the exact combat level formula from Old School RuneScape. + * Implements the configured combat-level formula used by the game. * Combat level determines player power and affects mob aggression behavior. * - * Formula source: https://oldschool.runescape.wiki/w/Combat_level * * Key mechanics: * - Base stats (Defence, Hitpoints, Prayer) contribute to all combat types @@ -39,7 +38,7 @@ export const MIN_COMBAT_LEVEL = 3; export const MAX_COMBAT_LEVEL = 126; /** - * Calculate OSRS-accurate combat level. + * Calculate rules-accurate combat level. * * Formula: * Base = 0.25 * (Defence + Hitpoints + floor(Prayer / 2)) @@ -127,7 +126,7 @@ export function normalizeCombatSkills( /** * Check if player level is high enough to be ignored by a mob. * - * OSRS Rule: Mobs ignore players whose combat level is MORE THAN DOUBLE the mob's level. + * classic MMORPG Rule: Mobs ignore players whose combat level is MORE THAN DOUBLE the mob's level. * * Examples: * - Level 2 goblin ignores level 5+ players (5 > 2*2 = 4) @@ -139,7 +138,6 @@ export function normalizeCombatSkills( * @param toleranceImmune - If true, mob never ignores players based on level (bosses) * @returns true if mob should ignore this player * - * @see https://oldschool.runescape.wiki/w/Aggression */ export function shouldMobIgnorePlayer( playerCombatLevel: number, @@ -149,6 +147,6 @@ export function shouldMobIgnorePlayer( // Some mobs (bosses, special encounters) never ignore based on level if (toleranceImmune) return false; - // OSRS rule: player level > (mob level * 2) = mob ignores player + // classic MMORPG rule: player level > (mob level * 2) = mob ignores player return playerCombatLevel > mobLevel * 2; } diff --git a/packages/shared/src/utils/game/CombatUtils.ts b/packages/shared/src/utils/game/CombatUtils.ts index 359a6a881..dd80d55f8 100644 --- a/packages/shared/src/utils/game/CombatUtils.ts +++ b/packages/shared/src/utils/game/CombatUtils.ts @@ -47,7 +47,7 @@ export function isEntityAlive(world: World, entityId: string): boolean { /** * Check if entity is in melee combat range (MVP: melee-only) * - * OSRS-STYLE: Must be on adjacent tile (Chebyshev distance = 1) + * classic MMORPG-STYLE: Must be on adjacent tile (Chebyshev distance = 1) */ export function isInCombatRange( world: World, @@ -325,7 +325,7 @@ export function hasEquippedWeapon(player: Player): boolean { * Get player's weapon attack range in tiles * Returns weapon's attackRange from manifest, or 1 for unarmed (punching) * - * OSRS-style ranges: + * classic MMORPG-style ranges: * - 1 = melee (sword, dagger, mace) or unarmed * - 2 = halberd, spear (extended melee) * - 7+ = ranged weapons (bow, crossbow, magic) diff --git a/packages/shared/src/utils/game/GatheringCalculations.ts b/packages/shared/src/utils/game/GatheringCalculations.ts index b6e4f9860..848df5bac 100644 --- a/packages/shared/src/utils/game/GatheringCalculations.ts +++ b/packages/shared/src/utils/game/GatheringCalculations.ts @@ -1,7 +1,7 @@ /** * Gathering Calculations * - * OSRS-style tick-based timing utilities for resource gathering. + * classic MMORPG-style tick-based timing utilities for resource gathering. * All gathering actions operate on 600ms game ticks. */ diff --git a/packages/shared/src/utils/game/HitDelayCalculator.ts b/packages/shared/src/utils/game/HitDelayCalculator.ts index 8ef614c80..e8f84784a 100644 --- a/packages/shared/src/utils/game/HitDelayCalculator.ts +++ b/packages/shared/src/utils/game/HitDelayCalculator.ts @@ -1,12 +1,11 @@ /** - * HitDelayCalculator - OSRS-Accurate Hit Delay System + * HitDelayCalculator - Rules-Accurate Hit Delay System * * Calculates the delay (in ticks) between an attack being made and * damage appearing on the target. This creates the projectile travel - * time effect seen in RuneScape. + * time effect seen in classic fantasy MMORPG. * - * OSRS HIT DELAY FORMULAS: - * @see https://oldschool.runescape.wiki/w/Hit_delay + * classic MMORPG HIT DELAY FORMULAS: * * MELEE: * Delay = 0 ticks (instant) @@ -182,7 +181,7 @@ export function calculateMagicHitDelay( * Calculate distance between two positions in tiles * * Uses Chebyshev distance (max of x/z difference) for tile-based games. - * This matches OSRS's tile distance calculation. + * This matches classic MMORPG's tile distance calculation. * * @param pos1 - First position * @param pos2 - Second position @@ -197,7 +196,7 @@ export function calculateTileDistance( const dx = Math.abs(pos1.x - pos2.x); const dz = Math.abs(pos1.z - pos2.z); - // Chebyshev distance (how OSRS calculates tile distance) + // Chebyshev distance (how classic MMORPG calculates tile distance) return Math.max(dx, dz); } diff --git a/packages/shared/src/utils/game/__tests__/CombatCalculations.test.ts b/packages/shared/src/utils/game/__tests__/CombatCalculations.test.ts index bf8538cd2..11270e1f0 100644 --- a/packages/shared/src/utils/game/__tests__/CombatCalculations.test.ts +++ b/packages/shared/src/utils/game/__tests__/CombatCalculations.test.ts @@ -1,7 +1,7 @@ /** * CombatCalculations Unit Tests * - * Tests for OSRS-style combat calculation functions: + * Tests for classic MMORPG-style combat calculation functions: * - Damage calculation with accuracy system * - Attack range checking (melee tile-adjacent) * - Attack cooldown checking (tick-based) @@ -40,7 +40,7 @@ describe("CombatCalculations", () => { expect(result).toHaveProperty("damageType"); expect(result).toHaveProperty("didHit"); expect(result.damageType).toBe(AttackType.MELEE); - expect(result.isCritical).toBe(false); // OSRS has no critical system + expect(result.isCritical).toBe(false); // classic MMORPG has no critical system }); it("returns non-negative damage", () => { @@ -237,18 +237,17 @@ describe("CombatCalculations", () => { expect(isInAttackRange(attacker, target, AttackType.MELEE)).toBe(true); }); - it("returns false for diagonally adjacent tiles (range-1 melee OSRS-accurate)", () => { - // OSRS: Range-1 melee (standard weapons) EXCLUDES diagonals + it("returns false for diagonally adjacent tiles (range-1 melee rules-accurate)", () => { + // classic MMORPG: Range-1 melee (standard weapons) EXCLUDES diagonals // Only cardinal directions (N, S, E, W) are valid for range-1 // Diagonal attacks require range-2+ weapons (halberds, spears) - // @see https://oldschool.runescape.wiki/w/Attack_range const attacker = { x: 0.5, y: 0, z: 0.5 }; const target = { x: 1.5, y: 0, z: 1.5 }; expect(isInAttackRange(attacker, target, AttackType.MELEE)).toBe(false); }); it("returns true for diagonally adjacent tiles with range-2 melee (halberd)", () => { - // OSRS: Range-2+ melee (halberds, spears) INCLUDES diagonals + // classic MMORPG: Range-2+ melee (halberds, spears) INCLUDES diagonals const attacker = { x: 0.5, y: 0, z: 0.5 }; const target = { x: 1.5, y: 0, z: 1.5 }; // Using meleeRange parameter = 2 (halberd range) @@ -262,7 +261,7 @@ describe("CombatCalculations", () => { expect(isInAttackRange(attacker, target, AttackType.MELEE)).toBe(false); }); - it("returns false for same tile (OSRS requires adjacent, not overlapping)", () => { + it("returns false for same tile (classic MMORPG requires adjacent, not overlapping)", () => { // Both on same tile - cannot attack from same tile const attacker = { x: 0.3, y: 0, z: 0.3 }; const target = { x: 0.7, y: 0, z: 0.7 }; diff --git a/packages/shared/src/utils/game/__tests__/CombatLevelCalculator.test.ts b/packages/shared/src/utils/game/__tests__/CombatLevelCalculator.test.ts index 44a9c8988..0dce87b0b 100644 --- a/packages/shared/src/utils/game/__tests__/CombatLevelCalculator.test.ts +++ b/packages/shared/src/utils/game/__tests__/CombatLevelCalculator.test.ts @@ -1,14 +1,13 @@ /** * Combat Level Calculator Tests * - * Verifies OSRS-accurate combat level calculation: + * Verifies rules-accurate combat level calculation: * - Level 3 minimum (fresh character) * - Level 126 maximum (all 99s) * - Correct formula application * - Combat type detection * - Double-level aggro rule * - * @see https://oldschool.runescape.wiki/w/Combat_level */ import { describe, it, expect } from "vitest"; @@ -358,9 +357,8 @@ describe("CombatLevelCalculator", () => { }); }); - describe("OSRS Wiki verification examples", () => { - // These test cases are derived from the OSRS Wiki combat level formula - // https://oldschool.runescape.wiki/w/Combat_level + describe("reference-rules verification examples", () => { + // These test cases verify the configured combat-level formula it("tutorial island character (level 3)", () => { // Fresh out of tutorial island: all 1s except HP = 10 diff --git a/packages/shared/src/utils/game/index.ts b/packages/shared/src/utils/game/index.ts index d1f5abbaa..dc891967c 100644 --- a/packages/shared/src/utils/game/index.ts +++ b/packages/shared/src/utils/game/index.ts @@ -35,5 +35,5 @@ export { export * from "./ComponentUtils"; -// Combat level calculation (OSRS-accurate) +// Combat level calculation (rules-accurate) export * from "./CombatLevelCalculator"; diff --git a/packages/shared/src/utils/index.ts b/packages/shared/src/utils/index.ts index dfddda12b..aa899fa26 100644 --- a/packages/shared/src/utils/index.ts +++ b/packages/shared/src/utils/index.ts @@ -12,7 +12,7 @@ export * from "./IdentifierUtils"; export * from "./PlayerIdMapper"; export * from "./ExternalAssetUtils"; export * from "./downloadFile"; -export * from "./SeededRandom"; // OSRS-accurate deterministic RNG +export * from "./SeededRandom"; // rules-accurate deterministic RNG export * from "./FrameBudgetManager"; // Frame time budget management for reducing jank // Export ValidationUtils without calculateDistance* (they re-export from MathUtils) @@ -38,5 +38,5 @@ export * from "./rendering"; // Rendering, mesh, model cache, UI export * from "./spatial"; // Spatial data structures for culling export * from "./workers"; // Web worker utilities for parallel processing -// Distance utilities (OSRS-style Chebyshev) +// Distance utilities (classic MMORPG-style Chebyshev) export * from "./distance"; diff --git a/packages/shared/src/utils/item-helpers.ts b/packages/shared/src/utils/item-helpers.ts index 94fa5fbd7..e8841046a 100644 --- a/packages/shared/src/utils/item-helpers.ts +++ b/packages/shared/src/utils/item-helpers.ts @@ -1,5 +1,5 @@ /** - * OSRS-accurate item type detection helpers. + * rules-accurate item type detection helpers. * Used for context menu ordering and left-click default actions. * * These helpers determine: @@ -98,10 +98,10 @@ export const HANDLED_INVENTORY_ACTIONS = new Set([ ]); /** - * Get primary action from manifest's inventoryActions (OSRS-accurate approach). + * Get primary action from manifest's inventoryActions (rules-accurate approach). * Returns the first action in the array, or null if no actions defined. * - * OSRS stores explicit inventory options per item in the manifest. + * classic MMORPG stores explicit inventory options per item in the manifest. * First option is always the left-click default. */ export function getPrimaryActionFromManifest( @@ -130,7 +130,7 @@ export function getPrimaryActionFromManifest( /** * Get primary action using manifest-first approach with heuristic fallback. - * OSRS-accurate: reads from inventoryActions if available. + * rules-accurate: reads from inventoryActions if available. */ export function getPrimaryAction( item: Item | null, diff --git a/packages/shared/src/utils/pools/TilePool.ts b/packages/shared/src/utils/pools/TilePool.ts index 52e4a8ca8..8074b6091 100644 --- a/packages/shared/src/utils/pools/TilePool.ts +++ b/packages/shared/src/utils/pools/TilePool.ts @@ -181,7 +181,7 @@ class TilePoolImpl { /** * Calculate Chebyshev distance between two tiles. - * This is the OSRS-style distance used for range checks. + * This is the classic MMORPG-style distance used for range checks. */ chebyshevDistance(a: PooledTile, b: PooledTile): number { const dx = Math.abs(a.x - b.x); diff --git a/packages/shared/src/utils/rendering/AnimationLOD.ts b/packages/shared/src/utils/rendering/AnimationLOD.ts index b57bec207..210262441 100644 --- a/packages/shared/src/utils/rendering/AnimationLOD.ts +++ b/packages/shared/src/utils/rendering/AnimationLOD.ts @@ -2,7 +2,7 @@ * AnimationLOD - Distance-Based Animation Update Throttling * * Reduces CPU/GPU load by throttling animation updates for distant entities. - * OSRS-style: Full animations up close, reduced/paused at distance. + * classic MMORPG-style: Full animations up close, reduced/paused at distance. * * ## LOD Levels (from DISTANCE_CONSTANTS.ANIMATION_LOD) * - **Full**: <30m - Update every frame (60fps animation) diff --git a/packages/shared/src/utils/rendering/DistanceFade.ts b/packages/shared/src/utils/rendering/DistanceFade.ts index 03b6bd575..3180cc66c 100644 --- a/packages/shared/src/utils/rendering/DistanceFade.ts +++ b/packages/shared/src/utils/rendering/DistanceFade.ts @@ -1,6 +1,6 @@ /** * Distance-based entity fade using dithered dissolve shader. - * Includes camera-to-player occlusion dissolve (RuneScape-style). + * Includes camera-to-player occlusion dissolve (classic fantasy MMORPG-style). * * ## WebGPU/WebGL Support * - WebGPU: Uses TSL (Three Shading Language) nodes for native WebGPU support @@ -264,7 +264,7 @@ function applyDissolveTSL( smoothstep(nearCameraFadeEnd, nearCameraFadeStart, camDist), ); - // Camera-to-player occlusion dissolve (RuneScape-style cone) + // Camera-to-player occlusion dissolve (classic fantasy MMORPG-style cone) const camToPlayer = sub(uPlayerPos, uCameraPos); const ctLengthSq = dot(camToPlayer, camToPlayer); const ctLength = sqrt(ctLengthSq); @@ -322,7 +322,7 @@ function applyDissolveTSL( ); const ditherValue = mul(bayerInt, float(0.0625)); - // RS3-style threshold: discard when fade >= dither + // modern MMORPG-style threshold: discard when fade >= dither // Only apply dithering when fadeValue > 0, otherwise step(0,0)=1 causes holes const hasAnyFade = step(float(0.001), fadeValue); const ditherThreshold = mul( diff --git a/packages/shared/src/utils/rendering/HealthBarRenderer.ts b/packages/shared/src/utils/rendering/HealthBarRenderer.ts index fa0b64c21..df10180c9 100644 --- a/packages/shared/src/utils/rendering/HealthBarRenderer.ts +++ b/packages/shared/src/utils/rendering/HealthBarRenderer.ts @@ -11,7 +11,7 @@ /// /** - * Health bar color scheme (RuneScape style) + * Health bar color scheme (classic fantasy MMORPG style) */ export const HEALTH_BAR_COLORS = { /** Red background for depleted health */ diff --git a/packages/shared/src/utils/rendering/InstancedMeshManager.ts b/packages/shared/src/utils/rendering/InstancedMeshManager.ts index 6cdc701e8..f301b3aa0 100644 --- a/packages/shared/src/utils/rendering/InstancedMeshManager.ts +++ b/packages/shared/src/utils/rendering/InstancedMeshManager.ts @@ -3474,7 +3474,7 @@ export class MobInstancedRenderer { // Combined distance fade (max of near and far fade) const distanceFade = max(farFade, nearFade); - // SCREEN-SPACE 4x4 BAYER DITHERING (RuneScape 3 style) + // SCREEN-SPACE 4x4 BAYER DITHERING (modern fantasy MMORPG style) // 4x4 Bayer matrix: [ 0, 8, 2,10; 12, 4,14, 6; 3,11, 1, 9; 15, 7,13, 5]/16 const ix = mod(floor(viewportCoordinate.x), float(4.0)); const iy = mod(floor(viewportCoordinate.y), float(4.0)); @@ -3495,7 +3495,7 @@ export class MobInstancedRenderer { ); const ditherValue = mul(bayerInt, float(0.0625)); - // RS3-style: discard when fade >= dither + // modern MMORPG-style: discard when fade >= dither // step returns 0 or 1, multiply by 2 so threshold > 1.0 causes discard // Only apply when there's actual fade (prevents holes when distanceFade=0) const hasAnyFade = step(float(0.001), distanceFade); diff --git a/packages/shared/src/utils/rendering/PostProcessingFactory.ts b/packages/shared/src/utils/rendering/PostProcessingFactory.ts index ca7aeddda..26247dc9a 100644 --- a/packages/shared/src/utils/rendering/PostProcessingFactory.ts +++ b/packages/shared/src/utils/rendering/PostProcessingFactory.ts @@ -3,9 +3,9 @@ * * Provides WebGPU-compatible post-processing effects including: * - 3D LUT color grading for cinematic looks - * - Depth-based camera blur (DoF) for RuneScape-style depth of field + * - Depth-based camera blur (DoF) for classic fantasy MMORPG-style depth of field * - Tone mapping control - * - Entity outline highlighting (RS3-style hover effect) + * - Entity outline highlighting (modern MMORPG-style hover effect) * * Uses Three.js TSL (Three Shading Language) for GPU-accelerated effects. */ @@ -62,7 +62,7 @@ type ShaderNodeLike = { mul: (other: unknown) => ShaderNodeLike; }; -/** Default depth blur parameters (RuneScape-style DoF) */ +/** Default depth blur parameters (classic fantasy MMORPG-style DoF) */ export const DEPTH_BLUR_DEFAULTS = { /** Focus distance in world units - objects at this distance are sharpest */ focusDistance: 100, diff --git a/packages/shared/src/utils/rendering/__tests__/PostProcessing.test.ts b/packages/shared/src/utils/rendering/__tests__/PostProcessing.test.ts index aa884b00b..e55d1aaa2 100644 --- a/packages/shared/src/utils/rendering/__tests__/PostProcessing.test.ts +++ b/packages/shared/src/utils/rendering/__tests__/PostProcessing.test.ts @@ -144,7 +144,7 @@ describe("Depth Blur Default Values", () => { expect(typeof DEPTH_BLUR_DEFAULTS.skyDistance).toBe("number"); }); - it("should have RuneScape-style focus distance (~100 world units)", () => { + it("should have classic fantasy MMORPG-style focus distance (~100 world units)", () => { // Focus far out so player and nearby objects stay sharp expect(DEPTH_BLUR_DEFAULTS.focusDistance).toBe(100); expect(DEPTH_BLUR_DEFAULTS.focusDistance).toBeGreaterThanOrEqual(40); @@ -157,8 +157,8 @@ describe("Depth Blur Default Values", () => { expect(DEPTH_BLUR_DEFAULTS.blurRange).toBeGreaterThan(0); }); - it("should have heavy default intensity for RuneScape-style blur", () => { - // High intensity like RuneScape's prominent depth blur + it("should have heavy default intensity for classic fantasy MMORPG-style blur", () => { + // High intensity like classic fantasy MMORPG's prominent depth blur expect(DEPTH_BLUR_DEFAULTS.intensity).toBe(0.85); expect(DEPTH_BLUR_DEFAULTS.intensity).toBeGreaterThan(0.5); expect(DEPTH_BLUR_DEFAULTS.intensity).toBeLessThanOrEqual(1); @@ -703,7 +703,7 @@ describe("Identity LUT Generation", () => { // ============================================================================ describe("Depth Blur Math", () => { - // Test the depth blur calculation logic (FAR BLUR ONLY - RuneScape style) + // Test the depth blur calculation logic (FAR BLUR ONLY - classic fantasy MMORPG style) // Smoothstep function (matches GLSL smoothstep) function smoothstep(edge0: number, edge1: number, x: number): number { diff --git a/packages/shared/src/utils/workers/MinimapWorker.ts b/packages/shared/src/utils/workers/MinimapWorker.ts index e4c3b22f3..350e2e7ae 100644 --- a/packages/shared/src/utils/workers/MinimapWorker.ts +++ b/packages/shared/src/utils/workers/MinimapWorker.ts @@ -12,7 +12,7 @@ * Features: * - Height-based terrain coloring * - Entity pip rendering - * - Camera rotation support (RS3-style) + * - Camera rotation support (modern MMORPG-style) * - Zoom/extent controls */ diff --git a/packages/web3/test/xp-table-parity.test.ts b/packages/web3/test/xp-table-parity.test.ts index c1123fb36..b025000ae 100644 --- a/packages/web3/test/xp-table-parity.test.ts +++ b/packages/web3/test/xp-table-parity.test.ts @@ -7,7 +7,7 @@ * This is critical: any mismatch means the on-chain skill levels would * diverge from the game server's calculations. * - * Reference: OSRS XP formula + * Reference: classic MMORPG XP formula * xpDelta(level) = floor((level - 1 + 300 * 2^((level-1)/7)) / 4) * xpForLevel(N) = sum(xpDelta(1)..xpDelta(N-1)) */ @@ -64,7 +64,7 @@ describe("XP Table Parity - TypeScript vs Solidity", () => { describe("XP Table - Key Milestones", () => { // These are the actual values from the JS formula, which differ slightly - // from OSRS wiki values at higher levels due to floating-point rounding. + // from classic MMORPG wiki values at higher levels due to floating-point rounding. const tsTable = generateTypeScriptXPTable(); it("level 1 = 0 XP", () => { @@ -159,7 +159,7 @@ describe("XP Table - Level Lookup (Reverse)", () => { describe("Combat Level Formula Parity", () => { /** - * OSRS combat level formula (from CombatLevel.sol and CombatCalculations.ts): + * classic MMORPG combat level formula (from CombatLevel.sol and CombatCalculations.ts): * base = 0.25 * (defense + constitution + floor(prayer / 2)) * melee = 0.325 * (attack + strength) * ranged = 0.325 * floor(ranged * 1.5) diff --git a/packages/website/src/app/layout.tsx b/packages/website/src/app/layout.tsx index 1cc9bc4bd..90df12bca 100644 --- a/packages/website/src/app/layout.tsx +++ b/packages/website/src/app/layout.tsx @@ -13,7 +13,7 @@ export const metadata: Metadata = { keywords: [ "MMORPG", "AI gaming", - "RuneScape", + "classic fantasy MMORPG", "ElizaOS", "autonomous agents", "Web3 gaming", diff --git a/publishing/config.yaml b/publishing/config.yaml index 0a8668407..d739dd025 100644 --- a/publishing/config.yaml +++ b/publishing/config.yaml @@ -29,7 +29,7 @@ app: # Long description (max 4000 characters) long_description: | - Hyperia is an AI-native MMORPG that combines classic RuneScape-style gameplay + Hyperia is an AI-native MMORPG that combines classic fantasy MMORPG gameplay with cutting-edge AI technology and blockchain integration. Features: diff --git a/publishing/publish.sh b/publishing/publish.sh index 1d59c1c51..07b9d9ff2 100755 --- a/publishing/publish.sh +++ b/publishing/publish.sh @@ -109,7 +109,7 @@ if [ -n "$APP_ADDRESS" ]; then --banner "assets/banner.png" \ --screenshots "assets/screenshot_1.png,assets/screenshot_2.png,assets/screenshot_3.png,assets/screenshot_4.png" \ --short-description "An AI-native MMORPG built on Solana" \ - --long-description "Hyperia is an AI-native MMORPG combining classic RuneScape-style gameplay with AI technology and Solana blockchain integration." \ + --long-description "Hyperia is an AI-native MMORPG combining classic fantasy MMORPG gameplay with AI technology and Solana blockchain integration." \ --category "games" echo "" echo "✅ Release NFT created!"