1#![allow(clippy::needless_return)]
4#![allow(clippy::implicit_return)]
5#![allow(clippy::uninlined_format_args)]
6#![allow(clippy::items_after_statements)]
7#![allow(clippy::unnecessary_cast)]
8#![allow(clippy::doc_markdown)]
9#![allow(clippy::cast_sign_loss)]
10#![allow(clippy::explicit_iter_loop)]
11#![allow(clippy::format_in_format_args)]
12#![allow(clippy::cast_precision_loss)]
13#![allow(clippy::wildcard_imports)]
14#![allow(clippy::too_many_lines)]
15#![allow(clippy::std_instead_of_core)]
16#![allow(clippy::similar_names)]
17#![allow(clippy::duplicated_attributes)]
18#![allow(clippy::cast_possible_truncation)]
19#![allow(clippy::trivially_copy_pass_by_ref)]
20#![allow(clippy::missing_inline_in_public_items)]
21#![allow(clippy::useless_vec)]
22#![allow(clippy::unnested_or_patterns)]
23#![allow(clippy::else_if_without_else)]
24#![allow(clippy::unreadable_literal)]
25#![allow(clippy::redundant_else)]
26#![allow(clippy::min_ident_chars)]
27#![allow(clippy::if_not_else)]
28use tiles_tools::game_systems::*;
38use tiles_tools::events::{EventBus, EventResult};
39use tiles_tools::debug::{GridRenderer, GridStyle, DebugColor};
40use std::collections::HashMap;
41
42fn main() {
43 println!("š® Game Systems Demonstration");
44 println!("==============================");
45
46 println!("\nāļø Turn-Based Combat System");
48 println!("---------------------------");
49
50 demonstrate_turn_based_combat();
51
52 println!("\nšÆ Game State Management");
54 println!("------------------------");
55
56 demonstrate_game_state_machine();
57
58 println!("\nš Resource Management");
60 println!("----------------------");
61
62 demonstrate_resource_management();
63
64 println!("\nš Quest System");
66 println!("---------------");
67
68 demonstrate_quest_system();
69
70 println!("\nš Integrated Tactical RPG Session");
72 println!("----------------------------------");
73
74 demonstrate_integrated_gameplay();
75
76 println!("\n⨠Game Systems Demo Complete!");
77 println!("\nKey features demonstrated:");
78 println!("⢠Turn-based combat with initiative and action points");
79 println!("⢠Game state machine with transition management");
80 println!("⢠Resource management with regeneration and limits");
81 println!("⢠Quest system with objectives and branching logic");
82 println!("⢠Status effects with duration and stacking");
83 println!("⢠Integrated gameplay with multiple systems");
84 println!("⢠Event-driven architecture for system coordination");
85}
86
87fn demonstrate_turn_based_combat() {
88 let mut game = TurnBasedGame::new();
89
90 println!("Setting up combat participants...");
91
92 game.add_participant(1, 95); game.add_participant(2, 80); game.add_participant(3, 110); game.add_participant(4, 65); println!("Turn Order (by initiative):");
99 let participants = game.participants_in_order();
100 for (i, participant) in participants.iter().enumerate() {
101 let entity_type = match participant.entity_id {
102 1 => "Player",
103 2 => "Enemy Knight",
104 3 => "Enemy Archer",
105 4 => "Player Ally",
106 _ => "Unknown"
107 };
108 println!(" {}. {} (ID: {}, Initiative: {})",
109 i + 1, entity_type, participant.entity_id, participant.initiative);
110 }
111
112 println!("\nSimulating 2 rounds of combat:");
113
114 for round in 1..=2 {
115 println!("\n--- Round {} ---", round);
116
117 let mut turns_in_round = 0;
118 let start_round = game.round_number();
119
120 while game.round_number() == start_round && turns_in_round < 10 {
121 if let Some(current_entity) = game.current_turn() {
122 let entity_name = match current_entity {
123 1 => "Player",
124 2 => "Enemy Knight",
125 3 => "Enemy Archer",
126 4 => "Player Ally",
127 _ => "Unknown"
128 };
129
130 if let Some(participant) = game.current_participant() {
131 println!(" {}'s turn (AP: {})", entity_name, participant.action_points);
132
133 match current_entity {
135 1 => { println!(" Player attacks with sword (2 AP)");
137 game.spend_action_points(2);
138 if game.current_participant().unwrap().action_points > 0 {
139 println!(" Player moves closer (1 AP)");
140 game.spend_action_points(1);
141 }
142 },
143 2 => { println!(" Knight charges (3 AP)");
145 game.spend_action_points(3);
146 },
147 3 => { println!(" Archer shoots arrow (1 AP)");
149 game.spend_action_points(1);
150 println!(" Archer repositions (1 AP)");
151 game.spend_action_points(1);
152 println!(" Archer shoots again (1 AP)");
153 game.spend_action_points(1);
154 },
155 4 => { println!(" Ally casts healing spell (2 AP)");
157 game.spend_action_points(2);
158 println!(" Ally moves to better position (1 AP)");
159 game.spend_action_points(1);
160 },
161 _ => {}
162 }
163 }
164
165 game.end_turn();
166 turns_in_round += 1;
167 }
168 }
169 }
170
171 println!("\nCombat round completed! Final round: {}", game.round_number());
172
173 println!("\nApplying status effects...");
175
176 let poison = StatusEffect {
177 id: "poison".to_string(),
178 name: "Poison".to_string(),
179 description: "Takes 5 damage per turn".to_string(),
180 duration: 3,
181 magnitude: 5.0,
182 is_beneficial: false,
183 category: EffectCategory::DamageOverTime,
184 };
185
186 let blessing = StatusEffect {
187 id: "blessing".to_string(),
188 name: "Divine Blessing".to_string(),
189 description: "+2 attack power".to_string(),
190 duration: 5,
191 magnitude: 2.0,
192 is_beneficial: true,
193 category: EffectCategory::AttackPower,
194 };
195
196 game.apply_status_effect(1, blessing);
197 game.apply_status_effect(2, poison);
198
199 println!("Player has Divine Blessing (+2 attack, 5 turns)");
200 println!("Enemy Knight is poisoned (5 damage/turn, 3 turns)");
201
202 if let Some(player) = game.participants_in_order().iter().find(|p| p.entity_id == 1) {
204 println!("\nPlayer status effects: {}", player.status_effects.len());
205 for effect in &player.status_effects {
206 println!(" ⢠{} ({}): {} turns remaining",
207 effect.name, if effect.is_beneficial { "Buff" } else { "Debuff" }, effect.duration);
208 }
209 }
210}
211
212fn demonstrate_game_state_machine() {
213 let mut state_machine = GameStateMachine::new(GameState::Initialize);
214
215 println!("Starting game state machine...");
216 println!("Current state: {:?}", state_machine.current_state());
217
218 let state_transitions = [
220 (GameStateEvent::InitComplete, "Game initialized"),
221 (GameStateEvent::StartGame, "Starting new game"),
222 (GameStateEvent::StartGame, "Loading complete, entering gameplay"),
223 (GameStateEvent::EnterCombat, "Combat encounter!"),
224 (GameStateEvent::ExitCombat, "Combat resolved"),
225 (GameStateEvent::Pause, "Game paused"),
226 (GameStateEvent::Resume, "Game resumed"),
227 (GameStateEvent::OpenInventory, "Checking inventory"),
228 (GameStateEvent::CloseInventory, "Inventory closed"),
229 ];
230
231 for (event, description) in state_transitions {
232 if state_machine.process_event(event) {
233 println!(" {} ā {:?} ({})",
234 format!("{:?}", event),
235 state_machine.current_state(),
236 description);
237 } else {
238 println!(" {} ā Failed (invalid transition from {:?})",
239 format!("{:?}", event),
240 state_machine.current_state());
241 }
242 }
243
244 state_machine.set_state_data("player_name".to_string(), "Hero".to_string());
246 state_machine.set_state_data("level".to_string(), "forest_1".to_string());
247
248 println!("\nState data:");
249 if let Some(name) = state_machine.get_state_data("player_name") {
250 println!(" Player name: {}", name);
251 }
252 if let Some(level) = state_machine.get_state_data("level") {
253 println!(" Current level: {}", level);
254 }
255
256 println!("Final state: {:?}", state_machine.current_state());
257}
258
259fn demonstrate_resource_management() {
260 let mut resource_manager = ResourceManager::new();
261
262 println!("Setting up entities with resources...");
263
264 resource_manager.add_entity(1, 100.0, 50.0); resource_manager.add_entity(2, 80.0, 0.0); resource_manager.add_entity(3, 60.0, 100.0); resource_manager.add_entity(4, 150.0, 25.0); if let Some(resources) = resource_manager.get_resources_mut(1) {
272 resources.health.regeneration = 2.0; resources.mana.regeneration = 5.0; }
275
276 if let Some(resources) = resource_manager.get_resources_mut(3) {
277 resources.mana.regeneration = 3.0; }
279
280 println!("\nInitial resources:");
281 for entity_id in [1, 2, 3, 4] {
282 if let Some(resources) = resource_manager.get_resources(entity_id) {
283 let entity_type = match entity_id {
284 1 => "Player",
285 2 => "Warrior",
286 3 => "Mage",
287 4 => "Boss",
288 _ => "Unknown"
289 };
290 println!(" {}: {:.0}/{:.0} HP, {:.0}/{:.0} MP",
291 entity_type,
292 resources.health.current, resources.health.maximum,
293 resources.mana.current, resources.mana.maximum);
294 }
295 }
296
297 println!("\nSimulating combat damage...");
298
299 resource_manager.modify_health(1, -25.0);
301 resource_manager.modify_mana(1, -15.0);
302 println!(" Player takes 25 damage, uses 15 mana");
303
304 resource_manager.modify_health(2, -60.0);
306 println!(" Warrior takes 60 damage");
307
308 resource_manager.modify_mana(3, -80.0);
310 println!(" Mage uses 80 mana for powerful spell");
311
312 resource_manager.modify_health(4, -45.0);
314 println!(" Boss takes 45 damage from combined attacks");
315
316 println!("\nAfter combat:");
317 for entity_id in [1, 2, 3, 4] {
318 if let Some(resources) = resource_manager.get_resources(entity_id) {
319 let entity_type = match entity_id {
320 1 => "Player",
321 2 => "Warrior",
322 3 => "Mage",
323 4 => "Boss",
324 _ => "Unknown"
325 };
326 println!(" {}: {:.0}/{:.0} HP ({:.0}%), {:.0}/{:.0} MP ({:.0}%)",
327 entity_type,
328 resources.health.current, resources.health.maximum,
329 resources.health.percentage() * 100.0,
330 resources.mana.current, resources.mana.maximum,
331 resources.mana.percentage() * 100.0);
332 }
333 }
334
335 println!("\nSimulating 3 seconds of regeneration...");
336 resource_manager.update_all(3.0);
337
338 println!("After regeneration:");
339 for entity_id in [1, 3] { if let Some(resources) = resource_manager.get_resources(entity_id) {
341 let entity_type = if entity_id == 1 { "Player" } else { "Mage" };
342 println!(" {}: {:.0}/{:.0} HP, {:.0}/{:.0} MP",
343 entity_type,
344 resources.health.current, resources.health.maximum,
345 resources.mana.current, resources.mana.maximum);
346 }
347 }
348
349 let defeated = resource_manager.get_defeated_entities();
351 if !defeated.is_empty() {
352 println!("\nDefeated entities: {:?}", defeated);
353 } else {
354 println!("\nNo entities defeated");
355 }
356}
357
358fn demonstrate_quest_system() {
359 let mut quest_manager = QuestManager::new();
360
361 println!("Setting up quest system...");
362
363 let main_quest = Quest {
365 id: "save_village".to_string(),
366 name: "Save the Village".to_string(),
367 description: "The village is under attack by orcs. Eliminate the threat!".to_string(),
368 status: QuestStatus::Available,
369 objectives: vec![
370 QuestObjective {
371 id: "kill_orcs".to_string(),
372 description: "Eliminate 5 orc raiders".to_string(),
373 completed: false,
374 objective_type: ObjectiveType::KillTargets {
375 target_type: "orc".to_string(),
376 count: 5,
377 current: 0,
378 },
379 optional: false,
380 },
381 QuestObjective {
382 id: "find_chief".to_string(),
383 description: "Find and defeat the orc chieftain".to_string(),
384 completed: false,
385 objective_type: ObjectiveType::KillTargets {
386 target_type: "orc_chief".to_string(),
387 count: 1,
388 current: 0,
389 },
390 optional: false,
391 },
392 QuestObjective {
393 id: "rescue_villagers".to_string(),
394 description: "Rescue captured villagers (Optional)".to_string(),
395 completed: false,
396 objective_type: ObjectiveType::Custom {
397 data: vec![("rescued".to_string(), "0".to_string())].into_iter().collect(),
398 },
399 optional: true,
400 },
401 ],
402 prerequisites: vec![],
403 rewards: vec![
404 QuestReward::Experience(500),
405 QuestReward::Currency(100),
406 QuestReward::Items("healing_potion".to_string(), 3),
407 ],
408 data: HashMap::new(),
409 };
410
411 let side_quest = Quest {
413 id: "gather_herbs".to_string(),
414 name: "Herb Gathering".to_string(),
415 description: "Collect medicinal herbs for the village healer".to_string(),
416 status: QuestStatus::Available,
417 objectives: vec![
418 QuestObjective {
419 id: "collect_herbs".to_string(),
420 description: "Collect 10 healing herbs".to_string(),
421 completed: false,
422 objective_type: ObjectiveType::CollectItems {
423 item_id: "healing_herb".to_string(),
424 count: 10,
425 current: 0,
426 },
427 optional: false,
428 },
429 ],
430 prerequisites: vec![],
431 rewards: vec![
432 QuestReward::Experience(100),
433 QuestReward::Currency(25),
434 ],
435 data: HashMap::new(),
436 };
437
438 quest_manager.add_quest(main_quest);
439 quest_manager.add_quest(side_quest);
440
441 println!("\nStarting quests...");
443 quest_manager.start_quest("save_village", 1);
444 quest_manager.start_quest("gather_herbs", 1);
445
446 println!("Active quests: {}", quest_manager.active_quests().len());
447 for quest in quest_manager.active_quests() {
448 println!(" ⢠{} - {}", quest.name, quest.description);
449 for objective in &quest.objectives {
450 let status = if objective.completed { "ā" } else { "ā" };
451 let optional = if objective.optional { " (Optional)" } else { "" };
452 println!(" {} {}{}", status, objective.description, optional);
453 }
454 }
455
456 println!("\nSimulating quest progress...");
457
458 quest_manager.update_objective("gather_herbs", "collect_herbs", 4);
460 println!(" Collected 4 herbs...");
461
462 quest_manager.update_objective("gather_herbs", "collect_herbs", 6);
463 println!(" Collected 6 more herbs (10/10 complete)");
464
465 quest_manager.update_objective("save_village", "kill_orcs", 3);
467 println!(" Defeated 3 orcs...");
468
469 quest_manager.update_objective("save_village", "kill_orcs", 2);
470 println!(" Defeated 2 more orcs (5/5 complete)");
471
472 quest_manager.update_objective("save_village", "find_chief", 1);
474 println!(" Defeated orc chieftain!");
475
476 println!("\nQuest completion status:");
477 println!(" Completed quests: {}", quest_manager.completed_quest_count());
478 for quest in quest_manager.completed_quests() {
479 println!(" ā {} - Completed!", quest.name);
480 println!(" Rewards:");
481 for reward in &quest.rewards {
482 match reward {
483 QuestReward::Experience(exp) => println!(" ⢠{} Experience", exp),
484 QuestReward::Currency(gold) => println!(" ⢠{} Gold", gold),
485 QuestReward::Items(item, count) => println!(" ⢠{} x{}", item, count),
486 QuestReward::UnlockQuest(quest_id) => println!(" ⢠Unlock Quest: {}", quest_id),
487 QuestReward::SetFlag(flag) => println!(" ⢠Set Flag: {}", flag),
488 }
489 }
490 }
491
492 quest_manager.set_flag("village_saved".to_string(), true);
494 quest_manager.set_flag("hero_reputation".to_string(), true);
495
496 println!("\nGlobal flags set:");
497 println!(" village_saved: {}", quest_manager.get_flag("village_saved"));
498 println!(" hero_reputation: {}", quest_manager.get_flag("hero_reputation"));
499}
500
501fn demonstrate_integrated_gameplay() {
502 println!("Setting up integrated tactical RPG session...");
503
504 let mut turn_game = TurnBasedGame::new();
506 let mut resources = ResourceManager::new();
507 let mut state_machine = GameStateMachine::new(GameState::Playing);
508 let mut quest_manager = QuestManager::new();
509 let mut event_bus = EventBus::new();
510
511 event_bus.subscribe(|event: &TurnStartedEvent| {
513 println!("šÆ Turn started for entity {} (Round {})", event.entity_id, event.round_number);
514 EventResult::Continue
515 });
516
517 event_bus.subscribe(|event: &ResourceChangedEvent| {
518 if event.resource_type == "health" && event.new_value <= 0.0 {
519 println!("š Entity {} has fallen!", event.entity_id);
520 }
521 EventResult::Continue
522 });
523
524 println!("\nšŗļø Tactical Battle Setup");
526 println!("Party vs Orc Raiders");
527
528 turn_game.add_participant(1, 85); turn_game.add_participant(2, 95); turn_game.add_participant(3, 75); turn_game.add_participant(11, 80); turn_game.add_participant(12, 70); turn_game.add_participant(13, 90); resources.add_entity(1, 120.0, 30.0); resources.add_entity(2, 70.0, 100.0); resources.add_entity(3, 90.0, 80.0); resources.add_entity(11, 85.0, 10.0); resources.add_entity(12, 85.0, 10.0); resources.add_entity(13, 65.0, 60.0); let battle_quest = Quest {
549 id: "orc_encounter".to_string(),
550 name: "Orc Encounter".to_string(),
551 description: "Defeat the orc raiding party".to_string(),
552 status: QuestStatus::Active,
553 objectives: vec![
554 QuestObjective {
555 id: "defeat_orcs".to_string(),
556 description: "Defeat all orc raiders".to_string(),
557 completed: false,
558 objective_type: ObjectiveType::KillTargets {
559 target_type: "orc".to_string(),
560 count: 3,
561 current: 0,
562 },
563 optional: false,
564 },
565 ],
566 prerequisites: vec![],
567 rewards: vec![QuestReward::Experience(200)],
568 data: HashMap::new(),
569 };
570
571 quest_manager.add_quest(battle_quest);
572
573 let mut battle_grid = GridRenderer::new()
575 .with_size(12, 8)
576 .with_style(GridStyle::Square8);
577
578 battle_grid.add_colored_marker((2, 6), "F", "Fighter", DebugColor::Green, 10);
580 battle_grid.add_colored_marker((1, 5), "M", "Mage", DebugColor::Blue, 10);
581 battle_grid.add_colored_marker((3, 5), "C", "Cleric", DebugColor::Yellow, 10);
582
583 battle_grid.add_colored_marker((9, 4), "O1", "Orc Warrior", DebugColor::Red, 10);
585 battle_grid.add_colored_marker((10, 6), "O2", "Orc Warrior", DebugColor::Red, 10);
586 battle_grid.add_colored_marker((8, 2), "S", "Orc Shaman", DebugColor::Purple, 10);
587
588 battle_grid.add_colored_marker((5, 3), "T", "Tree", DebugColor::Green, 5);
590 battle_grid.add_colored_marker((6, 5), "R", "Rock", DebugColor::Gray, 5);
591
592 println!("\nBattlefield:");
593 println!("{}", battle_grid.render_ascii());
594
595 println!("Combat begins!");
596
597 let mut actions_this_round = 0;
599 let start_round = turn_game.round_number();
600
601 while turn_game.round_number() == start_round && actions_this_round < 6 {
602 if let Some(current_entity) = turn_game.current_turn() {
603 let entity_name = match current_entity {
604 1 => "Fighter",
605 2 => "Mage",
606 3 => "Cleric",
607 11 => "Orc Warrior 1",
608 12 => "Orc Warrior 2",
609 13 => "Orc Shaman",
610 _ => "Unknown"
611 };
612
613 event_bus.publish(TurnStartedEvent {
615 entity_id: current_entity,
616 round_number: turn_game.round_number(),
617 action_points: turn_game.current_participant().unwrap().action_points,
618 });
619
620 match current_entity {
622 1 => { println!(" {} attacks Orc Warrior 1 with sword!", entity_name);
624 resources.modify_health(11, -25.0);
625 turn_game.spend_action_points(2);
626
627 event_bus.publish(ResourceChangedEvent {
628 entity_id: 11,
629 resource_type: "health".to_string(),
630 old_value: 85.0,
631 new_value: resources.get_resources(11).unwrap().health.current,
632 });
633 },
634 2 => { println!(" {} casts fireball at Orc Shaman!", entity_name);
636 resources.modify_health(13, -35.0);
637 resources.modify_mana(2, -20.0);
638 turn_game.spend_action_points(3);
639 },
640 3 => { println!(" {} heals Fighter!", entity_name);
642 resources.modify_health(1, 15.0);
643 resources.modify_mana(3, -15.0);
644 turn_game.spend_action_points(2);
645 },
646 11 => { if resources.get_resources(11).unwrap().health.current > 0.0 {
648 println!(" {} attacks Fighter with axe!", entity_name);
649 resources.modify_health(1, -20.0);
650 turn_game.spend_action_points(2);
651 }
652 },
653 12 => { println!(" {} charges at Mage!", entity_name);
655 resources.modify_health(2, -18.0);
656 turn_game.spend_action_points(3);
657 },
658 13 => { if resources.get_resources(13).unwrap().health.current > 0.0 {
660 println!(" {} casts dark bolt at Cleric!", entity_name);
661 resources.modify_health(3, -15.0);
662 resources.modify_mana(13, -10.0);
663 turn_game.spend_action_points(2);
664 }
665 },
666 _ => {}
667 }
668
669 turn_game.end_turn();
670 actions_this_round += 1;
671 }
672
673 event_bus.process_events();
674 }
675
676 println!("\nš End of Round Status:");
677 for entity_id in [1, 2, 3, 11, 12, 13] {
678 if let Some(res) = resources.get_resources(entity_id) {
679 let name = match entity_id {
680 1 => "Fighter",
681 2 => "Mage",
682 3 => "Cleric",
683 11 => "Orc Warrior 1",
684 12 => "Orc Warrior 2",
685 13 => "Orc Shaman",
686 _ => "Unknown"
687 };
688
689 let status = if res.health.current <= 0.0 { " [DEFEATED]" } else { "" };
690 println!(" {}: {:.0}/{:.0} HP, {:.0}/{:.0} MP{}",
691 name, res.health.current, res.health.maximum,
692 res.mana.current, res.mana.maximum, status);
693 }
694 }
695
696 let mut orcs_defeated = 0;
698 for orc_id in [11, 12, 13] {
699 if let Some(res) = resources.get_resources(orc_id) {
700 if res.health.current <= 0.0 {
701 orcs_defeated += 1;
702 }
703 }
704 }
705
706 if orcs_defeated > 0 {
707 quest_manager.update_objective("orc_encounter", "defeat_orcs", orcs_defeated);
708 println!("\nš Quest Progress: {} orcs defeated", orcs_defeated);
709 }
710
711 let party_alive = [1, 2, 3].iter().any(|&id| {
713 resources.get_resources(id).unwrap().health.current > 0.0
714 });
715
716 let enemies_alive = [11, 12, 13].iter().any(|&id| {
717 resources.get_resources(id).unwrap().health.current > 0.0
718 });
719
720 if !enemies_alive && party_alive {
721 println!("\nš Victory! All orcs defeated!");
722 state_machine.process_event(GameStateEvent::VictoryAchieved);
723
724 if quest_manager.is_quest_completed("orc_encounter") {
725 event_bus.publish(QuestCompletedEvent {
726 quest_id: "orc_encounter".to_string(),
727 rewards: vec![QuestReward::Experience(200)],
728 });
729 }
730 } else if !party_alive {
731 println!("\nš Defeat! The party has fallen...");
732 state_machine.process_event(GameStateEvent::PlayerDefeated);
733 } else {
734 println!("\nāļø Battle continues! Both sides still fighting.");
735 }
736
737 println!("Final game state: {:?}", state_machine.current_state());
738
739 event_bus.process_events();
740
741 println!("\nšÆ Integration Summary:");
742 println!("This demonstrated how all systems work together:");
743 println!("⢠Turn-based combat managed participant order and actions");
744 println!("⢠Resource system tracked health/mana for all entities");
745 println!("⢠Quest system monitored combat objectives");
746 println!("⢠Event system coordinated between systems");
747 println!("⢠State machine tracked overall game flow");
748 println!("⢠Debug visualization showed tactical positions");
749}