import type { MatrixClient } from "matrix-js-sdk"; import type { INPC, IPlayer, TFullNPC } from "./structures/entities.js"; import { locationFarlands } from "./structures/locations.js"; import { getAttack, getMaxHealth, getNpcData, isPlayer } from "./entity.js"; import { sleep } from "matrix-js-sdk/lib/utils.js"; import type { Attack } from "./structures/attacks.js"; const fightEntity = async ( client: MatrixClient, roomId: string, attacker: IPlayer | TFullNPC, defender: IPlayer | TFullNPC, ) => { let attackerAttacks: Attack[] = []; let attackerDamage = 10; let attackerDefense = 10; attacker.attacks.forEach((attack) => { attackerAttacks.push(attack); }); attacker.inventory.items.forEach((item) => { item.attacks.forEach((attack) => { attackerAttacks.push(attack); }); item.stats.forEach((stat) => { attackerDamage += stat.damage; attackerDefense += stat.defense; }); }); attackerDamage *= 1 + attacker.strength / 10; attackerDefense *= 1 + attacker.strength / 10; let defenderAttacks: Attack[] = []; let defenderDamage = 10; let defenderDefense = 10; defender.attacks.forEach((attack) => { defenderAttacks.push(attack); }); defender.inventory.items.forEach((item) => { item.attacks.forEach((attack) => { defenderAttacks.push(attack); }); item.stats.forEach((stat) => { defenderDamage += stat.damage; defenderDefense += stat.defense; }); }); defenderDamage *= 1 + defender.strength / 10; defenderDefense *= 1 + defender.strength / 10; let winner: IPlayer | TFullNPC | undefined = undefined; let loser: IPlayer | TFullNPC | undefined = undefined; let round = 0; while (true) { await sleep(3000); round++; client.sendTextMessage(roomId, `Round ${round}`); client.sendTextMessage( roomId, `${attacker.name}: ${attacker.health.toFixed(0)}/${getMaxHealth(attacker)}HP\n${defender.name}: ${defender.health.toFixed(0)}/${getMaxHealth(defender)}HP`, ); await sleep(3000); const attackerWon = fightRound( client, roomId, attacker, attackerAttacks, attackerDamage, defender, defenderDefense, ); if (attackerWon) { winner = attacker; loser = defender; break; } await sleep(3000); const defenderWon = fightRound( client, roomId, defender, defenderAttacks, defenderDamage, attacker, attackerDefense, ); if (defenderWon) { winner = defender; loser = attacker; break; } } client.sendTextMessage( roomId, `${winner.name} has won the fight against ${loser.name}!`, ); if (isPlayer(loser)) { respawnPlayer(client, roomId, loser as IPlayer); } else { const npcData = getNpcData((loser as INPC).id); npcData.dead = true; } }; const fightRound = ( client: MatrixClient, roomId: string, attacker: IPlayer | TFullNPC, attackerAttacks: Attack[], attackerDamage: number, defender: IPlayer | TFullNPC, defenderDefense: number, ): boolean => { const attackerAttack = attackerAttacks[Math.floor(Math.random() * attackerAttacks.length)]; if (!attackerAttack) { return false; } const attackerAttackInfo = getAttack(attackerAttack); const attackerAttackDamage = attackerDamage * attackerAttackInfo.damageMultiplier * (0.5 + Math.random() * 0.5); defender.health -= attackerAttackDamage; if (defender.health <= 0) { let msg = getRandomAttackMessage( defender.health <= -getMaxHealth(defender) ? attackerAttackInfo.messagesOverpower : attackerAttackInfo.messagesDead, ) + ` - Dealing ${attackerAttackDamage.toFixed(0)} damage`; msg = msg.replaceAll("ATTACKER", attacker.name); msg = msg.replaceAll("DEFENDER", defender.name); client.sendTextMessage(roomId, msg); return true; } let msg = getRandomAttackMessage(attackerAttackInfo.messages) + ` - Dealing ${attackerAttackDamage.toFixed(0)} damage`; msg = msg.replaceAll("ATTACKER", attacker.name); msg = msg.replaceAll("DEFENDER", defender.name); client.sendTextMessage(roomId, msg); return false; }; const respawnPlayer = ( client: MatrixClient, roomId: string, player: IPlayer, ) => { const defaultRespawn = locationFarlands; player.location = defaultRespawn.id; player.health = getMaxHealth(player); client.sendTextMessage( roomId, `${player.name} has been respawned in ${defaultRespawn.name}`, ); }; const getRandomAttackMessage = (messages: string[]): string => { return messages[Math.floor(Math.random() * messages.length)] ?? ""; }; export { fightEntity, fightRound, respawnPlayer, getRandomAttackMessage };