Finish item behaviors, implement kekklefruit, remove forest
This commit is contained in:
parent
af89379aa2
commit
5565668088
|
@ -1,7 +1,6 @@
|
|||
import { addBack } from "@server/backs";
|
||||
import Command from "@server/commands/Command";
|
||||
import { getInventory, updateInventory } from "@server/data/inventory";
|
||||
import { CosmicColor } from "@util/CosmicColor";
|
||||
import { itemBehaviorMap, runBehavior } from "@server/items/behavior";
|
||||
|
||||
export const eat = new Command(
|
||||
"eat",
|
||||
|
@ -9,7 +8,8 @@ export const eat = new Command(
|
|||
"Eat literally anything you have (except non-fish animals)",
|
||||
"eat <something>",
|
||||
"command.inventory.eat",
|
||||
async ({ id, command, args, prefix, part, user }) => {
|
||||
async props => {
|
||||
const { args, prefix, part, user } = props;
|
||||
const eating = args[0];
|
||||
if (!eating) return `What do you want to ${prefix}eat?`;
|
||||
|
||||
|
@ -17,8 +17,8 @@ export const eat = new Command(
|
|||
if (!inventory) return;
|
||||
|
||||
let foundObject: IObject | undefined;
|
||||
let tryChangingColor = false;
|
||||
let i = 0;
|
||||
let shouldRemove = false;
|
||||
|
||||
for (const item of inventory.items as unknown as IItem[]) {
|
||||
if (!item.name.toLowerCase().includes(eating.toLowerCase())) {
|
||||
|
@ -27,54 +27,11 @@ export const eat = new Command(
|
|||
}
|
||||
|
||||
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) (inventory.items as TInventoryItems).splice(i, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
||||
// no more eating animals
|
||||
// for (const pokemon of inventory.pokemon as TPokemonSack) {
|
||||
// if (!pokemon.name.toLowerCase().includes(eating.toLowerCase())) {
|
||||
// i++;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// foundObject = pokemon as unknown as IObject;
|
||||
|
||||
// let shouldRemove = false;
|
||||
|
||||
// if (typeof pokemon.count !== "undefined") {
|
||||
// if (pokemon.count > 1) {
|
||||
// shouldRemove = false;
|
||||
// ((inventory.pokemon as TPokemonSack)[i].count as number)--;
|
||||
// } else {
|
||||
// shouldRemove = true;
|
||||
// }
|
||||
// } else {
|
||||
// shouldRemove = true;
|
||||
// }
|
||||
|
||||
// if (shouldRemove) (inventory.pokemon as TPokemonSack).splice(i, 1);
|
||||
// break;
|
||||
// }
|
||||
|
||||
i = 0;
|
||||
|
||||
for (const fish of inventory.fishSack as TFishSack) {
|
||||
if (!fish.name.toLowerCase().includes(eating.toLowerCase())) {
|
||||
i++;
|
||||
|
@ -82,56 +39,77 @@ export const eat = new Command(
|
|||
}
|
||||
|
||||
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 "${eating}" to eat.`;
|
||||
if (foundObject.objtype == "fish") {
|
||||
tryChangingColor = true;
|
||||
|
||||
// Get item behaviors and run the "eat" script
|
||||
let thingy = foundObject.id;
|
||||
if (foundObject.objtype == "fish") thingy = "fish";
|
||||
|
||||
const bhv = itemBehaviorMap[thingy];
|
||||
if (!bhv) return `The ${foundObject.name} isn't edible.`;
|
||||
if (!bhv["eat"]) return `You can't eat the ${foundObject.name}.`;
|
||||
|
||||
const res = await runBehavior(thingy, "eat", foundObject, props);
|
||||
shouldRemove = res.shouldRemove;
|
||||
|
||||
if (shouldRemove) {
|
||||
if (foundObject.objtype == "fish") {
|
||||
i = 0;
|
||||
|
||||
for (const fish of inventory.fishSack as TFishSack) {
|
||||
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;
|
||||
}
|
||||
} else if (foundObject.objtype == "item") {
|
||||
i = 0;
|
||||
|
||||
for (const item of inventory.items as unknown as IItem[]) {
|
||||
if (typeof item.count == "number") {
|
||||
if (item.count > 1) {
|
||||
shouldRemove = false;
|
||||
((inventory.items as TInventoryItems)[i]
|
||||
.count as number)--;
|
||||
} else {
|
||||
shouldRemove = true;
|
||||
}
|
||||
} else {
|
||||
shouldRemove = true;
|
||||
}
|
||||
|
||||
if (shouldRemove)
|
||||
(inventory.items as TInventoryItems).splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
await updateInventory(inventory);
|
||||
}
|
||||
|
||||
await updateInventory(inventory);
|
||||
|
||||
if (!tryChangingColor) {
|
||||
if (foundObject.id == "sand") {
|
||||
return `Our friend ${part.name} ate of his/her ${foundObject.name}.`;
|
||||
if (foundObject.id == "sand") {
|
||||
if (res.and) {
|
||||
return `Our friend ${part.name} ate of his/her ${foundObject.name} ${res.and}`;
|
||||
} else {
|
||||
return `Our friend ${part.name} ate his/her ${foundObject.name}.`;
|
||||
return `Our friend ${part.name} ate of his/her ${foundObject.name}.`;
|
||||
}
|
||||
} else {
|
||||
const r = Math.random();
|
||||
|
||||
if (r < 0.3) {
|
||||
const color = new CosmicColor(
|
||||
Math.floor(Math.random() * 255),
|
||||
Math.floor(Math.random() * 255),
|
||||
Math.floor(Math.random() * 255)
|
||||
);
|
||||
|
||||
addBack(id, {
|
||||
m: "color",
|
||||
id: part.id,
|
||||
color: color.toHexa()
|
||||
});
|
||||
|
||||
return `Our friend ${part.name} ate his/her ${
|
||||
foundObject.name
|
||||
} and it made him/her turn ${color.getName().toLowerCase()}.`;
|
||||
if (res.and) {
|
||||
return `Our friend ${part.name} ate his/her ${foundObject.name} ${res.and}`;
|
||||
} else {
|
||||
return `Our friend ${part.name} ate his/her ${foundObject.name}.`;
|
||||
}
|
||||
|
|
|
@ -41,8 +41,11 @@ export async function tick() {
|
|||
}
|
||||
|
||||
const r = Math.random();
|
||||
const data = await getFishingChance(user.id);
|
||||
// After 30 minutes, reset chance
|
||||
if (data.t > 30 * 60000) await resetFishingChance(user.id);
|
||||
|
||||
if (r < 0.1) {
|
||||
if (r < data.chance / 10) {
|
||||
stopFishing(
|
||||
winner.id,
|
||||
winner.userID,
|
||||
|
@ -131,3 +134,33 @@ export function stopFishing(
|
|||
export function getFishing(id: string, userID: string) {
|
||||
return fishers[id + "~" + userID];
|
||||
}
|
||||
|
||||
export async function getFishingChance(userID: string) {
|
||||
const key = `fishingChance~${userID}`;
|
||||
const data = (await kvGet(key)) as IFishingChance;
|
||||
|
||||
if (!data) {
|
||||
await resetFishingChance(userID);
|
||||
return await getFishingChance(userID);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function resetFishingChance(userID: string) {
|
||||
const key = `fishingChance~${userID}`;
|
||||
await kvSet(key, {
|
||||
t: Date.now(),
|
||||
chance: 1
|
||||
} as IFishingChance);
|
||||
}
|
||||
|
||||
export async function incrementFishingChance(userID: string) {
|
||||
const key = `fishingChance~${userID}`;
|
||||
const data = (await kvGet(key)) as IFishingChance;
|
||||
if (!data) await resetFishingChance(userID);
|
||||
const r = Math.random();
|
||||
data.chance += r;
|
||||
await kvSet(key, data);
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -35,14 +35,6 @@ export const locations = loadConfig<ILocation[]>("config/locations.yml", [
|
|||
nearby: ["pond", "lake", "river"],
|
||||
hasSand: true,
|
||||
objects: []
|
||||
},
|
||||
|
||||
{
|
||||
id: "forest",
|
||||
name: "Forest",
|
||||
nearby: ["pond", "lake", "beach"],
|
||||
hasSand: false,
|
||||
objects: []
|
||||
}
|
||||
]);
|
||||
|
||||
|
|
|
@ -3,7 +3,9 @@ import "./cli/readline";
|
|||
import { startFisherTick } from "./fish/fishers";
|
||||
import { startObjectTimers } from "./fish/locations";
|
||||
import { initTree } from "./fish/tree";
|
||||
import { loadDefaultBehaviors } from "./items/behavior/defaults";
|
||||
|
||||
startObjectTimers();
|
||||
await startFisherTick();
|
||||
await initTree();
|
||||
loadDefaultBehaviors();
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
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,5 +1,26 @@
|
|||
export const itemBehaviorMap: TItemBehaviorMap = {};
|
||||
export const itemBehaviorMap: TBehaviorMap = {};
|
||||
|
||||
export function addItemBehavior(itemID: string, bhv: TItemBehavior) {
|
||||
itemBehaviorMap[itemID] = bhv;
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import { addBack } from "@server/backs";
|
||||
import { CosmicColor } from "@util/CosmicColor";
|
||||
|
||||
export const fish: IBehaviorDefinition = {
|
||||
id: "fish",
|
||||
bhv: {
|
||||
async eat(obj, props) {
|
||||
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()}.`
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
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;
|
||||
}
|
||||
|
||||
type TCommandCallback<User> = (props: {
|
||||
interface IContextProps {
|
||||
id: string;
|
||||
command: string;
|
||||
args: string[];
|
||||
|
@ -16,7 +16,9 @@ type TCommandCallback<User> = (props: {
|
|||
part: IPart;
|
||||
user: User;
|
||||
isDM: boolean;
|
||||
}) => Promise<string | void>;
|
||||
}
|
||||
|
||||
type TCommandCallback<User> = (props: IContextProps) => Promise<string | void>;
|
||||
|
||||
interface CountComponent {
|
||||
count: number;
|
||||
|
@ -112,19 +114,32 @@ interface TFisher {
|
|||
|
||||
type TPokedex = IPokemon[];
|
||||
|
||||
type TBehavior<T> = () => Promise<T>;
|
||||
type TBehaviorMap<T> = Record<T, TBehavior>;
|
||||
|
||||
interface IItemBehaviorData {
|
||||
status: boolean;
|
||||
text: string;
|
||||
userID: string;
|
||||
}
|
||||
|
||||
type TItemBehavior = Behavior<IItemBehaviorData>;
|
||||
type TItemBehaviorMap = TBehaviorMap<TItemBehavior>;
|
||||
|
||||
interface IGroup {
|
||||
id: 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 {
|
||||
chance: number;
|
||||
t: number;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue