Skip to content
Skip to documentation content

Defense / Counter Scout Plan

Counter Scout Plan

Pin attackers and impact targets, compare scout launch times across possible Tournament Square levels and record coordination status.

At a glance

Product route: /workspaces/{workspace_id}/counter-scout-plan.

Who can open this page: signed-in users with enabled workspace entitlement and verified membership, including the owner. Non-owners need active membership and collection; verified owners bypass the individual grant check, not entitlement or verification. Page viewing does not require a current linked-account resolver; certain write actions do. Navigation visibility never grants endpoint access.

What you see

Step1 Attackers accepts Coordinates and Add; rows show Tribe icon, Player, Village/coordinates, TS minimum–maximum, Slowest Unit selector (label and base fields/hour), and Remove. Step2 Targets accepts Coordinates and optional Impact time with seconds; rows show Player, Village/coordinates, Impact Time, Tags and Remove. Coordinates such as synthetic 12|-34 or (12,-34) are parsed integers; this form does not bound them to the world or require roster existence.

Step3 Scout Plan shows Account, Village, Send Time, Timer, Scouter Target (attacker village), TS (assumed attacker TS), Counter Scout For (defender target village) and Status. The scouter’s own TS is used in travel but is not this TS column. Scout counts, travel durations, attacker departure, generated-at timestamp and unit type exist as context or outputs but are not displayed as separate plan columns. Status cycles Not sent → Scout on the way → Scout verified → Not sent. Changing a status records coordination only; it never launches troops or verifies a game report automatically.

Who fills in each field

Field or data What it means Who fills it in Can it be changed here? When it updates
Attacker, slowest unit and TS range Coordinate is member input; roster supplies player/village/tribe. Captured TS initializes a single-level range; unknown TS defaults0…20. Member chooses a one-based unit slot1…10 and inclusive range0…20. signed-in-member, roster-ingest, extension-collected, backend-derived Verified collection; TS min≤max and unit slot validated Add, range/unit edit; labels refreshed on reload
Target and impact time Coordinate and optional local datetime input; roster supplies labels/tags. Browser submits ISO UTC; malformed/absent impact becomes missing. signed-in-member, roster-ingest Add again at same coordinates replaces impact; no inline time editor Target add/update and reload
Scouters Current captured workspace villages carrying the manual scouter tag, their source TS and tribe scout speed; no positive scout-count test. signed-in-member, extension-collected, backend-derived Read-only here; manage tag on Villages and source TS on Troops Overview Plan generation from current recorded data
Send time and timer Every resolvable attacker × timed target × inclusive attacker TS level × eligible scouter; future-first ordering, then nearest overdue. backend-derived Read-only Plan reload after selection edits; display ticks each second
Status pending, sent or verified, keyed to attacker, target, scouter coordinates and attacker TS level. signed-in-member Verified collection; click cycles states Status submission; default pending

Calculations

Wrapped map distance

Calculation ID: map.wrapped-distance. Shortest Euclidean distance on a toroidal Travian world.

size=2*radius+1; dx=min(abs(x1-x2),size-abs(x1-x2)); same for dy; hypot(dx,dy). Default radius200 means401coordinates per axis, so -200 and200 are adjacent.

Input Who supplies it Unit Optional / fallback
Source/destination coordinates signed-in-member, roster-ingest, extension-collected map coordinates Required; Required; no fallback
radius backend-derived fields Optional; 200

Output: fields. Precision: Floating point hypot. Rounding: No rounding. Clamp: No output clamp. Timezone: not-applicable.

Same coordinate returns zero. Assumes coordinates in the configured world; this helper does not validate/wrap arbitrary out-of-world values. Browser radius null also defaults200; mirrors are separately hashed and not proof of equivalence.

For each axis choose the shorter of the direct difference and the difference across the map edge, then take the Euclidean length of those two distances. On the default map coordinates lie in −200…200. For synthetic (−200|0) to (200|0), the distance is one field. This helper is not an out-of-bounds validator.

Canonical source and dependencies: see the reviewed references below. Mirrors are independent copies, not an equivalence guarantee.

Calculation source references - Canonical: `src/trapitan/core/travian.py` — `travian_distance`. - Non-canonical mirror: `src/trapitan/web/static/js/travian-distance.js` — ` function travianDistance(`. - Non-canonical mirror: `extension/chromium/lib/def-call-dispatch.js` — `function travianDistance(`.

