예제 #1
0
 def serialize_bonds(self):
     """
     Serializes the 50 bonds into bytes.
     Returns:
         50 x 4B ints representing all of the bonds.
     """
     data = bytearray()
     for bond in self.bonds:
         data += bytearray(serialize_int32(bond))
     return data
예제 #2
0
 def serialize_ordinances(self):
     """
     Convert the ordinance flags to their 4-byte integer representation.
     Returns:
         Byte representation of the ordinance flags.
     """
     # Bitshifting to convert the list of 0/1s to an int.
     bits = 0
     for bit in self.ordinance_flags:
         bits = (bits << 1) | bit
     return serialize_int32(bits)
예제 #3
0
 def serialize_budget(self):
     """
     Serializes the budget into bytes.
     Returns:
         Bytearray representing the budget for saving to a .sc2 file.
     """
     output = bytearray()
     for sub_budget in self.budget_items.values():
         for e in sub_budget.values():
             output += bytearray(serialize_int32(e))
     return output
예제 #4
0
def interleave_data(data):
    """
    Interleaves data for the Population and Industry Graphs.
    Each of the lists must be the same length.
    Args:
        data (list(list(int))): List of lists of the graph data.
    Returns:
        Bytearray containing the interleaved data.
    """
    # In hindsight, this is probably better served using zip().
    output = bytearray()
    for x in range(len(data[1])):
        for a in [serialize_int32(a[x]) for a in data]:
            output += bytearray(a)
    return output
예제 #5
0
def serialize_chunks(chunks):
    """
    Takes a dictionary of chunks and serializes the into a big bytearray.
    They should already be compressed (or not) as required.
    Args:
        chunks (dict): Key is the chunk name, like "ALTM" and the value being the bytes,
    Returns:
        bytearray of the bytes.
    """
    output_bytes = bytearray()
    for segment_name, segment_data in chunks.items():
        # There are duplicate TEXT entries, despite this not being allowed by the IFF spec.
        # So this needs to be handled specially when serializing the data.
        segment_header = bytes(segment_name, 'ascii') + serialize_int32(
            len(segment_data))
        output_bytes += bytearray(segment_header + segment_data)
    return output_bytes
