essences/
fighting.rs

1use crate::abilities::AbilityId;
2use crate::bundles::BundleId;
3use crate::dungeons::DungeonTemplateId;
4use crate::entity::{Coordinates, Entity, EntityId};
5use crate::game::EntityTemplateId;
6use crate::pets::PetId;
7
8use crate::prelude::*;
9
10use strum_macros::{Display, EnumString};
11
12#[derive(
13    Clone,
14    Debug,
15    Default,
16    Serialize,
17    Deserialize,
18    PartialEq,
19    Eq,
20    Tsify,
21    EnumString,
22    Display,
23    JsonSchema,
24)]
25#[tsify(from_wasm_abi, into_wasm_abi)]
26pub enum EntityTeam {
27    #[default]
28    Ally,
29    Enemy,
30}
31
32impl CustomType for EntityTeam {
33    fn build(mut builder: TypeBuilder<Self>) {
34        builder
35            .with_name("EntityTeam")
36            .with_fn("EntityTeam", |team: &str| {
37                if team == "Ally" {
38                    Self::Ally
39                } else {
40                    Self::Enemy
41                }
42            })
43            .with_get("str", |et: &mut EntityTeam| EntityTeam::to_string(et));
44    }
45}
46
47#[derive(
48    Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Tsify, Display, JsonSchema,
49)]
50#[tsify(from_wasm_abi, into_wasm_abi)]
51pub enum EntityType {
52    #[schemars(title = "ПВЕ юнит")]
53    PVEEntity {
54        #[schemars(title = "ID юнита", schema_with = "entity_link_id_schema")]
55        entity_template_id: EntityTemplateId,
56    },
57    #[default]
58    #[schemars(title = "ПВП юнит")]
59    PVPEntity,
60}
61
62#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Tsify, JsonSchema)]
63pub struct FightEntity {
64    #[schemars(title = "Тип юнита")]
65    pub entity_type: EntityType,
66    #[schemars(title = "Координаты юнита")]
67    pub position: Coordinates,
68    #[schemars(title = "Нужна ли отрисовка большого хп бара")]
69    pub has_big_hp_bar: bool,
70    #[schemars(title = "Команда юнита")]
71    pub team: EntityTeam,
72}
73
74#[derive(
75    Clone,
76    Debug,
77    Default,
78    Serialize,
79    Deserialize,
80    PartialEq,
81    Eq,
82    Tsify,
83    EnumString,
84    Display,
85    JsonSchema,
86)]
87#[tsify(from_wasm_abi, into_wasm_abi)]
88pub enum FightType {
89    #[default]
90    CampaignFight,
91    CampaignBossFight,
92    ArenaPVP,
93    VassalPVP,
94    SingleFight,
95}
96
97#[declare]
98pub type FightTemplateId = Uuid;
99
100#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Tsify, JsonSchema, CustomType)]
101pub struct FightTemplate {
102    #[schemars(schema_with = "id_schema")]
103    pub id: FightTemplateId,
104
105    #[schemars(title = "Название боя")]
106    pub title: i18n::I18nString,
107
108    #[schemars(title = "Мощь боя")]
109    pub power: Option<u64>,
110
111    // TODO #[schemars(schema_with = "battlefield_id_schema")]
112    // pub battlefield: BattlefieldId, // TODO mb location, not battlefield?
113    #[schemars(title = "Все существа в бою")]
114    pub fight_entities: Vec<FightEntity>,
115
116    #[schemars(title = "Максимальная длительность боя в тиках")]
117    pub max_duration_ticks: u64,
118
119    #[schemars(title = "Целевая ширина экрана (в клетках)")]
120    pub target_width_cells: u64,
121
122    #[schemars(title = "Fx на старте боя")]
123    // TODO needs implementation + maybe add delay ticks, so fx would have enought time to play?
124    pub starting_fx: String,
125
126    #[schemars(title = "Тип боя")]
127    pub fight_type: FightType,
128
129    #[schemars(title = "Количество волн в бою")]
130    pub waves_amount: i64,
131
132    #[schemars(title = "Скрипт для подготовки боя", schema_with = "script_schema")]
133    pub prepare_fight_script: String,
134
135    #[schemars(title = "Скрипт для начала боя", schema_with = "script_schema")]
136    pub start_script: String,
137
138    #[schemars(title = "Задник", schema_with = "aa_background_schema")]
139    pub background: String,
140
141    #[schemars(
142        title = "Время ожидания перед стартом следующего боя в тиках",
143        description = "Это момент анимации перебежки персонажа между битвами"
144    )]
145    pub start_fight_delay_ticks: Option<u64>,
146
147    #[schemars(
148        title = "Время ожидания перед стартом уже начавшегося боя в случае победы",
149        description = "Это момент, когда враги выбегают на экран"
150    )]
151    pub prepare_fight_win_duration_ticks: Option<u64>,
152
153    #[schemars(
154        title = "Время ожидания перед стартом уже начавшегося боя в случае поражения",
155        description = "Это момент, когда враги выбегают на экран"
156    )]
157    pub prepare_fight_lose_duration_ticks: Option<u64>,
158
159    #[schemars(title = "Время ожидания перед окончанием боя")]
160    pub end_fight_delay_ticks: Option<u64>,
161
162    #[schemars(
163        title = "Бандл награды за победу в бою",
164        schema_with = "option_bundle_id_schema"
165    )]
166    pub bundle_reward_id: Option<BundleId>,
167
168    #[schemars(title = "Останавливать ли бой после победы")]
169    pub stop_on_win: bool,
170
171    #[schemars(title = "Останавливать ли бой после поражения")]
172    pub stop_on_lose: bool,
173
174    #[schemars(title = "Показывать ли VS экран в начале боя")]
175    pub show_vs_screen: bool,
176
177    #[schemars(title = "Показывать ли стейджи")]
178    pub show_stages: Option<bool>,
179}
180
181#[derive(
182    Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Tsify, JsonSchema, CustomType,
183)]
184pub struct ActiveDungeon {
185    pub id: DungeonTemplateId,
186    pub difficulty: i64,
187}
188
189#[derive(
190    Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Tsify, JsonSchema, CustomType,
191)]
192pub struct ActivePetAbility {
193    pub pet_template_id: PetId,
194    pub ability_id: AbilityId,
195    pub charge: i64,
196    pub max_charge: i64,
197}
198
199#[derive(
200    Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, Tsify, JsonSchema, CustomType,
201)]
202pub struct ActiveFight {
203    pub id: uuid::Uuid,
204    pub fight_id: FightTemplateId,
205    pub current_wave: i64,
206    pub player_id: EntityId,
207    pub party_player_id: Option<EntityId>,
208    pub entities: Vec<Entity>,
209    pub fight_stopped: bool,
210    pub fight_ended: bool,
211    pub max_duration_ticks: u64,
212    pub dungeon: Option<ActiveDungeon>,
213    pub paused: bool,
214    pub pet_combat_state: Option<ActivePetAbility>,
215    pub leader_pet_template_id: Option<PetId>,
216}
217
218impl ActiveFight {
219    pub fn get_player(&self) -> Option<&Entity> {
220        self.entities
221            .iter()
222            .find(|entity| entity.id == self.player_id)
223    }
224
225    pub fn get_player_mut(&mut self) -> Option<&mut Entity> {
226        self.entities
227            .iter_mut()
228            .find(|entity| entity.id == self.player_id)
229    }
230
231    pub fn get_party_player(&self) -> Option<&Entity> {
232        let party_id = self.party_player_id?;
233        self.entities.iter().find(|entity| entity.id == party_id)
234    }
235
236    pub fn get_party_player_mut(&mut self) -> Option<&mut Entity> {
237        let party_id = self.party_player_id?;
238        self.entities
239            .iter_mut()
240            .find(|entity| entity.id == party_id)
241    }
242
243    pub fn get_enemies_amount(&self) -> usize {
244        self.entities
245            .iter()
246            .filter(|entity| entity.team == EntityTeam::Enemy)
247            .count()
248    }
249}