Used on: Villages, Def Calls, Counter Scout Plan, Artifacts Registry, Operation Dashboard.

Server troop movement multiplier

Calculation ID: server.movement-multiplier. Map hostname speed labels to actual troop movement scaling.

Regex .x(\d+). yields server label (default1); mapping {1:1,2:2,3:2,5:2,10:4}, unknown label=>1. Movement is not linear with server speed.

Input Who supplies it Unit Optional / fallback
server_domain backend-derived canonical hostname Required; Required; no fallback
UNIT_SPEEDS backend-derived fields/hour per tribe slot Optional; Unsupported tribe uses Roman speed table

Output: speed multiplier. Precision: Exact integer. Rounding: No rounding. Clamp: No output clamp. Timezone: not-applicable.

No xN label defaults1. Unknown speed labels fall back1. Browser/extension dispatch consumes the backend multiplier, rather than copying the hostname map.

A hostname containing .x3. gives movement ×2; .x10. gives ×4. Missing or unrecognized labels give ×1. The base speed is measured in fields per hour. Roman t1…t10 speeds are 6,5,7,16,14,10,4,3,4,5; Teuton 7,7,6,9,10,9,4,3,4,5; Gaul 7,6,17,19,16,13,4,3,5,5. Unsupported tribe uses the Roman table. Dispatch uses the slowest included troop; Counter Scout uses the manually chosen attacker unit and the scouter tribe’s scout (Roman slot4 speed16; Teuton slot4 speed9; Gaul slot3 speed17).

Canonical source and dependencies: see the reviewed references below. Mirrors are independent copies, not an equivalence guarantee.

Calculation source references - Canonical: `src/trapitan/intelligence/service.py` — `parse_server_speed`. - Dependency: `src/trapitan/intelligence/service.py` — `_SERVER_SPEED_RE`. - Dependency: `src/trapitan/intelligence/service.py` — `troop_speed_multiplier`. - Dependency: `src/trapitan/intelligence/service.py` — `_TROOP_SPEED_MULTIPLIERS`. - Dependency: `src/trapitan/intelligence/service.py` — `UNIT_SPEEDS`. - Dependency: `src/trapitan/intelligence/service.py` — `unit_speeds_for_tribe`. - Non-canonical mirrors: none registered.

Used on: Def Calls, Counter Scout Plan, Operation Dashboard.

Tournament Square travel

Calculation ID: travel.tournament-square. Platform one-way travel seconds using slowest troop speed and TS after20fields.

d=wrapped distance; d==0 =>0 before speed validation; v=base_speedspeed_multiplier; v<=0 raises; d<=20 or TS<=0 =>3600d/v; otherwise3600(20/v+(d-20)/(v(1+0.1TS))). Caller chooses slowest present selected unit. Operation planner rounds one-way seconds to integer. Related extension farm-list variant uses0.2TS, clampsTS0..20, returns round-trip minutes and is not interchangeable with this platform formula.

Input Who supplies it Unit Optional / fallback
Coordinates signed-in-member, roster-ingest map coordinates Required; Required; no fallback
base_speed backend-derived fields/hour Required; Required; no fallback
speed_multiplier backend-derived multiplier Optional; 1
Tournament Square extension-collected, signed-in-member level Optional; 0

Output: one-way seconds. Precision: Floating-point seconds; planner uses integer seconds. Rounding: Python round(seconds) in planner; browser display varies: operation travel rounds minutes with minimum1 for positive travel, defense countdown floors absolute seconds. Clamp: No output clamp. Timezone: Travel duration independent of timezone.

Zero distance returns0 even with invalid speed. Unknown/empty speeds: platform raises on nonpositive speed; browser dispatch returns null, operation mirror Infinity. Farm-list mirror is a related divergent20% round-trip variant outside web guide scope; do not describe it as equal. No hero/artifact movement bonus is applied by these formulas.

Let d be distance in fields, v the base fields/hour multiplied by server movement, and L the source TS level. Convert hours to seconds by multiplying by 3,600. The first 20 fields use ordinary speed; only the remaining distance uses the factor 1+0.1L. At distance20 or TS0 there is no TS benefit. A synthetic distance30, speed10, multiplier1, TS10 takes 9,000 seconds (2½ hours). Def Calls uses fractional seconds internally and floors the absolute countdown; Counter Scout retains fractional travel for its timestamp calculation and floors only the displayed timer. No hero or artifact travel bonus is included.

