use std::sync::Arc;
use wows_replays::analyzer::decoder::{DeathCause, Recognized};
use wows_replays::types::{EntityId, PlaneId};
use crate::map_data::MinimapPos;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ShipVisibility {
Visible,
MinimapOnly,
Undetected,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ShipConfigCircleKind {
Detection,
MainBattery,
SecondaryBattery,
Radar,
Hydro,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct ShipConfigFilter {
pub detection: bool,
pub main_battery: bool,
pub secondary_battery: bool,
pub radar: bool,
pub hydro: bool,
}
impl ShipConfigFilter {
pub fn is_enabled(&self, kind: &ShipConfigCircleKind) -> bool {
match kind {
ShipConfigCircleKind::Detection => self.detection,
ShipConfigCircleKind::MainBattery => self.main_battery,
ShipConfigCircleKind::SecondaryBattery => self.secondary_battery,
ShipConfigCircleKind::Radar => self.radar,
ShipConfigCircleKind::Hydro => self.hydro,
}
}
pub fn all_enabled() -> Self {
Self {
detection: true,
main_battery: true,
secondary_battery: true,
radar: true,
hydro: true,
}
}
pub fn any_enabled(&self) -> bool {
self.detection || self.main_battery || self.secondary_battery || self.radar || self.hydro
}
}
pub enum ShipConfigVisibility {
SelfOnly,
Filtered(Arc<dyn Fn(EntityId) -> Option<ShipConfigFilter> + Send + Sync>),
}
impl ShipConfigVisibility {
pub fn filter_for(&self, is_self: bool, entity_id: EntityId) -> Option<ShipConfigFilter> {
match self {
ShipConfigVisibility::SelfOnly => {
if is_self {
Some(ShipConfigFilter::all_enabled())
} else {
None
}
}
ShipConfigVisibility::Filtered(cb) => cb(entity_id),
}
}
}
impl Default for ShipConfigVisibility {
fn default() -> Self {
Self::SelfOnly
}
}
impl Clone for ShipConfigVisibility {
fn clone(&self) -> Self {
match self {
Self::SelfOnly => Self::SelfOnly,
Self::Filtered(cb) => Self::Filtered(Arc::clone(cb)),
}
}
}
impl std::fmt::Debug for ShipConfigVisibility {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::SelfOnly => write!(f, "SelfOnly"),
Self::Filtered(_) => write!(f, "Filtered(<callback>)"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FontHint {
#[default]
Primary,
Fallback(usize),
}
#[derive(Debug, Clone)]
pub struct ChatEntry {
pub clan_tag: String,
pub clan_color: Option<[u8; 3]>,
pub player_name: String,
pub team_color: [u8; 3],
pub ship_species: Option<String>,
pub ship_name: Option<String>,
pub message: String,
pub message_color: [u8; 3],
pub opacity: f32,
pub font_hint: FontHint,
}
#[derive(Debug, Clone)]
pub struct KillFeedEntry {
pub killer_name: String,
pub killer_species: Option<String>,
pub killer_ship_name: Option<String>,
pub killer_color: [u8; 3],
pub victim_name: String,
pub victim_species: Option<String>,
pub victim_ship_name: Option<String>,
pub victim_color: [u8; 3],
pub cause: Recognized<DeathCause>,
}
#[derive(Debug)]
pub enum DrawCommand {
ShotTracer {
from: MinimapPos,
to: MinimapPos,
color: [u8; 3],
},
Torpedo { pos: MinimapPos, color: [u8; 3] },
Smoke {
pos: MinimapPos,
radius: i32,
color: [u8; 3],
alpha: f32,
},
Ship {
entity_id: EntityId,
pos: MinimapPos,
yaw: f32,
species: Option<String>,
color: Option<[u8; 3]>,
visibility: ShipVisibility,
opacity: f32,
is_self: bool,
player_name: Option<String>,
ship_name: Option<String>,
is_detected_teammate: bool,
name_color: Option<[u8; 3]>,
},
HealthBar {
entity_id: EntityId,
pos: MinimapPos,
fraction: f32,
fill_color: [u8; 3],
background_color: [u8; 3],
background_alpha: f32,
},
DeadShip {
entity_id: EntityId,
pos: MinimapPos,
yaw: f32,
species: Option<String>,
color: Option<[u8; 3]>,
is_self: bool,
player_name: Option<String>,
ship_name: Option<String>,
},
BuffZone {
pos: MinimapPos,
radius: i32,
color: [u8; 3],
alpha: f32,
marker_name: Option<String>,
},
CapturePoint {
pos: MinimapPos,
radius: i32,
color: [u8; 3],
alpha: f32,
label: String,
progress: f32,
invader_color: Option<[u8; 3]>,
},
TurretDirection {
entity_id: EntityId,
pos: MinimapPos,
yaw: f32,
color: [u8; 3],
length: i32,
},
Building {
pos: MinimapPos,
color: [u8; 3],
is_alive: bool,
},
Plane {
plane_id: PlaneId,
owner_entity_id: EntityId,
pos: MinimapPos,
icon_key: String,
player_name: Option<String>,
ship_name: Option<String>,
},
ConsumableRadius {
entity_id: EntityId,
pos: MinimapPos,
radius_px: i32,
color: [u8; 3],
alpha: f32,
},
PatrolRadius {
plane_id: PlaneId,
pos: MinimapPos,
radius_px: i32,
color: [u8; 3],
alpha: f32,
},
ConsumableIcons {
entity_id: EntityId,
pos: MinimapPos,
icon_keys: Vec<String>,
is_friendly: bool,
has_hp_bar: bool,
},
ShipConfigCircle {
entity_id: EntityId,
pos: MinimapPos,
radius_px: f32,
color: [u8; 3],
alpha: f32,
dashed: bool,
label: Option<String>,
kind: ShipConfigCircleKind,
player_name: String,
is_self: bool,
},
PositionTrail {
entity_id: EntityId,
player_name: Option<String>,
points: Vec<(MinimapPos, [u8; 3])>,
},
TeamBuffs {
friendly_buffs: Vec<(String, u32)>,
enemy_buffs: Vec<(String, u32)>,
},
ScoreBar {
team0: i32,
team1: i32,
team0_color: [u8; 3],
team1_color: [u8; 3],
max_score: i32,
team0_timer: Option<String>,
team1_timer: Option<String>,
advantage_label: String,
advantage_team: i32,
},
TeamAdvantage {
label: String,
color: [u8; 3],
breakdown: crate::advantage::AdvantageBreakdown,
},
Timer {
time_remaining: Option<i64>,
elapsed: f32,
},
PreBattleCountdown { seconds: i64 },
KillFeed { entries: Vec<KillFeedEntry> },
ChatOverlay { entries: Vec<ChatEntry> },
BattleResultOverlay {
text: String,
subtitle: Option<String>,
color: [u8; 3],
subtitle_above: bool,
},
}
pub trait RenderTarget {
fn begin_frame(&mut self);
fn draw(&mut self, cmd: &DrawCommand);
fn end_frame(&mut self);
}