1use crate::{
2 async_handler::handler::OverlordAsyncEventHandler, event::OverlordEvent,
3 game_config_helpers::GameConfigLookup, state::OverlordState,
4};
5
6use chrono::Utc;
7
8use essences::{
9 currency::CurrencySource,
10 vassals::{Suzerain, VassalTask, VassalTaskStatus},
11};
12
13use event_system::system::EventHandleResult;
14use uuid::Uuid;
15
16impl OverlordAsyncEventHandler {
17 pub fn handle_new_task(
18 &self,
19 new_task: VassalTask,
20 mut state: OverlordState,
21 ) -> EventHandleResult<OverlordEvent, OverlordState> {
22 if state.character_state.vassal_tasks.contains(&new_task) {
23 tracing::error!("Tried pushing new task {new_task:?}, but its already in state");
24 return EventHandleResult::fail(state);
25 };
26
27 state.character_state.vassal_tasks.push(new_task);
28
29 EventHandleResult::ok(state)
30 }
31
32 pub fn handle_give_resist_task(
33 &self,
34 new_task: VassalTask,
35 mut state: OverlordState,
36 ) -> EventHandleResult<OverlordEvent, OverlordState> {
37 let game_config = self.game_config.get();
38
39 if new_task.template_task_id != game_config.game_settings.resist_task_id {
40 tracing::error!(
41 "Tried giving resist task, but it's id is {}, while in config it's {}",
42 new_task.template_task_id,
43 game_config.game_settings.resist_task_id,
44 );
45 return EventHandleResult::fail(state);
46 }
47 if state.character_state.vassal_tasks.iter().any(|task| {
48 task.template_task_id == game_config.game_settings.resist_task_id
49 && !matches!(
50 task.task_status,
51 VassalTaskStatus::FinishedGood | VassalTaskStatus::FinishedBad
52 )
53 }) {
54 tracing::error!(
55 "Tried giving new resist task {new_task:?} to vassal, but its already in state"
56 );
57 return EventHandleResult::fail(state);
58 };
59 state.character_state.vassal_tasks.push(new_task);
60 EventHandleResult::ok(state)
61 }
62
63 pub fn handle_accept_task(
64 &self,
65 task_id: Uuid,
66 is_good: bool,
67 mut state: OverlordState,
68 ) -> EventHandleResult<OverlordEvent, OverlordState> {
69 let game_config = self.game_config.get();
70
71 let Some(task) = state
72 .character_state
73 .vassal_tasks
74 .iter_mut()
75 .find(|task| task.id == task_id)
76 else {
77 tracing::error!(
78 "Tried accepting task with id = {}, but didn't find it in state",
79 task_id
80 );
81 return EventHandleResult::fail(state);
82 };
83
84 let Ok(task_template) = game_config.require_vassal_task_template(task.template_task_id)
85 else {
86 tracing::error!(
87 "Tried finding task with template_id = {}, but didn't find it in config",
88 task.template_task_id
89 );
90 return EventHandleResult::fail(state);
91 };
92
93 if task.task_status != VassalTaskStatus::NotStarted {
94 tracing::error!(
95 "Tried accepting task with id = {}, but its not in NotStarted state",
96 task_id
97 );
98 return EventHandleResult::fail(state);
99 }
100
101 let started_time = ::time::utc_now();
102
103 if is_good {
104 task.task_status = VassalTaskStatus::StartedGood;
105 } else {
106 task.task_status = VassalTaskStatus::StartedBad;
107 }
108
109 task.started_at = Some(started_time);
110 task.finish_at = Some(started_time + time::Duration::from_secs(task_template.duration_sec));
111
112 EventHandleResult::ok(state)
113 }
114
115 pub fn handle_task_accepted(
116 &self,
117 task_id: Uuid,
118 started_good: bool,
119 started_at: chrono::DateTime<Utc>,
120 finish_at: chrono::DateTime<Utc>,
121 mut state: OverlordState,
122 ) -> EventHandleResult<OverlordEvent, OverlordState> {
123 let Some(task) = state
124 .character_state
125 .vassal_tasks
126 .iter_mut()
127 .find(|task| task.id == task_id)
128 else {
129 tracing::error!(
130 "Tried accepting task with id = {}, but didn't find it in state",
131 task_id
132 );
133 return EventHandleResult::fail(state);
134 };
135
136 if started_good {
137 task.task_status = VassalTaskStatus::StartedGood
138 } else {
139 task.task_status = VassalTaskStatus::StartedBad
140 };
141
142 task.started_at = Some(started_at);
143 task.finish_at = Some(finish_at);
144
145 EventHandleResult::ok(state)
146 }
147
148 pub fn handle_resist_task_accepted(
149 &self,
150 resist_task: VassalTask,
151 mut state: OverlordState,
152 ) -> EventHandleResult<OverlordEvent, OverlordState> {
153 if let Some(existing) = state
154 .character_state
155 .vassal_tasks
156 .iter_mut()
157 .find(|t| t.id == resist_task.id)
158 {
159 *existing = resist_task;
160 } else {
161 state.character_state.vassal_tasks.push(resist_task);
162 }
163 EventHandleResult::ok(state)
164 }
165
166 pub fn handle_hit_hands(
167 &self,
168 task_id: Uuid,
169 mut state: OverlordState,
170 ) -> EventHandleResult<OverlordEvent, OverlordState> {
171 let Some(task) = state
172 .character_state
173 .vassal_tasks
174 .iter_mut()
175 .find(|task| task.id == task_id)
176 else {
177 tracing::error!(
178 "Tried hitting hands on task with id = {}, but didn't find it in state",
179 task_id
180 );
181 return EventHandleResult::fail(state);
182 };
183
184 if task.task_status != VassalTaskStatus::StartedBad {
185 tracing::error!(
186 "Tried hitting hands on task with id = {}, but its not in StartedBad state",
187 task_id
188 );
189 return EventHandleResult::fail(state);
190 };
191
192 if task.finish_at.unwrap() < ::time::utc_now() {
193 tracing::error!(
194 "Tried hitting hands on task with id = {}, but its finished by time",
195 task_id
196 );
197 return EventHandleResult::fail(state);
198 };
199
200 task.task_status = VassalTaskStatus::ChangedBadToGood;
201
202 EventHandleResult::ok(state)
203 }
204
205 pub fn handle_catch_resist_task(
206 &self,
207 task_id: Uuid,
208 mut state: OverlordState,
209 ) -> EventHandleResult<OverlordEvent, OverlordState> {
210 let Some(task) = state
211 .character_state
212 .vassal_tasks
213 .iter_mut()
214 .find(|task| task.id == task_id)
215 else {
216 tracing::error!(
217 "Tried catching resist task with id = {}, but didn't find it in state",
218 task_id
219 );
220 return EventHandleResult::fail(state);
221 };
222
223 if task.task_status != VassalTaskStatus::StartedBad {
224 tracing::error!(
225 "Tried catching resist task with id = {}, but its not in StartedBad state",
226 task_id
227 );
228 return EventHandleResult::fail(state);
229 };
230
231 if task.finish_at.unwrap() < ::time::utc_now() {
232 tracing::error!(
233 "Tried catching task with id = {}, but its finished by time {}",
234 task_id,
235 ::time::utc_now(),
236 );
237 return EventHandleResult::fail(state);
238 };
239
240 task.task_status = VassalTaskStatus::FinishedGood;
241
242 EventHandleResult::ok(state)
243 }
244
245 pub fn handle_hands_hitted(
246 &self,
247 task_id: Uuid,
248 mut state: OverlordState,
249 ) -> EventHandleResult<OverlordEvent, OverlordState> {
250 let Some(task) = state
251 .character_state
252 .vassal_tasks
253 .iter_mut()
254 .find(|task| task.id == task_id)
255 else {
256 tracing::error!(
257 "Tried hitting hands on task with id = {}, but didn't find it in state",
258 task_id
259 );
260 return EventHandleResult::fail(state);
261 };
262
263 if task.task_status != VassalTaskStatus::StartedBad {
264 tracing::error!(
265 "Tried hitting hands on task with id = {}, but its not in StartedBad state",
266 task_id
267 );
268 return EventHandleResult::fail(state);
269 }
270 task.task_status = VassalTaskStatus::ChangedBadToGood;
271
272 EventHandleResult::ok(state)
273 }
274
275 pub fn handle_resist_task_catched(
276 &self,
277 task_id: Uuid,
278 mut state: OverlordState,
279 ) -> EventHandleResult<OverlordEvent, OverlordState> {
280 let Some(task) = state
281 .character_state
282 .vassal_tasks
283 .iter_mut()
284 .find(|task| task.id == task_id)
285 else {
286 tracing::error!(
287 "Tried catching resist task with id = {}, but didn't find it in state",
288 task_id
289 );
290 return EventHandleResult::fail(state);
291 };
292
293 if task.task_status != VassalTaskStatus::StartedBad {
294 tracing::error!(
295 "Tried catching resist task with id = {}, but its not in StartedBad state",
296 task_id
297 );
298 return EventHandleResult::fail(state);
299 }
300
301 task.task_status = VassalTaskStatus::FinishedGood;
302
303 EventHandleResult::ok(state)
304 }
305
306 pub fn handle_finish_task(
307 &self,
308 task_id: Uuid,
309 mut state: OverlordState,
310 ) -> EventHandleResult<OverlordEvent, OverlordState> {
311 let Some(vassal_task) = state
312 .character_state
313 .vassal_tasks
314 .iter_mut()
315 .find(|task| task.id == task_id)
316 else {
317 tracing::error!(
318 "Tried finish task with id = {}, but didn't find it in state",
319 task_id
320 );
321 return EventHandleResult::fail(state);
322 };
323
324 if !matches!(
325 vassal_task.task_status,
326 VassalTaskStatus::StartedBad
327 | VassalTaskStatus::StartedGood
328 | VassalTaskStatus::ChangedBadToGood
329 ) {
330 tracing::error!(
331 "Task with id = {} is not being done, state: {}",
332 task_id,
333 vassal_task.task_status
334 );
335 return EventHandleResult::fail(state);
336 };
337
338 let finish_time = match vassal_task.finish_at {
339 Some(finish_time) => finish_time,
340 None => {
341 tracing::error!("Task with id = {} has no finish_time", task_id);
342 return EventHandleResult::fail(state);
343 }
344 };
345
346 if finish_time > ::time::utc_now() {
347 tracing::error!(
348 "Tried finishing task with id = {}, but its not finished {}, {}",
349 task_id,
350 finish_time,
351 ::time::utc_now(),
352 );
353 return EventHandleResult::fail(state);
354 };
355
356 if vassal_task.suzerain_id == state.character_state.character.id {
357 let Some(vassal) = state
358 .character_state
359 .vassals
360 .iter_mut()
361 .find(|vassal| vassal.character_id == vassal_task.vassal_id)
362 else {
363 tracing::error!(
364 "Tried finishing task with id = {}, in which character is the suzerain, but didn't find vassal in state with id: {}",
365 task_id,
366 vassal_task.vassal_id
367 );
368 return EventHandleResult::fail(state);
369 };
370
371 if matches!(
372 vassal_task.task_status,
373 VassalTaskStatus::StartedGood | VassalTaskStatus::ChangedBadToGood
374 ) {
375 vassal.loyalty += vassal_task.good_loyalty;
376 } else if vassal_task.task_status == VassalTaskStatus::StartedBad {
377 vassal.loyalty += vassal_task.bad_loyalty;
378 } else {
379 tracing::error!(
380 "Tried finishing task with id = {}, but its in weird state {}",
381 task_id,
382 vassal_task.task_status,
383 );
384 return EventHandleResult::fail(state);
385 }
386 } else if vassal_task.vassal_id == state.character_state.character.id {
387 let Some(suzerain) = state.character_state.suzerain.as_mut() else {
388 tracing::error!(
389 "Tried finishing task with id = {}, in which character is the vassal, but didn't find suzerain in state",
390 task_id
391 );
392 return EventHandleResult::fail(state);
393 };
394 if matches!(
395 vassal_task.task_status,
396 VassalTaskStatus::StartedGood | VassalTaskStatus::ChangedBadToGood
397 ) {
398 suzerain.loyalty += vassal_task.good_loyalty;
399 } else if vassal_task.task_status == VassalTaskStatus::StartedBad {
400 suzerain.loyalty += vassal_task.bad_loyalty;
401 } else {
402 tracing::error!(
403 "Tried finishing task with id = {}, but its in weird state {}",
404 task_id,
405 vassal_task.task_status,
406 );
407 return EventHandleResult::fail(state);
408 }
409 } else {
410 tracing::error!(
411 "Tried finishing task with id = {}, but you are not Vassal or Suzerain",
412 task_id
413 );
414 return EventHandleResult::fail(state);
415 }
416
417 vassal_task.task_status = if matches!(
418 vassal_task.task_status,
419 VassalTaskStatus::StartedGood | VassalTaskStatus::ChangedBadToGood
420 ) {
421 VassalTaskStatus::FinishedGood
422 } else {
423 VassalTaskStatus::FinishedBad
424 };
425
426 EventHandleResult::ok(state)
427 }
428
429 pub fn handle_resist_task_finished(
430 &self,
431 task_id: Uuid,
432 mut state: OverlordState,
433 ) -> EventHandleResult<OverlordEvent, OverlordState> {
434 let Some(resist_task) = state
435 .character_state
436 .vassal_tasks
437 .iter_mut()
438 .find(|task| task.id == task_id)
439 else {
440 tracing::error!(
441 "Tried finish resist task with id = {}, but didn't find it in state",
442 task_id
443 );
444 return EventHandleResult::fail(state);
445 };
446
447 if resist_task.task_status != VassalTaskStatus::StartedBad {
448 tracing::error!(
449 "Resist task with id = {} is not being done, state: {}",
450 task_id,
451 resist_task.task_status
452 );
453 return EventHandleResult::fail(state);
454 };
455
456 let finish_time = match resist_task.finish_at {
457 Some(finish_time) => finish_time,
458 None => {
459 tracing::error!("Resist task with id = {} has no finish_time", task_id);
460 return EventHandleResult::fail(state);
461 }
462 };
463
464 if finish_time > ::time::utc_now() {
465 tracing::error!(
466 "Tried finishing resist task with id = {}, but its not finished",
467 task_id
468 );
469 return EventHandleResult::fail(state);
470 };
471
472 if resist_task.suzerain_id == state.character_state.character.id {
473 let Some(vassal) = state
474 .character_state
475 .vassals
476 .iter_mut()
477 .find(|vassal| vassal.character_id == resist_task.vassal_id)
478 else {
479 tracing::error!(
480 "Tried finishing resist task with id = {}, in which character is the suzerain, but didn't find vassal in state with id: {}",
481 task_id,
482 resist_task.vassal_id
483 );
484 return EventHandleResult::fail(state);
485 };
486 if matches!(
487 resist_task.task_status,
488 VassalTaskStatus::StartedGood | VassalTaskStatus::ChangedBadToGood
489 ) {
490 vassal.loyalty += resist_task.good_loyalty;
491 } else if resist_task.task_status == VassalTaskStatus::StartedBad {
492 vassal.loyalty += resist_task.bad_loyalty;
493 } else {
494 tracing::error!(
495 "Tried finishing resist task with id = {}, but its in weird state {}",
496 task_id,
497 resist_task.task_status,
498 );
499 return EventHandleResult::fail(state);
500 }
501 } else if resist_task.vassal_id == state.character_state.character.id {
502 let Some(suzerain) = state.character_state.suzerain.as_mut() else {
503 tracing::error!(
504 "Tried finishing resist task with id = {}, in which character is the vassal, but didn't find suzerain in state",
505 task_id
506 );
507 return EventHandleResult::fail(state);
508 };
509 if matches!(
510 resist_task.task_status,
511 VassalTaskStatus::StartedGood | VassalTaskStatus::ChangedBadToGood
512 ) {
513 suzerain.loyalty += resist_task.good_loyalty;
514 } else if resist_task.task_status == VassalTaskStatus::StartedBad {
515 suzerain.loyalty += resist_task.bad_loyalty;
516 } else {
517 tracing::error!(
518 "Tried finishing resist task with id = {}, but its in weird state {}",
519 task_id,
520 resist_task.task_status,
521 );
522 return EventHandleResult::fail(state);
523 }
524 } else {
525 tracing::error!(
526 "Tried finishing resist task with id = {}, but you are not Vassal or Suzerain",
527 task_id
528 );
529 return EventHandleResult::fail(state);
530 }
531
532 resist_task.task_status = if matches!(
533 resist_task.task_status,
534 VassalTaskStatus::StartedGood | VassalTaskStatus::ChangedBadToGood
535 ) {
536 VassalTaskStatus::FinishedGood
537 } else {
538 VassalTaskStatus::FinishedBad
539 };
540
541 EventHandleResult::ok(state)
542 }
543
544 pub fn handle_claim_task_reward(
545 &self,
546 task_id: Uuid,
547 mut state: OverlordState,
548 ) -> EventHandleResult<OverlordEvent, OverlordState> {
549 let mut vassal_tasks = state.character_state.vassal_tasks.clone();
550
551 let Some(vassal_task) = vassal_tasks.iter_mut().find(|task| task.id == task_id) else {
552 tracing::error!(
553 "Tried claiming reward on task with id = {}, but didn't find it in state",
554 task_id
555 );
556 return EventHandleResult::fail(state);
557 };
558
559 if !matches!(
560 vassal_task.task_status,
561 VassalTaskStatus::FinishedGood | VassalTaskStatus::FinishedBad
562 ) {
563 tracing::error!(
564 "Tried claiming reward on task with id = {}, but its not finished",
565 task_id
566 );
567 return EventHandleResult::fail(state);
568 };
569
570 if let Some(pos) = state
571 .character_state
572 .vassal_tasks
573 .iter_mut()
574 .position(|x| x == vassal_task)
575 {
576 state.character_state.vassal_tasks.swap_remove(pos);
577 } else {
578 tracing::error!(
579 "Tried claiming reward on task with id = {}, but didn't find it in state",
580 task_id
581 );
582 return EventHandleResult::fail(state);
583 };
584
585 let mut events = vec![];
586
587 if vassal_task.task_status == VassalTaskStatus::FinishedGood {
588 events.push(Self::currency_increase(
589 &vassal_task.good_reward,
590 CurrencySource::VassalTaskCompletion,
591 ));
592 } else if vassal_task.task_status == VassalTaskStatus::FinishedBad {
593 events.push(Self::currency_increase(
594 &vassal_task.bad_reward,
595 CurrencySource::VassalTaskCompletion,
596 ));
597 } else {
598 tracing::error!(
599 "Tried finishing task with id = {}, but its in weird state {}",
600 task_id,
601 vassal_task.task_status,
602 );
603 return EventHandleResult::fail(state);
604 }
605
606 EventHandleResult::ok_events(state, events)
607 }
608
609 pub fn handle_claim_resist_task_reward(
610 &self,
611 task_id: Uuid,
612 mut state: OverlordState,
613 ) -> EventHandleResult<OverlordEvent, OverlordState> {
614 let mut vassal_tasks = state.character_state.vassal_tasks.clone();
615
616 let Some(resist_task) = vassal_tasks.iter_mut().find(|task| task.id == task_id) else {
617 tracing::error!(
618 "Tried claiming reward on resist task with id = {}, but didn't find it in state",
619 task_id
620 );
621 return EventHandleResult::fail(state);
622 };
623
624 if !matches!(
625 resist_task.task_status,
626 VassalTaskStatus::FinishedGood | VassalTaskStatus::FinishedBad
627 ) {
628 tracing::error!(
629 "Tried claiming reward on resist task with id = {}, but its not finished",
630 task_id
631 );
632 return EventHandleResult::fail(state);
633 };
634
635 if let Some(pos) = state
636 .character_state
637 .vassal_tasks
638 .iter_mut()
639 .position(|x| x == resist_task)
640 {
641 state.character_state.vassal_tasks.remove(pos);
642 } else {
643 tracing::error!(
644 "Tried claiming reward on resist task with id = {}, but didn't find it in state",
645 task_id
646 );
647 return EventHandleResult::fail(state);
648 };
649
650 let mut events = vec![];
651
652 if resist_task.task_status == VassalTaskStatus::FinishedGood {
653 events.push(Self::currency_increase(
654 &resist_task.good_reward,
655 CurrencySource::VassalTaskCompletion,
656 ));
657 } else if resist_task.task_status == VassalTaskStatus::FinishedBad {
658 events.push(Self::currency_increase(
659 &resist_task.bad_reward,
660 CurrencySource::VassalTaskCompletion,
661 ));
662 } else {
663 tracing::error!(
664 "Tried claiming resist task reward with id = {}, but its in weird state {}",
665 task_id,
666 resist_task.task_status,
667 );
668 return EventHandleResult::fail(state);
669 }
670
671 EventHandleResult::ok_events(state, events)
672 }
673
674 pub fn handle_new_suzerain(
675 &self,
676 new_suzerain: Option<Suzerain>,
677 mut state: OverlordState,
678 ) -> EventHandleResult<OverlordEvent, OverlordState> {
679 state.character_state.suzerain = new_suzerain;
680
681 state
682 .character_state
683 .vassal_tasks
684 .retain(|task| task.vassal_id != state.character_state.character.id);
685
686 EventHandleResult::ok(state)
687 }
688
689 pub fn handle_remove_vassal(
690 &self,
691 vassal_id: Uuid,
692 mut state: OverlordState,
693 ) -> EventHandleResult<OverlordEvent, OverlordState> {
694 let Some(vassal_position) = state
695 .character_state
696 .vassals
697 .iter()
698 .position(|vassal| vassal.character_id == vassal_id)
699 else {
700 tracing::error!(
701 "Tried removing vassal with id = {}, but didnt find it in state",
702 vassal_id
703 );
704 return EventHandleResult::fail(state);
705 };
706
707 state.character_state.vassals.remove(vassal_position);
708
709 EventHandleResult::ok(state)
710 }
711}