Main Page   Data Structures   File List   Data Fields   Globals   Related Pages  

source/simulation.c

Go to the documentation of this file.
00001 
00009 #include <handler.h>
00010 #include <drawing.h>
00011 #include <zakdef.h>
00012 #include <logging.h>
00013 #include <locking.h>
00014 #include <ui.h>
00015 #include <globals.h>
00016 #include <handler.h>
00017 #include <disaster.h>
00018 #include <simulation.h>
00019 #include <stack.h>
00020 #include <compilerpragmas.h>
00021 #include <mem_compat.h>
00022 
00024 #define SHORT_BIT       1
00025 #define OUT_BIT         2
00026 
00027 #define DONTPAINT       (unsigned char)(1U<<7)
00028 
00030 typedef struct _distrib {
00031         carryfn_t       doescarry; 
00033         problem_t       error_flag; 
00034         Int16 (*isplant)(welem_t, UInt32, selem_t);
00035         void *needSourceList; 
00036         void *unvisitedNodes; 
00037         selem_t flagToSet; 
00038         Int16 SourceLeft; 
00039         Int16 SourceTotal; 
00040         Int16 NodesTotal; 
00041         Int16 NodesSupplied; 
00042         Int16 ShortOrOut; 
00043 } distrib_t;
00044 
00045 static void DoTaxes(void);
00046 static void DoUpkeep(void);
00047 static Int16 DistributeNumberOfSquaresAround(distrib_t *distrib, UInt32 pos);
00048 
00049 static void reGradeZones(void);
00050 static void UpgradeZone(UInt32 pos);
00051 static void DowngradeZone(UInt32 pos);
00052 static Int16 DoTheRoadTrip(UInt32 startPos);
00053 static UInt32 DistributeMoveOn(UInt32 pos, dirType direction);
00054 static void DistributeUnvisited(distrib_t *distrib);
00055 
00056 static long GetZoneScore(UInt32 pos);
00057 static Int16 GetScoreFor(zoneType iamthis, welem_t what);
00058 static Int32 GetRandomZone(void);
00059 static void FindZonesForUpgrading(void);
00060 static Int16 FindScoreForZones(void);
00061 static void AddNeighbors(distrib_t *distrib, UInt32 pos);
00062 static UInt8 ExistsNextto(UInt32 pos, UInt8 dirs, welem_t what);
00063 
00064 /*
00065  * The power/water grid is updated using the following mechanism:
00066  * 1: While there are more plants to consume do:
00067  * a: While you can visit more points do:
00068  * i: If it's a source then add it's donation to the supply
00069  *        - if the 'to be powered' list has members then supply them
00070  *        - go to step (1.a.iii)
00071  * ii: if you've power then mark the point as visited, supplied & decrement
00072  *        - otherwise put it on the 'to be powered' list
00073  * iii: Find all the possible connections to visit and put them on the trip list
00074  * b: Purge the 'to be powered list'; they can't be b/c of no connections
00075  *
00076  * The WorldFlag are used as a bitfield for this, every tile has a byte:
00077  *  8765 4321
00078  *  |||| |||`- 1 = this tile is powered
00079  *  |||| ||`-- 1 = this tile is watered
00080  *  |||| |`---
00081  *  |||| `----
00082  *  |||`------
00083  *  ||`-------
00084  *  |`--------
00085  *  `--------- 1 = Scratch / Visited
00086  *
00087  *  don't use any of the free flags without asking (thanks)
00088  *  please note that the flags are saved, adding an extra 10k to the savegame
00089  *  structure. It could be collapsed during save to the number of bits
00090  *  that are occupied, but that seems like too much effort.
00091  *
00092  *  How to recreate:
00093  *        call the distribution routine... it knows how to do each type
00094  */
00095 static void DoDistribute(Int16 grid);
00096 
00101 static void
00102 Sim_Distribute_Specific(Int16 gridonly)
00103 {
00104         if (gridonly == 0) gridonly = GRID_ALL;
00105 
00106         if ((gridonly & GRID_POWER)) {
00107                 DoDistribute(GRID_POWER);
00108                 ClearUpdate(GRID_POWER);
00109         }
00110         if ((gridonly & GRID_WATER)) {
00111                 DoDistribute(GRID_WATER);
00112                 ClearUpdate(GRID_WATER);
00113         }
00114         addGraphicUpdate(gu_playarea);
00115         addGraphicUpdate(gu_desires);
00116 }
00117 
00125 static Int16
00126 IsItAPowerPlant(welem_t point, UInt32 coord __attribute__((unused)),
00127     selem_t flags __attribute__((unused)))
00128 {
00129         switch (point) {
00130         case Z_COALPLANT_START:
00131                 return (SUPPLY_POWER_PLANT);
00132         case Z_NUCLEARPLANT_START:
00133                 return (SUPPLY_NUCLEAR_PLANT);
00134         default:
00135                 return (0);
00136         }
00137 }
00138 
00149 static Int16
00150 IsItAWaterPump(welem_t point, UInt32 coord, selem_t flags)
00151 {
00152         if ((point == Z_PUMP) && (flags & POWEREDBIT) &&
00153             ExistsNextto(coord, DIR_ALL, Z_REALWATER))
00154                 return (SUPPLY_WATER_PUMP);
00155         return (0);
00156 }
00157 
00163 static void
00164 SetSupplied(distrib_t *distrib, UInt32 point)
00165 {
00166         distrib->NodesSupplied++;
00167         if (!(getWorldFlags(point) & distrib->flagToSet)) {
00168                 orWorldFlags(point, distrib->flagToSet);
00169         }
00170 }
00171 
00180 static Int16
00181 SupplyIfPlant(distrib_t *distrib, UInt32 pos, welem_t point, selem_t status)
00182 {
00183         Int16 pt;
00184         if (!(pt = distrib->isplant(point, pos, status)))
00185                 return (0);
00186         if (getScratch(pos))
00187                 return (0);
00188         SetSupplied(distrib, pos);
00189         setScratch(pos);
00190         distrib->NodesTotal++;
00191         distrib->SourceLeft += pt;
00192         distrib->SourceTotal += pt;
00193         if (!StackIsEmpty(distrib->needSourceList)) {
00194                 while (distrib->SourceLeft &&
00195                     !StackIsEmpty(distrib->needSourceList)) {
00196                         pos = (UInt32)StackPop(distrib->needSourceList);
00197                         distrib->SourceLeft--;
00198                         SetSupplied(distrib, pos);
00199                 }
00200         }
00201         return (pt);
00202 }
00203 
00208 static void
00209 DoDistribute(Int16 grid)
00210 {
00211         /* type == GRID_POWER | GRID_POWER */
00212         UInt32 i;
00213         welem_t gw;
00214         distrib_t *distrib = gMalloc(sizeof (distrib_t));
00215 
00216         distrib->SourceLeft = 0;
00217         distrib->SourceTotal = 0;
00218         distrib->NodesTotal = 0;
00219         distrib->NodesSupplied = 0;
00220         distrib->ShortOrOut = 0;
00221         distrib->needSourceList = StackNew();
00222         distrib->unvisitedNodes = StackNew();
00223 
00224         /* Step 1: Find all the powerplants and move out from there */
00225         if (grid == GRID_POWER) {
00226                 distrib->isplant = &IsItAPowerPlant;
00227                 distrib->doescarry = &CarryPower;
00228                 distrib->flagToSet = POWEREDBIT;
00229                 distrib->error_flag = peFineOnPower;
00230         } else {
00231                 distrib->isplant = &IsItAWaterPump;
00232                 distrib->doescarry = &CarryWater;
00233                 distrib->flagToSet = WATEREDBIT;
00234                 distrib->error_flag = peFineOnWater;
00235         }
00236 
00237         LockZone(lz_world); /* this lock locks for ALL power subs */
00238         LockZone(lz_flags);
00239         for (i = 0; i < MapMul(); i++) {
00240                 if (distrib->doescarry(getWorld(i)))
00241                         andWorldFlags(i,
00242                             (selem_t)~(distrib->flagToSet |
00243                                 SCRATCHBIT | PAINTEDBIT));
00244         }
00245         for (i = 0; i < MapMul(); i++) {
00246                 gw = getWorld(i);
00247                 if (!getScratch(i)) {
00248                         if (SupplyIfPlant(distrib, i, gw, getWorldFlags(i))) {
00249                                 AddNeighbors(distrib, i);
00250                                 DistributeUnvisited(distrib);
00251                                 /* unpowered points are removed */
00252                                 StackDoEmpty(distrib->needSourceList);
00253                                 WriteLog("Grid#%d Supplied Nodes: %d/%d "
00254                                     "SrcRemain: %d/%d\n", (int)grid,
00255                                     (int)distrib->NodesSupplied,
00256                                     (int)distrib->NodesTotal,
00257                                     (int)distrib->SourceLeft,
00258                                     (int)distrib->SourceTotal);
00259                                 if (distrib->SourceLeft < 25) {
00260                                         distrib->ShortOrOut |= SHORT_BIT;
00261                                         if (distrib->SourceLeft == 0)
00262                                                 distrib->ShortOrOut |= OUT_BIT;
00263                                 }
00264                                 distrib->SourceLeft = 0;
00265                                 distrib->SourceTotal = 0;
00266                                 distrib->NodesSupplied = 0;
00267                                 distrib->NodesTotal = 0;
00268                         }
00269                 }
00270         }
00271         UnlockZone(lz_flags);
00272         UnlockZone(lz_world);
00273         StackDelete(distrib->needSourceList);
00274         StackDelete(distrib->unvisitedNodes);
00275         if (distrib->ShortOrOut & OUT_BIT) {
00276                 UIProblemNotify(distrib->error_flag + 2);
00277         } else if (distrib->ShortOrOut & SHORT_BIT) {
00278                 UIProblemNotify(distrib->error_flag + 1);
00279         } else {
00280                 UIProblemNotify(distrib->error_flag);
00281         }
00282         gFree(distrib);
00283 }
00284 
00288 static void
00289 DistributeUnvisited(distrib_t *distrib)
00290 {
00291         UInt32 pos;
00292         UInt8 flag;
00293 
00294         while (!StackIsEmpty(distrib->unvisitedNodes)) {
00295                 pos = (UInt32)StackPop(distrib->unvisitedNodes);
00296                 flag = getWorldFlags(pos);
00297                 if (SupplyIfPlant(distrib, pos, getWorld(pos), flag)) {
00298                         goto nextneighbor;
00299                 }
00300 
00301                 if (distrib->SourceLeft && ((flag & distrib->flagToSet) == 0)) {
00302                         /*
00303                          * if this field hasn't been powered,
00304                          * we need to "use" some power to move further along
00305                          */
00306                         distrib->SourceLeft--;
00307                 }
00308 
00309                 /* do we have more power left? */
00310                 if (distrib->SourceLeft <= 0)
00311                         StackPush(distrib->needSourceList, (Int32)pos);
00312                 else
00313                         SetSupplied(distrib, pos);
00314 
00315                 /* now, set the flags to indicate we've been here */
00316                 setScratch(pos);
00317 
00318 nextneighbor:
00319                 /* find the possible ways we can move on from here */
00320                 AddNeighbors(distrib, pos);
00321         };
00322 }
00323 
00329 static void
00330 AddNeighbors(distrib_t *distrib, UInt32 pos)
00331 {
00332         Int16 cross = DistributeNumberOfSquaresAround(distrib, pos);
00333 
00334         /* if there's "no way out", return */
00335         if ((cross & 0x0f) == 0)
00336                 return;
00337 
00338         distrib->NodesTotal += cross & 0x0f;
00339 
00340         if ((cross & 0x10) == 0x10) {
00341                 StackPush(distrib->unvisitedNodes,
00342                     (Int32)(pos - getMapWidth()));
00343         }
00344         if ((cross & 0x20) == 0x20) {
00345                 StackPush(distrib->unvisitedNodes,
00346                     (Int32)(pos + 1));
00347         }
00348         if ((cross & 0x40) == 0x40) {
00349                 StackPush(distrib->unvisitedNodes,
00350                     (Int32)(pos + getMapWidth()));
00351         }
00352         if ((cross & 0x80) == 0x80) {
00353                 StackPush(distrib->unvisitedNodes, (Int32)(pos - 1));
00354         }
00355 }
00356 
00357 /*
00358  * \brief check that the node carries something.
00359  *
00360  * Note that this function is used internally in the power distribution
00361  * routine. Therefore it will return false for tiles we've already been at,
00362  * to avoid backtracking any nodes we've already encountered.
00363  * \param pos location of item.
00364  */
00365 static Int16
00366 Carries(Int16 (*doescarry)(welem_t), UInt32 pos)
00367 {
00368         if (getScratch(pos))
00369                 return (0);
00370         return (doescarry(getWorld(pos)));
00371 }
00372 
00387 static Int16
00388 DistributeNumberOfSquaresAround(distrib_t *distrib, UInt32 pos)
00389 {
00390         Int16 retval = 0;
00391         Int8 number = 0;
00392         Int16 (*carries)(welem_t) = distrib->doescarry;
00393 
00394         if (Carries(carries, DistributeMoveOn(pos, dtUp))) {
00395                 retval |= 0x10;
00396                 number++;
00397         }
00398         if (Carries(carries, DistributeMoveOn(pos, dtRight))) {
00399                 retval |= 0x20;
00400                 number++;
00401         }
00402         if (Carries(carries, DistributeMoveOn(pos, dtDown))) {
00403                 retval |= 0x40;
00404                 number++;
00405         }
00406         if (Carries(carries, DistributeMoveOn(pos, dtLeft))) {
00407                 retval |= 0x80;
00408                 number++;
00409         }
00410 
00411         retval |= number;
00412 
00413         return (retval);
00414 }
00415 
00426 static UInt32
00427 DistributeMoveOn(UInt32 pos, dirType direction)
00428 {
00429         switch (direction) {
00430         case dtUp:
00431                 if (pos < getMapWidth())
00432                         return (pos);
00433                 pos -= getMapWidth();
00434                 break;
00435         case dtRight:
00436                 if (((pos%getMapWidth()) + 1) >= getMapWidth())
00437                         return (pos);
00438                 pos++;
00439                 break;
00440         case dtDown:
00441                 if ((pos+getMapWidth()) >= MapMul())
00442                         return (pos);
00443                 pos += getMapWidth();
00444                 break;
00445         case dtLeft:
00446                 if (pos % getMapWidth() == 0)
00447                         return (pos);
00448                 pos--;
00449                 break;
00450         }
00451         return (pos);
00452 }
00453 
00461 static UInt8
00462 ExistsNextto(UInt32 pos, UInt8 dirs, welem_t what)
00463 {
00464         UInt8 rv = 0;
00465 
00466         if ((dirs & DIR_UP) && (pos > getMapWidth()) &&
00467             (what == getWorld(pos - getMapWidth())))
00468                 rv |= DIR_UP;
00469         if ((dirs & DIR_DOWN) && (pos < (UInt32)(MapMul() - getMapWidth())) &&
00470             (what == getWorld(pos + getMapWidth())))
00471                 rv |= DIR_DOWN;
00472         if ((dirs & DIR_LEFT) && (pos % getMapWidth()) && 
00473             (what == getWorld(pos - 1)))
00474                 rv |= DIR_LEFT;
00475         if ((dirs & DIR_RIGHT) && (((pos % getMapWidth()) + 1) < getMapWidth())
00476                 && (what == getWorld(pos + 1)))
00477                 rv |= DIR_RIGHT;
00478         return (rv);
00479 }
00480 
00481 
00482 /* Zones upgrade/downgrade */
00483 
00485 typedef struct {
00486         Int32 pos; 
00487         Int32 score; 
00488 } ZoneScore;
00489 
00491 static ZoneScore *ran_zone;
00492 
00494 static Int32 at_pos;
00495 
00497 static UInt16 counter;
00498 
00500 static UInt16 max_list;
00501 
00508 static void
00509 FindZonesForUpgrading(void)
00510 {
00511         UInt16 i;
00512         Int32 randomZone;
00513 
00514         if (ran_zone == NULL) {
00515                 max_list = (getMapWidth() < getMapHeight() ? getMapHeight() :
00516                     (UInt16)(getMapWidth())) * 3;
00517                 ran_zone = (ZoneScore *)gCalloc(max_list, sizeof (ZoneScore));
00518         }
00519 
00520         at_pos = 0;
00521 
00522         /* find some random zones */
00523         for (i = 0; i < max_list; i++) {
00524                 ran_zone[at_pos].pos = -1;
00525                 randomZone = GetRandomZone();
00526                 if (randomZone != -1) { /* -1 means we didn't find a zone */
00527                         ran_zone[at_pos++].pos = randomZone;
00528                 }
00529         }
00530 }
00531 
00532 
00542 Int16
00543 FindScoreForZones(void)
00544 {
00545         Int32 i;
00546         Int32 score;
00547 
00548         counter += 20;
00549 
00550         LockZone(lz_world);
00551         LockZone(lz_flags);
00552 
00553         for (i = counter - 20; i < (Int16)counter; i++) {
00554                 if (i >= at_pos) {
00555                         counter = 0;
00556                         UnlockZone(lz_world);
00557                         return (0);
00558                 }
00559                 score = GetZoneScore((UInt32)ran_zone[i].pos);
00560                 if (score != -1) {
00561                         ran_zone[i].score = score;
00562                 } else {
00563                         ran_zone[i].score = -1;
00564                         WriteLog("Instadowngrade (%d,%d)\n",
00565                             (int)(ran_zone[i].pos % getMapWidth()),
00566                             (int)(ran_zone[i].pos / getMapWidth()));
00567                         DowngradeZone((UInt32)ran_zone[i].pos);
00568                         ran_zone[i].pos = -1;
00569                 }
00570         }
00571         UnlockZone(lz_flags);
00572         UnlockZone(lz_world);
00573         return (1); /* there's still more zones that need a score. */
00574 }
00575 
00582 static Int16
00583 zoneCmpFn(void *a, void *b, Int32 other __attribute__((unused)))
00584 {
00585         ZoneScore *zs1 = (ZoneScore *)a;
00586         ZoneScore *zs2 = (ZoneScore *)b;
00587 
00588         if (zs1->score > zs2->score)
00589                 return (1);
00590         if (zs1->score < zs2->score)
00591                 return (-1);
00592         return (0);
00593 }
00594 
00601 void
00602 reGradeZones(void)
00603 {
00604         Int32 i;
00605         Int16 downCount = 10;
00606         Int16 upCount = 12;
00607 
00608         QSort(ran_zone, at_pos, sizeof (ZoneScore), zoneCmpFn);
00609         WriteLog("Used: %ld\n", at_pos);
00610         /* upgrade the upCount best */
00611         for (i = at_pos - 1; i >= 0 && i > (at_pos - upCount); i--) {
00612                 if (ran_zone[i].pos == -1) continue;
00613 
00614                 /* upgrade him/her/it/whatever */
00615                 UpgradeZone((UInt32)ran_zone[i].pos);
00616                 WriteLog("Upgrade (%d, %d)(%ld)\n",
00617                     (int)(ran_zone[i].pos % getMapWidth()),
00618                     (int)(ran_zone[i].pos / getMapWidth()),
00619                     ran_zone[i].score);
00620                 ran_zone[i].pos = -1;
00621         }
00622 
00623         /* downgrade the downCount worst */
00624         for (i = 0; i < downCount && i < (at_pos - upCount); i++) {
00625                 /* downgrade him/her/it/whatever */
00626                 if (ran_zone[i].pos == -1) continue;
00627                 if (ran_zone[i].score > 0) continue;
00628                 DowngradeZone((UInt32)ran_zone[i].pos);
00629                 WriteLog("Downgrade (%d, %d)(%ld)\n",
00630                     (int)(ran_zone[i].pos % getMapWidth()),
00631                     (int)(ran_zone[i].pos / getMapWidth()),
00632                     ran_zone[i].score);
00633                 ran_zone[i].pos = -1;
00634         }
00635         at_pos = 0;
00636 }
00637 
00642 static void
00643 DowngradeZone(UInt32 pos)
00644 {
00645         welem_t type;
00646         welem_t ntype;
00647         UInt16 xpos = (UInt16)(pos % getMapWidth());
00648         UInt16 ypos = (UInt16)(pos / getMapWidth());
00649 
00650         LockZone(lz_world);
00651         LockZone(lz_flags);
00652         type = getWorld(pos);
00653         ntype = type;
00654         if (IsCommercial(type) && type != Z_COMMERCIAL_SLUM) {
00655                 ntype = (type == Z_COMMERCIAL_MIN) ?
00656                     Z_COMMERCIAL_SLUM : (welem_t)(type - 1);
00657                 vgame.BuildCount[bc_value_commercial]--;
00658                 if (ntype == Z_COMMERCIAL_SLUM)
00659                         vgame.BuildCount[bc_count_commercial]--;
00660         } else if (IsResidential(type) && type != Z_RESIDENTIAL_SLUM) {
00661                 ntype = (type == Z_RESIDENTIAL_MIN) ?
00662                     Z_RESIDENTIAL_SLUM : (welem_t)(type - 1);
00663                 vgame.BuildCount[bc_value_residential]--;
00664                 if (ntype == Z_RESIDENTIAL_SLUM)
00665                         vgame.BuildCount[bc_count_residential]--;
00666         } else if (IsIndustrial(type) && type != Z_INDUSTRIAL_SLUM) {
00667                 ntype = (type == Z_INDUSTRIAL_MIN) ?
00668                     Z_INDUSTRIAL_SLUM : (welem_t)(type - 1);
00669                 vgame.BuildCount[bc_value_industrial]--;
00670                 if (ntype == Z_INDUSTRIAL_SLUM)
00671                         vgame.BuildCount[bc_count_industrial]--;
00672         }
00673         if (ntype != type) {
00674                 setWorld(pos, ntype);
00675 
00676                 DrawFieldWithoutInit(xpos, ypos);
00677         }
00678 
00679         UnlockZone(lz_flags);
00680         UnlockZone(lz_world);
00681 }
00682 
00683 /*
00684  * \brief Upgrade the zone at the position
00685  * \param pos the location on the map to upgrade
00686  */
00687 static void
00688 UpgradeZone(UInt32 pos)
00689 {
00690         welem_t type, ntype;
00691         UInt16 xpos = (UInt16)(pos % getMapWidth());
00692         UInt16 ypos = (UInt16)(pos / getMapWidth());
00693 
00694         LockZone(lz_world);
00695         LockZone(lz_flags);
00696         type = getWorld(pos);
00697         ntype = type;
00698         if (IsCommercial(type) && type < Z_COMMERCIAL_MAX) {
00699                 ntype = (type == Z_COMMERCIAL_SLUM) ?
00700                     Z_COMMERCIAL_MIN : (welem_t)(type + 1);
00701                 vgame.BuildCount[bc_value_commercial]++;
00702                 if (type == Z_COMMERCIAL_SLUM)
00703                         vgame.BuildCount[bc_count_commercial]++;
00704         } else if (IsResidential(type) && type < Z_RESIDENTIAL_MAX) {
00705                 ntype = (type == Z_RESIDENTIAL_SLUM) ?
00706                     Z_RESIDENTIAL_MIN : (welem_t)(type + 1);
00707                 vgame.BuildCount[bc_value_residential]++;
00708                 if (type == Z_RESIDENTIAL_SLUM)
00709                         vgame.BuildCount[bc_count_residential]++;
00710         } else if (IsIndustrial(type) && type < Z_INDUSTRIAL_MAX) {
00711                 ntype = (type == Z_INDUSTRIAL_SLUM) ?
00712                     Z_INDUSTRIAL_MIN : (welem_t)(type + 1);
00713                 vgame.BuildCount[bc_value_industrial]++;
00714                 if (type == Z_RESIDENTIAL_SLUM)
00715                         vgame.BuildCount[bc_count_industrial]++;
00716         }
00717         if (ntype != type) {
00718                 setWorld(pos, ntype);
00719 
00720                 DrawFieldWithoutInit(xpos, ypos);
00721         }
00722 
00723         UnlockZone(lz_flags);
00724         UnlockZone(lz_world);
00725 }
00726 
00731 static Int16
00732 DoTheRoadTrip(UInt32 startPos __attribute__((unused)))
00733 {
00734         return (1); /* for now */
00735 }
00736 
00744 long
00745 GetZoneScore(UInt32 pos)
00746 {
00747         long score = -1; /* Will downgrade to begin with */
00748         Int16 x = (Int16)(pos % getMapWidth());
00749         Int16 y = (Int16)(pos / getMapWidth());
00750         int ax, ay;
00751         int maxx, maxy;
00752         int bRoad = 0;
00753         zoneType type = ztWhat;
00754         UInt8 zone;
00755 
00756         LockZone(lz_world);
00757         LockZone(lz_flags);
00758         zone = getWorld(pos);
00759         type = (IsZone(zone, ztCommercial) ? ztCommercial :
00760             (IsZone(zone, ztResidential) ? ztResidential : ztIndustrial));
00761 
00762         if (((getWorldFlags(pos) & POWEREDBIT) == 0) ||
00763             ((getWorldFlags(pos) & WATEREDBIT) == 0)) {
00764                 /* whoops, no power or no water */
00765                 WriteLog("No Power || Water\n");
00766                 goto unlock_ret;
00767         }
00768 
00769         if (IsSlum(zone)) {
00770                 score = 50;
00771                 goto unlock_ret;
00772         }
00773 
00774         if ((type == ztIndustrial) || (type == ztCommercial))  {
00775                 /*
00776                  * see if there's actually enough residential population
00777                  * to support a new zone of ind or com
00778                  */
00779 
00780                 Int32 availPop = (Int32)((vgame.BuildCount[bc_value_residential]*25)
00781                     - (vgame.BuildCount[bc_value_commercial]*25
00782                     + vgame.BuildCount[bc_value_industrial]*25));
00783                 /* pop is too low */
00784                 if (availPop <= 0) {
00785                         WriteLog("Pop too low to promote ind || comm\n");
00786                         goto unlock_ret;
00787                 }
00788         } else if (type == ztResidential) {
00789                 /*
00790                  * the population can't skyrocket all at once, we need a cap
00791                  * somewhere - note, this should be fine tuned somehow
00792                  * A factor might be the number of (road/train/airplane)
00793                  * connections to the surrounding world - this would
00794                  * bring more potential residents into our little city
00795                  */
00796                 Int32 availPop = (Int32)(((getMonthsElapsed() * getMonthsElapsed()) /
00797                     35) + 30 - vgame.BuildCount[bc_value_residential]);
00798                 /* hmm - need more children */
00799                 if (availPop <= 0) {
00800                         WriteLog("No People\n");
00801                         goto unlock_ret;
00802                 }
00803         }
00804 
00805         if (type == ztCommercial) {
00806                 /*
00807                  * and what is a store without something to sell? We need
00808                  * enough industrial zones before commercial zones kick in.
00809                  */
00810 
00811                 Int32 availGoods =(Int32)((vgame.BuildCount[bc_value_industrial] /
00812                     3 * 2) - (vgame.BuildCount[bc_value_commercial]));
00813                 /* darn, nothing to sell here */
00814                 if (availGoods <= 0) {
00815                         WriteLog("No Goods\n");
00816                         goto unlock_ret;
00817                 }
00818         }
00819 
00820         /* take a look around at the enviroment */
00821         maxx = (4 + x < getMapWidth()) ? 4 + x : getMapWidth() - 1;
00822         maxy = (4 + y < getMapHeight()) ? 4 + y : getMapHeight() - 1;
00823         ax = (x - 3 > 0) ? x - 3 : 0;
00824         while (ax < maxx) {
00825                 ay = (y - 3 > 0) ? y - 3 : 0;
00826                 while (ay < maxy) {
00827                         score += GetScoreFor(type, getWorld(WORLDPOS(ax, ay)));
00828                         if (IsRoad(getWorld(WORLDPOS(ax, ay))) && bRoad == 0) {
00829                                 /*
00830                                  * can we reach all kinds of
00831                                  * zones from here?
00832                                  */
00833                                 bRoad = DoTheRoadTrip(WORLDPOS(ax, ay));
00834                                 if (!bRoad) {
00835                                         score = -1;
00836                                         goto unlock_ret;
00837                                 }
00838                         }
00839                         ay++;
00840                 }
00841                 ax++;
00842         }
00843 
00844 unlock_ret:
00845         UnlockZone(lz_flags);
00846         UnlockZone(lz_world);
00847         return (score);
00848 }
00849 
00856 Int16
00857 GetScoreFor(zoneType iamthis, welem_t what)
00858 {
00859         if (IsZone(what, ztCommercial)) {
00860                 return (iamthis == ztCommercial) ? 1 :
00861                     ((iamthis == ztResidential) ? 50 :
00862                     ((iamthis == ztIndustrial) ? 50 : 50));
00863         }
00864         if (IsZone(what, ztResidential)) {
00865                 return (iamthis == ztCommercial) ? 50 :
00866                     ((iamthis == ztResidential) ? 1 :
00867                     ((iamthis == ztIndustrial) ? 50 : 50));
00868         }
00869         if (IsZone(what, ztIndustrial)) {
00870                 return (iamthis == ztCommercial) ? (-25) :
00871                     ((iamthis == ztResidential) ? (-75) :
00872                     ((iamthis == ztIndustrial) ? 1 : (-50)));
00873         }
00874         if (IsRoad(what)) {
00875                 return (iamthis == ztCommercial) ? 75 :
00876                     ((iamthis == ztResidential) ? 50 :
00877                     ((iamthis == ztIndustrial) ? 75 : 66));
00878         }
00879         if (IsCoalPlant(what)) {
00880                 return (iamthis == ztCommercial) ? (-75) :
00881                         ((iamthis == ztResidential) ? (-100) :
00882                         ((iamthis == ztIndustrial) ? 30 : (-75)));
00883         }
00884         if (IsNukePlant(what)) {
00885                 return (iamthis == ztCommercial) ? (-150) :
00886                         ((iamthis == ztResidential) ? (-200) :
00887                         ((iamthis == ztIndustrial) ? 15 : (-175)));
00888         }
00889         if (IsRealTree(what)) {
00890                 return (iamthis == ztCommercial) ? 50 :
00891                         ((iamthis == ztResidential) ? 85 :
00892                         ((iamthis == ztIndustrial)? 25 : 50));
00893         }
00894         if (IsFakeTree(what)) {
00895                 return (iamthis == ztCommercial) ? 25 :
00896                         ((iamthis == ztResidential) ? 42 :
00897                         ((iamthis == ztIndustrial)? 12 : 25));
00898         }
00899         if (IsRealWater(what)) {
00900                 return (iamthis == ztCommercial) ? 175 :
00901                         ((iamthis == ztResidential) ? 550 :
00902                         ((iamthis == ztIndustrial) ? 95 : 250));
00903         }
00904         if (IsFakeWater(what)) {
00905                 return (iamthis == ztCommercial) ? 80 :
00906                         ((iamthis == ztResidential) ? 80 :
00907                         ((iamthis == ztIndustrial) ? 45 : 25));
00908         }
00909         return (0);
00910 }
00911 
00918 static Int32
00919 GetRandomZone(void)
00920 {
00921         UInt32 pos = 0;
00922         UInt16 i;
00923         UInt8 type;
00924 
00925         LockZone(lz_world);
00926         LockZone(lz_flags);
00927         for (i = 0; i < 5; i++) { /* try five times to hit a valid zone */
00928                 pos = GetRandomNumber(MapMul());
00929                 type = getWorld(pos);
00930                 if (IsGrowable(type)) {
00931                         UnlockZone(lz_world);
00932                         return ((Int32)pos);
00933                 }
00934         }
00935 
00936         UnlockZone(lz_flags);
00937         UnlockZone(lz_world);
00938         return (-1);
00939 }
00940 
00942 static const struct countCosts {
00943         BuildCount      count; 
00944         UInt32  cost;   
00945 } countCosts[] = {
00946         { bc_value_residential, INCOME_RESIDENTIAL },
00947         { bc_value_commercial, INCOME_COMMERCIAL },
00948         { bc_value_industrial, INCOME_INDUSTRIAL },
00949         { bc_count_roads, UPKEEP_ROAD },
00950         { bc_count_trees, 0 },
00951         { bc_water, 0 },
00952         { bc_powerlines, UPKEEP_POWERLINE },
00953         { bc_coalplants, UPKEEP_POWERPLANT },
00954         { bc_nuclearplants, UPKEEP_NUCLEARPLANT },
00955         { bc_waste, 0 },
00956         { bc_fire, 0 },
00957         { bc_fire_stations, UPKEEP_FIRE_STATIONS },
00958         { bc_police_departments, UPKEEP_POLICE_STATIONS },
00959         { bc_military_bases, UPKEEP_MILITARY_BASES },
00960         { bc_waterpipes, 0 },
00961         { bc_waterpumps, 0 }
00962 };
00963 
00964 #define CCSIZE  (sizeof (countCosts) / sizeof (countCosts[0]))
00965 
00971 static Int32
00972 costIt(BuildCode item)
00973 {
00974         UInt16 i;
00975         for (i = 0; i < CCSIZE; i++)
00976                 if (countCosts[i].count == item)
00977                         return ((Int32)(vgame.BuildCount[item] * countCosts[i].cost));
00978         WriteLog("Fell off the end of costIt here (%d)\n", item);
00979         return (0);
00980 }
00981 
00982 Int32
00983 BudgetGetNumber(BudgetNumber type)
00984 {
00985         Int32 ret = 0;
00986         switch (type) {
00987         case bnResidential:
00988                 ret = (Int32)costIt(bc_value_residential) * getTax() / 100;
00989                 break;
00990         case bnCommercial:
00991                 ret = (Int32)costIt(bc_value_commercial) * getTax() / 100;
00992                 break;
00993         case bnIndustrial:
00994                 ret = (Int32)costIt(bc_value_industrial) * getTax() / 100;
00995                 break;
00996         case bnIncome:
00997                 ret = ((costIt(bc_value_residential) + 
00998                     costIt(bc_value_commercial) +
00999                     costIt(bc_value_industrial)) * getTax()) / 100;
01000                 break;
01001         case bnTraffic:
01002                 ret = (Int32)(costIt(bc_count_roads) *
01003                     getUpkeep(ue_traffic)) / 100;
01004                 break;
01005         case bnPower:
01006                 ret = (Int32)((costIt(bc_powerlines) +
01007                     costIt(bc_nuclearplants) + costIt(bc_coalplants)) *
01008                     getUpkeep(ue_power)) / 100;
01009                 break;
01010         case bnDefence:
01011                 ret = (Int32)((costIt(bc_fire_stations) +
01012                     costIt(bc_police_departments) +
01013                     costIt(bc_military_bases)) *
01014                     getUpkeep(ue_defense)) / 100;
01015                 break;
01016         case bnCurrentBalance:
01017                 ret = getCredits();
01018                 break;
01019         case bnChange:
01020                 ret = (Int32)BudgetGetNumber(bnIncome)
01021                         - BudgetGetNumber(bnTraffic)
01022                         - BudgetGetNumber(bnPower)
01023                         - BudgetGetNumber(bnDefence);
01024                 break;
01025         case bnNextMonth:
01026                 ret = (Int32)BudgetGetNumber(bnCurrentBalance) +
01027                         BudgetGetNumber(bnChange);
01028                 break;
01029         }
01030         return (ret);
01031 }
01032 
01036 void
01037 DoTaxes(void)
01038 {
01039         incCredits(BudgetGetNumber(bnIncome));
01040 }
01041 
01045 void
01046 DoUpkeep(void)
01047 {
01048         UInt32 upkeep;
01049 
01050         upkeep = (UInt32)(BudgetGetNumber(bnTraffic) +
01051             BudgetGetNumber(bnPower) + BudgetGetNumber(bnDefence));
01052 
01053         WriteLog("Upkeep: %lu\n", (unsigned long)upkeep);
01054 
01055         DoCommitmentNasties();
01056         if (upkeep <= (UInt32)getCredits()) {
01057                 decCredits((Int32)upkeep);
01058                 return;
01059         }
01060         WriteLog("*** Negative Cashflow\n");
01061         setCredits(0);
01062 
01063         /* roads */
01064         DoNastyStuffTo(Z_ROAD, 1, 1);
01065         DoNastyStuffTo(Z_POWERLINE, 5, 1);
01066         DoNastyStuffTo(Z_COALPLANT, 15, 0);
01067         DoNastyStuffTo(Z_NUCLEARPLANT, 50, 0);
01068         DoNastyStuffTo(Z_FIRESTATION, 10, 1);
01069         DoNastyStuffTo(Z_POLICEDEPT, 12, 1);
01070         DoNastyStuffTo(Z_ARMYBASE, 35, 0);
01071 }
01072 
01076 Int16
01077 Sim_DoPhase(Int16 nPhase)
01078 {
01079         switch (nPhase) {
01080         case 1:
01081                 if (NeedsUpdate(GRID_POWER)) {
01082                         WriteLog("Simulation phase 1 - power grid\n");
01083                         Sim_Distribute_Specific(GRID_POWER);
01084                         ClearUpdate(GRID_POWER);
01085                 }
01086                 nPhase = 2;
01087                 break;
01088         case 2:
01089                 if (NeedsUpdate(GRID_WATER)) {
01090                         WriteLog("Simulation phase 2 - water grid\n");
01091                         Sim_Distribute_Specific(GRID_WATER);
01092                         ClearUpdate(GRID_WATER);
01093                 }
01094                 nPhase = 3;
01095                 break;
01096         case 3:
01097                 WriteLog("Simulation phase 3 - Find zones for upgrading\n");
01098                 FindZonesForUpgrading();
01099                 nPhase = 4;
01100                 /* this can't be below */
01101                 WriteLog("Simulation phase 4 - Find score for zones\n");
01102                 break;
01103         case 4:
01104                 if (FindScoreForZones() == 0)
01105                         nPhase = 5;
01106                 break;
01107         case 5:
01108                 WriteLog("Simulation phase 5 - Regrade Zones\n");
01109                 reGradeZones();
01110                 addGraphicUpdate(gu_desires);
01111                 nPhase = 6;
01112                 break;
01113         case 6:
01114                 WriteLog("Simulation phase 6 - Update disasters\n");
01115                 /* UpdateDisasters(); */
01116                 DoRandomDisaster();
01117                 addGraphicUpdate(gu_desires);
01118                 nPhase = 7;
01119                 break;
01120         case 7:
01121                 WriteLog("Simulation phase 7 - Economics\n");
01122                 DoTaxes();
01123                 incrementTimeElapsed(4);
01124                 nPhase = 0;
01125                 addGraphicUpdate(gu_credits);
01126                 addGraphicUpdate(gu_population);
01127                 addGraphicUpdate(gu_desires);
01128                 UICheckMoney();
01129                 DoUpkeep();
01130                 break;
01131         }
01132 
01133         return (nPhase);
01134 }
01135 
01136 void
01137 UpdateVolatiles(void)
01138 {
01139         UInt32 p;
01140 
01141         LockZone(lz_world);
01142         LockZone(lz_flags);
01143 
01144         for (p = 0; p < MapMul(); p++) {
01145                 UInt8 elt = getWorld(p);
01146 
01147                 /* Gahd this is terrible. I need to fix it. */
01148                 if (IsCommercial(elt)) {
01149                         vgame.BuildCount[bc_count_commercial]++;
01150                         vgame.BuildCount[bc_value_commercial] += ZoneValue(elt);
01151                 }
01152                 if (IsResidential(elt)) {
01153                         vgame.BuildCount[bc_count_residential]++;
01154                         vgame.BuildCount[bc_value_residential] +=
01155                             ZoneValue(elt);
01156                 }
01157                 if (IsIndustrial(elt)) {
01158                         vgame.BuildCount[bc_count_industrial]++;
01159                         vgame.BuildCount[bc_value_industrial] += ZoneValue(elt);
01160                 }
01161                 if (IsRoad(elt)) {
01162                         vgame.BuildCount[bc_count_roads]++;
01163                         vgame.BuildCount[bc_value_roads] += ZoneValue(elt);
01164                 }
01165                 if (IsFakeTree(elt)) {
01166                         vgame.BuildCount[bc_count_trees]++;
01167                 }
01168                 if (IsFakeWater(elt)) {
01169                         vgame.BuildCount[bc_water]++;
01170                 }
01171                 if (IsRoadPower(elt)) {
01172                         vgame.BuildCount[bc_powerlines]++;
01173                         vgame.BuildCount[bc_count_roads]++;
01174                         vgame.BuildCount[bc_value_roads] += ZoneValue(elt);
01175                 }
01176                 if (IsPowerLine(elt))
01177                         vgame.BuildCount[bc_powerlines]++;
01178                 if (elt == Z_COALPLANT)
01179                         vgame.BuildCount[bc_coalplants]++;
01180                 if (elt == Z_NUCLEARPLANT)
01181                         vgame.BuildCount[bc_nuclearplants]++;
01182                 if (elt == Z_WASTE) vgame.BuildCount[bc_waste]++;
01183                 if (elt >= Z_FIRE1 && elt <= Z_FIRE3)
01184                         vgame.BuildCount[bc_fire]++;
01185                 if (elt == Z_FIRESTATION)
01186                         vgame.BuildCount[bc_fire_stations]++;
01187                 if (elt == Z_POLICEDEPT)
01188                         vgame.BuildCount[bc_police_departments]++;
01189                 if (elt == Z_ARMYBASE)
01190                         vgame.BuildCount[bc_military_bases]++;
01191                 if (IsWaterPipe(elt))
01192                         vgame.BuildCount[bc_waterpipes]++;
01193                 if (IsRoadPipe(elt)) {
01194                         vgame.BuildCount[bc_waterpipes]++;
01195                         vgame.BuildCount[bc_count_roads]++;
01196                         vgame.BuildCount[bc_value_roads] += ZoneValue(elt);
01197                 }
01198                 if (IsPowerWater(elt)) {
01199                         vgame.BuildCount[bc_waterpipes]++;
01200                         vgame.BuildCount[bc_powerlines]++;
01201                 }
01202                 if (IsPump(elt))
01203                         vgame.BuildCount[bc_waterpumps]++;
01204         }
01205         UnlockZone(lz_flags);
01206         UnlockZone(lz_world);
01207 }
01208 
01220 static UInt16
01221 ShuffleIndividualStatistic(UInt16 *ary, UInt16 load)
01222 {
01223         int atItem = STAT_ENTRIES - 1;
01224         UInt16 newvalue;
01225 
01226         newvalue = ary[atItem];
01227         for (atItem = STAT_ENTRIES - 1; atItem > 0; atItem--) {
01228                 ary[atItem] = ary[atItem-1];
01229         }
01230         ary[0] = load;
01231         return (newvalue);
01232 }
01233 
01234 void
01235 UpdateCounters(void)
01236 {
01237         /* cashflow: */
01238         if (vgame.prior_credit == 0) {
01239                 vgame.prior_credit = (UInt32)getCredits();
01240         }
01241         /*
01242          * Don't worry about the overflow on the last bit, the upper 16 bits
01243          * of this value will be stripped automatically. What we end up doing
01244          * is adding even more to this (possibly negative) value.
01245          */
01246         vgame.BuildCount[bc_cashflow] = (Int16)((OFFSET_FOR_CASHFLOW_BC -
01247             vgame.prior_credit) + getCredits());
01248         /* Update the prior_credit field */
01249         vgame.prior_credit = (UInt32)getCredits();
01266 }
01267 
01273 void
01274 RecordStatistics(void)
01275 {
01276         StatisticItem item;
01277         stat_item *stat;
01278         BuildCount offset;
01279         UInt16 stat_value;
01280         UInt32 tmpval;
01281         
01282         for (item = st_cashflow; item < st_tail; item++) {
01283                 offset = statvalues[item].offset;
01284                 stat_value = (UInt16)vgame.BuildCount[offset];
01285                 stat = getStatistics(offset);
01286                 
01287                 tmpval = (UInt32)stat->last_ten[0] * 3 + stat_value;
01288                 tmpval >>= 2;
01289                 /* overflow */
01290                 if (tmpval > (UInt16)MAX_UINT16) {
01291                         stat->last_ten[0] = MAX_UINT16;
01292                 } else {
01293                         stat->last_ten[0] = (UInt16)tmpval;
01294                 }
01295                 /* XXX: fixme! */
01296                 /* shuffle the statistics every month */
01297                 if ((getMonthsElapsed() & 3) == 3) {
01298                         (void)ShuffleIndividualStatistic(
01299                             &stat->last_ten[0], stat_value);
01300                 }
01301                 if ((getMonthsElapsed() & (3*12)) == (3 * 12)) {
01302                 }
01303         }
01304 }
01305 
01306 UInt32
01307 getPopulation(void)
01308 {
01309         return ((vgame.BuildCount[bc_value_residential] +
01310                 (vgame.BuildCount[bc_value_commercial] * 8) +
01311                 (vgame.BuildCount[bc_value_industrial] * 8)) * 20);
01312 }
01313 
01317 Int16
01318 CarryPower(welem_t x)
01319 {
01320         return 
01321         /* ((IsPump(x) || IsPowerLine(x) || IsPowerWater(x) ||
01322             IsSlum(x) || IsCoalPlant(x) || IsNuclearPlant(x) ||
01323             IsFireStation(x) || IsPoliceDept(x) || IsArmyBase(x) ||
01324             IsCommercial(x) || IsResidential(x) || IsIndustrial(x) ||
01325             IsPowerRoad(x) || IsRailPower(x)) ? 1 : 0); */
01326             ((IsPump(x)) ||
01327             ((x >= Z_POWERLINE) && (x <= Z_POWERROAD_PVER)) ||
01328             (IsRailPower(x)) ? 1 : 0);
01329 }
01330 
01338 Int16
01339 CarryWater(welem_t x)
01340 {
01341         return (IsPump(x) || IsWaterPipe(x) ||
01342             ((x >= Z_POWERWATER_START) && (x <= Z_INDUSTRIAL_MAX)) ||
01343             IsRoadPipe(x) || IsRailPipe(x) ? 1 : 0);
01344 }
01345 
01346 Int16
01347 IsPowerLine(welem_t x)
01348 {
01349         return ((((x >= Z_POWERLINE_START) && (x <= Z_POWERLINE_END))) ? 1 : 0);
01350 }
01351 
01352 Int16
01353 IsRoad(welem_t x)
01354 {
01355         return (((x >= Z_ROAD_START) && (x <= Z_ROAD_END)) ? 1 : 0);
01356 }
01357 
01358 Int16
01359 IsRoadBridge(welem_t x)
01360 {
01361         return (((x >= Z_BRIDGE_START) && (x <= Z_BRIDGE_END)) ? 1 : 0);
01362 }
01363  
01364 Int16
01365 IsWaterPipe(welem_t x)
01366 {
01367         return (((x >= Z_PIPE_START) && (x <= Z_PIPE_END)) ? 1 : 0);
01368 }
01369 
01370 Int16
01371 ZoneValue(welem_t x)
01372 {
01373         if ((x >= Z_COMMERCIAL_SLUM) && (x <= Z_INDUSTRIAL_SLUM))
01374                 return (0);
01375         if ((x >= Z_COMMERCIAL_MIN) && (x <= Z_INDUSTRIAL_MAX)) {
01376                 return (1 + ((x - Z_COMMERCIAL_MIN) % 10));
01377         }
01378         if (IsRoad(x))
01379                 return ((x - Z_ROAD_START) + 1);
01380         if (IsRail(x))
01381                 return ((x - Z_RAIL_START) + 1);
01382         else
01383                 return (0);
01384 }
01385  
01386 Int16
01387 IsRoadPipe(welem_t x)
01388 {
01389         return (((x >= Z_PIPEROAD_START) && (x <= Z_PIPEROAD_END)) ? 1 : 0);
01390 }
01391 
01392 Int16
01393 IsRoadPower(welem_t x)
01394 {
01395         return (((x >= Z_POWERROAD_START) && (x <= Z_POWERROAD_END)) ? 1 : 0);
01396 }
01397 
01398 Int16
01399 IsPowerWater(welem_t x)
01400 {
01401         return (((x >= Z_POWERWATER_START) && (x <= Z_POWERWATER_END)) ? 1 : 0);
01402 }
01403 
01404 Int16
01405 IsZone(welem_t x, zoneType nType)
01406 {
01407         /* Slum handling - the slums & idents are in the same order */
01408         if (x == nType)
01409                 return (1);
01410         nType -= Z_COMMERCIAL_SLUM;
01411         if ((x >= (welem_t)(nType * 10 + Z_COMMERCIAL_MIN)) && 
01412             (x <= (welem_t)(nType * 10 + Z_COMMERCIAL_MAX)))
01413                 return (1);
01414         return (0);
01415 }
01416 
01417 Int16
01418 IsTransport(welem_t x)
01419 {
01420         return (IsRoad(x) || IsRoadPipe(x) || IsRoadPower(x) ||
01421             IsRoadBridge(x) ||
01422             IsRail(x) || IsRailPipe(x) || IsRailPower(x) || IsRailTunnel(x) ||
01423             IsRailOvRoad(x));
01424 }
01425 
01426 Int16
01427 IsRoadOrBridge(welem_t x)
01428 {
01429         return (IsRoad(x) || IsRoadBridge(x));
01430 }
01431 
01432 Int16
01433 IsRail(welem_t x)
01434 {
01435         return (((x >= Z_RAIL_START) && (x <= Z_RAIL_END)) ? 1 : 0);
01436 }
01437 
01438 Int16
01439 IsRailPower(welem_t x)
01440 {
01441         return (((x >= Z_RAILPOWER_START) && (x <= Z_RAILPOWER_END)) ? 1 : 0);
01442 }
01443 
01444 Int16
01445 IsRailPipe(welem_t x)
01446 {
01447         return (((x >= Z_RAILPIPE_START) && (x <= Z_RAILPIPE_END)) ? 1 : 0);
01448 }
01449 
01450 Int16
01451 IsRailTunnel(welem_t x)
01452 {
01453         return (((x >= Z_RAILTUNNEL_START) && (x <= Z_RAILTUNNEL_END)) ? 1 : 0);
01454 }
01455 
01456 Int16
01457 IsRailOrTunnel(welem_t x)
01458 {
01459         return (IsRail(x) || IsRailTunnel(x));
01460 }
01461 
01462 Int16
01463 IsRailOvRoad(welem_t x)
01464 {
01465         return (((x >= Z_RAILOVROAD_START) && (x <= Z_RAILOVROAD_END)) ? 1 : 0);
01466 }
01467 
01468 Int16
01469 IsOccupied(welem_t x)
01470 {
01471         return (!((x <= Z_REALWATER) || (x > Z_ENDMARKER)));
01472 }
01473 
01474 UInt8
01475 CheckNextTo(UInt32 pos, UInt8 dirs, Int16 (*checkfn)(welem_t))
01476 {
01477         UInt8 rv = 0;
01478 
01479         if ((dirs & DIR_UP) && (pos > getMapWidth()) &&
01480             checkfn(getWorld((UInt32)(pos - getMapWidth()))))
01481                 rv |= DIR_UP;
01482         if ((dirs & DIR_DOWN) && ((Int32)pos < (MapMul() - getMapWidth())) &&
01483             checkfn(getWorld((UInt32)(pos + getMapWidth()))))
01484                 rv |= DIR_DOWN;
01485         if ((dirs & DIR_LEFT) && (pos % getMapWidth()) && 
01486             checkfn(getWorld((UInt32)(pos - 1))))
01487                 rv |= DIR_LEFT;
01488         if ((dirs & DIR_RIGHT) && (((pos % getMapWidth()) + 1) < getMapWidth())
01489                 && checkfn(getWorld((UInt32)(pos + 1))))
01490                 rv |= DIR_RIGHT;
01491         return (rv);
01492 }
01493 
01494 UInt8
01495 CheckNextTo1(UInt32 pos, UInt8 dirs, carryfnarg_t checkfn, void *cfarg)
01496 {
01497         UInt8 rv = 0;
01498 
01499         if ((dirs & DIR_UP) && (pos > getMapWidth()) &&
01500             checkfn(getWorld((UInt32)(pos - getMapWidth())), cfarg))
01501                 rv |= DIR_UP;
01502         if ((dirs & DIR_DOWN) && ((Int32)pos < (MapMul() - getMapWidth())) &&
01503             checkfn(getWorld((UInt32)(pos + getMapWidth())), cfarg))
01504                 rv |= DIR_DOWN;
01505         if ((dirs & DIR_LEFT) && (pos % getMapWidth()) && 
01506             checkfn(getWorld((UInt32)(pos - 1)), cfarg))
01507                 rv |= DIR_LEFT;
01508         if ((dirs & DIR_RIGHT) && (((pos % getMapWidth()) + 1) < getMapWidth())
01509                 && checkfn(getWorld((UInt32)(pos + 1)), cfarg))
01510                 rv |= DIR_RIGHT;
01511         return (rv);
01512 }
01513 
01514 void
01515 endSimulation(void)
01516 {
01517         if (ran_zone != NULL) {
01518                 gFree(ran_zone);
01519                 ran_zone = NULL;
01520         }
01521 }

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