Files
mtgodot-poc/project/monarch_election_ui_system.gd
T
shenandshen 66d217b313 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 客户端对拍缺陷发现与修复工程指南
2026-09-19 08:51:25 -07:00

231 lines
7.1 KiB
GDScript

# 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