team04_server/messages/
attack.rs

1use crate::{board::Coord, lobby::state::clients::PlayerId, unit::UnitType};
2
3use super::*;
4
5pub struct Attack {
6    attacks_per_match: Vec<PerMatch>,
7}
8#[derive(Serialize)]
9#[serde(rename_all = "camelCase")]
10struct PerMatch {
11    #[serde(rename = "match")]
12    matchup: [PlayerId; 2],
13    current_fight_round: u64,
14    attacks: Vec<SingleAttack>,
15}
16#[derive(Serialize)]
17#[serde(rename_all = "camelCase")]
18pub struct SingleAttack {
19    unit: UnitType,
20    #[serde(rename = "playerID")]
21    player_id: PlayerId,
22    current_position: [usize; 2],
23    target_position: [usize; 2],
24    /// can be negative to represent healing
25    damage: i64,
26}
27impl SingleAttack {
28    pub fn new(
29        unit: UnitType,
30        player_id: PlayerId,
31        current_position: Coord,
32        target_position: Coord,
33        damage: i64,
34    ) -> Self {
35        Self {
36            unit,
37            player_id,
38            current_position: [current_position.x, current_position.y],
39            target_position: [target_position.x, target_position.y],
40            damage,
41        }
42    }
43}
44
45impl Attack {
46    /// Use this to create a new attack message, then add attacks to
47    /// it using [with_attack](Self::with_attack) or [push_attack](Self::push_attack).
48    pub fn new_empty() -> Self {
49        Self {
50            attacks_per_match: vec![],
51        }
52    }
53    pub fn is_empty(&self) -> bool {
54        self.attacks_per_match.is_empty()
55    }
56    fn coord_to_arr(coord: Coord) -> [usize; 2] {
57        [coord.x, coord.y]
58    }
59    pub fn with_attack(
60        mut self,
61        matchup: (PlayerId, PlayerId),
62        current_fight_round: u64,
63        attack: SingleAttack,
64    ) -> Self {
65        self.push_attack(matchup, current_fight_round, attack);
66        self
67    }
68    pub fn push_attack(
69        &mut self,
70        matchup: (PlayerId, PlayerId),
71        current_fight_round: u64,
72        attack: SingleAttack,
73    ) -> &mut Self {
74        // Note: this code is duplicated, see also messages/movement
75        if let Some(per_match) = self.attacks_per_match.iter_mut().find(|m| {
76            (m.matchup[0] == matchup.0 && m.matchup[1] == matchup.1)
77                || (m.matchup[0] == matchup.1 && m.matchup[1] == matchup.0)
78        }) {
79            per_match.attacks.push(attack);
80        } else {
81            self.attacks_per_match.push(PerMatch {
82                matchup: [matchup.0, matchup.1],
83                current_fight_round,
84                attacks: vec![attack],
85            });
86        }
87        self
88    }
89}
90
91impl MessageTx for Attack {
92    fn serialize(&self) -> String {
93        #[derive(Serialize)]
94        #[serde(rename_all = "camelCase")]
95        pub struct Attack<'a> {
96            message_type: &'static str,
97            attacks_per_match: &'a [PerMatch],
98        }
99
100        let message = Attack {
101            message_type: "ATTACK",
102            attacks_per_match: &self.attacks_per_match,
103        };
104
105        serialize(&message)
106    }
107}