Ejemplo n.º 1
0
def cargo_list(value, max_num_cargos):
    """
    Encode an array of cargo types in a single property value. If less than the maximum
    number of cargos are given the rest is filled up with 0xFF (=invalid cargo).

    @param value: Array of cargo types.
    @type  value: C{Array}

    @param max_num_cargos: The maximum number of cargos in the array.
    @type  max_num_cargos: C{int}

    @param prop_num: Property number.
    @type  prop_num: C{int}

    @param prop_size: Property size in bytes.
    @type  prop_size: C{int}
    """
    if not isinstance(value, Array) or len(value.values) > max_num_cargos:
        raise generic.ScriptError("Cargo list must be an array with no more than {:d} values".format(max_num_cargos), value.pos)
    cargoes = value.values + [ConstantNumeric(0xFF, value.pos) for _ in range(max_num_cargos - len(value.values))]

    ret = None
    for i, cargo in enumerate(cargoes):
        byte = BinOp(nmlop.AND, cargo, ConstantNumeric(0xFF, cargo.pos), cargo.pos)
        if i == 0:
            ret = byte
        else:
            byte = BinOp(nmlop.SHIFT_LEFT, byte, ConstantNumeric(i * 8, cargo.pos), cargo.pos)
            ret = BinOp(nmlop.OR, ret, byte, cargo.pos)
    return ret.reduce()
Ejemplo n.º 2
0
def mt_house_prop09(value, num_ids, size_bit):
    # Only bit 5 should be set for additional tiles
    # Additionally, correctly set the size bit (0, 2, 3 or 4) for the first tile
    if isinstance(value, ConstantNumeric) and (value.value & 0x1D) != 0:
        raise generic.ScriptError("Invalid bits set in house property 'building_flags'.", value.pos)
    ret = [BinOp(nmlop.OR, value, ConstantNumeric(1 << size_bit, value.pos), value.pos).reduce()]
    for _i in range(1, num_ids):
        ret.append(BinOp(nmlop.AND, value, ConstantNumeric(1 << 5, value.pos), value.pos).reduce())
    return ret
Ejemplo n.º 3
0
def roadveh_speed_prop(prop_info):
    # prop 08 value is min(value, 255)
    prop08_value = lambda value: BinOp(nmlop.MIN, value, ConstantNumeric(0xFF, value.pos), value.pos).reduce()
    # prop 15 value is (value + 3) / 4
    prop15_value = lambda value: BinOp(nmlop.DIV, BinOp(nmlop.ADD, value, ConstantNumeric(3, value.pos), value.pos), ConstantNumeric(4, value.pos), value.pos).reduce()
    # prop 15 should not be set if value(prop08_value) <= 255. But as we test prop15 and prop15 = 0.25/prop08, test for 64:
    prop15_test = lambda value: isinstance(value, ConstantNumeric) and value.value >= 0x40
    prop08 = {'size': 1, 'num': 0x08, 'value_function': prop08_value}
    prop15 = {'size': 1, 'num': 0x15, 'value_function': prop15_value, 'test_function': prop15_test}
    for key in prop_info:
        prop08[key] = prop15[key] = prop_info[key]
    return [prop08, prop15]
Ejemplo n.º 4
0
def house_random_colours(value):
    # User sets array with 4 values (range 0..15)
    # Output is a dword, each byte being a value from the array
    if not isinstance(value, Array) or len(value.values) != 4:
        raise generic.ScriptError("Random colours must be an array with exactly four values", value.pos)

    ret = None
    for i, colour in enumerate(value.values):
        if isinstance(colour, ConstantNumeric):
            generic.check_range(colour.value, 0, 15, "Random house colours", colour.pos)
        byte = BinOp(nmlop.AND, colour, ConstantNumeric(0xFF, colour.pos), colour.pos)
        if i == 0:
            ret = byte
        else:
            byte = BinOp(nmlop.SHIFT_LEFT, byte, ConstantNumeric(i * 8, colour.pos), colour.pos)
            ret = BinOp(nmlop.OR, ret, byte, colour.pos)
    return ret.reduce()
Ejemplo n.º 5
0
def mt_house_old_id(value, num_ids, size_bit):
    # For substitute / override properties
    # Set value for tile i (0 .. 3) to (value + i)
    # Also validate that the size of the old house matches
    if isinstance(value, ConstantNumeric) and not value.value in old_houses[size_bit]:
        raise generic.ScriptError("Substitute / override house type must have the same size as the newly defined house.", value.pos)
    ret = [value]
    for i in range(1, num_ids):
        ret.append(BinOp(nmlop.ADD, value, ConstantNumeric(i, value.pos), value.pos).reduce())
    return ret
Ejemplo n.º 6
0
def house_available_mask(value):
    # User sets [town_zones, climates] array
    # Which is mapped to (town_zones | (climates & 0x800) | ((climates & 0xF) << 12))
    if not isinstance(value, Array) or len(value.values) != 2:
        raise generic.ScriptError("availability_mask must be an array with exactly 2 values", value.pos)

    climates = BinOp(nmlop.AND, value.values[1], ConstantNumeric(0xF, value.pos), value.pos)
    climates = BinOp(nmlop.SHIFT_LEFT, climates, ConstantNumeric(12, value.pos), value.pos)
    above_snow = BinOp(nmlop.AND, value.values[1], ConstantNumeric(0x800, value.pos), value.pos)

    ret = BinOp(nmlop.OR, climates, value.values[0], value.pos)
    ret = BinOp(nmlop.OR, ret, above_snow, value.pos)
    return ret.reduce()