Canonical source and dependencies: see the reviewed references below. Mirrors are independent copies, not an equivalence guarantee.

Calculation source references - Canonical: `src/trapitan/intelligence/service.py` — `travel_seconds`. - Dependency: `src/trapitan/intelligence/service.py` — `TS_BONUS_PER_LEVEL`. - Dependency: `src/trapitan/intelligence/service.py` — `UNIT_SPEEDS`. - Dependency: `src/trapitan/core/travian.py` — `travian_distance`. - Dependency: `src/trapitan/api/routes/web.py` — `create_operation_plan`. - Non-canonical mirror: `src/trapitan/web/templates/def_calls.html` — ` function travelSeconds(`. - Non-canonical mirror: `src/trapitan/web/static/js/operation-dashboard.js` — ` function planTravelSeconds(`. - Non-canonical mirror: `extension/chromium/lib/def-call-dispatch.js` — `function travelSeconds(`. - Non-canonical mirror: `extension/chromium/lib/farm-list-calculator.js` — `export function roundTripMinutes(`.

Used on: Def Calls, Counter Scout Plan, Operation Dashboard.

Counter-scout send time

Calculation ID: counter-scout.send-time. Scout launch deadline before attacker departure.

attacker_departure=impact-attacker_travel; scout_send=impact-(attacker_travel+scout_travel). Generate every attacker × timed target × inclusive TS level × scouter row; timer=(send-now).total_seconds(); sorting key future=(0,seconds), overdue=(1,abs(seconds)).

Input Who supplies it Unit Optional / fallback
impact_time signed-in-member timestamp Required; Required; no fallback
Attacker/scout travel backend-derived seconds Required; Required; no fallback
Current time backend-derived UTC timestamp Optional; datetime.now(UTC)

Output: timestamp and timer seconds. Precision: Datetime timedelta precision; fractional timer seconds. Rounding: Backend no display rounding; client countdown floors absolute milliseconds/1000. Clamp: No output clamp. Timezone: Datetime subtraction preserves supplied impact timezone; browser local input is converted to ISO UTC (Z); planner compares against UTC now. No universal direct-submission UTC-normalization guarantee..

Missing target impact produces no rows. Unresolvable attackers are skipped. Overdue rows remain visible after future rows; status key includes TS level.

Subtract attacker travel from impact to find attacker departure, then subtract scouter-to-attacker travel to find scout send time. A synthetic impact18:00 UTC, attacker travel2h and scout travel30min gives send15:30 UTC. The UI converts local datetime input to ISO UTC; the input parser also accepts offset-bearing ISO values, so direct submissions do not have an explicit UTC-normalization step here. Future timers including zero come first in ascending time; negative timers follow in ascending absolute overdue duration. Backend keeps datetime precision; the browser floors absolute milliseconds/1,000 and prefixes overdue timers with minus. There is no output clamp and no availability window/half-open interval test.

Canonical source and dependencies: see the reviewed references below. Mirrors are independent copies, not an equivalence guarantee.

Calculation source references - Canonical: `src/trapitan/intelligence/service.py` — `counter_scout_send_time`. - Dependency: `src/trapitan/intelligence/service.py` — `counter_scout_timer_sort_key`. - Dependency: `src/trapitan/api/routes/web.py` — `get_counter_scout_plan`. - Dependency: `src/trapitan/api/routes/web.py` — `_parse_impact_time`. - Dependency: `src/trapitan/api/routes/web.py` — `add_counter_scout_target`. - Non-canonical mirror: `src/trapitan/web/static/js/counter-scout-plan.js` — `(function () { var root = document.querySelector`.

Used on: Counter Scout Plan.

Freshness and updates

Attackers and targets load separately on entry, each causing plan generation. Changes to unit/TS/target/attacker/status reload relevant recorded data and plan. The one-second browser interval only recalculates timer display/order; it does not poll the backend or collect game data. Impact and Send Time display browser-local DD/MM/YYYY HH:MM:SS. Source roster labels and village TS/tags may change between loads. TS default is captured when an attacker is first added; adding an existing attacker leaves its range unchanged. The server generation time is UTC; a browser clock change affects the visible timer. A tagged village can be included with zero recorded scouts: plan eligibility is not a guarantee of troop availability.

Actions and permissions

