mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 08:00:43 +00:00
Add retreating warship indicator and warship 2-color treatment
Warships now render with a dedicated center accent band so their state reads at a glance: - Normal: center + outer ring share the territory color (2-color look), hull uses the border color. - Angry (attacking): outer ring and center turn red. - Retreating to repair: the center blinks black. The warship sprite center moved to its own gray value (100) in the unit atlas so the shader can drive it via a new fourth replacement band, with no per-unit-type branching — the missiles' shared 130 blend band is untouched. Warship repair-retreat (warshipState.state === "retreating") now feeds the existing UnitState.retreating boolean in UnitView, which UnitPass maps to a FLAG_RETREATING instance flag.
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 298 B After Width: | Height: | Size: 595 B |
@@ -93,7 +93,7 @@ const HYDROGEN_BOMB_COL = UNIT_ORDER.indexOf(UT_HYDROGEN_BOMB);
|
|||||||
* Per-instance data (16 bytes):
|
* Per-instance data (16 bytes):
|
||||||
* float x, y, ownerID — 12 bytes (3 floats)
|
* float x, y, ownerID — 12 bytes (3 floats)
|
||||||
* uint8 atlasIdx — 1 byte (atlas column 0–11)
|
* uint8 atlasIdx — 1 byte (atlas column 0–11)
|
||||||
* uint8 flags — 1 byte (0 = normal, 1 = flicker, 2 = angry)
|
* uint8 flags — 1 byte (0 = normal, 1 = flicker, 2 = angry, 3 = trade-friendly, 4 = retreating)
|
||||||
* 2 bytes padding — aligns to 4-byte boundary
|
* 2 bytes padding — aligns to 4-byte boundary
|
||||||
*/
|
*/
|
||||||
const FLOATS_PER_INSTANCE = 4;
|
const FLOATS_PER_INSTANCE = 4;
|
||||||
@@ -104,6 +104,7 @@ const FLAG_NORMAL = 0;
|
|||||||
const FLAG_FLICKER = 1;
|
const FLAG_FLICKER = 1;
|
||||||
const FLAG_ANGRY = 2;
|
const FLAG_ANGRY = 2;
|
||||||
const FLAG_TRADE_FRIENDLY = 3;
|
const FLAG_TRADE_FRIENDLY = 3;
|
||||||
|
const FLAG_RETREATING = 4;
|
||||||
|
|
||||||
/** Atlas column indices for train sub-types (resolved from trainType + loaded) */
|
/** Atlas column indices for train sub-types (resolved from trainType + loaded) */
|
||||||
const TRAIN_ENGINE_COL = UNIT_ORDER.indexOf("TrainEngine");
|
const TRAIN_ENGINE_COL = UNIT_ORDER.indexOf("TrainEngine");
|
||||||
@@ -395,6 +396,8 @@ export class UnitPass {
|
|||||||
|
|
||||||
if (atlasIdx === undefined) continue;
|
if (atlasIdx === undefined) continue;
|
||||||
|
|
||||||
|
const isRetreatingWarship =
|
||||||
|
unit.unitType === UT_WARSHIP && unit.retreating;
|
||||||
const isAngryWarship =
|
const isAngryWarship =
|
||||||
unit.unitType === UT_WARSHIP && unit.targetUnitId !== null;
|
unit.unitType === UT_WARSHIP && unit.targetUnitId !== null;
|
||||||
const isFlicker = FLICKER_TYPES.has(unit.unitType);
|
const isFlicker = FLICKER_TYPES.has(unit.unitType);
|
||||||
@@ -416,13 +419,16 @@ export class UnitPass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const flags = isTradeFriendly
|
let flags = FLAG_NORMAL;
|
||||||
? FLAG_TRADE_FRIENDLY
|
if (isTradeFriendly) {
|
||||||
: isAngryWarship
|
flags = FLAG_TRADE_FRIENDLY;
|
||||||
? FLAG_ANGRY
|
} else if (isRetreatingWarship) {
|
||||||
: isFlicker
|
flags = FLAG_RETREATING;
|
||||||
? FLAG_FLICKER
|
} else if (isAngryWarship) {
|
||||||
: FLAG_NORMAL;
|
flags = FLAG_ANGRY;
|
||||||
|
} else if (isFlicker) {
|
||||||
|
flags = FLAG_FLICKER;
|
||||||
|
}
|
||||||
const isMissile = MISSILE_TYPES.has(unit.unitType);
|
const isMissile = MISSILE_TYPES.has(unit.unitType);
|
||||||
|
|
||||||
const x = unit.pos % this.mapW;
|
const x = unit.pos % this.mapW;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ out vec4 fragColor;
|
|||||||
const float FLAG_FLICKER = 1.0;
|
const float FLAG_FLICKER = 1.0;
|
||||||
const float FLAG_ANGRY = 2.0;
|
const float FLAG_ANGRY = 2.0;
|
||||||
const float FLAG_TRADE_FRIENDLY = 3.0;
|
const float FLAG_TRADE_FRIENDLY = 3.0;
|
||||||
|
const float FLAG_RETREATING = 4.0;
|
||||||
|
|
||||||
// Ally color for trade-friendly override (yellow — matches affiliation.ts ALLY)
|
// Ally color for trade-friendly override (yellow — matches affiliation.ts ALLY)
|
||||||
const vec3 ALLY_COLOR = vec3(1.0, 1.0, 0.0);
|
const vec3 ALLY_COLOR = vec3(1.0, 1.0, 0.0);
|
||||||
@@ -83,10 +84,15 @@ void main() {
|
|||||||
// Flag states (uint8 passed as float via vertex attribute):
|
// Flag states (uint8 passed as float via vertex attribute):
|
||||||
// 0 = normal
|
// 0 = normal
|
||||||
// 1 = flicker (nukes/warheads — cycling hot colors)
|
// 1 = flicker (nukes/warheads — cycling hot colors)
|
||||||
// 2 = angry (warships attacking — solid red territory band)
|
// 2 = angry (warships attacking — outer ring (180 band) solid red)
|
||||||
|
// 4 = retreating (warships fleeing to port — blinking black center)
|
||||||
|
float retreatBlink = 0.0;
|
||||||
if (abs(vFlags - FLAG_ANGRY) < 0.1) {
|
if (abs(vFlags - FLAG_ANGRY) < 0.1) {
|
||||||
// Angry: solid red territory band
|
// Angry: the outer ring (180) and center (100) go red via territoryColor
|
||||||
territoryColor = uAngryColor;
|
territoryColor = uAngryColor;
|
||||||
|
} else if (abs(vFlags - FLAG_RETREATING) < 0.1) {
|
||||||
|
// Retreating: slowly blink the center (100 band) black so the ship reads as fleeing
|
||||||
|
retreatBlink = step(0.5, fract(uTick * 0.07));
|
||||||
} else if (abs(vFlags - FLAG_FLICKER) < 0.1) {
|
} else if (abs(vFlags - FLAG_FLICKER) < 0.1) {
|
||||||
// Flicker: cycle through hot colors, offset by position hash
|
// Flicker: cycle through hot colors, offset by position hash
|
||||||
float phase = fract(uTick * uFlickerSpeed + vHash);
|
float phase = fract(uTick * uFlickerSpeed + vHash);
|
||||||
@@ -95,19 +101,24 @@ void main() {
|
|||||||
borderColor = FLICKER_COLORS[(idx + 2) % 4];
|
borderColor = FLICKER_COLORS[(idx + 2) % 4];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Three-band gray replacement:
|
// Four-band gray replacement:
|
||||||
// 180/255 ~ 0.706 -> territory color (light band)
|
// 180/255 ~ 0.706 -> territory color (light band)
|
||||||
// 130/255 ~ 0.510 -> spawn/mid color (interpolated)
|
// 130/255 ~ 0.510 -> spawn/mid color (interpolated; used by missiles)
|
||||||
|
// 100/255 ~ 0.392 -> center accent (warship center — tracks ring, blinks black)
|
||||||
// 70/255 ~ 0.275 -> border color (dark band)
|
// 70/255 ~ 0.275 -> border color (dark band)
|
||||||
vec3 spawnColor = mix(territoryColor, borderColor, 0.5);
|
vec3 spawnColor = mix(territoryColor, borderColor, 0.5);
|
||||||
|
vec3 centerColor = mix(territoryColor, vec3(0.0), retreatBlink);
|
||||||
|
|
||||||
vec3 color;
|
vec3 color;
|
||||||
if (gray > 0.6) {
|
if (gray > 0.6) {
|
||||||
// Light band (180) -> territory color
|
// Light band (180) -> territory color
|
||||||
color = territoryColor;
|
color = territoryColor;
|
||||||
} else if (gray > 0.4) {
|
} else if (gray > 0.45) {
|
||||||
// Mid band (130) -> spawn color
|
// Mid band (130) -> spawn color
|
||||||
color = spawnColor;
|
color = spawnColor;
|
||||||
|
} else if (gray > 0.34) {
|
||||||
|
// Center accent band (100) -> center color
|
||||||
|
color = centerColor;
|
||||||
} else {
|
} else {
|
||||||
// Dark band (70) -> border color
|
// Dark band (70) -> border color
|
||||||
color = borderColor;
|
color = borderColor;
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ function unitStateFromUpdate(u: UnitUpdate): UnitState {
|
|||||||
lastPos: u.lastPos,
|
lastPos: u.lastPos,
|
||||||
isActive: u.isActive,
|
isActive: u.isActive,
|
||||||
reachedTarget: u.reachedTarget,
|
reachedTarget: u.reachedTarget,
|
||||||
retreating: u.transportShipState?.isRetreating ?? false,
|
retreating:
|
||||||
|
(u.transportShipState?.isRetreating ?? false) ||
|
||||||
|
u.warshipState?.state === "retreating",
|
||||||
targetable: u.targetable,
|
targetable: u.targetable,
|
||||||
markedForDeletion: u.markedForDeletion,
|
markedForDeletion: u.markedForDeletion,
|
||||||
health: u.health ?? null,
|
health: u.health ?? null,
|
||||||
@@ -79,7 +81,9 @@ function applyUpdateInPlace(target: UnitState, u: UnitUpdate): void {
|
|||||||
target.lastPos = u.lastPos;
|
target.lastPos = u.lastPos;
|
||||||
target.isActive = u.isActive;
|
target.isActive = u.isActive;
|
||||||
target.reachedTarget = u.reachedTarget;
|
target.reachedTarget = u.reachedTarget;
|
||||||
target.retreating = u.transportShipState?.isRetreating ?? false;
|
target.retreating =
|
||||||
|
(u.transportShipState?.isRetreating ?? false) ||
|
||||||
|
u.warshipState?.state === "retreating";
|
||||||
target.targetable = u.targetable;
|
target.targetable = u.targetable;
|
||||||
target.markedForDeletion = u.markedForDeletion;
|
target.markedForDeletion = u.markedForDeletion;
|
||||||
target.health = u.health ?? null;
|
target.health = u.health ?? null;
|
||||||
|
|||||||
Reference in New Issue
Block a user