Files
mtgodot-poc/project/net_client_fake.gd
T
shenandshen c93894313a fix: 装备属性面板避让逻辑 + 多项功能更新
- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧
- inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域
- 包含其他累积的功能开发和测试文件
2026-09-21 16:38:59 -07:00

222 lines
6.3 KiB
GDScript

extends Node
## Shared headless client fixture for scene/skill-flow tests.
##
## It models the public M2Client surface used by GameScene, NetPlay and
## Quickbar. Quickslot mutations are server-confirmed immediately by
## emitting quickslots_changed; tests that need delayed confirmation should
## use their dedicated fixture and emit the signal manually.
signal entity_spawned(entity: Dictionary)
signal entity_despawned(vid: int)
signal entity_moved(vid: int)
signal entity_info(vid: int, entity: Dictionary)
signal entity_main_set(vid: int)
signal entity_dead(vid: int)
signal vitals_changed(vid: int)
signal point_changed(vid: int, point_type: int, value: int, amount: int)
signal points_changed(points: Dictionary)
signal target_info(vid: int, hp_percent: int)
signal observer_mode_changed(enabled: bool)
signal fishing_event(subheader: int, info: int, dir: int)
signal chat(type: int, vid: int, text: String)
signal damage(vid: int, amount: int, flag: int)
signal motion(vid: int, victim_vid: int, motion: int)
signal effect_cue(vid: int, name: String, special: int)
signal emoticon_requested(index: int)
signal gift_available()
signal script_dialog(skin: int, text: String)
signal affect_added(affect: Dictionary)
signal affect_removed(type: int)
signal guild_invite_ask(guild_id: int, guild_name: String, leader: String)
signal guild_make_requested()
signal warp(pos: Vector3, same_server: bool)
signal world_reset()
signal channel_changed(channel: int)
signal disconnected(reason: String)
signal entered_game()
signal login_failed(reason: String)
signal skills_changed()
signal skill_group_changed(group: int)
signal skill_cooldown_end(skill: int)
signal quickslots_changed()
var in_game := true
var main := 1000
var entities: Dictionary = {
1000: {"vid": 1000, "name": "Me", "race": 0, "kind": 0, "ch_type": 0,
"pos": Vector3.ZERO, "pos_cm": Vector3.ZERO, "moving_speed": 100,
"attack_speed": 100, "hp": 100, "max_hp": 100, "dead": false}
}
var ground_items: Array = []
var inventory: Array = []
var equipment: Array = []
var affects: Array = []
var skills: Array = [{"id": 1, "level": 5, "master": 0}]
var skill_group := 1
var points: Dictionary = {
"level": 30, "skill_active": 5, "skill_support": 3, "skill_horse": 2,
"casting_speed": 100, "hp": 100, "max_hp": 100, "sp": 100, "max_sp": 100,
"exp": 0, "next_exp": 1000,
}
var target_vid := 0
var quickslots: Array = []
var calls: Array = []
func is_in_game() -> bool:
return in_game
func get_main_vid() -> int:
return main
func get_entity(vid: int) -> Dictionary:
return entities.get(int(vid), {})
func get_entities() -> Array:
return entities.values()
func get_ground_items() -> Array:
return ground_items
func get_inventory() -> Array:
return inventory
func get_equipment() -> Array:
return equipment
func get_affects() -> Array:
return affects
func get_skills() -> Array:
return skills
func get_skill_group() -> int:
return skill_group
func get_points() -> Dictionary:
return points
func get_quickslots() -> Array:
return quickslots
func get_target() -> Dictionary:
return {"vid": target_vid}
func spawn(vid: int, name: String, pos: Vector3, is_main := false) -> void:
var entity := {"vid": vid, "name": name, "race": 0, "kind": 2,
"ch_type": 2, "pos": pos, "pos_cm": pos * 100.0, "moving_speed": 100,
"attack_speed": 100, "hp": 100, "max_hp": 100, "dead": false,
"is_main": is_main}
entities[vid] = entity
if is_main:
main = vid
entity_main_set.emit(vid)
entity_spawned.emit(entity)
func move(func_id: int, arg: int, rot: float, x: int, y: int) -> bool:
calls.append(["move", func_id, arg, rot, x, y])
return in_game
func attack(motion_id: int, victim: int) -> bool:
calls.append(["attack", motion_id, victim])
return in_game
func set_target(vid: int) -> bool:
target_vid = vid
calls.append(["set_target", vid])
return in_game
func click_npc(vid: int) -> bool:
calls.append(["click_npc", vid])
return in_game
func pickup_item(vid: int) -> bool:
calls.append(["pickup_item", vid])
return in_game
func add_fly_targeting(vid: int, x: int, y: int) -> bool:
calls.append(["add_fly_targeting", vid, x, y])
return in_game
func fishing(rot_deg: float) -> bool:
calls.append(["fishing", rot_deg])
return in_game
func cast_skill(motion_id: int, rot: float, x: int, y: int, arg := 0) -> bool:
calls.append(["cast_skill", motion_id, rot, x, y, arg])
return in_game
func use_skill(skill_id: int, victim: int) -> bool:
calls.append(["use_skill", skill_id, victim])
return in_game
func use_item(window: int, cell: int) -> bool:
calls.append(["use_item", window, cell])
return in_game
func send_emoticon(index: int) -> bool:
calls.append(["send_emoticon", index])
return in_game
func say(type: int, text: String) -> bool:
calls.append(["say", type, text])
return in_game
func shoot(skill_id: int) -> bool:
calls.append(["shoot", skill_id])
return in_game
func skill_up(skill_id: int) -> bool:
calls.append(["skill_up", skill_id])
return in_game
func quickslot_add(pos: int, type: int, ref: int) -> bool:
calls.append(["quickslot_add", pos, type, ref])
quickslots = quickslots.filter(func(q: Dictionary) -> bool: return int(q.get("pos", -1)) != pos)
quickslots.append({"pos": pos, "type": type, "ref": ref})
quickslots_changed.emit()
return in_game
func quickslot_del(pos: int) -> bool:
calls.append(["quickslot_del", pos])
quickslots = quickslots.filter(func(q: Dictionary) -> bool: return int(q.get("pos", -1)) != pos)
quickslots_changed.emit()
return in_game
func quickslot_swap(pos: int, change_pos: int) -> bool:
calls.append(["quickslot_swap", pos, change_pos])
var a := -1
var b := -1
for i in quickslots.size():
if int(quickslots[i].get("pos", -1)) == pos:
a = i
if int(quickslots[i].get("pos", -1)) == change_pos:
b = i
if a >= 0 and b >= 0:
var tmp: Dictionary = quickslots[a]
quickslots[a] = quickslots[b]
quickslots[b] = tmp
quickslots[a]["pos"] = pos
quickslots[b]["pos"] = change_pos
elif a >= 0:
quickslots[a]["pos"] = change_pos
elif b >= 0:
quickslots[b]["pos"] = pos
quickslots_changed.emit()
return in_game
func get_channel() -> int:
return 1
func set_item_proto(_proto: Object) -> void:
pass
func get_item_proto(_vnum: int) -> Dictionary:
return {}
func guild_answer_invite(_guild_id: int, _accept: bool) -> bool:
return in_game
func guild_answer_make(_name: String) -> bool:
return in_game