qpremake 1.5.1 → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,16 +1,438 @@
1
- # qpRemake
2
- Alpha branch is finally ended and will be merged into main!!, only a renderer pending!
1
+ # qpRemake
2
+
3
+ This is a card effect processing system for the game "Quantum Protocol" remade in native Typescript.
4
+
5
+ > Quantum Protocol and Jkong reserves all rights to the game and all related assets.
6
+
7
+ ## Table of contents
8
+
9
+ - [qpRemake](#qpremake)
10
+ - [Table of contents](#table-of-contents)
11
+ - [Installation](#installation)
12
+ - [Usage](#usage)
13
+ - [Basic usage](#basic-usage)
14
+ - [What the imported objects do](#what-the-imported-objects-do)
15
+ - [**queenSystem**](#queensystem)
16
+ - [**queenSystemComponents**](#queensystemcomponents)
17
+ - [**gameComponent**:](#gamecomponent)
18
+ - [**systemComponent**](#systemcomponent)
19
+ - [**queenSystemUtils**](#queensystemutils)
20
+ - [Advanced usage:](#advanced-usage)
21
+ - [Making your own renderer](#making-your-own-renderer)
22
+ - [Saving and loading game state:](#saving-and-loading-game-state)
23
+ - [Display texts](#display-texts)
24
+ - [Handling inputs](#handling-inputs)
25
+ - [Modding](#modding)
26
+ - [What is a mod?](#what-is-a-mod)
27
+ - [How mods are run](#how-mods-are-run)
28
+ - [How to make a mod](#how-to-make-a-mod)
29
+ - [Adding a mod](#adding-a-mod)
30
+ - [Example: Adding a custom effect](#example-adding-a-custom-effect)
31
+ - [Project contribution](#project-contribution)
32
+ - [Current progress:](#current-progress)
33
+ - [How to get and develop the project](#how-to-get-and-develop-the-project)
34
+ - [Clone the project:](#clone-the-project)
35
+ - [Run the project](#run-the-project)
36
+ - [Game components](#game-components)
37
+ - [Main gameplay loop](#main-gameplay-loop)
38
+ - [Project structure](#project-structure)
39
+ - [Contribution workflow guide](#contribution-workflow-guide)
40
+ - [Make effects](#make-effects)
41
+ - [Add more actions (if needed)](#add-more-actions-if-needed)
42
+ - [Update effect registry](#update-effect-registry)
43
+ - [Update card registry](#update-card-registry)
44
+ - [Update defaultSetting](#update-defaultsetting)
45
+ - [Running tests](#running-tests)
46
+ - [Make renderers](#make-renderers)
47
+ - [Improving the text parser](#improving-the-text-parser)
48
+
49
+
50
+
51
+ # Installation
52
+
53
+ The system is available via npm.
3
54
 
55
+ ```bash
56
+ npm i qpremake
57
+ ```
58
+
59
+ And then can be imported via
60
+
61
+ ```ts
62
+ // ts
63
+ import {
64
+ queenSystem as s,
65
+ queenSystemComponents,
66
+ queenSystemUtils
67
+ } from "qpremake"
68
+ ```
69
+
70
+ or
71
+
72
+ ```js
73
+ // js
74
+ const {
75
+ queenSystem,
76
+ queenSystemComponents,
77
+ queenSystemUtils
78
+ } = require("qpremake")
79
+ ```
80
+
81
+ There is also a default import for just the ```queenSystem```
82
+
83
+ ```ts
84
+ // ts
85
+ import queenSystem from "qpRemake"
86
+ ```
87
+
88
+ or
89
+
90
+ ```js
91
+ // js
92
+ const queenSystem = require("qpRemake")
93
+ ```
94
+
95
+ # Usage
96
+
97
+ This section is dedicated to thos who wish to use the system and render out a game, rather than modding stuff.
98
+
99
+ ## Basic usage
100
+
101
+ This here is just a calculator for card effects. To have it renders out something visible, (like text or an HTML page), you have to hook it up to a ```Renderer```.
102
+
103
+ This code binds a renderer of your choice to the system for rendering. More info on how the rendering life cycle work in later sections.
104
+
105
+ ```ts
106
+ import {queenSystem, queenSystemComponents} from "qpRemake"
107
+
108
+ const { operatorRegistry } = queenSystemComponents.registry
109
+ const sampleRenderer = queenSystemComponents.systemComponent.sampleRenderer
110
+ const defaultSetting = { queenSystemComponents }
111
+
112
+ let setting = new defaultSetting()
113
+ let renderer = new YourRendererHere()
114
+ // Your renderer shoudld be here
115
+ // What interface it follows is in the later sections.
116
+
117
+ let s = new queenSystem(setting, sampleRenderer)
118
+ renderer.bind(s)
119
+ s.addPlayers("player", operatorRegistry.o_esper)
120
+ s.addPlayers("enemy", operatorRegistry.o_null)
121
+ await s.load()
122
+
123
+ s.start();
124
+ ```
125
+
126
+ ## What the imported objects do
127
+
128
+ ### **queenSystem**
129
+
130
+ The queenSystem is a class that handles card effect calculations.
131
+
132
+ It must first be loaded (async sadly cause file import is async) via ```load()```.
133
+
134
+ You can then load players gradually by ```addPlayers```, this will only accept 2 type "player" and "enemy" at the moment. The appropriate zones will be added correctly to the internal zone list.
135
+
136
+ With a renderer bound, the ```start``` method begins the communication loops between the queenSystem and the renderer.
137
+
138
+ The procedure goes as follows:
139
+ 1. The queenSystem calls ```turnStart``` of the renderer to begin a turn play.
140
+ 2. Once the Renderer can continue with player's action for that turn, ```processTurn``` is called
141
+ 3. Inside ```processTurn```, certain events will cause the system to halt and return control to the renderer. The renderer can decide when to continue by calling ```continue```;
142
+ 4. This continues until the player loses or won the round.
143
+
144
+ from the renderer's perspective, these functions are passed in so they need not remember what to call.
145
+
146
+ Here is a cheatsheet of what this class does from the perspective of a renderer:
147
+
148
+ 1. ```load``` : required to run before starting the game, async
149
+ 2. ```addPlayers``` : for adding players
150
+ 3. ```addDeck``` : for adding decks
151
+ 4. ```start``` : start the game
152
+
153
+ ### **queenSystemComponents**
154
+
155
+ Various classes used in the processing of card effects.
156
+
157
+ Use from the perspective of a modder who wants to add more cards / effects.
158
+ Outside of this, one can read the data from the various registries (either enum or const key -> data pair).
159
+
160
+ For a cheat sheet, here are the properties of systemComponent:
161
+
162
+ 1. ```gameComponent``` : holds various game component classes.
163
+ 2. ```systemComponent``` : holds various services to operate on data
164
+ 3. ```displayComponent``` : holds display parsed segements
165
+ 4. ```registry``` : holds data
166
+ 5. ```defaultSetting``` : holds the default setting
167
+ 6. ```mod``` : holds what format mods must follows
168
+
169
+ #### **gameComponent**:
170
+
171
+ Holds various game component classes like ```Card, Effect, ...```.
172
+
173
+ The complete list is:
174
+
175
+ *Class entries*
176
+ 1. ```Card```
177
+ 2. ```Effect```
178
+ 3. ```Zone_grid``` and ```Zone_stack``` : Default zone implementation
179
+ 4. ```Action```
180
+
181
+ *Objects with classes inside*
182
+
183
+ 5. ```EffectType``` :Various effect types
184
+ 6. ```EffectSubType``` : Various effect subtypes
185
+ 7. ```Zone``` : Various default zones
186
+ 8. ```Serialized``` : Serialized components, for saving and loading
187
+ 9. ```Localized``` : Localized components, passed to the renderer
188
+
189
+ #### **systemComponent**
190
+
191
+ Hold various services outside of gameplay intepretations.
192
+
193
+ The complete list is:
194
+
195
+ 1. ```EffectTextParser``` : parses effect text
196
+ 2. ```Localizer``` : localzied game components
197
+ 3. ```ActionGenerator``` : generates actions
198
+ 4. ```InputRequester``` : generates input requests
199
+ 5. ```Renderer``` : an abstract class to how a renderer linked to the system shoudll be formatted.
200
+ 6. ```SampleRenderer``` : an example renderer
201
+
202
+ ### **queenSystemUtils**
203
+
204
+ Holds various utilities functions like rng or ID generation.
205
+
206
+ This object is also available as a global object in ```Utils```.
207
+
208
+ ## Advanced usage:
209
+
210
+ ### Making your own renderer
211
+
212
+ A renderer's job is to ..well render stuff.
213
+
214
+ The work flow of a renderer in **qpRemake** is to receive API like requests during the turn, renders it, then return control to the system to process more stuff.
215
+
216
+ The base abstract class / interface can be found in
217
+
218
+ ```ts
219
+ import {queenSystemComponents} from "qpremake"
220
+ const {Renderer} = queenSystemComponents.systemComponent
221
+ ```
222
+
223
+ This class is as follows:
224
+
225
+ ```ts
226
+ abstract class Renderer {
227
+ abstract gameStart(
228
+ s: LocalizedSystem,
229
+ callback: () => any
230
+ ) : void;
231
+
232
+ abstract turnStart(
233
+ s: LocalizedSystem,
234
+ callback: (a? : Action) => any
235
+ ) : void;
236
+
237
+ abstract update(
238
+ phase: TurnPhase,
239
+ s: LocalizedSystem,
240
+ a: Action,
241
+ callback: () => any
242
+ ) : void;
243
+
244
+ abstract requestInput(
245
+ inputSet: inputData[],
246
+ phase: TurnPhase,
247
+ s: LocalizedSystem,
248
+ a: Action,
249
+ callback: (
250
+ input : inputData
251
+ ) => any
252
+ ) : void;
253
+ }
254
+ ```
255
+
256
+ These methods are called appropriately. There shoudl be guide comments when one implement these.
257
+
258
+ Notably, the system is paused after calling one of these. Sort of *"handing control over"* to the renderer. The system only resumes after **the provided callback()** is called.
259
+
260
+ One can make a new renderer to whatever front end frame work one likes by implementing this class.
261
+
262
+ ### Saving and loading game state:
4
263
 
5
- 1. make effects
6
- 2. add more actions (if needed)
7
- 3. update the effect registry
8
- 4. update the card registry
9
- 5. add a deck registry
10
- 6. make level / wave control
11
- 7. make a good renderer
264
+ Game state or more specifically is an instance of ```SerializedSystem```.
12
265
 
266
+ At any time, this is obtained via:
13
267
 
268
+ ```ts
269
+ s.toSerialized()
270
+ ```
271
+
272
+ This file can then be JSON and saved to a text file.
273
+
274
+ Loading said file is possible via the normal ```load()``` functionn before start:
275
+
276
+ ```ts
277
+ const data = fs.readFileSync(...) as SerializedSystem
278
+ s.load(data)
279
+ ```
280
+
281
+ ### Display texts
282
+
283
+ All texts provided via a ```Localized``` object is an array of ```Display components``` to guide the injection of icons and text formatting.
284
+
285
+ Those objects are available via:
286
+
287
+ ```ts
288
+ import {queenSystemComponents} from "qpremake"
289
+ const {TextComponent, IconComponent, ImageComponent} = queenSystemComponents.displayComponent
290
+ ```
291
+
292
+ ### Handling inputs
293
+
294
+ Whenever an action wants an input (say, when a card says choose a card, choose a space on the board, etc). The method ```requestInput``` of the renderer is called.
295
+
296
+ All possible inputs is in the ```inputSet``` components, all these are in one specific type (a card, a spot on the field, a number, etc).
297
+
298
+ Inputs if required multiple are done sequentially. If a card wants the player to select 2 spots in the field, the request input function will be called twice for each.
299
+
300
+ At the start of the turn, there is also the need to select a **turn action**. Thus the ```turnStart``` method also have an option to continue with a player action.
301
+
302
+
303
+ # Modding
304
+
305
+ This section is dedicated to whomever wants to mod the system (add more cards, more localizations, etc).
306
+
307
+ ## What is a mod?
308
+
309
+ Mods are ts files that changes the data od the system
310
+
311
+ There are 2 types:
312
+
313
+ 1. gameplay mods, these can change what effects, cards, zones, characters, ... are possible
314
+ 2. parsing mods, these changes the behavior of how card text are parse and localized. (If one specifically target changing localization, look in a localization file.)
315
+
316
+ ## How mods are run
317
+
318
+ In the loading step of the system, mods are loaded and can change various registries via an API interface.
319
+
320
+ ## How to make a mod
321
+
322
+ There are 2 ways. One either can clone / fork [the github rerpo](https://github.com/BlueG15/qpRemake).
323
+ Or add stuff after installing the system in the setting.
324
+
325
+ Both are essentially the same but you appear on the npm of the project under contribution :).
326
+
327
+ ## Adding a mod
328
+
329
+ In the settings of the system, there is the field ```mods```, which stores an array of strings to code files inside the mod folder ("One can change this too").
330
+
331
+ A mod file exports default an implementation to the class ```mod``` available via:
332
+
333
+ ```ts
334
+ import {queenSystemComponents} from "qpremake"
335
+ const {GameModule, ParserModule} = queenSystemComponents.mod
336
+ ```
337
+
338
+ This game module is just this:
339
+
340
+ ```ts
341
+ class GameModule {
342
+ //should override, call upon load
343
+ load(API : registryAPI) : void {}
344
+ }
345
+ ```
346
+
347
+ Very simple. That registryAPI looks like this:
348
+
349
+ ```ts
350
+ interface registryAPI {
351
+ //SAFE registry edit
352
+ //There is also the registry for effectType and Action, but those doesnt need to be modified
353
+ registry_edit_card(key : string, value : cardData) : void;
354
+ registry_edit_effect_data(key : string, data : effectData) : void;
355
+ registry_edit_effect_class(
356
+ key : string,
357
+ constructors : typeof Effect | Record<string, typeof Effect>
358
+ ) : void;
359
+ registry_edit_effect(
360
+ key : string,
361
+ data : effectData,
362
+ constructors : typeof Effect | Record<string, typeof Effect>
363
+ ): void
364
+ registry_edit_effect_subtype(
365
+ key : string,
366
+ constructor : typeof EffectSubtype
367
+ ) : void;
368
+
369
+ registry_edit_zone_data(key : string, data : zoneData) : void;
370
+ registry_edit_zone_class(
371
+ key : string,
372
+ constructor : typeof Zone
373
+ ) : void;
374
+ registry_edit_zone(
375
+ key : string,
376
+ data : zoneData,
377
+ constructor : typeof Zone
378
+ ) : void;
379
+
380
+ //UNSFAFE registry edit
381
+ registry_edit_custom_action_handler(
382
+ actionIDs : number[],
383
+ handlerFunc : ((a : Action, system : queenSystem) => undefined | void | Action[])
384
+ ) : void;
385
+
386
+ //localization edit
387
+ registry_edit_localization(language : string, key : string, val : string) : void;
388
+
389
+ //... more coming
390
+ }
391
+ ```
392
+
393
+ These methods are passed into the mod for editting.
394
+
395
+ ## Example: Adding a custom effect
396
+
397
+ Effect have 2 parts, like almost every other gameplay components.
398
+
399
+ Those 2 parts are **Class part** and **Data part**
400
+
401
+ Those 2 parts are available via ```registry_edit_effect_data``` and ```registry_edit_effect_class``` respectively.
402
+
403
+ or both at the same time via ```registry_edit_effect```.
404
+
405
+ For this simple example, we ignore the data for now and implements the class part (data can be hard coded via the specified **effectData**) type.
406
+
407
+ We import the ```Effect``` class:
408
+
409
+ ```ts
410
+ import {queenSystemComponents} from "qpremake"
411
+ const {Effect} = queenSystemComponents.gameComponent
412
+ ```
413
+
414
+ And add it in:
415
+
416
+ ```ts
417
+ class CustomEffect extends Effect {
418
+ // Your implementation here
419
+ }
420
+
421
+ export default class customMod extends GameModule {
422
+ override load(API : registryAPI){
423
+ API.registry_edit_effect_class(
424
+ "customEffect1",
425
+ CustomEffect
426
+ )
427
+ }
428
+ }
429
+ ```
430
+
431
+ What an effect does and how to implement its behavior is in the **make effect** section below.
432
+
433
+ Importantly, one **MUST NOT** override the contructor.
434
+
435
+ # Project contribution
14
436
 
15
437
  ## Current progress:
16
438
 
@@ -21,7 +443,7 @@ Alpha branch is finally ended and will be merged into main!!, only a renderer pe
21
443
 
22
444
  ( * ) : Fruit and Some of Generic
23
445
 
24
- ## How to get and run the project
446
+ ## How to get and develop the project
25
447
 
26
448
  ### Clone the project:
27
449
 
@@ -165,7 +587,13 @@ There are only a handful of modules right now, allowing stuff like
165
587
  ```XML
166
588
  <if type = "number"><numeric> a + b > c </><string> A + B </><string> C + D </></>
167
589
  ```
168
- Check the GitHub repo for the parser for more info.
590
+
591
+ Effect text now allow these short hand
592
+
593
+ ```
594
+ =abc prints a, b, c out
595
+ =<exprerssion>; inserts the expression
596
+ ```
169
597
 
170
598
 
171
599
 
@@ -1,7 +1,25 @@
1
1
  import type { Action } from "../handler/actionGenrator";
2
2
  import type { inputDataSpecific, inputType, TurnPhase } from "../../data/systemRegistry";
3
3
  import type { LocalizedSystem } from "../../types/abstract/serializedGameComponents/Localized";
4
- export interface qpRenderer {
4
+ export declare abstract class qpRenderer {
5
+ abstract gameStart(s: LocalizedSystem, callback: () => any): void;
6
+ abstract turnStart(s: LocalizedSystem, callback: (a?: Action) => any): void;
7
+ /**
8
+ * update is called upon every game update for every phase for whatever reason
9
+ * right after applying the action to the game states
10
+ * call callback() to conttinue */
11
+ abstract update(phase: TurnPhase, s: LocalizedSystem, a: Action, callback: () => any): void;
12
+ /**
13
+ * request input is called wheever the system is processing an action and wants a user input
14
+ * @param inputSet : a array of allowed inputs
15
+ * @param phase : phase
16
+ * @param s : system state
17
+ * @param a : action
18
+ * @param callback : callback function, call to continue
19
+ */
20
+ abstract requestInput<T extends inputType>(inputSet: inputDataSpecific<T>[], phase: TurnPhase, s: LocalizedSystem, a: Action, callback: (input: inputDataSpecific<T>) => any): void;
21
+ }
22
+ export declare class sampleRenderer extends qpRenderer {
5
23
  gameStart(s: LocalizedSystem, callback: () => any): void;
6
24
  turnStart(s: LocalizedSystem, callback: (a?: Action) => any): void;
7
25
  update(phase: TurnPhase, s: LocalizedSystem, a: Action, callback: () => any): void;
@@ -1,2 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sampleRenderer = exports.qpRenderer = void 0;
4
+ class qpRenderer {
5
+ }
6
+ exports.qpRenderer = qpRenderer;
7
+ class sampleRenderer extends qpRenderer {
8
+ gameStart(s, callback) {
9
+ console.log("Game start called");
10
+ return callback();
11
+ }
12
+ turnStart(s, callback) {
13
+ console.log(`Turn start called`);
14
+ return callback();
15
+ }
16
+ update(phase, s, a, callback) {
17
+ console.log(`Update called on phase ${phase}, on action ${a.type}`);
18
+ return callback();
19
+ }
20
+ requestInput(inputSet, phase, s, a, callback) {
21
+ console.log(`Input requested, continue with 1st input`);
22
+ return callback(inputSet[0]);
23
+ }
24
+ }
25
+ exports.sampleRenderer = sampleRenderer;