11import { get } from "svelte/store" ;
22import { Block , Facing } from "./constants.ts" ;
3+ import { printCells } from "./grid.ts" ;
34import { createSnapshot } from "./history.ts" ;
45import type { Player } from "./player.ts" ;
56import type {
@@ -44,6 +45,12 @@ export class AbilityControl {
4445 e . preventDefault ( ) ;
4546 if ( this . usage . paste > 0 ) this . paste ( cx , parent . facing ) ;
4647 } ) ;
48+ const ss = createSnapshot ( cx ) ;
49+ const cfg = get ( cx . config ) ;
50+ ss . playerX = cfg . initialPlayerX ;
51+ ss . playerY = cfg . initialPlayerY ;
52+ console . log ( ss ) ;
53+ this . pushHistory ( cx , ss ) ;
4754 }
4855 setInventory ( cx : Context , inventory : MovableObject | null ) {
4956 this . inventory = structuredClone ( inventory ) ;
@@ -96,7 +103,7 @@ export class AbilityControl {
96103 paste ( cx : Context , facing : Facing ) {
97104 const state = get ( cx . state ) ;
98105 if ( ! this . focused ) return ;
99- if ( ! this . inventory /*|| this.inventory === Block.air*/ ) return ;
106+ if ( ! this . inventory ) return ;
100107
101108 // 左向きのときにブロックを配置する位置を変更するのに使用
102109 const width =
@@ -134,6 +141,7 @@ export class AbilityControl {
134141 paste : -- this . usage . paste ,
135142 } ) ) ;
136143
144+ printCells ( createSnapshot ( cx ) . game . cells , "paste" ) ;
137145 this . pushHistory ( cx , createSnapshot ( cx ) ) ;
138146 }
139147 cut ( cx : Context ) {
@@ -145,90 +153,103 @@ export class AbilityControl {
145153 const target = cx . grid . getBlock ( x , y ) ;
146154 // removable 以外はカットできない
147155 if ( ! target || target !== Block . movable ) return ;
148- const prevInventory = this . inventory ;
149156 const movableObject = cx . grid . getMovableObject ( x , y ) ;
150157 if ( ! movableObject ) return ;
151158
152- this . pushHistory ( cx , createSnapshot ( cx ) ) ; // TODO: snapshot current state
153-
159+ this . pushHistory ( cx , createSnapshot ( cx ) ) ;
154160 this . setInventory ( cx , movableObject ) ;
155161
156162 cx . grid . update ( cx , ( prev ) =>
157163 prev . objectId === movableObject . objectId ? { block : Block . air } : prev ,
158164 ) ;
159- const prevEnabled = { ...this . usage } ;
160165 cx . uiContext . update ( ( prev ) => ( {
161166 ...prev ,
162167 cut : -- this . usage . cut ,
163168 } ) ) ;
164169
170+ printCells ( createSnapshot ( cx ) . game . cells , "cut" ) ;
165171 this . pushHistory ( cx , createSnapshot ( cx ) ) ;
166172 }
167173
168174 // History については、 `docs/history-stack.png` を参照のこと
169175 pushHistory ( cx : Context , h : StateSnapshot ) {
176+ printCells ( h . game . cells , "pushHistory" ) ;
170177 cx . history . update ( ( prev ) => {
171- prev . tree = prev . tree . slice ( 0 , prev . index + 1 ) ;
178+ if ( prev . tree . length > prev . index + 1 ) {
179+ // redo した後に undo した場合、履歴を切り詰める
180+ prev . tree . length = prev . index + 1 ;
181+ }
172182 prev . tree . push ( h ) ;
173- prev . index ++ ;
183+ prev . index = prev . tree . length - 1 ;
174184 return prev ;
175185 } ) ;
176186 }
177- undo ( cx : Context ) {
178- cx . history . update ( ( prev ) => {
179- const history = prev ;
180- const grid = cx . grid ;
181- if ( history . index <= 0 ) return history ;
182- history . index -- ;
183- const snapshot = history . tree [ history . index ] ;
187+ undo ( cx : Context ) : { x : number ; y : number } | undefined {
188+ const history = get ( cx . history ) ;
189+ if ( history . index <= 0 ) return undefined ;
190+ const grid = cx . grid ;
191+ history . index -- ;
192+ const snapshot = history . tree [ history . index ] ;
193+ printCells ( snapshot . game . cells ) ;
184194
185- // オブジェクトを配置
186- this . setInventory ( cx , snapshot . game . inventory ) ;
187- grid . diffAndUpdateTo ( snapshot . game . cells ) ;
195+ // オブジェクトを配置
196+ this . setInventory ( cx , snapshot . game . inventory ) ;
197+ grid . diffAndUpdateTo ( cx , snapshot . game . cells ) ;
198+ printCells ( snapshot . game . cells , "undo" ) ;
199+ this . usage = snapshot . game . usage ;
200+ cx . uiContext . update ( ( ui ) => ( {
201+ ...ui ,
202+ ...this . usage ,
203+ undo : history . index ,
204+ redo : history . tree . length - history . index ,
205+ } ) ) ;
188206
189- this . usage = snapshot . game . usage ;
190- cx . uiContext . update ( ( prev ) => ( {
191- ...prev ,
192- ...this . usage ,
193- undo : history . index ,
194- redo : history . tree . length - history . index ,
195- } ) ) ;
207+ cx . history . set ( history ) ;
196208
197- console . log ( `history: ${ history . index } / ${ history . tree . length } ` ) ;
198- return prev ;
199- } ) ;
209+ console . log ( `history: ${ history . index } / ${ history . tree . length - 1 } ` ) ;
210+ return {
211+ x : history . tree [ history . index ] . playerX ,
212+ y : history . tree [ history . index ] . playerY ,
213+ } ;
200214 }
201- redo ( cx : Context , history : GameHistory ) {
202- if ( history . index >= history . tree . length ) return ;
215+ redo ( cx : Context ) : { x : number ; y : number } | undefined {
216+ // TODO: プレイヤーの座標の履歴を「いい感じ」にするため、 history を二重管理する
217+ const history = get ( cx . history ) ;
218+ if ( history . index >= history . tree . length - 1 ) return undefined ;
203219 const snapshot = history . tree [ history . index ] ;
220+ printCells ( snapshot . game . cells , "redo" ) ;
204221 history . index ++ ; // redo は、巻き戻し前の index
205222 const grid = cx . grid ;
206223
207- // オブジェクトを配置
208- grid . diffAndUpdateTo ( snapshot . game . cells ) ;
209-
224+ // 状態を巻き戻す
225+ grid . diffAndUpdateTo ( cx , snapshot . game . cells ) ;
210226 this . setInventory ( cx , snapshot . game . inventory ) ;
211227
212228 this . usage = snapshot . game . usage ;
213- cx . uiContext . update ( ( prev ) => ( {
214- ...prev ,
229+ cx . uiContext . update ( ( ui ) => ( {
230+ ...ui ,
215231 ...this . usage ,
216232 undo : history . index ,
217233 redo : history . tree . length - history . index ,
218234 } ) ) ;
219235
220- console . log ( `history: ${ history . index } / ${ history . tree . length } ` ) ;
236+ console . log ( `history: ${ history . index } / ${ history . tree . length - 1 } ` ) ;
237+ cx . history . set ( history ) ;
238+ return {
239+ x : history . tree [ history . index ] . playerX ,
240+ y : history . tree [ history . index ] . playerY ,
241+ } ;
221242 }
222243 handleKeyDown (
223244 cx : Context ,
224245 e : KeyboardEvent ,
225246 onGround : boolean ,
226247 facing : Facing ,
227- history : GameHistory ,
228248 playerAt : Coords ,
229- ) {
249+ ) : { x : number ; y : number } | undefined {
230250 if ( ! ( e . ctrlKey || e . metaKey ) ) return undefined ;
231251
252+ e . preventDefault ( ) ;
232253 if ( this . usage . paste > 0 && onGround && e . key === "v" ) {
233254 this . paste ( cx , facing ) ;
234255 }
@@ -237,24 +258,14 @@ export class AbilityControl {
237258 }
238259 if ( this . usage . cut > 0 && onGround && e . key === "x" ) {
239260 this . cut ( cx ) ;
261+ return undefined ;
240262 }
241263 if ( e . key === "z" ) {
242- console . log ( history ) ;
243- this . undo ( cx ) ;
244- e . preventDefault ( ) ;
245- return {
246- x : history . tree [ history . index ] . playerX ,
247- y : history . tree [ history . index ] . playerY ,
248- } ;
264+ return this . undo ( cx ) ;
249265 }
250266 if ( e . key === "y" ) {
251- this . redo ( cx , history ) ;
252267 e . preventDefault ( ) ;
253- if ( history . index >= history . tree . length ) return ;
254- return {
255- x : history . tree [ history . index ] . playerX ,
256- y : history . tree [ history . index ] . playerY ,
257- } ;
268+ return this . redo ( cx ) ;
258269 }
259270 }
260271}
@@ -263,11 +274,11 @@ function placeMovableObject(
263274 cx : Context ,
264275 x : number ,
265276 y : number ,
266- movableObject : MovableObject ,
277+ object : MovableObject ,
267278) {
268279 const grid = cx . grid ;
269280
270- for ( const i of movableObject . relativePositions ) {
281+ for ( const i of object . relativePositions ) {
271282 const positionX = x + i . x ;
272283 const positionY = y + i . y ;
273284 const target = grid . getBlock ( positionX , positionY ) ;
@@ -276,12 +287,12 @@ function placeMovableObject(
276287 return ;
277288 }
278289 }
279- for ( const i of movableObject . relativePositions ) {
280- const positionX = x + i . x ;
281- const positionY = y + i . y ;
282- grid . setBlock ( cx , x , y , {
283- block : movableObject . block ,
284- objectId : movableObject . objectId ,
290+ for ( const rel of object . relativePositions ) {
291+ const positionX = x + rel . x ;
292+ const positionY = y + rel . y ;
293+ grid . setBlock ( cx , positionX , positionY , {
294+ block : object . block ,
295+ objectId : object . objectId ,
285296 } ) ;
286297 }
287298}
0 commit comments