187 lines
5.2 KiB
TypeScript
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 };
|