Skip to content

Repeat a small map over the torus to fill a large one - #261

Draft
Giszmo wants to merge 20 commits into
masterfrom
feat/map-tiling-rebased
Draft

Giszmo wants to merge 20 commits into
masterfrom
feat/map-tiling-rebased

Conversation

@Giszmo

@Giszmo Giszmo commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Repeat a small map over the torus until it fills a large one. A 64 x 64 map
repeated 2 x 2 becomes a 128 x 128 map with four copies of the landscape and
one colony per copy, each dealt to a fresh team. The editor now also offers
32 x 32 as a map size, which is the natural input for repeating.

This is Bob's and Junior's feat/map-tiling (tip 6fdb347, last touched
2026-09-06) rebased onto current master. The branch was never proposed; master
has moved 53 commits since it forked.

Changes

  • Map::tile() repeats the terrain, discovered mask and undermap arrays over the
    torus, dropping the per-team state that is rebuilt afterwards (src/map/MapTile.cpp).
  • Game::tileForPlay() deals each repeated copy's buildings and units to a fresh
    team, wrapping every colony so a base stays together across the seam
    (src/Game_tiling.cpp, src/MapTiling.cpp).
  • The map chooser gains tile x / tile y / colonies / bases controls, previews the
    repeated map rather than the source, and paints buildings and units in their
    team colour. Choosing Ok writes the repeated map to the temp directory, so tiled
    maps never appear in the maps folder.
  • The editor and the custom-game generator offer 32 as a width and height. That is
    one shared control definition on master now, so the new minimum applies to both.
  • -dump-tiled <map> <rx> <ry> <colonies> <bases> gives a headless check of a
    repeated map's colonies.

What the rebase had to change

Master renamed a lot of what this branch calls:

  • FormatableString -> FormattableString, isRessourceTakeable -> isResourceTakeable,
    Building::ressources -> resources, MAX_NB_RESSOURCES -> MAX_NB_RESOURCES,
    Unit::hungryness -> hungriness.
  • Map::cases -> Map::tiles and Case -> Tile (PR 199).
  • Team::setBaseTeam() was removed as dead code by PR 190. Its five lines are
    inlined at the one call site that wanted them.
  • The editor's size widgets were replaced by MapGenerationDescriptor::sharedControls()
    in PR 238, so "allow 32 x 32" is now a minimum of 5 on the wDec/hDec controls
    instead of an extra add(32).

Each of the twelve commits was adapted in place, so every commit on the branch builds.

Screenshots

Editor create-map dialog, 32 x 32 now selectable:

Editor 32 x 32

Map chooser, "balanced for 2" at 1 x 1 — 2 bases, 64 x 64:

Chooser 1 x 1

The same map at 2 x 2 — 8 bases, 128 x 128 (64 x 64), preview shows the repeat:

Chooser 2 x 2

The repeated map loaded in the editor; the minimap shows the four copies:

Editor with the tiled map

The screenshot files live in commit e8c8229e0 and are removed again at the branch tip.

Validation

  • scons release=1 clean, no warnings introduced.
  • test/TestsRunner: OK (187 tests). test/WinningConditionsHarness: exit 0.
  • ./glob2 -dump-tiled maps/balanced_for_2.map 2 2 4 1 reports 128x128, teams=4
    with each colony's units and buildings wrapped to its own quarter.
  • Screenshots above were driven through the real GUI under Xvfb, not mocked up.
  • The rebase's first attempt silently broke the translation files: stripping the
    conflict markers also removed a literal <<<<<<< line that lives inside
    data/texts.br.txt on master, and left a stray blank line in front of the
    appended block in fourteen files. Both desynchronise StringTable's key/value
    pairing and the game asserts on startup. Fixed in every commit, and a pairing
    check now passes at each of the twelve.

After #240: merge, translations, and review follow-ups

