extends RigidBody # Game export var team = "RED" export (int) var health = 100 var weapon = null var world # Camera export(float) var mouse_sensitivity = 12.0 export(float) var FOV = 90.0 var mouse_axis := Vector2() onready var head: Spatial = $Neck/Head onready var neck: Spatial = $Neck # Move var velocity := Vector3() var direction := Vector3() var move_axis := Vector2() var floorspeed := Vector3() var jumping = false var can_jump = true onready var nav = $NavigationAgent # Walk const FLOOR_MAX_ANGLE: float = deg2rad(46.0) export(float) var jump_height = 400.0 var in_water : bool = false var swim_speed : float = 450.0 var climb_speed : float = 5.0 # Control var controlling_machine = false #whether character is riding/controlling something var machine = null export var is_player = false #whether character is currently controlled by a player var ladder_m = null #physics var player_state : PhysicsDirectBodyState var is_on_floor:bool var floor_normal : Vector3 = Vector3.UP var acceleration = 80.0 export(int) var walk_speed = 5 var c_friction = 4.0 var air_control = 0.3 # Called when the node enters the scene tree func _ready() -> void: weapon = preload("res://scenes/weapons/w_Rockets.tscn").instance() add_child(weapon) world = get_tree().get_root().get_node("GAMEWORLD") $"%UseRay".add_exception(self) $"%MeleeRay".add_exception(self) $"%UseRay".add_exception($AreaDetect) $"%MeleeRay".add_exception($AreaDetect) func get_init_info(): return {"linear_velocity" : linear_velocity, "angular_velocity" : angular_velocity, "controlling_machine" : controlling_machine, "team" : team, "health" : health, "nametag" : $Nametag.text} func mp_init(init_info): for variable in init_info.keys(): set(variable, init_info[variable]) $Nametag.text = init_info["nametag"] remote func set_phys_transform(trfrm, lvel): transform = trfrm linear_velocity = lvel # Called every frame. 'delta' is the elapsed time since the previous frame func _process(_delta: float) -> void: if is_player and !world.is_chatting: if Input.is_action_just_pressed("use"): initiate_use() if controlling_machine: if Input.is_action_just_pressed("fire"): machine.attack1() if Input.is_action_just_pressed("fire2"): machine.attack2() machine.direction_input(Input.get_action_strength("move_forward"),Input.get_action_strength("move_backward"), Input.get_action_strength("move_right"),Input.get_action_strength("move_left"), Input.get_action_strength("alt_right"),Input.get_action_strength("alt_left")) machine.misc_input(Input.get_action_strength("move_duck"),Input.get_action_strength("move_jump"),Input.get_action_strength("move_walk")) machine.mouse_input(Input.get_action_strength("fire"), Input.get_action_strength("fire3"),Input.get_action_strength("fire2")) else: jumping = Input.get_action_strength("move_jump") if Input.is_action_just_pressed("fire"): weapon.attack1() move_axis.x = Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward") move_axis.y = Input.get_action_strength("move_right") - Input.get_action_strength("move_left") func initiate_use(): if controlling_machine: machine.relinquish_control() return if ladder_m != null: leave_ladder() return if $"%UseRay".is_colliding(): var area_c = $"%UseRay".get_collider() match area_c.name: "SteerArea": world.rpc_id(1, "_call_on_server", "_client_request_control_vehicle", {"id" : world.client_id, "machine_path" : area_c.get_parent().get_path(), "char_name" : name}) "LadderArea": mount_ladder(area_c.get_parent()) "TugArea": pass "PickupArea": pass _: pass remotesync func set_net_owner(owner_id): $Nametag.text = "" set_network_master(owner_id) if owner_id != 1: $Nametag.text = world.players_info[owner_id][0] if get_tree().get_network_unique_id() != 1: if owner_id == world.client_id: $Nametag.visible = false world.player_char = self is_player = true world.cam.attach(self, "FIRSTPERSON", "./Neck/Head") else: $Nametag.visible = true is_player = false world.get_node("HUD").update_characters() func deselect_character(): if is_network_master(): world.player_char = null if world.client_id != 1: world.cam.attach(world, "STATIC", "./DEFAULTCAM") rpc("set_net_owner", 1) func take_control_of_machine(slave_machine): machine = slave_machine controlling_machine = true func lose_machine(): if is_network_master(): world.cam.attach(self, "FIRSTPERSON", "./Neck/Head") controlling_machine = false machine = null # Called every physics tick. 'delta' is constant func _physics_process(delta: float) -> void: if is_network_master(): if ladder_m != null: climb_ladder(delta) elif !on_floor_test() and in_water: swim(delta) else: walk(delta) is_on_floor = false #reset whether is on floor in between frames # called each physics frame func on_floor_test() -> bool: if $Feet.is_colliding(): is_on_floor = true floor_normal = Vector3.UP floorspeed = $Feet.get_collider().get_linear_velocity() if $Feet.get_collider().has_method("get_linear_velocity") else Vector3.ZERO return true if player_state: for i in range(player_state.get_contact_count()): var contact_angle_from_up : float = Vector3.UP.angle_to(player_state.get_contact_local_normal(i)) if contact_angle_from_up < FLOOR_MAX_ANGLE: floor_normal = player_state.get_contact_local_normal(i) is_on_floor = true return true return false #modify simulated physics results func _integrate_forces(state) -> void: player_state = state velocity = state.get_linear_velocity() $normal_vis.look_at($normal_vis.global_transform.origin + global_transform.basis.z, floor_normal) for i in range(player_state.get_contact_count()): var contact_angle_from_up : float = Vector3.UP.angle_to(player_state.get_contact_local_normal(i)) if contact_angle_from_up > FLOOR_MAX_ANGLE and !is_on_floor: friction = 0 break if i == player_state.get_contact_count() - 1: friction = 1 if is_network_master(): rpc("set_phys_transform", transform, linear_velocity) if global_transform.origin.y < -30: rpc("damage", 500000, "drown", [1, "Davy Jones"]) func walk(_delta:float) -> void: # Input direction = Vector3() var aim: Basis = head.get_global_transform().basis direction += -move_axis.x * aim.z + move_axis.y * aim.x direction.y = 0 direction = direction.normalized() if floor_normal != Vector3.UP: direction = direction.rotated(floor_normal.cross(Vector3.UP).normalized(), Vector3.UP.angle_to(floor_normal)) # Jump if is_player and jumping and is_on_floor and can_jump: jump() #max walk speed var _speed = walk_speed var _temp_accel: float = acceleration var _cspeed = sqrt(pow(velocity.x-floorspeed.x,2)+pow(velocity.z-floorspeed.z,2)) if not is_on_floor: _temp_accel *= air_control var projVel = Vector2(velocity.x-floorspeed.x,velocity.z-floorspeed.z).dot(Vector2(direction.x,direction.z)) if is_on_floor: add_central_force(-mass*_cspeed*linear_velocity.normalized()*c_friction)#friction if _speed - _cspeed > 0: add_central_force (mass*Vector3(direction.x*_temp_accel, 0, direction.z*_temp_accel))#velocity.x += direction.x*_temp_accel else: add_central_force(mass*Vector3(direction.x*(_speed-projVel), 0, direction.z*(_speed-projVel))) elif 1.0 - projVel > 0: add_central_force (mass*Vector3(direction.x*_temp_accel, 0, direction.z*_temp_accel)) func jump(): can_jump = false apply_central_impulse(Vector3.UP*jump_height) yield(get_tree().create_timer(0.05),"timeout") can_jump = true func swim(_delta): #drag and buoyancy add_central_force(Vector3.UP*weight*1.0) add_central_force(-1*linear_velocity*100) #controls var dir: Basis = head.get_global_transform().basis var m_dir: Vector3 = -move_axis.x * dir.z + move_axis.y * dir.x m_dir = m_dir.normalized() add_central_force(swim_speed*m_dir) if jumping: add_central_force(Vector3.UP*weight*0.5) func enter_water(): in_water = true func exit_water(): in_water = false func mount_ladder(target_ladder): var ladder_tracker = Spatial.new() ladder_tracker.name = name target_ladder.add_child(ladder_tracker) ladder_tracker.transform = target_ladder.bottom.transform ladder_tracker.global_transform.origin = target_ladder.get_nearest_point_to_route(global_transform.origin) look_at(global_transform.origin + target_ladder.global_transform.basis.x, target_ladder.global_transform.basis.y) ladder_m = ladder_tracker global_transform.origin = ladder_m.global_transform.origin global_transform.basis = ladder_m.global_transform.basis.orthonormalized() linear_velocity = Vector3.ZERO set_gravity_scale(0.0) #called each frame while climbing ladder func climb_ladder(delta): var new_ladder_pos = ladder_m.global_transform.origin + ladder_m.global_transform.basis.y.normalized() * move_axis.x * delta * climb_speed var prog = ladder_m.get_parent().get_climb_scalar(new_ladder_pos) if prog >= 0.0 and prog <= 1.0: ladder_m.global_transform.origin = new_ladder_pos global_transform.origin = ladder_m.global_transform.origin global_transform.basis = ladder_m.global_transform.basis.orthonormalized() func leave_ladder(): if (ladder_m.get_parent().top.global_transform.origin - global_transform.origin).length_squared() < 0.01: apply_central_impulse(-400*ladder_m.global_transform.basis.z) global_transform.basis = world.global_transform.basis set_gravity_scale(1.0) ladder_m.queue_free() ladder_m = null remotesync func damage(dmg_amt, _type, shooter, extra = ""): health -= dmg_amt if health <= 0 and is_network_master(): if shooter[0] != get_network_master() and shooter[0] != 1: world.rpc_id(shooter[0], "game_killsound") if get_network_master() == 1: world._call_on_server("_character_death", {"killer_id" : shooter[0], "killer" : shooter[1], "victim_mp_id" : get_network_master(), "victim" : name, "extra" : extra}) else: world.rpc_id(1, "_call_on_server", "_character_death", {"killer_id" : shooter[0], "killer" : shooter[1], "victim_mp_id" : get_network_master(), "victim" : name, "extra" : extra}) elif is_network_master(): if shooter[0] != get_network_master() and shooter[0] != 1: world.rpc_id(shooter[0], "game_hitsound") remotesync func remove_dead_character(): if is_network_master() and machine != null: machine.relinquish_control() deselect_character() queue_free() remotesync func net_apply_impulse(impulse_v): apply_central_impulse(impulse_v)