Ejemplo n.º 7
0
def house_accepted_cargo_types(value):
    if not isinstance(value, Array) or len(value.values) > 3:
        raise generic.ScriptError("accepted_cargos must be an array with no more than 3 values", value.pos)

    cargoes = []
    for i in range(3):
        if i < len(value.values):
            cargo_amount_pair = value.values[i]
            if not isinstance(cargo_amount_pair, Array) or len(cargo_amount_pair.values) != 2:
                raise generic.ScriptError("Each element of accepted_cargos must be an array with two elements: cargoid and amount", cargo_amount_pair.pos)
            cargoes.append(cargo_amount_pair.values[0])
        else:
            cargoes.append(ConstantNumeric(0xFF, value.pos))

    ret = None
    for i, cargo in enumerate(cargoes):
        byte = BinOp(nmlop.AND, cargo, ConstantNumeric(0xFF, cargo.pos), cargo.pos)
        if i == 0:
            ret = byte
        else:
            byte = BinOp(nmlop.SHIFT_LEFT, byte, ConstantNumeric(i * 8, cargo.pos), cargo.pos)
            ret = BinOp(nmlop.OR, ret, byte, cargo.pos)
    return ret.reduce()
Ejemplo n.º 8
0
def house_prop_0A(value):
    # User sets an array [min_year, max_year] as property value
    # House property 0A is set to ((max_year - 1920) << 8) | (min_year - 1920)
    # With both bytes clamped to the 0 .. 255 range
    if not isinstance(value, Array) or len(value.values) != 2:
        raise generic.ScriptError("Availability years must be an array with exactly two values", value.pos)

    min_year = BinOp(nmlop.SUB, value.values[0], ConstantNumeric(1920, value.pos), value.pos)
    min_year = BinOp(nmlop.MAX, min_year, ConstantNumeric(0, value.pos), value.pos)
    min_year = BinOp(nmlop.MIN, min_year, ConstantNumeric(255, value.pos), value.pos)

    max_year = BinOp(nmlop.SUB, value.values[1], ConstantNumeric(1920, value.pos), value.pos)
    max_year = BinOp(nmlop.MAX, max_year, ConstantNumeric(0, value.pos), value.pos)
    max_year = BinOp(nmlop.MIN, max_year, ConstantNumeric(255, value.pos), value.pos)
    max_year = BinOp(nmlop.SHIFT_LEFT, max_year, ConstantNumeric(8, value.pos), value.pos)

    return BinOp(nmlop.OR, max_year, min_year, value.pos).reduce()
Ejemplo n.º 9
0
def two_byte_property(low_prop, high_prop, low_prop_info = {}, high_prop_info = {}):
    """
    Decode a two byte value into two action 0 properties.

    @param low_prop: Property number for the low 8 bits of the value.
    @type  low_prop: C{int}

    @param high_prop: Property number for the high 8 bits of the value.
    @type  high_prop: C{int}

    @param low_prop_info: Dictionary with additional property information for the low byte.
    @type low_prop_info: C{dict}

    @param high_prop_info: Dictionary with additional property information for the low byte.
    @type high_prop_info: C{dict}

    @return: Sequence of two dictionaries with property information (low part, high part).
    @rtype:  C{list} of C{dict}
    """
    low_byte_info = {'num': low_prop, 'size': 1, 'value_function': lambda value: BinOp(nmlop.AND, value, ConstantNumeric(0xFF, value.pos), value.pos).reduce()}
    high_byte_info = {'num': high_prop, 'size': 1, 'value_function': lambda value: BinOp(nmlop.SHIFT_RIGHT, value, ConstantNumeric(8, value.pos), value.pos).reduce()}
    low_byte_info.update(low_prop_info)
    high_byte_info.update(high_prop_info)
    return [low_byte_info, high_byte_info]
Ejemplo n.º 10
0
def mt_house_mask(mask, value, num_ids, size_bit):
    # Mask out the bits not present in the 'mask' parameter for additional tiles
    ret = [value]
    for _i in range(1, num_ids):
        ret.append(BinOp(nmlop.AND, value, ConstantNumeric(mask, value.pos), value.pos).reduce())
    return ret
Ejemplo n.º 11
0
def aircraft_is_large(value):
    return BinOp(nmlop.AND, value, ConstantNumeric(1, value.pos), value.pos).reduce()
Ejemplo n.º 12
0
def aircraft_is_heli(value):
    if isinstance(value, ConstantNumeric) and not value.value in (0, 2, 3):
        raise generic.ScriptError("Invalid value for aircraft_type", value.pos)
    return BinOp(nmlop.AND, value, ConstantNumeric(2, value.pos), value.pos).reduce()
Ejemplo n.º 13
0
def speed_fraction(value):
    # Unit is already converted to 0 .. 255 range when we get here
    if isinstance(value, ConstantNumeric) and not (0 <= value.value <= 255):
        # Do not use check_range to provide better error message
        raise generic.ScriptError("speed fraction must be in range 0 .. 1", value.pos)
    return BinOp(nmlop.SUB, ConstantNumeric(255, value.pos), value, value.pos).reduce()
Ejemplo n.º 14
0
def vehicle_length(value):
    if isinstance(value, ConstantNumeric):
        generic.check_range(value.value, 1, 8, "vehicle length", value.pos)
    return BinOp(nmlop.SUB, ConstantNumeric(8, value.pos), value, value.pos).reduce()