Unit SimUnit; { Reads a SimCity .CTY file, reports its various parameters, and allows one to change them } Interface Type Str64 = String[64]; Str40 = String[40]; Str2 = String[2]; {Holds the lower 10 bits of the map tile integer} MapTileIndex_Rec = Record ClearTerrain : word; Water : word; River : word; RiverEdge : word; TreeEdge : word; Trees : word; Parks : word; Rubble : word; Flood : word; Radiation : word; Fire : word; Road_NoTraf : word; Road_LtTraf : word; Road_HvTraf : word; Power : word; Transit : word; EmptyRes : word; Houses : word; ResLoVal1 : word; {1 = low density to highest density} ResLoVal2 : word; ResLoVal3 : word; ResLoVal4 : word; ResMidVal1 : word; ResMidVal2 : word; ResMidVal3 : word; ResMidVal4 : word; ResUpVal1 : word; ResUpVal2 : word; ResUpVal3 : word; ResUpVal4 : word; ResHiVal1 : word; ResHiVal2 : word; ResHiVal3 : word; ResHiVal4 : word; Hospital : word; Church : word; EmptyCom : word; ComLoVal1 : word; ComLoVal2 : word; ComLoVal3 : word; ComLoVal4 : word; ComLoVal5 : word; ComMidVal1 : word; ComMidVal2 : word; ComMidVal3 : word; ComMidVal4 : word; ComMidVal5 : word; ComUpVal1 : word; ComUpVal2 : word; ComUpVal3 : word; ComUpVal4 : word; ComUpVal5 : word; ComHiVal1 : word; ComHiVal2 : word; ComHiVal3 : word; ComHiVal4 : word; ComHiVal5 : word; IndEmpty : word; IndLoVal1 : word; IndLoVal2 : word; IndLoVal3 : word; IndLoVal4 : word; IndHiVal1 : word; IndHiVal2 : word; IndHiVal3 : word; IndHiVal4 : word; SeaPort : word; Airport : word; CoalPower : word; FireStation : word; PoliceStation: word; StadiumEmpty : word; StadiumFull : word; NuclearPower : word; OpenH_Bridge : word; RadarDish : word; Fountain : word; OpenV_Bridge : word; end; {Holds the upper 6 bits of the map tile integer} MapTileAttr_Rec = Record ZoneCenter : Boolean; Animated : Boolean; Bulldozable : Boolean; Burnable : Boolean; ConductPower : Boolean; Powered : Boolean; end; {Misc variables in the SimCity File} MiscVar_Rec = record filler : word; ExtMktSize : word; ResPop : word; ComPop : word; IndPop : word; ResVal : word; ComVal : word; IndVal : word; {7} CityTime : LongInt; {8&9} CrimeRamp : word; PolluteRamp : word; LandValAvg : word; CrimeAvg : word; PollutionAvg : word; GameLevel : word; CityClass : word; CityScore : word; {17} Filler1 : Array[1..32] of word; TotalFunds : LongInt; {50&51} AutoBull : word; AutoBudget : word; AutoGo : word; SoundEffects : word; TaxRate : word; SimSpeed : word; {57} PoliceBudget : LongInt; FireBudget : LongInt; RoadBudget : LongInt; {62&63} Filler2 : Array[1..56] of word; {120} end; Map_Rec = Array [1..120,1..100] of word; {the SimCity Map} Char64 = Array [1..64] of char; Char480 = Array [1..480] of char; {The Record that holds the complete SimCity File} SimCity_Rec = Record CityName : Char64; MacInfo : Char64; ResHis : Char480; ComHis : Char480; IndHis : Char480; CrimeHis : Char480; PolluteHis : Char480; CashFlowHis: Char480; MiscVar : MiscVar_Rec; Map : Map_Rec; end; Var SimCityFname : Str40; {SimCity File name} SimCityRecord : SimCity_Rec; {SimCity File Record} SimCityFile : File of SimCity_Rec; {SimCity File} MapRecord : MapTileIndex_Rec; {Map Tile INDEX records} MapAttrRecord : MapTileAttr_Rec; {Map Tile Attribute record} Procedure ReadSimCityFile; Procedure WriteSimCityFile; Procedure MapTileIndexValues; Implementation {****************************************************************************} Function SwapLong(L : LongInt) : LongInt; {Converts a 32 bit word from "Mototola" format to "Intel" format} { Tp-inline code from Pat Ritchey The first 2 pops accomplish the swap of the hi and low words and the XCHGs do the equivalent of the TP swap() function } inline( $5A/ { POP DX } $58/ { POP AX } $86/$E0/ { XCHG AH,AL } $86/$F2 { XCHG DH,DL } ); {****************************************************************************} Procedure SwapVariables; { after reading a SimCity file, the function will change all word/longint variables from "Mototola" format to "Intel" format or vise versa} var i, k : Byte; begin With SimCityRecord.MiscVar do begin filler := swap(filler); ExtMktSize := swap(ExtMktSize); ResPop := swap(ResPop); ComPop := swap(ComPop); IndPop := swap(IndPop); ResVal := swap(ResVal); ComVal := swap(ComVal); IndVal := swap(IndVal); CityTime := swaplong(CityTime); CrimeRamp := swap(CrimeRamp); PolluteRamp := swap(PolluteRamp); LandValAvg := swap(LandValAvg); CrimeAvg := swap(CrimeAvg); PollutionAvg := swap(PollutionAvg); GameLevel := swap(GameLevel); CityClass := swap(CityClass); CityScore := swap(CityScore); for i := 1 to 32 do Filler1[i] := swap(Filler1[i]); TotalFunds := swaplong(TotalFunds); AutoBull := swap(AutoBull); AutoBudget := swap(AutoBudget); AutoGo := swap(AutoGo); SoundEffects := swap(SoundEffects); TaxRate := swap(TaxRate); SimSpeed := swap(SimSpeed); PoliceBudget := swaplong(PoliceBudget); FireBudget := swaplong(FireBudget); RoadBudget := swaplong(RoadBudget); for i := 1 to 56 do Filler2[i] := swap(Filler2[i]); end; With SimCityRecord do for i := 1 to 120 do for k := 1 to 100 do Map[i,k] := swap(Map[i,k]); end; {****************************************************************************} Procedure ReadSimCityFile; { Reads a SimCity file into SimCityRecord and swaps all word/longint into intel format. CAUTION: This procedure ASSUMEs a VALID filename! } begin Assign(SimCityFile, SimCityFname); Reset(SimCityFile); Read(SimCityFile, SimCityRecord); Close(SimCityFile); SwapVariables; end; {****************************************************************************} Procedure WriteSimCityFile; { Swaps all word/longint variable from Intel to Mototola format and writes a SimCity file back to disk } begin SwapVariables; Assign(SimCityFile, SimCityFname); Rewrite(SimCityFile); Write(SimCityFile, SimCityRecord); Close(SimCityFile); end; {****************************************************************************} Function MapTileIndex(W : Word) : Word; { Retrieves the tile index number from a map tile. This number is the lower 10 bits of the integer. The upper 6 bits are tile attribute flags and can be read by MapTileAttr(). The Procedure MapTileIndexValues() is used to read the index value of each map square } begin MapTileIndex := W and $03FF; end; {****************************************************************************} Function MapTileAttr(W : Word; FlagNo : Byte) : Boolean; { FlagNo ranges from 0 to 5. These are the upper 6 bits of the map tile integer. This function could be writen much more efficient by passing the entire MapAttrRecord variable and changing it in one pass. However, this function is written this way to allow any manipulation you may want. In general these attributes are NOT very useful, so this function is NOT activated in this unit. } begin MapTileAttr := False; Case FlagNo of 1 : if (W AND $0400 > 0) then MapTileAttr := True; {zoned} 2 : if (W AND $0800 > 0) then MapTileAttr := True; {animated} 3 : if (W AND $1000 > 0) then MapTileAttr := True; {bulldozable} 4 : if (W AND $2000 > 0) then MapTileAttr := True; {burnable} 5 : if (W AND $4000 > 0) then MapTileAttr := True; {conductPower} 6 : if (W AND $8000 > 0) then MapTileAttr := True; {powered} end; end; {****************************************************************************} Procedure MapTileIndexValues; { Retrieves the INDEX value for each map tile (square) } var i, k : Byte; Index: word; begin FillChar(MapRecord, SizeOf(MapRecord), 0); With SimCityRecord do for i := 1 to 120 do for k := 1 to 100 do begin index := MapTileIndex(Map[i,k]); With MapRecord do Case Index of 0 : inc(ClearTerrain); 2 : inc(Water); 4 : inc(River); 5..20 : inc(RiverEdge); 21..36 : inc(TreeEdge); 37 : inc(Trees); 40..43 : inc(Parks); 44..47 : inc(Rubble); 48..51 : inc(Flood); 52 : inc(Radiation); 56..63 : inc(Fire); 64..78 : inc(Road_NoTraf); 80..142 : inc(Road_LtTraf); 144..206 : inc(Road_HvTraf); 208..222 : inc(Power); 224..238 : inc(Transit); 244 : inc(EmptyRes); 249..260 : inc(Houses); 265 : inc(ResLoVal1); 274 : inc(ResLoVal2); 283 : inc(ResLoVal3); 292 : inc(ResLoVal4); 301 : inc(ResMidVal1); 310 : inc(ResMidVal2); 319 : inc(ResMidVal3); 328 : inc(ResMidVal4); 337 : inc(ResUpVal1); 346 : inc(ResUpVal2); 355 : inc(ResUpVal3); 364 : inc(ResUpVal4); 373 : inc(ResHiVal1); 382 : inc(ResHiVal2); 391 : inc(ResHiVal3); 400 : inc(ResHiVal4); 409 : inc(Hospital); 418 : inc(Church); 427 : inc(EmptyCom); 436 : inc(ComLoVal1); 445 : inc(ComLoVal2); 454 : inc(ComLoVal3); 463 : inc(ComLoVal4); 472 : inc(ComLoVal5); 481 : inc(ComMidVal1); 490 : inc(ComMidVal2); 499 : inc(ComMidVal3); 508 : inc(ComMidVal4); 517 : inc(ComMidVal5); 526 : inc(ComUpVal1); 535 : inc(ComUpVal2); 544 : inc(ComUpVal3); 553 : inc(ComUpVal4); 562 : inc(ComUpVal5); 571 : inc(ComHiVal1); 580 : inc(ComHiVal2); 589 : inc(ComHiVal3); 598 : inc(ComHiVal4); 607 : inc(ComHiVal5); 616 : inc(IndEmpty); 625 : inc(IndLoVal1); 634 : inc(IndLoVal2); 643 : inc(IndLoVal3); 652 : inc(IndLoVal4); 661 : inc(IndHiVal1); 670 : inc(IndHiVal2); 679 : inc(IndHiVal3); 688 : inc(IndHiVal4); 698 : inc(SeaPort); 716 : inc(Airport); 750 : inc(CoalPower); 765 : inc(FireStation); 774 : inc(PoliceStation); 784 : inc(StadiumEmpty); 800 : inc(StadiumFull); 816 : inc(NuclearPower); 828..831 : inc(OpenH_Bridge); 832..839 : inc(RadarDish); 840..843 : inc(Fountain); 948..951 : inc(OpenV_Bridge); end; {case} end; {for k} end; {****************************************************************************} end.