class_name FriendVisitController extends RefCounted # 好友访问控制器。 # # 参考原 H5: # - 好友列表点击房屋/手指后触发 interaction/get-other-user-info。 # - 访问他人农场后的土地操作统一走 interaction/interaction。 # - interaction type 来自 common/utils/EnumUtil.php: # 0 偷菜,1 放虫,2 放草,3 浇水,4 除虫,5 除草。 # # 控制器只处理接口请求和业务回写,不持有场景节点。 const ACTION_STEAL := "steal" const ACTION_PUT_BUG := "put_bug" const ACTION_PUT_GRASS := "put_grass" const ACTION_WATER := "water" const ACTION_DIE_BUG := "die_bug" const ACTION_DIE_GRASS := "die_grass" const INTERACTION_TYPE_STEAL := 0 const INTERACTION_TYPE_BUG := 1 const INTERACTION_TYPE_GRASS := 2 const INTERACTION_TYPE_WATERING := 3 const INTERACTION_TYPE_DISINSECTION := 4 const INTERACTION_TYPE_WEEDING := 5 var _interaction_api var _game_config var _crop_phase_rules var _callbacks: Dictionary = {} func setup(options: Dictionary) -> void: _interaction_api = options.get("interaction_api") _game_config = options.get("game_config") _crop_phase_rules = options.get("crop_phase_rules") _callbacks = options.get("callbacks", {}) func visit_friend_home(row: Dictionary) -> void: var target_id := target_user_id(row) if target_id <= 0: _show_toast("好友数据异常") return if target_id == _player_id(): _show_toast("这是你的农场,不用去啦!") return if _is_busy() or _interaction_api == null: return var token := _token() if token.is_empty(): _show_toast("登录已失效") return _set_busy(true) var result: Dictionary = await _interaction_api.fetch_other_user_info(token, target_id) _set_busy(false) if not result.get("ok", false): _show_toast(_response_status_text(result, "访问好友失败")) return var data = _response_data(result, {}) if not data is Dictionary: _show_toast("好友数据异常") return _call("enter_friend_farm", [data]) func interact_land(action: String) -> void: if not _is_visiting_friend() or _interaction_api == null: return var position := _selected_position() if position < 0 or _is_busy(): return var interaction_type := _interaction_type(action) if interaction_type < 0: return var token := _token() var visited_friend_id := _visited_friend_id() if token.is_empty() or visited_friend_id <= 0: _show_toast("登录已失效") return var old_land := _land_data(position) _set_busy(true) var result: Dictionary = await _interaction_api.interact(token, visited_friend_id, position, interaction_type) _set_busy(false) if not result.get("ok", false): _show_toast(_response_status_text(result, "好友互动失败")) return var data = _response_data(result, {}) var response_data: Dictionary = data if data is Dictionary else {} var land_data: Dictionary = old_land.duplicate(true) var returned_land = response_data.get("land", {}) if returned_land is Dictionary: land_data = returned_land.duplicate(true) if not land_data.has("position"): land_data["position"] = position if not land_data.has("crop_phase") and _crop_phase_rules != null: land_data["crop_phase"] = _crop_phase_rules.get_phase(land_data) land_data["interaction_type_list"] = _remove_interaction_type(old_land.get("interaction_type_list", []), interaction_type) _call("apply_land_data", [land_data]) _apply_interaction_reward(interaction_type, response_data, old_land) _call("hide_selection_ui") _call("render_lands") func target_user_id(row: Dictionary) -> int: for key in ["uid", "user_id", "id"]: var value := int(row.get(key, 0)) if value > 0: return value return 0 func _interaction_type(action: String) -> int: match action: ACTION_STEAL: return INTERACTION_TYPE_STEAL ACTION_PUT_BUG: return INTERACTION_TYPE_BUG ACTION_PUT_GRASS: return INTERACTION_TYPE_GRASS ACTION_WATER: return INTERACTION_TYPE_WATERING ACTION_DIE_BUG: return INTERACTION_TYPE_DISINSECTION ACTION_DIE_GRASS: return INTERACTION_TYPE_WEEDING _: return -1 func _remove_interaction_type(raw_types: Variant, interaction_type: int) -> Array[int]: var next_types: Array[int] = [] if not raw_types is Array: return next_types for raw_type in raw_types: var type_id := int(raw_type) if type_id != interaction_type and not next_types.has(type_id): next_types.append(type_id) return next_types func _apply_interaction_reward(interaction_type: int, response_data: Dictionary, old_land: Dictionary) -> void: match interaction_type: INTERACTION_TYPE_STEAL: _apply_steal_reward(response_data, old_land) INTERACTION_TYPE_BUG: _show_toast("放虫成功") INTERACTION_TYPE_GRASS: _show_toast("放草成功") INTERACTION_TYPE_WATERING: _show_toast("浇水成功") INTERACTION_TYPE_DISINSECTION: _show_toast("除虫成功") INTERACTION_TYPE_WEEDING: _show_toast("除草成功") func _apply_steal_reward(response_data: Dictionary, old_land: Dictionary) -> void: var deduct_gold := int(response_data.get("deduct_gold", 0)) if deduct_gold > 0: _call("decrease_player_currency", [deduct_gold, 0]) _show_toast("偷菜不幸被狗狗发现,逃跑过程中遗落了%s金币" % deduct_gold) return var steal_count := int(response_data.get("steal_count", 0)) var crop_id := int(old_land.get("crop_id", 0)) if crop_id <= 0: var returned_land = response_data.get("land", {}) if returned_land is Dictionary: crop_id = int(returned_land.get("crop_id", 0)) var crop_name := "作物" var item_id := 0 if _game_config != null: crop_name = _game_config.get_crop_name(crop_id) if _game_config.has_method("get_crop_output_item_id"): item_id = int(_game_config.get_crop_output_item_id(crop_id)) if item_id > 0 and steal_count > 0: _call("add_reward_items", ["%s:%s" % [item_id, steal_count]]) _show_toast("偷取%sx%s" % [crop_name, steal_count]) func _selected_position() -> int: return int(_call("selected_position", [], -1)) func _token() -> String: return str(_call("token", [], "")) func _player_id() -> int: return int(_call("player_id", [], 0)) func _visited_friend_id() -> int: return int(_call("visited_friend_id", [], 0)) func _land_data(position: int) -> Dictionary: var result = _call("land_data", [position], {}) return result if result is Dictionary else {} func _is_visiting_friend() -> bool: return bool(_call("is_visiting_friend", [], false)) func _is_busy() -> bool: return bool(_call("is_operation_in_progress", [], false)) func _set_busy(value: bool) -> void: _call("set_operation_in_progress", [value]) func _response_data(result: Dictionary, fallback: Variant = {}) -> Variant: return _call("response_data", [result, fallback], fallback) func _response_status_text(result: Dictionary, fallback := "操作失败") -> String: return str(_call("response_status_text", [result, fallback], fallback)) func _show_toast(message: String) -> void: _call("show_toast", [message]) func _call(name: String, args: Array = [], fallback: Variant = null) -> Variant: var callable: Callable = _callbacks.get(name, Callable()) if not callable.is_valid(): return fallback return callable.callv(args)