Micropolis
generate.cpp
Go to the documentation of this file.
1/* generate.cpp
2 *
3 * Micropolis, Unix Version. This game was released for the Unix platform
4 * in or about 1990 and has been modified for inclusion in the One Laptop
5 * Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
6 * you need assistance with this program, you may contact:
7 * http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. You should have received a
18 * copy of the GNU General Public License along with this program. If
19 * not, see <http://www.gnu.org/licenses/>.
20 *
21 * ADDITIONAL TERMS per GNU GPL Section 7
22 *
23 * No trademark or publicity rights are granted. This license does NOT
24 * give you any right, title or interest in the trademark SimCity or any
25 * other Electronic Arts trademark. You may not distribute any
26 * modification of this program using the trademark SimCity or claim any
27 * affliation or association with Electronic Arts Inc. or its employees.
28 *
29 * Any propagation or conveyance of this program must include this
30 * copyright notice and these terms.
31 *
32 * If you convey this program (or any modifications of it) and assume
33 * contractual liability for the program to recipients of it, you agree
34 * to indemnify Electronic Arts for any liability that those contractual
35 * assumptions impose on Electronic Arts.
36 *
37 * You may not misrepresent the origins of this program; modified
38 * versions of the program must be marked as such and not identified as
39 * the original program.
40 *
41 * This disclaimer supplements the one included in the General Public
42 * License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
43 * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
44 * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
45 * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
46 * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
47 * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
48 * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
49 * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
50 * USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
51 * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
52 * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
53 * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
54 * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
55 * CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
56 * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
57 * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
58 * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
59 * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
60 * NOT APPLY TO YOU.
61 */
62
79
80
81#include "micropolis.h"
82
83
85
86
96
97
103{
104 cityFileName = "";
105
106 generateMap(seed);
108 cityTime = 0;
109 initSimLoad = 2;
110 doInitialEval = false;
111
116 updateFunds();
117 doSimInit();
118
119 simUpdate();
120
121 callback->didGenerateMap(this, callbackVal, seed);
122}
123
124
130{
131 generatedCitySeed = seed;
132
133 seedRandom(seed);
134
135 // Construct land.
136 if (terrainCreateIsland < 0) {
137 if (getRandom(100) < 10) { /* chance that island is generated */
138 makeIsland();
139 return;
140 }
141 }
142
143 if (terrainCreateIsland == 1) {
145 } else {
146 clearMap();
147 }
148
149 // Lay a river.
150 if (terrainCurveLevel != 0) {
151 int terrainXStart = 40 + getRandom(WORLD_W - 80);
152 int terrainYStart = 33 + getRandom(WORLD_H - 67);
153
154 Position terrainPos(terrainXStart, terrainYStart);
155
156 doRivers(terrainPos);
157 }
158
159 // Lay a few lakes.
160 if (terrainLakeLevel != 0) {
161 makeLakes();
162 }
163
164 smoothRiver();
165
166 // And add trees.
167 if (terrainTreeLevel != 0) {
168 doTrees();
169 }
170
171}
172
173
176{
177 short x, y;
178
179 for (x = 0; x < WORLD_W; x++) {
180 for (y = 0; y < WORLD_H; y++) {
181 map[x][y] = DIRT;
182 }
183 }
184}
185
186
189{
190 short x, y;
191
192 for (x = 0; x < WORLD_W; x++) {
193 for (y = 0; y < WORLD_H; y++) {
194 if (map[x][y] > WOODS) {
195 map[x][y] = DIRT;
196 }
197 }
198 }
199}
200
205{
206 const int terrainIslandRadius = ISLAND_RADIUS;
207 int x, y;
208
209 for (x = 0; x < WORLD_W; x++) {
210 for (y = 0; y < WORLD_H; y++) {
211 if ((x < 5) || (x >= WORLD_W - 5) ||
212 (y < 5) || (y >= WORLD_H - 5)) {
213 map[x][y] = RIVER;
214 } else {
215 map[x][y] = DIRT;
216 }
217 }
218 }
219
220 for (x = 0; x < WORLD_W - 5; x += 2) {
221
222 int mapY = getERandom(terrainIslandRadius);
223 plopBRiver(Position(x, mapY));
224
225 mapY = (WORLD_H - 10) - getERandom(terrainIslandRadius);
226 plopBRiver(Position(x, mapY));
227
228 plopSRiver(Position(x, 0));
229 plopSRiver(Position(x, WORLD_H - 6));
230 }
231
232 for (y = 0; y < WORLD_H - 5; y += 2) {
233
234 int mapX = getERandom(terrainIslandRadius);
235 plopBRiver(Position(mapX, y));
236
237 mapX = (WORLD_W - 10) - getERandom(terrainIslandRadius);
238 plopBRiver(Position(mapX, y));
239
240 plopSRiver(Position(0, y));
241 plopSRiver(Position(WORLD_W - 6, y));
242 }
243
244}
245
246
249{
251 smoothRiver();
252 doTrees();
253}
254
255
260{
261 short numLakes;
262
263 if (terrainLakeLevel < 0) {
264 numLakes = getRandom(10);
265 } else {
266 numLakes = terrainLakeLevel / 2;
267 }
268
269 while (numLakes > 0) {
270 int x = getRandom(WORLD_W - 21) + 10;
271 int y = getRandom(WORLD_H - 20) + 10;
272
274
275 numLakes--;
276 }
277}
278
284{
285 int numPlops = getRandom(12) + 2;
286
287 while (numPlops > 0) {
288 Position plopPos(pos, getRandom(12) - 6, getRandom(12) - 6);
289
290 if (getRandom(4)) {
291 plopSRiver(plopPos);
292 } else {
293 plopBRiver(plopPos);
294 }
295
296 numPlops--;
297 }
298}
299
300
310void Micropolis::treeSplash(short xloc, short yloc)
311{
312 short numTrees;
313
314 if (terrainTreeLevel < 0) {
315 numTrees = getRandom(150) + 50;
316 } else {
317 numTrees = getRandom(100 + (terrainTreeLevel * 2)) + 50;
318 }
319
320 Position treePos(xloc, yloc);
321
322 while (numTrees > 0) {
324 treePos.move(dir);
325
326 if (!treePos.testBounds()) {
327 return;
328 }
329
330 if ((map[treePos.posX][treePos.posY] & LOMASK) == DIRT) {
331 map[treePos.posX][treePos.posY] = WOODS | BLBNBIT;
332 }
333
334 numTrees--;
335 }
336}
337
338
341{
342 short Amount, x, xloc, yloc;
343
344 if (terrainTreeLevel < 0) {
345 Amount = getRandom(100) + 50;
346 } else {
347 Amount = terrainTreeLevel + 3;
348 }
349
350 for (x = 0; x < Amount; x++) {
351 xloc = getRandom(WORLD_W - 1);
352 yloc = getRandom(WORLD_H - 1);
353 treeSplash(xloc, yloc);
354 }
355
356 smoothTrees();
357 smoothTrees();
358}
359
360
361void Micropolis::smoothRiver()
362{
363 static short dx[4] = { -1, 0, 1, 0 };
364 static short dy[4] = { 0, 1, 0, -1 };
365 static short REdTab[16] = {
366 13 | BULLBIT, 13 | BULLBIT, 17 | BULLBIT, 15 | BULLBIT,
367 5 | BULLBIT, 2, 19 | BULLBIT, 17 | BULLBIT,
368 9 | BULLBIT, 11 | BULLBIT, 2, 13 | BULLBIT,
369 7 | BULLBIT, 9 | BULLBIT, 5 | BULLBIT, 2 };
370
371 short bitIndex, z, xTemp, yTemp;
372 short temp, x, y;
373
374 for (x = 0; x < WORLD_W; x++) {
375 for (y = 0; y < WORLD_H; y++) {
376
377 if (map[x][y] == REDGE) {
378 bitIndex = 0;
379
380 for (z = 0; z < 4; z++) {
381 bitIndex = bitIndex << 1;
382 xTemp = x + dx[z];
383 yTemp = y + dy[z];
384 if (testBounds(xTemp, yTemp) &&
385 ((map[xTemp][yTemp] & LOMASK) != DIRT) &&
386 (((map[xTemp][yTemp] & LOMASK) < WOODS_LOW) ||
387 ((map[xTemp][yTemp] & LOMASK) > WOODS_HIGH))) {
388 bitIndex++;
389 }
390 }
391
392 temp = REdTab[bitIndex & 15];
393
394 if ((temp != RIVER) &&
395 getRandom(1)) {
396 temp++;
397 }
398
399 map[x][y] = temp;
400 }
401 }
402 }
403}
404
405
406bool Micropolis::isTree(MapValue cell)
407{
408 if ((cell & LOMASK) >= WOODS_LOW && (cell & LOMASK) <= WOODS_HIGH) {
409 return true;
410 }
411
412 return false;
413}
414
415
416void Micropolis::smoothTrees()
417{
418 short x, y;
419 for (x = 0; x < WORLD_W; x++) {
420 for (y = 0; y < WORLD_H; y++) {
421 if (isTree(map[x][y])) {
422 smoothTreesAt(x, y, false);
423 }
424 }
425 }
426}
427
429void Micropolis::smoothTreesAt(int x, int y, bool preserve)
430{
431 ToolEffects effects(this);
432
433 smoothTreesAt(x, y, preserve, &effects);
434 effects.modifyWorld();
435}
436
437
441void Micropolis::smoothTreesAt(int x, int y, bool preserve,
442 ToolEffects *effects)
443{
444 static short dx[4] = { -1, 0, 1, 0 };
445 static short dy[4] = { 0, 1, 0, -1 };
446 static const short treeTable[16] = {
447 0, 0, 0, 34,
448 0, 0, 36, 35,
449 0, 32, 0, 33,
450 30, 31, 29, 37,
451 };
452
453 if (!isTree(effects->getMapValue(x, y))) {
454 return;
455 }
456
457 int bitIndex = 0;
458 int z;
459 for (z = 0; z < 4; z++) {
460 bitIndex = bitIndex << 1;
461 int xTemp = x + dx[z];
462 int yTemp = y + dy[z];
463 if (testBounds(xTemp, yTemp)
464 && isTree(effects->getMapValue(xTemp, yTemp))) {
465 bitIndex++;
466 }
467 }
468
469 int temp = treeTable[bitIndex & 15];
470 if (temp) {
471 if (temp != WOODS) {
472 if ((x + y) & 1) {
473 temp = temp - 8;
474 }
475 }
476 effects->setMapValue(x, y, temp | BLBNBIT);
477 } else {
478 if (!preserve) {
479 effects->setMapValue(x, y, temp);
480 }
481 }
482}
483
484
489void Micropolis::doRivers(const Position &terrainPos)
490{
491 Direction2 riverDir; // Global direction of the river
492 Direction2 terrainDir; // Local direction of the river
493
494 riverDir = (Direction2)(DIR2_NORTH + (getRandom(3) * 2));
495 doBRiver(terrainPos, riverDir, riverDir);
496
497 riverDir = rotate180(riverDir);
498 terrainDir = doBRiver(terrainPos, riverDir, riverDir);
499
500 riverDir = (Direction2)(DIR2_NORTH + (getRandom(3) * 2));
501 doSRiver(terrainPos, riverDir, terrainDir);
502}
503
504
513 Direction2 riverDir, Direction2 terrainDir)
514{
515 int rate1, rate2;
516
517 if (terrainCurveLevel < 0) {
518 rate1 = 100;
519 rate2 = 200;
520 } else {
521 rate1 = terrainCurveLevel + 10;
522 rate2 = terrainCurveLevel + 100;
523 }
524
525 Position pos(riverPos);
526
527 while (testBounds(pos.posX + 4, pos.posY + 4)) {
528 plopBRiver(pos);
529 if (getRandom(rate1) < 10) {
530 terrainDir = riverDir;
531 } else {
532 if (getRandom(rate2) > 90) {
533 terrainDir = rotate45(terrainDir);
534 }
535 if (getRandom(rate2) > 90) {
536 terrainDir = rotate45(terrainDir, 7);
537 }
538 }
539 pos.move(terrainDir);
540 }
541
542 return terrainDir;
543}
544
553 Direction2 riverDir, Direction2 terrainDir)
554{
555 int rate1, rate2;
556
557 if (terrainCurveLevel < 0) {
558 rate1 = 100;
559 rate2 = 200;
560 } else {
561 rate1 = terrainCurveLevel + 10;
562 rate2 = terrainCurveLevel + 100;
563 }
564
565 Position pos(riverPos);
566
567 while (testBounds(pos.posX + 3, pos.posY + 3)) {
568 //printf("doSRiver %d %d td %d rd %d\n", pos.posX, pos.posY, terrainDir, riverDir);
569 plopSRiver(pos);
570 if (getRandom(rate1) < 10) {
571 terrainDir = riverDir;
572 } else {
573 if (getRandom(rate2) > 90) {
574 terrainDir = rotate45(terrainDir);
575 }
576 if (getRandom(rate2) > 90) {
577 terrainDir = rotate45(terrainDir, 7);
578 }
579 }
580 pos.move(terrainDir);
581 }
582
583 return terrainDir;
584}
585
586
593void Micropolis::putOnMap(MapValue mChar, short xLoc, short yLoc)
594{
595 if (mChar == 0) {
596 return;
597 }
598
599 if (!testBounds(xLoc, yLoc)) {
600 return;
601 }
602
603 MapValue temp = map[xLoc][yLoc];
604
605 if (temp != DIRT) {
606 temp = temp & LOMASK;
607 if (temp == RIVER) {
608 if (mChar != CHANNEL) {
609 return;
610 }
611 }
612 if (temp == CHANNEL) {
613 return;
614 }
615 }
616 map[xLoc][yLoc] = mChar;
617}
618
624{
625 short x, y;
626 static MapValue BRMatrix[9][9] = {
627 { 0, 0, 0, REDGE, REDGE, REDGE, 0, 0, 0 },
628 { 0, 0, REDGE, RIVER, RIVER, RIVER, REDGE, 0, 0 },
629 { 0, REDGE, RIVER, RIVER, RIVER, RIVER, RIVER, REDGE, 0 },
630 { REDGE, RIVER, RIVER, RIVER, RIVER, RIVER, RIVER, RIVER, REDGE },
631 { REDGE, RIVER, RIVER, RIVER, CHANNEL, RIVER, RIVER, RIVER, REDGE },
632 { REDGE, RIVER, RIVER, RIVER, RIVER, RIVER, RIVER, RIVER, REDGE },
633 { 0, REDGE, RIVER, RIVER, RIVER, RIVER, RIVER, REDGE, 0 },
634 { 0, 0, REDGE, RIVER, RIVER, RIVER, REDGE, 0, 0 },
635 { 0, 0, 0, REDGE, REDGE, REDGE, 0, 0, 0 },
636 };
637
638 for (x = 0; x < 9; x++) {
639 for (y = 0; y < 9; y++) {
640 putOnMap(BRMatrix[y][x], pos.posX + x, pos.posY + y);
641 }
642 }
643}
644
645
651{
652 short x, y;
653 static MapValue SRMatrix[6][6] = {
654 { 0, 0, REDGE, REDGE, 0, 0 },
655 { 0, REDGE, RIVER, RIVER, REDGE, 0 },
656 { REDGE, RIVER, RIVER, RIVER, RIVER, REDGE },
657 { REDGE, RIVER, RIVER, RIVER, RIVER, REDGE },
658 { 0, REDGE, RIVER, RIVER, REDGE, 0 },
659 { 0, 0, REDGE, REDGE, 0, 0 },
660 };
661
662 for (x = 0; x < 6; x++) {
663 for (y = 0; y < 6; y++) {
664 putOnMap(SRMatrix[y][x], pos.posX + x, pos.posY + y);
665 }
666 }
667}
668
669
670void Micropolis::smoothWater()
671{
672 int x, y;
673 MapTile tile;
674 Direction2 dir;
675
676 for (x = 0; x < WORLD_W; x++) {
677 for (y = 0; y < WORLD_H; y++) {
678
679 tile = map[x][y] & LOMASK;
680
681 /* If (x, y) is water: */
682 if (tile >= WATER_LOW && tile <= WATER_HIGH) {
683
684 const Position pos(x, y);
685 for (dir = DIR2_BEGIN; dir < DIR2_END; dir = increment90(dir)) {
686
687 /* If getting a tile off-map, condition below fails. */
688 // @note I think this may have been a bug, since it always uses DIR2_WEST instead of dir.
689 //tile = getTileFromMap(pos, DIR2_WEST, WATER_LOW);
690 tile = getTileFromMap(pos, dir, WATER_LOW);
691
692 /* If nearest object is not water: */
693 if (tile < WATER_LOW || tile > WATER_HIGH) {
694 map[x][y] = REDGE; /* set river edge */
695 break; // Continue with next tile
696 }
697 }
698 }
699 }
700 }
701
702 for (x = 0; x < WORLD_W; x++) {
703 for (y = 0; y < WORLD_H; y++) {
704
705 tile = map[x][y] & LOMASK;
706
707 /* If water which is not a channel: */
708 if (tile != CHANNEL && tile >= WATER_LOW && tile <= WATER_HIGH) {
709
710 bool makeRiver = true; // make (x, y) a river
711
712 const Position pos(x, y);
713 for (dir = DIR2_BEGIN; dir < DIR2_END; dir = increment90(dir)) {
714
715 /* If getting a tile off-map, condition below fails. */
716 // @note I think this may have been a bug, since it always uses DIR2_WEST instead of dir.
717 //tile = getTileFromMap(pos, DIR2_WEST, WATER_LOW);
718 tile = getTileFromMap(pos, dir, WATER_LOW);
719
720 /* If nearest object is not water: */
721 if (tile < WATER_LOW || tile > WATER_HIGH) {
722 makeRiver = false;
723 break;
724 }
725 }
726
727 if (makeRiver) {
728 map[x][y] = RIVER; /* make it a river */
729 }
730 }
731 }
732 }
733
734 for (x = 0; x < WORLD_W; x++) {
735 for (y = 0; y < WORLD_H; y++) {
736
737 tile = map[x][y] & LOMASK;
738
739 /* If woods: */
740 if (tile >= WOODS_LOW && tile <= WOODS_HIGH) {
741
742 const Position pos(x, y);
743 for (dir = DIR2_BEGIN; dir < DIR2_END; dir = increment90(dir)) {
744
745 /* If getting a tile off-map, condition below fails. */
746 // @note I think this may have been a bug, since it always uses DIR2_WEST instead of dir.
747 //tile = getTileFromMap(pos, DIR2_WEST, WATER_LOW);
748 tile = getTileFromMap(pos, dir, TILE_INVALID);
749
750 if (tile == RIVER || tile == CHANNEL) {
751 map[x][y] = REDGE; /* make it water's edge */
752 break;
753 }
754 }
755 }
756 }
757 }
758}
759
760
void makeSingleLake(const Position &pos)
Definition generate.cpp:283
int terrainCreateIsland
bool doInitialEval
Need to perform initial city evaluation.
void generateSomeCity(int seed)
Definition generate.cpp:102
void resetMapState()
void seedRandom(int seed)
Definition random.cpp:177
void simUpdate()
void doRivers(const Position &terrainPos)
Definition generate.cpp:489
int terrainTreeLevel
void putOnMap(MapValue mChar, short xLoc, short yLoc)
Definition generate.cpp:593
Scenario scenario
Scenario being played.
void generateSomeRandomCity()
Definition generate.cpp:92
Direction2 doSRiver(const Position &riverPos, Direction2 riverDir, Direction2 terrainDir)
Definition generate.cpp:552
Callback * callback
Definition micropolis.h:955
MapTile getTileFromMap(const Position &pos, Direction2 dir, MapTile defaultTile)
Definition traffic.cpp:407
std::string cityFileName
Filename of the last loaded city.
int terrainCurveLevel
short getRandom(short range)
Definition random.cpp:110
int getRandom16()
Definition random.cpp:130
void makeIsland()
Definition generate.cpp:248
void resetEditorState()
void updateFunds()
Definition update.cpp:127
void makeLakes()
Definition generate.cpp:259
int generatedCitySeed
unsigned short * map[WORLD_W]
int terrainLakeLevel
void generateMap(int seed)
Definition generate.cpp:129
void doTrees()
Definition generate.cpp:340
Direction2 doBRiver(const Position &riverPos, Direction2 riverDir, Direction2 terrainDir)
Definition generate.cpp:512
static bool testBounds(int wx, int wy)
void makeNakedIsland()
Definition generate.cpp:204
void invalidateMaps()
void clearMap()
Definition generate.cpp:175
void plopSRiver(const Position &pos)
Definition generate.cpp:650
void treeSplash(short xloc, short yloc)
Definition generate.cpp:310
void clearUnnatural()
Definition generate.cpp:188
void initWillStuff()
void smoothTreesAt(int x, int y, bool preserve)
Definition generate.cpp:429
short getERandom(short limit)
Definition random.cpp:155
void plopBRiver(const Position &pos)
Definition generate.cpp:623
void doSimInit()
Definition simulate.cpp:288
int posY
Vertical coordnate of the position.
Definition position.h:169
int posX
Horizontal coordinate of the position.
Definition position.h:168
bool move(Direction2 dir)
Definition position.cpp:161
bool testBounds()
Definition position.h:177
void setMapValue(const Position &pos, MapValue mapVal)
Definition tool.cpp:186
void modifyWorld()
Definition tool.cpp:121
MapValue getMapValue(const Position &pos) const
Definition tool.cpp:169
static const int WORLD_H
Definition map_type.h:95
static const int WORLD_W
Definition map_type.h:90
Header file for Micropolis game engine.
@ SC_NONE
No scenario (free playing)
Definition micropolis.h:699
@ WATER_LOW
First water tile.
Definition micropolis.h:392
@ WATER_HIGH
Last water tile (inclusive)
Definition micropolis.h:393
@ DIRT
Clear tile.
Definition micropolis.h:382
@ TILE_INVALID
Invalid tile (not used in the world map).
Definition micropolis.h:690
static const int ISLAND_RADIUS
Definition micropolis.h:239
static Direction2 rotate45(Direction2 dir, int count=1)
Definition position.h:127
static Direction2 rotate180(Direction2 dir)
Definition position.h:147
Direction2
Definition position.h:86
@ DIR2_BEGIN
First valid direction.
Definition position.h:97
@ DIR2_END
End-condition for directions.
Definition position.h:98
@ DIR2_NORTH
Direction pointing north.
Definition position.h:88
static Direction2 increment90(Direction2 dir)
Definition position.h:117
unsigned short MapTile
Definition tool.h:108
@ LOMASK
Mask for the Tiles part of the tile.
Definition tool.h:129
@ BULLBIT
bit 12, tile is bulldozable.
Definition tool.h:123
unsigned short MapValue
Definition tool.h:101