Three commits on top, after #240 landed:

  • Merge master. The catalogs take master's generator strings, then the tiling block.
    MapThumbnail keeps master's loadFromMap(const Map&) beside the team-coloured
    overload (both draw through one render), dumpResources follows the CORNWHEAT
    rename. The 32 x 32 minimum no longer lives in the deleted MapGenerationDescriptor.cpp.
    Since Map generation improvements: modular framework and twelve new generators #240 the size controls are shared by the editor and the custom-game lobby, and
    lowering them put 32 x 32 in the lobby too. There most landscapes cannot seat colonies,
    and CI's setup harness failed on it. So only the editor offers 32 x 32:
    editorSizeControl lowers the minimum on the new-map screen and in request validation,
    and switching landscapes keeps the size. The lobby is unchanged from master.
  • Translations. The seven tiling strings are translated in all 32 catalogs.
    test_translations.py and check_translations.py --strict pass. "bases" is added to the
    shared vocabulary for br, ca, es, fr, nl and pt, where the word is the same as in English.
  • Painted areas and clearing flags survive the repeat. Map::tile clears the per-team
    forbidden, guard and clearing masks, and tileForPlay never painted them again, so a
    map's hand-drawn zones vanished from every copy. Each copy now paints its colony's areas
    for the team the colony is dealt to, and clearing flags keep their resource choices. New
    MapTilingHarness (map-tiling-test, in CI) checks areas, flag choice, buildings and
    units per copy. Without the fix it fails. It also checks the editor-only 32 x 32 size, and
    that such a map generates.
  • LAN transfer of a tiled map. A tiled map exists only in the temp directory, behind
    MapHeader's file name override, and the override is not serialised. The LAN session
    test gained --tiled (in CI): the host tiles FourSquares1 2 x 2, and the guest must
    download it and match the bytes exactly. It passes over two join/leave cycles. The guest
    stores the map under maps/, so on the joining side a tiled map does appear in the
    user's map list. The 3 MB map takes most of a minute to transfer, so tiled mode stays in
    the lobby longer.

What a repeat still drops, by design or as a known limit: units inside buildings, a
building's in-progress upgrade, and each team's local resource counters. Only ALIVE
buildings and units standing on the map are copied.

Verified locally (macOS arm64)

  • Full client build.
  • MapGeneratorDefaultsTest, MapGeneratorGoldenTest --require-rows (248 rows, 0 failures)
    and CustomGameSetupHarness all pass.
  • MapTilingHarness passes, and fails with the painted-area fix reverted.
  • LAN session test passes in plain and --tiled modes.
  • A full 90,000-tick headless game on the tiled FourSquares1 2x2 map (Nicowar, Cabino,
    Castor, Warrush) ran to the end without errors.
  • Every generator at 32 x 32 (1, 2 and 4 colonies, 5 seeds each) either refuses the request
    up front or fails with a diagnostic. None crashes. Some fail for every seed at a given
    colony count: isles with 1 colony, fjord-continent and concrete-islands with 2 or 4,
    contested-commons with 4. In the editor, those combinations show the generator's
    message.

The simulation, save format, replay and network versions are unchanged. Tiling only builds
a new map file, which then loads and plays like any other map.

🤖 Generated with Claude Code

Bob and others added 15 commits September 12, 2026 02:00
Map::tile copies terrain, resources, discovery and script areas rx by ry
times into a map of the enlarged power-of-two size, and marks every cell
free of immobile units, which setSize does not and the building
gradients read as walls. Buildings, units and the per-team zones are
left out: they are placed again per colony.

Opus 5 helped authoring this commit.
Game::tileForPlay captures every colony of the loaded map, repeats the
map, creates the requested teams with colours spread around the wheel,
and places colony n on team n mod teams, with the placed colonies spread
evenly over the copies. Each team gets an equal share, capped by the
colonies-per-team choice; the rest is dropped. MapTiling::writeTiledMap
runs that on a map file and saves the result next to the user's own
maps, so the game, LAN and YOG see an ordinary map and clients receive
it through the usual map transfer.

Opus 5 helped authoring this commit.
Four controls under the map information: repeat horizontally, repeat
vertically, powers of two while the map stays within 512, the number of
teams, and the colonies per team, the last two following the colony
count until the user picks them. The chooser shows the header of the
repeated map so the player slots follow, and writes the map file when
Ok is pressed.

Opus 5 helped authoring this commit.
Small maps are the natural input for repeating.

Opus 5 helped authoring this commit.
The four controls read tile x, tile y, colonies and swarms, with the
map date making room for the captions. The colony count offers the
whole range: raising it grows the repeat, shorter side first, until
the colonies fit, and switching maps keeps the count the user picked
while the repeat and the swarms per colony are adjusted to the new
map. Until the user picks them, colonies follow the map and swarms
are as many as fit.

Opus 5 helped authoring this commit.
-dump-tiled <map> <rx> <ry> <colonies> <swarms> loads the map, repeats
it the way the chooser does and lists each team's units, buildings and
swarm positions, so a placement question can be answered without the
GUI. Run with --nox to skip the video device.

Opus 5 helped authoring this commit.
gcc's -Wmisleading-indentation flagged the paired ifs.

Opus 5 helped authoring this commit.
The map name and file version leave the right column: the name is the
list selection and the version told the player nothing. What remains is
the base count of the map as repeated, the size, and four labelled rows,
tile x, tile y, colonies and bases, each with a wider control. Swarms
became bases: a base is one team of the map as drawn, and a map's team
may own more than one swarm.

The preview now shows the repeated map itself, rendered from the same
routine that writes the map file at Ok, so a 2 x 1 repeat appears as a
landscape and every building and unit carries the colour of the team it
is dealt to. MapThumbnail renders from a loaded map and header, and
MapTiling shares one loader between the preview and the written file.

