extends CharacterBody3D # Load Config File var player_data = {} var player_config = ConfigFile.new() var player_filepath = "res://Player/player.ini" #Camera moving with Mouse var mouse_axis := Vector2() var camera_change = false var mouse_sensitivity = 8.0 @export var FOV = 80.0 @export var neck_path = NodePath("Neck") @export var head_path = NodePath("Neck/Head") @export var camera_path = NodePath("Neck/Head/Camera") @onready var neck: SpringArm3D = get_node(neck_path) @onready var head: Node3D = get_node(head_path) @onready var camera: Camera3D = get_node(camera_path) # Walk and Sprint const FLOOR_MAX_ANGLE: float = deg2rad(46.0) @export var walk_speed = 5 @export var sprint_speed = 9 @export var acceleration = 8 @export var deacceleration = 10 @export var jump_height = 4.5 var speed = 5.0 var sprint_enabled := true var hold_walk := false var stamina_delay = 0 # Player defaults if not found in INI file var player = "player" var exhausted_delay = 60 var sprint_energy_consumption = 0.5 var stamina_regen_speed = 0.5 var mana_needed_to_heal = 30 var mana_heal_ammount = 10 var mana_regen_speed = 0.1 var fall_threshold_damage = 9 # distance down a player has to fall before taking damage # Move var falling := Vector3() # Grounded enum GROUNDED_STATE { GROUNDED, MIDAIR, TOUCHDOWN } var player_state = GROUNDED_STATE.GROUNDED # Damage var max_fall := Vector3() # Total disatance fallen down # Get the gravity from the project settings to be synced with RigidDynamicBody nodes. var gravity = ProjectSettings.get_setting("physics/3d/default_gravity") func _ready() -> void: Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) if player_config.load(player_filepath) == OK: mana_needed_to_heal = player_config.get_value(player, "mana_needed_to_heal") mana_heal_ammount = player_config.get_value(player, "mana_heal_ammount") mana_regen_speed = player_config.get_value(player, "mana_regen_speed") fall_threshold_damage = player_config.get_value(player, "fall_threshold_damage") gravity = player_config.get_value(player, "gravity") walk_speed = player_config.get_value(player, "walk_speed") exhausted_delay = player_config.get_value(player, "exhausted_delay") stamina_regen_speed = player_config.get_value(player, "stamina_regen_speed") sprint_speed = player_config.get_value(player, "sprint_speed") sprint_energy_consumption = player_config.get_value(player, "sprint_energy_consumption") jump_height = player_config.get_value(player, "jump_height") Universal.player = player_config.get_value(player, "playername") Universal.health = player_config.get_value(player, "health") Universal.stamina = player_config.get_value(player, "stamina") Universal.mana = player_config.get_value(player, "mana") Universal.lifeforce = player_config.get_value(player, "lifeforce") Universal.xp = player_config.get_value(player, "xp") Universal.dead = player_config.get_value(player, "dead") else: print("Player Config File Not Found - Using defaults") stat_change() # Used to update display for stats func _physics_process(delta): #Checks to see if player is dead if Universal.dead == true: dead() Universal.dead = null # Reset player stats if respauned if Universal.respaun == true: Universal.respaun = false stamina_delay = 0 visible = true get_node("PlayerInterface").visible = true _ready() velocity.x = 0 velocity.z = 0 hold_walk = false position.x = 0 position.y = 0.7 position.z = 0 stat_change() # Used to update display for stats player_state = GROUNDED_STATE.GROUNDED max_fall.y = 0 # Pause menu if Input.is_action_just_pressed("ui_cancel") && Universal.dead == false: velocity.x = 0 velocity.z = 0 hold_walk = false if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) $Pause.visible = !$Pause.visible if Universal.ui_lock == false: Universal.ui_lock = true else: Universal.ui_lock = false else: Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) $Pause.visible = !$Pause.visible Universal.ui_lock = false # Add the gravity. if not is_on_floor(): velocity.y -= gravity * delta # Get the input direction and handle the movement/deceleration. # As good practice, you should replace UI actions with custom gameplay actions. var input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_backward") # Overide to force continus walking if Input.is_action_just_pressed("hold_move_forward"): if hold_walk == true: hold_walk = false else: hold_walk = true if Input.is_action_just_pressed("move_forward") || Input.is_action_just_pressed("move_backward"): hold_walk = false if hold_walk == true: input_dir.y = -1 if Universal.ui_lock == false: # Handle Jump. if Input.is_action_just_pressed("move_jump") and is_on_floor(): velocity.y = jump_height #Move Player var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized() if direction: velocity.x = direction.x * speed velocity.z = direction.z * speed else: velocity.x = move_toward(velocity.x, 0, speed) velocity.z = move_toward(velocity.z, 0, speed) sprint(delta) move_and_slide() if Input.is_action_just_pressed("camera_perspective"): var player_camera = $Neck/Head/Camera if camera_change == true: player_camera.position.z = 0 player_camera.position.x = 0 player_camera.position.y = 0 camera_change = false else: player_camera.position.z = 1.5 player_camera.position.x = 0.25 player_camera.position.y = 0.5 camera_change = true # Fall damage calculation match player_state: GROUNDED_STATE.GROUNDED: falling = Vector3.ZERO if not is_on_floor(): player_state = GROUNDED_STATE.MIDAIR GROUNDED_STATE.MIDAIR: falling += Vector3.DOWN * gravity * delta if velocity.y <= -fall_threshold_damage: max_fall = velocity if is_on_floor(): player_state = GROUNDED_STATE.TOUCHDOWN GROUNDED_STATE.TOUCHDOWN: if falling.length() >= fall_threshold_damage and max_fall.y <= -fall_threshold_damage: Universal.health -= round(-(max_fall.y + fall_threshold_damage)) Universal.stamina -= round(-(max_fall.y + fall_threshold_damage)) if round(-(max_fall.y + fall_threshold_damage)) > 5: Universal.health -= round(-(max_fall.y + fall_threshold_damage)*9) else: if round(-(max_fall.y + fall_threshold_damage)) > 10: Universal.health -= round(-(max_fall.y + fall_threshold_damage)*15) if Universal.health <= 0: dead() get_node("PlayerInterface/VBoxContainer/BottomRight2/Health").value = Universal.health max_fall = Vector3.ZERO player_state = GROUNDED_STATE.GROUNDED func dead(): velocity.x = 0 velocity.z = 0 hold_walk = false Universal.ui_lock = true Universal.dead = true Universal.health = 0 Universal.lifeforce = 0 Universal.mana = 0 Universal.stamina = 0 sprint_enabled = false stamina_delay = exhausted_delay stamina_regen_speed = 0 visible = false get_node("PlayerInterface").visible = false stat_change() Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) $Dead.visible = !$Dead.visible # Called when there is an input event func _input(event: InputEvent) -> void: if event is InputEventMouseMotion: mouse_axis = event.relative camera_rotation() # Heal button if Input.is_action_just_pressed("player_heal") && Universal.mana >= mana_needed_to_heal: if Universal.health != 1000: Universal.mana -= mana_needed_to_heal if 1000 < Universal.health + mana_heal_ammount: Universal.health = 1000 elif Universal.health == 0: Universal.health = mana_heal_ammount else: Universal.health += mana_heal_ammount stat_change() # Used to update display for stats func camera_rotation() -> void: if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED: return if mouse_axis.length() > 0: var horizontal: float = -mouse_axis.x * (mouse_sensitivity / 100) var vertical: float = -mouse_axis.y * (mouse_sensitivity / 100) mouse_axis = Vector2() rotate_y(deg2rad(horizontal)) camera.rotate_x(deg2rad(vertical)) # Clamp mouse rotation var temp_rot = camera.rotation.x if camera_change == false: temp_rot = clamp(temp_rot, -1.5, 2) else: temp_rot = clamp(temp_rot, -0.5, 2) camera.rotation.x = temp_rot func can_sprint() -> bool: return (sprint_enabled and is_on_floor() and Input.is_action_pressed("move_sprint")) func sprint(delta: float) -> void: if can_sprint(): if Universal.stamina >= 0 && stamina_delay <= 1: speed = sprint_speed camera.set_fov(lerp(camera.fov, FOV * 1.25, delta * 8)) Universal.stamina -= sprint_energy_consumption if Universal.stamina <= 0: stamina_delay = exhausted_delay sprint_enabled = false camera.fov = FOV speed = walk_speed return stat_change() # Used to update display for stats else: speed = walk_speed camera.set_fov(lerp(camera.fov, FOV, delta * 8)) if stamina_delay >= 0: stamina_delay -= 0.1 sprint_enabled = true elif Universal.stamina <= 1000: if velocity.x == 0: Universal.stamina += stamina_regen_speed * 2 else: Universal.stamina += stamina_regen_speed stat_change() # Used to update display for stats a elif Universal.stamina >= 1000 && Universal.mana < 1000: if velocity.x == 0: Universal.mana += mana_regen_speed * 2 else: Universal.mana += mana_regen_speed stat_change() # Used to update display for stats a func stat_change(): # Change the stats & displaybox size and refreshes so everythine stays at the bottom of the screen var sbox_size = 0 var hbox_size = 0 var mbox_size = 0 var lbox_size = 0 var default_size = -130 if Universal.stamina >= Universal.stamina_max: sbox_size = 30 get_node("PlayerInterface/VBoxContainer/BottomRight1").visible = false else: sbox_size = 0 get_node("PlayerInterface/VBoxContainer/BottomRight1").visible = true if Universal.health == Universal.health_max: hbox_size = 30 get_node("PlayerInterface/VBoxContainer/BottomRight2").visible = false else: hbox_size = 0 get_node("PlayerInterface/VBoxContainer/BottomRight2").visible = true if Universal.mana >= Universal.mana_max -1: mbox_size = 30 get_node("PlayerInterface/VBoxContainer/BottomRight3").visible = false else: mbox_size = 3 get_node("PlayerInterface/VBoxContainer/BottomRight3").visible = true if Universal.lifeforce == Universal.lifeforce_max: lbox_size = 30 get_node("PlayerInterface/VBoxContainer/BottomRight4").visible = false else: lbox_size = 0 get_node("PlayerInterface/VBoxContainer/BottomRight4").visible = true get_node("PlayerInterface/VBoxContainer").offset_top = default_size + sbox_size + hbox_size + mbox_size + lbox_size get_node("PlayerInterface/VBoxContainer/BottomRight1/Energy").value = Universal.stamina get_node("PlayerInterface/VBoxContainer/BottomRight4/Food").value = Universal.lifeforce get_node("PlayerInterface/VBoxContainer/BottomRight3/Mana").value = Universal.mana get_node("PlayerInterface/VBoxContainer/BottomRight2/Health").value = Universal.health