1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
|
#include "DifficultySettingsManager.h"
#include "ieclass.h"
#include "itextstream.h"
#include "entitylib.h"
#include "gamelib.h"
#include "maplib.h"
#include "string/string.h"
#include "registry/registry.h"
#include "DifficultyEntity.h"
#include "DifficultyEntityFinder.h"
namespace difficulty {
DifficultySettingsPtr DifficultySettingsManager::getSettings(int level) {
for (std::size_t i = 0; i < _settings.size(); i++) {
if (_settings[i]->getLevel() == level) {
return _settings[i];
}
}
return DifficultySettingsPtr();
}
void DifficultySettingsManager::loadSettings() {
loadDefaultSettings();
loadMapSettings();
loadDifficultyNames();
}
void DifficultySettingsManager::loadDefaultSettings() {
// Try to lookup the given entityDef
IEntityClassPtr eclass = GlobalEntityClassManager().findClass(
game::current::getValue<std::string>(GKEY_DIFFICULTY_ENTITYDEF_DEFAULT)
);
if (eclass == NULL) {
rError() << "Could not find default difficulty settings entityDef.\n";
return;
}
// greebo: Setup the default difficulty levels using the found entityDef
int numLevels = game::current::getValue<int>(GKEY_DIFFICULTY_LEVELS);
for (int i = 0; i < numLevels; i++) {
// Allocate a new settings object
DifficultySettingsPtr settings(new DifficultySettings(i));
// Parse the settings from the given default settings entityDef
settings->parseFromEntityDef(eclass);
// Store the settings object in the local list
_settings.push_back(settings);
}
}
void DifficultySettingsManager::loadMapSettings()
{
// Construct a helper walker
DifficultyEntityFinder finder;
GlobalSceneGraph().root()->traverse(finder);
const DifficultyEntityFinder::EntityList& found = finder.getEntities();
// Pop all entities into each difficulty setting
for (DifficultyEntityFinder::EntityList::const_iterator ent = found.begin();
ent != found.end(); ent++)
{
for (std::size_t i = 0; i < _settings.size(); i++) {
_settings[i]->parseFromMapEntity(*ent);
}
}
}
namespace
{
// Class to manage mod-specific difficulty names (which are probably string
// table entries like "#str_000300") and their English translations (we
// maintain these translations separately in the .game file since we don't have
// any support for parsing the mod-specific translation data).
class ModDifficultyNames
{
// Lookup table of strings and their translations
std::map<std::string, std::string> _transStrings;
// Mod-specific entity giving default difficulty names
IEntityClassPtr _menuEclass;
public:
// Construct and initialise
ModDifficultyNames()
: _menuEclass(
GlobalEntityClassManager().findClass(
game::current::getValue<std::string>(GKEY_DIFFICULTY_ENTITYDEF_MENU)
)
)
{
// Load translations from xml nodes in the .game file
xml::NodeList transNodes = game::current::getNodes(
GKEY_DIFFICULTY_ENTITYDEF_MENU + "/string"
);
for (auto xmlNode: transNodes)
{
_transStrings[xmlNode.getAttributeValue("id")] = xmlNode.getContent();
}
}
// Return the translated name for the difficulty level identified by the
// given key (e.g. the translated name for "diff0Default" might be "Easy").
std::string getNameForKey(const std::string& nameKey) const
{
if (_menuEclass)
{
std::string rawName = _menuEclass->getAttributeValue(nameKey);
if (!rawName.empty())
{
// Look for a translation, otherwise use the raw name
auto found = _transStrings.find(rawName);
if (found != _transStrings.end())
return found->second;
else
return rawName;
}
}
return "";
}
};
// Return key for a difficulty level name
std::string diffNameKeyForLevel(int level)
{
return "diff" + std::to_string(level) + "default";
}
}
void DifficultySettingsManager::loadDifficultyNames()
{
// Load mod-specific difficulty names first if possible
ModDifficultyNames diffNames;
// Look up a name for each difficulty level, starting with a map-specific
// name set on the worldspawn, then falling back to mod default names and
// then autogenerated names.
int numLevels = game::current::getValue<int>(GKEY_DIFFICULTY_LEVELS);
for (int i = 0; i < numLevels; i++)
{
std::string nameKey = diffNameKeyForLevel(i);
// Load the mod default, get the translated value by the helper class
std::string defaultName = diffNames.getNameForKey(nameKey);
if (!defaultName.empty())
{
// Use the (hopefully translated) mod-specific default name
_difficultyNames.push_back(defaultName);
}
else
{
// Fall back to a non-empty default
_difficultyNames.push_back(std::to_string(i));
}
}
// Store the current set as default for later change detection
_defaultDifficultyNames = _difficultyNames;
// Locate the worldspawn entity to find any map-specific names
Entity* worldspawn = map::current::getWorldspawn();
if (worldspawn != nullptr)
{
assert(static_cast<int>(_difficultyNames.size()) == numLevels);
for (int i = 0; i < numLevels; i++)
{
std::string nameKey = diffNameKeyForLevel(i);
// First, try to find a map-specific name
std::string name = worldspawn->getKeyValue(nameKey);
if (!name.empty())
{
// Found a setting on worldspawn, take it
_difficultyNames[i] = name;
}
}
}
}
void DifficultySettingsManager::saveSettings()
{
// Locates all difficulty entities
DifficultyEntityFinder finder;
GlobalSceneGraph().root()->traverse(finder);
// Copy the list from the finder to a local list
DifficultyEntityFinder::EntityList entities = finder.getEntities();
if (entities.empty())
{
// Create a new difficulty entity
std::string eclassName = game::current::getValue<std::string>(GKEY_DIFFICULTY_ENTITYDEF_MAP);
IEntityClassPtr diffEclass = GlobalEntityClassManager().findClass(eclassName);
if (diffEclass == NULL) {
rError() << "[Diff]: Cannot create difficulty entity!\n";
return;
}
// Create and insert a new entity node into the scenegraph root
IEntityNodePtr entNode = GlobalEntityModule().createEntity(diffEclass);
GlobalSceneGraph().root()->addChildNode(entNode);
// Add the entity to the list
entities.push_back(&entNode->getEntity());
}
// Clear all difficulty-spawnargs from existing entities
for (DifficultyEntityFinder::EntityList::const_iterator i = entities.begin();
i != entities.end(); i++)
{
// Construct a difficulty entity using the raw Entity* pointer
DifficultyEntity diffEnt(*i);
// Clear the difficulty-related spawnargs from the entity
diffEnt.clear();
}
// Take the first entity
DifficultyEntity diffEnt(*entities.begin());
// Cycle through all settings objects and issue save call
for (std::size_t i = 0; i < _settings.size(); i++) {
_settings[i]->saveToEntity(diffEnt);
}
// Write the changed difficulty (and only those) names into the worldspawn
Entity* worldspawn = map::current::getWorldspawn(true);
if (!worldspawn)
{
throw std::logic_error("DifficultySettingsManager::saveSettings():"
" could not find or create worldspawn"
);
}
for (std::size_t i = 0; i < _difficultyNames.size(); ++i)
{
// Compare each value to the default set
if (_defaultDifficultyNames.size() > i && _defaultDifficultyNames[i] != _difficultyNames[i])
{
worldspawn->setKeyValue(diffNameKeyForLevel(i), _difficultyNames[i]);
}
else
{
// Remove the corresponding spawnarg from the worldspawn if there's no override
worldspawn->setKeyValue(diffNameKeyForLevel(i), "");
}
}
}
std::string DifficultySettingsManager::getDifficultyName(int level)
{
if (level < 0 || level >= static_cast<int>(_difficultyNames.size()))
{
return "";
}
return _difficultyNames[level];
}
void DifficultySettingsManager::setDifficultyName(int level, const std::string& name)
{
if (level < 0 || level >= static_cast<int>(_difficultyNames.size()))
{
throw std::logic_error(
"Invalid difficulty level (" + std::to_string(level) + ")"
);
}
_difficultyNames[level] = name;
}
} // namespace difficulty
|