diff --git a/examples/bridge/example_bridge.nml b/examples/bridge/example_bridge.nml new file mode 100644 index 000000000..b285748db --- /dev/null +++ b/examples/bridge/example_bridge.nml @@ -0,0 +1,177 @@ +/* + * This file is aimed to provide an example on how to code a custom bridge in NML. + * It creates a cable bridge with support for multiple transport types (rail, road, + * monorail, maglev). The same set of cable sprites is reused across all transport + * types; the game overlays the correct track or road surface at runtime. + * + * To keep the code readable, not every property is documented in detail. + * Refer to the bridge-specific reference in the documentation for the full list + * of available properties and callbacks. + * + * Apart from this file, you will also need the following: + * - Graphics, in gfx/cable.png + * - Language files, to be placed in the 'lang' folder. + * Currently english.lng is supplied. + * + * Graphics are from JP+ Bridges by Emperor Jake. + */ + +/* + * First, define a grf block. This defines some basic properties of the grf, + * which are required for the grf to be valid and loadable. + */ +grf { + /* This grf is part of NML, therefore "NML" is chosen as the first three + * characters of the GRFID. It is the eighth example grf defined as part of + * NML, therefore the last character is set to 7 as numbering is zero-based. + */ + grfid: "NML\07"; + /* GRF name and description strings are defined in the lang files */ + name: string(STR_GRF_NAME); + desc: string(STR_GRF_DESC); + /* This is the first version, start numbering at 1. */ + version: 1; + min_compatible_version: 1; +} + +/* Next: a series of templates for the bridge graphics. + * Templates allow you to avoid repeating sprite coordinates for each spriteset. + * Parameter t selects the column within the sprite sheet (0 = leftmost column, + * 1 = next, and so on), so different bridge part slots can share the same layout. + * + * Each template produces two sprites: one for each track orientation (X-axis and Y-axis). + * + * A bridge span is divided into four visual layers: + * head - the ramp pieces where vehicles enter and leave the bridge + * back - the structural section drawn behind vehicles + * front - the structural section drawn in front of vehicles + * pillar - the support columns underneath the span + */ +template template_head(t) { + [1 + t*130, 1, 64, 64, -31, -24] + [66 + t*130, 1, 64, 64, -31, -24] +} + +template template_back(t) { + /* ANIM marks these sprites as safe for animated palettes */ + [1 + t*130, 66, 64, 128, -31, -84, ANIM] + [66 + t*130, 66, 64, 128, -31, -84, ANIM] +} + +template template_front(t) { + [1 + t*130, 195, 64, 128, -55, -96, ANIM] + [66 + t*130, 195, 64, 128, -7, -96, ANIM] +} + +template template_pillar(t) { + [1 + t*130, 324, 64, 128, -55, -96] + [66 + t*130, 324, 64, 128, -7, -96] +} + +/* The back, front and pillar spritesets each contain six part slots (0-5), which + * the game assembles in different combinations depending on bridge length: + * + * _0_ Bridge of length 3 + * _0(23)1_ Bridge of even length + * _0(23)4(23)1_ Bridge of lengths 5, 9, 13, 17 etc. + * _0(23)253(23)1_ Bridge of lengths 7, 11, 15, 19 etc. + * + * Here _ represents the head/ramp (a separate spriteset), and the numbers 0-5 are + * the span slots drawn in sequence. Slots 2 and 3 repeat as needed to fill the span. + * Slots 4 and 5 are inserted once in the middle to handle longer odd-length bridges. + */ + +/* The head spriteset has eight sprites in total: a flat approach piece and a ramp piece + * for each bridge end (north and south), each in both track orientations (X-axis and Y-axis). + * Each template call produces the X-axis and Y-axis sprites for one piece. + */ +spriteset(cable_head, "gfx/cable.png") { + template_head(0) // north flat (X and Y) + template_head(1) // south flat (X and Y) + template_head(2) // north ramp (X and Y) + template_head(3) // south ramp (X and Y) +} + +/* The back and front spritesets have one pair of sprites per slot. + * Slots 1 and 4 reuse the same column as slot 0 since they share the same appearance. + */ +spriteset(cable_back, "gfx/cable.png") { + template_back(0) // slot 0 + template_back(0) // slot 1: same appearance as slot 0 + template_back(2) // slot 2 + template_back(3) // slot 3 + template_back(0) // slot 4: same appearance as slot 0 + template_back(5) // slot 5 +} + +spriteset(cable_front, "gfx/cable.png") { + template_front(0) // slot 0 + template_front(0) // slot 1: same appearance as slot 0 + template_front(2) // slot 2 + template_front(3) // slot 3 + template_front(0) // slot 4: same appearance as slot 0 + template_front(5) // slot 5 +} + +/* Empty sprite pairs [] [] mean no pillar is drawn for that slot. + * Pillars are only needed at slots 3 and 5, where longer spans need support. + */ +spriteset(cable_pillar, "gfx/cable.png") { + [] [] // slot 0: no pillar at the ramp + [] [] // slot 1: short spans need no pillar + [] [] // slot 2: no pillar here + template_pillar(3) // slot 3: pillar for longer spans + [] [] // slot 4: no pillar here + template_pillar(3) // slot 5: reuse the same pillar graphics +} + +/* + * Now define the bridge item itself. + * Unlike vehicles, bridges are identified by a fixed slot index rather than a + * named label. Valid IDs are 0x00 to 0x0D (0–13), each replacing the corresponding + * default OpenTTD bridge. It is not possible to add bridges beyond that range. + */ +item(FEAT_BRIDGES, wood_rail_bridge, 0x00) { + property { + min_length: 0; // allow spans of any length + max_length: 255; // effectively unlimited + cost_factor: 224; + speed_limit: 300 km/h; + flags: bitmask(FAR_PILLARS_DISABLE); // omit distant pillars for this style + avail_year: 1970; + name: string(STR_BRIDGE_NAME); + description_road: string(STR_BRIDGE_DESC_ROAD); + description_rail: string(STR_BRIDGE_DESC_RAIL); + + /* pillar_info declares where the bridge's pillars and walls are located for each + * span slot. There are six slots, each with one byte for the X orientation and one + * for Y, giving 12 values in total. Each byte is a bitmask of corners and edges, + * using BRIDGE_PILLAR_CORNER_{N,S,W,E} and BRIDGE_PILLAR_EDGE_{NE,SE,SW,NW}. + * The game checks this against whatever sits on the tiles underneath: if a tile + * conflicts with a declared pillar position, the game skips rendering that pillar + * for that tile. A value of 0 means no pillars for that slot and orientation. + */ + pillar_info: [ + 0, 0, // slot 0: no pillars + 0, 0, // slot 1: no pillars + 0, 0, // slot 2: no pillars + bitmask(BRIDGE_PILLAR_CORNER_N, BRIDGE_PILLAR_CORNER_E), // slot 3, X-axis + bitmask(BRIDGE_PILLAR_CORNER_S, BRIDGE_PILLAR_CORNER_W), // slot 3, Y-axis + 0, 0, // slot 4: no pillars + bitmask(BRIDGE_PILLAR_CORNER_N, BRIDGE_PILLAR_CORNER_E), // slot 5, X-axis + bitmask(BRIDGE_PILLAR_CORNER_S, BRIDGE_PILLAR_CORNER_W), // slot 5, Y-axis + ]; + } + + /* Assign spritesets to each visual layer. + * Each list holds four entries, one per transport type: [rail, road, monorail, maglev]. + * We supply the same cable sprites for all transport types; the game draws + * the appropriate track or road surface on top automatically. + */ + graphics { + bridge_head: [cable_head, cable_head, cable_head, cable_head]; + bridge_back: [cable_back, cable_back, cable_back, cable_back]; + bridge_front: [cable_front, cable_front, cable_front, cable_front]; + bridge_pillars: [cable_pillar, cable_pillar, cable_pillar, cable_pillar]; + } +} \ No newline at end of file diff --git a/examples/bridge/gfx/cable.png b/examples/bridge/gfx/cable.png new file mode 100644 index 000000000..42e1cb2c9 Binary files /dev/null and b/examples/bridge/gfx/cable.png differ diff --git a/examples/bridge/lang/english.lng b/examples/bridge/lang/english.lng new file mode 100644 index 000000000..f532774d1 --- /dev/null +++ b/examples/bridge/lang/english.lng @@ -0,0 +1,6 @@ +##grflangid 0x01 +STR_GRF_NAME :NML Example NewGRF: Bridge +STR_GRF_DESC :{ORANGE}NML Example NewGRF: Bridge{}{BLACK}This NewGRF is intended to provide a coding example for the high-level NewGRF-coding language NML.{}It demonstrates how to define a custom bridge using FEAT_BRIDGES with sprite templates, 6-table duplication for bridge_parts, and 4x zoom alternatives. +STR_BRIDGE_NAME :Cable-Stayed Bridge +STR_BRIDGE_DESC_RAIL :Cable-Stayed Rail Bridge +STR_BRIDGE_DESC_ROAD :Cable-Stayed Road Bridge diff --git a/nml/actions/action0bridge.py b/nml/actions/action0bridge.py new file mode 100644 index 000000000..48412b403 --- /dev/null +++ b/nml/actions/action0bridge.py @@ -0,0 +1,475 @@ +__license__ = """ +NML 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 2 of the License, or +(at your option) any later version. + +NML 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 NML; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.""" + +""" +Handles the ``graphics { }`` block for bridges (feature 0x06, property 0x0D). + +All defined bridge sprites are collected and deduplicated first. +A single ActionD reserves the full sprite block in the GRM and stores the +GRM base address in param 0x3F. The sprites are then loaded in ActionA +chunks, each preceded by Action6 to patch the chunk's first_sprite to +GRM_base + offset. Finally, each bridge's prop tables are emitted in +Action0, with another Action6 patching their relative indices by adding +param 0x3F. + +Param 0x3F must not be claimed by the user -- it is reserved for the GRM +base and must persist for the duration of the whole compile. A ScriptError +is raised if it is already in use. + +Two entry points: + ``collect(graphics_block, pos)`` + Phase 1 (GraphicsBlock.pre_process): validates and registers this + bridge's sprites in the shared pool. Idempotent. + ``emit_actions(graphics_block, bridge_id, pos)`` + Phase 2 (GraphicsBlock.get_action_list): emits the one-shot GRM + reservation + ActionA sprite-load sequence (skipped when no bridge + contributed sprites), then this bridge's Action6 + Action0. +""" + +from nml import expression, generic, global_constants, nmlop +from nml.actions import action2, action6, real_sprite +from nml.actions.action0 import Action0 +from nml.actions.action0properties import BaseAction0Property +from nml.actions.actionA import ActionA +from nml.actions.actionD import ActionD +from nml.ast.grf import param_stats +from nml.ast.spriteblock import SpriteSet + +# ---- Constants ---- + +_GRM_FEATURE = 0x08 # generic sprites +_BRIDGE_PARAM = 0x3F # user-param slot reserved for the GRM base register + +# Action0 header: action(1) + feature(1) + numprops(1) + numinfo(1) +# + id_high(1) + id_word(2). Prop data starts at offset 7. +_ACTION0_HDR = 7 + +# ActionA layout: action(1) + num_sets(1) + num_per_set(1) + first_sprite(2) +# The first_sprite word sits at offset 3. +_ACTIONA_FIRST_SPRITE_OFFSET = 3 + + +# ---- Transpose tables ---- +# Input index within each 48-sprite array: i = g * 12 + t * 2 + c +# g in 0..3 transport (rail=0, road=1, mono=2, maglev=3) +# t in 0..5 piece (0=BRIDGE_PIECE_NORTH, 1=BRIDGE_PIECE_SOUTH, +# 2=BRIDGE_PIECE_INNER_NORTH, 3=BRIDGE_PIECE_INNER_SOUTH, +# 4=BRIDGE_PIECE_MIDDLE_ODD, 5=BRIDGE_PIECE_MIDDLE_EVEN) +# c in 0..1 coord (X=0, Y=1) +# +# NFO slot within BridgePartsProp (6 tables x 32 DWORDs = 192): +# slot = t * 32 + g * 8 + c * 4 + tp +# tp = 0 for back, 1 for front, 2 for pillars +# (tp == 3 slots are reserved, never written) + +_BACK_TO_NFO = [0] * 48 +_FRONT_TO_NFO = [0] * 48 +_PILLARS_TO_NFO = [0] * 48 +for _g in range(4): + for _t in range(6): + for _c in range(2): + _i = _g * 12 + _t * 2 + _c + _BACK_TO_NFO[_i] = _t * 32 + _g * 8 + _c * 4 + 0 + _FRONT_TO_NFO[_i] = _t * 32 + _g * 8 + _c * 4 + 1 + _PILLARS_TO_NFO[_i] = _t * 32 + _g * 8 + _c * 4 + 2 + + +# ---- Role definitions ---- +# (role_name, expected_sprite_count, parts_transpose_table_or_None) +# bridge_head (BRIDGE_PIECE_HEAD) has its own prop; its transpose table is None. +_ROLES = ( + ("bridge_back", 48, _BACK_TO_NFO), + ("bridge_front", 48, _FRONT_TO_NFO), + ("bridge_pillars", 48, _PILLARS_TO_NFO), + ("bridge_head", 32, None), +) +_ROLE_NAMES = tuple(r[0] for r in _ROLES) +_PARTS_ROLES = tuple(r[0] for r in _ROLES if r[2] is not None) +_ENDS_ROLE = "bridge_head" + + +# ---- Sprite key helpers ---- + + +def _rs_key(rs): + """Structural key for one RealSprite (one zoom/bpp variant of a slot).""" + mp = getattr(rs, "mask_pos", None) + return ( + rs.file.value, + rs.xpos.value if rs.xpos is not None else None, + rs.ypos.value if rs.ypos is not None else None, + rs.xsize.value if rs.xsize is not None else None, + rs.ysize.value if rs.ysize is not None else None, + rs.xrel.value, + rs.yrel.value, + rs.mask_file.value if getattr(rs, "mask_file", None) is not None else None, + (mp[0].value, mp[1].value) if mp is not None else None, + rs.flags.value if getattr(rs, "flags", None) is not None else 0, + getattr(rs, "bit_depth", 8), + getattr(rs, "zoom_level", 0), + ) + + +def _sprite_key(rsa): + """Returns a key covering all zoom/bpp variants of a RealSpriteAction. + Ensures two slots sharing an 8bpp primary but differing in alternate data + (e.g. a 32bpp variant or mask) are treated as distinct sprites.""" + return tuple(_rs_key(rs) for rs in rsa.sprite_list) + + +def _is_empty_rsa(rsa): + """True if this RealSpriteAction came from a blank ``[]`` literal -- its + underlying RealSprite has no parameters and ``is_empty`` is set. Such + slots map to dword=0 with no GRM patch.""" + return bool(rsa.sprite_list) and getattr(rsa.sprite_list[0], "is_empty", False) + + +# ---- Property classes ---- + + +class BridgePartsProp(BaseAction0Property): + """Prop 0x0D entry: tableid=0, numtables=6, 192 DWORDs (tables 0-5).""" + + TOTAL_DWORDS = 192 + HEADER_LEN = 3 # prop-num + tableid + numtables + + def __init__(self, dwords): + assert len(dwords) == self.TOTAL_DWORDS + self.dwords = dwords + + def write(self, file): + file.print_bytex(0x0D) + file.print_byte(0) + file.print_byte(6) + file.newline() + for t in range(6): + for i in range(32): + file.print_dwordx(self.dwords[t * 32 + i]) + file.newline() + + def get_size(self): + return self.HEADER_LEN + self.TOTAL_DWORDS * 4 + + +class BridgeEndsProp(BaseAction0Property): + """Prop 0x0D entry: tableid=6, numtables=1, 32 DWORDs (table 6).""" + + TOTAL_DWORDS = 32 + HEADER_LEN = 3 + + def __init__(self, dwords): + assert len(dwords) == self.TOTAL_DWORDS + self.dwords = dwords + + def write(self, file): + file.print_bytex(0x0D) + file.print_byte(6) + file.print_byte(1) + file.newline() + for i in range(32): + file.print_dwordx(self.dwords[i]) + file.newline() + + def get_size(self): + return self.HEADER_LEN + self.TOTAL_DWORDS * 4 # 3 + 128 = 131 + + +# ---- BridgeSpriteRegistry ---- + + +class BridgeSpriteRegistry: + """Deduplicating pool of bridge sprites shared across all bridges in a + compile. Pure data store; emission lives in module-level _emit_prelude.""" + + def __init__(self): + self._sprite_to_index = {} # sprite_key -> global index + self._unique = [] # unique RealSpriteActions in insertion order + self._prelude_emitted = False + + def intern(self, sprites): + """Interns a flat list of RealSpriteActions into the shared pool. + Idempotent -- the same sprite always gets the same index. Empty + (``[]``) sprites are skipped; their slot in the returned list is + ``None``, indicating the dword should stay 0 and not be patched.""" + indices = [] + for rsa in sprites: + if _is_empty_rsa(rsa): + indices.append(None) + continue + k = _sprite_key(rsa) + if k not in self._sprite_to_index: + self._sprite_to_index[k] = len(self._unique) + self._unique.append(rsa) + indices.append(self._sprite_to_index[k]) + return indices + + def is_empty(self): + return not self._unique + + def needs_prelude(self): + return not self._prelude_emitted + + def mark_prelude_emitted(self): + self._prelude_emitted = True + + @property + def unique(self): + return self._unique + + +# ---- BridgeGraphics ---- + + +class BridgeGraphics: + """Parses and resolves one bridge's ``graphics { }`` block. Pure parser: + validates each named role (bridge_back, bridge_front, bridge_pillars, + bridge_head), resolves its spriteset references, and exposes a flat + list of RealSpriteActions per role via ``self.sprites``.""" + + def __init__(self, graphics_block, pos): + self.pos = pos + self.sprites = {role: None for role in _ROLE_NAMES} + self._parse(graphics_block) + + def _parse(self, graphics_block): + if graphics_block.default_graphics is not None: + raise generic.ScriptError( + "graphics for bridges does not accept a default / returned value", + graphics_block.default_graphics.pos, + ) + + values = {role: None for role in _ROLE_NAMES} + for gdef in graphics_block.graphics_list: + name = gdef.cargo_id + if not isinstance(name, expression.Identifier) or name.value not in values: + raise generic.ScriptError( + "graphics for bridges: unknown attribute; expected one of " + "bridge_back, bridge_front, bridge_pillars, bridge_head", + name.pos, + ) + if values[name.value] is not None: + raise generic.ScriptError( + "graphics for bridges: duplicate '{}' attribute".format(name.value), + name.pos, + ) + if gdef.result.value is None: + raise generic.ScriptError( + "graphics for bridges: 'return' is not allowed", + gdef.result.pos, + ) + values[name.value] = gdef.result.value.reduce(global_constants.const_list) + + for role, expected, _ in _ROLES: + value = values[role] + if value is not None: + self.sprites[role] = self._resolve_and_flatten(value, expected, role) + + @staticmethod + def _resolve_and_flatten(value, expected, role): + if isinstance(value, (expression.SpriteGroupRef, expression.Identifier, expression.StringLiteral)): + # Single spriteset -- wrap so the loop below handles it uniformly. + elems = [value] + elif isinstance(value, expression.Array): + elems = value.values + else: + raise generic.ScriptError( + "graphics: '{}' requires a spriteset or an array of spritesets".format(role), value.pos + ) + sprites = [] + for elem in elems: + if isinstance(elem, expression.SpriteGroupRef): + name = elem.name + elif isinstance(elem, (expression.Identifier, expression.StringLiteral)): + name = elem + else: + raise generic.ScriptError("Each element must be a spriteset name", elem.pos) + sg = action2.resolve_spritegroup(name) + if not isinstance(sg, SpriteSet): + raise generic.ScriptError("'{}' is not a spriteset".format(name.value), elem.pos) + sprites.extend(real_sprite.parse_sprite_data(sg)) + if len(sprites) != expected: + raise generic.ScriptError( + "graphics: '{}' must total exactly {:d} sprites ({:d} provided)".format(role, expected, len(sprites)), + value.pos, + ) + return sprites + + def register(self, registry): + """Add this bridge's role sprites to the shared pool (phase 1). + Indices aren't needed at this stage.""" + for sprites in self.sprites.values(): + if sprites is not None: + registry.intern(sprites) + + +# ---- Emission helpers ---- + + +def _emit_prelude(registry, pos): + """Emits the one-shot GRM reservation and sprite-load sequence. + Reserves all interned sprites in the GRM (storing the base in param + 0x3F via ActionD), then loads them in ActionA chunks of up to 255, + each preceded by an Action6 that adjusts the chunk's first_sprite + to GRM_base + chunk_start.""" + # Verify param 0x3F is available before emitting anything. + if param_stats[0] > _BRIDGE_PARAM: + raise generic.ScriptError( + "GRF parameter 0x{:02X} is reserved for bridge sprite loading when a bridge defines graphics. " + "Move your parameter to a lower index (< 0x{:02X}) or remove the bridge's graphics block.".format( + _BRIDGE_PARAM, _BRIDGE_PARAM + ), + pos, + ) + + # Reserve n generic sprites in the GRM and store the base address in param 0x3F via ActionD. + n = len(registry.unique) + grm_data = expression.ConstantNumeric(0xFF | (_GRM_FEATURE << 8) | (n << 16)) + out = [ + ActionD( + expression.ConstantNumeric(_BRIDGE_PARAM), + nmlop.GRM_RESERVE, + nmlop.ASSIGN, + expression.ConstantNumeric(0xFE), + grm_data, + ) + ] + idx = 0 + while idx < n: + k = min(n - idx, 255) + # Action6 patches this chunk's ActionA first_sprite: first_sprite += param 0x3F (GRM base). + act6 = action6.Action6() + act6.modify_bytes(_BRIDGE_PARAM, 0x82, _ACTIONA_FIRST_SPRITE_OFFSET) + out.append(act6) + out.append(ActionA([(k, idx)])) + out.extend(registry.unique[idx : idx + k]) + idx += k + + registry.mark_prelude_emitted() + return out + + +def _build_parts_prop(indices_by_role): + """Merges bridge_back/front/pillars indices into the single 192-DWORD + BridgePartsProp. Returns (prop, written_slots) or None when none of + the three parts roles are provided. ``None`` entries inside an + indices list (`[]` blank slots) leave the dword at 0 and stay out + of ``written``.""" + if all(indices_by_role[r] is None for r in _PARTS_ROLES): + return None + dwords = [0] * BridgePartsProp.TOTAL_DWORDS + written = set() + for role, _, slot_table in _ROLES: + if slot_table is None: + continue + m = indices_by_role[role] + if m is None: + continue + for i, uniq_idx in enumerate(m): + if uniq_idx is None: + continue + slot = slot_table[i] + dwords[slot] = uniq_idx + written.add(slot) + return BridgePartsProp(dwords), written + + +def _build_ends_prop(indices): + """Returns (prop, written_slots) or None when bridge_head is missing. + ``None`` entries inside the indices list (`[]` blank slots) become + dword=0 and are excluded from ``written_slots`` so they aren't + patched with the GRM base offset.""" + if indices is None: + return None + dwords = [0 if idx is None else idx for idx in indices] + written = {i for i, idx in enumerate(indices) if idx is not None} + return BridgeEndsProp(dwords), written + + +def _emit_bridge(sprites_by_role, registry, bridge_id): + """Builds Action6 + Action0 for one bridge. Resolves each role's + relative sprite indices from the registry and assembles prop 0x0D + entries with their Action6 patch offsets. Returns [] if no roles + were provided.""" + indices_by_role = { + role: registry.intern(sprites) if sprites is not None else None + for role, sprites in sprites_by_role.items() + } + + props = [] + mods = [] # (param, size_byte, absolute_byte_offset) + prop_offset = 0 + + built = _build_parts_prop(indices_by_role) + if built is not None: + parts_prop, written = built + props.append(parts_prop) + # Only patch slots we actually wrote. Unwritten slots (missing + # role or `[]` blank) stay 0 -- adding GRM_base would wrongly + # turn them into the first bridge sprite. 0x82 = 2-byte add on + # the sprite-ID word only; leaves the palette word untouched. + for slot in sorted(written): + mods.append((_BRIDGE_PARAM, 0x82, _ACTION0_HDR + prop_offset + BridgePartsProp.HEADER_LEN + slot * 4)) + prop_offset += parts_prop.get_size() + + ends_built = _build_ends_prop(indices_by_role[_ENDS_ROLE]) + if ends_built is not None: + ends_prop, ends_written = ends_built + props.append(ends_prop) + for i in sorted(ends_written): + mods.append((_BRIDGE_PARAM, 0x82, _ACTION0_HDR + prop_offset + BridgeEndsProp.HEADER_LEN + i * 4)) + prop_offset += ends_prop.get_size() + + if not props: + return [] + + out = [] + act6 = action6.Action6() + for param, size_byte, abs_off in mods: + act6.modify_bytes(param, size_byte, abs_off) + if act6.modifications: + out.append(act6) + + act0 = Action0(0x06, bridge_id.value) + act0.prop_list = props + act0.num_ids = 1 + out.append(act0) + + return out + + +# ---- Module singleton + entry points ---- + +_registry = BridgeSpriteRegistry() + + +def collect(graphics_block, pos): + """Phase 1 -- called from GraphicsBlock.pre_process for bridge items. + Validates the graphics block and registers its sprites in the shared + registry so the prelude can reserve GRM space for all bridges together.""" + BridgeGraphics(graphics_block, pos).register(_registry) + + +def emit_actions(graphics_block, bridge_id, pos): + """Phase 2 -- called from GraphicsBlock.get_action_list for bridge items. + Emits the shared prelude on first use (ActionD + ActionA + sprites) + when at least one bridge contributed sprites, followed by this + bridge's Action6 + Action0. Empty graphics blocks contribute nothing + and are silently skipped.""" + bridge = BridgeGraphics(graphics_block, pos) + out = [] + if _registry.needs_prelude() and not _registry.is_empty(): + out.extend(_emit_prelude(_registry, pos)) + out.extend(_emit_bridge(bridge.sprites, _registry, bridge_id)) + return out diff --git a/nml/actions/action0properties.py b/nml/actions/action0properties.py index 5b71255ef..ca6a82556 100644 --- a/nml/actions/action0properties.py +++ b/nml/actions/action0properties.py @@ -928,7 +928,74 @@ def station_tile_list(value, prop_num, description): "graphic_flags": {"size": 1, "num": 0x09}, } -# TODO: Feature 0x06 + +# +# Feature 0x06 (Bridges) +# + + +class BridgePillarInfoProp(BaseAction0Property): + """Prop 0x15: pillar info -- 2n raw bytes, one pair per pillar config.""" + + def __init__(self, bytes_list): + assert len(bytes_list) % 2 == 0 and len(bytes_list) > 0 + self.bytes = bytes_list + + def write(self, file): + file.print_bytex(0x15) + file.print_bytex(len(self.bytes) // 2) + for i, b in enumerate(self.bytes): + if i > 0 and i % 8 == 0: + file.newline() + file.print_bytex(b) + file.newline() + + def get_size(self): + return 2 + len(self.bytes) # prop_num(1) + size_byte(1) + 2n data bytes + + +# fmt: off +def bridge_pillar_info(value): + if not isinstance(value, Array) or len(value.values) % 2 != 0 or len(value.values) == 0: + raise generic.ScriptError( + "pillar_info must be an array with an even number of bytes (2 per pillar config, typically 12)", + value.pos, + ) + + bytes_list = [] + for elem in value.values: + reduced = elem.reduce(global_constants.const_list) + if not isinstance(reduced, ConstantNumeric): + raise generic.ScriptError("pillar_info values must be compile-time constants", elem.pos) + generic.check_range(reduced.value, 0, 255, "pillar_info byte", elem.pos) + bytes_list.append(reduced.value) + + return [BridgePillarInfoProp(bytes_list)] + + +properties[0x06] = { + # 0x08 - year availability (old way) + "min_length": {"size": 1, "num": 0x09}, + "max_length": {"size": 1, "num": 0x0A}, + # 0x0B - cost factor (old way) + "speed_limit": { + "size": 2, + "num": 0x0C, + "unit_type": "speed", + "unit_conversion": (5000, 1397), + "adjust_value": lambda val, unit: ottd_display_speed(val, 1, 1, unit), + }, + # 0x0D - sprite tables (set via the `graphics { bridge_back/front/pillars/head: ... }` block) + "flags": {"size": 1, "num": 0x0E}, + "avail_year": {"size": 4, "num": 0x0F}, + "name": {"size": 2, "num": 0x10, "string": 0xDC}, + "description_rail": {"size": 2, "num": 0x11, "string": 0xDC}, + "description_road": {"size": 2, "num": 0x12, "string": 0xDC}, + "cost_factor": {"size": 2, "num": 0x13}, + "pillar_info": {"num": 0x15, "custom_function": bridge_pillar_info}, +} + +# fmt: on # # Feature 0x07 (Houses) diff --git a/nml/ast/item.py b/nml/ast/item.py index 87cc32901..3bc377ac6 100644 --- a/nml/ast/item.py +++ b/nml/ast/item.py @@ -14,7 +14,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.""" from nml import expression, generic, global_constants -from nml.actions import action0, action2, action2var, action3 +from nml.actions import action0, action0bridge, action2, action2var, action3 from nml.ast import base_statement, general item_feature = None @@ -234,6 +234,10 @@ def __init__(self, graphics_list, default_graphics, pos): self.default_graphics = default_graphics def pre_process(self): + if item_feature == 0x06: + action0bridge.collect(self, self.pos) + return + for graphics_def in self.graphics_list: graphics_def.reduce_expressions(action2var.get_scope(item_feature)) if self.default_graphics is not None: @@ -267,7 +271,9 @@ def debug_print(self, indentation): self.default_graphics.debug_print(indentation + 4) def get_action_list(self): - if self.prepare_act2_output(): + if item_feature == 0x06: + return action0bridge.emit_actions(self, item_id, self.pos) + elif self.prepare_act2_output(): return action3.parse_graphics_block(self, item_feature, item_id, item_size) return [] diff --git a/nml/global_constants.py b/nml/global_constants.py index cf808621e..5dcf41b6c 100644 --- a/nml/global_constants.py +++ b/nml/global_constants.py @@ -395,6 +395,9 @@ def constant_number(name, info, pos): # station tiles "STAT_ALL_TILES" : 0xFF, + # bridge general flags + "FAR_PILLARS_DISABLE" : 0, + # bridge pillar flags "BRIDGE_PILLAR_CORNER_W" : 0, "BRIDGE_PILLAR_CORNER_S" : 1, diff --git a/regression/043_bridge.nml b/regression/043_bridge.nml new file mode 100644 index 000000000..bcf38811c --- /dev/null +++ b/regression/043_bridge.nml @@ -0,0 +1,62 @@ +grf { + grfid: "NML+"; + name: string(STR_REGRESSION_NAME); + desc: string(STR_REGRESSION_DESC); + version: 0; + min_compatible_version: 0; +} + +/* Minimal bridge sprite template -- reuses a small region of oneway.png */ +template bridge_spr() { + [0, 0, 4, 4, -2, -2] +} + +/* + * Each of bridge_back/bridge_front/bridge_pillars is 48 sprites (4 transports x 6 tables x 2 coords). + * bridge_ends is 32 sprites (4 transports x flat/ramp x 4 sub-slots). + * 4 rows x 12 = 48 for parts; 4 rows x 8 = 32 for ends. + */ +spriteset(bridge_parts_spr, "oneway.png") { + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() +} + +spriteset(bridge_ends_spr, "oneway.png") { + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() +} + +item(FEAT_BRIDGES, my_bridge, 0x01) { + property { + min_length: 0; + max_length: 12; + cost_factor: 40; + speed_limit: 64 km/h; + flags: 0; + avail_year: 1930; + pillar_info: [ + bitmask(BRIDGE_PILLAR_CORNER_N, BRIDGE_PILLAR_CORNER_S), // BRIDGE_PIECE_NORTH x + bitmask(BRIDGE_PILLAR_CORNER_W, BRIDGE_PILLAR_CORNER_E), // BRIDGE_PIECE_NORTH y + bitmask(BRIDGE_PILLAR_EDGE_NE), // BRIDGE_PIECE_SOUTH x + bitmask(BRIDGE_PILLAR_EDGE_SW), // BRIDGE_PIECE_SOUTH y + 0x00, // BRIDGE_PIECE_INNER_NORTH x + 0x00, // BRIDGE_PIECE_INNER_NORTH y + 0xFF, // BRIDGE_PIECE_INNER_SOUTH x + 0xFF, // BRIDGE_PIECE_INNER_SOUTH y + bitmask(BRIDGE_PILLAR_EDGE_NW, BRIDGE_PILLAR_EDGE_SE), // BRIDGE_PIECE_MIDDLE_ODD x + bitmask(BRIDGE_PILLAR_CORNER_N), // BRIDGE_PIECE_MIDDLE_ODD y + 0x00, // BRIDGE_PIECE_MIDDLE_EVEN x + 0x00, // BRIDGE_PIECE_MIDDLE_EVEN y + ]; + } + graphics { + bridge_back: [bridge_parts_spr]; + bridge_front: [bridge_parts_spr]; + bridge_pillars: [bridge_parts_spr]; + bridge_head: [bridge_ends_spr]; + } +} diff --git a/regression/044_two_bridges.nml b/regression/044_two_bridges.nml new file mode 100644 index 000000000..4fa7ea7bd --- /dev/null +++ b/regression/044_two_bridges.nml @@ -0,0 +1,84 @@ +grf { + grfid: "NML+"; + name: string(STR_REGRESSION_NAME); + desc: string(STR_REGRESSION_DESC); + version: 0; + min_compatible_version: 0; +} + +/* Two independent bridges using the `graphics { bridge_back/bridge_front/bridge_pillars/bridge_ends: ... }` + block. Unique sprites from both bridges share a single GRM reservation and + a single ActionA sprite-load sequence, emitted once before the first bridge's + Action0. Each bridge's Action0 is patched via its own Action6. */ + +template bridge_spr() { + [0, 0, 4, 4, -2, -2] +} + +/* Bridge A sprites (48 for parts, 32 for ends) */ + +spriteset(bridge_a_parts_spr, "oneway.png") { + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() +} + +spriteset(bridge_a_ends_spr, "oneway.png") { + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() +} + +/* Bridge B sprites (48 for parts, 32 for ends) */ + +spriteset(bridge_b_parts_spr, "oneway.png") { + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() +} + +spriteset(bridge_b_ends_spr, "oneway.png") { + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() + bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() bridge_spr() +} + +/* Bridge definitions */ + +item(FEAT_BRIDGES, bridge_a, 0x01) { + property { + min_length: 0; + max_length: 12; + cost_factor: 40; + speed_limit: 64 km/h; + flags: 0; + avail_year: 1930; + } + graphics { + bridge_back: [bridge_a_parts_spr]; + bridge_front: [bridge_a_parts_spr]; + bridge_pillars: [bridge_a_parts_spr]; + bridge_head: [bridge_a_ends_spr]; + } +} + +item(FEAT_BRIDGES, bridge_b, 0x02) { + property { + min_length: 0; + max_length: 16; + cost_factor: 60; + speed_limit: 80 km/h; + flags: 0; + avail_year: 1950; + } + graphics { + bridge_back: [bridge_b_parts_spr]; + bridge_front: [bridge_b_parts_spr]; + bridge_pillars: [bridge_b_parts_spr]; + bridge_head: [bridge_b_ends_spr]; + } +} diff --git a/regression/045_bridge_dedup.nml b/regression/045_bridge_dedup.nml new file mode 100644 index 000000000..45e4c45f2 --- /dev/null +++ b/regression/045_bridge_dedup.nml @@ -0,0 +1,92 @@ +grf { + grfid: "NML+"; + name: string(STR_REGRESSION_NAME); + desc: string(STR_REGRESSION_DESC); + version: 0; + min_compatible_version: 0; +} + +/* + * Dedup regression test (global pool). + * + * bridge_back/bridge_front/bridge_pillars each reference `dedup_12` (12 distinct xrel sprites) + * four times -- 4 refs x 12 sprites = 48 per role, same 12 unique sprites. + * bridge_ends uses `dedup_ends` (32 identical sprites) -> 1 unique. + * + * Expected: + * - GRM reserves 13 sprites (12 unique parts + 1 unique end), shared globally. + * - Exactly one ActionA chunk of 13 sprites. + * - Prop 0x0D slots for bridge_back/bridge_front/bridge_pillars cycle indices 0..11 across each + * role; all 32 bridge_ends slots resolve to index 12. + */ + +/* 12 sprites with distinct xrel values -- one unique sprite per xrel. */ +spriteset(dedup_12, "oneway.png") { + [0, 0, 4, 4, -2, 0] + [0, 0, 4, 4, -3, 0] + [0, 0, 4, 4, -4, 0] + [0, 0, 4, 4, -5, 0] + [0, 0, 4, 4, -6, 0] + [0, 0, 4, 4, -7, 0] + [0, 0, 4, 4, -8, 0] + [0, 0, 4, 4, -9, 0] + [0, 0, 4, 4, -10, 0] + [0, 0, 4, 4, -11, 0] + [0, 0, 4, 4, -12, 0] + [0, 0, 4, 4, -13, 0] +} + +/* 32 identical sprites for ends -- deduplicates to 1 unique. */ +spriteset(dedup_ends, "oneway.png") { + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] + [0, 0, 4, 4, -2, -2] +} + +item(FEAT_BRIDGES, dedup_bridge, 0x03) { + property { + min_length: 0; + max_length: 12; + cost_factor: 40; + speed_limit: 64 km/h; + flags: 0; + avail_year: 1930; + } + graphics { + /* 4 refs x 12 sprites = 48 per role, 12 unique across back/front/pillars */ + bridge_back: [dedup_12, dedup_12, dedup_12, dedup_12]; + bridge_front: [dedup_12, dedup_12, dedup_12, dedup_12]; + bridge_pillars: [dedup_12, dedup_12, dedup_12, dedup_12]; + /* 32 sprites, all identical -> 1 unique */ + bridge_head: [dedup_ends]; + } +} diff --git a/regression/expected/043_bridge.grf b/regression/expected/043_bridge.grf new file mode 100644 index 000000000..c613f3da4 Binary files /dev/null and b/regression/expected/043_bridge.grf differ diff --git a/regression/expected/043_bridge.nfo b/regression/expected/043_bridge.nfo new file mode 100644 index 000000000..8de02cd57 --- /dev/null +++ b/regression/expected/043_bridge.nfo @@ -0,0 +1,228 @@ +// Automatically generated by GRFCODEC. Do not modify! +// (Info version 32) +// Escapes: 2+ 2- 2< 2> 2u< 2u> 2/ 2% 2u/ 2u% 2* 2& 2| 2^ 2sto = 2s 2rst = 2r 2psto 2ror = 2rot 2cmp 2ucmp 2<< 2u>> 2>> +// Escapes: 71 70 7= 7! 7< 7> 7G 7g 7gG 7GG 7gg 7c 7C +// Escapes: D= = DR D+ = DF D- = DC Du* = DM D* = DnF Du<< = DnC D<< = DO D& D| Du/ D/ Du% D% +// Format: spritenum imagefile depth xpos ypos xsize ysize xrel yrel zoom flags + +0 * 4 \d9 + +1 * 54 14 "C" "INFO" +"B" "VRSN" \w4 \dx00000000 +"B" "MINV" \w4 \dx00000000 +"B" "NPAR" \w1 00 +"B" "PALS" \w1 "W" +"B" "BLTR" \w1 "8" +00 +00 +2 * 52 08 08 "NML+" "NML regression test" 00 "A test newgrf testing NML" 00 +3 * 38 00 06 \b7 01 FF \wx0001 +09 00 +0A 0C +13 \wx0028 +0C \wx0040 +0E 00 +0F \dx0000078A +15 06 0A 05 10 40 00 00 FF FF +A0 08 00 00 + +// param[63] = param[\DR] +4 * 9 0D 3F \D= \DR FE \dx000108FF + +5 * 7 06 +3F 82 FF \wx0003 +FF + +6 * 5 0A \b1 \b1 \w0 + +7 oneway.png 8bpp 0 0 4 4 -2 -2 normal +8 * 882 06 +3F 82 FF \wx000A +3F 82 FF \wx000E +3F 82 FF \wx0012 +3F 82 FF \wx001A +3F 82 FF \wx001E +3F 82 FF \wx0022 +3F 82 FF \wx002A +3F 82 FF \wx002E +3F 82 FF \wx0032 +3F 82 FF \wx003A +3F 82 FF \wx003E +3F 82 FF \wx0042 +3F 82 FF \wx004A +3F 82 FF \wx004E +3F 82 FF \wx0052 +3F 82 FF \wx005A +3F 82 FF \wx005E +3F 82 FF \wx0062 +3F 82 FF \wx006A +3F 82 FF \wx006E +3F 82 FF \wx0072 +3F 82 FF \wx007A +3F 82 FF \wx007E +3F 82 FF \wx0082 +3F 82 FF \wx008A +3F 82 FF \wx008E +3F 82 FF \wx0092 +3F 82 FF \wx009A +3F 82 FF \wx009E +3F 82 FF \wx00A2 +3F 82 FF \wx00AA +3F 82 FF \wx00AE +3F 82 FF \wx00B2 +3F 82 FF \wx00BA +3F 82 FF \wx00BE +3F 82 FF \wx00C2 +3F 82 FF \wx00CA +3F 82 FF \wx00CE +3F 82 FF \wx00D2 +3F 82 FF \wx00DA +3F 82 FF \wx00DE +3F 82 FF \wx00E2 +3F 82 FF \wx00EA +3F 82 FF \wx00EE +3F 82 FF \wx00F2 +3F 82 FF \wx00FA +3F 82 FF \wx00FE +3F 82 FF \wx0102 +3F 82 FF \wx010A +3F 82 FF \wx010E +3F 82 FF \wx0112 +3F 82 FF \wx011A +3F 82 FF \wx011E +3F 82 FF \wx0122 +3F 82 FF \wx012A +3F 82 FF \wx012E +3F 82 FF \wx0132 +3F 82 FF \wx013A +3F 82 FF \wx013E +3F 82 FF \wx0142 +3F 82 FF \wx014A +3F 82 FF \wx014E +3F 82 FF \wx0152 +3F 82 FF \wx015A +3F 82 FF \wx015E +3F 82 FF \wx0162 +3F 82 FF \wx016A +3F 82 FF \wx016E +3F 82 FF \wx0172 +3F 82 FF \wx017A +3F 82 FF \wx017E +3F 82 FF \wx0182 +3F 82 FF \wx018A +3F 82 FF \wx018E +3F 82 FF \wx0192 +3F 82 FF \wx019A +3F 82 FF \wx019E +3F 82 FF \wx01A2 +3F 82 FF \wx01AA +3F 82 FF \wx01AE +3F 82 FF \wx01B2 +3F 82 FF \wx01BA +3F 82 FF \wx01BE +3F 82 FF \wx01C2 +3F 82 FF \wx01CA +3F 82 FF \wx01CE +3F 82 FF \wx01D2 +3F 82 FF \wx01DA +3F 82 FF \wx01DE +3F 82 FF \wx01E2 +3F 82 FF \wx01EA +3F 82 FF \wx01EE +3F 82 FF \wx01F2 +3F 82 FF \wx01FA +3F 82 FF \wx01FE +3F 82 FF \wx0202 +3F 82 FF \wx020A +3F 82 FF \wx020E +3F 82 FF \wx0212 +3F 82 FF \wx021A +3F 82 FF \wx021E +3F 82 FF \wx0222 +3F 82 FF \wx022A +3F 82 FF \wx022E +3F 82 FF \wx0232 +3F 82 FF \wx023A +3F 82 FF \wx023E +3F 82 FF \wx0242 +3F 82 FF \wx024A +3F 82 FF \wx024E +3F 82 FF \wx0252 +3F 82 FF \wx025A +3F 82 FF \wx025E +3F 82 FF \wx0262 +3F 82 FF \wx026A +3F 82 FF \wx026E +3F 82 FF \wx0272 +3F 82 FF \wx027A +3F 82 FF \wx027E +3F 82 FF \wx0282 +3F 82 FF \wx028A +3F 82 FF \wx028E +3F 82 FF \wx0292 +3F 82 FF \wx029A +3F 82 FF \wx029E +3F 82 FF \wx02A2 +3F 82 FF \wx02AA +3F 82 FF \wx02AE +3F 82 FF \wx02B2 +3F 82 FF \wx02BA +3F 82 FF \wx02BE +3F 82 FF \wx02C2 +3F 82 FF \wx02CA +3F 82 FF \wx02CE +3F 82 FF \wx02D2 +3F 82 FF \wx02DA +3F 82 FF \wx02DE +3F 82 FF \wx02E2 +3F 82 FF \wx02EA +3F 82 FF \wx02EE +3F 82 FF \wx02F2 +3F 82 FF \wx02FA +3F 82 FF \wx02FE +3F 82 FF \wx0302 +3F 82 FF \wx030D +3F 82 FF \wx0311 +3F 82 FF \wx0315 +3F 82 FF \wx0319 +3F 82 FF \wx031D +3F 82 FF \wx0321 +3F 82 FF \wx0325 +3F 82 FF \wx0329 +3F 82 FF \wx032D +3F 82 FF \wx0331 +3F 82 FF \wx0335 +3F 82 FF \wx0339 +3F 82 FF \wx033D +3F 82 FF \wx0341 +3F 82 FF \wx0345 +3F 82 FF \wx0349 +3F 82 FF \wx034D +3F 82 FF \wx0351 +3F 82 FF \wx0355 +3F 82 FF \wx0359 +3F 82 FF \wx035D +3F 82 FF \wx0361 +3F 82 FF \wx0365 +3F 82 FF \wx0369 +3F 82 FF \wx036D +3F 82 FF \wx0371 +3F 82 FF \wx0375 +3F 82 FF \wx0379 +3F 82 FF \wx037D +3F 82 FF \wx0381 +3F 82 FF \wx0385 +3F 82 FF \wx0389 +FF + +9 * 909 00 06 \b2 01 FF \wx0001 +0D \b0 \b6 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +0D \b6 \b1 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 + diff --git a/regression/expected/044_two_bridges.grf b/regression/expected/044_two_bridges.grf new file mode 100644 index 000000000..44367a912 Binary files /dev/null and b/regression/expected/044_two_bridges.grf differ diff --git a/regression/expected/044_two_bridges.nfo b/regression/expected/044_two_bridges.nfo new file mode 100644 index 000000000..091250e1b --- /dev/null +++ b/regression/expected/044_two_bridges.nfo @@ -0,0 +1,424 @@ +// Automatically generated by GRFCODEC. Do not modify! +// (Info version 32) +// Escapes: 2+ 2- 2< 2> 2u< 2u> 2/ 2% 2u/ 2u% 2* 2& 2| 2^ 2sto = 2s 2rst = 2r 2psto 2ror = 2rot 2cmp 2ucmp 2<< 2u>> 2>> +// Escapes: 71 70 7= 7! 7< 7> 7G 7g 7gG 7GG 7gg 7c 7C +// Escapes: D= = DR D+ = DF D- = DC Du* = DM D* = DnF Du<< = DnC D<< = DO D& D| Du/ D/ Du% D% +// Format: spritenum imagefile depth xpos ypos xsize ysize xrel yrel zoom flags + +0 * 4 \d12 + +1 * 54 14 "C" "INFO" +"B" "VRSN" \w4 \dx00000000 +"B" "MINV" \w4 \dx00000000 +"B" "NPAR" \w1 00 +"B" "PALS" \w1 "W" +"B" "BLTR" \w1 "8" +00 +00 +2 * 52 08 08 "NML+" "NML regression test" 00 "A test newgrf testing NML" 00 +3 * 24 00 06 \b6 01 FF \wx0001 +09 00 +0A 0C +13 \wx0028 +0C \wx0040 +0E 00 +0F \dx0000078A + +// param[63] = param[\DR] +4 * 9 0D 3F \D= \DR FE \dx000108FF + +5 * 7 06 +3F 82 FF \wx0003 +FF + +6 * 5 0A \b1 \b1 \w0 + +7 oneway.png 8bpp 0 0 4 4 -2 -2 normal +8 * 882 06 +3F 82 FF \wx000A +3F 82 FF \wx000E +3F 82 FF \wx0012 +3F 82 FF \wx001A +3F 82 FF \wx001E +3F 82 FF \wx0022 +3F 82 FF \wx002A +3F 82 FF \wx002E +3F 82 FF \wx0032 +3F 82 FF \wx003A +3F 82 FF \wx003E +3F 82 FF \wx0042 +3F 82 FF \wx004A +3F 82 FF \wx004E +3F 82 FF \wx0052 +3F 82 FF \wx005A +3F 82 FF \wx005E +3F 82 FF \wx0062 +3F 82 FF \wx006A +3F 82 FF \wx006E +3F 82 FF \wx0072 +3F 82 FF \wx007A +3F 82 FF \wx007E +3F 82 FF \wx0082 +3F 82 FF \wx008A +3F 82 FF \wx008E +3F 82 FF \wx0092 +3F 82 FF \wx009A +3F 82 FF \wx009E +3F 82 FF \wx00A2 +3F 82 FF \wx00AA +3F 82 FF \wx00AE +3F 82 FF \wx00B2 +3F 82 FF \wx00BA +3F 82 FF \wx00BE +3F 82 FF \wx00C2 +3F 82 FF \wx00CA +3F 82 FF \wx00CE +3F 82 FF \wx00D2 +3F 82 FF \wx00DA +3F 82 FF \wx00DE +3F 82 FF \wx00E2 +3F 82 FF \wx00EA +3F 82 FF \wx00EE +3F 82 FF \wx00F2 +3F 82 FF \wx00FA +3F 82 FF \wx00FE +3F 82 FF \wx0102 +3F 82 FF \wx010A +3F 82 FF \wx010E +3F 82 FF \wx0112 +3F 82 FF \wx011A +3F 82 FF \wx011E +3F 82 FF \wx0122 +3F 82 FF \wx012A +3F 82 FF \wx012E +3F 82 FF \wx0132 +3F 82 FF \wx013A +3F 82 FF \wx013E +3F 82 FF \wx0142 +3F 82 FF \wx014A +3F 82 FF \wx014E +3F 82 FF \wx0152 +3F 82 FF \wx015A +3F 82 FF \wx015E +3F 82 FF \wx0162 +3F 82 FF \wx016A +3F 82 FF \wx016E +3F 82 FF \wx0172 +3F 82 FF \wx017A +3F 82 FF \wx017E +3F 82 FF \wx0182 +3F 82 FF \wx018A +3F 82 FF \wx018E +3F 82 FF \wx0192 +3F 82 FF \wx019A +3F 82 FF \wx019E +3F 82 FF \wx01A2 +3F 82 FF \wx01AA +3F 82 FF \wx01AE +3F 82 FF \wx01B2 +3F 82 FF \wx01BA +3F 82 FF \wx01BE +3F 82 FF \wx01C2 +3F 82 FF \wx01CA +3F 82 FF \wx01CE +3F 82 FF \wx01D2 +3F 82 FF \wx01DA +3F 82 FF \wx01DE +3F 82 FF \wx01E2 +3F 82 FF \wx01EA +3F 82 FF \wx01EE +3F 82 FF \wx01F2 +3F 82 FF \wx01FA +3F 82 FF \wx01FE +3F 82 FF \wx0202 +3F 82 FF \wx020A +3F 82 FF \wx020E +3F 82 FF \wx0212 +3F 82 FF \wx021A +3F 82 FF \wx021E +3F 82 FF \wx0222 +3F 82 FF \wx022A +3F 82 FF \wx022E +3F 82 FF \wx0232 +3F 82 FF \wx023A +3F 82 FF \wx023E +3F 82 FF \wx0242 +3F 82 FF \wx024A +3F 82 FF \wx024E +3F 82 FF \wx0252 +3F 82 FF \wx025A +3F 82 FF \wx025E +3F 82 FF \wx0262 +3F 82 FF \wx026A +3F 82 FF \wx026E +3F 82 FF \wx0272 +3F 82 FF \wx027A +3F 82 FF \wx027E +3F 82 FF \wx0282 +3F 82 FF \wx028A +3F 82 FF \wx028E +3F 82 FF \wx0292 +3F 82 FF \wx029A +3F 82 FF \wx029E +3F 82 FF \wx02A2 +3F 82 FF \wx02AA +3F 82 FF \wx02AE +3F 82 FF \wx02B2 +3F 82 FF \wx02BA +3F 82 FF \wx02BE +3F 82 FF \wx02C2 +3F 82 FF \wx02CA +3F 82 FF \wx02CE +3F 82 FF \wx02D2 +3F 82 FF \wx02DA +3F 82 FF \wx02DE +3F 82 FF \wx02E2 +3F 82 FF \wx02EA +3F 82 FF \wx02EE +3F 82 FF \wx02F2 +3F 82 FF \wx02FA +3F 82 FF \wx02FE +3F 82 FF \wx0302 +3F 82 FF \wx030D +3F 82 FF \wx0311 +3F 82 FF \wx0315 +3F 82 FF \wx0319 +3F 82 FF \wx031D +3F 82 FF \wx0321 +3F 82 FF \wx0325 +3F 82 FF \wx0329 +3F 82 FF \wx032D +3F 82 FF \wx0331 +3F 82 FF \wx0335 +3F 82 FF \wx0339 +3F 82 FF \wx033D +3F 82 FF \wx0341 +3F 82 FF \wx0345 +3F 82 FF \wx0349 +3F 82 FF \wx034D +3F 82 FF \wx0351 +3F 82 FF \wx0355 +3F 82 FF \wx0359 +3F 82 FF \wx035D +3F 82 FF \wx0361 +3F 82 FF \wx0365 +3F 82 FF \wx0369 +3F 82 FF \wx036D +3F 82 FF \wx0371 +3F 82 FF \wx0375 +3F 82 FF \wx0379 +3F 82 FF \wx037D +3F 82 FF \wx0381 +3F 82 FF \wx0385 +3F 82 FF \wx0389 +FF + +9 * 909 00 06 \b2 01 FF \wx0001 +0D \b0 \b6 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +0D \b6 \b1 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 + +10 * 24 00 06 \b6 01 FF \wx0002 +09 00 +0A 10 +13 \wx003C +0C \wx0050 +0E 00 +0F \dx0000079E + +11 * 882 06 +3F 82 FF \wx000A +3F 82 FF \wx000E +3F 82 FF \wx0012 +3F 82 FF \wx001A +3F 82 FF \wx001E +3F 82 FF \wx0022 +3F 82 FF \wx002A +3F 82 FF \wx002E +3F 82 FF \wx0032 +3F 82 FF \wx003A +3F 82 FF \wx003E +3F 82 FF \wx0042 +3F 82 FF \wx004A +3F 82 FF \wx004E +3F 82 FF \wx0052 +3F 82 FF \wx005A +3F 82 FF \wx005E +3F 82 FF \wx0062 +3F 82 FF \wx006A +3F 82 FF \wx006E +3F 82 FF \wx0072 +3F 82 FF \wx007A +3F 82 FF \wx007E +3F 82 FF \wx0082 +3F 82 FF \wx008A +3F 82 FF \wx008E +3F 82 FF \wx0092 +3F 82 FF \wx009A +3F 82 FF \wx009E +3F 82 FF \wx00A2 +3F 82 FF \wx00AA +3F 82 FF \wx00AE +3F 82 FF \wx00B2 +3F 82 FF \wx00BA +3F 82 FF \wx00BE +3F 82 FF \wx00C2 +3F 82 FF \wx00CA +3F 82 FF \wx00CE +3F 82 FF \wx00D2 +3F 82 FF \wx00DA +3F 82 FF \wx00DE +3F 82 FF \wx00E2 +3F 82 FF \wx00EA +3F 82 FF \wx00EE +3F 82 FF \wx00F2 +3F 82 FF \wx00FA +3F 82 FF \wx00FE +3F 82 FF \wx0102 +3F 82 FF \wx010A +3F 82 FF \wx010E +3F 82 FF \wx0112 +3F 82 FF \wx011A +3F 82 FF \wx011E +3F 82 FF \wx0122 +3F 82 FF \wx012A +3F 82 FF \wx012E +3F 82 FF \wx0132 +3F 82 FF \wx013A +3F 82 FF \wx013E +3F 82 FF \wx0142 +3F 82 FF \wx014A +3F 82 FF \wx014E +3F 82 FF \wx0152 +3F 82 FF \wx015A +3F 82 FF \wx015E +3F 82 FF \wx0162 +3F 82 FF \wx016A +3F 82 FF \wx016E +3F 82 FF \wx0172 +3F 82 FF \wx017A +3F 82 FF \wx017E +3F 82 FF \wx0182 +3F 82 FF \wx018A +3F 82 FF \wx018E +3F 82 FF \wx0192 +3F 82 FF \wx019A +3F 82 FF \wx019E +3F 82 FF \wx01A2 +3F 82 FF \wx01AA +3F 82 FF \wx01AE +3F 82 FF \wx01B2 +3F 82 FF \wx01BA +3F 82 FF \wx01BE +3F 82 FF \wx01C2 +3F 82 FF \wx01CA +3F 82 FF \wx01CE +3F 82 FF \wx01D2 +3F 82 FF \wx01DA +3F 82 FF \wx01DE +3F 82 FF \wx01E2 +3F 82 FF \wx01EA +3F 82 FF \wx01EE +3F 82 FF \wx01F2 +3F 82 FF \wx01FA +3F 82 FF \wx01FE +3F 82 FF \wx0202 +3F 82 FF \wx020A +3F 82 FF \wx020E +3F 82 FF \wx0212 +3F 82 FF \wx021A +3F 82 FF \wx021E +3F 82 FF \wx0222 +3F 82 FF \wx022A +3F 82 FF \wx022E +3F 82 FF \wx0232 +3F 82 FF \wx023A +3F 82 FF \wx023E +3F 82 FF \wx0242 +3F 82 FF \wx024A +3F 82 FF \wx024E +3F 82 FF \wx0252 +3F 82 FF \wx025A +3F 82 FF \wx025E +3F 82 FF \wx0262 +3F 82 FF \wx026A +3F 82 FF \wx026E +3F 82 FF \wx0272 +3F 82 FF \wx027A +3F 82 FF \wx027E +3F 82 FF \wx0282 +3F 82 FF \wx028A +3F 82 FF \wx028E +3F 82 FF \wx0292 +3F 82 FF \wx029A +3F 82 FF \wx029E +3F 82 FF \wx02A2 +3F 82 FF \wx02AA +3F 82 FF \wx02AE +3F 82 FF \wx02B2 +3F 82 FF \wx02BA +3F 82 FF \wx02BE +3F 82 FF \wx02C2 +3F 82 FF \wx02CA +3F 82 FF \wx02CE +3F 82 FF \wx02D2 +3F 82 FF \wx02DA +3F 82 FF \wx02DE +3F 82 FF \wx02E2 +3F 82 FF \wx02EA +3F 82 FF \wx02EE +3F 82 FF \wx02F2 +3F 82 FF \wx02FA +3F 82 FF \wx02FE +3F 82 FF \wx0302 +3F 82 FF \wx030D +3F 82 FF \wx0311 +3F 82 FF \wx0315 +3F 82 FF \wx0319 +3F 82 FF \wx031D +3F 82 FF \wx0321 +3F 82 FF \wx0325 +3F 82 FF \wx0329 +3F 82 FF \wx032D +3F 82 FF \wx0331 +3F 82 FF \wx0335 +3F 82 FF \wx0339 +3F 82 FF \wx033D +3F 82 FF \wx0341 +3F 82 FF \wx0345 +3F 82 FF \wx0349 +3F 82 FF \wx034D +3F 82 FF \wx0351 +3F 82 FF \wx0355 +3F 82 FF \wx0359 +3F 82 FF \wx035D +3F 82 FF \wx0361 +3F 82 FF \wx0365 +3F 82 FF \wx0369 +3F 82 FF \wx036D +3F 82 FF \wx0371 +3F 82 FF \wx0375 +3F 82 FF \wx0379 +3F 82 FF \wx037D +3F 82 FF \wx0381 +3F 82 FF \wx0385 +3F 82 FF \wx0389 +FF + +12 * 909 00 06 \b2 01 FF \wx0002 +0D \b0 \b6 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 +0D \b6 \b1 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 + diff --git a/regression/expected/045_bridge_dedup.grf b/regression/expected/045_bridge_dedup.grf new file mode 100644 index 000000000..6dc14f0b8 Binary files /dev/null and b/regression/expected/045_bridge_dedup.grf differ diff --git a/regression/expected/045_bridge_dedup.nfo b/regression/expected/045_bridge_dedup.nfo new file mode 100644 index 000000000..2cfc344a5 --- /dev/null +++ b/regression/expected/045_bridge_dedup.nfo @@ -0,0 +1,239 @@ +// Automatically generated by GRFCODEC. Do not modify! +// (Info version 32) +// Escapes: 2+ 2- 2< 2> 2u< 2u> 2/ 2% 2u/ 2u% 2* 2& 2| 2^ 2sto = 2s 2rst = 2r 2psto 2ror = 2rot 2cmp 2ucmp 2<< 2u>> 2>> +// Escapes: 71 70 7= 7! 7< 7> 7G 7g 7gG 7GG 7gg 7c 7C +// Escapes: D= = DR D+ = DF D- = DC Du* = DM D* = DnF Du<< = DnC D<< = DO D& D| Du/ D/ Du% D% +// Format: spritenum imagefile depth xpos ypos xsize ysize xrel yrel zoom flags + +0 * 4 \d21 + +1 * 54 14 "C" "INFO" +"B" "VRSN" \w4 \dx00000000 +"B" "MINV" \w4 \dx00000000 +"B" "NPAR" \w1 00 +"B" "PALS" \w1 "W" +"B" "BLTR" \w1 "8" +00 +00 +2 * 52 08 08 "NML+" "NML regression test" 00 "A test newgrf testing NML" 00 +3 * 24 00 06 \b6 01 FF \wx0003 +09 00 +0A 0C +13 \wx0028 +0C \wx0040 +0E 00 +0F \dx0000078A + +// param[63] = param[\DR] +4 * 9 0D 3F \D= \DR FE \dx000D08FF + +5 * 7 06 +3F 82 FF \wx0003 +FF + +6 * 5 0A \b1 \b13 \w0 + +7 oneway.png 8bpp 0 0 4 4 -2 0 normal +8 oneway.png 8bpp 0 0 4 4 -3 0 normal +9 oneway.png 8bpp 0 0 4 4 -4 0 normal +10 oneway.png 8bpp 0 0 4 4 -5 0 normal +11 oneway.png 8bpp 0 0 4 4 -6 0 normal +12 oneway.png 8bpp 0 0 4 4 -7 0 normal +13 oneway.png 8bpp 0 0 4 4 -8 0 normal +14 oneway.png 8bpp 0 0 4 4 -9 0 normal +15 oneway.png 8bpp 0 0 4 4 -10 0 normal +16 oneway.png 8bpp 0 0 4 4 -11 0 normal +17 oneway.png 8bpp 0 0 4 4 -12 0 normal +18 oneway.png 8bpp 0 0 4 4 -13 0 normal + +19 oneway.png 8bpp 0 0 4 4 -2 -2 normal +20 * 882 06 +3F 82 FF \wx000A +3F 82 FF \wx000E +3F 82 FF \wx0012 +3F 82 FF \wx001A +3F 82 FF \wx001E +3F 82 FF \wx0022 +3F 82 FF \wx002A +3F 82 FF \wx002E +3F 82 FF \wx0032 +3F 82 FF \wx003A +3F 82 FF \wx003E +3F 82 FF \wx0042 +3F 82 FF \wx004A +3F 82 FF \wx004E +3F 82 FF \wx0052 +3F 82 FF \wx005A +3F 82 FF \wx005E +3F 82 FF \wx0062 +3F 82 FF \wx006A +3F 82 FF \wx006E +3F 82 FF \wx0072 +3F 82 FF \wx007A +3F 82 FF \wx007E +3F 82 FF \wx0082 +3F 82 FF \wx008A +3F 82 FF \wx008E +3F 82 FF \wx0092 +3F 82 FF \wx009A +3F 82 FF \wx009E +3F 82 FF \wx00A2 +3F 82 FF \wx00AA +3F 82 FF \wx00AE +3F 82 FF \wx00B2 +3F 82 FF \wx00BA +3F 82 FF \wx00BE +3F 82 FF \wx00C2 +3F 82 FF \wx00CA +3F 82 FF \wx00CE +3F 82 FF \wx00D2 +3F 82 FF \wx00DA +3F 82 FF \wx00DE +3F 82 FF \wx00E2 +3F 82 FF \wx00EA +3F 82 FF \wx00EE +3F 82 FF \wx00F2 +3F 82 FF \wx00FA +3F 82 FF \wx00FE +3F 82 FF \wx0102 +3F 82 FF \wx010A +3F 82 FF \wx010E +3F 82 FF \wx0112 +3F 82 FF \wx011A +3F 82 FF \wx011E +3F 82 FF \wx0122 +3F 82 FF \wx012A +3F 82 FF \wx012E +3F 82 FF \wx0132 +3F 82 FF \wx013A +3F 82 FF \wx013E +3F 82 FF \wx0142 +3F 82 FF \wx014A +3F 82 FF \wx014E +3F 82 FF \wx0152 +3F 82 FF \wx015A +3F 82 FF \wx015E +3F 82 FF \wx0162 +3F 82 FF \wx016A +3F 82 FF \wx016E +3F 82 FF \wx0172 +3F 82 FF \wx017A +3F 82 FF \wx017E +3F 82 FF \wx0182 +3F 82 FF \wx018A +3F 82 FF \wx018E +3F 82 FF \wx0192 +3F 82 FF \wx019A +3F 82 FF \wx019E +3F 82 FF \wx01A2 +3F 82 FF \wx01AA +3F 82 FF \wx01AE +3F 82 FF \wx01B2 +3F 82 FF \wx01BA +3F 82 FF \wx01BE +3F 82 FF \wx01C2 +3F 82 FF \wx01CA +3F 82 FF \wx01CE +3F 82 FF \wx01D2 +3F 82 FF \wx01DA +3F 82 FF \wx01DE +3F 82 FF \wx01E2 +3F 82 FF \wx01EA +3F 82 FF \wx01EE +3F 82 FF \wx01F2 +3F 82 FF \wx01FA +3F 82 FF \wx01FE +3F 82 FF \wx0202 +3F 82 FF \wx020A +3F 82 FF \wx020E +3F 82 FF \wx0212 +3F 82 FF \wx021A +3F 82 FF \wx021E +3F 82 FF \wx0222 +3F 82 FF \wx022A +3F 82 FF \wx022E +3F 82 FF \wx0232 +3F 82 FF \wx023A +3F 82 FF \wx023E +3F 82 FF \wx0242 +3F 82 FF \wx024A +3F 82 FF \wx024E +3F 82 FF \wx0252 +3F 82 FF \wx025A +3F 82 FF \wx025E +3F 82 FF \wx0262 +3F 82 FF \wx026A +3F 82 FF \wx026E +3F 82 FF \wx0272 +3F 82 FF \wx027A +3F 82 FF \wx027E +3F 82 FF \wx0282 +3F 82 FF \wx028A +3F 82 FF \wx028E +3F 82 FF \wx0292 +3F 82 FF \wx029A +3F 82 FF \wx029E +3F 82 FF \wx02A2 +3F 82 FF \wx02AA +3F 82 FF \wx02AE +3F 82 FF \wx02B2 +3F 82 FF \wx02BA +3F 82 FF \wx02BE +3F 82 FF \wx02C2 +3F 82 FF \wx02CA +3F 82 FF \wx02CE +3F 82 FF \wx02D2 +3F 82 FF \wx02DA +3F 82 FF \wx02DE +3F 82 FF \wx02E2 +3F 82 FF \wx02EA +3F 82 FF \wx02EE +3F 82 FF \wx02F2 +3F 82 FF \wx02FA +3F 82 FF \wx02FE +3F 82 FF \wx0302 +3F 82 FF \wx030D +3F 82 FF \wx0311 +3F 82 FF \wx0315 +3F 82 FF \wx0319 +3F 82 FF \wx031D +3F 82 FF \wx0321 +3F 82 FF \wx0325 +3F 82 FF \wx0329 +3F 82 FF \wx032D +3F 82 FF \wx0331 +3F 82 FF \wx0335 +3F 82 FF \wx0339 +3F 82 FF \wx033D +3F 82 FF \wx0341 +3F 82 FF \wx0345 +3F 82 FF \wx0349 +3F 82 FF \wx034D +3F 82 FF \wx0351 +3F 82 FF \wx0355 +3F 82 FF \wx0359 +3F 82 FF \wx035D +3F 82 FF \wx0361 +3F 82 FF \wx0365 +3F 82 FF \wx0369 +3F 82 FF \wx036D +3F 82 FF \wx0371 +3F 82 FF \wx0375 +3F 82 FF \wx0379 +3F 82 FF \wx037D +3F 82 FF \wx0381 +3F 82 FF \wx0385 +3F 82 FF \wx0389 +FF + +21 * 909 00 06 \b2 01 FF \wx0003 +0D \b0 \b6 +\dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000001 \dx00000001 \dx00000001 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000001 \dx00000001 \dx00000001 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000001 \dx00000001 \dx00000001 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000000 \dx00000001 \dx00000001 \dx00000001 \dx00000000 +\dx00000002 \dx00000002 \dx00000002 \dx00000000 \dx00000003 \dx00000003 \dx00000003 \dx00000000 \dx00000002 \dx00000002 \dx00000002 \dx00000000 \dx00000003 \dx00000003 \dx00000003 \dx00000000 \dx00000002 \dx00000002 \dx00000002 \dx00000000 \dx00000003 \dx00000003 \dx00000003 \dx00000000 \dx00000002 \dx00000002 \dx00000002 \dx00000000 \dx00000003 \dx00000003 \dx00000003 \dx00000000 +\dx00000004 \dx00000004 \dx00000004 \dx00000000 \dx00000005 \dx00000005 \dx00000005 \dx00000000 \dx00000004 \dx00000004 \dx00000004 \dx00000000 \dx00000005 \dx00000005 \dx00000005 \dx00000000 \dx00000004 \dx00000004 \dx00000004 \dx00000000 \dx00000005 \dx00000005 \dx00000005 \dx00000000 \dx00000004 \dx00000004 \dx00000004 \dx00000000 \dx00000005 \dx00000005 \dx00000005 \dx00000000 +\dx00000006 \dx00000006 \dx00000006 \dx00000000 \dx00000007 \dx00000007 \dx00000007 \dx00000000 \dx00000006 \dx00000006 \dx00000006 \dx00000000 \dx00000007 \dx00000007 \dx00000007 \dx00000000 \dx00000006 \dx00000006 \dx00000006 \dx00000000 \dx00000007 \dx00000007 \dx00000007 \dx00000000 \dx00000006 \dx00000006 \dx00000006 \dx00000000 \dx00000007 \dx00000007 \dx00000007 \dx00000000 +\dx00000008 \dx00000008 \dx00000008 \dx00000000 \dx00000009 \dx00000009 \dx00000009 \dx00000000 \dx00000008 \dx00000008 \dx00000008 \dx00000000 \dx00000009 \dx00000009 \dx00000009 \dx00000000 \dx00000008 \dx00000008 \dx00000008 \dx00000000 \dx00000009 \dx00000009 \dx00000009 \dx00000000 \dx00000008 \dx00000008 \dx00000008 \dx00000000 \dx00000009 \dx00000009 \dx00000009 \dx00000000 +\dx0000000A \dx0000000A \dx0000000A \dx00000000 \dx0000000B \dx0000000B \dx0000000B \dx00000000 \dx0000000A \dx0000000A \dx0000000A \dx00000000 \dx0000000B \dx0000000B \dx0000000B \dx00000000 \dx0000000A \dx0000000A \dx0000000A \dx00000000 \dx0000000B \dx0000000B \dx0000000B \dx00000000 \dx0000000A \dx0000000A \dx0000000A \dx00000000 \dx0000000B \dx0000000B \dx0000000B \dx00000000 +0D \b6 \b1 +\dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C \dx0000000C + diff --git a/regression/expected/example_bridge.grf b/regression/expected/example_bridge.grf new file mode 100644 index 000000000..ca0615296 Binary files /dev/null and b/regression/expected/example_bridge.grf differ diff --git a/regression/expected/example_bridge.nfo b/regression/expected/example_bridge.nfo new file mode 100644 index 000000000..71d85a22d --- /dev/null +++ b/regression/expected/example_bridge.nfo @@ -0,0 +1,229 @@ +// Automatically generated by GRFCODEC. Do not modify! +// (Info version 32) +// Escapes: 2+ 2- 2< 2> 2u< 2u> 2/ 2% 2u/ 2u% 2* 2& 2| 2^ 2sto = 2s 2rst = 2r 2psto 2ror = 2rot 2cmp 2ucmp 2<< 2u>> 2>> +// Escapes: 71 70 7= 7! 7< 7> 7G 7g 7gG 7GG 7gg 7c 7C +// Escapes: D= = DR D+ = DF D- = DC Du* = DM D* = DnF Du<< = DnC D<< = DO D& D| Du/ D/ Du% D% +// Format: spritenum imagefile depth xpos ypos xsize ysize xrel yrel zoom flags + +0 * 4 \d35 + +1 * 54 14 "C" "INFO" +"B" "VRSN" \w4 \dx00000001 +"B" "MINV" \w4 \dx00000001 +"B" "NPAR" \w1 00 +"B" "PALS" \w1 "D" +"B" "BLTR" \w1 "8" +00 +00 +2 * 313 08 08 "NML\07" "NML Example NewGRF: Bridge" 00 "\8ENML Example NewGRF: Bridge\0D\98This NewGRF is intended to provide a coding example for the high-level NewGRF-coding language NML.\0DIt demonstrates how to define a custom bridge using FEAT_BRIDGES with sprite templates, 6-table duplication for bridge_parts, and 4x zoom alternatives." 00 +3 * 76 04 06 FF 03 \wxDC00 "Cable-Stayed Bridge" 00 "Cable-Stayed Road Bridge" 00 "Cable-Stayed Rail Bridge" 00 + +4 * 47 00 06 \b10 01 FF \wx0000 +09 00 +0A FF +13 \wx00E0 +0C \wx012B +0E 01 +0F \dx000007B2 +10 \wxDC00 +12 \wxDC01 +11 \wxDC02 +15 06 00 00 00 00 00 00 0C 03 +00 00 0C 03 + +// param[63] = param[\DR] +5 * 9 0D 3F \D= \DR FE \dx001A08FF + +6 * 7 06 +3F 82 FF \wx0003 +FF + +7 * 5 0A \b1 \b26 \w0 + +8 gfx/cable.png 8bpp 1 66 64 128 -31 -84 normal +9 gfx/cable.png 8bpp 66 66 64 128 -31 -84 normal +10 gfx/cable.png 8bpp 261 66 64 128 -31 -84 normal +11 gfx/cable.png 8bpp 326 66 64 128 -31 -84 normal +12 gfx/cable.png 8bpp 391 66 64 128 -31 -84 normal +13 gfx/cable.png 8bpp 456 66 64 128 -31 -84 normal +14 gfx/cable.png 8bpp 651 66 64 128 -31 -84 normal +15 gfx/cable.png 8bpp 716 66 64 128 -31 -84 normal + +16 gfx/cable.png 8bpp 1 195 64 128 -55 -96 normal +17 gfx/cable.png 8bpp 66 195 64 128 -7 -96 normal +18 gfx/cable.png 8bpp 261 195 64 128 -55 -96 normal +19 gfx/cable.png 8bpp 326 195 64 128 -7 -96 normal +20 gfx/cable.png 8bpp 391 195 64 128 -55 -96 normal +21 gfx/cable.png 8bpp 456 195 64 128 -7 -96 normal +22 gfx/cable.png 8bpp 651 195 64 128 -55 -96 normal +23 gfx/cable.png 8bpp 716 195 64 128 -7 -96 normal + +24 gfx/cable.png 8bpp 391 324 64 128 -55 -96 normal +25 gfx/cable.png 8bpp 456 324 64 128 -7 -96 normal +26 gfx/cable.png 8bpp 1 1 64 64 -31 -24 normal +27 gfx/cable.png 8bpp 66 1 64 64 -31 -24 normal +28 gfx/cable.png 8bpp 131 1 64 64 -31 -24 normal +29 gfx/cable.png 8bpp 196 1 64 64 -31 -24 normal +30 gfx/cable.png 8bpp 261 1 64 64 -31 -24 normal +31 gfx/cable.png 8bpp 326 1 64 64 -31 -24 normal +32 gfx/cable.png 8bpp 391 1 64 64 -31 -24 normal +33 gfx/cable.png 8bpp 456 1 64 64 -31 -24 normal + +34 * 722 06 +3F 82 FF \wx000A +3F 82 FF \wx000E +3F 82 FF \wx001A +3F 82 FF \wx001E +3F 82 FF \wx002A +3F 82 FF \wx002E +3F 82 FF \wx003A +3F 82 FF \wx003E +3F 82 FF \wx004A +3F 82 FF \wx004E +3F 82 FF \wx005A +3F 82 FF \wx005E +3F 82 FF \wx006A +3F 82 FF \wx006E +3F 82 FF \wx007A +3F 82 FF \wx007E +3F 82 FF \wx008A +3F 82 FF \wx008E +3F 82 FF \wx009A +3F 82 FF \wx009E +3F 82 FF \wx00AA +3F 82 FF \wx00AE +3F 82 FF \wx00BA +3F 82 FF \wx00BE +3F 82 FF \wx00CA +3F 82 FF \wx00CE +3F 82 FF \wx00DA +3F 82 FF \wx00DE +3F 82 FF \wx00EA +3F 82 FF \wx00EE +3F 82 FF \wx00FA +3F 82 FF \wx00FE +3F 82 FF \wx010A +3F 82 FF \wx010E +3F 82 FF \wx011A +3F 82 FF \wx011E +3F 82 FF \wx012A +3F 82 FF \wx012E +3F 82 FF \wx013A +3F 82 FF \wx013E +3F 82 FF \wx014A +3F 82 FF \wx014E +3F 82 FF \wx015A +3F 82 FF \wx015E +3F 82 FF \wx016A +3F 82 FF \wx016E +3F 82 FF \wx017A +3F 82 FF \wx017E +3F 82 FF \wx018A +3F 82 FF \wx018E +3F 82 FF \wx0192 +3F 82 FF \wx019A +3F 82 FF \wx019E +3F 82 FF \wx01A2 +3F 82 FF \wx01AA +3F 82 FF \wx01AE +3F 82 FF \wx01B2 +3F 82 FF \wx01BA +3F 82 FF \wx01BE +3F 82 FF \wx01C2 +3F 82 FF \wx01CA +3F 82 FF \wx01CE +3F 82 FF \wx01D2 +3F 82 FF \wx01DA +3F 82 FF \wx01DE +3F 82 FF \wx01E2 +3F 82 FF \wx01EA +3F 82 FF \wx01EE +3F 82 FF \wx01F2 +3F 82 FF \wx01FA +3F 82 FF \wx01FE +3F 82 FF \wx0202 +3F 82 FF \wx020A +3F 82 FF \wx020E +3F 82 FF \wx021A +3F 82 FF \wx021E +3F 82 FF \wx022A +3F 82 FF \wx022E +3F 82 FF \wx023A +3F 82 FF \wx023E +3F 82 FF \wx024A +3F 82 FF \wx024E +3F 82 FF \wx025A +3F 82 FF \wx025E +3F 82 FF \wx026A +3F 82 FF \wx026E +3F 82 FF \wx027A +3F 82 FF \wx027E +3F 82 FF \wx028A +3F 82 FF \wx028E +3F 82 FF \wx0292 +3F 82 FF \wx029A +3F 82 FF \wx029E +3F 82 FF \wx02A2 +3F 82 FF \wx02AA +3F 82 FF \wx02AE +3F 82 FF \wx02B2 +3F 82 FF \wx02BA +3F 82 FF \wx02BE +3F 82 FF \wx02C2 +3F 82 FF \wx02CA +3F 82 FF \wx02CE +3F 82 FF \wx02D2 +3F 82 FF \wx02DA +3F 82 FF \wx02DE +3F 82 FF \wx02E2 +3F 82 FF \wx02EA +3F 82 FF \wx02EE +3F 82 FF \wx02F2 +3F 82 FF \wx02FA +3F 82 FF \wx02FE +3F 82 FF \wx0302 +3F 82 FF \wx030D +3F 82 FF \wx0311 +3F 82 FF \wx0315 +3F 82 FF \wx0319 +3F 82 FF \wx031D +3F 82 FF \wx0321 +3F 82 FF \wx0325 +3F 82 FF \wx0329 +3F 82 FF \wx032D +3F 82 FF \wx0331 +3F 82 FF \wx0335 +3F 82 FF \wx0339 +3F 82 FF \wx033D +3F 82 FF \wx0341 +3F 82 FF \wx0345 +3F 82 FF \wx0349 +3F 82 FF \wx034D +3F 82 FF \wx0351 +3F 82 FF \wx0355 +3F 82 FF \wx0359 +3F 82 FF \wx035D +3F 82 FF \wx0361 +3F 82 FF \wx0365 +3F 82 FF \wx0369 +3F 82 FF \wx036D +3F 82 FF \wx0371 +3F 82 FF \wx0375 +3F 82 FF \wx0379 +3F 82 FF \wx037D +3F 82 FF \wx0381 +3F 82 FF \wx0385 +3F 82 FF \wx0389 +FF + +35 * 909 00 06 \b2 01 FF \wx0000 +0D \b0 \b6 +\dx00000000 \dx00000008 \dx00000000 \dx00000000 \dx00000001 \dx00000009 \dx00000000 \dx00000000 \dx00000000 \dx00000008 \dx00000000 \dx00000000 \dx00000001 \dx00000009 \dx00000000 \dx00000000 \dx00000000 \dx00000008 \dx00000000 \dx00000000 \dx00000001 \dx00000009 \dx00000000 \dx00000000 \dx00000000 \dx00000008 \dx00000000 \dx00000000 \dx00000001 \dx00000009 \dx00000000 \dx00000000 +\dx00000000 \dx00000008 \dx00000000 \dx00000000 \dx00000001 \dx00000009 \dx00000000 \dx00000000 \dx00000000 \dx00000008 \dx00000000 \dx00000000 \dx00000001 \dx00000009 \dx00000000 \dx00000000 \dx00000000 \dx00000008 \dx00000000 \dx00000000 \dx00000001 \dx00000009 \dx00000000 \dx00000000 \dx00000000 \dx00000008 \dx00000000 \dx00000000 \dx00000001 \dx00000009 \dx00000000 \dx00000000 +\dx00000002 \dx0000000A \dx00000000 \dx00000000 \dx00000003 \dx0000000B \dx00000000 \dx00000000 \dx00000002 \dx0000000A \dx00000000 \dx00000000 \dx00000003 \dx0000000B \dx00000000 \dx00000000 \dx00000002 \dx0000000A \dx00000000 \dx00000000 \dx00000003 \dx0000000B \dx00000000 \dx00000000 \dx00000002 \dx0000000A \dx00000000 \dx00000000 \dx00000003 \dx0000000B \dx00000000 \dx00000000 +\dx00000004 \dx0000000C \dx00000010 \dx00000000 \dx00000005 \dx0000000D \dx00000011 \dx00000000 \dx00000004 \dx0000000C \dx00000010 \dx00000000 \dx00000005 \dx0000000D \dx00000011 \dx00000000 \dx00000004 \dx0000000C \dx00000010 \dx00000000 \dx00000005 \dx0000000D \dx00000011 \dx00000000 \dx00000004 \dx0000000C \dx00000010 \dx00000000 \dx00000005 \dx0000000D \dx00000011 \dx00000000 +\dx00000000 \dx00000008 \dx00000000 \dx00000000 \dx00000001 \dx00000009 \dx00000000 \dx00000000 \dx00000000 \dx00000008 \dx00000000 \dx00000000 \dx00000001 \dx00000009 \dx00000000 \dx00000000 \dx00000000 \dx00000008 \dx00000000 \dx00000000 \dx00000001 \dx00000009 \dx00000000 \dx00000000 \dx00000000 \dx00000008 \dx00000000 \dx00000000 \dx00000001 \dx00000009 \dx00000000 \dx00000000 +\dx00000006 \dx0000000E \dx00000010 \dx00000000 \dx00000007 \dx0000000F \dx00000011 \dx00000000 \dx00000006 \dx0000000E \dx00000010 \dx00000000 \dx00000007 \dx0000000F \dx00000011 \dx00000000 \dx00000006 \dx0000000E \dx00000010 \dx00000000 \dx00000007 \dx0000000F \dx00000011 \dx00000000 \dx00000006 \dx0000000E \dx00000010 \dx00000000 \dx00000007 \dx0000000F \dx00000011 \dx00000000 +0D \b6 \b1 +\dx00000012 \dx00000013 \dx00000014 \dx00000015 \dx00000016 \dx00000017 \dx00000018 \dx00000019 \dx00000012 \dx00000013 \dx00000014 \dx00000015 \dx00000016 \dx00000017 \dx00000018 \dx00000019 \dx00000012 \dx00000013 \dx00000014 \dx00000015 \dx00000016 \dx00000017 \dx00000018 \dx00000019 \dx00000012 \dx00000013 \dx00000014 \dx00000015 \dx00000016 \dx00000017 \dx00000018 \dx00000019 + diff --git a/tmp/043_bridge.grf b/tmp/043_bridge.grf new file mode 100644 index 000000000..c613f3da4 Binary files /dev/null and b/tmp/043_bridge.grf differ