Set up main display including component coercion

This commit is contained in:
thepaperpilot 2021-05-27 01:14:43 -05:00
parent b91a7cdc28
commit e6676d48fc
25 changed files with 457 additions and 129 deletions

15
package-lock.json generated
View file

@ -10,6 +10,7 @@
"dependencies": {
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-fragment": "^1.5.2",
"vue-select": "^3.11.2",
"vuex": "^3.4.0"
},
@ -13458,6 +13459,14 @@
"node": ">=8.0.0"
}
},
"node_modules/vue-fragment": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/vue-fragment/-/vue-fragment-1.5.2.tgz",
"integrity": "sha512-KEW0gkeNOLJjtXN4jqJhTazez5jtrwimHkE5Few/VxblH4F9EcvJiEsahrV5kg5uKd5U8du4ORKS6QjGE0piYA==",
"peerDependencies": {
"vue": "^2.5.16"
}
},
"node_modules/vue-hot-reload-api": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",
@ -25801,6 +25810,12 @@
}
}
},
"vue-fragment": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/vue-fragment/-/vue-fragment-1.5.2.tgz",
"integrity": "sha512-KEW0gkeNOLJjtXN4jqJhTazez5jtrwimHkE5Few/VxblH4F9EcvJiEsahrV5kg5uKd5U8du4ORKS6QjGE0piYA==",
"requires": {}
},
"vue-hot-reload-api": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.4.tgz",

View file

@ -10,6 +10,7 @@
"dependencies": {
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-fragment": "^1.5.2",
"vue-select": "^3.11.2",
"vuex": "^3.4.0"
},

View file

@ -0,0 +1,49 @@
<template>
<div>
<span v-if="showPrefix">You have</span>
<resource :amount="amount" :color="color" />
{{ resource }}<!-- remove whitespace -->
<span v-if="effectDescription">, <component :is="effectDescription" /></span>
<br><br>
</div>
</template>
<script>
import { player } from '../../store/proxies';
import { layers } from '../../store/layers';
import { format, formatWhole } from '../../util/bignum';
import { coerceComponent } from '../../util/vue';
export default {
name: 'main-display',
inject: [ 'layer' ],
props: {
precision: Number
},
computed: {
style() {
return layers[this.layer].componentStyles?.['main-display'];
},
resource() {
return layers[this.layer].resource;
},
effectDescription() {
return coerceComponent(layers[this.layer].effectDescription);
},
showPrefix() {
return player[this.layer].points.lt('1e1000');
},
color() {
return layers[this.layer].color;
},
amount() {
return this.precision == undefined ?
formatWhole(player[this.layer].points) :
format(player[this.layer].points, this.precision);
}
}
};
</script>
<style scoped>
</style>

42
src/components/index.js Normal file
View file

@ -0,0 +1,42 @@
// Import and register all components,
// which will allow us to use them in any template strings anywhere in the project
import Vue from 'vue';
/* system */
import DefaultLayerTab from './system/DefaultLayerTab';
import Info from './system/Info';
import LayerProvider from './system/LayerProvider';
import LayerTab from './system/LayerTab';
import Modal from './system/Modal';
import Nav from './system/Nav';
import Options from './system/Options';
import Resource from './system/Resource';
import Tabs from './system/Tabs';
import TPS from './system/TPS';
/* fields */
import Select from './fields/Select';
import Toggle from './fields/Toggle';
/* features */
import MainDisplay from './features/MainDisplay';
/* misc */
import { Fragment } from 'vue-fragment';
/* system */
Vue.component(DefaultLayerTab.name, DefaultLayerTab);
Vue.component(Info.name, Info);
Vue.component(LayerProvider.name, LayerProvider);
Vue.component(LayerTab.name, LayerTab);
Vue.component(Modal.name, Modal);
Vue.component(Nav.name, Nav);
Vue.component(Options.name, Options);
Vue.component(Resource.name, Resource);
Vue.component(Tabs.name, Tabs);
Vue.component(TPS.name, TPS);
/* fields */
Vue.component(Select.name, Select);
Vue.component(Toggle.name, Toggle);
/* features */
Vue.component(MainDisplay.name, MainDisplay);
/* misc */
Vue.component(Fragment.name, Fragment);

View file

@ -0,0 +1,38 @@
<template>
<fragment>
<infobox v-if="infobox != undefined" :id="infobox" />
<main-display />
<prestige-button v-if="type !== 'none'" />
<resource-display />
<milestones />
<component v-if="midsection" :is="midsection" />
<clickables />
<buyables />
<upgrades />
<challenges />
<achievements />
</fragment>
</template>
<script>
import { layers } from '../../store/layers';
export default {
name: 'default-layer-tab',
inject: [ 'layer' ],
computed: {
infobox() {
return layers[this.layer].infoboxes && Object.keys(layers[this.layer].infoboxes)[0];
},
type() {
return layers[this.layer].type;
},
midsection() {
return layers[this.layer].midsection;
}
}
};
</script>
<style scoped>
</style>

