feat(client): 完成40250客户端核心功能1:1对齐与桥梁高度采样修复
- 桥梁与静态物体高度采样修复: - 严格对齐 40250 CMapOutdoor::GetHeight 与 CAttributeInstance::GetHeight - 解析 .mdatr 中的 AttributeHeight 网格,使用 is_in_triangle_2d 准确计算桥面多边形平面方程 - sample_height 查询邻近区块并返回 fMAX(fObjectHeight, fTerrainHeight),彻底解决走上桥面穿透掉入水底/河床的问题 - 新增 test_bridge_height_parity.gd 自动化对拍测试 - 40250 怪物击杀经验动效: - 1:1 实现 FLY_EXP(0) / FLY_HP / FLY_SP 粒子轨迹与爆炸吸附 - 40250 客户端全系统功能对齐(Batches 1-31): - 包含公会、交易、骑乘、变身、钓鱼、采矿、商城、信件、结婚、地牢等 134 套对拍系统与自动化回归测试 - 文档沉淀: - 新增 docs/CLIENT-PARITY-AUDIT-AND-FIX-GUIDE.md 客户端对拍缺陷发现与修复工程指南
This commit is contained in:
+295
-21
@@ -35,11 +35,50 @@ static func _make(spec: Dictionary, ctx: Dictionary, parent_size: Vector2i) -> C
|
||||
var type := _str(spec.get("type", "window"))
|
||||
var w := _i(spec, "width", 0)
|
||||
var h := _i(spec, "height", 0)
|
||||
if type == "titlebar" and h == 0:
|
||||
h = 23
|
||||
elif type == "horizontalbar" and h == 0:
|
||||
h = 17
|
||||
elif (type == "grid_table" or type == "slot") and (w == 0 or h == 0):
|
||||
if w == 0 and spec.has("x_count"):
|
||||
var xc := maxi(1, _i(spec, "x_count", 1))
|
||||
var xs := _i(spec, "x_step", 32)
|
||||
var xb := _i(spec, "x_blank", 0)
|
||||
w = xc * (xs + xb)
|
||||
if h == 0 and spec.has("y_count"):
|
||||
var yc := maxi(1, _i(spec, "y_count", 1))
|
||||
var ys := _i(spec, "y_step", 32)
|
||||
var yb := _i(spec, "y_blank", 0)
|
||||
h = yc * (ys + yb)
|
||||
var node := _make_by_type(type, spec, ctx, Vector2i(w, h))
|
||||
if node == null:
|
||||
node = Control.new()
|
||||
|
||||
node.name = _safe_name(_str(spec.get("name", type)))
|
||||
var halign := _str(spec.get("text_horizontal_align", ""))
|
||||
var valign := _str(spec.get("text_vertical_align", ""))
|
||||
var allalign := _str(spec.get("all_align", ""))
|
||||
if type == "text":
|
||||
if allalign == "center":
|
||||
if w == 0: w = parent_size.x
|
||||
if h == 0: h = parent_size.y
|
||||
else:
|
||||
if halign == "center" and w == 0:
|
||||
w = parent_size.x if parent_size.x > 0 else 100
|
||||
if (valign == "center" or _str(spec.get("vertical_align", "")) == "center") and h == 0:
|
||||
h = parent_size.y if parent_size.y > 0 else 17
|
||||
if (w == 0 or h == 0) and node is TextureRect and (node as TextureRect).texture != null:
|
||||
var tex: Texture2D = (node as TextureRect).texture
|
||||
if w == 0: w = tex.get_width()
|
||||
if h == 0: h = tex.get_height()
|
||||
elif (w == 0 or h == 0) and node is Button:
|
||||
var btn := node as Button
|
||||
var nrm_sb = btn.get_theme_stylebox("normal")
|
||||
if nrm_sb is StyleBoxTexture and (nrm_sb as StyleBoxTexture).texture != null:
|
||||
var tex: Texture2D = (nrm_sb as StyleBoxTexture).texture
|
||||
if w == 0: w = tex.get_width()
|
||||
if h == 0: h = tex.get_height()
|
||||
|
||||
if w > 0:
|
||||
node.custom_minimum_size = Vector2(w, h)
|
||||
node.size = Vector2(w, h)
|
||||
@@ -47,11 +86,17 @@ static func _make(spec: Dictionary, ctx: Dictionary, parent_size: Vector2i) -> C
|
||||
# 位置:x/y + horizontal_align / vertical_align(相对父)
|
||||
var x := _i(spec, "x", 0)
|
||||
var y := _i(spec, "y", 0)
|
||||
if type == "text" and halign == "center" and _i(spec, "width", 0) == 0:
|
||||
x = 0
|
||||
match _str(spec.get("horizontal_align", "left")):
|
||||
"center": x = (parent_size.x - w) / 2 + x
|
||||
"right": x = parent_size.x - w - x
|
||||
match _str(spec.get("vertical_align", "top")):
|
||||
"center": y = (parent_size.y - h) / 2 + y
|
||||
"center":
|
||||
if type == "text" and (valign == "center" or _str(spec.get("vertical_align", "")) == "center") and h == parent_size.y:
|
||||
pass
|
||||
else:
|
||||
y = (parent_size.y - h) / 2 + y
|
||||
"bottom": y = parent_size.y - h - y
|
||||
node.position = Vector2(x, y)
|
||||
|
||||
@@ -59,7 +104,7 @@ static func _make(spec: Dictionary, ctx: Dictionary, parent_size: Vector2i) -> C
|
||||
if nm != "":
|
||||
ctx["nodes"][nm] = node
|
||||
|
||||
var self_size := Vector2i(w, h) if w > 0 else parent_size
|
||||
var self_size := Vector2i(w, h) if (w > 0 and h > 0) else parent_size
|
||||
for child in spec.get("children", []):
|
||||
if child is Dictionary:
|
||||
var c := _make(child, ctx, self_size)
|
||||
@@ -85,36 +130,109 @@ static func _make_by_type(type: String, spec: Dictionary, ctx: Dictionary, sz: V
|
||||
p.set_meta("titlebar_h", 24)
|
||||
return p
|
||||
"titlebar":
|
||||
var t := Panel.new()
|
||||
t.set_meta("is_titlebar", true)
|
||||
return t
|
||||
return _titlebar(assets, sz.x, spec)
|
||||
"text":
|
||||
var lbl := Label.new()
|
||||
lbl.text = _str(spec.get("text", ""))
|
||||
if spec.has("text_color"):
|
||||
lbl.add_theme_color_override("font_color", _argb(int(spec["text_color"])))
|
||||
match _str(spec.get("text_horizontal_align", "left")):
|
||||
elif spec.has("color"):
|
||||
lbl.add_theme_color_override("font_color", _argb(int(spec["color"])))
|
||||
elif spec.has("r") and spec.has("g") and spec.has("b"):
|
||||
var r := float(spec["r"])
|
||||
var g := float(spec["g"])
|
||||
var b := float(spec["b"])
|
||||
var a := float(spec.get("a", 1.0))
|
||||
lbl.add_theme_color_override("font_color", Color(r, g, b, a))
|
||||
else:
|
||||
lbl.add_theme_color_override("font_color", Color(0.8549, 0.8549, 0.8549))
|
||||
|
||||
var font_size := 12
|
||||
var fs_spec := _str(spec.get("fontsize", "")).to_upper()
|
||||
var fn_spec := _str(spec.get("fontname", "")).to_upper()
|
||||
if fs_spec == "LARGE" or "LARGE" in fn_spec:
|
||||
font_size = 14
|
||||
elif fs_spec == "SMALL" or "SMALL" in fn_spec:
|
||||
font_size = 9
|
||||
lbl.add_theme_font_size_override("font_size", font_size)
|
||||
|
||||
var halign := _str(spec.get("text_horizontal_align", ""))
|
||||
var valign := _str(spec.get("text_vertical_align", ""))
|
||||
if _str(spec.get("all_align", "")) == "center":
|
||||
halign = "center"
|
||||
valign = "center"
|
||||
match halign:
|
||||
"center": lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
"right": lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
|
||||
lbl.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
_: lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||
match valign:
|
||||
"center": lbl.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
"bottom": lbl.vertical_alignment = VERTICAL_ALIGNMENT_BOTTOM
|
||||
_: lbl.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
lbl.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
return lbl
|
||||
"button", "toggle_button":
|
||||
"button", "toggle_button", "radio_button":
|
||||
var b := Button.new()
|
||||
b.text = _str(spec.get("text", ""))
|
||||
b.toggle_mode = (type == "toggle_button")
|
||||
b.toggle_mode = (type == "toggle_button" or type == "radio_button")
|
||||
if spec.has("text_color"):
|
||||
var col := _argb(int(spec["text_color"]))
|
||||
b.add_theme_color_override("font_color", col)
|
||||
b.add_theme_color_override("font_pressed_color", col)
|
||||
b.add_theme_color_override("font_hover_color", col)
|
||||
b.add_theme_color_override("font_focus_color", col)
|
||||
elif spec.has("color"):
|
||||
var col := _argb(int(spec["color"]))
|
||||
b.add_theme_color_override("font_color", col)
|
||||
b.add_theme_color_override("font_pressed_color", col)
|
||||
b.add_theme_color_override("font_hover_color", col)
|
||||
b.add_theme_color_override("font_focus_color", col)
|
||||
b.vertical_icon_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
b.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
b.alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
b.clip_text = true
|
||||
|
||||
var btn_fsize := 12
|
||||
var fs_spec := _str(spec.get("fontsize", "")).to_upper()
|
||||
var fn_spec := _str(spec.get("fontname", "")).to_upper()
|
||||
if fs_spec == "LARGE" or "LARGE" in fn_spec:
|
||||
btn_fsize = 14
|
||||
elif fs_spec == "SMALL" or "SMALL" in fn_spec:
|
||||
btn_fsize = 9
|
||||
b.add_theme_font_size_override("font_size", btn_fsize)
|
||||
|
||||
var nrm := UiAssets.load_tex(assets, _str(spec.get("default_image", "")))
|
||||
var ovr := UiAssets.load_tex(assets, _str(spec.get("over_image", "")))
|
||||
var dwn := UiAssets.load_tex(assets, _str(spec.get("down_image", "")))
|
||||
var empty := StyleBoxEmpty.new()
|
||||
empty.content_margin_left = 0
|
||||
empty.content_margin_right = 0
|
||||
empty.content_margin_top = 0
|
||||
empty.content_margin_bottom = 0
|
||||
if nrm:
|
||||
b.add_theme_stylebox_override("normal", _sb_tex(nrm))
|
||||
if ovr: b.add_theme_stylebox_override("hover", _sb_tex(ovr))
|
||||
if dwn: b.add_theme_stylebox_override("pressed", _sb_tex(dwn))
|
||||
b.add_theme_stylebox_override("hover", _sb_tex(ovr if ovr else nrm))
|
||||
b.add_theme_stylebox_override("pressed", _sb_tex(dwn if dwn else nrm))
|
||||
b.add_theme_stylebox_override("disabled", _sb_tex(nrm))
|
||||
b.add_theme_stylebox_override("focus", empty)
|
||||
var tex_w := nrm.get_width()
|
||||
var tex_h := nrm.get_height()
|
||||
b.custom_minimum_size = Vector2(tex_w, tex_h)
|
||||
b.size = Vector2(tex_w, tex_h)
|
||||
# 40250 对齐:进入节点树时重设尺寸,防止被 Godot 默认最小高度撑大到 31px
|
||||
b.tree_entered.connect(func():
|
||||
b.size = b.custom_minimum_size
|
||||
)
|
||||
if btn_fsize + 6 > tex_h:
|
||||
btn_fsize = maxi(8, tex_h - 6)
|
||||
b.add_theme_font_size_override("font_size", btn_fsize)
|
||||
else:
|
||||
b.add_theme_stylebox_override("normal", empty)
|
||||
b.add_theme_stylebox_override("hover", empty)
|
||||
b.add_theme_stylebox_override("pressed", empty)
|
||||
b.add_theme_stylebox_override("focus", empty)
|
||||
b.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
return b
|
||||
"radio_button":
|
||||
var cb := CheckBox.new()
|
||||
cb.text = _str(spec.get("text", ""))
|
||||
return cb
|
||||
"image", "expanded_image", "ani_image", "mark":
|
||||
var ir := TextureRect.new()
|
||||
ir.texture = UiAssets.load_tex(assets, _str(spec.get("image", "")))
|
||||
@@ -138,11 +256,13 @@ static func _make_by_type(type: String, spec: Dictionary, ctx: Dictionary, sz: V
|
||||
return ln
|
||||
"listbox", "candidate_list":
|
||||
return ItemList.new()
|
||||
"gauge", "bar", "horizontalbar":
|
||||
"gauge", "bar":
|
||||
var pb := ProgressBar.new()
|
||||
pb.show_percentage = false
|
||||
pb.value = 100.0
|
||||
return pb
|
||||
"horizontalbar":
|
||||
return _horizontalbar(assets, _i(spec, "width", 100))
|
||||
"grid_table", "slotbar", "slot":
|
||||
# Metin2 物品格容器:有 start_index/x_count 或显式 "slot" 元组 -> 建子格;
|
||||
# 否则 grid_table 退化成普通 GridContainer。
|
||||
@@ -153,6 +273,8 @@ static func _make_by_type(type: String, spec: Dictionary, ctx: Dictionary, sz: V
|
||||
return g
|
||||
var s := Control.new()
|
||||
s.set_meta("is_slot_container", true)
|
||||
var base_img := _str(spec.get("image", ""))
|
||||
var base_tex: Texture2D = UiAssets.load_tex(assets, base_img) if base_img != "" else null
|
||||
for cd in cells:
|
||||
var cell := Panel.new()
|
||||
cell.name = "slot_%d" % int(cd["index"])
|
||||
@@ -161,10 +283,33 @@ static func _make_by_type(type: String, spec: Dictionary, ctx: Dictionary, sz: V
|
||||
cell.size = Vector2(cd["w"], cd["h"])
|
||||
cell.set_meta("slot_index", int(cd["index"]))
|
||||
cell.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
if base_tex != null:
|
||||
cell.add_theme_stylebox_override("panel", _sb_tex(base_tex))
|
||||
s.add_child(cell)
|
||||
return s
|
||||
"sliderbar":
|
||||
return HSlider.new()
|
||||
var slider := HSlider.new()
|
||||
# 40250 sliderbar.sub (175×12), sliderbar_cursor.sub (53×12)
|
||||
slider.custom_minimum_size = Vector2(175, 12)
|
||||
slider.size = Vector2(175, 12)
|
||||
slider.min_value = 0.0
|
||||
slider.max_value = 1.0
|
||||
slider.step = 0.01
|
||||
var track_tex := UiAssets.load_tex(assets, "d:/ymir work/ui/game/windows/sliderbar.sub")
|
||||
var grab_tex := UiAssets.load_tex(assets, "d:/ymir work/ui/game/windows/sliderbar_cursor.sub")
|
||||
if track_tex:
|
||||
var sb_track := StyleBoxTexture.new()
|
||||
sb_track.texture = track_tex
|
||||
sb_track.content_margin_left = 0
|
||||
sb_track.content_margin_right = 0
|
||||
sb_track.content_margin_top = 0
|
||||
sb_track.content_margin_bottom = 0
|
||||
slider.add_theme_stylebox_override("slider", sb_track)
|
||||
if grab_tex:
|
||||
slider.add_theme_icon_override("grabber", grab_tex)
|
||||
slider.add_theme_icon_override("grabber_highlight", grab_tex)
|
||||
slider.add_theme_icon_override("grabber_disabled", grab_tex)
|
||||
return slider
|
||||
"scrollbar", "thin_scrollbar":
|
||||
return VScrollBar.new()
|
||||
_:
|
||||
@@ -174,14 +319,20 @@ static func _make_by_type(type: String, spec: Dictionary, ctx: Dictionary, sz: V
|
||||
|
||||
static func _board(assets: String, prefix: String, sz: Vector2i) -> Panel:
|
||||
var p := Panel.new()
|
||||
if sz.x > 0 and sz.y > 0:
|
||||
p.custom_minimum_size = Vector2(sz)
|
||||
p.size = Vector2(sz)
|
||||
var np: NinePatchRect = null
|
||||
if assets != "":
|
||||
np = UiKit.board(assets, prefix, 32, 128)
|
||||
var m := 16 if prefix == "thinboard" else 32
|
||||
var base_sz := 32 if prefix == "thinboard" else 128
|
||||
np = UiKit.board(assets, prefix, m, base_sz)
|
||||
if np and np.texture:
|
||||
np.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
np.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
p.add_child(np)
|
||||
np.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
p.get_child(0).show_behind_parent = true
|
||||
p.add_theme_stylebox_override("panel", StyleBoxEmpty.new())
|
||||
else:
|
||||
var sb := StyleBoxFlat.new()
|
||||
sb.bg_color = Color(0.10, 0.11, 0.14, 0.92)
|
||||
@@ -191,6 +342,123 @@ static func _board(assets: String, prefix: String, sz: Vector2i) -> Panel:
|
||||
p.add_theme_stylebox_override("panel", sb)
|
||||
return p
|
||||
|
||||
static func _titlebar(assets: String, width: int, spec: Dictionary) -> Control:
|
||||
var t := Control.new()
|
||||
var w := maxi(64, width)
|
||||
t.custom_minimum_size = Vector2(w, 23)
|
||||
t.size = Vector2(w, 23)
|
||||
t.set_meta("is_titlebar", true)
|
||||
|
||||
# Background textures (left, center, right)
|
||||
var left_tex := UiKit.ui_tex(assets, "titlebar_left")
|
||||
var center_tex := UiKit.ui_tex(assets, "titlebar_center")
|
||||
var right_tex := UiKit.ui_tex(assets, "titlebar_right")
|
||||
if left_tex and center_tex and right_tex:
|
||||
var img_left := TextureRect.new()
|
||||
img_left.name = "TitleBarLeft"
|
||||
img_left.texture = left_tex
|
||||
img_left.position = Vector2.ZERO
|
||||
img_left.size = Vector2(32, 23)
|
||||
img_left.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
img_left.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
t.add_child(img_left)
|
||||
|
||||
var img_center := TextureRect.new()
|
||||
img_center.name = "TitleBarCenter"
|
||||
img_center.texture = center_tex
|
||||
img_center.position = Vector2(32, 0)
|
||||
img_center.size = Vector2(maxi(0, w - 64), 23)
|
||||
img_center.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
img_center.stretch_mode = TextureRect.STRETCH_TILE
|
||||
img_center.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
t.add_child(img_center)
|
||||
|
||||
var img_right := TextureRect.new()
|
||||
img_right.name = "TitleBarRight"
|
||||
img_right.texture = right_tex
|
||||
img_right.position = Vector2(w - 32, 0)
|
||||
img_right.size = Vector2(32, 23)
|
||||
img_right.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
img_right.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
t.add_child(img_right)
|
||||
else:
|
||||
var p := Panel.new()
|
||||
p.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
var sb := StyleBoxFlat.new()
|
||||
sb.bg_color = Color(0.2, 0.2, 0.25, 0.9)
|
||||
p.add_theme_stylebox_override("panel", sb)
|
||||
p.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
t.add_child(p)
|
||||
|
||||
# Close Button
|
||||
var btn_close := Button.new()
|
||||
btn_close.name = "CloseButton"
|
||||
var nrm := UiAssets.load_tex(assets, "d:/ymir work/ui/public/close_button_01.sub")
|
||||
var ovr := UiAssets.load_tex(assets, "d:/ymir work/ui/public/close_button_02.sub")
|
||||
var dwn := UiAssets.load_tex(assets, "d:/ymir work/ui/public/close_button_03.sub")
|
||||
if nrm:
|
||||
btn_close.add_theme_stylebox_override("normal", _sb_tex(nrm))
|
||||
if ovr: btn_close.add_theme_stylebox_override("hover", _sb_tex(ovr))
|
||||
if dwn: btn_close.add_theme_stylebox_override("pressed", _sb_tex(dwn))
|
||||
var bw := nrm.get_width()
|
||||
var bh := nrm.get_height()
|
||||
btn_close.size = Vector2(bw, bh)
|
||||
btn_close.position = Vector2(w - bw - 3, 3)
|
||||
else:
|
||||
btn_close.text = "×"
|
||||
btn_close.size = Vector2(16, 16)
|
||||
btn_close.position = Vector2(w - 19, 3)
|
||||
btn_close.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
|
||||
t.add_child(btn_close)
|
||||
t.set_meta("close_button", btn_close)
|
||||
return t
|
||||
|
||||
static func _horizontalbar(assets: String, width: int) -> Control:
|
||||
var w := maxi(96, width)
|
||||
var bar := Control.new()
|
||||
bar.custom_minimum_size = Vector2(w, 17)
|
||||
bar.size = Vector2(w, 17)
|
||||
bar.mouse_filter = Control.MOUSE_FILTER_PASS
|
||||
|
||||
var left_tex := UiKit.ui_tex(assets, "horizontalbar_left")
|
||||
var center_tex := UiKit.ui_tex(assets, "horizontalbar_center")
|
||||
var right_tex := UiKit.ui_tex(assets, "horizontalbar_right")
|
||||
|
||||
if left_tex and center_tex and right_tex:
|
||||
var img_left := TextureRect.new()
|
||||
img_left.name = "HorizontalBarLeft"
|
||||
img_left.texture = left_tex
|
||||
img_left.position = Vector2.ZERO
|
||||
img_left.size = Vector2(32, 17)
|
||||
img_left.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
bar.add_child(img_left)
|
||||
|
||||
var img_center := TextureRect.new()
|
||||
img_center.name = "HorizontalBarCenter"
|
||||
img_center.texture = center_tex
|
||||
img_center.position = Vector2(32, 0)
|
||||
img_center.size = Vector2(maxi(0, w - 64), 17)
|
||||
img_center.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
img_center.stretch_mode = TextureRect.STRETCH_TILE
|
||||
img_center.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
bar.add_child(img_center)
|
||||
|
||||
var img_right := TextureRect.new()
|
||||
img_right.name = "HorizontalBarRight"
|
||||
img_right.texture = right_tex
|
||||
img_right.position = Vector2(w - 32, 0)
|
||||
img_right.size = Vector2(32, 17)
|
||||
img_right.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
bar.add_child(img_right)
|
||||
else:
|
||||
var sb := StyleBoxFlat.new()
|
||||
sb.bg_color = Color(0.2, 0.22, 0.25, 0.85)
|
||||
var p := Panel.new()
|
||||
p.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
p.add_theme_stylebox_override("panel", sb)
|
||||
bar.add_child(p)
|
||||
return bar
|
||||
|
||||
# slot 容器的子格:显式 "slot" 元组,或 start_index/x_count/y_count/x_step/y_step 网格。
|
||||
static func _slot_cells(spec: Dictionary) -> Array:
|
||||
var cells := []
|
||||
@@ -205,15 +473,21 @@ static func _slot_cells(spec: Dictionary) -> Array:
|
||||
var yc := maxi(1, _i(spec, "y_count", 1))
|
||||
var xs := _i(spec, "x_step", 32)
|
||||
var ys := _i(spec, "y_step", 32)
|
||||
var xb := _i(spec, "x_blank", 0)
|
||||
var yb := _i(spec, "y_blank", 0)
|
||||
for row in yc:
|
||||
for col in xc:
|
||||
cells.append({"index": si + row * xc + col, "x": col * xs, "y": row * ys,
|
||||
"w": 32, "h": 32})
|
||||
cells.append({"index": si + row * xc + col, "x": col * (xs + xb), "y": row * (ys + yb),
|
||||
"w": xs, "h": ys})
|
||||
return cells
|
||||
|
||||
static func _sb_tex(t: Texture2D) -> StyleBoxTexture:
|
||||
var sb := StyleBoxTexture.new()
|
||||
sb.texture = t
|
||||
sb.content_margin_left = 0
|
||||
sb.content_margin_top = 0
|
||||
sb.content_margin_right = 0
|
||||
sb.content_margin_bottom = 0
|
||||
return sb
|
||||
|
||||
static func _argb(v: int) -> Color:
|
||||
|
||||
Reference in New Issue
Block a user