From: <geo...@us...> - 2010-02-04 10:46:12
|
Revision: 3348 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=3348&view=rev Author: geoffthemedio Date: 2010-02-04 10:46:06 +0000 (Thu, 04 Feb 2010) Log Message: ----------- Tweaks to target selection in (temporary) auto-resolve combat system Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2010-02-04 09:15:13 UTC (rev 3347) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2010-02-04 10:46:06 UTC (rev 3348) @@ -37,6 +37,11 @@ return; } + // add copy of system to full / complete objects in combat + System* copy_system = system->Clone(); + objects.Insert(system_id, copy_system); + + // find ships and their owners in system std::vector<int> ship_ids = system->FindObjectIDs<Ship>(); for (std::vector<int>::const_iterator it = ship_ids.begin(); it != ship_ids.end(); ++it) { @@ -80,8 +85,16 @@ // TODO: should buildings be considered separately? // now that all participants in the battle have been found, loop through - // ships and planets again to assemble each participant empire's latest + // objects again to assemble each participant empire's latest // known information about all objects in this battle + + // system + for (std::set<int>::const_iterator empire_it = empire_ids.begin(); empire_it != empire_ids.end(); ++empire_it) { + int empire_id = *empire_it; + System* visibility_limited_copy = system->Clone(empire_id); + empire_known_objects[empire_id].Insert(system_id, visibility_limited_copy); + } + // ships for (std::vector<int>::const_iterator it = ship_ids.begin(); it != ship_ids.end(); ++it) { int ship_id = *it; const Ship* ship = GetObject<Ship>(ship_id); @@ -98,6 +111,7 @@ } } } + // planets for (std::vector<int>::const_iterator it = planet_ids.begin(); it != planet_ids.end(); ++it) { int planet_id = *it; const Planet* planet = GetObject<Planet>(planet_id); @@ -257,55 +271,110 @@ int seed = first_object->ID() + CurrentTurn(); Seed(seed); - std::vector<UniverseObject*> all_combat_objects = combat_info.objects.FindObjects<UniverseObject>(); - SmallIntDistType object_num_dist = SmallIntDist(0, all_combat_objects.size() - 1); // to pick an object from the vector + std::vector<int> all_combat_object_IDs = combat_info.objects.FindObjectIDs<UniverseObject>(); + SmallIntDistType object_num_dist = SmallIntDist(0, all_combat_object_IDs.size() - 1); // to pick an object from the vector - const int NUM_COMBAT_ROUNDS = 100; + // map from empire to set of IDs of objects that empire's objects + // could target. presently valid targets are objects not owned by + // the empire, that are not systems or fleets + std::map<int, std::vector<int> > empire_valid_targets; + for (std::vector<int>::const_iterator object_it = all_combat_object_IDs.begin(); object_it != all_combat_object_IDs.end(); ++object_it) { + int object_id = *object_it; + const UniverseObject* obj = combat_info.objects.Object(object_id); + if (universe_object_cast<const System*>(obj)) + continue; + if (universe_object_cast<const Fleet*>(obj)) + continue; + + const std::set<int>& owners = obj->Owners(); + + for (std::set<int>::const_iterator empire_it = combat_info.empire_ids.begin(); empire_it != combat_info.empire_ids.end(); ++empire_it) { + int empire_id = *empire_it; + if (owners.find(empire_id) == owners.end()) + empire_valid_targets[empire_id].push_back(object_id); + } + } + + // Each combat "round" a randomly-selected object in the battle attacks + // something, if it is able to do so. The number of rounds scales with the + // number of objects, so the total actions per object is the same for + // battles, roughly independent of number of objects in the battle + const int NUM_COMBAT_ROUNDS = 20*all_combat_object_IDs.size(); + for (int round = 1; round <= NUM_COMBAT_ROUNDS; ++round) { Logger().debugStream() << "Combat at " << system->Name() << " (" << combat_info.system_id << ") Round " << round; // select attacking object in battle int attacker_index = object_num_dist(); + int attacker_id = all_combat_object_IDs.at(attacker_index); // check if object is already destroyed. if so, skip this round - if (combat_info.destroyed_object_ids.find(attacker_index) != combat_info.destroyed_object_ids.end()) + if (combat_info.destroyed_object_ids.find(attacker_id) != combat_info.destroyed_object_ids.end()) { + Logger().debugStream() << "skipping destroyed object as attack object"; continue; + } + UniverseObject* attacker = combat_info.objects.Object(attacker_id); + if (!attacker) { + Logger().errorStream() << "ResolveCombat couldn't get object with id " << attacker_id; + continue; + } - // TODO:: ensure target object is only selected from objects not owned by attacker object's owner + // fleets and the system can't attack + if (universe_object_cast<const System*>(attacker)) { + Logger().debugStream() << "skipping system as attack object"; + continue; + } + if (universe_object_cast<const Fleet*>(attacker)) { + Logger().debugStream() << "skipping fleet as attack object"; + continue; + } + // TODO: skip buildings? + // select object from valid targets for this object's owner. assuming + // this object has only one onwer. + const std::set<int>& owners = attacker->Owners(); + if (owners.empty()) { + Logger().debugStream() << "skipping unowned attacker object: " << attacker->Name() << "(" << attacker->ID() << ")"; + continue; + } + + // get attacker owner id + int attacker_owner_id = *owners.begin(); + + // get valid targets set for attacker owner + std::map<int, std::vector<int> >::iterator target_vec_it = empire_valid_targets.find(attacker_owner_id); + if (target_vec_it == empire_valid_targets.end()) { + Logger().debugStream() << "couldn't find target set for owner with id: " << attacker_owner_id; + continue; + } + const std::vector<int>& valid_target_ids = target_vec_it->second; + + + Logger().debugStream() << "Attacker: " << attacker->Name() << "(" << attacker->ID() << ")"; + + SmallIntDistType target_id_num_dist = SmallIntDist(0, valid_target_ids.size() - 1); // to pick an object from the vector + // select target object - int target_index = object_num_dist(); + int target_index = target_id_num_dist(); + int target_id = valid_target_ids.at(target_index); // check if object is already destroyed. if so, skip this round - if (combat_info.destroyed_object_ids.find(target_index) != combat_info.destroyed_object_ids.end()) + if (combat_info.destroyed_object_ids.find(target_id) != combat_info.destroyed_object_ids.end()) { + Logger().debugStream() << "skipping already destroyed object with id " << target_id; continue; + } - // get objects - UniverseObject* attacker = 0; - UniverseObject* target = 0; - try { - attacker = all_combat_objects.at(attacker_index); - target = all_combat_objects.at(target_index); - } catch (std::out_of_range) { - Logger().errorStream() << "tried to get out of range combat object?! index " << attacker_index << " or " << target_index; + + UniverseObject* target = combat_info.objects.Object(target_id); + if (!target) { + Logger().errorStream() << "ResolveCombat couldn't get object with id " << target_id; continue; } - // check ownership... avoid friendly fire. Can be removed if above TODO re: ownership is fixed - const std::set<int>& attacker_owners = attacker->Owners(); - const std::set<int>& target_owners = target->Owners(); - bool abort = false; - for (std::set<int>::const_iterator it = attacker_owners.begin(); it != attacker_owners.end(); ++it) { - if (target_owners.find(*it) != target_owners.end()) { - abort = true; - break; - } - } - if (abort) - continue; // attacker and target had one of the same owners. skip this combination to avoid friendly fire. + Logger().debugStream() << "Target: " << target->Name() << "(" << target->ID() << ")"; // do actual attack if (Ship* attack_ship = universe_object_cast<Ship*>(attacker)) { @@ -325,8 +394,6 @@ // check for destruction if (target->GetMeter(METER_HEALTH)->Current() <= 0.0) { - int target_id = target->ID(); - // object id destroyed combat_info.destroyed_object_ids.insert(target_id); // all empires in battle know object was destroyed |
From: <geo...@us...> - 2010-03-21 08:11:46
|
Revision: 3393 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=3393&view=rev Author: geoffthemedio Date: 2010-03-21 08:11:40 +0000 (Sun, 21 Mar 2010) Log Message: ----------- Fixed issue with combat autoresolve that was causing repeated planet starvation messages in systems where battles were occurring and uncolonized planets were present. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2010-03-21 07:32:47 UTC (rev 3392) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2010-03-21 08:11:40 UTC (rev 3393) @@ -406,10 +406,15 @@ } // and capture of planets } else if (Planet* planet = universe_object_cast<Planet*>(target)) { + if (planet->Unowned()) + continue; if (target->GetMeter(METER_CONSTRUCTION)->Current() <= 0.0) { const std::set<int>& attacker_owners = attacker->Owners(); - if (attacker_owners.size() == 1) - planet->Conquer(*attacker_owners.begin()); + if (attacker_owners.size() == 1) { + int attacker_owner = *attacker_owners.begin(); + if (!planet->OwnedBy(attacker_owner)) + planet->Conquer(attacker_owner); + } } } } |
From: <geo...@us...> - 2010-04-03 13:00:19
|
Revision: 3421 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=3421&view=rev Author: geoffthemedio Date: 2010-04-03 13:00:13 +0000 (Sat, 03 Apr 2010) Log Message: ----------- Tweaked AutoResolveCombat to use System object in CombatInfo rather than getting from main Universe ObjectMap. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2010-04-03 04:14:41 UTC (rev 3420) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2010-04-03 13:00:13 UTC (rev 3421) @@ -261,7 +261,7 @@ if (combat_info.objects.Empty()) return; - System* system = GetObject<System>(combat_info.system_id); + const System* system = combat_info.objects.Object<System>(combat_info.system_id); if (!system) { Logger().errorStream() << "AutoResolveCombat couldn't get system with id " << combat_info.system_id; } |
From: <geo...@us...> - 2010-06-13 00:20:00
|
Revision: 3621 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=3621&view=rev Author: geoffthemedio Date: 2010-06-13 00:19:50 +0000 (Sun, 13 Jun 2010) Log Message: ----------- Fixed crash during combat resolution related to missed substitution from METER_HEALTH to METER_STRUCTURE for ships Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2010-06-12 23:22:53 UTC (rev 3620) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2010-06-13 00:19:50 UTC (rev 3621) @@ -425,7 +425,7 @@ const std::vector<int>& valid_target_ids = target_vec_it->second; - Logger().debugStream() << "Attacker: " << attacker->Name() << "(" << attacker->ID() << ")"; + Logger().debugStream() << "Attacker: " << attacker->Name() << " (" << attacker->ID() << ")"; SmallIntDistType target_id_num_dist = SmallIntDist(0, valid_target_ids.size() - 1); // to pick an object from the vector @@ -446,7 +446,7 @@ continue; } - Logger().debugStream() << "Target: " << target->Name() << "(" << target->ID() << ")"; + Logger().debugStream() << "Target: " << target->Name() << " (" << target->ID() << ")"; // do actual attack if (Ship* attack_ship = universe_object_cast<Ship*>(attacker)) { @@ -466,7 +466,7 @@ // check for destruction of ships if (universe_object_cast<Ship*>(target)) { - if (target->UniverseObject::GetMeter(METER_HEALTH)->Current() <= 0.0) { + if (target->CurrentMeterValue(METER_STRUCTURE) <= 0.0) { // object id destroyed combat_info.destroyed_object_ids.insert(target_id); // all empires in battle know object was destroyed @@ -479,7 +479,7 @@ } else if (Planet* planet = universe_object_cast<Planet*>(target)) { if (planet->Unowned()) continue; - if (target->UniverseObject::GetMeter(METER_CONSTRUCTION)->Current() <= 0.0) { + if (target->CurrentMeterValue(METER_CONSTRUCTION) <= 0.0) { const std::set<int>& attacker_owners = attacker->Owners(); if (attacker_owners.size() == 1) { int attacker_owner = *attacker_owners.begin(); |
From: <geo...@us...> - 2011-08-17 05:17:41
|
Revision: 4157 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=4157&view=rev Author: geoffthemedio Date: 2011-08-17 05:17:35 +0000 (Wed, 17 Aug 2011) Log Message: ----------- Removed planet conquering during ship combat (since it now happens as separate troop-based step). Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2011-08-17 05:16:54 UTC (rev 4156) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2011-08-17 05:17:35 UTC (rev 4157) @@ -499,26 +499,6 @@ combat_info.destroyed_object_knowers[empire_id].insert(target_id); } } - // and capture of planets - } else if (Planet* planet = universe_object_cast<Planet*>(target)) { - // can only conquer populated planets, or planets with an owner - if (target->CurrentMeterValue(METER_POPULATION) == 0.0 && target->Unowned()) - continue; - - // conquering requires knocking construction to 0 - if (target->CurrentMeterValue(METER_CONSTRUCTION) > 0.0) - continue; - - // can only be conquered by a single attacker who is an empire - if (attacker->Unowned()) - continue; - - // can't conquer self! - if (planet->OwnedBy(attacker->Owner())) - continue; - - // conquer for new owner - planet->Conquer(attacker->Owner()); } } |
From: <geo...@us...> - 2012-02-19 03:44:37
|
Revision: 4660 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=4660&view=rev Author: geoffthemedio Date: 2012-02-19 03:44:31 +0000 (Sun, 19 Feb 2012) Log Message: ----------- -Tweaked combat log messages. -Added additional tracking of which empires have which combat objects that can attack or be attacked, and added early combat abort when nothing further can attack. -Moved combat results random seeding from start of combat to each round, to hopefully prevent strings of the same attacker attacking the same target over successive combat rounds. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2012-02-18 21:44:05 UTC (rev 4659) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2012-02-19 03:44:31 UTC (rev 4660) @@ -70,8 +70,9 @@ continue; } - // add owner to empires that have assets in this battle - empire_ids.insert(planet->Owner()); + // if planet is populated, add owner to empires that have assets in this battle + if (planet->CurrentMeterValue(METER_POPULATION) > 0.0) + empire_ids.insert(planet->Owner()); // add copy of ship to full / complete copy of objects in system Planet* copy = planet->Clone(); @@ -229,13 +230,9 @@ if (!attacker_design) return; double damage = attacker_design->Attack(); - if (damage <= 0.0) return; - Logger().debugStream() << "AttackShipShip: attacker: " << attacker->Dump() << "\ntarget: " << target->Dump(); - - Meter* target_shield = target->UniverseObject::GetMeter(METER_SHIELD); Meter* target_structure = target->UniverseObject::GetMeter(METER_STRUCTURE); if (!target_shield || ! target_structure) { @@ -243,6 +240,10 @@ return; } + Logger().debugStream() << "AttackShipShip: attacker: " << attacker->Name() << " damage: " << damage + << "\ntarget: " << target->Name() << " shield: " << target_shield->Current() + << " structure: " << target_structure->Current(); + // damage shields, limited by shield current value and damage amount. // remaining damage, if any, above shield current value goes to structure double shield_damage = std::min(target_shield->Current(), damage); @@ -261,8 +262,6 @@ attacker->SetLastTurnActiveInCombat(CurrentTurn()); target->SetLastTurnActiveInCombat(CurrentTurn()); - - Logger().debugStream() << "after AttackShipShip: attacker: " << attacker->Dump() << "\ntarget: " << target->Dump(); } void AttackShipPlanet(Ship* attacker, Planet* target) { @@ -272,12 +271,9 @@ if (!attacker_design) return; double damage = attacker_design->Attack(); - if (damage <= 0.0) return; - Logger().debugStream() << "AttackShipPlanet: ship: " << attacker->Dump() << "\nplanet: " << target->Dump(); - Meter* target_shield = target->GetMeter(METER_SHIELD); Meter* target_defense = target->UniverseObject::GetMeter(METER_DEFENSE); Meter* target_construction = target->UniverseObject::GetMeter(METER_CONSTRUCTION); @@ -294,6 +290,11 @@ return; } + Logger().debugStream() << "AttackShipPlanet: attacker: " << attacker->Name() << " damage: " << damage + << "\ntarget: " << target->Name() << " shield: " << target_shield->Current() + << " defense: " << target_defense->Current() + << " infra: " << target_construction->Current(); + // damage shields, limited by shield current value and damage amount. // remaining damage, if any, above shield current value goes to defense. // remaining damage, if any, above defense current value goes to construction @@ -317,25 +318,20 @@ if (construction_damage >= 0) { target_construction->AddToCurrent(-construction_damage); - Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << construction_damage << " construction damage to Planet " << target->Name() << " (" << target->ID() << ")"; + Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << construction_damage << " instrastructure damage to Planet " << target->Name() << " (" << target->ID() << ")"; } attacker->SetLastTurnActiveInCombat(CurrentTurn()); target->SetLastTurnAttackedByShip(CurrentTurn()); - - Logger().debugStream() << "after AttackShipPlanet: ship: " << attacker->Dump() << "\nplanet: " << target->Dump(); } void AttackPlanetShip(Planet* attacker, Ship* target) { if (!attacker || ! target) return; double damage = attacker->UniverseObject::GetMeter(METER_DEFENSE)->Current(); // planet "Defense" meter is actually its attack power - if (damage <= 0.0) return; - Logger().debugStream() << "AttackPlanetShip: planet: " << attacker->Dump() << "\nship: " << target->Dump(); - Meter* target_shield = target->UniverseObject::GetMeter(METER_SHIELD); Meter* target_structure = target->UniverseObject::GetMeter(METER_STRUCTURE); if (!target_shield || ! target_structure) { @@ -343,6 +339,10 @@ return; } + Logger().debugStream() << "AttackPlanetShip: attacker: " << attacker->Name() << " damage: " << damage + << "\ntarget: " << target->Name() << " shield: " << target_shield->Current() + << " structure: " << target_structure->Current(); + // damage shields, limited by shield current value and damage amount. // remaining damage, if any, above shield current value goes to structure double shield_damage = std::min(target_shield->Current(), damage); @@ -360,14 +360,44 @@ } target->SetLastTurnActiveInCombat(CurrentTurn()); - - Logger().debugStream() << "after AttackPlanetShip: planet: " << attacker->Dump() << "\nship: " << target->Dump(); } void AttackPlanetPlanet(Planet* attacker, Planet* target) { Logger().debugStream() << "AttackPlanetPlanet does nothing!"; // intentionally left empty } + + bool ObjectCanBeAttacked(const UniverseObject* obj) { + if (const Ship* ship = universe_object_cast<const Ship*>(obj)) { + return true; + } else if (const Planet* planet = universe_object_cast<const Planet*>(obj)) { + if (planet->CurrentMeterValue(METER_POPULATION) > 0.0) + return true; + else + return false; + } else { + return false; + } + } + + bool ObjectAttackableByEmpire(const UniverseObject* obj, int empire_id) { + if (obj->OwnedBy(empire_id)) + return false; + if (obj->Unowned() && empire_id == ALL_EMPIRES) + return false; + return ObjectCanBeAttacked(obj); + } + + bool ObjectCanAttack(const UniverseObject* obj) { + if (const Ship* ship = universe_object_cast<const Ship*>(obj)) { + return ship->IsArmed(); + } else if (const Planet* planet = universe_object_cast<const Planet*>(obj)) { + return planet->CurrentMeterValue(METER_POPULATION) > 0.0 && + planet->CurrentMeterValue(METER_DEFENSE) > 0.0; + } else { + return false; + } + } } void AutoResolveCombat(CombatInfo& combat_info) { @@ -383,29 +413,32 @@ Logger().debugStream() << "AutoResolveCombat objects before resolution: " << combat_info.objects.Dump(); // reasonably unpredictable but reproducible random seeding - const UniverseObject* first_object = combat_info.objects.begin()->second; - int seed = first_object->ID() + CurrentTurn(); - Seed(seed); + const int base_seed = combat_info.objects.begin()->first + CurrentTurn(); // compile list of valid objects to attack or be attacked in this combat - std::vector<int> all_combat_object_IDs; + std::set<int> valid_target_object_ids; // all objects that can be attacked + std::set<int> valid_attacker_object_ids; // all objects that can attack + std::map<int, std::set<int> > empire_valid_attacker_object_ids; // objects that can attack that each empire owns + for (ObjectMap::iterator it = combat_info.objects.begin(); it != combat_info.objects.end(); ++it) { const UniverseObject* obj = it->second; - if (universe_object_cast<const System*>(obj)) - continue; - if (universe_object_cast<const Fleet*>(obj)) - continue; - all_combat_object_IDs.push_back(it->first); + if (ObjectCanAttack(obj)) { + valid_attacker_object_ids.insert(it->first); + empire_valid_attacker_object_ids[obj->Owner()].insert(it->first); + } + if (ObjectCanBeAttacked(obj)) + valid_target_object_ids.insert(it->first); } // map from empire to set of IDs of objects that empire's objects - // could target. presently valid targets are objects not owned by - // the empire, that are not systems or fleets - std::map<int, std::vector<int> > empire_valid_targets; - for (std::vector<int>::const_iterator object_it = all_combat_object_IDs.begin(); object_it != all_combat_object_IDs.end(); ++object_it) { - int object_id = *object_it; + // could potentially target. + std::map<int, std::set<int> > empire_valid_target_object_ids; // objects that each empire can attack + for (std::set<int>::const_iterator target_it = valid_target_object_ids.begin(); + target_it != valid_target_object_ids.end(); ++target_it) + { + int object_id = *target_it; const UniverseObject* obj = combat_info.objects.Object(object_id); // which empire owns this object @@ -416,85 +449,91 @@ empire_it != combat_info.empire_ids.end(); ++empire_it) { int empire_id = *empire_it; - if (empire_id != owner) { - empire_valid_targets[empire_id].push_back(object_id); - } + if (ObjectAttackableByEmpire(obj, empire_id)) + empire_valid_target_object_ids[empire_id].insert(object_id); } } + // Each combat "round" a randomly-selected object in the battle attacks // something, if it is able to do so. The number of rounds scales with the // number of objects, so the total actions per object is the same for // battles, roughly independent of number of objects in the battle - const int NUM_COMBAT_ROUNDS = 10*all_combat_object_IDs.size(); + const int NUM_COMBAT_ROUNDS = 10*valid_attacker_object_ids.size(); for (int round = 1; round <= NUM_COMBAT_ROUNDS; ++round) { + Seed(base_seed + round); // ensure each combat round produces different results + + // ensure something can attack and something can be attacked + if (valid_attacker_object_ids.empty()) { + Logger().debugStream() << "Nothing left can attack; combat over"; + break; + } + if (empire_valid_target_object_ids.empty()) { + Logger().debugStream() << "Nothing left can be attacked; combat over"; + break; + } + // empires may have valid targets, but nothing to attack with. If all + // empires have no attackers or no valid targers, combat is over + bool someone_can_attack_something = false; + for (std::map<int, std::set<int> >::const_iterator attacker_it = empire_valid_attacker_object_ids.begin(); + attacker_it != empire_valid_attacker_object_ids.end(); ++attacker_it) + { + if (empire_valid_target_object_ids.find(attacker_it->first) != empire_valid_target_object_ids.end()) { + someone_can_attack_something = true; + break; + } + } + if (!someone_can_attack_something) { + Logger().debugStream() << "No empire has valid targets and something to attack with; combat over."; + break; + } + Logger().debugStream() << "Combat at " << system->Name() << " (" << combat_info.system_id << ") Round " << round; // select attacking object in battle - SmallIntDistType object_num_dist = SmallIntDist(0, all_combat_object_IDs.size() - 1); // to pick an object id from the vector - int attacker_index = object_num_dist(); - int attacker_id = all_combat_object_IDs.at(attacker_index); + SmallIntDistType attacker_id_num_dist = SmallIntDist(0, valid_attacker_object_ids.size() - 1); + std::set<int>::const_iterator attacker_it = valid_attacker_object_ids.begin(); + std::advance(attacker_it, attacker_id_num_dist()); + assert(attacker_it != valid_attacker_object_ids.end()); + int attacker_id = *attacker_it; - // check if object is already destroyed. if so, skip this round - if (combat_info.destroyed_object_ids.find(attacker_id) != combat_info.destroyed_object_ids.end()) { - //Logger().debugStream() << "skipping destroyed object as attack object"; - continue; - } - UniverseObject* attacker = combat_info.objects.Object(attacker_id); if (!attacker) { Logger().errorStream() << "AutoResolveCombat couldn't get object with id " << attacker_id; continue; } + Logger().debugStream() << "Attacker: " << attacker->Name(); - // fleets and the system can't attack - if (universe_object_cast<const System*>(attacker)) { - //Logger().debugStream() << "skipping system as attack object"; - continue; - } - if (universe_object_cast<const Fleet*>(attacker)) { - //Logger().debugStream() << "skipping fleet as attack object"; - continue; - } - // TODO: skip buildings? - // select object from valid targets for this object's owner. // get attacker owner id int attacker_owner_id = attacker->Owner(); // get valid targets set for attacker owner - std::map<int, std::vector<int> >::iterator target_vec_it = empire_valid_targets.find(attacker_owner_id); - if (target_vec_it == empire_valid_targets.end()) { - Logger().debugStream() << "couldn't find target set for owner with id: " << attacker_owner_id; + std::map<int, std::set<int> >::iterator target_vec_it = empire_valid_target_object_ids.find(attacker_owner_id); + if (target_vec_it == empire_valid_target_object_ids.end()) { + Logger().debugStream() << "No targets for attacker with id: " << attacker_owner_id; continue; } - const std::vector<int>& valid_target_ids = target_vec_it->second; + const std::set<int>& valid_target_ids = target_vec_it->second; + if (valid_target_ids.empty()) continue; // should be redundant with this entry being erased when emptied - Logger().debugStream() << "Attacker: " << attacker->Dump(); - - SmallIntDistType target_id_num_dist = SmallIntDist(0, valid_target_ids.size() - 1); // to pick an object id from the vector - // select target object - int target_index = target_id_num_dist(); - int target_id = valid_target_ids.at(target_index); + SmallIntDistType target_id_num_dist = SmallIntDist(0, valid_target_ids.size() - 1); + std::set<int>::const_iterator target_it = valid_target_ids.begin(); + std::advance(target_it, target_id_num_dist()); + assert(target_it != valid_target_ids.end()); + int target_id = *target_it; - // check if object is already destroyed. if so, skip this round - if (combat_info.destroyed_object_ids.find(target_id) != combat_info.destroyed_object_ids.end()) { - Logger().debugStream() << "skipping already destroyed object with id " << target_id; - continue; - } - - UniverseObject* target = combat_info.objects.Object(target_id); if (!target) { - Logger().errorStream() << "AutoResolveCombat couldn't get object with id " << target_id; + Logger().errorStream() << "AutoResolveCombat couldn't get target object with id " << target_id; continue; } + Logger().debugStream() << "Target: " << target->Name(); - Logger().debugStream() << "Target: " << target->Dump(); // do actual attack if (Ship* attack_ship = universe_object_cast<Ship*>(attacker)) { @@ -515,16 +554,65 @@ // check for destruction of ships if (universe_object_cast<Ship*>(target)) { if (target->CurrentMeterValue(METER_STRUCTURE) <= 0.0) { + Logger().debugStream() << "!! Target Ship is destroyed!"; // object id destroyed combat_info.destroyed_object_ids.insert(target_id); // all empires in battle know object was destroyed - for (std::set<int>::const_iterator it = combat_info.empire_ids.begin(); it != combat_info.empire_ids.end(); ++it) { + for (std::set<int>::const_iterator it = combat_info.empire_ids.begin(); + it != combat_info.empire_ids.end(); ++it) + { int empire_id = *it; if (empire_id != ALL_EMPIRES) combat_info.destroyed_object_knowers[empire_id].insert(target_id); } + // remove destroyed ship's ID from lists of valid attackers and targets + valid_attacker_object_ids.erase(target_id); + valid_target_object_ids.erase(target_id); // probably not necessary as this set isn't used in this loop + for (target_vec_it = empire_valid_target_object_ids.begin(); + target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) + { target_vec_it->second.erase(target_id); } + for (target_vec_it = empire_valid_attacker_object_ids.begin(); + target_vec_it != empire_valid_attacker_object_ids.end(); ++target_vec_it) + { target_vec_it->second.erase(target_id); } } + } else if (universe_object_cast<Planet*>(target)) { + if (target->CurrentMeterValue(METER_SHIELD) <= 0.0 && + target->CurrentMeterValue(METER_DEFENSE) <= 0.0 && + target->CurrentMeterValue(METER_CONSTRUCTION) <= 0.0) + { + Logger().debugStream() << "!! Target Planet is knocked out of battle"; + // remove disabled planet's ID from lists of valid attackers and targets + valid_attacker_object_ids.erase(target_id); + valid_target_object_ids.erase(target_id); // probably not necessary as this set isn't used in this loop + for (target_vec_it = empire_valid_target_object_ids.begin(); + target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) + { target_vec_it->second.erase(target_id); } + } } + + // check if any empire has no remaining target or attacker objects. + // If so, remove that empire's entry + std::map<int, std::set<int> > temp = empire_valid_target_object_ids; + for (target_vec_it = empire_valid_target_object_ids.begin(); + target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) + { + if (target_vec_it->second.empty()) { + temp.erase(target_vec_it->first); + Logger().debugStream() << "No valid targets left for empire with id: " << target_vec_it->first; + } + } + empire_valid_target_object_ids = temp; + + temp = empire_valid_attacker_object_ids; + for (target_vec_it = empire_valid_attacker_object_ids.begin(); + target_vec_it != empire_valid_attacker_object_ids.end(); ++target_vec_it) + { + if (target_vec_it->second.empty()) { + temp.erase(target_vec_it->first); + Logger().debugStream() << "No valid attacking objects left for empire with id: " << target_vec_it->first; + } + } + empire_valid_attacker_object_ids = temp; } // ensure every participant knows what happened. TODO: this should probably |
From: <geo...@us...> - 2012-07-03 06:57:02
|
Revision: 4972 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=4972&view=rev Author: geoffthemedio Date: 2012-07-03 06:56:53 +0000 (Tue, 03 Jul 2012) Log Message: ----------- Modified combat target selection to account for visibility, aggression setting, and diplomatic status. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2012-07-03 06:55:36 UTC (rev 4971) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2012-07-03 06:56:53 UTC (rev 4972) @@ -101,12 +101,22 @@ Logger().errorStream() << "CombatInfo::CombatInfo couldn't get ship with id " << ship_id << " in system " << system->Name() << " (" << system_id << ")"; continue; } + const Fleet* fleet = GetFleet(ship->FleetID()); + if (!fleet) { + Logger().errorStream() << "CombatInfo::CombatInfo couldn't get fleet with id " << ship->FleetID() << " in system " << system->Name() << " (" << system_id << ")"; + continue; + } for (std::set<int>::const_iterator empire_it = empire_ids.begin(); empire_it != empire_ids.end(); ++empire_it) { int empire_id = *empire_it; if (empire_id == ALL_EMPIRES) continue; - if (universe.GetObjectVisibilityByEmpire(ship_id, empire_id) >= VIS_BASIC_VISIBILITY) { + if (universe.GetObjectVisibilityByEmpire(ship_id, empire_id) >= VIS_BASIC_VISIBILITY || + (fleet->Aggressive() && + (empire_id == ALL_EMPIRES || + fleet->Unowned() || + Empires().GetDiplomaticStatus(empire_id, fleet->Owner()) == DIPLO_WAR))) + { Ship* visibility_limited_copy = ship->Clone(empire_id); empire_known_objects[empire_id].Insert(ship_id, visibility_limited_copy); } @@ -389,7 +399,7 @@ if (const Ship* ship = universe_object_cast<const Ship*>(obj)) { return true; } else if (const Planet* planet = universe_object_cast<const Planet*>(obj)) { - if (planet->CurrentMeterValue(METER_POPULATION) > 0.0) + if (planet->CurrentMeterValue(METER_POPULATION) > 0.0 || !planet->Unowned()) return true; else return false; @@ -398,11 +408,19 @@ } } - bool ObjectAttackableByEmpire(const UniverseObject* obj, int empire_id) { + bool ObjectAttackableByEmpire(const UniverseObject* obj, int empire_id, const ObjectMap& empire_known_objects) { if (obj->OwnedBy(empire_id)) return false; if (obj->Unowned() && empire_id == ALL_EMPIRES) return false; + + if (empire_id != ALL_EMPIRES && !obj->Unowned() && + Empires().GetDiplomaticStatus(empire_id, obj->Owner()) != DIPLO_WAR) + { return false; } + + if (!empire_known_objects.Object(obj->ID())) + return false; + return ObjectCanBeAttacked(obj); } @@ -467,8 +485,10 @@ empire_it != combat_info.empire_ids.end(); ++empire_it) { int empire_id = *empire_it; - if (ObjectAttackableByEmpire(obj, empire_id)) - empire_valid_target_object_ids[empire_id].insert(object_id); + std::map<int, ObjectMap>::const_iterator known_objects_it = combat_info.empire_known_objects.find(empire_id); + if (known_objects_it != combat_info.empire_known_objects.end()) + if (ObjectAttackableByEmpire(obj, empire_id, known_objects_it->second)) + empire_valid_target_object_ids[empire_id].insert(object_id); } } |
From: <geo...@us...> - 2012-07-09 00:08:28
|
Revision: 5006 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=5006&view=rev Author: geoffthemedio Date: 2012-07-09 00:08:22 +0000 (Mon, 09 Jul 2012) Log Message: ----------- Fixed monsters attacking during ship battles. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2012-07-08 22:19:02 UTC (rev 5005) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2012-07-09 00:08:22 UTC (rev 5006) @@ -424,6 +424,25 @@ return ObjectCanBeAttacked(obj); } + // monsters / natives can attack any planet, but can only attack + // visible ships or ships that are in aggressive fleets + bool ObjectAttackableByMonsters(const UniverseObject* obj, const ObjectMap& objects) { + if (obj->Unowned()) + return false; + if (const Planet* planet = universe_object_cast<const Planet*>(obj)) + return true; + if (const Ship* ship = universe_object_cast<const Ship*>(obj)) { + // TODO: something about visiblity... + const Fleet* fleet = objects.Object<Fleet>(ship->FleetID()); + if (!fleet) + return true; + if (fleet->Aggressive()) + return true; + return true; // TODO: check monster detection? + } + return false; + } + bool ObjectCanAttack(const UniverseObject* obj) { if (const Ship* ship = universe_object_cast<const Ship*>(obj)) { return ship->IsArmed(); @@ -477,18 +496,25 @@ int object_id = *target_it; const UniverseObject* obj = combat_info.objects.Object(object_id); - // which empire owns this object - int owner = obj->Owner(); - // for all empires, can they attack this object? for (std::set<int>::const_iterator empire_it = combat_info.empire_ids.begin(); empire_it != combat_info.empire_ids.end(); ++empire_it) { - int empire_id = *empire_it; - std::map<int, ObjectMap>::const_iterator known_objects_it = combat_info.empire_known_objects.find(empire_id); - if (known_objects_it != combat_info.empire_known_objects.end()) - if (ObjectAttackableByEmpire(obj, empire_id, known_objects_it->second)) - empire_valid_target_object_ids[empire_id].insert(object_id); + int attacking_empire_id = *empire_it; + if (attacking_empire_id == ALL_EMPIRES) { + if (ObjectAttackableByMonsters(obj, combat_info.objects)) + empire_valid_target_object_ids[ALL_EMPIRES].insert(object_id); + + } else { + // call function to find if empires can attack objects... + std::map<int, ObjectMap>::const_iterator known_objects_it = + combat_info.empire_known_objects.find(attacking_empire_id); + if (known_objects_it == combat_info.empire_known_objects.end()) + continue; // no known stuff for that empire? + + if (ObjectAttackableByEmpire(obj, attacking_empire_id, known_objects_it->second)) + empire_valid_target_object_ids[attacking_empire_id].insert(object_id); + } } } |
From: <geo...@us...> - 2012-10-24 09:37:12
|
Revision: 5331 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=5331&view=rev Author: geoffthemedio Date: 2012-10-24 09:37:05 +0000 (Wed, 24 Oct 2012) Log Message: ----------- Made each weapon on ships in combat fire independently whenever the ship gets a combat attack round, potentially targetting different enemy ships. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2012-10-24 06:57:37 UTC (rev 5330) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2012-10-24 09:37:05 UTC (rev 5331) @@ -243,15 +243,14 @@ // AutoResolveCombat //////////////////////////////////////////////// namespace { - void AttackShipShip(Ship* attacker, Ship* target, std::set<int>& damaged_object_ids) { + void AttackShipShip(Ship* attacker, double damage, Ship* target, std::set<int>& damaged_object_ids) { if (!attacker || ! target) return; + if (damage <= 0.0) + return; const ShipDesign* attacker_design = attacker->Design(); if (!attacker_design) return; - double damage = attacker_design->Attack(); - if (damage <= 0.0) - return; Meter* target_shield = target->UniverseObject::GetMeter(METER_SHIELD); Meter* target_structure = target->UniverseObject::GetMeter(METER_STRUCTURE); @@ -261,7 +260,7 @@ } Logger().debugStream() << "AttackShipShip: attacker: " << attacker->Name() << " damage: " << damage - << "\ntarget: " << target->Name() << " shield: " << target_shield->Current() + << " target: " << target->Name() << " shield: " << target_shield->Current() << " structure: " << target_structure->Current(); // damage shields, limited by shield current value and damage amount. @@ -287,15 +286,14 @@ target->SetLastTurnActiveInCombat(CurrentTurn()); } - void AttackShipPlanet(Ship* attacker, Planet* target, std::set<int>& damaged_object_ids) { + void AttackShipPlanet(Ship* attacker, double damage, Planet* target, std::set<int>& damaged_object_ids) { if (!attacker || ! target) return; + if (damage <= 0.0) + return; const ShipDesign* attacker_design = attacker->Design(); if (!attacker_design) return; - double damage = attacker_design->Attack(); - if (damage <= 0.0) - return; Meter* target_shield = target->GetMeter(METER_SHIELD); Meter* target_defense = target->UniverseObject::GetMeter(METER_DEFENSE); @@ -453,6 +451,45 @@ return false; } } + + struct PartAttackInfo { + PartAttackInfo(ShipPartClass c, const std::string& s, double a) : + part_class(c), + part_type_name(s), + part_attack(a) + {} + ShipPartClass part_class; + std::string part_type_name; + double part_attack; + }; + + std::vector<PartAttackInfo> ShipWeaponsStrengths(const Ship* ship) { + std::vector<PartAttackInfo> retval; + if (!ship) + return retval; + const ShipDesign* design = GetShipDesign(ship->DesignID()); + if (!design) + return retval; + const std::vector<std::string>& parts = design->Parts(); + // check if each part is a weapon + for (std::vector<std::string>::const_iterator it = parts.begin(); it != parts.end(); ++it) { + const PartType* part = GetPartType(*it); + if (!part) + continue; + + double part_attack = 0.0; + if (part->Class() == PC_SHORT_RANGE || part->Class() == PC_POINT_DEFENSE) + part_attack = boost::get<DirectFireStats>(part->Stats()).m_damage; + else if (part->Class() == PC_MISSILES) + part_attack = boost::get<LRStats>(part->Stats()).m_damage; + else if (part->Class() == PC_FIGHTERS) + part_attack = boost::get<FighterStats>(part->Stats()).m_anti_ship_damage; + if (part_attack == 0.0) + continue; + retval.push_back(PartAttackInfo(part->Class(), *it, part_attack)); + } + return retval; + } } void AutoResolveCombat(CombatInfo& combat_info) { @@ -521,8 +558,8 @@ // Each combat "round" a randomly-selected object in the battle attacks // something, if it is able to do so. The number of rounds scales with the - // number of objects, so the total actions per object is the same for - // battles, roughly independent of number of objects in the battle + // number of objects, so the total actions per object is independent of + // number of objects in the battle const int NUM_COMBAT_ROUNDS = 10*valid_attacker_object_ids.size(); for (int round = 1; round <= NUM_COMBAT_ROUNDS; ++round) { @@ -570,115 +607,145 @@ Logger().debugStream() << "Attacker: " << attacker->Name(); - // select object from valid targets for this object's owner. - // get attacker owner id - int attacker_owner_id = attacker->Owner(); + Ship* attack_ship = universe_object_cast<Ship*>(attacker); + Planet* attack_planet = universe_object_cast<Planet*>(attacker); - // get valid targets set for attacker owner - std::map<int, std::set<int> >::iterator target_vec_it = empire_valid_target_object_ids.find(attacker_owner_id); - if (target_vec_it == empire_valid_target_object_ids.end()) { - Logger().debugStream() << "No targets for attacker with id: " << attacker_owner_id; - continue; + // loop over weapons of attacking object. each gets a shot at a + // randomly selected target object + std::vector<PartAttackInfo> weapons; + + if (attack_ship) { + weapons = ShipWeaponsStrengths(attack_ship); + for (std::vector<PartAttackInfo>::const_iterator part_it = weapons.begin(); + part_it != weapons.end(); ++part_it) + { + Logger().debugStream() << "weapon: " << part_it->part_type_name << + " attack: " << part_it->part_attack; + } + } else if (attack_planet) { // treat planet defenses as short range + weapons.push_back(PartAttackInfo(PC_SHORT_RANGE, "", attack_planet->CurrentMeterValue(METER_DEFENSE))); } - const std::set<int>& valid_target_ids = target_vec_it->second; - if (valid_target_ids.empty()) continue; // should be redundant with this entry being erased when emptied + if (weapons.empty()) { + Logger().debugStream() << "no weapons' can't attack"; + continue; // no ability to attack! + } - // select target object - SmallIntDistType target_id_num_dist = SmallIntDist(0, valid_target_ids.size() - 1); - std::set<int>::const_iterator target_it = valid_target_ids.begin(); - std::advance(target_it, target_id_num_dist()); - assert(target_it != valid_target_ids.end()); - int target_id = *target_it; + for (std::vector<PartAttackInfo>::const_iterator weapon_it = weapons.begin(); + weapon_it != weapons.end(); ++weapon_it) + { + // select object from valid targets for this object's owner TODO: with this weapon... + Logger().debugStream() << "Attacking with weapon " << weapon_it->part_type_name << " with power " << weapon_it->part_attack; - UniverseObject* target = combat_info.objects.Object(target_id); - if (!target) { - Logger().errorStream() << "AutoResolveCombat couldn't get target object with id " << target_id; - continue; - } - Logger().debugStream() << "Target: " << target->Name(); + // get valid targets set for attacker owner. need to do this for + // each weapon that is attacking, as the previous shot might have + // destroyed something + int attacker_owner_id = attacker->Owner(); + std::map<int, std::set<int> >::iterator target_vec_it = empire_valid_target_object_ids.find(attacker_owner_id); + if (target_vec_it == empire_valid_target_object_ids.end()) { + Logger().debugStream() << "No targets for attacker with id: " << attacker_owner_id; + break; + } + const std::set<int>& valid_target_ids = target_vec_it->second; + if (valid_target_ids.empty()) break; // should be redundant with this entry being erased when emptied - // do actual attack - if (Ship* attack_ship = universe_object_cast<Ship*>(attacker)) { - if (Ship* target_ship = universe_object_cast<Ship*>(target)) { - AttackShipShip(attack_ship, target_ship, combat_info.damaged_object_ids); - } else if (Planet* target_planet = universe_object_cast<Planet*>(target)) { - AttackShipPlanet(attack_ship, target_planet, combat_info.damaged_object_ids); + // select target object + SmallIntDistType target_id_num_dist = SmallIntDist(0, valid_target_ids.size() - 1); + std::set<int>::const_iterator target_it = valid_target_ids.begin(); + std::advance(target_it, target_id_num_dist()); + assert(target_it != valid_target_ids.end()); + int target_id = *target_it; + + UniverseObject* target = combat_info.objects.Object(target_id); + if (!target) { + Logger().errorStream() << "AutoResolveCombat couldn't get target object with id " << target_id; + continue; } - } else if (Planet* attack_planet = universe_object_cast<Planet*>(attacker)) { - if (Ship* target_ship = universe_object_cast<Ship*>(target)) { - AttackPlanetShip(attack_planet, target_ship, combat_info.damaged_object_ids); - } else if (Planet* target_planet = universe_object_cast<Planet*>(target)) { - AttackPlanetPlanet(attack_planet, target_planet, combat_info.damaged_object_ids); + Logger().debugStream() << "Target: " << target->Name(); + + + // do actual attack + if (attack_ship) { + if (Ship* target_ship = universe_object_cast<Ship*>(target)) { + AttackShipShip(attack_ship, weapon_it->part_attack, target_ship, combat_info.damaged_object_ids); + } else if (Planet* target_planet = universe_object_cast<Planet*>(target)) { + AttackShipPlanet(attack_ship, weapon_it->part_attack, target_planet, combat_info.damaged_object_ids); + } + } else if (attack_planet) { + if (Ship* target_ship = universe_object_cast<Ship*>(target)) { + AttackPlanetShip(attack_planet, target_ship, combat_info.damaged_object_ids); + } else if (Planet* target_planet = universe_object_cast<Planet*>(target)) { + AttackPlanetPlanet(attack_planet, target_planet, combat_info.damaged_object_ids); + } } - } - // check for destruction of ships - if (universe_object_cast<Ship*>(target)) { - if (target->CurrentMeterValue(METER_STRUCTURE) <= 0.0) { - Logger().debugStream() << "!! Target Ship is destroyed!"; - // object id destroyed - combat_info.destroyed_object_ids.insert(target_id); - // all empires in battle know object was destroyed - for (std::set<int>::const_iterator it = combat_info.empire_ids.begin(); - it != combat_info.empire_ids.end(); ++it) + // check for destruction of ships + if (universe_object_cast<Ship*>(target)) { + if (target->CurrentMeterValue(METER_STRUCTURE) <= 0.0) { + Logger().debugStream() << "!! Target Ship is destroyed!"; + // object id destroyed + combat_info.destroyed_object_ids.insert(target_id); + // all empires in battle know object was destroyed + for (std::set<int>::const_iterator it = combat_info.empire_ids.begin(); + it != combat_info.empire_ids.end(); ++it) + { + int empire_id = *it; + if (empire_id != ALL_EMPIRES) + combat_info.destroyed_object_knowers[empire_id].insert(target_id); + } + // remove destroyed ship's ID from lists of valid attackers and targets + valid_attacker_object_ids.erase(target_id); + valid_target_object_ids.erase(target_id); // probably not necessary as this set isn't used in this loop + for (target_vec_it = empire_valid_target_object_ids.begin(); + target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) + { target_vec_it->second.erase(target_id); } + for (target_vec_it = empire_valid_attacker_object_ids.begin(); + target_vec_it != empire_valid_attacker_object_ids.end(); ++target_vec_it) + { target_vec_it->second.erase(target_id); } + } + } else if (universe_object_cast<Planet*>(target)) { + if (target->CurrentMeterValue(METER_SHIELD) <= 0.0 && + target->CurrentMeterValue(METER_DEFENSE) <= 0.0 && + target->CurrentMeterValue(METER_CONSTRUCTION) <= 0.0) { - int empire_id = *it; - if (empire_id != ALL_EMPIRES) - combat_info.destroyed_object_knowers[empire_id].insert(target_id); + Logger().debugStream() << "!! Target Planet is knocked out of battle"; + // remove disabled planet's ID from lists of valid attackers and targets + valid_attacker_object_ids.erase(target_id); + valid_target_object_ids.erase(target_id); // probably not necessary as this set isn't used in this loop + for (target_vec_it = empire_valid_target_object_ids.begin(); + target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) + { target_vec_it->second.erase(target_id); } } - // remove destroyed ship's ID from lists of valid attackers and targets - valid_attacker_object_ids.erase(target_id); - valid_target_object_ids.erase(target_id); // probably not necessary as this set isn't used in this loop - for (target_vec_it = empire_valid_target_object_ids.begin(); - target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) - { target_vec_it->second.erase(target_id); } - for (target_vec_it = empire_valid_attacker_object_ids.begin(); - target_vec_it != empire_valid_attacker_object_ids.end(); ++target_vec_it) - { target_vec_it->second.erase(target_id); } } - } else if (universe_object_cast<Planet*>(target)) { - if (target->CurrentMeterValue(METER_SHIELD) <= 0.0 && - target->CurrentMeterValue(METER_DEFENSE) <= 0.0 && - target->CurrentMeterValue(METER_CONSTRUCTION) <= 0.0) + + // check if any empire has no remaining target or attacker objects. + // If so, remove that empire's entry + std::map<int, std::set<int> > temp = empire_valid_target_object_ids; + for (target_vec_it = empire_valid_target_object_ids.begin(); + target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) { - Logger().debugStream() << "!! Target Planet is knocked out of battle"; - // remove disabled planet's ID from lists of valid attackers and targets - valid_attacker_object_ids.erase(target_id); - valid_target_object_ids.erase(target_id); // probably not necessary as this set isn't used in this loop - for (target_vec_it = empire_valid_target_object_ids.begin(); - target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) - { target_vec_it->second.erase(target_id); } + if (target_vec_it->second.empty()) { + temp.erase(target_vec_it->first); + Logger().debugStream() << "No valid targets left for empire with id: " << target_vec_it->first; + } } - } + empire_valid_target_object_ids = temp; - // check if any empire has no remaining target or attacker objects. - // If so, remove that empire's entry - std::map<int, std::set<int> > temp = empire_valid_target_object_ids; - for (target_vec_it = empire_valid_target_object_ids.begin(); - target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) - { - if (target_vec_it->second.empty()) { - temp.erase(target_vec_it->first); - Logger().debugStream() << "No valid targets left for empire with id: " << target_vec_it->first; + temp = empire_valid_attacker_object_ids; + for (target_vec_it = empire_valid_attacker_object_ids.begin(); + target_vec_it != empire_valid_attacker_object_ids.end(); ++target_vec_it) + { + if (target_vec_it->second.empty()) { + temp.erase(target_vec_it->first); + Logger().debugStream() << "No valid attacking objects left for empire with id: " << target_vec_it->first; + } } - } - empire_valid_target_object_ids = temp; + empire_valid_attacker_object_ids = temp; + } // end for over weapons + } // end for over combat arounds - temp = empire_valid_attacker_object_ids; - for (target_vec_it = empire_valid_attacker_object_ids.begin(); - target_vec_it != empire_valid_attacker_object_ids.end(); ++target_vec_it) - { - if (target_vec_it->second.empty()) { - temp.erase(target_vec_it->first); - Logger().debugStream() << "No valid attacking objects left for empire with id: " << target_vec_it->first; - } - } - empire_valid_attacker_object_ids = temp; - } - // ensure every participant knows what happened. TODO: this should probably // be more discriminating about what info is or isn't copied. for (std::map<int, ObjectMap>::iterator it = combat_info.empire_known_objects.begin(); |
From: <geo...@us...> - 2012-12-08 17:35:17
|
Revision: 5531 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=5531&view=rev Author: geoffthemedio Date: 2012-12-08 17:35:10 +0000 (Sat, 08 Dec 2012) Log Message: ----------- -Adjusted code that decides when battles occur to consider attacker visibility (including monster detection strength) and target stealth. -Made not-visible ships not valid targets for empires / monsters that can't see them until the stealthy ship attacks, at which point the target becomes able to see its attacker and can attack back. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2012-12-08 17:29:01 UTC (rev 5530) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2012-12-08 17:35:10 UTC (rev 5531) @@ -395,10 +395,13 @@ } bool ObjectCanBeAttacked(const UniverseObject* obj) { - if (/*const Ship* ship = */universe_object_cast<const Ship*>(obj)) { + if (!obj) + return false; + UniverseObjectType obj_type = obj->ObjectType(); + if (obj_type == OBJ_SHIP) { return true; - } else if (const Planet* planet = universe_object_cast<const Planet*>(obj)) { - if (planet->CurrentMeterValue(METER_POPULATION) > 0.0f || !planet->Unowned()) + } else if (obj_type == OBJ_PLANET) { + if (!obj->Unowned() || obj->CurrentMeterValue(METER_POPULATION) > 0.0f) return true; else return false; @@ -407,7 +410,7 @@ } } - bool ObjectAttackableByEmpire(const UniverseObject* obj, int empire_id, const ObjectMap& empire_known_objects) { + bool ObjectAttackableByEmpire(const UniverseObject* obj, int empire_id) { if (obj->OwnedBy(empire_id)) return false; if (obj->Unowned() && empire_id == ALL_EMPIRES) @@ -417,7 +420,7 @@ Empires().GetDiplomaticStatus(empire_id, obj->Owner()) != DIPLO_WAR) { return false; } - if (!empire_known_objects.Object(obj->ID())) + if (GetUniverse().GetObjectVisibilityByEmpire(obj->ID(), empire_id) < VIS_BASIC_VISIBILITY) return false; return ObjectCanBeAttacked(obj); @@ -425,20 +428,21 @@ // monsters / natives can attack any planet, but can only attack // visible ships or ships that are in aggressive fleets - bool ObjectAttackableByMonsters(const UniverseObject* obj, const ObjectMap& objects) { + bool ObjectAttackableByMonsters(const UniverseObject* obj, float monster_detection = 0.0) { if (obj->Unowned()) return false; - if (/*const Planet* planet = */universe_object_cast<const Planet*>(obj)) + + //Logger().debugStream() << "Testing if object " << obj->Name() << " is attackable by monsters"; + + UniverseObjectType obj_type = obj->ObjectType(); + if (obj_type == OBJ_PLANET) { return true; - if (const Ship* ship = universe_object_cast<const Ship*>(obj)) { - // TODO: something about visiblity... - const Fleet* fleet = objects.Object<Fleet>(ship->FleetID()); - if (!fleet) + } else if (obj_type == OBJ_SHIP) { + float stealth = obj->CurrentMeterValue(METER_STEALTH); + if (monster_detection >= stealth) return true; - if (fleet->Aggressive()) - return true; - return true; // TODO: check monster detection? } + //Logger().debugStream() << "... ... is NOT attackable by monsters"; return false; } @@ -501,6 +505,8 @@ const System* system = combat_info.objects.Object<System>(combat_info.system_id); if (!system) Logger().errorStream() << "AutoResolveCombat couldn't get system with id " << combat_info.system_id; + else + Logger().debugStream() << "AutoResolveCombat at " << system->Name(); if (GetOptionsDB().Get<bool>("verbose-logging")) { Logger().debugStream() << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"; @@ -515,15 +521,22 @@ std::set<int> valid_target_object_ids; // all objects that can be attacked std::set<int> valid_attacker_object_ids; // all objects that can attack std::map<int, std::set<int> > empire_valid_attacker_object_ids; // objects that can attack that each empire owns + float monster_detection = 0.0; for (ObjectMap::iterator it = combat_info.objects.begin(); it != combat_info.objects.end(); ++it) { const UniverseObject* obj = it->second; + //Logger().debugStream() << "Considerting object " << obj->Name() << " owned by " << obj->Owner(); if (ObjectCanAttack(obj)) { + //Logger().debugStream() << "... can attack"; valid_attacker_object_ids.insert(it->first); empire_valid_attacker_object_ids[obj->Owner()].insert(it->first); } - if (ObjectCanBeAttacked(obj)) + if (ObjectCanBeAttacked(obj)) { + //Logger().debugStream() << "... can be attacked"; valid_target_object_ids.insert(it->first); + } + if (obj->Unowned() && obj->ObjectType() == OBJ_SHIP) + monster_detection = std::max(monster_detection, obj->CurrentMeterValue(METER_DETECTION)); } @@ -535,6 +548,7 @@ { int object_id = *target_it; const UniverseObject* obj = combat_info.objects.Object(object_id); + //Logger().debugStream() << "Considering attackability of object " << obj->Name() << " owned by " << obj->Owner(); // for all empires, can they attack this object? for (std::set<int>::const_iterator empire_it = combat_info.empire_ids.begin(); @@ -542,18 +556,17 @@ { int attacking_empire_id = *empire_it; if (attacking_empire_id == ALL_EMPIRES) { - if (ObjectAttackableByMonsters(obj, combat_info.objects)) + if (ObjectAttackableByMonsters(obj, monster_detection)) { + //Logger().debugStream() << "object: " << obj->Name() << " attackable by monsters"; empire_valid_target_object_ids[ALL_EMPIRES].insert(object_id); + } } else { // call function to find if empires can attack objects... - std::map<int, ObjectMap>::const_iterator known_objects_it = - combat_info.empire_known_objects.find(attacking_empire_id); - if (known_objects_it == combat_info.empire_known_objects.end()) - continue; // no known stuff for that empire? - - if (ObjectAttackableByEmpire(obj, attacking_empire_id, known_objects_it->second)) + if (ObjectAttackableByEmpire(obj, attacking_empire_id)) { + //Logger().debugStream() << "object: " << obj->Name() << " attackable by empire " << attacking_empire_id; empire_valid_target_object_ids[attacking_empire_id].insert(object_id); + } } } } @@ -644,13 +657,16 @@ // each weapon that is attacking, as the previous shot might have // destroyed something int attacker_owner_id = attacker->Owner(); + std::map<int, std::set<int> >::iterator target_vec_it = empire_valid_target_object_ids.find(attacker_owner_id); if (target_vec_it == empire_valid_target_object_ids.end()) { Logger().debugStream() << "No targets for attacker with id: " << attacker_owner_id; break; } + const std::set<int>& valid_target_ids = target_vec_it->second; - if (valid_target_ids.empty()) break; // should be redundant with this entry being erased when emptied + if (valid_target_ids.empty()) + break; // should be redundant with this entry being erased when emptied // select target object @@ -668,23 +684,27 @@ Logger().debugStream() << "Target: " << target->Name(); - // do actual attack + // do actual attacks, and mark attackers as valid targets for attacked object's owners if (attack_ship) { if (Ship* target_ship = universe_object_cast<Ship*>(target)) { AttackShipShip(attack_ship, weapon_it->part_attack, target_ship, combat_info.damaged_object_ids); + empire_valid_target_object_ids[target_ship->Owner()].insert(attack_ship->Owner()); } else if (Planet* target_planet = universe_object_cast<Planet*>(target)) { AttackShipPlanet(attack_ship, weapon_it->part_attack, target_planet, combat_info.damaged_object_ids); + empire_valid_target_object_ids[target_planet->Owner()].insert(attack_ship->Owner()); } } else if (attack_planet) { if (Ship* target_ship = universe_object_cast<Ship*>(target)) { AttackPlanetShip(attack_planet, target_ship, combat_info.damaged_object_ids); + empire_valid_target_object_ids[target_ship->Owner()].insert(attack_planet->Owner()); } else if (Planet* target_planet = universe_object_cast<Planet*>(target)) { AttackPlanetPlanet(attack_planet, target_planet, combat_info.damaged_object_ids); + empire_valid_target_object_ids[target_planet->Owner()].insert(attack_planet->Owner()); } } - // check for destruction of ships + // check for destruction of target object if (target->ObjectType() == OBJ_SHIP) { if (target->CurrentMeterValue(METER_STRUCTURE) <= 0.0) { Logger().debugStream() << "!! Target Ship is destroyed!"; @@ -698,28 +718,38 @@ if (empire_id != ALL_EMPIRES) combat_info.destroyed_object_knowers[empire_id].insert(target_id); } + // remove destroyed ship's ID from lists of valid attackers and targets valid_attacker_object_ids.erase(target_id); valid_target_object_ids.erase(target_id); // probably not necessary as this set isn't used in this loop + for (target_vec_it = empire_valid_target_object_ids.begin(); target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) { target_vec_it->second.erase(target_id); } + for (target_vec_it = empire_valid_attacker_object_ids.begin(); target_vec_it != empire_valid_attacker_object_ids.end(); ++target_vec_it) - { target_vec_it->second.erase(target_id); } + { target_vec_it->second.erase(target_id); } // TODO: only erase from owner's entry in this list } + } else if (target->ObjectType() == OBJ_PLANET) { if (target->CurrentMeterValue(METER_SHIELD) <= 0.0 && target->CurrentMeterValue(METER_DEFENSE) <= 0.0 && target->CurrentMeterValue(METER_CONSTRUCTION) <= 0.0) { Logger().debugStream() << "!! Target Planet is knocked out of battle"; + // remove disabled planet's ID from lists of valid attackers and targets valid_attacker_object_ids.erase(target_id); valid_target_object_ids.erase(target_id); // probably not necessary as this set isn't used in this loop + for (target_vec_it = empire_valid_target_object_ids.begin(); target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) { target_vec_it->second.erase(target_id); } + + for (target_vec_it = empire_valid_attacker_object_ids.begin(); + target_vec_it != empire_valid_attacker_object_ids.end(); ++target_vec_it) + { target_vec_it->second.erase(target_id); } // TODO: only erase from owner's entry in this list } } |
From: <geo...@us...> - 2012-12-15 20:10:25
|
Revision: 5541 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=5541&view=rev Author: geoffthemedio Date: 2012-12-15 20:10:18 +0000 (Sat, 15 Dec 2012) Log Message: ----------- Fixed autoresolve combat, which was marking empire ids instead of ship/planet ids as valid targets after attacks. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2012-12-14 15:27:31 UTC (rev 5540) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2012-12-15 20:10:18 UTC (rev 5541) @@ -688,18 +688,18 @@ if (attack_ship) { if (Ship* target_ship = universe_object_cast<Ship*>(target)) { AttackShipShip(attack_ship, weapon_it->part_attack, target_ship, combat_info.damaged_object_ids); - empire_valid_target_object_ids[target_ship->Owner()].insert(attack_ship->Owner()); + empire_valid_target_object_ids[target_ship->Owner()].insert(attacker_id); } else if (Planet* target_planet = universe_object_cast<Planet*>(target)) { AttackShipPlanet(attack_ship, weapon_it->part_attack, target_planet, combat_info.damaged_object_ids); - empire_valid_target_object_ids[target_planet->Owner()].insert(attack_ship->Owner()); + empire_valid_target_object_ids[target_planet->Owner()].insert(attacker_id); } } else if (attack_planet) { if (Ship* target_ship = universe_object_cast<Ship*>(target)) { AttackPlanetShip(attack_planet, target_ship, combat_info.damaged_object_ids); - empire_valid_target_object_ids[target_ship->Owner()].insert(attack_planet->Owner()); + empire_valid_target_object_ids[target_ship->Owner()].insert(attacker_id); } else if (Planet* target_planet = universe_object_cast<Planet*>(target)) { AttackPlanetPlanet(attack_planet, target_planet, combat_info.damaged_object_ids); - empire_valid_target_object_ids[target_planet->Owner()].insert(attack_planet->Owner()); + empire_valid_target_object_ids[target_planet->Owner()].insert(attacker_id); } } |
From: <geo...@us...> - 2013-01-01 08:59:26
|
Revision: 5602 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=5602&view=rev Author: geoffthemedio Date: 2013-01-01 08:59:20 +0000 (Tue, 01 Jan 2013) Log Message: ----------- Experimentally reduced number of combat rounds to 3 * number of ships in battle, from 10 * number of ships. Most combats seem to finish in just a few rounds anyway, but this might make balancing for less weapon strength or more hull more interesting, and was suggested on forums. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2013-01-01 08:58:00 UTC (rev 5601) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2013-01-01 08:59:20 UTC (rev 5602) @@ -586,7 +586,7 @@ // something, if it is able to do so. The number of rounds scales with the // number of objects, so the total actions per object is independent of // number of objects in the battle - const int NUM_COMBAT_ROUNDS = 10*valid_attacker_object_ids.size(); + const int NUM_COMBAT_ROUNDS = 3*valid_attacker_object_ids.size(); for (int round = 1; round <= NUM_COMBAT_ROUNDS; ++round) { Seed(base_seed + round); // ensure each combat round produces different results |
From: <geo...@us...> - 2013-03-27 18:24:01
|
Revision: 5908 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=5908&view=rev Author: geoffthemedio Date: 2013-03-27 18:23:55 +0000 (Wed, 27 Mar 2013) Log Message: ----------- Combat event logging progress. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2013-03-26 01:04:18 UTC (rev 5907) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2013-03-27 18:23:55 UTC (rev 5908) @@ -257,7 +257,7 @@ // AutoResolveCombat //////////////////////////////////////////////// namespace { - void AttackShipShip(Ship* attacker, float damage, Ship* target, CombatInfo& combat_info) { + void AttackShipShip(Ship* attacker, float damage, Ship* target, CombatInfo& combat_info, int round) { if (!attacker || ! target) return; if (damage <= 0.0f) return; @@ -298,11 +298,19 @@ Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << structure_damage << " structure damage to Ship " << target->Name() << " (" << target->ID() << ")"; } + AttackEvent attack; + attack.attacker_id = attacker->ID(); + attack.target_id = target->ID(); + attack.round = round; + attack.damage = damage; + attack.target_destroyed = (target_structure->Current() <= 0.0f); + combat_info.combat_events.push_back(attack); + attacker->SetLastTurnActiveInCombat(CurrentTurn()); target->SetLastTurnActiveInCombat(CurrentTurn()); } - void AttackShipPlanet(Ship* attacker, float damage, Planet* target, CombatInfo& combat_info) { + void AttackShipPlanet(Ship* attacker, float damage, Planet* target, CombatInfo& combat_info, int round) { if (!attacker || ! target) return; if (damage <= 0.0f) return; @@ -362,11 +370,19 @@ Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << construction_damage << " instrastructure damage to Planet " << target->Name() << " (" << target->ID() << ")"; } + AttackEvent attack; + attack.attacker_id = attacker->ID(); + attack.target_id = target->ID(); + attack.round = round; + attack.damage = damage; + attack.target_destroyed = false; + combat_info.combat_events.push_back(attack); + attacker->SetLastTurnActiveInCombat(CurrentTurn()); target->SetLastTurnAttackedByShip(CurrentTurn()); } - void AttackPlanetShip(Planet* attacker, Ship* target, CombatInfo& combat_info) { + void AttackPlanetShip(Planet* attacker, Ship* target, CombatInfo& combat_info, int round) { if (!attacker || ! target) return; float damage = attacker->UniverseObject::GetMeter(METER_DEFENSE)->Current(); // planet "Defense" meter is actually its attack power @@ -405,10 +421,18 @@ Logger().debugStream() << "COMBAT: Planet " << attacker->Name() << " (" << attacker->ID() << ") does " << structure_damage << " structure damage to Ship " << target->Name() << " (" << target->ID() << ")"; } + AttackEvent attack; + attack.attacker_id = attacker->ID(); + attack.target_id = target->ID(); + attack.round = round; + attack.damage = damage; + attack.target_destroyed = (target_structure->Current() <= 0.0f); + combat_info.combat_events.push_back(attack); + target->SetLastTurnActiveInCombat(CurrentTurn()); } - void AttackPlanetPlanet(Planet* attacker, Planet* target, CombatInfo& combat_info) { + void AttackPlanetPlanet(Planet* attacker, Planet* target, CombatInfo& combat_info, int round) { Logger().debugStream() << "AttackPlanetPlanet does nothing!"; // intentionally left empty } @@ -678,16 +702,25 @@ int attacker_owner_id = attacker->Owner(); std::map<int, std::set<int> >::iterator target_vec_it = empire_valid_target_object_ids.find(attacker_owner_id); - if (target_vec_it == empire_valid_target_object_ids.end()) { + if (target_vec_it == empire_valid_target_object_ids.end() || target_vec_it->second.empty()) { Logger().debugStream() << "No targets for attacker with id: " << attacker_owner_id; break; } const std::set<int>& valid_target_ids = target_vec_it->second; - if (valid_target_ids.empty()) - break; // should be redundant with this entry being erased when emptied + // DEBUG + std::string id_list; + for (std::set<int>::const_iterator target_it = valid_target_ids.begin(); + target_it != valid_target_ids.end(); ++target_it) + { id_list += boost::lexical_cast<std::string>(*target_it) + " "; } + Logger().debugStream() << "Valid targets for attacker with id: " << attacker_owner_id + << " owned by empire: " << attacker_owner_id + << " : " << id_list; + // END DEBUG + + // select target object SmallIntDistType target_id_num_dist = SmallIntDist(0, valid_target_ids.size() - 1); std::set<int>::const_iterator target_it = valid_target_ids.begin(); @@ -706,18 +739,18 @@ // do actual attacks, and mark attackers as valid targets for attacked object's owners if (attack_ship) { if (Ship* target_ship = universe_object_cast<Ship*>(target)) { - AttackShipShip(attack_ship, weapon_it->part_attack, target_ship, combat_info); + AttackShipShip(attack_ship, weapon_it->part_attack, target_ship, combat_info, round); empire_valid_target_object_ids[target_ship->Owner()].insert(attacker_id); } else if (Planet* target_planet = universe_object_cast<Planet*>(target)) { - AttackShipPlanet(attack_ship, weapon_it->part_attack, target_planet, combat_info); + AttackShipPlanet(attack_ship, weapon_it->part_attack, target_planet, combat_info, round); empire_valid_target_object_ids[target_planet->Owner()].insert(attacker_id); } } else if (attack_planet) { if (Ship* target_ship = universe_object_cast<Ship*>(target)) { - AttackPlanetShip(attack_planet, target_ship, combat_info); + AttackPlanetShip(attack_planet, target_ship, combat_info, round); empire_valid_target_object_ids[target_ship->Owner()].insert(attacker_id); } else if (Planet* target_planet = universe_object_cast<Planet*>(target)) { - AttackPlanetPlanet(attack_planet, target_planet, combat_info); + AttackPlanetPlanet(attack_planet, target_planet, combat_info, round); empire_valid_target_object_ids[target_planet->Owner()].insert(attacker_id); } } @@ -809,4 +842,14 @@ if (GetOptionsDB().Get<bool>("verbose-logging")) Logger().debugStream() << "AutoResolveCombat objects after resolution: " << combat_info.objects.Dump(); + + Logger().debugStream() << "combat event log:"; + for (std::vector<AttackEvent>::const_iterator it = combat_info.combat_events.begin(); + it != combat_info.combat_events.end(); ++it) + { + Logger().debugStream() << "rnd: " << it->round << " : " + << it->attacker_id << " -> " << it->target_id << " : " + << it->damage + << (it->target_destroyed ? " (destroyed)" : ""); + } } |
From: <geo...@us...> - 2013-03-31 13:37:58
|
Revision: 5924 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=5924&view=rev Author: geoffthemedio Date: 2013-03-31 13:37:47 +0000 (Sun, 31 Mar 2013) Log Message: ----------- Tweaked combat attacker and target selection randomization code. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2013-03-31 13:11:04 UTC (rev 5923) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2013-03-31 13:37:47 UTC (rev 5924) @@ -650,9 +650,10 @@ Logger().debugStream() << "Combat at " << system->Name() << " (" << combat_info.system_id << ") Round " << round; // select attacking object in battle - SmallIntDistType attacker_id_num_dist = SmallIntDist(0, valid_attacker_object_ids.size() - 1); + int attacker_idx = RandInt(0, valid_attacker_object_ids.size() - 1); + Logger().debugStream() << "Battle round " << round << " attacker index: " << attacker_idx << " of " << valid_attacker_object_ids.size() - 1; std::set<int>::const_iterator attacker_it = valid_attacker_object_ids.begin(); - std::advance(attacker_it, attacker_id_num_dist()); + std::advance(attacker_it, attacker_idx); assert(attacker_it != valid_attacker_object_ids.end()); int attacker_id = *attacker_it; @@ -720,9 +721,10 @@ // select target object - SmallIntDistType target_id_num_dist = SmallIntDist(0, valid_target_ids.size() - 1); + int target_idx = RandInt(0, valid_target_ids.size() - 1); + Logger().debugStream() << " ... target index: " << target_idx << " of " << valid_target_ids.size() - 1; std::set<int>::const_iterator target_it = valid_target_ids.begin(); - std::advance(target_it, target_id_num_dist()); + std::advance(target_it, target_idx); assert(target_it != valid_target_ids.end()); int target_id = *target_it; |
From: <geo...@us...> - 2013-04-01 00:45:56
|
Revision: 5929 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=5929&view=rev Author: geoffthemedio Date: 2013-04-01 00:45:41 +0000 (Mon, 01 Apr 2013) Log Message: ----------- Made ship shields act as damage reduction instead of additional structure. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2013-03-31 16:48:36 UTC (rev 5928) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2013-04-01 00:45:41 UTC (rev 5929) @@ -261,44 +261,28 @@ namespace { void AttackShipShip(Ship* attacker, float damage, Ship* target, CombatInfo& combat_info, int round) { if (!attacker || ! target) return; - if (damage <= 0.0f) - return; std::set<int>& damaged_object_ids = combat_info.damaged_object_ids; - const ShipDesign* attacker_design = attacker->Design(); - if (!attacker_design) - return; - - Meter* target_shield = target->UniverseObject::GetMeter(METER_SHIELD); Meter* target_structure = target->UniverseObject::GetMeter(METER_STRUCTURE); - if (!target_shield || ! target_structure) { + if (!target_structure) { Logger().errorStream() << "couldn't get target structure or shield meter"; return; } + Meter* target_shield = target->UniverseObject::GetMeter(METER_SHIELD); + float shield = (target_shield ? target_shield->Current() : 0.0f); + Logger().debugStream() << "AttackShipShip: attacker: " << attacker->Name() << " damage: " << damage << " target: " << target->Name() << " shield: " << target_shield->Current() << " structure: " << target_structure->Current(); - // damage shields, limited by shield current value and damage amount. - // remaining damage, if any, above shield current value goes to structure - float shield_damage = std::min(target_shield->Current(), damage); - float structure_damage = 0.0f; - if (shield_damage >= target_shield->Current()) - structure_damage = std::min(target_structure->Current(), damage - shield_damage); + damage = std::max(0.0f, damage - shield); - if (shield_damage > 0 || structure_damage > 0) - damaged_object_ids.insert(target->ID()); - - if (shield_damage > 0) { - target_shield->AddToCurrent(-shield_damage); - Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << shield_damage << " shield damage to Ship " << target->Name() << " (" << target->ID() << ")"; + if (damage > 0.0f) { + target_structure->AddToCurrent(-damage); + Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << damage << " damage to Ship " << target->Name() << " (" << target->ID() << ")"; } - if (structure_damage > 0) { - target_structure->AddToCurrent(-structure_damage); - Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << structure_damage << " structure damage to Ship " << target->Name() << " (" << target->ID() << ")"; - } AttackEvent attack(round, attacker->ID(), target->ID(), damage, (target_structure->Current() <= 0.0f)); @@ -368,12 +352,7 @@ Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << construction_damage << " instrastructure damage to Planet " << target->Name() << " (" << target->ID() << ")"; } - AttackEvent attack; - attack.attacker_id = attacker->ID(); - attack.target_id = target->ID(); - attack.round = round; - attack.damage = damage; - attack.target_destroyed = false; + AttackEvent attack(round, attacker->ID(), target->ID(), damage, false); combat_info.combat_events.push_back(attack); attacker->SetLastTurnActiveInCombat(CurrentTurn()); @@ -383,48 +362,35 @@ void AttackPlanetShip(Planet* attacker, Ship* target, CombatInfo& combat_info, int round) { if (!attacker || ! target) return; - float damage = attacker->UniverseObject::GetMeter(METER_DEFENSE)->Current(); // planet "Defense" meter is actually its attack power - if (damage <= 0.0) - return; + float damage = 0.0f; + const Meter* attacker_damage = attacker->UniverseObject::GetMeter(METER_DEFENSE); + if (attacker_damage) + damage = attacker_damage->Current(); // planet "Defense" meter is actually its attack power std::set<int>& damaged_object_ids = combat_info.damaged_object_ids; - Meter* target_shield = target->UniverseObject::GetMeter(METER_SHIELD); Meter* target_structure = target->UniverseObject::GetMeter(METER_STRUCTURE); - if (!target_shield || ! target_structure) { + if (!target_structure) { Logger().errorStream() << "couldn't get target structure or shield meter"; return; } + Meter* target_shield = target->UniverseObject::GetMeter(METER_SHIELD); + float shield = (target_shield ? target_shield->Current() : 0.0f); + Logger().debugStream() << "AttackPlanetShip: attacker: " << attacker->Name() << " damage: " << damage - << "\ntarget: " << target->Name() << " shield: " << target_shield->Current() + << " target: " << target->Name() << " shield: " << target_shield->Current() << " structure: " << target_structure->Current(); - // damage shields, limited by shield current value and damage amount. - // remaining damage, if any, above shield current value goes to structure - float shield_damage = std::min(target_shield->Current(), damage); - float structure_damage = 0.0f; - if (shield_damage >= target_shield->Current()) - structure_damage = std::min(target_structure->Current(), damage - shield_damage); + damage = std::max(0.0f, damage - shield); - if (shield_damage > 0 || structure_damage > 0) - damaged_object_ids.insert(target->ID()); - - if (shield_damage >= 0) { - target_shield->AddToCurrent(-shield_damage); - Logger().debugStream() << "COMBAT: Planet " << attacker->Name() << " (" << attacker->ID() << ") does " << shield_damage << " shield damage to Ship " << target->Name() << " (" << target->ID() << ")"; + if (damage > 0.0f) { + target_structure->AddToCurrent(-damage); + Logger().debugStream() << "COMBAT: Planet " << attacker->Name() << " (" << attacker->ID() << ") does " << damage << " damage to Ship " << target->Name() << " (" << target->ID() << ")"; } - if (structure_damage >= 0) { - target_structure->AddToCurrent(-structure_damage); - Logger().debugStream() << "COMBAT: Planet " << attacker->Name() << " (" << attacker->ID() << ") does " << structure_damage << " structure damage to Ship " << target->Name() << " (" << target->ID() << ")"; - } - AttackEvent attack; - attack.attacker_id = attacker->ID(); - attack.target_id = target->ID(); - attack.round = round; - attack.damage = damage; - attack.target_destroyed = (target_structure->Current() <= 0.0f); + AttackEvent attack(round, attacker->ID(), target->ID(), damage, + (target_structure->Current() <= 0.0f)); combat_info.combat_events.push_back(attack); target->SetLastTurnActiveInCombat(CurrentTurn()); |
From: <dil...@us...> - 2013-07-18 21:48:28
|
Revision: 6242 http://sourceforge.net/p/freeorion/code/6242 Author: dilvish-fo Date: 2013-07-18 21:48:26 +0000 (Thu, 18 Jul 2013) Log Message: ----------- - a couple planetary combat adjustments -- removes a population requirement that kept outposts from defending themselves -- removes planets from the valid_attacker list once they can no longer attack Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2013-07-18 14:34:16 UTC (rev 6241) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2013-07-18 21:48:26 UTC (rev 6242) @@ -455,8 +455,7 @@ if (const Ship* ship = universe_object_cast<const Ship*>(obj)) { return ship->IsArmed(); } else if (const Planet* planet = universe_object_cast<const Planet*>(obj)) { - return planet->CurrentMeterValue(METER_POPULATION) > 0.0 && - planet->CurrentMeterValue(METER_DEFENSE) > 0.0; + return planet->CurrentMeterValue(METER_DEFENSE) > 0.0; } else { return false; } @@ -753,14 +752,18 @@ } } else if (target->ObjectType() == OBJ_PLANET) { + if (!ObjectCanAttack(target) && valid_attacker_object_ids.find(target_id)!=valid_attacker_object_ids.end()) { + Logger().debugStream() << "!! Target Planet defenses knocked out, can no longer attack"; + // remove disabled planet's ID from lists of valid attackers + valid_attacker_object_ids.erase(target_id); + } if (target->CurrentMeterValue(METER_SHIELD) <= 0.0 && target->CurrentMeterValue(METER_DEFENSE) <= 0.0 && target->CurrentMeterValue(METER_CONSTRUCTION) <= 0.0) { - Logger().debugStream() << "!! Target Planet is knocked out of battle"; + Logger().debugStream() << "!! Target Planet is entirely knocked out of battle"; - // remove disabled planet's ID from lists of valid attackers and targets - valid_attacker_object_ids.erase(target_id); + // remove disabled planet's ID from lists of valid targets valid_target_object_ids.erase(target_id); // probably not necessary as this set isn't used in this loop for (target_vec_it = empire_valid_target_object_ids.begin(); |
From: <dil...@us...> - 2013-09-24 16:40:51
|
Revision: 6422 http://sourceforge.net/p/freeorion/code/6422 Author: dilvish-fo Date: 2013-09-24 16:40:47 +0000 (Tue, 24 Sep 2013) Log Message: ----------- makes most combat debug logging subject to verbose-logging option Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2013-09-21 20:46:35 UTC (rev 6421) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2013-09-24 16:40:47 UTC (rev 6422) @@ -583,11 +583,13 @@ // ensure something can attack and something can be attacked if (valid_attacker_object_ids.empty()) { - Logger().debugStream() << "Nothing left can attack; combat over"; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "Nothing left can attack; combat over"; break; } if (empire_valid_target_object_ids.empty()) { - Logger().debugStream() << "Nothing left can be attacked; combat over"; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "Nothing left can be attacked; combat over"; break; } // empires may have valid targets, but nothing to attack with. If all @@ -602,15 +604,18 @@ } } if (!someone_can_attack_something) { - Logger().debugStream() << "No empire has valid targets and something to attack with; combat over."; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "No empire has valid targets and something to attack with; combat over."; break; } - Logger().debugStream() << "Combat at " << system->Name() << " (" << combat_info.system_id << ") Round " << round; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "Combat at " << system->Name() << " (" << combat_info.system_id << ") Round " << round; // select attacking object in battle int attacker_idx = RandInt(0, valid_attacker_object_ids.size() - 1); - Logger().debugStream() << "Battle round " << round << " attacker index: " << attacker_idx << " of " << valid_attacker_object_ids.size() - 1; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "Battle round " << round << " attacker index: " << attacker_idx << " of " << valid_attacker_object_ids.size() - 1; std::set<int>::const_iterator attacker_it = valid_attacker_object_ids.begin(); std::advance(attacker_it, attacker_idx); assert(attacker_it != valid_attacker_object_ids.end()); @@ -621,7 +626,8 @@ Logger().errorStream() << "AutoResolveCombat couldn't get object with id " << attacker_id; continue; } - Logger().debugStream() << "Attacker: " << attacker->Name(); + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "Attacker: " << attacker->Name(); TemporaryPtr<Ship> attack_ship = universe_object_ptr_cast<Ship>(attacker); @@ -636,15 +642,18 @@ for (std::vector<PartAttackInfo>::const_iterator part_it = weapons.begin(); part_it != weapons.end(); ++part_it) { - Logger().debugStream() << "weapon: " << part_it->part_type_name << + if (GetOptionsDB().Get<bool>("verbose-logging")) { + Logger().debugStream() << "weapon: " << part_it->part_type_name << " attack: " << part_it->part_attack; + } } } else if (attack_planet) { // treat planet defenses as short range weapons.push_back(PartAttackInfo(PC_SHORT_RANGE, "", attack_planet->CurrentMeterValue(METER_DEFENSE))); } if (weapons.empty()) { - Logger().debugStream() << "no weapons' can't attack"; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "no weapons' can't attack"; continue; // no ability to attack! } @@ -652,7 +661,8 @@ weapon_it != weapons.end(); ++weapon_it) { // select object from valid targets for this object's owner TODO: with this weapon... - Logger().debugStream() << "Attacking with weapon " << weapon_it->part_type_name << " with power " << weapon_it->part_attack; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "Attacking with weapon " << weapon_it->part_type_name << " with power " << weapon_it->part_attack; // get valid targets set for attacker owner. need to do this for // each weapon that is attacking, as the previous shot might have @@ -661,7 +671,8 @@ std::map<int, std::set<int> >::iterator target_vec_it = empire_valid_target_object_ids.find(attacker_owner_id); if (target_vec_it == empire_valid_target_object_ids.end() || target_vec_it->second.empty()) { - Logger().debugStream() << "No targets for attacker with id: " << attacker_owner_id; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "No targets for attacker with id: " << attacker_owner_id; break; } @@ -673,15 +684,18 @@ target_it != valid_target_ids.end(); ++target_it) { id_list += boost::lexical_cast<std::string>(*target_it) + " "; } - Logger().debugStream() << "Valid targets for attacker with id: " << attacker_owner_id + if (GetOptionsDB().Get<bool>("verbose-logging")) { + Logger().debugStream() << "Valid targets for attacker with id: " << attacker_owner_id << " owned by empire: " << attacker_owner_id << " : " << id_list; + } // END DEBUG // select target object int target_idx = RandInt(0, valid_target_ids.size() - 1); - Logger().debugStream() << " ... target index: " << target_idx << " of " << valid_target_ids.size() - 1; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << " ... target index: " << target_idx << " of " << valid_target_ids.size() - 1; std::set<int>::const_iterator target_it = valid_target_ids.begin(); std::advance(target_it, target_idx); assert(target_it != valid_target_ids.end()); @@ -692,7 +706,8 @@ Logger().errorStream() << "AutoResolveCombat couldn't get target object with id " << target_id; continue; } - Logger().debugStream() << "Target: " << target->Name(); + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "Target: " << target->Name(); // do actual attacks, and mark attackers as valid targets for attacked object's owners @@ -718,7 +733,8 @@ // check for destruction of target object if (target->ObjectType() == OBJ_SHIP) { if (target->CurrentMeterValue(METER_STRUCTURE) <= 0.0) { - Logger().debugStream() << "!! Target Ship is destroyed!"; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "!! Target Ship is destroyed!"; // object id destroyed combat_info.destroyed_object_ids.insert(target_id); // all empires in battle know object was destroyed @@ -727,7 +743,8 @@ { int empire_id = *it; if (empire_id != ALL_EMPIRES) { - Logger().debugStream() << "Giving knowledge of destroyed object " << target_id << " to empire " << empire_id; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "Giving knowledge of destroyed object " << target_id << " to empire " << empire_id; combat_info.destroyed_object_knowers[empire_id].insert(target_id); } } @@ -747,7 +764,8 @@ } else if (target->ObjectType() == OBJ_PLANET) { if (!ObjectCanAttack(target) && valid_attacker_object_ids.find(target_id)!=valid_attacker_object_ids.end()) { - Logger().debugStream() << "!! Target Planet defenses knocked out, can no longer attack"; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "!! Target Planet defenses knocked out, can no longer attack"; // remove disabled planet's ID from lists of valid attackers valid_attacker_object_ids.erase(target_id); } @@ -755,7 +773,8 @@ target->CurrentMeterValue(METER_DEFENSE) <= 0.0 && target->CurrentMeterValue(METER_CONSTRUCTION) <= 0.0) { - Logger().debugStream() << "!! Target Planet is entirely knocked out of battle"; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "!! Target Planet is entirely knocked out of battle"; // remove disabled planet's ID from lists of valid targets valid_target_object_ids.erase(target_id); // probably not necessary as this set isn't used in this loop @@ -778,7 +797,8 @@ { if (target_vec_it->second.empty()) { temp.erase(target_vec_it->first); - Logger().debugStream() << "No valid targets left for empire with id: " << target_vec_it->first; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "No valid targets left for empire with id: " << target_vec_it->first; } } empire_valid_target_object_ids = temp; @@ -789,7 +809,8 @@ { if (target_vec_it->second.empty()) { temp.erase(target_vec_it->first); - Logger().debugStream() << "No valid attacking objects left for empire with id: " << target_vec_it->first; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "No valid attacking objects left for empire with id: " << target_vec_it->first; } } empire_valid_attacker_object_ids = temp; @@ -805,16 +826,17 @@ it != combat_info.empire_known_objects.end(); ++it) { it->second.Copy(combat_info.objects); } - if (GetOptionsDB().Get<bool>("verbose-logging")) + if (GetOptionsDB().Get<bool>("verbose-logging")) { Logger().debugStream() << "AutoResolveCombat objects after resolution: " << combat_info.objects.Dump(); - Logger().debugStream() << "combat event log:"; - for (std::vector<AttackEvent>::const_iterator it = combat_info.combat_events.begin(); - it != combat_info.combat_events.end(); ++it) - { - Logger().debugStream() << "rnd: " << it->round << " : " - << it->attacker_id << " -> " << it->target_id << " : " - << it->damage - << (it->target_destroyed ? " (destroyed)" : ""); + Logger().debugStream() << "combat event log:"; + for (std::vector<AttackEvent>::const_iterator it = combat_info.combat_events.begin(); + it != combat_info.combat_events.end(); ++it) + { + Logger().debugStream() << "rnd: " << it->round << " : " + << it->attacker_id << " -> " << it->target_id << " : " + << it->damage + << (it->target_destroyed ? " (destroyed)" : ""); + } } } |
From: <dil...@us...> - 2013-09-29 20:25:03
|
Revision: 6425 http://sourceforge.net/p/freeorion/code/6425 Author: dilvish-fo Date: 2013-09-29 20:24:59 +0000 (Sun, 29 Sep 2013) Log Message: ----------- makes more combat logging gated by verbose logging option Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2013-09-27 17:26:44 UTC (rev 6424) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2013-09-29 20:24:59 UTC (rev 6425) @@ -270,7 +270,8 @@ if (damage > 0.0f) { target_structure->AddToCurrent(-damage); damaged_object_ids.insert(target->ID()); - Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << damage << " damage to Ship " << target->Name() << " (" << target->ID() << ")"; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << damage << " damage to Ship " << target->Name() << " (" << target->ID() << ")"; } AttackEvent attack(round, attacker->ID(), target->ID(), damage, @@ -308,10 +309,12 @@ return; } - Logger().debugStream() << "AttackShipPlanet: attacker: " << attacker->Name() << " damage: " << damage + if (GetOptionsDB().Get<bool>("verbose-logging")) { + Logger().debugStream() << "AttackShipPlanet: attacker: " << attacker->Name() << " damage: " << damage << "\ntarget: " << target->Name() << " shield: " << target_shield->Current() << " defense: " << target_defense->Current() << " infra: " << target_construction->Current(); + } // damage shields, limited by shield current value and damage amount. // remaining damage, if any, above shield current value goes to defense. @@ -330,15 +333,18 @@ if (shield_damage >= 0) { target_shield->AddToCurrent(-shield_damage); - Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << shield_damage << " shield damage to Planet " << target->Name() << " (" << target->ID() << ")"; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << shield_damage << " shield damage to Planet " << target->Name() << " (" << target->ID() << ")"; } if (defense_damage >= 0) { target_defense->AddToCurrent(-defense_damage); - Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << defense_damage << " defense damage to Planet " << target->Name() << " (" << target->ID() << ")"; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << defense_damage << " defense damage to Planet " << target->Name() << " (" << target->ID() << ")"; } if (construction_damage >= 0) { target_construction->AddToCurrent(-construction_damage); - Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << construction_damage << " instrastructure damage to Planet " << target->Name() << " (" << target->ID() << ")"; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "COMBAT: Ship " << attacker->Name() << " (" << attacker->ID() << ") does " << construction_damage << " instrastructure damage to Planet " << target->Name() << " (" << target->ID() << ")"; } AttackEvent attack(round, attacker->ID(), target->ID(), damage, false); @@ -367,16 +373,19 @@ Meter* target_shield = target->UniverseObject::GetMeter(METER_SHIELD); float shield = (target_shield ? target_shield->Current() : 0.0f); - Logger().debugStream() << "AttackPlanetShip: attacker: " << attacker->Name() << " damage: " << damage + if (GetOptionsDB().Get<bool>("verbose-logging")) { + Logger().debugStream() << "AttackPlanetShip: attacker: " << attacker->Name() << " damage: " << damage << " target: " << target->Name() << " shield: " << target_shield->Current() << " structure: " << target_structure->Current(); + } damage = std::max(0.0f, damage - shield); if (damage > 0.0f) { target_structure->AddToCurrent(-damage); damaged_object_ids.insert(target->ID()); - Logger().debugStream() << "COMBAT: Planet " << attacker->Name() << " (" << attacker->ID() << ") does " << damage << " damage to Ship " << target->Name() << " (" << target->ID() << ")"; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "COMBAT: Planet " << attacker->Name() << " (" << attacker->ID() << ") does " << damage << " damage to Ship " << target->Name() << " (" << target->ID() << ")"; } AttackEvent attack(round, attacker->ID(), target->ID(), damage, @@ -387,7 +396,8 @@ } void AttackPlanetPlanet(TemporaryPtr<Planet> attacker, TemporaryPtr<Planet> target, CombatInfo& combat_info, int round) { - Logger().debugStream() << "AttackPlanetPlanet does nothing!"; + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "AttackPlanetPlanet does nothing!"; // intentionally left empty } |
From: <geo...@us...> - 2014-05-04 19:59:21
|
Revision: 7114 http://sourceforge.net/p/freeorion/code/7114 Author: geoffthemedio Date: 2014-05-04 19:59:17 +0000 (Sun, 04 May 2014) Log Message: ----------- Patch by Mitten.O refactoring the combat processing code. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2014-05-04 18:39:21 UTC (rev 7113) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2014-05-04 19:59:17 UTC (rev 7114) @@ -233,6 +233,18 @@ // AutoResolveCombat //////////////////////////////////////////////// namespace { + struct PartAttackInfo { + PartAttackInfo(ShipPartClass part_class_, const std::string& part_name_, float part_attack_) : + part_class(part_class_), + part_type_name(part_name_), + part_attack(part_attack_) + {} + ShipPartClass part_class; + std::string part_type_name; + float part_attack; + }; + + void AttackShipShip(TemporaryPtr<Ship> attacker, float damage, TemporaryPtr<Ship> target, CombatInfo& combat_info, int round) { if (!attacker || ! target) return; @@ -381,12 +393,23 @@ target->SetLastTurnActiveInCombat(CurrentTurn()); } - void AttackPlanetPlanet(TemporaryPtr<Planet> attacker, TemporaryPtr<Planet> target, CombatInfo& combat_info, int round) { - if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << "AttackPlanetPlanet does nothing!"; - // intentionally left empty + void Attack(TemporaryPtr<UniverseObject>& attacker, const PartAttackInfo& weapon, TemporaryPtr<UniverseObject>& target, CombatInfo& combat_info, int round){ + TemporaryPtr<Ship> attack_ship = boost::dynamic_pointer_cast<Ship>(attacker); + TemporaryPtr<Planet> attack_planet = boost::dynamic_pointer_cast<Planet>(attacker); + TemporaryPtr<Ship> target_ship = boost::dynamic_pointer_cast<Ship>(target); + TemporaryPtr<Planet> target_planet = boost::dynamic_pointer_cast<Planet>(target); + + if (attack_ship && target_ship) { + AttackShipShip(attack_ship, weapon.part_attack, target_ship, combat_info, round); + } else if (attack_ship && target_planet) { + AttackShipPlanet(attack_ship, weapon.part_attack, target_planet, combat_info, round); + } else if (attack_planet && target_ship) { + AttackPlanetShip(attack_planet, target_ship, combat_info, round); + } else if (attack_planet && target_planet) { + // Planets don't attack each other, silly + } } - + bool ObjectCanBeAttacked(TemporaryPtr<const UniverseObject> obj) { if (!obj) return false; @@ -449,17 +472,6 @@ } } - struct PartAttackInfo { - PartAttackInfo(ShipPartClass part_class_, const std::string& part_name_, float part_attack_) : - part_class(part_class_), - part_type_name(part_name_), - part_attack(part_attack_) - {} - ShipPartClass part_class; - std::string part_type_name; - float part_attack; - }; - std::vector<PartAttackInfo> ShipWeaponsStrengths(TemporaryPtr<const Ship> ship) { std::vector<PartAttackInfo> retval; if (!ship) @@ -492,240 +504,84 @@ } return retval; } -} - -void AutoResolveCombat(CombatInfo& combat_info) { - if (combat_info.objects.Empty()) - return; - - TemporaryPtr<const System> system = combat_info.objects.Object<System>(combat_info.system_id); - if (!system) - Logger().errorStream() << "AutoResolveCombat couldn't get system with id " << combat_info.system_id; - else - Logger().debugStream() << "AutoResolveCombat at " << system->Name(); - - if (GetOptionsDB().Get<bool>("verbose-logging")) { - Logger().debugStream() << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"; - Logger().debugStream() << "AutoResolveCombat objects before resolution: " << combat_info.objects.Dump(); - } - - // reasonably unpredictable but reproducible random seeding - const int base_seed = combat_info.objects.begin()->ID() + CurrentTurn(); - - - // compile list of valid objects to attack or be attacked in this combat - std::set<int> valid_target_object_ids; // all objects that can be attacked - std::set<int> valid_attacker_object_ids; // all objects that can attack - std::map<int, std::set<int> > empire_valid_attacker_object_ids; // objects that can attack that each empire owns - float monster_detection = 0.0; - - for (ObjectMap::iterator<> it = combat_info.objects.begin(); it != combat_info.objects.end(); ++it) { - TemporaryPtr<const UniverseObject> obj = *it; - //Logger().debugStream() << "Considerting object " << obj->Name() << " owned by " << obj->Owner(); - if (ObjectCanAttack(obj)) { - //Logger().debugStream() << "... can attack"; - valid_attacker_object_ids.insert(it->ID()); - empire_valid_attacker_object_ids[obj->Owner()].insert(it->ID()); + + // Information about a single empire during combat + struct EmpireCombatInfo{ + std::set<int> attacker_ids; + std::set<int> target_ids; + + bool HasTargets() const { + return !target_ids.empty(); } - if (ObjectCanBeAttacked(obj)) { - //Logger().debugStream() << "... can be attacked"; - valid_target_object_ids.insert(it->ID()); + + bool HasAttackers() const { + return !attacker_ids.empty(); } - if (obj->Unowned() && obj->ObjectType() == OBJ_SHIP) - monster_detection = std::max(monster_detection, obj->CurrentMeterValue(METER_DETECTION)); + }; + + // Populate lists of things that can attack and be attacked. List attackers also by empire. + void GetAttackersAndTargets(const CombatInfo& combat_info, std::set<int>& valid_target_object_ids, + std::set<int>& valid_attacker_object_ids, std::map<int, EmpireCombatInfo>& empire_infos){ + for (ObjectMap::const_iterator<> it = combat_info.objects.const_begin(); it != combat_info.objects.const_end(); ++it) { + TemporaryPtr<const UniverseObject> obj = *it; + //Logger().debugStream() << "Considerting object " << obj->Name() << " owned by " << obj->Owner(); + if (ObjectCanAttack(obj)) { + //Logger().debugStream() << "... can attack"; + valid_attacker_object_ids.insert(it->ID()); + empire_infos[obj->Owner()].attacker_ids.insert(it->ID()); + } + if (ObjectCanBeAttacked(obj)) { + //Logger().debugStream() << "... can be attacked"; + valid_target_object_ids.insert(it->ID()); + } + } } - - - // map from empire to set of IDs of objects that empire's objects - // could potentially target. - std::map<int, std::set<int> > empire_valid_target_object_ids; // objects that each empire can attack - for (std::set<int>::const_iterator target_it = valid_target_object_ids.begin(); - target_it != valid_target_object_ids.end(); ++target_it) - { - int object_id = *target_it; - TemporaryPtr<const UniverseObject> obj = combat_info.objects.Object(object_id); - //Logger().debugStream() << "Considering attackability of object " << obj->Name() << " owned by " << obj->Owner(); - - // for all empires, can they attack this object? - for (std::set<int>::const_iterator empire_it = combat_info.empire_ids.begin(); - empire_it != combat_info.empire_ids.end(); ++empire_it) - { - int attacking_empire_id = *empire_it; - if (attacking_empire_id == ALL_EMPIRES) { - if (ObjectAttackableByMonsters(obj, monster_detection)) { - //Logger().debugStream() << "object: " << obj->Name() << " attackable by monsters"; - empire_valid_target_object_ids[ALL_EMPIRES].insert(object_id); - } - - } else { - // call function to find if empires can attack objects... - if (ObjectAttackableByEmpire(obj, attacking_empire_id)) { - //Logger().debugStream() << "object: " << obj->Name() << " attackable by empire " << attacking_empire_id; - empire_valid_target_object_ids[attacking_empire_id].insert(object_id); - } + + // Calculate monster detection strength in system + float GetMonsterDetection(const CombatInfo& combat_info) { + float monster_detection = 0.0; + for (ObjectMap::const_iterator<> it = combat_info.objects.const_begin(); it != combat_info.objects.const_end(); ++it) { + TemporaryPtr<const UniverseObject> obj = *it; + if (obj->Unowned() && obj->ObjectType() == OBJ_SHIP){ + monster_detection = std::max(monster_detection, obj->CurrentMeterValue(METER_DETECTION)); } } + return monster_detection; } - - - // Each combat "round" a randomly-selected object in the battle attacks - // something, if it is able to do so. The number of rounds scales with the - // number of objects, so the total actions per object is independent of - // number of objects in the battle - const int NUM_COMBAT_ROUNDS = 3*valid_attacker_object_ids.size(); - - for (int round = 1; round <= NUM_COMBAT_ROUNDS; ++round) { - Seed(base_seed + round); // ensure each combat round produces different results - - // ensure something can attack and something can be attacked - if (valid_attacker_object_ids.empty()) { - if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << "Nothing left can attack; combat over"; - break; - } - if (empire_valid_target_object_ids.empty()) { - if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << "Nothing left can be attacked; combat over"; - break; - } - // empires may have valid targets, but nothing to attack with. If all - // empires have no attackers or no valid targers, combat is over - bool someone_can_attack_something = false; - for (std::map<int, std::set<int> >::const_iterator attacker_it = empire_valid_attacker_object_ids.begin(); - attacker_it != empire_valid_attacker_object_ids.end(); ++attacker_it) + + /// A collection of information the autoresolution must keep around + struct AutoresolveInfo { + typedef std::map<int, EmpireCombatInfo>::iterator empire_it; + + std::set<int> valid_target_object_ids; // all objects that can be attacked + std::set<int> valid_attacker_object_ids; // all objects that can attack + std::map<int, EmpireCombatInfo> empire_infos; // empire specific information + float monster_detection; // monster's detections strength + CombatInfo& combat_info; // a reference to the combat info + + AutoresolveInfo(CombatInfo& combat_info): + combat_info(combat_info) { - if (empire_valid_target_object_ids.find(attacker_it->first) != empire_valid_target_object_ids.end()) { - someone_can_attack_something = true; - break; - } + monster_detection = GetMonsterDetection(combat_info); + PopulateAttackersAndTargets(combat_info); + PopulateEmpireTargets(combat_info); } - if (!someone_can_attack_something) { - if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << "No empire has valid targets and something to attack with; combat over."; - break; + + // Return true if some empire that can attack has some targets that it can attack + bool CanSomeoneAttackSomething() const { + for (std::map<int, EmpireCombatInfo>::const_iterator attacker_it = empire_infos.begin(); + attacker_it != empire_infos.end(); ++attacker_it) + { + if (attacker_it->second.HasTargets() && attacker_it->second.HasAttackers()) { + return true; + } + } + return false; } - - if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << "Combat at " << system->Name() << " (" << combat_info.system_id << ") Round " << round; - - // select attacking object in battle - int attacker_idx = RandInt(0, valid_attacker_object_ids.size() - 1); - if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << "Battle round " << round << " attacker index: " << attacker_idx << " of " << valid_attacker_object_ids.size() - 1; - std::set<int>::const_iterator attacker_it = valid_attacker_object_ids.begin(); - std::advance(attacker_it, attacker_idx); - assert(attacker_it != valid_attacker_object_ids.end()); - int attacker_id = *attacker_it; - - TemporaryPtr<UniverseObject> attacker = combat_info.objects.Object(attacker_id); - if (!attacker) { - Logger().errorStream() << "AutoResolveCombat couldn't get object with id " << attacker_id; - continue; - } - if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << "Attacker: " << attacker->Name(); - - - TemporaryPtr<Ship> attack_ship = boost::dynamic_pointer_cast<Ship>(attacker); - TemporaryPtr<Planet> attack_planet = boost::dynamic_pointer_cast<Planet>(attacker); - - // loop over weapons of attacking object. each gets a shot at a - // randomly selected target object - std::vector<PartAttackInfo> weapons; - - if (attack_ship) { - weapons = ShipWeaponsStrengths(attack_ship); - for (std::vector<PartAttackInfo>::const_iterator part_it = weapons.begin(); - part_it != weapons.end(); ++part_it) - { - if (GetOptionsDB().Get<bool>("verbose-logging")) { - Logger().debugStream() << "weapon: " << part_it->part_type_name - << " attack: " << part_it->part_attack; - } - } - } else if (attack_planet) { // treat planet defenses as short range - weapons.push_back(PartAttackInfo(PC_SHORT_RANGE, "", attack_planet->CurrentMeterValue(METER_DEFENSE))); - } - - if (weapons.empty()) { - if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << "no weapons' can't attack"; - continue; // no ability to attack! - } - - for (std::vector<PartAttackInfo>::const_iterator weapon_it = weapons.begin(); - weapon_it != weapons.end(); ++weapon_it) - { - // select object from valid targets for this object's owner TODO: with this weapon... - if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << "Attacking with weapon " << weapon_it->part_type_name << " with power " << weapon_it->part_attack; - - // get valid targets set for attacker owner. need to do this for - // each weapon that is attacking, as the previous shot might have - // destroyed something - int attacker_owner_id = attacker->Owner(); - - std::map<int, std::set<int> >::iterator target_vec_it = empire_valid_target_object_ids.find(attacker_owner_id); - if (target_vec_it == empire_valid_target_object_ids.end() || target_vec_it->second.empty()) { - if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << "No targets for attacker with id: " << attacker_owner_id; - break; - } - - const std::set<int>& valid_target_ids = target_vec_it->second; - - // DEBUG - std::string id_list; - for (std::set<int>::const_iterator target_it = valid_target_ids.begin(); - target_it != valid_target_ids.end(); ++target_it) - { id_list += boost::lexical_cast<std::string>(*target_it) + " "; } - - if (GetOptionsDB().Get<bool>("verbose-logging")) { - Logger().debugStream() << "Valid targets for attacker with id: " << attacker_owner_id - << " owned by empire: " << attacker_owner_id - << " : " << id_list; - } - // END DEBUG - - - // select target object - int target_idx = RandInt(0, valid_target_ids.size() - 1); - if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << " ... target index: " << target_idx << " of " << valid_target_ids.size() - 1; - std::set<int>::const_iterator target_it = valid_target_ids.begin(); - std::advance(target_it, target_idx); - assert(target_it != valid_target_ids.end()); - int target_id = *target_it; - - TemporaryPtr<UniverseObject> target = combat_info.objects.Object(target_id); - if (!target) { - Logger().errorStream() << "AutoResolveCombat couldn't get target object with id " << target_id; - continue; - } - if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << "Target: " << target->Name(); - - - // do actual attacks, and mark attackers as valid targets for attacked object's owners - if (attack_ship) { - if (TemporaryPtr<Ship> target_ship = boost::dynamic_pointer_cast<Ship>(target)) { - AttackShipShip(attack_ship, weapon_it->part_attack, target_ship, combat_info, round); - empire_valid_target_object_ids[target_ship->Owner()].insert(attacker_id); - } else if (TemporaryPtr<Planet> target_planet = boost::dynamic_pointer_cast<Planet>(target)) { - AttackShipPlanet(attack_ship, weapon_it->part_attack, target_planet, combat_info, round); - empire_valid_target_object_ids[target_planet->Owner()].insert(attacker_id); - } - } else if (attack_planet) { - if (TemporaryPtr<Ship> target_ship = boost::dynamic_pointer_cast<Ship>(target)) { - AttackPlanetShip(attack_planet, target_ship, combat_info, round); - empire_valid_target_object_ids[target_ship->Owner()].insert(attacker_id); - } else if (TemporaryPtr<Planet> target_planet = boost::dynamic_pointer_cast<Planet>(target)) { - AttackPlanetPlanet(attack_planet, target_planet, combat_info, round); - empire_valid_target_object_ids[target_planet->Owner()].insert(attacker_id); - } - } - - + + /// Checks if target is destroyed and if it is, update lists of living objects + void CheckDestruction(TemporaryPtr<UniverseObject>& target) { + int target_id = target->ID(); // check for destruction of target object if (target->ObjectType() == OBJ_SHIP) { if (target->CurrentMeterValue(METER_STRUCTURE) <= 0.0) { @@ -744,73 +600,285 @@ combat_info.destroyed_object_knowers[empire_id].insert(target_id); } } - + // remove destroyed ship's ID from lists of valid attackers and targets valid_attacker_object_ids.erase(target_id); valid_target_object_ids.erase(target_id); // probably not necessary as this set isn't used in this loop - - for (target_vec_it = empire_valid_target_object_ids.begin(); - target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) - { target_vec_it->second.erase(target_id); } - - for (target_vec_it = empire_valid_attacker_object_ids.begin(); - target_vec_it != empire_valid_attacker_object_ids.end(); ++target_vec_it) - { target_vec_it->second.erase(target_id); } // TODO: only erase from owner's entry in this list + + for (empire_it targeter_it = empire_infos.begin(); + targeter_it != empire_infos.end(); ++targeter_it) + { targeter_it->second.target_ids.erase(target_id); } + + // Remove target from its empire's list of attackers + empire_infos[target->Owner()].attacker_ids.erase(target_id); } - + } else if (target->ObjectType() == OBJ_PLANET) { if (!ObjectCanAttack(target) && valid_attacker_object_ids.find(target_id)!=valid_attacker_object_ids.end()) { if (GetOptionsDB().Get<bool>("verbose-logging")) Logger().debugStream() << "!! Target Planet defenses knocked out, can no longer attack"; // remove disabled planet's ID from lists of valid attackers valid_attacker_object_ids.erase(target_id); + } if (target->CurrentMeterValue(METER_SHIELD) <= 0.0 && target->CurrentMeterValue(METER_DEFENSE) <= 0.0 && target->CurrentMeterValue(METER_CONSTRUCTION) <= 0.0) { - if (GetOptionsDB().Get<bool>("verbose-logging")) + if (GetOptionsDB().Get<bool>("verbose-logging")) { Logger().debugStream() << "!! Target Planet is entirely knocked out of battle"; - + } + // remove disabled planet's ID from lists of valid targets valid_target_object_ids.erase(target_id); // probably not necessary as this set isn't used in this loop - - for (target_vec_it = empire_valid_target_object_ids.begin(); - target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) - { target_vec_it->second.erase(target_id); } - - for (target_vec_it = empire_valid_attacker_object_ids.begin(); - target_vec_it != empire_valid_attacker_object_ids.end(); ++target_vec_it) - { target_vec_it->second.erase(target_id); } // TODO: only erase from owner's entry in this list + + for (empire_it targeter_it = empire_infos.begin(); + targeter_it != empire_infos.end(); ++targeter_it) + { targeter_it->second.target_ids.erase(target_id); } + + // Remove target from its empire's list of attackers + empire_infos[target->Owner()].attacker_ids.erase(target_id); } } - - // check if any empire has no remaining target or attacker objects. - // If so, remove that empire's entry - std::map<int, std::set<int> > temp = empire_valid_target_object_ids; - for (target_vec_it = empire_valid_target_object_ids.begin(); - target_vec_it != empire_valid_target_object_ids.end(); ++target_vec_it) + + CleanEmpires(); + } + + /// check if any empire has no remaining target or attacker objects. + /// If so, remove that empire's entry + void CleanEmpires(){ + std::map<int, EmpireCombatInfo> temp = empire_infos; + for (empire_it empire_it = empire_infos.begin(); + empire_it != empire_infos.end(); ++empire_it) { - if (target_vec_it->second.empty()) { - temp.erase(target_vec_it->first); + if (!empire_it->second.HasTargets() && ! empire_it->second.HasAttackers()) { + temp.erase(empire_it->first); if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << "No valid targets left for empire with id: " << target_vec_it->first; + Logger().debugStream() << "No valid attacking objects left for empire with id: " << empire_it->first; } } - empire_valid_target_object_ids = temp; - - temp = empire_valid_attacker_object_ids; - for (target_vec_it = empire_valid_attacker_object_ids.begin(); - target_vec_it != empire_valid_attacker_object_ids.end(); ++target_vec_it) + empire_infos = temp; + } + + private: + typedef std::set<int>::const_iterator const_id_iterator; + + // Populate lists of things that can attack and be attacked. List attackers also by empire. + void PopulateAttackersAndTargets(const CombatInfo& combat_info) { + for (ObjectMap::const_iterator<> it = combat_info.objects.const_begin(); it != combat_info.objects.const_end(); ++it) { + TemporaryPtr<const UniverseObject> obj = *it; + //Logger().debugStream() << "Considerting object " << obj->Name() << " owned by " << obj->Owner(); + if (ObjectCanAttack(obj)) { + //Logger().debugStream() << "... can attack"; + valid_attacker_object_ids.insert(it->ID()); + empire_infos[obj->Owner()].attacker_ids.insert(it->ID()); + } + if (ObjectCanBeAttacked(obj)) { + //Logger().debugStream() << "... can be attacked"; + valid_target_object_ids.insert(it->ID()); + } + } + } + + // Get a map from empire to set of IDs of objects that empire's objects + // could potentially target. + void PopulateEmpireTargets(const CombatInfo& combat_info) { + for (std::set<int>::const_iterator target_it = valid_target_object_ids.begin(); + target_it != valid_target_object_ids.end(); ++target_it) { - if (target_vec_it->second.empty()) { - temp.erase(target_vec_it->first); - if (GetOptionsDB().Get<bool>("verbose-logging")) - Logger().debugStream() << "No valid attacking objects left for empire with id: " << target_vec_it->first; + int object_id = *target_it; + TemporaryPtr<const UniverseObject> obj = combat_info.objects.Object(object_id); + //Logger().debugStream() << "Considering attackability of object " << obj->Name() << " owned by " << obj->Owner(); + + // for all empires, can they attack this object? + for (std::set<int>::const_iterator empire_it = combat_info.empire_ids.begin(); + empire_it != combat_info.empire_ids.end(); ++empire_it) + { + int attacking_empire_id = *empire_it; + if (attacking_empire_id == ALL_EMPIRES) { + if (ObjectAttackableByMonsters(obj, monster_detection)) { + //Logger().debugStream() << "object: " << obj->Name() << " attackable by monsters"; + empire_infos[ALL_EMPIRES].target_ids.insert(object_id); + } + + } else { + // call function to find if empires can attack objects... + if (ObjectAttackableByEmpire(obj, attacking_empire_id)) { + //Logger().debugStream() << "object: " << obj->Name() << " attackable by empire " << attacking_empire_id; + empire_infos[attacking_empire_id].target_ids.insert(object_id); + } + } } } - empire_valid_attacker_object_ids = temp; + } + }; + + + void ShootAllWeapons(TemporaryPtr<UniverseObject>& attacker, const std::vector<PartAttackInfo>& weapons, AutoresolveInfo& combat_state, int round){ + if (weapons.empty()) { + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "no weapons' can't attack"; + return; // no ability to attack! + } + + for (std::vector<PartAttackInfo>::const_iterator weapon_it = weapons.begin(); + weapon_it != weapons.end(); ++weapon_it) + { + // select object from valid targets for this object's owner TODO: with this weapon... + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "Attacking with weapon " << weapon_it->part_type_name << " with power " << weapon_it->part_attack; + + // get valid targets set for attacker owner. need to do this for + // each weapon that is attacking, as the previous shot might have + // destroyed something + int attacker_owner_id = attacker->Owner(); + + std::map<int, EmpireCombatInfo >::iterator target_vec_it = combat_state.empire_infos.find(attacker_owner_id); + if (target_vec_it == combat_state.empire_infos.end() || !target_vec_it->second.HasTargets()) { + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "No targets for attacker with id: " << attacker_owner_id; + break; + } + + const std::set<int>& valid_target_ids = target_vec_it->second.target_ids; + + // DEBUG + std::string id_list; + for (std::set<int>::const_iterator target_it = valid_target_ids.begin(); + target_it != valid_target_ids.end(); ++target_it) + { id_list += boost::lexical_cast<std::string>(*target_it) + " "; } + + if (GetOptionsDB().Get<bool>("verbose-logging")) { + Logger().debugStream() << "Valid targets for attacker with id: " << attacker_owner_id + << " owned by empire: " << attacker_owner_id + << " : " << id_list; + } + // END DEBUG + + + // select target object + int target_idx = RandInt(0, valid_target_ids.size() - 1); + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << " ... target index: " << target_idx << " of " << valid_target_ids.size() - 1; + std::set<int>::const_iterator target_it = valid_target_ids.begin(); + std::advance(target_it, target_idx); + assert(target_it != valid_target_ids.end()); + int target_id = *target_it; + + TemporaryPtr<UniverseObject> target = combat_state.combat_info.objects.Object(target_id); + if (!target) { + Logger().errorStream() << "AutoResolveCombat couldn't get target object with id " << target_id; + continue; + } + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "Target: " << target->Name(); + + + // do actual attacks, and mark attackers as valid targets for attacked object's owners + Attack(attacker, *weapon_it, target, combat_state.combat_info, round); + combat_state.empire_infos[target->Owner()].target_ids.insert(attacker->ID()); + + // Check if the target was destroyed and update lists if yes + combat_state.CheckDestruction(target); } // end for over weapons + } + + + std::vector<PartAttackInfo> GetWeapons(TemporaryPtr<UniverseObject>& attacker){ + // loop over weapons of attacking object. each gets a shot at a + // randomly selected target object + std::vector<PartAttackInfo> weapons; + + TemporaryPtr<Ship> attack_ship = boost::dynamic_pointer_cast<Ship>(attacker); + TemporaryPtr<Planet> attack_planet = boost::dynamic_pointer_cast<Planet>(attacker); + + if (attack_ship) { + weapons = ShipWeaponsStrengths(attack_ship); + for (std::vector<PartAttackInfo>::const_iterator part_it = weapons.begin(); + part_it != weapons.end(); ++part_it) + { + if (GetOptionsDB().Get<bool>("verbose-logging")) { + Logger().debugStream() << "weapon: " << part_it->part_type_name + << " attack: " << part_it->part_attack; + } + } + } else if (attack_planet) { // treat planet defenses as short range + weapons.push_back(PartAttackInfo(PC_SHORT_RANGE, "", attack_planet->CurrentMeterValue(METER_DEFENSE))); + } + return weapons; + } + + void CombatRound(int round, CombatInfo& combat_info, AutoresolveInfo& combat_state) { + + int attacker_idx = RandInt(0, combat_state.valid_attacker_object_ids.size() - 1); + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "Battle round " << round << " attacker index: " << attacker_idx << " of " << combat_state.valid_attacker_object_ids.size() - 1; + std::set<int>::const_iterator attacker_it = combat_state.valid_attacker_object_ids.begin(); + std::advance(attacker_it, attacker_idx); + assert(attacker_it != combat_state.valid_attacker_object_ids.end()); + int attacker_id = *attacker_it; + + TemporaryPtr<UniverseObject> attacker = combat_info.objects.Object(attacker_id); + if (!attacker) { + Logger().errorStream() << "CombatRound couldn't get object with id " << attacker_id; + return; + } + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "Attacker: " << attacker->Name(); + + // loop over weapons of attacking object. each gets a shot at a + // randomly selected target object + std::vector<PartAttackInfo> weapons = GetWeapons(attacker); + + ShootAllWeapons(attacker, weapons, combat_state, round); + } + +} + +void AutoResolveCombat(CombatInfo& combat_info) { + if (combat_info.objects.Empty()) + return; + + TemporaryPtr<const System> system = combat_info.objects.Object<System>(combat_info.system_id); + if (!system) + Logger().errorStream() << "AutoResolveCombat couldn't get system with id " << combat_info.system_id; + else + Logger().debugStream() << "AutoResolveCombat at " << system->Name(); + + if (GetOptionsDB().Get<bool>("verbose-logging")) { + Logger().debugStream() << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"; + Logger().debugStream() << "AutoResolveCombat objects before resolution: " << combat_info.objects.Dump(); + } + + // reasonably unpredictable but reproducible random seeding + const int base_seed = combat_info.objects.begin()->ID() + CurrentTurn(); + + + // compile list of valid objects to attack or be attacked in this combat + AutoresolveInfo combat_state(combat_info); + + + // Each combat "round" a randomly-selected object in the battle attacks + // something, if it is able to do so. The number of rounds scales with the + // number of objects, so the total actions per object is independent of + // number of objects in the battle + const int NUM_COMBAT_ROUNDS = 3*combat_state.valid_attacker_object_ids.size(); + + for (int round = 1; round <= NUM_COMBAT_ROUNDS; ++round) { + Seed(base_seed + round); // ensure each combat round produces different results + + // empires may have valid targets, but nothing to attack with. If all + // empires have no attackers or no valid targers, combat is over + if (!combat_state.CanSomeoneAttackSomething()) { + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "No empire has valid targets and something to attack with; combat over."; + break; + } + + if (GetOptionsDB().Get<bool>("verbose-logging")) + Logger().debugStream() << "Combat at " << system->Name() << " (" << combat_info.system_id << ") Round " << round; + + CombatRound(round, combat_info, combat_state); } // end for over combat arounds // ensure every participant knows what happened. |
From: <geo...@us...> - 2014-07-21 21:15:35
|
Revision: 7280 http://sourceforge.net/p/freeorion/code/7280 Author: geoffthemedio Date: 2014-07-21 21:15:27 +0000 (Mon, 21 Jul 2014) Log Message: ----------- Grooming, hopefully not affecting behaviour. Modified Paths: -------------- trunk/FreeOrion/combat/CombatSystem.cpp Modified: trunk/FreeOrion/combat/CombatSystem.cpp =================================================================== --- trunk/FreeOrion/combat/CombatSystem.cpp 2014-07-21 21:14:32 UTC (rev 7279) +++ trunk/FreeOrion/combat/CombatSystem.cpp 2014-07-21 21:15:27 UTC (rev 7280) @@ -168,12 +168,15 @@ filtered_objects = this->objects; // for now, include all objects in battle / system } -void CombatInfo::GetEmpireKnownObjectsToSerialize(std::map<int, ObjectMap>& filtered_empire_known_objects, int encoding_empire) const { +void CombatInfo::GetEmpireKnownObjectsToSerialize(std::map<int, ObjectMap>& filtered_empire_known_objects, + int encoding_empire) const +{ if (&filtered_empire_known_objects == &this->empire_known_objects) return; - for (std::map<int, ObjectMap>::iterator it = filtered_empire_known_objects.begin(); it != filtered_empire_known_objects.end(); ++it) - it->second.Clear(); + for (std::map<int, ObjectMap>::iterator it = filtered_empire_known_objects.begin(); + it != filtered_empire_known_objects.end(); ++it) + { it->second.Clear(); } filtered_empire_known_objects.clear(); if (encoding_empire == ALL_EMPIRES) { @@ -189,7 +192,9 @@ } } -void CombatInfo::GetDamagedObjectsToSerialize(std::set<int>& filtered_damaged_objects, int encoding_empire) const { +void CombatInfo::GetDamagedObjectsToSerialize(std::set<int>& filtered_damaged_objects, + int encoding_empire) const +{ if (encoding_empire == ALL_EMPIRES) { filtered_damaged_objects = this->damaged_object_ids; return; @@ -198,7 +203,9 @@ filtered_damaged_objects = this->damaged_object_ids; } -void CombatInfo::GetDestroyedObjectsToSerialize(std::set<int>& filtered_destroyed_objects, int encoding_empire) const { +void CombatInfo::GetDestroyedObjectsToSerialize(std::set<int>& filtered_destroyed_objects, + int encoding_empire) const +{ if (encoding_empire == ALL_EMPIRES) { filtered_destroyed_objects = this->destroyed_object_ids; return; @@ -208,7 +215,8 @@ } void CombatInfo::GetDestroyedObjectKnowersToSerialize(std::map<int, std::set<int> >& - filtered_destroyed_object_knowers, int encoding_empire) const + filtered_destroyed_object_knowers, + int encoding_empire) const { if (encoding_empire == ALL_EMPIRES) { filtered_destroyed_object_knowers = this->destroyed_object_knowers; @@ -226,7 +234,7 @@ } void CombatInfo::GetEmpireObjectVisibilityToSerialize(Universe::EmpireObjectVisibilityMap& - filtered_empire_object_visibility, + filtered_empire_object_visibility, int encoding_empire) const { filtered_empire_object_visibility = this->empire_object_visibility; @@ -246,8 +254,7 @@ std::string part_type_name; float part_attack; }; - - + void AttackShipShip(TemporaryPtr<Ship> attacker, float damage, TemporaryPtr<Ship> target, CombatInfo& combat_info, int bout, int round) { if (!attacker || ! target) return; @@ -392,11 +399,11 @@ } void Attack(TemporaryPtr<UniverseObject>& attacker, const PartAttackInfo& weapon, TemporaryPtr<UniverseObject>& target, CombatInfo& combat_info, int bout, int round){ - TemporaryPtr<Ship> attack_ship = boost::dynamic_pointer_cast<Ship>(attacker); - TemporaryPtr<Planet> attack_planet = boost::dynamic_pointer_cast<Planet>(attacker); - TemporaryPtr<Ship> target_ship = boost::dynamic_pointer_cast<Ship>(target); - TemporaryPtr<Planet> target_planet = boost::dynamic_pointer_cast<Planet>(target); - + TemporaryPtr<Ship> attack_ship = boost::dynamic_pointer_cast<Ship>(attacker); + TemporaryPtr<Planet> attack_planet = boost::dynamic_pointer_cast<Planet>(attacker); + TemporaryPtr<Ship> target_ship = boost::dynamic_pointer_cast<Ship>(target); + TemporaryPtr<Planet> target_planet = boost::dynamic_pointer_cast<Planet>(target); + if (attack_ship && target_ship) { AttackShipShip(attack_ship, weapon.part_attack, target_ship, combat_info, bout, round); } else if (attack_ship && target_planet) { @@ -407,21 +414,23 @@ // Planets don't attack each other, silly } } - + bool ObjectCanBeAttacked(TemporaryPtr<const UniverseObject> obj) { if (!obj) return false; + UniverseObjectType obj_type = obj->ObjectType(); - if (obj_type == OBJ_SHIP) { + + if (obj_type == OBJ_SHIP) return true; - } else if (obj_type == OBJ_PLANET) { + + if (obj_type == OBJ_PLANET) { if (!obj->Unowned() || obj->CurrentMeterValue(METER_POPULATION) > 0.0f) return true; - else - return false; - } else { return false; } + + return false; } bool ObjectAttackableByEmpire(TemporaryPtr<const UniverseObject> obj, int empire_id) { @@ -502,24 +511,20 @@ } return retval; } - + // Information about a single empire during combat struct EmpireCombatInfo{ std::set<int> attacker_ids; std::set<int> target_ids; - - bool HasTargets() const { - return !target_ids.empty(); - } - - bool HasAttackers() const { - return !attacker_ids.empty(); - } + bool HasTargets() const { return !target_ids.empty(); } + bool HasAttackers() const { return !attacker_ids.empty(); } }; - + // Populate lists of things that can attack and be attacked. List attackers also by empire. void GetAttackersAndTargets(const CombatInfo& combat_info, std::set<int>& valid_target_object_ids, - std::set<int>& valid_attacker_object_ids, std::map<int, EmpireCombatInfo>& empire_infos) { + std::set<int>& valid_attacker_object_ids, + std::map<int, EmpireCombatInfo>& empire_infos) + { for (ObjectMap::const_iterator<> it = combat_info.objects.const_begin(); it != combat_info.objects.const_end(); ++it) { TemporaryPtr<const UniverseObject> obj = *it; //Logger().debugStream() << "Considerting object " << obj->Name() << " owned by " << obj->Owner(); @@ -534,7 +539,7 @@ } } } - + // Calculate monster detection strength in system float GetMonsterDetection(const CombatInfo& combat_info) { float monster_detection = 0.0; @@ -546,17 +551,17 @@ } return monster_detection; } - + /// A collection of information the autoresolution must keep around struct AutoresolveInfo { typedef std::map<int, EmpireCombatInfo>::iterator empire_it; - - std::set<int> valid_target_object_ids; // all objects that can be attacked - std::set<int> valid_attacker_object_ids; // all objects that can attack - std::map<int, EmpireCombatInfo> empire_infos; // empire specific information - float monster_detection; // monster's detections strength - CombatInfo& combat_info; // a reference to the combat info - + + std::set<int> valid_target_object_ids; // all objects that can be attacked + std::set<int> valid_attacker_object_ids; // all objects that can attack + std::map<int, EmpireCombatInfo> empire_infos; // empire specific information + float monster_detection; // monster's detections strength + CombatInfo& combat_info; // a reference to the combat info + AutoresolveInfo(CombatInfo& combat_info): combat_info(combat_info) { @@ -564,39 +569,38 @@ PopulateAttackersAndTargets(combat_info); PopulateEmpireTargets(combat_info); } - + // Return true if some empire that can attack has some targets that it can attack bool CanSomeoneAttackSomething() const { for (std::map<int, EmpireCombatInfo>::const_iterator attacker_it = empire_infos.begin(); attacker_it != empire_infos.end(); ++attacker_it) - { - if (attacker_it->second.HasTargets() && attacker_it->second.HasAttackers()) { - return true; - } - } - return false; + { + if (attacker_it->second.HasTargets() && attacker_it->second.HasAttackers()) + return true; + } + return false; } - + /// Removes dead units from lists of attackers and defenders - void CullTheDead ( int bout ) { - for ( ObjectMap::const_iterator<> it = combat_info.objects.const_begin(); it != combat_info.objects.const_end(); ++it ) { + void CullTheDead(int bout) { + for (ObjectMap::const_iterator<> it = combat_info.objects.const_begin(); + it != combat_info.objects.const_end(); ++it) + { TemporaryPtr<const UniverseObject> obj = *it; - - // There may be objects, for example unowned planets, that were no a part of the battle to start with. - // Ignore them - if ( valid_attacker_object_ids.find ( obj->ID() ) == valid_attacker_object_ids.end() && - valid_target_object_ids.find(obj->ID()) == valid_target_object_ids.end()){ - continue; - } - + + // There may be objects, for example unowned planets, that were + // not a part of the battle to start with. Ignore them + if (valid_attacker_object_ids.find(obj->ID()) == valid_attacker_object_ids.end() && + valid_target_object_ids.find(obj->ID()) == valid_target_object_ids.end()) + { continue; } + // Check if the target was destroyed and update lists if yes bool destroyed = CheckDestruction(obj); - if ( destroyed ) { + if (destroyed) combat_info.combat_events.push_back(boost::make_shared<IncapacitationEvent>(bout, obj->ID())); - } } } - + /// Checks if target is destroyed and if it is, update lists of living objects. /// Return true if is incapacitated bool CheckDestruction(const TemporaryPtr<const UniverseObject>& target) { @@ -633,14 +637,15 @@ CleanEmpires(); return true; } - + } else if (target->ObjectType() == OBJ_PLANET) { - if (!ObjectCanAttack(target) && valid_attacker_object_ids.find(target_id)!=valid_attacker_object_ids.end()) { + if (!ObjectCanAttack(target) && + valid_attacker_object_ids.find(target_id) != valid_attacker_object_ids.end()) + { if (GetOptionsDB().Get<bool>("verbose-logging")) Logger().debugStream() << "!! Target Planet defenses knocked out, can no longer attack"; // remove disabled planet's ID from lists of valid attackers valid_attacker_object_ids.erase(target_id); - } if (target->CurrentMeterValue(METER_SHIELD) <= 0.0 && target->CurrentMeterValue(METER_DEFENSE) <= 0.0 && @@ -649,28 +654,28 @@ if (GetOptionsDB().Get<bool>("verbose-logging")) { Logger().debugStream() << "!! Target Planet is entirely knocked out of battle"; } - + // remove disabled planet's ID from lists of valid targets valid_target_object_ids.erase(target_id); // probably not necessary as this set isn't used in this loop - + for (empire_it targeter_it = empire_infos.begin(); targeter_it != empire_infos.end(); ++targeter_it) { targeter_it->second.target_ids.erase(target_id); } - + // Remove target from its empire's list of attackers empire_infos[target->Owner()].attacker_ids.erase(target_id); - + CleanEmpires(); return true; } } - + return false; } - + /// check if any empire has no remaining target or attacker objects. /// If so, remove that empire's entry - void CleanEmpires(){ + void CleanEmpires() { std::map<int, EmpireCombatInfo> temp = empire_infos; for (empire_it empire_it = empire_infos.begin(); empire_it != empire_infos.end(); ++empire_it) @@ -683,14 +688,14 @@ } empire_infos = temp; } - + /// Returns the list of attacker ids in a random order void GiveAttackersShuffled(std::vector<int>& shuffled) { shuffled.clear(); shuffled.insert(shuffled.begin(), valid_attacker_object_ids.begin(), valid_attacker_object_ids.end()); - + const unsigned swaps = shuffled.size(); - for(unsigned i = 0; i < swaps; ++i){ + for (unsigned i = 0; i < swaps; ++i){ int pos1 = RandInt(0, shuffled.size() - 1); int pos2 = RandInt(0, shuffled.size() - 1); std::swap(shuffled[pos1], shuffled[pos2]); @@ -698,7 +703,7 @@ } private: typedef std::set<int>::const_iterator const_id_iterator; - + // Populate lists of things that can attack and be attacked. List attackers also by empire. void PopulateAttackersAndTargets(const CombatInfo& combat_info) { for (ObjectMap::const_iterator<> it = combat_info.objects.const_begin(); it != combat_info.objects.const_end(); ++it) { @@ -715,7 +720,7 @@ } } } - + // Get a map from empire to set of IDs of objects that empire's objects // could potentially target. void PopulateEmpireTargets(const CombatInfo& combat_info) { @@ -724,23 +729,22 @@ { int object_id = *target_it; TemporaryPtr<const UniverseObject> obj = combat_info.objects.Object(object_id); - //Logger().debugStream() << "Considering attackability of object " << obj->Name() << " owned by " << obj->Owner(); - + // Logger().debugStream() << "Considering attackability of object " << obj->Name() << " owned by " << obj->Owner(); + // for all empires, can they attack this object? for (std::set<int>::const_iterator empire_it = combat_info.empire_ids.begin(); - empire_it != combat_info.empire_ids.end(); ++empire_it) + empire_it != combat_info.empire_ids.end(); ++empire_it) { int attacking_empire_id = *empire_it; if (attacking_empire_id == ALL_EMPIRES) { if (ObjectAttackableByMonsters(obj, monster_detection)) { - //Logger().debugStream() << "object: " << obj->Name() << " attackable by monsters"; + // Logger().debugStream() << "object: " << obj->Name() << " attackable by monsters"; empire_infos[ALL_EMPIRES].target_ids.insert(object_id); } - + } else { - // call function to find if empires can attack objects... if (ObjectAttackableByEmpire(obj, attacking_empire_id)) { - //Logger().debugStream() << "object: " << obj->Name() << " attackable by empire " << attacking_empire_id; + // Logger().debugStream() << "object: " << obj->Name() << " attackable by empire " << attacking_empire_id; empire_infos[attacking_empire_id].target_ids.insert(object_id); } } @@ -748,50 +752,52 @@ } } }; - - - void ShootAllWeapons(TemporaryPtr<UniverseObject>& attacker, const std::vector<PartAttackInfo>& weapons, AutoresolveInfo& combat_state, int bout, int round) { + + void ShootAllWeapons(TemporaryPtr<UniverseObject>& attacker, + const std::vector<PartAttackInfo>& weapons, + AutoresolveInfo& combat_state, + int bout, int round) + { if (weapons.empty()) { if (GetOptionsDB().Get<bool>("verbose-logging")) Logger().debugStream() << "no weapons' can't attack"; return; // no ability to attack! } - + for (std::vector<PartAttackInfo>::const_iterator weapon_it = weapons.begin(); weapon_it != weapons.end(); ++weapon_it) { // select object from valid targets for this object's owner TODO: with this weapon... if (GetOptionsDB().Get<bool>("verbose-logging")) Logger().debugStream() << "Attacking with weapon " << weapon_it->part_type_name << " with power " << weapon_it->part_attack; - + // get valid targets set for attacker owner. need to do this for // each weapon that is attacking, as the previous shot might have // destroyed something int attacker_owner_id = attacker->Owner(); - + std::map<int, EmpireCombatInfo >::iterator target_vec_it = combat_state.empire_infos.find(attacker_owner_id); if (target_vec_it == combat_state.empire_infos.end() || !target_vec_it->second.HasTargets()) { if (GetOptionsDB().Get<bool>("verbose-logging")) Logger().debugStream() << "No targets for attacker with id: " << attacker_owner_id; break; } - + const std::set<int>& valid_target_ids = target_vec_it->second.target_ids; - + // DEBUG std::string id_list; for (std::set<int>::const_iterator target_it = valid_target_ids.begin(); - target_it != valid_target_ids.end(); ++target_it) + target_it != valid_target_ids.end(); ++target_it) { id_list += boost::lexical_cast<std::string>(*target_it) + " "; } - + if (GetOptionsDB().Get<bool>("verbose-logging")) { Logger().debugStream() << "Valid targets for attacker with id: " << attacker_owner_id << " owned by empire: " << attacker_owner_id << " : " << id_list; } // END DEBUG - - + // select target object int target_idx = RandInt(0, valid_target_ids.size() - 1); if (GetOptionsDB().Get<bool>("verbose-logging")) @@ -800,7 +806,7 @@ std::advance(target_it, target_idx); assert(target_it != valid_target_ids.end()); int target_id = *target_it; - + TemporaryPtr<UniverseObject> target = combat_state.combat_info.objects.Object(target_id); if (!target) { Logger().errorStream() << "AutoResolveCombat couldn't get target object with id " << target_id; @@ -808,24 +814,25 @@ } if (GetOptionsDB().Get<bool>("verbose-logging")) Logger().debugStream() << "Target: " << target->Name(); - - - // do actual attacks, and mark attackers as valid targets for attacked object's owners + + // do actual attacks Attack(attacker, *weapon_it, target, combat_state.combat_info, bout, round); + + // mark attackers as valid targets for attacked object's owners, so + // attacker they can be counter-attacked in subsequent rounds if it + // was not already attackable combat_state.empire_infos[target->Owner()].target_ids.insert(attacker->ID()); - } // end for over weapons } - - + std::vector<PartAttackInfo> GetWeapons(TemporaryPtr<UniverseObject>& attacker) { // loop over weapons of attacking object. each gets a shot at a // randomly selected target object std::vector<PartAttackInfo> weapons; - + TemporaryPtr<Ship> attack_ship = boost::dynamic_pointer_cast<Ship>(attacker); TemporaryPtr<Planet> attack_planet = boost::dynamic_pointer_cast<Planet>(attacker); - + if (attack_ship) { weapons = ShipWeaponsStrengths(attack_ship); for (std::vector<PartAttackInfo>::const_iterator part_it = weapons.begin(); @@ -833,7 +840,7 @@ { if (GetOptionsDB().Get<bool>("verbose-logging")) { Logger().debugStream() << "weapon: " << part_it->part_type_name - << " attack: " << part_it->part_attack; + << " attack: " << part_it->part_attack; } } } else if (attack_planet) { // treat planet defenses as short range @@ -841,24 +848,25 @@ } return weapons; } - + void CombatRound(int bout, CombatInfo& combat_info, AutoresolveInfo& combat_state) { - combat_info.combat_events.push_back(boost::make_shared<BoutBeginEvent>(bout)); - + std::vector<int> shuffled_attackers; combat_state.GiveAttackersShuffled(shuffled_attackers); - + int round = 1; - + // Planets are processed first so that they still have full power as intended, // despite their attack power depending on a thing (defence meter) // processing shots at them may reduce. - for(std::vector<int>::iterator attacker_it = shuffled_attackers.begin(); attacker_it != shuffled_attackers.end(); ++attacker_it) { + for (std::vector<int>::iterator attacker_it = shuffled_attackers.begin(); + attacker_it != shuffled_attackers.end(); ++attacker_it) + { int attacker_id = *attacker_it; - + TemporaryPtr<UniverseObject> attacker = combat_info.objects.Object(attacker_id); - + if (!attacker) { Logger().errorStream() << "CombatRound couldn't get object with id " << attacker_id; return; @@ -872,16 +880,18 @@ } if (GetOptionsDB().Get<bool>("verbose-logging")) Logger().debugStream() << "Planet: " << attacker->Name(); - + std::vector<PartAttackInfo> weapons = GetWeapons(attacker); ShootAllWeapons(attacker, weapons, combat_state, bout, round++); } - - for(std::vector<int>::iterator attacker_it = shuffled_attackers.begin(); attacker_it != shuffled_attackers.end(); ++attacker_it) { + + for (std::vector<int>::iterator attacker_it = shuffled_attackers.begin(); + attacker_it != shuffled_attackers.end(); ++attacker_it) + { int attacker_id = *attacker_it; - + TemporaryPtr<UniverseObject> attacker = combat_info.objects.Object(attacker_id); - + if (!attacker) { Logger().errorStream() << "CombatRound couldn't get object with id " << attacker_id; return; @@ -895,17 +905,16 @@ } if (GetOptionsDB().Get<bool>("verbose-logging")) Logger().debugStream() << "Attacker: " << attacker->Name(); - + // loop over weapons of the attacking object. each gets a shot at a // randomly selected target object std::vector<PartAttackInfo> weapons = GetWeapons(attacker); ShootAllWeapons(attacker, weapons, combat_state, bout, round++); } - + /// Remove all who died in the bout combat_state.CullTheDead(bout); } - } void AutoResolveCombat(CombatInfo& combat_info) { @@ -931,7 +940,7 @@ AutoresolveInfo combat_state(combat_info); - // Each combat "bout" all attackers get turns in a random order + // Each combat "bout" all attackers attack one target (if any are available) const int NUM_COMBAT_BOUTS = 3; for (int bout = 1; bout <= NUM_COMBAT_BOUTS; ++bout) { @@ -965,9 +974,7 @@ Logger().debugStream() << "combat event log:"; for (std::vector<CombatEventPtr>::const_iterator it = combat_info.combat_events.begin(); - it != combat_info.combat_events.end(); ++it) - { - Logger().debugStream() << (*it)->DebugString(); - } + it != combat_info.combat_events.end(); ++it) + { Logger().debugStream() << (*it)->DebugString(); } } } |