aslobot-matrix/src/services/game/game.ts
2026-01-23 11:15:33 -05:00

187 lines
5.2 KiB
TypeScript

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 };