Skip to main content

Control points and circles

Space players hold, for two node types from one crate. The hub reads where players are with the node API (scope world.read): a client never says it is on a point or inside the circle, so these hubs see players whose actors are in the world near them.

  • territory: control points that the factions capture by having more members standing on them than any other faction has, capture progress that decays when nobody presses it, income for each point held, and a winning score. The shape of a conquest mode, a guild war, a king of the hill. A point changing hands is also realtime event 96 at the point.
  • zone: a circle that holds, then shrinks, phase by phase, and wears down every player outside it until one is left. The battle royale's circle; pair it with an arena for the fighting. Its moves are also realtime event 98 at its centre. It sees players within about ten chunks of its centre, so its first circle is at most that.

A type runs as the one its seed's mode names ({"mode": "zone", ...}), or as the one its name is.

Starter: crate territory, node type territory and zone, keyed by the map, or the match. Module: kit.territory.map(key) and kit.territory.zone(key) in CrowdyJS, territory().map(key) and territory().zone(key) in CrowdyCPP, kit.territory.map(key) and kit.territory.zone(key) in CrowdyPy.

Endpoints​

EndpointWhoWhat
join { faction }territory: playersOnce: a player keeps their faction. conflict, bad_request, full
resetterritory: developersA new war
joinzone: playersstarted, full
startzone: the first to join, or a developerforbidden, not_ready, started
statebothThe war, or the circle

Every change takes an action_id, answered once; refusals carry the codes above (see the protocol).

Topics​

territory: snapshots when a point moves; events captured, income, won. zone: snapshots each scan; events warning, shrinking, settled, final, eliminated, won.

Config​

A type's seed (seed_b64 in the manifest, the same for every key) is the starter's JSON config; what it leaves out keeps its default. Territory: points (each id, x, y, z, radius in chunks), factions, capture_per_sec, decay_per_sec, scan_ms, income_ms, income_per_point, win_score, members_max. Zone: center and y, radius (at most about ten chunks), the shrink phases (radius, hold_ms, shrink_ms), hp, damage_per_sec, scan_ms, players_max.

CrowdyJS​

const war = kit.territory.map('valley');
war.view.onEvent((e) => e.type === 'captured' && toast(`${e.owner} took ${e.point}`));
await war.watch();
await war.join('blue');

const circle = kit.territory.zone(matchId);
await circle.watch();
await circle.join();

CrowdyCPP​

auto& war = kit->territory().map("valley");
war.join("blue", [](crowdy::kit::KitReply r) {
if (r.code() == "conflict") showFactionTaken();
});
auto& circle = kit->territory().zone(matchId);
circle.watch([&](crowdy::kit::KitReply) { drawCircle(circle.view().get()); });
game.poll(); // replies, topic messages and mirror changes arrive here

CrowdyPy​

war = kit.territory.map("valley")
await war.watch()
await war.join("blue")

circle = kit.territory.zone(match_id)
await circle.watch()
await circle.join()