Compare commits

..

No commits in common. "89164bf83dd2167a324dd0db5aa7f7c4688eaa7c56c99326fa2d83f08efeb825" and "a14be66890fdcddff509a8c1c04e07afcf312db91ae53b71bc22fce6085277f3" have entirely different histories.

5 changed files with 1 additions and 324 deletions

View file

@ -25,7 +25,6 @@ import {
} from "../../services/game/location.js"; } from "../../services/game/location.js";
import { getLevel } from "../../services/game/entity.js"; import { getLevel } from "../../services/game/entity.js";
import { import {
fightEntity,
getFullItemName, getFullItemName,
getTotalStats, getTotalStats,
type IEntity, type IEntity,
@ -80,10 +79,6 @@ const registerModuleGame = (
startConditions: [`${gamePrefix} entity `], startConditions: [`${gamePrefix} entity `],
callbackFunc: onEntity, callbackFunc: onEntity,
}); });
callbackStore.messageCallbacks.push({
startConditions: [`${gamePrefix} fight `],
callbackFunc: onFight,
});
}; };
const onHelp = (_text: string, roomId: string) => { const onHelp = (_text: string, roomId: string) => {
@ -102,7 +97,7 @@ const onHelp = (_text: string, roomId: string) => {
<li><b>!game entities</b> - Shows entities at your location</li> <li><b>!game entities</b> - Shows entities at your location</li>
<li><b>!game entity {entity}</b> - Shows information about an entity</li> <li><b>!game entity {entity}</b> - Shows information about an entity</li>
<li><b>(WIP) !game talk {entity}</b> - Talk to an entity</li> <li><b>(WIP) !game talk {entity}</b> - Talk to an entity</li>
<li><b>!game fight {entity}</b> - Fight an entity</li> <li><b>(WIP) !game fight {entity}</b> - Fight an entity</li>
<li><b>(WIP) !game work {action}</b> - Start work</li> <li><b>(WIP) !game work {action}</b> - Start work</li>
</ul>`, </ul>`,
); );
@ -348,22 +343,4 @@ const onEntity = (text: string, roomId: string, sender: string) => {
onStatusName(roomId, entity.name); onStatusName(roomId, entity.name);
}; };
const onFight = (text: string, roomId: string, sender: string) => {
const player = getPlayer(sender);
const entityName = text.replace(`${gamePrefix} entity `, "").trim();
if (!existsEntity(entityName)) {
client.sendTextMessage(roomId, "No such entity exists");
return;
}
const entity = getEntityByName(entityName);
if (!entitiesShareLocation(player, entity)) {
client.sendTextMessage(roomId, "No such entity in your vicinity");
return;
}
fightEntity(client, roomId, player, entity);
};
export { registerModuleGame }; export { registerModuleGame };

View file

