fix(@projects/@magic-civilization): 🐛 fix axial-to-offset conversion for grid visibility
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
d83ded529e
commit
a804ceb430
2 changed files with 57 additions and 4 deletions
|
|
@ -329,10 +329,18 @@ static func _refresh_learned_player_snapshot(gd_state: RefCounted) -> void:
|
|||
for u: RefCounted in p.units:
|
||||
if u == null or not u.is_alive():
|
||||
continue
|
||||
# CRITICAL (p1-29k root-cause fix): GDScript stores unit `position`
|
||||
# in AXIAL (q, r), but the Rust grid + `compute_vision` +
|
||||
# Move/Attack legal-action enumeration all operate in ODD-Q OFFSET
|
||||
# (col, row) space (`neighbours_offset` parity-by-column +
|
||||
# `wrap_coord` rectangular bounds). Passing raw axial put units
|
||||
# off-grid → no tile under them → visible_tiles=0, move/attack=0.
|
||||
# Convert to offset so units sit on the same grid the vision walk uses.
|
||||
var u_off: Vector2i = HexUtilsScript.axial_to_offset(u.position)
|
||||
unit_dicts.append({
|
||||
"id": pi * ID_STRIDE + ui,
|
||||
"col": int(u.position.x),
|
||||
"row": int(u.position.y),
|
||||
"col": u_off.x,
|
||||
"row": u_off.y,
|
||||
"hp": int(u.hp),
|
||||
"max_hp": int(u.max_hp),
|
||||
"attack": int(u.attack),
|
||||
|
|
@ -349,9 +357,13 @@ static func _refresh_learned_player_snapshot(gd_state: RefCounted) -> void:
|
|||
for c: RefCounted in p.cities:
|
||||
if c == null:
|
||||
continue
|
||||
# Same axial→offset conversion as units — city centres feed
|
||||
# city-sourced vision (`compute_player_visible_set`) and the
|
||||
# capital position, both in offset space.
|
||||
var c_off: Vector2i = HexUtilsScript.axial_to_offset(c.position)
|
||||
city_dicts.append({
|
||||
"col": int(c.position.x),
|
||||
"row": int(c.position.y),
|
||||
"col": c_off.x,
|
||||
"row": c_off.y,
|
||||
"population": maxi(1, int(c.population)),
|
||||
"food_yield": int(c.get("food_yield")) if c.get("food_yield") != null else 2,
|
||||
"prod_yield": int(c.get("prod_yield")) if c.get("prod_yield") != null else 2,
|
||||
|
|
|
|||
|
|
@ -4883,6 +4883,47 @@ impl GdGameState {
|
|||
d.set("attack_bits", attack_bits as i64);
|
||||
d.set("queue_production_bits", queue_production_bits as i64);
|
||||
d.set("trivial_bits", trivial_bits as i64);
|
||||
|
||||
// Grid introspection (hypothesis 1) — prove the grid is populated and
|
||||
// that the player's first unit sits ON a real tile with a biome
|
||||
// label. `tile_under_unit_biome` empty ⇒ the unit is off-grid
|
||||
// (coordinate-space mismatch) — the exact failure mode behind
|
||||
// visible_tiles=0.
|
||||
match self.inner.grid.as_ref() {
|
||||
Some(g) => {
|
||||
d.set("grid_width", g.width as i64);
|
||||
d.set("grid_height", g.height as i64);
|
||||
d.set("grid_tiles", g.tiles.len() as i64);
|
||||
let labelled = g
|
||||
.tiles
|
||||
.iter()
|
||||
.filter(|t| !t.biome_label_id.is_empty())
|
||||
.count();
|
||||
d.set("grid_tiles_with_biome", labelled as i64);
|
||||
if let Some(sample) = g.tiles.iter().find(|t| !t.biome_label_id.is_empty()) {
|
||||
d.set(
|
||||
"grid_sample_biome",
|
||||
GString::from(sample.biome_label_id.as_str()),
|
||||
);
|
||||
}
|
||||
// First own unit: report its (col,row) and the biome of the
|
||||
// tile it occupies (empty string = no tile under it).
|
||||
if let Some(ps) = self.inner.players.iter().find(|p| p.player_index == player) {
|
||||
if let Some(u0) = ps.units.first() {
|
||||
d.set("unit0_col", u0.col as i64);
|
||||
d.set("unit0_row", u0.row as i64);
|
||||
let biome_under = g
|
||||
.tile(u0.col, u0.row)
|
||||
.map(|t| t.biome_label_id.clone())
|
||||
.unwrap_or_default();
|
||||
d.set("tile_under_unit_biome", GString::from(biome_under.as_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
d.set("grid_tiles", 0i64);
|
||||
}
|
||||
}
|
||||
d
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue