Add battlefield visuals and camp talk slice
This commit is contained in:
@@ -8,6 +8,7 @@ signal log_added(message: String)
|
||||
signal dialogue_requested(lines: Array)
|
||||
signal combat_feedback_requested(unit_id: String, text: String, kind: String)
|
||||
signal unit_motion_requested(unit_id: String, from_cell: Vector2i, to_cell: Vector2i)
|
||||
signal unit_action_motion_requested(unit_id: String, from_cell: Vector2i, to_cell: Vector2i, action_kind: String)
|
||||
signal objective_updated(victory: String, defeat: String)
|
||||
|
||||
const TEAM_PLAYER := "player"
|
||||
@@ -93,6 +94,7 @@ var shop := {}
|
||||
var deployment_rules := {}
|
||||
var formation_cells: Array[Vector2i] = []
|
||||
var map_size := Vector2i.ZERO
|
||||
var map_background := ""
|
||||
var terrain_rows: Array[String] = []
|
||||
var terrain_defs := DEFAULT_TERRAIN_DEFS.duplicate(true)
|
||||
var units: Array[Dictionary] = []
|
||||
@@ -176,6 +178,7 @@ func _apply_battle_data(data: Dictionary, roster_overrides := {}) -> void:
|
||||
|
||||
var map_data: Dictionary = data.get("map", {})
|
||||
map_size = Vector2i(int(map_data.get("width", 0)), int(map_data.get("height", 0)))
|
||||
map_background = str(map_data.get("background", ""))
|
||||
terrain_rows.clear()
|
||||
for row in map_data.get("terrain", []):
|
||||
terrain_rows.append(String(row))
|
||||
@@ -253,7 +256,7 @@ func _normalized_shop(source) -> Dictionary:
|
||||
var seen := {}
|
||||
var stock := {}
|
||||
if typeof(source) != TYPE_DICTIONARY:
|
||||
return {"items": item_ids, "stock": stock}
|
||||
return {"items": item_ids, "stock": stock, "merchant": {}}
|
||||
for entry in source.get("items", []):
|
||||
var item_id := _shop_item_id_from_entry(entry)
|
||||
if item_id.is_empty() or seen.has(item_id):
|
||||
@@ -275,7 +278,24 @@ func _normalized_shop(source) -> Dictionary:
|
||||
item_ids.append(item_id)
|
||||
_apply_shop_stock_entry(stock, item_id, entry)
|
||||
_apply_shop_stock_block(stock, block.get("stock", {}), seen)
|
||||
return {"items": item_ids, "stock": stock}
|
||||
return {"items": item_ids, "stock": stock, "merchant": _normalized_shop_merchant(source.get("merchant", {}))}
|
||||
|
||||
|
||||
func _normalized_shop_merchant(source) -> Dictionary:
|
||||
if typeof(source) != TYPE_DICTIONARY:
|
||||
return {}
|
||||
var lines := []
|
||||
for line in source.get("lines", []):
|
||||
var text := str(line).strip_edges()
|
||||
if not text.is_empty():
|
||||
lines.append(text)
|
||||
var name := str(source.get("name", "Merchant")).strip_edges()
|
||||
if name.is_empty() and lines.is_empty():
|
||||
return {}
|
||||
return {
|
||||
"name": "Merchant" if name.is_empty() else name,
|
||||
"lines": lines
|
||||
}
|
||||
|
||||
|
||||
func _shop_item_id_from_entry(entry) -> String:
|
||||
@@ -1552,6 +1572,13 @@ func get_shop_stock_limit(item_id: String) -> int:
|
||||
return int(stock.get(normalized, -1))
|
||||
|
||||
|
||||
func get_shop_merchant() -> Dictionary:
|
||||
var merchant = shop.get("merchant", {})
|
||||
if typeof(merchant) != TYPE_DICTIONARY:
|
||||
return {}
|
||||
return merchant.duplicate(true)
|
||||
|
||||
|
||||
func get_formation_cells() -> Array[Vector2i]:
|
||||
return formation_cells.duplicate()
|
||||
|
||||
@@ -1842,6 +1869,10 @@ func get_terrain_key(cell: Vector2i) -> String:
|
||||
return row.substr(cell.x, 1)
|
||||
|
||||
|
||||
func get_map_background_path() -> String:
|
||||
return map_background
|
||||
|
||||
|
||||
func get_terrain_name(cell: Vector2i) -> String:
|
||||
return String(terrain_defs.get(get_terrain_key(cell), DEFAULT_TERRAIN_DEFS["G"]).get("name", "Plain"))
|
||||
|
||||
@@ -3099,6 +3130,12 @@ func _resolve_combat(attacker: Dictionary, target: Dictionary) -> void:
|
||||
func _resolve_attack(attacker: Dictionary, target: Dictionary, is_counter := false) -> Dictionary:
|
||||
var hit_chance := calculate_hit_chance(attacker, target)
|
||||
var verb := "counterattacks" if is_counter else "attacks"
|
||||
unit_action_motion_requested.emit(
|
||||
str(attacker.get("id", "")),
|
||||
attacker.get("pos", Vector2i(-1, -1)),
|
||||
target.get("pos", Vector2i(-1, -1)),
|
||||
"counter" if is_counter else "attack"
|
||||
)
|
||||
if rng.randi_range(1, 100) > hit_chance:
|
||||
_emit_log("%s %s %s but misses. Hit %d%%." % [attacker["name"], verb, target["name"], hit_chance])
|
||||
_emit_combat_feedback(target, "MISS", "miss")
|
||||
|
||||
Reference in New Issue
Block a user