From ea24a931cad94dc27486b7f02e57fc282fc7e90b Mon Sep 17 00:00:00 2001 From: "Jill \"oatmealine\" Monoids" Date: Wed, 22 Nov 2023 00:14:07 +0300 Subject: [PATCH] slight behavior redesign progress --- src/lib/db.ts | 5 +++ src/lib/rpg/behaviors.ts | 78 +++++++++++++++++++++++++++++++++------- src/lib/rpg/items.ts | 8 +++-- src/lib/util.ts | 15 +++++++- 4 files changed, 90 insertions(+), 16 deletions(-) diff --git a/src/lib/db.ts b/src/lib/db.ts index 62244b6..e55e449 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -91,4 +91,9 @@ export interface InitHealth { export interface InvincibleUser { user: string, since: number, +} +export interface ItemBehavior { + item: number, + behavior: string, + value?: number } \ No newline at end of file diff --git a/src/lib/rpg/behaviors.ts b/src/lib/rpg/behaviors.ts index b867781..e9496c6 100644 --- a/src/lib/rpg/behaviors.ts +++ b/src/lib/rpg/behaviors.ts @@ -1,26 +1,78 @@ -import type { User } from 'discord.js'; -import type { Item } from './items'; +import { giveItem, type Item, isDefaultItem } from './items'; +import { Either, Left } from '../util'; +import { ItemBehavior, db } from '../db'; +import { BLOOD_ITEM, dealDamage } from './pvp'; export interface Behavior { name: string, description: string, itemType: 'plain' | 'weapon' | 'consumable', + // make it look fancy + format?: (value: number) => string, // triggers upon use - // for 'weapons', this is on hit - // for 'consumable', this is on use - // for 'plain', ...?? - // returns `true` upon success, `false` otherwise - action?: (item: Item, user: User) => Promise + // for 'weapons', this is on attack + // for 'consumable' and `plain`, this is on use + // returns Left upon success, the reason for failure otherwise (Right) + onUse?: (value: number, item: Item, user: string) => Promise>, + // triggers upon `weapons` attack + // returns the new damage value upon success (Left), the reason for failure otherwise (Right) + onAttack?: (value: number, item: Item, user: string, target: string, damage: number) => Promise>, } export const behaviors: Behavior[] = [ { name: 'heal', - description: 'Heals the user by `behaviorValue`', + description: 'Heals the user by `value`', itemType: 'consumable', - action: async (item, user) => { - // todo - return false; - } + async onUse(value, item, user) { + await dealDamage(user, -Math.floor(value)); + return new Left(null); + }, + }, + { + name: 'damage', + description: 'Damages the user by `value', + itemType: 'consumable', + async onUse(value, item, user) { + await dealDamage(user, Math.floor(value)); + return new Left(null); + }, + }, + { + name: 'random_up', + description: 'Randomizes the attack value up by a maximum of `value`', + itemType: 'weapon', + format: (value) => `random +${value}`, + async onAttack(value, item, user, target, damage) { + return new Left(damage + Math.round(Math.random() * value)); + }, + }, + { + name: 'random_down', + description: 'Randomizes the attack value down by a maximum of `value`', + itemType: 'weapon', + format: (value) => `random -${value}`, + async onAttack(value, item, user, target, damage) { + return new Left(damage - Math.round(Math.random() * value)); + }, + }, + { + name: 'lifesteal', + description: 'Gain blood by stabbing your foes, scaled by `value`x', + itemType: 'weapon', + format: (value) => `lifesteal: ${value}x`, + async onAttack(value, item, user, target, damage) { + giveItem(user, BLOOD_ITEM, Math.floor(damage * value)); + return new Left(damage); + }, } -]; \ No newline at end of file +]; + +export async function getBehaviors(item: Item) { + if (isDefaultItem(item)) { + return item.behaviors || []; + } else { + return await db('itemBehaviors') + .where('item', item.id); + } +} \ No newline at end of file diff --git a/src/lib/rpg/items.ts b/src/lib/rpg/items.ts index e9ec8a3..19d49ad 100644 --- a/src/lib/rpg/items.ts +++ b/src/lib/rpg/items.ts @@ -1,8 +1,8 @@ import { AutocompleteInteraction } from 'discord.js'; -import { CustomItem, ItemInventory, db } from '../db'; +import { CustomItem, ItemBehavior, ItemInventory, db } from '../db'; // uses negative IDs -export type DefaultItem = Omit; +export type DefaultItem = Omit & { behaviors?: Omit[] }; export type Item = DefaultItem | CustomItem; export interface Items { @@ -362,6 +362,10 @@ export function getMaxStack(item: Item) { return item.type === 'weapon' ? 1 : item.maxStack; } +export function isDefaultItem(item: Item): item is DefaultItem { + return (item as DefaultItem).behaviors !== undefined; // ough +} + export function formatItem(item: Item | undefined, disableBold = false) { if (!item) return disableBold ? '? MISSINGNO' : '? **MISSINGNO**'; return disableBold ? `${item.emoji} ${item.name}` : `${item.emoji} **${item.name}**`; diff --git a/src/lib/util.ts b/src/lib/util.ts index cb36114..d822174 100644 --- a/src/lib/util.ts +++ b/src/lib/util.ts @@ -27,4 +27,17 @@ export async function writeTmpFile(data: string | Buffer, filename?: string, ext export function pickRandom(list: T[]): T { return list[Math.floor(Math.random() * list.length)]; -} \ No newline at end of file +} + +// WE OUT HERE +export type Either = Left | Right + +export class Left { + constructor(private readonly value: L) {} + public getValue() { return this.value; } +} + +export class Right { + constructor(private readonly value: R) {} + public getValue() { return this.value; } +}