feat: integrate combat system with equipment and HP persistence

- Refactored combat mechanics to utilize player equipment stats for damage and defense calculations.
- Implemented a system to track player HP across combat encounters, including regeneration rules upon defeat.
- Enhanced tool management by introducing a logging system for tool breaks, allowing players to view recent tool usage and breakage events.
- Added commands for viewing combat history and tool break logs, providing players with insights into their performance.
- Updated various game commands to utilize new formatting functions for combat summaries and tool information.
- Introduced a new mob data structure to define mob characteristics and scaling based on area levels.
This commit is contained in:
2025-10-09 00:44:30 -05:00
parent b66379d790
commit 2befd4a278
12 changed files with 684 additions and 202 deletions

View File

@@ -19,6 +19,7 @@ import {
dividerBlock,
textBlock,
} from "../../../core/lib/componentsV2";
import { formatToolLabel, combatSummaryRPG } from "../../../game/lib/rpgFormat";
import { buildAreaMetadataBlocks } from "./_helpers";
const FIGHT_ACCENT = 0x992d22;
@@ -115,54 +116,37 @@ export const command: CommandMessage = {
const mobsLines = result.mobs.length
? result.mobs.map((m) => `${m}`).join("\n")
: "• —";
const durabilityBar = () => {
if (
!result.tool ||
result.tool.remaining == null ||
result.tool.max == null
)
return "";
const rem = Math.max(0, result.tool.remaining);
const max = Math.max(1, result.tool.max);
const ratio = rem / max;
const totalSegs = 10;
const filled = Math.round(ratio * totalSegs);
const bar = Array.from({ length: totalSegs })
.map((_, i) => (i < filled ? "█" : "░"))
.join("");
return `\nDurabilidad: [${bar}] ${rem}/${max}`;
};
const toolInfo = result.tool?.key
? (() => {
const base = formatItemLabel(
? formatToolLabel({
key: result.tool.key,
displayName: formatItemLabel(
rewardItems.get(result.tool.key) ?? {
key: result.tool.key,
name: null,
icon: null,
},
{ fallbackIcon: "🗡️" }
);
if (result.tool.broken)
return `${base} (agotada)${durabilityBar()}`;
if (result.tool.brokenInstance)
return `${base} (se rompió una instancia, quedan ${
result.tool.instancesRemaining
}) (-${result.tool.durabilityDelta ?? 0} dur.)${durabilityBar()}`;
const multi =
result.tool.instancesRemaining &&
result.tool.instancesRemaining > 1
? ` (x${result.tool.instancesRemaining})`
: "";
return `${base}${multi} (-${
result.tool.durabilityDelta ?? 0
} dur.)${durabilityBar()}`;
})()
),
instancesRemaining: result.tool.instancesRemaining,
broken: result.tool.broken,
brokenInstance: result.tool.brokenInstance,
durabilityDelta: result.tool.durabilityDelta,
remaining: result.tool.remaining,
max: result.tool.max,
source: result.tool.toolSource,
})
: "—";
const combatSummary = (() => {
if (!result.combat) return null;
const c = result.combat;
return `**Combate**\n• Mobs: ${c.mobs.length} | Derrotados: ${c.mobsDefeated}/${result.mobs.length}\n• Daño hecho: ${c.totalDamageDealt} | Daño recibido: ${c.totalDamageTaken}`;
})();
const combatSummary = result.combat
? combatSummaryRPG({
mobs: result.mobs.length,
mobsDefeated: result.combat.mobsDefeated,
totalDamageDealt: result.combat.totalDamageDealt,
totalDamageTaken: result.combat.totalDamageTaken,
playerStartHp: result.combat.playerStartHp,
playerEndHp: result.combat.playerEndHp,
outcome: result.combat.outcome,
})
: null;
const blocks = [textBlock("# ⚔️ Arena")];