/** Add a creature by template name to the roster list. */ bool Roster::addRosterMemberByTemplate(Common::UString name, Common::UString cTemplate) { // Disallow null strings if (name.size() == 0 || cTemplate.size() == 0) return false; // Don't permit duplicate roster names auto match = std::find_if(_members.begin(), _members.end(), [&](const Member &m) { return m.rosterName == name; }); if (match != _members.end()) return false; // A matching template file must exist if (!ResMan.hasResource(cTemplate, Aurora::kFileTypeUTC)) { // HACK: Check for custom unit test token "[GTEST]" at start if (!cTemplate.beginsWith("[GTEST]")) return false; } // Add roster member to the list Member member; member.rosterName = name; member.cTemplate = cTemplate; _members.push_back(member); // TODO: Template is not stored in ROSTER.rst, so load creature into game for saving, but don't spawn return true; }
void Game::loadTalkTables(const Common::UString &dir, uint32 priority, ChangeList &res, Aurora::Language language) { if (EventMan.quitRequested()) return; const Common::UString tlkDir = Common::FilePath::findSubDirectory(ResMan.getDataBase(), dir + "/data/talktables", true); Common::FileList files(tlkDir, 0); files.sort(true); files.relativize(tlkDir); const Common::UString languageTLK = DragonAge2Engine::getLanguageString(language) + ".tlk"; const Common::UString languageTLKP = DragonAge2Engine::getLanguageString(language) + "_p.tlk"; for (Common::FileList::const_iterator f = files.begin(); f != files.end(); ++f) { if (f->toLower().endsWith(languageTLK)) { Common::UString tlk = *f; tlk.truncate(tlk.size() - languageTLK.size()); loadTalkTable(tlk, "", language, priority++, res); } else if (f->toLower().endsWith(languageTLKP)) { Common::UString tlk = *f; tlk.truncate(tlk.size() - languageTLKP.size()); loadTalkTable(tlk, "_p", language, priority++, res); } } }
void parsePassword(const Common::UString &arg, std::vector<byte> &password) { const size_t length = arg.size(); password.clear(); password.reserve(length / 2); size_t i = 0; byte c = 0x00; for (Common::UString::iterator s = arg.begin(); s != arg.end(); ++s, i++) { byte d = 0; if (*s >= '0' && *s <= '9') d = *s - '0'; else if (*s >= 'a' && *s <= 'f') d = *s - 'a' + 10; else if (*s >= 'A' && *s <= 'F') d = *s - 'A' + 10; else throw Common::Exception("0x%08X is not a valid hex digit", (uint) *s); if ((i % 2) == 1) { c |= d; password.push_back(c); c = 0x00; } else c |= d << 4; } }
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(); }
UString FilePath::relativize(const UString &basePath, const UString &path) { const Common::UString normPath = normalize(path, false); const Common::UString normBase = normalize(basePath, false); UString relative = ""; if (normPath.beginsWith(normBase)) relative = normPath.substr(normPath.getPosition(normBase.size() + 1), normPath.end()); return relative; }
bool TwoDAFile::dumpASCII(const Common::UString &fileName) const { Common::DumpFile file; if (!file.open(fileName)) return false; // Write header file.writeString("2DA V2.0\n"); file.writeString(_defaultString); file.writeByte('\n'); // Calculate column lengths std::vector<uint32> colLength; colLength.resize(_headers.size() + 1); const Common::UString maxRow = Common::UString::sprintf("%d", (int)_rows.size() - 1); colLength[0] = maxRow.size(); for (uint32 i = 0; i < _headers.size(); i++) colLength[i + 1] = _headers[i].size(); for (uint32 i = 0; i < _rows.size(); i++) for (uint32 j = 0; j < _rows[i]->_data.size(); j++) colLength[j + 1] = MAX<uint32>(colLength[j + 1], _rows[i]->_data[j].size()); // Write column headers file.writeString(Common::UString::sprintf("%-*s", colLength[0], "")); for (uint32 i = 0; i < _headers.size(); i++) file.writeString(Common::UString::sprintf(" %-*s", colLength[i + 1], _headers[i].c_str())); file.writeByte('\n'); // Write array for (uint32 i = 0; i < _rows.size(); i++) { file.writeString(Common::UString::sprintf("%*d", colLength[0], i)); for (uint32 j = 0; j < _rows[i]->_data.size(); j++) file.writeString(Common::UString::sprintf(" %-*s", colLength[j + 1], _rows[i]->_data[j].c_str())); file.writeByte('\n'); } file.flush(); file.close(); return true; }
static bool parseOption(const Common::UString &arg, Common::UString &key) { if (arg.size() < 2) { warning("Unrecognized command line argument \"%s\"", arg.c_str()); return false; } Common::UString::iterator start = arg.begin(); ++start; Common::UString value; if (*start == '-') { // Long option ++start; Common::UString::iterator e = arg.findFirst('='); if (e != arg.end()) { key = arg.substr(start, e++); value = arg.substr(e, arg.end()); } else key = arg.substr(start, arg.end()); } else { // Short option key = convertShortToLongOption(*start++); value = arg.substr(start, arg.end()); } if (key.empty()) { warning("Unrecognized command line argument \"%s\"", arg.c_str()); return false; } if (value.empty()) return true; if (!setOption(key, value)) return false; return true; }
void Console::printList(const std::list<Common::UString> &list, uint32 maxSize) { const uint32 columns = getColumns(); if (maxSize > 0) maxSize = MAX<uint32>(maxSize, 3); uint32 lineSize = 1; if (maxSize >= (columns - 2)) maxSize = columns; else if (maxSize > 0) lineSize = columns / (maxSize + 2); std::list<Common::UString>::const_iterator l = list.begin(); while (l != list.end()) { Common::UString line; for (uint32 i = 0; (i < lineSize) && (l != list.end()); i++, ++l) { Common::UString item = *l; uint32 itemSize = item.size(); if (itemSize > maxSize) { item.truncate(maxSize - 3); item += "..."; itemSize = maxSize; } uint32 pad = (maxSize + 2) - itemSize; while (pad-- > 0) item += ' '; line += item; } print(line); } }
void Game::getModules(std::vector<Common::UString> &modules) { modules.clear(); Common::UString moduleDir = ConfigMan.getString("KOTOR_moduleDir"); if (moduleDir.empty()) return; Common::FileList mods; mods.addDirectory(moduleDir); for (Common::FileList::const_iterator m = mods.begin(); m != mods.end(); ++m) { Common::UString file = m->toLower(); if (!file.endsWith("_s.rim")) continue; file = Common::FilePath::getStem(file); file.truncate(file.size() - Common::UString("_s").size()); modules.push_back(file); } std::sort(modules.begin(), modules.end(), Common::UString::iless()); }
void listVerboseFiles(Aurora::ERFFile &erf, Aurora::GameID game) { const Aurora::Archive::ResourceList &resources = erf.getResources(); const size_t fileCount = resources.size(); std::printf("Number of files: %u\n\n", (uint)fileCount); std::vector<FileEntry> fileEntries; fileEntries.reserve(fileCount); size_t nameLength = 10; for (Aurora::Archive::ResourceList::const_iterator r = resources.begin(); r != resources.end(); ++r) { const Aurora::FileType type = TypeMan.aliasFileType(r->type, game); Common::UString name = r->name; if (name.empty()) findHashedName(r->hash, name); name.replaceAll('\\', '/'); name = TypeMan.addFileType(name, type); nameLength = MAX<size_t>(nameLength, name.size() + 1); fileEntries.push_back(FileEntry(name, erf.getResourceSize(r->index))); } if ((nameLength % 2) == 1) nameLength++; std::printf("%sFileName%s| Size\n", Common::UString(' ', (nameLength - 8) / 2).c_str(), Common::UString(' ', (nameLength - 8) / 2).c_str()); std::printf("%s|===========\n", Common::UString('=', nameLength).c_str()); for (std::vector<FileEntry>::const_iterator f = fileEntries.begin(); f != fileEntries.end(); ++f) std::printf("%-*s| %10d\n", (int)nameLength, f->file.c_str(), f->size); }
void Text::parseColors(const Common::UString &str, Common::UString &parsed, ColorPositions &colors) { parsed.clear(); colors.clear(); ColorPosition color; // Split by text tokens. They will have a strictly interleaving plain/token order std::vector<Common::UString> tokens; Common::UString::splitTextTokens(str, tokens); bool plain = false; for (std::vector<Common::UString>::iterator t = tokens.begin(); t != tokens.end(); ++t) { plain = !plain; if (plain) { // Plain text, add it verbatim parsed += *t; continue; } if ((t->size() == 11) && t->beginsWith("<c") && t->endsWith(">")) { // Color start token uint8 colorValue[4]; Common::UString::iterator it = t->begin(); // Skip "<c" ++it; ++it; for (int i = 0; i < 8; i++, ++it) { uint32 c = *it; // Convert the hex values into true nibble values if ((c >= '0') && (c <= '9')) c = c - '0'; else if ((c >= 'A') && (c <= 'F')) c = (c - 'A') + 10; else if ((c >= 'f') && (c <= 'f')) c = (c - 'a') + 10; else c = 15; // Merge two nibbles into one color value byte uint8 &value = colorValue[i / 2]; bool high = (i % 2) == 0; if (high) value = c << 4; else value |= c; } // Add the color change color.position = parsed.size(); color.defaultColor = false; color.r = colorValue[0] / 255.0f; color.g = colorValue[1] / 255.0f; color.b = colorValue[2] / 255.0f; color.a = colorValue[3] / 255.0f; colors.push_back(color); } else if (*t == "</c>") { // Color end token, add a "uncolor" / default color change color.position = parsed.size(); color.defaultColor = true; colors.push_back(color); } else // Ignore non-color tokens parsed += *t; } }