tool extends Node2D class_name GameMap var debug_areas := false var ship_direction := 0 var ship_speed := 0 var current_ship_position := Vector2.ZERO var current_ship_subpos := Vector2.ZERO var current_ship_target = Vector2.ZERO var current_ship_direction := 0.0 var current_ship_speed := 0.0 var deepspace_mat: ShaderMaterial = null var warp_state := false puppet var pup_ship_position := Vector2.ZERO puppet var pup_ship_subpos := Vector2.ZERO puppet var pup_ship_target := Vector2.ZERO puppet var pup_ship_direction := 0.0 puppet var pup_ship_speed := 0.0 const MAX_ACCELERATION := 0.03 const MAX_STEERING := 0.06 const EPSILON := 1e-3 const SCROLL_MULTIPLIER := 1e4 const ENGINE_MULTIPLIER := 5000 const NO_SPEED_THRESHOLD := 0.01 const ProbeElectricity := preload("res://Actors/Systems/Electricity/ElectricProbe.tscn") onready var tilemaps := [ $tiles/base, $tiles/cables, $tiles/floor, $tiles/walls ] onready var pois := $pois export var unlit := false setget set_unlit onready var darkness := $darkness export var shadow_intensity := 0.2 func _ready(): if Engine.editor_hint: return set_unlit(true) if not is_network_master(): return # Run autotile conversions and generate occlusions $tiles/walls.run_conversions() # Electricity setup make_electric_probes($tiles/cables, "Wire") # Set engines to expected power level set_engine_strength(current_ship_speed) deepspace_mat = $deepspace.material as ShaderMaterial func _process(delta: float): if Engine.editor_hint: return var engines := get_engine_count() var max_speed := get_max_speed() # Ease ship speed/direction changes if abs(current_ship_direction) > PI*2: current_ship_direction -= PI*2 * sign(current_ship_direction) var direction_delta := ship_direction - current_ship_direction if direction_delta < 0: direction_delta += PI*2 if direction_delta > PI: direction_delta -= PI*2 if abs(direction_delta) < 1e-3: current_ship_direction = ship_direction else: # Avoid stuttering by not turning until there's enough reason to if abs(direction_delta) > 0.1: current_ship_direction += MAX_STEERING * engines * delta * sign(direction_delta) var speed_delta := ship_speed - current_ship_speed if abs(speed_delta) < EPSILON: current_ship_speed = ship_speed else: current_ship_speed += MAX_ACCELERATION * max_speed * delta * sign(speed_delta) set_engine_strength(current_ship_speed * ENGINE_MULTIPLIER) deepspace_mat.set_shader_param("scroll_speed", current_ship_speed * 5000) func _physics_process(delta): if Engine.editor_hint: return if is_network_master(): var adj_position := current_ship_position+current_ship_subpos if current_ship_target != null: var distance := adj_position.distance_to(current_ship_target) if distance > NO_SPEED_THRESHOLD: ship_direction = current_ship_target.angle_to_point(adj_position) var max_speed := get_max_speed() if max_speed > 0: var deceleration_time = current_ship_speed / (MAX_ACCELERATION * max_speed) if current_ship_speed * deceleration_time < distance: ship_speed = max_speed else: ship_speed = 0.0 else: ship_speed = 0.0 rset("pup_ship_direction", ship_direction) rset("pup_ship_speed", ship_speed) else: ship_speed = 0.0 rset("pup_ship_speed", ship_speed) if current_ship_speed > EPSILON: var pos_delta: Vector2 = (Vector2.RIGHT * current_ship_speed * delta).rotated(current_ship_direction) current_ship_subpos += pos_delta if current_ship_subpos.x >= 1.0: var int_part := floor(current_ship_subpos.x) current_ship_position.x += int_part current_ship_subpos.x -= int_part if current_ship_subpos.y >= 1.0: var int_part := floor(current_ship_subpos.y) current_ship_position.y += int_part current_ship_subpos.y -= int_part rset("pup_ship_position", current_ship_position) rset("pup_ship_subpos", current_ship_subpos) if not warp_state and current_ship_speed > 0.05: # Engage FTL rpc("warp_enter") elif warp_state and current_ship_speed < 0.02: # Diseangage FTL rpc("warp_exit") else: ship_speed = 0.0 rset("pup_ship_speed", ship_speed) else: ship_direction = pup_ship_direction ship_speed = pup_ship_speed current_ship_position = pup_ship_position current_ship_subpos = pup_ship_subpos func get_engine_count() -> int: var working_engines := 0 for child in $engines.get_children(): var engine := child as GameObjectEngine if engine.force > 0: working_engines += 1 return working_engines func get_max_speed() -> float: var max_speed := 0.0 for child in $engines.get_children(): var engine := child as GameObjectEngine max_speed += engine.force return max_speed # Serialization / Deserialization func serialize() -> Dictionary: # Get tilemap data var tilemapdata := {} for tilemap in tilemaps: var data := [] for cell in tilemap.get_used_cells(): data.append([cell, tilemap.get_cellv(cell)]) tilemapdata[tilemap.name] = data return { "tilemaps": tilemapdata, "engines": serialize_children($engines), "objects": serialize_children($objects), "lights": serialize_children($lights), "sockets": serialize_children($sockets), "pois": serialize_children($pois), "areas": serialize_children($areas), "ship": { "position": current_ship_position, "target": current_ship_target, "set_speed": ship_speed, "set_direction": ship_direction, "speed": current_ship_speed, "direction": current_ship_direction } } func deserialize(data: Dictionary) -> void: # Create maps for tilemap in data["tilemaps"]: var tilemap_node = get_node(tilemap) as TileMap for tile in data["tilemaps"][tilemap]: tilemap_node.set_cellv(tile[0], tile[1]) tilemap_node.update_bitmask_region() tilemap_node.update_dirty_quadrants() # Create objects deserialize_children($engines, data["engines"]) deserialize_children($objects, data["objects"]) deserialize_children($lights, data["lights"]) deserialize_children($pois, data["pois"]) deserialize_children($sockets, data["sockets"]) deserialize_children($sockets, data["sockets"]) deserialize_children($areas, data["areas"], true) # Set ship parameters current_ship_position = data["ship"]["position"] current_ship_target = data["ship"]["target"] ship_speed = data["ship"]["set_speed"] ship_direction = data["ship"]["set_direction"] current_ship_speed = data["ship"]["speed"] current_ship_direction = data["ship"]["direction"] # Run autotile conversions and generate occlusions $tiles/walls.run_conversions() func serialize_children(node: Node) -> Dictionary: var data := {} for child in node.get_children(): data[child.name] = { "filename": child.filename, "data": child.serialize(), "transform": child.transform } return data func deserialize_children(node: Node, data: Dictionary, deserialize_first: bool = false) -> void: for node_name in data: var node_data := data[node_name] as Dictionary var node_scene = load(node_data.filename).instance() node_scene.name = node_name node_scene.transform = node_data.transform if deserialize_first: node_scene.deserialize(node_data.data) node.add_child(node_scene, true) if not deserialize_first: node_scene.deserialize(node_data.data) # Lighting func set_unlit(val: bool): unlit = val if darkness: darkness.visible = not val # Engine related functions func set_engine_strength(val: float): # Set energy strength to current speed for child in $engines.get_children(): if child is GameObjectEngine: var engine := child as GameObjectEngine engine.strength = val remotesync func warp_enter(): $deepspace/AnimationPlayer.play("warp-enter") warp_state = true remotesync func warp_exit(): $deepspace/AnimationPlayer.play("warp-exit") warp_state = false # Tileset related functions func make_electric_probes(tilemap: TileMap, tile_name: String): var tile_id := tilemap.tile_set.find_tile_by_name(tile_name) for cell in tilemap.get_used_cells_by_id(tile_id): var coord := tilemap.map_to_world(cell) var probe := ProbeElectricity.instance() probe.position = coord tilemap.add_child(probe) func get_pois(type_filter, class_filter) -> Array: var filtered := [] for child in $pois.get_children(): if type_filter != null and child.poitype != type_filter: continue if class_filter != null and child.poiclass != class_filter: continue filtered.append(child) return filtered