summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/game.gd60
-rw-r--r--client/map/tiles/floor.gd5
-rw-r--r--client/menu/blur_setup.gd1
-rw-r--r--client/menu/character.gd12
-rw-r--r--client/menu/communicate/popup_message/popup_message.gd117
-rw-r--r--client/menu/communicate/popup_message/popup_message.tscn86
-rw-r--r--client/menu/communicate/popup_message/server_message.gd13
-rw-r--r--client/menu/communicate/popup_message/server_message.tscn6
-rw-r--r--client/menu/hairstyle_preview.gd2
-rw-r--r--client/menu/ingame.gd39
-rw-r--r--client/menu/lobby.gd42
-rw-r--r--client/menu/menu_background.gd32
-rw-r--r--client/menu/play.gd1
-rw-r--r--client/player/character/character.gd106
-rw-r--r--client/player/character/character.tscn8
-rw-r--r--client/player/controllable_player.gd13
-rw-r--r--client/player/player.gd2
17 files changed, 302 insertions, 243 deletions
diff --git a/client/game.gd b/client/game.gd
index 76bb271a..fe1e9ba6 100644
--- a/client/game.gd
+++ b/client/game.gd
@@ -21,9 +21,8 @@ extends Node3D
signal update_players(players: Dictionary)
signal data_updated()
signal in_lobby_updated(in_lobby: bool)
+signal join_state_updated(state: JoinState)
signal text_message(player: int, text: String, timeout_initial: float, timeout_remaining: float)
-signal joined()
-signal left()
signal update_tutorial_running(running: bool)
enum SpectatingMode {
@@ -31,6 +30,12 @@ enum SpectatingMode {
FREE,
}
+enum JoinState {
+ SPECTATING,
+ WAITING,
+ JOINED,
+}
+
var player_id: int = -1
var item_names: Array = []
var item_index_by_name: Dictionary = {}
@@ -42,10 +47,10 @@ var maps: Array = []
var bot_algos: Array
var text_message_history: Array[Array] = []
+var join_state: JoinState = JoinState.SPECTATING
+
var in_lobby := false
var is_replay := false
-var is_joined := false
-var join_sent := false
var tutorial_running := false
var tutorial_queue := []
var last_position := Vector2(0, 0)
@@ -99,8 +104,7 @@ func handle_packet(p):
in_lobby_updated.connect(player_instance.onscreen_controls.in_lobby_updated)
player_instance.onscreen_controls.in_lobby_updated(in_lobby)
camera.target = player_instance.movement_base
- is_joined = true
- joined.emit()
+ set_join_state(JoinState.JOINED)
else:
player_instance = Player.new(p.id, p.name, p.position, p.character, self)
players[p.id] = player_instance
@@ -114,8 +118,7 @@ func handle_packet(p):
tutorial_queue.erase(player.current_item_message)
pinned_items.clear_item(p.id)
if p.id == player_id:
- is_joined = false
- left.emit()
+ set_join_state(JoinState.SPECTATING)
camera.target = $Center
if player.hand != null:
player.hand.queue_free()
@@ -244,18 +247,15 @@ func handle_packet(p):
map.gi_bake()
await get_parent()._menu_open()
map.autobake = true
-
- if in_lobby: popup_message.lobby()
- else: popup_message.ingame()
+
+ in_lobby_updated.emit(in_lobby)
else:
map.autobake = false
await get_parent()._menu_exit()
-
+
lobby.visible = in_lobby
- if lobby and not join_sent:
- join()
-
- in_lobby_updated.emit(in_lobby)
+ if lobby and join_state == JoinState.SPECTATING:
+ toggle_join()
"score":
if p.time_remaining != null:
overlay.update(p.demands_failed, p.demands_completed, p.points, p.time_remaining)
@@ -291,7 +291,7 @@ func handle_packet(p):
"server_message":
var mstr := get_message_str(p.message)
if p.error:
- # popup_message.display_server_msg(tr("c.error.server").format([mstr]))
+ popup_message.display_server_msg(tr("c.error.server").format([mstr]))
push_error(tr("c.error.server").format([mstr]))
else:
popup_message.display_server_msg(mstr)
@@ -310,7 +310,7 @@ func handle_packet(p):
else:
# Positional hint message
if message == null:
- popup_message.clear_server_msg()
+ popup_message.clear_server_msg(position_)
else:
popup_message.display_server_msg_positional(get_message_str(message), position_, false)
"environment":
@@ -323,16 +323,20 @@ func handle_packet(p):
_: push_error("Unrecognized packet type: %s" % p.type)
-func join():
- if join_sent:
- push_error("Join was already sent. Tried to join twice.")
- return
- join_sent = true
- mp.send_join(Global.get_profile("username"), Global.get_profile("character"))
+func set_join_state(state: JoinState):
+ join_state = state
+ join_state_updated.emit(state)
-func leave():
- join_sent = false
- mp.send_leave(player_id)
+func toggle_join():
+ match join_state:
+ JoinState.SPECTATING:
+ set_join_state(JoinState.WAITING)
+ mp.send_join(Global.get_profile("username"), Global.get_profile("character"))
+ JoinState.WAITING:
+ push_error("Join/Leave action already toggled.")
+ JoinState.JOINED:
+ set_join_state(JoinState.WAITING)
+ mp.send_leave(player_id)
func _process(delta):
update_center()
@@ -359,7 +363,7 @@ func get_tile_interactive(pos: Vector2i) -> bool:
func update_center():
- if is_joined:
+ if join_state != JoinState.SPECTATING:
return
if Input.get_vector("left", "right", "forwards", "backwards").normalized().length() > .1:
spectating_mode = SpectatingMode.FREE
diff --git a/client/map/tiles/floor.gd b/client/map/tiles/floor.gd
index 8e75834b..dd51c928 100644
--- a/client/map/tiles/floor.gd
+++ b/client/map/tiles/floor.gd
@@ -16,11 +16,12 @@
class_name Floor
extends Tile
-var opt
+var opt: bool
+
func _init(ctx: TileFactory.TileCC):
opt = ctx.floor_mesher != null
super(ctx)
- if opt: ctx.floor_mesher.add_tile(ctx.position)
+ if not base_mesh: ctx.floor_mesher.add_tile(ctx.position)
func get_base_mesh():
if opt: return null
diff --git a/client/menu/blur_setup.gd b/client/menu/blur_setup.gd
index 331d1f47..9d55a9d4 100644
--- a/client/menu/blur_setup.gd
+++ b/client/menu/blur_setup.gd
@@ -14,6 +14,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
extends Control
+class_name BlurSetup
func _ready():
update(Global.get_setting("graphics.ui_blur"))
diff --git a/client/menu/character.gd b/client/menu/character.gd
index 6af30250..dd3bc5cd 100644
--- a/client/menu/character.gd
+++ b/client/menu/character.gd
@@ -18,7 +18,6 @@
extends Menu
@onready var character: Character = $Node3D/Character
-@onready var num_hairstyles := character.hairstyles.keys().size()
@onready var back_button := $VBoxContainer/bottom_panel/back
@onready var map: Map = $Node3D/Map
@onready var username_edit = $VBoxContainer/top_panel/a/username
@@ -26,7 +25,7 @@ extends Menu
func _ready():
super()
$VBoxContainer/top_panel/a/username.text = Global.get_profile("username")
- character.select_hairstyle(Global.get_profile("character"))
+ character.set_style(Global.get_profile("character"))
init_map()
func init_map():
@@ -53,6 +52,7 @@ func init_map():
for y in tiles.size():
for x in tiles[y].size():
map.set_tile(Vector2i(x,y) - co, gt.call([x,y]), [[x,y-1],[x-1,y],[x,y+1],[x+1,y]].map(gt))
+ map.flush()
func _input(_event):
if Input.is_action_just_pressed("ui_cancel"):
@@ -68,9 +68,9 @@ func _on_back_pressed():
replace_menu("res://menu/main.tscn")
func _on_character_back_pressed():
- Global.set_profile("character", (Global.get_profile("character") - 1) % num_hairstyles)
- character.select_hairstyle(Global.get_profile("character"))
+ Global.set_profile("character", max(Global.get_profile("character") - 1, 0))
+ character.set_style(Global.get_profile("character"))
func _on_character_forward_pressed():
- Global.set_profile("character", (Global.get_profile("character") + 1) % num_hairstyles)
- character.select_hairstyle(Global.get_profile("character"))
+ Global.set_profile("character", max(Global.get_profile("character") + 1, 0))
+ character.set_style(Global.get_profile("character"))
diff --git a/client/menu/communicate/popup_message/popup_message.gd b/client/menu/communicate/popup_message/popup_message.gd
index 6c2c2c0e..98bd94e3 100644
--- a/client/menu/communicate/popup_message/popup_message.gd
+++ b/client/menu/communicate/popup_message/popup_message.gd
@@ -14,45 +14,34 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
-extends MarginContainer
+extends Control
class_name PopupMessage
+const SERVER_MESSAGE_SCENE = preload("res://menu/communicate/popup_message/server_message.tscn")
+
var is_ingame := false
var is_joined := false
-@onready var server_msg = $VBox/ServerMessage
-@onready var server_msg_positional = $ServerMessagePositional
-@onready var hint_msg = $VBox/HintMessage
-
-@onready var server_msg_timer: Timer = $ServerTimer
-@onready var hint_msg_timer: Timer = $HintTimer
-
-@onready var server_msg_label: Label = $VBox/ServerMessage/CenterContainer/Label
-@onready var server_msg_positional_label: Label = $ServerMessagePositional/ServerMessage/CenterContainer/Label
-@onready var hint_msg_label: Label = $VBox/HintMessage/CenterContainer/Label
+var positional_messages = {}
-@onready var server_msg_positional_panel: PanelContainer = $ServerMessagePositional/ServerMessage
+@onready var positional_messages_node: Control = $Positional
+@onready var server_msg = $Static/VBox/ServerMessage
+@onready var hint_msg = $Static/VBox/HintMessage
-@onready var auto_hint_timers: Node = $AutoHintTimers
+@onready var server_msg_label: Label = $Static/VBox/ServerMessage/CenterContainer/Label
+@onready var hint_msg_label: Label = $Static/VBox/HintMessage/CenterContainer/Label
-@onready var reset_timer = $Reset
-@onready var join_while_running_timer = $JoinWhileRunning
+@onready var auto_hint_timers: Node = $Timers/AutoHints
+@onready var server_msg_timer: Timer = $Timers/Server
+@onready var hint_msg_timer: Timer = $Timers/Hint
+@onready var reset_timer = $Timers/Reset
+@onready var join_while_running_timer = $Timers/JoinWhileRunning
@onready var game: Game = $"../Game"
-var server_message_position := Vector2.ZERO
-var last_server_message_panel_size := Vector2.ZERO
-
func _ready():
- game.joined.connect(
- func player_joined():
- is_joined = true
- update_state()
- )
- game.left.connect(
- func player_joined():
- is_joined = false
- update_state()
+ game.join_state_updated.connect(func(state: Game.JoinState):
+ is_joined = state == Game.JoinState.JOINED
)
game.update_tutorial_running.connect(
func a(running: bool):
@@ -61,25 +50,26 @@ func _ready():
else:
update_state()
)
+ game.in_lobby_updated.connect(
+ func a(in_lobby):
+ is_ingame = not in_lobby
+ update_state()
+ )
func _process(_delta: float):
- if server_msg_positional.visible:
- var pos_3d = Vector3(server_message_position.x + 0.5, 1.5, server_message_position.y + 0.5)
+ for pos: Vector2 in positional_messages.keys():
+ var msg: PositionalMessage = positional_messages[pos]
+ var pos_3d = Vector3(pos.x + 0.5, 1.5, pos.y + 0.5)
var pos_2d = get_viewport().get_camera_3d().unproject_position(pos_3d)
- var server_message_panel_size = server_msg_positional_panel.size
- server_msg_positional.position = pos_2d.clamp(Vector2.ZERO + 0.5 * server_message_panel_size, Vector2(get_viewport_rect().size) - 0.5 * server_message_panel_size)
- if server_message_panel_size != last_server_message_panel_size:
- last_server_message_panel_size = server_message_panel_size
- server_msg_positional_panel.position = -0.5 * last_server_message_panel_size
-
-func ingame():
- is_ingame = true
- update_state()
-
-func lobby():
- is_ingame = false
- update_state()
+ msg.node_2d.position = pos_2d.clamp(
+ Vector2.ZERO + 0.5 * msg.node.size,
+ Vector2(get_viewport_rect().size) - 0.5 * msg.node.size
+ )
+
+ if msg.node.size != msg.last_size:
+ msg.last_size = msg.node.size
+ msg.node.position = -0.5 * msg.last_size
func update_state():
if is_ingame and is_joined:
@@ -91,30 +81,35 @@ func update_state():
stop_game_hints()
func display_server_msg(msg: String, auto_remove := true):
- clear_server_msg()
server_msg.show()
server_msg_label.text = msg
if auto_remove:
server_msg_timer.start()
-func display_server_msg_positional(msg: String, pos: Vector2, auto_remove := true):
+func _on_server_timeout() -> void:
clear_server_msg()
- server_msg_positional.show()
- server_message_position = pos
- server_msg_positional_label.text = msg
- server_msg_positional_panel.size = Vector2.ZERO
-
- if auto_remove:
- server_msg_timer.start()
-func clear_server_msg():
- server_msg_timer.stop()
- server_msg.hide()
- server_msg_positional.hide()
+func display_server_msg_positional(text: String, pos: Vector2, use_monospace: bool):
+ var msg := PositionalMessage.new()
+ msg.node = SERVER_MESSAGE_SCENE.instantiate()
+ msg.node_2d = Node2D.new()
+ positional_messages_node.add_child(msg.node_2d)
+ msg.node_2d.add_child(msg.node)
+ msg.node.set_text(text, use_monospace)
+ msg.node.size = Vector2.ZERO
+ msg.position = pos
+ positional_messages[pos] = msg
-func _on_server_timer_timeout():
- clear_server_msg()
+func clear_server_msg(position_ = null):
+ if position_ == null:
+ server_msg_timer.stop()
+ server_msg.hide()
+ else:
+ if position_ in positional_messages:
+ var msg: PositionalMessage = positional_messages[position_]
+ msg.node_2d.queue_free()
+ positional_messages.erase(position_)
func display_hint_msg(msg: String):
hint_msg.show()
@@ -220,7 +215,7 @@ func _on_rotate_camera_timeout():
)]))
func _on_join_while_running_timeout():
- if not game.is_joined and not Global.get_hint("has_seen_join_while_running"):
+ if not game.join_state == Game.JoinState.JOINED and not Global.get_hint("has_seen_join_while_running"):
Global.set_hint("has_seen_join_while_running", true)
display_hint_msg(tr("c.hint.join_while_running").format([display_keybind("menu")]))
@@ -228,3 +223,9 @@ func _on_performance_timeout() -> void:
if not Global.get_hint("has_seen_performance") and Engine.get_frames_per_second() < DisplayServer.screen_get_refresh_rate() * 0.75:
Global.set_hint("has_seen_performance", true)
display_hint_msg(tr("c.hint.framerate_low"))
+
+class PositionalMessage:
+ var node: ServerMessage
+ var node_2d: Node2D
+ var position: Vector2
+ var last_size: Vector2
diff --git a/client/menu/communicate/popup_message/popup_message.tscn b/client/menu/communicate/popup_message/popup_message.tscn
index 799712e1..880e8670 100644
--- a/client/menu/communicate/popup_message/popup_message.tscn
+++ b/client/menu/communicate/popup_message/popup_message.tscn
@@ -33,25 +33,35 @@ content_margin_top = 8.0
content_margin_right = 32.0
content_margin_bottom = 8.0
-[node name="PopupMessage" type="MarginContainer"]
+[node name="PopupMessage" type="Control"]
+layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
-theme = ExtResource("1_a1566")
script = ExtResource("2_sbew6")
-[node name="VBox" type="VBoxContainer" parent="."]
+[node name="Static" type="MarginContainer" parent="."]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_filter = 2
+theme = ExtResource("1_a1566")
+
+[node name="VBox" type="VBoxContainer" parent="Static"]
layout_mode = 2
mouse_filter = 2
-[node name="ServerMessage" parent="VBox" instance=ExtResource("3_m3rok")]
+[node name="ServerMessage" parent="Static/VBox" instance=ExtResource("3_m3rok")]
visible = false
layout_mode = 2
-[node name="HintMessage" type="PanelContainer" parent="VBox"]
+[node name="HintMessage" type="PanelContainer" parent="Static/VBox"]
visible = false
material = SubResource("ShaderMaterial_k0m35")
layout_mode = 2
@@ -60,12 +70,12 @@ mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_vq4dg")
script = ExtResource("4_pvwmw")
-[node name="CenterContainer" type="HBoxContainer" parent="VBox/HintMessage"]
+[node name="CenterContainer" type="HBoxContainer" parent="Static/VBox/HintMessage"]
layout_mode = 2
mouse_filter = 2
alignment = 1
-[node name="MarginContainer" type="MarginContainer" parent="VBox/HintMessage/CenterContainer"]
+[node name="MarginContainer" type="MarginContainer" parent="Static/VBox/HintMessage/CenterContainer"]
layout_mode = 2
mouse_filter = 2
theme_override_constants/margin_left = 4
@@ -73,7 +83,7 @@ theme_override_constants/margin_top = 4
theme_override_constants/margin_right = 4
theme_override_constants/margin_bottom = 4
-[node name="TextureRect" type="TextureRect" parent="VBox/HintMessage/CenterContainer/MarginContainer"]
+[node name="TextureRect" type="TextureRect" parent="Static/VBox/HintMessage/CenterContainer/MarginContainer"]
custom_minimum_size = Vector2(28, 28)
layout_mode = 2
mouse_filter = 2
@@ -81,7 +91,7 @@ texture = ExtResource("5_2dxsd")
expand_mode = 1
stretch_mode = 4
-[node name="Label" type="Label" parent="VBox/HintMessage/CenterContainer"]
+[node name="Label" type="Label" parent="Static/VBox/HintMessage/CenterContainer"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_fonts/font = SubResource("FontVariation_qfltj")
@@ -89,60 +99,66 @@ theme_override_styles/normal = SubResource("StyleBoxEmpty_3rgop")
text = "A hint is worth more than a thousand manuals"
autowrap_mode = 3
-[node name="ServerTimer" type="Timer" parent="."]
+[node name="Positional" type="Control" parent="."]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+mouse_filter = 2
+
+[node name="Timers" type="Node" parent="."]
+
+[node name="Server" type="Timer" parent="Timers"]
wait_time = 5.0
one_shot = true
-[node name="HintTimer" type="Timer" parent="."]
+[node name="Hint" type="Timer" parent="Timers"]
wait_time = 10.0
one_shot = true
-[node name="AutoHintTimers" type="Node" parent="."]
+[node name="AutoHints" type="Node" parent="Timers"]
-[node name="Move" type="Timer" parent="AutoHintTimers"]
+[node name="Move" type="Timer" parent="Timers/AutoHints"]
wait_time = 2.0
one_shot = true
-[node name="Performance" type="Timer" parent="AutoHintTimers"]
+[node name="Performance" type="Timer" parent="Timers/AutoHints"]
wait_time = 20.0
one_shot = true
-[node name="Boost" type="Timer" parent="AutoHintTimers"]
+[node name="Boost" type="Timer" parent="Timers/AutoHints"]
wait_time = 90.0
one_shot = true
-[node name="Interact" type="Timer" parent="AutoHintTimers"]
+[node name="Interact" type="Timer" parent="Timers/AutoHints"]
wait_time = 15.0
one_shot = true
-[node name="RotateCamera" type="Timer" parent="AutoHintTimers"]
+[node name="RotateCamera" type="Timer" parent="Timers/AutoHints"]
wait_time = 120.0
one_shot = true
-[node name="Zoom" type="Timer" parent="AutoHintTimers"]
+[node name="Zoom" type="Timer" parent="Timers/AutoHints"]
wait_time = 135.0
one_shot = true
-[node name="Reset" type="Timer" parent="."]
+[node name="Reset" type="Timer" parent="Timers"]
wait_time = 10.0
one_shot = true
-[node name="JoinWhileRunning" type="Timer" parent="."]
+[node name="JoinWhileRunning" type="Timer" parent="Timers"]
wait_time = 5.0
one_shot = true
-[node name="ServerMessagePositional" type="Node2D" parent="."]
-visible = false
-
-[node name="ServerMessage" parent="ServerMessagePositional" instance=ExtResource("3_m3rok")]
-
-[connection signal="timeout" from="ServerTimer" to="." method="_on_server_timer_timeout"]
-[connection signal="timeout" from="HintTimer" to="." method="_on_hint_timer_timeout"]
-[connection signal="timeout" from="AutoHintTimers/Move" to="." method="_on_move_timeout"]
-[connection signal="timeout" from="AutoHintTimers/Performance" to="." method="_on_performance_timeout"]
-[connection signal="timeout" from="AutoHintTimers/Boost" to="." method="_on_boost_timeout"]
-[connection signal="timeout" from="AutoHintTimers/Interact" to="." method="_on_interact_timeout"]
-[connection signal="timeout" from="AutoHintTimers/RotateCamera" to="." method="_on_rotate_camera_timeout"]
-[connection signal="timeout" from="AutoHintTimers/Zoom" to="." method="_on_zoom_timeout"]
-[connection signal="timeout" from="Reset" to="." method="_on_reset_timeout"]
-[connection signal="timeout" from="JoinWhileRunning" to="." method="_on_join_while_running_timeout"]
+[connection signal="timeout" from="Timers/Server" to="." method="_on_server_timeout"]
+[connection signal="timeout" from="Timers/Hint" to="Static" method="_on_hint_timer_timeout"]
+[connection signal="timeout" from="Timers/AutoHints/Move" to="Static" method="_on_move_timeout"]
+[connection signal="timeout" from="Timers/AutoHints/Performance" to="Static" method="_on_performance_timeout"]
+[connection signal="timeout" from="Timers/AutoHints/Boost" to="Static" method="_on_boost_timeout"]
+[connection signal="timeout" from="Timers/AutoHints/Interact" to="Static" method="_on_interact_timeout"]
+[connection signal="timeout" from="Timers/AutoHints/RotateCamera" to="Static" method="_on_rotate_camera_timeout"]
+[connection signal="timeout" from="Timers/AutoHints/Zoom" to="Static" method="_on_zoom_timeout"]
+[connection signal="timeout" from="Timers/Reset" to="Static" method="_on_reset_timeout"]
+[connection signal="timeout" from="Timers/JoinWhileRunning" to="Static" method="_on_join_while_running_timeout"]
diff --git a/client/menu/communicate/popup_message/server_message.gd b/client/menu/communicate/popup_message/server_message.gd
new file mode 100644
index 00000000..fc12ee76
--- /dev/null
+++ b/client/menu/communicate/popup_message/server_message.gd
@@ -0,0 +1,13 @@
+extends BlurSetup
+class_name ServerMessage
+
+const DEFAULT_FONT = preload("res://menu/theme/font-josefin-sans.woff2")
+const MONOSPACE_FONT = preload("res://menu/theme/font-azaret-mono.woff2")
+
+@onready var label: Label = $CenterContainer/Label
+
+func set_text(text: String, use_monospace := true):
+ label.text = text
+ var font: FontVariation = label.get_theme_font("font")
+ font.base_font = MONOSPACE_FONT if use_monospace else DEFAULT_FONT
+ label.add_theme_font_size_override("font_size", 16 if use_monospace else 20)
diff --git a/client/menu/communicate/popup_message/server_message.tscn b/client/menu/communicate/popup_message/server_message.tscn
index 63160942..2a848419 100644
--- a/client/menu/communicate/popup_message/server_message.tscn
+++ b/client/menu/communicate/popup_message/server_message.tscn
@@ -1,7 +1,7 @@
[gd_scene load_steps=8 format=3 uid="uid://dq61p3a8og2b6"]
[ext_resource type="Shader" path="res://menu/blur_mix.gdshader" id="1_qv8ew"]
-[ext_resource type="Script" path="res://menu/blur_setup.gd" id="2_80a6b"]
+[ext_resource type="Script" path="res://menu/communicate/popup_message/server_message.gd" id="2_csqo8"]
[ext_resource type="FontFile" uid="uid://bk704sc5gkrb3" path="res://menu/theme/font-azaret-mono.woff2" id="3_dw20j"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_q3bbd"]
@@ -20,6 +20,7 @@ corner_radius_bottom_right = 16
corner_radius_bottom_left = 16
[sub_resource type="FontVariation" id="FontVariation_qfltj"]
+resource_local_to_scene = true
base_font = ExtResource("3_dw20j")
variation_embolden = 0.75
@@ -35,7 +36,7 @@ size_flags_horizontal = 4
size_flags_vertical = 0
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_vq4dg")
-script = ExtResource("2_80a6b")
+script = ExtResource("2_csqo8")
[node name="CenterContainer" type="CenterContainer" parent="."]
layout_mode = 2
@@ -45,5 +46,6 @@ mouse_filter = 2
layout_mode = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_fonts/font = SubResource("FontVariation_qfltj")
+theme_override_font_sizes/font_size = 16
theme_override_styles/normal = SubResource("StyleBoxEmpty_3rgop")
text = "Server message"
diff --git a/client/menu/hairstyle_preview.gd b/client/menu/hairstyle_preview.gd
index 5a9cce68..08b6aab9 100644
--- a/client/menu/hairstyle_preview.gd
+++ b/client/menu/hairstyle_preview.gd
@@ -19,7 +19,7 @@ extends VBoxContainer
signal selected(character: int)
func setup(character: int, group: ButtonGroup):
- $HairViewport/Node3D/Character.select_hairstyle(character)
+ $HairViewport/Node3D/Character.set_style(character)
$Select.button_group = group
$Select.text = tr("c.setup.uniform.value").format([character + 1])
$Select.pressed.connect(func(): selected.emit(character))
diff --git a/client/menu/ingame.gd b/client/menu/ingame.gd
index 7052f237..ba365f8e 100644
--- a/client/menu/ingame.gd
+++ b/client/menu/ingame.gd
@@ -26,19 +26,16 @@ extends Menu
var opened
func _ready():
opened = Time.get_ticks_msec()
- game.joined.connect(_on_game_joined)
- game.left.connect(_on_game_left)
- update_button_text()
- game.joined.connect(update_lobby_button)
- game.left.connect(update_lobby_button)
+ game.join_state_updated.connect(_on_game_join_state_changed)
+ _on_game_join_state_changed(game.join_state)
update_lobby_button()
super()
func update_lobby_button():
- lobby_button.disabled = game.in_lobby or not game.is_joined
+ lobby_button.disabled = game.in_lobby or game.join_state == Game.JoinState.SPECTATING
if game.in_lobby:
lobby_button.tooltip_text = "Cannot cancel game since no game is running."
- elif not game.is_joined:
+ elif not game.join_state == Game.JoinState.JOINED:
lobby_button.tooltip_text = "You must join in order to be able to cancel the current game."
else:
lobby_button.tooltip_text = ""
@@ -71,21 +68,15 @@ func _on_lobby_pressed():
exit()
func _on_leave_pressed():
- if game.is_joined:
- game.mp.send_leave(game.player_id)
- elif not game.join_sent:
- leave_button.disabled = true
- game.join()
+ game.toggle_join()
-func _on_game_joined():
- leave_button.disabled = false
- update_button_text()
-
-func _on_game_left():
- update_button_text()
-
-func update_button_text():
- if game.is_joined:
- leave_button.text = tr("c.menu.ingame.leave")
- else:
- leave_button.text = tr("c.menu.ingame.join")
+func _on_game_join_state_changed(state: Game.JoinState):
+ match state:
+ Game.JoinState.JOINED:
+ leave_button.disabled = false
+ leave_button.text = tr("c.menu.ingame.leave")
+ Game.JoinState.SPECTATING:
+ leave_button.disabled = false
+ leave_button.text = tr("c.menu.ingame.join")
+ Game.JoinState.WAITING:
+ leave_button.disabled = true
diff --git a/client/menu/lobby.gd b/client/menu/lobby.gd
index 0dca6f4c..d595444e 100644
--- a/client/menu/lobby.gd
+++ b/client/menu/lobby.gd
@@ -52,8 +52,8 @@ func _ready():
game.update_players.connect(update_players)
initialize()
game.data_updated.connect(initialize)
- game.joined.connect(_on_game_joined)
- game.left.connect(_on_game_left)
+ game.join_state_updated.connect(_on_game_join_state_updated)
+ _on_game_join_state_updated(game.join_state)
check_for_music()
func initialize():
@@ -145,18 +145,6 @@ func _input(_event):
elif Input.is_action_just_pressed("next") and not next_map.disabled:
next_map.emit_signal("pressed")
-func _on_game_joined():
- map_selector.show()
- map_list.show()
- bots_container.show()
- start_button.disabled = false
-
-func _on_game_left():
- map_selector.hide()
- map_list.hide()
- bots_container.hide()
- start_button.disabled = true
-
func _on_left_pressed():
selected_map = (selected_map - 1) % map_count
select_map(selected_map)
@@ -177,13 +165,27 @@ func _on_controller_button_pressed():
game.mp.send_chat(game.player_id, start_msg)
Sound.play_music("stop") # TODO: Game music enter
+func _on_game_join_state_updated(state: Game.JoinState):
+ match state:
+ Game.JoinState.JOINED:
+ map_selector.show()
+ map_list.show()
+ bots_container.show()
+ start_button.disabled = false
+ join_spectate.disabled = false
+ join_spectate.text = tr("c.menu.ingame.spectate")
+ Game.JoinState.SPECTATING:
+ map_selector.hide()
+ map_list.hide()
+ bots_container.hide()
+ start_button.disabled = true
+ join_spectate.disabled = false
+ join_spectate.text = tr("c.menu.ingame.join")
+ Game.JoinState.WAITING:
+ join_spectate.disabled = true
+
func _on_join_spectate_pressed():
- if game.is_joined:
- game.leave()
- join_spectate.text = tr("c.menu.ingame.join")
- elif not game.join_sent:
- game.join()
- join_spectate.text = tr("c.menu.ingame.spectate")
+ game.toggle_join()
func check_for_music():
if visible:
diff --git a/client/menu/menu_background.gd b/client/menu/menu_background.gd
index 33ec6e43..77fb123f 100644
--- a/client/menu/menu_background.gd
+++ b/client/menu/menu_background.gd
@@ -17,8 +17,8 @@
#
extends Node3D
-const NULLS = [null,null,null,null]
-const BUCKETS = [[], ["floor","floor","floor","floor","tomato-crate", "steak-crate"], ["table", "chair", "counter"], ["sink", "stove"]]
+const CRATES = ["tomato-crate", "steak-crate", "cheese-crate", "lettuce-crate", "flour-crate", "coconut-crate"]
+const TOOLS = ["sink", "cuttingboard", "stove", "oven", "freezer"]
@onready var environment: WorldEnvironment = $Environment
@onready var map: Map = $Map
@@ -27,12 +27,26 @@ func _ready():
if !Global.on_vulkan():
environment.environment.tonemap_exposure = 0.25
- for x in range(-10,11):
- for y in range(-10,11):
- var w = exp(-sqrt(x*x+y*y) * 0.15)
+ var tiles = {}
+ for x in range(-10, 11):
+ for y in range(-10, 11):
+ var w = exp(-sqrt(x * x + y * y) * 0.15)
var k = randf() * w
- var bucket = BUCKETS[int(floor(k * BUCKETS.size())) % BUCKETS.size()]
- if bucket.size() == 0: continue
- var tile_name = bucket[randi() % bucket.size()]
- map.set_tile(Vector2i(x,y), tile_name)
+ var tn = null
+ if k > 0.25: tn = "floor"
+ if k > 0.4: tn = choose(CRATES) if randf() > 0.3 else "counter"
+ if k > 0.6: tn = choose(TOOLS)
+ if tn != null: tiles[str(Vector2i(x,y))] = [tn,[x,y]]
+
+ var gt = func (cs):
+ var t = tiles.get(str(Vector2i(cs[0],cs[1])))
+ return null if t == null else t[0]
+ for pk in tiles.keys():
+ var x = tiles[pk][1][0]
+ var y = tiles[pk][1][1]
+ var t = gt.call([x,y])
+ if t != null: map.set_tile(Vector2i(x,y), t, [[x,y-1],[x-1,y],[x,y+1],[x+1,y]].map(gt))
+
map.flush()
+
+func choose(a): return a[floor(a.size() * randf())]
diff --git a/client/menu/play.gd b/client/menu/play.gd
index 1fe19224..b117d6a4 100644
--- a/client/menu/play.gd
+++ b/client/menu/play.gd
@@ -19,7 +19,6 @@ extends Menu
var url_regex: RegEx = RegEx.new()
-@onready var req: HTTPRequest = $HTTPRequest
@onready var server_list: VBoxContainer = $side/margin/options/second/ScrollContainerCustom/ServerList
@onready var server_list_loading: Label = $side/margin/options/second/Loading
@onready var connect_uri = $side/margin/options/second/connect/uri
diff --git a/client/player/character/character.gd b/client/player/character/character.gd
index 66a3435b..65275549 100644
--- a/client/player/character/character.gd
+++ b/client/player/character/character.gd
@@ -42,11 +42,16 @@ var current_animation := "idle"
@onready var tie = $Main/Tie
@onready var knife = $Main/HandRight/Knife
-@onready var hairstyles := {
- "Brown": $Main/HeadDefault/Hair,
- "Blond": $Main/HeadDefault/Hair2,
- "E. Parsley": $Main/HeadDefault/Hair3
-}
+const NUM_COLORS = 5;
+const NUM_HAIRS = 3;
+@onready var hairstyles := [$Main/HeadDefault/Hair, $Main/HeadDefault/Hair2, $Main/HeadDefault/Hair3]
+var colors = [
+ Color(0.204, 0.361, 0.624),
+ Color(0.568, 0.256, 0.602),
+ Color(0.575, 0.341, 0.117),
+ Color(0.3, 0.455, 0.221),
+ Color(0.101, 0.452, 0.521)
+]
@onready var head_default: MeshInstance3D = $Main/HeadDefault
@onready var head_robot: MeshInstance3D = $Main/HeadRobot
@@ -54,28 +59,41 @@ var current_animation := "idle"
@onready var step_sounds: PlayRandom = $Steps
@onready var boost_sounds: PlayRandom = $Boosts
+class ParsedStyle:
+ var color: int
+ var hair: int
+ var robot: bool
+ var customer: bool
+ func _init(n: int) -> void:
+ customer = n < 0
+ if customer: n *= -1
+ if n == 51: robot = true
+ else:
+ hair = n % NUM_HAIRS
+ color = n / NUM_HAIRS % NUM_COLORS
+ func pack() -> int:
+ if robot: return 51
+ return (hair + color * NUM_HAIRS) * (-1 if customer else 1)
+
func _ready():
play_animation("idle")
var t := 0.0
func _process(delta):
- if walking:
- t += delta
- main_height_target = default_height + sin(t * WALK_ANIM_SPEED) * WALK_ANIM_STRENGTH
- else:
- t = 0
+ t += delta
+ if walking: main_height_target = default_height + sin(t * WALK_ANIM_SPEED) * WALK_ANIM_STRENGTH
+ else: t = 0
main.position.y = main_height_target
# Update animation:
var next_animation: String
- if holding:
- next_animation = "hold"
- elif cutting:
- next_animation = "cut"
- elif walking:
- next_animation = "walk"
- else:
- next_animation = "idle"
+ if holding: next_animation = "hold"
+ elif cutting: next_animation = "cut"
+ elif walking: next_animation = "walk"
+ else: next_animation = "idle"
+
+ if current_animation != next_animation:
+ play_animation(next_animation)
walking_particles.emitting = walking
if boosting and walking and not was_boosting:
@@ -85,47 +103,31 @@ func _process(delta):
boosting_particles.emitting = false
was_boosting = boosting and walking
- if current_animation != next_animation:
- play_animation(next_animation)
-
-func select_hairstyle(id: int):
- if id == 51:
- toggle_robot(true)
- return
- if id < 0:
- to_customer()
- id *= -1
- var hairstyle_count = hairstyles.keys().size()
- id = id % hairstyle_count
- var target = hairstyles.keys()[id]
- for k in hairstyles.keys():
- if k == target:
- hairstyles[k].show()
- else:
- hairstyles[k].hide()
-
-func to_customer():
- main.mesh = CUSTOMER_MAIN_MESH
- tie.queue_free()
+func set_style(id: int):
+ var p = ParsedStyle.new(id)
+ set_customer(p.customer)
+ set_robot(p.robot)
+ for h in hairstyles: h.hide()
+ hairstyles[p.hair].show()
+ $Main.get_active_material(0).albedo_color = colors[p.color]
-func toggle_robot(b: bool):
+func set_customer(b: bool):
if b:
- head_robot.show()
- head_default.hide()
- main.mesh = ROBOT_MAIN_MESH
- else:
- head_robot.hide()
- head_default.show()
- main.mesh = DEFAULT_MAIN_MESH
+ main.mesh = CUSTOMER_MAIN_MESH
+ tie.queue_free()
+ else: pass # TODO
+
+func set_robot(b: bool):
+ head_robot.visible = b
+ head_default.visible = not b
+ main.mesh = ROBOT_MAIN_MESH if b else DEFAULT_MAIN_MESH
func play_animation(name_: String):
current_animation = name_
hand_animations.play(name_)
- if name_ == "walk":
- step_sounds.start_autoplay()
- else:
- step_sounds.stop_autoplay()
+ if name_ == "walk": step_sounds.start_autoplay()
+ else: step_sounds.stop_autoplay()
knife.visible = name_ == "cut"
diff --git a/client/player/character/character.tscn b/client/player/character/character.tscn
index a7c09c01..aca0658a 100644
--- a/client/player/character/character.tscn
+++ b/client/player/character/character.tscn
@@ -1,4 +1,4 @@
-[gd_scene load_steps=27 format=3 uid="uid://b3hhir2fvnunu"]
+[gd_scene load_steps=28 format=3 uid="uid://b3hhir2fvnunu"]
[ext_resource type="Script" path="res://player/character/character.gd" id="1_12lbh"]
[ext_resource type="ArrayMesh" uid="uid://bnmm01yjwultj" path="res://player/character/default/main.res" id="2_uovyg"]
@@ -18,6 +18,11 @@
[ext_resource type="AudioStream" uid="uid://1jsqpnk3igj3" path="res://player/sounds/woosh1.ogg" id="14_ikcec"]
[ext_resource type="AudioStream" uid="uid://cwme7eatip0jc" path="res://player/sounds/woosh2.ogg" id="15_iv4wu"]
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_7ojaw"]
+resource_local_to_scene = true
+resource_name = "main"
+cull_mode = 2
+
[sub_resource type="Animation" id="Animation_tdhvg"]
length = 0.001
tracks/0/type = "bezier"
@@ -729,6 +734,7 @@ script = ExtResource("1_12lbh")
transform = Transform3D(0.33, 0, 0, 0, 0.33, 0, 0, 0, 0.33, 0, 0.33, 0)
mesh = ExtResource("2_uovyg")
skeleton = NodePath("")
+surface_material_override/0 = SubResource("StandardMaterial3D_7ojaw")
[node name="HandRight" type="MeshInstance3D" parent="Main"]
transform = Transform3D(0.287144, 0.2864, -1.17785e-06, 0.402357, -0.133775, 0.337554, 0.292329, -0.0971941, -0.464603, -1.302, -0.17, 0)
diff --git a/client/player/controllable_player.gd b/client/player/controllable_player.gd
index 0cabcb64..131bc55d 100644
--- a/client/player/controllable_player.gd
+++ b/client/player/controllable_player.gd
@@ -43,7 +43,7 @@ func _ready():
add_child(timer)
timer.start()
timer.connect("timeout", func():
- if game.mp != null and game.join_sent:
+ if game.mp != null and game.join_state == Game.JoinState.JOINED:
game.mp.send_movement(game.player_id, position_, direction, boosting)
)
add_child(onscreen_controls)
@@ -60,13 +60,20 @@ func _process(delta):
update_touch_scrolls()
var moving_duration = 0
+var fps_rotation_target = 0
func _process_movement(delta):
var input = Input.get_vector("left", "right", "forwards", "backwards") if is_input_enabled() else Vector2.ZERO
if Global.get_setting("gameplay.first_person"):
- input.x *= 0.1
+ fps_rotation_target += input.x * delta * 3.
+ if abs(input.x) > 0.1: input.y -= 0.5
+ input.x = 0.
input.y = min(input.y, 0)
+ input = input.rotated(fps_rotation_target)
+ else:
+ input = input.rotated(input_rotation)
+
var boost = Input.is_action_pressed("boost") or (Global.get_setting("gameplay.latch_boost") and boosting)
- input = input.rotated(input_rotation)
+ #
if Input.is_action_pressed("interact") or Input.is_action_just_released("interact"):
input *= 0
else:
diff --git a/client/player/player.gd b/client/player/player.gd
index 31a7a337..6ff28e81 100644
--- a/client/player/player.gd
+++ b/client/player/player.gd
@@ -79,7 +79,7 @@ func _init(_id: int, new_name: String, pos: Vector2, new_character_idx: int, new
is_customer = character_idx < 0
func _ready():
- character.select_hairstyle(character_idx)
+ character.set_style(character_idx)
clear_timer.timeout.connect(clear_message)
Settings.hook_changed_init("gameplay.usernames", false, update_username_tag)