View file

@ -54,7 +54,6 @@
</template>
<script>
import Modal from './Modal';
import modInfo from '../../data/modInfo';
import { formatTime } from '../../util/bignum';
@ -67,9 +66,6 @@ export default {
props: {
show: Boolean
},
components: {
Modal
},
computed: {
timePlayed() {
return formatTime(this.$store.state.timePlayed);

View file

@ -1,5 +1,7 @@
<template>
<span><slot /></span>
<fragment>
<slot />
</fragment>
</template>
<script>

View file

@ -1,12 +1,18 @@
<template>
<LayerProvider :layer="layer" :index="index">
<div>
<div :style="styles">
<div v-if="subtabs && subtabs.length">
<button v-for="subtab in subtabs" @click="selectSubtab(subtab)" :key="subtab">{{ subtab }}</button>
</div>
<component :is="customComponent" v-if="customComponent" />
<default-layer-tab v-else />
</div>
</LayerProvider>
</template>
<script>
import LayerProvider from './LayerProvider';
import { layers } from '../../store/layers';
import { player } from '../../store/proxies';
export default {
name: 'layer-tab',
@ -14,8 +20,36 @@ export default {
layer: String,
index: Number
},
components: {
LayerProvider
computed: {
styles() {
const styles = [];
if (layers[this.layer].style) {
styles.push(layers[this.layer].style);
}
if (layers[this.layer].activeSubtab?.style) {
styles.push(layers[this.layer].activeSubtab.style);
}
return styles;
},
customComponent() {
return this.activeSubtab != undefined ? this.activeSubtab.component : layers[this.layer].component;
},
subtabs() {
if (layers[this.layer].subtabs) {
return Object.entries(layers[this.layer].subtabs)
.filter(subtab => subtab[1].unlocked)
.map(subtab => subtab[0]);
}
return null;
},
activeSubtab() {
return player.subtabs[this.layer];
}
},
methods: {
selectSubtab(subtab) {
player.subtabs[this.layer] = subtab;
}
}
};
</script>

View file

@ -42,8 +42,6 @@
<script>
import modInfo from '../../data/modInfo';
import Info from './Info';
import Options from './Options';
export default {
name: 'Nav',
@ -60,9 +58,6 @@ export default {
showChangelog: false
}
},
components: {
Info, Options
},
methods: {
openDiscord() {
window.open(this.discordLink, 'mywindow');

View file

@ -19,9 +19,6 @@
</template>
<script>
import Modal from './Modal';
import Toggle from '../fields/Toggle';
import Select from '../fields/Select';
import themes from '../../data/themes';
import { camelToTitle } from '../../util/common';
import { mapState } from 'vuex';
@ -37,9 +34,6 @@ export default {
themes: Object.keys(themes).map(theme => ({ label: camelToTitle(theme), value: theme }))
}
},
components: {
Modal, Toggle, Select
},
computed: mapState([ "autosave", "offlineProd", "showTPS", "theme" ]),
methods: {
toggleOption(option) {
@ -49,16 +43,16 @@ export default {
player.theme = theme;
},
save() {
console.warn("Not yet implemented!");
},
hardReset() {
console.warn("Not yet implemented!");
},
exportSave() {
console.warn("Not yet implemented!");
},
importSave() {
console.warn("Not yet implemented!");
}
}
};

View file

@ -0,0 +1,18 @@
<template>
<h2 v-bind:style="{ color, 'text-shadow': '0px 0px 10px ' + color }">
{{ amount }}
</h2>
</template>
<script>
export default {
name: 'resource',
props: {
color: String,
amount: String
}
};
</script>
<style scoped>
</style>

View file

@ -2,7 +2,7 @@
<div class="tabs">
<div v-for="(tab, index) in tabs" class="tab" :key="index">
<button v-if="index > 0" class="goBack" @click="goBack(index)"></button>
<LayerProvider :layer="tab" :index="index" v-if="tab in layers && layers[tab].component">
<LayerProvider :layer="tab" :index="index" v-if="tab in layers && layers[tab].component != undefined">
<component :is="layers[tab].component" />
</LayerProvider>
<layer-tab :layer="tab" :index="index" v-else-if="tab in layers" />
@ -13,25 +13,21 @@
</template>
<script>
import LayerProvider from './LayerProvider';
import LayerTab from './LayerTab';
import { mapState } from 'vuex';
import { layers } from '../../store/layers';
import { player } from '../../store/proxies';
export default {
name: 'Tabs',
data() {
return {
layers: this.$root.layers
};
computed: {
...mapState([ 'tabs' ]),
layers() {
return layers;
}
},
components: {
LayerProvider, LayerTab
},
computed: mapState([ 'tabs' ]),
methods: {
goBack(index) {
player.tabs.splice(0, index);
player.tabs = player.tabs.slice(0, index);
}
}
};
@ -49,6 +45,7 @@ export default {
height: 100%;
width: 100%;
padding: 0 10px;
padding-top: 50px;
}
.separator {

View file

@ -1,3 +1,9 @@
import Decimal, { format } from '../../util/bignum';
import { player } from '../../store/proxies';
import { layers } from '../../store/layers';
import { hasUpgrade, hasMilestone, getBuyableAmount, setBuyableAmount, hasChallenge } from '../../util/features';
import { canReset, doReset } from '../../util/layers';
export default {
id: "i",
position: 0, // Horizontal position within a row. By default it uses the layer id and sorts in alphabetical order
@ -75,7 +81,7 @@ unlocked(){return hasMilestone(this.layer,this.id-1)}
},
resetsNothing(){return hasMilestone(this.layer,6)},
autoPrestige(){return hasMilestone(this.layer,6)},
update(diff){
update(){
if (hasMilestone(this.layer,0)){
if (!hasMilestone("p",0)){
player.p.milestones.push(0)

View file

@ -1,6 +1,11 @@
import Decimal, { format } from '../../util/bignum';
import { player } from '../../store/proxies';
import { layers } from '../../store/layers';
import { hasUpgrade, hasMilestone, getBuyableAmount, setBuyableAmount, hasChallenge } from '../../util/features';
import { canReset, doReset } from '../../util/layers';
export default {
id: "p",
row: 0,
position: 0,
startData() { return {
unlocked: true,
@ -26,7 +31,7 @@ export default {
type: "normal", // normal: cost to gain currency depends on amount gained. static: cost depends on how much you already have
exponent: 0.5, // Prestige currency exponent
gainMult() { // Calculate the multiplier for main currency from bonuses
mult = new Decimal(1)
let mult = new Decimal(1)
if (hasUpgrade(this.layer,131))mult=mult.times(10)
if (player.i.unlocked)mult=mult.times(player.i.points.plus(1).pow(hasUpgrade("p",235)?6.9420:1))
if (hasUpgrade(this.layer,222))mult=mult.times(getBuyableAmount(this.layer,22).plus(1))
@ -562,7 +567,7 @@ challenges:{
rows: 99,
cols: 4,
11: {
cost(x) { return new Decimal(0)},
cost() { return new Decimal(0)},
display() { return "Reset all upgrades and challenges, but get a boost. You have reset "+getBuyableAmount(this.layer,this.id)+" times.<br>"+(getBuyableAmount(this.layer,this.id).eq(6)?"You can't buy more than 6 boosts!":"You need all upgrades to reset.") },
canAfford() { return (player[this.layer].points.gte(this.cost())&&hasUpgrade(this.layer,74)&&hasUpgrade(this.layer,64))&&getBuyableAmount(this.layer,this.id).lt(6) },
buy() {
@ -581,7 +586,7 @@ challenges:{
unlocked(){return (hasUpgrade(this.layer,74)&&hasUpgrade(this.layer,64))||hasMilestone(this.layer,0)}
},
12: {
cost(x) { return new Decimal(1).times(new Decimal(hasChallenge(this.layer,21)?4:10).sub(hasUpgrade(this.layer,122)?2:0).pow(player.p.buyables[this.id])).div(hasUpgrade(this.layer,224)?(hasUpgrade("p",132)?player.p.gp.plus(1).pow(new Decimal(1).div(2)):hasUpgrade("p",101)?player.p.gp.plus(1).pow(new Decimal(1).div(3)):hasUpgrade("p",93)?player.p.gp.plus(1).pow(0.2):player.p.gp.plus(1).log10()):1)},
cost() { return new Decimal(1).times(new Decimal(hasChallenge(this.layer,21)?4:10).sub(hasUpgrade(this.layer,122)?2:0).pow(player.p.buyables[this.id])).div(hasUpgrade(this.layer,224)?(hasUpgrade("p",132)?player.p.gp.plus(1).pow(new Decimal(1).div(2)):hasUpgrade("p",101)?player.p.gp.plus(1).pow(new Decimal(1).div(3)):hasUpgrade("p",93)?player.p.gp.plus(1).pow(0.2):player.p.gp.plus(1).log10()):1)},
display() { return "Buy a generator for "+format(this.cost())+" points" },
canAfford() { return (player.points.gte(this.cost())&&hasMilestone(this.layer,5)) },
buy() {
@ -592,7 +597,7 @@ challenges:{
unlocked(){return (hasMilestone(this.layer,5))}
},
13: {
cost(x) { return new Decimal(1).times(new Decimal(2).pow(player.p.buyables[this.id])).div(hasUpgrade(this.layer,224)?(hasUpgrade("p",132)?player.p.gp.plus(1).pow(new Decimal(1).div(2)):hasUpgrade("p",101)?player.p.gp.plus(1).pow(new Decimal(1).div(3)):hasUpgrade("p",93)?player.p.gp.plus(1).pow(0.2):player.p.gp.plus(1).log10()):1)},
cost() { return new Decimal(1).times(new Decimal(2).pow(player.p.buyables[this.id])).div(hasUpgrade(this.layer,224)?(hasUpgrade("p",132)?player.p.gp.plus(1).pow(new Decimal(1).div(2)):hasUpgrade("p",101)?player.p.gp.plus(1).pow(new Decimal(1).div(3)):hasUpgrade("p",93)?player.p.gp.plus(1).pow(0.2):player.p.gp.plus(1).log10()):1)},
display() { return "Buy a generator for "+format(this.cost())+" prestige points" },
canAfford() { return (player.p.points.gte(this.cost())&&hasUpgrade("p",82)) },
buy() {
@ -603,7 +608,7 @@ challenges:{
unlocked(){return (hasUpgrade(this.layer,82))}
},
14: {
cost(x) { return new Decimal(900).mul(new Decimal(1.01).pow(getBuyableAmount(this.layer,this.id))).round().div(hasUpgrade(this.layer,234)?getBuyableAmount(this.layer,23).pow(0.3).plus(1):1)},
cost() { return new Decimal(900).mul(new Decimal(1.01).pow(getBuyableAmount(this.layer,this.id))).round().div(hasUpgrade(this.layer,234)?getBuyableAmount(this.layer,23).pow(0.3).plus(1):1)},
display() { return "Buy a generator for "+format(this.cost())+" Infinity points" },
canAfford() { return (player.i.points.gte(this.cost())&&hasUpgrade("p",232)) },
buy() {
@ -614,7 +619,7 @@ challenges:{
unlocked(){return (hasUpgrade(this.layer,232))}
},
21: {
cost(x) { return new Decimal(20).plus(getBuyableAmount(this.layer, this.id).pow(new Decimal(2).sub(new Decimal(hasUpgrade(this.layer,221)?0.9:hasUpgrade(this.layer,214)?0.6:0.3).times(hasUpgrade(this.layer,212)?(new Decimal(1).sub(new Decimal(0.75).pow(getBuyableAmount(this.layer,22)))):0))))},
cost() { return new Decimal(20).plus(getBuyableAmount(this.layer, this.id).pow(new Decimal(2).sub(new Decimal(hasUpgrade(this.layer,221)?0.9:hasUpgrade(this.layer,214)?0.6:0.3).times(hasUpgrade(this.layer,212)?(new Decimal(1).sub(new Decimal(0.75).pow(getBuyableAmount(this.layer,22)))):0))))},
display() { return "Reset your generators for +1 pointy point! Cost: "+format(this.cost())+" Generators" },
canAfford() { return (player.p.g.gte(this.cost())&&hasUpgrade("p",104)) },
buy() {
@ -627,7 +632,7 @@ challenges:{
unlocked(){return (hasUpgrade(this.layer,104))}
},
22: {
cost(x) { return new Decimal(8).plus(getBuyableAmount(this.layer,this.id))},
cost() { return new Decimal(8).plus(getBuyableAmount(this.layer,this.id))},
display() { return "Gain a pointy prestige point. Cost: "+format(this.cost())+" Pointy Points" },
canAfford() { return (getBuyableAmount(this.layer,21).gte(this.cost())&&(hasMilestone("i",5))) },
buy() {
@ -637,7 +642,7 @@ challenges:{
unlocked(){return (hasMilestone("i",5))}
},
23: {
cost(x) { return new Decimal(124).plus(getBuyableAmount(this.layer,this.id).times(2).pow(2))},
cost() { return new Decimal(124).plus(getBuyableAmount(this.layer,this.id).times(2).pow(2))},
display() { return "Gain a booster. Cost: "+format(this.cost())+" Pointy Points" },
canAfford() { return (getBuyableAmount(this.layer,21).gte(this.cost())&&(hasMilestone("i",5))) },
buy() {
@ -659,7 +664,7 @@ challenges:{
unlocked(){return (hasUpgrade("p",225)||getBuyableAmount("p",23).gt(0))}
},
31: {
cost(x) { return new Decimal(1e93).times(new Decimal(1.5).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(1.1).pow(getBuyableAmount(this.layer,this.id).pow(2)))},
cost() { return new Decimal(1e93).times(new Decimal(1.5).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(1.1).pow(getBuyableAmount(this.layer,this.id).pow(2)))},
effect(){return new Decimal(2).plus(layers.p.buyables[33].effect()).pow(getBuyableAmount(this.layer,this.id).plus(layers.p.buyables[51].effect()))},
display() { return "Double point gain. \nCurrently: x"+format(this.effect())+"\nCost: "+format(this.cost())+" Prestige points" },
canAfford() { return (player.p.points.gte(this.cost())&&(hasMilestone("p",13))) },
@ -670,7 +675,7 @@ challenges:{
unlocked(){return (hasMilestone("p",13))}
},
32: {
cost(x) { return new Decimal(1e95).times(new Decimal(2).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(1.01).pow(getBuyableAmount(this.layer,this.id).pow(2)))},
cost() { return new Decimal(1e95).times(new Decimal(2).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(1.01).pow(getBuyableAmount(this.layer,this.id).pow(2)))},
display() { return "Double prestige point gain. \nCurrently: x"+format(new Decimal(2).plus(layers.p.buyables[33].effect()).pow(getBuyableAmount(this.layer,this.id)))+"\nCost: "+format(this.cost())+" Prestige points" },
canAfford() { return (player.p.points.gte(this.cost())&&(hasMilestone("p",13))) },
buy() {
@ -680,7 +685,7 @@ challenges:{
unlocked(){return (hasMilestone("p",13)&&getBuyableAmount(this.layer,31).gte(5))}
},
33: {
cost(x) { return new Decimal(1e100).times(new Decimal(10).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(1.01).pow(getBuyableAmount(this.layer,this.id).pow(2)))},
cost() { return new Decimal(1e100).times(new Decimal(10).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(1.01).pow(getBuyableAmount(this.layer,this.id).pow(2)))},
effect(){return new Decimal(0.01).mul(getBuyableAmount(this.layer,this.id)).times(layers.p.buyables[43].effect())},
display() { return "Add 0.01 to the previous 2 buyable bases. \nCurrently: +"+format(this.effect())+"\nCost: "+format(this.cost())+" Prestige points" },
canAfford() { return (player.p.points.gte(this.cost())&&(hasMilestone("p",13))) },
@ -691,7 +696,7 @@ challenges:{
unlocked(){return (hasMilestone("p",13)&&(getBuyableAmount(this.layer,this.id).gt(0)||player.p.points.gte(1e100)))}
},
41: {
cost(x) { return new Decimal(1e110).times(new Decimal(10).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(10).pow(getBuyableAmount(this.layer,this.id).pow(2)))},
cost() { return new Decimal(1e110).times(new Decimal(10).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(10).pow(getBuyableAmount(this.layer,this.id).pow(2)))},
effect(){return new Decimal(0.01).mul(getBuyableAmount(this.layer,this.id).plus(layers.p.buyables[51].effect()))},
display() { return "Add 0.01 to the booster effect base. \nCurrently: +"+format(this.effect())+"\nCost: "+format(this.cost())+" Prestige points" },
canAfford() { return (player.p.points.gte(this.cost())&&(hasMilestone("p",13))) },
@ -702,7 +707,7 @@ challenges:{
unlocked(){return (hasMilestone("p",13)&&(getBuyableAmount(this.layer,this.id).gt(0)||player.p.points.gte(1e110)))}
},
42: {
cost(x) { let c = new Decimal(1e270).times(new Decimal(2).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(1.01).pow(getBuyableAmount(this.layer,this.id).pow(2)))
cost() { let c = new Decimal(1e270).times(new Decimal(2).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(1.01).pow(getBuyableAmount(this.layer,this.id).pow(2)))
return c
},
@ -722,7 +727,7 @@ challenges:{
unlocked(){return (hasMilestone("p",13)&&(getBuyableAmount(this.layer,this.id).gt(0)||player.p.points.gte(1e270)))}
},
43: {
cost(x) { return new Decimal("1e375").times(new Decimal(10).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(10).pow(getBuyableAmount(this.layer,this.id).pow(2)))},
cost() { return new Decimal("1e375").times(new Decimal(10).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(10).pow(getBuyableAmount(this.layer,this.id).pow(2)))},
effect(){return new Decimal(0.01).mul(getBuyableAmount(this.layer,this.id)).plus(1)},
display() { return "Multiply the above buyable effect. \nCurrently: *"+format(this.effect())+"\nCost: "+format(this.cost())+" Prestige points" },
canAfford() { return (player.p.points.gte(this.cost())&&(hasMilestone("p",13))) },
@ -733,7 +738,7 @@ challenges:{
unlocked(){return (hasMilestone("p",13)&&(getBuyableAmount(this.layer,this.id).gt(0)||player.p.points.gte("1e375")))}
},
51: {
cost(x) { return new Decimal("1e1740").times(new Decimal(10).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(1e10).pow(getBuyableAmount(this.layer,this.id).pow(2)))},
cost() { return new Decimal("1e1740").times(new Decimal(10).pow(getBuyableAmount(this.layer,this.id))).times(new Decimal(1e10).pow(getBuyableAmount(this.layer,this.id).pow(2)))},
effect(){return getBuyableAmount(this.layer,this.id).pow(0.55)},
display() { return "Add free levels to the above 2 buyables \nCurrently: "+format(this.effect())+"\nCost: "+format(this.cost())+" Prestige points" },
canAfford() { return (player.p.points.gte(this.cost())&&(hasMilestone("p",13))) },

View file

@ -5,10 +5,10 @@ import Decimal from '../util/bignum';
import modInfo from './modInfo';
// Import initial layers
//import demo from './layers/demo.js';
//import demoInfinity from './layers/demo-infinity.js';
import demo from './layers/demo.js';
import demoInfinity from './layers/demo-infinity.js';
export const initialLayers = [];
export const initialLayers = [ demo, demoInfinity ];
export function update(delta) {
let gain = new Decimal(3.19)

View file

@ -13,7 +13,7 @@
"useHeader": false,
"banner": null,
"logo": null,
"initialTabs": ["tree-tab", "p"],
"initialTabs": ["tree-tab", "p", "i"],
"maxTickLength": 3600
}

View file

@ -2,15 +2,19 @@ import Vue from 'vue';
import App from './App';
import store from './store';
import { layers, hotkeys } from './store/layers';
import { setVue } from './util/vue';
import './components/index';
// Setup
Vue.config.productionTip = false;
// Create Vue
window.vue = new Vue({
const vue = window.vue = new Vue({
store,
render: h => h(App),
data: { layers, hotkeys }
}).$mount('#app');
setVue(vue);
// Start game loop

View file

@ -4,11 +4,9 @@ import Decimal from '../util/bignum';
import store from './index';
// Add layers on second frame so dependencies can resolve
requestAnimationFrame(() => {
const { initialLayers } = import('../data/mod');
for (let layer in initialLayers) {
addLayer(layer);
}
requestAnimationFrame(async () => {
const { initialLayers } = await import('../data/mod');
initialLayers.forEach(addLayer);
});
export const layers = {};
@ -23,6 +21,7 @@ export function addLayer(layer) {
// Set default property values
layer = Object.assign({}, defaultLayerProperties, layer);
layer.layer = layer.id;
const getters = {};
@ -34,76 +33,117 @@ export function addLayer(layer) {
}
for (let property in featureProperties) {
if (layer[property]) {
setupFeature(layer.name, layer[property]);
setupFeature(layer.id, layer[property]);
}
}
if (layer.upgrades) {
if (player[layer.id].upgrades == undefined) {
player[layer.id].upgrades = [];
}
for (let id in layer.upgrades) {
if (isPlainObject(layer.upgrades[id])) {
layer.upgrades[id].bought = function() {
return !this.deactivated && player[layer.name].upgrades.some(upgrade => upgrade == id);
return !this.deactivated && player[layer.id].upgrades.some(upgrade => upgrade == id);
}
}
}
}
if (layer.achievements) {
if (player[layer.id].achievements == undefined) {
player[layer.id].achievements = [];
}
for (let id in layer.achievements) {
if (isPlainObject(layer.achievements[id])) {
layer.achievements[id].earned = function() {
return !this.deactivated && player[layer.name].achievements.some(achievement => achievement == id);
return !this.deactivated && player[layer.id].achievements.some(achievement => achievement == id);
}
}
}
}
if (layer.challenges) {
if (player[layer.id].challenges == undefined) {
player[layer.id].challenges = {};
}
for (let id in layer.challenges) {
if (isPlainObject(layer.challenges[id])) {
layer.challenges[id].completed = function() {
return !this.deactivated && !!player[layer.name].challenges[id];
return !this.deactivated && !!player[layer.id].challenges[id];
}
layer.challenges[id].completions = function() {
return player[layer.name].challenges[id];
return player[layer.id].challenges[id];
}
layer.challenges[id].maxed = function() {
return !this.deactivated && Decimal.gte(player[layer.name].challenges[id], this.completionLimit);
return !this.deactivated && Decimal.gte(player[layer.id].challenges[id], this.completionLimit);
}
if (layer.challenges[id].marked == undefined) {
layer.challenges[id].marked = function() {
return this.maxed;
}
}
layer.challenges[id].active = function() {
// TODO search for other rows that "count as" this challenge as well
return !this.deactivated && (player[layer.id].activeChallenge === id || layers[layer.id].challenges[player[layer.id].activeChallenge]?.countsAs?.includes(id));
}
}
}
}
if (layer.buyables) {
if (player[layer.id].buyables == undefined) {
player[layer.id].buyables = {};
}
for (let id in layer.buyables) {
if (isPlainObject(layer.buyables[id])) {
layer.buyables[id].amount = function() {
return player[layer.name].buyables[id];
return player[layer.id].buyables[id];
}
layer.buyables[id].amountSet = function(amount) {
player[layer.name].buyables[id] = amount;
player[layer.id].buyables[id] = amount;
}
layer.buyables[id].canBuy = function() {
return !this.deactivated && this.unlocked !== false && this.canAfford !== false && Decimal.lt(player[layer.name].buyables[id], this.purchaseLimit);
return !this.deactivated && this.unlocked !== false && this.canAfford !== false && Decimal.lt(player[layer.id].buyables[id], this.purchaseLimit);
}
if (layer.buyables[id].purchaseLimit == undefined) {
layer.buyables[id].purchaseLimit = new Decimal(Infinity);
}
}
}
}
if (layer.clickables) {
if (player[layer.id].clickables == undefined) {
player[layer.id].clickables = {};
}
for (let id in layer.clickables) {
if (isPlainObject(layer.clickables[id])) {
layer.clickables[id].state = function() {
return player[layer.name].clickables[id];
return player[layer.id].clickables[id];
}
layer.clickables[id].stateSet = function(state) {
player[layer.name].clickables[id] = state;
player[layer.id].clickables[id] = state;
}
}
}
}
if (layer.milestones) {
if (player[layer.id].milestones == undefined) {
player[layer.id].milestones = [];
}
for (let id in layer.milestones) {
if (isPlainObject(layer.milestones[id])) {
layer.milestones[id].earned = function() {
return !this.deactivated && player[layer.name].milestones.some(milestone => milestone == id);
return !this.deactivated && player[layer.id].milestones.some(milestone => milestone == id);
}
}
}
}
if (layer.grids) {
if (player[layer.id].grids == undefined) {
player[layer.id].grids = {};
}
for (let id in layer.grids) {
if (isPlainObject(layer.grids[id])) {
if (player[layer.id].grids[id] == undefined) {
player[layer.id].grids[id] = {};
}
if (layer.grids[id].getUnlocked == undefined) {
layer.grids[id].getUnlocked = true;
}
@ -111,21 +151,32 @@ export function addLayer(layer) {
layer.grids[id].getCanClick = true;
}
layer.grids[id].data = function(cell) {
return player[layer.name].grids[id][cell];
return player[layer.id].grids[id][cell];
}
layer.grids[id].dataSet = function(cell, data) {
player[layer.name].grids[id][cell] = data;
player[layer.id].grids[id][cell] = data;
}
createGridProxy(layer.grids[id], getters, `${layer.id}/grids-${id}-`);
}
}
}
if (layer.subtabs) {
layer.activeSubtab = function() {
if (this.subtabs != undefined) {
if (player.subtabs[layer.id] in this.subtabs && this.subtabs[player.subtabs[layer.id]].unlocked !== false) {
return player.subtabs[layer.id];
}
return Object.keys(this.subtabs).find(subtab => this.subtabs[subtab].unlocked !== false);
}
createGridProxy(layer.name, layer.grids[id], getters, `grids-${id}-`);
}
}
// Create layer proxy
layer = createProxy(layer.name, layer, getters);
layer = createProxy(layer, getters, `${layer.id}/`);
// Register layer
layers[layer.name] = layer;
store.registerModule(layer.name, { getters });
layers[layer.id] = layer;
store.registerModule(`layer-${layer.id}`, { getters });
// Register hotkeys
if (layer.hotkeys) {
@ -144,11 +195,11 @@ export function removeLayer(layer) {
}
// Un-register layer
store.unregisterModule(layer);
store.unregisterModule(`layer-${layer}`);
}
export function reloadLayer(layer) {
removeLayer(layer.name);
removeLayer(layer.id);
// Re-create layer
addLayer(layer);
@ -161,7 +212,7 @@ const defaultLayerProperties = {
glowColor: "red"
};
const gridProperties = [ 'upgrades', 'achievements', 'challenges', 'buyables', 'clickables' ];
const featureProperties = [ 'upgrades', 'achievements', 'challenges', 'buyables', 'clickables', 'milestones', 'bars', 'infoboxes', 'grids', 'hotkeys' ];
const featureProperties = [ 'upgrades', 'achievements', 'challenges', 'buyables', 'clickables', 'milestones', 'bars', 'infoboxes', 'grids', 'hotkeys', 'subtabs' ];
function setRowCol(features) {
if (features.rows && features.cols) {
@ -183,7 +234,7 @@ function setRowCol(features) {
features.cols = maxCol;
}
function setupFeature(getters, layer, featurePrefix, features) {
function setupFeature(layer, features) {
for (let id in features) {
const feature = features[id];
if (isPlainObject(feature)) {

View file

@ -1,5 +1,6 @@
import { layers } from './layers';
import { isFunction, isPlainObject } from '../util/common';
import Decimal from '../util/bignum';
import store from './index';
import Vue from 'vue';
@ -13,26 +14,46 @@ export const tmp = new Proxy({}, {
}
});
export const player = window.player = new Proxy(store.state, {
const playerHandler = {
get(target, key) {
if (key == 'isProxy') {
return true;
}
if (typeof target[key] == "undefined") {
return;
}
if (!target[key].isProxy && !(target[key] instanceof Decimal) && isPlainObject(target[key])) {
// Note that player isn't pre-created since it (shouldn't) have functions or getters
// so creating proxies as they're requested is A-OK
target[key] = new Proxy(target[key], playerHandler);
return target[key];
}
return target[key];
},
set(target, property, value) {
Vue.set(target, property, value);
return true;
}
});
};
export const player = window.player = new Proxy(store.state, playerHandler);
export function createProxy(layer, object, getters, prefix = "") {
const objectProxy = new Proxy(object, getHandler(`${layer}/${prefix}`));
travel(createProxy, layer, object, objectProxy, getters, prefix);
export function createProxy(object, getters, prefix) {
const objectProxy = new Proxy(object, getHandler(prefix));
travel(createProxy, object, objectProxy, getters, prefix);
return objectProxy;
}
// TODO cache grid values? Currently they'll be calculated every render they're visible
export function createGridProxy(layer, object, getters, prefix = "") {
const objectProxy = new Proxy(object, getGridHandler(`${layer}/${prefix}`));
travel(createGridProxy, layer, object, objectProxy, getters, prefix);
export function createGridProxy(object, getters, prefix) {
const objectProxy = new Proxy(object, getGridHandler(prefix));
travel(createGridProxy, object, objectProxy, getters, prefix);
return objectProxy;
}
function travel(callback, layer, object, objectProxy, getters, prefix) {
function travel(callback, object, objectProxy, getters, prefix) {
for (let key in object) {
if (object[key].isProxy) {
continue;
@ -46,7 +67,7 @@ function travel(callback, layer, object, objectProxy, getters, prefix) {
return object[key].call(objectProxy);
}
} else if (isPlainObject(object[key])) {
object[key] = callback(layer, object[key], getters, `${prefix}${key}-`);
object[key] = callback(object[key], getters, `${prefix}${key}-`);
}
}
}
@ -72,7 +93,7 @@ function getHandler(prefix) {
} else if (isFunction(target[key])) {
const getterID = `${prefix}${key}`;
if (getterID in store.getters) {
return store.getters[getterID]();
return store.getters[getterID];
} else {
return target[key].bind(receiver);
}

View file

@ -14,4 +14,15 @@ export const {
invertOOM
} = numberUtils;
window.Decimal = Decimal;
window.exponentialFormat = exponentialFormat;
window.commaFormat = commaFormat;
window.regularFormat = regularFormat;
window.format = format;
window.formatWhole = formatWhole;
window.formatTime = formatTime;
window.toPlaces = toPlaces;
window.formatSmall = formatSmall;
window.invertOOM = invertOOM;
export default Decimal;

View file

@ -24,6 +24,10 @@ export function challengeCompletions(layer, id) {
return layers[layer].challenges[id].completions;
}
export function inChallenge(layer, id) {
return layers[layer].challenges[id].active;
}
export function getBuyableAmount(layer, id) {
return layers[layer].buyables[id].amount;
}

11
src/util/layers.js Normal file
View file

@ -0,0 +1,11 @@
export function canReset(layer) {
console.warn("Not yet implemented!", layer);
}
export function doReset(layer) {
console.warn("Not yet implemented!", layer);
}
export function layerDataReset(layer) {
console.warn("Not yet implemented!", layer);
}

View file

@ -13,9 +13,10 @@ export function getInitialStore() {
lastTenTicks: [],
showTPS: true,
theme: "paper",
subtabs: {},
...getStartingData(),
...initialLayers.reduce((acc, layer) => {
acc[layer.name] = layer.startData();
acc[layer.id] = layer.startData();
return acc;
}, {})
}

32
src/util/vue.js Normal file
View file

@ -0,0 +1,32 @@
import { player } from '../store/proxies';
import { layers } from '../store/layers';
import Decimal, * as numberUtils from './bignum';
let vue;
export function setVue(vm) {
vue = vm;
}
// Pass in various data that the template could potentially use
const defaultComputed = {
player() { return player; },
layers() { return layers; }
};
const defaultData = function() {
return { Decimal, ...numberUtils };
}
export function coerceComponent(component) {
if (typeof component === 'string' && !(component in vue.$options.components)) {
let computed = defaultComputed;
let data = defaultData;
if (component.charAt(0) !== '<') {
// Not a template string, so make it one and remove the data
component = `<span>${component}</span>`;
computed = null;
data = null;
}
return { template: component, computed, data };
}
return component;
}

View file

@ -1,5 +1,6 @@
module.exports = {
publicPath: process.env.NODE_ENV === 'production'
? '/The-Modding-Tree-X'
: '/'
: '/',
runtimeCompiler: true
};