@ -1,12 +1,8 @@
import { getUserNameById } from "../../helpers.js"; import { getUserNameById } from "../../helpers.js";
import { state } from "../../store/store.js"; import { state } from "../../store/store.js";
import { import {
Attack,
attackPunch,
attacks,
npcBecky, npcBecky,
npcs, npcs,
type IAttack,
type IEntity, type IEntity,
type INPC, type INPC,
type INPCData, type INPCData,
@ -20,7 +16,6 @@ import { Race, raceHuman, races, type IRace } from "./structures/races.js";
import type { ILevel } from "./types.js"; import type { ILevel } from "./types.js";
const createPlayer = (name: string): IPlayer => ({ const createPlayer = (name: string): IPlayer => ({
isPlayer: true,
name: name, name: name,
description: "", description: "",
race: Race.HUMAN, race: Race.HUMAN,
@ -40,7 +35,6 @@ const createPlayer = (name: string): IPlayer => ({
stealth: 0, stealth: 0,
charisma: 0, charisma: 0,
lockpicking: 0, lockpicking: 0,
attacks: [Attack.PUNCH, Attack.KICK],
}); });
const createNpcData = (npc: INPC): INPCData => ({ const createNpcData = (npc: INPC): INPCData => ({
@ -49,10 +43,6 @@ const createNpcData = (npc: INPC): INPCData => ({
dead: false, dead: false,
}); });
const isPlayer = (entity: IEntity): boolean => {
return "isPlayer" in entity;
};
const existsPlayer = (name: string): boolean => { const existsPlayer = (name: string): boolean => {
return ( return (
state.game.players.find( state.game.players.find(
@ -72,12 +62,6 @@ const existsEntity = (name: string): boolean => {
return existsPlayer(name) || existsNpc(name); return existsPlayer(name) || existsNpc(name);
}; };
const getAttack = (id: Attack): IAttack => {
const attack = attacks.find((attack) => attack.id === id);
return attack ? attack : attackPunch;
};
const getPlayer = (userId: string): IPlayer => { const getPlayer = (userId: string): IPlayer => {
return getPlayerByName(getUserNameById(userId)); return getPlayerByName(getUserNameById(userId));
}; };
@ -192,11 +176,9 @@ const getSpeed = (entity: IEntity) => {
export { export {
createPlayer, createPlayer,
createNpcData, createNpcData,
isPlayer,
existsPlayer, existsPlayer,
existsNpc, existsNpc,
existsEntity, existsEntity,
getAttack,
getPlayer, getPlayer,
getPlayerByName, getPlayerByName,
getEntityByName, getEntityByName,

View file

@ -1,160 +0,0 @@
import type { MatrixClient } from "matrix-js-sdk";
import type {
Attack,
IEntity,
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";
const fightEntity = async (
client: MatrixClient,
roomId: string,
attacker: IPlayer | TFullNPC,
defender: IPlayer | TFullNPC,
) => {
let attackerAttacks: Attack[] = [];
let attackerDamage = 0;
let attackerDefense = 0;
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 = 0;
let defenderDefense = 0;
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;
while (true) {
await sleep(5000);
const attackerWon = fightRound(
client,
roomId,
attackerAttacks,
attackerDamage,
defender,
defenderDefense,
);
if (attackerWon) {
winner = attacker;
loser = defender;
break;
}
const defenderWon = fightRound(
client,
roomId,
defenderAttacks,
defenderDamage,
attacker,
attackerDefense,
);
if (defenderWon) {
winner = defender;
loser = attacker;
break;
}
}
client.sendTextMessage(
roomId,
`${attacker.name} has won the fight against ${defender.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,
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) {
const msg = getRandomAttackMessage(
defender.health <= -getMaxHealth(defender)
? attackerAttackInfo.messagesOverpower
: attackerAttackInfo.messagesDead,
);
client.sendTextMessage(roomId, msg);
return true;
}
const msg = getRandomAttackMessage(attackerAttackInfo.messages);
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 };

View file

@ -1,7 +1,6 @@
import { Location } from "./locations.js"; import { Location } from "./locations.js";
import { Race } from "./races.js"; import { Race } from "./races.js";
import type { IInventory } from "../types.js"; import type { IInventory } from "../types.js";
import { DamageType } from "./items.js";
export interface IEntity { export interface IEntity {
name: string; name: string;
@ -20,11 +19,9 @@ export interface IEntity {
stealth: number; stealth: number;
charisma: number; charisma: number;
lockpicking: number; lockpicking: number;
attacks: Attack[];
} }
export interface IPlayer extends IEntity { export interface IPlayer extends IEntity {
isPlayer: true;
health: number; health: number;
} }
@ -52,120 +49,6 @@ export enum NpcType {
AGGRESIVE = "AGGRESIVE", AGGRESIVE = "AGGRESIVE",
} }
export interface IAttack {
id: Attack;
damageType: DamageType;
damageMultiplier: number;
messages: string[];
messagesDead: string[];
messagesOverpower: string[];
}
export enum Attack {
PUNCH = "PUNCH",
CUT = "CUT",
STAB = "STAB",
KICK = "KICK",
STOMP = "STOMP",
SIT = "SIT",
RIP = "RIP",
}
export const attackPunch: IAttack = {
id: Attack.PUNCH,
damageType: DamageType.PHYSICAL,
damageMultiplier: 0.5,
messages: ["ATTACKER punches DEFENDER"],
messagesDead: [
"ATTACKER punches DEFENDER to death",
"ATTACKER beats DEFENDER to death",
],
messagesOverpower: ["ATTACKER punches DEFENDER into mush"],
};
export const attackCut: IAttack = {
id: Attack.CUT,
damageType: DamageType.PHYSICAL,
damageMultiplier: 1,
messages: ["ATTACKER cuts DEFENDER"],
messagesDead: [
"ATTACKER cuts DEFENDER in half",
"ATTACKER cuts DEFENDER's head off",
"ATTACKER cuts DEFENDER, instantly killing them",
],
messagesOverpower: ["ATTACKER cuts DEFENDER in half"],
};
export const attackStab: IAttack = {
id: Attack.STAB,
damageType: DamageType.PHYSICAL,
damageMultiplier: 1.5,
messages: ["ATTACKER stabs DEFENDER"],
messagesDead: [
"ATTACKER stabs DEFENDER to death",
"ATTACKER stabs DEFENDER, instantly killing them",
],
messagesOverpower: ["ATTACKER stabs DEFENDER, instantly killing them"],
};
export const attackKick: IAttack = {
id: Attack.KICK,
damageType: DamageType.PHYSICAL,
damageMultiplier: 0.75,
messages: [
"ATTACKER kick DEFENDER",
"ATTACKER kick DEFENDER in their face",
],
messagesDead: ["ATTACKER kicks DEFENDER to death"],
messagesOverpower: ["ATTACKER kicks DEFENDER into mush"],
};
export const attackStomp: IAttack = {
id: Attack.STOMP,
damageType: DamageType.PHYSICAL,
damageMultiplier: 0.75,
messages: [
"ATTACKER stomps DEFENDER",
"ATTACKER stomps DEFENDER in their face",
],
messagesDead: ["ATTACKER stomps DEFENDER to death"],
messagesOverpower: [
"ATTACKER stomps DEFENDER into mush",
"DEFENDER explodes after ATTACKER stomps them into bloody mush",
],
};
export const attackSit: IAttack = {
id: Attack.SIT,
damageType: DamageType.PHYSICAL,
damageMultiplier: 0.65,
messages: ["ATTACKER sits on DEFENDER"],
messagesDead: ["ATTACKER sits on DEFENDER and crushes them to death"],
messagesOverpower: [
"ATTACKER sits on DEFENDER and crushes them into mush and goo",
"DEFENDER explodes after ATTACKER sits on them with their full weight",
],
};
export const attackRip: IAttack = {
id: Attack.RIP,
damageType: DamageType.PHYSICAL,
damageMultiplier: 0.3,
messages: ["ATTACKER tries to rip DEFENDER's limbs off"],
messagesDead: ["ATTACKER rips DEFENDER's head off"],
messagesOverpower: ["ATTACKER effortlessly rips DEFENDER's body in half"],
};
export const attacks = [
attackPunch,
attackCut,
attackStab,
attackKick,
attackStomp,
attackSit,
attackRip,
];
export const npcBecky: INPC = { export const npcBecky: INPC = {
id: NPC.BECKY, id: NPC.BECKY,
name: "Becky", name: "Becky",
@ -187,7 +70,6 @@ export const npcBecky: INPC = {
charisma: 5, charisma: 5,
lockpicking: 50, lockpicking: 50,
type: NpcType.QUEST_GIVER, type: NpcType.QUEST_GIVER,
attacks: [Attack.KICK, Attack.STOMP, Attack.SIT, Attack.RIP],
}; };
export const npcTato: INPC = { export const npcTato: INPC = {
@ -211,7 +93,6 @@ export const npcTato: INPC = {
charisma: 20, charisma: 20,
lockpicking: 0, lockpicking: 0,
type: NpcType.QUEST_GIVER, type: NpcType.QUEST_GIVER,
attacks: [Attack.PUNCH],
}; };
export const npcs = [npcBecky, npcTato]; export const npcs = [npcBecky, npcTato];

View file

@ -1,4 +1,3 @@
import { Attack } from "./entities.js";
import { Rarity } from "./rarities.js"; import { Rarity } from "./rarities.js";
export interface IItem { export interface IItem {
@ -9,7 +8,6 @@ export interface IItem {
type: ItemType; type: ItemType;
rarity: Rarity; rarity: Rarity;
stats: IStat[]; stats: IStat[];
attacks: Attack[];
} }
export interface IStat { export interface IStat {
@ -58,5 +56,4 @@ export const itemShortsword: IItem = {
defense: 0, defense: 0,
}, },
], ],
attacks: [Attack.CUT, Attack.STAB],
}; };