@@ -7,11 +7,13 @@ export type Coords = {
77} ;
88export type AbilityInit = {
99 enabled ?: AbilityEnableOptions ;
10+ inventoryIsInfinite ?: boolean ;
1011} ;
1112export type AbilityEnableOptions = {
12- copy : boolean ;
13- paste : boolean ;
14- cut : boolean ;
13+ // 回数 or Number.POSITIVE_INFINITY
14+ copy : number ;
15+ paste : number ;
16+ cut : number ;
1517} ;
1618type History = {
1719 at : { x : number ; y : number } ;
@@ -21,33 +23,53 @@ type History = {
2123 before : Block | null ;
2224 after : Block | null ;
2325 } ;
26+ enabled : {
27+ before : AbilityEnableOptions ;
28+ after : AbilityEnableOptions ;
29+ } ;
2430} ;
2531export class AbilityControl {
2632 history : History [ ] = [ ] ;
2733 historyIndex = 0 ;
2834 inventory : Block | null = null ;
29- inventoryIsInfinite = false ;
35+ inventoryIsInfinite : boolean ;
3036 enabled : AbilityEnableOptions ;
3137 focused : Coords | undefined ;
3238 constructor ( cx : Context , options ?: AbilityInit ) {
3339 this . enabled = options ?. enabled ?? {
34- copy : true ,
35- paste : true ,
36- cut : true ,
40+ copy : Number . POSITIVE_INFINITY ,
41+ paste : Number . POSITIVE_INFINITY ,
42+ cut : Number . POSITIVE_INFINITY ,
3743 } ;
44+ this . inventoryIsInfinite = options ?. inventoryIsInfinite ?? false ;
45+ cx . uiContext . update ( ( prev ) => ( {
46+ ...prev ,
47+ inventory : this . inventory ,
48+ inventoryIsInfinite : this . inventoryIsInfinite ,
49+ ...this . enabled ,
50+ undo : 0 ,
51+ redo : 0 ,
52+ } ) ) ;
3853 document . addEventListener ( "copy" , ( e ) => {
3954 e . preventDefault ( ) ;
40- if ( this . enabled . copy ) this . copy ( cx ) ;
55+ if ( this . enabled . copy > 0 ) this . copy ( cx ) ;
4156 } ) ;
4257 document . addEventListener ( "cut" , ( e ) => {
4358 e . preventDefault ( ) ;
44- if ( this . enabled . cut ) this . cut ( cx ) ;
59+ if ( this . enabled . cut > 0 ) this . cut ( cx ) ;
4560 } ) ;
4661 document . addEventListener ( "paste" , ( e ) => {
4762 e . preventDefault ( ) ;
48- if ( this . enabled . paste ) this . paste ( cx ) ;
63+ if ( this . enabled . paste > 0 ) this . paste ( cx ) ;
4964 } ) ;
5065 }
66+ setInventory ( cx : Context , inventory : Block | null ) {
67+ this . inventory = inventory ;
68+ cx . uiContext . update ( ( prev ) => ( {
69+ ...prev ,
70+ inventory,
71+ } ) ) ;
72+ }
5173 highlightCoord ( playerAt : Coords , facing : Facing ) {
5274 let dx : number ;
5375 switch ( facing ) {
@@ -70,7 +92,11 @@ export class AbilityControl {
7092 if ( ! this . focused ) return ;
7193 const target = cx . grid . getBlock ( this . focused . x , this . focused . y ) ;
7294 if ( ! target || target !== Block . movable ) return ;
73- this . inventory = target ;
95+ this . setInventory ( cx , target ) ;
96+ cx . uiContext . update ( ( prev ) => ( {
97+ ...prev ,
98+ copy : -- this . enabled . copy ,
99+ } ) ) ;
74100 }
75101 paste ( cx : Context ) {
76102 if ( ! this . focused ) return ;
@@ -80,17 +106,25 @@ export class AbilityControl {
80106 const prevInventory = this . inventory ;
81107 cx . grid . setBlock ( cx , this . focused . x , this . focused . y , this . inventory ) ;
82108 if ( ! this . inventoryIsInfinite ) {
83- this . inventory = null ;
109+ this . setInventory ( cx , null ) ;
84110 }
85-
86- this . pushHistory ( {
111+ const prevEnabled = { ...this . enabled } ;
112+ cx . uiContext . update ( ( prev ) => ( {
113+ ...prev ,
114+ paste : -- this . enabled . paste ,
115+ } ) ) ;
116+ this . pushHistory ( cx , {
87117 at : { ...this . focused } ,
88118 from : Block . air ,
89119 to : prevInventory ,
90120 inventory : {
91121 before : prevInventory ,
92122 after : this . inventory ,
93123 } ,
124+ enabled : {
125+ before : prevEnabled ,
126+ after : this . enabled ,
127+ } ,
94128 } ) ;
95129 }
96130 cut ( cx : Context ) {
@@ -99,55 +133,82 @@ export class AbilityControl {
99133 // removable 以外はカットできない
100134 if ( ! target || target !== Block . movable ) return ;
101135 const prevInventory = this . inventory ;
102- this . inventory = target ;
136+ this . setInventory ( cx , target ) ;
103137 cx . grid . setBlock ( cx , this . focused . x , this . focused . y , Block . air ) ;
104-
105- this . pushHistory ( {
138+ const prevEnabled = { ...this . enabled } ;
139+ cx . uiContext . update ( ( prev ) => ( {
140+ ...prev ,
141+ cut : -- this . enabled . cut ,
142+ } ) ) ;
143+ this . pushHistory ( cx , {
106144 at : { ...this . focused } ,
107145 from : target ,
108146 to : Block . air ,
109147 inventory : {
110148 before : prevInventory ,
111149 after : target ,
112150 } ,
151+ enabled : {
152+ before : prevEnabled ,
153+ after : this . enabled ,
154+ } ,
113155 } ) ;
114156 }
115157
116158 // History については、 `docs/history-stack.png` を参照のこと
117- pushHistory ( h : History ) {
159+ pushHistory ( cx : Context , h : History ) {
118160 this . history = this . history . slice ( 0 , this . historyIndex ) ;
119161 this . history . push ( h ) ;
120162 this . historyIndex = this . history . length ;
121163 console . log ( `history: ${ this . historyIndex } / ${ this . history . length } ` ) ;
164+ cx . uiContext . update ( ( prev ) => ( {
165+ ...prev ,
166+ undo : this . historyIndex ,
167+ redo : 0 ,
168+ } ) ) ;
122169 }
123170 undo ( cx : Context ) {
124171 if ( this . historyIndex <= 0 ) return ;
125172 this . historyIndex -- ; // undo は、巻き戻し後の index で計算する
126173 const op = this . history [ this . historyIndex ] ;
127174 cx . grid . setBlock ( cx , op . at . x , op . at . y , op . from ) ;
128- this . inventory = op . inventory . before ;
175+ this . setInventory ( cx , op . inventory . before ) ;
176+ this . enabled = op . enabled . before ;
177+ cx . uiContext . update ( ( prev ) => ( {
178+ ...prev ,
179+ ...this . enabled ,
180+ undo : this . historyIndex ,
181+ redo : this . history . length - this . historyIndex ,
182+ } ) ) ;
129183 console . log ( `history: ${ this . historyIndex } / ${ this . history . length } ` ) ;
130184 }
131185 redo ( cx : Context ) {
132186 if ( this . historyIndex >= this . history . length ) return ;
133187 const op = this . history [ this . historyIndex ] ;
134188 this . historyIndex ++ ; // redo は、巻き戻し前の index
135- this . inventory = op . inventory . after ;
189+ this . setInventory ( cx , op . inventory . after ) ;
136190 cx . grid . setBlock ( cx , op . at . x , op . at . y , op . to ) ;
191+ this . enabled = op . enabled . after ;
192+ cx . uiContext . update ( ( prev ) => ( {
193+ ...prev ,
194+ ...this . enabled ,
195+ undo : this . historyIndex ,
196+ redo : this . history . length - this . historyIndex ,
197+ } ) ) ;
137198 console . log ( `history: ${ this . historyIndex } / ${ this . history . length } ` ) ;
138199 }
139- handleKeyDown ( cx : Context , e : KeyboardEvent , onGround : boolean ) {
200+ handleKeyDown ( cx : Context , e : KeyboardEvent /* , onGround: boolean*/ ) {
140201 if ( ! ( e . ctrlKey || e . metaKey ) ) return ;
141202
142- if ( this . enabled . paste && onGround && e . key === "v" ) {
143- this . paste ( cx ) ;
144- }
145- if ( this . enabled . copy && onGround && e . key === "c" ) {
146- this . copy ( cx ) ;
147- }
148- if ( this . enabled . cut && onGround && e . key === "x" ) {
149- this . cut ( cx ) ;
150- }
203+ // if (this.enabled.paste > 0 && onGround && e.key === "v") {
204+ // this.paste(cx);
205+ // }
206+ // if (this.enabled.copy > 0 && onGround && e.key === "c") {
207+ // this.copy(cx);
208+ // }
209+ // if (this.enabled.cut > 0 && onGround && e.key === "x") {
210+ // this.cut(cx);
211+ // }
151212 if ( e . key === "z" ) {
152213 this . undo ( cx ) ;
153214 e . preventDefault ( ) ;
0 commit comments