summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Weipert <git@mail.dweipert.de>2024-12-30 15:15:01 +0100
committerDaniel Weipert <git@mail.dweipert.de>2024-12-30 15:15:01 +0100
commite08a29e73ea4f7e6d78e8e7f5a6e7033dbc1f542 (patch)
tree966b95a7cdad16f7658d2e10cec6e549f3b98c17
parent6e2deea3d1b2fb4d79dac02a0d4310936c7f317c (diff)
next commitHEADmain
-rw-r--r--.gitignore5
-rw-r--r--client.gd33
-rw-r--r--client.tscn2
-rw-r--r--data_models/login_character_list.gd16
-rw-r--r--extractor/gat_format.gd18
-rw-r--r--extractor/gnd_format.gd11
-rw-r--r--extractor/grf.gd5
-rw-r--r--extractor/rsm_format.gd87
-rw-r--r--packets/map_server/initial_status_packet.gd2
-rw-r--r--packets/map_server/update_hotkeys_packet.gd2
-rw-r--r--ui/chat_window.tscn2
-rw-r--r--ui/login.gd29
-rw-r--r--ui/login.tscn37
-rw-r--r--ui/login/character_selection_item.gd54
-rw-r--r--ui/login/character_selection_item.tscn19
-rw-r--r--ui/login/character_selection_status.gd18
-rw-r--r--ui/login/character_selection_status.tscn36
-rw-r--r--ui/login/login_character_selection_list.gd111
-rw-r--r--ui/login/login_character_selection_list.tscn61
-rw-r--r--ui/theme_clear.tres4
-rw-r--r--ui/window.gd1
-rw-r--r--ui/window.tscn5
22 files changed, 457 insertions, 101 deletions
diff --git a/.gitignore b/.gitignore
index 653681f..375f419 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,9 +3,6 @@
*.gd.uid
/android/
-/client_data/*.grf
-/client_data/data/
-/client_data/BGM/
-/client_data/System/
+/client_data/
/extractor/test/
diff --git a/client.gd b/client.gd
index 5025c8c..3a69e9d 100644
--- a/client.gd
+++ b/client.gd
@@ -21,19 +21,26 @@ func _ready() -> void:
#FileAccess.get_file_as_bytes("res://client_data/data/sprite/cursors.act")
#)
#)
- GATFormat.from_bytes(
- ByteStream.from_bytes(
- FileAccess.get_file_as_bytes("res://client_data/data/int_land02.gat")
- )
- )
- GNDFormat.from_bytes(
- ByteStream.from_bytes(
- FileAccess.get_file_as_bytes("res://client_data/data/int_land02.gnd")
- )
- )
- RSWFormat.from_bytes(
+ #GATFormat.from_bytes(
+ #ByteStream.from_bytes(
+ #FileAccess.get_file_as_bytes("res://client_data/data/int_land02.gat")
+ #)
+ #)
+ #GNDFormat.from_bytes(
+ #ByteStream.from_bytes(
+ #FileAccess.get_file_as_bytes("res://client_data/data/int_land02.gnd")
+ #)
+ #)
+ #RSWFormat.from_bytes(
+ #ByteStream.from_bytes(
+ ##FileAccess.get_file_as_bytes("res://client_data/data/int_land02.rsw")
+ #FileAccess.get_file_as_bytes("res://client_data/data/pay_dun00.rsw")
+ #)
+ #)
+ RSMFormat.from_bytes(
ByteStream.from_bytes(
- #FileAccess.get_file_as_bytes("res://client_data/data/int_land02.rsw")
- FileAccess.get_file_as_bytes("res://client_data/data/pay_dun00.rsw")
+ #FileAccess.get_file_as_bytes("res://client_data/data/model/prontera/chair_01.rsm")
+ FileAccess.get_file_as_bytes("res://client_data/data/model/izlude/iz_academy.rsm")
+ # TODO: find newer version rsm to test
)
)
diff --git a/client.tscn b/client.tscn
index 9578f9d..c9d2006 100644
--- a/client.tscn
+++ b/client.tscn
@@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=3 uid="uid://cuylx656oarpy"]
-[ext_resource type="Script" uid="uid://dsiqqaly54ms0" path="res://client.gd" id="1_e4txq"]
+[ext_resource type="Script" uid="uid://u2h0eahwiv1u" path="res://client.gd" id="1_e4txq"]
[ext_resource type="PackedScene" uid="uid://n0y3fpb8j820" path="res://ui/cursor.tscn" id="2_abx5m"]
[node name="Client" type="Node"]
diff --git a/data_models/login_character_list.gd b/data_models/login_character_list.gd
new file mode 100644
index 0000000..f34d61e
--- /dev/null
+++ b/data_models/login_character_list.gd
@@ -0,0 +1,16 @@
+class_name LoginCharacterList
+extends Resource
+
+
+var slot_count: int
+
+var character_information: Array[CharacterInformation]
+
+
+static func from_character_list_packet(packet: CharacterServerLoginSuccessCharacterListPacket) -> LoginCharacterList:
+ var resource := LoginCharacterList.new()
+
+ resource.slot_count = packet.maximum_slot_count
+ resource.character_information = packet.character_information
+
+ return resource
diff --git a/extractor/gat_format.gd b/extractor/gat_format.gd
index 712657b..7192cbc 100644
--- a/extractor/gat_format.gd
+++ b/extractor/gat_format.gd
@@ -42,6 +42,14 @@ static func from_bytes(bytes: ByteStream) -> GATFormat:
return gat_format
+enum TileFlags {
+ Walkable = 0b00000001,
+ Water = 0b00000010,
+ Snipable = 0b00000100,
+ Cliff = 0b00001000,
+}
+
+
class Tile:
## Byte Type: f32 [br]
## Byte Length: 4 [br]
@@ -63,12 +71,12 @@ class Tile:
## Orignal Coordinates: (1, 1)
var top_right_altitude: int
- ## Byte Type: u32 ?[br]
- ## Byte Length: 4 ?
+ ## Byte Type: u8 [br]
+ ## Byte Length: 1
var terrain_type: int
- func get_height_map() -> Dictionary: # Dictionary[Vector2, int]
+ func get_height_map() -> Dictionary[Vector2, int]:
return {
Vector2(0, 0): top_left_altitude,
Vector2(1, 0): top_right_altitude,
@@ -84,6 +92,8 @@ class Tile:
tile.bottom_right_altitude = bytes.decode_float()
tile.top_left_altitude = bytes.decode_float()
tile.top_right_altitude = bytes.decode_float()
- tile.terrain_type = bytes.decode_u32()
+ tile.terrain_type = bytes.decode_u8()
+
+ bytes.advance(3) # unused
return tile
diff --git a/extractor/gnd_format.gd b/extractor/gnd_format.gd
index f13956e..ea8d965 100644
--- a/extractor/gnd_format.gd
+++ b/extractor/gnd_format.gd
@@ -211,7 +211,7 @@ class Surface:
var vertex_color_alpha: int
- func get_uvs() -> Dictionary: # Dictionary[Vector2, Vector2]
+ func get_uvs() -> Dictionary[Vector2, Vector2]:
return {
Vector2(0, 0): Vector2(u_top_left, v_top_left),
Vector2(1, 0): Vector2(u_top_right, v_top_right),
@@ -220,6 +220,15 @@ class Surface:
}
+ func get_vertex_color() -> Color:
+ return Color8(
+ vertex_color_red,
+ vertex_color_green,
+ vertex_color_blue,
+ vertex_color_alpha
+ )
+
+
static func from_bytes(bytes: ByteStream) -> Surface:
var surface = Surface.new()
diff --git a/extractor/grf.gd b/extractor/grf.gd
index e2a3c82..1d19046 100644
--- a/extractor/grf.gd
+++ b/extractor/grf.gd
@@ -446,6 +446,11 @@ func convert(destination: String = "res://client_data"):
scene_root.add_child(audio, true)
audio.owner = scene_root
+ var surfrace_tool := SurfaceTool.new()
+ for surface: GNDFormat.Surface in gnd.surfaces:
+ pass
+ #surfrace_tool.add_vertex()
+
scene.pack(scene_root)
ResourceSaver.save(scene, "%s/%s/%s.tscn" % [destination, base_directory_path, file_name])
diff --git a/extractor/rsm_format.gd b/extractor/rsm_format.gd
new file mode 100644
index 0000000..d3dabb0
--- /dev/null
+++ b/extractor/rsm_format.gd
@@ -0,0 +1,87 @@
+class_name RSMFormat
+
+
+## Byte Length: 4 [br]
+## GRAT
+var signature: String = "GRSM"
+
+## Byte Type: u8 [br]
+## Byte Length: 2
+var version: Version
+
+## Byte Type: u32 [br]
+## Byte Length: 4
+var animation_length: int
+
+## Byte Type: u32 [br]
+## Byte Length: 4
+var shade_type: int
+
+## Byte Type: u8 [br]
+## Byte Length: 1
+## Versions: [>=1.4]
+var alpha: int
+
+## Byte Type: u8 [br]
+## Byte Length: 16
+## Versions: [<2.2]
+var reserved: PackedByteArray
+
+## Byte Type: f32 [br]
+## Byte Length: 4
+## Versions: [>=2.2]
+var frames_per_second: float
+
+## Byte Type: u32 [br]
+## Byte Length: 4
+## Versions: [<2.3]
+var texture_count: int
+
+## Length: [member texture_count]
+## Byte Length: 40
+var texture_names: Array[String]
+
+## Byte Type: u8
+## Byte Length: 40
+var root_node_name: String
+
+## Byte Type: u32 [br]
+## Byte Length: 4
+## Versions: [>=2.2]
+var root_node_count: int
+
+## Length: [member root_node_count]
+## Byte Length: 40
+var root_node_names: Array[String]
+
+## Byte Type: u32 [br]
+## Byte Length: 4
+var node_count: int
+
+## Length: [member node_count]
+var nodes: Array[ModelNode]
+
+
+static func from_bytes(bytes: ByteStream) -> RSMFormat:
+ var rsm_format = RSMFormat.new()
+
+ bytes.advance(rsm_format.signature.length())
+
+ @warning_ignore("shadowed_variable")
+ var version = Version.new()
+ version.major = bytes.decode_u8()
+ version.minor = bytes.decode_u8()
+ rsm_format.version = version
+
+ print(inst_to_dict(rsm_format))
+ return rsm_format
+
+
+class ModelNode:
+ ## Byte Type: u8 [br]
+ ## Byte Length: 40
+ var node_name: String
+
+ ## Byte Type: u8 [br]
+ ## Byte Length: 40
+ var parent_node_name: String
diff --git a/packets/map_server/initial_status_packet.gd b/packets/map_server/initial_status_packet.gd
index 9c41ef9..43b65fe 100644
--- a/packets/map_server/initial_status_packet.gd
+++ b/packets/map_server/initial_status_packet.gd
@@ -12,7 +12,7 @@ const BYTE_LENGTH := 2 + 14 + 28
# TODO
-static func from_bytes(bytes: PackedByteArray) -> InitialStatusPacket:
+static func from_bytes(_bytes: PackedByteArray) -> InitialStatusPacket:
var packet = InitialStatusPacket.new()
return packet
diff --git a/packets/map_server/update_hotkeys_packet.gd b/packets/map_server/update_hotkeys_packet.gd
index f991a7e..3788d1d 100644
--- a/packets/map_server/update_hotkeys_packet.gd
+++ b/packets/map_server/update_hotkeys_packet.gd
@@ -11,7 +11,7 @@ const BYTE_LENGTH := 2 + 1 + 2 + 7*38
# TODO
-static func from_bytes(bytes: PackedByteArray) -> UpdateHotkeysPacket:
+static func from_bytes(_bytes: PackedByteArray) -> UpdateHotkeysPacket:
var packet = UpdateHotkeysPacket.new()
return packet
diff --git a/ui/chat_window.tscn b/ui/chat_window.tscn
index 5b4e8aa..e67d360 100644
--- a/ui/chat_window.tscn
+++ b/ui/chat_window.tscn
@@ -1,6 +1,6 @@
[gd_scene load_steps=3 format=3 uid="uid://c8uqw08hxfqlu"]
-[ext_resource type="Script" uid="uid://bdjmcp6ewhq54" path="res://ui/chat_window.gd" id="1_vovuq"]
+[ext_resource type="Script" uid="uid://cy5bwkc4gokw1" path="res://ui/chat_window.gd" id="1_vovuq"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ku06j"]
bg_color = Color(0.133333, 0.133333, 0.133333, 0.784314)
diff --git a/ui/login.gd b/ui/login.gd
index 3180024..8cabec8 100644
--- a/ui/login.gd
+++ b/ui/login.gd
@@ -88,23 +88,20 @@ func _on_character_server_login_pressed(character_server_info: CharacterServerIn
var character_list: CharacterServerLoginSuccessCharacterListPacket = await Network.character_server.logged_in_character_list
- for node in %CharacterList.get_children():
- node.queue_free()
-
- for slot_idx in character_list.character_information.size():
- var info: CharacterInformation = character_list.character_information[slot_idx]
- var character = preload("res://ui/login/character_selection_item.tscn").instantiate()
- character.initialize_with_info(info)
- character.selected.connect(func():
- current_character_slot_idx = slot_idx
- current_character_information = info
- %CharacterSelectionStatus.set_info(info)
- )
- %CharacterList.add_child(character)
+ var login_character_list := LoginCharacterList.from_character_list_packet(character_list)
+ %CharacterSelectionList.login_character_list = login_character_list
+ %CharacterSelectionList.selected.connect(func(slot_idx: int):
+ current_character_slot_idx = slot_idx
+ %CharacterSelectionSlotLabel.text = "%s/%s" % [str(slot_idx + 1), login_character_list.slot_count]
- # pre-select first character
- if slot_idx == 0:
- character.selected.emit()
+ if slot_idx < character_list.character_information.size():
+ current_character_information = character_list.character_information[slot_idx]
+ else:
+ current_character_information = null
+ )
+
+ # pre-select first character
+ %CharacterSelectionList.select(0)
switch_screen(%CharacterSelection)
diff --git a/ui/login.tscn b/ui/login.tscn
index 9cba3ca..4842c26 100644
--- a/ui/login.tscn
+++ b/ui/login.tscn
@@ -1,7 +1,7 @@
[gd_scene load_steps=20 format=4 uid="uid://dser74lcd3a4g"]
[ext_resource type="Script" uid="uid://dqswsdaamfhbq" path="res://ui/login.gd" id="1_1m5cv"]
-[ext_resource type="Texture2D" uid="uid://cxd6dnc7s17vg" path="res://ui/login/backround.jpg" id="2_elmti"]
+[ext_resource type="Texture2D" uid="uid://cxd6dnc7s17vg" path="res://client_data/skin/login_background.jpg" id="2_elmti"]
[ext_resource type="AudioStream" uid="uid://br8ujl4uxv14a" path="res://client_data/BGM/01.mp3" id="3_2nukd"]
[ext_resource type="Theme" uid="uid://c5sm3yvuakj3b" path="res://ui/theme.tres" id="3_7ogdv"]
[ext_resource type="PackedScene" uid="uid://cjcm2mai50thr" path="res://ui/bmp_texture_button.tscn" id="3_qemc0"]
@@ -16,7 +16,7 @@
[ext_resource type="Texture2D" uid="uid://b13jh48hyjyrt" path="res://client_data/data/texture/À¯ÀúÀÎÅÍÆäÀ̽º/btn_next.bmp" id="14_pfdi0"]
[ext_resource type="Texture2D" uid="uid://bo277gh8uyw1w" path="res://client_data/data/texture/À¯ÀúÀÎÅÍÆäÀ̽º/btn_next_b.bmp" id="15_38pxr"]
[ext_resource type="Texture2D" uid="uid://qvmuk8xa3yej" path="res://client_data/data/texture/À¯ÀúÀÎÅÍÆäÀ̽º/btn_next_a.bmp" id="16_hqeko"]
-[ext_resource type="PackedScene" uid="uid://uo7qgv3ydh0q" path="res://ui/login/character_selection_status.tscn" id="16_tihdy"]
+[ext_resource type="PackedScene" uid="uid://bxbprntny8duj" path="res://ui/login/login_character_selection_list.tscn" id="16_tihdy"]
[ext_resource type="PackedScene" uid="uid://swtqlba1wi3o" path="res://ui/window.tscn" id="17_mma3j"]
[sub_resource type="AudioStreamWAV" id="AudioStreamWAV_f4kp2"]
@@ -72,6 +72,7 @@ theme_override_constants/margin_bottom = 15
[node name="VBoxContainer" type="VBoxContainer" parent="Login/Window/VBoxContainer/Body/MarginContainer"]
layout_mode = 2
+theme_override_constants/separation = 6
[node name="Username" type="HBoxContainer" parent="Login/Window/VBoxContainer/Body/MarginContainer/VBoxContainer"]
layout_mode = 2
@@ -249,23 +250,35 @@ text = "Cancel"
[node name="Window" parent="CharacterSelection" instance=ExtResource("17_mma3j")]
layout_mode = 2
-[node name="MarginContainer" type="MarginContainer" parent="CharacterSelection/Window/VBoxContainer/Body" index="0"]
+[node name="HBoxContainer" type="HBoxContainer" parent="CharacterSelection/Window/VBoxContainer/TitleBar/TitleBarElements" index="0"]
layout_mode = 2
-theme_override_constants/margin_left = 64
-theme_override_constants/margin_top = 16
-theme_override_constants/margin_right = 64
-theme_override_constants/margin_bottom = 16
-[node name="VBoxContainer" type="VBoxContainer" parent="CharacterSelection/Window/VBoxContainer/Body/MarginContainer"]
+[node name="Label" type="Label" parent="CharacterSelection/Window/VBoxContainer/TitleBar/TitleBarElements/HBoxContainer"]
+texture_filter = 1
+layout_mode = 2
+theme = ExtResource("9_toei2")
+text = "Character Select"
+
+[node name="-" type="Label" parent="CharacterSelection/Window/VBoxContainer/TitleBar/TitleBarElements/HBoxContainer"]
+texture_filter = 1
layout_mode = 2
-theme_override_constants/separation = 32
+theme = ExtResource("9_toei2")
+text = "-"
-[node name="CharacterList" type="HBoxContainer" parent="CharacterSelection/Window/VBoxContainer/Body/MarginContainer/VBoxContainer"]
+[node name="CharacterSelectionSlotLabel" type="Label" parent="CharacterSelection/Window/VBoxContainer/TitleBar/TitleBarElements/HBoxContainer"]
unique_name_in_owner = true
+texture_filter = 1
+layout_mode = 2
+theme = ExtResource("9_toei2")
+
+[node name="MarginContainer" type="MarginContainer" parent="CharacterSelection/Window/VBoxContainer/Body" index="0"]
layout_mode = 2
-theme_override_constants/separation = 32
+theme_override_constants/margin_left = 64
+theme_override_constants/margin_top = 16
+theme_override_constants/margin_right = 64
+theme_override_constants/margin_bottom = 16
-[node name="CharacterSelectionStatus" parent="CharacterSelection/Window/VBoxContainer/Body/MarginContainer/VBoxContainer" instance=ExtResource("16_tihdy")]
+[node name="CharacterSelectionList" parent="CharacterSelection/Window/VBoxContainer/Body/MarginContainer" instance=ExtResource("16_tihdy")]
unique_name_in_owner = true
layout_mode = 2
diff --git a/ui/login/character_selection_item.gd b/ui/login/character_selection_item.gd
index 7ad77b6..fa0fad8 100644
--- a/ui/login/character_selection_item.gd
+++ b/ui/login/character_selection_item.gd
@@ -4,14 +4,22 @@ extends PanelContainer
signal selected
-static var selected_item: CharacterSelectionItem:
+var is_hovered := false:
set(value):
- var previous_item = selected_item
- selected_item = value
- if previous_item:
- previous_item.draw_highlight(false)
+ is_hovered = value
+ draw_highlight(value)
+
+var is_selected := false:
+ set(value):
+ is_selected = value
+ draw_highlight(false)
+ if value:
+ selected.emit()
-var is_hovered := false
+
+func _ready() -> void:
+ clear()
+ %SelectionBorder.visible = false
func initialize_with_info(info: CharacterInformation):
@@ -21,6 +29,7 @@ func initialize_with_info(info: CharacterInformation):
Constants.FilePaths.get_player_head(info.gender, info.head),
]
)
+ %Head.visible = true
%Body.texture = load(
"%s/%s/000.png" % [
@@ -28,30 +37,43 @@ func initialize_with_info(info: CharacterInformation):
Constants.FilePaths.get_player_body(info.gender, info.job),
]
)
-
- %Name.text = info.name
+ %Body.visible = true
+
+
+func clear():
+ %Head.visible = false
+ %Body.visible = false
func draw_highlight(is_highlighted: bool):
- if selected_item == self:
- is_highlighted = true
-
var style_box: StyleBoxFlat = get_theme_stylebox("panel").duplicate()
style_box.draw_center = is_highlighted
add_theme_stylebox_override("panel", style_box)
+
+ if is_selected:
+ %SelectionBorder.visible = true
+ var style_box2: StyleBoxFlat = get_theme_stylebox("panel").duplicate()
+ style_box2.border_color.a = 0.0
+ add_theme_stylebox_override("panel", style_box2)
+
+ # spacing "fix"
+ #%SelectionBorder.top_level = true
+ #await get_tree().process_frame
+ #%SelectionBorder.global_position = global_position
+ else:
+ %SelectionBorder.visible = false
+ var style_box2: StyleBoxFlat = get_theme_stylebox("panel").duplicate()
+ style_box2.border_color.a = 1.0
+ add_theme_stylebox_override("panel", style_box2)
func _on_gui_input(event: InputEvent) -> void:
if event.is_pressed():
- selected_item = self
- draw_highlight(true)
- selected.emit()
+ is_selected = true
func _on_mouse_entered() -> void:
is_hovered = true
- draw_highlight(is_hovered)
func _on_mouse_exited() -> void:
is_hovered = false
- draw_highlight(is_hovered)
diff --git a/ui/login/character_selection_item.tscn b/ui/login/character_selection_item.tscn
index adc37bb..4b8a249 100644
--- a/ui/login/character_selection_item.tscn
+++ b/ui/login/character_selection_item.tscn
@@ -1,9 +1,10 @@
-[gd_scene load_steps=6 format=3 uid="uid://rrd131rq74n5"]
+[gd_scene load_steps=7 format=3 uid="uid://rrd131rq74n5"]
[ext_resource type="Script" uid="uid://bsglhorusc7ug" path="res://ui/login/character_selection_item.gd" id="1_25yur"]
[ext_resource type="Texture2D" uid="uid://danymuvfjf4o1" path="res://client_data/data/sprite/Àΰ£Á·/¸Ó¸®Åë/³²/16_³²/000.png" id="2_aqbfs"]
[ext_resource type="Texture2D" uid="uid://cwqgdd00sf7pu" path="res://client_data/data/sprite/Àΰ£Á·/¸öÅë/³²/Ãʺ¸ÀÚ_³²/000.png" id="3_xv3pn"]
-[ext_resource type="Theme" uid="uid://c6y6r8kcnbb10" path="res://ui/theme_clear.tres" id="4_u21ok"]
+[ext_resource type="PackedScene" uid="uid://knmmuhon34rh" path="res://ui/bmp_texture_rect.tscn" id="4_vhrt2"]
+[ext_resource type="Texture2D" uid="uid://g2cx2uuvffe" path="res://client_data/data/texture/À¯ÀúÀÎÅÍÆäÀ̽º/login_interface/box_select.bmp" id="5_vhrt2"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_u21ok"]
bg_color = Color(0, 0, 0, 0.0980392)
@@ -15,9 +16,9 @@ border_width_bottom = 1
border_color = Color(0.760784, 0.760784, 0.760784, 1)
[node name="CharacterSelectionItem" type="PanelContainer"]
-custom_minimum_size = Vector2(150, 150)
-offset_right = 150.0
-offset_bottom = 163.0
+custom_minimum_size = Vector2(141, 146)
+offset_right = 141.0
+offset_bottom = 146.0
mouse_default_cursor_shape = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_u21ok")
script = ExtResource("1_25yur")
@@ -52,12 +53,12 @@ layout_mode = 2
texture = ExtResource("3_xv3pn")
stretch_mode = 3
-[node name="Name" type="Label" parent="MarginContainer/VBoxContainer"]
+[node name="SelectionBorder" parent="." instance=ExtResource("4_vhrt2")]
unique_name_in_owner = true
+show_behind_parent = true
layout_mode = 2
-theme = ExtResource("4_u21ok")
-text = "Name"
-horizontal_alignment = 1
+texture = ExtResource("5_vhrt2")
+stretch_mode = 4
[connection signal="gui_input" from="." to="." method="_on_gui_input"]
[connection signal="mouse_entered" from="." to="." method="_on_mouse_entered"]
diff --git a/ui/login/character_selection_status.gd b/ui/login/character_selection_status.gd
index 2c0e450..5bbd200 100644
--- a/ui/login/character_selection_status.gd
+++ b/ui/login/character_selection_status.gd
@@ -17,3 +17,21 @@ func set_info(info: CharacterInformation):
%Luk.text = str(info.luck)
%Map.text = info.map_name.substr(0, info.map_name.length() - 4)
+
+
+func clear():
+ %Name.text = ""
+ %Job.text = ""
+ %Level.text = ""
+ %Exp.text = ""
+ %Hp.text = ""
+ %Sp.text = ""
+
+ %Str.text = ""
+ %Agi.text = ""
+ %Vit.text = ""
+ %Int.text = ""
+ %Dex.text = ""
+ %Luk.text = ""
+
+ %Map.text = ""
diff --git a/ui/login/character_selection_status.tscn b/ui/login/character_selection_status.tscn
index 0de1865..31c5ab0 100644
--- a/ui/login/character_selection_status.tscn
+++ b/ui/login/character_selection_status.tscn
@@ -6,15 +6,15 @@
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_qjr2b"]
[node name="CharacterSelectionStatus" type="PanelContainer"]
-offset_right = 360.0
-offset_bottom = 158.0
+offset_right = 352.0
+offset_bottom = 152.0
theme = ExtResource("1_o7mxo")
theme_override_styles/panel = SubResource("StyleBoxEmpty_qjr2b")
script = ExtResource("2_nhn0f")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 2
-theme_override_constants/separation = 8
+theme_override_constants/separation = 2
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer"]
layout_mode = 2
@@ -32,11 +32,11 @@ custom_minimum_size = Vector2(45, 0)
layout_mode = 2
theme = ExtResource("1_o7mxo")
theme_type_variation = &"CharacterSelectionStatusLabel"
-text = "NAME"
+text = "Name"
[node name="Name" type="Label" parent="VBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer"]
unique_name_in_owner = true
-custom_minimum_size = Vector2(130, 0)
+custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 3
theme = ExtResource("1_o7mxo")
@@ -55,7 +55,7 @@ text = "STR"
[node name="Str" type="Label" parent="VBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer2"]
unique_name_in_owner = true
-custom_minimum_size = Vector2(130, 0)
+custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 3
theme = ExtResource("1_o7mxo")
@@ -74,11 +74,11 @@ custom_minimum_size = Vector2(45, 0)
layout_mode = 2
theme = ExtResource("1_o7mxo")
theme_type_variation = &"CharacterSelectionStatusLabel"
-text = "JOB"
+text = "Job"
[node name="Job" type="Label" parent="VBoxContainer/VBoxContainer/HBoxContainer2/HBoxContainer"]
unique_name_in_owner = true
-custom_minimum_size = Vector2(130, 0)
+custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 3
theme = ExtResource("1_o7mxo")
@@ -97,7 +97,7 @@ text = "AGI"
[node name="Agi" type="Label" parent="VBoxContainer/VBoxContainer/HBoxContainer2/HBoxContainer2"]
unique_name_in_owner = true
-custom_minimum_size = Vector2(130, 0)
+custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 3
theme = ExtResource("1_o7mxo")
@@ -120,7 +120,7 @@ text = "Lv."
[node name="Level" type="Label" parent="VBoxContainer/VBoxContainer/HBoxContainer3/HBoxContainer"]
unique_name_in_owner = true
-custom_minimum_size = Vector2(130, 0)
+custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 3
theme = ExtResource("1_o7mxo")
@@ -139,7 +139,7 @@ text = "VIT"
[node name="Vit" type="Label" parent="VBoxContainer/VBoxContainer/HBoxContainer3/HBoxContainer2"]
unique_name_in_owner = true
-custom_minimum_size = Vector2(130, 0)
+custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 3
theme = ExtResource("1_o7mxo")
@@ -162,7 +162,7 @@ text = "EXP"
[node name="Exp" type="Label" parent="VBoxContainer/VBoxContainer/HBoxContainer4/HBoxContainer"]
unique_name_in_owner = true
-custom_minimum_size = Vector2(130, 0)
+custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 3
theme = ExtResource("1_o7mxo")
@@ -181,7 +181,7 @@ text = "INT"
[node name="Int" type="Label" parent="VBoxContainer/VBoxContainer/HBoxContainer4/HBoxContainer2"]
unique_name_in_owner = true
-custom_minimum_size = Vector2(130, 0)
+custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 3
theme = ExtResource("1_o7mxo")
@@ -204,7 +204,7 @@ text = "HP"
[node name="Hp" type="Label" parent="VBoxContainer/VBoxContainer/HBoxContainer5/HBoxContainer"]
unique_name_in_owner = true
-custom_minimum_size = Vector2(130, 0)
+custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 3
theme = ExtResource("1_o7mxo")
@@ -223,7 +223,7 @@ text = "DEX"
[node name="Dex" type="Label" parent="VBoxContainer/VBoxContainer/HBoxContainer5/HBoxContainer2"]
unique_name_in_owner = true
-custom_minimum_size = Vector2(130, 0)
+custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 3
theme = ExtResource("1_o7mxo")
@@ -246,7 +246,7 @@ text = "SP"
[node name="Sp" type="Label" parent="VBoxContainer/VBoxContainer/HBoxContainer6/HBoxContainer"]
unique_name_in_owner = true
-custom_minimum_size = Vector2(130, 0)
+custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 3
theme = ExtResource("1_o7mxo")
@@ -265,7 +265,7 @@ text = "LUK"
[node name="Luk" type="Label" parent="VBoxContainer/VBoxContainer/HBoxContainer6/HBoxContainer2"]
unique_name_in_owner = true
-custom_minimum_size = Vector2(130, 0)
+custom_minimum_size = Vector2(120, 0)
layout_mode = 2
size_flags_horizontal = 3
theme = ExtResource("1_o7mxo")
@@ -284,7 +284,7 @@ text = "MAP"
[node name="Map" type="Label" parent="VBoxContainer/HBoxContainer"]
unique_name_in_owner = true
-custom_minimum_size = Vector2(307, 0)
+custom_minimum_size = Vector2(287, 0)
layout_mode = 2
theme = ExtResource("1_o7mxo")
theme_type_variation = &"CharacterSelectionStatusLabel2"
diff --git a/ui/login/login_character_selection_list.gd b/ui/login/login_character_selection_list.gd
new file mode 100644
index 0000000..221c47f
--- /dev/null
+++ b/ui/login/login_character_selection_list.gd
@@ -0,0 +1,111 @@
+class_name CharacterSelectionList
+extends Control
+
+
+signal selected(slot_idx: int)
+
+var item_scene := preload("res://ui/login/character_selection_item.tscn")
+
+var slot_offset := 0
+
+@export var displayed_slots_count: int = 3:
+ set = set_displayed_slots_count
+
+@export var selected_slot_index: int = -1:
+ set = set_selected_slot_index
+
+@export var login_character_list: LoginCharacterList:
+ set = set_login_character_list
+
+
+func _ready() -> void:
+ if %CharacterList.get_child_count() != displayed_slots_count:
+ set_displayed_slots_count(displayed_slots_count)
+
+
+func set_displayed_slots_count(value: int) -> void:
+ displayed_slots_count = value
+
+ for node in %CharacterList.get_children():
+ node.queue_free()
+
+ for _idx in displayed_slots_count:
+ var item = preload("res://ui/login/character_selection_item.tscn").instantiate()
+ %CharacterList.add_child(item)
+
+ draw()
+
+
+func set_selected_slot_index(value: int) -> void:
+ if selected_slot_index == value:
+ return
+
+ var character_list := login_character_list.character_information
+ var maximum_slot_count := login_character_list.slot_count
+
+ %CharacterList.get_child(selected_slot_index - slot_offset).is_selected = false
+
+ if value >= maximum_slot_count:
+ selected_slot_index = 0
+ elif value < 0:
+ selected_slot_index = maximum_slot_count - 1
+ else:
+ selected_slot_index = value
+
+ if selected_slot_index > slot_offset + (displayed_slots_count - 1):
+ #slot_offset = selected_slot_index - (displayed_slots_count - 1)
+ slot_offset = min(selected_slot_index, maximum_slot_count - displayed_slots_count)
+ elif selected_slot_index < slot_offset:
+ #slot_offset = selected_slot_index
+ slot_offset = max(0, selected_slot_index - displayed_slots_count)
+
+ draw()
+ %CharacterList.get_child(selected_slot_index - slot_offset).is_selected = true
+
+ if selected_slot_index < character_list.size():
+ %CharacterSelectionStatus.set_info(character_list[selected_slot_index])
+ else:
+ $CharacterSelectionStatus.clear()
+
+ selected.emit(selected_slot_index)
+
+
+func set_login_character_list(value: LoginCharacterList) -> void:
+ login_character_list = value
+ draw()
+
+
+func draw():
+ if not login_character_list:
+ return
+
+ var character_information: Array[CharacterInformation] = login_character_list.character_information
+
+ for display_slot_idx in displayed_slots_count:
+ var item: CharacterSelectionItem = %CharacterList.get_child(display_slot_idx)
+ var slot_idx = slot_offset + display_slot_idx
+
+ if slot_idx < character_information.size():
+ var info: CharacterInformation = character_information[slot_idx]
+ item.initialize_with_info(info)
+ else:
+ item.clear()
+
+ if item.selected.is_connected(_on_item_selected):
+ item.selected.disconnect(_on_item_selected)
+ item.selected.connect(_on_item_selected.bind(slot_idx))
+
+
+func select(slot_idx: int):
+ selected_slot_index = slot_idx
+
+
+func _on_item_selected(slot_idx: int):
+ selected_slot_index = slot_idx
+
+
+func _on_button_left_pressed() -> void:
+ selected_slot_index -= 1
+
+func _on_button_right_pressed() -> void:
+ selected_slot_index += 1
diff --git a/ui/login/login_character_selection_list.tscn b/ui/login/login_character_selection_list.tscn
new file mode 100644
index 0000000..1a5aba7
--- /dev/null
+++ b/ui/login/login_character_selection_list.tscn
@@ -0,0 +1,61 @@
+[gd_scene load_steps=11 format=3 uid="uid://bxbprntny8duj"]
+
+[ext_resource type="PackedScene" uid="uid://uo7qgv3ydh0q" path="res://ui/login/character_selection_status.tscn" id="1_5anyi"]
+[ext_resource type="Script" uid="uid://dmch4gi1khn2r" path="res://ui/login/login_character_selection_list.gd" id="1_togb6"]
+[ext_resource type="PackedScene" uid="uid://rrd131rq74n5" path="res://ui/login/character_selection_item.tscn" id="2_k142l"]
+[ext_resource type="PackedScene" uid="uid://cjcm2mai50thr" path="res://ui/bmp_texture_button.tscn" id="2_s7n6r"]
+[ext_resource type="Texture2D" uid="uid://s5uc6sa6y88f" path="res://client_data/data/texture/À¯ÀúÀÎÅÍÆäÀ̽º/select_character/chr_arrow_l_out.bmp" id="3_c5a25"]
+[ext_resource type="Texture2D" uid="uid://b8n4w8a4yumax" path="res://client_data/data/texture/À¯ÀúÀÎÅÍÆäÀ̽º/select_character/chr_arrow_l_press.bmp" id="4_ntkas"]
+[ext_resource type="Texture2D" uid="uid://e3k5tdqv2jft" path="res://client_data/data/texture/À¯ÀúÀÎÅÍÆäÀ̽º/select_character/chr_arrow_l_over.bmp" id="5_606nc"]
+[ext_resource type="Texture2D" uid="uid://bhap22qcv1mga" path="res://client_data/data/texture/À¯ÀúÀÎÅÍÆäÀ̽º/select_character/chr_arrow_r_out.bmp" id="7_c8nb3"]
+[ext_resource type="Texture2D" uid="uid://dvf7yx7b3dj4m" path="res://client_data/data/texture/À¯ÀúÀÎÅÍÆäÀ̽º/select_character/chr_arrow_r_press.bmp" id="8_p8h60"]
+[ext_resource type="Texture2D" uid="uid://4ngcs00s5cnn" path="res://client_data/data/texture/À¯ÀúÀÎÅÍÆäÀ̽º/select_character/chr_arrow_r_over.bmp" id="9_7p86f"]
+
+[node name="LoginCharacterSelectionList" type="VBoxContainer"]
+theme_override_constants/separation = 32
+script = ExtResource("1_togb6")
+
+[node name="MarginContainer" type="MarginContainer" parent="."]
+layout_mode = 2
+theme_override_constants/margin_left = -30
+theme_override_constants/margin_top = 0
+theme_override_constants/margin_right = 0
+
+[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer"]
+layout_mode = 2
+theme_override_constants/separation = 16
+alignment = 1
+
+[node name="ButtonLeft" parent="MarginContainer/HBoxContainer" instance=ExtResource("2_s7n6r")]
+texture_filter = 0
+layout_mode = 2
+texture_normal = ExtResource("3_c5a25")
+texture_pressed = ExtResource("4_ntkas")
+texture_hover = ExtResource("5_606nc")
+stretch_mode = 5
+
+[node name="CharacterList" type="HBoxContainer" parent="MarginContainer/HBoxContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+theme_override_constants/separation = 32
+
+[node name="CharacterSelectionItem" parent="MarginContainer/HBoxContainer/CharacterList" instance=ExtResource("2_k142l")]
+layout_mode = 2
+
+[node name="CharacterSelectionItem2" parent="MarginContainer/HBoxContainer/CharacterList" instance=ExtResource("2_k142l")]
+layout_mode = 2
+
+[node name="ButtonRight" parent="MarginContainer/HBoxContainer" instance=ExtResource("2_s7n6r")]
+texture_filter = 0
+layout_mode = 2
+texture_normal = ExtResource("7_c8nb3")
+texture_pressed = ExtResource("8_p8h60")
+texture_hover = ExtResource("9_7p86f")
+stretch_mode = 5
+
+[node name="CharacterSelectionStatus" parent="." instance=ExtResource("1_5anyi")]
+unique_name_in_owner = true
+layout_mode = 2
+
+[connection signal="pressed" from="MarginContainer/HBoxContainer/ButtonLeft" to="." method="_on_button_left_pressed"]
+[connection signal="pressed" from="MarginContainer/HBoxContainer/ButtonRight" to="." method="_on_button_right_pressed"]
diff --git a/ui/theme_clear.tres b/ui/theme_clear.tres
index a02f1b4..5805499 100644
--- a/ui/theme_clear.tres
+++ b/ui/theme_clear.tres
@@ -65,9 +65,9 @@ texture = SubResource("GradientTexture2D_je15x")
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_f5aki"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_f5aki"]
-content_margin_left = 2.0
+content_margin_left = 3.0
content_margin_top = 0.0
-content_margin_right = 2.0
+content_margin_right = 3.0
content_margin_bottom = 0.0
bg_color = Color(0.94902, 0.94902, 0.94902, 1)
border_width_left = 1
diff --git a/ui/window.gd b/ui/window.gd
index cd6fade..25b0988 100644
--- a/ui/window.gd
+++ b/ui/window.gd
@@ -8,6 +8,7 @@ var drag_anchor := Vector2.ZERO
func _process(_delta: float) -> void:
if is_dragging:
global_position += get_global_mouse_position() - drag_anchor
+ #%TitleBar.size # TODO: use title bar size as min/max. dont let the bar vanish
drag_anchor = get_global_mouse_position()
diff --git a/ui/window.tscn b/ui/window.tscn
index 6208682..5a0ecc9 100644
--- a/ui/window.tscn
+++ b/ui/window.tscn
@@ -17,8 +17,8 @@ border_width_right = 1
border_color = Color(0.760784, 0.760784, 0.760784, 1)
[node name="Window" type="PanelContainer"]
-offset_right = 209.0
-offset_bottom = 136.0
+offset_right = 432.0
+offset_bottom = 188.0
script = ExtResource("1_hfgic")
[node name="VBoxContainer" type="VBoxContainer" parent="."]
@@ -26,6 +26,7 @@ layout_mode = 2
theme_override_constants/separation = 0
[node name="TitleBar" type="PanelContainer" parent="VBoxContainer"]
+unique_name_in_owner = true
layout_mode = 2
[node name="TitleBarBackground" type="HBoxContainer" parent="VBoxContainer/TitleBar"]