Oil prototype

This commit is contained in:
ducdat0507 2022-12-08 21:04:58 +07:00
parent 132ef32525
commit 6a9e3cc1ac
7 changed files with 1250 additions and 52 deletions

View file

@ -5,5 +5,8 @@
}, },
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "esbenp.prettier-vscode",
"git.ignoreLimitWarning": true, "git.ignoreLimitWarning": true,
"typescript.tsdk": "node_modules/typescript/lib", "[typescriptreact]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"typescript.tsdk": "node_modules/typescript/lib"
} }

View file

@ -44,8 +44,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
width: 100, width: 100,
height: 10, height: 10,
style: "margin-top: 8px", style: "margin-top: 8px",
borderStyle: "border-color: black",
baseStyle: "margin-top: 0", baseStyle: "margin-top: 0",
fillStyle: "margin-top: 0; transition-duration: 0s", fillStyle: "margin-top: 0; transition-duration: 0s; background: black",
progress: () => Decimal.div(breedingProgress.value, computedBreedingCooldown.value) progress: () => Decimal.div(breedingProgress.value, computedBreedingCooldown.value)
})); }));
const breeding = createClickable(() => ({ const breeding = createClickable(() => ({
@ -79,8 +80,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
width: 100, width: 100,
height: 10, height: 10,
style: "margin-top: 8px", style: "margin-top: 8px",
borderStyle: "border-color: black",
baseStyle: "margin-top: 0", baseStyle: "margin-top: 0",
fillStyle: "margin-top: 0; transition-duration: 0s", fillStyle: "margin-top: 0; transition-duration: 0s; background: black",
progress: () => Decimal.div(shearingProgress.value, computedShearingCooldown.value) progress: () => Decimal.div(shearingProgress.value, computedShearingCooldown.value)
})); }));
const shearing = createClickable(() => ({ const shearing = createClickable(() => ({
@ -114,8 +116,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
width: 100, width: 100,
height: 10, height: 10,
style: "margin-top: 8px", style: "margin-top: 8px",
borderStyle: "border-color: black",
baseStyle: "margin-top: 0", baseStyle: "margin-top: 0",
fillStyle: "margin-top: 0; transition-duration: 0s", fillStyle: "margin-top: 0; transition-duration: 0s; background: black",
progress: () => Decimal.div(spinningProgress.value, computedSpinningCooldown.value) progress: () => Decimal.div(spinningProgress.value, computedSpinningCooldown.value)
})); }));
const spinning = createClickable(() => ({ const spinning = createClickable(() => ({

View file

@ -27,7 +27,7 @@ import {
createSequentialModifier, createSequentialModifier,
Modifier Modifier
} from "game/modifiers"; } from "game/modifiers";
import { createUpgrade, Upgrade } from "features/upgrades/upgrade"; import { createUpgrade, Upgrade, UpgradeOptions } from "features/upgrades/upgrade";
import elves from "./elves"; import elves from "./elves";
import paper from "./paper"; import paper from "./paper";
import boxes from "./boxes"; import boxes from "./boxes";
@ -35,6 +35,7 @@ import metal from "./metal";
import { cloneWithoutLoc } from "@babel/types"; import { cloneWithoutLoc } from "@babel/types";
import cloth from "./cloth"; import cloth from "./cloth";
import { WithRequired } from "util/common"; import { WithRequired } from "util/common";
import oil from "./oil";
interface BetterFertilizerUpgOptions { interface BetterFertilizerUpgOptions {
canAfford: () => boolean; canAfford: () => boolean;
@ -53,6 +54,16 @@ interface UnlockKilnUpgOptions {
style: StyleValue; style: StyleValue;
visibility: () => Visibility; visibility: () => Visibility;
} }
interface EfficientSmeltherUpgOptions {
resource: Resource;
cost: DecimalSource;
display: {
title: string;
description: string;
};
style: StyleValue;
visibility: () => Visibility;
}
const id = "coal"; const id = "coal";
const day = 3; const day = 3;
@ -144,8 +155,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
activeFires.value = buildFire.amount.value; activeFires.value = buildFire.amount.value;
} }
})); }));
const fireResource = createResource(buildFire.amount, "small fires"); const fireResource = createResource(buildFire.amount, "small fires");
const activeBonfires = persistent<DecimalSource>(0); const activeBonfires = persistent<DecimalSource>(0);
const bonfireLogs = computed(() => Decimal.times(activeBonfires.value, 10000)); const bonfireLogs = computed(() => Decimal.times(activeBonfires.value, 10000));
const bonfireCoal = computed(() => Decimal.times(activeBonfires.value, 10)); const bonfireCoal = computed(() => Decimal.times(activeBonfires.value, 10));
@ -302,7 +313,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
})); }));
const activeDrills = persistent<DecimalSource>(0); const activeDrills = persistent<DecimalSource>(0);
const drillCoal = computed(() => Decimal.times(activeDrills.value, 5e7)); const drillCoal = computed(() => Decimal.times(Decimal.pow(activeDrills.value, oil.row2Upgrades[1].bought.value ? 2 : 1), 5e7).times(metal.efficientDrill.bought.value ? 2 : 1));
const buildDrill = createBuyable(() => ({ const buildDrill = createBuyable(() => ({
resource: metal.metal, resource: metal.metal,
cost() { cost() {
@ -473,6 +484,18 @@ const layer = createLayer(id, function (this: BaseLayer) {
})); }));
const row2upgrades = [dedicatedCutters, dedicatedPlanters, betterFertilizer, unlockKiln]; const row2upgrades = [dedicatedCutters, dedicatedPlanters, betterFertilizer, unlockKiln];
const efficientSmelther: Upgrade<EfficientSmeltherUpgOptions> = createUpgrade(() => ({
resource: coal,
cost: 1e19,
display: {
title: "Efficient Crucibles",
description: "Double auto smelting speed and triple metal gain from auto smelting"
},
style: { color: colorText },
visibility: () => showIf(oil.depthMilestones[4].earned.value)
}));
const row3upgrades = [efficientSmelther];
const heatedCutters = createBuyable(() => ({ const heatedCutters = createBuyable(() => ({
resource: noPersist(coal), resource: noPersist(coal),
cost() { cost() {
@ -666,7 +689,17 @@ const layer = createLayer(id, function (this: BaseLayer) {
description: "3 Elves Trained", description: "3 Elves Trained",
enabled: elves.milestones[2].earned, enabled: elves.milestones[2].earned,
supportLowNumbers: true supportLowNumbers: true
})) })),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.mul(oil.depth.value, 0.25).add(1),
description: "5m Well Depth",
enabled: oil.depthMilestones[0].earned,
})),
createMultiplicativeModifier(() => ({
multiplier: oil.extractorCoal,
description: "Heavy Extractor",
enabled: () => Decimal.gt(oil.activeExtractor.value, 0)
})),
]) as WithRequired<Modifier, "description" | "revert">; ]) as WithRequired<Modifier, "description" | "revert">;
const computedCoalGain = computed(() => coalGain.apply(0)); const computedCoalGain = computed(() => coalGain.apply(0));
@ -861,6 +894,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
dedicatedPlanters, dedicatedPlanters,
betterFertilizer, betterFertilizer,
unlockKiln, unlockKiln,
efficientSmelther,
heatedCutters, heatedCutters,
heatedPlanters, heatedPlanters,
moreFertilizer, moreFertilizer,
@ -947,6 +981,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
<Spacer /> <Spacer />
{renderRow(...row1upgrades)} {renderRow(...row1upgrades)}
{renderRow(...row2upgrades)} {renderRow(...row2upgrades)}
{renderRow(...row3upgrades)}
{renderRow(...row3buyables)} {renderRow(...row3buyables)}
</> </>
)) ))

