2026-05-29 19:54:56 +08:00

563 lines
26 KiB
GDScript

class_name BuildingPanel
extends RefCounted
# 建筑升级面板:
# - 管理房屋升级、土地升级和扩建,消耗判断统一走 callbacks/InventoryFacade。
# - FarmMapper 负责把后端土地列表转成主场景可渲染数据,本面板不直接拼土地节点。
# - 升级成功后只触发资源/土地刷新,具体视觉重绘仍由 game_scene/LandGridView 完成。
const NumberFormatterScript := preload("res://scripts/core/number_formatter.gd")
const I18nScript := preload("res://scripts/core/i18n.gd")
var _ui
var _texture_provider
var _game_config
var _building_api
var _farm_mapper
var _get_item_icon_texture: Callable
var _context
var _callbacks: Dictionary = {}
var _panel_screen_size := Vector2(640.0, 960.0)
var _max_farm_level := 20
var _land_count := 12
var _land_upgrade_tab_index := 0
var _land_upgrade_content: Control
var _land_upgrade_panel: Control
func setup(options: Dictionary) -> void:
_ui = options.get("ui_builder")
_texture_provider = options.get("texture_provider")
_game_config = options.get("game_config")
_building_api = options.get("building_api")
_farm_mapper = options.get("farm_mapper")
_get_item_icon_texture = options.get("get_item_icon_texture", Callable())
_context = options.get("context")
_callbacks = options.get("callbacks", {})
if _callbacks.is_empty() and _context != null and _context.has_method("legacy_callbacks"):
_callbacks = _context.legacy_callbacks()
_panel_screen_size = options.get("panel_screen_size", _panel_screen_size)
_max_farm_level = int(options.get("max_farm_level", _max_farm_level))
_land_count = int(options.get("land_count", _land_count))
func open_house_upgrade() -> void:
var panel: Control = await create_house_upgrade()
if panel != null:
_call("open_modal_panel", [panel])
func open_land_upgrade(tab_index := 0) -> void:
var panel: Control = await create_land_upgrade(tab_index)
if panel != null:
_call("open_modal_panel", [panel])
func open_land_extend() -> void:
var panel: Control = create_land_extend()
if panel != null:
_call("open_modal_panel", [panel])
func create_house_upgrade() -> Control:
if _is_busy():
return null
_call("close_modal_panel", [false])
await _call_async("refresh_store_house")
var player := _player_data()
var current_level := clampi(int(player.get("farm_level", 1)), 1, _max_farm_level)
var next_level := clampi(current_level + 1, 1, _max_farm_level)
var is_max := current_level >= _max_farm_level
var config: Dictionary = _game_config.get_farm_level_config(next_level)
var cost_text := str(config.get("item_id", ""))
var level_required := int(config.get("player_level", 0))
var level_enough := int(player.get("level", 1)) >= level_required
var cost_enough := _has_costs(cost_text)
var panel: Control = _ui.create_common_panel_shell("BuildingPanel", Vector2(640.0, 810.0), "panel_icon_building", _texture_provider.atlas_path("common"), "panel_title_building", _texture_provider.atlas_path("common"))
_ui.add_content_panel_background(panel, "InnerPageBack", Vector2(51.0, 204.0), Vector2(538.0, 598.0))
_ui.add_content_panel_background(panel, "InnerPage", Vector2(51.0, 214.0), Vector2(538.0, 579.0))
_ui.create_tab_bar(panel, "BuildingTabs", ["房屋升级"], Vector2(80.0, 157.0), 0, Callable(self, "_on_house_tab_pressed"))
_ui.add_texture(panel, "HouseBg", load("res://assets/egret/assets/game/landup/building_housebg.png"), Vector2(77.0, 226.0), Vector2(485.0, 290.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED)
_ui.add_texture(panel, "Tuding", _texture_provider.common("tuding"), Vector2(520.0, 225.0), Vector2(52.0, 50.0))
_ui.add_texture(panel, "HouseIcon", _house_texture(next_level), Vector2(190.0, 222.0), Vector2(260.0, 245.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED)
_ui.add_texture(panel, "LvBg", _texture_provider.building("building_lvbg"), Vector2(56.0, 218.0), Vector2(122.0, 85.0))
var lv_label: Label = _ui.add_panel_label(panel, "BuildingLv", "LV.%s" % next_level, Vector2(69.0, 250.0), Vector2(98.0, 34.0), 29, Color.html("#fff05a"), 3, Color.html("#8a4b18"))
lv_label.rotation_degrees = -15.0
var upgrade_button: Control = _ui.add_texture_button(panel, "UpgradeHouse", _texture_provider.building("btn_building_up"), Vector2(254.0, 234.0), Vector2(159.0, 65.0), "升级", Callable(self, "_upgrade_house").bind(config.duplicate(true)), 38)
_style_upgrade_button_label(upgrade_button)
_ui.add_texture(upgrade_button, "Arrow", _texture_provider.building("building_up_arrow"), Vector2(115.0, -2.0), Vector2(40.0, 53.0))
var can_upgrade := not is_max and not config.is_empty() and level_enough and cost_enough
_set_texture_button_enabled(upgrade_button, can_upgrade, _texture_provider.building("btn_building_up"), _texture_provider.building("btn_building_up_gray"))
_ui.add_nine_patch(panel, "Line", _texture_provider.common("line"), Vector2(74.0, 590.0), Vector2(490.0, 4.0), Vector4.ZERO)
_ui.add_panel_label(panel, "NeedLevelText", "升级房屋需要农场主等级达到:", Vector2(104.0, 610.0), Vector2(310.0, 32.0), 18, Color.html("#ffcc00"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_ui.add_panel_label(panel, "NeedLevel", "LV.%s" % level_required, Vector2(381.0, 606.0), Vector2(80.0, 32.0), 22, Color.html("#73ff8d") if level_enough else Color.html("#ff4b2e"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_ui.add_panel_label(panel, "AddOutputText", "收获土地的果实将增加产量百分比:", Vector2(82.0, 641.0), Vector2(336.0, 32.0), 18, Color.html("#ffcc00"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_ui.add_panel_label(panel, "AddOutput", "%s%%" % int(config.get("output", 0)), Vector2(381.0, 637.0), Vector2(80.0, 32.0), 22, Color.html("#73ff8d"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_ui.add_panel_label(panel, "AddExpText", "升级房屋等级将增加农场主经验百分比:", Vector2(82.0, 673.0), Vector2(346.0, 32.0), 18, Color.html("#ffcc00"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_ui.add_panel_label(panel, "AddExp", "%s%%" % int(config.get("add_exp", 0)), Vector2(381.0, 669.0), Vector2(80.0, 32.0), 22, Color.html("#73ff8d"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
if is_max:
var label := upgrade_button.get_node_or_null("Label") as Label
if label != null:
label.text = I18nScript.t("满级")
else:
_add_house_cost_slots(panel, _parse_cost_string(cost_text))
return panel
func create_land_upgrade(tab_index := 0) -> Control:
if _is_busy():
return null
_call("close_modal_panel", [false])
await _call_async("refresh_store_house")
_land_upgrade_tab_index = clampi(tab_index, 0, 2)
var panel: Control = _ui.create_common_panel_shell("LandUpgradePanel", Vector2(640.0, 864.0), "panel_icon_landup", _texture_provider.atlas_path("landup"), "panel_title_landup", _texture_provider.atlas_path("landup"))
_ui.add_content_panel_background(panel, "InnerPage", Vector2(51.0, 194.0), Vector2(538.0, 652.0))
_ui.create_tab_bar(panel, "LandUpgradeTabs", ["棕土地", "银土地", "紫土地"], Vector2(80.0, 147.0), _land_upgrade_tab_index, Callable(self, "_on_land_upgrade_tab_pressed"))
_land_upgrade_content = Control.new()
_land_upgrade_content.name = "LandUpgradeContent"
_land_upgrade_content.position = Vector2(51.0, 194.0)
_land_upgrade_content.size = Vector2(537.0, 652.0)
panel.add_child(_land_upgrade_content)
_land_upgrade_panel = panel
render_land_upgrade()
return panel
func create_land_extend() -> Control:
if _is_busy():
return null
_call("close_modal_panel", [false])
var player := _player_data()
var next_count := _lands_by_position().size() + 1
var config: Dictionary = _game_config.get_land_extend_config(next_count)
var level_required := int(config.get("player_level", 0))
var gold_required := int(config.get("gold", 0))
var level_enough := int(player.get("level", 1)) >= level_required
var gold_enough := int(player.get("gold", 0)) >= gold_required
var panel := Control.new()
panel.name = "LandOpenPanel"
panel.size = _panel_screen_size
panel.mouse_filter = Control.MOUSE_FILTER_STOP
var mask := Button.new()
mask.name = "ModalMask"
mask.set_anchors_preset(Control.PRESET_FULL_RECT)
mask.text = ""
mask.focus_mode = Control.FOCUS_NONE
_ui.apply_empty_button_style(mask)
mask.pressed.connect(_callback("close_modal_panel"))
panel.add_child(mask)
_ui.add_nine_patch(panel, "PanelBg", _texture_provider.common("c_panel2"), Vector2(88.0, 365.0), Vector2(464.0, 230.0), Vector4(136.0, 128.0, 4.0, 2.0))
_ui.add_texture(panel, "PanelIcon", _texture_provider.landup("panel_icon_landopen"), Vector2(162.0, 331.0), Vector2(108.0, 78.0))
var title: Texture2D = _texture_provider.landup("panel_title_landopen")
_ui.add_texture(panel, "PanelTitle", title, Vector2(342.0 - title.get_width() * 0.5, 329.0), title.get_size())
_ui.add_texture_button(panel, "PanelClose", _texture_provider.common("btn_close"), Vector2(480.0, 341.0), Vector2(80.0, 74.0), "", _callback("close_modal_panel"), 20)
_ui.add_panel_label(panel, "NeedText", "扩建这块土地需要:", Vector2(133.0, 430.0), Vector2(250.0, 32.0), 24, Color.html("#ffcc00"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_ui.add_panel_label(panel, "LevelText", "角色等级:", Vector2(133.0, 475.0), Vector2(116.0, 32.0), 24, Color.html("#ffcc00"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_ui.add_panel_label(panel, "LandNeedLevel", "LV.%s" % level_required, Vector2(249.0, 476.0), Vector2(82.0, 32.0), 24, Color.WHITE if level_enough else Color.html("#ff4b2e"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_ui.add_texture(panel, "GoldIcon", _texture_provider.common("sicon_gold"), Vector2(338.0, 469.0), Vector2(35.0, 35.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED)
_ui.add_panel_label(panel, "LandNeedGold", NumberFormatterScript.compact(gold_required), Vector2(381.0, 476.0), Vector2(132.0, 32.0), 24, Color.WHITE if gold_enough else Color.html("#ff4b2e"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
var open_button: Control = _ui.add_texture_button(panel, "OpenLand", _texture_provider.common("c_btn3"), Vector2(237.0, 529.0), Vector2(166.0, 58.0), "扩建", Callable(self, "_extend_land").bind(config.duplicate(true)), 30)
_set_texture_button_enabled(open_button, not config.is_empty() and level_enough and gold_enough, _texture_provider.common("c_btn3"), _texture_provider.common("c_btn3_gray"))
return panel
func render_land_upgrade() -> void:
if _land_upgrade_content == null:
return
_clear_children(_land_upgrade_content)
var player := _player_data()
var target_level := _land_upgrade_tab_index + 1
var target_name := _land_level_name(target_level)
var order := _count_lands_by_level(target_level, true) + 1
var config: Dictionary = _game_config.get_land_upgrade_config_for(target_level, order)
var cost_text := str(config.get("item_id", ""))
var costs := _parse_cost_string(cost_text)
var level_required := int(config.get("player_level", 0))
var level_enough := int(player.get("level", 1)) >= level_required
var base_land_available := _count_lands_by_level(target_level - 1, false) > 0
var cost_enough := _has_costs(cost_text)
var can_upgrade := not config.is_empty() and level_enough and base_land_available and cost_enough
_ui.add_texture(_land_upgrade_content, "HouseBg", load("res://assets/egret/assets/game/landup/building_housebg.png"), Vector2(22.0, 38.0), Vector2(505.0, 290.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED)
_ui.add_texture(_land_upgrade_content, "Light", load("res://assets/egret/assets/game/landup/land_up_light.png"), Vector2(36.0, -35.0), Vector2(468.0, 368.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED)
_ui.add_texture(_land_upgrade_content, "Icon", load("res://assets/egret/assets/game/landup/land_up_icon%s.png" % target_level), Vector2(172.0, 36.0), Vector2(220.0, 190.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED)
_ui.add_texture(_land_upgrade_content, "SkinTop", _texture_provider.common("skin_top"), Vector2(127.0, 16.0), Vector2(311.0, 61.0))
_ui.add_texture(_land_upgrade_content, "Name", _texture_provider.landup("land_up_name%s" % target_level), Vector2(180.0, 16.0), Vector2(181.0, 52.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED)
_ui.add_nine_patch(_land_upgrade_content, "StarTip", _texture_provider.common("s_tip"), Vector2(187.0, 335.0), Vector2(310.0, 26.0), Vector4(13.0, 12.0, 1.0, 2.0))
_render_land_upgrade_stars(_land_upgrade_content, target_level)
_ui.add_panel_label(_land_upgrade_content, "NeedLevelText", "升级%s需要农场主等级达到:" % target_name, Vector2(18.0, 382.0), Vector2(390.0, 30.0), 22, Color.html("#ffcc00"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_ui.add_panel_label(_land_upgrade_content, "NeedLevel", "LV%s" % level_required, Vector2(411.0, 382.0), Vector2(82.0, 30.0), 22, Color.html("#73ff8d") if level_enough else Color.html("#ff4b2e"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_ui.add_panel_label(_land_upgrade_content, "ExpText", "收获%s的果实将增加农场主经验点:" % target_name, Vector2(18.0, 413.0), Vector2(390.0, 30.0), 22, Color.html("#ffcc00"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_ui.add_panel_label(_land_upgrade_content, "ExpAdd", "%s" % int(config.get("add_exp", 0)), Vector2(410.0, 413.0), Vector2(100.0, 30.0), 22, Color.html("#73ff8d"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_ui.add_panel_label(_land_upgrade_content, "OutputText", "收获%s的果实将增加产量个数:" % target_name, Vector2(18.0, 446.0), Vector2(390.0, 30.0), 22, Color.html("#ffcc00"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_ui.add_panel_label(_land_upgrade_content, "OutputAdd", "%s" % int(config.get("output", 0)), Vector2(410.0, 446.0), Vector2(100.0, 30.0), 22, Color.html("#73ff8d"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
_add_land_upgrade_cost_slots(_land_upgrade_content, costs)
var button: Control = _ui.add_texture_button(_land_upgrade_content, "UpgradeLand", _texture_provider.common("c_btn3"), Vector2(185.0, 500.0), Vector2(166.0, 58.0), "升级", Callable(self, "_upgrade_land").bind(target_level, config.duplicate(true)), 30)
_set_texture_button_enabled(button, can_upgrade, _texture_provider.common("c_btn3"), _texture_provider.common("c_btn3_gray"))
_ui.add_panel_label(_land_upgrade_content, "Error", _land_upgrade_error_text(config, level_enough, base_land_available, cost_enough), Vector2(23.0, 620.0), Vector2(490.0, 30.0), 22, Color.html("#eb060a"), 1, Color.html("#9c460b"))
func _on_house_tab_pressed(_index: int) -> void:
pass
func _on_land_upgrade_tab_pressed(index: int) -> void:
_land_upgrade_tab_index = clampi(index, 0, 2)
if _land_upgrade_panel != null:
var tabs := _land_upgrade_panel.get_node_or_null("LandUpgradeTabs") as Control
_ui.update_tab_bar(tabs, _land_upgrade_tab_index)
render_land_upgrade()
func _add_house_cost_slots(panel: Control, costs: Array[Dictionary]) -> void:
var icon_positions := [Vector2(89.0, 723.0), Vector2(211.0, 723.0), Vector2(336.0, 723.0), Vector2(459.0, 723.0)]
var label_positions := [Vector2(127.0, 725.0), Vector2(252.0, 725.0), Vector2(374.0, 725.0), Vector2(499.0, 725.0)]
for index in range(mini(costs.size(), 4)):
var cost := costs[index]
var item_id := int(cost.get("item_id", 0))
var count := int(cost.get("count", 0))
var enough := _owned_amount(item_id) >= count
_ui.add_texture(panel, "CostIcon%s" % index, _item_icon_texture(_game_config.get_item_icon_id(item_id)), icon_positions[index], Vector2(35.0, 35.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED)
_ui.add_panel_label(panel, "CostLabel%s" % index, NumberFormatterScript.compact(count), label_positions[index], Vector2(74.0, 30.0), 22, Color.html("#73ff8d") if enough else Color.html("#ff4b2e"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
func _style_upgrade_button_label(button_holder: Control) -> void:
var label := button_holder.get_node_or_null("Label") as Label
if label == null:
return
label.position = Vector2(12.0, 0.0)
label.size = Vector2(114.0, 65.0)
_ui.style_label(label, 38, Color.WHITE, 2, Color.html("#643591"))
func _upgrade_house(config: Dictionary) -> void:
if _is_busy():
return
var token := _token()
if token.is_empty():
_show_toast("登录信息失效")
return
var player := _player_data()
var next_level := clampi(int(player.get("farm_level", 1)) + 1, 1, _max_farm_level)
if int(player.get("farm_level", 1)) >= _max_farm_level:
_show_toast("房屋已满级")
return
if config.is_empty():
_show_toast("房屋配置缺失")
return
var level_required := int(config.get("player_level", 0))
if int(player.get("level", 1)) < level_required:
_show_toast("农场主等级不足")
return
var cost_text := str(config.get("item_id", ""))
if not _has_costs(cost_text):
_show_toast("升级材料不足")
return
_set_busy(true)
var result: Dictionary = await _building_api.upgrade_house(token)
_set_busy(false)
if not result.get("ok", false):
_show_toast("房屋升级失败:%s" % result.get("game_status", result.get("status", 0)))
return
_apply_cost_deduction(cost_text)
player["farm_level"] = next_level
player["exp"] = int(player.get("exp", 0)) + int(config.get("add_exp", 0))
_call("render_house_art")
_call("render_player")
_show_toast("房屋升级")
await _call_async("refresh_store_house")
var panel: Control = await create_house_upgrade()
if panel != null:
_call("open_modal_panel", [panel])
func _render_land_upgrade_stars(parent: Control, target_level: int) -> void:
var upgraded_count := _count_lands_by_level(target_level, true)
for index in range(12):
var texture_name := "building_land_num%s" % target_level if upgraded_count > index else "building_land_num0"
_ui.add_texture(parent, "LandStar%s" % index, _texture_provider.landup(texture_name), Vector2(204.0 + float(index) * 23.6, 339.0), Vector2(20.0, 19.0))
func _add_land_upgrade_cost_slots(parent: Control, costs: Array[Dictionary]) -> void:
var icon_positions := [Vector2(26.0, 563.0), Vector2(147.0, 563.0), Vector2(282.0, 563.0), Vector2(408.0, 563.0)]
var label_positions := [Vector2(62.0, 570.0), Vector2(181.0, 570.0), Vector2(316.0, 570.0), Vector2(444.0, 570.0)]
for index in range(mini(costs.size(), 4)):
var cost := costs[index]
var item_id := int(cost.get("item_id", 0))
var count := int(cost.get("count", 0))
var enough := _owned_amount(item_id) >= count
_ui.add_texture(parent, "LandCostIcon%s" % index, _item_icon_texture(_game_config.get_item_icon_id(item_id)), icon_positions[index], Vector2(35.0, 35.0), TextureRect.STRETCH_KEEP_ASPECT_CENTERED)
_ui.add_panel_label(parent, "LandCostLabel%s" % index, NumberFormatterScript.compact(count), label_positions[index], Vector2(74.0, 30.0), 22, Color.html("#73ff8d") if enough else Color.html("#ff4b2e"), 2, Color.html("#9c460b"), HORIZONTAL_ALIGNMENT_LEFT)
func _land_upgrade_error_text(config: Dictionary, level_enough: bool, base_land_available: bool, cost_enough: bool) -> String:
if config.is_empty():
return "配置缺失"
if not base_land_available:
return "没有足够的%s" % _land_level_name(_land_upgrade_tab_index)
if not level_enough:
return "等级不足"
if not cost_enough:
return "材料不足"
return ""
func _upgrade_land(target_level: int, config: Dictionary) -> void:
if _is_busy():
return
var token := _token()
if token.is_empty():
_show_toast("登录信息失效")
return
if config.is_empty():
_show_toast("土地升级配置缺失")
return
var base_position := _first_land_position_by_level(target_level - 1)
if base_position < 0:
_show_toast("没有足够的%s" % _land_level_name(target_level - 1))
return
var player := _player_data()
var level_required := int(config.get("player_level", 0))
if int(player.get("level", 1)) < level_required:
_show_toast("农场主等级不足")
return
var cost_text := str(config.get("item_id", ""))
if not _has_costs(cost_text):
_show_toast("材料不足")
return
_set_busy(true)
var result: Dictionary = await _building_api.upgrade_land(token, target_level)
_set_busy(false)
if not result.get("ok", false):
_show_toast(_response_status_text(result, "土地升级失败"))
return
var lands := _lands_by_position()
var land_data: Dictionary = _farm_mapper.land_data_from_result(result, base_position, lands.get(base_position, {}))
if land_data.is_empty():
land_data = lands.get(base_position, {}).duplicate(true)
land_data["position"] = base_position
land_data["level"] = target_level
_call("apply_land_data", [land_data])
_apply_cost_deduction(cost_text)
_call("render_player")
_call("render_lands")
await _call_async("refresh_store_house")
_show_toast("升级成功")
render_land_upgrade()
func _extend_land(config: Dictionary) -> void:
if _is_busy():
return
var token := _token()
if token.is_empty():
_show_toast("登录信息失效")
return
if config.is_empty():
_show_toast("扩建配置缺失")
return
var player := _player_data()
var level_required := int(config.get("player_level", 0))
var gold_required := int(config.get("gold", 0))
if int(player.get("level", 1)) < level_required:
_show_toast("角色等级不足")
return
if int(player.get("gold", 0)) < gold_required:
_show_toast("金豆不足,无法扩建")
return
_set_busy(true)
var result: Dictionary = await _building_api.extend_land(token)
_set_busy(false)
if not result.get("ok", false):
_show_toast("扩建土地失败:%s" % result.get("game_status", result.get("status", 0)))
return
var fallback_position := _first_locked_land_position()
var land_data := _land_data_from_extend_result(result, fallback_position)
_call("apply_land_data", [land_data])
player["gold"] = maxi(int(player.get("gold", 0)) - gold_required, 0)
_call("render_player")
_call("render_lands")
_call("close_modal_panel")
_show_toast("扩建土地成功")
func _count_lands_by_level(level: int, include_above: bool) -> int:
var count := 0
for land_data in _lands_by_position().values():
if not land_data is Dictionary:
continue
var current_level := _land_level(land_data)
if (include_above and current_level >= level) or ((not include_above) and current_level == level):
count += 1
return count
func _first_land_position_by_level(level: int) -> int:
var lands := _lands_by_position()
for position in range(_land_count):
var land_data: Dictionary = lands.get(position, {})
if not land_data.is_empty() and _land_level(land_data) == level:
return position
return -1
func _land_level(land_data: Dictionary) -> int:
return clampi(int(land_data.get("level", land_data.get("landLv", 0))), 0, 3)
func _land_level_name(level: int) -> String:
var names := ["普通土地", "棕土地", "银土地", "紫土地"]
return names[clampi(level, 0, names.size() - 1)]
func _land_data_from_extend_result(result: Dictionary, fallback_position: int) -> Dictionary:
var body = result.get("body", {})
if body is Dictionary:
var data = body.get("data", {})
if data is Dictionary and int(data.get("position", -1)) >= 0:
var normalized: Dictionary = data.duplicate(true)
if not normalized.has("level"):
normalized["level"] = 0
if not normalized.has("crop_id"):
normalized["crop_id"] = 0
if not normalized.has("crop_phase"):
normalized["crop_phase"] = -1
return normalized
return {
"position": fallback_position,
"level": 0,
"crop_id": 0,
"crop_num": 0,
"crop_start_time": 0,
"crop_gather_time": 0,
"is_ripe": 0,
"has_dry": 0,
"has_bug": 0,
"has_grass": 0,
"has_gather": 0,
"crop_phase": -1,
"is_mystery_seed": 0
}
func _first_locked_land_position() -> int:
var lands := _lands_by_position()
for position in range(_land_count):
if not lands.has(position):
return position
return _land_count - 1
func _clear_children(node: Node) -> void:
for child in node.get_children():
child.queue_free()
func _parse_cost_string(cost_text: String) -> Array[Dictionary]:
var result = _call("parse_cost_string", [cost_text], [])
var costs: Array[Dictionary] = []
if result is Array:
for cost in result:
if cost is Dictionary:
costs.append(cost)
return costs
func _has_costs(cost_text: String) -> bool:
return bool(_call("has_costs", [cost_text], false))
func _apply_cost_deduction(cost_text: String) -> void:
_call("apply_cost_deduction", [cost_text])
func _owned_amount(item_id: int) -> int:
return int(_call("owned_amount", [item_id], 0))
func _set_texture_button_enabled(button_holder: Control, enabled: bool, normal_texture: Texture2D = null, disabled_texture: Texture2D = null) -> void:
_call("set_texture_button_enabled", [button_holder, enabled, normal_texture, disabled_texture])
func _house_texture(level: int) -> Texture2D:
var result = _call("get_house_texture", [level], null)
return result as Texture2D
func _item_icon_texture(icon_id: int) -> Texture2D:
if _texture_provider != null and _texture_provider.has_method("item_icon"):
return _texture_provider.item_icon(icon_id)
if _get_item_icon_texture.is_valid():
return _get_item_icon_texture.call(icon_id) as Texture2D
return _texture_provider.common("item_bg")
func _player_data() -> Dictionary:
var result = _call("player_data", [], {})
return result if result is Dictionary else {}
func _lands_by_position() -> Dictionary:
var result = _call("lands_by_position", [], {})
return result if result is Dictionary else {}
func _token() -> String:
return str(_call("token", [], ""))
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 _show_toast(message: String) -> void:
_call("show_toast", [message])
func _response_status_text(result: Dictionary, fallback := "操作失败") -> String:
return I18nScript.t(str(_call("response_status_text", [result, fallback], fallback)))
func _callback(name: String) -> Callable:
if _context != null and _context.has_method("callback"):
return _context.callback(name)
return _callbacks.get(name, Callable()) as Callable
func _call(name: String, args: Array = [], fallback: Variant = null) -> Variant:
if _context != null and _context.has_method("call_action"):
return _context.call_action(name, args, fallback)
var callable := _callback(name)
if not callable.is_valid():
return fallback
return callable.callv(args)
func _call_async(name: String, args: Array = []) -> Variant:
if _context != null and _context.has_method("call_action_async"):
return await _context.call_action_async(name, args)
var callable := _callback(name)
if not callable.is_valid():
return null
return await callable.callv(args)