Micropolis
traffic.cpp
Go to the documentation of this file.
1/* traffic.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
95short Micropolis::makeTrafficAt(int x, int y, ZoneType dest)
96{
97 Position pos;
98 pos.posX = x;
99 pos.posY = y;
100
101 if (tryDrive(pos, dest)) { /* attempt to drive somewhere */
102 addToTrafficDensityMap(); /* if sucessful, inc trafdensity */
103 return 1; /* traffic passed */
104 }
105
106 return 0; /* traffic failed */
107}
108
109
118short Micropolis::makeTraffic(int x, int y, ZoneType dest)
119{
120 Position startPos;
121 startPos.posX = x;
122 startPos.posY = y;
123 return makeTraffic(startPos, dest);
124}
125
126
134short Micropolis::makeTraffic(const Position &startPos, ZoneType dest)
135{
136 curMapStackPointer = 0; // Clear position stack
137
138 Position pos(startPos);
139
140#if 0
141 if ((!getRandom(2)) && findPerimeterTelecom(pos)) {
142 /* printf("Telecom!\n"); */
143 return 1;
144 }
145#endif
146
147 if (findPerimeterRoad(&pos)) { /* look for road on zone perimeter */
148
149 if (tryDrive(pos, dest)) { /* attempt to drive somewhere */
150 addToTrafficDensityMap(); /* if sucessful, inc trafdensity */
151 return 1; /* traffic passed */
152 }
153
154 return 0; /* traffic failed */
155 } else {
156 return -1; /* no road found */
157 }
158}
159
160
166{
167 /* For each saved position of the drive */
168 while (curMapStackPointer > 0) {
169
170 Position pos = pullPos();
171 if (pos.testBounds()) {
172
173 MapTile tile = map[pos.posX][pos.posY] & LOMASK;
174
175 if (tile >= ROADBASE && tile < POWERBASE) {
176 SimSprite *sprite;
177
178 // Update traffic density.
179 int traffic = trafficDensityMap.worldGet(pos.posX, pos.posY);
180 traffic += 50;
181 traffic = min(traffic, 240);
182 trafficDensityMap.worldSet(pos.posX, pos.posY, (Byte)traffic);
183
184 // Check for heavy traffic.
185 if (traffic >= 240 && getRandom(5) == 0) {
186
187 trafMaxX = pos.posX;
188 trafMaxY = pos.posY;
189
190 /* Direct helicopter towards heavy traffic */
192 if (sprite != NULL && sprite->control == -1) {
193
194 sprite->destX = trafMaxX * 16;
195 sprite->destY = trafMaxY * 16;
196
197 }
198 }
199 }
200 }
201 }
202}
203
204
216
217
229
230
240{
241 /* look for road on edges of zone */
242 static const short PerimX[12] = {-1, 0, 1, 2, 2, 2, 1, 0,-1,-2,-2,-2};
243 static const short PerimY[12] = {-2,-2,-2,-1, 0, 1, 2, 2, 2, 1, 0,-1};
244 short tx, ty;
245
246 for (short z = 0; z < 12; z++) {
247
248 tx = pos->posX + PerimX[z];
249 ty = pos->posY + PerimY[z];
250
251 if (testBounds(tx, ty)) {
252
253 if (roadTest(map[tx][ty])) {
254
255 pos->posX = tx;
256 pos->posY = ty;
257
258 return true;
259 }
260 }
261 }
262
263 return false;
264}
265
266
275{
276 /* look for telecom on edges of zone */
277 static const short PerimX[12] = {-1, 0, 1, 2, 2, 2, 1, 0,-1,-2,-2,-2};
278 static const short PerimY[12] = {-2,-2,-2,-1, 0, 1, 2, 2, 2, 1, 0,-1};
279 short tx, ty, tile;
280
281 for (short z = 0; z < 12; z++) {
282
283 tx = pos.posX + PerimX[z];
284 ty = pos.posX + PerimY[z];
285
286 if (testBounds(tx, ty)) {
287
288 tile = map[tx][ty] & LOMASK;
289 if (tile >= TELEBASE && tile <= TELELAST) {
290 return true;
291 }
292 }
293 }
294
295 return false;
296}
297
298
309bool Micropolis::tryDrive(const Position &startPos, ZoneType destZone)
310{
311 Direction2 dirLast = DIR2_INVALID;
312 Position drivePos(startPos);
313
314 /* Maximum distance to try */
315 for (short dist = 0; dist < MAX_TRAFFIC_DISTANCE; dist++) {
316
317 Direction2 dir = tryGo(drivePos, dirLast);
318 if (dir != DIR2_INVALID) { // we found a road
319 drivePos.move(dir);
320 dirLast = rotate180(dir);
321
322 /* Save pos every other move.
323 * This also relates to
324 * Micropolis::trafficDensityMap::MAP_BLOCKSIZE
325 */
326 if (dist & 1) {
327 pushPos(drivePos);
328 }
329
330 if (driveDone(drivePos, destZone)) { // if destination is reached
331 return true; /* pass */
332 }
333
334 } else {
335
336 if (curMapStackPointer > 0) { /* dead end, backup */
338 dist += 3;
339 } else {
340 return false; /* give up at start */
341 }
342
343 }
344 }
345
346 return false; /* gone MAX_TRAFFIC_DISTANCE */
347}
348
349
357{
358 Direction2 directions[4];
359
360 // Find connections from current position.
362 int count = 0;
363 for (int i = 0; i < 4; i++) {
364 if (dir != dirLast && roadTest(getTileFromMap(pos, dir, DIRT))) {
365 // found a road in an allowed direction
366 directions[i] = dir;
367 count++;
368 } else {
369 directions[i] = DIR2_INVALID;
370 }
371
372 dir = rotate90(dir);
373 }
374
375 if (count == 0) { // dead end
376 return DIR2_INVALID;
377 }
378
379 // We have at least one way to go.
380
381 if (count == 1) { // only one solution
382 for (int i = 0; i < 4; i++) {
383 if (directions[i] != DIR2_INVALID) {
384 return directions[i];
385 }
386 }
387 }
388
389 // more than one choice, draw a random number.
390 int i = getRandom16() & 3;
391 while (directions[i] == DIR2_INVALID) {
392 i = (i + 1) & 3;
393 }
394 return directions[i];
395}
396
397
408 Direction2 dir, MapTile defaultTile)
409{
410 switch (dir) {
411
412 case DIR2_NORTH:
413 if (pos.posY > 0) {
414 return map[pos.posX][pos.posY - 1] & LOMASK;
415 }
416
417 return defaultTile;
418
419 case DIR2_EAST:
420 if (pos.posX < WORLD_W - 1) {
421 return map[pos.posX + 1][pos.posY] & LOMASK;
422 }
423
424 return defaultTile;
425
426 case DIR2_SOUTH:
427 if (pos.posY < WORLD_H - 1) {
428 return map[pos.posX][pos.posY + 1] & LOMASK;
429 }
430
431 return defaultTile;
432
433 case DIR2_WEST:
434 if (pos.posX > 0) {
435 return map[pos.posX - 1][pos.posY] & LOMASK;
436 }
437
438 return defaultTile;
439
440 default:
441 return defaultTile;
442
443 }
444}
445
446
453bool Micropolis::driveDone(const Position &pos, ZoneType destZone)
454{
455 // FIXME: Use macros to determine the zone type: residential, commercial or industrial.
456 /* commercial, industrial, residential destinations */
457 static const MapTile targetLow[3] = {COMBASE, LHTHR, LHTHR};
458 static const MapTile targetHigh[3] = {NUCLEAR, PORT, COMBASE};
459
460 assert(ZT_NUM_DESTINATIONS == LENGTH_OF(targetLow));
461 assert(ZT_NUM_DESTINATIONS == LENGTH_OF(targetHigh));
462
463 MapTile l = targetLow[destZone]; // Lowest acceptable tile value
464 MapTile h = targetHigh[destZone]; // Highest acceptable tile value
465
466 if (pos.posY > 0) {
467 MapTile z = map[pos.posX][pos.posY - 1] & LOMASK;
468 if (z >= l && z <= h) {
469 return true;
470 }
471 }
472
473 if (pos.posX < (WORLD_W - 1)) {
474 MapTile z = map[pos.posX + 1][pos.posY] & LOMASK;
475 if (z >= l && z <= h) {
476 return true;
477 }
478 }
479
480 if (pos.posY < (WORLD_H - 1)) {
481 MapTile z = map[pos.posX][pos.posY + 1] & LOMASK;
482 if (z >= l && z <= h) {
483 return true;
484 }
485 }
486
487 if (pos.posX > 0) {
488 MapTile z = map[pos.posX - 1][pos.posY] & LOMASK;
489 if (z >= l && z <= h) {
490 return true;
491 }
492 }
493
494 return false;
495}
496
497
504{
505 MapTile tile = mv & LOMASK;
506
507 if (tile < ROADBASE || tile > LASTRAIL) {
508 return false;
509 }
510
511 if (tile >= POWERBASE && tile < LASTPOWER) {
512 return false;
513 }
514
515 return true;
516}
517
518
DATA worldGet(int x, int y) const
Definition map_type.h:316
void worldSet(int x, int y, DATA val)
Definition map_type.h:297
bool driveDone(const Position &pos, ZoneType destZone)
Definition traffic.cpp:453
Position pullPos()
Definition traffic.cpp:223
bool findPerimeterTelecom(const Position &pos)
Definition traffic.cpp:274
bool tryDrive(const Position &startPos, ZoneType destZone)
Definition traffic.cpp:309
void pushPos(const Position &pos)
Definition traffic.cpp:210
MapTile getTileFromMap(const Position &pos, Direction2 dir, MapTile defaultTile)
Definition traffic.cpp:407
short makeTraffic(int x, int y, ZoneType dest)
Definition traffic.cpp:118
short getRandom(short range)
Definition random.cpp:110
Position curMapStackXY[MAX_TRAFFIC_DISTANCE+1]
Position stack.
int getRandom16()
Definition random.cpp:130
short trafMaxY
Y coordinate of a position with heavy traffic.
short trafMaxX
X coordinate of a position with heavy traffic.
SimSprite * getSprite(int type)
Definition sprite.cpp:338
unsigned short * map[WORLD_W]
short makeTrafficAt(int x, int y, ZoneType dest)
Definition traffic.cpp:95
Direction2 tryGo(const Position &pos, Direction2 dirLast)
Definition traffic.cpp:356
MapByte2 trafficDensityMap
Traffic density map.
static bool testBounds(int wx, int wy)
void addToTrafficDensityMap()
Definition traffic.cpp:165
short curMapStackPointer
bool roadTest(MapValue tile)
Definition traffic.cpp:503
bool findPerimeterRoad(Position *pos)
Definition traffic.cpp:239
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
int destX
Destination X coordinate of the sprite.
Definition micropolis.h:902
int destY
Destination Y coordinate of the sprite.
Definition micropolis.h:903
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.
ZoneType
Definition micropolis.h:718
@ ZT_NUM_DESTINATIONS
Number of available zones.
Definition micropolis.h:723
@ NUCLEAR
'Center' tile nuclear power plant.
Definition micropolis.h:604
@ PORT
Center tile of the seaport.
Definition micropolis.h:568
@ DIRT
Clear tile.
Definition micropolis.h:382
static T min(const T a, const T b)
Definition micropolis.h:784
@ SPRITE_HELICOPTER
Helicopter sprite.
Definition micropolis.h:332
#define LENGTH_OF(array)
Definition micropolis.h:843
static const int MAX_TRAFFIC_DISTANCE
Definition micropolis.h:248
static Direction2 rotate180(Direction2 dir)
Definition position.h:147
Direction2
Definition position.h:86
@ DIR2_WEST
Direction pointing west.
Definition position.h:94
@ DIR2_INVALID
Invalid direction.
Definition position.h:87
@ DIR2_SOUTH
Direction pointing south.
Definition position.h:92
@ DIR2_EAST
Direction pointing east.
Definition position.h:90
@ DIR2_NORTH
Direction pointing north.
Definition position.h:88
static Direction2 rotate90(Direction2 dir)
Definition position.h:137
unsigned short MapTile
Definition tool.h:108
@ LOMASK
Mask for the Tiles part of the tile.
Definition tool.h:129
unsigned short MapValue
Definition tool.h:101