// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "nel/misc/path.h" #include "fame.h" #include "nel/misc/diff_tool.h" #include "ryzom_entity_id.h" //#include "../entities_game_service/egs_variables.h" //#include "pvp_clan.h" using namespace std; using namespace NLMISC; using namespace STRING_MANAGER; std::string RowIdToStringCb(void *value); std::string FameToStringCb(void *value) { sint32 &fame = *((sint32*)value); if (fame == NO_FAME) return "NO_FAME"; else return toString("%.3f", fame/1000.0); } CStaticFames *CStaticFames::_Instance = NULL; CFameInterface *CFameInterface::_Instance = NULL; sint16 CFameInterface::TFameOwner::CivilisationPropIndex = 0; sint16 CFameInterface::TFameOwner::GuildPropIndex = 0; sint16 CFameInterface::TFameOwner::FameMemoryPropIndex = 0; sint16 CFameInterface::TFameOwner::FirstFamePropIndex = 0; CVariable UseAsymmetricStaticFames("variables", "UseAsymmetricStaticFames", "if 1, fame between faction A and B may be different that between B and A", false, 0, true); //---------------------------------------------------------------------------- NLMISC_COMMAND(displayFactions, "Display a list of fame faction", "") { CStaticFames &sf = CStaticFames::getInstance(); const std::vector &names = sf.getFactionNames(); log.displayNL("Listing %u factions:", names.size()); for (uint i=0; i]") { if (args.size() > 1) return false; CStaticFames &sf = CStaticFames::getInstance(); const std::vector &names = sf.getFactionNames(); uint start =0; uint end = (uint)names.size(); if (args.size() == 1) { uint32 factionIndex = sf.getFactionIndex(args[0]); if (factionIndex != CStaticFames::INVALID_FACTION_INDEX) { start = factionIndex; end = start+1; } else { log.displayNL("invalid faction name '%s'", args[0].c_str()); return true; } } for (uint i=start; i [] []* ") { if (args.size() < 1) return false; CFameInterface &fi = CFameInterface::getInstance(); CEntityId eid(args[0]); if (eid == CEntityId::Unknown) { log.display("Invalid entity id '%s'", args[0].c_str()); return false; } TDataSetRow dsr = fi.getFameDataSet()->getDataSetRow(eid); if (!fi.getFameDataSet()->isAccessible(dsr)) { log.display("Invalid entity id '%s', can't map in fame dataset", args[0].c_str()); return false; } const vector factionNames = CStaticFames::getInstance().getFactionNames(); // uint32 staticIndex = CStaticFames::INVALID_FACTION_INDEX; bool detail = false; if (args.size() >= 2) { if (args[1] == "detail") { detail = true; } } // build the filter list vector factionFilter; for (uint i=(detail ? 2 : 1); igetEntityId(mdsr), i, false, true); if (fame != NO_FAME) fm = toString("%7.3f", fame/1000.0f); else fm = "no fame"; } case RYZOMID::guild: if (fi.getFameDataSet()->isAccessible(gdsr)) { sint32 fame = fi.getFameIndexed(fi.getFameDataSet()->getEntityId(gdsr), i, false, true); if (fame != NO_FAME) fg = toString("%7.3f", fame/1000.0f); else fg = "no fame"; if (eid.getType() == RYZOMID::guild) cdsr = fi.getCivilisationIndex(eid); } case RYZOMID::civilisation: if (fi.getFameDataSet()->isAccessible(cdsr)) { sint32 fame = fi.getFameIndexed(fi.getFameDataSet()->getEntityId(cdsr), i, false, true); if (fame != NO_FAME) fc = toString("%7.3f", fame/1000.0f); else fc = "no fame"; } } // display the result log.displayNL("Fame between \t%s and %35s = P: %7s, G: %7s, M: %7s, C: %7s", eid.toString().c_str(), factionName.c_str(), fp.c_str(), fg.c_str(), fm.c_str(), fc.c_str()); } } } return true; } //---------------------------------------------------------------------------- NLMISC_COMMAND(addFame, "Add some fame value between an entity and a faction.", " ") { if (args.size() != 3) return false; CEntityId eid(args[0]); if (eid == CEntityId::Unknown) { log.display("Invalid entity id '%s'", args[0].c_str()); return false; } TDataSetRow dsr = CFameInterface::getInstance().getFameDataSet()->getDataSetRow(eid); if (!CFameInterface::getInstance().getFameDataSet()->isAccessible(dsr)) { log.display("Invalid entity id '%s', can't map in fame dataset", args[0].c_str()); return false; } uint32 factionIndex; if (isdigit(args[1][0])) { fromString(args[1], factionIndex); } else { factionIndex = CStaticFames::getInstance().getFactionIndex(args[1]); } if (factionIndex == CStaticFames::INVALID_FACTION_INDEX) { log.display("Invalid faction '%s'.\nTry displayFactions to list the available factions.", args[1].c_str()); return false; } sint32 delta; fromString(args[2], delta); // clamp(delta, FameAbsoluteMin, FameAbsoluteMax); // finaly, retreive the CFameInterface::getInstance().addFameIndexed(eid, factionIndex, delta, true); return true; } //---------------------------------------------------------------------------- CStaticFames::CStaticFames() { _FameTable = NULL; _PropagationFactorTable = NULL; loadStaticFame("static_fame.txt"); loadTribeThreshold("fame_tribes_threshold.txt"); } //---------------------------------------------------------------------------- CStaticFames::~CStaticFames() { delete[] _FameTable; _FameTable = NULL; delete[] _PropagationFactorTable; _PropagationFactorTable = NULL; } //---------------------------------------------------------------------------- void CStaticFames::releaseInstance() { if( _Instance ) { delete _Instance; _Instance = NULL; } } //---------------------------------------------------------------------------- void CStaticFames::loadStaticFame( const string& filename ) { _FameTableSize = 0; _FirstTribeFameIndex = 0; _FameTable = NULL; string path = CPath::lookup(filename, false); if (path.empty()) { nlwarning("FAME: Error can't find static fame file '%s' ! No static fame data available.", filename.c_str()); return; } STRING_MANAGER::TWorksheet ws; // load the static fame file if (loadExcelSheet(path, ws, false)) { // ok, we can parse the worksheet // 1st, build the index table for (uint i=1; isecond != i-2) { nlwarning("FAME: Error while reading fame file '%s' : identifier '%s' is in row %u but in column %u, column and row index must match !", path.c_str(), name.c_str(), it->second, i-2 ); nlwarning("FAME: The faction data will not be available !"); _FactionNameIndex.clear(); _FactionNames.clear(); _FactionSheets.clear(); _FactionSheetIndex.clear(); return; } } // 3rd, allocate fame table and load the data _FameTableSize = (uint)_FactionNameIndex.size(); _FameTable = new sint32[_FameTableSize*_FameTableSize]; _PropagationFactorTable = new float[_FameTableSize*_FameTableSize]; _FameIndexToDatabaseIndex.resize( _FameTableSize ); // Parse database indices for (uint i=1; i<_FameTableSize+1; ++i) { int iFaction = i-1; string s = ws.getData(i, 1).toString(); // get rid of " characters string::size_type k; while ( (k = s.find_first_of('"')) != string::npos) s.erase(k,1); uint databaseIndex; fromString(s, databaseIndex); if( databaseIndex >= 1000 ) { databaseIndex -= 1000; _FirstTribeFameIndex = iFaction; } _FameIndexToDatabaseIndex[iFaction] = databaseIndex; } // Parse static fames and propagation factors for (uint i=1; i<_FameTableSize+1; ++i) { int iFaction = i-1; for (uint j=2; j<_FameTableSize+2; ++j) { int jFaction = j-2; string s = ws.getData(i, j).toString(); // get rid of " characters string::size_type k; while ( (k = s.find_first_of('"')) != string::npos) s.erase(k,1); // Extract "fame;factor" float factor = 0.0f; string::size_type sep = s.find_first_of(';'); if (sep == string::npos) sep = s.size(); else factor = (float) atof( s.substr(sep+1, s.size()-sep-1).c_str()); // Fames in file are in [-600;600] so don't forget 1000 factor sint32 fame = (sint32)(atof(s.substr(0,sep).c_str())*1000.f); _FameTable[iFaction*_FameTableSize + jFaction] = fame; _PropagationFactorTable[iFaction*_FameTableSize + jFaction] = factor; if (fame != 0) { /* nldebug ("FAME: Setting fame between '%s' and '%s' to value %f, propagation factor %f", CStringMapper::unmap(_FactionNames[iFaction]).c_str(), CStringMapper::unmap(_FactionNames[jFaction]).c_str(), fame/1000.0f, factor );*/ } } } } else { nlwarning("FAME: Error while reading the static fame file '%s' ! No static fame data available.", path.c_str()); return; } nlassert(_FactionNames.size() == _FactionSheets.size() ); nlinfo("FAME: Loaded fame for %u factions, total of %u fame values", _FameTableSize, _FameTableSize*_FameTableSize); } //---------------------------------------------------------------------------- void CStaticFames::loadTribeThreshold( const string& filename ) { string path = CPath::lookup(filename, false); if (path.empty()) { nlwarning("FAME: Error can't find tribe threshold fame file '%s' ! No tribe threshold available.", filename.c_str()); return; } STRING_MANAGER::TWorksheet ws; // load the tribe threshold fame file if (loadExcelSheet(path, ws, false)) { // ok, we can parse the worksheet // check table structure uint nbTribe = ws.size()-2; nlassert(nbTribe<=_FameTableSize); nlassert(ws.ColCount == 16); // 5 ( 4 people + neutral ) * 3 cult + 1 for tribe name _TribeCultThresholdPerCiv.resize(nbTribe); for (uint i=2; isetKami(thresholdKami*6000); tc->setKaravan(thresholdKaravan*6000); tc->setNeutral(thresholdNeutral*6000); // This message removed by Sadge because there is no context displayed, meaning that message must be useless // nldebug(" %s", ws.getData(i, c).toString().c_str() ); } } } } //---------------------------------------------------------------------------- const std::string &CStaticFames::getFactionName(uint32 factionIndex) { const static std::string emptyString; if (factionIndex < _FactionNames.size()) return NLMISC::CStringMapper::unmap(_FactionNames[factionIndex]); else return emptyString; } //---------------------------------------------------------------------------- uint CStaticFames::getFactionIndex(NLMISC::TStringId factionName) { TFactionNameIndexList::iterator it(_FactionNameIndex.find(factionName)); if (it != _FactionNameIndex.end()) { return it->second; } return INVALID_FACTION_INDEX; } //---------------------------------------------------------------------------- uint CStaticFames::getFactionIndex(const std::string &factionName) { string n = strlwr(factionName); return getFactionIndex(CStringMapper::map(n)); } //---------------------------------------------------------------------------- sint32 CStaticFames::getStaticFameIndexed(uint factionIndex1, uint factionIndex2) { if ((factionIndex1 < factionIndex2) && !UseAsymmetricStaticFames) swap(factionIndex1, factionIndex2); if (factionIndex1 >= _FameTableSize || factionIndex2 >= _FameTableSize) { nlwarning("FAME: CStaticFames::getStaticFame invalid faction, return 0"); return 0; } #ifdef NL_DEBUG nlassert(factionIndex1 < _FameTableSize); nlassert(factionIndex2 < _FameTableSize); #endif return _FameTable[factionIndex1*_FameTableSize + factionIndex2]; } //---------------------------------------------------------------------------- float CStaticFames::getPropagationFactorIndexed(uint factionIndex1, uint factionIndex2) const { if ((factionIndex1 < factionIndex2) && !UseAsymmetricStaticFames) swap(factionIndex1, factionIndex2); if (factionIndex1 >= _FameTableSize || factionIndex2 >= _FameTableSize) { nlwarning("FAME: CStaticFames::getPropagationFactorIndexed invalid faction, return 0"); return 0.0f; } #ifdef NL_DEBUG nlassert(factionIndex1 < _FameTableSize); nlassert(factionIndex2 < _FameTableSize); #endif return _PropagationFactorTable[factionIndex1*_FameTableSize + factionIndex2]; } //---------------------------------------------------------------------------- sint32 CStaticFames::getStaticFame(NLMISC::TStringId faction1, NLMISC::TStringId faction2) { uint index1, index2; // retreive fame index index1 = getFactionIndex(faction1); index2 = getFactionIndex(faction2); return getStaticFameIndexed(index1, index2); } //---------------------------------------------------------------------------- sint32 CStaticFames::getStaticFame(const std::string &faction1, const std::string &faction2) { string n1, n2; n1 = strlwr(faction1); n2 = strlwr(faction2); return getStaticFame(CStringMapper::map(n1), CStringMapper::map(n2)); } //---------------------------------------------------------------------------- sint32 CFameInterface::getFameIndexed(const CEntityId &entityId, uint32 factionIndex, bool modulated, bool returnUnknownValue) { if (_FameOverload) { return _FameOverload->getFameIndexed(entityId, factionIndex, modulated, returnUnknownValue); } else { // if no faction, just return 0 if (factionIndex == CStaticFames::INVALID_FACTION_INDEX) return 0; // retrieve the faction TDataSetRow entityRow = _FameDataSet->getDataSetRow(entityId); TFameContainer::iterator it(_FamesOwners.find(entityRow)); if (it == _FamesOwners.end()) { // nlwarning("FAME: entity %x doesn't exist in fame owners containers!", entityIndex.getIndex()); return 0; } if (factionIndex >= MAX_FACTION) { nlwarning("FAME: entity %s : faction %u is out of limit (%u)", entityId.toString().c_str(), factionIndex, MAX_FACTION); return 0; } TFameOwner *fo = it->second; sint32 fame = fo->Fames[factionIndex]; // The return values *should* be clamped here, but the values are stored in the // EGS. Just return the raw value if we don't have the _FameOverload. if (!returnUnknownValue && fame == NO_FAME) fame = 0; return sint32(fame); } } //---------------------------------------------------------------------------- sint32 CFameInterface::getFactionIndex(TStringId faction) { CStaticFames &staticFame = CStaticFames::getInstance(); return staticFame.getFactionIndex(faction); } //---------------------------------------------------------------------------- sint32 CFameInterface::getFame(const CEntityId &entityId, TStringId faction, bool modulated, bool returnUnknowValue) { CStaticFames &staticFame = CStaticFames::getInstance(); // get the fame faction index uint oi = staticFame.getFactionIndex(faction); if(oi == CStaticFames::INVALID_FACTION_INDEX) return NO_FAME; return getFameIndexed(entityId, oi, modulated, returnUnknowValue); } //---------------------------------------------------------------------------- void CFameInterface::addFame(const CEntityId &entityId, NLMISC::TStringId faction, sint32 deltaFame, bool propagate) { // get the fame faction index CStaticFames &staticFame = CStaticFames::getInstance(); uint32 oi = staticFame.getFactionIndex(faction); if (oi == CStaticFames::INVALID_FACTION_INDEX) { nlwarning("FAME:addFame(): trying to add fame to faction '%s'(stringId=%u) which is not a valid faction name !", CStringMapper::unmap(faction).c_str(), faction); return; } addFameIndexed(entityId, oi, deltaFame, propagate); } //---------------------------------------------------------------------------- void CFameInterface::addFameIndexed(const CEntityId &entityId, uint32 factionIndex, sint32 deltaFame, bool propagate) { if (_FameOverload) { _FameOverload->addFameIndexed(entityId, factionIndex, deltaFame, propagate); } else { // retrieve the fame owner. TDataSetRow dsr = _FameDataSet->getDataSetRow(entityId); TFameContainer::iterator it(_FamesOwners.find(dsr)); if (it == _FamesOwners.end()) { nlwarning("FAME:addFameIndexed(): can't find info for entity %s(index=%u) in _FamesOwners, can't add fame", entityId.toString().c_str(), dsr.toString().c_str()); return; } if (factionIndex >= MAX_FACTION) { nlwarning("FAME:addFameIndexed(): trying to add fame for entity %s to an invalid faction %u, can't add fame", entityId.toString().c_str(), factionIndex); return; } NLNET::CMessage msg("FAME_DELTA"); // the entity index msg.serial(const_cast(entityId)); // the other faction index msg.serial(factionIndex); // the delta value msg.serial(deltaFame); msg.serial(propagate); // send the message NLNET::CUnifiedNetwork::getInstance()->send("EGS", msg); } } //---------------------------------------------------------------------------- const TDataSetRow &CFameInterface::getCivilisationIndex(const CEntityId &entityId) { static const TDataSetRow invalidIndex; if (_FameOverload) { return _FameOverload->getCivilisationIndex(entityId); } else { TDataSetRow dsr = _FameDataSet->getDataSetRow(entityId); TFameContainer::iterator it(_FamesOwners.find(dsr)); if (it == _FamesOwners.end()) return invalidIndex; return it->second->Civilisation; } } //---------------------------------------------------------------------------- const TDataSetRow &CFameInterface::getGuildIndex(const CEntityId &entityId) { static const TDataSetRow invalidIndex; if (_FameOverload) { return _FameOverload->getGuildIndex(entityId); } else { TDataSetRow dsr = _FameDataSet->getDataSetRow(entityId); TFameContainer::iterator it(_FamesOwners.find(dsr)); if (it == _FamesOwners.end()) return invalidIndex; return it->second->Guild; } } //---------------------------------------------------------------------------- const TDataSetRow &CFameInterface::getFameMemoryIndex(const CEntityId &entityId) { static const TDataSetRow invalidIndex; if (_FameOverload) { return _FameOverload->getFameMemoryIndex(entityId); } else { TDataSetRow dsr = _FameDataSet->getDataSetRow(entityId); TFameContainer::iterator it(_FamesOwners.find(dsr)); if (it == _FamesOwners.end()) return invalidIndex; return it->second->FameMemory; } } //---------------------------------------------------------------------------- void CFameInterface::setFameDataSet(CMirroredDataSet *fameDataSet, bool declareProperty) { const static std::string civilisation("Civilisation"); const static std::string guild("Guild"); const static std::string fameMemory("FameMemory"); const static std::string firstFame("Fame_0"); _FameDataSet = fameDataSet; if (!_FameDataSet) return; if (declareProperty) { // declare the fame properties fameDataSet->declareProperty( civilisation, PSOReadOnly ); fameDataSet->declareProperty( fameMemory, PSOReadOnly); fameDataSet->declareProperty( guild, PSOReadOnly); for (uint i=0; ideclareProperty( propName, PSOReadOnly ); } } // initialise property index TFameOwner::CivilisationPropIndex = _FameDataSet->getPropertyIndex("Civilisation"); TFameOwner::GuildPropIndex = _FameDataSet->getPropertyIndex("Guild"); TFameOwner::FameMemoryPropIndex = _FameDataSet->getPropertyIndex("FameMemory"); TFameOwner::FirstFamePropIndex = _FameDataSet->getPropertyIndex("Fame_0"); // set display call backs _FameDataSet->setDisplayCallback( TFameOwner::CivilisationPropIndex, RowIdToStringCb ); _FameDataSet->setDisplayCallback( TFameOwner::GuildPropIndex, RowIdToStringCb ); _FameDataSet->setDisplayCallback( TFameOwner::FameMemoryPropIndex, RowIdToStringCb ); for (uint i=0; isetDisplayCallback( TFameOwner::FirstFamePropIndex+i, FameToStringCb ); }