forked from cataclysmbnteam/Cataclysm-BN
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mapgen.h
476 lines (416 loc) · 16.1 KB
/
mapgen.h
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
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
#pragma once
#ifndef CATA_SRC_MAPGEN_H
#define CATA_SRC_MAPGEN_H
#include <cstddef>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "pimpl.h"
#include "point.h"
#include "regional_settings.h"
#include "type_id.h"
class JsonArray;
class JsonMember;
class JsonObject;
class map;
class mapgendata;
class mission;
struct json_source_location;
template <typename T> struct weighted_int_list;
using building_gen_pointer = void ( * )( mapgendata & );
//////////////////////////////////////////////////////////////////////////
///// function pointer class; provides abstract referencing of
///// map generator functions written in multiple ways for per-terrain
///// random selection pool
class mapgen_function
{
public:
int weight;
protected:
mapgen_function( const int w ) : weight( w ) { }
public:
virtual ~mapgen_function() = default;
virtual void setup() { } // throws
virtual void check( const std::string & /*oter_name*/ ) const { }
virtual void generate( mapgendata & ) = 0;
};
/////////////////////////////////////////////////////////////////////////////////
///// builtin mapgen
class mapgen_function_builtin : public virtual mapgen_function
{
public:
building_gen_pointer fptr;
mapgen_function_builtin( building_gen_pointer ptr, int w = 1000 ) : mapgen_function( w ),
fptr( ptr ) {
}
void generate( mapgendata &mgd ) override;
};
/////////////////////////////////////////////////////////////////////////////////
///// json mapgen (and friends)
/*
* Actually a pair of integers that can rng, for numbers that will never exceed INT_MAX
*/
struct jmapgen_int {
int val;
int valmax;
jmapgen_int( int v ) : val( v ), valmax( v ) {}
jmapgen_int( int v, int v2 ) : val( v ), valmax( v2 ) {}
jmapgen_int( point p );
/**
* Throws as usually if the json is invalid or missing.
*/
jmapgen_int( const JsonObject &jo, const std::string &tag );
/**
* Throws is the json is malformed (e.g. a string not an integer, but does not throw
* if the member is just missing (the default values are used instead).
*/
jmapgen_int( const JsonObject &jo, const std::string &tag, int def_val, int def_valmax );
int get() const;
};
enum jmapgen_setmap_op {
JMAPGEN_SETMAP_OPTYPE_POINT = 0,
JMAPGEN_SETMAP_TER,
JMAPGEN_SETMAP_FURN,
JMAPGEN_SETMAP_TRAP,
JMAPGEN_SETMAP_RADIATION,
JMAPGEN_SETMAP_BASH,
JMAPGEN_SETMAP_OPTYPE_LINE = 100,
JMAPGEN_SETMAP_LINE_TER,
JMAPGEN_SETMAP_LINE_FURN,
JMAPGEN_SETMAP_LINE_TRAP,
JMAPGEN_SETMAP_LINE_RADIATION,
JMAPGEN_SETMAP_OPTYPE_SQUARE = 200,
JMAPGEN_SETMAP_SQUARE_TER,
JMAPGEN_SETMAP_SQUARE_FURN,
JMAPGEN_SETMAP_SQUARE_TRAP,
JMAPGEN_SETMAP_SQUARE_RADIATION
};
struct jmapgen_setmap {
jmapgen_int x;
jmapgen_int y;
jmapgen_int x2;
jmapgen_int y2;
jmapgen_setmap_op op;
jmapgen_int val;
int chance;
jmapgen_int repeat;
int rotation;
int fuel;
int status;
jmapgen_setmap(
jmapgen_int ix, jmapgen_int iy, jmapgen_int ix2, jmapgen_int iy2,
jmapgen_setmap_op iop, jmapgen_int ival,
int ione_in = 1, jmapgen_int irepeat = jmapgen_int( 1, 1 ), int irotation = 0, int ifuel = -1,
int istatus = -1
) :
x( ix ), y( iy ), x2( ix2 ), y2( iy2 ), op( iop ), val( ival ), chance( ione_in ),
repeat( irepeat ), rotation( irotation ),
fuel( ifuel ), status( istatus ) {}
bool apply( mapgendata &dat, point offset ) const;
/**
* checks if applying these objects to data would cause cause a collision with vehicles
* on the same map
**/
bool has_vehicle_collision( mapgendata &dat, point offset ) const;
};
/**
* Basic mapgen object. It is supposed to place or do something on a specific square on the map.
* Inherit from this class and implement the @ref apply function.
*
* Instructions for adding more mapgen things:
* 1. create a new class inheriting from @ref jmapgen_piece.
* - It should have a constructor that a accepts a @ref JsonObject and initializes all it local
* members from it. On errors / invalid data, call @ref JsonObject::throw_error or similar.
* - Implement the @ref apply function to do the actual change on the map.
* 2. Go into @ref mapgen_function_json::setup and look for the lines with load_objects, add a new
* line with your own class there. It should look like
* @code load_objects<your_own_class_from_step_1>( jo, "place_something" ); @endcode
* Use a descriptive name for "something", preferably matching the name of your class.
* 3. Go into @ref mapgen_function_json::setup and look for the lines with load_place_mapings, add
* a new line with your class there. It should look like
* @code load_place_mapings<your_own_class_from_step_1>( jo, "something", format_placings ); @endcode
* Using the same "something" as in step 2 is preferred.
*
* For actual examples look at the commits that introduced the load_objects/load_place_mapings
* lines (ignore the changes to the json files).
*/
class jmapgen_piece
{
protected:
jmapgen_piece() : repeat( 1, 1 ) { }
public:
/** Sanity-check this piece */
virtual void check( const std::string &/*oter_name*/ ) const { }
/** Place something on the map from mapgendata &dat, at (x,y). */
virtual void apply( mapgendata &dat, const jmapgen_int &x, const jmapgen_int &y ) const = 0;
virtual ~jmapgen_piece() = default;
jmapgen_int repeat;
virtual bool has_vehicle_collision( mapgendata &/*dat*/, point /*offset*/ ) const {
return false;
}
};
/**
* Where to place something on a map.
*/
class jmapgen_place
{
public:
jmapgen_place() : x( 0, 0 ), y( 0, 0 ), repeat( 1, 1 ) { }
jmapgen_place( point p ) : x( p.x ), y( p.y ), repeat( 1, 1 ) { }
jmapgen_place( const JsonObject &jsi );
void offset( point );
jmapgen_int x;
jmapgen_int y;
jmapgen_int repeat;
};
using palette_id = std::string;
// Strong typedef for strings used as map/palette keys
// Each key should be a UTF-8 string displayed in only one column (i.e.
// utf8_width of 1) but can contain multiple Unicode code points.
class map_key
{
public:
map_key( const std::string & );
map_key( const JsonMember & );
friend bool operator==( const map_key &l, const map_key &r ) {
return l.str == r.str;
}
std::string str;
};
namespace std
{
template<>
struct hash<map_key> {
size_t operator()( const map_key &k ) const noexcept {
return hash<std::string> {}( k.str );
}
};
} // namespace std
class mapgen_palette
{
public:
palette_id id;
/**
* The mapping from character (key) to a list of things that should be placed. This is
* similar to objects, but it uses key to get the actual position where to place things
* out of the json "bitmap" (which is used to paint the terrain/furniture).
*/
using placing_map =
std::unordered_map<map_key, std::vector< shared_ptr_fast<const jmapgen_piece>>>;
std::unordered_map<map_key, ter_id> format_terrain;
std::unordered_map<map_key, furn_id> format_furniture;
placing_map format_placings;
template<typename PieceType>
/**
* Load (append to format_placings) the places that should be put there.
* member_name is the name of an optional object / array in the json object jsi.
*/
void load_place_mapings( const JsonObject &jo, const std::string &member_name,
placing_map &format_placings );
void check();
/**
* Loads a palette object and returns it. Doesn't save it anywhere.
*/
static mapgen_palette load_temp( const JsonObject &jo, const std::string &src );
/**
* Load a palette object and adds it to the global set of palettes.
* If "palette" field is specified, those palettes will be loaded recursively.
*/
static void load( const JsonObject &jo, const std::string &src );
/** Unload all palettes. */
static void reset();
/**
* Returns a palette with given id. If not found, debugmsg and returns a dummy.
*/
static const mapgen_palette &get( const palette_id &id );
static void check_definitions();
private:
static mapgen_palette load_internal( const JsonObject &jo, const std::string &src, bool require_id,
bool allow_recur );
/**
* Adds a palette to this one. New values take preference over the old ones.
*
*/
void add( const palette_id &rh );
void add( const mapgen_palette &rh );
};
struct jmapgen_objects {
jmapgen_objects( point offset, point mapsize, point tot_size );
bool check_bounds( const jmapgen_place &place, const JsonObject &jso );
void add( const jmapgen_place &place, shared_ptr_fast<const jmapgen_piece> piece );
/**
* PieceType must be inheriting from jmapgen_piece. It must have constructor that accepts a
* const JsonObject &as parameter. The function loads all objects from the json array and stores
* them in @ref objects.
*/
template<typename PieceType>
void load_objects( JsonArray parray );
/**
* Loads the mapgen objects from the array inside of jsi. If jsi has no member of that name,
* nothing is loaded and the function just returns.
*/
template<typename PieceType>
void load_objects( const JsonObject &jsi, const std::string &member_name );
void check( const std::string &oter_name ) const;
void apply( mapgendata &dat ) const;
void apply( mapgendata &dat, point offset ) const;
/**
* checks if applying these objects to data would cause cause a collision with vehicles
* on the same map
**/
bool has_vehicle_collision( mapgendata &dat, point offset ) const;
private:
/**
* Combination of where to place something and what to place.
*/
using jmapgen_obj = std::pair<jmapgen_place, shared_ptr_fast<const jmapgen_piece> >;
std::vector<jmapgen_obj> objects;
point m_offset;
point mapgensize;
point total_size;
};
class mapgen_function_json_base
{
public:
bool check_inbounds( const jmapgen_int &x, const jmapgen_int &y, const JsonObject &jso ) const;
size_t calc_index( point p ) const;
bool has_vehicle_collision( mapgendata &dat, point offset ) const;
private:
pimpl<json_source_location> jsrcloc;
protected:
explicit mapgen_function_json_base( const json_source_location &jsrcloc );
virtual ~mapgen_function_json_base();
void setup_common();
bool setup_common( const JsonObject &jo );
void setup_setmap( const JsonArray &parray );
// Returns true if the mapgen qualifies at this point already
virtual bool setup_internal( const JsonObject &jo ) = 0;
virtual void setup_setmap_internal() { }
void check_common( const std::string &oter_name ) const;
void formatted_set_incredibly_simple( map &m, point offset ) const;
bool do_format;
bool is_ready;
point mapgensize;
point m_offset;
std::vector<ter_furn_id> format;
point total_size;
std::vector<jmapgen_setmap> setmap_points;
jmapgen_objects objects;
};
class mapgen_function_json : public mapgen_function_json_base, public virtual mapgen_function
{
public:
void setup() override;
void check( const std::string &oter_name ) const override;
void generate( mapgendata & ) override;
mapgen_function_json( const json_source_location &jsrcloc, int w, point grid_offset,
point grid_total );
~mapgen_function_json() override = default;
ter_id fill_ter;
oter_id predecessor_mapgen;
protected:
bool setup_internal( const JsonObject &jo ) override;
private:
jmapgen_int rotation;
};
class update_mapgen_function_json : public mapgen_function_json_base
{
public:
explicit update_mapgen_function_json( const json_source_location &jsrcloc );
~update_mapgen_function_json() override = default;
void setup();
bool setup_update( const JsonObject &jo );
void check( const std::string &oter_name ) const;
bool update_map( const tripoint_abs_omt &omt_pos, point offset,
mission *miss, bool verify = false ) const;
bool update_map( mapgendata &md, point offset = point_zero,
bool verify = false ) const;
protected:
bool setup_internal( const JsonObject &/*jo*/ ) override;
ter_id fill_ter;
};
class mapgen_function_json_nested : public mapgen_function_json_base
{
public:
void setup();
void check( const std::string &oter_name ) const;
explicit mapgen_function_json_nested( const json_source_location &jsrcloc );
~mapgen_function_json_nested() override = default;
void nest( mapgendata &dat, point offset ) const;
protected:
bool setup_internal( const JsonObject &jo ) override;
private:
jmapgen_int rotation;
};
/////////////////////////////////////////////////////////
///// global per-terrain mapgen function lists
/*
* Load mapgen function of any type from a json object
*/
std::shared_ptr<mapgen_function> load_mapgen_function( const JsonObject &jio, point offset,
point total );
void load_and_add_mapgen_function(
const JsonObject &jio, const std::string &id_base, point offset, point total );
/*
* Load the above directly from a file via init, as opposed to riders attached to overmap_terrain. Added check
* for oter_mapgen / oter_mapgen_weights key, multiple possible ( i.e., [ "house_w_1", "duplex" ] )
*/
void load_mapgen( const JsonObject &jo );
void reset_mapgens();
/**
* Attempts to register the build-in function @p key as mapgen for the overmap terrain @p key.
* If there is no matching function, it does nothing (no error message) and returns -1.
* Otherwise it returns the index of the added entry in the vector of @ref oter_mapgen.
*/
// @TODO this should go away. It is only used for old build-in mapgen. Mapgen should be done via JSON.
int register_mapgen_function( const std::string &key );
/**
* Check that @p key is present in @ref oter_mapgen.
*/
bool has_mapgen_for( const std::string &key );
/*
* Sets the above after init, and initializes mapgen_function_json instances as well
*/
void calculate_mapgen_weights(); // throws
void check_mapgen_definitions();
/// move to building_generation
enum room_type {
room_null,
room_closet,
room_lobby,
room_chemistry,
room_teleport,
room_goo,
room_cloning,
room_vivisect,
room_bionics,
room_dorm,
room_living,
room_bathroom,
room_kitchen,
room_bedroom,
room_backyard,
room_study,
room_split
};
// helpful functions
bool connects_to( const oter_id &there, int dir );
void mapgen_rotate( map *m, oter_id terrain_type, bool north_is_down = false );
// wrappers for map:: functions
void line( map *m, const ter_id &type, point p1, point p2 );
void line_furn( map *m, const furn_id &type, point p1, point p2 );
void fill_background( map *m, const ter_id &type );
void fill_background( map *m, ter_id( *f )() );
void square( map *m, const ter_id &type, point p1, point p2 );
void square( map *m, ter_id( *f )(), point p1, point p2 );
void square( map *m, const weighted_int_list<ter_id> &f, point p1, point p2 );
void square_furn( map *m, const furn_id &type, point p1, point p2 );
void rough_circle( map *m, const ter_id &type, point, int rad );
void rough_circle_furn( map *m, const furn_id &type, point, int rad );
void circle( map *m, const ter_id &type, double x, double y, double rad );
void circle( map *m, const ter_id &type, point, int rad );
void circle_furn( map *m, const furn_id &type, point, int rad );
void add_corpse( map *m, point );
#endif // CATA_SRC_MAPGEN_H