-
Notifications
You must be signed in to change notification settings - Fork 15
/
${hyphenate(obj_key)}.ts
318 lines (269 loc) · 11.2 KB
/
${hyphenate(obj_key)}.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
<%include file="functions.noCreer" /><%
imports = shared['cerveau']['generate_imports'](obj_key, obj, {})
imports['./'] = []
imports['~/core/game'] = [ 'BaseGameRequiredData' if obj_key == 'Game' else 'BaseGameObjectRequiredData' ]
i_base_player = 'Base{}Player'.format(game_name)
if 'TiledGame' in game['serverParentClasses'] and obj_key == 'Tile':
imports['~/core/game/mixins/tiled'] = [ 'BaseTile' ]
if obj_key == 'Game':
imports['./game-settings'] = [ game_name + 'GameSettingsManager' ]
imports['./game-manager'] = [ game_name + 'GameManager' ]
else:
if obj_key == 'GameObject':
imports['./game-manager'] = [ game_name + 'GameManager' ]
imports['./game'] = [ game_name + 'Game' ]
if obj_key == 'Player':
imports['./'].append(i_base_player)
imports['./ai'] = [ 'AI' ]
imports['./'].append('{}ConstructorArgs'.format(obj_key))
functions = list(obj['function_names'])
for function_name in functions:
if function_name == 'log' and obj_key == 'GameObject':
continue
function_args_import = '{}{}Args'.format(obj_key, upcase_first(function_name))
imports['./'].append(function_args_import)
if 'log' in functions: # log is server implimented
functions.remove('log')
if len(functions) > 0:
# then there will be an invalidate function, which requires player
if not './player' in imports:
imports['./player'] = []
if not 'Player' in imports['./player']:
imports['./player'].append('Player')
extends = ''
if obj_key == 'Game' or obj_key == 'GameObject':
imports['./'].append('BaseClasses')
extends = 'BaseClasses.Game' if obj_key == 'Game' else 'BaseClasses.GameObject'
for parent_class in obj['parentClasses']:
extends = parent_class
filename = './' + hyphenate(parent_class)
if not filename in imports:
imports[filename] = []
if not parent_class in imports[filename]:
imports[filename].append(parent_class)
if obj_key == 'Player':
extends = extends + ' implements ' + i_base_player
%>${shared['cerveau']['imports'](imports)}
${merge('// ', 'imports', """// any additional imports you want can be placed here safely between creer runs
""", optional=True, help=False)}
% for attr_name in obj['attribute_names']:
<%
attr_parms = obj['attributes'][attr_name]
if not attr_parms['type']['literals']:
continue
%>
${shared['cerveau']['block_comment'](attr_parms)}
<%
prop_name = 'export type {}{} ='.format(obj_key, upcase_first(attr_name))
type_val = shared['cerveau']['type'](attr_parms['type'], nullable=False)
attr_type = prop_name + ' ' + type_val
if len(attr_type) > 79:
attr_type = prop_name + shared['cerveau']['type'](attr_parms['type'], nullable=False, wrap_literals_indent=True)
%>${attr_type};
% endfor
${shared['cerveau']['block_comment'](obj)}
export class ${obj_key if obj_key != 'Game' else (game_name + 'Game')} extends ${extends}${
' implements BaseTile' if 'TiledGame' in game['serverParentClasses'] and obj_key == 'Tile' else ''
} {
% if obj_key == 'Game':
/** The manager of this game, that controls everything around it. */
public readonly manager!: ${game_name}GameManager;
/** The settings used to initialize the game, as set by players. */
public readonly settings = Object.freeze(this.settingsManager.values);
% elif obj_key == 'Player':
/** The AI controlling this Player. */
public readonly ai!: AI;
% elif obj_key == 'GameObject':
/** The game this game object is in. */
public readonly game!: ${game_name}Game;
/** The manager of the game that controls this. */
public readonly manager!: ${game_name}GameManager;
% endif
% for attr_name in obj['attribute_names']:
<%
attr_parms = obj['attributes'][attr_name]
attr_type = attr_parms['type']
readonly = 'readonly ' if attr_type['const'] else ''
if attr_type['is_game_object'] and obj_key != 'Player':
nullable = '?' if attr_type['nullable'] else ''
if 'serverPredefined' in attr_parms and attr_parms['serverPredefined'] and not attr_type['nullable']:
nullable = '!' # because a base class will make sure it exists
else:
nullable = '!'
%>${shared['cerveau']['block_comment'](attr_parms, indent=1)}
<%
prop_name = ' public ' + readonly + attr_name + nullable + ':'
type_val = shared['cerveau']['type'](attr_parms['type'], nullable=False)
attr_type = prop_name + ' ' + type_val
if len(attr_type) > 78:
attr_type = prop_name + shared['cerveau']['type'](attr_parms['type'], nullable=False, wrap_literals_indent=1)
%>${attr_type};
% endfor
${merge(' // ', 'attributes', """
// Any additional member attributes can go here
// NOTE: They will not be sent to the AIs, those must be defined
// in the creer file.
""", optional=True, help=False)}
/**
* Called when a ${obj_key} is created.
*
% if obj_key == 'Game':
* @param settingsManager - The manager that holds initial settings.
% else:
* @param args - Initial value(s) to set member variables to.
% endif
* @param required - Data required to initialize this (ignore it).
*/
constructor(
% if obj_key == 'Game':
protected settingsManager: ${game_name}GameSettingsManager,
required: Readonly<BaseGameRequiredData>,
% else: # if not a base class, or it is a `Tile`, and this is not a tiled game
% if obj_key not in ['Player', 'GameObject', 'Tile'] or (obj_key == 'Tile' and 'TiledGame' not in game['serverParentClasses']):
args: ${obj_key}ConstructorArgs<{
${merge(' // ', 'constructor-args', """ // You can add more constructor args in here
""", optional=True, help=False)}
}>,
% else:
// never directly created by game developers
args: ${obj_key}ConstructorArgs,
% endif
required: Readonly<BaseGameObjectRequiredData>,
% endif
) {
super(${'settingsManager' if (obj_key == 'Game') else 'args'}, required);
${merge(' // ', 'constructor', """ // setup any thing you need here
""", optional=True, help=False)}
}
${merge(' // ', 'public-functions', """
// Any public functions can go here for other things in the game to use.
// NOTE: Client AIs cannot call these functions, those must be defined
// in the creer file.
""", optional=True, help=False)}
% if 'TiledGame' in game['serverParentClasses']:
% if obj_key == 'Game':
/**
* Gets the tile at (x, y), or undefined if the co-ordinates are off-map.
*
* @param x - The x position of the desired tile.
* @param y - The y position of the desired tile.
* @returns The Tile at (x, y) if valid, undefined otherwise.
*/
public getTile(x: number, y: number): Tile | undefined {
return super.getTile(x, y) as Tile | undefined;
}
% elif obj_key == 'Tile':
/**
* Gets the adjacent direction between this Tile and an adjacent Tile
* (if one exists).
*
* @param adjacentTile - A tile that should be adjacent to this Tile.
* @returns "North", "East", "South", or "West" if the tile is adjacent to
* this Tile in that direction. Otherwise undefined.
*/
public getAdjacentDirection(
adjacentTile: Tile | undefined,
): "North" | "South" | "East" | "West" | undefined {
return BaseTile.prototype.getAdjacentDirection.call(
this,
adjacentTile,
);
}
/**
* Gets a list of all the neighbors of this Tile.
*
* @returns An array of all adjacent tiles. Should be between 2 to 4 tiles.
*/
public getNeighbors(): Tile[] {
return BaseTile.prototype.getNeighbors.call(this) as Tile[];
}
/**
* Gets a neighbor in a particular direction.
*
* @param direction - The direction you want, must be
* "North", "East", "South", or "West".
* @returns The Tile in that direction, or undefined if there is none.
*/
public getNeighbor(
direction: "North" | "East" | "South" | "West",
): Tile | undefined {
return BaseTile.prototype.getNeighbor.call(this, direction) as
| Tile
| undefined;
}
/**
* Checks if a Tile has another Tile as its neighbor.
*
* @param tile - The Tile to check.
* @returns True if neighbor, false otherwise.
*/
public hasNeighbor(tile: Tile | undefined): boolean {
return BaseTile.prototype.hasNeighbor.call(this, tile);
}
/**
* Override for `toString` for easier debugging.
*
* @returns A string representation of the Tile.
*/
public toString(): string {
return BaseTile.prototype.toString.call(this);
}
% endif
% endif
% for function_name in obj['function_names']:
<%
if obj_key == 'GameObject' and function_name == 'log':
continue
upcase_first_function_name = upcase_first(function_name)
function_parms = obj['functions'][function_name]
invalidate_function_name = 'invalidate' + upcase_first_function_name
temp = { 'functions': {} }
temp['functions'][function_name] = dict(function_parms)
temp['functions'][function_name]['arguments'] = [{
'default': None,
'name': 'player',
'description': 'The player that called this.',
'type': {
'name': 'Player',
'is_game_object': True,
'valueType': None,
'keyType': None,
'nullable': False,
}
}] + function_parms['arguments']
temp['functions'][invalidate_function_name] = dict(temp['functions'][function_name])
invalidate_obj = temp['functions'][invalidate_function_name]
invalidate_obj['description'] = 'Invalidation function for {}. Try to find a reason why the passed in parameters are invalid, and return a human readable string telling them why it is invalid.'.format(function_name)
invalidate_obj['returns'] = {
'default': None,
'description': 'If the arguments are invalid, return a string explaining to human players why it is invalid. If it is valid return nothing, or an object with new arguments to use in the actual function.',
'invalidValue': None,
'type': {
'name': 'void | string | {}{}Args'.format(obj_key, upcase_first_function_name),
'is_game_object': False,
'valueType': None,
'keyType': None,
}
}
%>
${shared['cerveau']['formatted_function_top'](invalidate_function_name, temp, promise=False)}
${merge(' // ', 'invalidate-' + function_name, """
// Check all the arguments for {} here and try to
// return a string explaining why the input is wrong.
// If you need to change an argument for the real function, then
// changing its value in this scope is enough.
return undefined; // means nothing could be found that was ivalid.
""".format(function_name), optional=True, help=False)}
}
${shared['cerveau']['formatted_function_top'](function_name, temp)}
${merge(' // ', function_name, """
// Add logic here for {}.
// TODO: replace this with actual logic
return {};
""".format(function_name, shared['cerveau']['default'](function_parms['returns']['type'])), optional=True, help=False)}
}
% endfor
${merge(' // ', 'protected-private-functions', """
// Any additional protected or pirate methods can go here.
""", optional=True, help=False)}
}