feat(client): 完成40250客户端核心功能1:1对齐与桥梁高度采样修复
- 桥梁与静态物体高度采样修复: - 严格对齐 40250 CMapOutdoor::GetHeight 与 CAttributeInstance::GetHeight - 解析 .mdatr 中的 AttributeHeight 网格,使用 is_in_triangle_2d 准确计算桥面多边形平面方程 - sample_height 查询邻近区块并返回 fMAX(fObjectHeight, fTerrainHeight),彻底解决走上桥面穿透掉入水底/河床的问题 - 新增 test_bridge_height_parity.gd 自动化对拍测试 - 40250 怪物击杀经验动效: - 1:1 实现 FLY_EXP(0) / FLY_HP / FLY_SP 粒子轨迹与爆炸吸附 - 40250 客户端全系统功能对齐(Batches 1-31): - 包含公会、交易、骑乘、变身、钓鱼、采矿、商城、信件、结婚、地牢等 134 套对拍系统与自动化回归测试 - 文档沉淀: - 新增 docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md 客户端对拍缺陷发现与修复工程指南
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
# monarch_election_ui_system.gd —— 40250 帝国君主大选投票公示系统 1:1
|
||||
# 严格对照:
|
||||
# metin2/src/server/game/src/monarch.h, monarch.cpp (CMonarch)
|
||||
# metin2/src/server/share/locale/english/quest/xxx_monarch.quest
|
||||
# 40250/Server Client TMP4/mysql/player/monarch_candidacy.MYD, monarch_election.MYD
|
||||
extends RefCounted
|
||||
|
||||
const EMPIRE_SHINSOO := 1 # 赤蛇国 (进国)
|
||||
const EMPIRE_CHUNJO := 2 # 白虎国 (顺天)
|
||||
const EMPIRE_JINNO := 3 # 苍龙国 (忍国)
|
||||
|
||||
const STATUS_CLOSED := 0 # 选举未开放
|
||||
const STATUS_CANDIDACY := 1 # 候选人报名登记期
|
||||
const STATUS_VOTING := 2 # 全民大选投票期
|
||||
const STATUS_CONCLUDED := 3 # 大选揭晓,君主即位
|
||||
|
||||
const MIN_CANDIDATE_LEVEL := 50
|
||||
const MIN_VOTER_LEVEL := 50
|
||||
const CANDIDACY_FEE := 1000000 # 报名保证金 1,000,000 金币
|
||||
const MAX_CANDIDATES_PER_EMPIRE := 8 # 每国最多 8 名候选人
|
||||
|
||||
class CandidateInfo:
|
||||
var pid: int
|
||||
var name: String
|
||||
var empire: int
|
||||
var level: int
|
||||
var votes: int = 0
|
||||
var manifesto: String = ""
|
||||
|
||||
func _init(p_pid: int, p_name: String, p_emp: int, p_lvl: int, p_manifesto: String) -> void:
|
||||
pid = p_pid
|
||||
name = p_name
|
||||
empire = p_emp
|
||||
level = p_lvl
|
||||
votes = 0
|
||||
manifesto = p_manifesto
|
||||
|
||||
# 选举状态字典: empire_id -> status
|
||||
var election_states: Dictionary = {
|
||||
EMPIRE_SHINSOO: STATUS_CLOSED,
|
||||
EMPIRE_CHUNJO: STATUS_CLOSED,
|
||||
EMPIRE_JINNO: STATUS_CLOSED
|
||||
}
|
||||
|
||||
# 候选人名册: empire_id -> Array of CandidateInfo
|
||||
var candidates: Dictionary = {
|
||||
EMPIRE_SHINSOO: [],
|
||||
EMPIRE_CHUNJO: [],
|
||||
EMPIRE_JINNO: []
|
||||
}
|
||||
|
||||
# 选民投票记录: empire_id -> { voter_pid: candidate_pid }
|
||||
var voter_records: Dictionary = {
|
||||
EMPIRE_SHINSOO: {},
|
||||
EMPIRE_CHUNJO: {},
|
||||
EMPIRE_JINNO: {}
|
||||
}
|
||||
|
||||
# 现任君主数据: empire_id -> { "pid": int, "name": String, "treasury": int, "tax_rate": int }
|
||||
var current_monarchs: Dictionary = {
|
||||
EMPIRE_SHINSOO: { "pid": 0, "name": "", "treasury": 10000000, "tax_rate": 3 },
|
||||
EMPIRE_CHUNJO: { "pid": 0, "name": "", "treasury": 10000000, "tax_rate": 3 },
|
||||
EMPIRE_JINNO: { "pid": 0, "name": "", "treasury": 10000000, "tax_rate": 3 },
|
||||
}
|
||||
|
||||
func _init() -> void:
|
||||
reset_all_elections()
|
||||
|
||||
func reset_all_elections() -> void:
|
||||
for emp in [EMPIRE_SHINSOO, EMPIRE_CHUNJO, EMPIRE_JINNO]:
|
||||
election_states[emp] = STATUS_CLOSED
|
||||
candidates[emp] = []
|
||||
voter_records[emp] = {}
|
||||
|
||||
# 1. 管理员开启大选阶段 (GM: Kaiser Wahl Einstellung)
|
||||
func set_election_stage(empire: int, new_status: int) -> bool:
|
||||
if not election_states.has(empire):
|
||||
return false
|
||||
election_states[empire] = new_status
|
||||
return true
|
||||
|
||||
# 2. 候选人报名参选 (monarch_candidacy)
|
||||
func register_candidacy(
|
||||
pid: int,
|
||||
name: String,
|
||||
empire: int,
|
||||
level: int,
|
||||
player_gold: int,
|
||||
manifesto: String
|
||||
) -> Dictionary:
|
||||
var res := { "success": false, "gold_cost": 0, "error_code": "OK", "message": "" }
|
||||
|
||||
if election_states.get(empire) != STATUS_CANDIDACY:
|
||||
res["error_code"] = "CANDIDACY_NOT_OPEN"
|
||||
res["message"] = "当前未处于君主参选登记期。"
|
||||
return res
|
||||
|
||||
if level < MIN_CANDIDATE_LEVEL:
|
||||
res["error_code"] = "LEVEL_TOO_LOW"
|
||||
res["message"] = "参选君主等级必须达到 Lv 50。"
|
||||
return res
|
||||
|
||||
if player_gold < CANDIDACY_FEE:
|
||||
res["error_code"] = "INSUFFICIENT_GOLD"
|
||||
res["message"] = "报名参选需缴纳 1,000,000 金币保证金。"
|
||||
return res
|
||||
|
||||
var emp_candidates: Array = candidates[empire]
|
||||
if emp_candidates.size() >= MAX_CANDIDATES_PER_EMPIRE:
|
||||
res["error_code"] = "CANDIDATES_FULL"
|
||||
res["message"] = "本届君主候选人名额已满 (最多 8 人)。"
|
||||
return res
|
||||
|
||||
for c in emp_candidates:
|
||||
if c.pid == pid:
|
||||
res["error_code"] = "ALREADY_REGISTERED"
|
||||
res["message"] = "您已成功报名,无需重复登记。"
|
||||
return res
|
||||
|
||||
var cand = CandidateInfo.new(pid, name, empire, level, manifesto)
|
||||
emp_candidates.append(cand)
|
||||
|
||||
res["success"] = true
|
||||
res["gold_cost"] = CANDIDACY_FEE
|
||||
res["message"] = "恭喜!您已成功登记为第 %d 帝国君主候选人。" % empire
|
||||
return res
|
||||
|
||||
# 3. 选民投票 (monarch_election)
|
||||
func cast_vote(voter_pid: int, voter_empire: int, voter_level: int, target_candidate_pid: int) -> Dictionary:
|
||||
var res := { "success": false, "error_code": "OK", "message": "" }
|
||||
|
||||
if election_states.get(voter_empire) != STATUS_VOTING:
|
||||
res["error_code"] = "VOTING_NOT_OPEN"
|
||||
res["message"] = "当前未处于全民投票大选阶段。"
|
||||
return res
|
||||
|
||||
if voter_level < MIN_VOTER_LEVEL:
|
||||
res["error_code"] = "VOTER_LEVEL_TOO_LOW"
|
||||
res["message"] = "等级未达到 Lv 50,尚无大选投票权。"
|
||||
return res
|
||||
|
||||
var records: Dictionary = voter_records[voter_empire]
|
||||
if records.has(voter_pid):
|
||||
res["error_code"] = "ALREADY_VOTED"
|
||||
res["message"] = "您在本届选举中已经投过神圣的一票,不可重复投票。"
|
||||
return res
|
||||
|
||||
# 查找目标候选人
|
||||
var target_cand: CandidateInfo = null
|
||||
for c in candidates[voter_empire]:
|
||||
if c.pid == target_candidate_pid:
|
||||
target_cand = c
|
||||
break
|
||||
|
||||
if target_cand == null:
|
||||
res["error_code"] = "CANDIDATE_NOT_FOUND"
|
||||
res["message"] = "未找到该候选人。"
|
||||
return res
|
||||
|
||||
# 计票
|
||||
target_cand.votes += 1
|
||||
records[voter_pid] = target_candidate_pid
|
||||
|
||||
res["success"] = true
|
||||
res["message"] = "投票成功!感谢您支持候选人 %s。" % target_cand.name
|
||||
return res
|
||||
|
||||
# 4. 统计揭晓并任命新君主
|
||||
func conclude_election(empire: int) -> Dictionary:
|
||||
var res := { "success": false, "winner_pid": 0, "winner_name": "", "votes": 0 }
|
||||
if not election_states.has(empire):
|
||||
return res
|
||||
|
||||
var emp_candidates: Array = candidates[empire]
|
||||
if emp_candidates.is_empty():
|
||||
election_states[empire] = STATUS_CLOSED
|
||||
return res
|
||||
|
||||
# 选出最高票者
|
||||
var top_cand: CandidateInfo = emp_candidates[0]
|
||||
for c in emp_candidates:
|
||||
if c.votes > top_cand.votes:
|
||||
top_cand = c
|
||||
|
||||
# 就任君主
|
||||
current_monarchs[empire]["pid"] = top_cand.pid
|
||||
current_monarchs[empire]["name"] = top_cand.name
|
||||
election_states[empire] = STATUS_CONCLUDED
|
||||
|
||||
res["success"] = true
|
||||
res["winner_pid"] = top_cand.pid
|
||||
res["winner_name"] = top_cand.name
|
||||
res["votes"] = top_cand.votes
|
||||
return res
|
||||
|
||||
# 5. 君主行使特权:调整帝国商业税率 (1% ~ 10%)
|
||||
func set_tax_rate(caller_pid: int, empire: int, new_tax: int) -> Dictionary:
|
||||
var res := { "success": false, "error_code": "OK", "message": "" }
|
||||
var monarch = current_monarchs[empire]
|
||||
|
||||
if caller_pid != monarch["pid"]:
|
||||
res["error_code"] = "NOT_MONARCH"
|
||||
res["message"] = "只有现任帝国君主有权调整商业税率。"
|
||||
return res
|
||||
|
||||
var clamped_tax: int = clamp(new_tax, 1, 10)
|
||||
monarch["tax_rate"] = clamped_tax
|
||||
|
||||
res["success"] = true
|
||||
res["tax_rate"] = clamped_tax
|
||||
res["message"] = "帝国商业税率已调整为 %d%%。" % clamped_tax
|
||||
return res
|
||||
|
||||
# 6. 君主行使特权:释放全帝国神佑祝福
|
||||
func activate_monarch_blessing(caller_pid: int, empire: int) -> Dictionary:
|
||||
var res := { "success": false, "error_code": "OK", "blessing_buff": {}, "message": "" }
|
||||
var monarch = current_monarchs[empire]
|
||||
|
||||
if caller_pid != monarch["pid"]:
|
||||
res["error_code"] = "NOT_MONARCH"
|
||||
return res
|
||||
|
||||
res["success"] = true
|
||||
res["blessing_buff"] = {
|
||||
"exp_bonus": 10,
|
||||
"att_bonus": 10,
|
||||
"duration_sec": 7200
|
||||
}
|
||||
res["message"] = "君主神佑降临!帝国全体子民获得 +10% 经验与 +10% 攻击力加成 (持续2小时)。"
|
||||
return res
|
||||
Reference in New Issue
Block a user