The list sort only counts the colonies and bases the player picked; a
count still following the map is not a violation.

Opus 5 helped authoring this commit.
A map wraps, so a base's units may stand across the edge from their
swarm; Four Squares places two of every team's four unit pairs that
way. Copying positions as they were put those units next to the swarm
of the neighbouring copy, on another player's island. Every element is
now an offset from the base's anchor, the first swarm, taken the short
way round the source torus, and placed from the anchor of its copy.

A tower's bullets come along with its stone. In the chooser, shrinking
the repeat clips the colony and base counts to what the smaller map
holds instead of leaving a count the map cannot meet.

Opus 5 helped authoring this commit.
Buildings keep their inside capacity, flag level and market masks; units
keep hunger, experience, fruit and medical state.

Opus 5 helped authoring this commit.
MapTiling::writeTiledMap saved the generated map next to the user's
own maps, so every repeat cluttered the map list. MapHeader gains a
file name override that getFileName() returns verbatim when set;
writeTiledMap points it at a path under the system temp directory
(TMPDIR, or /tmp) instead of deriving one from the map name. The
override is transient and never serialized, so every later reload of
that same MapHeader (hosting, LAN/YOG map transfer) still finds the
right file, while the maps directory and its listing stay untouched.

Verified headlessly: writeTiledMap on maps/Oazis.map wrote only to
/tmp, left ~/.glob2/maps empty, and the returned header's
getFileName() reopened the written file directly.

Opus 5 helped authoring this commit.
Editor and chooser captures for the pull request. Removed again at the
branch tip; the blobs stay reachable at this commit.

Opus 5 helped authoring this commit.
They stay reachable at e8c8229 and are linked from the pull request.

Opus 5 helped authoring this commit.
Master already defines [colonies]; the tiling block added a second, English
copy to every catalog, and the languages added since this branch forked had
no tiling entries at all. Drop the duplicates and carry the keys into uk, id,
vi, ja and ko so data/check_translations.py --strict passes.

Opus 5 helped authoring this commit.
@genixpro

Copy link
Copy Markdown
Contributor

@Giszmo, we like this one. Plan: #240 (map generators) is about to land and touches the same shared width/height controls and map-setup screens, so we'll wait for it, then take the rebase and fixes on our side. No need for Bob to spend time on it meanwhile.

What we'll cover once #240 is in:

  • merge master, including the CORNWHEAT rename (Rename the CORN resource identifier to WHEAT #269). The new thumbnail code in MapThumbnail.cpp still uses CORN and won't compile on master as is;
  • translations for the seven new strings, so test_translations.py passes;
  • a look at what the repeat drops: painted forbidden, guard and clearing areas, flag settings beyond minLevelToFlag, units inside buildings;
  • checking that a client joining a LAN/YOG game on a repeated map gets the file, since the temp-path override isn't serialised.

On authorship: no rewrite needed. We'll squash-merge, so the commit on master is authored by you, and we'll drop the agent Co-authored-by lines in the merge message.

genixpro and others added 5 commits September 14, 2026 12:49
Resolves the catalogs (master's generator strings, then the tiling block),
Glob2.cpp includes and the CORN -> WHEAT rename in dumpResources, keeps
master's MapThumbnail::loadFromMap(const Map&) beside the team-coloured
overload, and moves the 32 x 32 minimum from the deleted
MapGenerationDescriptor.cpp to GeneratorControls.cpp and the custom-game
preference bounds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WePqccHKmAjY6cwoqEcvBE
The host tiles FourSquares1 2 x 2 with MapTiling::writeTiledMap, whose file
lives behind MapHeader's file name override, and the guest must receive the
exact bytes under maps/. The 3 MB map needs a longer stay in the lobby than
the plain 616 KB transfer. CI runs both modes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WePqccHKmAjY6cwoqEcvBE
Map::tile drops the per-team forbidden, guard and clearing masks, and
tileForPlay did not paint them again, so a map's hand-drawn zones vanished
from every copy. Each copy now paints its colony's areas for the team the
colony is dealt to, and clearing flags keep which resources they clear.
MapTilingHarness checks both, plus buildings and units per copy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WePqccHKmAjY6cwoqEcvBE
The size controls are shared since #240, so lowering their minimum put 32 x 32
in the lobby too, where most landscapes cannot seat colonies and the setup
harness's size step lands on an invalid map. The shared controls keep 64 as
the smallest size; the editor's new-map screen and request validation use
editorSizeControl, which reaches 32, and switching landscapes keeps the size.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WePqccHKmAjY6cwoqEcvBE
MapThumbnail was rewritten for shared, resolution-aware previews; the
team-coloured overload the repeat-map preview uses is ported onto it as a
header argument to the same renderer. Catalogs take master's map preview
strings, then the tiling block.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WePqccHKmAjY6cwoqEcvBE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants