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 industry_input_multiplier(value, prop_num):
    if not isinstance(value, Array) or len(value.values) > 2:
        raise generic.ScriptError("Input multiplier must be an array of up to two values", value.pos)
    val1 = value.values[0].reduce() if len(value.values) > 0 else ConstantNumeric(0)
    val2 = value.values[1].reduce() if len(value.values) > 1 else ConstantNumeric(0)
    if not isinstance(val1, (ConstantNumeric, ConstantFloat)) or not isinstance(val2, (ConstantNumeric, ConstantFloat)):
        raise generic.ScriptError("Expected a compile-time constant", value.pos)
    generic.check_range(val1.value, 0, 256, "input_multiplier", val1.pos)
    generic.check_range(val2.value, 0, 256, "input_multiplier", val2.pos)
    mul1 = int(val1.value * 256)
    mul2 = int(val2.value * 256)
    return [Action0Property(prop_num, ConstantNumeric(mul1 | (mul2 << 16)), 4)]
Ejemplo n.º 5
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.º 6
0
def animation_info(value, loop_bit=8, max_frame=253):
    """
    Convert animation info array of two elements to an animation info property.
    The first is 0/1, and defines whether or not the animation loops. The second is the number of frames, at most 253 frames.

    @param value: Array of animation info.
    @type  value: C{Array}

    @param loop_bit: Bit the loop information is stored.
    @type  loop_bit: C{int}

    @param max_frame: Max frames possible.
    @type  max_frame: C{int}

    @return: Value to use for animation property.
    @rtype:  L{Expression}
    """
    if not isinstance(value, Array) or len(value.values) != 2:
        raise generic.ScriptError("animation_info must be an array with exactly 2 constant values", value.pos)
    looping = value.values[0].reduce_constant().value
    frames  = value.values[1].reduce_constant().value
    if looping not in (0, 1):
        raise generic.ScriptError("First field of the animation_info array must be either 0 or 1", value.values[0].pos)
    if frames < 1 or frames > max_frame:
        raise generic.ScriptError("Second field of the animation_info array must be between 1 and " + str(max_frame), value.values[1].pos)

    return ConstantNumeric((looping << loop_bit) + frames - 1)
Ejemplo n.º 7
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.º 8
0
def object_size(value):
    if not isinstance(value, Array) or len(value.values) != 2:
        raise generic.ScriptError("Object size must be an array with exactly two values", value.pos)
    sizex = value.values[0].reduce_constant()
    sizey = value.values[1].reduce_constant()
    if sizex.value < 1 or sizex.value > 15 or sizey.value < 1 or sizey.value > 15:
        raise generic.ScriptError("The size of an object must be at least 1x1 and at most 15x15 tiles", value.pos)
    return [Action0Property(0x0C, ConstantNumeric(sizey.value << 4 | sizex.value), 1)]
Ejemplo n.º 9
0
def industrytile_cargos(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)
    prop_num = 0x0A
    props = []
    for cargo_amount_pair in value.values:
        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)
        cargo_id = cargo_amount_pair.values[0].reduce_constant().value
        cargo_amount = cargo_amount_pair.values[1].reduce_constant().value
        props.append(Action0Property(prop_num, ConstantNumeric((cargo_amount << 8) | cargo_id), 2))
        prop_num += 1

    while prop_num <= 0x0C:
        props.append(Action0Property(prop_num, ConstantNumeric(0), 2))
        prop_num += 1
    return props
Ejemplo n.º 10
0
def industry_prod_multiplier(value):
    if not isinstance(value, Array) or len(value.values) > 2:
        raise generic.ScriptError("Prod multiplier must be an array of up to two values", value.pos)
    props = []
    for i in range(0, 2):
        val = value.values[i].reduce_constant() if i < len(value.values) else ConstantNumeric(0)
        props.append(Action0Property(0x12 + i, val, 1))
    return props
Ejemplo n.º 11
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.º 12
0
def house_acceptance(value, index):
    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)

    if index < len(value.values):
        cargo_amount_pair = value.values[index]
        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)
        return cargo_amount_pair.values[1]
    else:
        return ConstantNumeric(0, value.pos)
Ejemplo n.º 13
0
def industry_conflicting_types(value):
    if not isinstance(value, Array):
        raise generic.ScriptError("conflicting_ind_types must be an array of industry types", value.pos)
    if len(value.values) > 3:
        raise generic.ScriptError("conflicting_ind_types may have at most three entries", value.pos)

    types_list = []
    for val in value.values:
        types_list.append(val.reduce_constant())
    while len(types_list) < 3:
        types_list.append(ConstantNumeric(0xFF))
    return [ConflictingTypesProp(types_list)]
Ejemplo n.º 14
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.º 15
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.º 16
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()
Ejemplo n.º 17
0
def mt_house_class(value, num_ids, size_bit):
    # Set class to 0xFF for additional tiles
    return [value] + (num_ids - 1) * [ConstantNumeric(0xFF, value.pos)]
Ejemplo n.º 18
0
def mt_house_zero(value, num_ids, size_bit):
    return [value] + (num_ids - 1) * [ConstantNumeric(0, value.pos)]
Ejemplo n.º 19
0
def zero_refit_mask(prop_num):
    # Zero the refit mask, in addition to setting some other refit property
    return {'size': 4, 'num': prop_num, 'value_function': lambda value: ConstantNumeric(0)}
Ejemplo n.º 20
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.º 21
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.º 22
0
def airport_years(value):
    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 = value.values[0].reduce_constant()
    max_year = value.values[1].reduce_constant()
    return [Action0Property(0x0C, ConstantNumeric(max_year.value << 16 | min_year.value), 4)]
Ejemplo n.º 23
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.º 24
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.º 25
0
def aircraft_is_large(value):
    return BinOp(nmlop.AND, value, ConstantNumeric(1, value.pos), value.pos).reduce()