diff --git a/src/modules/game/game.ts b/src/modules/game/game.ts
index 9bfafc3..02cbe82 100644
--- a/src/modules/game/game.ts
+++ b/src/modules/game/game.ts
@@ -4,9 +4,13 @@ import { config } from "../../config.js";
import { getPlayerById, getRace } from "../../services/game/entity.js";
import {
getLocation,
+ getLocationByName,
getLocationDistance,
+ getParentLocation,
+ hasLocation,
+ startTravel,
} from "../../services/game/location.js";
-import { getLevel } from "../../services/game/game.js";
+import { getLevel } from "../../services/game/entity.js";
import {
getFullItemName,
getTotalStats,
@@ -44,6 +48,10 @@ const registerModuleGame = (
startConditions: [`${gamePrefix} nearby`],
callbackFunc: onNearby,
});
+ callbackStore.messageCallbacks.push({
+ startConditions: [`${gamePrefix} travel`],
+ callbackFunc: onTravel,
+ });
};
const onHelp = (_text: string, roomId: string) => {
@@ -57,7 +65,7 @@ const onHelp = (_text: string, roomId: string) => {
!game inventory {index} - Shows information about an item in your inventory
!game location - Shows information about your current location
!game nearby - Shows nearby locations
- (WIP) !game travel {location} - Travel to a location
+ !game travel {location} - Travel to a location
(WIP) !game talk {entity} - Talk to an entity
(WIP) !game fight {entity} - Fight an entity
(WIP) !game work {action} - Start work
@@ -193,8 +201,35 @@ const onNearby = (_text: string, roomId: string, sender: string) => {
`There are ${location.childLocations.length} locations around you (${player.name})
${location.childLocations.map(mapLocation).join("\n")}
+ ${getParentLocation(player.location).childLocations.map(mapLocation).join("\n")}
`,
);
};
+const onTravel = (text: string, roomId: string, sender: string) => {
+ const player = getPlayerById(sender);
+
+ const locationName = text.replace(`${gamePrefix} travel `, "").trim();
+ const location = getLocationByName(locationName);
+ if (!location) {
+ client.sendTextMessage(roomId, "No such location exists");
+ return;
+ }
+
+ const currentLocationHasLocation = hasLocation(
+ player.location,
+ location.id,
+ );
+ const parentLocationHasLocation = hasLocation(
+ getParentLocation(player.location).id,
+ location.id,
+ );
+ if (!currentLocationHasLocation && !parentLocationHasLocation) {
+ client.sendTextMessage(roomId, "No such location found nearby");
+ return;
+ }
+
+ startTravel(player, location.id, client, roomId);
+};
+
export { registerModuleGame };
diff --git a/src/services/game/entity.ts b/src/services/game/entity.ts
index 80973e0..185cd00 100644
--- a/src/services/game/entity.ts
+++ b/src/services/game/entity.ts
@@ -1,9 +1,10 @@
import { getUserNameById } from "../../helpers.js";
import { state } from "../../store/store.js";
-import type { IPlayer } from "./structures/entities.js";
+import type { IEntity, IPlayer } from "./structures/entities.js";
import { itemShortsword } from "./structures/items.js";
import { Location } from "./structures/locations.js";
import { Race, raceHuman, races, type IRace } from "./structures/races.js";
+import type { ILevel } from "./types.js";
const createPlayer = (name: string): IPlayer => ({
name: name,
@@ -49,4 +50,27 @@ const getRace = (id: Race): IRace => {
return race ? race : raceHuman;
};
-export { createPlayer, getPlayerById, getPlayer, getRace };
+const getLevel = (experience: number): ILevel => {
+ let tmpExperience = experience;
+ let experienceToNextLevel = 50;
+ let level = 0;
+
+ while (tmpExperience >= experienceToNextLevel) {
+ level++;
+ tmpExperience -= experienceToNextLevel;
+ experienceToNextLevel = experienceToNextLevel *= 1.25;
+ }
+
+ return {
+ level: level,
+ totalExperience: Math.floor(experience),
+ experienceInLevel: Math.floor(tmpExperience),
+ experienceToNextLevel: Math.floor(experienceToNextLevel),
+ };
+};
+
+const getSpeed = (entity: IEntity) => {
+ return 1 + Math.sqrt(entity.agility + entity.endurance) / 3;
+};
+
+export { createPlayer, getPlayerById, getPlayer, getRace, getLevel, getSpeed };
diff --git a/src/services/game/game.ts b/src/services/game/game.ts
index 6e64232..473a0f4 100644
--- a/src/services/game/game.ts
+++ b/src/services/game/game.ts
@@ -1,22 +0,0 @@
-import type { ILevel } from "./types.js";
-
-const getLevel = (experience: number): ILevel => {
- let tmpExperience = experience;
- let experienceToNextLevel = 50;
- let level = 0;
-
- while (tmpExperience >= experienceToNextLevel) {
- level++;
- tmpExperience -= experienceToNextLevel;
- experienceToNextLevel = experienceToNextLevel *= 1.25;
- }
-
- return {
- level: level,
- totalExperience: Math.floor(experience),
- experienceInLevel: Math.floor(tmpExperience),
- experienceToNextLevel: Math.floor(experienceToNextLevel),
- };
-};
-
-export { getLevel };
diff --git a/src/services/game/location.ts b/src/services/game/location.ts
index 9e1b556..b30e890 100644
--- a/src/services/game/location.ts
+++ b/src/services/game/location.ts
@@ -1,9 +1,12 @@
+import type { MatrixClient } from "matrix-js-sdk";
import {
+ Location,
locationFarlands,
locations,
type ILocation,
- type Location,
} from "./structures/locations.js";
+import type { IPlayer } from "./structures/entities.js";
+import { getSpeed } from "./entity.js";
const getLocation = (id: Location): ILocation => {
const location = locations.find((location) => location.id === id);
@@ -11,6 +14,14 @@ const getLocation = (id: Location): ILocation => {
return location ? location : locationFarlands;
};
+const getLocationByName = (name: string): ILocation => {
+ const location = locations.find(
+ (location) => location.name.toLowerCase() === name.toLowerCase(),
+ );
+
+ return location ? location : locationFarlands;
+};
+
const getLocationDistance = (
locationA: ILocation,
locationB: ILocation,
@@ -23,4 +34,62 @@ const getLocationDistance = (
return Math.sqrt(deltaPow);
};
-export { getLocation, getLocationDistance };
+const getParentLocation = (childLocation: Location): ILocation => {
+ const parentLocation = locations.find((location) =>
+ location.childLocations.includes(childLocation),
+ );
+
+ return parentLocation ? parentLocation : locationFarlands;
+};
+
+const hasLocation = (
+ locationParent: Location,
+ locationChild: Location,
+): boolean => {
+ const childLocations = getLocation(locationParent).childLocations;
+
+ return childLocations.includes(locationChild);
+};
+
+const startTravel = (
+ player: IPlayer,
+ location: Location,
+ client: MatrixClient,
+ roomId: string,
+) => {
+ const currentLocation = getLocation(player.location);
+ const newLocation = getLocation(location);
+
+ const distance = getLocationDistance(currentLocation, newLocation);
+
+ setTimeout(
+ () => {
+ finishTravel(player, newLocation, client, roomId);
+ },
+ (distance / getSpeed(player)) * 3600000,
+ );
+};
+
+const finishTravel = (
+ player: IPlayer,
+ location: ILocation,
+ client: MatrixClient,
+ roomId: string,
+) => {
+ player.location = location.id;
+
+ client.sendTextMessage(
+ roomId,
+ `${player.name} has arrived to ${location.name}`,
+ );
+};
+
+export {
+ getLocation,
+ getLocationByName,
+ getLocationDistance,
+ getParentLocation,
+ hasLocation,
+ startTravel,
+ finishTravel,
+};