mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-22 19:58:05 +00:00
docs(npc): Apply codebase-verified corrections to hostile NPC plans
Apply critical corrections based on actual codebase verification: CORRECTIONS.md (Updated): - ✅ Confirms #exit_conversation tag ALREADY IMPLEMENTED * Location: person-chat-minigame.js line 537 * No handler needed in chat-helpers.js - ❌ Hostile tag still needs implementation in chat-helpers.js - Provides exact code for hostile tag handler - Clarifies tag format: #hostile:npcId or #hostile (uses current NPC) - Updated action items to reflect what's already working INTEGRATION_UPDATES.md (New): - Comprehensive correction document - Issue 1 Corrected: Exit conversation already works - Issue 6 Corrected: Punch mechanics are interaction-based with AOE - Details interaction-based punch targeting: * Player clicks hostile NPC OR presses 'E' nearby * Punch animation plays in facing direction * Damage applies to ALL NPCs in range + direction (AOE) * Can hit multiple enemies if grouped (strategic gameplay) - Provides complete implementation examples - Removes complexity of target selection systems - Uses existing interaction patterns quick_start.md (Updated): - Removed exit_conversation handler (already exists) - Updated hostile tag handler code - Added punch mechanics design section - Clarified interaction-based targeting - Added troubleshooting for exit_conversation Key Findings: ✅ Exit conversation tag works out of the box ✅ Punch targeting uses existing interaction system (simpler!) ✅ AOE punch adds strategic depth without complexity ❌ Only ONE critical task remains: Add hostile tag to chat-helpers.js Impact: - Less work required (don't need exit_conversation handler) - Simpler implementation (use existing interaction patterns) - Better gameplay (AOE punches, directional attacks) - Clear path forward with exact code examples
This commit is contained in:
@@ -35,6 +35,70 @@ The `#exit_conversation` tag tells the game engine to close the conversation UI,
|
||||
|
||||
---
|
||||
|
||||
## Exit Conversation Tag - Already Implemented ✅
|
||||
|
||||
**Good News**: The `#exit_conversation` tag is **already handled** in the codebase.
|
||||
|
||||
**Location**: `/js/minigames/person-chat/person-chat-minigame.js` line 537:
|
||||
```javascript
|
||||
const shouldExit = result?.tags?.some(tag => tag.includes('exit_conversation'));
|
||||
```
|
||||
|
||||
When this tag is detected, the minigame:
|
||||
1. Shows the NPC's final response
|
||||
2. Schedules the conversation to close
|
||||
3. Saves the NPC conversation state
|
||||
4. Exits the minigame
|
||||
|
||||
**No additional handler needed** for `#exit_conversation` - it works out of the box.
|
||||
|
||||
---
|
||||
|
||||
## Hostile Tag - Needs Implementation ❌
|
||||
|
||||
**Required**: The `#hostile` tag needs to be added to the tag processing system.
|
||||
|
||||
**Location**: `/js/minigames/helpers/chat-helpers.js`
|
||||
|
||||
**Where to Add**: In the `processGameActionTags()` function switch statement (around line 60), add:
|
||||
|
||||
```javascript
|
||||
case 'hostile': {
|
||||
const npcId = param || window.currentConversationNPCId;
|
||||
|
||||
if (!npcId) {
|
||||
result.message = '⚠️ hostile tag missing NPC ID';
|
||||
console.warn(result.message);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`🔴 Processing hostile tag for NPC: ${npcId}`);
|
||||
|
||||
// Set NPC to hostile state
|
||||
if (window.npcHostileSystem) {
|
||||
window.npcHostileSystem.setNPCHostile(npcId, true);
|
||||
result.success = true;
|
||||
result.message = `⚠️ ${npcId} is now hostile!`;
|
||||
} else {
|
||||
result.message = '⚠️ Hostile system not initialized';
|
||||
console.warn(result.message);
|
||||
}
|
||||
|
||||
// Emit event for other systems
|
||||
if (window.eventDispatcher) {
|
||||
window.eventDispatcher.emit('npc_became_hostile', { npcId });
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
**Tag Format**:
|
||||
- `#hostile:npcId` - Make specific NPC hostile
|
||||
- `#hostile` - Make current conversation NPC hostile (uses `window.currentConversationNPCId`)
|
||||
|
||||
---
|
||||
|
||||
## Files Needing Correction
|
||||
|
||||
### 1. implementation_plan.md
|
||||
@@ -85,25 +149,27 @@ Goodbye!
|
||||
```ink
|
||||
=== test_hostile ===
|
||||
# speaker:test_npc
|
||||
This will trigger hostile mode!
|
||||
Triggering hostile state for security guard!
|
||||
Watch out - they're coming for you!
|
||||
# hostile:security_guard
|
||||
# exit_conversation
|
||||
-> hub
|
||||
|
||||
=== test_exit ===
|
||||
# speaker:test_npc
|
||||
This will exit cleanly.
|
||||
Exiting the conversation cleanly.
|
||||
Goodbye, and good luck!
|
||||
# exit_conversation
|
||||
-> hub
|
||||
```
|
||||
|
||||
Note: The dialogue "You should now be in combat" and "Goodbye!" should come BEFORE the `#exit_conversation` tag, as the conversation closes when that tag is processed.
|
||||
**Note**: The dialogue should come BEFORE the `#exit_conversation` tag, as the conversation closes when that tag is processed. Text after the tag won't be shown.
|
||||
|
||||
---
|
||||
|
||||
### 3. implementation_roadmap.md
|
||||
|
||||
**Phase 7.2 section** - May reference similar patterns. Should be reviewed for consistency.
|
||||
**Phase 7.2 section** - References exit_conversation tag handler needing to be added. This should be removed since it already exists.
|
||||
|
||||
---
|
||||
|
||||
@@ -248,19 +314,21 @@ Goodbye, and good luck!
|
||||
## Summary of Corrections
|
||||
|
||||
1. **Never use `-> END`** - Always use `-> hub`
|
||||
2. **Exit pattern**: `# exit_conversation` followed by `-> hub`
|
||||
2. **Exit pattern**: `# exit_conversation` followed by `-> hub` (already works!)
|
||||
3. **Hostile pattern**: `# hostile:npcId` + `# exit_conversation` + `-> hub`
|
||||
4. **Hub pattern**: All conversation paths eventually return to hub
|
||||
5. **Multiple exits**: A conversation can have multiple exit points, all using the same pattern
|
||||
6. **Exit conversation already implemented**: No need to add handler, it already exists in person-chat-minigame.js
|
||||
|
||||
---
|
||||
|
||||
## Why This Pattern?
|
||||
|
||||
From analyzing `helper-npc.ink`:
|
||||
From analyzing `helper-npc.ink` and `person-chat-minigame.js`:
|
||||
|
||||
- The hub acts as a central conversation state
|
||||
- `#exit_conversation` is a **tag** that tells the game engine to close the UI
|
||||
- This tag is **already detected** in person-chat-minigame.js
|
||||
- The Ink story still needs to resolve to a valid state (the hub)
|
||||
- Returning to hub after exit means the NPC state is properly saved
|
||||
- If player talks to NPC again, conversation starts at `start` knot, not hub
|
||||
@@ -275,11 +343,13 @@ When implementing:
|
||||
1. ✅ Read this corrections document first
|
||||
2. ✅ Never use `-> END` in any Ink file
|
||||
3. ✅ Follow the corrected patterns above
|
||||
4. ✅ Test each conversation path thoroughly
|
||||
5. ✅ Verify `#exit_conversation` closes the UI
|
||||
6. ✅ Verify returning to hub doesn't cause issues
|
||||
7. ✅ Update security-guard.ink according to recommendations
|
||||
8. ✅ Create test-hostile.ink with corrected pattern
|
||||
4. ❌ **Don't add** exit_conversation handler - it already exists!
|
||||
5. ✅ **Do add** hostile tag handler to chat-helpers.js
|
||||
6. ✅ Test each conversation path thoroughly
|
||||
7. ✅ Verify `#exit_conversation` closes the UI (should work already)
|
||||
8. ✅ Verify returning to hub doesn't cause issues
|
||||
9. ✅ Update security-guard.ink according to recommendations
|
||||
10. ✅ Create test-hostile.ink with corrected pattern
|
||||
|
||||
---
|
||||
|
||||
@@ -287,6 +357,8 @@ When implementing:
|
||||
|
||||
- **Good Example**: `/scenarios/ink/helper-npc.ink` - Perfect hub pattern usage
|
||||
- **Needs Fixing**: `/scenarios/ink/security-guard.ink` - Has 8 `-> END` instances
|
||||
- **Exit Tag Implementation**: `/js/minigames/person-chat/person-chat-minigame.js` line 537
|
||||
- **Tag Processing**: `/js/minigames/helpers/chat-helpers.js` - Add hostile case here
|
||||
- **Pattern Source**: Lines 68-71 of `helper-npc.ink`:
|
||||
```ink
|
||||
+ [Thanks, I'm good for now.]
|
||||
|
||||
489
planning_notes/npc/hostile/review2/INTEGRATION_UPDATES.md
Normal file
489
planning_notes/npc/hostile/review2/INTEGRATION_UPDATES.md
Normal file
@@ -0,0 +1,489 @@
|
||||
# Integration Review Updates - Critical Corrections
|
||||
|
||||
## Date: 2025-11-14
|
||||
|
||||
This document contains critical corrections to the integration review based on codebase verification.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Issue 1 CORRECTION: Exit Conversation Tag Already Implemented
|
||||
|
||||
**Original Assessment**: Missing tag handler for `#exit_conversation`
|
||||
|
||||
**Actual State**: ✅ **ALREADY IMPLEMENTED**
|
||||
|
||||
**Location**: `/js/minigames/person-chat/person-chat-minigame.js` line 537
|
||||
|
||||
**Implementation**:
|
||||
```javascript
|
||||
const shouldExit = result?.tags?.some(tag => tag.includes('exit_conversation'));
|
||||
```
|
||||
|
||||
**What It Does**:
|
||||
When `#exit_conversation` tag is detected in Ink story tags:
|
||||
1. Shows the NPC's final response
|
||||
2. Schedules the conversation to close after a delay
|
||||
3. Saves the NPC conversation state
|
||||
4. Exits the person-chat minigame
|
||||
|
||||
**Impact on Planning**:
|
||||
- ❌ **Don't** add exit_conversation handler to chat-helpers.js (not needed!)
|
||||
- ✅ **Do** continue using `#exit_conversation` in Ink files (it works!)
|
||||
- ✅ **Do** always follow `#exit_conversation` with `-> hub` in Ink
|
||||
|
||||
**Revised Critical Issues**:
|
||||
Only **ONE** critical issue remains:
|
||||
1. ✅ Add hostile tag handler to chat-helpers.js
|
||||
|
||||
---
|
||||
|
||||
## ✅ Issue 6 CORRECTION: Punch Mechanics Already Designed
|
||||
|
||||
**Original Assessment**: Multiple hostile NPCs targeting logic not designed
|
||||
|
||||
**Actual Design**: ✅ **INTERACTION-BASED WITH AOE DAMAGE**
|
||||
|
||||
**How It Works**:
|
||||
|
||||
### Step 1: Initiate Punch via Interaction
|
||||
Player initiates punch by **interacting** with any hostile NPC:
|
||||
- **Click** on hostile NPC sprite
|
||||
- **Press 'E'** when near hostile NPC
|
||||
|
||||
This interaction targets the specific NPC to initiate the punch action.
|
||||
|
||||
### Step 2: Punch Animation Plays
|
||||
- Player character plays punch animation (walk + red tint placeholder)
|
||||
- Animation duration: 500ms (configurable)
|
||||
- Player facing direction determines attack direction
|
||||
|
||||
### Step 3: Damage Application (AOE)
|
||||
When punch animation completes, damage applies to:
|
||||
- **All NPCs** in punch range (default 60 pixels)
|
||||
- **In the player's facing direction** (directional attack)
|
||||
|
||||
This creates an **area-of-effect (AOE) punch** that can hit multiple enemies if they're grouped together.
|
||||
|
||||
### Example Scenarios
|
||||
|
||||
**Scenario A: Single Hostile NPC**
|
||||
1. Player clicks on hostile NPC or presses 'E' nearby
|
||||
2. Punch animation plays
|
||||
3. If NPC still in range + direction when animation completes → takes damage
|
||||
4. If NPC moved away → miss
|
||||
|
||||
**Scenario B: Multiple Hostile NPCs Grouped**
|
||||
1. Player clicks on one hostile NPC or presses 'E'
|
||||
2. Punch animation plays in facing direction
|
||||
3. All hostile NPCs within punch range AND in facing direction take damage
|
||||
4. Potential to damage 2-3 NPCs with one punch if they're close together
|
||||
|
||||
**Scenario C: NPC Behind Player**
|
||||
1. Player has NPC in front and one behind
|
||||
2. Player faces forward and clicks front NPC
|
||||
3. Punch animation plays facing forward
|
||||
4. Only front NPC takes damage (directional check)
|
||||
5. NPC behind is not in facing direction → no damage
|
||||
|
||||
### Implementation Details
|
||||
|
||||
**In interactions.js**:
|
||||
```javascript
|
||||
function checkHostileNPCInteractions() {
|
||||
// Find hostile NPCs player can interact with (click or 'E' key)
|
||||
const nearbyHostileNPCs = getHostileNPCsInInteractionRange();
|
||||
|
||||
// Highlight/indicate which NPCs are interactable
|
||||
for (const npc of nearbyHostileNPCs) {
|
||||
// Show punch cursor or interaction indicator
|
||||
showPunchIndicator(npc);
|
||||
}
|
||||
}
|
||||
|
||||
// When player clicks NPC or presses 'E'
|
||||
function onPlayerInteractWithHostileNPC(npc) {
|
||||
if (window.playerCombat?.canPlayerPunch()) {
|
||||
window.playerCombat.playerPunch(npc);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**In player-combat.js**:
|
||||
```javascript
|
||||
export async function playerPunch(targetNPC) {
|
||||
if (!canPlayerPunch()) return;
|
||||
|
||||
// Play punch animation in player's facing direction
|
||||
const direction = getPlayerFacingDirection();
|
||||
await playPlayerPunchAnimation(scene, player, direction);
|
||||
|
||||
// After animation, find ALL NPCs in range + direction
|
||||
const npcsHit = getNPCsInPunchRange(direction);
|
||||
|
||||
// Apply damage to all NPCs hit
|
||||
for (const npc of npcsHit) {
|
||||
window.npcHostileSystem.damageNPC(npc.id, COMBAT_CONFIG.player.punchDamage);
|
||||
// Show feedback
|
||||
window.damageNumbers?.show(npc.sprite.x, npc.sprite.y, damage);
|
||||
flashSprite(npc.sprite);
|
||||
}
|
||||
|
||||
startPunchCooldown();
|
||||
}
|
||||
|
||||
function getNPCsInPunchRange(facing Direction) {
|
||||
const playerPos = { x: window.player.x, y: window.player.y };
|
||||
const punchRange = COMBAT_CONFIG.player.punchRange;
|
||||
|
||||
return getHostileNPCsInRoom()
|
||||
.filter(npc => {
|
||||
// Check distance
|
||||
const distance = Phaser.Math.Distance.Between(
|
||||
playerPos.x, playerPos.y,
|
||||
npc.sprite.x, npc.sprite.y
|
||||
);
|
||||
if (distance > punchRange) return false;
|
||||
|
||||
// Check direction (is NPC in front of player?)
|
||||
return isInFacingDirection(playerPos, npc.sprite, facingDirection);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits of This Design**:
|
||||
1. **Intuitive**: Player targets specific NPC by clicking/interacting
|
||||
2. **Strategic**: Can hit multiple enemies if positioned well
|
||||
3. **Directional**: Can't hit enemies behind you
|
||||
4. **Existing Pattern**: Uses existing interaction system (click or 'E' key)
|
||||
|
||||
**Impact on Planning**:
|
||||
- ❌ **Don't** need tab-cycling or closest-target selection
|
||||
- ❌ **Don't** need complex targeting UI
|
||||
- ✅ **Do** use existing interaction system (checkObjectInteractions)
|
||||
- ✅ **Do** implement directional range check
|
||||
- ✅ **Do** support multi-target damage (AOE punch)
|
||||
|
||||
**No changes needed** to target selection plan - the design is solid and uses existing patterns!
|
||||
|
||||
---
|
||||
|
||||
## Revised Critical Prerequisites
|
||||
|
||||
### Before Phase 0:
|
||||
|
||||
**Only ONE critical task**:
|
||||
1. ✅ Add hostile tag handler to `/js/minigames/helpers/chat-helpers.js`
|
||||
|
||||
**Already working** (no action needed):
|
||||
- ✅ Exit conversation tag (already in person-chat-minigame.js)
|
||||
- ✅ Interaction system for punch targeting (already exists)
|
||||
|
||||
### Phase 0 Foundation:
|
||||
|
||||
**Update chat-helpers.js**:
|
||||
```javascript
|
||||
// Add this case to the switch statement in processGameActionTags()
|
||||
case 'hostile': {
|
||||
const npcId = param || window.currentConversationNPCId;
|
||||
|
||||
if (!npcId) {
|
||||
result.message = '⚠️ hostile tag missing NPC ID';
|
||||
console.warn(result.message);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`🔴 Processing hostile tag for NPC: ${npcId}`);
|
||||
|
||||
// Set NPC to hostile state
|
||||
if (window.npcHostileSystem) {
|
||||
window.npcHostileSystem.setNPCHostile(npcId, true);
|
||||
result.success = true;
|
||||
result.message = `⚠️ ${npcId} is now hostile!`;
|
||||
} else {
|
||||
result.message = '⚠️ Hostile system not initialized';
|
||||
console.warn(result.message);
|
||||
}
|
||||
|
||||
// Emit event
|
||||
if (window.eventDispatcher) {
|
||||
window.eventDispatcher.emit('npc_became_hostile', { npcId });
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
**Test the hostile tag**:
|
||||
1. Create test Ink file with `#hostile:security_guard` tag
|
||||
2. Talk to test NPC in game
|
||||
3. Choose option that triggers hostile tag
|
||||
4. Verify in console: "🔴 Processing hostile tag for NPC: security_guard"
|
||||
5. Verify conversation closes
|
||||
6. Verify security guard becomes hostile (once hostile system implemented)
|
||||
|
||||
---
|
||||
|
||||
## Revised Phase 5: Combat Mechanics
|
||||
|
||||
### Player Combat - Interaction-Based AOE Punch
|
||||
|
||||
**File**: `/js/systems/player-combat.js`
|
||||
|
||||
**Key Implementation**:
|
||||
```javascript
|
||||
// Called when player interacts with hostile NPC (click or 'E' key)
|
||||
export async function playerPunch(initiatingNPC) {
|
||||
if (!canPlayerPunch()) return;
|
||||
|
||||
// Get player facing direction
|
||||
const direction = getPlayerFacingDirection();
|
||||
|
||||
// Play punch animation
|
||||
await playPlayerPunchAnimation(scene, window.player, direction);
|
||||
|
||||
// Find ALL NPCs in punch range + facing direction
|
||||
const npcsInRange = getNPCsInPunchRange(direction);
|
||||
|
||||
if (npcsInRange.length > 0) {
|
||||
// HIT - damage all NPCs in range
|
||||
for (const npc of npcsInRange) {
|
||||
const damage = COMBAT_CONFIG.player.punchDamage;
|
||||
|
||||
window.npcHostileSystem.damageNPC(npc.id, damage);
|
||||
window.combatSounds?.playHit();
|
||||
|
||||
// Visual feedback per NPC
|
||||
flashSprite(npc.sprite, 0xffffff, 100);
|
||||
shakeSprite(npc.sprite, 5, 100);
|
||||
window.damageNumbers?.show(npc.sprite.x, npc.sprite.y - 20, damage, false, false);
|
||||
}
|
||||
} else {
|
||||
// MISS
|
||||
window.combatSounds?.playMiss();
|
||||
window.damageNumbers?.show(
|
||||
initiatingNPC.sprite.x,
|
||||
initiatingNPC.sprite.y - 20,
|
||||
0,
|
||||
false,
|
||||
true // isMiss
|
||||
);
|
||||
}
|
||||
|
||||
startPunchCooldown();
|
||||
}
|
||||
|
||||
function getNPCsInPunchRange(facingDirection) {
|
||||
const playerPos = { x: window.player.x, y: window.player.y };
|
||||
const punchRange = COMBAT_CONFIG.player.punchRange;
|
||||
|
||||
return getNPCsInRoom(window.currentRoom)
|
||||
.filter(npc => {
|
||||
// Only hostile, non-KO NPCs
|
||||
if (!window.npcHostileSystem?.isNPCHostile(npc.id)) return false;
|
||||
if (window.npcHostileSystem?.isNPCKO(npc.id)) return false;
|
||||
|
||||
// Check distance
|
||||
const distance = Phaser.Math.Distance.Between(
|
||||
playerPos.x, playerPos.y,
|
||||
npc.sprite.x, npc.sprite.y
|
||||
);
|
||||
if (distance > punchRange) return false;
|
||||
|
||||
// Check if NPC is in facing direction
|
||||
return isInFacingDirection(
|
||||
playerPos,
|
||||
{ x: npc.sprite.x, y: npc.sprite.y },
|
||||
facingDirection,
|
||||
90 // degrees tolerance (45° on each side)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function isInFacingDirection(origin, target, direction, tolerance = 90) {
|
||||
// Calculate angle from origin to target
|
||||
const angle = Phaser.Math.Angle.Between(
|
||||
origin.x, origin.y,
|
||||
target.x, target.y
|
||||
);
|
||||
|
||||
// Convert direction to angle
|
||||
const directionAngles = {
|
||||
'down': Math.PI / 2, // 90 degrees
|
||||
'up': -Math.PI / 2, // -90 degrees
|
||||
'right': 0, // 0 degrees
|
||||
'left': Math.PI, // 180 degrees
|
||||
'down-right': Math.PI / 4,
|
||||
'down-left': 3 * Math.PI / 4,
|
||||
'up-right': -Math.PI / 4,
|
||||
'up-left': -3 * Math.PI / 4
|
||||
};
|
||||
|
||||
const expectedAngle = directionAngles[direction];
|
||||
const toleranceRad = (tolerance * Math.PI) / 180;
|
||||
|
||||
// Check if angle is within tolerance
|
||||
const angleDiff = Math.abs(Phaser.Math.Angle.Wrap(angle - expectedAngle));
|
||||
return angleDiff <= toleranceRad;
|
||||
}
|
||||
```
|
||||
|
||||
**Benefits**:
|
||||
- Can hit multiple NPCs with one punch if grouped
|
||||
- Directional attack feels natural
|
||||
- Uses existing interaction system
|
||||
- No complex targeting UI needed
|
||||
|
||||
---
|
||||
|
||||
## Revised Phase 7: Integration Points
|
||||
|
||||
### 7.4: Punch Interaction (Corrected)
|
||||
|
||||
**File**: `/js/systems/interactions.js`
|
||||
|
||||
**Integration**:
|
||||
```javascript
|
||||
// Extend existing checkObjectInteractions() to include hostile NPCs
|
||||
function checkObjectInteractions() {
|
||||
// ... existing code for objects and friendly NPCs ...
|
||||
|
||||
// Check for hostile NPC interactions
|
||||
checkHostileNPCInteractions();
|
||||
}
|
||||
|
||||
function checkHostileNPCInteractions() {
|
||||
if (!window.player || window.playerHealth?.isPlayerKO()) return;
|
||||
|
||||
const playerPos = { x: window.player.x, y: window.player.y };
|
||||
const interactionRange = 64; // Existing interaction range
|
||||
|
||||
// Get hostile NPCs in interaction range
|
||||
const nearbyHostileNPCs = getNPCsInRoom(window.currentRoom)
|
||||
.filter(npc => {
|
||||
if (!window.npcHostileSystem?.isNPCHostile(npc.id)) return false;
|
||||
if (window.npcHostileSystem?.isNPCKO(npc.id)) return false;
|
||||
|
||||
const distance = Phaser.Math.Distance.Between(
|
||||
playerPos.x, playerPos.y,
|
||||
npc.sprite.x, npc.sprite.y
|
||||
);
|
||||
|
||||
return distance <= interactionRange;
|
||||
});
|
||||
|
||||
if (nearbyHostileNPCs.length > 0) {
|
||||
// Show punch interaction indicator
|
||||
for (const npc of nearbyHostileNPCs) {
|
||||
// Could show fist icon above NPC, or change cursor, or highlight sprite
|
||||
showPunchInteractionIndicator(npc);
|
||||
}
|
||||
|
||||
// Store for click/E key handling
|
||||
window.currentHostileNPCTargets = nearbyHostileNPCs;
|
||||
} else {
|
||||
window.currentHostileNPCTargets = [];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Click Handler** (in existing click handler):
|
||||
```javascript
|
||||
// When player clicks on hostile NPC
|
||||
this.input.on('pointerdown', (pointer) => {
|
||||
// Check if clicked on hostile NPC
|
||||
const clickedNPC = window.currentHostileNPCTargets?.find(npc =>
|
||||
// Check if click is on NPC sprite bounds
|
||||
isClickOnSprite(pointer, npc.sprite)
|
||||
);
|
||||
|
||||
if (clickedNPC) {
|
||||
// Initiate punch with this NPC
|
||||
if (window.playerCombat?.canPlayerPunch()) {
|
||||
window.playerCombat.playerPunch(clickedNPC);
|
||||
}
|
||||
return; // Don't process other click actions
|
||||
}
|
||||
|
||||
// ... existing click handling for movement, objects, etc. ...
|
||||
});
|
||||
```
|
||||
|
||||
**'E' Key Handler** (add to keyboard input):
|
||||
```javascript
|
||||
// When player presses 'E' key
|
||||
this.input.keyboard.on('keydown-E', () => {
|
||||
// If near hostile NPC, punch instead of normal interaction
|
||||
if (window.currentHostileNPCTargets?.length > 0) {
|
||||
// Punch closest hostile NPC
|
||||
const closestNPC = getClosestNPC(window.currentHostileNPCTargets);
|
||||
if (window.playerCombat?.canPlayerPunch()) {
|
||||
window.playerCombat.playerPunch(closestNPC);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ... existing 'E' key handling for doors, objects, friendly NPCs ...
|
||||
});
|
||||
```
|
||||
|
||||
**Visual Feedback**:
|
||||
- Show fist cursor when hovering over hostile NPC in range
|
||||
- Or: Red outline around punchable hostile NPCs
|
||||
- Or: "Press E to Punch" text above hostile NPC
|
||||
|
||||
---
|
||||
|
||||
## Summary of Corrections
|
||||
|
||||
### What Changed:
|
||||
|
||||
1. **Exit Conversation Tag**: ✅ Already implemented, no work needed
|
||||
2. **Punch Targeting**: ✅ Uses existing interaction system (click or 'E')
|
||||
3. **Punch Damage**: ✅ AOE damage to all NPCs in range + direction
|
||||
|
||||
### What Stays the Same:
|
||||
|
||||
1. **Hostile Tag**: ❌ Still needs to be added to chat-helpers.js
|
||||
2. **Ink Pattern**: All docs still need `-> hub` not `-> END`
|
||||
3. **All other systems**: Compatible as reviewed
|
||||
|
||||
### Impact on Implementation:
|
||||
|
||||
**Less work required**:
|
||||
- Don't need to add exit_conversation handler
|
||||
- Don't need to create complex targeting system
|
||||
- Use existing interaction patterns
|
||||
|
||||
**Simpler integration**:
|
||||
- One critical task (hostile tag handler)
|
||||
- Punch uses existing interaction system
|
||||
- AOE damage is bonus feature, not complexity
|
||||
|
||||
**Better gameplay**:
|
||||
- Punch feels natural (click or 'E' to interact)
|
||||
- Can strategically hit multiple enemies
|
||||
- Directional attacks add tactical depth
|
||||
|
||||
---
|
||||
|
||||
## Updated Quick Start - Phase -1
|
||||
|
||||
**Before implementing anything:**
|
||||
|
||||
1. ✅ Add hostile tag handler to chat-helpers.js (see code above)
|
||||
2. ✅ Fix Ink files to use `-> hub` not `-> END`
|
||||
3. ✅ Test hostile tag with simple Ink file
|
||||
4. ✅ Verify exit_conversation works (should already work!)
|
||||
|
||||
**That's it!** These are the only critical prerequisites.
|
||||
|
||||
Then proceed with Phase 0 as planned.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- **Exit Tag**: `/js/minigames/person-chat/person-chat-minigame.js` line 537
|
||||
- **Tag Processing**: `/js/minigames/helpers/chat-helpers.js` - Add hostile case here
|
||||
- **Interactions**: `/js/systems/interactions.js` - Extend for punch interaction
|
||||
- **Player Combat**: New file - Implement punch with AOE damage
|
||||
@@ -12,27 +12,32 @@ Read these documents in order:
|
||||
|
||||
## Critical Prerequisites (Must Complete First)
|
||||
|
||||
### 1. Add Ink Tag Handlers
|
||||
### 1. Add Hostile Tag Handler
|
||||
|
||||
**File**: `/js/minigames/helpers/chat-helpers.js`
|
||||
|
||||
**Location**: In the `processGameActionTags()` function, add these cases to the switch statement (around line 60):
|
||||
**Location**: In the `processGameActionTags()` function, add this case to the switch statement (around line 60):
|
||||
|
||||
```javascript
|
||||
case 'hostile': {
|
||||
const parts = tag.split(':');
|
||||
const npcId = parts[1] || (ui && ui.npcId);
|
||||
const npcId = param || window.currentConversationNPCId;
|
||||
|
||||
if (!npcId) {
|
||||
console.error('hostile tag missing NPC ID');
|
||||
result.message = '⚠️ hostile tag missing NPC ID';
|
||||
console.warn(result.message);
|
||||
break;
|
||||
}
|
||||
|
||||
console.log(`Processing hostile tag for NPC: ${npcId}`);
|
||||
console.log(`🔴 Processing hostile tag for NPC: ${npcId}`);
|
||||
|
||||
// Set NPC to hostile state
|
||||
if (window.npcHostileSystem) {
|
||||
window.npcHostileSystem.setNPCHostile(npcId, true);
|
||||
result.success = true;
|
||||
result.message = `⚠️ ${npcId} is now hostile!`;
|
||||
} else {
|
||||
result.message = '⚠️ Hostile system not initialized';
|
||||
console.warn(result.message);
|
||||
}
|
||||
|
||||
// Emit event for other systems
|
||||
@@ -40,25 +45,12 @@ case 'hostile': {
|
||||
window.eventDispatcher.emit('npc_became_hostile', { npcId });
|
||||
}
|
||||
|
||||
// Exit conversation after hostile trigger
|
||||
if (ui && typeof ui.exitConversation === 'function') {
|
||||
ui.exitConversation();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'exit_conversation': {
|
||||
console.log('Processing exit_conversation tag');
|
||||
|
||||
if (ui && typeof ui.exitConversation === 'function') {
|
||||
ui.exitConversation();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
```
|
||||
|
||||
**Note on Exit Conversation**: ✅ The `#exit_conversation` tag is **already handled** in `/js/minigames/person-chat/person-chat-minigame.js` line 537. **No additional handler needed!**
|
||||
|
||||
**Test**: Verify with test Ink file before proceeding.
|
||||
|
||||
---
|
||||
@@ -515,13 +507,42 @@ Follow **implementation_roadmap.md** for detailed phase breakdowns.
|
||||
|
||||
---
|
||||
|
||||
## Punch Mechanics Design (For Reference)
|
||||
|
||||
### How Punching Works
|
||||
|
||||
**Initiation** (Interaction-Based):
|
||||
- Player **clicks** on hostile NPC, OR
|
||||
- Player presses **'E' key** when near hostile NPC
|
||||
- Uses existing interaction system
|
||||
|
||||
**Animation**:
|
||||
- Player punch animation plays (walk + red tint, 500ms)
|
||||
- Animation plays in player's facing direction
|
||||
|
||||
**Damage Application** (AOE):
|
||||
- After animation completes, check ALL hostile NPCs
|
||||
- Damage applies to NPCs that are:
|
||||
1. Within punch range (60 pixels default)
|
||||
2. In player's facing direction (90° cone)
|
||||
3. Not already KO'd
|
||||
|
||||
**Result**:
|
||||
- Can hit multiple NPCs with one punch if grouped
|
||||
- Directional attack (can't hit NPCs behind you)
|
||||
- Miss if target moves out of range during animation
|
||||
|
||||
**Implementation Note**: Phase 5 will implement this using existing interaction patterns from interactions.js
|
||||
|
||||
---
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### Issue: "Player health not initialized"
|
||||
**Solution**: Make sure initPlayerHealth() is called in game.js create()
|
||||
|
||||
### Issue: "hostile tag not working"
|
||||
**Solution**: Check that tag handler added to chat-helpers.js and function exported
|
||||
**Solution**: Check that tag handler added to chat-helpers.js with correct case statement
|
||||
|
||||
### Issue: "Events not firing"
|
||||
**Solution**: Verify window.eventDispatcher exists (should be created by NPC system)
|
||||
@@ -532,6 +553,9 @@ Follow **implementation_roadmap.md** for detailed phase breakdowns.
|
||||
### Issue: "NPC not found"
|
||||
**Solution**: Verify NPC exists in scenario and npcManager is initialized
|
||||
|
||||
### Issue: "exit_conversation not working"
|
||||
**Solution**: This should already work! Check /js/minigames/person-chat/person-chat-minigame.js line 537
|
||||
|
||||
---
|
||||
|
||||
## Critical Reminders
|
||||
|
||||
Reference in New Issue
Block a user