@@ -2,13 +2,13 @@ import { get } from "svelte/store";
22import { Block , Facing } from "./constants.ts" ;
33import { printCells } from "./grid.ts" ;
44import { createSnapshot } from "./history.ts" ;
5+ import * as History from "./history.ts" ;
56import type {
67 AbilityInit ,
78 Context ,
89 Coords ,
910 MovableObject ,
1011} from "./public-types.ts" ;
11- import type { StateSnapshot } from "./public-types.ts" ;
1212
1313export function init ( cx : Context , options ?: AbilityInit ) {
1414 cx . state . update ( ( prev ) => ( {
@@ -37,29 +37,24 @@ export function init(cx: Context, options?: AbilityInit) {
3737 e . preventDefault ( ) ;
3838 if ( get ( cx . state ) . usage . paste > 0 && onGround ) paste ( cx ) ;
3939 } ) ;
40- // TODO: use proper event names, because it won't work
41- document . addEventListener ( "undo" , ( e ) => {
42- e . preventDefault ( ) ;
43- undo ( cx ) ;
44- } ) ;
45- document . addEventListener ( "redo" , ( e ) => {
46- e . preventDefault ( ) ;
47- redo ( cx ) ;
40+
41+ // there is no such thing as undo / redo event
42+ document . addEventListener ( "keydown" , ( e ) => {
43+ if ( ! e . ctrlKey && ! e . metaKey ) return ;
44+ switch ( e . key ) {
45+ case "z" :
46+ e . preventDefault ( ) ;
47+ History . undo ( cx ) ;
48+ break ;
49+ case "y" :
50+ e . preventDefault ( ) ;
51+ History . redo ( cx ) ;
52+ break ;
53+ }
4854 } ) ;
49- const ss = createSnapshot ( cx ) ;
50- const cfg = get ( cx . config ) ;
51- ss . playerX = cfg . initialPlayerX ;
52- ss . playerY = cfg . initialPlayerY ;
53- console . log ( ss ) ;
54- pushHistory ( cx , ss ) ;
55+ History . record ( cx ) ;
5556}
5657
57- export function setInventory ( cx : Context , inventory : MovableObject | null ) {
58- cx . state . update ( ( prev ) => ( {
59- ...prev ,
60- inventory : structuredClone ( inventory ) ,
61- } ) ) ;
62- }
6358export function focusCoord ( playerAt : Coords , facing : Facing ) {
6459 let dx : number ;
6560 switch ( facing ) {
@@ -89,14 +84,14 @@ export function copy(cx: Context) {
8984 const movableObject = cx . grid . getMovableObject ( x , y ) ;
9085 if ( ! movableObject ) return ;
9186
92- pushHistory ( cx , createSnapshot ( cx ) ) ;
87+ History . record ( cx ) ;
9388
94- // コピー元とは別のオブジェクトとして管理する (これ必要?)
95- movableObject . objectId = self . crypto . randomUUID ( ) ;
96-
97- setInventory ( cx , movableObject ) ;
89+ cx . state . update ( ( prev ) => {
90+ prev . inventory = movableObject ;
91+ return prev ;
92+ } ) ;
9893
99- pushHistory ( cx , createSnapshot ( cx ) ) ;
94+ History . record ( cx ) ;
10095}
10196export function paste ( cx : Context ) {
10297 const state = get ( cx . state ) ;
@@ -126,14 +121,17 @@ export function paste(cx: Context) {
126121 }
127122 }
128123
129- pushHistory ( cx , createSnapshot ( cx ) ) ;
124+ History . record ( cx ) ;
130125 placeMovableObject ( cx , x , y , inventory ) ;
131126 if ( ! get ( cx . state ) . inventoryIsInfinite ) {
132- setInventory ( cx , null ) ;
127+ cx . state . update ( ( prev ) => {
128+ prev . inventory = null ;
129+ return prev ;
130+ } ) ;
133131 }
134132
135133 printCells ( createSnapshot ( cx ) . game . cells , "paste" ) ;
136- pushHistory ( cx , createSnapshot ( cx ) ) ;
134+ History . record ( cx ) ;
137135}
138136export function cut ( cx : Context ) {
139137 const { focus } = cx . dynamic ;
@@ -147,86 +145,18 @@ export function cut(cx: Context) {
147145 const movableObject = cx . grid . getMovableObject ( x , y ) ;
148146 if ( ! movableObject ) return ;
149147
150- pushHistory ( cx , createSnapshot ( cx ) ) ;
151- setInventory ( cx , movableObject ) ;
148+ History . record ( cx ) ;
152149
150+ cx . state . update ( ( prev ) => {
151+ prev . inventory = movableObject ;
152+ return prev ;
153+ } ) ;
153154 cx . grid . update ( cx , ( prev ) =>
154155 prev . objectId === movableObject . objectId ? { block : Block . air } : prev ,
155156 ) ;
156157
157158 printCells ( createSnapshot ( cx ) . game . cells , "cut" ) ;
158- pushHistory ( cx , createSnapshot ( cx ) ) ;
159- }
160-
161- // History については、 `docs/history-stack.png` を参照のこと
162- export function pushHistory ( cx : Context , h : StateSnapshot ) {
163- printCells ( h . game . cells , "pushHistory" ) ;
164- cx . history . update ( ( prev ) => {
165- if ( prev . tree . length > prev . index + 1 ) {
166- // undo した後に pushHistory をする場合、履歴を切り詰める
167- prev . tree . length = prev . index + 1 ;
168- }
169- prev . tree . push ( h ) ;
170- prev . index = prev . tree . length - 1 ;
171- return prev ;
172- } ) ;
173- }
174- function undo ( cx : Context ) : { x : number ; y : number } | undefined {
175- const history = get ( cx . history ) ;
176- if ( history . index <= 0 ) return undefined ;
177- const grid = cx . grid ;
178- history . index -- ;
179- const snapshot = history . tree [ history . index ] ;
180- printCells ( snapshot . game . cells ) ;
181-
182- // オブジェクトを配置
183- setInventory ( cx , snapshot . game . inventory ) ;
184- grid . diffAndUpdateTo ( cx , snapshot . game . cells ) ;
185- printCells ( snapshot . game . cells , "undo" ) ;
186- cx . state . update ( ( prev ) => {
187- return {
188- ...prev ,
189- usage : snapshot . game . usage ,
190- inventory : snapshot . game . inventory ,
191- inventoryIsInfinite : snapshot . game . inventoryIsInfinite ,
192- } ;
193- } ) ;
194- cx . dynamic . player . x = snapshot . playerX ;
195- cx . dynamic . player . y = snapshot . playerY ;
196-
197- cx . history . set ( history ) ;
198-
199- console . log ( `history: ${ history . index } / ${ history . tree . length - 1 } ` ) ;
200- return {
201- x : history . tree [ history . index ] . playerX ,
202- y : history . tree [ history . index ] . playerY ,
203- } ;
204- }
205-
206- function redo ( cx : Context ) : { x : number ; y : number } | undefined {
207- // TODO: プレイヤーの座標の履歴を「いい感じ」にするため、 history を二重管理する
208- const history = get ( cx . history ) ;
209- if ( history . index >= history . tree . length - 1 ) return undefined ;
210- const snapshot = history . tree [ history . index ] ;
211- printCells ( snapshot . game . cells , "redo" ) ;
212- history . index ++ ; // redo は、巻き戻し前の index
213- const grid = cx . grid ;
214-
215- // 状態を巻き戻す
216- grid . diffAndUpdateTo ( cx , snapshot . game . cells ) ;
217- setInventory ( cx , snapshot . game . inventory ) ;
218-
219- cx . state . update ( ( prev ) => ( {
220- ...prev ,
221- usage : snapshot . game . usage ,
222- } ) ) ;
223-
224- console . log ( `history: ${ history . index } / ${ history . tree . length - 1 } ` ) ;
225- cx . history . set ( history ) ;
226- return {
227- x : history . tree [ history . index ] . playerX ,
228- y : history . tree [ history . index ] . playerY ,
229- } ;
159+ History . record ( cx ) ;
230160}
231161
232162export function placeMovableObject (
0 commit comments