"""Generate the first-pass NWN tileset definition `twu01.set` from tiles.py. python make_set.py [out.set] # default: twu01.set Pure Python, no Blender. Emits a valid, DOS/CRLF `.set` (AGENTS.md §4/§9: Unix line endings crash the toolset). Corners/heights/crossers derive from each tile's edge grammar; this is a DRAFT to load and hand-tune in the toolset, not a final set. See CAVEATS below. CAVEATS (first pass — tune in the toolset): * PathNode is a placeholder ('A' walkable / 'N' non-walkable). Real pathnode letters govern creature routing and must be verified against the toolset. * ImageMap2D references minimaps (twu01_.tga) that are not rendered yet. * Groups/features Count=0; add multi-tile groups later. """ import sys import tiles PREFIX = tiles.PREFIX def tile_block(i, spec): cor = tiles.nwn_corners(spec["edges"]) n, e, s, w = spec["edges"] tl, tr, bl, br = cor["TopLeft"], cor["TopRight"], cor["BottomLeft"], cor["BottomRight"] ref = tiles.resref(spec) walkable = spec["kind"] != "canal" # Field order/values mirror the stock BioWare sets (the toolset's .set reader # is picky); WalkMesh=msb01 is the universal legacy label, not a file. L = [f"[TILE{i}]"] L += [ f"Model={ref}", "WalkMesh=msb01", f"TopLeft={tl[0]}", f"TopLeftHeight={tl[1]}", f"TopRight={tr[0]}", f"TopRightHeight={tr[1]}", f"BottomLeft={bl[0]}", f"BottomLeftHeight={bl[1]}", f"BottomRight={br[0]}", f"BottomRightHeight={br[1]}", f"Top={tiles.nwn_crosser(n)}", f"Right={tiles.nwn_crosser(e)}", f"Bottom={tiles.nwn_crosser(s)}", f"Left={tiles.nwn_crosser(w)}", "MainLight1=1", "MainLight2=1", "SourceLight1=1", "SourceLight2=1", "AnimLoop1=1", "AnimLoop2=1", "AnimLoop3=1", "Doors=0", "Sounds=0", f"PathNode={'A' if walkable else 'N'}", # placeholder — verify in toolset "Orientation=0", "VisibilityNode=A", "VisibilityOrientation=0", f"ImageMap2D={ref}", # minimap resref (no .tga yet; blank in toolset) ] return L def build(): L = [] L += [ "[GENERAL]", f"Name={PREFIX}", "Type=SET", "Interior=0", "HasHeightTransition=1", "Transition=1.5", # metres per height step = Z=1.5 raised tier "Border=cobble", "Default=cobble", "Floor=cobble", "DisplayName=-1", "UnlocalizedName=Westgate Urban Foundation", "Version=V1.0", "EnvMap=", "SelectorHeight=3", "", "[GRASS]", "Grass=0", "GrassTextureName=", "Density=0.0", "Height=0.0", "AmbientRed=0.0", "AmbientGreen=0.0", "AmbientBlue=0.0", "DiffuseRed=0.0", "DiffuseGreen=0.0", "DiffuseBlue=0.0", "", "[TERRAIN TYPES]", f"Count={len(tiles.TERRAINS)}", ] for idx, t in enumerate(tiles.TERRAINS): L += ["", f"[TERRAIN{idx}]", f"Name={t}", "StrRef=-1"] L += ["", "[CROSSER TYPES]", f"Count={len(tiles.CROSSERS)}"] for idx, cr in enumerate(tiles.CROSSERS): L += ["", f"[CROSSER{idx}]", f"Name={cr}", "StrRef=-1"] L += ["", "[PRIMARY RULES]", "Count=0", "", "[SECONDARY RULES]", "Count=0", "", "[TILES]", f"Count={len(tiles.TILES)}"] for i, spec in enumerate(tiles.TILES): L.append("") L += tile_block(i, spec) L += ["", "[GROUPS]", "Count=0", ""] return L def main(): out = sys.argv[1] if len(sys.argv) > 1 else f"{PREFIX}.set" with open(out, "w", newline="") as fh: # newline='' + explicit \r\n = CRLF fh.write("\r\n".join(build())) print(f"wrote {out} ({len(tiles.TILES)} tiles, " f"{len(tiles.TERRAINS)} terrains, {len(tiles.CROSSERS)} crossers, CRLF)") if __name__ == "__main__": main()