extends RigidBody var player_id : int var mouse_over_player : RigidBody = null var thrust_plan : Plan = Plan.new() var weapons_plan : Plan = Plan.new() var is_local : bool = false var running_plan : bool = false var was_running_plan : bool = false var plan_time : float = 0.0 var last_translation : Vector3 = get_translation() var last_rotation : Vector3 = get_rotation() var initial_translation : Vector3 = get_translation() var initial_rotation : Vector3 = get_rotation() var initial_velocity : Vector3 = Vector3(0,0,0) var initial_rotational_velocity : Vector3 = Vector3(0,0,0) var enable_physics : bool = false var end_translation : Vector3 = Vector3.ZERO var end_rotation : Vector3 = Vector3.ZERO var end_linear_velocity : Vector3 = Vector3.ZERO var end_rotational_velocity : Vector3 = Vector3.ZERO var round_time : float = 0.0 var turn_counter : int = 0 var end_of_round_translation : Vector3 = get_translation() var end_of_round_rotation : Vector3 = get_rotation() var time_of_death : float = -1 var is_alive : bool = true var health : float = 100.0 var end_health : float = 100.0 var energy : float = 100.0 var end_energy : float = 100.0 onready var arrow_obj : Spatial = $ArrowContainer onready var arrow_scale_obj : Spatial = $ArrowContainer/ArrowScaleContainer onready var rotate_arrow_obj : Spatial = $RotateArrowContainer onready var rotate_arrow_scale_obj : Spatial = $RotateArrowContainer/RotateArrowScaleContainer onready var turn_end_banner : TextureRect = $TurnEndBanner onready var health_bar : ColorRect = $StatusPanel/HealthBarContainer/HealthBar const TIME_STEP : float = 0.01 const MAX_LIN_THRUST : float = 1.0 const MAX_ROT_THRUST : float = 0.01 const BASE_DPS : float = 300.0 const BASE_ENERGY_USAGE : float = 75.0 const BASE_ENERGY_REGEN : float = 150.0 const BASE_OVERCHARGE_DAMAGE : float = 5.0 const OOB_DAMAGE : float = 100.0 func init(id : int, color : Color) -> void: player_id = id last_rotation = get_rotation() last_translation = get_translation() initial_rotation = get_rotation() initial_translation = get_translation() enable_physics = true get_parent().get_parent().console_print("Player is set to local? " + String(is_local)) if is_local: $MainPanel.visible = true $ThrustPanel.visible = true $WeaponsPanel.visible = true $InfoPanel.visible = true $StatusPanel.visible = true set_colors(color) func send_thrust_plan() -> void: for element in thrust_plan.current_elements: get_parent().get_parent().console_print('Sending data = ' + String(element.time) + String(element.linear_thrust) + String(element.rotational_thrust)) rpc_id(1, "add_thrust_element", element.time, element.linear_thrust, element.rotational_thrust) func send_weapons_plan() -> void: for element in weapons_plan.current_elements: get_parent().get_parent().console_print('Sending data = ' + String(element.time) + String(element.firing)) rpc_id(1, "add_weapons_element", element.time, element.firing) remote func add_thrust_element(time: float, linear_thrust : Vector3, rotational_thrust : Vector3) -> void: if is_local: return var element : ThrustElement = ThrustElement.new() element.time = time element.linear_thrust = linear_thrust element.rotational_thrust = rotational_thrust get_parent().get_parent().console_print(String(is_local) + ": Adding thrust element with the following params: time = " + String(time) + ", lin = " + String(linear_thrust) + ", rot = " + String(rotational_thrust) + ".") thrust_plan.add_element(element) remote func add_weapons_element(time : float, firing : bool) -> void: if is_local: return var element : WeaponsElement = WeaponsElement.new() element.time = time element.firing = firing get_parent().get_parent().console_print(String(is_local) + ": Adding weapons element with the following params: time = " + String(time) + ", firing = " + String(firing)) weapons_plan.add_element(element) remote func r_end_turn( r_time_of_death : float, r_end_translation : Vector3, r_end_rotation : Vector3, r_end_linear_velocity : Vector3, r_end_rotational_velocity : Vector3, r_end_health : float, r_end_energy : float) -> void: self._on_PlayButton_pressed() time_of_death = r_time_of_death end_translation = r_end_translation end_rotation = r_end_rotation end_linear_velocity = r_end_linear_velocity end_rotational_velocity = r_end_rotational_velocity end_health = r_end_health end_energy = r_end_energy turn_counter += 1 if is_local: $MainPanel/EndTurnButton.disabled = false $MainPanel/TimeBar.value = 0 $TurnEndBanner.visible = true $TurnEndBanner/AnimationPlayer.play() return thrust_plan.new_turn() weapons_plan.new_turn() func _on_TimeBar_value_changed(value : float) -> void: var min_time : float = thrust_plan.current_time() #get_parent().get_parent().console_print(String(is_local) + ": Current plan time is " + String(min_time)) if value <= min_time: $MainPanel/TimeBar.value = min_time func _on_AddButton_pressed() -> void: var new_thrust_element : ThrustElement = ThrustElement.new() new_thrust_element.linear_thrust = get_linear_vector() new_thrust_element.rotational_thrust = get_rotational_vector() new_thrust_element.time = $MainPanel/TimeBar.value - thrust_plan.current_time() if (thrust_plan.add_element(new_thrust_element)): get_parent().get_parent().console_print(String(is_local) + ": Added thrust element with " + String(new_thrust_element.time) + String(new_thrust_element.rotational_thrust) + String(new_thrust_element.linear_thrust)) else: get_parent().get_parent().console_print(String(is_local) + ": Failed to add thrust element") var new_weapons_element : WeaponsElement = WeaponsElement.new() new_weapons_element.firing = $WeaponsPanel/WeaponsSwitch.pressed new_weapons_element.time = $MainPanel/TimeBar.value - weapons_plan.current_time() if (weapons_plan.add_element(new_weapons_element)): get_parent().get_parent().console_print(String(is_local) + ": Added weapons element with " + String(new_weapons_element.firing)) else: get_parent().get_parent().console_print(String(is_local) + ": Failed to add weapons element") func _on_RemoveButton_pressed() -> void: thrust_plan.remove_last_element() weapons_plan.remove_last_element() func _on_ClearButton_pressed() -> void: thrust_plan.remove_all_elements() weapons_plan.remove_all_elements() func _on_EndTurnButton_pressed() -> void: fix_plans() $MainPanel/EndTurnButton.disabled = true send_thrust_plan() send_weapons_plan() rpc_id(1, "end_turn") thrust_plan.new_turn() weapons_plan.new_turn() round_time += 5 func _update_arrow() -> void: var linear_thrust : Vector3 = get_linear_vector() var linear_thrust_normalized : Vector3 = linear_thrust.normalized() var linear_thrust_magnitude : float = linear_thrust.length() var phi : float if linear_thrust_normalized.x == 0 and linear_thrust_normalized.z == 0: phi = PI/2 else: phi = asin(linear_thrust_normalized.x / sqrt(pow(linear_thrust_normalized.x, 2) + pow(linear_thrust_normalized.z,2))) if linear_thrust_normalized.z < 0: phi = PI - phi var theta : float = -asin(linear_thrust_normalized.y) arrow_obj.rotation = Vector3(0,0,0) arrow_obj.rotate(Vector3(1,0,0), theta) arrow_obj.rotate(Vector3(0,1,0), phi) arrow_scale_obj.scale = Vector3(linear_thrust_magnitude, linear_thrust_magnitude, linear_thrust_magnitude) func _update_rotate_arrow() -> void: var rotational_thrust : Vector3 = get_rotational_vector() var rotational_thrust_normalized : Vector3 = rotational_thrust.normalized() var rotational_thrust_magnitude : float = rotational_thrust.length() var phi : float if rotational_thrust_normalized.x == 0 and rotational_thrust_normalized.z == 0: phi = PI/2 else: phi = asin(rotational_thrust_normalized.x / sqrt(pow(rotational_thrust_normalized.x, 2) + pow(rotational_thrust_normalized.z,2))) if rotational_thrust_normalized.z < 0: phi = PI - phi var theta : float = -asin(rotational_thrust_normalized.y) rotate_arrow_obj.rotation = Vector3(0,0,0) rotate_arrow_obj.rotate(Vector3(1,0,0), theta) rotate_arrow_obj.rotate(Vector3(0,1,0), phi) rotate_arrow_scale_obj.scale = Vector3(rotational_thrust_magnitude, rotational_thrust_magnitude, rotational_thrust_magnitude)*100 func get_linear_vector() -> Vector3: return Vector3($ThrustPanel/XLin.value, -$ThrustPanel/YLin.value, $ThrustPanel/ZLin.value) * MAX_LIN_THRUST func get_rotational_vector() -> Vector3: return Vector3($ThrustPanel/XRot.value, -$ThrustPanel/YRot.value, $ThrustPanel/ZRot.value) * MAX_ROT_THRUST func _on_XLin_value_changed(value : float) -> void: self._update_arrow() if get_linear_vector().length() < 1.0: return $ThrustPanel/XLin.value = sign($ThrustPanel/XLin.value) * \ sqrt(1 - pow($ThrustPanel/YLin.value, 2) - pow($ThrustPanel/ZLin.value, 2)) func _on_XRot_value_changed(value : float) -> void: self._update_rotate_arrow() if get_rotational_vector().length() < 1.0: return $ThrustPanel/XRot.value = sign($ThrustPanel/XRot.value) * \ sqrt(1 - pow($ThrustPanel/YRot.value, 2) - pow($ThrustPanel/ZRot.value, 2)) func _on_YLin_value_changed(value : float) -> void: self._update_arrow() if get_linear_vector().length() < 1.0: return $ThrustPanel/YLin.value = sign($ThrustPanel/YLin.value) * \ sqrt(1 - pow($ThrustPanel/XLin.value, 2) - pow($ThrustPanel/ZLin.value, 2)) func _on_YRot_value_changed(value : float) -> void: self._update_rotate_arrow() if get_rotational_vector().length() < 1.0: return $ThrustPanel/YRot.value = sign($ThrustPanel/YRot.value) * \ sqrt(1 - pow($ThrustPanel/XRot.value, 2) - pow($ThrustPanel/ZRot.value, 2)) func _on_ZLin_value_changed(value : float) -> void: self._update_arrow() if get_linear_vector().length() < 1.0: return $ThrustPanel/ZLin.value = sign($ThrustPanel/ZLin.value) * \ sqrt(1 - pow($ThrustPanel/YLin.value, 2) - pow($ThrustPanel/XLin.value, 2)) func _on_ZRot_value_changed(value : float) -> void: self._update_rotate_arrow() if get_rotational_vector().length() < 1.0: return $ThrustPanel/ZRot.value = sign($ThrustPanel/ZRot.value) * \ sqrt(1 - pow($ThrustPanel/YRot.value, 2) - pow($ThrustPanel/XRot.value, 2)) func _on_ResetButton_pressed(): $ThrustPanel/XLin.value = 0 $ThrustPanel/XRot.value = 0 $ThrustPanel/YLin.value = 0 $ThrustPanel/YRot.value = 0 $ThrustPanel/ZLin.value = 0 $ThrustPanel/ZRot.value = 0 func _get_current_plan_element(all_elements) -> PlanElement: var summed_time : float = 0.0 for element in all_elements: summed_time += element.time if summed_time > plan_time: return element return null func _get_all_thrust_elements(): var all_elements = [] for element in thrust_plan.elements: all_elements.append(element) for element in thrust_plan.current_elements: all_elements.append(element) return all_elements func _get_all_weapons_elements(): var all_elements = [] for element in weapons_plan.elements: all_elements.append(element) for element in weapons_plan.current_elements: all_elements.append(element) return all_elements func _physics_process(delta : float) -> void: if !enable_physics: return if !running_plan: if is_local and was_running_plan: get_parent().show_winner() $GunContainer.visible = false arrow_obj.visible = true rotate_arrow_obj.visible = true disable_all_engine_particles() set_translation(last_translation) set_rotation(last_rotation) was_running_plan = false return was_running_plan = true if time_of_death > 0 and plan_time > time_of_death: self.visible = false $CollisionShape.disabled = true is_alive = false else: self.visible = true $CollisionShape.disabled = false is_alive = true var all_thrust_elements = _get_all_thrust_elements() var current_thrust_element : ThrustElement = _get_current_plan_element(all_thrust_elements) if current_thrust_element == null: last_translation = get_translation() last_rotation = get_rotation() running_plan = false return arrow_obj.visible = false rotate_arrow_obj.visible = false add_central_force(self.transform.basis.xform(current_thrust_element.linear_thrust)) add_torque(self.transform.basis.xform(current_thrust_element.rotational_thrust)) update_engine_particles(current_thrust_element.linear_thrust, current_thrust_element.rotational_thrust) var all_weapons_elements = _get_all_weapons_elements() var current_weapons_element : WeaponsElement = _get_current_plan_element(all_weapons_elements) if current_weapons_element == null: $GunContainer.visible = false running_plan = false return if current_weapons_element.firing and is_alive: _fire_gun(delta) elif energy < 100: $GunContainer.visible = false energy += BASE_ENERGY_REGEN * delta else: $GunContainer.visible = false calculate_other_damage(delta) plan_time += delta func _process(delta : float) -> void: _update_battery_visuals(energy) _update_health_bar(health) if mouse_over_player: display_data(mouse_over_player) func disable_all_engine_particles() -> void: var engine_particles = [ $"EngineParticleContainer/S-X,R+Y", $"EngineParticleContainer/S+X,R-Y", $"EngineParticleContainer/S-X,R-Y", $"EngineParticleContainer/S+X,R+Y", $"EngineParticleContainer/S-Y,R+Z,R+X", $"EngineParticleContainer/S-Y,R-Z,R+X", $"EngineParticleContainer/S-Y,R-Z,R-X", $"EngineParticleContainer/S-Y,R+Z,R-X", $"EngineParticleContainer/S+Y,R-Z,R+X", $"EngineParticleContainer/S+Y,R+Z,R+X", $"EngineParticleContainer/S+Y,R-Z,R-X", $"EngineParticleContainer/S+Y,R+Z,R-X", $EngineParticleContainer/SZ, $EngineParticleContainer/SZ2 ] for ep in engine_particles: ep.emitting = false func update_engine_particles(linear_thrust : Vector3, rotational_thrust : Vector3) -> void: var engine_particles : Particles = $"EngineParticleContainer/S-X,R-Y" if linear_thrust.x < 0 or rotational_thrust.y > 0: engine_particles.emitting = true engine_particles.scale = Vector3.ONE * (max(-linear_thrust.x, 0)+max(rotational_thrust.y, 0)) * 0.005 else: engine_particles.emitting = false engine_particles = $"EngineParticleContainer/S+X,R+Y" if linear_thrust.x > 0 or rotational_thrust.y < 0: engine_particles.emitting = true engine_particles.scale = Vector3.ONE * (max(linear_thrust.x, 0)+max(-rotational_thrust.y, 0)) * 0.005 else: engine_particles.emitting = false engine_particles = $"EngineParticleContainer/S-X,R+Y" if linear_thrust.x < 0 or rotational_thrust.y < 0: engine_particles.emitting = true engine_particles.scale = Vector3.ONE * (max(-linear_thrust.x, 0)+max(-rotational_thrust.y, 0)) * 0.005 else: engine_particles.emitting = false engine_particles = $"EngineParticleContainer/S+X,R-Y" if linear_thrust.x > 0 or rotational_thrust.y > 0: engine_particles.emitting = true engine_particles.scale = Vector3.ONE * (max(linear_thrust.x, 0)+max(rotational_thrust.y, 0)) * 0.005 else: engine_particles.emitting = false engine_particles = $"EngineParticleContainer/S-Y,R+Z,R+X" if linear_thrust.y < 0 or rotational_thrust.z > 0 or rotational_thrust.x > 0: engine_particles.emitting = true engine_particles.scale = Vector3.ONE * (max(-linear_thrust.y, 0)+max(rotational_thrust.z, 0)+max(rotational_thrust.x, 0)) * 0.01/3 else: engine_particles.emitting = false engine_particles = $"EngineParticleContainer/S-Y,R-Z,R+X" if linear_thrust.y < 0 or rotational_thrust.z < 0 or rotational_thrust.x > 0: engine_particles.emitting = true engine_particles.scale = Vector3.ONE * (max(-linear_thrust.y, 0)+max(-rotational_thrust.z, 0)+max(rotational_thrust.x, 0)) * 0.01/3 else: engine_particles.emitting = false engine_particles = $"EngineParticleContainer/S-Y,R-Z,R-X" if linear_thrust.y < 0 or rotational_thrust.z < 0 or rotational_thrust.x < 0: engine_particles.emitting = true engine_particles.scale = Vector3.ONE * (max(-linear_thrust.y, 0)+max(-rotational_thrust.z, 0)+max(-rotational_thrust.x, 0)) * 0.01/3 else: engine_particles.emitting = false engine_particles = $"EngineParticleContainer/S-Y,R+Z,R-X" if linear_thrust.y < 0 or rotational_thrust.z > 0 or rotational_thrust.x < 0: engine_particles.emitting = true engine_particles.scale = Vector3.ONE * (max(-linear_thrust.y, 0)+max(rotational_thrust.z, 0)+max(-rotational_thrust.x, 0)) * 0.01/3 else: engine_particles.emitting = false engine_particles = $"EngineParticleContainer/S+Y,R-Z,R+X" if linear_thrust.y > 0 or rotational_thrust.z < 0 or rotational_thrust.x > 0: engine_particles.emitting = true engine_particles.scale = Vector3.ONE * (max(linear_thrust.y, 0)+max(-rotational_thrust.z, 0)+max(rotational_thrust.x, 0)) * 0.01/3 else: engine_particles.emitting = false engine_particles = $"EngineParticleContainer/S+Y,R+Z,R+X" if linear_thrust.y > 0 or rotational_thrust.z > 0 or rotational_thrust.x > 0: engine_particles.emitting = true engine_particles.scale = Vector3.ONE * (max(linear_thrust.y, 0)+max(rotational_thrust.z, 0)+max(rotational_thrust.x, 0)) * 0.01/3 else: engine_particles.emitting = false engine_particles = $"EngineParticleContainer/S+Y,R-Z,R-X" if linear_thrust.y > 0 or rotational_thrust.z < 0 or rotational_thrust.x < 0: engine_particles.emitting = true engine_particles.scale = Vector3.ONE * (max(linear_thrust.y, 0)+max(-rotational_thrust.z, 0)+max(-rotational_thrust.x, 0)) * 0.01/3 else: engine_particles.emitting = false engine_particles = $"EngineParticleContainer/S+Y,R+Z,R-X" if linear_thrust.y > 0 or rotational_thrust.z > 0 or rotational_thrust.x < 0: engine_particles.emitting = true engine_particles.scale = Vector3.ONE * (max(linear_thrust.y, 0)+max(rotational_thrust.z, 0)+max(-rotational_thrust.x, 0)) * 0.01/3 else: engine_particles.emitting = false engine_particles = $EngineParticleContainer/SZ var engine_particles2 : Particles = $EngineParticleContainer/SZ2 if linear_thrust.z != 0: engine_particles.emitting = true engine_particles2.emitting = true var modz : float = linear_thrust.z if modz < 0: modz = -modz engine_particles.scale = Vector3.ONE * (modz) * 0.02 engine_particles2.scale = Vector3.ONE * (modz) * 0.02 else: engine_particles.emitting = false engine_particles2.emitting = false func play_current_plan() -> void: set_linear_velocity(end_linear_velocity) set_angular_velocity(end_rotational_velocity) set_translation(end_translation) set_rotation(end_rotation) health = end_health energy = end_energy running_plan = true plan_time = 5 * turn_counter func play_all_plans() -> void: get_parent().play_full_plans() func play_full_plan() -> void: set_linear_velocity(initial_velocity) set_angular_velocity(initial_rotational_velocity) set_translation(initial_translation) set_rotation(initial_rotation) running_plan = true plan_time = 0.0 health = 100.0 energy = 100.0 func _on_PlayButton_pressed() -> void: play_all_plans() func _update_battery_visuals(value : float) -> void: $WeaponsPanel/FillingBlocker.margin_bottom = 65 - (clamp(value, 0.0, 100.0) * 1.2) func _update_laser(length : float) -> void: $GunContainer/RayCast/CSGCylinder.height = length*10 $GunContainer/RayCast/CSGCylinder.translation = Vector3(0, length*5, 0) func _fire_gun(delta : float) -> void: $GunContainer.visible = true if $GunContainer/RayCast.is_colliding(): var raycast_pos : Vector3 = $GunContainer/RayCast.global_transform.origin var target_pos : Vector3 = $GunContainer/RayCast.get_collision_point() _update_laser(raycast_pos.distance_to(target_pos)) else: _update_laser($GunContainer/RayCast.cast_to.y) energy -= delta * BASE_ENERGY_USAGE if $GunContainer/RayCast.is_colliding(): var target : RigidBody = $GunContainer/RayCast.get_collider() target.take_damage(BASE_DPS * delta) func get_display_name() -> String: return get_parent().get_parent().name_dict[player_id] func get_human_readable_vector(vector : Vector3) -> String: return "(" + String(round(vector.x * 10)/10) + ", " + \ String(round(vector.y * 10)/10) + ", " + \ String(round(vector.z * 10)/10) + ")" func display_data(player_obj : RigidBody) -> void: var text = "Name: " + player_obj.get_display_name() + "\n" text += "Position: " + get_human_readable_vector(player_obj.translation) + "\n" text += "Rotation: " + get_human_readable_vector(player_obj.rotation_degrees) + "\n" text += "Hull Integrity: " + String(player_obj.health) + "%\n" $InfoPanel/Label.text = text mouse_over_player = player_obj func clear_info_panel() -> void: $InfoPanel/Label.text = "" mouse_over_player = null func _on_Player_mouse_entered(): get_parent().mouse_enter(self) func _on_Player_mouse_exited(): get_parent().mouse_exit(self) func _on_PlayLastButton_pressed(): if len(thrust_plan.elements) == 0: play_full_plan() else: play_current_plan() func set_colors(color : Color): var insideMaterial : Material = preload("res://Shaders/InsideSpaceship.tres").duplicate() insideMaterial.emission = color var outsideMaterial : Material = preload("res://Shaders/OutsideSpaceship.material").duplicate() outsideMaterial.emission = color outsideMaterial.albedo_color = color var particleMaterial : Material = preload("res://Shaders/ParticleSpaceship.tres").duplicate() particleMaterial.emission = color for child in $EngineParticleContainer.get_children(): child.draw_pass_1.material = particleMaterial for child in $spaceship.get_children(): if child.name == "Cube": child.set_surface_material(0, insideMaterial) else: child.set_surface_material(0, outsideMaterial) func take_damage(damage : float) -> void: health -= damage func calculate_other_damage(delta : float): if (translation.length_squared() > 100): take_damage(OOB_DAMAGE * delta) if energy < 0: take_damage(-energy * BASE_OVERCHARGE_DAMAGE * delta) func _update_health_bar(value : float) -> void: health_bar.anchor_left = 0.5 - clamp(value, 0.0, 100.0)/200 health_bar.anchor_right = 0.5 + clamp(value, 0.0, 100.0)/200 func fix_plans() -> void: if thrust_plan.current_time() < 5.0: var new_thrust_element : ThrustElement = ThrustElement.new() new_thrust_element.linear_thrust = Vector3.ZERO new_thrust_element.rotational_thrust = Vector3.ZERO new_thrust_element.time = 5.0 - thrust_plan.current_time() if weapons_plan.current_time() < 5.0: var new_weapons_element : WeaponsElement = WeaponsElement.new() new_weapons_element.firing = false new_weapons_element.time = 5.0 - weapons_plan.current_time()