View file

@ -25,6 +25,7 @@ import { createUpgrade, GenericUpgrade } from "features/upgrades/upgrade";
import { noPersist } from "game/persistence"; import { noPersist } from "game/persistence";
import { createBuyable, GenericBuyable } from "features/buyable"; import { createBuyable, GenericBuyable } from "features/buyable";
import { main } from "../projEntry"; import { main } from "../projEntry";
import oil from "./oil";
const id = "metal"; const id = "metal";
const day = 7; const day = 7;
@ -67,9 +68,32 @@ const layer = createLayer(id, function (this: BaseLayer) {
addend: () => Decimal.times(industrialCrucible.amount.value, 10), addend: () => Decimal.times(industrialCrucible.amount.value, 10),
description: "Industrial Crucibles", description: "Industrial Crucibles",
enabled: () => Decimal.gte(industrialCrucible.amount.value, 1) enabled: () => Decimal.gte(industrialCrucible.amount.value, 1)
})) })),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "Efficient Crucibles",
enabled: coal.efficientSmelther.bought
})),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.mul(oil.activeSmelter.value, oil.oilEffectiveness.value).add(1),
description: "Oil Smelter",
enabled: () => Decimal.gt(oil.activeSmelter.value, 0)
})),
]); ]);
const computedAutoSmeltSpeed = computed(() => autoSmeltSpeed.apply(0)); const computedAutoSmeltSpeed = computed(() => autoSmeltSpeed.apply(0));
const autoSmeltMulti = createSequentialModifier(() => [
createMultiplicativeModifier(() => ({
multiplier: 3,
description: "Efficient Crucibles",
enabled: coal.efficientSmelther.bought
})),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.add(oil.activeBurner.value, 1).mul(oil.oilEffectiveness.value),
description: "Blaster Burner",
enabled: oil.row2Upgrades[2].bought
})),
]);
const computedAutoSmeltMulti = computed(() => autoSmeltMulti.apply(1));
const coalCost = 1e10; const coalCost = 1e10;
const smeltableOre = computed(() => const smeltableOre = computed(() =>
@ -106,9 +130,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
minHeight: "unset" minHeight: "unset"
} }
})); }));
function smeltOre(amount: DecimalSource) { function smeltOre(amount: DecimalSource, multi: DecimalSource = 1) {
const [metalGain, oreConsumption, coalConsumption] = [ const [metalGain, oreConsumption, coalConsumption] = [
Decimal.times(amount, computedOrePurity.value), Decimal.times(amount, computedOrePurity.value).times(multi),
amount, amount,
Decimal.times(amount, coalCost) Decimal.times(amount, coalCost)
]; ];
@ -122,7 +146,17 @@ const layer = createLayer(id, function (this: BaseLayer) {
addend: () => oreDrill.amount.value, addend: () => oreDrill.amount.value,
description: "Mining Drills", description: "Mining Drills",
enabled: () => Decimal.gte(oreDrill.amount.value, 1) enabled: () => Decimal.gte(oreDrill.amount.value, 1)
})) })),
createMultiplicativeModifier(() => ({
multiplier: () => Decimal.mul(oil.depth.value, 0.05).add(1),
description: "25m Well Depth",
enabled: oil.depthMilestones[2].earned,
})),
createMultiplicativeModifier(() => ({
multiplier: oil.extractorOre,
description: "Heavy Extractor",
enabled: () => Decimal.gt(oil.activeExtractor.value, 0)
})),
]); ]);
const computedOreAmount = computed(() => oreAmount.apply(1)); const computedOreAmount = computed(() => oreAmount.apply(1));
const oreSpeed = createSequentialModifier(() => [ const oreSpeed = createSequentialModifier(() => [
@ -140,9 +174,19 @@ const layer = createLayer(id, function (this: BaseLayer) {
multiplier: 2.5, multiplier: 2.5,
description: "Mining Drills", description: "Mining Drills",
enabled: () => Decimal.gte(oreDrill.amount.value, 1) enabled: () => Decimal.gte(oreDrill.amount.value, 1)
})),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "Efficient Drills",
enabled: efficientDrill.bought
})),
createMultiplicativeModifier(() => ({
multiplier: 2,
description: "Oil the Mining Drills",
enabled: oil.row2Upgrades[1].bought
})) }))
]); ]);
const computedOreSpeed = computed(() => oreSpeed.apply(1)); const computedOreSpeed = computed(() => oreSpeed.apply(Decimal.recip(maxOreProgress)));
const oreProgress = persistent<DecimalSource>(0); const oreProgress = persistent<DecimalSource>(0);
const maxOreProgress = 10; const maxOreProgress = 10;
const oreBar = createBar(() => ({ const oreBar = createBar(() => ({
@ -150,7 +194,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
height: 25, height: 25,
direction: Direction.Right, direction: Direction.Right,
fillStyle: { backgroundColor: color }, fillStyle: { backgroundColor: color },
progress: () => Decimal.div(oreProgress.value, maxOreProgress) progress: () => oreProgress.value
})); }));
const oreGain = createSequentialModifier(() => [ const oreGain = createSequentialModifier(() => [
@ -160,9 +204,6 @@ const layer = createLayer(id, function (this: BaseLayer) {
createMultiplicativeModifier(() => ({ createMultiplicativeModifier(() => ({
multiplier: computedOreSpeed multiplier: computedOreSpeed
})), })),
createMultiplicativeModifier(() => ({
multiplier: Decimal.reciprocate(maxOreProgress)
}))
]); ]);
const computedOreGain = computed(() => oreGain.apply(0)); const computedOreGain = computed(() => oreGain.apply(0));
const netOreGain = createSequentialModifier(() => [ const netOreGain = createSequentialModifier(() => [
@ -176,6 +217,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
]); ]);
const computedNetOreGain = computed(() => netOreGain.apply(0)); const computedNetOreGain = computed(() => netOreGain.apply(0));
const simplePickaxe = createUpgrade(() => ({ const simplePickaxe = createUpgrade(() => ({
resource: noPersist(metal), resource: noPersist(metal),
cost: 0.1, cost: 0.1,
@ -206,7 +248,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
visibility: () => visibility: () =>
showIf( showIf(
crucible.bought.value || crucible.bought.value ||
Decimal.div(bestOre.value, computedOrePurity.value).plus(bestMetal.value).gte(1) Decimal.div(bestOre.value, computedOrePurity.value).plus(bestMetal.value).gte(1)
) )
})) as GenericUpgrade; })) as GenericUpgrade;
const coalDrill = createUpgrade(() => ({ const coalDrill = createUpgrade(() => ({
@ -220,13 +262,12 @@ const layer = createLayer(id, function (this: BaseLayer) {
visibility: () => visibility: () =>
showIf( showIf(
Decimal.gte(oreDrill.amount.value, 1) && Decimal.gte(oreDrill.amount.value, 1) &&
(coalDrill.bought.value || (coalDrill.bought.value ||
Decimal.lt( Decimal.lt(
coal.computedCoalGain.value, coal.computedCoalGain.value,
Decimal.times(computedOreAmount.value, computedOreSpeed.value) Decimal.times(computedOreAmount.value, computedOreSpeed.value)
.div(maxOreProgress) .times(coalCost)
.times(coalCost) ))
))
), ),
onPurchase() { onPurchase() {
main.days[2].recentlyUpdated.value = true; main.days[2].recentlyUpdated.value = true;
@ -248,6 +289,16 @@ const layer = createLayer(id, function (this: BaseLayer) {
Cost: 50 ${metal.displayName}<br/>${format(1e11)} ${coal.coal.displayName}` Cost: 50 ${metal.displayName}<br/>${format(1e11)} ${coal.coal.displayName}`
} }
})); }));
const efficientDrill = createUpgrade(() => ({
resource: noPersist(metal),
cost: 100000,
display: {
title: "Efficient Drills",
description: `Use metal and a bunch of R&D to make drilling stuff faster. Double coal and ore mining speed.`
},
visibilty: () => showIf(oil.depthMilestones[4].earned.value)
}));
const oreDrill = createBuyable(() => ({ const oreDrill = createBuyable(() => ({
resource: noPersist(metal), resource: noPersist(metal),
@ -267,9 +318,9 @@ const layer = createLayer(id, function (this: BaseLayer) {
visibility: () => visibility: () =>
showIf( showIf(
Decimal.gte(oreDrill.amount.value, 1) || Decimal.gte(oreDrill.amount.value, 1) ||
Decimal.div(bestOre.value, computedOrePurity.value) Decimal.div(bestOre.value, computedOrePurity.value)
.plus(bestMetal.value) .plus(bestMetal.value)
.gte(10) .gte(10)
), ),
style: { width: "200px" } style: { width: "200px" }
})) as GenericBuyable; })) as GenericBuyable;
@ -291,8 +342,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
visibility: () => visibility: () =>
showIf( showIf(
Decimal.gte(industrialCrucible.amount.value, 1) || Decimal.gte(industrialCrucible.amount.value, 1) ||
Decimal.gte(oreDrill.amount.value, 4) || Decimal.gte(oreDrill.amount.value, 4) ||
Decimal.gte(bestOre.value, 50) Decimal.gte(bestOre.value, 50)
), ),
style: { width: "200px" } style: { width: "200px" }
})) as GenericBuyable; })) as GenericBuyable;
@ -321,29 +372,38 @@ const layer = createLayer(id, function (this: BaseLayer) {
globalBus.on("update", diff => { globalBus.on("update", diff => {
oreProgress.value = Decimal.times(diff, computedOreSpeed.value).plus(oreProgress.value); oreProgress.value = Decimal.times(diff, computedOreSpeed.value).plus(oreProgress.value);
const oreGain = oreProgress.value.div(maxOreProgress).trunc(); const oreGain = oreProgress.value.trunc();
oreProgress.value = oreProgress.value.minus(oreGain.times(maxOreProgress)); oreProgress.value = oreProgress.value.minus(oreGain);
ore.value = Decimal.add(ore.value, Decimal.times(oreGain, computedOreAmount.value)); ore.value = Decimal.add(ore.value, Decimal.times(oreGain, computedOreAmount.value));
if (autoSmeltEnabled.value) { if (autoSmeltEnabled.value) {
smeltOre( smeltOre(
Decimal.min( Decimal.min(
smeltableOre.value, smeltableOre.value,
Decimal.times(industrialCrucible.amount.value, 10).times(diff) Decimal.times(computedAutoSmeltSpeed.value, diff)
) ), computedAutoSmeltMulti.value
); );
} }
}); });
const [generalTab, generalTabCollapsed] = createCollapsibleModifierSections(() => [ const [generalTab, generalTabCollapsed] = createCollapsibleModifierSections(() => [
{ {
title: "Automatic Smelting", title: "Auto Smelt Speed",
modifier: autoSmeltSpeed, modifier: autoSmeltSpeed,
base: 0, base: 0,
unit: "/s",
visible() { visible() {
return Decimal.gt(industrialCrucible.amount.value, 0); return Decimal.gt(industrialCrucible.amount.value, 0);
} }
}, },
{
title: "Auto Smelt Multiplier",
modifier: autoSmeltMulti,
base: 1,
visible() {
return Decimal.gt(computedAutoSmeltMulti.value, 1);
}
},
{ {
title: "Metal per Ore", title: "Metal per Ore",
modifier: orePurity, modifier: orePurity,
@ -357,7 +417,8 @@ const layer = createLayer(id, function (this: BaseLayer) {
{ {
title: "Mining Speed", title: "Mining Speed",
modifier: oreSpeed, modifier: oreSpeed,
base: 1 base: 0.1,
unit: "/s",
} }
]); ]);
const showModifiersModal = ref(false); const showModifiersModal = ref(false);
@ -399,6 +460,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
crucible, crucible,
coalDrill, coalDrill,
industrialFurnace, industrialFurnace,
efficientDrill,
oreDrill, oreDrill,
industrialCrucible, industrialCrucible,
autoSmeltEnabled, autoSmeltEnabled,
@ -418,14 +480,14 @@ const layer = createLayer(id, function (this: BaseLayer) {
<> <>
{autoSmeltEnabled.value && Decimal.gte(industrialCrucible.amount.value, 1) {autoSmeltEnabled.value && Decimal.gte(industrialCrucible.amount.value, 1)
? `+${formatLimit( ? `+${formatLimit(
[ [
[computedAutoSmeltSpeed.value, "smelting speed"], [computedAutoSmeltSpeed.value, "smelting speed"],
[computedOreGain.value, "ore gain"], [computedOreGain.value, "ore gain"],
[Decimal.div(coal.computedCoalGain.value, coalCost), "coal gain"] [Decimal.div(coal.computedCoalGain.value, coalCost), "coal gain"]
], ],
"/s", "/s",
computedOrePurity.value Decimal.mul(computedOrePurity.value, computedAutoSmeltMulti.value)
)}` )}`
: undefined} : undefined}
</> </>
))} ))}
@ -437,7 +499,7 @@ const layer = createLayer(id, function (this: BaseLayer) {
<Toggle <Toggle
title="Auto Smelt" title="Auto Smelt"
modelValue={autoSmeltEnabled.value} modelValue={autoSmeltEnabled.value}
onUpdate:modelValue={value => (autoSmeltEnabled.value = value)} onUpdate:modelValue={(value: boolean) => (autoSmeltEnabled.value = value)}
/> />
</div> </div>
) : undefined} ) : undefined}
@ -454,11 +516,11 @@ const layer = createLayer(id, function (this: BaseLayer) {
<Spacer /> <Spacer />
<div> <div>
Currently mining {format(computedOreAmount.value)} ore every{" "} Currently mining {format(computedOreAmount.value)} ore every{" "}
{format(Decimal.div(maxOreProgress, computedOreSpeed.value))} seconds {format(Decimal.recip(computedOreSpeed.value))} seconds
</div> </div>
{render(oreBar)} {render(oreBar)}
<Spacer /> <Spacer />
{renderRow(simplePickaxe, doublePickaxe, crucible, coalDrill, industrialFurnace)} {renderRow(simplePickaxe, doublePickaxe, crucible, coalDrill, industrialFurnace, efficientDrill)}
{renderRow(oreDrill, industrialCrucible, hotterForge)} {renderRow(oreDrill, industrialCrucible, hotterForge)}
</> </>
)) ))

