void Battle::NextTurn() { std::queue<BattleEvent> events; std::sort(combatants.begin(), combatants.end(), [](Creature* a, Creature* b) { return a->GetAgility() > b->GetAgility(); }); for (auto com : combatants) { if (com->GetID() == "Player") { Dialogue targetSelection = Dialogue("Who?", {}); for (auto target : combatants) if (target->GetID() != "Player") targetSelection.AddChoice(target->GetName()); int choice = battleOptions.Activate(); switch (choice) { default: case 1: { int position = targetSelection.Activate(); for (int i = 0; i < position; i++) if (combatants[i]->GetID() == "Player") position++; Creature* target = combatants[position - 1]; events.push(BattleEvent(com, target, BattleEventType::ATTACK)); break; } case 2: { events.push(BattleEvent(com, nullptr, BattleEventType::DEFEND)); break; } } } else { Creature* player = *std::find_if(combatants.begin(), combatants.end(), [](Creature* a) { return a->GetID() == "Player"; }); events.push(BattleEvent(com, player, BattleEventType::ATTACK)); } } while (!events.empty()) { BattleEvent event = events.front(); switch (event.GetType()) { case BattleEventType::ATTACK: { auto a = combatants.begin(); auto b = combatants.end(); if (std::find(a, b, event.GetSource()) == b || std::find(a, b, event.GetTarget()) == b) break; std::cout << event.GetSource()->GetName() << " attacks " << event.GetTarget()->GetName() << " for " << event.Run() << " damage!" << std::endl; if (event.GetTarget()->GetHP() <= 0) Kill(event.GetTarget()); break; } case BattleEventType::DEFEND: std::cout << event.GetSource()->GetName() << " defends!\n"; break; default: break; } events.pop(); } }
void Battle::next_turn() { // Queue of battle events. Fastest combatants will be // at the start of the queue, and so will go first, // whereas slower ones will be at the back std::queue<BattleEvent> events; // Sort the combatants in agility order std::sort(combatants.begin(), combatants.end(), [](Creature* a, Creature* b) { return a->agility < b->agility; }); // Iterate over the combatants and decide what they should do, // before adding the action to the event queue. for(auto com : this->combatants) { if(com->id == "player") { // Create the target selection dialogue Dialogue targetSelection = Dialogue("Who?", {}); // Created every turn because some combatants may die for(auto target : this->combatants) { if(target->id != "player") { targetSelection.addChoice(target->name); } } // Ask the player for their action (attack or defend) int choice = this->battleOptions.activate(); switch(choice) { default: case 1: { // Player is attacking, so ask for the target. // Dialogue returns the number of the choice, but we // want the pointer that name corresponds to and so we // must look it up in the combatant vector Creature* target = this->combatants[targetSelection.activate()-1]; // Add the attack command to the event queue events.push(BattleEvent(com, target, BattleEventType::ATTACK)); break; } case 2: { // Player is defending, so do nothing events.push(BattleEvent(com, nullptr, BattleEventType::DEFEND)); break; } } } else { // Simple enemy AI where enemy constantly attacks player Creature* player = *std::find_if(this->combatants.begin(), this->combatants.end(), [](Creature* a) { return a->id == "player"; }); events.push(BattleEvent(com, player, BattleEventType::ATTACK)); } } // Take each event from the queue in turn and process them, // displaying the results while(!events.empty()) { // Take event from the front of the queue BattleEvent event = events.front(); switch(event.type) { case BattleEventType::ATTACK: { // The event can't be run if either the source or the // target were slain previously in this turn, so we // must check that they're valid first auto a = this->combatants.begin(); auto b = this->combatants.end(); if(std::find(a, b, event.source) == b || std::find(a, b, event.target) == b) { break; } std::cout << event.source->name << " attacks " << event.target->name << " for " << event.run() << " damage!\n"; // Delete slain enemies if(event.target->hp <= 0) { this->kill(event.target); } break; } case BattleEventType::DEFEND: std::cout << event.source->name << " defends!\n"; break; default: break; } events.pop(); } }