slight behavior redesign progress
This commit is contained in:
parent
8ad18e9b19
commit
ea24a931ca
|
@ -91,4 +91,9 @@ export interface InitHealth {
|
|||
export interface InvincibleUser {
|
||||
user: string,
|
||||
since: number,
|
||||
}
|
||||
export interface ItemBehavior {
|
||||
item: number,
|
||||
behavior: string,
|
||||
value?: number
|
||||
}
|
|
@ -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<boolean>
|
||||
// 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<Either<null, string>>,
|
||||
// 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<Either<number, string>>,
|
||||
}
|
||||
|
||||
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);
|
||||
},
|
||||
}
|
||||
];
|
||||
];
|
||||
|
||||
export async function getBehaviors(item: Item) {
|
||||
if (isDefaultItem(item)) {
|
||||
return item.behaviors || [];
|
||||
} else {
|
||||
return await db<ItemBehavior>('itemBehaviors')
|
||||
.where('item', item.id);
|
||||
}
|
||||
}
|
|
@ -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<CustomItem, 'guild'>;
|
||||
export type DefaultItem = Omit<CustomItem, 'guild'> & { behaviors?: Omit<ItemBehavior, 'item'>[] };
|
||||
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}**`;
|
||||
|
|
|
@ -27,4 +27,17 @@ export async function writeTmpFile(data: string | Buffer, filename?: string, ext
|
|||
|
||||
export function pickRandom<T>(list: T[]): T {
|
||||
return list[Math.floor(Math.random() * list.length)];
|
||||
}
|
||||
}
|
||||
|
||||
// WE OUT HERE
|
||||
export type Either<L,R> = Left<L> | Right<R>
|
||||
|
||||
export class Left<L> {
|
||||
constructor(private readonly value: L) {}
|
||||
public getValue() { return this.value; }
|
||||
}
|
||||
|
||||
export class Right<R> {
|
||||
constructor(private readonly value: R) {}
|
||||
public getValue() { return this.value; }
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue