App 2.38.0: Overview styles Visor and Empire

Visor, after Halo's helmet display: the battery as the shield bar, the
range as the ammunition counter, P R N D as grenade slots, the speed in
the reticle with power round it, and the power trail as blips on a
motion tracker that sweeps while moving. Original blue or the accent.

Empire, after Age of Empires: a wooden resource bar, an isometric world
that moves with the speed, the car as the selected unit, P R N D as
commands, a diamond minimap, and ages by odometer (EmpireAge, tested).
The app takes the player's blue.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LhzAVaUyqcw5PkGjz4mWW6
This commit is contained in:
2026-10-26 21:00:50 +01:00
co-authored by Claude Opus 5.5
parent 96b9659bdd
commit 7d2c1e8bb4
18 changed files with 961 additions and 18 deletions
@@ -0,0 +1,49 @@
package com.evsuite.abrp;
/**
* The Empire style's ages, by odometer: the Dark Age below 10,000 km, the Feudal Age below
* 30,000, the Castle Age below 60,000 and the Imperial Age from there. Pure Java, unit-tested.
*/
final class EmpireAge {
private static final String[] NAMES = { "Dark Age", "Feudal Age", "Castle Age", "Imperial Age" };
/** Where each age after the first begins, in km. */
private static final float[] STARTS = { 10_000f, 30_000f, 60_000f };
private EmpireAge() {}
/** 0 to 3, or -1 when the odometer is unread. */
static int index(Float km) {
if (km == null || Float.isNaN(km)) return -1;
int age = 0;
while (age < STARTS.length && km >= STARTS[age]) age++;
return age;
}
/** The age's name, "—" when unread. */
static String name(Float km) {
int age = index(km);
return age < 0 ? "—" : NAMES[age];
}
/** The next age's name, or null in the last age and when unread. */
static String next(Float km) {
int age = index(km);
return age < 0 || age >= STARTS.length ? null : NAMES[age + 1];
}
/** Kilometres left to the next age, or null in the last age and when unread. */
static Float toNext(Float km) {
int age = index(km);
return age < 0 || age >= STARTS.length ? null : STARTS[age] - km;
}
/** How far through the current age, 0..1; 1 in the last age, 0 when unread. */
static float progress(Float km) {
int age = index(km);
if (age < 0) return 0f;
if (age >= STARTS.length) return 1f;
float from = age == 0 ? 0f : STARTS[age - 1];
return Math.max(0f, Math.min(1f, (km - from) / (STARTS[age] - from)));
}
}