Skip to content

Commit

Permalink
refactor: finish moving product to separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
leaftail1880 committed Sep 3, 2024
1 parent a330b48 commit 2abd9fe
Show file tree
Hide file tree
Showing 9 changed files with 75,418 additions and 75,346 deletions.
150,544 changes: 75,303 additions & 75,241 deletions src/lib/assets/lang.ts

Large diffs are not rendered by default.

7 changes: 1 addition & 6 deletions src/lib/shop/buttons/item-modifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ export function createItemModifier(
)
return false
})
.texture()
.sell()
.customCostBuy(true)
.setCustomCostBuy(true)
}

export type ShopMenuWithSlotCreate = (
Expand Down Expand Up @@ -81,9 +79,6 @@ export function createItemModifierSection(
select()
return false
})
.texture()
.sell()
.customCostBuy(false)
}

function onSelect(
Expand Down
34 changes: 14 additions & 20 deletions src/lib/shop/buttons/sellable-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,18 @@ function createBuy(
const total = getTotal(count, i => getBuy(dbCount - i))
const cost = total <= 0 ? ImpossibleBuyCost : dbCount - count < 0 ? NoItemsToSell : new MoneyCost(total)

form.product(
itemDescription({ typeId: type, amount: count }),
cost,
player => {
form.product
.name(itemDescription({ typeId: type, amount: count }))
.cost(cost)
.onBuy(player => {
if (!player.container) return

cost.buy(player)
db[type] = Math.max(0, (db[type] ?? count) - count)
player.runCommand(`give @s ${type} ${count}`)
},
aux,
undefined,
false,
)
})
.setTexture(aux)
.setCustomCostBuy(true)
}
}

Expand All @@ -130,24 +128,20 @@ function createSell(
new ItemCost(type, count),
)

form.product(
new MoneyCost(total).toString(),
cost,
player => {
form.product
.name(new MoneyCost(total).toString())
.cost(cost)
.onBuy(player => {
db[type] = Math.min(maxCount, (db[type] ?? 0) + count)
player.scores.money += total
},
aux,
true,
)
})
.setTexture(aux)
}
}

function getTotal(addCount: number, adder: (n: number) => number) {
let total = 0
for (let i = 0; i < addCount; i++) {
total += adder(i)
}
for (let i = 0; i < addCount; i++) total += adder(i)
return ~~total
}

