İlk commit: Stepstead Godot istemci (4.6 Mobile)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
jts 2026-07-11 11:31:35 +03:00
commit 6a1706051d
346 changed files with 14415 additions and 0 deletions

155
scripts/city_map.gd Normal file
View file

@ -0,0 +1,155 @@
extends CanvasLayer
## Şehir haritası — bir şehir location'ının içi. Prosedürel placeholder zemin
## (bina blokları + yollar) üzerinde vendor NPC pinleri. Pine tıkla → dükkan (VendorShop).
## "🗺 Dünya Haritası" ile kapanır. world.gd oluşturur; açıkken world input'u durur.
## Node adı "CityMap".
var _root: Control
var _canvas: Control
var _pins_box: Control
var _title: Label
var _shop: PanelContainer
var _vendors: Array = [] # {npc_id,name,role}
var _pin_pos: Array = [] # Vector2 ekran koordinatları (canvas _draw kullanır)
var _location_name := ""
func _ready() -> void:
name = "CityMap"
layer = 4
visible = false
_build_ui()
func is_open() -> bool:
return visible
func _build_ui() -> void:
_root = Control.new()
_root.set_anchors_preset(Control.PRESET_FULL_RECT)
_root.mouse_filter = Control.MOUSE_FILTER_STOP
add_child(_root)
# Prosedürel zemin (buildings + yollar) — pin konumlarına göre çizilir
_canvas = CityCanvas.new()
_canvas.set_anchors_preset(Control.PRESET_FULL_RECT)
_canvas.mouse_filter = Control.MOUSE_FILTER_IGNORE
_root.add_child(_canvas)
# Pin container (butonlar mutlak konumlu)
_pins_box = Control.new()
_pins_box.set_anchors_preset(Control.PRESET_FULL_RECT)
_pins_box.mouse_filter = Control.MOUSE_FILTER_IGNORE
_root.add_child(_pins_box)
# Üst bar
var bar := PanelContainer.new()
bar.set_anchors_preset(Control.PRESET_TOP_WIDE)
bar.offset_bottom = 64
var sb := StyleBoxFlat.new()
sb.bg_color = Color(0.08, 0.09, 0.12, 0.95)
bar.add_theme_stylebox_override("panel", sb)
_root.add_child(bar)
var hb := HBoxContainer.new()
hb.add_theme_constant_override("separation", 10)
bar.add_child(hb)
var m := MarginContainer.new()
m.add_theme_constant_override("margin_left", 12)
m.add_theme_constant_override("margin_right", 12)
m.add_theme_constant_override("margin_top", 8)
m.add_theme_constant_override("margin_bottom", 8)
m.size_flags_horizontal = Control.SIZE_EXPAND_FILL
hb.add_child(m)
_title = Label.new()
_title.add_theme_font_size_override("font_size", 18)
m.add_child(_title)
var back := Button.new()
back.text = "🗺 Dünya Haritası"
back.pressed.connect(_close)
hb.add_child(back)
# Satıcı dükkanı (alt-sheet) — pinlerin üstünde
_shop = preload("res://scripts/vendor_shop.gd").new()
add_child(_shop)
func open() -> void:
visible = true
_title.text = "🏙 Yükleniyor…"
var res: Dictionary = await GameState.city_vendors()
if not res.ok or not (res.body is Dictionary):
_title.text = "🏙 Şehir yüklenemedi"
_vendors = []
else:
_location_name = str(res.body.get("location_name", "Şehir"))
_vendors = res.body.get("vendors", [])
_title.text = "🏙 %s" % _location_name
_layout_pins()
func _close() -> void:
_shop.visible = false
visible = false
func _layout_pins() -> void:
for c in _pins_box.get_children():
c.queue_free()
_pin_pos.clear()
var size := get_viewport().get_visible_rect().size
var n := _vendors.size()
if n == 0:
_canvas.queue_redraw()
return
# Zikzak yerleşim: üst bar altından alt nav üstüne kadar dağıt
var top := 110.0
var bottom := size.y - 140.0
for i in range(n):
var t := float(i) / float(maxi(1, n - 1)) if n > 1 else 0.5
var y := lerpf(top, bottom, t)
var x := size.x * (0.30 if i % 2 == 0 else 0.68)
var pos := Vector2(x, y)
_pin_pos.append(pos)
_add_pin(_vendors[i], pos)
_canvas.pins = _pin_pos
_canvas.queue_redraw()
func _add_pin(v: Dictionary, pos: Vector2) -> void:
var btn := Button.new()
var role := str(v.get("role", ""))
btn.text = "🏪\n%s" % str(v.get("name", ""))
btn.tooltip_text = role
btn.add_theme_font_size_override("font_size", 13)
btn.custom_minimum_size = Vector2(150, 64)
var sb := StyleBoxFlat.new()
sb.bg_color = Color(0.18, 0.15, 0.10, 0.96)
sb.border_color = Color(0.85, 0.7, 0.35)
sb.set_border_width_all(2)
sb.set_corner_radius_all(8)
btn.add_theme_stylebox_override("normal", sb)
_pins_box.add_child(btn)
btn.size = btn.custom_minimum_size
btn.position = pos - btn.custom_minimum_size / 2.0
var npc_id := int(v.get("npc_id", 0))
var vname := str(v.get("name", ""))
btn.pressed.connect(func() -> void: _shop.open(npc_id, vname))
## Prosedürel şehir zemini — zemin, yollar, pin altı bina blokları.
class CityCanvas extends Control:
var pins: Array = []
func _draw() -> void:
var s := size
# Zemin (toprak/çim degrade hissi)
draw_rect(Rect2(Vector2.ZERO, s), Color(0.16, 0.18, 0.13))
draw_rect(Rect2(Vector2(0, s.y * 0.5), Vector2(s.x, s.y * 0.5)), Color(0.14, 0.15, 0.11))
# Ana yol (dikey)
var road_col := Color(0.30, 0.27, 0.22)
draw_rect(Rect2(Vector2(s.x * 0.5 - 22, 90), Vector2(44, s.y - 220)), road_col)
# Pin altı bina blokları
for p in pins:
var bp: Vector2 = p
draw_line(Vector2(s.x * 0.5, bp.y), bp, road_col, 14.0)
var bsize := Vector2(120, 90)
var top_left := bp - Vector2(bsize.x / 2.0, bsize.y + 20)
draw_rect(Rect2(top_left, bsize), Color(0.28, 0.24, 0.20))
draw_rect(Rect2(top_left, bsize), Color(0.5, 0.42, 0.30), false, 2.0)
var roof := PackedVector2Array([
top_left + Vector2(-8, 0), top_left + Vector2(bsize.x + 8, 0),
top_left + Vector2(bsize.x / 2.0, -34)])
draw_colored_polygon(roof, Color(0.45, 0.22, 0.18))