Who can perform each action / Who can take action: the actor labels describe data responsibility; actual grants and action-specific guards decide access. Every feature request remains workspace-scoped and entitlement/verification-gated.

Action Actor Permission
Maintain attacker/target rows signed-in-member Verified collection, entitlement and same origin; parsed coordinates, workspace-scoped removal; selected unit1…10. Unknown roster coordinates may be saved
Change TS range signed-in-member Verified collection, entitlement, same origin, workspace attacker, integer levels0…20 and min≤max
Mark scout status signed-in-member Verified collection, entitlement and same origin; pending/sent/verified, valid workspace attacker/target, eligible scouter coordinate and TS in attacker range

States and edge cases

Empty sections say “No attackers yet” or “No targets yet”; the empty scout plan asks for attackers, targets and alliance villages tagged scouter. Load failures clear the corresponding table; plan-load failure clears rows without a dedicated error message. Add failures show a section error, failed deletes leave the row, failed unit/TS edits reload stored values and failed status writes retain the previous state. Missing roster attackers remain saved but are skipped in generation; unknown targets can still produce rows using their coordinates with dash labels. Missing or invalid impact generates no rows.

Overdue rows remain visible with a negative duration; future rows including exactly-zero timer sort first. There is no availability calendar, interval gate or half-open availability rule here. TS affects only travel beyond20 fields, not the first20. Coordinates at −200 and200 are adjacent; arbitrary out-of-world inputs are not safely normalized by the geometry helper. A manually selected “Slowest Unit” is an assumption about the attacking wave, not an inferred troop composition. Unsupported tribes use Roman speed options while unresolved tribe display remains unknown. Scouter tags/source TS changes can invalidate a saved status combination; returning combinations reuse the saved key.

Incoming Attacks, Def Calls, Villages, Troops Overview.

Source references

Stable page ID: defense.counter-scout.

Source reviewed: 2026-10-07

Reviewed handlers, visible controls and producers - `src/trapitan/api/routes/web.py` — `counter_scout_plan_page`. - `src/trapitan/web/templates/counter_scout_plan.html` — bounded template/script region. - `src/trapitan/api/routes/web.py` — `_shell_context`. - `src/trapitan/api/routes/web.py` — `_parse_impact_time`. - `src/trapitan/api/routes/web.py` — `_coerce_coordinates`. - `src/trapitan/api/routes/web.py` — `_attacker_payload`. - `src/trapitan/api/routes/web.py` — `_target_payload`. - `src/trapitan/api/routes/web.py` — `list_counter_scout_attackers`. - `src/trapitan/api/routes/web.py` — `list_counter_scout_targets`. - `src/trapitan/api/routes/web.py` — `get_counter_scout_plan`. - `src/trapitan/web/static/js/counter-scout-plan.js` — bounded template/script region. - `src/trapitan/authorization/dependencies.py` — `require_workspace_permission`. - `src/trapitan/authorization/policy.py` — `authorize_workspace_action`. - `src/trapitan/authorization/policy.py` — `_authorize_from_database`. - `src/trapitan/authorization/policy.py` — `is_membership_verified`. - `src/trapitan/authorization/policy.py` — `_active_membership`. - `src/trapitan/authorization/policy.py` — `_is_workspace_entitled`. - `src/trapitan/authorization/policy.py` — `_has_active_permission`. - `src/trapitan/authorization/policy.py` — `WorkspaceAction`. - `src/trapitan/authorization/policy.py` — `GRANTABLE_ACTIONS`. - `src/trapitan/api/routes/web.py` — `add_counter_scout_attacker`. - `src/trapitan/api/routes/web.py` — `update_counter_scout_attacker_unit`. - `src/trapitan/api/routes/web.py` — `update_counter_scout_attacker_ts_range`. - `src/trapitan/intelligence/service.py` — `IntelligenceService.resolve_counter_scout_attacker`. - `src/trapitan/api/routes/web.py` — `add_counter_scout_target`. - `src/trapitan/intelligence/service.py` — `IntelligenceService.counter_scout_scouters`. - `src/trapitan/api/routes/web.py` — `update_counter_scout_status`. - `src/trapitan/api/routes/web.py` — `delete_counter_scout_attacker`. - `src/trapitan/api/routes/web.py` — `delete_counter_scout_target`. - `src/trapitan/api/routes/guards.py` — `is_same_origin`.