Renamed buyables to repeatables

This commit is contained in:
thepaperpilot 2023-02-14 13:23:59 -06:00
parent 8987c0c69f
commit ccb8e76eaf

View file

@ -25,9 +25,9 @@ import { coerceComponent, isCoercableComponent } from "util/vue";
import type { Ref } from "vue"; import type { Ref } from "vue";
import { computed, unref } from "vue"; import { computed, unref } from "vue";
export const BuyableType = Symbol("Buyable"); export const RepeatableType = Symbol("Repeatable");
export type BuyableDisplay = export type RepeatableDisplay =
| CoercableComponent | CoercableComponent
| { | {
title?: CoercableComponent; title?: CoercableComponent;
@ -36,7 +36,7 @@ export type BuyableDisplay =
showAmount?: boolean; showAmount?: boolean;
}; };
export interface BuyableOptions { export interface RepeatableOptions {
visibility?: Computable<Visibility>; visibility?: Computable<Visibility>;
requirements: Requirements; requirements: Requirements;
purchaseLimit?: Computable<DecimalSource>; purchaseLimit?: Computable<DecimalSource>;
@ -46,24 +46,24 @@ export interface BuyableOptions {
mark?: Computable<boolean | string>; mark?: Computable<boolean | string>;
small?: Computable<boolean>; small?: Computable<boolean>;
buyMax?: Computable<boolean>; buyMax?: Computable<boolean>;
display?: Computable<BuyableDisplay>; display?: Computable<RepeatableDisplay>;
onPurchase?: VoidFunction; onPurchase?: VoidFunction;
} }
export interface BaseBuyable { export interface BaseRepeatable {
id: string; id: string;
amount: Persistent<DecimalSource>; amount: Persistent<DecimalSource>;
maxed: Ref<boolean>; maxed: Ref<boolean>;
canClick: ProcessedComputable<boolean>; canClick: ProcessedComputable<boolean>;
onClick: VoidFunction; onClick: VoidFunction;
purchase: VoidFunction; purchase: VoidFunction;
type: typeof BuyableType; type: typeof RepeatableType;
[Component]: typeof ClickableComponent; [Component]: typeof ClickableComponent;
[GatherProps]: () => Record<string, unknown>; [GatherProps]: () => Record<string, unknown>;
} }
export type Buyable<T extends BuyableOptions> = Replace< export type Repeatable<T extends RepeatableOptions> = Replace<
T & BaseBuyable, T & BaseRepeatable,
{ {
visibility: GetComputableTypeWithDefault<T["visibility"], Visibility.Visible>; visibility: GetComputableTypeWithDefault<T["visibility"], Visibility.Visible>;
requirements: GetComputableType<T["requirements"]>; requirements: GetComputableType<T["requirements"]>;
@ -77,90 +77,96 @@ export type Buyable<T extends BuyableOptions> = Replace<
} }
>; >;
export type GenericBuyable = Replace< export type GenericRepeatable = Replace<
Buyable<BuyableOptions>, Repeatable<RepeatableOptions>,
{ {
visibility: ProcessedComputable<Visibility>; visibility: ProcessedComputable<Visibility>;
purchaseLimit: ProcessedComputable<DecimalSource>; purchaseLimit: ProcessedComputable<DecimalSource>;
} }
>; >;
export function createBuyable<T extends BuyableOptions>( export function createRepeatable<T extends RepeatableOptions>(
optionsFunc: OptionsFunc<T, BaseBuyable, GenericBuyable> optionsFunc: OptionsFunc<T, BaseRepeatable, GenericRepeatable>
): Buyable<T> { ): Repeatable<T> {
const amount = persistent<DecimalSource>(0); const amount = persistent<DecimalSource>(0);
return createLazyProxy(() => { return createLazyProxy(() => {
const buyable = optionsFunc(); const repeatable = optionsFunc();
buyable.id = getUniqueID("buyable-"); repeatable.id = getUniqueID("repeatable-");
buyable.type = BuyableType; repeatable.type = RepeatableType;
buyable[Component] = ClickableComponent; repeatable[Component] = ClickableComponent;
buyable.amount = amount; repeatable.amount = amount;
buyable.amount[DefaultValue] = buyable.initialValue ?? 0; repeatable.amount[DefaultValue] = repeatable.initialValue ?? 0;
const limitRequirement = { const limitRequirement = {
requirementMet: computed(() => requirementMet: computed(() =>
Decimal.sub( Decimal.sub(
unref((buyable as GenericBuyable).purchaseLimit), unref((repeatable as GenericRepeatable).purchaseLimit),
(buyable as GenericBuyable).amount.value (repeatable as GenericRepeatable).amount.value
) )
), ),
requiresPay: false, requiresPay: false,
visibility: Visibility.None visibility: Visibility.None
} as const; } as const;
const visibilityRequirement = createVisibilityRequirement(buyable as GenericBuyable); const visibilityRequirement = createVisibilityRequirement(repeatable as GenericRepeatable);
if (isArray(buyable.requirements)) { if (isArray(repeatable.requirements)) {
buyable.requirements.unshift(visibilityRequirement); repeatable.requirements.unshift(visibilityRequirement);
buyable.requirements.push(limitRequirement); repeatable.requirements.push(limitRequirement);
} else { } else {
buyable.requirements = [visibilityRequirement, buyable.requirements, limitRequirement]; repeatable.requirements = [
visibilityRequirement,
repeatable.requirements,
limitRequirement
];
} }
buyable.maxed = computed(() => repeatable.maxed = computed(() =>
Decimal.gte( Decimal.gte(
(buyable as GenericBuyable).amount.value, (repeatable as GenericRepeatable).amount.value,
unref((buyable as GenericBuyable).purchaseLimit) unref((repeatable as GenericRepeatable).purchaseLimit)
) )
); );
processComputable(buyable as T, "classes"); processComputable(repeatable as T, "classes");
const classes = buyable.classes as ProcessedComputable<Record<string, boolean>> | undefined; const classes = repeatable.classes as
buyable.classes = computed(() => { | ProcessedComputable<Record<string, boolean>>
| undefined;
repeatable.classes = computed(() => {
const currClasses = unref(classes) || {}; const currClasses = unref(classes) || {};
if ((buyable as GenericBuyable).maxed.value) { if ((repeatable as GenericRepeatable).maxed.value) {
currClasses.bought = true; currClasses.bought = true;
} }
return currClasses; return currClasses;
}); });
buyable.canClick = computed(() => requirementsMet(buyable.requirements)); repeatable.canClick = computed(() => requirementsMet(repeatable.requirements));
buyable.onClick = buyable.purchase = repeatable.onClick = repeatable.purchase =
buyable.onClick ?? repeatable.onClick ??
buyable.purchase ?? repeatable.purchase ??
function (this: GenericBuyable) { function (this: GenericRepeatable) {
const genericBuyable = buyable as GenericBuyable; const genericRepeatable = repeatable as GenericRepeatable;
if (!unref(genericBuyable.canClick)) { if (!unref(genericRepeatable.canClick)) {
return; return;
} }
payRequirements( payRequirements(
buyable.requirements, repeatable.requirements,
unref(genericBuyable.buyMax) unref(genericRepeatable.buyMax)
? maxRequirementsMet(genericBuyable.requirements) ? maxRequirementsMet(genericRepeatable.requirements)
: 1 : 1
); );
genericBuyable.amount.value = Decimal.add(genericBuyable.amount.value, 1); genericRepeatable.amount.value = Decimal.add(genericRepeatable.amount.value, 1);
genericBuyable.onPurchase?.(); genericRepeatable.onPurchase?.();
}; };
processComputable(buyable as T, "display"); processComputable(repeatable as T, "display");
const display = buyable.display; const display = repeatable.display;
buyable.display = jsx(() => { repeatable.display = jsx(() => {
// TODO once processComputable types correctly, remove this "as X" // TODO once processComputable types correctly, remove this "as X"
const currDisplay = unref(display) as BuyableDisplay; const currDisplay = unref(display) as RepeatableDisplay;
if (isCoercableComponent(currDisplay)) { if (isCoercableComponent(currDisplay)) {
const CurrDisplay = coerceComponent(currDisplay); const CurrDisplay = coerceComponent(currDisplay);
return <CurrDisplay />; return <CurrDisplay />;
} }
if (currDisplay != null) { if (currDisplay != null) {
const genericBuyable = buyable as GenericBuyable; const genericRepeatable = repeatable as GenericRepeatable;
const Title = coerceComponent(currDisplay.title ?? "", "h3"); const Title = coerceComponent(currDisplay.title ?? "", "h3");
const Description = coerceComponent(currDisplay.description ?? ""); const Description = coerceComponent(currDisplay.description ?? "");
const EffectDisplay = coerceComponent(currDisplay.effectDisplay ?? ""); const EffectDisplay = coerceComponent(currDisplay.effectDisplay ?? "");
@ -176,12 +182,12 @@ export function createBuyable<T extends BuyableOptions>(
{currDisplay.showAmount === false ? null : ( {currDisplay.showAmount === false ? null : (
<div> <div>
<br /> <br />
{unref(genericBuyable.purchaseLimit) === Decimal.dInf ? ( {unref(genericRepeatable.purchaseLimit) === Decimal.dInf ? (
<>Amount: {formatWhole(genericBuyable.amount.value)}</> <>Amount: {formatWhole(genericRepeatable.amount.value)}</>
) : ( ) : (
<> <>
Amount: {formatWhole(genericBuyable.amount.value)} /{" "} Amount: {formatWhole(genericRepeatable.amount.value)} /{" "}
{formatWhole(unref(genericBuyable.purchaseLimit))} {formatWhole(unref(genericRepeatable.purchaseLimit))}
</> </>
)} )}
</div> </div>
@ -192,13 +198,13 @@ export function createBuyable<T extends BuyableOptions>(
Currently: <EffectDisplay /> Currently: <EffectDisplay />
</div> </div>
)} )}
{genericBuyable.maxed.value ? null : ( {genericRepeatable.maxed.value ? null : (
<div> <div>
<br /> <br />
{displayRequirements( {displayRequirements(
genericBuyable.requirements, genericRepeatable.requirements,
unref(genericBuyable.buyMax) unref(genericRepeatable.buyMax)
? maxRequirementsMet(genericBuyable.requirements) ? maxRequirementsMet(genericRepeatable.requirements)
: 1 : 1
)} )}
</div> </div>
@ -209,16 +215,16 @@ export function createBuyable<T extends BuyableOptions>(
return ""; return "";
}); });
processComputable(buyable as T, "visibility"); processComputable(repeatable as T, "visibility");
setDefault(buyable, "visibility", Visibility.Visible); setDefault(repeatable, "visibility", Visibility.Visible);
processComputable(buyable as T, "purchaseLimit"); processComputable(repeatable as T, "purchaseLimit");
setDefault(buyable, "purchaseLimit", Decimal.dInf); setDefault(repeatable, "purchaseLimit", Decimal.dInf);
processComputable(buyable as T, "style"); processComputable(repeatable as T, "style");
processComputable(buyable as T, "mark"); processComputable(repeatable as T, "mark");
processComputable(buyable as T, "small"); processComputable(repeatable as T, "small");
processComputable(buyable as T, "buyMax"); processComputable(repeatable as T, "buyMax");
buyable[GatherProps] = function (this: GenericBuyable) { repeatable[GatherProps] = function (this: GenericRepeatable) {
const { display, visibility, style, classes, onClick, canClick, small, mark, id } = const { display, visibility, style, classes, onClick, canClick, small, mark, id } =
this; this;
return { return {
@ -234,6 +240,6 @@ export function createBuyable<T extends BuyableOptions>(
}; };
}; };
return buyable as unknown as Buyable<T>; return repeatable as unknown as Repeatable<T>;
}); });
} }