/*
* Copyright 2010-2016 OpenXcom Developers.
*
* This file is part of OpenXcom.
*
* OpenXcom is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenXcom is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenXcom. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "AlienStrategy.h"
#include "WeightedOptions.h"
#include "../Mod/Mod.h"
#include "../Mod/RuleRegion.h"
namespace OpenXcom
{
typedef std::map<std::string, WeightedOptions*> MissionsByRegion;
/**
* Create an AlienStrategy with no values.
* Running a game like this will most likely crash.
*/
AlienStrategy::AlienStrategy()
{
// Empty by design!
}
/**
* Free all resources used by this AlienStrategy.
*/
AlienStrategy::~AlienStrategy()
{
// Free allocated memory.
for (MissionsByRegion::iterator ii = _regionMissions.begin(); ii != _regionMissions.end(); ++ii)
{
delete ii->second;
}
}
/**
* Get starting values from the rules.
* @param mod Pointer to the game mod.
*/
void AlienStrategy::init(const Mod *mod)
{
std::vector<std::string> regions = mod->getRegionsList();
for (std::vector<std::string>::const_iterator rr = regions.begin(); rr != regions.end(); ++rr)
{
RuleRegion *region = mod->getRegion(*rr, true);
_regionChances.set(*rr, region->getWeight());
WeightedOptions *missions = new WeightedOptions(region->getAvailableMissions());
_regionMissions.insert(std::make_pair(*rr, missions));
}
}
/**
* Loads the data from a YAML file.
* @param node YAML node.
*/
void AlienStrategy::load(const YAML::Node &node)
{
// Free allocated memory.
for (MissionsByRegion::iterator ii = _regionMissions.begin(); ii != _regionMissions.end(); ++ii)
{
delete ii->second;
}
_regionMissions.clear();
_regionChances.clear();
_regionChances.load(node["regions"]);
const YAML::Node &strat = node["possibleMissions"];
for (YAML::const_iterator nn = strat.begin(); nn != strat.end(); ++nn)
{
std::string region = (*nn)["region"].as<std::string>();
const YAML::Node &missions = (*nn)["missions"];
WeightedOptions *options = new WeightedOptions();
options->load(missions);
_regionMissions.insert(std::make_pair(region, options));
}
_missionLocations = node["missionLocations"].as< std::map<std::string, std::vector<std::pair<std::string, int> > > >(_missionLocations);
_missionRuns = node["missionsRun"].as< std::map<std::string, int> >(_missionRuns);
}
/**
* Saves the alien data to a YAML file.
* @return YAML node.
*/
YAML::Node AlienStrategy::save() const
{
YAML::Node node;
node["regions"] = _regionChances.save();
for (MissionsByRegion::const_iterator ii = _regionMissions.begin(); ii != _regionMissions.end(); ++ii)
{
YAML::Node subnode;
subnode["region"] = ii->first;
subnode["missions"] = ii->second->save();
node["possibleMissions"].push_back(subnode);
}
node["missionLocations"] = _missionLocations;
node["missionsRun"] = _missionRuns;
return node;
}
/**
* Choose one of the regions for a mission.
* @param mod Pointer to the mod.
* @return The region id.
*/
std::string AlienStrategy::chooseRandomRegion(const Mod *mod)
{
std::string chosen = _regionChances.choose();
if (chosen.empty())
{
// no more missions to choose from: refresh.
// First, free allocated memory.
for (MissionsByRegion::iterator ii = _regionMissions.begin(); ii != _regionMissions.end(); ++ii)
{
delete ii->second;
}
_regionMissions.clear();
// re-initialize the list
init(mod);
// now let's try that again.
chosen = _regionChances.choose();
}
assert ("" != chosen);
return chosen;
}
/**
* Choose one missions available for @a region.
* @param region The region id.
* @return The mission id.
*/
std::string AlienStrategy::chooseRandomMission(const std::string ®ion) const
{
MissionsByRegion::const_iterator found = _regionMissions.find(region);
assert(found != _regionMissions.end());
return found->second->choose();
}
/**
* Remove @a mission from the list of possible missions for @a region.
* @param region The region id.
* @param mission The mission id.
* @return If there are no more regions with missions available.
*/
bool AlienStrategy::removeMission(const std::string ®ion, const std::string &mission)
{
MissionsByRegion::iterator found = _regionMissions.find(region);
if (found != _regionMissions.end())
{
found->second->set(mission, 0);
if (found->second->empty())
{
_regionMissions.erase(found);
_regionChances.set(region, 0);
}
}
return _regionMissions.empty();
}
/**
* Checks the number of missions run labelled as "varName".
* @return the number of missions run under the variable name.
*/
int AlienStrategy::getMissionsRun(const std::string &varName)
{
if (_missionRuns.find(varName) != _missionRuns.end())
return _missionRuns[varName];
return 0;
}
/**
* Increments the number of missions run labelled as "varName".
* @param varName the variable name that we want to use to keep track of this.
* @param increment the value to increment by.
*/
void AlienStrategy::addMissionRun(const std::string &varName, int increment)
{
if (varName.empty())
return;
_missionRuns[varName] += increment;
}
/**
* Adds a mission location to our storage array.
* @param varName the name on the variable under which to store this info.
* @param regionName the name of the region we're using.
* @param zoneNumber the number of the zone within that region we're using.
* @param maximum the maximum size of the list we want to maintain.
*/
void AlienStrategy::addMissionLocation(const std::string &varName, const std::string ®ionName, int zoneNumber, int maximum)
{
if (maximum <= 0) return;
_missionLocations[varName].push_back(std::make_pair(regionName, zoneNumber));
if (_missionLocations[varName].size() > (size_t)(maximum))
{
_missionLocations.erase(_missionLocations.begin());
}
}
/**
* Checks that a given mission location (city or whatever) isn't stored in our list of previously attacked locations.
* @param varName the name of the variable that is storing our data.
* @param regionName the name of the region we're looking for.
* @param zoneNumber the number in the region that we want to check.
* @return if the region is valid (meaning it is not in our table).
*/
bool AlienStrategy::validMissionLocation(const std::string &varName, const std::string ®ionName, int zoneNumber)
{
if (_missionLocations.find(varName) != _missionLocations.end())
{
for (std::vector<std::pair<std::string, int> >::const_iterator i = _missionLocations[varName].begin();
i != _missionLocations[varName].end();
++i)
{
if ((*i).first == regionName && (*i).second == zoneNumber)
return false;
}
}
return true;
}
/**
* Checks that a given region appears in our strategy table.
* @param region the region we want to check for validity.
* @return if the region appears in the table or not.
*/
bool AlienStrategy::validMissionRegion(const std::string ®ion)
{
std::map<std::string, WeightedOptions*>::iterator i = _regionMissions.find(region);
return (i != _regionMissions.end());
}
}
↑ V823 Decreased performance. Object may be created in-place in the '_regionMissions' container. Consider replacing methods: 'insert' -> 'emplace'.
↑ V823 Decreased performance. Object may be created in-place in the '_regionMissions' container. Consider replacing methods: 'insert' -> 'emplace'.
↑ V823 Decreased performance. Object may be created in-place in the '_missionLocations[varName]' container. Consider replacing methods: 'push_back' -> 'emplace_back'.
↑ V832 It's better to use '= default;' syntax instead of empty constructor body.
↑ V815 Decreased performance. Consider replacing the expression 'chosen != ""' with '!chosen.empty()'.