Rework behaviors
This commit is contained in:
parent
f6ca90329c
commit
c73a4d2abf
|
@ -17450,7 +17450,10 @@ var TalkomaticBot = class extends import_node_events.EventEmitter {
|
||||||
async start() {
|
async start() {
|
||||||
this.logger.info("Starting");
|
this.logger.info("Starting");
|
||||||
this.client.connect();
|
this.client.connect();
|
||||||
let data = await this.findChannel(this.config.channel.name) || await this.createChannel(this.config.channel.name, "private");
|
let data = await this.findChannel(this.config.channel.name) || await this.createChannel(
|
||||||
|
this.config.channel.name,
|
||||||
|
this.config.channel.type
|
||||||
|
);
|
||||||
this.logger.debug(data);
|
this.logger.debug(data);
|
||||||
if (typeof data !== "undefined") {
|
if (typeof data !== "undefined") {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,32 +1,41 @@
|
||||||
- id: pond
|
- id: pond
|
||||||
name: Pond
|
name: Pond
|
||||||
nearby:
|
nearby:
|
||||||
- lake
|
- lake
|
||||||
- river
|
- river
|
||||||
- sea
|
- sea
|
||||||
|
- shop
|
||||||
hasSand: true
|
hasSand: true
|
||||||
objects: []
|
objects: []
|
||||||
- id: lake
|
- id: lake
|
||||||
name: Lake
|
name: Lake
|
||||||
nearby:
|
nearby:
|
||||||
- pond
|
- pond
|
||||||
- river
|
- river
|
||||||
- sea
|
- sea
|
||||||
hasSand: false
|
hasSand: false
|
||||||
objects: []
|
objects: []
|
||||||
- id: river
|
- id: river
|
||||||
name: River
|
name: River
|
||||||
nearby:
|
nearby:
|
||||||
- pond
|
- pond
|
||||||
- lake
|
- lake
|
||||||
- sea
|
- sea
|
||||||
hasSand: false
|
hasSand: false
|
||||||
objects: []
|
objects: []
|
||||||
- id: sea
|
- id: sea
|
||||||
name: Sea
|
name: Sea
|
||||||
nearby:
|
nearby:
|
||||||
- pond
|
- pond
|
||||||
- lake
|
- lake
|
||||||
- river
|
- river
|
||||||
hasSand: true
|
hasSand: true
|
||||||
objects: []
|
objects: []
|
||||||
|
- id: shop
|
||||||
|
name: Shop
|
||||||
|
nearby:
|
||||||
|
- pond
|
||||||
|
- id: bed # /go sleep?
|
||||||
|
name: Bed
|
||||||
|
nearby:
|
||||||
|
- pond
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
- channel:
|
- channel:
|
||||||
name: test/fishing
|
name: test/fishing
|
||||||
|
type: public
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
interface IBehaviorValidResponse<State> {
|
||||||
|
success: true;
|
||||||
|
|
||||||
|
// shouldRemove: boolean;
|
||||||
|
// and?: string;
|
||||||
|
state: State;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IBehaviorErrorResponse {
|
||||||
|
success: false;
|
||||||
|
err: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type TBehaviorResponse<State> =
|
||||||
|
| IBehaviorValidResponse<State>
|
||||||
|
| IBehaviorErrorResponse;
|
||||||
|
|
||||||
|
type TBehaviorCallback<Context, State> = (
|
||||||
|
context: Context
|
||||||
|
) => Promise<TBehaviorResponse<State>>;
|
||||||
|
type TBehavior<Context, State> = Record<
|
||||||
|
string,
|
||||||
|
TBehaviorCallback<Context, State>
|
||||||
|
>;
|
||||||
|
type TBehaviorMap<Context, State> = Map<string, TBehavior<Context, State>>; //Record<string, TBehavior<C>>;
|
||||||
|
|
||||||
|
type TBehaviorNamespace = string;
|
||||||
|
type TBehaviorAction = keyof IBehaviorContextStateDefinitions;
|
||||||
|
type TBehaviorID = `${TBehaviorNamespace}:${TBehaviorAction}`;
|
||||||
|
|
||||||
|
interface IBehaviorDefinition<Context> {
|
||||||
|
id: string;
|
||||||
|
bhv: TBehavior<Context>;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare interface IBehaviorContextStateDefinitions
|
||||||
|
extends Record<Record<{ context: unknown; state: unknown }>> {
|
||||||
|
eat: {
|
||||||
|
context: {
|
||||||
|
id: string;
|
||||||
|
part: IPart;
|
||||||
|
object: IObject;
|
||||||
|
user: User;
|
||||||
|
};
|
||||||
|
|
||||||
|
state: {
|
||||||
|
shouldRemove: boolean;
|
||||||
|
and?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
yeet: {
|
||||||
|
context: {
|
||||||
|
part: IPart;
|
||||||
|
};
|
||||||
|
|
||||||
|
state: {
|
||||||
|
shouldRemove: boolean;
|
||||||
|
text: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
import { logger } from "@server/commands/handler";
|
||||||
|
|
||||||
|
export const behaviorMap = new Map<string, TBehavior<unknown, unknown>>();
|
||||||
|
|
||||||
|
class BehaviorError extends Error {
|
||||||
|
constructor(...args: string[]) {
|
||||||
|
super(...args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function splitBehaviorID(id: TBehaviorID) {
|
||||||
|
const args = id.split(":");
|
||||||
|
|
||||||
|
if (typeof args[0] == "undefined" || typeof args[1] == "undefined")
|
||||||
|
throw new BehaviorError(
|
||||||
|
"Incomplete behavior ID (should have exactly two segments)"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (typeof args[0] !== "string" || typeof args[1] !== "string")
|
||||||
|
throw new BehaviorError(
|
||||||
|
`Invalid behavior ID (expected: string:string, got: ${typeof args[0]}:${typeof args[1]})`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (typeof args[3] !== "undefined")
|
||||||
|
throw new BehaviorError("Invalid behavior ID: Too many segments");
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerBehavior<
|
||||||
|
K extends keyof IBehaviorContextStateDefinitions,
|
||||||
|
Context = IBehaviorContextStateDefinitions[K]["context"],
|
||||||
|
State = IBehaviorContextStateDefinitions[K]["state"]
|
||||||
|
>(id: TBehaviorID, behavior: TBehaviorCallback<Context, State>) {
|
||||||
|
try {
|
||||||
|
const args = splitBehaviorID(id);
|
||||||
|
const namespace = args[0];
|
||||||
|
const action = args[1];
|
||||||
|
|
||||||
|
if (!behaviorMap.has(namespace)) behaviorMap.set(namespace, {});
|
||||||
|
const set = behaviorMap.get(namespace);
|
||||||
|
if (!set)
|
||||||
|
throw new BehaviorError("Unable to resolve namespace to value");
|
||||||
|
set[action] = behavior as TBehaviorCallback<unknown, unknown>;
|
||||||
|
} catch (err) {
|
||||||
|
if (!(err instanceof BehaviorError)) err = "Unknown error";
|
||||||
|
throw new BehaviorError("Unable to register behavior: " + err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function executeBehavior<
|
||||||
|
K extends keyof IBehaviorContextStateDefinitions,
|
||||||
|
Context = IBehaviorContextStateDefinitions[K]["context"],
|
||||||
|
State = IBehaviorContextStateDefinitions[K]["state"]
|
||||||
|
>(id: TBehaviorID, context: Context): Promise<TBehaviorResponse<State>> {
|
||||||
|
const args = splitBehaviorID(id);
|
||||||
|
const namespace = args[0];
|
||||||
|
const action = args[1];
|
||||||
|
|
||||||
|
const set = behaviorMap.get(namespace);
|
||||||
|
if (!set) throw new BehaviorError("Unable to resolve namespace to value");
|
||||||
|
|
||||||
|
const callback = set[action];
|
||||||
|
|
||||||
|
if (!callback)
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
err: "No callback defined for " + id
|
||||||
|
};
|
||||||
|
|
||||||
|
return (await callback(context)) as TBehaviorResponse<State>;
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
import { addBack } from "@server/backs";
|
||||||
|
import { CosmicColor } from "@util/CosmicColor";
|
||||||
|
import { registerBehavior } from "..";
|
||||||
|
|
||||||
|
registerBehavior<"eat">("burger:eat", async context => {
|
||||||
|
const r = Math.random();
|
||||||
|
|
||||||
|
// 2%
|
||||||
|
if (r < 0.02) {
|
||||||
|
const color = new CosmicColor("#E5B73B");
|
||||||
|
|
||||||
|
addBack(context.id, {
|
||||||
|
m: "color",
|
||||||
|
id: context.part.id,
|
||||||
|
color: color.toHexa()
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true,
|
||||||
|
and: `and it made him/her turn ${color
|
||||||
|
.getName()
|
||||||
|
.toLowerCase()}.`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
registerBehavior<"yeet">("burger:yeet", async context => {
|
||||||
|
const name = context.part.name;
|
||||||
|
|
||||||
|
const tossed = [
|
||||||
|
`Friend ${name} tossed the meaty burger. It skipped off the water like a pebble.`,
|
||||||
|
`Friend ${name} yeeted the slimy burger into the stratosphere. It came around the other side of the planet and hit them in the head.`,
|
||||||
|
`The hamburger gracefully soared through the air.`,
|
||||||
|
`In a majestic flight, the burger takes off like a plane and floats away into the horizon.`,
|
||||||
|
`A film crew and director watch ${name} toss a burger from afar. After a few months, the burger wins an Oscar.`,
|
||||||
|
`Friend ${name} flings a Junior Baconator into the sky with enough force to create a second moon.`,
|
||||||
|
`The burger launched like a rocket and reaches outer space. Suddenly, a ship full of Kerbonauts crashes into the patty, diverting it back to the planet.`,
|
||||||
|
`Friend ${name} tosses the burger. Suddenly, the burger is hit by a flying hot dog.`,
|
||||||
|
`The burger sprouts wings and floats away.`,
|
||||||
|
`Friend ${name} tosses a burger ${
|
||||||
|
Math.trunc(Math.random() * 1000) / 100
|
||||||
|
} inches in front of themselves.`,
|
||||||
|
`Friend ${name} winds up for a big throw and yeets the burger. After travelling the sky for a few seconds, it enters somebody else's car window.`,
|
||||||
|
`Friend ${name} tosses the burger. The local weather station reports falling food.`,
|
||||||
|
`The burger goes through a cloud shaped like ${name}'s head.`,
|
||||||
|
`After a long 10 minutes, the burger comes down from the ceiling.`,
|
||||||
|
`Friend ${name} tosses the burger like a frisbee and it lands on a nearby roof.`,
|
||||||
|
`Friend ${name} carelessly sends the burger into a passing seagull's mouth.`,
|
||||||
|
`Friend ${name} managed to deliver a burger perfectly into the window of a house.`,
|
||||||
|
`The burger hits the water and a shark fin suddenly appears.`,
|
||||||
|
`After ${name} hurls the burger, it lands onto a nearby grill.`,
|
||||||
|
`Friend ${name} flings a burger patty into the atmosphere.`,
|
||||||
|
`Friend ${name} throws a boomerang-shaped hamburger. It comes back and hits ${name} on the head.`,
|
||||||
|
`Friend ${name} tosses the burger.`,
|
||||||
|
`Friend ${name} tosses the burger into the air and it lands on their face.`,
|
||||||
|
`Friend ${name} tosses the burger to the other side of a rainbow.`
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true,
|
||||||
|
text: tossed[Math.floor(Math.random() * tossed.length)]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { addBack } from "@server/backs";
|
||||||
|
import { CosmicColor } from "@util/CosmicColor";
|
||||||
|
import { registerBehavior } from "..";
|
||||||
|
|
||||||
|
registerBehavior<"eat">("fish:eat", async context => {
|
||||||
|
const r = Math.random();
|
||||||
|
|
||||||
|
// 50%
|
||||||
|
if (r < 0.5) {
|
||||||
|
const color = new CosmicColor(
|
||||||
|
Math.floor(Math.random() * 255),
|
||||||
|
Math.floor(Math.random() * 255),
|
||||||
|
Math.floor(Math.random() * 255)
|
||||||
|
);
|
||||||
|
|
||||||
|
addBack(context.id, {
|
||||||
|
m: "color",
|
||||||
|
id: context.part.id,
|
||||||
|
color: color.toHexa()
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true,
|
||||||
|
and: `and it made him/her turn ${color
|
||||||
|
.getName()
|
||||||
|
.toLowerCase()}.`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { incrementFishingChance } from "@server/fish/fishers";
|
||||||
|
import { registerBehavior } from "..";
|
||||||
|
|
||||||
|
registerBehavior<"eat">("kekklefruit:eat", async context => {
|
||||||
|
const test = await incrementFishingChance(context.user.id);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true,
|
||||||
|
and: "and got a temporary fishing boost."
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { registerBehavior } from "..";
|
||||||
|
|
||||||
|
registerBehavior<"yeet">("sand:yeet", async context => {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: false,
|
||||||
|
text: `No, ${context.part.name}, don't yeet sand.`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
export function registerBehaviors() {
|
||||||
|
require("./objects/fish");
|
||||||
|
require("./objects/kekklefruit");
|
||||||
|
require("./objects/burger");
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import type { ReadlineCommand } from "./ReadlineCommand";
|
import type { ReadlineCommand } from "./ReadlineCommand";
|
||||||
import { deltoken } from "./commands/deltoken";
|
import { deltoken } from "./commands/deltoken";
|
||||||
import { gentoken } from "./commands/gentoken";
|
import { gentoken } from "./commands/gentoken";
|
||||||
|
import { grow_fruit } from "./commands/grow_fruit";
|
||||||
import { help } from "./commands/help";
|
import { help } from "./commands/help";
|
||||||
import { lstoken } from "./commands/lstoken";
|
import { lstoken } from "./commands/lstoken";
|
||||||
import { stop } from "./commands/stop";
|
import { stop } from "./commands/stop";
|
||||||
|
@ -12,3 +13,4 @@ readlineCommands.push(gentoken);
|
||||||
readlineCommands.push(deltoken);
|
readlineCommands.push(deltoken);
|
||||||
readlineCommands.push(lstoken);
|
readlineCommands.push(lstoken);
|
||||||
readlineCommands.push(stop);
|
readlineCommands.push(stop);
|
||||||
|
readlineCommands.push(grow_fruit);
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { getAllTokens } from "@server/data/token";
|
||||||
|
import { ReadlineCommand } from "../ReadlineCommand";
|
||||||
|
import { growFruit } from "@server/fish/tree";
|
||||||
|
|
||||||
|
export const grow_fruit = new ReadlineCommand(
|
||||||
|
"grow_fruit",
|
||||||
|
["grow_fruit", "grow", "grow_kekklefruit"],
|
||||||
|
"Grow kekklefruit on the tree",
|
||||||
|
"grow_fruit <number>",
|
||||||
|
async line => {
|
||||||
|
try {
|
||||||
|
const args = line.split(" ");
|
||||||
|
const num = parseInt(args[1], 10);
|
||||||
|
await growFruit(num);
|
||||||
|
return `grew ${num} kekklefruit`;
|
||||||
|
} catch (err) {
|
||||||
|
return "bad";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
|
@ -0,0 +1,46 @@
|
||||||
|
import type { User } from "@prisma/client";
|
||||||
|
import Command from "./Command";
|
||||||
|
import { behaviorMap, executeBehavior } from "@server/behavior";
|
||||||
|
import { logger } from "./handler";
|
||||||
|
|
||||||
|
export class BehaviorCommand extends Command {
|
||||||
|
constructor(
|
||||||
|
public id: string,
|
||||||
|
public aliases: string[],
|
||||||
|
public description: string,
|
||||||
|
public usage: string,
|
||||||
|
public permissionNode: string,
|
||||||
|
callback: TCommandCallbackWithSelf<User, BehaviorCommand>,
|
||||||
|
public visible: boolean = true
|
||||||
|
) {
|
||||||
|
super(
|
||||||
|
id,
|
||||||
|
aliases,
|
||||||
|
description,
|
||||||
|
usage,
|
||||||
|
permissionNode,
|
||||||
|
props => callback(props, this),
|
||||||
|
visible
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async behave<
|
||||||
|
K extends keyof IBehaviorContextStateDefinitions,
|
||||||
|
C = IBehaviorContextStateDefinitions[K]["context"],
|
||||||
|
S = IBehaviorContextStateDefinitions[K]["state"]
|
||||||
|
>(context: C, objectId: string, defaultCallback: TBehaviorCallback<C, S>) {
|
||||||
|
const key = `${objectId}:${this.id}` as TBehaviorID;
|
||||||
|
let hasBehavior = false;
|
||||||
|
const container = behaviorMap.get(objectId);
|
||||||
|
|
||||||
|
if (container) hasBehavior = typeof container[this.id] === "function";
|
||||||
|
|
||||||
|
if (hasBehavior) {
|
||||||
|
return await executeBehavior(key, context);
|
||||||
|
} else {
|
||||||
|
return (await defaultCallback(context)) as TBehaviorResponse<S>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BehaviorCommand;
|
|
@ -3,7 +3,7 @@ import Command from "@server/commands/Command";
|
||||||
export const info = new Command(
|
export const info = new Command(
|
||||||
"info",
|
"info",
|
||||||
["info"],
|
["info"],
|
||||||
"Get your own user ID",
|
"Show information about the bot",
|
||||||
"info",
|
"info",
|
||||||
"command.general.info",
|
"command.general.info",
|
||||||
async ({ id, command, args, prefix, part, user }) => {
|
async ({ id, command, args, prefix, part, user }) => {
|
||||||
|
|
|
@ -13,10 +13,10 @@ import { eat } from "./inventory/eat";
|
||||||
import { sack } from "./inventory/sack";
|
import { sack } from "./inventory/sack";
|
||||||
import { reel } from "./fishing/reel";
|
import { reel } from "./fishing/reel";
|
||||||
import { memory } from "./util/mem";
|
import { memory } from "./util/mem";
|
||||||
import { pokemon } from "./inventory/pokemon";
|
import { pokemon } from "./pokemon/pokemon";
|
||||||
import { color } from "./general/color";
|
import { color } from "./general/color";
|
||||||
import { autofish } from "./util/autofish";
|
import { autofish } from "./util/autofish";
|
||||||
import { pokedex } from "./util/pokedex";
|
import { pokedex } from "./pokemon/pokedex";
|
||||||
import { myid } from "./general/myid";
|
import { myid } from "./general/myid";
|
||||||
import { yeet } from "./inventory/yeet";
|
import { yeet } from "./inventory/yeet";
|
||||||
import { tree } from "./fishing/tree";
|
import { tree } from "./fishing/tree";
|
||||||
|
@ -63,7 +63,7 @@ commandGroups.push(inventoryGroup);
|
||||||
const pokemonGroup: ICommandGroup = {
|
const pokemonGroup: ICommandGroup = {
|
||||||
id: "pokemon",
|
id: "pokemon",
|
||||||
displayName: "Pokémon",
|
displayName: "Pokémon",
|
||||||
commands: [daily, pokedex]
|
commands: [daily, pokemon, pokedex]
|
||||||
};
|
};
|
||||||
|
|
||||||
commandGroups.push(pokemonGroup);
|
commandGroups.push(pokemonGroup);
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import Command from "@server/commands/Command";
|
import BehaviorCommand from "@server/commands/BehaviorCommand";
|
||||||
import { logger } from "@server/commands/handler";
|
import { logger } from "@server/commands/handler";
|
||||||
import { getInventory, updateInventory } from "@server/data/inventory";
|
import { getInventory, updateInventory } from "@server/data/inventory";
|
||||||
import { findItemByNameFuzzy, removeItem } from "@server/items";
|
import { findItemByNameFuzzy, removeItem } from "@server/items";
|
||||||
import { itemBehaviorMap, runBehavior } from "@server/items/behavior";
|
// import { itemBehaviorMap, runBehavior } from "@server/items/behavior";
|
||||||
|
|
||||||
export const eat = new Command(
|
export const eat = new BehaviorCommand(
|
||||||
"eat",
|
"eat",
|
||||||
["eat", "oot"],
|
["eat", "oot"],
|
||||||
"Eat literally anything you have (except non-fish animals)",
|
"Eat literally anything you have (except non-fish animals)",
|
||||||
"eat <something>",
|
"eat <something>",
|
||||||
"command.inventory.eat",
|
"command.inventory.eat",
|
||||||
async props => {
|
async (props, self) => {
|
||||||
const { args, prefix, part, user } = props;
|
const { args, prefix, part, user } = props;
|
||||||
// const eating = args[0];
|
// const eating = args[0];
|
||||||
const eating = args.join(" ");
|
const eating = args.join(" ");
|
||||||
|
@ -33,18 +33,48 @@ export const eat = new Command(
|
||||||
let thingy = foundObject.id;
|
let thingy = foundObject.id;
|
||||||
if (foundObject.objtype == "fish") thingy = "fish";
|
if (foundObject.objtype == "fish") thingy = "fish";
|
||||||
|
|
||||||
const bhv = itemBehaviorMap[thingy];
|
// const bhv = itemBehaviorMap[thingy];
|
||||||
|
// let res;
|
||||||
|
|
||||||
|
// if (bhv) {
|
||||||
|
// if (!bhv["eat"]) return `You can't eat the ${foundObject.name}.`;
|
||||||
|
|
||||||
|
// res = await runBehavior(thingy, "eat", foundObject, props);
|
||||||
|
|
||||||
|
// // Check if response had an error, and populate our state that way
|
||||||
|
// if (res.success) shouldRemove = res.state.shouldRemove;
|
||||||
|
// else shouldRemove = false;
|
||||||
|
// } else {
|
||||||
|
// shouldRemove = true;
|
||||||
|
// }
|
||||||
|
|
||||||
let res;
|
let res;
|
||||||
|
let bhvNamespace = foundObject.id;
|
||||||
|
|
||||||
if (bhv) {
|
if (foundObject.objtype == "fish") {
|
||||||
if (!bhv["eat"]) return `You can't eat the ${foundObject.name}.`;
|
bhvNamespace = "fish";
|
||||||
|
|
||||||
res = await runBehavior(thingy, "eat", foundObject, props);
|
|
||||||
shouldRemove = res.shouldRemove;
|
|
||||||
} else {
|
|
||||||
shouldRemove = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res = await self.behave<"eat">(
|
||||||
|
{ id: props.id, part, object: foundObject, user },
|
||||||
|
bhvNamespace,
|
||||||
|
async () => {
|
||||||
|
shouldRemove = true;
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!res) throw new Error(`Unable to eat fish: no behavior result`);
|
||||||
|
|
||||||
|
if (res.success) shouldRemove = res.state.shouldRemove;
|
||||||
|
else shouldRemove = false;
|
||||||
|
|
||||||
if (shouldRemove) {
|
if (shouldRemove) {
|
||||||
if (foundObject.objtype == "fish") {
|
if (foundObject.objtype == "fish") {
|
||||||
removeItem(inventory.fishSack, foundObject);
|
removeItem(inventory.fishSack, foundObject);
|
||||||
|
@ -55,15 +85,22 @@ export const eat = new Command(
|
||||||
await updateInventory(inventory);
|
await updateInventory(inventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!res.success) {
|
||||||
|
return `You broke the bot trying to ${prefix}eat the ${foundObject.name}. Congratulations.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const state =
|
||||||
|
res.state as IBehaviorContextStateDefinitions["eat"]["state"];
|
||||||
|
|
||||||
if (foundObject.id == "sand") {
|
if (foundObject.id == "sand") {
|
||||||
if (res && res.and) {
|
if (res && res.success && typeof state.and !== "undefined") {
|
||||||
return `Our friend ${part.name} ate of his/her ${foundObject.name} ${res.and}`;
|
return `Our friend ${part.name} ate of his/her ${foundObject.name} ${state.and}`;
|
||||||
} else {
|
} else {
|
||||||
return `Our friend ${part.name} ate of his/her ${foundObject.name}.`;
|
return `Our friend ${part.name} ate of his/her ${foundObject.name}.`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (res && res.and) {
|
if (res && res.success && typeof state.and !== "undefined") {
|
||||||
return `Our friend ${part.name} ate his/her ${foundObject.name} ${res.and}`;
|
return `Our friend ${part.name} ate his/her ${foundObject.name} ${state.and}`;
|
||||||
} else {
|
} else {
|
||||||
return `Our friend ${part.name} ate his/her ${foundObject.name}.`;
|
return `Our friend ${part.name} ate his/her ${foundObject.name}.`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,20 @@
|
||||||
import { addBack } from "@server/backs";
|
import BehaviorCommand from "@server/commands/BehaviorCommand";
|
||||||
import Command from "@server/commands/Command";
|
|
||||||
import { logger } from "@server/commands/handler";
|
import { logger } from "@server/commands/handler";
|
||||||
import { getInventory, updateInventory } from "@server/data/inventory";
|
import { getInventory, updateInventory } from "@server/data/inventory";
|
||||||
import prisma from "@server/data/prisma";
|
|
||||||
import { getUser } from "@server/data/user";
|
import { getUser } from "@server/data/user";
|
||||||
import { getSizeString } from "@server/fish/fish";
|
import { getSizeString } from "@server/fish/fish";
|
||||||
import { fishers, getFishing } from "@server/fish/fishers";
|
import { fishers } from "@server/fish/fishers";
|
||||||
import { locations } from "@server/fish/locations";
|
import { locations } from "@server/fish/locations";
|
||||||
import { addItem } from "@server/items";
|
import { addItem, findItemByNameFuzzy, removeItem } from "@server/items";
|
||||||
import { CosmicColor } from "@util/CosmicColor";
|
|
||||||
|
|
||||||
export const yeet = new Command(
|
export const yeet = new BehaviorCommand(
|
||||||
"yeet",
|
"yeet",
|
||||||
["yeet", "yoot"],
|
["yeet", "yoot"],
|
||||||
"Yeet literally anything you have (except non-fish animals)",
|
"Yeet literally anything you have (except non-fish animals)",
|
||||||
"yeet <something>",
|
"yeet <something>",
|
||||||
"command.inventory.yeet",
|
"command.inventory.yeet",
|
||||||
async ({ id, command, args, prefix, part, user }) => {
|
async ({ id, command, args, prefix, part, user }, self) => {
|
||||||
const yeeting = args[0];
|
const yeeting = args.join(" ");
|
||||||
if (!yeeting) return `What do you want to ${prefix}yeet?`;
|
if (!yeeting) return `What do you want to ${prefix}yeet?`;
|
||||||
|
|
||||||
const inventory = await getInventory(user.inventoryId);
|
const inventory = await getInventory(user.inventoryId);
|
||||||
|
@ -26,273 +23,314 @@ export const yeet = new Command(
|
||||||
let foundObject: IObject | undefined;
|
let foundObject: IObject | undefined;
|
||||||
let tryKekGen = false;
|
let tryKekGen = false;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
let shouldRemove = false;
|
||||||
|
|
||||||
for (const item of inventory.items as unknown as IItem[]) {
|
foundObject =
|
||||||
if (!item.name.toLowerCase().includes(yeeting.toLowerCase())) {
|
findItemByNameFuzzy(inventory.items, yeeting) ||
|
||||||
i++;
|
findItemByNameFuzzy(inventory.fishSack, yeeting);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foundObject = item;
|
|
||||||
|
|
||||||
let shouldRemove = false;
|
|
||||||
|
|
||||||
if (typeof item.count !== "undefined") {
|
|
||||||
if (item.count > 1) {
|
|
||||||
shouldRemove = false;
|
|
||||||
((inventory.items as TInventoryItems)[i].count as number)--;
|
|
||||||
} else {
|
|
||||||
shouldRemove = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
shouldRemove = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldRemove && item.id !== "sand")
|
|
||||||
(inventory.items as TInventoryItems).splice(i, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
for (const fish of inventory.fishSack as TFishSack) {
|
|
||||||
if (!fish.name.toLowerCase().includes(yeeting.toLowerCase())) {
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foundObject = fish;
|
|
||||||
|
|
||||||
let shouldRemove = false;
|
|
||||||
|
|
||||||
if (typeof fish.count !== "undefined") {
|
|
||||||
if (fish.count > 1) {
|
|
||||||
shouldRemove = false;
|
|
||||||
((inventory.fishSack as TFishSack)[i].count as number)--;
|
|
||||||
} else {
|
|
||||||
shouldRemove = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
shouldRemove = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldRemove) (inventory.fishSack as TFishSack).splice(i, 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!foundObject) return `You don't have "${yeeting}" to yeet.`;
|
if (!foundObject) return `You don't have "${yeeting}" to yeet.`;
|
||||||
|
|
||||||
|
let bhvNamespace = foundObject.id;
|
||||||
|
let output = `Friend ${part.name} tossed his/her ${foundObject.name}.`;
|
||||||
|
|
||||||
if (foundObject.objtype == "fish") {
|
if (foundObject.objtype == "fish") {
|
||||||
|
bhvNamespace = "fish";
|
||||||
tryKekGen = true;
|
tryKekGen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const res = await self.behave<"yeet">(
|
||||||
|
{
|
||||||
|
part
|
||||||
|
},
|
||||||
|
foundObject.id,
|
||||||
|
async ctx => {
|
||||||
|
logger.debug("stuff");
|
||||||
|
if (tryKekGen) {
|
||||||
|
// 15%
|
||||||
|
if (Math.random() < 0.15) {
|
||||||
|
const randomFisher =
|
||||||
|
Object.values(fishers)[
|
||||||
|
Math.floor(
|
||||||
|
Math.random() *
|
||||||
|
Object.values(fishers).length
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
let person;
|
||||||
|
|
||||||
|
if (!randomFisher) {
|
||||||
|
person = {
|
||||||
|
name: "Anonymous"
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
person = await getUser(randomFisher.userID);
|
||||||
|
}
|
||||||
|
|
||||||
|
let target: string;
|
||||||
|
|
||||||
|
if (!person || person?.id == part.id) {
|
||||||
|
target = "Anonymous";
|
||||||
|
} else {
|
||||||
|
target = person.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
let handsAdjective = [
|
||||||
|
" violent ",
|
||||||
|
" shaking ",
|
||||||
|
" angery ",
|
||||||
|
" two (2) ",
|
||||||
|
" unknown number of ",
|
||||||
|
" "
|
||||||
|
];
|
||||||
|
|
||||||
|
let pastTense = [
|
||||||
|
"slung",
|
||||||
|
"foisted",
|
||||||
|
"launched",
|
||||||
|
"yeeted",
|
||||||
|
"expelled",
|
||||||
|
"fired"
|
||||||
|
];
|
||||||
|
|
||||||
|
let presentTense = [
|
||||||
|
"lazily",
|
||||||
|
"forcefully",
|
||||||
|
"haphazardly",
|
||||||
|
"angrily",
|
||||||
|
"playfully",
|
||||||
|
"lovingly"
|
||||||
|
];
|
||||||
|
|
||||||
|
let ending = [
|
||||||
|
`in the direction of ${target}.`,
|
||||||
|
`at where ${target} happens to be.`,
|
||||||
|
`at ${target}.`,
|
||||||
|
`directly at ${target}'s location in this realm.`,
|
||||||
|
`at the general vicinity of ${target}.`
|
||||||
|
];
|
||||||
|
|
||||||
|
let itemAdjective = [
|
||||||
|
"gooey",
|
||||||
|
"powdery",
|
||||||
|
"residual",
|
||||||
|
"smelly",
|
||||||
|
"appropriate",
|
||||||
|
foundObject.name,
|
||||||
|
foundObject.name + "y",
|
||||||
|
"greasy",
|
||||||
|
"uncomfortable",
|
||||||
|
"delicious",
|
||||||
|
"wonderful",
|
||||||
|
"questionable",
|
||||||
|
"nice",
|
||||||
|
"gelatinous",
|
||||||
|
"shampoo",
|
||||||
|
"fatty",
|
||||||
|
"warm",
|
||||||
|
"hot",
|
||||||
|
"cold",
|
||||||
|
"dripping",
|
||||||
|
"fish",
|
||||||
|
"unknown"
|
||||||
|
];
|
||||||
|
|
||||||
|
let ps = [
|
||||||
|
"It missed.",
|
||||||
|
"It grazed his/her cheek, leaving a small dab of " +
|
||||||
|
foundObject.name +
|
||||||
|
".",
|
||||||
|
foundObject.objtype == "fish"
|
||||||
|
? "Being that it was so " +
|
||||||
|
getSizeString((foundObject as IFish).size) +
|
||||||
|
", I'm sure you can infer how comical the result is!"
|
||||||
|
: "Being that it was so voluminous, I'm sure you can infer how comical the result is!",
|
||||||
|
"It smacked right across his/her face.",
|
||||||
|
"It got hung in his/her shirt and he/she flung it out onto the ground and it was quite a silly scene.",
|
||||||
|
`It scooted across his/her head before rebounding off onto the ground nearby. The ${
|
||||||
|
itemAdjective[
|
||||||
|
Math.floor(
|
||||||
|
Math.random() * itemAdjective.length
|
||||||
|
)
|
||||||
|
]
|
||||||
|
} residue was left behind in ${target}'s hair.`
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true,
|
||||||
|
text: `Friend ${part.name}'s ${
|
||||||
|
handsAdjective[
|
||||||
|
Math.floor(
|
||||||
|
Math.random() *
|
||||||
|
handsAdjective.length
|
||||||
|
)
|
||||||
|
]
|
||||||
|
} hands grabbed his/her ${
|
||||||
|
foundObject.name
|
||||||
|
} and ${
|
||||||
|
pastTense[
|
||||||
|
Math.floor(
|
||||||
|
Math.random() * pastTense.length
|
||||||
|
)
|
||||||
|
]
|
||||||
|
} it ${
|
||||||
|
presentTense[
|
||||||
|
Math.floor(
|
||||||
|
Math.random() * presentTense.length
|
||||||
|
)
|
||||||
|
]
|
||||||
|
} ${
|
||||||
|
ending[
|
||||||
|
Math.floor(
|
||||||
|
Math.random() * ending.length
|
||||||
|
)
|
||||||
|
]
|
||||||
|
} ${ps[Math.floor(Math.random() * ps.length)]}`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.random() < 0.15) {
|
||||||
|
let size =
|
||||||
|
foundObject.objtype == "fish"
|
||||||
|
? getSizeString((foundObject as IFish).size)
|
||||||
|
: "voluminous";
|
||||||
|
|
||||||
|
let fish = foundObject.name;
|
||||||
|
let name = part.name;
|
||||||
|
|
||||||
|
const loc = locations.find(
|
||||||
|
loc => loc.id == inventory.location
|
||||||
|
);
|
||||||
|
if (!loc)
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true,
|
||||||
|
text: `Friend ${part.name} carelessly hurled their ${foundObject.name} into the void.`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
addItem(
|
||||||
|
locations[locations.indexOf(loc)].objects,
|
||||||
|
foundObject
|
||||||
|
);
|
||||||
|
|
||||||
|
let kekNames = [
|
||||||
|
"kek of good fortune",
|
||||||
|
"lucky kek",
|
||||||
|
"kek",
|
||||||
|
"fortunate kek",
|
||||||
|
"the kekklefruit that was knocked from the tree",
|
||||||
|
"sandy kekklefruit",
|
||||||
|
"baby kekklefruit"
|
||||||
|
];
|
||||||
|
|
||||||
|
addItem(locations[locations.indexOf(loc)].objects, {
|
||||||
|
id: "kekklefruit",
|
||||||
|
name: kekNames[
|
||||||
|
Math.floor(Math.random() * kekNames.length)
|
||||||
|
],
|
||||||
|
objtype: "item",
|
||||||
|
count: 1,
|
||||||
|
emoji: "🍍"
|
||||||
|
});
|
||||||
|
|
||||||
|
// transcribed from the old code
|
||||||
|
const yeets = [
|
||||||
|
"The " +
|
||||||
|
size +
|
||||||
|
" " +
|
||||||
|
fish +
|
||||||
|
" thwapped into the kekklefruit tree sending debris flying. A kekklefruit was knocked to the ground.",
|
||||||
|
"It's lying there next to the tree.",
|
||||||
|
"It got splattered on the tree.",
|
||||||
|
"Part of it is stuck to the tree, but it came to rest on the ground nearby.",
|
||||||
|
"A distressed-looking " +
|
||||||
|
fish +
|
||||||
|
" on the ground near the tree.",
|
||||||
|
"It landed in the grass.",
|
||||||
|
"It's kinda scuffed up.",
|
||||||
|
"It's got tree on it. And " + name + "prints.",
|
||||||
|
"It's " + size + ".",
|
||||||
|
"It belongs to the tree now.",
|
||||||
|
"It's by the tree now.",
|
||||||
|
"It's a " +
|
||||||
|
size +
|
||||||
|
" " +
|
||||||
|
fish +
|
||||||
|
" previously owned by " +
|
||||||
|
name +
|
||||||
|
" if you still want it after that."
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true,
|
||||||
|
text: yeets[
|
||||||
|
Math.floor(Math.random() * yeets.length)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.random() < 0.4) {
|
||||||
|
const yeets = [
|
||||||
|
"Tossed " + foundObject.name + " into the water.",
|
||||||
|
"It looks like somebody tossed it haphazardly into the shallow water. It is not swimming.",
|
||||||
|
"It's in the shallows trying to swim away...",
|
||||||
|
user.name +
|
||||||
|
" tossed this into the shallows where it rests today. I don't think it's moving.",
|
||||||
|
"I think it's a " +
|
||||||
|
foundObject.name +
|
||||||
|
". A very immobile one.",
|
||||||
|
" It's resting at the edge of the water where you can /take it."
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true,
|
||||||
|
text: yeets[
|
||||||
|
Math.floor(Math.random() * yeets.length)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true,
|
||||||
|
text: output
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (res.success == true) {
|
||||||
|
const state =
|
||||||
|
res.state as IBehaviorContextStateDefinitions["yeet"]["state"];
|
||||||
|
shouldRemove = state.shouldRemove;
|
||||||
|
output = state.text;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldRemove) {
|
||||||
|
if (foundObject.objtype == "fish") {
|
||||||
|
removeItem(inventory.fishSack, foundObject);
|
||||||
|
} else if (foundObject.objtype == "item") {
|
||||||
|
removeItem(inventory.items, foundObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateInventory(inventory);
|
||||||
|
}
|
||||||
|
|
||||||
await updateInventory(inventory);
|
await updateInventory(inventory);
|
||||||
|
|
||||||
if (foundObject.id == "sand") {
|
return output;
|
||||||
return `No, ${
|
|
||||||
part.name
|
|
||||||
}, don't yeet ${foundObject.name.toLowerCase()}.`;
|
|
||||||
} else {
|
|
||||||
if (Math.random() < 0.15) {
|
|
||||||
const randomFisher =
|
|
||||||
Object.values(fishers)[
|
|
||||||
Math.floor(
|
|
||||||
Math.random() * Object.values(fishers).length
|
|
||||||
)
|
|
||||||
];
|
|
||||||
|
|
||||||
let person;
|
|
||||||
|
|
||||||
if (!randomFisher) {
|
|
||||||
person = {
|
|
||||||
name: "Anonymous"
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
person = await getUser(randomFisher.userID);
|
|
||||||
}
|
|
||||||
|
|
||||||
let target: string;
|
|
||||||
|
|
||||||
if (!person || person?.id == part.id) {
|
|
||||||
target = "Anonymous";
|
|
||||||
} else {
|
|
||||||
target = person.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
let handsAdjective = [
|
|
||||||
" violent ",
|
|
||||||
" shaking ",
|
|
||||||
" angery ",
|
|
||||||
" two (2) ",
|
|
||||||
" unknown number of ",
|
|
||||||
" "
|
|
||||||
];
|
|
||||||
|
|
||||||
let pastTense = [
|
|
||||||
"slung",
|
|
||||||
"foisted",
|
|
||||||
"launched",
|
|
||||||
"yeeted",
|
|
||||||
"expelled",
|
|
||||||
"fired"
|
|
||||||
];
|
|
||||||
|
|
||||||
let presentTense = [
|
|
||||||
"lazily",
|
|
||||||
"forcefully",
|
|
||||||
"haphazardly",
|
|
||||||
"angrily",
|
|
||||||
"playfully",
|
|
||||||
"lovingly"
|
|
||||||
];
|
|
||||||
|
|
||||||
let ending = [
|
|
||||||
`in the direction of ${target}.`,
|
|
||||||
`at where ${target} happens to be.`,
|
|
||||||
`at ${target}.`,
|
|
||||||
`directly at ${target}'s location in this realm.`,
|
|
||||||
`at the general vicinity of ${target}.`
|
|
||||||
];
|
|
||||||
|
|
||||||
let itemAdjective = [
|
|
||||||
"gooey",
|
|
||||||
"powdery",
|
|
||||||
"residual",
|
|
||||||
"smelly",
|
|
||||||
"appropriate",
|
|
||||||
foundObject.name,
|
|
||||||
foundObject.name + "y",
|
|
||||||
"greasy",
|
|
||||||
"uncomfortable",
|
|
||||||
"delicious",
|
|
||||||
"wonderful",
|
|
||||||
"questionable",
|
|
||||||
"nice",
|
|
||||||
"gelatinous",
|
|
||||||
"shampoo",
|
|
||||||
"fatty",
|
|
||||||
"warm",
|
|
||||||
"hot",
|
|
||||||
"cold",
|
|
||||||
"dripping",
|
|
||||||
"fish",
|
|
||||||
"unknown"
|
|
||||||
];
|
|
||||||
|
|
||||||
let ps = [
|
|
||||||
"It missed.",
|
|
||||||
"It grazed his/her cheek, leaving a small dab of " +
|
|
||||||
foundObject.name +
|
|
||||||
".",
|
|
||||||
foundObject.objtype == "fish"
|
|
||||||
? "Being that it was so " +
|
|
||||||
getSizeString((foundObject as IFish).size) +
|
|
||||||
", I'm sure you can infer how comical the result is!"
|
|
||||||
: "Being that it was so voluminous, I'm sure you can infer how comical the result is!",
|
|
||||||
"It smacked right across his/her face.",
|
|
||||||
"It got hung in his/her shirt and he/she flung it out onto the ground and it was quite a silly scene.",
|
|
||||||
`It scooted across his/her head before rebounding off onto the ground nearby. The ${
|
|
||||||
itemAdjective[
|
|
||||||
Math.floor(Math.random() * itemAdjective.length)
|
|
||||||
]
|
|
||||||
} residue was left behind in ${target}'s hair.`
|
|
||||||
];
|
|
||||||
|
|
||||||
return `Friend ${part.name}'s ${
|
|
||||||
handsAdjective[
|
|
||||||
Math.floor(Math.random() * handsAdjective.length)
|
|
||||||
]
|
|
||||||
} hands grabbed his/her ${foundObject.name} and ${
|
|
||||||
pastTense[Math.floor(Math.random() * pastTense.length)]
|
|
||||||
} it ${
|
|
||||||
presentTense[
|
|
||||||
Math.floor(Math.random() * presentTense.length)
|
|
||||||
]
|
|
||||||
} ${ending[Math.floor(Math.random() * ending.length)]} ${
|
|
||||||
ps[Math.floor(Math.random() * ps.length)]
|
|
||||||
}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Math.random() < 0.15) {
|
|
||||||
let size =
|
|
||||||
foundObject.objtype == "fish"
|
|
||||||
? getSizeString((foundObject as IFish).size)
|
|
||||||
: "voluminous";
|
|
||||||
|
|
||||||
let fish = foundObject.name;
|
|
||||||
let name = part.name;
|
|
||||||
|
|
||||||
const loc = locations.find(loc => loc.id == inventory.location);
|
|
||||||
if (!loc)
|
|
||||||
return `Friend ${part.name} carelessly hurled their ${foundObject.name} into the void.`;
|
|
||||||
|
|
||||||
addItem(locations[locations.indexOf(loc)].objects, foundObject);
|
|
||||||
|
|
||||||
let kekNames = [
|
|
||||||
"kek of good fortune",
|
|
||||||
"lucky kek",
|
|
||||||
"kek",
|
|
||||||
"fortunate kek",
|
|
||||||
"the kekklefruit that was knocked from the tree",
|
|
||||||
"sandy kekklefruit",
|
|
||||||
"baby kekklefruit"
|
|
||||||
];
|
|
||||||
|
|
||||||
addItem(locations[locations.indexOf(loc)].objects, {
|
|
||||||
id: "kekklefruit",
|
|
||||||
name: kekNames[Math.floor(Math.random() * kekNames.length)],
|
|
||||||
objtype: "item",
|
|
||||||
count: 1,
|
|
||||||
emoji: "🍍"
|
|
||||||
});
|
|
||||||
|
|
||||||
// transcribed from the old code
|
|
||||||
let yeets = [
|
|
||||||
"The " +
|
|
||||||
size +
|
|
||||||
" " +
|
|
||||||
fish +
|
|
||||||
" thwapped into the kekklefruit tree sending debris flying. A kekklefruit was knocked to the ground.",
|
|
||||||
"It's lying there next to the tree.",
|
|
||||||
"It got splattered on the tree.",
|
|
||||||
"Part of it is stuck to the tree, but it came to rest on the ground nearby.",
|
|
||||||
"A distressed-looking " +
|
|
||||||
fish +
|
|
||||||
" on the ground near the tree.",
|
|
||||||
"It landed in the grass.",
|
|
||||||
"It's kinda scuffed up.",
|
|
||||||
"It's got tree on it. And " + name + "prints.",
|
|
||||||
"It's " + size + ".",
|
|
||||||
"It belongs to the tree now.",
|
|
||||||
"It's by the tree now.",
|
|
||||||
"It's a " +
|
|
||||||
size +
|
|
||||||
" " +
|
|
||||||
fish +
|
|
||||||
" previously owned by " +
|
|
||||||
name +
|
|
||||||
" if you still want it after that."
|
|
||||||
];
|
|
||||||
|
|
||||||
return yeets[Math.floor(Math.random() * yeets.length)];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Math.random() < 0.4) {
|
|
||||||
const yeets = [
|
|
||||||
"Tossed " + foundObject.name + " into the water.",
|
|
||||||
"It looks like somebody tossed it haphazardly into the shallow water. It is not swimming.",
|
|
||||||
"It's in the shallows trying to swim away...",
|
|
||||||
user.name +
|
|
||||||
" tossed this into the shallows where it rests today. I don't think it's moving.",
|
|
||||||
"I think it's a " +
|
|
||||||
foundObject.name +
|
|
||||||
". A very immobile one.",
|
|
||||||
" It's resting at the edge of the water where you can /take it."
|
|
||||||
];
|
|
||||||
|
|
||||||
return yeets[Math.floor(Math.random() * yeets.length)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return `Friend ${part.name} tossed his/her ${foundObject.name}.`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,12 +2,14 @@ import { startAutorestart } from "@util/autorestart";
|
||||||
import { startFisherTick } from "./fish/fishers";
|
import { startFisherTick } from "./fish/fishers";
|
||||||
import { startObjectTimers } from "./fish/locations";
|
import { startObjectTimers } from "./fish/locations";
|
||||||
import { initTree } from "./fish/tree";
|
import { initTree } from "./fish/tree";
|
||||||
import { loadDefaultBehaviors } from "./items/behavior/defaults";
|
import { registerBehaviors } from "./behavior/register";
|
||||||
|
// import { loadDefaultBehaviors } from "./items/behavior/defaults";
|
||||||
|
|
||||||
startObjectTimers();
|
startObjectTimers();
|
||||||
await startFisherTick();
|
await startFisherTick();
|
||||||
await initTree();
|
await initTree();
|
||||||
loadDefaultBehaviors();
|
// loadDefaultBehaviors();
|
||||||
|
registerBehaviors();
|
||||||
|
|
||||||
require("./api/server");
|
require("./api/server");
|
||||||
require("./cli/readline");
|
require("./cli/readline");
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { addItemBehavior } from ".";
|
|
||||||
import { fish } from "./items/fish";
|
|
||||||
import { kekklefruit } from "./items/kekklefruit";
|
|
||||||
|
|
||||||
export function loadDefaultBehaviors() {
|
|
||||||
const list: IBehaviorDefinition[] = [fish, kekklefruit];
|
|
||||||
|
|
||||||
for (const item of list) {
|
|
||||||
for (const key of Object.keys(item.bhv)) {
|
|
||||||
addItemBehavior(item.id, key, item.bhv[key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
export const itemBehaviorMap: TBehaviorMap = {};
|
|
||||||
|
|
||||||
export function addItemBehavior(
|
|
||||||
itemID: string,
|
|
||||||
bhvID: string,
|
|
||||||
bhv: TBehaviorCallback
|
|
||||||
) {
|
|
||||||
if (!itemBehaviorMap[itemID]) itemBehaviorMap[itemID] = {};
|
|
||||||
itemBehaviorMap[itemID][bhvID] = bhv;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function runBehavior(
|
|
||||||
itemID: string,
|
|
||||||
bhvID: string,
|
|
||||||
obj: IObject,
|
|
||||||
props: IContextProps
|
|
||||||
): Promise<IBehaviorResponse> {
|
|
||||||
const callback = itemBehaviorMap[itemID][bhvID];
|
|
||||||
if (!callback)
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
err: "No callback",
|
|
||||||
shouldRemove: false
|
|
||||||
};
|
|
||||||
return await callback(obj, props);
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
import { addBack } from "@server/backs";
|
|
||||||
import { CosmicColor } from "@util/CosmicColor";
|
|
||||||
|
|
||||||
export const fish: IBehaviorDefinition = {
|
|
||||||
id: "fish",
|
|
||||||
bhv: {
|
|
||||||
async eat(obj, props) {
|
|
||||||
const r = Math.random();
|
|
||||||
|
|
||||||
const fish = obj as IFish;
|
|
||||||
|
|
||||||
// 50%
|
|
||||||
if (r < 0.5) {
|
|
||||||
const color = new CosmicColor(
|
|
||||||
Math.floor(Math.random() * 255),
|
|
||||||
Math.floor(Math.random() * 255),
|
|
||||||
Math.floor(Math.random() * 255)
|
|
||||||
);
|
|
||||||
|
|
||||||
addBack(props.id, {
|
|
||||||
m: "color",
|
|
||||||
id: props.part.id,
|
|
||||||
color: color.toHexa()
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
shouldRemove: true,
|
|
||||||
and: `and it made him/her turn ${color
|
|
||||||
.getName()
|
|
||||||
.toLowerCase()}.`
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
shouldRemove: true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,16 +0,0 @@
|
||||||
import { incrementFishingChance } from "@server/fish/fishers";
|
|
||||||
|
|
||||||
export const kekklefruit: IBehaviorDefinition = {
|
|
||||||
id: "kekklefruit",
|
|
||||||
bhv: {
|
|
||||||
async eat(obj, props) {
|
|
||||||
const test = await incrementFishingChance(props.user.id);
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
shouldRemove: true,
|
|
||||||
and: "and got a temporary fishing boost."
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -8,7 +8,7 @@ interface ICommandResponse {
|
||||||
response: string;
|
response: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IContextProps {
|
interface ICommandContextProps {
|
||||||
id: string;
|
id: string;
|
||||||
channel: string;
|
channel: string;
|
||||||
command: string;
|
command: string;
|
||||||
|
@ -19,7 +19,14 @@ interface IContextProps {
|
||||||
isDM: boolean;
|
isDM: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type TCommandCallback<User> = (props: IContextProps) => Promise<string | void>;
|
type TCommandCallback<User> = (
|
||||||
|
props: ICommandContextProps
|
||||||
|
) => Promise<string | void>;
|
||||||
|
|
||||||
|
type TCommandCallbackWithSelf<User, T> = (
|
||||||
|
props: ICommandContextProps,
|
||||||
|
self: T
|
||||||
|
) => Promise<string | void>;
|
||||||
|
|
||||||
interface ICountComponent {
|
interface ICountComponent {
|
||||||
count: number;
|
count: number;
|
||||||
|
@ -139,26 +146,6 @@ interface IGroup {
|
||||||
permissions: string[];
|
permissions: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IBehaviorResponse {
|
|
||||||
success: boolean;
|
|
||||||
err?: string;
|
|
||||||
|
|
||||||
shouldRemove: boolean;
|
|
||||||
and?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type TBehaviorCallback = (
|
|
||||||
obj: IObject,
|
|
||||||
props: IContextProps
|
|
||||||
) => Promise<IBehaviorResponse>;
|
|
||||||
type TBehavior = Record<string, TBehaviorCallback>;
|
|
||||||
type TBehaviorMap = Record<string, TBehavior>;
|
|
||||||
|
|
||||||
interface IBehaviorDefinition {
|
|
||||||
id: string;
|
|
||||||
bhv: TBehavior;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IFishingChance {
|
interface IFishingChance {
|
||||||
chance: number;
|
chance: number;
|
||||||
t: number;
|
t: number;
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { executeBehavior, registerBehavior } from "@server/behavior";
|
||||||
|
import { test, expect } from "bun:test";
|
||||||
|
|
||||||
|
test("Behavior registering works", async () => {
|
||||||
|
try {
|
||||||
|
registerBehavior("fish:eat", async ctx => {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
registerBehavior("hamburger:yeet", async ctx => {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: false,
|
||||||
|
and: "the hamburger rolled away"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
expect(err).toBeUndefined();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Behavior execution is correct", async () => {
|
||||||
|
registerBehavior<"eat", { cooked: boolean }, { shouldRemove: boolean }>(
|
||||||
|
"hamburger:eat",
|
||||||
|
async ctx => {
|
||||||
|
if (ctx.cooked === false) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
err: "the hamburgers are not cooked yet"
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
state: {
|
||||||
|
shouldRemove: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let response = await executeBehavior("hamburger:eat", {
|
||||||
|
cooked: false
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.success).toBeFalse();
|
||||||
|
|
||||||
|
response = await executeBehavior("hamburger:eat", {
|
||||||
|
cooked: true
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(response.success).toBeTrue();
|
||||||
|
});
|
Loading…
Reference in New Issue