|
|
1.1 ! root 1: /* terragen.c: Terrain generator ! 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 [email protected]. ! 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: ! 63: /* Micropolis simulator code. Copyright 1988, 1989 Maxis, Will Wright */ ! 64: /* modified by Paul Schmidt 10-89 to implement terrain editor quickly... - rax */ ! 65: ! 66: #include "..\sim\sim.h" ! 67: ! 68: #define TRUE 1 ! 69: #define FALSE 0 ! 70: #define WORLD_X 120 ! 71: #define WORLD_Y 100 ! 72: #define RIVER 2 ! 73: #define REDGE 3 ! 74: #define CHANNEL 4 ! 75: #define WOODS 37 ! 76: #define BL 4096 ! 77: #define BN 8192 ! 78: #define BLN BL+BN ! 79: ! 80: #define WATER_LOW 2 /* range for water */ ! 81: #define WATER_HIGH 20 ! 82: #define WOODS_LOW 21 /* range for woods */ ! 83: #define WOODS_HIGH 39 ! 84: ! 85: static int XStart, YStart; ! 86: static int Dir, LastDir; ! 87: ! 88: /* trash values for GRand() */ ! 89: static int GRanArray[5] = { 1018,4521,202,419,3 }; ! 90: ! 91: extern int treeLevel; /* level for tree creation (terra.c) */ ! 92: extern int lakeLevel; /* level for lake creation (terra.c) */ ! 93: extern int curvLevel; /* level for river curviness (terra.c) */ ! 94: ! 95: rax_ClearMap() ! 96: { ! 97: register int x, y; ! 98: ! 99: for (x=0; x<WORLD_X; x++) ! 100: for (y=0; y<WORLD_Y; y++) ! 101: Map[x][y] = 0; ! 102: } ! 103: ! 104: rax_WaterEdges() /* set water edges */ ! 105: { ! 106: register int x,y; /* temporary counters */ ! 107: ! 108: for(x=0;x < WORLD_X;x++) { ! 109: for(y=0;y < WORLD_Y;y++) { ! 110: if((Map[x][y]&LOMASK) >= WATER_LOW && (Map[x][y]&LOMASK) <= WATER_HIGH) { /* if water */ ! 111: if(x > 0) { ! 112: if((Map[x-1][y]&LOMASK) < WATER_LOW || (Map[x-1][y]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */ ! 113: goto edge; ! 114: } ! 115: } ! 116: if(x < WORLD_X-1) { ! 117: if((Map[x+1][y]&LOMASK) < WATER_LOW || (Map[x+1][y]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */ ! 118: goto edge; ! 119: } ! 120: } ! 121: if(y > 0) { ! 122: if((Map[x][y-1]&LOMASK) < WATER_LOW || (Map[x][y-1]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */ ! 123: goto edge; ! 124: } ! 125: } ! 126: if(y < WORLD_Y-1) { ! 127: if((Map[x][y+1]&LOMASK) < WATER_LOW || (Map[x][y+1]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */ ! 128: edge: ! 129: Map[x][y]=REDGE; /* set river edge */ ! 130: continue; ! 131: } ! 132: } ! 133: } ! 134: } ! 135: } ! 136: for(x=0;x < WORLD_X;x++) { ! 137: for(y=0;y < WORLD_Y;y++) { ! 138: if((Map[x][y]&LOMASK) != CHANNEL && (Map[x][y]&LOMASK) >= WATER_LOW && (Map[x][y]&LOMASK) <= WATER_HIGH) { /* if water which is not a channel */ ! 139: if(x > 0) { ! 140: if((Map[x-1][y]&LOMASK) < WATER_LOW || (Map[x-1][y]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */ ! 141: continue; ! 142: } ! 143: } ! 144: if(x < WORLD_X-1) { ! 145: if((Map[x+1][y]&LOMASK) < WATER_LOW || (Map[x+1][y]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */ ! 146: continue; ! 147: } ! 148: } ! 149: if(y > 0) { ! 150: if((Map[x][y-1]&LOMASK) < WATER_LOW || (Map[x][y-1]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */ ! 151: continue; ! 152: } ! 153: } ! 154: if(y < WORLD_Y-1) { ! 155: if((Map[x][y+1]&LOMASK) < WATER_LOW || (Map[x][y+1]&LOMASK) > WATER_HIGH) { /* if nearest object is not water */ ! 156: continue; ! 157: } ! 158: } ! 159: Map[x][y]=RIVER; /* make it a river */ ! 160: } ! 161: } ! 162: } ! 163: for(x=0;x < WORLD_X;x++) { ! 164: for(y=0;y < WORLD_Y;y++) { ! 165: if((Map[x][y]&LOMASK) >= WOODS_LOW && (Map[x][y]&LOMASK) <= WOODS_HIGH) { /* if woods */ ! 166: if(x > 0) { ! 167: if(Map[x-1][y] == RIVER || Map[x-1][y] == CHANNEL) { /* if nearest object is water */ ! 168: Map[x][y]=REDGE; /* make it water's edge */ ! 169: continue; ! 170: } ! 171: } ! 172: if(x < WORLD_X-1) { ! 173: if(Map[x+1][y] == RIVER || Map[x+1][y] == CHANNEL) { /* if nearest object is water */ ! 174: Map[x][y]=REDGE; /* make it water's edge */ ! 175: continue; ! 176: } ! 177: } ! 178: if(y > 0) { ! 179: if(Map[x][y-1] == RIVER || Map[x][y-1] == CHANNEL) { /* if nearest object is water */ ! 180: Map[x][y]=REDGE; /* make it water's edge */ ! 181: continue; ! 182: } ! 183: } ! 184: if(y < WORLD_Y-1) { ! 185: if(Map[x][y+1] == RIVER || Map[x][y+1] == CHANNEL) { /* if nearest object is water */ ! 186: Map[x][y]=REDGE; /* make it water's edge */ ! 187: continue; ! 188: } ! 189: } ! 190: } ! 191: } ! 192: } ! 193: } ! 194: ! 195: #define RADIUS 18 ! 196: ! 197: rax_MakeIsland() ! 198: { ! 199: register int x,y,z; ! 200: ! 201: for (x=0; x<WORLD_X; x++) ! 202: for (y=0; y<WORLD_Y; y++) ! 203: Map[x][y] = RIVER; ! 204: for (x=5; x<WORLD_X-5; x++) ! 205: for (y=5; y<WORLD_Y-5; y++) ! 206: Map[x][y] = 0; ! 207: for (x=0; x<WORLD_X-5; x+=2) { ! 208: MapX= x ; ! 209: MapY= rax_EGRand(RADIUS); ! 210: rax_BRivPlop(); ! 211: MapY= 90-rax_EGRand(RADIUS); ! 212: rax_BRivPlop(); ! 213: MapY= 0; ! 214: rax_SRivPlop(); ! 215: MapY= 94; ! 216: rax_SRivPlop(); ! 217: } ! 218: for (y=0; y<WORLD_Y-5; y+=2) { ! 219: MapY= y ; ! 220: MapX= rax_EGRand(RADIUS); ! 221: rax_BRivPlop(); ! 222: MapX= 110-rax_EGRand(RADIUS); ! 223: rax_BRivPlop(); ! 224: MapX= 0; ! 225: rax_SRivPlop(); ! 226: MapX= 114; ! 227: rax_SRivPlop(); ! 228: } ! 229: } ! 230: ! 231: rax_MakeLakes() ! 232: { ! 233: int Lim1, Lim2, t, z; ! 234: register int x, y; ! 235: ! 236: /* Lim1 = rax_GRand(10); /**/ ! 237: Lim1=lakeLevel/2; ! 238: for (t = 0; t < Lim1; t++) { ! 239: x = rax_GRand(99) + 10; ! 240: y = rax_GRand(80) + 10; ! 241: Lim2 = rax_GRand(12)+2; ! 242: for (z = 0; z < Lim2; z++) { ! 243: MapX = x - 6 + rax_GRand(12); ! 244: MapY = y - 6 + rax_GRand(12); ! 245: if (rax_GRand(4)) rax_SRivPlop(); ! 246: else rax_BRivPlop(); ! 247: } ! 248: } ! 249: } ! 250: ! 251: rax_GetRandStart() ! 252: { ! 253: XStart = 40 + rax_GRand(40); ! 254: YStart = 33 + rax_GRand(33); ! 255: MapX = XStart; ! 256: MapY = YStart; ! 257: } ! 258: ! 259: rax_DoTrees() ! 260: { ! 261: int x,xloc,yloc; ! 262: ! 263: for(x=0;x < (treeLevel*3);x++) { ! 264: xloc=rax_GRand(119); ! 265: yloc=rax_GRand(99); ! 266: rax_TreeSplash(xloc,yloc); ! 267: } ! 268: rax_SmoothTrees(); ! 269: rax_SmoothTrees(); ! 270: } ! 271: ! 272: rax_TreeSplash(xloc,yloc) ! 273: int xloc,yloc; ! 274: { ! 275: int Dis, Dir; ! 276: register int xoff, yoff,z; ! 277: ! 278: Dis = rax_GRand(100+(treeLevel*2))+50; ! 279: MapX = xloc; ! 280: MapY = yloc; ! 281: for (z=0; z<Dis; z++) { ! 282: Dir = rax_GRand(7); ! 283: rax_MoveMap(Dir); ! 284: if (!(rax_TestBounds(MapX,MapY))) return; ! 285: if (Map[MapX][MapY] == 0) Map[MapX][MapY] = WOODS+ BLN; ! 286: } ! 287: } ! 288: ! 289: rax_SmoothRiver() ! 290: { ! 291: static int DX[4] = {-1, 0, 1, 0}; ! 292: static int DY[4] = { 0, 1, 0,-1}; ! 293: static int REdTab[16] = { 13+BL,13+BL,17+BL,15+BL,5+BL,2,19+BL, ! 294: 17+BL,9+BL,11+BL,2,13+BL,7+BL,9+BL,5+BL,2}; ! 295: int bitindex, z,Xtem,Ytem; ! 296: register int temp,MapX,MapY; ! 297: ! 298: for (MapX = 0; MapX < WORLD_X; MapX++) ! 299: for (MapY = 0; MapY < WORLD_Y; MapY++) ! 300: if (Map[MapX][MapY] == REDGE) { ! 301: bitindex = 0; ! 302: for (z=0; z<4; z++) { ! 303: bitindex = bitindex << 1; ! 304: Xtem = MapX + DX[z]; ! 305: Ytem = MapY + DY[z]; ! 306: if (rax_TestBounds(Xtem, Ytem)) ! 307: /* if(Map[Xtem][Ytem]) bitindex++; /* original code */ ! 308: if((Map[Xtem][Ytem]&LOMASK) && ((Map[Xtem][Ytem]&LOMASK) < WOODS_LOW || (Map[Xtem][Ytem]&LOMASK) > WOODS_HIGH)) bitindex++; /* new code - rax */ ! 309: } ! 310: temp = REdTab[bitindex & 15]; ! 311: if ((temp != 2) && (rax_GRand(1))) temp++; ! 312: Map[MapX][MapY] = temp; ! 313: } ! 314: } ! 315: ! 316: IsTree(cell) /* return TRUE or FALSE if cell value is a tree cell */ ! 317: register int cell; ! 318: { ! 319: if((cell&LOMASK) >= WOODS_LOW && (cell&LOMASK) <= WOODS_HIGH) return TRUE; else return FALSE; ! 320: } ! 321: ! 322: rax_SmoothTrees() ! 323: { ! 324: static int DX[4] = {-1, 0, 1, 0}; ! 325: static int DY[4] = { 0, 1, 0,-1}; ! 326: static int TEdTab[16] = {0,0,0,34,0,0,36,35,0,32,0,33,30,31,29,37}; ! 327: int bitindex, z,Xtem,Ytem; ! 328: register int temp,MapX,MapY; ! 329: ! 330: for (MapX = 0; MapX < WORLD_X; MapX++) ! 331: for (MapY = 0; MapY < WORLD_Y; MapY++) ! 332: if (IsTree(Map[MapX][MapY])) { ! 333: bitindex = 0; ! 334: for (z=0; z<4; z++) { ! 335: bitindex = bitindex << 1; ! 336: Xtem = MapX + DX[z]; ! 337: Ytem = MapY + DY[z]; ! 338: if (rax_TestBounds(Xtem, Ytem)) ! 339: if(IsTree(Map[Xtem][Ytem])) bitindex++; ! 340: ! 341: } ! 342: temp = TEdTab[bitindex & 15]; ! 343: if (temp) { ! 344: if (temp != 37) ! 345: if ((MapX+MapY) & 1) ! 346: temp = temp-8; ! 347: Map[MapX][MapY] = temp+BLN; ! 348: } ! 349: else Map[MapX][MapY] = temp; ! 350: } ! 351: } ! 352: ! 353: rax_DoRivers() ! 354: { ! 355: LastDir = rax_GRand(3); ! 356: Dir = LastDir; ! 357: rax_DoBRiv(); ! 358: MapX = XStart; ! 359: MapY = YStart; ! 360: LastDir = LastDir ^ 4; ! 361: Dir = LastDir; ! 362: rax_DoBRiv(); ! 363: MapX = XStart; ! 364: MapY = YStart; ! 365: LastDir = rax_GRand(3); ! 366: rax_DoSRiv(); ! 367: } ! 368: ! 369: rax_DoBRiv() ! 370: { ! 371: while(rax_TestBounds (MapX+4, MapY+4)) { ! 372: rax_BRivPlop(); ! 373: if(rax_GRand(curvLevel+10) < 10) { ! 374: Dir=LastDir; ! 375: } else { ! 376: if(rax_GRand(curvLevel+100) > 90) { ! 377: Dir++; ! 378: } ! 379: if(rax_GRand(curvLevel+100) > 90) { ! 380: Dir--; ! 381: } ! 382: } ! 383: rax_MoveMap(Dir); ! 384: } ! 385: } ! 386: ! 387: rax_DoSRiv() ! 388: { ! 389: while(rax_TestBounds (MapX+3, MapY+3)) { ! 390: rax_SRivPlop(); ! 391: if(rax_GRand(curvLevel+10) < 10) { ! 392: Dir=LastDir; ! 393: } else { ! 394: if(rax_GRand(curvLevel+100) > 90) { ! 395: Dir++; ! 396: } ! 397: if(rax_GRand(curvLevel+100) > 90) { ! 398: Dir--; ! 399: } ! 400: } ! 401: rax_MoveMap(Dir); ! 402: } ! 403: } ! 404: ! 405: rax_MoveMap (dir) ! 406: int dir; ! 407: { ! 408: static int DirTab[2][8] ={ { 0, 1, 1, 1, 0, -1, -1, -1}, ! 409: {-1,-1, 0, 1, 1, 1, 0, -1} }; ! 410: dir = dir & 7; ! 411: MapX += DirTab[0][dir]; ! 412: MapY += DirTab[1][dir]; ! 413: } ! 414: ! 415: ! 416: ! 417: ! 418: rax_BRivPlop() ! 419: { ! 420: static int BRMatrix[9][9] ={ ! 421: {0,0,0,3,3,3,0,0,0}, ! 422: {0,0,3,2,2,2,3,0,0}, ! 423: {0,3,2,2,2,2,2,3,0}, ! 424: {3,2,2,2,2,2,2,2,3}, ! 425: {3,2,2,2,4,2,2,2,3}, ! 426: {3,2,2,2,2,2,2,2,3}, ! 427: {0,3,2,2,2,2,2,3,0}, ! 428: {0,0,3,2,2,2,3,0,0}, ! 429: {0,0,0,3,3,3,0,0,0} }; ! 430: int x, y; ! 431: ! 432: for (x=0; x<9; x++) ! 433: for (y=0; y<9; y++) ! 434: rax_PutOnMap (BRMatrix[y][x], x, y); ! 435: } ! 436: ! 437: rax_SRivPlop() ! 438: { ! 439: static int SRMatrix[6][6] ={ ! 440: {0,0,3,3,0,0}, ! 441: {0,3,2,2,3,0}, ! 442: {3,2,2,2,2,3}, ! 443: {3,2,2,2,2,3}, ! 444: {0,3,2,2,3,0}, ! 445: {0,0,3,3,0,0} }; ! 446: int x, y; ! 447: ! 448: for (x=0; x<6; x++) ! 449: for (y=0; y<6; y++) ! 450: rax_PutOnMap (SRMatrix[y][x], x, y); ! 451: } ! 452: ! 453: rax_PutOnMap (Mchar, Xoff, Yoff) ! 454: int Mchar, Xoff, Yoff; ! 455: { ! 456: register int Xloc, Yloc, temp; ! 457: ! 458: if (Mchar == 0) return; ! 459: Xloc = MapX + Xoff; ! 460: Yloc = MapY + Yoff; ! 461: if (rax_TestBounds (Xloc, Yloc) == FALSE) return (FALSE); ! 462: if (temp = Map [Xloc][Yloc]) { ! 463: temp = temp & 1023; ! 464: if (temp == RIVER) ! 465: if (Mchar != CHANNEL) ! 466: return (FALSE); ! 467: if (temp == CHANNEL) return (FALSE); ! 468: } ! 469: Map [Xloc][Yloc] = Mchar; ! 470: } ! 471: ! 472: rax_TestBounds(x, y) ! 473: register int x, y; ! 474: { ! 475: if ((( x >= 0) && (x < WORLD_X)) && (( y >= 0) && (y < WORLD_Y))) ! 476: return (TRUE); ! 477: return (FALSE); ! 478: } ! 479: ! 480: ! 481: ! 482: rax_EGRand(limit) ! 483: int limit; ! 484: { ! 485: int x,z; ! 486: ! 487: z= rax_GRand(limit); ! 488: x= rax_GRand(limit); ! 489: if (z < x) return(z); ! 490: return(x); ! 491: } ! 492: ! 493: #define RANMASK 32767 ! 494: ! 495: rax_GRand(range) /* stupid but works */ ! 496: int range; ! 497: { ! 498: register x, newv, divisor; ! 499: ! 500: divisor = RANMASK/ (range+1); ! 501: newv = 0; ! 502: for (x=4; x!=0; x--) ! 503: newv += (GRanArray[x] = GRanArray[x-1]); ! 504: GRanArray[0] = newv; ! 505: x = (newv & RANMASK) / divisor; ! 506: if (x > range) return(range); ! 507: return(x); ! 508: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.