feat(@projects/@magic-civilization): ✅ p3-23 DONE — trade richness complete; deal-UI screenshot-proven
Phase-gate proof for the deal UI (revival step 5 verification): diplomacy_deal_proof.tscn instantiates the REAL diplomacy_panel.tscn with a crafted GameState (human + 2 AI rivals, ledger holding one LuxurySwap + one StrategicSwap + one ResourceSale) and self-captures. Screenshot reviewed in-conversation — the panel renders, in the correct per-rival rows: - AI 1 (Ironhold): "Luxury Trade: Receiving Silk for Furs" + "Resource Sale: Buying Horses (−2 gold/turn)" - AI 2 (Goldvein): "Strategic Trade: Receiving Coal Seam for Iron Ore" All three deal types render with correct direction, resources, and gold flow. p3-23 status partial → done. Every acceptance bullet now met with evidence: gold↔resource + strategic swaps + luxury swaps (mc-trade) · AI evaluation · in-game pipeline revived end-to-end (steps 1-4, GUT 750/0 + 25-turn arena exit 0) · deal UI (step 5, screenshot). tribute.rs stays Game-2 deferred. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
99e0a4447f
commit
e6b7c9b2ce
5 changed files with 117 additions and 27 deletions
|
|
@ -17,8 +17,8 @@
|
|||
| **P0** | 44 | 0 | 0 | 0 | 0 | 0 | 44 |
|
||||
| **P1** | 88 | 0 | 0 | 0 | 0 | 1 | 89 |
|
||||
| **P2** | 130 | 0 | 0 | 0 | 0 | 1 | 131 |
|
||||
| **P3 (oos)** | 33 | 0 | 2 | 0 | 0 | 29 | 64 |
|
||||
| **total** | **295** | **0** | **2** | **0** | **0** | **31** | **328** |
|
||||
| **P3 (oos)** | 34 | 0 | 1 | 0 | 0 | 29 | 64 |
|
||||
| **total** | **296** | **0** | **1** | **0** | **0** | **31** | **328** |
|
||||
|
||||
</td><td valign='top' style='padding-left:2em'>
|
||||
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
| Team Lead | Remaining |
|
||||
|---|---|
|
||||
| [warcouncil](../team-leads/warcouncil.md) | 2 |
|
||||
| [warcouncil](../team-leads/warcouncil.md) | 1 |
|
||||
|
||||
</td></tr></table>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
id: p3-23
|
||||
title: Trade richness — gold & strategic-resource trades with opponents
|
||||
priority: p3
|
||||
status: partial
|
||||
status: done
|
||||
scope: game1
|
||||
owner: warcouncil
|
||||
updated_at: 2026-06-25
|
||||
updated_at: 2026-06-26
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
|
@ -46,19 +46,19 @@ is all **inert in-game until the diplomacy turn-integration is revived**. The
|
|||
(`evaluate_trades` is the shared evaluation surface). *(In-game: the FFI caller
|
||||
must source each player's `tile_strategics` — forward-compatible via
|
||||
`#[serde(default)]`. Wiring follow-up.)*
|
||||
- [~] Logic in Rust (`mc-trade`): gold-for-luxury sale + strategic-for-strategic
|
||||
- [x] Logic in Rust (`mc-trade`): gold-for-luxury sale + strategic-for-strategic
|
||||
swap + strategic sale all evaluate + activate (8 cargo tests; mc-trade 66/0).
|
||||
**In-game application — part A (gold flow) wired but INERT:** `GdTradeLedger.gold_flow_for`
|
||||
+ `GdEconomy` `trade_gold` param + `economy.gd` sourcing are correct and GUT-tested
|
||||
(`test_trade_gold_flows_into_net_gold`, seller +/buyer −) — but they read
|
||||
`GameState.trade_ledger_json`, which is **never populated in-game** (the only writer is
|
||||
the disabled `Diplomacy.process_turn`). So gold flow works the instant the trade
|
||||
integration is revived, but produces 0 until then.
|
||||
**[ ] REAL remaining work — revive the diplomacy trade turn-integration** (see the
|
||||
DISCOVERY note): reconcile the 3 `diplomacy.gd ↔ process_trades` contract drifts,
|
||||
re-enable `Diplomacy.process_turn` in `turn_manager.gd` (carefully — disabled modules
|
||||
there can abort the arena turn loop), add `PlayerState.traded_strategics` + unit-gating,
|
||||
verify the full pipeline headless + GUT. Then the deal UI. → status stays `partial`.
|
||||
**In-game application — REVIVED + verified end-to-end (2026-06-25/26, steps 1–5).**
|
||||
The diplomacy trade turn-integration is live: (1) `diplomacy.gd ↔ process_trades`
|
||||
contract reconciled (`_serialize_players` emits PlayerTradeInput, `process_turn`
|
||||
consumes `{ledger}`); (2) `Diplomacy.process_turn` re-enabled in `turn_manager.gd`,
|
||||
loop-survival proven (25-turn arena, exit 0); (3) `PlayerState.traded_strategics` +
|
||||
unit-gating (`_player_owns_resource` honors traded strategics); (4) tile-sourcing
|
||||
+ full chain GUT-proven; (5) **deal UI** — active swaps/sales render in the diplomacy
|
||||
panel (`diplomacy_deal_proof.tscn`, screenshot reviewed: luxury/strategic/sale rows
|
||||
with correct direction + gold). Gold flow is no longer inert — `process_turn` now
|
||||
populates `GameState.trade_ledger_json` each round, which `economy.gd` reads. Full
|
||||
GUT suite 750/0.
|
||||
|
||||
## Progress (2026-06-25)
|
||||
|
||||
|
|
@ -163,6 +163,8 @@ reads `incoming_strategics`, happiness reads sale luxuries; (c) GDScript deal UI
|
|||
|
||||
## Notes
|
||||
|
||||
Verified 2026-06-25. Status `partial`: luxury swaps work; gold + strategic trades
|
||||
are the missing half. (Strategic-resource trade may be a deliberate Game-1 scope
|
||||
limit — confirm before building if it conflicts with the strategic-scarcity design.)
|
||||
Verified 2026-06-26. Status `done`: gold sales + strategic swaps + luxury swaps all
|
||||
form in `mc-trade`, the diplomacy turn-integration is revived and runs each round, and
|
||||
deals apply in-game (gold flow, happiness luxuries, strategic unit-gating) and render in
|
||||
the diplomacy panel. Closed across revival steps 1–5 (see Progress); GUT 750/0 + panel
|
||||
screenshot reviewed in-conversation. The `tribute.rs` path remains Game-2 deferred.
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"generated_at": "2026-06-26T03:38:21Z",
|
||||
"generated_at": "2026-06-26T04:07:21Z",
|
||||
"totals": {
|
||||
"oos": 31,
|
||||
"missing": 0,
|
||||
"done": 295,
|
||||
"partial": 2,
|
||||
"in_progress": 0,
|
||||
"done": 296,
|
||||
"partial": 1,
|
||||
"stub": 0,
|
||||
"missing": 0,
|
||||
"in_progress": 0,
|
||||
"total": 328
|
||||
},
|
||||
"objectives": [
|
||||
|
|
@ -3274,10 +3274,10 @@
|
|||
"id": "p3-23",
|
||||
"title": "Trade richness — gold & strategic-resource trades with opponents",
|
||||
"priority": "p3",
|
||||
"status": "partial",
|
||||
"status": "done",
|
||||
"scope": "game1",
|
||||
"owner": "warcouncil",
|
||||
"updated_at": "2026-06-25",
|
||||
"updated_at": "2026-06-26",
|
||||
"summary": "> **DISCOVERY (2026-06-25, verify-first):** the original premise was wrong. The\n> inter-player trade turn-integration is **DISABLED in the played game**, not\n> \"luxury-only\". `turn_manager.gd:287` has `Diplomacy.process_turn()` commented out\n> with a stale \"empty stub module\" note (diplomacy.gd was rebuilt but never\n> re-enabled). The *only* writer of `GameState.trade_ledger_json` is diplomacy.gd:32\n> inside that disabled call, so **no inter-player trades run at all** (luxury, strategic,\n> or gold). Worse, the `diplomacy.gd ↔ GdTrade.process_trades` contract has drifted\n> in 3 places: (1) `_serialize_players` emits `{index, traded_luxuries, personality}`\n> but `process_trades` deserializes `Vec<PlayerTradeInput>` (`player_index`,\n> `tile_luxuries`, `tile_strategics`, `trade_willingness`); (2) `process_trades`\n> returns `{ledger}` but diplomacy.gd reads `result[\"trade_ledger_json\"]`,\n> `[\"relation_changes\"]`, `[\"new_trades\"]`, `[\"broken_trades\"]`; (3) relations\n> advancement isn't returned. So enabling is NOT a one-line uncomment.\n\nThe **simulation logic is complete + cargo-tested** (luxury/strategic swaps + gold\nsales in `mc-trade`, 66/0) and the gold-flow application is wired (part A) — but it\nis all **inert in-game until the diplomacy turn-integration is revived**. The\n`tribute.rs` path stays Game-2 deferred."
|
||||
},
|
||||
{
|
||||
|
|
|
|||
80
src/game/engine/scenes/tests/diplomacy_deal_proof.gd
Normal file
80
src/game/engine/scenes/tests/diplomacy_deal_proof.gd
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
extends Control
|
||||
## p3-23 proof: the REAL diplomacy panel rendering ACTIVE INTER-PLAYER TRADE
|
||||
## DEALS (luxury swap, strategic swap, gold sale) in its per-rival agreement
|
||||
## section. Crafts a GameState with a human + two AI rivals and a trade ledger
|
||||
## holding one of each deal type, instantiates the real diplomacy_panel.tscn
|
||||
## (exercising get_active_agreements + _make_agreement_section), self-captures.
|
||||
|
||||
const OUTPUT_DIR: String = "user://screenshots"
|
||||
const VIEWPORT_SIZE: Vector2i = Vector2i(1280, 720)
|
||||
const CAPTURE_DELAY: float = 0.8
|
||||
const PANEL_SCENE: PackedScene = preload("res://engine/scenes/hud/diplomacy_panel.tscn")
|
||||
const PlayerScript: GDScript = preload("res://engine/src/entities/player.gd")
|
||||
|
||||
const LEDGER_JSON: String = (
|
||||
'{"agreements":['
|
||||
+ '{"LuxurySwap":{"partners":[0,1],'
|
||||
+ '"gives_a":"furs","gives_b":"silk","turn_started":1}},'
|
||||
+ '{"ResourceSale":{"partners":[0,1],"seller":1,"buyer":0,'
|
||||
+ '"resource":"horses","strategic":true,"gold_per_turn":2,"turn_started":1}},'
|
||||
+ '{"StrategicSwap":{"partners":[0,2],'
|
||||
+ '"gives_a":"iron_ore","gives_b":"coal_seam","turn_started":1}}'
|
||||
+ '],"next_agreement_id":0}'
|
||||
)
|
||||
|
||||
var _captured: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
get_viewport().size = VIEWPORT_SIZE
|
||||
DisplayServer.window_set_size(VIEWPORT_SIZE)
|
||||
RenderingServer.set_default_clear_color(Color(0.06, 0.07, 0.10))
|
||||
DataLoader.load_theme("age-of-dwarves")
|
||||
ThemeAssets.set_theme("age-of-dwarves")
|
||||
ThemeVocabulary.load_vocabulary("age-of-dwarves")
|
||||
_setup_state()
|
||||
var panel: Control = PANEL_SCENE.instantiate() as Control
|
||||
add_child(panel)
|
||||
panel.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||
# The first frame(s) come back blank on this renderer — let the panel lay out
|
||||
# and render several frames before grabbing the viewport texture.
|
||||
for _i: int in range(8):
|
||||
await get_tree().process_frame
|
||||
await get_tree().create_timer(CAPTURE_DELAY).timeout
|
||||
_capture_and_quit()
|
||||
|
||||
|
||||
func _setup_state() -> void:
|
||||
var human: RefCounted = PlayerScript.new(0, "You", "dwarf")
|
||||
human.is_human = true
|
||||
var r1: RefCounted = PlayerScript.new(1, "Ironhold", "dwarf")
|
||||
r1.is_human = false
|
||||
r1.clan_id = "ironhold"
|
||||
var r2: RefCounted = PlayerScript.new(2, "Goldvein", "dwarf")
|
||||
r2.is_human = false
|
||||
r2.clan_id = "goldvein"
|
||||
GameState.players = [human, r1, r2]
|
||||
GameState.diplomacy = {}
|
||||
GameState.trade_ledger_json = LEDGER_JSON
|
||||
|
||||
|
||||
func _capture_and_quit() -> void:
|
||||
if _captured:
|
||||
return
|
||||
_captured = true
|
||||
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(OUTPUT_DIR))
|
||||
var image: Image = get_viewport().get_texture().get_image()
|
||||
if image == null:
|
||||
push_error("diplomacy_deal_proof: viewport image null")
|
||||
get_tree().quit(1)
|
||||
return
|
||||
var rel_path: String = "%s/diplomacy_deal_proof.png" % OUTPUT_DIR
|
||||
var abs_path: String = ProjectSettings.globalize_path(rel_path)
|
||||
var err: Error = image.save_png(abs_path)
|
||||
if err == OK:
|
||||
print("SCREENSHOT_PATH:%s" % abs_path)
|
||||
print("diplomacy_deal_proof: %dx%d saved" % [image.get_width(), image.get_height()])
|
||||
else:
|
||||
push_error("diplomacy_deal_proof: save failed: %s" % error_string(err))
|
||||
get_tree().quit()
|
||||
8
src/game/engine/scenes/tests/diplomacy_deal_proof.tscn
Normal file
8
src/game/engine/scenes/tests/diplomacy_deal_proof.tscn
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://engine/scenes/tests/diplomacy_deal_proof.gd" id="1"]
|
||||
|
||||
[node name="DiplomacyDealProof" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
script = ExtResource("1")
|
||||
Loading…
Add table
Reference in a new issue