void Module::loadModule(const Common::UString &module) { unload(); if (module.empty()) throw Common::Exception("Tried to load an empty module"); try { indexMandatoryArchive(module, 1001, &_resModule); _ifo.load(); if (_ifo.isSave()) throw Common::Exception("This is a save"); _tag = _ifo.getTag(); } catch (Common::Exception &e) { e.add("Can't load module \"%s\"", module.c_str()); throw e; } _newModule.clear(); _hasModule = true; }
void extractFiles(Aurora::RIMFile &rim, Aurora::GameID game) { const Aurora::Archive::ResourceList &resources = rim.getResources(); const size_t fileCount = resources.size(); std::printf("Number of files: %u\n\n", (uint)fileCount); size_t i = 1; for (Aurora::Archive::ResourceList::const_iterator r = resources.begin(); r != resources.end(); ++r, ++i) { const Aurora::FileType type = TypeMan.aliasFileType(r->type, game); const Common::UString fileName = TypeMan.setFileType(r->name, type); std::printf("Extracting %u/%u: %s ... ", (uint)i, (uint)fileCount, fileName.c_str()); Common::SeekableReadStream *stream = 0; try { stream = rim.getResource(r->index); dumpStream(*stream, fileName); std::printf("Done\n"); } catch (Common::Exception &e) { Common::printException(e, ""); } delete stream; } }
void QuickTimeDecoder::VideoSampleDesc::initCodec(Graphics::Surface &surface) { if (_codecTag == MKID_BE('mp4v')) { Common::UString videoType; // Parse the object type switch (_parentTrack->objectTypeMP4) { case 0x20: videoType = "h.263"; _videoCodec = new H263Codec(_parentTrack->width, _parentTrack->height); if (_parentTrack->extraData) _videoCodec->decodeFrame(surface, *_parentTrack->extraData); break; default: videoType = "Unknown"; break; } if (!_videoCodec) warning("MPEG-4 Video (%s) not yet supported", videoType.c_str()); } else if (_codecTag == MKID_BE('SVQ3')) { // TODO: Sorenson Video 3 warning("Sorenson Video 3 not yet supported"); } else { warning("Unsupported codec \'%s\'", tag2str(_codecTag)); } }
bool ScriptContainer::runScript(const Common::UString &script, const Aurora::NWScript::ScriptState &state, Aurora::NWScript::Object *owner, Aurora::NWScript::Object *triggerer) { if (script.empty()) return true; try { Aurora::NWScript::NCSFile ncs(script); const Aurora::NWScript::Variable &retVal = ncs.run(state, owner, triggerer); if (retVal.getType() == Aurora::NWScript::kTypeInt) return retVal.getInt() != 0; if (retVal.getType() == Aurora::NWScript::kTypeFloat) return retVal.getFloat() != 0.0f; return true; } catch (Common::Exception &e) { e.add("Failed running script \"%s\"", script.c_str()); Common::printException(e, "WARNING: "); return false; } return true; }
void extractFiles(Aurora::HERFFile &herf) { const Aurora::Archive::ResourceList &resources = herf.getResources(); const size_t fileCount = resources.size(); std::printf("Number of files: %u\n\n", (uint)fileCount); size_t i = 1; for (Aurora::Archive::ResourceList::const_iterator r = resources.begin(); r != resources.end(); ++r, ++i) { Common::UString fileName = r->name, fileExt = TypeMan.setFileType("", r->type); if (fileName.empty()) findHashedName(r->hash, fileName, fileExt); fileName = fileName + fileExt; std::printf("Extracting %u/%u: %s ... ", (uint)i, (uint)fileCount, fileName.c_str()); Common::SeekableReadStream *stream = 0; try { stream = herf.getResource(r->index); dumpStream(*stream, fileName); std::printf("Done\n"); } catch (Common::Exception &e) { Common::printException(e, ""); } delete stream; } }
void ResourceManager::dumpResourcesList(const Common::UString &fileName) const { Common::DumpFile file; if (!file.open(fileName)) throw Common::Exception(Common::kOpenError); file.writeString(" Name | Hash | Size \n"); file.writeString("-------------------------------------|--------------------|-------------\n"); for (ResourceMap::const_iterator r = _resources.begin(); r != _resources.end(); ++r) { if (r->second.empty()) continue; const Resource &res = r->second.back(); const Common::UString &name = res.name; const Common::UString ext = TypeMan.setFileType("", res.type); const uint64 hash = r->first; const uint32 size = getResourceSize(res); const Common::UString line = Common::UString::sprintf("%32s%4s | 0x%016llX | %12d\n", name.c_str(), ext.c_str(), (unsigned long long) hash, size); file.writeString(line); } file.flush(); if (file.err()) throw Common::Exception("Write error"); file.close(); }
ResourceManager::ChangeID ResourceManager::addResourceDir(const Common::UString &dir, const char *glob, int depth, uint32 priority) { // Find the directory Common::UString directory = Common::FilePath::findSubDirectory(_baseDir, dir, true); if (directory.empty()) throw Common::Exception("No such directory \"%s\"", dir.c_str()); // Find files Common::FileList files; files.addDirectory(directory, depth); ChangeID change = newChangeSet(); if (!glob) { // Add the files addResources(files, change, priority); return change; } // Find files matching the glob pattern Common::FileList globFiles; files.getSubList(glob, globFiles, true); // Add the files addResources(globFiles, change, priority); return change; }
void printUsage(FILE *stream, const Common::UString &name) { std::fprintf(stream, "BioWare TLK to XML converter\n\n"); std::fprintf(stream, "Usage: %s [<options>] <input file> [<output file>]\n", name.c_str()); std::fprintf(stream, " -h --help This help text\n"); std::fprintf(stream, " --version Display version information\n\n"); std::fprintf(stream, " --cp1250 Read TLK strings as Windows CP-1250\n"); std::fprintf(stream, " --cp1251 Read TLK strings as Windows CP-1251\n"); std::fprintf(stream, " --cp1252 Read TLK strings as Windows CP-1252\n"); std::fprintf(stream, " --cp932 Read TLK strings as Windows CP-932\n"); std::fprintf(stream, " --cp936 Read TLK strings as Windows CP-936\n"); std::fprintf(stream, " --cp949 Read TLK strings as Windows CP-949\n"); std::fprintf(stream, " --cp950 Read TLK strings as Windows CP-950\n"); std::fprintf(stream, " --utf8 Read TLK strings as UTF-8\n"); std::fprintf(stream, " --utf16le Read TLK strings as little-endian UTF-16\n"); std::fprintf(stream, " --utf16be Read TLK strings as big-endian UTF-16\n\n"); std::fprintf(stream, " --nwn Use Neverwinter Nights encodings\n"); std::fprintf(stream, " --nwn2 Use Neverwinter Nights 2 encodings\n"); std::fprintf(stream, " --kotor Use Knights of the Old Republic encodings\n"); std::fprintf(stream, " --kotor2 Use Knights of the Old Republic II encodings\n"); std::fprintf(stream, " --jade Use Jade Empire encodings\n"); std::fprintf(stream, " --witcher Use The Witcher encodings\n"); std::fprintf(stream, " --dragonage Use Dragon Age encodings\n"); std::fprintf(stream, " --dragonage2 Use Dragon Age II encodings\n\n"); std::fprintf(stream, "If no output file is given, the output is written to stdout.\n\n"); std::fprintf(stream, "There is no way to autodetect the encoding of strings in TLK files,\n"); std::fprintf(stream, "so an encoding must be specified. Alternatively, the game this TLK\n"); std::fprintf(stream, "is from can be given, and an appropriate encoding according to that\n"); std::fprintf(stream, "game and the language ID found in the TLK is used.\n"); }
void Room::loadLayout(const Common::UString &roomFile) { if (!ResMan.hasResource(roomFile, Aurora::kFileTypeRML) || EventMan.quitRequested()) return; GFF4File rml(roomFile, Aurora::kFileTypeRML, kRMLID); if (rml.getTypeVersion() != kVersion40) throw Common::Exception("Unsupported RML version %s", Common::debugTag(rml.getTypeVersion()).c_str()); const GFF4Struct &rmlTop = rml.getTopLevel(); float roomPos[3] = { 0.0f, 0.0f, 0.0f }; rmlTop.getVector3(kGFF4Position, roomPos[0], roomPos[1], roomPos[2]); float roomOrient[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; rmlTop.getVector4(kGFF4Orientation, roomOrient[0], roomOrient[1], roomOrient[2], roomOrient[3]); roomOrient[3] = Common::rad2deg(acos(roomOrient[3]) * 2.0); Common::Matrix4x4 roomTransform; roomTransform.translate(roomPos[0], roomPos[1], roomPos[2]); roomTransform.rotate(roomOrient[3], roomOrient[0], roomOrient[1], roomOrient[2]); status("Loading room \"%s\" (%d)", roomFile.c_str(), _id); const GFF4List &models = rmlTop.getList(kGFF4EnvRoomModelList); _models.reserve(models.size()); for (GFF4List::const_iterator m = models.begin(); m != models.end(); ++m) { if (!*m || ((*m)->getLabel() != kMDLID)) continue; float scale = (*m)->getFloat(kGFF4EnvModelScale); float pos[3] = { 0.0f, 0.0f, 0.0f }; (*m)->getVector3(kGFF4Position, pos[0], pos[1], pos[2]); float orient[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; (*m)->getVector4(kGFF4Orientation, orient[0], orient[1], orient[2], orient[3]); orient[3] = Common::rad2deg(acos(orient[3]) * 2.0); // TODO: Instances Graphics::Aurora::Model *model = loadModelObject((*m)->getString(kGFF4EnvModelFile)); if (!model) continue; _models.push_back(model); Common::Matrix4x4 modelTransform(roomTransform); modelTransform.translate(pos[0], pos[1], pos[2]); modelTransform.rotate(orient[3], orient[0], orient[1], orient[2]); modelTransform.getPosition(pos[0], pos[1], pos[2]); modelTransform.getAxisAngle(orient[3], orient[0], orient[1], orient[2]); model->setPosition(pos[0], pos[1], pos[2]); model->setOrientation(orient[0], orient[1], orient[2], orient[3]); model->setScale(scale, scale, scale); } }
void ScriptObject::readVarTable(const GFF4List &varTable) { for (GFF4List::const_iterator v = varTable.begin(); v != varTable.end(); ++v) { if (!*v || ((*v)->getLabel() != kVARSID)) continue; const Common::UString name = (*v)->getString (kGFF4ScriptVarTableName); const uint8 type = (*v)->getUint (kGFF4ScriptVarTableType); const GFF4Struct *value = (*v)->getGeneric(kGFF4ScriptVarTableValue); if (name.empty() || (type == 0) || !value || !value->hasField(0)) continue; switch (type) { case 4: setVariable(name, Aurora::NWScript::Variable()); break; case 1: setVariable(name, (int32) value->getSint(0)); break; case 2: setVariable(name, (float) value->getDouble(0)); break; case 3: case 12: setVariable(name, value->getString(0)); break; default: throw Common::Exception("Unknown variable type %u (\"%s\")", type, name.c_str()); } } }
void Object::speakOneLiner(Common::UString conv, Object *UNUSED(tokenTarget)) { if (conv.empty()) conv = _conversation; if (conv.empty()) return; Common::UString text; Common::UString sound; try { Aurora::DLGFile dlg(conv, this); const Aurora::DLGFile::Line *line = dlg.getOneLiner(); if (line) { text = line->text.getString(); sound = line->sound; } } catch (Common::Exception &e) { e.add("Failed evaluating one-liner from conversation \"%s\"", conv.c_str()); Common::printException(e, "WARNING: "); } if (!text.empty()) speakString(text, 0); if (!sound.empty()) playSound(sound); }
void AreaBackground::loadTexture(const Common::UString &name) { Common::SeekableReadStream *cbgt = 0, *pal = 0, *twoda = 0; Graphics::CBGT *image = 0; try { if (!(cbgt = ResMan.getResource(name, Aurora::kFileTypeCBGT))) throw Common::Exception("No such CBGT"); if (!(pal = ResMan.getResource(name, Aurora::kFileTypePAL))) throw Common::Exception("No such PAL"); if (!(twoda = ResMan.getResource(name, Aurora::kFileType2DA))) throw Common::Exception("No such 2DA"); image = new Graphics::CBGT(*cbgt, *pal, *twoda); _texture = TextureMan.add(Graphics::Aurora::Texture::create(image, Aurora::kFileTypeCBGT), name); } catch (Common::Exception &e) { delete image; delete cbgt; delete pal; delete twoda; e.add("Failed loading area background \"%s\"", name.c_str()); throw; } delete cbgt; delete pal; delete twoda; }
void ScriptObject::readVarTable(const GFF3List &varTable) { for (GFF3List::const_iterator v = varTable.begin(); v != varTable.end(); ++v) { const Common::UString name = (*v)->getString ("Name"); const uint8 type = (*v)->getUint ("Type"); if (name.empty()) continue; switch (type) { case 0: case 4: setVariable(name, Aurora::NWScript::Variable()); break; case 1: setVariable(name, (int32) (*v)->getSint("Value")); break; case 2: setVariable(name, (float) (*v)->getDouble("Value")); break; case 3: case 12: setVariable(name, (*v)->getString("Value")); break; default: throw Common::Exception("Unknown variable type %u (\"%s\")", type, name.c_str()); } } }
void VideoPlayer::load(const Common::UString &name) { delete _video; _video = 0; ::Aurora::FileType type; Common::SeekableReadStream *video = ResMan.getResource(::Aurora::kResourceVideo, name, &type); if (!video) throw Common::Exception("No such video resource \"%s\"", name.c_str()); // Loading the different image formats switch (type) { case ::Aurora::kFileTypeBIK: _video = new Bink(video); break; case ::Aurora::kFileTypeMOV: _video = new QuickTimeDecoder(video); break; case ::Aurora::kFileTypeXMV: _video = new XboxMediaVideo(video); break; case ::Aurora::kFileTypeVX: _video = new ActimagineDecoder(video); break; default: delete video; throw Common::Exception("Unsupported video resource type %d", (int) type); } _video->setScale(VideoDecoder::kScaleUpDown); }
void Module::loadModule(const Common::UString &module, const Common::UString &entryLocation, ObjectType entryLocationType) { unload(false); _module = module; _entryLocation = entryLocation; _entryLocationType = entryLocationType; try { load(); } catch (Common::Exception &e) { _module.clear(); e.add("Failed loading module \"%s\"", module.c_str()); throw e; } _newModule.clear(); _hasModule = true; }
TextureHandle TextureManager::add(Texture *texture, Common::UString name) { Common::StackLock lock(_mutex); bool reloadable = true; if (name.empty()) { reloadable = false; name = Common::generateIDRandomString(); } TextureMap::iterator text = _textures.find(name); if (text != _textures.end()) throw Common::Exception("Texture \"%s\" already exists", name.c_str()); std::pair<TextureMap::iterator, bool> result; ManagedTexture *t = new ManagedTexture(name, texture); result = _textures.insert(std::make_pair(name, t)); text = result.first; text->second->reloadable = reloadable; return TextureHandle(text); }
void Functions::executeScript(Aurora::NWScript::FunctionContext &ctx) { Common::UString script = ctx.getParams()[0].getString(); // Max resource name length is 16, and ExecuteScript should truncate accordingly script.truncate(16); if (!ResMan.hasResource(script, Aurora::kFileTypeNCS)) return; Aurora::NWScript::Object *object = getParamObject(ctx, 1); try { Aurora::NWScript::NCSFile ncs(script); // Let the child script inherit the environment of this parent script Aurora::NWScript::VariableContainer *env = ctx.getCurrentEnvironment(); if (env) ncs.setEnvironment(*env); ncs.run(object); } catch (Common::Exception &e) { e.add("Failed ExecuteScript(\"%s\", %s)", script.c_str(), Aurora::NWScript::formatTag(object).c_str()); Common::printException(e, "WARNING: "); } }
UString debugTag(uint32 tag, bool trim) { Common::UString str; if (tagToString(tag, trim, str)) return UString::sprintf("0x%08X ('%s')", FROM_BE_32(tag), str.c_str()); return UString::sprintf("0x%08X", FROM_BE_32(tag)); }
void printUsage(FILE *stream, const Common::UString &name) { std::fprintf(stream, "XML to BioWare TLK converter\n\n"); std::fprintf(stream, "Usage: %s [<options>] [<input file>] <output file>\n", name.c_str()); std::fprintf(stream, " -h --help This help text\n"); std::fprintf(stream, " --version Display version information\n"); std::fprintf(stream, " -3 --version30 Write a V3.0 TLK file\n"); std::fprintf(stream, " -4 --version40 Write a V4.0 TLK file\n"); std::fprintf(stream, " -l <id> --language <id> Override the TLK language ID\n\n"); std::fprintf(stream, " --cp1250 Write TLK strings as Windows CP-1250\n"); std::fprintf(stream, " --cp1251 Write TLK strings as Windows CP-1251\n"); std::fprintf(stream, " --cp1252 Write TLK strings as Windows CP-1252\n"); std::fprintf(stream, " --cp932 Write TLK strings as Windows CP-932\n"); std::fprintf(stream, " --cp936 Write TLK strings as Windows CP-936\n"); std::fprintf(stream, " --cp949 Write TLK strings as Windows CP-949\n"); std::fprintf(stream, " --cp950 Write TLK strings as Windows CP-950\n"); std::fprintf(stream, " --utf8 Write TLK strings as UTF-8\n"); std::fprintf(stream, " --utf16le Write TLK strings as little-endian UTF-16\n"); std::fprintf(stream, " --utf16be Write TLK strings as big-endian UTF-16\n\n"); std::fprintf(stream, " --nwn Use Neverwinter Nights encodings\n"); std::fprintf(stream, " --nwn2 Use Neverwinter Nights 2 encodings\n"); std::fprintf(stream, " --kotor Use Knights of the Old Republic encodings\n"); std::fprintf(stream, " --kotor2 Use Knights of the Old Republic II encodings\n"); std::fprintf(stream, " --jade Use Jade Empire encodings\n"); std::fprintf(stream, " --witcher Use The Witcher encodings\n"); std::fprintf(stream, " --dragonage Use Dragon Age encodings\n"); std::fprintf(stream, " --dragonage2 Use Dragon Age II encodings\n\n"); std::fprintf(stream, "If no input file is given, the input is read from stdin.\n\n"); std::fprintf(stream, "One of --version* to specify the version of TLK to write is mandatory,\n"); std::fprintf(stream, "as is one of the flags for the encoding. If the XML file provides a\n"); std::fprintf(stream, "language ID, the --language flag is optional.\n\n"); std::fprintf(stream, "There is no way to autodetect the encoding of strings in TLK files,\n"); std::fprintf(stream, "so an encoding must be specified. Alternatively, the game this TLK\n"); std::fprintf(stream, "is from can be given, and an appropriate encoding according to that\n"); std::fprintf(stream, "game and the language ID is used.\n"); }
void TwoDAFile::writeASCII(Common::WriteStream &out) const { // Write header out.writeString("2DA V2.0\n"); if (!_defaultString.empty()) out.writeString(Common::UString::format("DEFAULT: %s", _defaultString.c_str())); out.writeByte('\n'); // Calculate column lengths std::vector<size_t> colLength; colLength.resize(_headers.size() + 1, 0); const Common::UString maxRow = Common::UString::format("%d", (int)_rows.size() - 1); colLength[0] = maxRow.size(); for (size_t i = 0; i < _headers.size(); i++) colLength[i + 1] = _headers[i].size(); for (size_t i = 0; i < _rows.size(); i++) { for (size_t j = 0; j < _rows[i]->_data.size(); j++) { const bool needQuote = _rows[i]->_data[j].contains(' '); const size_t length = needQuote ? _rows[i]->_data[j].size() + 2 : _rows[i]->_data[j].size(); colLength[j + 1] = MAX<size_t>(colLength[j + 1], length); } } // Write column headers out.writeString(Common::UString::format("%-*s", (int)colLength[0], "")); for (size_t i = 0; i < _headers.size(); i++) out.writeString(Common::UString::format(" %-*s", (int)colLength[i + 1], _headers[i].c_str())); out.writeByte('\n'); // Write array for (size_t i = 0; i < _rows.size(); i++) { out.writeString(Common::UString::format("%*u", (int)colLength[0], (uint)i)); for (size_t j = 0; j < _rows[i]->_data.size(); j++) { const bool needQuote = _rows[i]->_data[j].contains(' '); Common::UString cellString; if (needQuote) cellString = Common::UString::format("\"%s\"", _rows[i]->_data[j].c_str()); else cellString = _rows[i]->_data[j]; out.writeString(Common::UString::format(" %-*s", (int)colLength[j + 1], cellString.c_str())); } out.writeByte('\n'); } out.flush(); }
void Tooltip::redoBubble() { delete _bubble; _bubble = 0; if (!_showBubble || (_height <= 0.0)) return; float height = _height - _lineHeight; uint32 lines = 1; while (height > _lineSpacing) { height -= (_lineSpacing + _lineHeight); lines++; } Common::UString bubbleModel = getBubbleModel(lines, _width); _bubble = loadModelGUI(bubbleModel); if (!_bubble) { warning("Tooltip::redoBubble(): Failed loading model \"%s\"", bubbleModel.c_str()); return; } _bubble->setTag("Tooltip#Bubble"); }
void Tileset::loadTile(const Common::ConfigFile &set, uint i, Tile &tile) { Common::UString domainName = Common::UString::sprintf("TILE%u", i); const Common::ConfigDomain *domain = set.getDomain(domainName); if (!domain) throw Common::Exception("Tileset has no \"%s\" domain", domainName.c_str()); tile.model = domain->getString("Model"); }
void Campaign::setupStandaloneModule(const Common::UString &module) { const Common::UString mod = Module::findModule(module, true); if (mod.empty()) throw Common::Exception("No such module \"%s\"", module.c_str()); _modules.push_back(mod); _startModule = mod; }
Model_KotOR::ParserContext::ParserContext(const Common::UString &name, const Common::UString &t, bool k2) : mdl(0), mdx(0), state(0), texture(t), kotor2(k2) { try { if (!(mdl = ResMan.getResource(name, ::Aurora::kFileTypeMDL))) throw Common::Exception("No such MDL \"%s\"", name.c_str()); if (!(mdx = ResMan.getResource(name, ::Aurora::kFileTypeMDX))) throw Common::Exception("No such MDX \"%s\"", name.c_str()); } catch (...) { delete mdl; delete mdx; throw; } }
Variable ScriptManager::getGlobalVariable(const Common::UString &name) const { StackGuard guard(*_luaState); lua_getglobal(_luaState, name.c_str()); Stack stack(*_luaState); return stack.getVariableAt(-1); }
bool Stack::isUserTypeAt(int index, const Common::UString &type) const { if (type.empty()) { return getTypeAt(index) == kTypeUserType; } tolua_Error error; return checkIndex(index) && tolua_isusertype(&_luaState, index, type.c_str(), 0, &error) != 0; }
void PanelPreviewSound::update() { uint64 t = SoundMan.getChannelDurationPlayed(_sound); Common::UString played = formatTime(t); Common::UString total = formatTime(_duration); Common::UString percent = formatPercent(_duration, t); _textPosition->SetLabelMarkup(Common::UString::format("<tt>%s</tt>", played.c_str())); _textPercent->SetLabelMarkup(Common::UString::format("<tt>%s</tt>", percent.c_str())); _textDuration->SetLabelMarkup(Common::UString::format("<tt>%s</tt>", total.c_str())); _sliderPosition->SetValue(getSliderPos(_duration, t)); bool isPlaying = SoundMan.isPlaying(_sound); bool isPaused = SoundMan.isPaused(_sound); setButtons(!isPlaying || isPaused, isPlaying && !isPaused, isPlaying); }
void Functions::writeTimestampedLogEntry(Aurora::NWScript::FunctionContext &ctx) { boost::posix_time::ptime t(boost::posix_time::second_clock::universal_time()); const Common::UString tstamp = Common::UString::format("%04d-%02d-%02dT%02d:%02d:%02d", (int) t.date().year(), (int) t.date().month(), (int) t.date().day(), (int) t.time_of_day().hours(), (int) t.time_of_day().minutes(), (int) t.time_of_day().seconds()); status("NWN2: %s: %s", tstamp.c_str(), ctx.getParams()[0].getString().c_str()); }
void SaveLoadMenu::tryLoadGame(const Common::UString &dir) { try { Common::ScopedPtr<SavedGame> save(SavedGame::load(dir, true)); _module->loadSavedGame(save.get()); _returnCode = 2; } catch (Common::Exception &e) { warning("Failed to load saved game: %s %s", dir.c_str(), e.what()); } }
void checkConfigDouble(const Common::UString &key, double min, double max, double def) { double value = ConfigMan.getDouble(key, def); if ((value >= min) && (value <= max)) return; warning("Config \"%s\" has invalid value (%lf), resetting to default (%lf)", key.c_str(), value, def); ConfigMan.setDouble(key, def); }