00001
00008 #include <config.h>
00009
00010 #include <handler.h>
00011 #include <drawing.h>
00012 #include <zakdef.h>
00013 #include <logging.h>
00014 #include <locking.h>
00015 #include <ui.h>
00016 #include <globals.h>
00017 #include <handler.h>
00018 #include <build.h>
00019 #include <disaster.h>
00020 #include <simulation.h>
00021
00022 #if defined(PALM)
00023 #include <StringMgr.h>
00024 #include <unix_stdio.h>
00025 #else
00026 #include <stdio.h>
00027 #endif
00028
00029 static void FireSpread(UInt16 x, UInt16 y) DISASTER_SECTION;
00030 static void CreateWaste(UInt16 x, UInt16 y) DISASTER_SECTION;
00031 static UInt16 GetDefenceValue(UInt16 xpos, UInt16 ypos) DISASTER_SECTION;
00032 static UInt16 ContainsDefence(UInt16 x, UInt16 y) DISASTER_SECTION;
00033 static void MonsterCheckSurrounded(UInt16 i) DISASTER_SECTION;
00034 static void CreateMeteor(UInt16 x, UInt16 y, Int16 size) DISASTER_SECTION;
00035
00036 void
00037 DoCommitmentNasties(void)
00038 {
00039 int i;
00040
00041 for (i = 0; i < 60 - getTax(); i++) {
00042 UInt32 loc = GetRandomNumber(MapMul());
00043 welem_t world = getWorld(GetRandomNumber(MapMul()));
00044 int x = loc % getMapWidth();
00045 int y = loc % getMapHeight();
00046
00047 if ((IsTransport(world)) &&
00048 (GetRandomNumber(100) > getUpkeep(ue_traffic)))
00049 Build_Destroy(x, y);
00050 if ((IsWaterPipe(world) || IsPowerLine(world) ||
00051 IsPowerWater(world)) &&
00052 (GetRandomNumber(100) > getUpkeep(ue_power)))
00053 Build_Destroy(x, y);
00054 }
00055 }
00056
00057 void
00058 DoNastyStuffTo(welem_t type, UInt16 probability, UInt8 purge)
00059 {
00060
00061 UInt32 randomTile;
00062 UInt16 i, x, y;
00063
00064 if (GetRandomNumber(probability) != 0)
00065 return;
00066
00067 LockZone(lz_world);
00068 LockZone(lz_flags);
00069 for (i = 0; i < 50; i++) {
00070 randomTile = GetRandomNumber(MapMul());
00071 if (getWorld(randomTile) == type) {
00072
00073 x = (UInt16)(randomTile % getMapWidth());
00074 y = (UInt16)(randomTile / getMapWidth());
00075 if (!purge)
00076 CreateWaste(x, y);
00077 else
00078 Build_Destroy(x, y);
00079 break;
00080 }
00081 }
00082 UnlockZone(lz_flags);
00083 UnlockZone(lz_world);
00084 }
00085
00086 void
00087 DoRandomDisaster(void)
00088 {
00089 UInt32 randomTile;
00090 Int16 i, x, y, type, random;
00091 UInt8 disaster_level;
00092
00093 disaster_level = getDisasterLevel();
00094
00095 if (disaster_level == 0)
00096 return;
00097
00098 LockZone(lz_world);
00099 LockZone(lz_flags);
00100
00101 for (i = 0; i < 100; i++) {
00102 randomTile = GetRandomNumber(MapMul());
00103 type = getWorld(randomTile);
00104 if (type != Z_DIRT &&
00105 type != Z_REALWATER &&
00106 type != Z_CRATER) {
00107 x = (Int16)(randomTile % getMapWidth());
00108 y = (Int16)(randomTile / getMapHeight());
00109
00110 random = (Int16)GetRandomNumber(1000 / disaster_level);
00111 WriteLog("Random Disaster: %d\n", (int)random);
00112 if (random < 10 && vgame.BuildCount[bc_fire] == 0) {
00113 DoSpecificDisaster(diFireOutbreak);
00114 } else if (random < 15 &&
00115 game.objects[obj_monster].active == 0) {
00116 DoSpecificDisaster(diMonster);
00117 } else if (random < 17 &&
00118 game.objects[obj_dragon].active == 0) {
00119 DoSpecificDisaster(diDragon);
00120 } else if (random < 19) {
00121 DoSpecificDisaster(diMeteor);
00122 }
00123
00124 break;
00125 }
00126 }
00127 UnlockZone(lz_flags);
00128 UnlockZone(lz_world);
00129 }
00130
00131 void
00132 DoSpecificDisaster(disaster_t disaster)
00133 {
00134 UInt32 randomTile;
00135 UInt16 x, y;
00136 Int16 ce = 0;
00137 Int16 i = 0;
00138
00139 while (i++ < 400 && ce == 0) {
00140 randomTile = GetRandomNumber(MapMul());
00141 x = (UInt16)(randomTile % getMapWidth());
00142 y = (UInt16)(randomTile / getMapHeight());
00143
00144 switch (disaster) {
00145 case diFireOutbreak:
00146 ce = BurnField(x, y, (UInt16)0);
00147 break;
00148 case diPlantExplosion:
00149 ce = 0;
00150 break;
00151 case diMonster:
00152 ce = CreateMonster(x, y);
00153 break;
00154 case diDragon:
00155 ce = CreateDragon(x, y);
00156 break;
00157 case diMeteor:
00158 ce = MeteorDisaster(x, y);
00159 break;
00160 default: break;
00161 }
00162 }
00163 if (ce) {
00164 UIDisasterNotify(disaster);
00165 Goto(x, y, goto_center);
00166 MapHasJumped();
00167 }
00168 }
00169
00170 Int16
00171 UpdateDisasters(void)
00172 {
00173
00174 UInt16 i, j;
00175 welem_t type;
00176 int retval = 0;
00177
00178 LockZone(lz_world);
00179 LockZone(lz_flags);
00180 clearScratch();
00181 for (i = 0; i < getMapHeight(); i++) {
00182 for (j = 0; j < getMapWidth(); j++) {
00183 type = getWorld(WORLDPOS(i, j));
00184
00185 if (getScratch(WORLDPOS(i, j)) == 0) {
00186 if (type == Z_FIRE2) {
00187 retval = 1;
00188 if (GetRandomNumber(5) != 0) {
00189
00190 if (GetDefenceValue(i, j) < 3) {
00191 FireSpread(i, j);
00192 }
00193 setWorldAndFlag(WORLDPOS(i, j),
00194 Z_FIRE3, 0);
00195 } else {
00196 CreateWaste(i, j);
00197 }
00198 } else if (type == Z_FIRE1) {
00199 retval = 1;
00200 setWorldAndFlag(WORLDPOS(i, j),
00201 Z_FIRE2, 0);
00202 } else if (type == Z_FIRE3) {
00203 retval = 1;
00204 CreateWaste(i, j);
00205 }
00206 }
00207 }
00208 }
00209 UnlockZone(lz_flags);
00210 UnlockZone(lz_world);
00211 return (retval);
00212 }
00213
00219 static void
00220 FireSpread(UInt16 x, UInt16 y)
00221 {
00222 if (x > 0)
00223 BurnField((UInt16)(x - 1), (UInt16)y, 0);
00224 if (x < (UInt16)(getMapWidth() - 1))
00225 BurnField((UInt16)(x + 1), (UInt16)y, 0);
00226 if (y > 0)
00227 BurnField((UInt16)x, (UInt16)(y - 1), 0);
00228 if (y < (UInt16)(getMapHeight() - 1))
00229 BurnField((UInt16)x, (UInt16)(y + 1), 0);
00230 }
00231
00232 Int16
00233 BurnField(UInt16 x, UInt16 y, Int16 forceit)
00234 {
00235 welem_t node;
00236 int rv = 0;
00237
00238 LockZone(lz_world);
00239 LockZone(lz_flags);
00240 node = getWorld(WORLDPOS(x, y));
00241 if ((forceit != 0 && node != Z_BRIDGE &&
00242 node != Z_REALWATER) ||
00243 (node != Z_FIRE1 &&
00244 node != Z_FIRE2 &&
00245 node != Z_FIRE3 &&
00246 node != Z_DIRT &&
00247 node != Z_WASTE &&
00248 node != Z_FAKEWATER &&
00249 node != Z_REALWATER &&
00250 node != Z_CRATER &&
00251 node != Z_BRIDGE &&
00252 ContainsDefence(x, y) == 0)) {
00253 Build_Destroy(x, y);
00254 setWorldAndFlag(WORLDPOS(x, y), Z_FIRE1, 1);
00255 setScratch(WORLDPOS(x, y));
00256 DrawCross(x, y, 1, 1);
00257 vgame.BuildCount[bc_fire]++;
00258 rv = 1;
00259 }
00260 UnlockZone(lz_flags);
00261 UnlockZone(lz_world);
00262 return (rv);
00263 }
00264
00265 Int16
00266 CreateMonster(UInt16 x, UInt16 y)
00267 {
00268 welem_t node;
00269 int rv = 0;
00270
00271 LockZone(lz_world);
00272 LockZone(lz_flags);
00273 node = getWorld(WORLDPOS(x, y));
00274 if (node != Z_REALWATER && node != Z_CRATER) {
00275 game.objects[obj_monster].x = x;
00276 game.objects[obj_monster].y = y;
00277 game.objects[obj_monster].dir = (UInt16)GetRandomNumber(8);
00278 game.objects[obj_monster].active = 1;
00279 DrawField(x, y);
00280 rv = 1;
00281 }
00282 UnlockZone(lz_flags);
00283 UnlockZone(lz_world);
00284 return (rv);
00285 }
00286
00287 Int16
00288 CreateDragon(UInt16 x, UInt16 y)
00289 {
00290 welem_t node;
00291 int rv = 0;
00292
00293 LockZone(lz_world);
00294 LockZone(lz_flags);
00295 node = getWorld(WORLDPOS(x, y));
00296 if (node != Z_REALWATER && node != Z_CRATER) {
00297 game.objects[obj_dragon].x = x;
00298 game.objects[obj_dragon].y = y;
00299 game.objects[obj_dragon].dir = (UInt16)GetRandomNumber(8);
00300 game.objects[obj_dragon].active = 1;
00301 DrawField(x, y);
00302 rv = 1;
00303 }
00304 UnlockZone(lz_flags);
00305 UnlockZone(lz_world);
00306 return (rv);
00307 }
00308
00313 static void
00314 MonsterCheckSurrounded(UInt16 i)
00315 {
00316 if (GetDefenceValue(game.objects[i].x, game.objects[i].y) >= 11 ||
00317 GetRandomNumber(50) < 2) {
00318 game.objects[i].active = 0;
00319 WriteLog("killing a monster\n");
00320 }
00321 }
00322
00329 static UInt16
00330 GetDefenceValue(UInt16 xpos, UInt16 ypos)
00331 {
00332
00333
00334
00335 UInt16 def =
00336 ContainsDefence(xpos + 1, ypos) +
00337 ContainsDefence(xpos + 1, ypos + 1) +
00338 ContainsDefence(xpos + 1, ypos - 1) +
00339 ContainsDefence(xpos, ypos + 1) +
00340 ContainsDefence(xpos, ypos - 1) +
00341 ContainsDefence(xpos - 1, ypos) +
00342 ContainsDefence(xpos - 1, ypos + 1) +
00343 ContainsDefence(xpos - 1, ypos + 1);
00344 return (def);
00345 }
00346
00355 static UInt16
00356 ContainsDefence(UInt16 x, UInt16 y)
00357 {
00358 int i;
00359
00360 for (i = 0; i < NUM_OF_UNITS; i++) {
00361 if (game.units[i].x == x &&
00362 game.units[i].y == y &&
00363 game.units[i].active != 0) {
00364 switch (game.units[i].type) {
00365 case DuPolice:
00366 return (2);
00367 case DuFireman:
00368 return (3);
00369 case DuMilitary:
00370 return (6);
00371 default:
00372 return (0);
00373 }
00374 }
00375 }
00376 return (0);
00377 }
00378
00379 void
00380 MoveAllObjects(void)
00381 {
00382 UInt16 i, x, y;
00383
00384 for (i = 0; i < NUM_OF_OBJECTS; i++) {
00385 if (game.objects[i].active != 0) {
00386
00387 if (i == obj_dragon) {
00388 if (!BurnField(game.objects[i].x,
00389 game.objects[i].y, 1)) {
00390 CreateWaste(game.objects[i].x,
00391 game.objects[i].y);
00392 }
00393 MonsterCheckSurrounded(i);
00394 } else if (i == obj_monster) {
00395
00396 CreateWaste(game.objects[i].x,
00397 game.objects[i].y);
00398 MonsterCheckSurrounded(i);
00399 }
00400
00401 x = game.objects[i].x;
00402 y = game.objects[i].y;
00403
00404 switch (GetRandomNumber(OBJ_CHANCE_OF_TURNING)) {
00405 case 1:
00406 game.objects[i].dir = (game.objects[i].dir+1)%8;
00407 break;
00408 case 2:
00409 game.objects[i].dir = (game.objects[i].dir+7)%8;
00410 break;
00411 default:
00412 break;
00413 }
00414
00415 switch (game.objects[i].dir) {
00416 case 0:
00417 case 1:
00418 case 7:
00419 if (game.objects[i].y > 0) {
00420 game.objects[i].y--;
00421 } else {
00422 game.objects[i].dir = 4;
00423 }
00424 break;
00425 case 3:
00426 case 4:
00427 case 5:
00428 if (game.objects[i].y <
00429 (UInt16)(getMapHeight()-1)) {
00430 game.objects[i].y++;
00431 } else {
00432 game.objects[i].dir = 0;
00433 }
00434 break;
00435 default:
00436 break;
00437 }
00438
00439 switch (game.objects[i].dir) {
00440 case 1:
00441 case 2:
00442 case 3:
00443 if (game.objects[i].x <
00444 (UInt16)(getMapWidth()-1)) {
00445 game.objects[i].x++;
00446 } else {
00447 game.objects[i].dir = 6;
00448 }
00449 break;
00450 case 5:
00451 case 6:
00452 case 7:
00453 if (game.objects[i].x > 0) {
00454 game.objects[i].x--;
00455 } else {
00456 game.objects[i].dir = 2;
00457 }
00458 break;
00459 default:
00460 break;
00461 }
00462 LockZone(lz_world);
00463 LockZone(lz_flags);
00464 DrawCross(x, y, 1, 1);
00465 DrawField(game.objects[i].x, game.objects[i].y);
00466 UnlockZone(lz_flags);
00467 UnlockZone(lz_world);
00468 }
00469 }
00470 }
00471
00472 Int16
00473 MeteorDisaster(UInt16 x, UInt16 y)
00474 {
00475 Int16 k;
00476
00477 k = (Int16)GetRandomNumber(3) + 1;
00478 CreateMeteor(x, y, k);
00479 return (1);
00480 }
00481
00488 static void
00489 CreateMeteor(UInt16 x, UInt16 y, Int16 size)
00490 {
00491 UInt16 j;
00492 UInt16 i = (Int16)(x - size) < 0 ? 0 : (UInt16)(x - size);
00493
00494 LockZone(lz_world);
00495 LockZone(lz_flags);
00496 UILockScreen();
00497 for (; i <= x + size; i++) {
00498 j = (Int16)(y - size) < 0 ? 0 : (UInt16)(y - size);
00499 for (; j <= y + size; j++) {
00500 if (i < getMapWidth() &&
00501 j < getMapHeight()) {
00502 if (GetRandomNumber(5) < 2) {
00503 if (getWorld(WORLDPOS(i, j)) !=
00504 Z_REALWATER) {
00505 CreateWaste(i, j);
00506 }
00507 } else if (GetRandomNumber(5) < 4) {
00508 if (getWorld(WORLDPOS(i, j)) !=
00509 Z_REALWATER &&
00510 getWorld(WORLDPOS(i, j)) !=
00511 Z_FAKEWATER) {
00512 BurnField(i, j, 1);
00513 }
00514 }
00515 }
00516 }
00517 }
00518 Build_Destroy(x, y);
00519 setWorldAndFlag(WORLDPOS(x, y), Z_CRATER, 0);
00520 UnlockZone(lz_flags);
00521 UnlockZone(lz_world);
00522 UIUnlockScreen();
00523 RedrawAllFields();
00524 }
00525
00531 static void
00532 CreateWaste(UInt16 x, UInt16 y)
00533 {
00534 welem_t node;
00535
00536 LockZone(lz_world);
00537 LockZone(lz_flags);
00538 node = getWorld(WORLDPOS(x, y));
00539 Build_Destroy(x, y);
00540 if (node == Z_REALWATER || IsRoadBridge(node)) {
00541 UnlockZone(lz_flags);
00542 UnlockZone(lz_world);
00543 return;
00544 }
00545 setWorldAndFlag(WORLDPOS(x, y), Z_WASTE, 0);
00546 vgame.BuildCount[bc_waste]++;
00547 DrawCross(x, y, 1, 1);
00548 UnlockZone(lz_flags);
00549 UnlockZone(lz_world);
00550 if (node == Z_COALPLANT || node == Z_NUCLEARPLANT) {
00551 UIDisasterNotify(diPlantExplosion);
00552 FireSpread(x, y);
00553 }
00554 }
00555