Expand Down
10 changes: 5 additions & 5 deletions src/lib/shop/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,10 @@ export class ShopForm {
* @returns
*/
product = Product.create()
.creator<ShopForm>(
.creator<Product>(
product => {
this.buttons.push(product)
return this
return product
},
message => this.show(message),
)
Expand Down Expand Up @@ -132,9 +132,9 @@ export class ShopForm {
cost.buy(player)
player.container.addItem(item)
})
.texture(texture)
.sell(false)
.customCostBuy(true)
.setTexture(texture)
.setSell(false)
.setCustomCostBuy(true)

return this
}
Expand Down
61 changes: 36 additions & 25 deletions src/lib/shop/product.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type OnProductCreate<T> = (product: Product) => T
export class Product<T extends Cost = any> {
static create<C extends Cost>() {
let onCreateCallback: OnProductCreate<any> = s => s

return {
creator<P>(onCreate: OnProductCreate<P>, form: ProductBackForm) {
onCreateCallback = onCreate
Expand All @@ -31,24 +32,10 @@ export class Product<T extends Cost = any> {
player: (player: Player) => ({
name: (name: ProductName) => ({
cost: (cost: C) => ({
onBuy: (onBuy: ProductOnBuy) => ({
texture: (texture?: string) => ({
sell: (sell = false) => ({
customCostBuy: (customCostBuy = false) => {
const shop = new Product<C>(
name,
cost,
player,
customCostBuy ? onBuy : (...args) => (cost.buy(player), onBuy(...args)),
texture,
sell,
backForm,
)
return (onCreateCallback as OnProductCreate<P>)(shop)
},
}),
}),
}),
onBuy: (onBuy: ProductOnBuy) => {
const shop = new Product<C>(name, cost, player, onBuy, backForm)
return (onCreateCallback as OnProductCreate<P>)(shop)
},
}),
}),
}),
Expand All @@ -60,13 +47,32 @@ export class Product<T extends Cost = any> {
private nameGenerator: ProductName,
private cost: T,
private player: Player,
private onBuy: ProductOnBuy,
private onProductBuy: ProductOnBuy,
/** Texture represnting product */
public texture: string | undefined,
private sell: boolean,
private backForm: ProductBackForm,
) {}

private sell = false

setSell(value: boolean) {
this.sell = value
return this
}

private customCostBuy = false

setCustomCostBuy(value: boolean) {
this.customCostBuy = value
return this
}

public texture?: string

setTexture(texture: string) {
this.texture = texture
return this
}

private canBuy = this.cost.has(this.player)

private name = typeof this.nameGenerator === 'function' ? this.nameGenerator(this.canBuy) : this.nameGenerator
Expand Down Expand Up @@ -95,7 +101,9 @@ export class Product<T extends Cost = any> {
}

/* Action form button that represents this product */
button = [this.text, this.texture, this.callback] as const
get button() {
return [this.text, this.texture, this.callback] as const
}

private costString = this.cost.toString(true)

Expand All @@ -113,14 +121,17 @@ export class Product<T extends Cost = any> {

private buy = () => {
if (!this.ensurePlayerCanBuy()) return
const { onBuy, player, sell, name, backForm, costString } = this

const { sell, name, costString } = this
const successBuyText = sell
? t.options({ text: '§a' }).raw`Успешная продажа ${name} за ${costString}!`
: t.options({ text: '§a' }).raw`Успешная покупка ${name} за ${costString}!`

const successBuy = () => backForm(successBuyText)
const successBuy = () => this.backForm(successBuyText)

if (onBuy(player, name, successBuy, successBuyText) !== false) successBuy()
if (this.onBuy(this.player, name, successBuy, successBuyText) !== false) successBuy()
}

onBuy: ProductOnBuy = (...args) =>
this.customCostBuy ? (this.cost.buy(this.player), this.onProductBuy(...args)) : this.onProductBuy(...args)
}
4 changes: 4 additions & 0 deletions src/lib/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,7 @@ type Key = string | symbol | number
export function isKeyof<O extends Record<Key, unknown>>(key: Key, object: O): key is keyof O {
return key in object
}

/** Empty function that does nothing. */
// eslint-disable-next-line @typescript-eslint/no-empty-function
export const doNothing = () => {}
3 changes: 2 additions & 1 deletion src/modules/places/anarchy/anarchy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { GameMode, Player } from '@minecraft/server'
import { InventoryStore, Portal, ValidLocation, Vector, location, rawMessageToString } from 'lib'
import { Language } from 'lib/assets/lang'
import { isNotPlaying } from 'lib/game-utils'
import { itemDescription } from 'lib/shop/rewards'
import { t } from 'lib/text'
Expand Down Expand Up @@ -110,7 +111,7 @@ class AnarchyBuilder extends AreaWithInventory {
const inv = this.inventoryStore.get(player.id, { remove: false, fallback: InventoryStore.emptyInventory })

this.logger.player(player).info`Saved inventory:\n${Object.entries(inv.slots)
.map(([slot, item]) => ` §6${slot}§f ${rawMessageToString(itemDescription(item), 'ru_RU')}`)
.map(([slot, item]) => ` §6${slot}§f ${rawMessageToString(itemDescription(item), Language.ru_RU)}`)
.join('\n')}`

// Do not save location if on spawn
Expand Down
24 changes: 14 additions & 10 deletions src/modules/places/stone-quarry/gunsmith.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ export class Gunsmith extends ShopNpc {
).includes(item.typeId),
'Алмазный предмет',
(form, slot) => {
form.product('Улучшить', new MultiCost().item(i.NetheriteIngot, 1).money(1000), () =>
this.upgradeDiamondSwordToNetherite(slot, player),
)
form.product
.name('Улучшить')
.cost(new MultiCost().item(i.NetheriteIngot, 1).money(1000))
.onBuy(() => this.upgradeDiamondSwordToNetherite(slot, player))
},
)

Expand All @@ -48,13 +49,16 @@ export class Gunsmith extends ShopNpc {
const item = slot.getItem()
if (!item?.durability) return false

form.product('Починить', new MultiCost().xp(item.durability.damage / 10), () => {
if (item.durability) item.durability.damage = 0
const olditem = item.clone()
item.enchantable?.removeAllEnchantments()
this.copyEnchantments(item, olditem, player)
slot.setItem(item)
})
form.product
.name('Починить')
.cost(new MultiCost().xp(item.durability.damage / 10))
.onBuy(() => {
if (item.durability) item.durability.damage = 0
const olditem = item.clone()
item.enchantable?.removeAllEnchantments()
this.copyEnchantments(item, olditem, player)
slot.setItem(item)
})
},
)
})
Expand Down
77 changes: 39 additions & 38 deletions src/modules/places/village-of-explorers/mage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
MinecraftEnchantmentTypes,
MinecraftItemTypes,
} from '@minecraft/vanilla-data'
import { Enchantments, getAuxOrTexture, isKeyof } from 'lib'
import { doNothing, Enchantments, getAuxOrTexture, isKeyof } from 'lib'
import { Sounds } from 'lib/assets/custom-sounds'
import { Group } from 'lib/rpg/place'
import { Cost, MoneyCost, MultiCost } from 'lib/shop/cost'
Expand Down Expand Up @@ -78,10 +78,7 @@ export class Mage extends ShopNpc {
(bookForm, book, bookItem) => {
const bookEnch = bookItem.enchantable?.getEnchantments()[0]
const type = Object.values(MinecraftEnchantmentTypes).find(e => e === bookEnch?.type.id)
if (!bookEnch || !type)
return bookForm.product('Нет зачарований', Incompatible, () => {
return
})
if (!bookEnch || !type) return bookForm.product.name('Нет зачарований').cost(Incompatible).onBuy(doNothing)

bookForm.itemModifierSection(
'Предмет',
Expand All @@ -91,29 +88,29 @@ export class Mage extends ShopNpc {
const enchs = targetItem.enchantable?.getEnchantments().reduce((p, c) => p + c.level, 1) ?? 1
const level = targetItem.enchantable?.getEnchantment(new EnchantmentType(type))?.level ?? 0

itemForm.product(
t.raw`§r§7Выбранная книга: ${translateEnchantment(bookEnch)}`,
FreeCost,
() => bookForm.show(),
getAuxOrTexture(MinecraftItemTypes.EnchantedBook),
)
itemForm.product
.name(t.raw`§r§7Выбранная книга: ${translateEnchantment(bookEnch)}`)
.cost(FreeCost)
.onBuy(() => bookForm.show())
.setTexture(getAuxOrTexture(MinecraftItemTypes.EnchantedBook))

addSelectItem()

itemForm.product(
t.raw`Зачаровать`,
level >= bookEnch.level
? level === bookEnch.level
? LevelIsSame
: LevelIsHigher
: new MultiCost().money(1000).xp(~~((bookEnch.level * enchs) / 2)),
(_, __, _s, text) => {
itemForm.product
.name(t.raw`Зачаровать`)
.cost(
level >= bookEnch.level
? level === bookEnch.level
? LevelIsSame
: LevelIsHigher
: new MultiCost().money(1000).xp(~~((bookEnch.level * enchs) / 2)),
)
.onBuy((_, __, _s, text) => {
book.setItem(undefined)
this.updateEnchatnment(target, type, bookEnch.level - level)
form.show(text)
return false
},
)
})
},
true,
)
Expand All @@ -122,14 +119,17 @@ export class Mage extends ShopNpc {

form.section('Оружие со способностями', (form, player) => {
const cost = new MultiCost().item(i.DiamondSword).item(i.LapisLazuli, 100).item(i.Redstone, 100).money(10000)
form.product(`§r§fМеч со способностью §7${ItemAbility.names[ItemAbility.Ability.Vampire]}`, cost, player => {
if (!player.container) return
form.product
.name(`§r§fМеч со способностью §7${ItemAbility.names[ItemAbility.Ability.Vampire]}`)
.cost(cost)
.onBuy(player => {
if (!player.container) return

cost.buy(player)
player.container.addItem(
ItemAbility.schema.create({ ability: ItemAbility.Ability.Vampire }, i.DiamondSword).item,
)
})
cost.buy(player)
player.container.addItem(
ItemAbility.schema.create({ ability: ItemAbility.Ability.Vampire }, i.DiamondSword).item,
)
})
})

form.section('Все для магии', form =>
Expand Down Expand Up @@ -183,18 +183,19 @@ export class Mage extends ShopNpc {
createEnch(form: ShopFormSection, item: ItemStack, slot: ContainerSlot) {
return (type: e, getCost: (currentLevel: number) => Cost, up = 1) => {
const { can, level } = this.updateEnchatnment(slot, type, up, true)
form.product(
{ rawtext: [{ text: `${can ? '' : '§7'}+` }, ...(translateEnchantment(type).rawtext ?? [])] },
can
? new MultiCost(getCost(level)).item(MinecraftItemTypes.LapisLazuli, level)
: level === -1
? Incompatible
: MaxLevel,
player => {
form.product
.name({ rawtext: [{ text: `${can ? '' : '§7'}+` }, ...(translateEnchantment(type).rawtext ?? [])] })
.cost(
can
? new MultiCost(getCost(level)).item(MinecraftItemTypes.LapisLazuli, level)
: level === -1
? Incompatible
: MaxLevel,
)
.onBuy(player => {
this.updateEnchatnment(slot, type, up)
player.playSound(Sounds.LevelUp)
},
)
})
}
}

Expand Down

0 comments on commit 2abd9fe

Please sign in to comment.