Main Page   Data Structures   File List   Data Fields   Globals   Related Pages  

source/disaster.c

Go to the documentation of this file.
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         /* nasty stuff means: turn it into wasteland */
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                         /* wee, let's destroy something */
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         /* for those who can't handle the game (truth?) */
00095         if (disaster_level == 0)
00096                 return;
00097 
00098         LockZone(lz_world);
00099         LockZone(lz_flags);
00100 
00101         for (i = 0; i < 100; i++) { /* 100 tries to hit a useful tile */
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                         /* TODO: should depend on difficulty */
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                         /* only one chance for disaster per turn */
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         /* return false if no disasters are found */
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                         /* already looked at this one? */
00185                         if (getScratch(WORLDPOS(i, j)) == 0) {
00186                                 if (type == Z_FIRE2) {
00187                                         retval = 1;
00188                                         if (GetRandomNumber(5) != 0) {
00189                                                 /* are there any defences */
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; /* kill the sucker */
00319                 WriteLog("killing a monster\n");
00320         }
00321 }
00322 
00329 static UInt16
00330 GetDefenceValue(UInt16 xpos, UInt16 ypos)
00331 {
00332         /* police = 2 */
00333         /* firemen = 3 */
00334         /* military = 6 */
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                         /* hmm, is this thing destructive? */
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                                 /* whoo-hoo, bingo again */
00396                                 CreateWaste(game.objects[i].x,
00397                                     game.objects[i].y);
00398                                 MonsterCheckSurrounded(i);
00399                         }
00400 
00401                         x = game.objects[i].x; /* save old position */
00402                         y = game.objects[i].y;
00403 
00404                         switch (GetRandomNumber(OBJ_CHANCE_OF_TURNING)) {
00405                         case 1: /* yes, clockwise */
00406                                 game.objects[i].dir = (game.objects[i].dir+1)%8;
00407                                 break;
00408                         case 2: /* yes, counter-clockwise */
00409                                 game.objects[i].dir = (game.objects[i].dir+7)%8;
00410                                 break;
00411                         default:
00412                                 break;
00413                         }
00414                         /* now move it a nod */
00415                         switch (game.objects[i].dir) { /* first up/down */
00416                         case 0: /* up */
00417                         case 1: /* up-right */
00418                         case 7: /* up-left */
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: /* down-right */
00426                         case 4: /* down */
00427                         case 5: /* down-left */
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) { /* then left/right */
00440                         case 1: /* up-right */
00441                         case 2: /* right */
00442                         case 3: /* down-right */
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: /* down-left */
00451                         case 6: /* left */
00452                         case 7: /* up-left */
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); /* (erase it) */
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 

Generated on Mon Aug 30 19:44:16 2004 for pocketcity by doxygen1.2.18