mirror of
https://github.com/tonytins/citylimits
synced 2025-06-25 01:14:44 -04:00
Initial source commit
This commit is contained in:
commit
5f7cefb98e
1794 changed files with 40615 additions and 0 deletions
173
core/allocate.cpp
Normal file
173
core/allocate.cpp
Normal file
|
@ -0,0 +1,173 @@
|
|||
/* allocate.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file allocate.cpp
|
||||
* @brief Implementation of map array initialization and destruction
|
||||
* in Micropolis.
|
||||
*
|
||||
* This source file contains functions for initializing and destroying
|
||||
* map arrays in the Micropolis game engine. It includes the
|
||||
* allocation of memory for various map-related data structures such
|
||||
* as the main city map, history data, and various density maps. The
|
||||
* functions handle the setup of necessary resources when the game
|
||||
* starts and ensure proper cleanup of these resources upon
|
||||
* termination, maintaining efficient memory management throughout the
|
||||
* lifecycle of the game.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** Allocate and initialize arrays for the maps */
|
||||
void Micropolis::initMapArrays()
|
||||
{
|
||||
short i;
|
||||
|
||||
if (!mapBase) {
|
||||
mapBase = (unsigned short *)newPtr(
|
||||
sizeof(unsigned short) *
|
||||
WORLD_W * WORLD_H);
|
||||
}
|
||||
|
||||
for (i = 0; i < WORLD_W; i++) {
|
||||
map[i] = (unsigned short *)(mapBase + (i * WORLD_H));
|
||||
}
|
||||
|
||||
resHist = (short *)newPtr(HISTORY_LENGTH);
|
||||
comHist = (short *)newPtr(HISTORY_LENGTH);
|
||||
indHist = (short *)newPtr(HISTORY_LENGTH);
|
||||
moneyHist = (short *)newPtr(HISTORY_LENGTH);
|
||||
pollutionHist = (short *)newPtr(HISTORY_LENGTH);
|
||||
crimeHist = (short *)newPtr(HISTORY_LENGTH);
|
||||
miscHist = (short *)newPtr(MISC_HISTORY_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
/** Free all map arrays */
|
||||
void Micropolis::destroyMapArrays()
|
||||
{
|
||||
|
||||
if (mapBase != NULL) {
|
||||
freePtr(mapBase);
|
||||
mapBase = NULL;
|
||||
}
|
||||
|
||||
memset(map, 0, sizeof(short *) * WORLD_W);
|
||||
|
||||
populationDensityMap.clear();
|
||||
trafficDensityMap.clear();
|
||||
pollutionDensityMap.clear();
|
||||
landValueMap.clear();
|
||||
crimeRateMap.clear();
|
||||
|
||||
tempMap1.clear();
|
||||
tempMap2.clear();
|
||||
tempMap3.clear();
|
||||
|
||||
terrainDensityMap.clear();
|
||||
|
||||
if (resHist != NULL) {
|
||||
freePtr(resHist);
|
||||
resHist = NULL;
|
||||
}
|
||||
|
||||
if (comHist != NULL) {
|
||||
freePtr(comHist);
|
||||
comHist = NULL;
|
||||
}
|
||||
|
||||
if (indHist != NULL) {
|
||||
freePtr(indHist);
|
||||
indHist = NULL;
|
||||
}
|
||||
|
||||
if (moneyHist != NULL) {
|
||||
freePtr(moneyHist);
|
||||
moneyHist = NULL;
|
||||
}
|
||||
|
||||
if (pollutionHist != NULL) {
|
||||
freePtr(pollutionHist);
|
||||
pollutionHist = NULL;
|
||||
}
|
||||
|
||||
if (crimeHist != NULL) {
|
||||
freePtr(crimeHist);
|
||||
crimeHist = NULL;
|
||||
}
|
||||
|
||||
if (miscHist != NULL) {
|
||||
freePtr(miscHist);
|
||||
miscHist = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
244
core/animate.cpp
Normal file
244
core/animate.cpp
Normal file
|
@ -0,0 +1,244 @@
|
|||
/* animate.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file animate.cpp
|
||||
* @brief Animation routines for the Micropolis game engine.
|
||||
*
|
||||
* This file contains functions responsible for animating various
|
||||
* tiles within the Micropolis game. It includes a mapping of each
|
||||
* tile to its next animated state, and functions that iterate through
|
||||
* the game world's tiles to update their animation states. The
|
||||
* animation process is crucial for enhancing the game's visual appeal
|
||||
* and dynamic feel by animating elements like water, fire, and smoke.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Tile animation table. For each tile, it states the next tile to display.
|
||||
*
|
||||
* @bug Tile 620 points to 852. That should be tile 621.
|
||||
*
|
||||
* @todo Generate the table below from the animation sequences file
|
||||
* doc/AnimationSequences.txt and the doc/genAnimationTable.py
|
||||
* program
|
||||
*/
|
||||
static short animatedTiles[TILE_COUNT] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55,
|
||||
/* Fire */
|
||||
57, 58, 59, 60, 61, 62, 63, 56,
|
||||
/* No Traffic */
|
||||
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
|
||||
/* Light Traffic */
|
||||
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
|
||||
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
|
||||
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
|
||||
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
|
||||
/* Heavy Traffic */
|
||||
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
|
||||
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
|
||||
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
|
||||
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
|
||||
/* Wires & Rails */
|
||||
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
|
||||
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
|
||||
/* Residential */
|
||||
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
|
||||
256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271,
|
||||
272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287,
|
||||
288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303,
|
||||
304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319,
|
||||
320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335,
|
||||
336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351,
|
||||
352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367,
|
||||
368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383,
|
||||
384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399,
|
||||
400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415,
|
||||
416, 417, 418, 419, 420, 421, 422,
|
||||
/* Commercial */
|
||||
423, 424, 425, 426, 427, 428, 429, 430, 431,
|
||||
432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447,
|
||||
448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463,
|
||||
464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479,
|
||||
480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495,
|
||||
496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511,
|
||||
512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527,
|
||||
528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543,
|
||||
544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559,
|
||||
560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575,
|
||||
576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591,
|
||||
592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607,
|
||||
608, 609, 610, 611,
|
||||
/* Industrial */
|
||||
612, 613, 614, 615, 616, 617, 618, 619, 620, 852, 622, 623,
|
||||
624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639,
|
||||
640, 884, 642, 643, 888, 645, 646, 647, 648, 892, 896, 651, 652, 653, 654, 655,
|
||||
656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671,
|
||||
672, 673, 674, 675, 900, 904, 678, 679, 680, 681, 682, 683, 684, 685, 908, 687,
|
||||
688, 912, 690, 691, 692,
|
||||
/* SeaPort */
|
||||
693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703,
|
||||
704, 705, 706, 707, 708,
|
||||
/* AirPort */
|
||||
// 832 was previous value of 711, to start radar
|
||||
// animation, but now we break the link and the
|
||||
// simulator switches the tiles.
|
||||
709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719,
|
||||
720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735,
|
||||
736, 737, 738, 739, 740, 741, 742, 743, 744,
|
||||
/* Coal power */
|
||||
745, 746, 916, 920, 749, 750, 924,
|
||||
928, 753, 754, 755, 756, 757, 758, 759, 760,
|
||||
/* Fire Dept */
|
||||
761, 762, 763, 764, 765, 766, 767,
|
||||
768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778,
|
||||
/* Stadium */
|
||||
779, 780, 781, 782, 783,
|
||||
784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794,
|
||||
/* Stadium Anims */
|
||||
795, 796, 797, 798, 799,
|
||||
800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810,
|
||||
/* Nuclear Power */
|
||||
811, 812, 813, 814, 815,
|
||||
816, 817, 818, 819, 952, 821, 822, 823, 824, 825, 826,
|
||||
/* Power out + Bridges */
|
||||
827, 828, 829, 830, 831,
|
||||
/* Radar dish */
|
||||
833, 834, 835, 836, 837, 838, 839, 832,
|
||||
/* Fountain / Flag */
|
||||
841, 842, 843, 840, 845, 846, 847, 848,
|
||||
849, 850, 851, 844, 853, 854, 855, 856, 857, 858, 859, 852,
|
||||
/* zone destruct & rubblize */
|
||||
861, 862, 863, 864,
|
||||
865, 866, 867, 867,
|
||||
/* totally unsure */
|
||||
868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879,
|
||||
880, 881, 882, 883,
|
||||
/* Smoke stacks */
|
||||
885, 886, 887, 884, 889, 890, 891, 888, 893, 894, 895, 892,
|
||||
897, 898, 899, 896, 901, 902, 903, 900, 905, 906, 907, 904, 909, 910, 911, 908,
|
||||
913, 914, 915, 912, 917, 918, 919, 916, 921, 922, 923, 920, 925, 926, 927, 924,
|
||||
929, 930, 931, 928,
|
||||
/* Stadium Playfield */
|
||||
933, 934, 935, 936, 937, 938, 939, 932, 941, 942, 943, 944,
|
||||
945, 946, 947, 940,
|
||||
/* Bridge up chars */
|
||||
948, 949, 950, 951,
|
||||
/* Nuclear swirl */
|
||||
953, 954, 955, 952,
|
||||
/* Churches */
|
||||
956, 957, 958, 959,
|
||||
960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975,
|
||||
976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991,
|
||||
992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007,
|
||||
1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023,
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/* comefrom: moveWorld doEditWindow scoreDoer doMapInFront graphDoer */
|
||||
void Micropolis::animateTiles()
|
||||
{
|
||||
unsigned short tilevalue, tileflags;
|
||||
unsigned short *tMapPtr;
|
||||
int i;
|
||||
|
||||
/* Animate whole world */
|
||||
tMapPtr = (unsigned short *)&(map[0][0]);
|
||||
|
||||
for (i = WORLD_W * WORLD_H; i > 0; i--) {
|
||||
tilevalue = (*tMapPtr);
|
||||
if (tilevalue & ANIMBIT) {
|
||||
tileflags = tilevalue & ALLBITS;
|
||||
tilevalue &= LOMASK;
|
||||
tilevalue = animatedTiles[tilevalue];
|
||||
tilevalue |= tileflags;
|
||||
(*tMapPtr) = tilevalue;
|
||||
}
|
||||
tMapPtr++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Micropolis::getNextAnimatedTile(int index)
|
||||
{
|
||||
if ((index < 0) || (index >= TILE_COUNT)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return animatedTiles[index];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
352
core/budget.cpp
Normal file
352
core/budget.cpp
Normal file
|
@ -0,0 +1,352 @@
|
|||
/* budget.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file budget.cpp
|
||||
* @brief Budget management functions for the Micropolis game engine.
|
||||
*
|
||||
* This file encompasses the functions responsible for managing the
|
||||
* game's budget. It includes initializing funding levels, handling
|
||||
* budget windows, updating budget allocations based on available
|
||||
* funds, and setting city tax rates. The budget management is vital
|
||||
* for the simulation aspect of the game, influencing the city's
|
||||
* development and the player's strategy.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void Micropolis::initFundingLevel()
|
||||
{
|
||||
firePercent = 1.0;
|
||||
fireValue = 0;
|
||||
policePercent = 1.0;
|
||||
policeValue = 0;
|
||||
roadPercent = 1.0;
|
||||
roadValue = 0;
|
||||
mustDrawBudget = 1;
|
||||
}
|
||||
|
||||
/** Game decided to show the budget window */
|
||||
void Micropolis::doBudget()
|
||||
{
|
||||
doBudgetNow(false);
|
||||
}
|
||||
|
||||
|
||||
/** User queried the budget window */
|
||||
void Micropolis::doBudgetFromMenu()
|
||||
{
|
||||
doBudgetNow(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle budget window.
|
||||
* @param fromMenu User requested the budget window.
|
||||
* @todo Simplify this code. Instead of this nested mess, make a sequence of
|
||||
* assigning funds to road, fire, and police.
|
||||
*/
|
||||
void Micropolis::doBudgetNow(bool fromMenu)
|
||||
{
|
||||
Quad fireInt = (int)(fireFund * firePercent);
|
||||
Quad policeInt = (int)(policeFund * policePercent);
|
||||
Quad roadInt = (int)(roadFund * roadPercent);
|
||||
|
||||
Quad total = fireInt + policeInt + roadInt;
|
||||
|
||||
Quad yumDuckets = taxFund + totalFunds;
|
||||
|
||||
if (yumDuckets > total) {
|
||||
|
||||
// Enough yumDuckets to fully fund fire, police and road.
|
||||
|
||||
fireValue = fireInt;
|
||||
policeValue = policeInt;
|
||||
roadValue = roadInt;
|
||||
|
||||
/// @todo Why are we not subtracting from yumDuckets what we
|
||||
/// spend, like the code below is doing?
|
||||
|
||||
} else if (total > 0) {
|
||||
|
||||
assert(yumDuckets <= total);
|
||||
|
||||
// Not enough yumDuckets to fund everything.
|
||||
// First spend on roads, then on fire, then on police.
|
||||
|
||||
if (yumDuckets > roadInt) {
|
||||
|
||||
// Enough yumDuckets to fully fund roads.
|
||||
|
||||
roadValue = roadInt;
|
||||
yumDuckets -= roadInt;
|
||||
|
||||
if (yumDuckets > fireInt) {
|
||||
|
||||
// Enough yumDuckets to fully fund fire.
|
||||
|
||||
fireValue = fireInt;
|
||||
yumDuckets -= fireInt;
|
||||
|
||||
if (yumDuckets > policeInt) {
|
||||
|
||||
// Enough yumDuckets to fully fund police.
|
||||
// Hey what are we doing here? Should never get here.
|
||||
// We tested for yumDuckets > total above
|
||||
// (where total = fireInt + policeInt + roadInt),
|
||||
// so this should never happen.
|
||||
|
||||
policeValue = policeInt;
|
||||
yumDuckets -= policeInt;
|
||||
|
||||
} else {
|
||||
|
||||
// Fuly funded roads and fire.
|
||||
// Partially fund police.
|
||||
|
||||
policeValue = yumDuckets;
|
||||
|
||||
if (yumDuckets > 0) {
|
||||
|
||||
// Scale back police percentage to available cash.
|
||||
|
||||
policePercent = ((float)yumDuckets) / ((float)policeFund);
|
||||
|
||||
} else {
|
||||
|
||||
// Exactly nothing left, so scale back police percentage to zero.
|
||||
|
||||
policePercent = 0.0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Not enough yumDuckets to fully fund fire.
|
||||
|
||||
fireValue = yumDuckets;
|
||||
|
||||
// No police after funding roads and fire.
|
||||
|
||||
policeValue = 0;
|
||||
policePercent = 0.0;
|
||||
|
||||
if (yumDuckets > 0) {
|
||||
|
||||
// Scale back fire percentage to available cash.
|
||||
|
||||
firePercent =
|
||||
((float)yumDuckets) / ((float)fireFund);
|
||||
|
||||
} else {
|
||||
|
||||
// Exactly nothing left, so scale back fire percentage to zero.
|
||||
|
||||
firePercent = 0.0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Not enough yumDuckets to fully fund roads.
|
||||
|
||||
roadValue = yumDuckets;
|
||||
|
||||
// No fire or police after funding roads.
|
||||
|
||||
fireValue = 0;
|
||||
policeValue = 0;
|
||||
firePercent = 0.0;
|
||||
policePercent = 0.0;
|
||||
|
||||
if (yumDuckets > 0) {
|
||||
|
||||
// Scale back road percentage to available cash.
|
||||
|
||||
roadPercent = ((float)yumDuckets) / ((float)roadFund);
|
||||
|
||||
} else {
|
||||
|
||||
// Exactly nothing left, so scale back road percentage to zero.
|
||||
|
||||
roadPercent = 0.0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
assert(yumDuckets == total);
|
||||
assert(total == 0);
|
||||
|
||||
// Zero funding, so no values but full percentages.
|
||||
|
||||
fireValue = 0;
|
||||
policeValue = 0;
|
||||
roadValue = 0;
|
||||
firePercent = 1.0;
|
||||
policePercent = 1.0;
|
||||
roadPercent = 1.0;
|
||||
|
||||
}
|
||||
|
||||
noMoney:
|
||||
|
||||
if (!autoBudget || fromMenu) {
|
||||
|
||||
// FIXME: This might have blocked on the Mac, but now it's asynchronous.
|
||||
// Make sure the stuff we do just afterwards is intended to be done immediately
|
||||
// and is not supposed to wait until after the budget dialog is dismissed.
|
||||
// Otherwise don't do it after this and arrange for it to happen when the
|
||||
// modal budget dialog is dismissed.
|
||||
showBudgetWindowAndStartWaiting();
|
||||
|
||||
// FIXME: Only do this AFTER the budget window is accepted.
|
||||
|
||||
if (!fromMenu) {
|
||||
|
||||
fireSpend = fireValue;
|
||||
policeSpend = policeValue;
|
||||
roadSpend = roadValue;
|
||||
|
||||
total = fireSpend + policeSpend + roadSpend;
|
||||
|
||||
Quad moreDough = (Quad)(taxFund - total);
|
||||
spend(-moreDough);
|
||||
|
||||
}
|
||||
|
||||
mustDrawBudget = 1;
|
||||
doUpdateHeads();
|
||||
|
||||
} else { /* autoBudget & !fromMenu */
|
||||
|
||||
// FIXME: Not sure yumDuckets is the right value here. It gets the
|
||||
// amount spent subtracted from it above in some cases, but not if
|
||||
// we are fully funded. I think we want to use the original value
|
||||
// of yumDuckets, which is taxFund + totalFunds.
|
||||
|
||||
if (yumDuckets > total) {
|
||||
|
||||
Quad moreDough = (Quad)(taxFund - total);
|
||||
spend(-moreDough);
|
||||
|
||||
fireSpend = fireFund;
|
||||
policeSpend = policeFund;
|
||||
roadSpend = roadFund;
|
||||
|
||||
mustDrawBudget = 1;
|
||||
doUpdateHeads();
|
||||
|
||||
} else {
|
||||
|
||||
setAutoBudget(false); /* force autobudget */
|
||||
mustUpdateOptions = true;
|
||||
sendMessage(MESSAGE_NO_MONEY, NOWHERE, NOWHERE, false, true);
|
||||
goto noMoney;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::updateBudget()
|
||||
{
|
||||
/// The scripting language should pull these raw values out
|
||||
/// and format them, instead of the callback pushing them out.
|
||||
|
||||
if (mustDrawBudget) {
|
||||
callback->updateBudget(this, callbackVal);
|
||||
mustDrawBudget = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::showBudgetWindowAndStartWaiting()
|
||||
{
|
||||
callback->showBudgetAndWait(this, callbackVal);
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::setCityTax(short tax)
|
||||
{
|
||||
cityTax = tax;
|
||||
callback->updateTaxRate(this, callbackVal, cityTax);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
302
core/callback.cpp
Normal file
302
core/callback.cpp
Normal file
|
@ -0,0 +1,302 @@
|
|||
/* callback.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file callback.cpp
|
||||
* @brief Implementation of the Callback interface for Micropolis game
|
||||
* engine.
|
||||
*
|
||||
* This file provides the implementation of the Callback class defined
|
||||
* in callback.h. It includes a series of methods that are called by
|
||||
* the Micropolis game engine to interact with the user interface.
|
||||
* These methods include functionalities like logging actions,
|
||||
* updating game states, and responding to user actions. The use of
|
||||
* EM_ASM macros indicates direct interaction with JavaScript, typical
|
||||
* in a web environment using Emscripten.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
#include <emscripten.h>
|
||||
|
||||
|
||||
ConsoleCallback::~ConsoleCallback() {
|
||||
EM_ASM_({
|
||||
console.log('~ConsoleCallback destructor');
|
||||
});
|
||||
}
|
||||
|
||||
void ConsoleCallback::autoGoto(Micropolis *micropolis, emscripten::val callbackVal, int x, int y, std::string message) {
|
||||
EM_ASM_({
|
||||
console.log('autoGoto:', 'x:', $0, 'y:', $1, 'message:', UTF8ToString($2));
|
||||
}, x, y, message.c_str());
|
||||
}
|
||||
|
||||
void ConsoleCallback::didGenerateMap(Micropolis *micropolis, emscripten::val callbackVal, int seed) {
|
||||
EM_ASM_({
|
||||
console.log('didGenerateMap:', 'seed:', $0);
|
||||
}, seed);
|
||||
}
|
||||
|
||||
void ConsoleCallback::didLoadCity(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) {
|
||||
EM_ASM_({
|
||||
console.log('didLoadCity:', 'filename:', UTF8ToString($0));
|
||||
}, filename.c_str());
|
||||
}
|
||||
|
||||
void ConsoleCallback::didLoadScenario(Micropolis *micropolis, emscripten::val callbackVal, std::string name, std::string fname) {
|
||||
EM_ASM_({
|
||||
console.log('didLoadScenario:', 'name:', UTF8ToString($0), 'fname:', UTF8ToString($1));
|
||||
}, name.c_str(), fname.c_str());
|
||||
}
|
||||
|
||||
void ConsoleCallback::didLoseGame(Micropolis *micropolis, emscripten::val callbackVal) {
|
||||
EM_ASM_({
|
||||
console.log('didLoseGame');
|
||||
});
|
||||
}
|
||||
|
||||
void ConsoleCallback::didSaveCity(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) {
|
||||
EM_ASM_({
|
||||
console.log('didSaveCity:', 'filename:', UTF8ToString($0));
|
||||
}, filename.c_str());
|
||||
}
|
||||
|
||||
void ConsoleCallback::didTool(Micropolis *micropolis, emscripten::val callbackVal, std::string name, int x, int y) {
|
||||
EM_ASM_({
|
||||
console.log('didTool:', 'name:', UTF8ToString($0), 'x:', $1, 'y:', $2);
|
||||
}, name.c_str(), x, y);
|
||||
}
|
||||
|
||||
void ConsoleCallback::didWinGame(Micropolis *micropolis, emscripten::val callbackVal) {
|
||||
EM_ASM_({
|
||||
console.log('didWinGame');
|
||||
});
|
||||
}
|
||||
|
||||
void ConsoleCallback::didntLoadCity(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) {
|
||||
EM_ASM_({
|
||||
console.log('didntLoadCity:', 'filename:', UTF8ToString($0));
|
||||
}, filename.c_str());
|
||||
}
|
||||
|
||||
void ConsoleCallback::didntSaveCity(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) {
|
||||
EM_ASM_({
|
||||
console.log('didntSaveCity:', 'filename:', UTF8ToString($0));
|
||||
}, filename.c_str());
|
||||
}
|
||||
|
||||
void ConsoleCallback::makeSound(Micropolis *micropolis, emscripten::val callbackVal, std::string channel, std::string sound, int x, int y) {
|
||||
EM_ASM_({
|
||||
console.log('makeSound:', 'channel:', UTF8ToString($0), 'sound:', UTF8ToString($1), 'x:', $2, 'y:', $3);
|
||||
}, channel.c_str(), sound.c_str(), x, y);
|
||||
}
|
||||
|
||||
void ConsoleCallback::newGame(Micropolis *micropolis, emscripten::val callbackVal) {
|
||||
EM_ASM_({
|
||||
console.log('newGame');
|
||||
});
|
||||
}
|
||||
|
||||
void ConsoleCallback::saveCityAs(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) {
|
||||
EM_ASM_({
|
||||
console.log('saveCityAs:', 'filename:', UTF8ToString($0));
|
||||
}, filename.c_str());
|
||||
}
|
||||
|
||||
void ConsoleCallback::sendMessage(Micropolis *micropolis, emscripten::val callbackVal, int messageIndex, int x, int y, bool picture, bool important) {
|
||||
EM_ASM_({
|
||||
console.log('sendMessage:', 'messageIndex:', $0, 'x:', $1, 'y:', $2, 'picture:', $3, 'important:', $4);
|
||||
}, messageIndex, x, y, picture, important);
|
||||
}
|
||||
|
||||
void ConsoleCallback::showBudgetAndWait(Micropolis *micropolis, emscripten::val callbackVal) {
|
||||
EM_ASM_({
|
||||
console.log('showBudgetAndWait');
|
||||
});
|
||||
}
|
||||
|
||||
void ConsoleCallback::showZoneStatus(Micropolis *micropolis, emscripten::val callbackVal, int tileCategoryIndex, int populationDensityIndex, int landValueIndex, int crimeRateIndex, int pollutionIndex, int growthRateIndex, int x, int y) {
|
||||
EM_ASM_({
|
||||
console.log('showZoneStatus:', 'tileCategoryIndex:', $0, 'populationDensityIndex:', $1, 'landValueIndex:', $2, 'crimeRateIndex:', $3, 'pollutionIndex:', $4, 'growthRateIndex:', $5, 'x:', $6, 'y:', $7);
|
||||
}, tileCategoryIndex, populationDensityIndex, landValueIndex, crimeRateIndex, pollutionIndex, growthRateIndex, x, y);
|
||||
}
|
||||
|
||||
void ConsoleCallback::simulateRobots(Micropolis *micropolis, emscripten::val callbackVal) {
|
||||
EM_ASM_({
|
||||
console.log('simulateRobots');
|
||||
});
|
||||
}
|
||||
|
||||
void ConsoleCallback::simulateChurch(Micropolis *micropolis, emscripten::val callbackVal, int posX, int posY, int churchNumber) {
|
||||
EM_ASM_({
|
||||
console.log('simulateChurch:', 'posX:', $0, 'posY:', $1, 'churchNumber:', $2);
|
||||
}, posX, posY, churchNumber);
|
||||
}
|
||||
|
||||
void ConsoleCallback::startEarthquake(Micropolis *micropolis, emscripten::val callbackVal, int strength) {
|
||||
EM_ASM_({
|
||||
console.log('startEarthquake:', 'strength:', $0);
|
||||
}, strength);
|
||||
}
|
||||
|
||||
void ConsoleCallback::startGame(Micropolis *micropolis, emscripten::val callbackVal) {
|
||||
EM_ASM_({
|
||||
console.log('startGame');
|
||||
});
|
||||
}
|
||||
|
||||
void ConsoleCallback::startScenario(Micropolis *micropolis, emscripten::val callbackVal, int scenario) {
|
||||
EM_ASM_({
|
||||
console.log('startScenario:', 'scenario:', $0);
|
||||
}, scenario);
|
||||
}
|
||||
|
||||
void ConsoleCallback::updateBudget(Micropolis *micropolis, emscripten::val callbackVal) {
|
||||
EM_ASM_({
|
||||
console.log('updateBudget');
|
||||
});
|
||||
}
|
||||
|
||||
void ConsoleCallback::updateCityName(Micropolis *micropolis, emscripten::val callbackVal, std::string cityName) {
|
||||
EM_ASM_({
|
||||
console.log('updateCityName:', 'cityName:', UTF8ToString($0));
|
||||
}, cityName.c_str());
|
||||
}
|
||||
|
||||
void ConsoleCallback::updateDate(Micropolis *micropolis, emscripten::val callbackVal, int cityYear, int cityMonth) {
|
||||
EM_ASM_({
|
||||
console.log('updateDate:', 'cityYear:', $0, 'cityMonth:', $1);
|
||||
}, cityYear, cityMonth);
|
||||
}
|
||||
|
||||
void ConsoleCallback::updateDemand(Micropolis *micropolis, emscripten::val callbackVal, float r, float c, float i) {
|
||||
EM_ASM_({
|
||||
console.log('updateDemand:', 'r:', $0, 'c:', $1, 'i:', $2);
|
||||
}, r, c, i);
|
||||
}
|
||||
|
||||
void ConsoleCallback::updateEvaluation(Micropolis *micropolis, emscripten::val callbackVal) {
|
||||
EM_ASM({
|
||||
console.log('updateEvaluation');
|
||||
});
|
||||
}
|
||||
|
||||
void ConsoleCallback::updateFunds(Micropolis *micropolis, emscripten::val callbackVal, int totalFunds) {
|
||||
EM_ASM_({
|
||||
console.log('updateFunds:', 'totalFunds:', $0);
|
||||
}, totalFunds);
|
||||
}
|
||||
|
||||
void ConsoleCallback::updateGameLevel(Micropolis *micropolis, emscripten::val callbackVal, int gameLevel) {
|
||||
EM_ASM_({
|
||||
console.log('updateGameLevel:', 'gameLevel:', $0);
|
||||
}, gameLevel);
|
||||
}
|
||||
|
||||
void ConsoleCallback::updateHistory(Micropolis *micropolis, emscripten::val callbackVal) {
|
||||
EM_ASM({
|
||||
console.log('updateHistory');
|
||||
});
|
||||
}
|
||||
|
||||
void ConsoleCallback::updateMap(Micropolis *micropolis, emscripten::val callbackVal) {
|
||||
EM_ASM({
|
||||
console.log('updateMap');
|
||||
});
|
||||
}
|
||||
|
||||
void ConsoleCallback::updateOptions(Micropolis *micropolis, emscripten::val callbackVal) {
|
||||
EM_ASM({
|
||||
console.log('updateOptions');
|
||||
});
|
||||
}
|
||||
|
||||
void ConsoleCallback::updatePasses(Micropolis *micropolis, emscripten::val callbackVal, int passes) {
|
||||
EM_ASM_({
|
||||
console.log('updatePasses:', 'passes:', $0);
|
||||
}, passes);
|
||||
}
|
||||
|
||||
void ConsoleCallback::updatePaused(Micropolis *micropolis, emscripten::val callbackVal, bool simPaused) {
|
||||
EM_ASM_({
|
||||
console.log('updatePaused:', 'simPaused:', $0);
|
||||
}, simPaused);
|
||||
}
|
||||
|
||||
void ConsoleCallback::updateSpeed(Micropolis *micropolis, emscripten::val callbackVal, int speed) {
|
||||
EM_ASM_({
|
||||
console.log('updateSpeed:', 'speed:', $0);
|
||||
}, speed);
|
||||
}
|
||||
|
||||
void ConsoleCallback::updateTaxRate(Micropolis *micropolis, emscripten::val callbackVal, int cityTax) {
|
||||
EM_ASM_({
|
||||
console.log('updateTaxRate:', 'cityTax:', $0);
|
||||
}, cityTax);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
177
core/callback.h
Normal file
177
core/callback.h
Normal file
|
@ -0,0 +1,177 @@
|
|||
/* callback.h
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file callback.h
|
||||
* @brief Interface for callbacks in the Micropolis game engine.
|
||||
*
|
||||
* This file defines the Callback class, which serves as an interface
|
||||
* for various callbacks used in the Micropolis game engine. These
|
||||
* callbacks cover a wide range of functionalities including UI
|
||||
* updates, game state changes, sound effects, simulation events, and
|
||||
* more. The methods in this class are virtual and intended to be
|
||||
* implemented by the game's frontend to interact with the user
|
||||
* interface and handle game events.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _H_CALLBACK
|
||||
#define _H_CALLBACK
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class Micropolis;
|
||||
|
||||
|
||||
class Callback {
|
||||
|
||||
public:
|
||||
|
||||
virtual ~Callback() {}
|
||||
virtual void autoGoto(Micropolis *micropolis, emscripten::val callbackVal, int x, int y, std::string message) = 0;
|
||||
virtual void didGenerateMap(Micropolis *micropolis, emscripten::val callbackVal, int seed) = 0;
|
||||
virtual void didLoadCity(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) = 0;
|
||||
virtual void didLoadScenario(Micropolis *micropolis, emscripten::val callbackVals, std::string name, std::string fname) = 0;
|
||||
virtual void didLoseGame(Micropolis *micropolis, emscripten::val callbackVal) = 0;
|
||||
virtual void didSaveCity(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) = 0;
|
||||
virtual void didTool(Micropolis *micropolis, emscripten::val callbackVal, std::string name, int x, int y) = 0;
|
||||
virtual void didWinGame(Micropolis *micropolis, emscripten::val callbackVal) = 0;
|
||||
virtual void didntLoadCity(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) = 0;
|
||||
virtual void didntSaveCity(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) = 0;
|
||||
virtual void makeSound(Micropolis *micropolis, emscripten::val callbackVal, std::string channel, std::string sound, int x, int y) = 0;
|
||||
virtual void newGame(Micropolis *micropolis, emscripten::val callbackVal) = 0;
|
||||
virtual void saveCityAs(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) = 0;
|
||||
virtual void sendMessage(Micropolis *micropolis, emscripten::val callbackVal, int messageIndex, int x, int y, bool picture, bool important) = 0;
|
||||
virtual void showBudgetAndWait(Micropolis *micropolis, emscripten::val callbackVal) = 0;
|
||||
virtual void showZoneStatus(Micropolis *micropolis, emscripten::val callbackVal, int tileCategoryIndex, int populationDensityIndex, int landValueIndex, int crimeRateIndex, int pollutionIndex, int growthRateIndex, int x, int y) = 0;
|
||||
virtual void simulateRobots(Micropolis *micropolis, emscripten::val callbackVal) = 0;
|
||||
virtual void simulateChurch(Micropolis *micropolis, emscripten::val callbackVal, int posX, int posY, int churchNumber) = 0;
|
||||
virtual void startEarthquake(Micropolis *micropolis, emscripten::val callbackVal, int strength) = 0;
|
||||
virtual void startGame(Micropolis *micropolis, emscripten::val callbackVal) = 0;
|
||||
virtual void startScenario(Micropolis *micropolis, emscripten::val callbackVal, int scenario) = 0;
|
||||
virtual void updateBudget(Micropolis *micropolis, emscripten::val callbackVal) = 0;
|
||||
virtual void updateCityName(Micropolis *micropolis, emscripten::val callbackVal, std::string cityName) = 0;
|
||||
virtual void updateDate(Micropolis *micropolis, emscripten::val callbackVal, int cityYear, int cityMonth) = 0;
|
||||
virtual void updateDemand(Micropolis *micropolis, emscripten::val callbackVal, float r, float c, float i) = 0;
|
||||
virtual void updateEvaluation(Micropolis *micropolis, emscripten::val callbackVal) = 0;
|
||||
virtual void updateFunds(Micropolis *micropolis, emscripten::val callbackVal, int totalFunds) = 0;
|
||||
virtual void updateGameLevel(Micropolis *micropolis, emscripten::val callbackVal, int gameLevel) = 0;
|
||||
virtual void updateHistory(Micropolis *micropolis, emscripten::val callbackVal) = 0;
|
||||
virtual void updateMap(Micropolis *micropolis, emscripten::val callbackVal) = 0;
|
||||
virtual void updateOptions(Micropolis *micropolis, emscripten::val callbackVal) = 0;
|
||||
virtual void updatePasses(Micropolis *micropolis, emscripten::val callbackVal, int passes) = 0;
|
||||
virtual void updatePaused(Micropolis *micropolis, emscripten::val callbackVal, bool simPaused) = 0;
|
||||
virtual void updateSpeed(Micropolis *micropolis, emscripten::val callbackVal, int speed) = 0;
|
||||
virtual void updateTaxRate(Micropolis *micropolis, emscripten::val callbackVal, int cityTax) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class ConsoleCallback : public Callback {
|
||||
|
||||
public:
|
||||
|
||||
virtual ~ConsoleCallback();
|
||||
virtual void autoGoto(Micropolis *micropolis, emscripten::val callbackVal, int x, int y, std::string message) override;
|
||||
virtual void didGenerateMap(Micropolis *micropolis, emscripten::val callbackVal, int seed) override;
|
||||
virtual void didLoadCity(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) override;
|
||||
virtual void didLoadScenario(Micropolis *micropolis, emscripten::val callbackVal, std::string name, std::string fname) override;
|
||||
virtual void didLoseGame(Micropolis *micropolis, emscripten::val callbackVal) override;
|
||||
virtual void didSaveCity(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) override;
|
||||
virtual void didTool(Micropolis *micropolis, emscripten::val callbackVal, std::string name, int x, int y) override;
|
||||
virtual void didWinGame(Micropolis *micropolis, emscripten::val callbackVal) override;
|
||||
virtual void didntLoadCity(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) override;
|
||||
virtual void didntSaveCity(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) override;
|
||||
virtual void makeSound(Micropolis *micropolis, emscripten::val callbackVal, std::string channel, std::string sound, int x, int y) override;
|
||||
virtual void newGame(Micropolis *micropolis, emscripten::val callbackVal) override;
|
||||
virtual void saveCityAs(Micropolis *micropolis, emscripten::val callbackVal, std::string filename) override;
|
||||
virtual void sendMessage(Micropolis *micropolis, emscripten::val callbackVal, int messageIndex, int x, int y, bool picture, bool important) override;
|
||||
virtual void showBudgetAndWait(Micropolis *micropolis, emscripten::val callbackVal) override;
|
||||
virtual void showZoneStatus(Micropolis *micropolis, emscripten::val callbackVal, int tileCategoryIndex, int populationDensityIndex, int landValueIndex, int crimeRateIndex, int pollutionIndex, int growthRateIndex, int x, int y) override;
|
||||
virtual void simulateRobots(Micropolis *micropolis, emscripten::val callbackVal) override;
|
||||
virtual void simulateChurch(Micropolis *micropolis, emscripten::val callbackVal, int posX, int posY, int churchNumber) override;
|
||||
virtual void startEarthquake(Micropolis *micropolis, emscripten::val callbackVal, int strength) override;
|
||||
virtual void startGame(Micropolis *micropolis, emscripten::val callbackVal) override;
|
||||
virtual void startScenario(Micropolis *micropolis, emscripten::val callbackVal, int scenario) override;
|
||||
virtual void updateBudget(Micropolis *micropolis, emscripten::val callbackVal) override;
|
||||
virtual void updateCityName(Micropolis *micropolis, emscripten::val callbackVal, std::string cityName) override;
|
||||
virtual void updateDate(Micropolis *micropolis, emscripten::val callbackVal, int cityYear, int cityMonth) override;
|
||||
virtual void updateDemand(Micropolis *micropolis, emscripten::val callbackVal, float r, float c, float i) override;
|
||||
virtual void updateEvaluation(Micropolis *micropolis, emscripten::val callbackVal) override;
|
||||
virtual void updateFunds(Micropolis *micropolis, emscripten::val callbackVal, int totalFunds) override;
|
||||
virtual void updateGameLevel(Micropolis *micropolis, emscripten::val callbackVal, int gameLevel) override;
|
||||
virtual void updateHistory(Micropolis *micropolis, emscripten::val callbackVal) override;
|
||||
virtual void updateMap(Micropolis *micropolis, emscripten::val callbackVal) override;
|
||||
virtual void updateOptions(Micropolis *micropolis, emscripten::val callbackVal) override;
|
||||
virtual void updatePasses(Micropolis *micropolis, emscripten::val callbackVal, int passes) override;
|
||||
virtual void updatePaused(Micropolis *micropolis, emscripten::val callbackVal, bool simPaused) override;
|
||||
virtual void updateSpeed(Micropolis *micropolis, emscripten::val callbackVal, int speed) override;
|
||||
virtual void updateTaxRate(Micropolis *micropolis, emscripten::val callbackVal, int cityTax) override;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#endif
|
745
core/connect.cpp
Normal file
745
core/connect.cpp
Normal file
|
@ -0,0 +1,745 @@
|
|||
/* connect.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file connect.cpp
|
||||
* @brief Implements connection utilities for roads, rails, and wires
|
||||
* in Micropolis.
|
||||
*
|
||||
* This file contains functions for laying down and updating roads,
|
||||
* railways, and power lines in the Micropolis game. It handles the
|
||||
* logic for determining the appropriate tile transformations when
|
||||
* these elements are placed on the map, considering existing terrain
|
||||
* and infrastructure. The file includes utilities for bulldozing,
|
||||
* repairing, and modifying tiles to ensure correct connectivity and
|
||||
* appearance on the game map.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static const unsigned short RoadTable[16] = {
|
||||
ROADS, ROADS2, ROADS, ROADS3,
|
||||
ROADS2, ROADS2, ROADS4, ROADS8,
|
||||
ROADS, ROADS6, ROADS, ROADS7,
|
||||
ROADS5, ROADS10, ROADS9, INTERSECTION
|
||||
};
|
||||
|
||||
static const unsigned short RailTable[16] = {
|
||||
LHRAIL, LVRAIL, LHRAIL, LVRAIL2,
|
||||
LVRAIL, LVRAIL, LVRAIL3, LVRAIL7,
|
||||
LHRAIL, LVRAIL5, LHRAIL, LVRAIL6,
|
||||
LVRAIL4, LVRAIL9, LVRAIL8, LVRAIL10
|
||||
};
|
||||
|
||||
static const unsigned short WireTable[16] = {
|
||||
LHPOWER, LVPOWER, LHPOWER, LVPOWER2,
|
||||
LVPOWER, LVPOWER, LVPOWER3, LVPOWER7,
|
||||
LHPOWER, LVPOWER5, LHPOWER, LVPOWER6,
|
||||
LVPOWER4, LVPOWER9, LVPOWER8, LVPOWER10
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Remove road from the tile.
|
||||
* @param tile Current tile value.
|
||||
* @return Equivalent tile without road.
|
||||
*/
|
||||
static inline MapTile neutralizeRoad(MapTile tile)
|
||||
{
|
||||
if (tile >= 64 && tile <= 207) {
|
||||
tile = (tile & 0x000F) + 64;
|
||||
}
|
||||
return tile;
|
||||
};
|
||||
|
||||
/**
|
||||
* Perform the command, and fix wire/road/rail/zone connections around it.
|
||||
* Store modification in the \a effects object.
|
||||
* @param x X world position to perform the command.
|
||||
* @param y Y world position to perform the command.
|
||||
* @param cmd Command to perform.
|
||||
* @param effects Modification collecting object.
|
||||
* @return Tool result.
|
||||
*/
|
||||
ToolResult Micropolis::connectTile(short x, short y,
|
||||
ConnectTileCommand cmd, ToolEffects *effects)
|
||||
{
|
||||
ToolResult result = TOOLRESULT_OK;
|
||||
|
||||
// Make sure the array subscripts are in bounds.
|
||||
if (!testBounds(x, y)) {
|
||||
return TOOLRESULT_FAILED;
|
||||
}
|
||||
|
||||
// Perform auto-doze if appropriate.
|
||||
switch (cmd) {
|
||||
|
||||
case CONNECT_TILE_ROAD:
|
||||
case CONNECT_TILE_RAILROAD:
|
||||
case CONNECT_TILE_WIRE:
|
||||
|
||||
// Silently skip auto-bulldoze if no money.
|
||||
if (autoBulldoze) {
|
||||
|
||||
MapValue mapVal = effects->getMapValue(x, y);
|
||||
|
||||
if (mapVal & BULLBIT) {
|
||||
mapVal &= LOMASK;
|
||||
mapVal = neutralizeRoad(mapVal);
|
||||
|
||||
/* Maybe this should check BULLBIT instead of checking tile values? */
|
||||
if ((mapVal >= TINYEXP && mapVal <= LASTTINYEXP) ||
|
||||
(mapVal < HBRIDGE && mapVal != DIRT)) {
|
||||
|
||||
effects->addCost(1);
|
||||
|
||||
effects->setMapValue(x, y, DIRT);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Do nothing.
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
// Perform the command.
|
||||
switch (cmd) {
|
||||
|
||||
case CONNECT_TILE_FIX: // Fix zone.
|
||||
fixZone(x, y, effects);
|
||||
break;
|
||||
|
||||
case CONNECT_TILE_BULLDOZE: // Bulldoze zone.
|
||||
result = layDoze(x, y, effects);
|
||||
fixZone(x, y, effects);
|
||||
break;
|
||||
|
||||
case CONNECT_TILE_ROAD: // Lay road.
|
||||
result = layRoad(x, y, effects);
|
||||
fixZone(x, y, effects);
|
||||
break;
|
||||
|
||||
case CONNECT_TILE_RAILROAD: // Lay railroad.
|
||||
result = layRail(x, y, effects);
|
||||
fixZone(x, y, effects);
|
||||
break;
|
||||
|
||||
case CONNECT_TILE_WIRE: // Lay wire.
|
||||
result = layWire(x, y, effects);
|
||||
fixZone(x, y, effects);
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builldoze a tile (make it a #RIVER or #DIRT).
|
||||
* @param x X map coordinate.
|
||||
* @param y Y map coordinate.
|
||||
* @param effects Modification collecting object.
|
||||
* @return Tool result.
|
||||
*/
|
||||
ToolResult Micropolis::layDoze(int x, int y, ToolEffects *effects)
|
||||
{
|
||||
MapValue tile = effects->getMapValue(x, y);
|
||||
|
||||
if (!(tile & BULLBIT)) {
|
||||
return TOOLRESULT_FAILED; /* Check dozeable bit. */
|
||||
}
|
||||
|
||||
tile &= LOMASK;
|
||||
tile = neutralizeRoad(tile);
|
||||
|
||||
switch (tile) {
|
||||
case HBRIDGE:
|
||||
case VBRIDGE:
|
||||
case BRWV:
|
||||
case BRWH:
|
||||
case HBRDG0:
|
||||
case HBRDG1:
|
||||
case HBRDG2:
|
||||
case HBRDG3:
|
||||
case VBRDG0:
|
||||
case VBRDG1:
|
||||
case VBRDG2:
|
||||
case VBRDG3:
|
||||
case HPOWER:
|
||||
case VPOWER:
|
||||
case HRAIL:
|
||||
case VRAIL: /* Dozing over water, replace with water. */
|
||||
effects->setMapValue(x, y, RIVER);
|
||||
break;
|
||||
|
||||
default: /* Dozing on land, replace with land. Simple, eh? */
|
||||
effects->setMapValue(x, y, DIRT);
|
||||
break;
|
||||
}
|
||||
|
||||
effects->addCost(1); /* Costs $1.00.... */
|
||||
|
||||
return TOOLRESULT_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lay a road, and update road around it.
|
||||
* @param x X map coordinate.
|
||||
* @param y Y map coordinate.
|
||||
* @param effects Modification collecting object.
|
||||
* @return Tool result.
|
||||
*/
|
||||
ToolResult Micropolis::layRoad(int x, int y, ToolEffects *effects)
|
||||
{
|
||||
int cost = 10;
|
||||
|
||||
MapTile tile = effects->getMapTile(x, y);
|
||||
|
||||
switch (tile) {
|
||||
|
||||
case DIRT:
|
||||
effects->setMapValue(x, y, ROADS | BULLBIT | BURNBIT);
|
||||
break;
|
||||
|
||||
case RIVER: /* Road on Water */
|
||||
case REDGE:
|
||||
case CHANNEL: /* Check how to build bridges, if possible. */
|
||||
cost = 50;
|
||||
|
||||
if (x < WORLD_W - 1) {
|
||||
tile = effects->getMapTile(x + 1, y);
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile == VRAILROAD || tile == HBRIDGE
|
||||
|| (tile >= ROADS && tile <= HROADPOWER)) {
|
||||
effects->setMapValue(x, y, HBRIDGE | BULLBIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (x > 0) {
|
||||
tile = effects->getMapTile(x - 1, y);
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile == VRAILROAD || tile == HBRIDGE
|
||||
|| (tile >= ROADS && tile <= INTERSECTION)) {
|
||||
effects->setMapValue(x, y, HBRIDGE | BULLBIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (y < WORLD_H - 1) {
|
||||
tile = effects->getMapTile(x, y + 1);
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile == HRAILROAD || tile == VROADPOWER
|
||||
|| (tile >= VBRIDGE && tile <= INTERSECTION)) {
|
||||
effects->setMapValue(x, y, VBRIDGE | BULLBIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (y > 0) {
|
||||
tile = effects->getMapTile(x, y - 1);
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile == HRAILROAD || tile == VROADPOWER
|
||||
|| (tile >= VBRIDGE && tile <= INTERSECTION)) {
|
||||
effects->setMapValue(x, y, VBRIDGE | BULLBIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Can't do road... */
|
||||
return TOOLRESULT_FAILED;
|
||||
|
||||
case LHPOWER: /* Road on power */
|
||||
effects->setMapValue(x, y, VROADPOWER | CONDBIT | BURNBIT | BULLBIT);
|
||||
break;
|
||||
|
||||
case LVPOWER: /* Road on power #2 */
|
||||
effects->setMapValue(x, y, HROADPOWER | CONDBIT | BURNBIT | BULLBIT);
|
||||
break;
|
||||
|
||||
case LHRAIL: /* Road on rail */
|
||||
effects->setMapValue(x, y, HRAILROAD | BURNBIT | BULLBIT);
|
||||
break;
|
||||
|
||||
case LVRAIL: /* Road on rail #2 */
|
||||
effects->setMapValue(x, y, VRAILROAD | BURNBIT | BULLBIT);
|
||||
break;
|
||||
|
||||
default: /* Can't do road */
|
||||
return TOOLRESULT_FAILED;
|
||||
|
||||
}
|
||||
|
||||
effects->addCost(cost);
|
||||
return TOOLRESULT_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lay a rail, and update connections (rail, road, and wire) around it.
|
||||
* @param x X map coordinate.
|
||||
* @param y Y map coordinate.
|
||||
* @param effects Modification collecting object.
|
||||
* @return Tool result.
|
||||
*/
|
||||
ToolResult Micropolis::layRail(int x, int y, ToolEffects *effects)
|
||||
{
|
||||
int cost = 20;
|
||||
|
||||
MapTile tile = effects->getMapTile(x, y);
|
||||
|
||||
tile = neutralizeRoad(tile);
|
||||
|
||||
switch (tile) {
|
||||
case DIRT: /* Rail on Dirt */
|
||||
|
||||
effects->setMapValue(x, y, LHRAIL | BULLBIT | BURNBIT);
|
||||
|
||||
break;
|
||||
|
||||
case RIVER: /* Rail on Water */
|
||||
case REDGE:
|
||||
case CHANNEL: /* Check how to build underwater tunnel, if possible. */
|
||||
|
||||
cost = 100;
|
||||
|
||||
if (x < WORLD_W - 1) {
|
||||
tile = effects->getMapTile(x + 1, y);
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile == RAILHPOWERV || tile == HRAIL
|
||||
|| (tile >= LHRAIL && tile <= HRAILROAD)) {
|
||||
effects->setMapValue(x, y, HRAIL | BULLBIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (x > 0) {
|
||||
tile = effects->getMapTile(x - 1, y);
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile == RAILHPOWERV || tile == HRAIL
|
||||
|| (tile > VRAIL && tile < VRAILROAD)) {
|
||||
effects->setMapValue(x, y, HRAIL | BULLBIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (y < WORLD_H - 1) {
|
||||
tile = effects->getMapTile(x, y + 1);
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile == RAILVPOWERH || tile == VRAILROAD
|
||||
|| (tile > HRAIL && tile < HRAILROAD)) {
|
||||
effects->setMapValue(x, y, VRAIL | BULLBIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (y > 0) {
|
||||
tile = effects->getMapTile(x, y - 1);
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile == RAILVPOWERH || tile == VRAILROAD
|
||||
|| (tile > HRAIL && tile < HRAILROAD)) {
|
||||
effects->setMapValue(x, y, VRAIL | BULLBIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Can't do rail... */
|
||||
return TOOLRESULT_FAILED;
|
||||
|
||||
case LHPOWER: /* Rail on power */
|
||||
effects->setMapValue(x, y, RAILVPOWERH | CONDBIT | BURNBIT | BULLBIT);
|
||||
break;
|
||||
|
||||
case LVPOWER: /* Rail on power #2 */
|
||||
effects->setMapValue(x, y, RAILHPOWERV | CONDBIT | BURNBIT | BULLBIT);
|
||||
break;
|
||||
|
||||
case ROADS: /* Rail on road */
|
||||
effects->setMapValue(x, y, VRAILROAD | BURNBIT | BULLBIT);
|
||||
break;
|
||||
|
||||
case ROADS2: /* Rail on road #2 */
|
||||
effects->setMapValue(x, y, HRAILROAD | BURNBIT | BULLBIT);
|
||||
break;
|
||||
|
||||
default: /* Can't do rail */
|
||||
return TOOLRESULT_FAILED;
|
||||
}
|
||||
|
||||
effects->addCost(cost);
|
||||
return TOOLRESULT_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lay a wire, and update connections (rail, road, and wire) around it.
|
||||
* @param x X map coordinate.
|
||||
* @param y Y map coordinate.
|
||||
* @param effects Modification collecting object.
|
||||
* @return Tool result.
|
||||
*/
|
||||
ToolResult Micropolis::layWire(int x, int y, ToolEffects *effects)
|
||||
{
|
||||
int cost = 5;
|
||||
|
||||
MapTile tile = effects->getMapTile(x, y);
|
||||
|
||||
tile = neutralizeRoad(tile);
|
||||
|
||||
switch (tile) {
|
||||
|
||||
case DIRT: /* Wire on Dirt */
|
||||
|
||||
effects->setMapValue(x, y, LHPOWER | CONDBIT | BURNBIT | BULLBIT);
|
||||
|
||||
break;
|
||||
|
||||
case RIVER: /* Wire on Water */
|
||||
case REDGE:
|
||||
case CHANNEL: /* Check how to lay underwater wire, if possible. */
|
||||
|
||||
cost = 25;
|
||||
|
||||
if (x < WORLD_W - 1) {
|
||||
tile = effects->getMapValue(x + 1, y);
|
||||
if (tile & CONDBIT) {
|
||||
tile &= LOMASK;
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile != HROADPOWER && tile != RAILHPOWERV && tile != HPOWER) {
|
||||
effects->setMapValue(x, y, VPOWER | CONDBIT | BULLBIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (x > 0) {
|
||||
tile = effects->getMapValue(x - 1, y);
|
||||
if (tile & CONDBIT) {
|
||||
tile &= LOMASK;
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile != HROADPOWER && tile != RAILHPOWERV && tile != HPOWER) {
|
||||
effects->setMapValue(x, y, VPOWER | CONDBIT | BULLBIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (y < WORLD_H - 1) {
|
||||
tile = effects->getMapValue(x, y + 1);
|
||||
if (tile & CONDBIT) {
|
||||
tile &= LOMASK;
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile != VROADPOWER && tile != RAILVPOWERH && tile != VPOWER) {
|
||||
effects->setMapValue(x, y, HPOWER | CONDBIT | BULLBIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (y > 0) {
|
||||
tile = effects->getMapValue(x, y - 1);
|
||||
if (tile & CONDBIT) {
|
||||
tile &= LOMASK;
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile != VROADPOWER && tile != RAILVPOWERH && tile != VPOWER) {
|
||||
effects->setMapValue(x, y, HPOWER | CONDBIT | BULLBIT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Can't do wire... */
|
||||
return TOOLRESULT_FAILED;
|
||||
|
||||
case ROADS: /* Wire on Road */
|
||||
effects->setMapValue(x, y, HROADPOWER | CONDBIT | BURNBIT | BULLBIT);
|
||||
break;
|
||||
|
||||
case ROADS2: /* Wire on Road #2 */
|
||||
effects->setMapValue(x, y, VROADPOWER | CONDBIT | BURNBIT | BULLBIT);
|
||||
break;
|
||||
|
||||
case LHRAIL: /* Wire on rail */
|
||||
effects->setMapValue(x, y, RAILHPOWERV | CONDBIT | BURNBIT | BULLBIT);
|
||||
break;
|
||||
|
||||
case LVRAIL: /* Wire on rail #2 */
|
||||
effects->setMapValue(x, y, RAILVPOWERH | CONDBIT | BURNBIT | BULLBIT);
|
||||
break;
|
||||
|
||||
default: /* Can't do wire */
|
||||
return TOOLRESULT_FAILED;
|
||||
|
||||
}
|
||||
|
||||
effects->addCost(cost);
|
||||
return TOOLRESULT_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update connections (rails, and wire connections) to a zone.
|
||||
* @param x X map coordinate
|
||||
* @param y Y map coordinate.
|
||||
* @param effects Modification collecting object.
|
||||
*/
|
||||
void Micropolis::fixZone(int x, int y, ToolEffects *effects)
|
||||
{
|
||||
fixSingle(x, y, effects);
|
||||
|
||||
if (y > 0) {
|
||||
fixSingle(x, y - 1, effects);
|
||||
}
|
||||
|
||||
if (x < WORLD_W - 1) {
|
||||
fixSingle(x + 1, y, effects);
|
||||
}
|
||||
|
||||
if (y < WORLD_H - 1) {
|
||||
fixSingle(x, y + 1, effects);
|
||||
}
|
||||
|
||||
if (x > 0) {
|
||||
fixSingle(x - 1, y, effects);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Modify road, rails, and wire connections at a given tile.
|
||||
* @param x X map coordinate.
|
||||
* @param y Y map coordinate.
|
||||
* @param effects Modification collecting object.
|
||||
*/
|
||||
void Micropolis::fixSingle(int x, int y, ToolEffects *effects)
|
||||
{
|
||||
unsigned short adjTile = 0;
|
||||
|
||||
MapTile tile = effects->getMapTile(x, y);
|
||||
|
||||
tile = neutralizeRoad(tile);
|
||||
|
||||
if (tile >= ROADS && tile <= INTERSECTION) { /* Cleanup Road */
|
||||
|
||||
if (y > 0) {
|
||||
tile = effects->getMapTile(x, y - 1);
|
||||
tile = neutralizeRoad(tile);
|
||||
if ((tile == HRAILROAD || (tile >= ROADBASE && tile <= VROADPOWER))
|
||||
&& tile != HROADPOWER && tile != VRAILROAD
|
||||
&& tile != ROADBASE) {
|
||||
adjTile |= 0x0001;
|
||||
}
|
||||
}
|
||||
|
||||
if (x < WORLD_W - 1) {
|
||||
tile = effects->getMapTile(x + 1, y);
|
||||
tile = neutralizeRoad(tile);
|
||||
if ((tile == VRAILROAD || (tile >= ROADBASE && tile <= VROADPOWER))
|
||||
&& tile != VROADPOWER && tile != HRAILROAD
|
||||
&& tile != VBRIDGE) {
|
||||
adjTile |= 0x0002;
|
||||
}
|
||||
}
|
||||
|
||||
if (y < WORLD_H - 1) {
|
||||
tile = effects->getMapTile(x, y + 1);
|
||||
tile = neutralizeRoad(tile);
|
||||
if ((tile == HRAILROAD || (tile >= ROADBASE && tile <= VROADPOWER))
|
||||
&& tile != HROADPOWER && tile != VRAILROAD
|
||||
&& tile != ROADBASE) {
|
||||
adjTile |= 0x0004;
|
||||
}
|
||||
}
|
||||
|
||||
if (x > 0) {
|
||||
tile = effects->getMapTile(x - 1, y);
|
||||
tile = neutralizeRoad(tile);
|
||||
if ((tile == VRAILROAD || (tile >= ROADBASE && tile <= VROADPOWER))
|
||||
&& tile != VROADPOWER && tile != HRAILROAD
|
||||
&& tile != VBRIDGE) {
|
||||
adjTile |= 0x0008;
|
||||
}
|
||||
}
|
||||
|
||||
effects->setMapValue(x, y, RoadTable[adjTile] | BULLBIT | BURNBIT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tile >= LHRAIL && tile <= LVRAIL10) { /* Cleanup Rail */
|
||||
|
||||
if (y > 0) {
|
||||
tile = effects->getMapTile(x, y - 1);
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile >= RAILHPOWERV && tile <= VRAILROAD
|
||||
&& tile != RAILHPOWERV && tile != HRAILROAD
|
||||
&& tile != HRAIL) {
|
||||
adjTile |= 0x0001;
|
||||
}
|
||||
}
|
||||
|
||||
if (x < WORLD_W - 1) {
|
||||
tile = effects->getMapTile(x + 1, y);
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile >= RAILHPOWERV && tile <= VRAILROAD
|
||||
&& tile != RAILVPOWERH && tile != VRAILROAD
|
||||
&& tile != VRAIL) {
|
||||
adjTile |= 0x0002;
|
||||
}
|
||||
}
|
||||
|
||||
if (y < WORLD_H - 1) {
|
||||
tile = effects->getMapTile(x, y + 1);
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile >= RAILHPOWERV && tile <= VRAILROAD
|
||||
&& tile != RAILHPOWERV && tile != HRAILROAD
|
||||
&& tile != HRAIL) {
|
||||
adjTile |= 0x0004;
|
||||
}
|
||||
}
|
||||
|
||||
if (x > 0) {
|
||||
tile = effects->getMapTile(x - 1, y);
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile >= RAILHPOWERV && tile <= VRAILROAD
|
||||
&& tile != RAILVPOWERH && tile != VRAILROAD
|
||||
&& tile != VRAIL) {
|
||||
adjTile |= 0x0008;
|
||||
}
|
||||
}
|
||||
|
||||
effects->setMapValue(x, y, RailTable[adjTile] | BULLBIT | BURNBIT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tile >= LHPOWER && tile <= LVPOWER10) { /* Cleanup Wire */
|
||||
|
||||
if (y > 0) {
|
||||
tile = effects->getMapValue(x, y - 1);
|
||||
if (tile & CONDBIT) {
|
||||
tile &= LOMASK;
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile != VPOWER && tile != VROADPOWER && tile != RAILVPOWERH) {
|
||||
adjTile |= 0x0001;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (x < WORLD_W - 1) {
|
||||
tile = effects->getMapValue(x + 1, y);
|
||||
if (tile & CONDBIT) {
|
||||
tile &= LOMASK;
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile != HPOWER && tile != HROADPOWER && tile != RAILHPOWERV) {
|
||||
adjTile |= 0x0002;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (y < WORLD_H - 1) {
|
||||
tile = effects->getMapValue(x, y + 1);
|
||||
if (tile & CONDBIT) {
|
||||
tile &= LOMASK;
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile != VPOWER && tile != VROADPOWER && tile != RAILVPOWERH) {
|
||||
adjTile |= 0x0004;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (x > 0) {
|
||||
tile = effects->getMapValue(x - 1, y);
|
||||
if (tile & CONDBIT) {
|
||||
tile &= LOMASK;
|
||||
tile = neutralizeRoad(tile);
|
||||
if (tile != HPOWER && tile != HROADPOWER && tile != RAILHPOWERV) {
|
||||
adjTile |= 0x0008;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
effects->setMapValue(x, y, WireTable[adjTile] | BLBNCNBIT);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
90
core/data_types.h
Normal file
90
core/data_types.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
/* data_types.h
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file data_types.h
|
||||
* @brief Commonly used data types in Micropolis game engine.
|
||||
*
|
||||
* This header file defines basic data types used throughout the
|
||||
* Micropolis game engine. These include types for bytes, pointers,
|
||||
* and quad values (both signed and unsigned). This file provides a
|
||||
* centralized definition of these types to ensure consistency and
|
||||
* readability across the game engine's codebase. By abstracting data
|
||||
* types in this manner, the code maintains flexibility and ease of
|
||||
* maintenance.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef H_DATA_TYPES
|
||||
#define H_DATA_TYPES
|
||||
|
||||
|
||||
typedef unsigned char Byte;
|
||||
|
||||
typedef Byte *Ptr;
|
||||
|
||||
typedef long Quad;
|
||||
|
||||
typedef unsigned long UQuad;
|
||||
|
||||
|
||||
#endif
|
418
core/disasters.cpp
Normal file
418
core/disasters.cpp
Normal file
|
@ -0,0 +1,418 @@
|
|||
/* disasters.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file disasters.cpp
|
||||
* @brief Handles disaster events in the Micropolis game engine.
|
||||
*
|
||||
* This file includes functions to trigger and manage various disaster
|
||||
* events such as earthquakes, fires, floods, and other scenarios. It
|
||||
* controls the probability of disasters occurring based on the game
|
||||
* level and executes disaster-specific effects on the city, like
|
||||
* damaging structures and changing terrain. The file plays a critical
|
||||
* role in adding challenge and dynamic events to the gameplay
|
||||
* experience.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Let disasters happen.
|
||||
* @todo Decide what to do with the 'nothing happens' disaster (since the
|
||||
* chance that a disaster happens is expressed in the \c DisChance
|
||||
* table).
|
||||
*/
|
||||
void Micropolis::doDisasters()
|
||||
{
|
||||
/* Chance of disasters at lev 0 1 2 */
|
||||
static const short DisChance[3] = {
|
||||
10 * 48, // Game level 0
|
||||
5 * 48, // Game level 1
|
||||
60 // Game level 2
|
||||
};
|
||||
assert(LEVEL_COUNT == LENGTH_OF(DisChance));
|
||||
|
||||
if (floodCount) {
|
||||
floodCount--;
|
||||
}
|
||||
|
||||
if (disasterEvent != SC_NONE) {
|
||||
scenarioDisaster();
|
||||
}
|
||||
|
||||
if (!enableDisasters) { // Disasters have been disabled
|
||||
return;
|
||||
}
|
||||
|
||||
int x = gameLevel;
|
||||
if (x > LEVEL_LAST) {
|
||||
x = LEVEL_EASY;
|
||||
}
|
||||
|
||||
if (!getRandom(DisChance[x])) {
|
||||
switch (getRandom(8)) {
|
||||
case 0:
|
||||
case 1:
|
||||
setFire(); // 2/9 chance a fire breaks out
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
makeFlood(); // 2/9 chance for a flood
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// 1/9 chance nothing happens (was airplane crash,
|
||||
// which EA removed after 9/11, and requested it be
|
||||
// removed from this code)
|
||||
break;
|
||||
|
||||
case 5:
|
||||
makeTornado(); // 1/9 chance tornado
|
||||
break;
|
||||
|
||||
case 6:
|
||||
makeEarthquake(); // 1/9 chance earthquake
|
||||
break;
|
||||
|
||||
case 7:
|
||||
case 8:
|
||||
// 2/9 chance a scary monster arrives in a dirty town
|
||||
if (pollutionAverage > /* 80 */ 60) {
|
||||
makeMonster();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Let disasters of the scenario happen */
|
||||
void Micropolis::scenarioDisaster()
|
||||
{
|
||||
switch (disasterEvent) {
|
||||
case SC_DULLSVILLE:
|
||||
break;
|
||||
|
||||
case SC_SAN_FRANCISCO:
|
||||
if (disasterWait == 1) {
|
||||
makeEarthquake();
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_HAMBURG:
|
||||
if (disasterWait % 10 == 0) {
|
||||
makeFireBombs();
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_BERN:
|
||||
break;
|
||||
|
||||
case SC_TOKYO:
|
||||
if (disasterWait == 1) {
|
||||
makeMonster();
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_DETROIT:
|
||||
break;
|
||||
|
||||
case SC_BOSTON:
|
||||
if (disasterWait == 1) {
|
||||
makeMeltdown();
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_RIO:
|
||||
if ((disasterWait % 24) == 0) {
|
||||
makeFlood();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break; // Never used
|
||||
}
|
||||
|
||||
if (disasterWait > 0) {
|
||||
disasterWait--;
|
||||
} else {
|
||||
disasterEvent = SC_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a nuclear power plant melt
|
||||
* @todo Randomize which nuke plant melts down.
|
||||
*/
|
||||
void Micropolis::makeMeltdown()
|
||||
{
|
||||
short x, y;
|
||||
|
||||
for (x = 0; x < (WORLD_W - 1); x++) {
|
||||
for (y = 0; y < (WORLD_H - 1); y++) {
|
||||
if ((map[x][y] & LOMASK) == NUCLEAR) {
|
||||
doMeltdown(Position(x, y));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Let a fire bomb explode at a random location */
|
||||
void Micropolis::fireBomb()
|
||||
{
|
||||
int crashX = getRandom(WORLD_W - 1);
|
||||
int crashY = getRandom(WORLD_H - 1);
|
||||
makeExplosion(crashX, crashY);
|
||||
sendMessage(MESSAGE_FIREBOMBING, crashX, crashY, true, true);
|
||||
}
|
||||
|
||||
|
||||
/** Throw several bombs onto the city. */
|
||||
void Micropolis::makeFireBombs()
|
||||
{
|
||||
int count = 2 + (getRandom16() & 1);
|
||||
|
||||
while (count > 0) {
|
||||
fireBomb();
|
||||
count--;
|
||||
}
|
||||
|
||||
// TODO: Schedule periodic fire bombs over time, every few ticks.
|
||||
}
|
||||
|
||||
|
||||
/** Change random tiles to fire or dirt as result of the earthquake */
|
||||
void Micropolis::makeEarthquake()
|
||||
{
|
||||
short x, y, z;
|
||||
|
||||
int strength = getRandom(700) + 300; // strength/duration of the earthquake
|
||||
|
||||
doEarthquake(strength);
|
||||
|
||||
sendMessage(MESSAGE_EARTHQUAKE, cityCenterX, cityCenterY, true);
|
||||
|
||||
for (z = 0; z < strength; z++) {
|
||||
x = getRandom(WORLD_W - 1);
|
||||
y = getRandom(WORLD_H - 1);
|
||||
|
||||
if (vulnerable(map[x][y])) {
|
||||
|
||||
if ((z & 0x3) != 0) { // 3 of 4 times reduce to rubble
|
||||
map[x][y] = randomRubble();
|
||||
} else {
|
||||
// 1 of 4 times start fire
|
||||
map[x][y] = randomFire();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Start a fire at a random place, random disaster or scenario */
|
||||
void Micropolis::setFire()
|
||||
{
|
||||
short x, y, z;
|
||||
|
||||
x = getRandom(WORLD_W - 1);
|
||||
y = getRandom(WORLD_H - 1);
|
||||
z = map[x][y];
|
||||
|
||||
if ((z & ZONEBIT) == 0) {
|
||||
z = z & LOMASK;
|
||||
if (z > LHTHR && z < LASTZONE) {
|
||||
map[x][y] = randomFire();
|
||||
sendMessage(MESSAGE_FIRE_REPORTED, x, y, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Start a fire at a random place, requested by user */
|
||||
void Micropolis::makeFire()
|
||||
{
|
||||
short t, x, y, z;
|
||||
|
||||
for (t = 0; t < 40; t++) {
|
||||
x = getRandom(WORLD_W - 1);
|
||||
y = getRandom(WORLD_H - 1);
|
||||
z = map[x][y];
|
||||
|
||||
if ((!(z & ZONEBIT)) && (z & BURNBIT)) {
|
||||
z = z & LOMASK;
|
||||
if ((z > 21) && (z < LASTZONE)) {
|
||||
map[x][y] = randomFire();
|
||||
sendMessage(MESSAGE_FIRE_REPORTED, x, y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is tile vulnerable for an earthquake?
|
||||
* @param tem Tile data
|
||||
* @return Function returns \c true if tile is vulnerable, and \c false if not
|
||||
*/
|
||||
bool Micropolis::vulnerable(int tem)
|
||||
{
|
||||
int tem2 = tem & LOMASK;
|
||||
|
||||
if (tem2 < RESBASE || tem2 > LASTZONE || (tem & ZONEBIT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Flood many tiles
|
||||
* @todo Use Direction and some form of XYPosition class here
|
||||
*/
|
||||
void Micropolis::makeFlood()
|
||||
{
|
||||
static const short Dx[4] = { 0, 1, 0, -1 };
|
||||
static const short Dy[4] = { -1, 0, 1, 0 };
|
||||
short xx, yy, c;
|
||||
short z, t, x, y;
|
||||
|
||||
for (z = 0; z < 300; z++) {
|
||||
x = getRandom(WORLD_W - 1);
|
||||
y = getRandom(WORLD_H - 1);
|
||||
c = map[x][y] & LOMASK;
|
||||
|
||||
if (c > CHANNEL && c <= WATER_HIGH) { /* if riveredge */
|
||||
for (t = 0; t < 4; t++) {
|
||||
xx = x + Dx[t];
|
||||
yy = y + Dy[t];
|
||||
if (testBounds(xx, yy)) {
|
||||
c = map[xx][yy];
|
||||
|
||||
/* tile is floodable */
|
||||
if (c == DIRT
|
||||
|| (c & (BULLBIT | BURNBIT)) == (BULLBIT | BURNBIT)) {
|
||||
map[xx][yy] = FLOOD;
|
||||
floodCount = 30;
|
||||
sendMessage(MESSAGE_FLOODING_REPORTED, xx, yy, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Flood around the given position.
|
||||
* @param pos Position around which to flood further.
|
||||
* @todo Use some form of rotating around a position.
|
||||
*/
|
||||
void Micropolis::doFlood(const Position& pos)
|
||||
{
|
||||
static const short Dx[4] = { 0, 1, 0, -1 };
|
||||
static const short Dy[4] = { -1, 0, 1, 0 };
|
||||
|
||||
if (floodCount > 0) {
|
||||
// Flood is not over yet
|
||||
for (int z = 0; z < 4; z++) {
|
||||
if ((getRandom16() & 7) == 0) { // 12.5% chance
|
||||
int xx = pos.posX + Dx[z];
|
||||
int yy = pos.posY + Dy[z];
|
||||
if (testBounds(xx, yy)) {
|
||||
MapValue c = map[xx][yy];
|
||||
MapTile t = c & LOMASK;
|
||||
|
||||
if ((c & BURNBIT) == BURNBIT || c == DIRT
|
||||
|| (t >= WOODS5 && t < FLOOD)) {
|
||||
if ((c & ZONEBIT) == ZONEBIT) {
|
||||
fireZone(Position(xx, yy), c);
|
||||
}
|
||||
map[xx][yy] = FLOOD + getRandom(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((getRandom16() & 15) == 0) { // 1/16 chance
|
||||
map[pos.posX][pos.posY] = DIRT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
1159
core/emscripten.cpp
Normal file
1159
core/emscripten.cpp
Normal file
File diff suppressed because it is too large
Load diff
573
core/evaluate.cpp
Normal file
573
core/evaluate.cpp
Normal file
|
@ -0,0 +1,573 @@
|
|||
/* evaluate.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file evaluate.cpp
|
||||
* @brief Evaluation and scoring for Micropolis city simulation.
|
||||
*
|
||||
* This file is part of the Micropolis game engine and handles the
|
||||
* evaluation and scoring aspects of a simulated city. It includes
|
||||
* functions to assess city value, compute population, classify city
|
||||
* based on population, evaluate city problems, vote on performance of
|
||||
* the mayor, and calculate the overall city score. The scoring system
|
||||
* considers various factors like crime, pollution, city class, road
|
||||
* effectiveness, and more to determine the success and challenges of
|
||||
* the city management.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* @todo: These strings should not be hard coded into the core simulator.
|
||||
* The scripting language should look them up in translation files.
|
||||
*/
|
||||
|
||||
// City Classes:
|
||||
// "VILLAGE", "TOWN", "CITY", "CAPITAL", "METROPOLIS", "MEGALOPOLIS"
|
||||
|
||||
// City Levels:
|
||||
// "Easy", "Medium", "Hard"
|
||||
|
||||
// City Problems:
|
||||
// "CRIME", "POLLUTION", "HOUSING COSTS", "TAXES",
|
||||
// "TRAFFIC", "UNEMPLOYMENT", "FIRES"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate city
|
||||
* @todo Handle lack of voting explicitly
|
||||
*/
|
||||
void Micropolis::cityEvaluation()
|
||||
{
|
||||
//printf("cityEvaluation totalPop %d\n", totalPop);
|
||||
if (totalPop > 0) {
|
||||
short problemTable[PROBNUM]; // Score for each problem, higher the more severe the problem is.
|
||||
for (int z = 0; z < PROBNUM; z++) {
|
||||
problemTable[z] = 0;
|
||||
}
|
||||
|
||||
getAssessedValue();
|
||||
doPopNum();
|
||||
doProblems(problemTable);
|
||||
getScore(problemTable);
|
||||
doVotes(); // How well is the mayor doing?
|
||||
changeEval();
|
||||
} else {
|
||||
evalInit();
|
||||
cityYes = 50; // No population => no voting. Let's say 50/50.
|
||||
changeEval();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize evaluation variables
|
||||
*/
|
||||
void Micropolis::evalInit()
|
||||
{
|
||||
cityYes = 0;
|
||||
cityPop = 0;
|
||||
cityPopDelta = 0;
|
||||
cityAssessedValue = 0;
|
||||
cityClass = CC_VILLAGE;
|
||||
cityScore = 500;
|
||||
cityScoreDelta = 0;
|
||||
for (int i = 0; i < PROBNUM; i++) {
|
||||
problemVotes[i] = 0;
|
||||
}
|
||||
for (int i = 0; i < CVP_PROBLEM_COMPLAINTS; i++) {
|
||||
problemOrder[i] = CVP_NUMPROBLEMS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Assess value of the city.
|
||||
* @post #cityAssessedValue contains the total city value.
|
||||
* @todo Make function return the value, or change the name of the function.
|
||||
*/
|
||||
void Micropolis::getAssessedValue()
|
||||
{
|
||||
Quad z;
|
||||
|
||||
z = roadTotal * 5;
|
||||
z += railTotal * 10;
|
||||
z += policeStationPop * 1000;
|
||||
z += fireStationPop * 1000;
|
||||
z += hospitalPop * 400;
|
||||
z += stadiumPop * 3000;
|
||||
z += seaportPop * 5000;
|
||||
z += airportPop * 10000;
|
||||
z += coalPowerPop * 3000;
|
||||
z += nuclearPowerPop * 6000;
|
||||
|
||||
cityAssessedValue = z * 1000;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute city population and city classification.
|
||||
* @see cityPop cityClass.
|
||||
*/
|
||||
void Micropolis::doPopNum()
|
||||
{
|
||||
Quad oldCityPop = cityPop;
|
||||
|
||||
cityPop = getPopulation();
|
||||
|
||||
if (oldCityPop == -1) {
|
||||
oldCityPop = cityPop;
|
||||
}
|
||||
|
||||
cityPopDelta = cityPop - oldCityPop;
|
||||
cityClass = getCityClass(cityPop);
|
||||
}
|
||||
|
||||
/** Compute city population. */
|
||||
Quad Micropolis::getPopulation()
|
||||
{
|
||||
Quad pop = (resPop + (comPop + indPop) * 8L) * 20L;
|
||||
return pop;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Classify the city based on its population.
|
||||
* @param cityPopulation Number of people in the city.
|
||||
* @return City classification.
|
||||
* @todo Put people counts into a table.
|
||||
*/
|
||||
CityClass Micropolis::getCityClass(Quad cityPopulation)
|
||||
{
|
||||
CityClass cityClassification = CC_VILLAGE;
|
||||
|
||||
if (cityPopulation > 2000) {
|
||||
cityClassification = CC_TOWN;
|
||||
}
|
||||
if (cityPopulation > 10000) {
|
||||
cityClassification = CC_CITY;
|
||||
}
|
||||
if (cityPopulation > 50000) {
|
||||
cityClassification = CC_CAPITAL;
|
||||
}
|
||||
if (cityPopulation > 100000) {
|
||||
cityClassification = CC_METROPOLIS;
|
||||
}
|
||||
if (cityPopulation > 500000) {
|
||||
cityClassification = CC_MEGALOPOLIS;
|
||||
}
|
||||
|
||||
return cityClassification;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate problems of the city, take votes, and decide which are the most
|
||||
* important ones.
|
||||
* @param problemTable Storage of how bad each problem is.
|
||||
* @post \a problemTable contains severity of each problem,
|
||||
* #problemVotes contains votes of each problem,
|
||||
* #problemOrder contains (in decreasing order) the worst problems.
|
||||
*/
|
||||
void Micropolis::doProblems(short problemTable[PROBNUM])
|
||||
{
|
||||
bool problemTaken[PROBNUM]; // Which problems are taken?
|
||||
|
||||
for (int z = 0; z < PROBNUM; z++) {
|
||||
problemTaken[z] = false;
|
||||
problemTable[z] = 0;
|
||||
}
|
||||
|
||||
problemTable[CVP_CRIME] = crimeAverage; /* Crime */
|
||||
problemTable[CVP_POLLUTION] = pollutionAverage; /* Pollution */
|
||||
problemTable[CVP_HOUSING] = landValueAverage * 7 / 10; /* Housing */
|
||||
problemTable[CVP_TAXES] = cityTax * 10; /* Taxes */
|
||||
problemTable[CVP_TRAFFIC] = getTrafficAverage(); /* Traffic */
|
||||
problemTable[CVP_UNEMPLOYMENT] = getUnemployment(); /* Unemployment */
|
||||
problemTable[CVP_FIRE] = getFireSeverity(); /* Fire */
|
||||
voteProblems(problemTable);
|
||||
|
||||
for (int z = 0; z < CVP_PROBLEM_COMPLAINTS; z++) {
|
||||
// Find biggest problem not taken yet
|
||||
int maxVotes = 0;
|
||||
int bestProblem = CVP_NUMPROBLEMS;
|
||||
for (int i = 0; i < CVP_NUMPROBLEMS; i++) {
|
||||
if ((problemVotes[i] > maxVotes) && (!problemTaken[i])) {
|
||||
bestProblem = i;
|
||||
maxVotes = problemVotes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// bestProblem == CVP_NUMPROBLEMS means no problem found
|
||||
problemOrder[z] = bestProblem;
|
||||
if (bestProblem < CVP_NUMPROBLEMS) {
|
||||
problemTaken[bestProblem] = true;
|
||||
}
|
||||
// else: No problem found.
|
||||
// Repeating the procedure will give the same result.
|
||||
// Optimize by filling all remaining entries, and breaking out
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Vote on the problems of the city.
|
||||
* @param problemTable Storage of how bad each problem is.
|
||||
*
|
||||
* @post problemVotes contains the vote counts
|
||||
*/
|
||||
void Micropolis::voteProblems(const short problemTable[PROBNUM])
|
||||
{
|
||||
for (int z = 0; z < PROBNUM; z++) {
|
||||
problemVotes[z] = 0;
|
||||
}
|
||||
|
||||
int problem = 0; // Problem to vote for
|
||||
int voteCount = 0; // Number of votes
|
||||
int loopCount = 0; // Number of attempts
|
||||
while (voteCount < 100 && loopCount < 600) {
|
||||
if (getRandom(300) < problemTable[problem]) {
|
||||
problemVotes[problem]++;
|
||||
voteCount++;
|
||||
}
|
||||
problem++;
|
||||
if (problem > PROBNUM) {
|
||||
problem = 0;
|
||||
}
|
||||
loopCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute average traffic in the city.
|
||||
* @return Value representing how large the traffic problem is.
|
||||
*/
|
||||
short Micropolis::getTrafficAverage()
|
||||
{
|
||||
Quad trafficTotal;
|
||||
short x, y, count;
|
||||
|
||||
trafficTotal = 0;
|
||||
count = 1;
|
||||
for (x=0; x < WORLD_W; x += landValueMap.MAP_BLOCKSIZE) {
|
||||
for (y=0; y < WORLD_H; y += landValueMap.MAP_BLOCKSIZE) {
|
||||
if (landValueMap.worldGet(x, y) > 0) {
|
||||
trafficTotal += trafficDensityMap.worldGet(x, y);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trafficAverage = (short)((trafficTotal / count) * 2.4);
|
||||
|
||||
return trafficAverage;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute severity of unemployment
|
||||
* @return Value representing the severity of unemployment problems
|
||||
*/
|
||||
short Micropolis::getUnemployment()
|
||||
{
|
||||
short b = (comPop + indPop) * 8;
|
||||
|
||||
if (b == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Ratio total people / working. At least 1.
|
||||
float r = ((float)resPop) / b;
|
||||
|
||||
b = (short)((r - 1) * 255); // (r - 1) is the fraction unemployed people
|
||||
return min(b, (short)255);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute severity of fire
|
||||
* @return Value representing the severity of fire problems
|
||||
*/
|
||||
short Micropolis::getFireSeverity()
|
||||
{
|
||||
return min(firePop * 5, 255);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute total score
|
||||
* @param problemTable Storage of how bad each problem is.
|
||||
*/
|
||||
void Micropolis::getScore(const short problemTable[PROBNUM])
|
||||
{
|
||||
int x, z;
|
||||
short cityScoreLast;
|
||||
|
||||
cityScoreLast = cityScore;
|
||||
x = 0;
|
||||
|
||||
for (z = 0; z < CVP_NUMPROBLEMS; z++) {
|
||||
x += problemTable[z]; /* add 7 probs */
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Should this expression depend on CVP_NUMPROBLEMS?
|
||||
*/
|
||||
x = x / 3; /* 7 + 2 average */
|
||||
x = min(x, 256);
|
||||
|
||||
z = clamp((256 - x) * 4, 0, 1000);
|
||||
|
||||
if (resCap) {
|
||||
z = (int)(z * .85);
|
||||
}
|
||||
|
||||
if (comCap) {
|
||||
z = (int)(z * .85);
|
||||
}
|
||||
|
||||
if (indCap) {
|
||||
z = (int)(z * .85);
|
||||
}
|
||||
|
||||
if (roadEffect < MAX_ROAD_EFFECT) {
|
||||
z -= MAX_ROAD_EFFECT - roadEffect;
|
||||
}
|
||||
|
||||
if (policeEffect < MAX_POLICE_STATION_EFFECT) {
|
||||
// 10.0001 = 10000.1 / 1000, 1/10.0001 is about 0.1
|
||||
z = (int)(z * (0.9 + (policeEffect / (10.0001 * MAX_POLICE_STATION_EFFECT))));
|
||||
}
|
||||
|
||||
if (fireEffect < MAX_FIRE_STATION_EFFECT) {
|
||||
// 10.0001 = 10000.1 / 1000, 1/10.0001 is about 0.1
|
||||
z = (int)(z * (0.9 + (fireEffect / (10.0001 * MAX_FIRE_STATION_EFFECT))));
|
||||
}
|
||||
|
||||
if (resValve < -1000) {
|
||||
z = (int)(z * .85);
|
||||
}
|
||||
|
||||
if (comValve < -1000) {
|
||||
z = (int)(z * .85);
|
||||
}
|
||||
|
||||
if (indValve < -1000) {
|
||||
z = (int)(z * .85);
|
||||
}
|
||||
|
||||
float SM = 1.0;
|
||||
if (cityPop == 0 || cityPopDelta == 0) {
|
||||
SM = 1.0; // there is nobody or no migration happened
|
||||
|
||||
} else if (cityPopDelta == cityPop) {
|
||||
SM = 1.0; // city sprang into existence or doubled in size
|
||||
|
||||
} else if (cityPopDelta > 0) {
|
||||
SM = ((float)cityPopDelta / cityPop) + 1.0f;
|
||||
|
||||
} else if (cityPopDelta < 0) {
|
||||
SM = 0.95f + ((float)cityPopDelta / (cityPop - cityPopDelta));
|
||||
}
|
||||
|
||||
z = (int)(z * SM);
|
||||
z = z - getFireSeverity() - cityTax; // dec score for fires and taxes
|
||||
|
||||
float TM = unpoweredZoneCount + poweredZoneCount; // dec score for unpowered zones
|
||||
if (TM > 0.0) {
|
||||
z = (int)(z * (float)(poweredZoneCount / TM));
|
||||
} else {
|
||||
}
|
||||
|
||||
z = clamp(z, 0, 1000);
|
||||
|
||||
cityScore = (cityScore + z) / 2;
|
||||
|
||||
cityScoreDelta = cityScore - cityScoreLast;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Vote whether the mayor is doing a good job
|
||||
* @post #cityYes contains the number of 'yes' votes
|
||||
*/
|
||||
void Micropolis::doVotes()
|
||||
{
|
||||
int z;
|
||||
|
||||
cityYes = 0;
|
||||
|
||||
for (z = 0; z < 100; z++) {
|
||||
if (getRandom(1000) < cityScore) {
|
||||
cityYes++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Push new score to the user */
|
||||
void Micropolis::doScoreCard()
|
||||
{
|
||||
// The user interface should pull these raw values out and format
|
||||
// them. The simulator core used to format them and push them out,
|
||||
// but the user interface should pull them out and format them
|
||||
// itself.
|
||||
|
||||
// City Evaluation ${FormatYear(currentYear())}
|
||||
// Public Opinion
|
||||
// Is the mayor doing a good job?
|
||||
// Yes: ${FormatPercent(cityYes)}
|
||||
// No: ${FormatPercent(100 - cityYes)}
|
||||
// What are the worst problems?
|
||||
// for i in range(0, CVP_PROBLEM_COMPLAINTS),
|
||||
// while problemOrder[i] < CVP_NUMPROBLEMS:
|
||||
// ${probStr[problemOrder[i]]}:
|
||||
// ${FormatPercent(problemVotes[problemOrder[i]])}
|
||||
// Statistics
|
||||
// Population: ${FormatNumber(cityPop)}
|
||||
// Net Migration: ${FormatNumber(cityPopDelta)} (last year)
|
||||
// Assessed Value: ${FormatMoney(cityAssessedValue))
|
||||
// Category: ${cityClassStr[cityClass]}
|
||||
// Game Level: ${cityLevelStr[gameLevel]}
|
||||
|
||||
callback->updateEvaluation(this, callbackVal);
|
||||
}
|
||||
|
||||
/** Request that new score is displayed to the user. */
|
||||
void Micropolis::changeEval()
|
||||
{
|
||||
//printf("changeEval\n");
|
||||
evalChanged = true;
|
||||
}
|
||||
|
||||
|
||||
/** Update the score after being requested. */
|
||||
void Micropolis::scoreDoer()
|
||||
{
|
||||
//printf("scoreDoer evalChanged %d\n", evalChanged);
|
||||
if (evalChanged) {
|
||||
doScoreCard();
|
||||
evalChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of problem in the city.
|
||||
* @return Number of problems.
|
||||
*/
|
||||
int Micropolis::countProblems()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < CVP_PROBLEM_COMPLAINTS; i++) {
|
||||
if (problemOrder[i] == CVP_NUMPROBLEMS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index of the \a i-th worst problem.
|
||||
* @param i Number of the problem.
|
||||
* @return Index into the #problemOrder table of the \a i-th problem.
|
||||
* Returns \c -1 if such a problem does not exist.
|
||||
*/
|
||||
int Micropolis::getProblemNumber(int i)
|
||||
{
|
||||
if (i < 0 || i >= CVP_PROBLEM_COMPLAINTS
|
||||
|| problemOrder[i] == CVP_NUMPROBLEMS) {
|
||||
return -1;
|
||||
} else {
|
||||
return problemOrder[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return number of votes to solve the \a i-th worst problem.
|
||||
* @param i Number of the problem.
|
||||
* @return Number of votes to solve the \a i-th worst problem.
|
||||
* Returns \c -1 if such a problem does not exist.
|
||||
*/
|
||||
int Micropolis::getProblemVotes(int i)
|
||||
{
|
||||
if (i < 0 || i >= CVP_PROBLEM_COMPLAINTS
|
||||
|| problemOrder[i] == CVP_NUMPROBLEMS) {
|
||||
return -1;
|
||||
} else {
|
||||
return problemVotes[problemOrder[i]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
646
core/fileio.cpp
Normal file
646
core/fileio.cpp
Normal file
|
@ -0,0 +1,646 @@
|
|||
/* fileio.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file fileio.cpp
|
||||
* @brief File I/O operations for Micropolis game engine.
|
||||
*
|
||||
* Implements file loading and saving functionalities for the
|
||||
* Micropolis game engine. It includes endianess conversions for data
|
||||
* compatibility between different architectures, loading and saving
|
||||
* city files, handling scenario files, and various utility functions
|
||||
* to support file I/O operations. It also includes functions to
|
||||
* report file operations to the front-end.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifdef IS_INTEL
|
||||
|
||||
/**
|
||||
* Convert an array of short values between MAC and Intel endian formats.
|
||||
* @param buf Array with shorts.
|
||||
* @param len Number of short values in the array.
|
||||
*/
|
||||
#define SWAP_SHORTS(buf, len) swap_shorts(buf, len)
|
||||
|
||||
/**
|
||||
* Convert an array of long values between MAC and Intel endian formats.
|
||||
* @param buf Array with longs.
|
||||
* @param len Number of long values in the array.
|
||||
*/
|
||||
#define HALF_SWAP_LONGS(buf, len) half_swap_longs(buf, len)
|
||||
|
||||
/**
|
||||
* Swap upper and lower byte of all shorts in the array.
|
||||
* @param buf Array with shorts.
|
||||
* @param len Number of short values in the array.
|
||||
*/
|
||||
static void swap_shorts(short *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Flip bytes in each short! */
|
||||
for (i = 0; i < len; i++) {
|
||||
*buf = ((*buf & 0xFF) <<8) | ((*buf &0xFF00) >>8);
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Swap upper and lower words of all longs in the array.
|
||||
* @param buf Array with longs.
|
||||
* @param len Number of long values in the array.
|
||||
*/
|
||||
static void half_swap_longs(long *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Flip bytes in each long! */
|
||||
for (i = 0; i < len; i++) {
|
||||
long l = *buf;
|
||||
*buf =
|
||||
((l & 0x0000ffff) << 16) |
|
||||
((l & 0xffff0000) >> 16);
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
/**
|
||||
* Convert an array of short values between MAC and MAC endian formats.
|
||||
* @param buf Array with shorts.
|
||||
* @param len Number of short values in the array.
|
||||
* @note This version does not change anything since the data is already in the
|
||||
* correct format.
|
||||
*/
|
||||
#define SWAP_SHORTS(buf, len)
|
||||
|
||||
/**
|
||||
* Convert an array of long values between MAC and MAC endian formats.
|
||||
* @param buf Array with longs.
|
||||
* @param len Number of long values in the array.
|
||||
* @note This version does not change anything since the data is already in the
|
||||
* correct format.
|
||||
*/
|
||||
#define HALF_SWAP_LONGS(buf, len)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Load an array of short values from file to memory.
|
||||
*
|
||||
* Convert to the correct processor architecture, if necessary.
|
||||
* @param buf Buffer to put the loaded short values in.
|
||||
* @param len Number of short values to load.
|
||||
* @param f File handle of the file to load from.
|
||||
* @return Load was succesfull.
|
||||
*/
|
||||
static bool load_short(short *buf, int len, FILE *f)
|
||||
{
|
||||
size_t result = fread(buf, sizeof(short), len, f);
|
||||
|
||||
if ((int)result != len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SWAP_SHORTS(buf, len); /* to intel */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save an array of short values from memory to file.
|
||||
*
|
||||
* Convert to the correct endianness first, if necessary.
|
||||
* @param buf Buffer containing the short values to save.
|
||||
* @param len Number of short values to save.
|
||||
* @param f File handle of the file to save to.
|
||||
* @return Save was succesfull.
|
||||
*/
|
||||
static bool save_short(short *buf, int len, FILE *f)
|
||||
{
|
||||
SWAP_SHORTS(buf, len); /* to MAC */
|
||||
|
||||
if ((int)fwrite(buf, sizeof(short), len, f) != len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SWAP_SHORTS(buf, len); /* back to intel */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a city file from a given filename and (optionally) directory.
|
||||
* @param filename Name of the file to load.
|
||||
* @param dir If not \c NULL, name of the directory containing the file.
|
||||
* @return Load was succesfull.
|
||||
*/
|
||||
bool Micropolis::loadFileData(const std::string &filename)
|
||||
{
|
||||
FILE *f;
|
||||
Quad size;
|
||||
|
||||
// Open the file.
|
||||
f = fopen(filename.c_str(), "rb");
|
||||
|
||||
// open() failed; report failure.
|
||||
if (f == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fseek(f, 0L, SEEK_END);
|
||||
size = ftell(f);
|
||||
fseek(f, 0L, SEEK_SET);
|
||||
|
||||
bool result =
|
||||
(size == 27120) &&
|
||||
load_short(resHist, HISTORY_LENGTH / sizeof(short), f) &&
|
||||
load_short(comHist, HISTORY_LENGTH / sizeof(short), f) &&
|
||||
load_short(indHist, HISTORY_LENGTH / sizeof(short), f) &&
|
||||
load_short(crimeHist, HISTORY_LENGTH / sizeof(short), f) &&
|
||||
load_short(pollutionHist, HISTORY_LENGTH / sizeof(short), f) &&
|
||||
load_short(moneyHist, HISTORY_LENGTH / sizeof(short), f) &&
|
||||
load_short(miscHist, MISC_HISTORY_LENGTH / sizeof(short), f) &&
|
||||
load_short(((short *)&map[0][0]), WORLD_W * WORLD_H, f);
|
||||
|
||||
fclose(f);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a file, and initialize the game variables.
|
||||
* @param filename Name of the file to load.
|
||||
* @return Load was succesfull.
|
||||
*/
|
||||
bool Micropolis::loadFile(const std::string &filename)
|
||||
{
|
||||
long n;
|
||||
|
||||
if (!loadFileData(filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* total funds is a long..... miscHist is array of shorts */
|
||||
/* total funds is being put in the 50th & 51th word of miscHist */
|
||||
/* find the address, cast the ptr to a longPtr, take contents */
|
||||
|
||||
n = *(Quad *)(miscHist + 50);
|
||||
HALF_SWAP_LONGS(&n, 1);
|
||||
setFunds(n);
|
||||
|
||||
n = *(Quad *)(miscHist + 8);
|
||||
HALF_SWAP_LONGS(&n, 1);
|
||||
cityTime = n;
|
||||
|
||||
setAutoBulldoze(miscHist[52] != 0); // flag for autoBulldoze
|
||||
setAutoBudget(miscHist[53] != 0); // flag for autoBudget
|
||||
setAutoGoto(miscHist[54] != 0); // flag for auto-goto
|
||||
setEnableSound(miscHist[55] != 0); // flag for the sound on/off
|
||||
setCityTax(miscHist[56]);
|
||||
setSpeed(miscHist[57]);
|
||||
changeCensus();
|
||||
mustUpdateOptions = true;
|
||||
|
||||
/* yayaya */
|
||||
|
||||
n = *(Quad *)(miscHist + 58);
|
||||
HALF_SWAP_LONGS(&n, 1);
|
||||
policePercent = ((float)n) / ((float)65536);
|
||||
|
||||
n = *(Quad *)(miscHist + 60);
|
||||
HALF_SWAP_LONGS(&n, 1);
|
||||
firePercent = (float)n / (float)65536.0;
|
||||
|
||||
n = *(Quad *)(miscHist + 62);
|
||||
HALF_SWAP_LONGS(&n, 1);
|
||||
roadPercent = (float)n / (float)65536.0;
|
||||
|
||||
policePercent =
|
||||
(float)(*(Quad*)(miscHist + 58)) /
|
||||
(float)65536.0; /* and 59 */
|
||||
firePercent =
|
||||
(float)(*(Quad*)(miscHist + 60)) /
|
||||
(float)65536.0; /* and 61 */
|
||||
roadPercent =
|
||||
(float)(*(Quad*)(miscHist + 62)) /
|
||||
(float)65536.0; /* and 63 */
|
||||
|
||||
cityTime = max((Quad)0, cityTime);
|
||||
|
||||
// If the tax is nonsensical, set it to a reasonable value.
|
||||
if (cityTax > 20 || cityTax < 0) {
|
||||
setCityTax(7);
|
||||
}
|
||||
|
||||
// If the speed is nonsensical, set it to a reasonable value.
|
||||
if (simSpeed < 0 || simSpeed > 3) {
|
||||
setSpeed(3);
|
||||
}
|
||||
|
||||
setSpeed(simSpeed);
|
||||
setPasses(1);
|
||||
initFundingLevel();
|
||||
|
||||
// Set the scenario id to 0.
|
||||
initWillStuff();
|
||||
scenario = SC_NONE;
|
||||
initSimLoad = 1;
|
||||
doInitialEval = false;
|
||||
doSimInit();
|
||||
invalidateMaps();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save a game to disk.
|
||||
* @param filename Name of the file to use for storing the game.
|
||||
* @return The game was saved successfully.
|
||||
*/
|
||||
bool Micropolis::saveFile(const std::string &filename)
|
||||
{
|
||||
long n;
|
||||
FILE *f;
|
||||
|
||||
if ((f = fopen(filename.c_str(), "wb")) == NULL) {
|
||||
/// @todo Report error saving file.
|
||||
return false;
|
||||
}
|
||||
|
||||
/* total funds is a long..... miscHist is array of ints */
|
||||
/* total funds is bien put in the 50th & 51th word of miscHist */
|
||||
/* find the address, cast the ptr to a longPtr, take contents */
|
||||
|
||||
n = totalFunds;
|
||||
HALF_SWAP_LONGS(&n, 1);
|
||||
(*(Quad *)(miscHist + 50)) = n;
|
||||
|
||||
n = cityTime;
|
||||
HALF_SWAP_LONGS(&n, 1);
|
||||
(*(Quad *)(miscHist + 8)) = n;
|
||||
|
||||
miscHist[52] = autoBulldoze; // flag for autoBulldoze
|
||||
miscHist[53] = autoBudget; // flag for autoBudget
|
||||
miscHist[54] = autoGoto; // flag for auto-goto
|
||||
miscHist[55] = enableSound; // flag for the sound on/off
|
||||
miscHist[57] = simSpeed;
|
||||
miscHist[56] = cityTax; /* post release */
|
||||
|
||||
/* yayaya */
|
||||
|
||||
n = (int)(policePercent * 65536);
|
||||
HALF_SWAP_LONGS(&n, 1);
|
||||
(*(Quad *)(miscHist + 58)) = n;
|
||||
|
||||
n = (int)(firePercent * 65536);
|
||||
HALF_SWAP_LONGS(&n, 1);
|
||||
(*(Quad *)(miscHist + 60)) = n;
|
||||
|
||||
n = (int)(roadPercent * 65536);
|
||||
HALF_SWAP_LONGS(&n, 1);
|
||||
(*(Quad *)(miscHist + 62)) = n;
|
||||
|
||||
bool result =
|
||||
save_short(resHist, HISTORY_LENGTH / 2, f) &&
|
||||
save_short(comHist, HISTORY_LENGTH / 2, f) &&
|
||||
save_short(indHist, HISTORY_LENGTH / 2, f) &&
|
||||
save_short(crimeHist, HISTORY_LENGTH / 2, f) &&
|
||||
save_short(pollutionHist, HISTORY_LENGTH / 2, f) &&
|
||||
save_short(moneyHist, HISTORY_LENGTH / 2, f) &&
|
||||
save_short(miscHist, MISC_HISTORY_LENGTH / 2, f) &&
|
||||
save_short(((short *)&map[0][0]), WORLD_W * WORLD_H, f);
|
||||
|
||||
fclose(f);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load a scenario.
|
||||
* @param s Scenario to load.
|
||||
* @note \a s cannot be \c SC_NONE.
|
||||
*/
|
||||
void Micropolis::loadScenario(Scenario s)
|
||||
{
|
||||
std::string name = NULL;
|
||||
std::string fname = NULL;
|
||||
|
||||
cityFileName = "";
|
||||
|
||||
setGameLevel(LEVEL_EASY);
|
||||
|
||||
if (s < SC_DULLSVILLE || s > SC_RIO) {
|
||||
s = SC_DULLSVILLE;
|
||||
}
|
||||
|
||||
switch (s) {
|
||||
case SC_DULLSVILLE:
|
||||
name = "Dullsville";
|
||||
fname = "cities/scenario_dullsville.cty";
|
||||
scenario = SC_DULLSVILLE;
|
||||
cityTime = ((1900 - 1900) * 48) + 2;
|
||||
setFunds(5000);
|
||||
break;
|
||||
case SC_SAN_FRANCISCO:
|
||||
name = "San Francisco";
|
||||
fname = "cities/scenario_san_francisco.cty";
|
||||
scenario = SC_SAN_FRANCISCO;
|
||||
cityTime = ((1906 - 1900) * 48) + 2;
|
||||
setFunds(20000);
|
||||
break;
|
||||
case SC_HAMBURG:
|
||||
name = "Hamburg";
|
||||
fname = "cities/scenario_hamburg.cty";
|
||||
scenario = SC_HAMBURG;
|
||||
cityTime = ((1944 - 1900) * 48) + 2;
|
||||
setFunds(20000);
|
||||
break;
|
||||
case SC_BERN:
|
||||
name = "Bern";
|
||||
fname = "cities/scenario_bern.cty";
|
||||
scenario = SC_BERN;
|
||||
cityTime = ((1965 - 1900) * 48) + 2;
|
||||
setFunds(20000);
|
||||
break;
|
||||
case SC_TOKYO:
|
||||
name = "Tokyo";
|
||||
fname = "cities/scenario_tokyo.cty";
|
||||
scenario = SC_TOKYO;
|
||||
cityTime = ((1957 - 1900) * 48) + 2;
|
||||
setFunds(20000);
|
||||
break;
|
||||
case SC_DETROIT:
|
||||
name = "Detroit";
|
||||
fname = "cities/scenario_detroit.cty";
|
||||
scenario = SC_DETROIT;
|
||||
cityTime = ((1972 - 1900) * 48) + 2;
|
||||
setFunds(20000);
|
||||
break;
|
||||
case SC_BOSTON:
|
||||
name = "Boston";
|
||||
fname = "cities/scenario_boston.cty";
|
||||
scenario = SC_BOSTON;
|
||||
cityTime = ((2010 - 1900) * 48) + 2;
|
||||
setFunds(20000);
|
||||
break;
|
||||
case SC_RIO:
|
||||
name = "Rio de Janeiro";
|
||||
fname = "cities/scenario_rio_de_janeiro.cty";
|
||||
scenario = SC_RIO;
|
||||
cityTime = ((2047 - 1900) * 48) + 2;
|
||||
setFunds(20000);
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
|
||||
setCleanCityName(name);
|
||||
setSpeed(3);
|
||||
setCityTax(7);
|
||||
|
||||
loadFileData(fname);
|
||||
|
||||
initWillStuff();
|
||||
initFundingLevel();
|
||||
updateFunds();
|
||||
invalidateMaps();
|
||||
initSimLoad = 1;
|
||||
doInitialEval = false;
|
||||
doSimInit();
|
||||
didLoadScenario(s, name, fname);
|
||||
}
|
||||
|
||||
|
||||
/** Report to the front-end that the scenario was loaded. */
|
||||
void Micropolis::didLoadScenario(int s, const std::string name, const std::string fname)
|
||||
{
|
||||
callback->didLoadScenario(this, callbackVal, name, fname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to load a new game from disk.
|
||||
* @param filename Name of the file to load.
|
||||
* @return Game was loaded successfully.
|
||||
* @todo In what state is the game left when loading fails?
|
||||
* @todo String normalization code is duplicated in Micropolis::saveCityAs().
|
||||
* Extract to a sub-function.
|
||||
* @bug Function fails if \c lastDot<lastSlash (ie with \c "x.y/bla" )
|
||||
*/
|
||||
bool Micropolis::loadCity(const std::string &filename)
|
||||
{
|
||||
if (loadFile(filename)) {
|
||||
|
||||
cityFileName = filename;
|
||||
|
||||
size_t lastSlash = cityFileName.find_last_of('/');
|
||||
size_t pos = (lastSlash == std::string::npos) ? 0 : lastSlash + 1;
|
||||
|
||||
size_t lastDot = cityFileName.find_last_of('.');
|
||||
size_t last =
|
||||
(lastDot == std::string::npos) ? cityFileName.length() : lastDot;
|
||||
|
||||
std::string newCityName = cityFileName.substr(pos, last - pos);
|
||||
setCityName(newCityName);
|
||||
|
||||
didLoadCity(filename);
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
didntLoadCity(filename);
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** Report to the frontend that the game was successfully loaded. */
|
||||
void Micropolis::didLoadCity(const std::string &filename)
|
||||
{
|
||||
callback->didLoadCity(this, callbackVal, filename);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Report to the frontend that the game failed to load.
|
||||
* @param msg File that attempted to load
|
||||
*/
|
||||
void Micropolis::didntLoadCity(const std::string &filename)
|
||||
{
|
||||
callback->didntLoadCity(this, callbackVal, filename);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to save the game.
|
||||
* @todo This is a no-op if the Micropolis::cityFileName is empty.
|
||||
* In that case, we should probably warn the user about the failure.
|
||||
*/
|
||||
void Micropolis::saveCity()
|
||||
{
|
||||
if (cityFileName.length() > 0) {
|
||||
|
||||
doSaveCityAs(cityFileName);
|
||||
|
||||
} else {
|
||||
if (saveFile(cityFileName)) {
|
||||
|
||||
didSaveCity(cityFileName);
|
||||
|
||||
} else {
|
||||
|
||||
didntSaveCity(cityFileName);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Report to the frontend that the city is being saved.
|
||||
* @param filename Name of the file used
|
||||
*/
|
||||
void Micropolis::doSaveCityAs(const std::string &filename)
|
||||
{
|
||||
callback->saveCityAs(this, callbackVal, filename);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Report to the frontend that the city was saved successfully.
|
||||
* @param filename Name of the file used
|
||||
*/
|
||||
void Micropolis::didSaveCity(const std::string &filename)
|
||||
{
|
||||
callback->didSaveCity(this, callbackVal, filename);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Report to the frontend that the city could not be saved.
|
||||
* @param filename Name of the file used
|
||||
*/
|
||||
void Micropolis::didntSaveCity(const std::string &filename)
|
||||
{
|
||||
callback->didntSaveCity(this, callbackVal, filename);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save the city under a new name (?)
|
||||
* @param filename Name of the file to use for storing the game.
|
||||
* @todo String normalization code is duplicated in Micropolis::loadCity().
|
||||
* Extract to a sub-function.
|
||||
* @bug Function fails if \c lastDot<lastSlash (ie with \c "x.y/bla" )
|
||||
*/
|
||||
void Micropolis::saveCityAs(const std::string &filename)
|
||||
{
|
||||
cityFileName = filename;
|
||||
|
||||
if (saveFile(cityFileName)) {
|
||||
|
||||
size_t lastDot = cityFileName.find_last_of('.');
|
||||
size_t lastSlash = cityFileName.find_last_of('/');
|
||||
|
||||
size_t pos =
|
||||
(lastSlash == std::string::npos) ? 0 : lastSlash + 1;
|
||||
size_t last =
|
||||
(lastDot == std::string::npos) ? cityFileName.length() : lastDot;
|
||||
size_t len =
|
||||
last - pos;
|
||||
std::string newCityName =
|
||||
cityFileName.substr(pos, len);
|
||||
|
||||
setCityName(newCityName);
|
||||
|
||||
didSaveCity(cityName);
|
||||
|
||||
} else {
|
||||
|
||||
didntSaveCity(cityFileName);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
149
core/frontendmessage.cpp
Normal file
149
core/frontendmessage.cpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
/* frontendmessage.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file frontendmessage.cpp
|
||||
* @brief Implementation of frontend message handling in the
|
||||
* Micropolis engine.
|
||||
*
|
||||
* This file is part of the Micropolis game engine. It defines the
|
||||
* FrontendMessage class and its subclasses, which are used to handle
|
||||
* communication between the game engine and the frontend. This
|
||||
* includes sending messages about tool actions and sound effects. The
|
||||
* design allows for a flexible way of notifying the frontend about
|
||||
* various events happening within the game engine.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Frontend message storage
|
||||
|
||||
|
||||
/** Base class constructor. */
|
||||
FrontendMessage::FrontendMessage()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/** Base class destructor. */
|
||||
FrontendMessage::~FrontendMessage()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @fn void FrontendMessage::sendMessage(Micropolis *sim)
|
||||
* @brief Send the message to the front-end.
|
||||
* @param sim Simulator instance to use.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
FrontendMessageDidTool::FrontendMessageDidTool(const std::string &tool, int x, int y)
|
||||
{
|
||||
this->tool = tool;
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
||||
|
||||
|
||||
FrontendMessageDidTool::~FrontendMessageDidTool()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void FrontendMessageDidTool::sendMessage(Micropolis *sim) const
|
||||
{
|
||||
sim->didTool(this->tool, this->x, this->y);
|
||||
}
|
||||
|
||||
|
||||
FrontendMessageMakeSound::FrontendMessageMakeSound(
|
||||
const std::string &channel,
|
||||
const std::string &sound,
|
||||
int x, int y)
|
||||
{
|
||||
this->channel = channel;
|
||||
this->sound = sound;
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
||||
|
||||
|
||||
FrontendMessageMakeSound::~FrontendMessageMakeSound()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void FrontendMessageMakeSound::sendMessage(Micropolis *sim) const
|
||||
{
|
||||
sim->makeSound(this->channel, this->sound, this->x, this->y);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
141
core/frontendmessage.h
Normal file
141
core/frontendmessage.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
/* frontendmessage.h
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file frontendmessage.h
|
||||
* @brief Defines classes for handling messages between the game
|
||||
* engine and the GUI frontend.
|
||||
*
|
||||
* This header file includes class definitions for managing and
|
||||
* sending messages from the Micropolis game engine to the graphical
|
||||
* user interface (GUI) frontend. It facilitates communication and
|
||||
* interactions between the game's backend and frontend, ensuring a
|
||||
* responsive and dynamic user experience. Classes defined here
|
||||
* include the general `FrontendMessage` class and its specialized
|
||||
* subclasses such as `FrontendMessageDidTool` and
|
||||
* `FrontendMessageMakeSound` for specific message types.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _H_FRONTENDMESSAGE
|
||||
#define _H_FRONTENDMESSAGE
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
class Micropolis; // Forward declaration.
|
||||
|
||||
|
||||
/** A message to the GUI frontend. */
|
||||
class FrontendMessage {
|
||||
|
||||
public:
|
||||
|
||||
FrontendMessage();
|
||||
|
||||
virtual ~FrontendMessage();
|
||||
|
||||
virtual void sendMessage(Micropolis *sim) const = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Store a 'didTool' message. */
|
||||
class FrontendMessageDidTool : public FrontendMessage {
|
||||
|
||||
public:
|
||||
|
||||
std::string tool;
|
||||
int x, y;
|
||||
|
||||
FrontendMessageDidTool(const std::string &tool, int x, int y);
|
||||
|
||||
virtual ~FrontendMessageDidTool();
|
||||
|
||||
virtual void sendMessage(Micropolis *sim) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Store a 'makeSound' message. */
|
||||
class FrontendMessageMakeSound : public FrontendMessage {
|
||||
|
||||
public:
|
||||
|
||||
std::string channel;
|
||||
std::string sound;
|
||||
int x, y;
|
||||
|
||||
FrontendMessageMakeSound(const std::string &channel, const std::string &sound, int x, int y);
|
||||
|
||||
virtual ~FrontendMessageMakeSound();
|
||||
|
||||
virtual void sendMessage(Micropolis *sim) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#endif
|
761
core/generate.cpp
Normal file
761
core/generate.cpp
Normal file
|
@ -0,0 +1,761 @@
|
|||
/* generate.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file generate.cpp
|
||||
* @brief Contains functions related to terrain generation in
|
||||
* Micropolis.
|
||||
*
|
||||
* This file is a part of Micropolis and is responsible for generating
|
||||
* various terrain features such as rivers, lakes, islands, and
|
||||
* forests. It includes functions for creating randomized maps and
|
||||
* modifying terrain features. The terrain generation methods take
|
||||
* into account different parameters like seed value for random
|
||||
* generation and terrain characteristics to create diverse and unique
|
||||
* city landscapes.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Create a new map for a city.
|
||||
* @bug We use a random number generator to draw a seed for initializing the
|
||||
* random number generator?
|
||||
*/
|
||||
void Micropolis::generateSomeRandomCity()
|
||||
{
|
||||
generateSomeCity(getRandom16());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a map for a city.
|
||||
* @param seed Random number generator initializing seed
|
||||
*/
|
||||
void Micropolis::generateSomeCity(int seed)
|
||||
{
|
||||
cityFileName = "";
|
||||
|
||||
generateMap(seed);
|
||||
scenario = SC_NONE;
|
||||
cityTime = 0;
|
||||
initSimLoad = 2;
|
||||
doInitialEval = false;
|
||||
|
||||
initWillStuff();
|
||||
resetMapState();
|
||||
resetEditorState();
|
||||
invalidateMaps();
|
||||
updateFunds();
|
||||
doSimInit();
|
||||
|
||||
simUpdate();
|
||||
|
||||
callback->didGenerateMap(this, callbackVal, seed);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a map.
|
||||
* @param seed Initialization seed for the random generator.
|
||||
*/
|
||||
void Micropolis::generateMap(int seed)
|
||||
{
|
||||
generatedCitySeed = seed;
|
||||
|
||||
seedRandom(seed);
|
||||
|
||||
// Construct land.
|
||||
if (terrainCreateIsland < 0) {
|
||||
if (getRandom(100) < 10) { /* chance that island is generated */
|
||||
makeIsland();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (terrainCreateIsland == 1) {
|
||||
makeNakedIsland();
|
||||
} else {
|
||||
clearMap();
|
||||
}
|
||||
|
||||
// Lay a river.
|
||||
if (terrainCurveLevel != 0) {
|
||||
int terrainXStart = 40 + getRandom(WORLD_W - 80);
|
||||
int terrainYStart = 33 + getRandom(WORLD_H - 67);
|
||||
|
||||
Position terrainPos(terrainXStart, terrainYStart);
|
||||
|
||||
doRivers(terrainPos);
|
||||
}
|
||||
|
||||
// Lay a few lakes.
|
||||
if (terrainLakeLevel != 0) {
|
||||
makeLakes();
|
||||
}
|
||||
|
||||
smoothRiver();
|
||||
|
||||
// And add trees.
|
||||
if (terrainTreeLevel != 0) {
|
||||
doTrees();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** Clear the whole world to ::DIRT tiles */
|
||||
void Micropolis::clearMap()
|
||||
{
|
||||
short x, y;
|
||||
|
||||
for (x = 0; x < WORLD_W; x++) {
|
||||
for (y = 0; y < WORLD_H; y++) {
|
||||
map[x][y] = DIRT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Clear everything from all land */
|
||||
void Micropolis::clearUnnatural()
|
||||
{
|
||||
short x, y;
|
||||
|
||||
for (x = 0; x < WORLD_W; x++) {
|
||||
for (y = 0; y < WORLD_H; y++) {
|
||||
if (map[x][y] > WOODS) {
|
||||
map[x][y] = DIRT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a plain island as world, surrounded by 5 tiles of river.
|
||||
*/
|
||||
void Micropolis::makeNakedIsland()
|
||||
{
|
||||
const int terrainIslandRadius = ISLAND_RADIUS;
|
||||
int x, y;
|
||||
|
||||
for (x = 0; x < WORLD_W; x++) {
|
||||
for (y = 0; y < WORLD_H; y++) {
|
||||
if ((x < 5) || (x >= WORLD_W - 5) ||
|
||||
(y < 5) || (y >= WORLD_H - 5)) {
|
||||
map[x][y] = RIVER;
|
||||
} else {
|
||||
map[x][y] = DIRT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; x < WORLD_W - 5; x += 2) {
|
||||
|
||||
int mapY = getERandom(terrainIslandRadius);
|
||||
plopBRiver(Position(x, mapY));
|
||||
|
||||
mapY = (WORLD_H - 10) - getERandom(terrainIslandRadius);
|
||||
plopBRiver(Position(x, mapY));
|
||||
|
||||
plopSRiver(Position(x, 0));
|
||||
plopSRiver(Position(x, WORLD_H - 6));
|
||||
}
|
||||
|
||||
for (y = 0; y < WORLD_H - 5; y += 2) {
|
||||
|
||||
int mapX = getERandom(terrainIslandRadius);
|
||||
plopBRiver(Position(mapX, y));
|
||||
|
||||
mapX = (WORLD_W - 10) - getERandom(terrainIslandRadius);
|
||||
plopBRiver(Position(mapX, y));
|
||||
|
||||
plopSRiver(Position(0, y));
|
||||
plopSRiver(Position(WORLD_W - 6, y));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** Construct a new world as an island */
|
||||
void Micropolis::makeIsland()
|
||||
{
|
||||
makeNakedIsland();
|
||||
smoothRiver();
|
||||
doTrees();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a number of lakes, depending on the Micropolis::terrainLakeLevel.
|
||||
*/
|
||||
void Micropolis::makeLakes()
|
||||
{
|
||||
short numLakes;
|
||||
|
||||
if (terrainLakeLevel < 0) {
|
||||
numLakes = getRandom(10);
|
||||
} else {
|
||||
numLakes = terrainLakeLevel / 2;
|
||||
}
|
||||
|
||||
while (numLakes > 0) {
|
||||
int x = getRandom(WORLD_W - 21) + 10;
|
||||
int y = getRandom(WORLD_H - 20) + 10;
|
||||
|
||||
makeSingleLake(Position(x, y));
|
||||
|
||||
numLakes--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a random lake at \a pos.
|
||||
* @param pos Rough position of the lake.
|
||||
*/
|
||||
void Micropolis::makeSingleLake(const Position &pos)
|
||||
{
|
||||
int numPlops = getRandom(12) + 2;
|
||||
|
||||
while (numPlops > 0) {
|
||||
Position plopPos(pos, getRandom(12) - 6, getRandom(12) - 6);
|
||||
|
||||
if (getRandom(4)) {
|
||||
plopSRiver(plopPos);
|
||||
} else {
|
||||
plopBRiver(plopPos);
|
||||
}
|
||||
|
||||
numPlops--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Splash a bunch of trees down near (\a xloc, \a yloc).
|
||||
*
|
||||
* Amount of trees is controlled by Micropolis::terrainTreeLevel.
|
||||
* @param xloc Horizontal position of starting point for splashing trees.
|
||||
* @param yloc Vertical position of starting point for splashing trees.
|
||||
* @note Trees are not smoothed.
|
||||
* @bug Function generates trees even if Micropolis::terrainTreeLevel is 0.
|
||||
*/
|
||||
void Micropolis::treeSplash(short xloc, short yloc)
|
||||
{
|
||||
short numTrees;
|
||||
|
||||
if (terrainTreeLevel < 0) {
|
||||
numTrees = getRandom(150) + 50;
|
||||
} else {
|
||||
numTrees = getRandom(100 + (terrainTreeLevel * 2)) + 50;
|
||||
}
|
||||
|
||||
Position treePos(xloc, yloc);
|
||||
|
||||
while (numTrees > 0) {
|
||||
Direction2 dir = (Direction2)(DIR2_NORTH + getRandom(7));
|
||||
treePos.move(dir);
|
||||
|
||||
if (!treePos.testBounds()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((map[treePos.posX][treePos.posY] & LOMASK) == DIRT) {
|
||||
map[treePos.posX][treePos.posY] = WOODS | BLBNBIT;
|
||||
}
|
||||
|
||||
numTrees--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Splash trees around the world. */
|
||||
void Micropolis::doTrees()
|
||||
{
|
||||
short Amount, x, xloc, yloc;
|
||||
|
||||
if (terrainTreeLevel < 0) {
|
||||
Amount = getRandom(100) + 50;
|
||||
} else {
|
||||
Amount = terrainTreeLevel + 3;
|
||||
}
|
||||
|
||||
for (x = 0; x < Amount; x++) {
|
||||
xloc = getRandom(WORLD_W - 1);
|
||||
yloc = getRandom(WORLD_H - 1);
|
||||
treeSplash(xloc, yloc);
|
||||
}
|
||||
|
||||
smoothTrees();
|
||||
smoothTrees();
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::smoothRiver()
|
||||
{
|
||||
static short dx[4] = { -1, 0, 1, 0 };
|
||||
static short dy[4] = { 0, 1, 0, -1 };
|
||||
static short REdTab[16] = {
|
||||
13 | BULLBIT, 13 | BULLBIT, 17 | BULLBIT, 15 | BULLBIT,
|
||||
5 | BULLBIT, 2, 19 | BULLBIT, 17 | BULLBIT,
|
||||
9 | BULLBIT, 11 | BULLBIT, 2, 13 | BULLBIT,
|
||||
7 | BULLBIT, 9 | BULLBIT, 5 | BULLBIT, 2 };
|
||||
|
||||
short bitIndex, z, xTemp, yTemp;
|
||||
short temp, x, y;
|
||||
|
||||
for (x = 0; x < WORLD_W; x++) {
|
||||
for (y = 0; y < WORLD_H; y++) {
|
||||
|
||||
if (map[x][y] == REDGE) {
|
||||
bitIndex = 0;
|
||||
|
||||
for (z = 0; z < 4; z++) {
|
||||
bitIndex = bitIndex << 1;
|
||||
xTemp = x + dx[z];
|
||||
yTemp = y + dy[z];
|
||||
if (testBounds(xTemp, yTemp) &&
|
||||
((map[xTemp][yTemp] & LOMASK) != DIRT) &&
|
||||
(((map[xTemp][yTemp] & LOMASK) < WOODS_LOW) ||
|
||||
((map[xTemp][yTemp] & LOMASK) > WOODS_HIGH))) {
|
||||
bitIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
temp = REdTab[bitIndex & 15];
|
||||
|
||||
if ((temp != RIVER) &&
|
||||
getRandom(1)) {
|
||||
temp++;
|
||||
}
|
||||
|
||||
map[x][y] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Micropolis::isTree(MapValue cell)
|
||||
{
|
||||
if ((cell & LOMASK) >= WOODS_LOW && (cell & LOMASK) <= WOODS_HIGH) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::smoothTrees()
|
||||
{
|
||||
short x, y;
|
||||
for (x = 0; x < WORLD_W; x++) {
|
||||
for (y = 0; y < WORLD_H; y++) {
|
||||
if (isTree(map[x][y])) {
|
||||
smoothTreesAt(x, y, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Temporary function to prevent breaking a lot of code. */
|
||||
void Micropolis::smoothTreesAt(int x, int y, bool preserve)
|
||||
{
|
||||
ToolEffects effects(this);
|
||||
|
||||
smoothTreesAt(x, y, preserve, &effects);
|
||||
effects.modifyWorld();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Smooth trees at a position.
|
||||
*/
|
||||
void Micropolis::smoothTreesAt(int x, int y, bool preserve,
|
||||
ToolEffects *effects)
|
||||
{
|
||||
static short dx[4] = { -1, 0, 1, 0 };
|
||||
static short dy[4] = { 0, 1, 0, -1 };
|
||||
static const short treeTable[16] = {
|
||||
0, 0, 0, 34,
|
||||
0, 0, 36, 35,
|
||||
0, 32, 0, 33,
|
||||
30, 31, 29, 37,
|
||||
};
|
||||
|
||||
if (!isTree(effects->getMapValue(x, y))) {
|
||||
return;
|
||||
}
|
||||
|
||||
int bitIndex = 0;
|
||||
int z;
|
||||
for (z = 0; z < 4; z++) {
|
||||
bitIndex = bitIndex << 1;
|
||||
int xTemp = x + dx[z];
|
||||
int yTemp = y + dy[z];
|
||||
if (testBounds(xTemp, yTemp)
|
||||
&& isTree(effects->getMapValue(xTemp, yTemp))) {
|
||||
bitIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
int temp = treeTable[bitIndex & 15];
|
||||
if (temp) {
|
||||
if (temp != WOODS) {
|
||||
if ((x + y) & 1) {
|
||||
temp = temp - 8;
|
||||
}
|
||||
}
|
||||
effects->setMapValue(x, y, temp | BLBNBIT);
|
||||
} else {
|
||||
if (!preserve) {
|
||||
effects->setMapValue(x, y, temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct rivers.
|
||||
* @param terrainPos Coordinate to start making a river.
|
||||
*/
|
||||
void Micropolis::doRivers(const Position &terrainPos)
|
||||
{
|
||||
Direction2 riverDir; // Global direction of the river
|
||||
Direction2 terrainDir; // Local direction of the river
|
||||
|
||||
riverDir = (Direction2)(DIR2_NORTH + (getRandom(3) * 2));
|
||||
doBRiver(terrainPos, riverDir, riverDir);
|
||||
|
||||
riverDir = rotate180(riverDir);
|
||||
terrainDir = doBRiver(terrainPos, riverDir, riverDir);
|
||||
|
||||
riverDir = (Direction2)(DIR2_NORTH + (getRandom(3) * 2));
|
||||
doSRiver(terrainPos, riverDir, terrainDir);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a big river.
|
||||
* @param pos Start position of making a river.
|
||||
* @param riverDir Global direction of the river.
|
||||
* @param terrainDir Local direction of the terrain.
|
||||
* @return Last used local terrain direction.
|
||||
*/
|
||||
Direction2 Micropolis::doBRiver(const Position &riverPos,
|
||||
Direction2 riverDir, Direction2 terrainDir)
|
||||
{
|
||||
int rate1, rate2;
|
||||
|
||||
if (terrainCurveLevel < 0) {
|
||||
rate1 = 100;
|
||||
rate2 = 200;
|
||||
} else {
|
||||
rate1 = terrainCurveLevel + 10;
|
||||
rate2 = terrainCurveLevel + 100;
|
||||
}
|
||||
|
||||
Position pos(riverPos);
|
||||
|
||||
while (testBounds(pos.posX + 4, pos.posY + 4)) {
|
||||
plopBRiver(pos);
|
||||
if (getRandom(rate1) < 10) {
|
||||
terrainDir = riverDir;
|
||||
} else {
|
||||
if (getRandom(rate2) > 90) {
|
||||
terrainDir = rotate45(terrainDir);
|
||||
}
|
||||
if (getRandom(rate2) > 90) {
|
||||
terrainDir = rotate45(terrainDir, 7);
|
||||
}
|
||||
}
|
||||
pos.move(terrainDir);
|
||||
}
|
||||
|
||||
return terrainDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a small river.
|
||||
* @param pos Start position of making a river.
|
||||
* @param riverDir Global direction of the river.
|
||||
* @param terrainDir Local direction of the terrain.
|
||||
* @return Last used local terrain direction.
|
||||
*/
|
||||
Direction2 Micropolis::doSRiver(const Position &riverPos,
|
||||
Direction2 riverDir, Direction2 terrainDir)
|
||||
{
|
||||
int rate1, rate2;
|
||||
|
||||
if (terrainCurveLevel < 0) {
|
||||
rate1 = 100;
|
||||
rate2 = 200;
|
||||
} else {
|
||||
rate1 = terrainCurveLevel + 10;
|
||||
rate2 = terrainCurveLevel + 100;
|
||||
}
|
||||
|
||||
Position pos(riverPos);
|
||||
|
||||
while (testBounds(pos.posX + 3, pos.posY + 3)) {
|
||||
//printf("doSRiver %d %d td %d rd %d\n", pos.posX, pos.posY, terrainDir, riverDir);
|
||||
plopSRiver(pos);
|
||||
if (getRandom(rate1) < 10) {
|
||||
terrainDir = riverDir;
|
||||
} else {
|
||||
if (getRandom(rate2) > 90) {
|
||||
terrainDir = rotate45(terrainDir);
|
||||
}
|
||||
if (getRandom(rate2) > 90) {
|
||||
terrainDir = rotate45(terrainDir, 7);
|
||||
}
|
||||
}
|
||||
pos.move(terrainDir);
|
||||
}
|
||||
|
||||
return terrainDir;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Put \a mChar onto the map at position \a xLoc, \a yLoc if possible.
|
||||
* @param mChar Map value to put ont the map.
|
||||
* @param xLoc Horizontal position at the map to put \a mChar.
|
||||
* @param yLoc Vertical position at the map to put \a mChar.
|
||||
*/
|
||||
void Micropolis::putOnMap(MapValue mChar, short xLoc, short yLoc)
|
||||
{
|
||||
if (mChar == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!testBounds(xLoc, yLoc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MapValue temp = map[xLoc][yLoc];
|
||||
|
||||
if (temp != DIRT) {
|
||||
temp = temp & LOMASK;
|
||||
if (temp == RIVER) {
|
||||
if (mChar != CHANNEL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (temp == CHANNEL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
map[xLoc][yLoc] = mChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put down a big river diamond-like shape.
|
||||
* @param pos Base coordinate of the blob (top-left position).
|
||||
*/
|
||||
void Micropolis::plopBRiver(const Position &pos)
|
||||
{
|
||||
short x, y;
|
||||
static MapValue BRMatrix[9][9] = {
|
||||
{ 0, 0, 0, REDGE, REDGE, REDGE, 0, 0, 0 },
|
||||
{ 0, 0, REDGE, RIVER, RIVER, RIVER, REDGE, 0, 0 },
|
||||
{ 0, REDGE, RIVER, RIVER, RIVER, RIVER, RIVER, REDGE, 0 },
|
||||
{ REDGE, RIVER, RIVER, RIVER, RIVER, RIVER, RIVER, RIVER, REDGE },
|
||||
{ REDGE, RIVER, RIVER, RIVER, CHANNEL, RIVER, RIVER, RIVER, REDGE },
|
||||
{ REDGE, RIVER, RIVER, RIVER, RIVER, RIVER, RIVER, RIVER, REDGE },
|
||||
{ 0, REDGE, RIVER, RIVER, RIVER, RIVER, RIVER, REDGE, 0 },
|
||||
{ 0, 0, REDGE, RIVER, RIVER, RIVER, REDGE, 0, 0 },
|
||||
{ 0, 0, 0, REDGE, REDGE, REDGE, 0, 0, 0 },
|
||||
};
|
||||
|
||||
for (x = 0; x < 9; x++) {
|
||||
for (y = 0; y < 9; y++) {
|
||||
putOnMap(BRMatrix[y][x], pos.posX + x, pos.posY + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Put down a small river diamond-like shape.
|
||||
* @param pos Base coordinate of the blob (top-left position).
|
||||
*/
|
||||
void Micropolis::plopSRiver(const Position &pos)
|
||||
{
|
||||
short x, y;
|
||||
static MapValue SRMatrix[6][6] = {
|
||||
{ 0, 0, REDGE, REDGE, 0, 0 },
|
||||
{ 0, REDGE, RIVER, RIVER, REDGE, 0 },
|
||||
{ REDGE, RIVER, RIVER, RIVER, RIVER, REDGE },
|
||||
{ REDGE, RIVER, RIVER, RIVER, RIVER, REDGE },
|
||||
{ 0, REDGE, RIVER, RIVER, REDGE, 0 },
|
||||
{ 0, 0, REDGE, REDGE, 0, 0 },
|
||||
};
|
||||
|
||||
for (x = 0; x < 6; x++) {
|
||||
for (y = 0; y < 6; y++) {
|
||||
putOnMap(SRMatrix[y][x], pos.posX + x, pos.posY + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::smoothWater()
|
||||
{
|
||||
int x, y;
|
||||
MapTile tile;
|
||||
Direction2 dir;
|
||||
|
||||
for (x = 0; x < WORLD_W; x++) {
|
||||
for (y = 0; y < WORLD_H; y++) {
|
||||
|
||||
tile = map[x][y] & LOMASK;
|
||||
|
||||
/* If (x, y) is water: */
|
||||
if (tile >= WATER_LOW && tile <= WATER_HIGH) {
|
||||
|
||||
const Position pos(x, y);
|
||||
for (dir = DIR2_BEGIN; dir < DIR2_END; dir = increment90(dir)) {
|
||||
|
||||
/* If getting a tile off-map, condition below fails. */
|
||||
// @note I think this may have been a bug, since it always uses DIR2_WEST instead of dir.
|
||||
//tile = getTileFromMap(pos, DIR2_WEST, WATER_LOW);
|
||||
tile = getTileFromMap(pos, dir, WATER_LOW);
|
||||
|
||||
/* If nearest object is not water: */
|
||||
if (tile < WATER_LOW || tile > WATER_HIGH) {
|
||||
map[x][y] = REDGE; /* set river edge */
|
||||
break; // Continue with next tile
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; x < WORLD_W; x++) {
|
||||
for (y = 0; y < WORLD_H; y++) {
|
||||
|
||||
tile = map[x][y] & LOMASK;
|
||||
|
||||
/* If water which is not a channel: */
|
||||
if (tile != CHANNEL && tile >= WATER_LOW && tile <= WATER_HIGH) {
|
||||
|
||||
bool makeRiver = true; // make (x, y) a river
|
||||
|
||||
const Position pos(x, y);
|
||||
for (dir = DIR2_BEGIN; dir < DIR2_END; dir = increment90(dir)) {
|
||||
|
||||
/* If getting a tile off-map, condition below fails. */
|
||||
// @note I think this may have been a bug, since it always uses DIR2_WEST instead of dir.
|
||||
//tile = getTileFromMap(pos, DIR2_WEST, WATER_LOW);
|
||||
tile = getTileFromMap(pos, dir, WATER_LOW);
|
||||
|
||||
/* If nearest object is not water: */
|
||||
if (tile < WATER_LOW || tile > WATER_HIGH) {
|
||||
makeRiver = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (makeRiver) {
|
||||
map[x][y] = RIVER; /* make it a river */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; x < WORLD_W; x++) {
|
||||
for (y = 0; y < WORLD_H; y++) {
|
||||
|
||||
tile = map[x][y] & LOMASK;
|
||||
|
||||
/* If woods: */
|
||||
if (tile >= WOODS_LOW && tile <= WOODS_HIGH) {
|
||||
|
||||
const Position pos(x, y);
|
||||
for (dir = DIR2_BEGIN; dir < DIR2_END; dir = increment90(dir)) {
|
||||
|
||||
/* If getting a tile off-map, condition below fails. */
|
||||
// @note I think this may have been a bug, since it always uses DIR2_WEST instead of dir.
|
||||
//tile = getTileFromMap(pos, DIR2_WEST, WATER_LOW);
|
||||
tile = getTileFromMap(pos, dir, TILE_INVALID);
|
||||
|
||||
if (tile == RIVER || tile == CHANNEL) {
|
||||
map[x][y] = REDGE; /* make it water's edge */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
399
core/graph.cpp
Normal file
399
core/graph.cpp
Normal file
|
@ -0,0 +1,399 @@
|
|||
/* graph.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file graph.cpp
|
||||
* @brief Implements functionality for graph data management in
|
||||
* Micropolis.
|
||||
*
|
||||
* This file contains functions for managing historical data used in
|
||||
* graphs, such as population and pollution levels. It includes
|
||||
* methods for initializing graphs, updating historical data, scaling
|
||||
* data for graph display, and retrieving specific historical values.
|
||||
* This file plays a key role in visualizing the evolution of the city
|
||||
* over time in various aspects.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
//char *Micropolis::histName[] = {
|
||||
// "Residential", "Commercial", "Industrial",
|
||||
// "Cash Flow", "Crime", "Pollution"
|
||||
//};
|
||||
|
||||
//unsigned char Micropolis::histColor[] = {
|
||||
// COLOR_LIGHTGREEN, COLOR_DARKBLUE, COLOR_YELLOW,
|
||||
// COLOR_DARKGREEN, COLOR_RED, COLOR_OLIVE
|
||||
//};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Copy history data to new array, scaling as needed.
|
||||
* @param hist Source history data.
|
||||
* @param s Destination byte array.
|
||||
* @param scale Scale factor.
|
||||
* @todo Figure out why we copy data.
|
||||
*/
|
||||
void Micropolis::drawMonth(short *hist, unsigned char *s, float scale)
|
||||
{
|
||||
int val, x;
|
||||
|
||||
for (x = 0; x < 120; x++) {
|
||||
val = (int)(hist[x] * scale);
|
||||
s[119 - x] = (unsigned char)clamp(val, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set flag that graph data has been changed and graphs should be updated.
|
||||
* @todo Rename function.
|
||||
*/
|
||||
void Micropolis::changeCensus()
|
||||
{
|
||||
censusChanged = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If graph data has been changed, update all graphs.
|
||||
* If graphs have been changed, tell the user front-end about it.
|
||||
*/
|
||||
void Micropolis::graphDoer()
|
||||
{
|
||||
if (censusChanged) {
|
||||
callback->updateHistory(this, callbackVal);
|
||||
censusChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Initialize graphs */
|
||||
void Micropolis::initGraphs()
|
||||
{
|
||||
if (!historyInitialized) {
|
||||
historyInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Compute various max ranges of graphs */
|
||||
void Micropolis::initGraphMax()
|
||||
{
|
||||
int x;
|
||||
|
||||
resHist10Max = 0;
|
||||
comHist10Max = 0;
|
||||
indHist10Max = 0;
|
||||
|
||||
for (x = 118; x >= 0; x--) {
|
||||
|
||||
if (resHist[x] < 0) {
|
||||
resHist[x] = 0;
|
||||
}
|
||||
if (comHist[x] < 0) {
|
||||
comHist[x] = 0;
|
||||
}
|
||||
if (indHist[x] < 0) {
|
||||
indHist[x] = 0;
|
||||
}
|
||||
|
||||
resHist10Max = max(resHist10Max, resHist[x]);
|
||||
comHist10Max = max(comHist10Max, comHist[x]);
|
||||
indHist10Max = max(indHist10Max, indHist[x]);
|
||||
|
||||
}
|
||||
|
||||
graph10Max =
|
||||
max(resHist10Max,
|
||||
max(comHist10Max,
|
||||
indHist10Max));
|
||||
|
||||
resHist120Max = 0;
|
||||
comHist120Max = 0;
|
||||
indHist120Max = 0;
|
||||
|
||||
for (x = 238; x >= 120; x--) {
|
||||
|
||||
if (resHist[x] < 0) {
|
||||
resHist[x] = 0;
|
||||
}
|
||||
if (comHist[x] < 0) {
|
||||
comHist[x] = 0;
|
||||
}
|
||||
if (indHist[x] < 0) {
|
||||
indHist[x] = 0;
|
||||
}
|
||||
|
||||
resHist120Max = max(resHist120Max, resHist[x]);
|
||||
comHist120Max = max(comHist120Max, comHist[x]);
|
||||
indHist120Max = max(indHist120Max, indHist[x]);
|
||||
|
||||
}
|
||||
|
||||
graph120Max =
|
||||
max(resHist120Max,
|
||||
max(comHist120Max,
|
||||
indHist120Max));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the minimal and maximal values of a historic graph.
|
||||
* @param historyType Type of history information. @see HistoryType
|
||||
* @param historyScale Scale of history data. @see HistoryScale
|
||||
* @param minValResult Pointer to variable to write minimal value to.
|
||||
* @param maxValResult Pointer to variable to write maximal value to.
|
||||
*/
|
||||
void Micropolis::getHistoryRange(int historyType, int historyScale,
|
||||
short *minValResult, short *maxValResult)
|
||||
{
|
||||
if (historyType < 0 || historyType >= HISTORY_TYPE_COUNT
|
||||
|| historyScale < 0 || historyScale >= HISTORY_SCALE_COUNT) {
|
||||
*minValResult = 0;
|
||||
*maxValResult = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
short *history = NULL;
|
||||
switch (historyType) {
|
||||
case HISTORY_TYPE_RES:
|
||||
history = resHist;
|
||||
break;
|
||||
case HISTORY_TYPE_COM:
|
||||
history = comHist;
|
||||
break;
|
||||
case HISTORY_TYPE_IND:
|
||||
history = indHist;
|
||||
break;
|
||||
case HISTORY_TYPE_MONEY:
|
||||
history = moneyHist;
|
||||
break;
|
||||
case HISTORY_TYPE_CRIME:
|
||||
history = crimeHist;
|
||||
break;
|
||||
case HISTORY_TYPE_POLLUTION:
|
||||
history = pollutionHist;
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
switch (historyScale) {
|
||||
case HISTORY_SCALE_SHORT:
|
||||
offset = 0;
|
||||
break;
|
||||
case HISTORY_SCALE_LONG:
|
||||
offset = 120;
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
|
||||
short minVal = 32000;
|
||||
short maxVal = -32000;
|
||||
|
||||
for (int i = 0; i < HISTORY_COUNT; i++) {
|
||||
short val = history[i + offset];
|
||||
|
||||
minVal = min(val, minVal);
|
||||
maxVal = max(val, maxVal);
|
||||
}
|
||||
|
||||
*minValResult = minVal;
|
||||
*maxValResult = maxVal;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a value from the history tables.
|
||||
* @param historyType Type of history information. @see HistoryType
|
||||
* @param historyScale Scale of history data. @see HistoryScale
|
||||
* @param historyIndex Index in the data to obtain
|
||||
* @return Historic data value of the requested graph
|
||||
*/
|
||||
short Micropolis::getHistory(int historyType, int historyScale,
|
||||
int historyIndex)
|
||||
{
|
||||
if (historyType < 0 || historyType >= HISTORY_TYPE_COUNT
|
||||
|| historyScale < 0 || historyScale >= HISTORY_SCALE_COUNT
|
||||
|| historyIndex < 0 || historyIndex >= HISTORY_COUNT) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
short *history = NULL;
|
||||
switch (historyType) {
|
||||
case HISTORY_TYPE_RES:
|
||||
history = resHist;
|
||||
break;
|
||||
case HISTORY_TYPE_COM:
|
||||
history = comHist;
|
||||
break;
|
||||
case HISTORY_TYPE_IND:
|
||||
history = indHist;
|
||||
break;
|
||||
case HISTORY_TYPE_MONEY:
|
||||
history = moneyHist;
|
||||
break;
|
||||
case HISTORY_TYPE_CRIME:
|
||||
history = crimeHist;
|
||||
break;
|
||||
case HISTORY_TYPE_POLLUTION:
|
||||
history = pollutionHist;
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
switch (historyScale) {
|
||||
case HISTORY_SCALE_SHORT:
|
||||
offset = 0;
|
||||
break;
|
||||
case HISTORY_SCALE_LONG:
|
||||
offset = 120;
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
|
||||
short result = history[historyIndex + offset];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store a value into the history tables.
|
||||
* @param historyType Type of history information. @see HistoryType
|
||||
* @param historyScale Scale of history data. @see HistoryScale
|
||||
* @param historyIndex Index in the data to obtain
|
||||
* @param historyValue Index in the value to store
|
||||
*/
|
||||
void Micropolis::setHistory(int historyType, int historyScale,
|
||||
int historyIndex, short historyValue)
|
||||
{
|
||||
if (historyType < 0 || historyType >= HISTORY_TYPE_COUNT
|
||||
|| historyScale < 0 || historyScale >= HISTORY_SCALE_COUNT
|
||||
|| historyIndex < 0 || historyIndex >= HISTORY_COUNT) {
|
||||
return;
|
||||
}
|
||||
|
||||
short *history = NULL;
|
||||
switch (historyType) {
|
||||
case HISTORY_TYPE_RES:
|
||||
history = resHist;
|
||||
break;
|
||||
case HISTORY_TYPE_COM:
|
||||
history = comHist;
|
||||
break;
|
||||
case HISTORY_TYPE_IND:
|
||||
history = indHist;
|
||||
break;
|
||||
case HISTORY_TYPE_MONEY:
|
||||
history = moneyHist;
|
||||
break;
|
||||
case HISTORY_TYPE_CRIME:
|
||||
history = crimeHist;
|
||||
break;
|
||||
case HISTORY_TYPE_POLLUTION:
|
||||
history = pollutionHist;
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
switch (historyScale) {
|
||||
case HISTORY_SCALE_SHORT:
|
||||
offset = 0;
|
||||
break;
|
||||
case HISTORY_SCALE_LONG:
|
||||
offset = 120;
|
||||
break;
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
}
|
||||
|
||||
history[historyIndex + offset] = historyValue;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
146
core/initialize.cpp
Normal file
146
core/initialize.cpp
Normal file
|
@ -0,0 +1,146 @@
|
|||
/* initialize.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file initialize.cpp
|
||||
* @brief Contains initialization functions for various game state
|
||||
* components in Micropolis.
|
||||
*
|
||||
* This file includes functions responsible for initializing and
|
||||
* resetting game state variables, maps, and editor tools. It sets up
|
||||
* initial values for game parameters and clears previous game data to
|
||||
* prepare for a new game session or to reset the current state.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/** Reset many game state variables */
|
||||
void Micropolis::initWillStuff()
|
||||
{
|
||||
randomlySeedRandom();
|
||||
initGraphMax();
|
||||
destroyAllSprites();
|
||||
|
||||
roadEffect = MAX_ROAD_EFFECT;
|
||||
policeEffect = MAX_POLICE_STATION_EFFECT;
|
||||
fireEffect = MAX_FIRE_STATION_EFFECT;
|
||||
cityScore = 500;
|
||||
cityPop = -1;
|
||||
cityTimeLast = -1;
|
||||
cityYearLast = -1;
|
||||
cityMonthLast = -1;
|
||||
totalFundsLast = -1;
|
||||
resLast = comLast = indLast = -999999;
|
||||
roadFund = 0;
|
||||
policeFund = 0;
|
||||
fireFund = 0;
|
||||
valveFlag = true;
|
||||
disasterEvent = SC_NONE;
|
||||
taxFlag = false;
|
||||
|
||||
populationDensityMap.clear();
|
||||
trafficDensityMap.clear();
|
||||
pollutionDensityMap.clear();
|
||||
landValueMap.clear();
|
||||
crimeRateMap.clear();
|
||||
terrainDensityMap.clear();
|
||||
rateOfGrowthMap.clear();
|
||||
comRateMap.clear();
|
||||
policeStationMap.clear();
|
||||
policeStationEffectMap.clear();
|
||||
fireStationMap.clear();
|
||||
fireStationEffectMap.clear();
|
||||
|
||||
doNewGame();
|
||||
doUpdateHeads();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reset all maps in the simulator.
|
||||
* @note Function is empty
|
||||
* @todo What should be done with this empty function?
|
||||
*/
|
||||
void Micropolis::resetMapState()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reset all tools in the simulator editor.
|
||||
* @note Function is empty
|
||||
* @todo What should be done with this empty function?
|
||||
*/
|
||||
void Micropolis::resetEditorState()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
1025
core/map.cpp
Normal file
1025
core/map.cpp
Normal file
File diff suppressed because it is too large
Load diff
354
core/map_type.h
Normal file
354
core/map_type.h
Normal file
|
@ -0,0 +1,354 @@
|
|||
/* map_type.h
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file map_type.h
|
||||
* @brief Map data structures for the Micropolis game engine.
|
||||
*
|
||||
* This header file defines the Map template class used for
|
||||
* representing various types of 2D grid maps in the Micropolis game
|
||||
* engine. It includes definitions for map dimensions and provides
|
||||
* specialized map types with different data storage granularities.
|
||||
* These map types are crucial for managing different aspects of the
|
||||
* game world, like terrain, population density, and resource
|
||||
* distribution. The Map class template offers flexibility in defining
|
||||
* maps with various data types and block sizes, optimizing memory
|
||||
* usage and access patterns for different game scenarios.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef H_MAP_TYPE
|
||||
#define H_MAP_TYPE
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Constants
|
||||
|
||||
|
||||
/**
|
||||
* Size of the world in horizontal direction.
|
||||
*/
|
||||
static const int WORLD_W = 120;
|
||||
|
||||
/**
|
||||
* Size of the world in vertical direction.
|
||||
*/
|
||||
static const int WORLD_H = 100;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Template class definitions
|
||||
|
||||
|
||||
/**
|
||||
* Generic class for maps in the Micropolis game.
|
||||
*
|
||||
* A map is assumed to cover a 2D grid of #WORLD_W times #WORLD_H positions.
|
||||
* A block of positions may be clustered, and represented by a single data
|
||||
* value.
|
||||
* @tparam DATA Data type of a data value.
|
||||
* @tparam BLKSIZE Size of the cluster.
|
||||
*/
|
||||
template <typename DATA, int BLKSIZE>
|
||||
class Map
|
||||
{
|
||||
public:
|
||||
Map(DATA defaultValue);
|
||||
Map(const Map<DATA, BLKSIZE>& map);
|
||||
Map& operator=(const Map<DATA, BLKSIZE> &map);
|
||||
~Map();
|
||||
|
||||
/** Size of a cluster in number of world positions. */
|
||||
const int MAP_BLOCKSIZE;
|
||||
const int MAP_W; ///< Number of clusters in horizontal direction.
|
||||
const int MAP_H; ///< Number of clusters in vertical direction.
|
||||
|
||||
void fill(DATA val);
|
||||
void clear();
|
||||
|
||||
inline void set(int x, int y, DATA val);
|
||||
inline DATA get(int x, int y) const;
|
||||
inline bool onMap(int x, int y) const;
|
||||
|
||||
inline void worldSet(int x, int y, DATA val);
|
||||
inline DATA worldGet(int x, int y) const;
|
||||
inline bool worldOnMap(int x, int y) const;
|
||||
|
||||
DATA *getBase();
|
||||
|
||||
inline size_t getTotalByteSize() const {
|
||||
return sizeof(DATA) *
|
||||
((WORLD_W + BLKSIZE - 1) / BLKSIZE) *
|
||||
((WORLD_H + BLKSIZE - 1) / BLKSIZE);
|
||||
}
|
||||
|
||||
private:
|
||||
/** Data fields of the map in column-major mode. */
|
||||
DATA _mapData[((WORLD_W + BLKSIZE - 1) / BLKSIZE) *
|
||||
((WORLD_H + BLKSIZE - 1) / BLKSIZE)];
|
||||
|
||||
const DATA _MAP_DEFAULT_VALUE; ///< Default value of a cluster.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Generic map constructor.
|
||||
* @param defaultValue Default value to use for off-map positions, and
|
||||
* for clearing the map.
|
||||
*/
|
||||
template <typename DATA, int BLKSIZE>
|
||||
Map<DATA, BLKSIZE>::Map(DATA defaultValue):
|
||||
MAP_BLOCKSIZE(BLKSIZE),
|
||||
MAP_W((WORLD_W + BLKSIZE - 1) / BLKSIZE),
|
||||
MAP_H((WORLD_H + BLKSIZE - 1) / BLKSIZE),
|
||||
_MAP_DEFAULT_VALUE(defaultValue)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/** Copy constructor */
|
||||
template <typename DATA, int BLKSIZE>
|
||||
Map<DATA, BLKSIZE>::Map(const Map<DATA, BLKSIZE> &map):
|
||||
MAP_BLOCKSIZE(BLKSIZE),
|
||||
MAP_W((WORLD_W + BLKSIZE - 1) / BLKSIZE),
|
||||
MAP_H((WORLD_H + BLKSIZE - 1) / BLKSIZE),
|
||||
_MAP_DEFAULT_VALUE(map._MAP_DEFAULT_VALUE)
|
||||
{
|
||||
for (int i = 0; i < this->MAP_W * this->MAP_H; i++) {
|
||||
this->_mapData[i] = map._mapData[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Assignment operator */
|
||||
template <typename DATA, int BLKSIZE>
|
||||
Map<DATA, BLKSIZE> &Map<DATA, BLKSIZE>::operator=(const Map<DATA, BLKSIZE> &map)
|
||||
{
|
||||
if(this != &map) {
|
||||
for (int i = 0; i < this->MAP_W * this->MAP_H; i++) {
|
||||
this->_mapData[i] = map._mapData[i];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/** Generic map destructor */
|
||||
template <typename DATA, int BLKSIZE>
|
||||
Map<DATA, BLKSIZE>::~Map()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generic fill routine.
|
||||
*
|
||||
* @param value Value with which to fill the map.
|
||||
*/
|
||||
template <typename DATA, int BLKSIZE>
|
||||
void Map<DATA, BLKSIZE>::fill(DATA value)
|
||||
{
|
||||
for (int i = 0; i < this->MAP_W * this->MAP_H; i++) {
|
||||
this->_mapData[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generic clear routine.
|
||||
*
|
||||
* Resets all data of the map to #_MAP_DEFAULT_VALUE.
|
||||
*/
|
||||
template <typename DATA, int BLKSIZE>
|
||||
void Map<DATA, BLKSIZE>::clear()
|
||||
{
|
||||
fill(this->_MAP_DEFAULT_VALUE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the base address of the map data.
|
||||
* @note Data is stored in column-major mode.
|
||||
*/
|
||||
template <typename DATA, int BLKSIZE>
|
||||
DATA *Map<DATA, BLKSIZE>::getBase()
|
||||
{
|
||||
return this->_mapData;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the value of a cluster.
|
||||
*
|
||||
* If the coordinate is off the map, the value is not stored.
|
||||
* @param x X cluster position (at world position \a x * #MAP_BLOCKSIZE).
|
||||
* @param y Y cluster position (at world position \a y * #MAP_BLOCKSIZE).
|
||||
* @param value Value to use.
|
||||
*/
|
||||
template <typename DATA, int BLKSIZE>
|
||||
inline void Map<DATA, BLKSIZE>::set(int x, int y, DATA value)
|
||||
{
|
||||
if(this->onMap(x, y)) {
|
||||
this->_mapData[x * MAP_H + y] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the value of a cluster.
|
||||
*
|
||||
* If the coordinate is off the map, the #_MAP_DEFAULT_VALUE is returned.
|
||||
* @param x X cluster position (at world position \a x * #MAP_BLOCKSIZE).
|
||||
* @param y Y cluster position (at world position \a y * #MAP_BLOCKSIZE).
|
||||
* @return Value of the cluster.
|
||||
*/
|
||||
template <typename DATA, int BLKSIZE>
|
||||
inline DATA Map<DATA, BLKSIZE>::get(int x, int y) const
|
||||
{
|
||||
if(!this->onMap(x, y)) {
|
||||
return this->_MAP_DEFAULT_VALUE;
|
||||
}
|
||||
|
||||
return this->_mapData[x * MAP_H + y];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verify that cluster coordinates are within map boundaries.
|
||||
* @param x X cluster position (at world position \a x * #MAP_BLOCKSIZE).
|
||||
* @param y Y cluster position (at world position \a y * #MAP_BLOCKSIZE).
|
||||
* @return Coordinate is within map boundaries.
|
||||
*/
|
||||
template <typename DATA, int BLKSIZE>
|
||||
inline bool Map<DATA, BLKSIZE>::onMap(int x, int y) const
|
||||
{
|
||||
return (x >= 0 && x < this->MAP_W) && (y >= 0 && y < this->MAP_H);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the value of a cluster.
|
||||
*
|
||||
* If the coordinate is off the map, the value is not stored.
|
||||
* @param x X world position.
|
||||
* @param y Y world position.
|
||||
* @param value Value to use.
|
||||
*/
|
||||
template <typename DATA, int BLKSIZE>
|
||||
inline void Map<DATA, BLKSIZE>::worldSet(int x, int y, DATA value)
|
||||
{
|
||||
if(this->worldOnMap(x, y)) {
|
||||
x /= BLKSIZE;
|
||||
y /= BLKSIZE;
|
||||
this->_mapData[x * MAP_H + y] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the value of a cluster.
|
||||
*
|
||||
* If the coordinate is off the map, the #_MAP_DEFAULT_VALUE is returned.
|
||||
* @param x X world position.
|
||||
* @param y Y world position.
|
||||
* @return Value of the cluster.
|
||||
*/
|
||||
template <typename DATA, int BLKSIZE>
|
||||
inline DATA Map<DATA, BLKSIZE>::worldGet(int x, int y) const
|
||||
{
|
||||
if(!this->worldOnMap(x, y)) {
|
||||
return this->_MAP_DEFAULT_VALUE;
|
||||
}
|
||||
|
||||
x /= BLKSIZE;
|
||||
y /= BLKSIZE;
|
||||
return this->_mapData[x * MAP_H + y];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verify that world coordinates are within map boundaries.
|
||||
* @param x X world position.
|
||||
* @param y Y world position.
|
||||
* @return Coordinate is within map boundaries.
|
||||
*/
|
||||
template <typename DATA, int BLKSIZE>
|
||||
inline bool Map<DATA, BLKSIZE>::worldOnMap(int x, int y) const
|
||||
{
|
||||
return (x >= 0 && x < WORLD_W) && (y >= 0 && y < WORLD_H);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Type definitions
|
||||
|
||||
|
||||
typedef Map<Byte, 1> MapByte1; ///< Map of ::Byte, with cluster size 1
|
||||
typedef Map<Byte, 2> MapByte2; ///< Map of ::Byte, with cluster size 2
|
||||
typedef Map<Byte, 4> MapByte4; ///< Map of ::Byte, with cluster size 4
|
||||
typedef Map<short, 8> MapShort8; ///< Map of ::short, with cluster size 8
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#endif
|
477
core/message.cpp
Normal file
477
core/message.cpp
Normal file
|
@ -0,0 +1,477 @@
|
|||
/* message.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file message.cpp
|
||||
* @brief Handles messaging and notifications within the Micropolis
|
||||
* game.
|
||||
*
|
||||
* This file includes functions for sending messages to the player,
|
||||
* based on various game events and scenario progress. It handles
|
||||
* displaying messages related to city growth, requirements,
|
||||
* disasters, and other significant events. It also deals with
|
||||
* triggering sound effects associated with specific messages.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
#include "text.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/** Check progress of the user, and send him messages about it. */
|
||||
void Micropolis::sendMessages()
|
||||
{
|
||||
short PowerPop;
|
||||
float TM;
|
||||
|
||||
// Running a scenario, and waiting it to 'end' so we can give a score
|
||||
if (scenario > SC_NONE && scoreType > SC_NONE && scoreWait > 0) {
|
||||
scoreWait--;
|
||||
if (scoreWait == 0) {
|
||||
doScenarioScore(scoreType);
|
||||
}
|
||||
}
|
||||
|
||||
checkGrowth();
|
||||
|
||||
totalZonePop = resZonePop + comZonePop + indZonePop;
|
||||
PowerPop = nuclearPowerPop + coalPowerPop;
|
||||
|
||||
switch (cityTime & 63) {
|
||||
|
||||
case 1:
|
||||
if (totalZonePop / 4 >= resZonePop) {
|
||||
sendMessage(MESSAGE_NEED_MORE_RESIDENTIAL);
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if (totalZonePop / 8 >= comZonePop) {
|
||||
sendMessage(MESSAGE_NEED_MORE_COMMERCIAL);
|
||||
}
|
||||
break;
|
||||
|
||||
case 10:
|
||||
if (totalZonePop / 8 >= indZonePop) {
|
||||
sendMessage(MESSAGE_NEED_MORE_INDUSTRIAL);
|
||||
}
|
||||
break;
|
||||
|
||||
case 14:
|
||||
if (totalZonePop > 10 && totalZonePop * 2 > roadTotal) {
|
||||
sendMessage(MESSAGE_NEED_MORE_ROADS);
|
||||
}
|
||||
break;
|
||||
|
||||
case 18:
|
||||
if (totalZonePop > 50 && totalZonePop > railTotal) {
|
||||
sendMessage(MESSAGE_NEED_MORE_RAILS);
|
||||
}
|
||||
break;
|
||||
|
||||
case 22:
|
||||
if (totalZonePop > 10 && PowerPop == 0) {
|
||||
sendMessage(MESSAGE_NEED_ELECTRICITY);
|
||||
}
|
||||
break;
|
||||
|
||||
case 26:
|
||||
if (resPop > 500 && stadiumPop == 0) {
|
||||
sendMessage(MESSAGE_NEED_STADIUM);
|
||||
resCap = true;
|
||||
} else {
|
||||
resCap = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 28:
|
||||
if (indPop > 70 && seaportPop == 0) {
|
||||
sendMessage(MESSAGE_NEED_SEAPORT);
|
||||
indCap = true;
|
||||
} else {
|
||||
indCap = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 30:
|
||||
if (comPop > 100 && airportPop == 0) {
|
||||
sendMessage(MESSAGE_NEED_AIRPORT);
|
||||
comCap = true;
|
||||
} else {
|
||||
comCap = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 32:
|
||||
TM = (float)(unpoweredZoneCount + poweredZoneCount); /* dec score for unpowered zones */
|
||||
if (TM > 0) {
|
||||
if (poweredZoneCount / TM < 0.7) {
|
||||
sendMessage(MESSAGE_BLACKOUTS_REPORTED);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 35:
|
||||
if (pollutionAverage > /* 80 */ 60) {
|
||||
sendMessage(MESSAGE_HIGH_POLLUTION, -1, -1, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case 42:
|
||||
if (crimeAverage > 100) {
|
||||
sendMessage(MESSAGE_HIGH_CRIME, -1, -1, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case 45:
|
||||
if (totalPop > 60 && fireStationPop == 0) {
|
||||
sendMessage(MESSAGE_NEED_FIRE_STATION);
|
||||
}
|
||||
break;
|
||||
|
||||
case 48:
|
||||
if (totalPop > 60 && policeStationPop == 0) {
|
||||
sendMessage(MESSAGE_NEED_POLICE_STATION);
|
||||
}
|
||||
break;
|
||||
|
||||
case 51:
|
||||
if (cityTax > 12) {
|
||||
sendMessage(MESSAGE_TAX_TOO_HIGH);
|
||||
}
|
||||
break;
|
||||
|
||||
case 54:
|
||||
// If roadEffect < 5/8 of max effect
|
||||
if (roadEffect < (5 * MAX_ROAD_EFFECT / 8) && roadTotal > 30) {
|
||||
sendMessage(MESSAGE_ROAD_NEEDS_FUNDING);
|
||||
}
|
||||
break;
|
||||
|
||||
case 57:
|
||||
// If fireEffect < 0.7 of max effect
|
||||
if (fireEffect < (7 * MAX_FIRE_STATION_EFFECT / 10) && totalPop > 20) {
|
||||
sendMessage(MESSAGE_FIRE_STATION_NEEDS_FUNDING);
|
||||
}
|
||||
break;
|
||||
|
||||
case 60:
|
||||
// If policeEffect < 0.7 of max effect
|
||||
if (policeEffect < (7 * MAX_POLICE_STATION_EFFECT / 10)
|
||||
&& totalPop > 20) {
|
||||
sendMessage(MESSAGE_POLICE_NEEDS_FUNDING);
|
||||
}
|
||||
break;
|
||||
|
||||
case 63:
|
||||
if (trafficAverage > 60) {
|
||||
sendMessage(MESSAGE_TRAFFIC_JAMS, -1, -1, true);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Detect a change in city class, and produce a message if the player has
|
||||
* reached the next class.
|
||||
* @todo This code is very closely related to Micropolis::doPopNum().
|
||||
* Maybe merge both in some way?
|
||||
* (This function gets called much more often however then doPopNum().
|
||||
* Also, at the first call, the difference between thisCityPop and
|
||||
* cityPop is huge.)
|
||||
*/
|
||||
void Micropolis::checkGrowth()
|
||||
{
|
||||
if ((cityTime & 3) == 0) {
|
||||
short category = 0;
|
||||
Quad thisCityPop = getPopulation();
|
||||
|
||||
if (cityPopLast > 0) {
|
||||
|
||||
CityClass lastClass = getCityClass(cityPopLast);
|
||||
CityClass newClass = getCityClass(thisCityPop);
|
||||
|
||||
if (lastClass != newClass) {
|
||||
|
||||
// Switched class, find appropiate message.
|
||||
switch (newClass) {
|
||||
|
||||
case CC_VILLAGE:
|
||||
// Don't mention it.
|
||||
break;
|
||||
|
||||
case CC_TOWN:
|
||||
category = MESSAGE_REACHED_TOWN;
|
||||
break;
|
||||
|
||||
case CC_CITY:
|
||||
category = MESSAGE_REACHED_CITY;
|
||||
break;
|
||||
|
||||
case CC_CAPITAL:
|
||||
category = MESSAGE_REACHED_CAPITAL;
|
||||
break;
|
||||
|
||||
case CC_METROPOLIS:
|
||||
category = MESSAGE_REACHED_METROPOLIS;
|
||||
break;
|
||||
|
||||
case CC_MEGALOPOLIS:
|
||||
category = MESSAGE_REACHED_MEGALOPOLIS;
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (category > 0 && category != categoryLast) {
|
||||
sendMessage(category, NOWHERE, NOWHERE, true);
|
||||
categoryLast = category;
|
||||
}
|
||||
|
||||
cityPopLast = thisCityPop;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute score for each scenario
|
||||
* @param type Scenario used
|
||||
* @note Parameter \a type may not be \c SC_NONE
|
||||
*/
|
||||
void Micropolis::doScenarioScore(Scenario type)
|
||||
{
|
||||
short z = MESSAGE_SCENARIO_LOST; /* you lose */
|
||||
|
||||
switch (type) {
|
||||
|
||||
case SC_DULLSVILLE:
|
||||
if (cityClass >= CC_METROPOLIS) {
|
||||
z = MESSAGE_SCENARIO_WON;
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_SAN_FRANCISCO:
|
||||
if (cityClass >= CC_METROPOLIS) {
|
||||
z = MESSAGE_SCENARIO_WON;
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_HAMBURG:
|
||||
if (cityClass >= CC_METROPOLIS) {
|
||||
z = MESSAGE_SCENARIO_WON;
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_BERN:
|
||||
if (trafficAverage < 80) {
|
||||
z = MESSAGE_SCENARIO_WON;
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_TOKYO:
|
||||
if (cityScore > 500) {
|
||||
z = MESSAGE_SCENARIO_WON;
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_DETROIT:
|
||||
if (crimeAverage < 60) {
|
||||
z = MESSAGE_SCENARIO_WON;
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_BOSTON:
|
||||
if (cityScore > 500) {
|
||||
z = MESSAGE_SCENARIO_WON;
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_RIO:
|
||||
if (cityScore > 500) {
|
||||
z = MESSAGE_SCENARIO_WON;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
sendMessage(z, NOWHERE, NOWHERE, true, true);
|
||||
|
||||
if (z == MESSAGE_SCENARIO_LOST) {
|
||||
doLoseGame();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send the user a message of an event that happens at a particular position
|
||||
* in the city.
|
||||
* @param messageIndex Message number of the message to display.
|
||||
* @param x X coordinate of the position of the event.
|
||||
* @param y Y coordinate of the position of the event.
|
||||
* @param picture Flag that is true if a picture should be shown.
|
||||
* @param important Flag that is true if the message is important.
|
||||
*/
|
||||
void Micropolis::sendMessage(short messageIndex, short x, short y, bool picture, bool important)
|
||||
{
|
||||
callback->sendMessage(this, callbackVal, messageIndex, x, y, picture, important);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a sound for message \a mesgNum if appropriate.
|
||||
* @param mesgNum Message number displayed.
|
||||
* @param x Horizontal coordinate in the city of the sound.
|
||||
* @param y Vertical coordinate in the city of the sound.
|
||||
*/
|
||||
void Micropolis::doMakeSound(int mesgNum, int x, int y)
|
||||
{
|
||||
assert(mesgNum >= 0);
|
||||
|
||||
switch (mesgNum) {
|
||||
|
||||
case MESSAGE_TRAFFIC_JAMS:
|
||||
if (getRandom(5) == 1) {
|
||||
makeSound("city", "HonkHonkMed", x, y);
|
||||
} else if (getRandom(5) == 1) {
|
||||
makeSound("city", "HonkHonkLow", x, y);
|
||||
} else if (getRandom(5) == 1) {
|
||||
makeSound("city", "HonkHonkHigh", x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case MESSAGE_HIGH_CRIME:
|
||||
case MESSAGE_FIRE_REPORTED:
|
||||
case MESSAGE_TORNADO_SIGHTED:
|
||||
case MESSAGE_EARTHQUAKE:
|
||||
case MESSAGE_PLANE_CRASHED:
|
||||
case MESSAGE_SHIP_CRASHED:
|
||||
case MESSAGE_TRAIN_CRASHED:
|
||||
case MESSAGE_HELICOPTER_CRASHED:
|
||||
makeSound("city", "Siren", x, y);
|
||||
break;
|
||||
|
||||
case MESSAGE_MONSTER_SIGHTED:
|
||||
makeSound("city", "Monster", x, y);
|
||||
break;
|
||||
|
||||
case MESSAGE_FIREBOMBING:
|
||||
makeSound("city", "ExplosionLow", x, y);
|
||||
makeSound("city", "Siren", x, y);
|
||||
break;
|
||||
|
||||
case MESSAGE_NUCLEAR_MELTDOWN:
|
||||
makeSound("city", "ExplosionHigh", x, y);
|
||||
makeSound("city", "ExplosionLow", x, y);
|
||||
makeSound("city", "Siren", x, y);
|
||||
break;
|
||||
|
||||
case MESSAGE_RIOTS_REPORTED:
|
||||
makeSound("city", "Siren", x, y);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the front-end that it should perform an auto-goto
|
||||
* @param x X position at the map
|
||||
* @param y Y position at the map
|
||||
* @param message Message
|
||||
*/
|
||||
void Micropolis::doAutoGoto(short x, short y, const std::string &message)
|
||||
{
|
||||
callback->autoGoto(this, callbackVal, x, y, message);
|
||||
}
|
||||
|
||||
|
||||
/** Tell the front-end that the player has lost the game */
|
||||
void Micropolis::doLoseGame()
|
||||
{
|
||||
callback->didLoseGame(this, callbackVal);
|
||||
}
|
||||
|
||||
|
||||
/** Tell the front-end that the player has won the game */
|
||||
void Micropolis::doWinGame()
|
||||
{
|
||||
callback->didWinGame(this, callbackVal);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
1599
core/micropolis.cpp
Normal file
1599
core/micropolis.cpp
Normal file
File diff suppressed because it is too large
Load diff
2702
core/micropolis.h
Normal file
2702
core/micropolis.h
Normal file
File diff suppressed because it is too large
Load diff
1
core/micropolisengine_lib.js
Normal file
1
core/micropolisengine_lib.js
Normal file
|
@ -0,0 +1 @@
|
|||
// micropolisengine_lib.js
|
13
core/micropolisengine_template.html
Normal file
13
core/micropolisengine_template.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Micropolis Engine</title>
|
||||
<style>
|
||||
/* Custom styles here */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{{{ SCRIPT }}}
|
||||
</body>
|
||||
</html>
|
238
core/position.cpp
Normal file
238
core/position.cpp
Normal file
|
@ -0,0 +1,238 @@
|
|||
/* position.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file position.cpp
|
||||
* @brief Defines the Position class for coordinate handling in
|
||||
* Micropolis.
|
||||
*
|
||||
* This file provides the implementation of the Position class, which
|
||||
* is used throughout the Micropolis game engine for managing x and y
|
||||
* coordinates. It includes various constructors for different
|
||||
* scenarios, a copy constructor, an assignment operator, and a method
|
||||
* for moving the position in a specified direction.
|
||||
*/
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/** Default constructor. */
|
||||
Position::Position()
|
||||
{
|
||||
this->posX = 0;
|
||||
this->posY = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a position at a given \a x and \a y coordinate.
|
||||
* @param x X coordinate of the new position.
|
||||
* @param y Y coordinate of the new position.
|
||||
*/
|
||||
Position::Position(int x, int y)
|
||||
{
|
||||
this->posX = x;
|
||||
this->posY = y;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
* @param pos Position to copy.
|
||||
*/
|
||||
Position::Position(const Position &pos)
|
||||
{
|
||||
this->posX = pos.posX;
|
||||
this->posY = pos.posY;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copy constructor with a single tile movement.
|
||||
* @param pos Position to copy.
|
||||
* @param dir Direction to move into.
|
||||
*/
|
||||
Position::Position(const Position &pos, Direction2 dir)
|
||||
{
|
||||
this->posX = pos.posX;
|
||||
this->posY = pos.posY;
|
||||
this->move(dir);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copy constructor with arbitrary movement.
|
||||
* @param pos Position to copy.
|
||||
* @param dx Horizontal offset.
|
||||
* @param dy Vertical offset.
|
||||
*/
|
||||
Position::Position(const Position &pos, int dx, int dy)
|
||||
{
|
||||
this->posX = pos.posX + dx;
|
||||
this->posY = pos.posY + dy;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Assignment operator.
|
||||
* @param pos Position to copy.
|
||||
*/
|
||||
Position &Position::operator=(const Position &pos)
|
||||
{
|
||||
if (this != &pos) {
|
||||
this->posX = pos.posX;
|
||||
this->posY = pos.posY;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Move the position one step in the indicated direction.
|
||||
* @param dir Direction to move into.
|
||||
* @return Position moved in the indicated direction.
|
||||
*/
|
||||
bool Position::move(Direction2 dir)
|
||||
{
|
||||
switch (dir) {
|
||||
case DIR2_INVALID:
|
||||
return true;
|
||||
|
||||
case DIR2_NORTH:
|
||||
if (this->posY > 0) {
|
||||
this->posY--;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIR2_NORTH_EAST:
|
||||
if (this->posX < WORLD_W - 1 && this->posY > 0) {
|
||||
this->posX++;
|
||||
this->posY--;
|
||||
return true;
|
||||
}
|
||||
case DIR2_EAST:
|
||||
if (this->posX < WORLD_W - 1) {
|
||||
this->posX++;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIR2_SOUTH_EAST:
|
||||
if (this->posX < WORLD_W -1 && this->posY < WORLD_H - 1) {
|
||||
this->posX++;
|
||||
this->posY++;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIR2_SOUTH:
|
||||
if (this->posY < WORLD_H - 1) {
|
||||
this->posY++;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIR2_SOUTH_WEST: this->posX--; this->posY++; break;
|
||||
if (this->posX > 0 && this->posY < WORLD_H - 1) {
|
||||
this->posX--;
|
||||
this->posY++;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIR2_WEST:
|
||||
if (this->posX > 0) {
|
||||
this->posX--;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIR2_NORTH_WEST:
|
||||
if (this->posX > 0 && this->posY > 0) {
|
||||
this->posX--;
|
||||
this->posY--;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
|
||||
// Movement was not possible, silently repair the position.
|
||||
if (this->posX < 0) this->posX = 0;
|
||||
if (this->posX >= WORLD_W) this->posX = WORLD_W - 1;
|
||||
if (this->posY < 0) this->posY = 0;
|
||||
if (this->posY >= WORLD_H) this->posY = WORLD_H - 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
197
core/position.h
Normal file
197
core/position.h
Normal file
|
@ -0,0 +1,197 @@
|
|||
/* position.h
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file position.h
|
||||
* @brief Defines position handling and direction enumeration for the
|
||||
* Micropolis game engine.
|
||||
*
|
||||
* This header file provides classes and functions for handling
|
||||
* positions and directions within the Micropolis game world. It
|
||||
* includes the 'Position' class for representing X/Y coordinates and
|
||||
* 'Direction2' enumeration for defining 8 cardinal directions.
|
||||
* Functions for manipulating and querying these positions and
|
||||
* directions are also provided, which are essential for navigating
|
||||
* and interacting with the game world's grid.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef H_POSITION
|
||||
#define H_POSITION
|
||||
|
||||
|
||||
/** Another direction enumeration class, with 8 possible directions.
|
||||
* @todo Eliminate #Direction.
|
||||
* @todo After eliminating #Direction, rename this enum to Direction.
|
||||
*/
|
||||
enum Direction2 {
|
||||
DIR2_INVALID, ///< Invalid direction.
|
||||
DIR2_NORTH, ///< Direction pointing north.
|
||||
DIR2_NORTH_EAST, ///< Direction pointing north-east.
|
||||
DIR2_EAST, ///< Direction pointing east.
|
||||
DIR2_SOUTH_EAST, ///< Direction pointing south-east.
|
||||
DIR2_SOUTH, ///< Direction pointing south.
|
||||
DIR2_SOUTH_WEST, ///< Direction pointing south-west.
|
||||
DIR2_WEST, ///< Direction pointing west.
|
||||
DIR2_NORTH_WEST, ///< Direction pointing north-west.
|
||||
|
||||
DIR2_BEGIN = DIR2_NORTH, ///< First valid direction.
|
||||
DIR2_END = DIR2_NORTH_WEST + 1, ///< End-condition for directions
|
||||
};
|
||||
|
||||
/**
|
||||
* Increment the direction by 45 degrees.
|
||||
* @param dir Direction to rotate.
|
||||
* @return Rotated direction, possibly >= DIR2_END.
|
||||
*/
|
||||
static inline Direction2 increment45(Direction2 dir, int count = 1)
|
||||
{
|
||||
return (Direction2)(dir + count);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Increment the direction by 90 degrees.
|
||||
* @param dir Direction to rotate.
|
||||
* @return Rotated direction, possibly >= DIR2_END.
|
||||
*/
|
||||
static inline Direction2 increment90(Direction2 dir)
|
||||
{
|
||||
return increment45(dir, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the direction by 45 degrees.
|
||||
* @param dir Direction to rotate.
|
||||
* @return Rotated direction.
|
||||
*/
|
||||
static inline Direction2 rotate45(Direction2 dir, int count = 1)
|
||||
{
|
||||
return (Direction2)(((dir - DIR2_NORTH + count) & 7) + DIR2_NORTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate the direction by 90 degrees.
|
||||
* @param dir Direction to rotate.
|
||||
* @return Rotated direction.
|
||||
*/
|
||||
static inline Direction2 rotate90(Direction2 dir)
|
||||
{
|
||||
return rotate45(dir, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate the direction by 180 degrees.
|
||||
* @param dir Direction to rotate.
|
||||
* @return Rotated direction.
|
||||
*/
|
||||
static inline Direction2 rotate180(Direction2 dir)
|
||||
{
|
||||
return rotate45(dir, 4);
|
||||
}
|
||||
|
||||
|
||||
/** X/Y position. */
|
||||
class Position {
|
||||
|
||||
public:
|
||||
|
||||
Position();
|
||||
Position(int x, int y);
|
||||
Position(const Position &pos);
|
||||
Position(const Position &pos, Direction2 dir);
|
||||
Position(const Position &pos, int dx, int dy);
|
||||
Position &operator=(const Position &pos);
|
||||
|
||||
bool move(Direction2 dir);
|
||||
inline bool testBounds();
|
||||
|
||||
int posX; ///< Horizontal coordinate of the position.
|
||||
int posY; ///< Vertical coordnate of the position.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Test whether the position is on-map.
|
||||
* @return Position is on-map.
|
||||
*/
|
||||
inline bool Position::testBounds()
|
||||
{
|
||||
return (this->posX >= 0 && this->posX < WORLD_W
|
||||
&& this->posY >= 0 && this->posY < WORLD_H);
|
||||
}
|
||||
|
||||
/**
|
||||
* Less-than comparison on positions (needed for map since Position is used as
|
||||
* key value).
|
||||
* @param pos1 First position.
|
||||
* @param pos2 Second position.
|
||||
* @return First position is smaller than second position.
|
||||
*/
|
||||
inline bool operator<(const Position &pos1, const Position &pos2)
|
||||
{
|
||||
if (pos1.posX != pos2.posX) return pos1.posX < pos2.posX;
|
||||
return pos1.posY < pos2.posY;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
195
core/power.cpp
Normal file
195
core/power.cpp
Normal file
|
@ -0,0 +1,195 @@
|
|||
/* power.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file power.cpp
|
||||
* @brief Manages power distribution in the Micropolis game.
|
||||
*
|
||||
* This file contains functions for scanning the game map to
|
||||
* distribute power from power plants to other structures. It utilizes
|
||||
* a power stack to track and update the power status of tiles. The
|
||||
* file includes constants for the power strength of coal and nuclear
|
||||
* power plants, and functions to test for conductive tiles, scan the
|
||||
* map for power distribution, and manipulate the power stack.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
#include "text.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Constants
|
||||
|
||||
/** Number of tiles that a coal power plant can supply power to. */
|
||||
static const Quad COAL_POWER_STRENGTH = 700L;
|
||||
|
||||
/** Number of tiles that a nuclear power plant can supply power to. */
|
||||
static const Quad NUCLEAR_POWER_STRENGTH = 2000L;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Check at position \a pos for a power-less conducting tile in the
|
||||
* direction \a testDir.
|
||||
* @param pos Position to start from.
|
||||
* @param testDir Direction to investigate.
|
||||
* @return Unpowered tile has been found in the indicated direction.
|
||||
* @todo Re-use something like Micropolis::getFromMap(), and fold this function
|
||||
* into its caller.
|
||||
*/
|
||||
bool Micropolis::testForConductive(const Position& pos, Direction2 testDir)
|
||||
{
|
||||
Position movedPos(pos);
|
||||
|
||||
if (movedPos.move(testDir)) {
|
||||
if ((map[movedPos.posX][movedPos.posY] & CONDBIT) == CONDBIT) {
|
||||
if (!powerGridMap.worldGet(movedPos.posX, movedPos.posY)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scan the map for powered tiles, and copy them to the Micropolis::powerGridMap
|
||||
* array.
|
||||
* Also warns the user about using too much power ('buy another power plant').
|
||||
*/
|
||||
void Micropolis::doPowerScan()
|
||||
{
|
||||
Direction2 anyDir,dir;
|
||||
int conNum;
|
||||
|
||||
// Clear power map.
|
||||
powerGridMap.clear();
|
||||
|
||||
// Power that the combined coal and nuclear power plants can deliver.
|
||||
Quad maxPower = coalPowerPop * COAL_POWER_STRENGTH +
|
||||
nuclearPowerPop * NUCLEAR_POWER_STRENGTH;
|
||||
|
||||
Quad numPower = 0; // Amount of power used.
|
||||
|
||||
while (powerStackPointer > 0) {
|
||||
Position pos = pullPowerStack();
|
||||
anyDir = DIR2_INVALID;
|
||||
do {
|
||||
numPower++;
|
||||
if (numPower > maxPower) {
|
||||
sendMessage(MESSAGE_NOT_ENOUGH_POWER);
|
||||
return;
|
||||
}
|
||||
if (anyDir != DIR2_INVALID) {
|
||||
pos.move(anyDir);
|
||||
}
|
||||
powerGridMap.worldSet(pos.posX, pos.posY, 1);
|
||||
conNum = 0;
|
||||
dir = DIR2_BEGIN;
|
||||
while (dir < DIR2_END && conNum < 2) {
|
||||
if (testForConductive(pos, dir)) {
|
||||
conNum++;
|
||||
anyDir = dir;
|
||||
}
|
||||
dir = increment90(dir);
|
||||
}
|
||||
if (conNum > 1) {
|
||||
pushPowerStack(pos);
|
||||
}
|
||||
} while (conNum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Push position \a pos onto the power stack if there is room.
|
||||
* @param pos Position to push.
|
||||
*/
|
||||
void Micropolis::pushPowerStack(const Position &pos)
|
||||
{
|
||||
if (powerStackPointer < (POWER_STACK_SIZE - 2)) {
|
||||
powerStackPointer++;
|
||||
powerStackXY[powerStackPointer] = pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pull a position from the power stack.
|
||||
* @return Pulled position.
|
||||
* @pre Stack must be non-empty (powerStackPointer > 0).
|
||||
*/
|
||||
Position Micropolis::pullPowerStack()
|
||||
{
|
||||
assert(powerStackPointer > 0);
|
||||
powerStackPointer--;
|
||||
return powerStackXY[powerStackPointer + 1];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
183
core/random.cpp
Normal file
183
core/random.cpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
/* random.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file random.cpp
|
||||
* @brief Contains functions for generating random numbers in
|
||||
* Micropolis.
|
||||
*
|
||||
* This file includes functions for generating random numbers used in
|
||||
* various aspects of the Micropolis game. It provides functions for
|
||||
* generating random numbers within specific ranges, signed and
|
||||
* unsigned random numbers, and a method to initialize the random
|
||||
* number generator with a random seed.
|
||||
*
|
||||
* @bug Code seems to assume that \c sizeof(short)==2 and \c
|
||||
* sizeof(int)==4 However, this depends on the compiler. We should
|
||||
* introduce typedefs for them, and check correctness of our
|
||||
* assumptions w.r.t. size of them (eg in
|
||||
* Micropolis::randomlySeedRandom() or in Micropolis::Micropolis()).
|
||||
*
|
||||
* @bug Code stores unsigned 16 bit numbers in \c short which is a
|
||||
* signed type.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Draw a random number (internal function).
|
||||
* @todo Use Wolfram's fast cellular automata pseudo random number generator.
|
||||
* @return Unsigned 16 bit random number.
|
||||
*/
|
||||
int Micropolis::simRandom()
|
||||
{
|
||||
nextRandom = nextRandom * 1103515245 + 12345;
|
||||
return (nextRandom & 0xffff00) >> 8;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Draw a random number in a given range.
|
||||
* @param range Upper bound of the range (inclusive).
|
||||
* @return Random number between \c 0 and \a range (inclusive).
|
||||
*/
|
||||
short Micropolis::getRandom(short range)
|
||||
{
|
||||
int maxMultiple, rnum;
|
||||
|
||||
range++; /// @bug Increment may cause range overflow.
|
||||
maxMultiple = 0xffff / range;
|
||||
maxMultiple *= range;
|
||||
|
||||
do {
|
||||
rnum = getRandom16();
|
||||
} while (rnum >= maxMultiple);
|
||||
|
||||
return (rnum % range);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get random 16 bit number.
|
||||
* @return Unsigned 16 bit random number.
|
||||
*/
|
||||
int Micropolis::getRandom16()
|
||||
{
|
||||
return simRandom() & 0x0000ffff;
|
||||
}
|
||||
|
||||
|
||||
/** Get signed 16 bit random number. */
|
||||
int Micropolis::getRandom16Signed()
|
||||
{
|
||||
int i = getRandom16();
|
||||
|
||||
if (i > 0x7fff) {
|
||||
i = 0x7fff - i;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a random number within a given range, with a preference to smaller
|
||||
* values.
|
||||
* @param limit Upper bound of the range (inclusive).
|
||||
* @return Random number between \c 0 and \a limit (inclusive).
|
||||
*/
|
||||
short Micropolis::getERandom(short limit)
|
||||
{
|
||||
short z = getRandom(limit);
|
||||
short x = getRandom(limit);
|
||||
|
||||
return min(z, x);
|
||||
}
|
||||
|
||||
|
||||
/** Initialize the random number generator with a 'random' seed. */
|
||||
void Micropolis::randomlySeedRandom()
|
||||
{
|
||||
struct timeval time;
|
||||
gettimeofday(&time, NULL);
|
||||
seedRandom(time.tv_usec ^ time.tv_sec);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set seed of the random number generator.
|
||||
* @param seed New seed.
|
||||
*/
|
||||
void Micropolis::seedRandom(int seed)
|
||||
{
|
||||
nextRandom = seed;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
600
core/scan.cpp
Normal file
600
core/scan.cpp
Normal file
|
@ -0,0 +1,600 @@
|
|||
/* scan.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file scan.cpp
|
||||
* @brief Implements various scanning and analysis algorithms for
|
||||
* Micropolis.
|
||||
*
|
||||
* This file contains functions for scanning and analyzing different
|
||||
* aspects of the city in the Micropolis game, including fire and
|
||||
* police station coverage, population density, pollution, land value,
|
||||
* crime rates, and terrain. It also includes utility functions for
|
||||
* smoothing maps and calculating distances.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Smooth a station map.
|
||||
*
|
||||
* Used for smoothing fire station and police station coverage maps.
|
||||
* @param map Map to smooth.
|
||||
*/
|
||||
static void smoothStationMap(MapShort8 *map)
|
||||
{
|
||||
short x, y, edge;
|
||||
MapShort8 tempMap(*map);
|
||||
|
||||
for (x = 0; x < tempMap.MAP_W; x++) {
|
||||
for (y = 0; y < tempMap.MAP_H; y++) {
|
||||
edge = 0;
|
||||
if (x > 0) {
|
||||
edge += tempMap.get(x - 1, y);
|
||||
}
|
||||
if (x < tempMap.MAP_W - 1) {
|
||||
edge += tempMap.get(x + 1, y);
|
||||
}
|
||||
if (y > 0) {
|
||||
edge += tempMap.get(x, y - 1);
|
||||
}
|
||||
if (y < tempMap.MAP_H - 1) {
|
||||
edge += tempMap.get(x, y + 1);
|
||||
}
|
||||
edge = tempMap.get(x, y) + edge / 4;
|
||||
map->set(x, y, edge / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make firerate map from firestation map.
|
||||
* @todo Comment seems wrong; what's a firerate map?
|
||||
*/
|
||||
void Micropolis::fireAnalysis()
|
||||
{
|
||||
smoothStationMap(&fireStationMap);
|
||||
smoothStationMap(&fireStationMap);
|
||||
smoothStationMap(&fireStationMap);
|
||||
|
||||
fireStationEffectMap = fireStationMap;
|
||||
|
||||
newMapFlags[MAP_TYPE_FIRE_RADIUS] = 1;
|
||||
newMapFlags[MAP_TYPE_DYNAMIC] = 1;
|
||||
}
|
||||
|
||||
|
||||
/** @todo The tempMap1 has MAP_BLOCKSIZE > 1, so we may be able to optimize
|
||||
* the first x, y loop.
|
||||
*/
|
||||
void Micropolis::populationDensityScan()
|
||||
{
|
||||
/* sets: populationDensityMap, , , comRateMap */
|
||||
tempMap1.clear();
|
||||
Quad Xtot = 0;
|
||||
Quad Ytot = 0;
|
||||
Quad Ztot = 0;
|
||||
for (int x = 0; x < WORLD_W; x++) {
|
||||
for (int y = 0; y < WORLD_H; y++) {
|
||||
MapValue mapValue = map[x][y];
|
||||
if (mapValue & ZONEBIT) {
|
||||
MapTile mapTile = mapValue & LOMASK;
|
||||
int pop = getPopulationDensity(Position(x, y), mapTile) * 8;
|
||||
pop = min(pop, 254);
|
||||
|
||||
tempMap1.worldSet(x, y, (Byte)pop);
|
||||
Xtot += x;
|
||||
Ytot += y;
|
||||
Ztot++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doSmooth1(); // tempMap1 -> tempMap2
|
||||
doSmooth2(); // tempMap2 -> tempMap1
|
||||
doSmooth1(); // tempMap1 -> tempMap2
|
||||
|
||||
assert(populationDensityMap.MAP_W == tempMap2.MAP_W);
|
||||
assert(populationDensityMap.MAP_H == tempMap2.MAP_H);
|
||||
|
||||
// Copy tempMap2 to populationDensityMap, multiplying by 2
|
||||
Byte *srcMap = tempMap2.getBase();
|
||||
Byte *destMap = populationDensityMap.getBase();
|
||||
for (int i = 0; i < tempMap2.MAP_W * tempMap2.MAP_H; i++) {
|
||||
destMap[i] = srcMap[i] * 2;
|
||||
}
|
||||
|
||||
computeComRateMap(); /* Compute the comRateMap */
|
||||
|
||||
|
||||
// Compute new city center
|
||||
if (Ztot > 0) { /* Find Center of Mass for City */
|
||||
cityCenterX = (short)(Xtot / Ztot);
|
||||
cityCenterY = (short)(Ytot / Ztot);
|
||||
} else {
|
||||
cityCenterX = WORLD_W / 2; /* if pop==0 center of map is city center */
|
||||
cityCenterY = WORLD_H / 2;
|
||||
}
|
||||
|
||||
// Set flags for updated maps
|
||||
newMapFlags[MAP_TYPE_POPULATION_DENSITY] = 1;
|
||||
newMapFlags[MAP_TYPE_RATE_OF_GROWTH] = 1;
|
||||
newMapFlags[MAP_TYPE_DYNAMIC] = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get population of a zone.
|
||||
* @param pos Position of the zone to count.
|
||||
* @param tile Tile of the zone.
|
||||
* @return Population of the zone.
|
||||
*/
|
||||
int Micropolis::getPopulationDensity(const Position &pos, MapTile tile)
|
||||
{
|
||||
int pop;
|
||||
|
||||
if (tile == FREEZ) {
|
||||
pop = doFreePop(pos);
|
||||
return pop;
|
||||
}
|
||||
|
||||
if (tile < COMBASE) {
|
||||
pop = getResZonePop(tile);
|
||||
return pop;
|
||||
}
|
||||
|
||||
if (tile < INDBASE) {
|
||||
pop = getComZonePop(tile) * 8;
|
||||
return pop;
|
||||
}
|
||||
|
||||
if (tile < PORTBASE) {
|
||||
pop = getIndZonePop(tile) * 8;
|
||||
return pop;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* comefrom: simulate SpecialInit */
|
||||
void Micropolis::pollutionTerrainLandValueScan()
|
||||
{
|
||||
/* Does pollution, terrain, land value */
|
||||
Quad ptot, LVtot;
|
||||
int x, y, z, dis;
|
||||
int pollutionLevel, loc, worldX, worldY, Mx, My, pnum, LVnum, pmax;
|
||||
|
||||
// tempMap3 is a map of development density, smoothed into terrainMap.
|
||||
tempMap3.clear();
|
||||
|
||||
LVtot = 0;
|
||||
LVnum = 0;
|
||||
|
||||
for (x = 0; x < landValueMap.MAP_W; x++) {
|
||||
for (y = 0; y < landValueMap.MAP_H; y++) {
|
||||
pollutionLevel = 0;
|
||||
bool landValueFlag = false;
|
||||
worldX = x * 2;
|
||||
worldY = y * 2;
|
||||
|
||||
for (Mx = worldX; Mx <= worldX + 1; Mx++) {
|
||||
for (My = worldY; My <= worldY + 1; My++) {
|
||||
loc = (map[Mx][My] & LOMASK);
|
||||
if (loc) {
|
||||
if (loc < RUBBLE) {
|
||||
// Increment terrain memory.
|
||||
Byte value = tempMap3.get(x >>1, y >>1);
|
||||
tempMap3.set(x >>1, y >>1, value + 15);
|
||||
continue;
|
||||
}
|
||||
pollutionLevel += getPollutionValue(loc);
|
||||
if (loc >= ROADBASE) {
|
||||
landValueFlag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX ??? This might have to do with the radiation tile returning -40.
|
||||
if (pollutionLevel < 0) {
|
||||
pollutionLevel = 250;
|
||||
}
|
||||
*/
|
||||
|
||||
pollutionLevel = min(pollutionLevel, 255);
|
||||
tempMap1.set(x, y, pollutionLevel);
|
||||
|
||||
if (landValueFlag) { /* LandValue Equation */
|
||||
dis = 34 - getCityCenterDistance(worldX, worldY) / 2;
|
||||
dis = dis <<2;
|
||||
dis += terrainDensityMap.get(x >>1, y >>1);
|
||||
dis -= pollutionDensityMap.get(x, y);
|
||||
if (crimeRateMap.get(x, y) > 190) {
|
||||
dis -= 20;
|
||||
}
|
||||
dis = clamp(dis, 1, 250);
|
||||
landValueMap.set(x, y, dis);
|
||||
LVtot += dis;
|
||||
LVnum++;
|
||||
} else {
|
||||
landValueMap.set(x, y, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (LVnum > 0) {
|
||||
landValueAverage = (short)(LVtot / LVnum);
|
||||
} else {
|
||||
landValueAverage = 0;
|
||||
}
|
||||
|
||||
doSmooth1(); // tempMap1 -> tempMap2
|
||||
doSmooth2(); // tempMap2 -> tempMap1
|
||||
|
||||
pmax = 0;
|
||||
pnum = 0;
|
||||
ptot = 0;
|
||||
|
||||
for (x = 0; x < WORLD_W; x += pollutionDensityMap.MAP_BLOCKSIZE) {
|
||||
for (y = 0; y < WORLD_H; y += pollutionDensityMap.MAP_BLOCKSIZE) {
|
||||
z = tempMap1.worldGet(x, y);
|
||||
pollutionDensityMap.worldSet(x, y, z);
|
||||
|
||||
if (z) { /* get pollute average */
|
||||
pnum++;
|
||||
ptot += z;
|
||||
/* find max pol for monster */
|
||||
if (z > pmax || (z == pmax && (getRandom16() & 3) == 0)) {
|
||||
pmax = z;
|
||||
pollutionMaxX = x;
|
||||
pollutionMaxY = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pnum) {
|
||||
pollutionAverage = (short)(ptot / pnum);
|
||||
} else {
|
||||
pollutionAverage = 0;
|
||||
}
|
||||
|
||||
smoothTerrain();
|
||||
|
||||
newMapFlags[MAP_TYPE_POLLUTION] = 1;
|
||||
newMapFlags[MAP_TYPE_LAND_VALUE] = 1;
|
||||
newMapFlags[MAP_TYPE_DYNAMIC] = 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return pollution of a tile value
|
||||
* @param loc Tile character
|
||||
* @return Value of the pollution (0..255, bigger is worse)
|
||||
*/
|
||||
int Micropolis::getPollutionValue(int loc)
|
||||
{
|
||||
if (loc < POWERBASE) {
|
||||
|
||||
if (loc >= HTRFBASE) {
|
||||
return /* 25 */ 75; /* heavy traf */
|
||||
}
|
||||
|
||||
if (loc >= LTRFBASE) {
|
||||
return /* 10 */ 50; /* light traf */
|
||||
}
|
||||
|
||||
if (loc < ROADBASE) {
|
||||
|
||||
if (loc > FIREBASE) {
|
||||
return /* 60 */ 90;
|
||||
}
|
||||
|
||||
/* XXX: Why negative pollution from radiation? */
|
||||
if (loc >= RADTILE) {
|
||||
return /* -40 */ 255; /* radioactivity */
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loc <= LASTIND) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (loc < PORTBASE) {
|
||||
return 50; /* Ind */
|
||||
}
|
||||
|
||||
if (loc <= LASTPOWERPLANT) {
|
||||
return /* 60 */ 100; /* prt, aprt, cpp */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute Manhattan distance between given world position and center of the
|
||||
* city.
|
||||
* @param x X world coordinate of given position.
|
||||
* @param y Y world coordinate of given position.
|
||||
* @return Manhattan distance (\c dx+dy ) between both positions.
|
||||
* @note For long distances (> 64), value 64 is returned.
|
||||
*/
|
||||
int Micropolis::getCityCenterDistance(int x, int y)
|
||||
{
|
||||
int xDis, yDis;
|
||||
|
||||
if (x > cityCenterX) {
|
||||
xDis = x - cityCenterX;
|
||||
} else {
|
||||
xDis = cityCenterX - x;
|
||||
}
|
||||
|
||||
if (y > cityCenterY) {
|
||||
yDis = y - cityCenterY;
|
||||
} else {
|
||||
yDis = cityCenterY - y;
|
||||
}
|
||||
|
||||
return min(xDis + yDis, 64);
|
||||
}
|
||||
|
||||
|
||||
/** Smooth police station map and compute crime rate */
|
||||
void Micropolis::crimeScan()
|
||||
{
|
||||
smoothStationMap(&policeStationMap);
|
||||
smoothStationMap(&policeStationMap);
|
||||
smoothStationMap(&policeStationMap);
|
||||
|
||||
Quad totz = 0;
|
||||
int numz = 0;
|
||||
int cmax = 0;
|
||||
|
||||
for (int x = 0; x < WORLD_W; x += crimeRateMap.MAP_BLOCKSIZE) {
|
||||
for (int y = 0; y < WORLD_H; y += crimeRateMap.MAP_BLOCKSIZE) {
|
||||
int z = landValueMap.worldGet(x, y);
|
||||
if (z > 0) {
|
||||
++numz;
|
||||
z = 128 - z;
|
||||
z += populationDensityMap.worldGet(x, y);
|
||||
z = min(z, 300);
|
||||
z -= policeStationMap.worldGet(x, y);
|
||||
z = clamp(z, 0, 250);
|
||||
crimeRateMap.worldSet(x, y, (Byte)z);
|
||||
totz += z;
|
||||
|
||||
// Update new crime hot-spot
|
||||
if (z > cmax || (z == cmax && (getRandom16() & 3) == 0)) {
|
||||
cmax = z;
|
||||
crimeMaxX = x;
|
||||
crimeMaxY = y;
|
||||
}
|
||||
|
||||
} else {
|
||||
crimeRateMap.worldSet(x, y, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numz > 0) {
|
||||
crimeAverage = (short)(totz / numz);
|
||||
} else {
|
||||
crimeAverage = 0;
|
||||
}
|
||||
|
||||
policeStationEffectMap = policeStationMap;
|
||||
|
||||
newMapFlags[MAP_TYPE_CRIME] = 1;
|
||||
newMapFlags[MAP_TYPE_POLICE_RADIUS] = 1;
|
||||
newMapFlags[MAP_TYPE_DYNAMIC] = 1;
|
||||
}
|
||||
|
||||
|
||||
/* comefrom: pollutionTerrainLandValueScan */
|
||||
void Micropolis::smoothTerrain()
|
||||
{
|
||||
if (donDither & 1) {
|
||||
int x, y = 0, dir = 1;
|
||||
unsigned z = 0;
|
||||
|
||||
for (x = 0; x < terrainDensityMap.MAP_W; x++) {
|
||||
for (; y != terrainDensityMap.MAP_H && y != -1; y += dir) {
|
||||
z +=
|
||||
tempMap3.get((x == 0) ? x : (x - 1), y) +
|
||||
tempMap3.get((x == (terrainDensityMap.MAP_W - 1)) ? x : (x + 1), y) +
|
||||
tempMap3.get(x, (y == 0) ? (0) : (y - 1)) +
|
||||
tempMap3.get(x, (y == (terrainDensityMap.MAP_H - 1)) ? y : (y + 1)) +
|
||||
(tempMap3.get(x, y) <<2);
|
||||
Byte val = (Byte)(z / 8);
|
||||
terrainDensityMap.set(x, y, val);
|
||||
z &= 0x7;
|
||||
}
|
||||
dir = -dir;
|
||||
y += dir;
|
||||
}
|
||||
} else {
|
||||
short x, y;
|
||||
|
||||
for (x = 0; x < terrainDensityMap.MAP_W; x++) {
|
||||
for (y = 0; y < terrainDensityMap.MAP_H; y++) {
|
||||
unsigned z = 0;
|
||||
if (x > 0) {
|
||||
z += tempMap3.get(x - 1, y);
|
||||
}
|
||||
if (x < (terrainDensityMap.MAP_W - 1)) {
|
||||
z += tempMap3.get(x + 1, y);
|
||||
}
|
||||
if (y > 0) {
|
||||
z += tempMap3.get(x, y - 1);
|
||||
}
|
||||
if (y < (terrainDensityMap.MAP_H - 1)) {
|
||||
z += tempMap3.get(x, y + 1);
|
||||
}
|
||||
Byte val = (Byte)(z / 4 + tempMap3.get(x, y)) / 2;
|
||||
terrainDensityMap.set(x, y, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform smoothing with or without dithering.
|
||||
* @param srcMap Source map.
|
||||
* @param destMap Destination map.
|
||||
* @param ditherFlag Function should apply dithering.
|
||||
*/
|
||||
static void smoothDitherMap(const MapByte2 &srcMap,
|
||||
MapByte2 *destMap,
|
||||
bool ditherFlag)
|
||||
{
|
||||
if (ditherFlag) {
|
||||
int x, y = 0, z = 0, dir = 1;
|
||||
|
||||
for (x = 0; x < srcMap.MAP_W; x++) {
|
||||
for (; y != srcMap.MAP_H && y != -1; y += dir) {
|
||||
z +=
|
||||
srcMap.get((x == 0) ? x : (x - 1), y) +
|
||||
srcMap.get((x == srcMap.MAP_W - 1) ? x : (x + 1), y) +
|
||||
srcMap.get(x, (y == 0) ? (0) : (y - 1)) +
|
||||
srcMap.get(x, (y == (srcMap.MAP_H - 1)) ? y : (y + 1)) +
|
||||
srcMap.get(x, y);
|
||||
Byte val = (Byte)(z / 4);
|
||||
destMap->set(x, y, val);
|
||||
z &= 3;
|
||||
}
|
||||
dir = -dir;
|
||||
y += dir;
|
||||
}
|
||||
} else {
|
||||
short x, y, z;
|
||||
|
||||
for (x = 0; x < srcMap.MAP_W; x++) {
|
||||
for (y = 0; y < srcMap.MAP_H; y++) {
|
||||
z = 0;
|
||||
if (x > 0) {
|
||||
z += srcMap.get(x - 1, y);
|
||||
}
|
||||
if (x < srcMap.MAP_W - 1) {
|
||||
z += srcMap.get(x + 1, y);
|
||||
}
|
||||
if (y > 0) {
|
||||
z += srcMap.get(x, y - 1);
|
||||
}
|
||||
if (y < (srcMap.MAP_H - 1)) {
|
||||
z += srcMap.get(x, y + 1);
|
||||
}
|
||||
z = (z + srcMap.get(x, y)) >>2;
|
||||
if (z > 255) {
|
||||
z = 255;
|
||||
}
|
||||
destMap->set(x, y, (Byte)z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Smooth Micropolis::tempMap1 to Micropolis::tempMap2 */
|
||||
void Micropolis::doSmooth1()
|
||||
{
|
||||
smoothDitherMap(tempMap1, &tempMap2, donDither & 2);
|
||||
}
|
||||
|
||||
|
||||
/* Smooth Micropolis::tempMap2 to Micropolis::tempMap1 */
|
||||
void Micropolis::doSmooth2()
|
||||
{
|
||||
smoothDitherMap(tempMap2, &tempMap1, donDither & 4);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute distance to city center for the entire map.
|
||||
* @see comRateMap
|
||||
*/
|
||||
void Micropolis::computeComRateMap()
|
||||
{
|
||||
short x, y, z;
|
||||
|
||||
for (x = 0; x < comRateMap.MAP_W; x++) {
|
||||
for (y = 0; y < comRateMap.MAP_H; y++) {
|
||||
z = (short)(getCityCenterDistance(x * 8,y * 8) / 2); // 0..32
|
||||
z = z * 4; // 0..128
|
||||
z = 64 - z; // 64..-64
|
||||
comRateMap.set(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
1723
core/simulate.cpp
Normal file
1723
core/simulate.cpp
Normal file
File diff suppressed because it is too large
Load diff
2039
core/sprite.cpp
Normal file
2039
core/sprite.cpp
Normal file
File diff suppressed because it is too large
Load diff
178
core/text.h
Normal file
178
core/text.h
Normal file
|
@ -0,0 +1,178 @@
|
|||
/* text.h
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file text.h
|
||||
* @brief Defines string identification numbers for texts used in the
|
||||
* Micropolis game engine.
|
||||
*
|
||||
* This file provides enumerations for identifying various strings and
|
||||
* messages used within the game. It includes definitions for scoring
|
||||
* metrics, in-game messages, and notifications. These identifications
|
||||
* facilitate the retrieval and display of context-specific text,
|
||||
* contributing to the user interface and game interactions.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _H_TEXT
|
||||
#define _H_TEXT
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/** String numbers of score card. */
|
||||
enum Stri202 {
|
||||
STR202_POPULATIONDENSITY_LOW = 0, ///< Low
|
||||
STR202_POPULATIONDENSITY_MEDIUM = 1, ///< Medium
|
||||
STR202_POPULATIONDENSITY_HIGH = 2, ///< High
|
||||
STR202_POPULATIONDENSITY_VERYHIGH = 3, ///< Very High
|
||||
|
||||
STR202_LANDVALUE_SLUM = 4, ///< Slum
|
||||
STR202_LANDVALUE_LOWER_CLASS = 5, ///< Lower Class
|
||||
STR202_LANDVALUE_MIDDLE_CLASS = 6, ///< Middle Class
|
||||
STR202_LANDVALUE_HIGH_CLASS = 7, ///< High
|
||||
|
||||
STR202_CRIME_NONE = 8, ///< Safe
|
||||
STR202_CRIME_LIGHT = 9, ///< Light
|
||||
STR202_CRIME_MODERATE = 10, ///< Moderate
|
||||
STR202_CRIME_DANGEROUS = 11, ///< Dangerous
|
||||
|
||||
STR202_POLLUTION_NONE = 12, ///< None
|
||||
STR202_POLLUTION_MODERATE = 13, ///< Moderate
|
||||
STR202_POLLUTION_HEAVY = 14, ///< Heavy
|
||||
STR202_POLLUTION_VERY_HEAVY = 15, ///< Very Heavy
|
||||
|
||||
STR202_GROWRATE_DECLINING = 16, ///< Declining
|
||||
STR202_GROWRATE_STABLE = 17, ///< Stable
|
||||
STR202_GROWRATE_SLOWGROWTH = 18, ///< Slow Growth
|
||||
STR202_GROWRATE_FASTGROWTH = 19, ///< Fast Growth
|
||||
};
|
||||
|
||||
/** String numbers of messages. */
|
||||
enum MessageNumber {
|
||||
MESSAGE_NEED_MORE_RESIDENTIAL = 1, ///< More residential zones needed.
|
||||
MESSAGE_NEED_MORE_COMMERCIAL, ///< More commercial zones needed.
|
||||
MESSAGE_NEED_MORE_INDUSTRIAL, ///< More industrial zones needed.
|
||||
MESSAGE_NEED_MORE_ROADS, ///< More roads required.
|
||||
MESSAGE_NEED_MORE_RAILS, ///< 5: Inadequate rail system.
|
||||
MESSAGE_NEED_ELECTRICITY, ///< Build a Power Plant.
|
||||
MESSAGE_NEED_STADIUM, ///< Residents demand a Stadium.
|
||||
MESSAGE_NEED_SEAPORT, ///< Industry requires a Sea Port.
|
||||
MESSAGE_NEED_AIRPORT, ///< Commerce requires an Airport.
|
||||
MESSAGE_HIGH_POLLUTION, ///< 10: Pollution very high.
|
||||
MESSAGE_HIGH_CRIME, ///< Crime very high.
|
||||
MESSAGE_TRAFFIC_JAMS, ///< Frequent traffic jams reported.
|
||||
MESSAGE_NEED_FIRE_STATION, ///< Citizens demand a Fire Department.
|
||||
MESSAGE_NEED_POLICE_STATION, ///< Citizens demand a Police Department.
|
||||
MESSAGE_BLACKOUTS_REPORTED, ///< 15: Blackouts reported. Check power map.
|
||||
MESSAGE_TAX_TOO_HIGH, ///< Citizens upset. The tax rate is too high.
|
||||
MESSAGE_ROAD_NEEDS_FUNDING, ///< Roads deteriorating, due to lack of funds.
|
||||
MESSAGE_FIRE_STATION_NEEDS_FUNDING, ///< Fire departments need funding.
|
||||
MESSAGE_POLICE_NEEDS_FUNDING, ///< Police departments need funding.
|
||||
MESSAGE_FIRE_REPORTED, ///< 20: Fire reported !
|
||||
MESSAGE_MONSTER_SIGHTED, ///< A Monster has been sighted !!
|
||||
MESSAGE_TORNADO_SIGHTED, ///< Tornado reported !!
|
||||
MESSAGE_EARTHQUAKE, ///< Major earthquake reported !!!
|
||||
MESSAGE_PLANE_CRASHED, ///< A plane has crashed !
|
||||
MESSAGE_SHIP_CRASHED, ///< 25: Shipwreck reported !
|
||||
MESSAGE_TRAIN_CRASHED, ///< A train crashed !
|
||||
MESSAGE_HELICOPTER_CRASHED, ///< A helicopter crashed !
|
||||
MESSAGE_HIGH_UNEMPLOYMENT, ///< Unemployment rate is high.
|
||||
MESSAGE_NO_MONEY, ///< YOUR CITY HAS GONE BROKE!
|
||||
MESSAGE_FIREBOMBING, ///< 30: Firebombing reported !
|
||||
MESSAGE_NEED_MORE_PARKS, ///< Need more parks.
|
||||
MESSAGE_EXPLOSION_REPORTED, ///< Explosion detected !
|
||||
MESSAGE_NOT_ENOUGH_FUNDS, ///< Insufficient funds to build that.
|
||||
MESSAGE_BULLDOZE_AREA_FIRST, ///< Area must be bulldozed first.
|
||||
MESSAGE_REACHED_TOWN, ///< 35: Population has reached 2,000.
|
||||
MESSAGE_REACHED_CITY, ///< Population has reached 10,000.
|
||||
MESSAGE_REACHED_CAPITAL, ///< Population has reached 50,000.
|
||||
MESSAGE_REACHED_METROPOLIS, ///< Population has reached 100,000.
|
||||
MESSAGE_REACHED_MEGALOPOLIS, ///< Population has reached 500,000.
|
||||
MESSAGE_NOT_ENOUGH_POWER, ///< 40: Brownouts, build another Power Plant.
|
||||
MESSAGE_HEAVY_TRAFFIC, ///< Heavy Traffic reported.
|
||||
MESSAGE_FLOODING_REPORTED, ///< Flooding reported !!
|
||||
MESSAGE_NUCLEAR_MELTDOWN, ///< A Nuclear Meltdown has occurred !!!
|
||||
MESSAGE_RIOTS_REPORTED, ///< They're rioting in the streets !!
|
||||
MESSAGE_STARTED_NEW_CITY, ///< 45: Started a New City.
|
||||
MESSAGE_LOADED_SAVED_CITY, ///< Restored a Saved City.
|
||||
MESSAGE_SCENARIO_WON, ///< You won the scenario
|
||||
MESSAGE_SCENARIO_LOST, ///< You lose the scenario
|
||||
MESSAGE_ABOUT_MICROPOLIS, ///< About micropolis.
|
||||
MESSAGE_SCENARIO_DULLSVILLE, ///< 50: Dullsville scenario.
|
||||
MESSAGE_SCENARIO_SAN_FRANCISCO, ///< San Francisco scenario.
|
||||
MESSAGE_SCENARIO_HAMBURG, ///< Hamburg scenario.
|
||||
MESSAGE_SCENARIO_BERN, ///< Bern scenario.
|
||||
MESSAGE_SCENARIO_TOKYO, ///< Tokyo scenario.
|
||||
MESSAGE_SCENARIO_DETROIT, ///< 55: Detroit scenario.
|
||||
MESSAGE_SCENARIO_BOSTON, ///< Boston scenario.
|
||||
MESSAGE_SCENARIO_RIO_DE_JANEIRO, ///< 57: Rio de Janeiro scenario.
|
||||
|
||||
MESSAGE_LAST = 57, ///< Last valid message
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#endif
|
1617
core/tool.cpp
Normal file
1617
core/tool.cpp
Normal file
File diff suppressed because it is too large
Load diff
347
core/tool.h
Normal file
347
core/tool.h
Normal file
|
@ -0,0 +1,347 @@
|
|||
/* tool.h
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file tool.h
|
||||
* @brief Defines tools, building properties, and tool effects for the
|
||||
* Micropolis game.
|
||||
*
|
||||
* This header file includes definitions for various tools used in the
|
||||
* game, along with the properties of buildings and the effects tools
|
||||
* have on the game's world. It encompasses the core functionalities
|
||||
* of tools, such as building, bulldozing, and querying, and their
|
||||
* impact on the game's map and financial aspects. The classes and
|
||||
* enumerations in this file form an integral part of the game's
|
||||
* interaction mechanics, allowing players to modify and interact with
|
||||
* the game world.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _H_TOOL
|
||||
#define _H_TOOL
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Forward declarations
|
||||
|
||||
|
||||
class Micropolis;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/** Value of a tile in the map array incuding the #MapTileBits. */
|
||||
typedef unsigned short MapValue;
|
||||
|
||||
|
||||
/**
|
||||
* Value of a tile in the map array excluding the #MapTileBits (that is, just
|
||||
* a value from #MapCharacters).
|
||||
*/
|
||||
typedef unsigned short MapTile;
|
||||
|
||||
|
||||
/**
|
||||
* Status bits of a map tile.
|
||||
* @see MapTile MapCharacters MapTile MapValue
|
||||
* @todo #ALLBITS should end with MASK.
|
||||
* @todo Decide what to do with #ANIMBIT (since sim-backend may not be the
|
||||
* optimal place to do animation).
|
||||
* @todo How many of these bits can be derived from the displayed tile?
|
||||
*/
|
||||
enum MapTileBits {
|
||||
PWRBIT = 0x8000, ///< bit 15, tile has power.
|
||||
CONDBIT = 0x4000, ///< bit 14. tile can conduct electricity.
|
||||
BURNBIT = 0x2000, ///< bit 13, tile can be lit.
|
||||
BULLBIT = 0x1000, ///< bit 12, tile is bulldozable.
|
||||
ANIMBIT = 0x0800, ///< bit 11, tile is animated.
|
||||
ZONEBIT = 0x0400, ///< bit 10, tile is the center tile of the zone.
|
||||
|
||||
/// Mask for the bits-part of the tile
|
||||
ALLBITS = ZONEBIT | ANIMBIT | BULLBIT | BURNBIT | CONDBIT | PWRBIT,
|
||||
LOMASK = 0x03ff, ///< Mask for the #Tiles part of the tile
|
||||
|
||||
BLBNBIT = BULLBIT | BURNBIT,
|
||||
BLBNCNBIT = BULLBIT | BURNBIT | CONDBIT,
|
||||
BNCNBIT = BURNBIT | CONDBIT,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Available tools.
|
||||
*
|
||||
* These describe the wand values, the object dragged around on the screen.
|
||||
*/
|
||||
enum EditingTool {
|
||||
TOOL_RESIDENTIAL,
|
||||
TOOL_COMMERCIAL,
|
||||
TOOL_INDUSTRIAL,
|
||||
TOOL_FIRESTATION,
|
||||
TOOL_POLICESTATION,
|
||||
TOOL_QUERY,
|
||||
TOOL_WIRE,
|
||||
TOOL_BULLDOZER,
|
||||
TOOL_RAILROAD,
|
||||
TOOL_ROAD,
|
||||
TOOL_STADIUM,
|
||||
TOOL_PARK,
|
||||
TOOL_SEAPORT,
|
||||
TOOL_COALPOWER,
|
||||
TOOL_NUCLEARPOWER,
|
||||
TOOL_AIRPORT,
|
||||
TOOL_NETWORK,
|
||||
TOOL_WATER,
|
||||
TOOL_LAND,
|
||||
TOOL_FOREST,
|
||||
|
||||
TOOL_COUNT,
|
||||
TOOL_FIRST = TOOL_RESIDENTIAL,
|
||||
TOOL_LAST = TOOL_FOREST,
|
||||
};
|
||||
|
||||
|
||||
/** Set of modifications in the world accessible by position. */
|
||||
typedef std::map<Position, MapValue> WorldModificationsMap;
|
||||
|
||||
|
||||
/** List of messages to send to the frontend. */
|
||||
typedef std::list<FrontendMessage *> FrontendMessages;
|
||||
|
||||
/**
|
||||
* Class for storing effects of applying a tool to the world.
|
||||
*
|
||||
* When applying a tool, two things change:
|
||||
* - The world map.
|
||||
* - The funds of the player.
|
||||
* - Messages sent to the player and the front-end.
|
||||
* - Sounds played for the player.
|
||||
*
|
||||
* The funds gives a decision problem. To decide whether the tool can be
|
||||
* applied, you need to know the cost. To know the cost you need to know the
|
||||
* exact changes being made.
|
||||
* The simplest way to compute the exact changes is to simply apply the tool to
|
||||
* the world. This holds especially when tools get stacked on top of each
|
||||
* other.
|
||||
*
|
||||
* This class provides an easy way out, greatly simplifying the problem.
|
||||
* All tools do not modify the world directly, but instead put their results
|
||||
* in an instance of this class, thus collecting all the modifications.
|
||||
* After the whole operation is 'done', the #ToolEffects instance can tell the
|
||||
* precise cost and what has been changed in the world. At that moment, the
|
||||
* yes/no decision can be made, and the effects can be copied to the real map
|
||||
* and funds.
|
||||
*
|
||||
* @todo Extend the class for storing messages and sounds.
|
||||
*/
|
||||
class ToolEffects
|
||||
{
|
||||
public:
|
||||
ToolEffects(Micropolis *sim);
|
||||
~ToolEffects();
|
||||
|
||||
void clear();
|
||||
void modifyWorld();
|
||||
bool modifyIfEnoughFunding();
|
||||
|
||||
MapValue getMapValue(const Position& pos) const;
|
||||
inline MapValue getMapValue(int x, int y) const;
|
||||
inline MapTile getMapTile(const Position& pos) const;
|
||||
inline MapTile getMapTile(int x, int y) const;
|
||||
inline int getCost() const;
|
||||
|
||||
inline void addCost(int amount);
|
||||
void setMapValue(const Position& pos, MapValue mapVal);
|
||||
inline void setMapValue(int x, int y, MapValue mapVal);
|
||||
inline void addFrontendMessage(FrontendMessage *msg);
|
||||
|
||||
private:
|
||||
Micropolis *sim; ///< Simulator to get map values from, and to apply changes.
|
||||
int cost; ///< Accumulated costs.
|
||||
WorldModificationsMap modifications; ///< Collected world modifications.
|
||||
FrontendMessages frontendMessages; ///< Collected messages to send.
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Get the tile of a map position.
|
||||
* @param pos Position being queried.
|
||||
* @return Tile at the specified position.
|
||||
*
|
||||
* @pre Position must be within map limits
|
||||
*/
|
||||
inline MapTile ToolEffects::getMapTile(const Position& pos) const
|
||||
{
|
||||
return this->getMapValue(pos) & LOMASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the tile of a map position.
|
||||
* @param x Horizontal coordinate of position being queried.
|
||||
* @param y Vertical coordinate of position being queried.
|
||||
* @return Tile at the specified position.
|
||||
*
|
||||
* @pre Position must be within map limits
|
||||
*/
|
||||
inline MapValue ToolEffects::getMapTile(int x, int y) const
|
||||
{
|
||||
return this->getMapValue(Position(x, y)) & LOMASK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the total cost collected so far.
|
||||
* @return Total cost.
|
||||
*/
|
||||
inline int ToolEffects::getCost() const
|
||||
{
|
||||
return this->cost;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add some amount to the total.
|
||||
*/
|
||||
inline void ToolEffects::addCost(int amount)
|
||||
{
|
||||
assert(amount >= 0); // To be on the safe side.
|
||||
this->cost += amount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the value of a map position.
|
||||
* @param x Horizontal coordinate of position being queried.
|
||||
* @param y Vertical coordinate of position being queried.
|
||||
* @return Map value at the specified position.
|
||||
*
|
||||
* @pre Position must be within map limits
|
||||
*/
|
||||
inline MapValue ToolEffects::getMapValue(int x, int y) const
|
||||
{
|
||||
return this->getMapValue(Position(x, y));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a new map value.
|
||||
* @param pos Position to set.
|
||||
* @param x Horizontal coordinate of position to set.
|
||||
* @param y Vertical coordinate of position to set.
|
||||
* @param mapVal Value to set.
|
||||
*/
|
||||
inline void ToolEffects::setMapValue(int x, int y, MapValue mapVal)
|
||||
{
|
||||
this->setMapValue(Position(x, y), mapVal);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a #FrontendMessage to the queue to send.
|
||||
* @param msg Frontend message to send.
|
||||
*/
|
||||
inline void ToolEffects::addFrontendMessage(FrontendMessage *msg)
|
||||
{
|
||||
this->frontendMessages.push_back(msg);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/** Properties of a building with respect to its construction. */
|
||||
class BuildingProperties
|
||||
{
|
||||
public:
|
||||
BuildingProperties(int xs, int ys, MapTile base, EditingTool tool,
|
||||
std::string tName, bool anim);
|
||||
~BuildingProperties();
|
||||
|
||||
const int sizeX; ///< Number of tiles in horizontal direction.
|
||||
const int sizeY; ///< Number of tiles in vertical direction.
|
||||
|
||||
const MapTile baseTile; ///< Tile value at top-left in the map.
|
||||
|
||||
const EditingTool tool; ///< Tool needed for making the building.
|
||||
|
||||
/** Name of the tool needed for making the building. */
|
||||
std::string toolName;
|
||||
|
||||
const bool buildingIsAnimated; ///< Building has animated tiles.
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#endif
|
519
core/traffic.cpp
Normal file
519
core/traffic.cpp
Normal file
|
@ -0,0 +1,519 @@
|
|||
/* traffic.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file traffic.cpp
|
||||
* @brief Implements traffic simulation for the Micropolis game
|
||||
* engine.
|
||||
*
|
||||
* This file handles the generation, management, and effects of
|
||||
* traffic within the Micropolis game. It includes functions for
|
||||
* simulating traffic flow, connecting destinations, and updating
|
||||
* traffic density maps. The code manages various traffic-related
|
||||
* tasks such as finding road connections, driving to destinations,
|
||||
* and handling dead-end situations. Additionally, it updates the
|
||||
* simulation's internal state based on traffic conditions.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Makes traffic starting from the road tile at \x, \y.
|
||||
* @param x Start x position of the attempt
|
||||
* @param y Start y position of the attempt
|
||||
* @param dest Zone type to go to.
|
||||
* @return \c 1 if connection found, \c 0 if not found,
|
||||
* \c -1 if no connection to road found.
|
||||
*/
|
||||
short Micropolis::makeTrafficAt(int x, int y, ZoneType dest)
|
||||
{
|
||||
Position pos;
|
||||
pos.posX = x;
|
||||
pos.posY = y;
|
||||
|
||||
if (tryDrive(pos, dest)) { /* attempt to drive somewhere */
|
||||
addToTrafficDensityMap(); /* if sucessful, inc trafdensity */
|
||||
return 1; /* traffic passed */
|
||||
}
|
||||
|
||||
return 0; /* traffic failed */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a connection over a road from position \a x \a y to a specified zone type.
|
||||
* @param x Start x position of the attempt
|
||||
* @param y Start y position of the attempt
|
||||
* @param dest Zone type to go to.
|
||||
* @return \c 1 if connection found, \c 0 if not found,
|
||||
* \c -1 if no connection to road found.
|
||||
*/
|
||||
short Micropolis::makeTraffic(int x, int y, ZoneType dest)
|
||||
{
|
||||
Position startPos;
|
||||
startPos.posX = x;
|
||||
startPos.posY = y;
|
||||
return makeTraffic(startPos, dest);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a connection over a road from \a startPos to a specified zone type.
|
||||
* @param startPos Start position of the attempt.
|
||||
* @param dest Zone type to go to.
|
||||
* @return \c 1 if connection found, \c 0 if not found,
|
||||
* \c -1 if no connection to road found.
|
||||
*/
|
||||
short Micropolis::makeTraffic(const Position &startPos, ZoneType dest)
|
||||
{
|
||||
curMapStackPointer = 0; // Clear position stack
|
||||
|
||||
Position pos(startPos);
|
||||
|
||||
#if 0
|
||||
if ((!getRandom(2)) && findPerimeterTelecom(pos)) {
|
||||
/* printf("Telecom!\n"); */
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (findPerimeterRoad(&pos)) { /* look for road on zone perimeter */
|
||||
|
||||
if (tryDrive(pos, dest)) { /* attempt to drive somewhere */
|
||||
addToTrafficDensityMap(); /* if sucessful, inc trafdensity */
|
||||
return 1; /* traffic passed */
|
||||
}
|
||||
|
||||
return 0; /* traffic failed */
|
||||
} else {
|
||||
return -1; /* no road found */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the #trafficDensityMap from the positions at the
|
||||
* #curMapStackXY stack.
|
||||
*/
|
||||
void Micropolis::addToTrafficDensityMap()
|
||||
{
|
||||
/* For each saved position of the drive */
|
||||
while (curMapStackPointer > 0) {
|
||||
|
||||
Position pos = pullPos();
|
||||
if (pos.testBounds()) {
|
||||
|
||||
MapTile tile = map[pos.posX][pos.posY] & LOMASK;
|
||||
|
||||
if (tile >= ROADBASE && tile < POWERBASE) {
|
||||
SimSprite *sprite;
|
||||
|
||||
// Update traffic density.
|
||||
int traffic = trafficDensityMap.worldGet(pos.posX, pos.posY);
|
||||
traffic += 50;
|
||||
traffic = min(traffic, 240);
|
||||
trafficDensityMap.worldSet(pos.posX, pos.posY, (Byte)traffic);
|
||||
|
||||
// Check for heavy traffic.
|
||||
if (traffic >= 240 && getRandom(5) == 0) {
|
||||
|
||||
trafMaxX = pos.posX;
|
||||
trafMaxY = pos.posY;
|
||||
|
||||
/* Direct helicopter towards heavy traffic */
|
||||
sprite = getSprite(SPRITE_HELICOPTER);
|
||||
if (sprite != NULL && sprite->control == -1) {
|
||||
|
||||
sprite->destX = trafMaxX * 16;
|
||||
sprite->destY = trafMaxY * 16;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Push a position onto the position stack.
|
||||
* @param pos Position to push.
|
||||
* @pre Stack may not be full.
|
||||
*/
|
||||
void Micropolis::pushPos(const Position &pos)
|
||||
{
|
||||
curMapStackPointer++;
|
||||
assert(curMapStackPointer < MAX_TRAFFIC_DISTANCE + 1);
|
||||
curMapStackXY[curMapStackPointer] = pos;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pull top-most position from the position stack.
|
||||
* @return Pulled position.
|
||||
* @pre Stack may not be empty (curMapStackPointer > 0)
|
||||
*/
|
||||
Position Micropolis::pullPos()
|
||||
{
|
||||
assert(curMapStackPointer > 0);
|
||||
curMapStackPointer--;
|
||||
return curMapStackXY[curMapStackPointer + 1];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a connection to a road at the perimeter.
|
||||
* @param pos Starting position.
|
||||
* Gets updated when a perimeter has been found.
|
||||
* @return Indication that a connection has been found.
|
||||
*
|
||||
* @todo We could randomize the search.
|
||||
*/
|
||||
bool Micropolis::findPerimeterRoad(Position *pos)
|
||||
{
|
||||
/* look for road on edges of zone */
|
||||
static const short PerimX[12] = {-1, 0, 1, 2, 2, 2, 1, 0,-1,-2,-2,-2};
|
||||
static const short PerimY[12] = {-2,-2,-2,-1, 0, 1, 2, 2, 2, 1, 0,-1};
|
||||
short tx, ty;
|
||||
|
||||
for (short z = 0; z < 12; z++) {
|
||||
|
||||
tx = pos->posX + PerimX[z];
|
||||
ty = pos->posY + PerimY[z];
|
||||
|
||||
if (testBounds(tx, ty)) {
|
||||
|
||||
if (roadTest(map[tx][ty])) {
|
||||
|
||||
pos->posX = tx;
|
||||
pos->posY = ty;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find a telecom connection at the perimeter.
|
||||
* @param pos Position to start searching.
|
||||
* @return A telecom connection has been found.
|
||||
*
|
||||
* @todo Decide whether we want telecomm code.
|
||||
*/
|
||||
bool Micropolis::findPerimeterTelecom(const Position &pos)
|
||||
{
|
||||
/* look for telecom on edges of zone */
|
||||
static const short PerimX[12] = {-1, 0, 1, 2, 2, 2, 1, 0,-1,-2,-2,-2};
|
||||
static const short PerimY[12] = {-2,-2,-2,-1, 0, 1, 2, 2, 2, 1, 0,-1};
|
||||
short tx, ty, tile;
|
||||
|
||||
for (short z = 0; z < 12; z++) {
|
||||
|
||||
tx = pos.posX + PerimX[z];
|
||||
ty = pos.posX + PerimY[z];
|
||||
|
||||
if (testBounds(tx, ty)) {
|
||||
|
||||
tile = map[tx][ty] & LOMASK;
|
||||
if (tile >= TELEBASE && tile <= TELELAST) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to drive to a destination.
|
||||
* @param startPos Starting position.
|
||||
* @param destZone Zonetype to drive to.
|
||||
* @return Was drive succesful?
|
||||
* @post Position stack (curMapStackXY) is filled with some intermediate
|
||||
* positions of the drive.
|
||||
*
|
||||
* @bug The stack is popped, but position (and dirLast) is not updated.
|
||||
*/
|
||||
bool Micropolis::tryDrive(const Position &startPos, ZoneType destZone)
|
||||
{
|
||||
Direction2 dirLast = DIR2_INVALID;
|
||||
Position drivePos(startPos);
|
||||
|
||||
/* Maximum distance to try */
|
||||
for (short dist = 0; dist < MAX_TRAFFIC_DISTANCE; dist++) {
|
||||
|
||||
Direction2 dir = tryGo(drivePos, dirLast);
|
||||
if (dir != DIR2_INVALID) { // we found a road
|
||||
drivePos.move(dir);
|
||||
dirLast = rotate180(dir);
|
||||
|
||||
/* Save pos every other move.
|
||||
* This also relates to
|
||||
* Micropolis::trafficDensityMap::MAP_BLOCKSIZE
|
||||
*/
|
||||
if (dist & 1) {
|
||||
pushPos(drivePos);
|
||||
}
|
||||
|
||||
if (driveDone(drivePos, destZone)) { // if destination is reached
|
||||
return true; /* pass */
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (curMapStackPointer > 0) { /* dead end, backup */
|
||||
curMapStackPointer--;
|
||||
dist += 3;
|
||||
} else {
|
||||
return false; /* give up at start */
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false; /* gone MAX_TRAFFIC_DISTANCE */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to drive one tile in a random direction.
|
||||
* @param pos Current position.
|
||||
* @param dirLast Forbidden direction for movement (to prevent reversing).
|
||||
* @return Direction of movement, \c #DIR2_INVALID is returned if not moved.
|
||||
*/
|
||||
Direction2 Micropolis::tryGo(const Position &pos, Direction2 dirLast)
|
||||
{
|
||||
Direction2 directions[4];
|
||||
|
||||
// Find connections from current position.
|
||||
Direction2 dir = DIR2_NORTH;
|
||||
int count = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (dir != dirLast && roadTest(getTileFromMap(pos, dir, DIRT))) {
|
||||
// found a road in an allowed direction
|
||||
directions[i] = dir;
|
||||
count++;
|
||||
} else {
|
||||
directions[i] = DIR2_INVALID;
|
||||
}
|
||||
|
||||
dir = rotate90(dir);
|
||||
}
|
||||
|
||||
if (count == 0) { // dead end
|
||||
return DIR2_INVALID;
|
||||
}
|
||||
|
||||
// We have at least one way to go.
|
||||
|
||||
if (count == 1) { // only one solution
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (directions[i] != DIR2_INVALID) {
|
||||
return directions[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// more than one choice, draw a random number.
|
||||
int i = getRandom16() & 3;
|
||||
while (directions[i] == DIR2_INVALID) {
|
||||
i = (i + 1) & 3;
|
||||
}
|
||||
return directions[i];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get neighbouring tile from the map.
|
||||
* @param pos Current position.
|
||||
* @param dir Direction of neighbouring tile, only horizontal and
|
||||
* vertical directions are supported.
|
||||
* @param defaultTile Tile to return if off-map.
|
||||
* @return The tile in the indicated direction. If tile is off-world or an
|
||||
* incorrect direction is given, \c DIRT is returned.
|
||||
*/
|
||||
MapTile Micropolis::getTileFromMap(const Position &pos,
|
||||
Direction2 dir, MapTile defaultTile)
|
||||
{
|
||||
switch (dir) {
|
||||
|
||||
case DIR2_NORTH:
|
||||
if (pos.posY > 0) {
|
||||
return map[pos.posX][pos.posY - 1] & LOMASK;
|
||||
}
|
||||
|
||||
return defaultTile;
|
||||
|
||||
case DIR2_EAST:
|
||||
if (pos.posX < WORLD_W - 1) {
|
||||
return map[pos.posX + 1][pos.posY] & LOMASK;
|
||||
}
|
||||
|
||||
return defaultTile;
|
||||
|
||||
case DIR2_SOUTH:
|
||||
if (pos.posY < WORLD_H - 1) {
|
||||
return map[pos.posX][pos.posY + 1] & LOMASK;
|
||||
}
|
||||
|
||||
return defaultTile;
|
||||
|
||||
case DIR2_WEST:
|
||||
if (pos.posX > 0) {
|
||||
return map[pos.posX - 1][pos.posY] & LOMASK;
|
||||
}
|
||||
|
||||
return defaultTile;
|
||||
|
||||
default:
|
||||
return defaultTile;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Has the journey arrived at its destination?
|
||||
* @param pos Current position.
|
||||
* @param destZone Zonetype to drive to.
|
||||
* @return Destination has been reached.
|
||||
*/
|
||||
bool Micropolis::driveDone(const Position &pos, ZoneType destZone)
|
||||
{
|
||||
// FIXME: Use macros to determine the zone type: residential, commercial or industrial.
|
||||
/* commercial, industrial, residential destinations */
|
||||
static const MapTile targetLow[3] = {COMBASE, LHTHR, LHTHR};
|
||||
static const MapTile targetHigh[3] = {NUCLEAR, PORT, COMBASE};
|
||||
|
||||
assert(ZT_NUM_DESTINATIONS == LENGTH_OF(targetLow));
|
||||
assert(ZT_NUM_DESTINATIONS == LENGTH_OF(targetHigh));
|
||||
|
||||
MapTile l = targetLow[destZone]; // Lowest acceptable tile value
|
||||
MapTile h = targetHigh[destZone]; // Highest acceptable tile value
|
||||
|
||||
if (pos.posY > 0) {
|
||||
MapTile z = map[pos.posX][pos.posY - 1] & LOMASK;
|
||||
if (z >= l && z <= h) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos.posX < (WORLD_W - 1)) {
|
||||
MapTile z = map[pos.posX + 1][pos.posY] & LOMASK;
|
||||
if (z >= l && z <= h) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos.posY < (WORLD_H - 1)) {
|
||||
MapTile z = map[pos.posX][pos.posY + 1] & LOMASK;
|
||||
if (z >= l && z <= h) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos.posX > 0) {
|
||||
MapTile z = map[pos.posX - 1][pos.posY] & LOMASK;
|
||||
if (z >= l && z <= h) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Can the given tile be used as road?
|
||||
* @param mv Value from the map.
|
||||
* @return Indication that you can drive on the given tile
|
||||
*/
|
||||
bool Micropolis::roadTest(MapValue mv)
|
||||
{
|
||||
MapTile tile = mv & LOMASK;
|
||||
|
||||
if (tile < ROADBASE || tile > LASTRAIL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tile >= POWERBASE && tile < LASTPOWER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
281
core/update.cpp
Normal file
281
core/update.cpp
Normal file
|
@ -0,0 +1,281 @@
|
|||
/* update.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file update.cpp
|
||||
* @brief Handles updates and refreshes in various aspects of
|
||||
* Micropolis.
|
||||
*
|
||||
* This file contains functions to update and refresh game elements
|
||||
* such as maps, graphs, evaluation metrics, financial status, and
|
||||
* other user interface components. It ensures that the game state is
|
||||
* accurately reflected in the user interface, including changes in
|
||||
* city time, budget, and city demand. The file plays a crucial role
|
||||
* in syncing the game's backend calculations with frontend displays
|
||||
* and interactions.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
#include "text.h"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void Micropolis::doUpdateHeads()
|
||||
{
|
||||
showValves();
|
||||
doTimeStuff();
|
||||
reallyUpdateFunds();
|
||||
updateOptions();
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::updateMaps()
|
||||
{
|
||||
invalidateMaps();
|
||||
doUpdateHeads();
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::updateGraphs()
|
||||
{
|
||||
changeCensus();
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::updateEvaluation()
|
||||
{
|
||||
changeEval();
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::updateHeads()
|
||||
{
|
||||
mustUpdateFunds = true;
|
||||
valveFlag = true;
|
||||
cityTimeLast = cityYearLast = cityMonthLast = totalFundsLast =
|
||||
resLast = comLast = indLast = -999999;
|
||||
doUpdateHeads();
|
||||
}
|
||||
|
||||
|
||||
/** Set a flag that the funds display is out of date. */
|
||||
void Micropolis::updateFunds()
|
||||
{
|
||||
mustUpdateFunds = true;
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::reallyUpdateFunds()
|
||||
{
|
||||
if (!mustUpdateFunds) {
|
||||
return;
|
||||
}
|
||||
|
||||
mustUpdateFunds = false;
|
||||
|
||||
if (totalFunds != totalFundsLast) {
|
||||
totalFundsLast = totalFunds;
|
||||
|
||||
callback->updateFunds(this, callbackVal, totalFunds);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::doTimeStuff()
|
||||
{
|
||||
updateDate();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @bug Message is wrong.
|
||||
*/
|
||||
void Micropolis::updateDate()
|
||||
{
|
||||
int megalinium = 1000000;
|
||||
|
||||
cityTimeLast = cityTime >> 2;
|
||||
|
||||
cityYear = ((int)cityTime / 48) + (int)startingYear;
|
||||
cityMonth = ((int)cityTime % 48) >> 2;
|
||||
|
||||
if (cityYear >= megalinium) {
|
||||
setYear(startingYear);
|
||||
cityYear = startingYear;
|
||||
sendMessage(MESSAGE_NOT_ENOUGH_POWER, NOWHERE, NOWHERE, true);
|
||||
|
||||
}
|
||||
|
||||
if ((cityYearLast != cityYear) ||
|
||||
(cityMonthLast != cityMonth)) {
|
||||
|
||||
cityYearLast = cityYear;
|
||||
cityMonthLast = cityMonth;
|
||||
|
||||
callback->updateDate(this, callbackVal, cityYear, cityMonth);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::showValves()
|
||||
{
|
||||
if (valveFlag) {
|
||||
drawValve();
|
||||
valveFlag = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::drawValve()
|
||||
{
|
||||
float r, c, i;
|
||||
|
||||
r = resValve;
|
||||
|
||||
if (r < -1500) {
|
||||
r = -1500;
|
||||
}
|
||||
|
||||
if (r > 1500) {
|
||||
r = 1500;
|
||||
}
|
||||
|
||||
c = comValve;
|
||||
|
||||
if (c < -1500) {
|
||||
c = -1500;
|
||||
}
|
||||
|
||||
if (c > 1500) {
|
||||
c = 1500;
|
||||
}
|
||||
|
||||
i = indValve;
|
||||
|
||||
if (i < -1500) {
|
||||
i = -1500;
|
||||
}
|
||||
|
||||
if (i > 1500) {
|
||||
i = 1500;
|
||||
}
|
||||
|
||||
if ((r != resLast) ||
|
||||
(c != comLast) ||
|
||||
(i != indLast)) {
|
||||
|
||||
resLast = (int)r;
|
||||
comLast = (int)c;
|
||||
indLast = (int)i;
|
||||
|
||||
setDemand(r, c, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::setDemand(float r, float c, float i)
|
||||
{
|
||||
callback->updateDemand(this, callbackVal, r, c, i);
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::updateOptions()
|
||||
{
|
||||
if (mustUpdateOptions) {
|
||||
mustUpdateOptions = false;
|
||||
callback->updateOptions(this, callbackVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** @todo Keeping track of pending updates should be moved to the interface
|
||||
* (the simulator generates events, the interface forwards them to
|
||||
* the GUI when possible/allowed.
|
||||
*/
|
||||
void Micropolis::updateUserInterface()
|
||||
{
|
||||
/// @todo Send all pending update messages to the user interface.
|
||||
|
||||
// city: after load file, load scenario, or generate city
|
||||
// map: when small overall map changes
|
||||
// editor: when large close-up map changes
|
||||
// graph: when graph changes
|
||||
// evaluation: when evaluation changes
|
||||
// budget: when budget changes
|
||||
// date: when date changes
|
||||
// funds: when funds change
|
||||
// demand: when demand changes
|
||||
// level: when level changes
|
||||
// speed: when speed changes
|
||||
// delay: when delay changes
|
||||
// option: when options change
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
435
core/utilities.cpp
Normal file
435
core/utilities.cpp
Normal file
|
@ -0,0 +1,435 @@
|
|||
/* utilities.cpp
|
||||
*
|
||||
* Micropolis, Unix Version. This game was released for the Unix platform
|
||||
* in or about 1990 and has been modified for inclusion in the One Laptop
|
||||
* Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
|
||||
* you need assistance with this program, you may contact:
|
||||
* http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details. You should have received a
|
||||
* copy of the GNU General Public License along with this program. If
|
||||
* not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ADDITIONAL TERMS per GNU GPL Section 7
|
||||
*
|
||||
* No trademark or publicity rights are granted. This license does NOT
|
||||
* give you any right, title or interest in the trademark SimCity or any
|
||||
* other Electronic Arts trademark. You may not distribute any
|
||||
* modification of this program using the trademark SimCity or claim any
|
||||
* affliation or association with Electronic Arts Inc. or its employees.
|
||||
*
|
||||
* Any propagation or conveyance of this program must include this
|
||||
* copyright notice and these terms.
|
||||
*
|
||||
* If you convey this program (or any modifications of it) and assume
|
||||
* contractual liability for the program to recipients of it, you agree
|
||||
* to indemnify Electronic Arts for any liability that those contractual
|
||||
* assumptions impose on Electronic Arts.
|
||||
*
|
||||
* You may not misrepresent the origins of this program; modified
|
||||
* versions of the program must be marked as such and not identified as
|
||||
* the original program.
|
||||
*
|
||||
* This disclaimer supplements the one included in the General Public
|
||||
* License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
|
||||
* PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
|
||||
* OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
|
||||
* SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
|
||||
* DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
|
||||
* INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
|
||||
* RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
|
||||
* USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
|
||||
* INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
|
||||
* MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
|
||||
* UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
|
||||
* WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
|
||||
* CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
|
||||
* ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
|
||||
* JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
|
||||
* WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
|
||||
* CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
|
||||
* NOT APPLY TO YOU.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file utilities.cpp
|
||||
* @brief Utility functions for the Micropolis game engine.
|
||||
*
|
||||
* This file includes a collection of utility functions used
|
||||
* throughout the Micropolis game engine. These functions perform a
|
||||
* variety of tasks such as manipulating game speed, updating game
|
||||
* levels, handling city names, and managing game settings like
|
||||
* disasters, auto-bulldoze, and sound. It also includes functions for
|
||||
* updating the financial status and formatting numbers into currency
|
||||
* strings. The utilities support the main game engine by providing
|
||||
* essential services for game management and player interaction.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "micropolis.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/* comefrom: drawTaxesCollected incBoxValue decBoxValue drawCurrentFunds
|
||||
drawActualBox updateFunds updateCurrentCost */
|
||||
std::string Micropolis::makeDollarDecimalStr(const std::string &numStr)
|
||||
{
|
||||
short leftMostSet;
|
||||
short numOfDigits;
|
||||
short numOfChars;
|
||||
short numOfCommas;
|
||||
short dollarIndex = 0;
|
||||
short numIndex = 0;
|
||||
short x;
|
||||
|
||||
numOfDigits = numStr.length();
|
||||
|
||||
std::string dollarStr;
|
||||
|
||||
dollarStr += '$';
|
||||
if (numOfDigits == 1) {
|
||||
dollarStr += numStr[0];
|
||||
return dollarStr;
|
||||
} else if (numOfDigits == 2) {
|
||||
dollarStr += numStr[0];
|
||||
dollarStr += numStr[1];
|
||||
return dollarStr;
|
||||
} else if (numOfDigits == 3) {
|
||||
dollarStr += numStr[0];
|
||||
dollarStr += numStr[1];
|
||||
dollarStr += numStr[2];
|
||||
return dollarStr;
|
||||
} else {
|
||||
leftMostSet = numOfDigits % 3;
|
||||
|
||||
if (leftMostSet == 0) {
|
||||
leftMostSet = 3;
|
||||
}
|
||||
|
||||
numOfCommas = (numOfDigits - 1) / 3;
|
||||
|
||||
/* add 1 for the dollar sign */
|
||||
numOfChars = numOfDigits + numOfCommas + 1;
|
||||
|
||||
for (x = 1; x <= leftMostSet; x++) {
|
||||
dollarStr += numStr[numIndex++];
|
||||
}
|
||||
|
||||
for (x = 1; x <= numOfCommas; x++) {
|
||||
dollarStr += ',';
|
||||
dollarStr += numStr[numIndex++];
|
||||
dollarStr += numStr[numIndex++];
|
||||
dollarStr += numStr[numIndex++];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return dollarStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause a simulation
|
||||
* @see resume
|
||||
*/
|
||||
void Micropolis::pause()
|
||||
{
|
||||
if (!simPaused) {
|
||||
simPausedSpeed = simSpeedMeta;
|
||||
setSpeed(0);
|
||||
simPaused = true;
|
||||
}
|
||||
|
||||
// Call back even if the state did not change.
|
||||
callback->updatePaused(this, callbackVal, simPaused);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume simulation after pausing it
|
||||
* @see pause
|
||||
*/
|
||||
void Micropolis::resume()
|
||||
{
|
||||
if (simPaused) {
|
||||
simPaused = false;
|
||||
setSpeed(simPausedSpeed);
|
||||
}
|
||||
|
||||
// Call back even if the state did not change.
|
||||
callback->updatePaused(this, callbackVal, simPaused);
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::setSpeed(short speed)
|
||||
{
|
||||
if (speed < 0) {
|
||||
speed = 0;
|
||||
} else if (speed > 3) {
|
||||
speed = 3;
|
||||
}
|
||||
|
||||
simSpeedMeta = speed;
|
||||
|
||||
if (simPaused) {
|
||||
simPausedSpeed = simSpeedMeta;
|
||||
speed = 0;
|
||||
}
|
||||
|
||||
simSpeed = speed;
|
||||
|
||||
callback->updateSpeed(this, callbackVal, speed);
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::setPasses(int passes)
|
||||
{
|
||||
simPasses = passes;
|
||||
simPass = 0;
|
||||
callback->updatePasses(this, callbackVal, passes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the game level and initial funds.
|
||||
* @param level New game level.
|
||||
*/
|
||||
void Micropolis::setGameLevelFunds(GameLevel level)
|
||||
{
|
||||
switch (level) {
|
||||
|
||||
default:
|
||||
case LEVEL_EASY:
|
||||
setFunds(20000);
|
||||
setGameLevel(LEVEL_EASY);
|
||||
break;
|
||||
|
||||
case LEVEL_MEDIUM:
|
||||
setFunds(10000);
|
||||
setGameLevel(LEVEL_MEDIUM);
|
||||
break;
|
||||
|
||||
case LEVEL_HARD:
|
||||
setFunds(5000);
|
||||
setGameLevel(LEVEL_HARD);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Set/change the game level.
|
||||
* @param level New game level.
|
||||
*/
|
||||
void Micropolis::setGameLevel(GameLevel level)
|
||||
{
|
||||
assert(level >= LEVEL_FIRST && level <= LEVEL_LAST);
|
||||
gameLevel = level;
|
||||
updateGameLevel();
|
||||
}
|
||||
|
||||
|
||||
/** Report to the front-end that a new game level has been set. */
|
||||
void Micropolis::updateGameLevel()
|
||||
{
|
||||
callback->updateGameLevel(this, callbackVal, gameLevel);
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::setCityName(const std::string &name)
|
||||
{
|
||||
std::string cleanName;
|
||||
|
||||
int i;
|
||||
int n = name.length();
|
||||
for (i = 0; i < n; i++) {
|
||||
char ch = name[i];
|
||||
if (!isalnum(ch)) {
|
||||
ch = '_';
|
||||
}
|
||||
cleanName.push_back(ch);
|
||||
}
|
||||
|
||||
setCleanCityName(cleanName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the city.
|
||||
* @param name New name of the city.
|
||||
*/
|
||||
void Micropolis::setCleanCityName(const std::string &name)
|
||||
{
|
||||
cityName = name;
|
||||
|
||||
callback->updateCityName(this, callbackVal, cityName);
|
||||
}
|
||||
|
||||
|
||||
void Micropolis::setYear(int year)
|
||||
{
|
||||
// Must prevent year from going negative, since it screws up the non-floored modulo arithmetic.
|
||||
if (year < startingYear) {
|
||||
year = startingYear;
|
||||
}
|
||||
|
||||
year = (year - startingYear) - (cityTime / 48);
|
||||
cityTime += year * 48;
|
||||
doTimeStuff();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the current year.
|
||||
* @return The current game year.
|
||||
*/
|
||||
int Micropolis::currentYear()
|
||||
{
|
||||
return (cityTime / 48) + startingYear;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notify the user interface to start a new game.
|
||||
*/
|
||||
void Micropolis::doNewGame()
|
||||
{
|
||||
callback->newGame(this, callbackVal);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set the enableDisasters flag, and set the flag to
|
||||
* update the user interface.
|
||||
* @param value New setting for #enableDisasters
|
||||
*/
|
||||
void Micropolis::setEnableDisasters(bool value)
|
||||
{
|
||||
enableDisasters = value;
|
||||
mustUpdateOptions = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the auto-budget to the given value.
|
||||
* @param value New value for the auto-budget setting.
|
||||
*/
|
||||
void Micropolis::setAutoBudget(bool value)
|
||||
{
|
||||
autoBudget = value;
|
||||
mustUpdateOptions = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the autoBulldoze flag to the given value,
|
||||
* and set the mustUpdateOptions flag to update
|
||||
* the user interface.
|
||||
*
|
||||
* @param value The value to set autoBulldoze to.
|
||||
*/
|
||||
void Micropolis::setAutoBulldoze(bool value)
|
||||
{
|
||||
autoBulldoze = value;
|
||||
mustUpdateOptions = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the autoGoto flag to the given value,
|
||||
* and set the mustUpdateOptions flag to update
|
||||
* the user interface.
|
||||
*
|
||||
* @param value The value to set autoGoto to.
|
||||
*/
|
||||
void Micropolis::setAutoGoto(bool value)
|
||||
{
|
||||
autoGoto = value;
|
||||
mustUpdateOptions = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the enableSound flag to the given value,
|
||||
* and set the mustUpdateOptions flag to update
|
||||
* the user interface.
|
||||
*
|
||||
* @param value The value to set enableSound to.
|
||||
*/
|
||||
void Micropolis::setEnableSound(bool value)
|
||||
{
|
||||
enableSound = value;
|
||||
mustUpdateOptions = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the doAnimation flag to the given value,
|
||||
* and set the mustUpdateOptions flag to update
|
||||
* the user interface.
|
||||
*
|
||||
* @param value The value to set doAnimation to.
|
||||
*/
|
||||
void Micropolis::setDoAnimation(bool value)
|
||||
{
|
||||
doAnimation = value;
|
||||
mustUpdateOptions = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the doMessages flag to the given value,
|
||||
* and set the mustUpdateOptions flag to update
|
||||
* the user interface.
|
||||
*
|
||||
* @param value The value to set doMessages to.
|
||||
*/
|
||||
void Micropolis::setDoMessages(bool value)
|
||||
{
|
||||
doMessages = value;
|
||||
mustUpdateOptions = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the doNotices flag to the given value,
|
||||
* and set the mustUpdateOptions flag to update
|
||||
* the user interface.
|
||||
*
|
||||
* @param value The value to set doNotices to.
|
||||
*/
|
||||
void Micropolis::setDoNotices(bool value)
|
||||
{
|
||||
doNotices = value;
|
||||
mustUpdateOptions = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the residential, commercial and industrial
|
||||
* development demands, as floating point numbers
|
||||
* from -1 (lowest demand) to 1 (highest demand).
|
||||
*/
|
||||
void Micropolis::getDemands(
|
||||
float *resDemandResult,
|
||||
float *comDemandResult,
|
||||
float *indDemandResult)
|
||||
{
|
||||
*resDemandResult = (float)resValve / (float)RES_VALVE_RANGE;
|
||||
*comDemandResult = (float)comValve / (float)COM_VALVE_RANGE;
|
||||
*indDemandResult = (float)indValve / (float)IND_VALVE_RANGE;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
1037
core/zone.cpp
Normal file
1037
core/zone.cpp
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue