feat: improved missions UI and more sophisticated unlock options
This commit is contained in:
		
							parent
							
								
									e65587bbb7
								
							
						
					
					
						commit
						4f0b3c7741
					
				| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="rounded-lg border text-center py-1">
 | 
				
			||||||
 | 
					    {{ mission.name }}
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  props: {
 | 
				
			||||||
 | 
					    mission: { type: Object, required: true },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					div {
 | 
				
			||||||
 | 
					  border-color: currentColor;
 | 
				
			||||||
 | 
					  background-color: rgba(0, 0, 0, 0.1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
| 
						 | 
					@ -4,8 +4,8 @@
 | 
				
			||||||
    :description="mission.description"
 | 
					    :description="mission.description"
 | 
				
			||||||
    :max="max"
 | 
					    :max="max"
 | 
				
			||||||
    :value="value"
 | 
					    :value="value"
 | 
				
			||||||
    :unit="unit"
 | 
					    :unit="mission.completionCriteria.unit"
 | 
				
			||||||
    @click="complete"
 | 
					    @click="$emit('click')"
 | 
				
			||||||
  />
 | 
					  />
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,22 +16,21 @@ export default {
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  computed: {
 | 
					  computed: {
 | 
				
			||||||
    value() {
 | 
					    value() {
 | 
				
			||||||
      return 'cost' in this.mission.completionCriteria
 | 
					      const { unit } = this.mission.completionCriteria
 | 
				
			||||||
        ? this.$store.state.currency
 | 
					
 | 
				
			||||||
        : this.$store.state.playerAge
 | 
					      if (unit === 'maxAge') {
 | 
				
			||||||
 | 
					        return this.$store.state.playerAge
 | 
				
			||||||
 | 
					      } else if (unit === 'spareTime') {
 | 
				
			||||||
 | 
					        return this.$store.state.currency
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        //  (unit === 'apprenticeLevels')
 | 
				
			||||||
 | 
					        return this.$store.getters.apprenticeLevels
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    max() {
 | 
					    max() {
 | 
				
			||||||
      return 'cost' in this.mission.completionCriteria
 | 
					      return this.mission.completionCriteria.unit === 'maxAge'
 | 
				
			||||||
        ? this.mission.completionCriteria.cost
 | 
					        ? this.$store.state.playerAgeMax
 | 
				
			||||||
        : this.$store.state.playerAgeMax
 | 
					        : this.mission.completionCriteria.value
 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    unit() {
 | 
					 | 
				
			||||||
      return 'cost' in this.mission.completionCriteria ? 'spareTime' : 'age'
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  methods: {
 | 
					 | 
				
			||||||
    complete() {
 | 
					 | 
				
			||||||
      this.$store.commit('completeMission', this.mission)
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,80 @@
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <responsive-grid>
 | 
					  <div class="missions grid">
 | 
				
			||||||
 | 
					    <responsive-grid
 | 
				
			||||||
 | 
					      v-if="incomplete.length"
 | 
				
			||||||
 | 
					      :class="
 | 
				
			||||||
 | 
					        completed.length &&
 | 
				
			||||||
 | 
					        `pb-6 border-b-2 border-${$store.getters.activeTab.darkColor}`
 | 
				
			||||||
 | 
					      "
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
      <mission-button
 | 
					      <mission-button
 | 
				
			||||||
      v-for="(mission, index) in $store.state.missions"
 | 
					        v-for="(mission, index) in incomplete"
 | 
				
			||||||
 | 
					        :key="index"
 | 
				
			||||||
 | 
					        :mission="mission"
 | 
				
			||||||
 | 
					        @click="complete(mission)"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </responsive-grid>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div
 | 
				
			||||||
 | 
					      v-else
 | 
				
			||||||
 | 
					      :class="
 | 
				
			||||||
 | 
					        completed.length &&
 | 
				
			||||||
 | 
					        `pt-6 pb-10 border-b-2 border-${$store.getters.activeTab.darkColor}`
 | 
				
			||||||
 | 
					      "
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <h3 class="text-center">No Missions Currently Available</h3>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <template v-if="completed.length">
 | 
				
			||||||
 | 
					      <h2 class="pt-2 pb-2 text-center text-xl">Completed Missions</h2>
 | 
				
			||||||
 | 
					      <responsive-grid min="1" mid="3" max="6">
 | 
				
			||||||
 | 
					        <completed-mission
 | 
				
			||||||
 | 
					          v-for="(mission, index) in completed"
 | 
				
			||||||
          :key="index"
 | 
					          :key="index"
 | 
				
			||||||
          :mission="mission"
 | 
					          :mission="mission"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </responsive-grid>
 | 
					      </responsive-grid>
 | 
				
			||||||
 | 
					    </template>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  computed: {
 | 
				
			||||||
 | 
					    unlocked() {
 | 
				
			||||||
 | 
					      return this.$store.state.missions.filter(({ unlockCriteria }) => {
 | 
				
			||||||
 | 
					        if (unlockCriteria.unit === 'instruments') {
 | 
				
			||||||
 | 
					          return unlockCriteria.value <= this.$store.getters.instruments
 | 
				
			||||||
 | 
					        } else if (unlockCriteria.unit === 'apprenticeLevels') {
 | 
				
			||||||
 | 
					          return unlockCriteria.value <= this.$store.getters.apprenticeLevels
 | 
				
			||||||
 | 
					        } else if (unlockCriteria.unit === 'missionsCompleted') {
 | 
				
			||||||
 | 
					          return unlockCriteria.value.every((name) =>
 | 
				
			||||||
 | 
					            this.$store.getters.missionIsCompleted(name)
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					        } else if (unlockCriteria.unit === 'timeJumpsBackwards') {
 | 
				
			||||||
 | 
					          return unlockCriteria.value <= this.$store.state.timeJumpsBackwards
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          return false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    incomplete() {
 | 
				
			||||||
 | 
					      return this.unlocked.filter((m) => !m.complete)
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    completed() {
 | 
				
			||||||
 | 
					      return this.unlocked.filter((m) => m.complete)
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  methods: {
 | 
				
			||||||
 | 
					    complete(mission) {
 | 
				
			||||||
 | 
					      this.$store.commit('completeMission', mission.name)
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					.missions {
 | 
				
			||||||
 | 
					  grid-template-rows: minmax(0, 1fr) auto auto;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										100
									
								
								store/index.js
								
								
								
								
							
							
						
						
									
										100
									
								
								store/index.js
								
								
								
								
							| 
						 | 
					@ -65,6 +65,7 @@ export const state = () => ({
 | 
				
			||||||
      instrument: 'Mechanical Clock',
 | 
					      instrument: 'Mechanical Clock',
 | 
				
			||||||
      worker: 'Engineer',
 | 
					      worker: 'Engineer',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      unlocked: true,
 | 
				
			||||||
      cost: 10,
 | 
					      cost: 10,
 | 
				
			||||||
      created: false,
 | 
					      created: false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,7 +74,7 @@ export const state = () => ({
 | 
				
			||||||
      baseReward: 5, // currency added when the bar is completed
 | 
					      baseReward: 5, // currency added when the bar is completed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      workerLevel: 0, // 0 = not hired; 1+ = hired
 | 
					      workerLevel: 0, // 0 = not hired; 1+ = hired
 | 
				
			||||||
      nextWorkerCost: 25, // currency cost of next worker
 | 
					      nextWorkerCost: 50, // currency cost of next worker
 | 
				
			||||||
      nextWorkerFactor: 1.5, // worker cost *= this factor after each purchase
 | 
					      nextWorkerFactor: 1.5, // worker cost *= this factor after each purchase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      unlockThreshold: { tech: null, currency: 0 },
 | 
					      unlockThreshold: { tech: null, currency: 0 },
 | 
				
			||||||
| 
						 | 
					@ -82,6 +83,8 @@ export const state = () => ({
 | 
				
			||||||
      instrument: 'Hourglass',
 | 
					      instrument: 'Hourglass',
 | 
				
			||||||
      worker: 'Glassblower',
 | 
					      worker: 'Glassblower',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      unlocked: false,
 | 
				
			||||||
 | 
					      minDateUnlocked: 1100 * 12,
 | 
				
			||||||
      cost: 100,
 | 
					      cost: 100,
 | 
				
			||||||
      created: false,
 | 
					      created: false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,7 +93,7 @@ export const state = () => ({
 | 
				
			||||||
      baseReward: 35,
 | 
					      baseReward: 35,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      workerLevel: 0,
 | 
					      workerLevel: 0,
 | 
				
			||||||
      nextWorkerCost: 200,
 | 
					      nextWorkerCost: 250,
 | 
				
			||||||
      nextWorkerFactor: 1.6,
 | 
					      nextWorkerFactor: 1.6,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      unlockThreshold: { tech: null, currency: 10000 },
 | 
					      unlockThreshold: { tech: null, currency: 10000 },
 | 
				
			||||||
| 
						 | 
					@ -99,6 +102,8 @@ export const state = () => ({
 | 
				
			||||||
      instrument: 'Pocket Watch',
 | 
					      instrument: 'Pocket Watch',
 | 
				
			||||||
      worker: 'Miniaturist',
 | 
					      worker: 'Miniaturist',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      unlocked: false,
 | 
				
			||||||
 | 
					      minDateUnlocked: 1600 * 12,
 | 
				
			||||||
      cost: 1000,
 | 
					      cost: 1000,
 | 
				
			||||||
      created: false,
 | 
					      created: false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -107,7 +112,7 @@ export const state = () => ({
 | 
				
			||||||
      baseReward: 80,
 | 
					      baseReward: 80,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      workerLevel: 0,
 | 
					      workerLevel: 0,
 | 
				
			||||||
      nextWorkerCost: 2000,
 | 
					      nextWorkerCost: 500,
 | 
				
			||||||
      nextWorkerFactor: 1.8,
 | 
					      nextWorkerFactor: 1.8,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      unlockThreshold: { tech: 0, currency: new Decimal(10e5) },
 | 
					      unlockThreshold: { tech: 0, currency: new Decimal(10e5) },
 | 
				
			||||||
| 
						 | 
					@ -124,12 +129,50 @@ export const state = () => ({
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  missions: [
 | 
					  missions: [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      name: 'Create the Time Machine',
 | 
					      name: 'Train an Apprentice',
 | 
				
			||||||
      description: 'Soon you will be able to control time itself.',
 | 
					      description:
 | 
				
			||||||
      completionCriteria: {
 | 
					        'One man can only spend so much time staring at clocks each day. Hiring a second may make this easier.',
 | 
				
			||||||
        cost: 6000,
 | 
					      unlockCriteria: {
 | 
				
			||||||
 | 
					        unit: 'instruments',
 | 
				
			||||||
 | 
					        value: 1,
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      available: true,
 | 
					      completionCriteria: {
 | 
				
			||||||
 | 
					        unit: 'apprenticeLevels',
 | 
				
			||||||
 | 
					        value: 5,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      unlocked: true,
 | 
				
			||||||
 | 
					      viewed: false,
 | 
				
			||||||
 | 
					      complete: false,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'Study Time Magic',
 | 
				
			||||||
 | 
					      description:
 | 
				
			||||||
 | 
					        "As time ticks away you begin to ponder the mysteries of time's origins and possibilities.",
 | 
				
			||||||
 | 
					      unlockCriteria: {
 | 
				
			||||||
 | 
					        unit: 'apprenticeLevels',
 | 
				
			||||||
 | 
					        value: 1,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      completionCriteria: {
 | 
				
			||||||
 | 
					        unit: 'spareTime',
 | 
				
			||||||
 | 
					        value: 250,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      unlocked: true,
 | 
				
			||||||
 | 
					      viewed: false,
 | 
				
			||||||
 | 
					      complete: false,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      name: 'Create the Time Machine',
 | 
				
			||||||
 | 
					      description:
 | 
				
			||||||
 | 
					        'Your magnum opus. Soon you will be able to control time itself.',
 | 
				
			||||||
 | 
					      unlockCriteria: {
 | 
				
			||||||
 | 
					        unit: 'missionsCompleted',
 | 
				
			||||||
 | 
					        value: ['Train an Apprentice', 'Study Time Magic'],
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      completionCriteria: {
 | 
				
			||||||
 | 
					        unit: 'spareTime',
 | 
				
			||||||
 | 
					        value: 1000,
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      unlocked: false,
 | 
				
			||||||
      viewed: false,
 | 
					      viewed: false,
 | 
				
			||||||
      complete: false,
 | 
					      complete: false,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					@ -139,24 +182,27 @@ export const state = () => ({
 | 
				
			||||||
        'Your body seems to be failing you. ' +
 | 
					        'Your body seems to be failing you. ' +
 | 
				
			||||||
        'Write a book to pass your knowedge to your younger self through the time machine. ' +
 | 
					        'Write a book to pass your knowedge to your younger self through the time machine. ' +
 | 
				
			||||||
        "Now where's your pen...",
 | 
					        "Now where's your pen...",
 | 
				
			||||||
      appearanceCriteria: {
 | 
					      unlockCriteria: {
 | 
				
			||||||
        age: 100,
 | 
					        unit: 'timeJumpsBackwards',
 | 
				
			||||||
 | 
					        value: 1,
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      completionCriteria: {
 | 
					      completionCriteria: {
 | 
				
			||||||
        maxAge: true,
 | 
					        unit: 'maxAge',
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      available: true,
 | 
					      unlocked: false,
 | 
				
			||||||
      viewed: false,
 | 
					      viewed: false,
 | 
				
			||||||
      complete: false,
 | 
					      complete: false,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
  gameDate: 1991 * 12,
 | 
					
 | 
				
			||||||
  playerAge: 34 * 12,
 | 
					  gameDate: 1400 * 12,
 | 
				
			||||||
  playerAgeMax: 80 * 12,
 | 
					  playerAge: 30 * 12,
 | 
				
			||||||
 | 
					  playerAgeMax: 60 * 12,
 | 
				
			||||||
  playerLivedTotal: 0,
 | 
					  playerLivedTotal: 0,
 | 
				
			||||||
  wisdomGained: 0, // wisdom gained so far on this run, not applied until player sends the book.
 | 
					  wisdomGained: 0, // wisdom gained so far on this run, not applied until player sends the book.
 | 
				
			||||||
  wisdomApplied: 0, // wisdom from previous runs
 | 
					  wisdomApplied: 0, // wisdom from previous runs
 | 
				
			||||||
  totalLifetimes: 1,
 | 
					  totalLifetimes: 1,
 | 
				
			||||||
 | 
					  timeJumpsBackwards: 0,
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getters = {
 | 
					export const getters = {
 | 
				
			||||||
| 
						 | 
					@ -205,6 +251,22 @@ export const getters = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return `${year}y${month}m`
 | 
					    return `${year}y${month}m`
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  missionIsCompleted: (state) => (missionName) => {
 | 
				
			||||||
 | 
					    const mission = state.missions.find((m) => m.name === missionName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return mission && mission.complete
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  apprenticeLevels: (state) =>
 | 
				
			||||||
 | 
					    state.processes.reduce(
 | 
				
			||||||
 | 
					      (totalLevels, process) => (totalLevels += process.workerLevel),
 | 
				
			||||||
 | 
					      0
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					  instruments: (state) =>
 | 
				
			||||||
 | 
					    state.processes.reduce(
 | 
				
			||||||
 | 
					      (totalInstruments, process) =>
 | 
				
			||||||
 | 
					        process.created ? totalInstruments + 1 : totalInstruments,
 | 
				
			||||||
 | 
					      0
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const mutations = {
 | 
					export const mutations = {
 | 
				
			||||||
| 
						 | 
					@ -229,10 +291,14 @@ export const mutations = {
 | 
				
			||||||
  setMissionViewed: (state, missionIndex) => {
 | 
					  setMissionViewed: (state, missionIndex) => {
 | 
				
			||||||
    Vue.set(state.missions[missionIndex], 'viewed', true)
 | 
					    Vue.set(state.missions[missionIndex], 'viewed', true)
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  completeMission: (state, mission) => {
 | 
					  completeMission: (state, missionName) => {
 | 
				
			||||||
    const index = state.missions.findIndex((m) => m.name === mission.name)
 | 
					    const index = state.missions.findIndex((m) => m.name === missionName)
 | 
				
			||||||
    Vue.set(state.missions[index], 'complete', true)
 | 
					    Vue.set(state.missions[index], 'complete', true)
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  unlockMission: (state, missionName) => {
 | 
				
			||||||
 | 
					    const index = state.missions.findIndex((m) => m.name === missionName)
 | 
				
			||||||
 | 
					    Vue.set(state.missions[index], 'unlocked', true)
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  levelUpApprentice: (state, process) => {
 | 
					  levelUpApprentice: (state, process) => {
 | 
				
			||||||
    if (process.nextWorkerCost > state.currency) {
 | 
					    if (process.nextWorkerCost > state.currency) {
 | 
				
			||||||
      return
 | 
					      return
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Reference in New Issue