예제 #6
0
def serialize_misc(city):
    """
    Serialized the MISC segment, 4800 bytes.
    Args:
        city (City): city file to save the MISC contents of.
    Returns:
        Byte representation of the MISC segment.
    """
    # This is the offset of the section that's being parsed from MISC.
    parse_order = {
        '0x0000': 'FirstEntry',
        '0x0004': 'GameMode',
        '0x0008': 'Compass',
        '0x000c': 'baseYear',
        '0x0010': 'simCycle',
        '0x0014': 'TotalFunds',
        '0x0018': 'TotalBonds',
        '0x001c': 'GameLevel',
        '0x0020': 'CityStatus',
        '0x0024': 'CityValue',
        '0x0028': 'LandValue',
        '0x002c': 'CrimeCount',
        '0x0030': 'TrafficCount',
        '0x0034': 'Pollution',
        '0x0038': 'CityFame',
        '0x003c': 'Advertising',
        '0x0040': 'Garbage',
        '0x0044': 'WorkerPercent',
        '0x0048': 'WorkerHealth',
        '0x004c': 'WorkerEducate',
        '0x0050': 'NationalPop',
        '0x0054': 'NationalValue',
        '0x0058': 'NationalTax',
        '0x005c': 'NationalTrend',
        '0x0060': 'heat',
        '0x0064': 'wind',
        '0x0068': 'humid',
        '0x006c': 'weatherTrend',
        '0x0070': 'NewDisaster',
        '0x0074': 'oldResPop',
        '0x0078': 'Rewards',
        '0x007c': 'Population Graphs',
        '0x016c': 'Industry Graphs',
        '0x01f0': 'Tile Counts',
        '0x05f0': 'ZonePop|0',
        '0x05f4': 'ZonePop|1',
        '0x05f8': 'ZonePop|2',
        '0x05fc': 'ZonePop|3',
        '0x0600': 'ZonePop|4',
        '0x0604': 'ZonePop|5',
        '0x0608': 'ZonePop|6',
        '0x060c': 'ZonePop|7',
        '0x0610': 'Bonds',
        '0x06d8': 'Neighbours',
        '0x0718': 'Valve?|0',
        '0x071c': 'Valve?|1',
        '0x0720': 'Valve?|2',
        '0x0724': 'Valve?|3',
        '0x0728': 'Valve?|4',
        '0x072c': 'Valve?|5',
        '0x0730': 'Valve?|6',
        '0x0734': 'Valve?|7',
        '0x0738': 'gas_power',
        '0x073c': 'nuclear_power',
        '0x0740': 'solar_power',
        '0x0744': 'wind_power',
        '0x0748': 'microwave_power',
        '0x074c': 'fusion_power',
        '0x0750': 'airport',
        '0x0754': 'highways',
        '0x0758': 'buses',
        '0x075c': 'subways',
        '0x0760': 'water_treatment',
        '0x0764': 'desalinisation',
        '0x0768': 'plymouth',
        '0x076c': 'forest',
        '0x0770': 'darco',
        '0x0774': 'launch',
        '0x0778': 'highway_2',
        '0x077c': 'Budget',
        '0x0e3c': 'YearEnd',
        '0x0e40': 'GlobalSeaLevel',
        '0x0e44': 'terCoast',
        '0x0e48': 'terRiver',
        '0x0e4c': 'Military',
        '0x0e50': 'Paper List',
        '0x0ec8': 'News List',
        '0x0fa0': 'Ordinances',
        '0x0fa4': 'unemployed',
        '0x0fa8': 'Military Count',
        '0x0fe8': 'SubwayCnt',
        '0x0fec': 'GameSpeed',
        '0x0ff0': 'AutoBudget',
        '0x0ff4': 'AutoGo',
        '0x0ff8': 'UserSoundOn',
        '0x0ffc': 'UserMusicOn',
        '0x1000': 'NoDisasters',
        '0x1004': 'PaperDeliver',
        '0x1008': 'PaperExtra',
        '0x100c': 'PaperChoice',
        '0x1010': 'unknown128',
        '0x1014': 'Zoom',
        '0x1018': 'CityCentX',
        '0x101c': 'CityCentY',
        '0x1020': 'GlobalArcoPop',
        '0x1024': 'ConnectTiles',
        '0x1028': 'TeamsActive',
        '0x102c': 'TotalPop',
        '0x1030': 'IndustryBonus',
        '0x1034': 'PolluteBonus',
        '0x1038': 'oldArrest',
        '0x103c': 'PoliceBonus',
        '0x1040': 'DisasterObject',
        '0x1044': 'CurrentDisaster',
        '0x1048': 'GoDisaster',
        '0x104c': 'SewerBonus',
        '0x1050': 'Extra',
    }
    handle_special = [
        'Population Graphs', 'Industry Graphs', 'Tile Counts', 'Bonds',
        'Neighbours', 'Budget', 'Military Count', 'Paper List', 'News List',
        'Extra', 'Ordinances'
    ]
    handle_special += list(city.simulator_settings.keys()) + list(
        city.game_settings.keys()) + list(city.inventions.keys())
    output_bytes = bytearray(b"\x00" * 4800)
    for k, v in parse_order.items():
        offset = int(k, 16)
        if v not in handle_special:
            data = serialize_uint32(city.city_attributes[v])
            output_bytes[offset:offset + 4] = data
        elif v == 'Population Graphs':
            graph_values = [[a for a in g]
                            for g in city.population_graphs.values()]
            data = interleave_data(graph_values)
            output_bytes[offset:offset + len(data)] = data
        elif v == 'Industry Graphs':
            graph_values = [[a for a in g]
                            for g in city.industry_graphs.values()]
            data = interleave_data(graph_values)
            output_bytes[offset:offset + len(data)] = data
        elif v == 'Tile Counts':
            for building_count in city.building_count.values():
                data = serialize_int32(building_count)
                output_bytes[offset:offset + 4] = data
                offset += 4
        elif v == 'Bonds':
            bonds_data = city.budget.serialize_bonds()
            output_bytes[offset:offset + len(bonds_data)] = bonds_data
        elif v == 'Ordinances':
            data = city.budget.serialize_ordinances()
            output_bytes[offset:offset + 4] = data
        elif v == 'Neighbours':
            for n in city.neighbor_info.values():
                for e in n.values():
                    data = serialize_int32(e)
                    output_bytes[offset:offset + 4] = data
                    offset += 4
        elif v == 'Budget':
            budget_data = city.budget.serialize_budget()
            output_bytes[offset:offset + len(budget_data)] = budget_data
        elif v == 'Military Count':
            num_items = 16
            for x in range(num_items):
                data = serialize_int32(
                    city.city_attributes[f"Military Count|{x}"])
                output_bytes[offset:offset + 4] = data
                offset += 4
        elif v == 'Paper List':
            num_items = 6 * 5
            for x in range(num_items):
                data = serialize_int32(city.city_attributes[f"Paper List|{x}"])
                output_bytes[offset:offset + 4] = data
                offset += 4
        elif v == 'News List':
            num_items = 9 * 6
            for x in range(num_items):
                data = serialize_int32(city.city_attributes[f"News List|{x}"])
                output_bytes[offset:offset + 4] = data
                offset += 4
        elif v == 'Extra':
            for x in range(156):
                data = serialize_int32(city.city_attributes[f"Extra|{x}"])
                output_bytes[offset:offset + 4] = data
                offset += 4
        elif v in list(city.simulator_settings.keys()):
            data = serialize_int32(city.simulator_settings[v])
            output_bytes[offset:offset + 4] = data
        elif v in list(city.game_settings.keys()):
            data = serialize_int32(city.game_settings[v])
            output_bytes[offset:offset + 4] = data
        elif v in list(city.inventions.keys()):
            data = serialize_int32(city.inventions[v])
            output_bytes[offset:offset + 4] = data
        else:
            # Fallthrough, this should never, ever, be hit.
            print("MISC is missing something!", k, v)
    return output_bytes