def write_gas(self) -> Gas: node_sections = [Section('t:snode,n:' + snode.guid.to_str_lower(), [ Attribute('bounds_camera', snode.bounds_camera), Attribute('camera_fade', snode.camera_fade), Attribute('guid', snode.guid), Attribute('mesh_guid', Hex(snode.mesh_guid)), Attribute('nodelevel', snode.nodelevel), Attribute('nodeobject', snode.nodeobject), Attribute('nodesection', snode.nodesection), Attribute('occludes_camera', snode.occludes_camera), Attribute('occludes_light', snode.occludes_light), Attribute('texsetabbr', snode.texsetabbr), ] + [Section('door*', [ Attribute('fardoor', door.fardoor), Attribute('farguid', door.farguid), Attribute('id', door.id), ]) for door in snode.doors]) for snode in self.nodes] return Gas([ Section('t:terrain_nodes,n:siege_node_list', [ Attribute('ambient_color', Hex(self.ambient_color)), Attribute('ambient_intensity', float(self.ambient_intensity)), Attribute('object_ambient_color', Hex(self.object_ambient_color)), Attribute('object_ambient_intensity', float(self.object_ambient_intensity)), Attribute('actor_ambient_color', Hex(self.actor_ambient_color)), Attribute('actor_ambient_intensity', float(self.actor_ambient_intensity)), Attribute('targetnode', self.targetnode) ] + node_sections) ])
def to_gas(self) -> Gas: map_section = Section('t:map,n:map', [ Attribute('name', self.name), Attribute('screen_name', self.screen_name), Attribute('description', self.description), Attribute('dev_only', self.dev_only), Attribute('timeofday', self.timeofday), Attribute('use_node_mesh_index', self.use_node_mesh_index), Attribute('use_player_journal', self.use_player_journal), Section('camera', [ Attribute('azimuth', self.camera.azimuth), Attribute('distance', self.camera.distance), Attribute('position', self.camera.position) ]) ]) if self.worlds is not None: world_sections: list[Section] = [] for name, world in self.worlds.items(): world_sections.append(Section(name, [ Attribute('screen_name', world.screen_name), Attribute('description', world.description), Attribute('required_level', str(world.required_level)) ])) map_section.items.append(Section('worlds', world_sections)) map_main_gas = Gas([map_section]) return map_main_gas
def store_start_positions(self): assert self.start_positions is not None info_dir = self.gas_dir.get_or_create_subdir('info') start_group_sections = [] gas_file = info_dir.get_or_create_gas_file('start_positions') gas_file.gas = Gas([ Section('start_positions', start_group_sections) ]) for sg_name, sg in self.start_positions.start_groups.items(): sp_sections: list = [ Section('start_position', [ Attribute('id', sp.id), Attribute('position', str(sp.position)), Section('camera', [ Attribute('azimuth', float(sp.camera.azimuth)), Attribute('distance', float(sp.camera.distance)), Attribute('orbit', float(sp.camera.orbit)), Attribute('position', str(sp.camera.position)) ]) ]) for sp in sg.start_positions ] start_group_sections.append(Section('t:start_group,n:' + sg_name, [ Attribute('default', self.start_positions.default == sg_name), Attribute('description', sg.description), Attribute('dev_only', sg.dev_only), Attribute('id', sg.id), Attribute('screen_name', sg.screen_name) ] + sp_sections))
def store_terrain(self): # index mesh_index = self.terrain.get_mesh_index() mesh_index = { Hex.parse('0x{:03X}{:05X}'.format(self.data.mesh_range, mesh_guid)): mesh_name for mesh_guid, mesh_name in mesh_index.items() } self.gas_dir.create_subdir( 'index', { 'node_mesh_index': Gas([ Section('node_mesh_index', [ Attribute(str(mesh_guid), mesh_name) for mesh_guid, mesh_name in mesh_index.items() ]) ]), 'streamer_node_index': Gas([ Section('streamer_node_index', [ Attribute('*', node.guid) for node in self.terrain.nodes ]) ]) }) # terrain_nodes nodes_gas = NodesGas() nodes_gas.ambient_color = self.terrain.ambient_light.terrain_color nodes_gas.ambient_intensity = self.terrain.ambient_light.terrain_intensity nodes_gas.object_ambient_color = self.terrain.ambient_light.object_color nodes_gas.object_ambient_intensity = self.terrain.ambient_light.object_intensity nodes_gas.actor_ambient_color = self.terrain.ambient_light.actor_color nodes_gas.actor_ambient_intensity = self.terrain.ambient_light.actor_intensity nodes_gas.targetnode = self.terrain.target_node.guid snodes = list() for node in self.terrain.nodes: mesh_guid = Terrain.mesh_index_lookup[node.mesh_name] mesh_guid = Hex.parse('0x{:03X}{:05X}'.format( self.data.mesh_range, mesh_guid)) doors = [ Door(door_id, far_node.guid, far_door) for door_id, (far_node, far_door) in node.doors.items() ] nodesection = Hex( node.section if node.section != -1 else 0xffffffff) nodelevel = Hex(node.section if node.section != -1 else 0xffffffff) nodeobject = Hex( node.section if node.section != -1 else 0xffffffff) snode = SNode(node.guid, mesh_guid, node.texture_set, True, False, False, True, nodesection, nodelevel, nodeobject, doors) snodes.append(snode) nodes_gas.nodes = snodes self.gas_dir.create_subdir('terrain_nodes', {'nodes': nodes_gas.write_gas()})
def make_gas(self) -> Section: items = [] if self.dev_instance_text is not None: items.append(Attribute('dev_instance_text', self.dev_instance_text)) if self.instance_triggers is not None: items.append( Section('instance_triggers', [ti.make_gas() for ti in self.instance_triggers])) return Section('common', items)
def ensure_north_vector(self): editor_subdir = self.gas_dir.get_or_create_subdir('editor') if not editor_subdir.has_gas_file('hotpoints'): hotpoints_gas = Gas([ Section('hotpoints', [ Section('t:hotpoint_directional,n:' + str(Hex(1)), [ Attribute('direction', '0,0,-1'), Attribute('id', Hex(1)) ]) ]) ]) editor_subdir.create_gas_file('hotpoints', hotpoints_gas)
def make_gas(self) -> Section: attrs = [] if self.orientation is not None: attrs.append(Attribute('orientation', self.orientation)) if self.position is not None: attrs.append(Attribute('position', self.position)) return Section('placement', attrs)
def to_gas_section(self, is_pos): return Section('position' if is_pos else 'direction', [ Attribute('node', self.node_guid), Attribute('x', self.x), Attribute('y', self.y), Attribute('z', self.z), ])
def write_gas(self) -> Gas: se_sections = [ Section(f't:stitch_editor,n:{se.dest_region}', [ Attribute('dest_region', se.dest_region), Section('node_ids', [ Attribute( Hex(stitch_id).to_str_lower(), f'{node_guid},{door}') for stitch_id, (node_guid, door) in se.node_ids.items() ]) ]) for se in self.stitch_editors ] return Gas([ Section('stitch_helper_data', [ Attribute('source_region_guid', Hex(self.source_region_guid)), Attribute('source_region_name', self.source_region_name), ] + se_sections) ])
def load_templates_rec(self, section: Section): if section.header.lower().startswith('t:template,'): template = Template(section) assert template.name.lower( ) not in self.templates, 'duplicate template name' self.templates[template.name.lower()] = template for subsection in section.get_sections(): self.load_templates_rec(subsection)
def make_gas(self) -> Section: sections = [] if self.aspect is not None: sections.append(self.aspect.make_gas()) if self.common is not None: sections.append(self.common.make_gas()) if self.placement is not None: sections.append(self.placement.make_gas()) return Section(f't:{self.template_name},n:{self.scid}', sections)
def from_gas(cls, decal_section: Section) -> Decal: assert decal_section.header == 't:decal,n:*' guid = decal_section.get_attr_value('guid') texture = decal_section.get_attr_value('texture') near_plane = decal_section.get_attr_value('near_plane') far_plane = decal_section.get_attr_value('far_plane') vertical_meters = decal_section.get_attr_value('vertical_meters') horizontal_meters = decal_section.get_attr_value('horizontal_meters') decal_origin = Position.parse( decal_section.get_attr_value('decal_origin')) decal_orientation = [ float(x) for x in decal_section.get_attr_value( 'decal_orientation').split(',') ] lod = decal_section.get_attr_value('lod') return Decal(guid, texture, near_plane, far_plane, vertical_meters, horizontal_meters, decal_origin, decal_orientation, lod)
def to_gas(self) -> Section: return Section('t:decal,n:*', [ Attribute('decal_orientation', ','.join( [str(x) for x in self.decal_orientation])), Attribute('decal_origin', str(self.decal_origin)), Attribute('far_plane', self.far_plane), Attribute('guid', self.guid), Attribute('horizontal_meters', self.horizontal_meters), Attribute('lod', self.lod), Attribute('near_plane', self.near_plane), Attribute('texture', self.texture), Attribute('vertical_meters', self.vertical_meters) ])
def load_profiles(cls, parent_section: Section, name) -> SingleProfile | ProfileVariants | None: profiles_section = parent_section.get_section(name) if profiles_section is None: return None profile_attr = profiles_section.get_attr('profile') if profile_attr is not None: profile_name = profile_attr.value return SingleProfile(profile_name) perlin_name = profiles_section.get_attr_value('perlin').strip() tx = profiles_section.get_attr_value('tx').strip() variant_a = cls.load_profiles(profiles_section, 'a') variant_b = cls.load_profiles(profiles_section, 'b') return ProfileVariants(variant_a, variant_b, perlin_name, tx)
def __init__(self, section: Section): self.section = section [t, n] = section.header.split(',') assert t.startswith('t:') assert n.startswith('n:') gas_obj_type = t[2:] assert gas_obj_type.lower() == 'template' self.name: str = n[2:] specializes = None specializes_attr = section.get_attr('specializes') if specializes_attr is not None: specializes = specializes_attr.value if specializes.startswith('"') and specializes.endswith('"'): specializes = specializes[1:-1] self.specializes: str = specializes self.parent_template = None self.child_templates = []
def store_lights(self): # Note: storing directional / point / spot lights; ambient light is part of terrain. # prepare if self.terrain is not None: target_node = self.terrain.target_node for light in self.lights: if isinstance(light, DirectionalLight): if light.direction.node_guid is None: light.direction.node_guid = target_node.guid # store lights_dir = self.gas_dir.get_or_create_subdir('lights', False) lights_dir.get_or_create_gas_file('lights').gas = Gas([ Section('lights', [light.to_gas_section() for light in self.lights]) ])
def _to_gas_section(self, type_name, direction: PosDir = None, position: PosDir = None) -> Section: section = Section(f't:{type_name},n:light_{self.id.to_str_lower()}', [ Attribute('active', self.active), Attribute('affects_actors', self.affects_actors), Attribute('affects_items', self.affects_items), Attribute('affects_terrain', self.affects_terrain), Attribute('color', self.color), Attribute('draw_shadow', self.draw_shadow), Attribute('inner_radius', float(self.inner_radius)), Attribute('intensity', float(self.intensity)), Attribute('occlude_geometry', self.occlude_geometry), Attribute('on_timer', self.on_timer), Attribute('outer_radius', float(self.outer_radius)) ]) if direction is not None: section.items.append(direction.to_gas_section(False)) if position is not None: section.items.append(position.to_gas_section(True)) return section
def convert_region(region: Region, nmg: NodeMeshGuids): index_dir = region.gas_dir.get_subdir('index') if index_dir.has_gas_file('node_mesh_index'): return nodes_file = region.gas_dir.get_subdir('terrain_nodes').get_gas_file( 'nodes') node_gas = nodes_file.get_gas() nodes_section: Section = node_gas.items[0] node_sections = nodes_section.get_sections() mesh_guid_attrs = [ns.get_attr('mesh_guid') for ns in node_sections] node_mesh_index = {} node_mesh_guids = nmg.get_node_mesh_guids() for mesh_guid_attr in mesh_guid_attrs: mesh_guid = mesh_guid_attr.value.to_str_lower() assert mesh_guid in node_mesh_guids, str( mesh_guid) + ' is not in ' + str(node_mesh_guids) if mesh_guid not in node_mesh_index: node_mesh_index[mesh_guid] = Hex(len(node_mesh_index) + 1) mesh_id = node_mesh_index[mesh_guid] mesh_guid_attr.value = mesh_id nodes_file.save() node_mesh_index_attrs = [ Attribute(mesh_id, node_mesh_guids[mesh_guid]) for mesh_guid, mesh_id in node_mesh_index.items() ] index_dir.create_gas_file( 'node_mesh_index', Gas([Section('node_mesh_index', node_mesh_index_attrs)])).save() region_data = region.get_data() if region_data.mesh_range == 0: if 0 < region_data.scid_range < Hex.parse('0x00001000'): region_data.mesh_range = region_data.scid_range elif 0 < region_data.id < Hex.parse('0x00001000'): region_data.mesh_range = region_data.id if region_data.mesh_range != 0: region.save() print(f'Converted region {region.get_name()} to NMI')
def from_gas_section(cls, section: Section): assert section.has_t_n_header() type_name, n = section.get_t_n_header() assert type_name in ['point', 'spot', 'directional'] assert n.startswith('light_') light: Light = PointLight() if type_name == 'point' else SpotLight( ) if type_name == 'spot' else DirectionalLight() light.id = Hex.parse(n[6:]) light.active = section.get_attr_value('active') light.affects_actors = section.get_attr_value('affects_actors') light.affects_items = section.get_attr_value('affects_items') light.affects_terrain = section.get_attr_value('affects_terrain') light.color = Color(section.get_attr_value('color')) light.draw_shadow = section.get_attr_value('draw_shadow') light.inner_radius = section.get_attr_value('inner_radius') light.intensity = section.get_attr_value('intensity') light.occlude_geometry = section.get_attr_value('occlude_geometry') light.on_timer = section.get_attr_value('on_timer') light.outer_radius = section.get_attr_value('outer_radius') if type_name in ['point', 'spot']: light.position = PosDir.from_gas_section( section.get_section('position')) if type_name in ['directional', 'spot']: light.direction = PosDir.from_gas_section( section.get_section('direction')) return light
def make_gas(self) -> Section: attrs = [] if self.scale_multiplier is not None: attrs.append(Attribute('scale_multiplier', self.scale_multiplier)) return Section('aspect', attrs)
def make_gas(self) -> Section: return Section('*', [ Attribute('condition*', self.condition), Attribute('action*', self.action) ])
def load_gas(cls, section: Section) -> ProgressionStep: plants_profile = cls.load_profiles(section, 'plants') enemies_profile = cls.load_profiles(section, 'enemies') node_set = section.get_attr_value('node_set') return ProgressionStep(plants_profile, enemies_profile, node_set)
def from_gas_section(cls, section: Section): x = section.get_attr_value('x') y = section.get_attr_value('y') z = section.get_attr_value('z') node = section.get_attr_value('node') return PosDir(x, y, z, node)
def write_gas(self) -> Gas: return Gas( [Section('decals', [decal.to_gas() for decal in self.decals])])