Skip to content

Commit 9966515

Browse files
Support Back Button in Tech Draft phase (instead of Reset button) (#62)
1 parent 05c7dca commit 9966515

17 files changed

Lines changed: 148 additions & 102 deletions

File tree

.vscode/settings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1-
{}
1+
{
2+
"i18n-ally.localesPaths": [
3+
"src/locales"
4+
]
5+
}

src/components/round/DebugInfo.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<b>draftingPriority</b>: <span v-html="getCardDeckInfo(draftingPriority)"></span><br/>
77
<b>construction</b>: <span v-html="getCardDeckInfo(construction)"></span><br/>
88
<b>war</b>: <span v-html="getCardDeckInfo(war)"></span><br/>
9+
<b>lastDraftStep</b>: {{navigationState.lastDraftStep}}<br/>
910
</p>
1011
</div>
1112
</template>

src/components/round/TechCardDraft.vue

Lines changed: 43 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -32,31 +32,27 @@
3232
<button class="btn btn-primary btn-lg me-3 mt-2" @click="next()">
3333
{{t('action.next')}}
3434
</button>
35-
<button class="btn btn-outline-secondary btn-sm mt-2" @click="reset()">
36-
{{t('action.reset')}}
37-
</button>
3835

3936
<div class="draftedCards">
40-
<div v-if="playerTechs.length > 0" class="mt-3">
41-
<TechCardsPlayerDraft :navigationState="navigationState" :playerTechs="playerTechs"/>
37+
<div v-if="techDraftStep.playerTechs.length > 0" class="mt-3">
38+
<TechCardsPlayerDraft :navigationState="navigationState" :playerTechs="techDraftStep.playerTechs"/>
4239
</div>
4340

44-
<div v-if="botTechs.length > 0" class="mt-3">
41+
<div v-if="techDraftStep.botTechs.length > 0" class="mt-3">
4542
<h5>{{t('phaseADrafting.botDraft')}}</h5>
4643
<div class="techs">
4744
<div class="techRow">
48-
<TechCard v-for="tech of botTechs" :key="tech" :navigationState="navigationState" :tech="tech" class="techCard disabled"/>
45+
<TechCard v-for="tech of techDraftStep.botTechs" :key="tech" :navigationState="navigationState" :tech="tech" class="techCard disabled"/>
4946
</div>
5047
</div>
5148
</div>
5249
</div>
53-
5450
</template>
5551

5652
<script lang="ts">
5753
import { defineComponent, ref } from 'vue'
5854
import { useI18n } from 'vue-i18n'
59-
import { useStateStore } from '@/store/state'
55+
import { TechDraftStep, useStateStore } from '@/store/state'
6056
import NavigationState from '@/util/NavigationState'
6157
import TechCardSelection from '@/services/TechCardSelection'
6258
import Tech from '@/services/enum/Tech'
@@ -67,6 +63,7 @@ import TechCard from './TechCard.vue'
6763
import AppIcon from '../structure/AppIcon.vue'
6864
import TechCardsPlayerDraft from './TechCardsPlayerDraft.vue'
6965
import { useRouter } from 'vue-router'
66+
import { cloneDeep } from 'lodash'
7067
7168
export default defineComponent({
7269
name: 'TechCardDraft',
@@ -81,11 +78,18 @@ export default defineComponent({
8178
const router = useRouter()
8279
8380
const roundData = state.rounds.find(item => item.round == props.navigationState.round)!
84-
const botTechs = ref(roundData.botTechs ?? [])
85-
const playerTechs = ref(roundData.playerTechs ?? [])
86-
const playerSpecialActions = ref(roundData.playerSpecialActions ?? 0)
81+
const lastTechDraftStep = props.navigationState.lastDraftStep
82+
const techDraftStep = ref({
83+
round: props.navigationState.round,
84+
step: props.navigationState.draftingStep,
85+
nextStartPlayer: lastTechDraftStep?.nextStartPlayer,
86+
nextArchitectPlayer: lastTechDraftStep?.nextArchitectPlayer,
87+
botTechs: cloneDeep(lastTechDraftStep?.botTechs ?? []),
88+
playerTechs: cloneDeep(lastTechDraftStep?.playerTechs ?? []),
89+
playerSpecialActions: lastTechDraftStep?.playerSpecialActions ?? 0
90+
} as TechDraftStep)
8791
88-
return { t, state, router, roundData, botTechs, playerTechs, playerSpecialActions }
92+
return { t, state, router, roundData, techDraftStep }
8993
},
9094
props: {
9195
navigationState: {
@@ -108,22 +112,22 @@ export default defineComponent({
108112
return this.navigationState.techCardSelection
109113
},
110114
botMarkerPlaced() : number {
111-
return this.botTechs.length
115+
return this.techDraftStep.botTechs.length
112116
},
113117
playerMarkerPlaced() : number {
114-
return this.playerTechs.length + this.playerSpecialActions
118+
return this.techDraftStep.playerTechs.length + this.techDraftStep.playerSpecialActions
115119
},
116120
draftingCompleted() : boolean {
117121
return this.botMarkerPlaced == 4 && this.playerMarkerPlaced == 4
118122
},
119123
playerIncomeTotal() : number {
120-
return this.playerTechs.map(tech => this.techCardSelection.getIncome(tech)).filter(value => value < 5).reduce((a,b) => a+b, 0)
124+
return this.techDraftStep.playerTechs.map(tech => this.techCardSelection.getIncome(tech)).filter(value => value < 5).reduce((a,b) => a+b, 0)
121125
},
122126
playerIncomeLockedTotal() : number {
123-
return this.playerTechs.map(tech => this.techCardSelection.getIncome(tech)).filter(value => value == 5).reduce((a,b) => a+b, 0)
127+
return this.techDraftStep.playerTechs.map(tech => this.techCardSelection.getIncome(tech)).filter(value => value == 5).reduce((a,b) => a+b, 0)
124128
},
125129
botRound8Army() : boolean {
126-
return this.navigationState.round == 8 && this.botTechs.includes(Tech.ARMY)
130+
return this.navigationState.round == 8 && this.techDraftStep.botTechs.includes(Tech.ARMY)
127131
}
128132
},
129133
methods: {
@@ -145,21 +149,15 @@ export default defineComponent({
145149
await new Promise(resolve => setTimeout(resolve, 400))
146150
this.removeAnimation = false
147151
this.navigationState.techCardSelection.remove(tech)
148-
this.persist()
149152
},
150153
async nextTurn() {
151154
if (this.draftingCompleted) {
152155
return
153156
}
154-
if (this.botMarkerPlaced < this.playerMarkerPlaced) {
157+
if (this.roundData.startPlayer == Player.BOT) {
155158
await this.nextTurnBot()
156-
}
157-
else if (this.playerMarkerPlaced < this.botMarkerPlaced) {
158159
await this.nextTurnPlayer()
159160
}
160-
else if (this.roundData.startPlayer == Player.BOT) {
161-
await this.nextTurnBot()
162-
}
163161
else {
164162
await this.nextTurnPlayer()
165163
}
@@ -169,15 +167,14 @@ export default defineComponent({
169167
const draftingRowCard = botCards.draftingRow.draw()
170168
const draftingPriorityCard = botCards.draftingPriority.draw()
171169
const tech = techCardSelection.determineTech(draftingRowCard, draftingPriorityCard, prosperityCards.current.flat())
172-
this.botTechs.push(tech)
170+
this.techDraftStep.botTechs.push(tech)
173171
if (tech == Tech.ARMY) {
174-
this.roundData.nextStartPlayer = Player.BOT
172+
this.techDraftStep.nextStartPlayer = Player.BOT
175173
}
176174
if (tech == Tech.ENGINEERING) {
177-
this.roundData.nextArchitectPlayer = Player.BOT
175+
this.techDraftStep.nextArchitectPlayer = Player.BOT
178176
}
179177
await this.remove(tech)
180-
await this.nextTurn()
181178
},
182179
async nextTurnPlayer() {
183180
this.playerTurn = true
@@ -191,48 +188,37 @@ export default defineComponent({
191188
return
192189
}
193190
this.playerTurn = false
194-
this.playerTechs.push(t)
195-
this.roundData.playerTechs = this.playerTechs
191+
this.techDraftStep.playerTechs.push(t)
196192
if (t == Tech.ARMY) {
197-
this.roundData.nextStartPlayer = Player.PLAYER
193+
this.techDraftStep.nextStartPlayer = Player.PLAYER
198194
}
199195
if (t == Tech.ENGINEERING) {
200-
this.roundData.nextArchitectPlayer = Player.PLAYER
196+
this.techDraftStep.nextArchitectPlayer = Player.PLAYER
201197
}
202198
await this.remove(t)
203-
await this.nextTurn()
204-
},
205-
async reset() {
206-
this.techCardSelection.reset()
207-
this.navigationState.botCards.draftingRow.reset()
208-
this.navigationState.botCards.draftingPriority.reset()
209-
this.roundData.nextStartPlayer = undefined
210-
this.roundData.nextArchitectPlayer = undefined
211-
this.roundData.playerTechs = undefined
212-
213-
this.botTechs = []
214-
this.playerTechs = []
215-
this.playerSpecialActions = 0
216-
217-
this.persist()
218-
await this.nextTurn()
199+
await this.playerTurnCompleted()
219200
},
220201
async next() {
221202
if (this.draftingCompleted) {
222203
this.router.push(this.nextButtonRouteTo)
223204
}
224205
else {
225-
this.playerSpecialActions++
206+
this.techDraftStep.playerSpecialActions++
226207
this.playerTurn = false
227-
this.persist()
228-
await this.nextTurn()
208+
await this.playerTurnCompleted()
209+
}
210+
},
211+
async playerTurnCompleted() {
212+
// if player was first player, execute bot turn before going to next step
213+
if (this.roundData.startPlayer == Player.PLAYER) {
214+
await this.nextTurnBot()
229215
}
216+
this.persistAndNextStep()
230217
},
231-
persist() : void {
232-
this.roundData.techCardSelection = this.techCardSelection.toPersistence()
233-
this.roundData.botTechs = this.botTechs
234-
this.roundData.playerTechs = this.playerTechs
235-
this.roundData.playerSpecialActions = this.playerSpecialActions
218+
persistAndNextStep() : void {
219+
this.techDraftStep.techCardSelection = this.techCardSelection.toPersistence()
220+
this.state.storeTechDraftStep(this.techDraftStep)
221+
this.router.push(`/round/${this.navigationState.round}/drafting/${this.techDraftStep.step+1}`)
236222
}
237223
},
238224
mounted() {

src/locales/de.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,7 @@
130130
"backToHome": "Zurück zum Anfang",
131131
"back": "Zurück",
132132
"close": "Schließen",
133-
"ok": "OK",
134-
"reset": "Zurücksetzen"
133+
"ok": "OK"
135134
},
136135
"footer": {
137136
"credits": "Credits"

src/locales/en.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,7 @@
130130
"backToHome": "Back to Home",
131131
"back": "Back",
132132
"close": "Close",
133-
"ok": "OK",
134-
"reset": "Reset"
133+
"ok": "OK"
135134
},
136135
"footer": {
137136
"credits": "Credits"

src/router/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ const routes: Array<RouteRecordRaw> = [
3535
},
3636
{
3737
path: '/round/:round/drafting',
38+
// redirect to step 1 of drafting phase (route is kept for backward compatibility)
39+
redirect: (to) => ({ name: 'PhaseADrafting', params: { round: to.params.round, step: '1' } })
40+
},
41+
{
42+
path: '/round/:round/drafting/:step',
3843
name: 'PhaseADrafting',
3944
component: PhaseADrafting
4045
},

src/services/TechCardSelection.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,6 @@ export default class TechCardSelection {
105105
throw new Error('Tech card not found.')
106106
}
107107

108-
/**
109-
* Resets the removed tech cards.
110-
*/
111-
public reset() : void {
112-
this._removedTechs.value = []
113-
}
114-
115108
/**
116109
* Creates a selection of techs in 4 ros respecting the placeholder rows.
117110
*/

src/store/state.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ export const useStateStore = defineStore(`${name}.state`, {
2525
storeRound(round : Round) {
2626
this.rounds = this.rounds.filter(item => item.round < round.round)
2727
this.rounds.push(round)
28+
},
29+
storeTechDraftStep(techDraftStep : TechDraftStep) {
30+
const round = this.rounds.find(item => item.round == techDraftStep.round)
31+
if (round) {
32+
round.techDraftSteps = (round.techDraftSteps ?? []).filter(item => item.step < techDraftStep.step)
33+
round.techDraftSteps.push(techDraftStep)
34+
}
2835
}
2936
},
3037
persist: true
@@ -51,12 +58,26 @@ export interface Round {
5158
prosperityCards: ProsperityCardsPersistence
5259
botCards: BotCardsPersistence
5360
rowPlaceholders: RowPlaceholdersPersistence
54-
techCardSelection: TechCardSelectionPersistence
61+
initialTechCardSelection?: TechCardSelectionPersistence
62+
techDraftSteps?: TechDraftStep[]
63+
// the following fields are deprecated, latest implementation uses the initialTechCardSelection and techDraftSteps fields instead
5564
nextStartPlayer?: Player
5665
nextArchitectPlayer?: Player
5766
botTechs?: Tech[]
5867
playerTechs?: Tech[]
5968
playerSpecialActions?: number
69+
techCardSelection?: TechCardSelectionPersistence
70+
}
71+
72+
export interface TechDraftStep {
73+
round: number
74+
step: number
75+
techCardSelection: TechCardSelectionPersistence
76+
nextStartPlayer?: Player
77+
nextArchitectPlayer?: Player
78+
botTechs: Tech[]
79+
playerTechs: Tech[]
80+
playerSpecialActions: number
6081
}
6182

6283
export interface BotCardsPersistence {

src/util/NavigationState.ts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Round, State } from '@/store/state'
1+
import { Round, State, TechCardSelectionPersistence, TechDraftStep } from '@/store/state'
22
import { RouteLocation } from 'vue-router'
33
import getIntRouteParam from '@brdgm/brdgm-commons/src/util/router/getIntRouteParam'
44
import Player from '@/services/enum/Player'
@@ -10,15 +10,18 @@ import TechCardSelection from '@/services/TechCardSelection'
1010
export default class NavigationState {
1111

1212
readonly round : number
13+
readonly draftingStep: number
1314
readonly prosperityCards : ProsperityCards
1415
readonly botCards : BotCards
1516
readonly rowPlaceholders : RowPlaceholders
1617
readonly techCardSelection : TechCardSelection
1718

1819
private readonly roundData : Round
20+
readonly lastDraftStep? : TechDraftStep
1921

2022
constructor(route: RouteLocation, state: State) {
2123
this.round = getIntRouteParam(route, 'round')
24+
this.draftingStep = getIntRouteParam(route, 'step')
2225

2326
let roundData = state.rounds.find(item => item.round === this.round)
2427
if (!roundData) {
@@ -31,22 +34,42 @@ export default class NavigationState {
3134
prosperityCards: ProsperityCards.new().toPersistence(),
3235
botCards: BotCards.new(state.setup.difficultyLevel).toPersistence(),
3336
rowPlaceholders: rowPlaceholders.toPersistence(),
34-
techCardSelection: TechCardSelection.new(rowPlaceholders.rows, this.round).toPersistence()
3537
}
3638
}
3739
this.roundData = roundData
40+
this.lastDraftStep = this.getLastDraftStep()
3841
this.prosperityCards = ProsperityCards.fromPersistence(roundData.prosperityCards)
3942
this.botCards = BotCards.fromPersistence(roundData.botCards)
4043
this.rowPlaceholders = RowPlaceholders.fromPersistence(roundData.rowPlaceholders)
41-
this.techCardSelection = TechCardSelection.fromPersistence(roundData.techCardSelection, this.round)
44+
this.techCardSelection = TechCardSelection.fromPersistence(this.getTechCardSelectionPersistence(), this.round)
4245
}
4346

4447
public get startPlayer() : Player {
45-
return this.roundData.nextStartPlayer ?? this.roundData.startPlayer
48+
return this.lastDraftStep?.nextStartPlayer ?? this.roundData.nextStartPlayer ?? this.roundData.startPlayer
4649
}
4750

4851
public get architectPlayer() : Player {
49-
return this.roundData.nextArchitectPlayer ?? this.roundData.architectPlayer
52+
return this.lastDraftStep?.nextArchitectPlayer ?? this.roundData.nextArchitectPlayer ?? this.roundData.architectPlayer
53+
}
54+
55+
private getLastDraftStep() : TechDraftStep | undefined {
56+
return (this.roundData.techDraftSteps?.toSorted((a, b) => a.step - b.step) ?? [])
57+
.findLast(item => item.step < this.draftingStep || this.draftingStep == 0)
58+
}
59+
60+
private getTechCardSelectionPersistence() : TechCardSelectionPersistence {
61+
if (this.lastDraftStep?.techCardSelection) {
62+
return this.lastDraftStep?.techCardSelection
63+
}
64+
if (this.roundData.initialTechCardSelection) {
65+
return this.roundData.initialTechCardSelection
66+
}
67+
if (this.roundData.techCardSelection) {
68+
// backward compatibility with old implementation; reset selection to restart draft
69+
return { techs: this.roundData.techCardSelection.techs, removedTechs: [] }
70+
}
71+
// should never happen
72+
return TechCardSelection.new(this.rowPlaceholders.rows, this.round).toPersistence()
5073
}
5174

5275
}

0 commit comments

Comments
 (0)