763 lines
25 KiB
C++
763 lines
25 KiB
C++
|
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||
|
// 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 <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
#include "stdpch.h"
|
||
|
|
||
|
#include "bar_manager.h"
|
||
|
#include "interface_manager.h"
|
||
|
#include "interface_expr.h"
|
||
|
#include "../time_client.h"
|
||
|
|
||
|
|
||
|
using namespace std;
|
||
|
using namespace NLMISC;
|
||
|
|
||
|
|
||
|
// ***************************************************************************
|
||
|
// LOG, for debug
|
||
|
#define ALLOW_BAR_LOG 0
|
||
|
|
||
|
// don't change this (ensure no bug in final version)
|
||
|
#if FINAL_VERSION
|
||
|
#undef ALLOW_BAR_LOG
|
||
|
#define ALLOW_BAR_LOG 0
|
||
|
#endif
|
||
|
#if ALLOW_BAR_LOG
|
||
|
# define barInfoLog nlinfo
|
||
|
#else // NL_RELEASE
|
||
|
# ifdef NL_COMP_VC71
|
||
|
# define barInfoLog __noop
|
||
|
# else
|
||
|
# define barInfoLog 0&&
|
||
|
# endif
|
||
|
#endif // NL_RELEASE
|
||
|
|
||
|
|
||
|
static const char *entryTypeToStr(CBarManager::TEntryType et)
|
||
|
{
|
||
|
switch(et)
|
||
|
{
|
||
|
case CBarManager::EntityType: return "Entity"; break;
|
||
|
case CBarManager::TeamMemberType: return "TeamMember"; break;
|
||
|
case CBarManager::AnimalType: return "Animal"; break;
|
||
|
case CBarManager::TargetType: return "Target"; break;
|
||
|
default: return "Unknown (Error!!)"; break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// ***************************************************************************
|
||
|
CBarManager *CBarManager::_Instance= NULL;
|
||
|
|
||
|
|
||
|
// ***************************************************************************
|
||
|
// ***************************************************************************
|
||
|
// ***************************************************************************
|
||
|
// ***************************************************************************
|
||
|
|
||
|
|
||
|
// ***************************************************************************
|
||
|
CBarManager::CBarDataEntry::CBarDataEntry()
|
||
|
{
|
||
|
clear();
|
||
|
resetDB();
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::CBarDataEntry::clear()
|
||
|
{
|
||
|
DataSetId= CLFECOMMON::INVALID_CLIENT_DATASET_INDEX;
|
||
|
BarInfo.reset();
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::CBarDataEntry::resetDB()
|
||
|
{
|
||
|
UIDIn= NULL;
|
||
|
PresentIn= NULL;
|
||
|
for(uint sc=0;sc<SCORES::NUM_SCORES;sc++)
|
||
|
{
|
||
|
ScoreIn[sc]= NULL;
|
||
|
ScoreOut[sc]= NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::CBarDataEntry::connectDB(const std::string &baseDBin, const std::string &baseDBout, const std::string &presentDB,
|
||
|
const std::string &hpDB, const std::string &sapDB, const std::string &staDB, const std::string &focusDB)
|
||
|
{
|
||
|
CInterfaceManager *pIM= CInterfaceManager::getInstance();
|
||
|
|
||
|
// can only manage 4 scores here
|
||
|
nlctassert(SCORES::NUM_SCORES==4);
|
||
|
|
||
|
// try to connect each input entry (don't create)
|
||
|
if(!baseDBin.empty())
|
||
|
{
|
||
|
UIDIn= pIM->getDbProp(baseDBin+"UID", false);
|
||
|
if(!presentDB.empty())
|
||
|
PresentIn= pIM->getDbProp(baseDBin+presentDB, false);
|
||
|
if(!hpDB.empty())
|
||
|
ScoreIn[SCORES::hit_points]= pIM->getDbProp(baseDBin+hpDB, false);
|
||
|
if(!sapDB.empty())
|
||
|
ScoreIn[SCORES::sap]= pIM->getDbProp(baseDBin+sapDB, false);
|
||
|
if(!staDB.empty())
|
||
|
ScoreIn[SCORES::stamina]= pIM->getDbProp(baseDBin+staDB, false);
|
||
|
if(!focusDB.empty())
|
||
|
ScoreIn[SCORES::focus]= pIM->getDbProp(baseDBin+focusDB, false);
|
||
|
}
|
||
|
|
||
|
// try to connect each output entry (don't create)
|
||
|
if(!baseDBout.empty())
|
||
|
{
|
||
|
if(!hpDB.empty())
|
||
|
ScoreOut[SCORES::hit_points]= pIM->getDbProp(baseDBout+hpDB, false);
|
||
|
if(!sapDB.empty())
|
||
|
ScoreOut[SCORES::sap]= pIM->getDbProp(baseDBout+sapDB, false);
|
||
|
if(!staDB.empty())
|
||
|
ScoreOut[SCORES::stamina]= pIM->getDbProp(baseDBout+staDB, false);
|
||
|
if(!focusDB.empty())
|
||
|
ScoreOut[SCORES::focus]= pIM->getDbProp(baseDBout+focusDB, false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::CBarDataEntry::flushDBOut()
|
||
|
{
|
||
|
for(uint sc=0;sc<SCORES::NUM_SCORES;sc++)
|
||
|
{
|
||
|
if(ScoreOut[sc])
|
||
|
ScoreOut[sc]->setValue8(BarInfo.Score[sc]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::CBarDataEntry::modifyFromDBIn(CBarInfo &barInfo) const
|
||
|
{
|
||
|
for(uint sc=0;sc<SCORES::NUM_SCORES;sc++)
|
||
|
{
|
||
|
if(ScoreIn[sc])
|
||
|
barInfo.Score[sc]= ScoreIn[sc]->getValue8();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// ***************************************************************************
|
||
|
// ***************************************************************************
|
||
|
// ***************************************************************************
|
||
|
// ***************************************************************************
|
||
|
|
||
|
|
||
|
// ***************************************************************************
|
||
|
CBarManager::CBarManager()
|
||
|
{
|
||
|
// if more than 256 entities, must change MaxEntity
|
||
|
nlctassert(sizeof(CLFECOMMON::TCLEntityId)==1);
|
||
|
|
||
|
// Allocate the array now
|
||
|
nlctassert(MaxEntryType==4);
|
||
|
_EntryBars[EntityType].resize(MaxEntity);
|
||
|
_EntryBars[TeamMemberType].resize(MaxTeamMember);
|
||
|
_EntryBars[AnimalType].resize(MaxAnimal);
|
||
|
_EntryBars[TargetType].resize(MaxTarget);
|
||
|
|
||
|
// no msg still sent
|
||
|
_LastUserBarMsgNumber= 0;
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::releaseInstance()
|
||
|
{
|
||
|
if( _Instance )
|
||
|
{
|
||
|
delete _Instance;
|
||
|
_Instance = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::initInGame()
|
||
|
{
|
||
|
CInterfaceManager *pIM= CInterfaceManager::getInstance();
|
||
|
|
||
|
//resetShardSpecificData(); // directly called by CFarTP::disconnectFromPreviousShard()
|
||
|
|
||
|
/* *** Verify that MaxTeamMember is correct according to database
|
||
|
change MaxTeamMember if no more the case
|
||
|
*/
|
||
|
uint i=0;
|
||
|
while( pIM->getDbProp(toString("SERVER:GROUP:%d:NAME", i), false) )
|
||
|
i++;
|
||
|
nlassert(i==MaxTeamMember);
|
||
|
|
||
|
|
||
|
// *** create connexion to the Local Output database
|
||
|
for(i=0;i<_EntryBars[TeamMemberType].size();i++)
|
||
|
{
|
||
|
// don't connect FOCUS, since not setuped by SERVER
|
||
|
_EntryBars[TeamMemberType][i].connectDB(
|
||
|
toString("SERVER:GROUP:%d:",i),
|
||
|
toString("UI:VARIABLES:BARS:TEAM:%d:",i),
|
||
|
"PRESENT",
|
||
|
"HP", "SAP", "STA", "");
|
||
|
}
|
||
|
for(i=0;i<_EntryBars[AnimalType].size();i++)
|
||
|
{
|
||
|
// don't connect STA, SAP and FOCUS for animal, since they don't have
|
||
|
_EntryBars[AnimalType][i].connectDB(
|
||
|
toString("SERVER:PACK_ANIMAL:BEAST%d:",i),
|
||
|
toString("UI:VARIABLES:BARS:ANIMAL:%d:",i),
|
||
|
"STATUS",
|
||
|
"HP", "", "", "");
|
||
|
}
|
||
|
nlassert(_EntryBars[TargetType].size()==1);
|
||
|
_EntryBars[TargetType][0].connectDB(
|
||
|
"SERVER:TARGET:BARS:",
|
||
|
"UI:VARIABLES:BARS:TARGET:",
|
||
|
"", // no present flag for target (not so important)
|
||
|
"HP", "SAP", "STA", "FOCUS");
|
||
|
|
||
|
// NB: don't connect the DB for entities, since CEntityCL read it directly from getBarsByEntityId() (simpler and faster)
|
||
|
|
||
|
|
||
|
// *** init _EntryScoreFlags
|
||
|
nlctassert(MaxEntryType==4);
|
||
|
nlctassert(SCORES::NUM_SCORES==4);
|
||
|
// For each entry type, tells what score they can affect (see DB connection above)
|
||
|
_EntryScoreFlags[EntityType]= HpFlag | SapFlag | StaFlag | FocusFlag; // all
|
||
|
_EntryScoreFlags[TeamMemberType]= HpFlag | SapFlag | StaFlag; // anything but focus
|
||
|
_EntryScoreFlags[AnimalType]= HpFlag; // Hp only
|
||
|
_EntryScoreFlags[TargetType]= HpFlag | SapFlag | StaFlag | FocusFlag; // all
|
||
|
|
||
|
|
||
|
// *** create connexion for User Bar mgt
|
||
|
// user now can only manage 4 scores
|
||
|
nlctassert(SCORES::NUM_SCORES==4);
|
||
|
// Input max values
|
||
|
_UserScores[SCORES::hit_points].DBInMax= pIM->getDbProp("SERVER:CHARACTER_INFO:SCORES0:Max", false);
|
||
|
_UserScores[SCORES::sap].DBInMax= pIM->getDbProp("SERVER:CHARACTER_INFO:SCORES2:Max", false);
|
||
|
_UserScores[SCORES::stamina].DBInMax= pIM->getDbProp("SERVER:CHARACTER_INFO:SCORES1:Max", false);
|
||
|
_UserScores[SCORES::focus].DBInMax= pIM->getDbProp("SERVER:CHARACTER_INFO:SCORES3:Max", false);
|
||
|
// Output real values
|
||
|
_UserScores[SCORES::hit_points].DBOutVal= pIM->getDbProp("UI:VARIABLES:USER:HP", false);
|
||
|
_UserScores[SCORES::sap].DBOutVal= pIM->getDbProp("UI:VARIABLES:USER:SAP", false);
|
||
|
_UserScores[SCORES::stamina].DBOutVal= pIM->getDbProp("UI:VARIABLES:USER:STA", false);
|
||
|
_UserScores[SCORES::focus].DBOutVal= pIM->getDbProp("UI:VARIABLES:USER:FOCUS", false);
|
||
|
// Output ratio values
|
||
|
_UserScores[SCORES::hit_points].DBOutRatio= pIM->getDbProp("UI:VARIABLES:USER:HP_RATIO", false);
|
||
|
_UserScores[SCORES::sap].DBOutRatio= pIM->getDbProp("UI:VARIABLES:USER:SAP_RATIO", false);
|
||
|
_UserScores[SCORES::stamina].DBOutRatio= pIM->getDbProp("UI:VARIABLES:USER:STA_RATIO", false);
|
||
|
_UserScores[SCORES::focus].DBOutRatio= pIM->getDbProp("UI:VARIABLES:USER:FOCUS_RATIO", false);
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::releaseInGame()
|
||
|
{
|
||
|
// Reset all, and also the DB out
|
||
|
for(uint type=0;type<MaxEntryType;type++)
|
||
|
{
|
||
|
for(uint i=0;i<_EntryBars[type].size();i++)
|
||
|
{
|
||
|
_EntryBars[type][i].clear();
|
||
|
_EntryBars[type][i].resetDB();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Reset the map
|
||
|
_UIDBars.clear();
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::resetShardSpecificData()
|
||
|
{
|
||
|
// Reset update counter to update properly when reselecting character
|
||
|
_LastUserBarMsgNumber = 0;
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::addEntry(TEntryType type, uint entryId, uint dataSetId)
|
||
|
{
|
||
|
std::vector<CBarDataEntry> &entryArray= _EntryBars[type];
|
||
|
nlassert(entryId<entryArray.size());
|
||
|
|
||
|
barInfoLog("BARS: addEntry(%s, eid=%d, dsid=%x)", entryTypeToStr(type), entryId, dataSetId);
|
||
|
|
||
|
// if bad id, quit
|
||
|
if(dataSetId==CLFECOMMON::INVALID_CLIENT_DATASET_INDEX)
|
||
|
return;
|
||
|
// if already registered, quit
|
||
|
if(entryArray[entryId].DataSetId==dataSetId)
|
||
|
return;
|
||
|
|
||
|
// remove the preceding entry, reseting values if necessary
|
||
|
delEntry(type, entryId);
|
||
|
|
||
|
// Add me to list of entries
|
||
|
CBarDataEntry &bde= entryArray[entryId];
|
||
|
bde.DataSetId= dataSetId;
|
||
|
// Add the entry connexion to map by DataSetId
|
||
|
CBarDataUID &barUID= _UIDBars[dataSetId];
|
||
|
barUID.EntryId[type].insert(entryId);
|
||
|
|
||
|
// Special case: if the entry added is the user (slot 0), then force the correct bars info
|
||
|
// This is important because the UserEntity can be created AFTER the receive of USER:BARS message.
|
||
|
if(dataSetId==_EntryBars[EntityType][0].DataSetId)
|
||
|
{
|
||
|
barUID.BarInfo= _UserBarInfo;
|
||
|
}
|
||
|
|
||
|
// Copy the current Bar Info from the map by dataSetId in case it exists before...
|
||
|
// Eg: an entity comes in vision (EntityType entry) while precedingly available in TeamMemberType Entry
|
||
|
bde.BarInfo= barUID.BarInfo;
|
||
|
// then report to DB (if any)
|
||
|
bde.flushDBOut();
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::delEntry(TEntryType type, uint entryId)
|
||
|
{
|
||
|
std::vector<CBarDataEntry> &entryArray= _EntryBars[type];
|
||
|
nlassert(entryId<entryArray.size());
|
||
|
|
||
|
barInfoLog("BARS: delEntry(%s, eid=%d)", entryTypeToStr(type), entryId);
|
||
|
|
||
|
// if a DataSetId was registered before
|
||
|
uint dataSetId= entryArray[entryId].DataSetId;
|
||
|
if(dataSetId!=CLFECOMMON::INVALID_CLIENT_DATASET_INDEX)
|
||
|
{
|
||
|
// then unconnect this from the map by UID
|
||
|
_UIDBars[dataSetId].EntryId[type].erase(entryId);
|
||
|
// if no more connexion are made to this UID
|
||
|
if(_UIDBars[dataSetId].noMoreEntry())
|
||
|
{
|
||
|
// erase it
|
||
|
_UIDBars.erase(dataSetId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// clear entry
|
||
|
entryArray[entryId].clear();
|
||
|
// flush the clear to the DB if any
|
||
|
entryArray[entryId].flushDBOut();
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::addEntity(CLFECOMMON::TCLEntityId entityId, uint dataSetId)
|
||
|
{
|
||
|
addEntry(EntityType, entityId, dataSetId);
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::delEntity(CLFECOMMON::TCLEntityId entityId)
|
||
|
{
|
||
|
delEntry(EntityType, entityId);
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::addTeamMember(uint teamMemberId, uint dataSetId)
|
||
|
{
|
||
|
addEntry(TeamMemberType, teamMemberId, dataSetId);
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::delTeamMember(uint teamMemberId)
|
||
|
{
|
||
|
delEntry(TeamMemberType, teamMemberId);
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::addAnimal(uint paId, uint dataSetId)
|
||
|
{
|
||
|
addEntry(AnimalType, paId, dataSetId);
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::delAnimal(uint paId)
|
||
|
{
|
||
|
delEntry(AnimalType, paId);
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::addTarget(uint dataSetId)
|
||
|
{
|
||
|
addEntry(TargetType, 0, dataSetId);
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::delTarget()
|
||
|
{
|
||
|
delEntry(TargetType, 0);
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::updateBars(uint dataSetId, CBarInfo barInfo, TGameCycle serverTick, uint scoreFlags)
|
||
|
{
|
||
|
// if dataSetId not registered, quit
|
||
|
TUIDToDatas::iterator it= _UIDBars.find(dataSetId);
|
||
|
if(it==_UIDBars.end())
|
||
|
return;
|
||
|
|
||
|
barInfoLog("BARS: updateBars(dsid=%x, biHP=%d, t=%d, sf=%x", dataSetId, barInfo.Score[SCORES::hit_points], serverTick, scoreFlags);
|
||
|
|
||
|
// special Case: if the info is for the User (slot 0)
|
||
|
if(dataSetId==_EntryBars[EntityType][0].DataSetId)
|
||
|
{
|
||
|
/* Then override the bar info with the one received by USER:BARS message (always take this one)
|
||
|
For instance user bars can be received from VP or from TARGET database (if he targets himself)
|
||
|
But always consider the message USER:BARS as the most accurate one
|
||
|
*/
|
||
|
barInfo= _UserBarInfo;
|
||
|
}
|
||
|
|
||
|
// fill bar info, with relevant values only
|
||
|
CBarDataUID &barUid= it->second;
|
||
|
for(uint sc=0;sc<SCORES::NUM_SCORES;sc++)
|
||
|
{
|
||
|
// if the update affect this score, and if the modification date is more recent (or at least the same)
|
||
|
if( (scoreFlags&(1<<sc)) && serverTick>=barUid.ScoreDate[sc] )
|
||
|
{
|
||
|
// then change this score with the more recent one!
|
||
|
barUid.ScoreDate[sc]= serverTick;
|
||
|
barUid.BarInfo.Score[sc]= barInfo.Score[sc];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// and report result to all connected entries
|
||
|
for(uint type=0;type<MaxEntryType;type++)
|
||
|
{
|
||
|
// For any connected entries of this type (see EntryId definitio why a set is necessary)
|
||
|
std::set<uint>::iterator itEid= barUid.EntryId[type].begin();
|
||
|
std::set<uint>::iterator itEidEnd= barUid.EntryId[type].end();
|
||
|
for(;itEid!=itEidEnd;itEid++)
|
||
|
{
|
||
|
uint entryId= *itEid;
|
||
|
nlassert(entryId<_EntryBars[type].size());
|
||
|
CBarDataEntry &bde= _EntryBars[type][entryId];
|
||
|
// copy the bar info (with relevant values)
|
||
|
bde.BarInfo= barUid.BarInfo;
|
||
|
// and flush DB (if any)
|
||
|
bde.flushDBOut();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::updateEntryFromDBNoAddDel(TEntryType type, CBarDataEntry &bde)
|
||
|
{
|
||
|
// get the Bar Info, from the input DB of this entry (only values linked)
|
||
|
CBarInfo barInfo;
|
||
|
bde.modifyFromDBIn(barInfo);
|
||
|
|
||
|
// Get the last DB modification server tick
|
||
|
TGameCycle serverTick= 0;
|
||
|
/* To do this, I test all DB input, and choose the highest changeDate
|
||
|
This works because the branch is atomic (all DB are relevant to the others, and
|
||
|
therefore relevant agst the most recent one)
|
||
|
*/
|
||
|
if(bde.UIDIn && bde.UIDIn->getLastChangeGC() > serverTick )
|
||
|
serverTick= bde.UIDIn->getLastChangeGC();
|
||
|
if(bde.PresentIn && bde.PresentIn->getLastChangeGC() > serverTick )
|
||
|
serverTick= bde.PresentIn->getLastChangeGC();
|
||
|
for(uint sc=0;sc<SCORES::NUM_SCORES;sc++)
|
||
|
{
|
||
|
if( bde.ScoreIn[sc] && bde.ScoreIn[sc]->getLastChangeGC() > serverTick )
|
||
|
serverTick= bde.ScoreIn[sc]->getLastChangeGC();
|
||
|
}
|
||
|
|
||
|
// then update the bars
|
||
|
updateBars(bde.DataSetId, barInfo, serverTick, _EntryScoreFlags[type] );
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::updateEntryFromDB(TEntryType type, uint entryId)
|
||
|
{
|
||
|
std::vector<CBarDataEntry> &entryArray= _EntryBars[type];
|
||
|
nlassert(entryId<entryArray.size());
|
||
|
CBarDataEntry &bde= entryArray[entryId];
|
||
|
|
||
|
// if the UID db was not found, can't do nothing... => abort
|
||
|
if(bde.UIDIn==NULL)
|
||
|
return;
|
||
|
|
||
|
// get the new UID from the SERVER DB
|
||
|
uint newDataSetId= bde.UIDIn->getValue32();
|
||
|
// if present flag is linked, and if 0, then force invalid data set id
|
||
|
if(bde.PresentIn && bde.PresentIn->getValue32()==0)
|
||
|
newDataSetId= CLFECOMMON::INVALID_CLIENT_DATASET_INDEX;
|
||
|
|
||
|
// *** if the data set id does not correspond as the cached one
|
||
|
if(newDataSetId!=bde.DataSetId)
|
||
|
{
|
||
|
// if deleted, delete this entry
|
||
|
if(newDataSetId==CLFECOMMON::INVALID_CLIENT_DATASET_INDEX)
|
||
|
delEntry(type, entryId);
|
||
|
// else add
|
||
|
else
|
||
|
addEntry(type, entryId, newDataSetId);
|
||
|
// should be changed
|
||
|
nlassert(bde.DataSetId==newDataSetId);
|
||
|
}
|
||
|
|
||
|
// *** update from DB
|
||
|
if(newDataSetId!=CLFECOMMON::INVALID_CLIENT_DATASET_INDEX)
|
||
|
{
|
||
|
updateEntryFromDBNoAddDel(type, bde);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::updateTeamMemberFromDB(uint teamMemberId)
|
||
|
{
|
||
|
updateEntryFromDB(TeamMemberType, teamMemberId);
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::updateAnimalFromDB(uint paId)
|
||
|
{
|
||
|
updateEntryFromDB(AnimalType, paId);
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::updateTargetFromDB()
|
||
|
{
|
||
|
/* Special case for Target. The DataSetId is not replaced with those in DB (setuped with setLocalTarget())
|
||
|
Instead, we ensure that the 2 match, else ignore DB change
|
||
|
*/
|
||
|
CBarDataEntry &bde= _EntryBars[TargetType][0];
|
||
|
|
||
|
// if the UID db was not found, can't do nothing... => abort
|
||
|
if(bde.UIDIn==NULL)
|
||
|
return;
|
||
|
|
||
|
// get the new UID from the SERVER DB
|
||
|
uint serverDataSetId= bde.UIDIn->getValue32();
|
||
|
|
||
|
barInfoLog("BARS: updateTargetFromDB(dsid=%x)", serverDataSetId);
|
||
|
|
||
|
// *** if the server data set id correspond to the local one (and not invalid), update from DB
|
||
|
if(serverDataSetId==bde.DataSetId && serverDataSetId!=CLFECOMMON::INVALID_CLIENT_DATASET_INDEX)
|
||
|
{
|
||
|
updateEntryFromDBNoAddDel(TargetType, bde);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::setLocalTarget(uint dataSetId)
|
||
|
{
|
||
|
CBarDataEntry &bde= _EntryBars[TargetType][0];
|
||
|
|
||
|
barInfoLog("BARS: setLocalTarget(dsid=%x)", dataSetId);
|
||
|
|
||
|
// *** if the data set id does not correspond as the cached one
|
||
|
if(dataSetId!=bde.DataSetId)
|
||
|
{
|
||
|
// if deleted, delete this entry
|
||
|
if(dataSetId==CLFECOMMON::INVALID_CLIENT_DATASET_INDEX)
|
||
|
delEntry(TargetType, 0);
|
||
|
// else add
|
||
|
else
|
||
|
addEntry(TargetType, 0, dataSetId);
|
||
|
// should be changed
|
||
|
nlassert(bde.DataSetId==dataSetId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
CBarManager::CBarInfo CBarManager::getBarsByEntityId(CLFECOMMON::TCLEntityId entityId) const
|
||
|
{
|
||
|
const std::vector<CBarDataEntry> &entityBars= _EntryBars[EntityType];
|
||
|
nlassert(entityId<entityBars.size());
|
||
|
|
||
|
return entityBars[entityId].BarInfo;
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::setupUserBarInfo(uint8 msgNumber, sint32 hp, sint32 sap, sint32 sta, sint32 focus)
|
||
|
{
|
||
|
/*
|
||
|
Since we are not sure of the message order, use a little counter to discard old messages
|
||
|
suppose that cannot have more than a jump of 127 messages.
|
||
|
eg:
|
||
|
If i Receive: 0..1..4..3..2..5
|
||
|
This will be applied: 0..1..4........5
|
||
|
*/
|
||
|
|
||
|
// compute the difference beetween the msgNumber and the last received
|
||
|
sint32 diff;
|
||
|
if(msgNumber>=_LastUserBarMsgNumber)
|
||
|
diff= (sint32)msgNumber - (sint32)_LastUserBarMsgNumber;
|
||
|
else
|
||
|
diff= (sint32)msgNumber + 256 - (sint32)_LastUserBarMsgNumber;
|
||
|
// if too big difference, suppose a roll (eg last==255, cur=0, real diff==1)
|
||
|
if(diff>127)
|
||
|
diff-=256;
|
||
|
|
||
|
// if diff<0, means that the cur message is actually too old => discard
|
||
|
if(diff<0)
|
||
|
return;
|
||
|
else
|
||
|
{
|
||
|
// bkup last
|
||
|
_LastUserBarMsgNumber= msgNumber;
|
||
|
// user now can only manage 4 scores
|
||
|
nlctassert(SCORES::NUM_SCORES==4);
|
||
|
_UserScores[SCORES::hit_points].Score= hp;
|
||
|
_UserScores[SCORES::sap].Score= sap;
|
||
|
_UserScores[SCORES::stamina].Score= sta;
|
||
|
_UserScores[SCORES::focus].Score= focus;
|
||
|
|
||
|
// update actual database now.
|
||
|
for(uint i=0;i<SCORES::NUM_SCORES;i++)
|
||
|
{
|
||
|
// Clamp To 0, since used only by entries that don't need negative values (for comma mode)
|
||
|
if(_UserScores[i].DBOutVal) _UserScores[i].DBOutVal->setValue32(max((sint32)0,_UserScores[i].Score));
|
||
|
}
|
||
|
|
||
|
// Update the Player Entry
|
||
|
updateUserBars();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
void CBarManager::updateUserBars()
|
||
|
{
|
||
|
// for all scores
|
||
|
for(uint i=0;i<SCORES::NUM_SCORES;i++)
|
||
|
{
|
||
|
CUserScore &us= _UserScores[i];
|
||
|
|
||
|
// get max value
|
||
|
sint32 maxVal= 1;
|
||
|
if(us.DBInMax)
|
||
|
{
|
||
|
maxVal= us.DBInMax->getValue32();
|
||
|
maxVal= max((sint32)1, maxVal);
|
||
|
}
|
||
|
|
||
|
// setup signed ratio. It is used for the view of Player interface
|
||
|
if(us.DBOutRatio)
|
||
|
{
|
||
|
sint32 v= UserBarMaxRatio*us.Score / maxVal;
|
||
|
clamp(v, (sint32)-UserBarMaxRatio, (sint32)UserBarMaxRatio);
|
||
|
us.DBOutRatio->setValue32(v);
|
||
|
}
|
||
|
|
||
|
// compute signed ratio -127 / 127, for CBarInfo replace
|
||
|
{
|
||
|
sint32 v= 127*us.Score / maxVal;
|
||
|
clamp(v, -127, 127);
|
||
|
_UserBarInfo.Score[i]= (sint8)v;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// replace the user Entry with the bar info.
|
||
|
// This is used only for the view of bars InScene, and in case the user target himself
|
||
|
uint userDataSetId= _EntryBars[EntityType][0].DataSetId;
|
||
|
if(userDataSetId!=CLFECOMMON::INVALID_CLIENT_DATASET_INDEX)
|
||
|
{
|
||
|
// Do a little cheat: force the update by retrieving the last update time in the BarData
|
||
|
TUIDToDatas::iterator it= _UIDBars.find(userDataSetId);
|
||
|
if(it!=_UIDBars.end())
|
||
|
{
|
||
|
TGameCycle serverTick= 0;
|
||
|
for(uint sc=0;sc<SCORES::NUM_SCORES;sc++)
|
||
|
{
|
||
|
if(it->second.ScoreDate[sc] > serverTick)
|
||
|
serverTick= it->second.ScoreDate[sc];
|
||
|
}
|
||
|
|
||
|
// update (user can only manage 4 scores for now)
|
||
|
nlctassert(SCORES::NUM_SCORES==4);
|
||
|
updateBars(userDataSetId, _UserBarInfo, serverTick, HpFlag | SapFlag | StaFlag | FocusFlag);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ***************************************************************************
|
||
|
sint32 CBarManager::getUserScore(SCORES::TScores score)
|
||
|
{
|
||
|
nlassert((uint) score < SCORES::NUM_SCORES);
|
||
|
nlassert(_UserScores[score].DBOutVal); // initInGame() not called ?
|
||
|
return _UserScores[score].DBOutVal->getValue32();
|
||
|
}
|
||
|
|
||
|
|
||
|
// ***************************************************************************
|
||
|
// ***************************************************************************
|
||
|
// ACTION HANDLERS
|
||
|
// ***************************************************************************
|
||
|
// ***************************************************************************
|
||
|
|
||
|
|
||
|
|
||
|
// ***************************************************************************
|
||
|
DECLARE_INTERFACE_CONSTANT(getMaxAnimal, CBarManager::MaxAnimal);
|
||
|
DECLARE_INTERFACE_CONSTANT(getMaxTeamMember, CBarManager::MaxTeamMember);
|
||
|
|
||
|
|
||
|
// ***************************************************************************
|
||
|
class CAHBarManagerOnTarget : public IActionHandler
|
||
|
{
|
||
|
public:
|
||
|
virtual void execute(CCtrlBase * /* pCaller */, const string &/* Params */)
|
||
|
{
|
||
|
CBarManager::getInstance()->updateTargetFromDB();
|
||
|
}
|
||
|
};
|
||
|
REGISTER_ACTION_HANDLER(CAHBarManagerOnTarget, "bar_manager_on_target");
|
||
|
|
||
|
// ***************************************************************************
|
||
|
class CAHBarManagerOnTeam : public IActionHandler
|
||
|
{
|
||
|
public:
|
||
|
virtual void execute(CCtrlBase * /* pCaller */, const string &Params)
|
||
|
{
|
||
|
uint index;
|
||
|
fromString(Params, index);
|
||
|
if(index<CBarManager::MaxTeamMember)
|
||
|
CBarManager::getInstance()->updateTeamMemberFromDB(index);
|
||
|
}
|
||
|
};
|
||
|
REGISTER_ACTION_HANDLER(CAHBarManagerOnTeam, "bar_manager_on_team");
|
||
|
|
||
|
// ***************************************************************************
|
||
|
class CAHBarManagerOnAnimal : public IActionHandler
|
||
|
{
|
||
|
public:
|
||
|
virtual void execute(CCtrlBase * /* pCaller */, const string &Params)
|
||
|
{
|
||
|
uint index;
|
||
|
fromString(Params, index);
|
||
|
if(index<CBarManager::MaxAnimal)
|
||
|
CBarManager::getInstance()->updateAnimalFromDB(index);
|
||
|
}
|
||
|
};
|
||
|
REGISTER_ACTION_HANDLER(CAHBarManagerOnAnimal, "bar_manager_on_animal");
|
||
|
|
||
|
// ***************************************************************************
|
||
|
class CAHBarManagerOnUserScores : public IActionHandler
|
||
|
{
|
||
|
public:
|
||
|
virtual void execute(CCtrlBase * /* pCaller */, const string &/* Params */)
|
||
|
{
|
||
|
CBarManager::getInstance()->updateUserBars();
|
||
|
}
|
||
|
};
|
||
|
REGISTER_ACTION_HANDLER(CAHBarManagerOnUserScores, "bar_manager_on_user_scores");
|
||
|
|
||
|
|
||
|
|