diff --git a/assets/level/floor/floor_6x9.mesh b/assets/level/floor/floor_6x9.mesh index 4c1520f..6009bfc 100644 Binary files a/assets/level/floor/floor_6x9.mesh and b/assets/level/floor/floor_6x9.mesh differ diff --git a/assets/level/hallway/hallway_4.mesh b/assets/level/hallway/hallway_4.mesh index f5d9c3a..9b4af08 100644 Binary files a/assets/level/hallway/hallway_4.mesh and b/assets/level/hallway/hallway_4.mesh differ diff --git a/src/equipment/spray.gd b/src/equipment/spray.gd index 1ef74ab..f31ff67 100644 --- a/src/equipment/spray.gd +++ b/src/equipment/spray.gd @@ -15,12 +15,18 @@ func _spray() -> void: func _fire() -> void: + rumbler.intensity = RUMBLE_INTENSITY + + if Game.manager.is_tank_full(): + Player.instance.hud.play_tank_full_alert() + idle() + return + _spray() spray_effect.visible = true beam_particles_1.emitting = true beam_particles_2.emitting = true - rumbler.intensity = RUMBLE_INTENSITY func _idle() -> void: diff --git a/src/equipment/toothbrush/toothbrush.gd b/src/equipment/toothbrush/toothbrush.gd index 372d65f..9d58228 100644 --- a/src/equipment/toothbrush/toothbrush.gd +++ b/src/equipment/toothbrush/toothbrush.gd @@ -14,7 +14,7 @@ const BRUSH_SCALE := 0.2 func _fire() -> void: - if raycast.is_colliding(): + if raycast.is_colliding() and not Game.manager.is_tank_full(): brush_animation.play("brush") var collider := raycast.get_collider() if collider is GunkBody: diff --git a/src/game/game.gd b/src/game/game.gd index f1ceb58..d5d9630 100644 --- a/src/game/game.gd +++ b/src/game/game.gd @@ -5,3 +5,5 @@ class_name Game extends Node static var manager: GameManagerType: get(): return GameManager + +static var hud: PlayerHUD diff --git a/src/game/game_manager.gd b/src/game/game_manager.gd index 95024c3..96d2850 100644 --- a/src/game/game_manager.gd +++ b/src/game/game_manager.gd @@ -15,6 +15,9 @@ signal alert_cleared const MAX_ALERT := 6 +## Maximum amount of grunk the player can carry in their tank. +@export var grunk_tank_limit := 120000 + ## Amount of grunk the player is currently carrying. var grunk_tank := 0.0 @@ -44,6 +47,14 @@ func deposit_tank() -> void: empty_tank() +func is_tank_full() -> bool: + return grunk_tank >= grunk_tank_limit + + +func get_tank_fill_pct() -> float: + return grunk_tank / grunk_tank_limit + + ## Raise the alert level, if possible. func raise_alert(delta: int) -> void: var new_value := clampi(alert_level + delta, 0, MAX_ALERT) diff --git a/src/player/player.gd b/src/player/player.gd index 7be6cbf..4404092 100644 --- a/src/player/player.gd +++ b/src/player/player.gd @@ -16,7 +16,7 @@ var gravity: Vector3 = ( var selected_interactive: Interactive var firing := false -@onready var player_hud: PlayerHUD = %PlayerHUD +@onready var hud: PlayerHUD = %PlayerHUD @onready var camera_pivot: CameraController = %CameraPivot @@ -27,6 +27,13 @@ var firing := false @onready var wide_spray: WideSpray = %WideSpray @onready var toothbrush: Tool = %Toothbrush +## Global static access to player singleton +static var instance: Player + + +func _ready() -> void: + instance = self + func get_speed() -> float: if is_on_floor(): @@ -51,7 +58,7 @@ func get_tool() -> Tool: func _physics_process(delta: float) -> void: # Will be null if no valid interactor is selected. var interactive: Interactive = interact_ray.get_collider() as Interactive - player_hud.select_interactive(interactive) + hud.select_interactive(interactive) # World interaction if interactive and Input.is_action_just_pressed("interact"): diff --git a/src/props/overhead_light/overhead_light.tscn b/src/props/overhead_light/overhead_light.tscn index 4ee14ec..bf7fccf 100644 --- a/src/props/overhead_light/overhead_light.tscn +++ b/src/props/overhead_light/overhead_light.tscn @@ -55,6 +55,33 @@ _surfaces = [{ blend_shape_mode = 0 shadow_mesh = SubResource("ArrayMesh_3gl0p") +[sub_resource type="Animation" id="Animation_g27yp"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath(".:mesh:surface_0/material:emission_energy_multiplier") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [12.0] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("../SpotLight3D:light_energy") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [2.0] +} + [sub_resource type="Animation" id="Animation_whqf3"] resource_name = "flicker" length = 0.01 @@ -85,33 +112,6 @@ tracks/1/keys = { "values": [3.0, 2.7] } -[sub_resource type="Animation" id="Animation_g27yp"] -length = 0.001 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath(".:mesh:surface_0/material:emission_energy_multiplier") -tracks/0/interp = 1 -tracks/0/loop_wrap = true -tracks/0/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [12.0] -} -tracks/1/type = "value" -tracks/1/imported = false -tracks/1/enabled = true -tracks/1/path = NodePath("../SpotLight3D:light_energy") -tracks/1/interp = 1 -tracks/1/loop_wrap = true -tracks/1/keys = { -"times": PackedFloat32Array(0), -"transitions": PackedFloat32Array(1), -"update": 0, -"values": [2.0] -} - [sub_resource type="AnimationLibrary" id="AnimationLibrary_ngq1d"] _data = { &"RESET": SubResource("Animation_g27yp"), diff --git a/src/ui/hud/grunk_counter/grunk_counter.gd b/src/ui/hud/grunk_counter/grunk_counter.gd index b3f38cf..1b31269 100644 --- a/src/ui/hud/grunk_counter/grunk_counter.gd +++ b/src/ui/hud/grunk_counter/grunk_counter.gd @@ -4,6 +4,8 @@ extends HBoxContainer const COUNTER_BUMP_RATE := 0.15 const COUNTER_SPINDOWN_TIME := 0.4 +const TANK_WARNING_BUFFER_PCT := 0.1 + @onready var counter: Label = %Counter @@ -14,11 +16,14 @@ func _ready() -> void: func on_grunk_collected(delta: float) -> void: - counter.text = str(int(Game.manager.grunk_tank)) + counter.text = str(int(clampf(Game.manager.grunk_tank, 0.0, Game.manager.grunk_tank_limit))) counter.scale = Vector2.ONE + Vector2.ONE * clampf(delta / 128.0, 0.1, 1.0) + var buffer := remap(Game.manager.get_tank_fill_pct(), 1 - TANK_WARNING_BUFFER_PCT, 1, 0, 1) + counter.modulate = Color.WHITE.lerp(Color.RED, clampf(buffer, 0, 1)) func on_grunk_emptied(amount: float) -> void: + counter.modulate = Color.WHITE create_tween().tween_method(_set_counter, int(amount), 0, COUNTER_SPINDOWN_TIME).set_trans( Tween.TRANS_EXPO ) diff --git a/src/ui/hud/grunk_counter/grunk_counter.tscn b/src/ui/hud/grunk_counter/grunk_counter.tscn index 3f35997..bb189fc 100644 --- a/src/ui/hud/grunk_counter/grunk_counter.tscn +++ b/src/ui/hud/grunk_counter/grunk_counter.tscn @@ -23,8 +23,9 @@ text = "GRUNK: " [node name="Counter" type="Label" parent="."] unique_name_in_owner = true texture_filter = 6 +custom_minimum_size = Vector2(120, 0) layout_mode = 2 size_flags_horizontal = 4 size_flags_vertical = 8 -text = " 0" +text = "0" horizontal_alignment = 2 diff --git a/src/ui/hud/player_hud.gd b/src/ui/hud/player_hud.gd index e25de67..3e6448e 100644 --- a/src/ui/hud/player_hud.gd +++ b/src/ui/hud/player_hud.gd @@ -7,6 +7,7 @@ class_name PlayerHUD extends Control func _ready() -> void: Game.manager.alert_raised.connect(_on_raise_alert) + Game.hud = self func select_interactive(prop: Interactive) -> void: @@ -15,3 +16,7 @@ func select_interactive(prop: Interactive) -> void: func _on_raise_alert(_new_value: int) -> void: alert_player.play("grunk_alert") + + +func play_tank_full_alert() -> void: + alert_player.play("tank_full_alert") diff --git a/src/ui/hud/player_hud.tscn b/src/ui/hud/player_hud.tscn index 5bac013..9bc6e54 100644 --- a/src/ui/hud/player_hud.tscn +++ b/src/ui/hud/player_hud.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=8 format=3 uid="uid://dq1x21tq06dud"] +[gd_scene load_steps=9 format=3 uid="uid://dq1x21tq06dud"] [ext_resource type="Theme" uid="uid://b07fevr214mmr" path="res://src/ui/hud/hud_theme.tres" id="1_lirk3"] [ext_resource type="Script" uid="uid://lrsv0185bfu" path="res://src/ui/hud/player_hud.gd" id="2_j6lpx"] @@ -31,6 +31,18 @@ tracks/1/keys = { "update": 0, "values": [Color(1, 1, 1, 0)] } +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("TankAlert:modulate") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 0)] +} [sub_resource type="Animation" id="Animation_5be8f"] resource_name = "grunk_alert" @@ -61,10 +73,28 @@ tracks/1/keys = { "values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 0)] } +[sub_resource type="Animation" id="Animation_ud8na"] +resource_name = "tank_full_alert" +length = 3.6 +step = 0.1 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("TankAlert:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.6, 1.2, 1.8, 2.4, 3, 3.6), +"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1), +"update": 0, +"values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 0), Color(1, 1, 1, 1), Color(1, 1, 1, 0)] +} + [sub_resource type="AnimationLibrary" id="AnimationLibrary_ud8na"] _data = { &"RESET": SubResource("Animation_n6jee"), -&"grunk_alert": SubResource("Animation_5be8f") +&"grunk_alert": SubResource("Animation_5be8f"), +&"tank_full_alert": SubResource("Animation_ud8na") } [node name="PlayerHUD" type="Control"] @@ -148,6 +178,21 @@ grow_horizontal = 2 grow_vertical = 2 mouse_filter = 1 +[node name="TankAlert" type="Label" parent="AlertHUD"] +modulate = Color(1, 1, 1, 0) +layout_mode = 1 +anchors_preset = 5 +anchor_left = 0.5 +anchor_right = 0.5 +offset_left = -268.0 +offset_right = 268.0 +offset_bottom = 88.0 +grow_horizontal = 2 +theme_type_variation = &"AlertLabel" +text = "TANK FULL +RETURN TO SHIP" +horizontal_alignment = 1 + [node name="GrunkAlert" type="Label" parent="AlertHUD"] modulate = Color(1, 1, 1, 0) layout_mode = 1