stepstead-client/scripts/location_panel.gd
jts 6a1706051d İlk commit: Stepstead Godot istemci (4.6 Mobile)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 11:31:35 +03:00

210 lines
7 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

extends PanelContainer
## Lokasyon paneli — bulunduğun yerin kaynakları (topla butonları), buradaki oyuncular.
## Kod ile kurulur, world.gd HUD'a ekler. Node adı "LocationPanel".
const PANEL_HEIGHT := 620.0
signal city_requested
var _city_btn: Button
var _title: Label
var _desc: Label
var _players: Label
var _list: VBoxContainer
var _scroll: ScrollContainer
var _header: TextureRect
func _ready() -> void:
name = "LocationPanel"
visible = false
_build_ui()
func _build_ui() -> void:
set_anchors_preset(Control.PRESET_BOTTOM_WIDE)
offset_top = -PANEL_HEIGHT
offset_left = 8
offset_right = -8
offset_bottom = -8
var sb := StyleBoxFlat.new()
sb.bg_color = Color(0.10, 0.12, 0.10, 0.97)
sb.set_corner_radius_all(10)
add_theme_stylebox_override("panel", sb)
var margin := MarginContainer.new()
margin.add_theme_constant_override("margin_left", 14)
margin.add_theme_constant_override("margin_right", 14)
margin.add_theme_constant_override("margin_top", 10)
margin.add_theme_constant_override("margin_bottom", 10)
add_child(margin)
var vbox := VBoxContainer.new()
vbox.add_theme_constant_override("separation", 6)
margin.add_child(vbox)
# Lokasyon başlık görseli (assets/locations/<code>.webp — varsa)
_header = TextureRect.new()
_header.custom_minimum_size = Vector2(0, 190)
_header.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
_header.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_COVERED
_header.clip_contents = true
_header.visible = false
vbox.add_child(_header)
var top := HBoxContainer.new()
_title = Label.new()
_title.add_theme_font_size_override("font_size", 20)
_title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
top.add_child(_title)
_city_btn = Button.new()
_city_btn.text = "🏙 Şehir Haritası"
_city_btn.visible = false
_city_btn.pressed.connect(func() -> void:
visible = false
city_requested.emit())
top.add_child(_city_btn)
var close_btn := Button.new()
close_btn.text = ""
close_btn.pressed.connect(func() -> void: visible = false)
top.add_child(close_btn)
vbox.add_child(top)
_desc = Label.new()
_desc.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_desc.add_theme_font_size_override("font_size", 13)
_desc.add_theme_color_override("font_color", Color(0.7, 0.72, 0.65))
vbox.add_child(_desc)
_players = Label.new()
_players.add_theme_font_size_override("font_size", 13)
_players.add_theme_color_override("font_color", Color(0.55, 0.75, 0.95))
vbox.add_child(_players)
_scroll = ScrollContainer.new()
_scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
_scroll.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
vbox.add_child(_scroll)
_list = VBoxContainer.new()
_list.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_list.add_theme_constant_override("separation", 6)
_scroll.add_child(_list)
func open() -> void:
visible = true
await refresh()
func refresh() -> void:
var res: Dictionary = await GameState.load_location()
if not res.ok or not (res.body is Dictionary):
_title.text = "Lokasyon yüklenemedi"
return
var loc: Dictionary = res.body
_title.text = "📍 %s" % str(loc.get("name", ""))
_city_btn.visible = str(loc.get("type", "")) in ["city", "village"]
_desc.text = str(loc.get("description", ""))
var img_path := "res://assets/locations/%s.webp" % str(loc.get("code", ""))
if ResourceLoader.exists(img_path):
_header.texture = load(img_path)
_header.visible = true
else:
_header.visible = false
var names: Array = loc.get("players_here", [])
_players.text = "👥 Burada: %s" % ", ".join(names) if not names.is_empty() else "👥 Burada başka kimse yok"
for c in _list.get_children():
c.queue_free()
_list.add_child(_camp_row(loc))
var resources: Array = loc.get("resources", [])
if resources.is_empty():
var l := Label.new()
l.text = "Burada toplanacak kaynak yok."
l.add_theme_color_override("font_color", Color(0.6, 0.6, 0.6))
_list.add_child(l)
return
var bal := int(GameState.character.get("step_balance", 0))
for r in resources:
if r is Dictionary:
_list.add_child(_resource_row(r, bal))
const SKILL_TR := {"mining": "Madencilik", "fishing": "Balıılık", "foraging": "Toplama",
"woodcutting": "Ağaç Kesme", "hunting": "Avcılık"}
func _resource_row(r: Dictionary, bal: int) -> HBoxContainer:
var row := HBoxContainer.new()
row.add_theme_constant_override("separation", 10)
var info := VBoxContainer.new()
info.size_flags_horizontal = Control.SIZE_EXPAND_FILL
var name_lbl := Label.new()
name_lbl.text = str(r.get("item_name", ""))
name_lbl.add_theme_font_size_override("font_size", 15)
info.add_child(name_lbl)
var meta := Label.new()
var skill: String = str(r.get("skill", ""))
meta.text = "%s%d👣 • +%dXP" % [SKILL_TR.get(skill, skill), int(r.get("step_cost", 0)), int(r.get("xp", 0))]
meta.add_theme_font_size_override("font_size", 12)
meta.add_theme_color_override("font_color", Color(0.6, 0.62, 0.58))
info.add_child(meta)
row.add_child(info)
var btn := Button.new()
var cd := int(r.get("cooldown_remaining", 0))
var tool_ok: bool = bool(r.get("tool_ok", true))
var cost := int(r.get("step_cost", 0))
if not tool_ok:
btn.text = "🔒 %s gerekli" % str(r.get("tool_needed", "Tool"))
btn.disabled = true
elif cd > 0:
btn.text = "%ds" % cd
btn.disabled = true
elif bal < cost:
btn.text = "👣 yetersiz"
btn.disabled = true
else:
btn.text = "Topla"
var code := str(r.get("item_code", ""))
btn.pressed.connect(_on_gather.bind(btn, code))
row.add_child(btn)
return row
const CAMP_ITEM_TR := {"log_oak": "Meşe Odunu", "stone_small": "Küçük Taş", "vine": "Sarmaşık"}
func _camp_row(loc: Dictionary) -> HBoxContainer:
var row := HBoxContainer.new()
row.add_theme_constant_override("separation", 10)
var lbl := Label.new()
lbl.size_flags_horizontal = Control.SIZE_EXPAND_FILL
lbl.add_theme_font_size_override("font_size", 13)
if bool(loc.get("has_camp", false)):
lbl.text = "⛺ Kampın var — toplama maliyeti -%25"
lbl.add_theme_color_override("font_color", Color(0.6, 0.85, 0.6))
row.add_child(lbl)
return row
var cost_items: Dictionary = loc.get("camp_cost_items", {})
var parts: Array[String] = []
for code in cost_items:
parts.append("%d %s" % [int(cost_items[code]), str(CAMP_ITEM_TR.get(code, code))])
lbl.text = "⛺ Kamp: %s + %d👣 (-%%25 maliyet)" % [", ".join(parts), int(loc.get("camp_step_cost", 100))]
lbl.add_theme_color_override("font_color", Color(0.75, 0.7, 0.55))
row.add_child(lbl)
var btn := Button.new()
btn.text = "Kur"
btn.pressed.connect(_on_build_camp.bind(btn))
row.add_child(btn)
return row
func _on_build_camp(btn: Button) -> void:
btn.disabled = true
var res: Dictionary = await GameState.build_camp()
if not res.ok and res.body is Dictionary and res.body.has("detail"):
print("[camp fail] ", str(res.body["detail"]))
await refresh()
func _on_gather(btn: Button, code: String) -> void:
btn.disabled = true
var res: Dictionary = await GameState.gather(code)
if not res.ok:
var msg := "Toplanamadı"
if res.body is Dictionary and res.body.has("detail"):
msg = str(res.body["detail"])
print("[gather fail] ", msg)
await refresh()