1094
src/data/layers/oil.tsx Normal file

File diff suppressed because it is too large Load diff

View file

@ -34,6 +34,7 @@ import paper from "./layers/paper";
import boxes from "./layers/boxes"; import boxes from "./layers/boxes";
import metal from "./layers/metal"; import metal from "./layers/metal";
import cloth from "./layers/cloth"; import cloth from "./layers/cloth";
import oil from "./layers/oil";
export interface Day extends VueFeature { export interface Day extends VueFeature {
day: number; day: number;
@ -225,10 +226,10 @@ export const main = createLayer("main", function (this: BaseLayer) {
createDay(() => ({ createDay(() => ({
day: 9, day: 9,
shouldNotify: false, shouldNotify: false,
layer: null, // "oil" layer: "oil",
symbol: "", symbol: "",
story: "", story: "Looks like you just need one more thing before the toy factory can get running: plastic! Every toy nowadays is made with plastic! But wait, how are you going to get plastic? What can make plastic? Wait that's right, oil! You figured out you might as well repurpose your coal and ore drills into something that can get you oil, unfortunately you'll need to mine much deeper that you're currently doing before, so let's get to work!",
completedStory: "" completedStory: "It took a while, but you finally got enough oil for the next step! You deserve a good rest after all these digging work - tomorrow will be a busy day! Good Job!"
})), })),
createDay(() => ({ createDay(() => ({
day: 10, day: 10,
@ -409,7 +410,7 @@ export const main = createLayer("main", function (this: BaseLayer) {
export const getInitialLayers = ( export const getInitialLayers = (
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
player: Partial<PlayerData> player: Partial<PlayerData>
): Array<GenericLayer> => [main, trees, workshop, coal, elves, paper, boxes, metal, cloth]; ): Array<GenericLayer> => [main, trees, workshop, coal, elves, paper, boxes, metal, cloth, oil];
/** /**
* A computed ref whose value is true whenever the game is over. * A computed ref whose value is true whenever the game is over.