Implement 40250 classic client port

This commit is contained in:
shenlei
2026-09-01 18:49:28 +09:00
parent 2277b1dd60
commit 8f61990a83
481 changed files with 169826 additions and 293 deletions
+112 -4
View File
@@ -19,6 +19,7 @@ const PlayerView = preload("res://ui/player_view.gd")
signal select_requested(index: int)
signal delete_requested(index: int, private_code: String)
signal create_requested(spec: Dictionary) # {slot, name, job, shape, con, int, str, dex}
signal change_name_requested(index: int, name: String)
signal back_requested()
const CLASS_CN := ["猛将", "刺客", "术士", "巫女"]
@@ -55,6 +56,8 @@ var _class_lbl: Label
var _status: Label
var _slot_lbl: Label
var _spin := 0.0
var _last_empire := -1
var _rename_pending := false
func setup(client: Node, assets_root: String, chars: Array) -> void:
_client = client
@@ -66,6 +69,7 @@ func setup(client: Node, assets_root: String, chars: Array) -> void:
_build_class_name()
_build_panel()
_build_status()
_last_empire = _empire_id()
set_process(true)
_select(_first_occupied())
@@ -107,9 +111,33 @@ func on_char_created(slot: int) -> void:
_set_status("角色已创建(槽位 %d" % slot)
func on_char_create_failed(reason_type: int) -> void:
if _rename_pending:
_rename_pending = false
const RENAME_R := {0: "名称不合法", 1: "该名称已被使用", 100: "角色槽位无效"}
_set_status("改名失败:%s" % RENAME_R.get(reason_type, "错误码 %d" % reason_type))
return
const R := {1: "该名称已被使用", 2: "名称不合法", 3: "该槽位已有角色", 4: "权限不足"}
_set_status("创建失败:%s" % R.get(reason_type, "错误码 %d" % reason_type))
func on_char_name_send_failed() -> void:
_rename_pending = false
_set_status("改名请求发送失败")
func on_char_name_changed(pid: int, name: String) -> void:
var matched := false
for c in _chars:
if int(c.get("id", 0)) == pid:
matched = true
c["name"] = name
c["change_name"] = false
if not matched and _rename_pending:
return
_rename_pending = false
_close_dialog()
_refresh_class_name()
_refresh_panel()
_set_status("角色已改名:%s" % name)
func on_char_deleted(slot: int) -> void:
_close_dialog()
_set_status("角色已删除(槽位 %d" % slot)
@@ -342,6 +370,32 @@ func _refresh_panel() -> void:
_panel_box.add_child(_sep())
# A fresh account has no empire yet. 40250 keeps the connection in the
# select phase and expects CG_EMPIRE before character creation/selection;
# expose that real protocol step instead of leaving the page apparently
# idle with a permanently disabled start button.
var empire_required := _empire_id() == 0
if empire_required:
_panel_box.add_child(_plain("请选择阵营", 14, Color(0.95, 0.85, 0.55)))
var erow := HBoxContainer.new()
erow.add_theme_constant_override("separation", 6)
_panel_box.add_child(erow)
for eid in [1, 2, 3]:
var empire_id: int = eid
var eb := Button.new()
eb.text = _empire_name_for(empire_id)
eb.custom_minimum_size = Vector2(82, 30)
eb.pressed.connect(func():
if _client == null or not _client.has_method("select_empire"):
_set_status("当前网络后端不支持选择阵营")
return
if bool(_client.call("select_empire", empire_id)):
_set_status("已发送阵营选择:%s" % _empire_name_for(empire_id))
else:
_set_status("阵营选择发送失败")
)
erow.add_child(eb)
# 槽位切换
if _chars.size() > 1:
var nav := HBoxContainer.new()
@@ -366,19 +420,19 @@ func _refresh_panel() -> void:
var start := Button.new()
start.text = "开始"
start.custom_minimum_size = Vector2(122, 34)
start.disabled = not has_char
start.disabled = not has_char or empire_required
start.pressed.connect(_do_start)
brow.add_child(start)
var create := Button.new()
create.text = "创建"
create.custom_minimum_size = Vector2(122, 34)
create.disabled = has_char
create.disabled = has_char or empire_required
create.pressed.connect(_open_create_dialog)
brow.add_child(create)
var del := Button.new()
del.text = "删除"
del.custom_minimum_size = Vector2(122, 34)
del.disabled = not has_char
del.disabled = not has_char or empire_required
del.pressed.connect(_open_delete_dialog)
brow.add_child(del)
var quit := Button.new()
@@ -432,6 +486,11 @@ func _do_start() -> void:
if d.is_empty() or String(d.get("name", "")) == "":
_set_status("空槽位不能进入")
return
# 40250's original select screen forces a character marked with
# change_name to complete the rename flow before entering the world.
if bool(d.get("change_name", false)):
_open_change_name_dialog()
return
select_requested.emit(_slot_index())
_set_status("进入游戏:%s" % d.get("name"))
@@ -546,6 +605,49 @@ func _open_create_dialog() -> void:
cancel.pressed.connect(_close_dialog)
brow.add_child(cancel)
func _open_change_name_dialog() -> void:
var d := _cur()
if String(d.get("name", "")) == "":
_set_status("空槽位不能改名")
return
var slot := _slot_index()
var box := _modal_root("修改角色名称", 400, 250)
box.add_child(_plain("该角色需要先修改名称才能进入游戏。", 13,
Color(0.95, 0.75, 0.7)))
var nrow := HBoxContainer.new()
nrow.add_theme_constant_override("separation", 8)
box.add_child(nrow)
nrow.add_child(_plain("新名称", 13, Color(0.72, 0.78, 0.85)))
var name_edit := LineEdit.new()
name_edit.name = "Name"
name_edit.max_length = 12
name_edit.custom_minimum_size = Vector2(220, 0)
name_edit.placeholder_text = "角色名(最多 12"
nrow.add_child(name_edit)
box.add_child(_sep())
var brow := HBoxContainer.new()
brow.alignment = BoxContainer.ALIGNMENT_CENTER
brow.add_theme_constant_override("separation", 16)
box.add_child(brow)
var ok := Button.new()
ok.text = "改名"
ok.custom_minimum_size = Vector2(120, 34)
ok.pressed.connect(func():
var nm := name_edit.text.strip_edges()
if nm.length() < 2:
_set_status("名称太短")
return
_rename_pending = true
_close_dialog()
_set_status("改名中…")
change_name_requested.emit(slot, nm))
brow.add_child(ok)
var cancel := Button.new()
cancel.text = "取消"
cancel.custom_minimum_size = Vector2(120, 34)
cancel.pressed.connect(_close_dialog)
brow.add_child(cancel)
func _open_delete_dialog() -> void:
var d := _cur()
if String(d.get("name", "")) == "":
@@ -587,7 +689,9 @@ func _empire_id() -> int:
return 0
func _empire_name() -> String:
var e := _empire_id()
return _empire_name_for(_empire_id())
func _empire_name_for(e: int) -> String:
# 优先 locale_game.txt 的 EMPIRE_A/B/C
var key: String = EMPIRE_KEY.get(e, "")
if key != "":
@@ -625,6 +729,10 @@ func _empire_flag_tex() -> Texture2D:
func _process(dt: float) -> void:
_spin += dt
var empire := _empire_id()
if empire != _last_empire:
_last_empire = empire
_refresh_panel()
if _pivot:
# 正面朝相机 + 轻微来回摆
_pivot.rotation.y = PI + sin(_spin * 0.3) * 0.35