khanat-code-old/code/ryzom/server/src/entities_game_service/death_penalties.cpp

207 lines
6.3 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/>.
// precompiled headers must be first
#include "stdpch.h"
// NeL MISC
#include "nel/misc/variable.h"
// Local
#include "death_penalties.h"
#include "player_manager/character.h"
#include "phrase_manager/phrase_utilities_functions.h"
#include "player_manager/item_service_manager.h"
#include "server_share/r2_variables.h"
NL_INSTANCE_COUNTER_IMPL(CDeathPenalties);
NLMISC::CVariable<bool> DissableDPInRing("egs", "DissableDPInRing", "Enable or dissable DP system in the Ring (should be dissabled unless this provokes bugs", true,0,true);
void CDeathPenalties::updataDb(CCharacter& user)
{
if ( _DeathXPToGain == 0 )
// user._PropertyDatabase.setProp( "USER:DEATH_XP_MALUS", 255 );
CBankAccessor_PLR::getUSER().setDEATH_XP_MALUS(user._PropertyDatabase, 255 );
else
// user._PropertyDatabase.setProp( "USER:DEATH_XP_MALUS", uint8( 254 * (1 - _CurrentDeathXP / _DeathXPToGain ) ) );
CBankAccessor_PLR::getUSER().setDEATH_XP_MALUS(user._PropertyDatabase, checkedCast<uint8>( 254 * (1 - _CurrentDeathXP / _DeathXPToGain ) ) );
}
void CDeathPenalties::addDeath(CCharacter& user, float deathPenaltyFactor )
{
// we don't add death penalty in the ring
if (IsRingShard && DissableDPInRing)
{
return;
}
// note that NB death is no more useful, but we keep it in serial until we have a better serial system
SKILLS::ESkills expSkill;
double maxXP = user.getSkills().getMaxXPToGain(expSkill);
_NbDeath++;
const double maxMalus = maxXP * user.getSkillBaseValue(expSkill);
double xpMalus = ((double)deathPenaltyFactor) * DeathXPFactor * maxMalus;
if ( xpMalus + _DeathXPToGain <= maxMalus )
_DeathXPToGain += xpMalus;
else
{
// cap death xp gain
xpMalus -= (maxMalus - _DeathXPToGain);
_DeathXPToGain = maxMalus;
// remove penalty surplus from already paid back Xp debt
if ( _CurrentDeathXP >= xpMalus )
_CurrentDeathXP -= xpMalus;
else
_CurrentDeathXP = 0.0;
}
updataDb(user);
if( _CurrentDeathXP || _DeathXPToGain )
{
SM_STATIC_PARAMS_2(params,STRING_MANAGER::integer,STRING_MANAGER::integer);
params[0].Int = sint32(10*_CurrentDeathXP);
params[1].Int = sint32(10*_DeathXPToGain);
CCharacter::sendDynamicSystemMessage( user.getId(),"DEATH_XP_DEATH",params);
}
}
uint32 CDeathPenalties::updateResorption( CCharacter& user )
{
// we don't add death penalty in the ring
if (IsRingShard && DissableDPInRing)
{
return 1800;
}
uint32 currentTime = NLMISC::CTime::getSecondsSince1970();
if ( _NbDeath && _BonusUpdateTime!=0 && _BonusUpdateTime<currentTime )
{
SKILLS::ESkills expSkill;
double maxXP = user.getSkills().getMaxXPToGain(expSkill);
double timeFactor = (double)(currentTime - _BonusUpdateTime) / (60.*60.*24. * user.getDPLossDuration());
const double maxMalus = maxXP * user.getSkillBaseValue(expSkill);
double xpBonus = ((double)timeFactor) * maxMalus;
addXP(user, SKILLS::unknown, xpBonus, xpBonus);
}
_BonusUpdateTime = currentTime;
if ( _NbDeath )
return 600;
else
return 1800;
}
void CDeathPenalties::addXP( CCharacter& user, SKILLS::ESkills usedSkill, double & xp )
{
// we don't add death penalty in the ring
if (IsRingShard && DissableDPInRing)
{
return;
}
if ( _NbDeath )
{
// we multiply gained xp by used skill level
const double skillBaseValue = user.getSkillBaseValue(usedSkill);
if (skillBaseValue <= 0)
{
nlwarning("Skill %s base value for char %s is <= 0 !!",SKILLS::toString(usedSkill).c_str(), user.getId().toString().c_str());
xp = 0;
return;
}
double xpBeforeDeathPenalty = xp;
double xpUsedForDeathPenalty = xp * _DeathPenaltyFactor;
xp -= xpUsedForDeathPenalty;
double tempXp = xpUsedForDeathPenalty * skillBaseValue;
addXP(user, usedSkill, tempXp, xpBeforeDeathPenalty);
xpUsedForDeathPenalty = tempXp / skillBaseValue;
xp += xpUsedForDeathPenalty;
}
}
void CDeathPenalties::addXP( CCharacter& user, SKILLS::ESkills usedSkill, double & xp, double xpRaw )
{
// we don't add death penalty in the ring
if (IsRingShard && DissableDPInRing)
{
return;
}
_CurrentDeathXP += xp;
if ( _CurrentDeathXP >= _DeathXPToGain )
{
// no more death penalties, only keep the xp surplus
xp = _CurrentDeathXP - _DeathXPToGain;
reset(user);
if( _CurrentDeathXP || _DeathXPToGain )
{
PHRASE_UTILITIES::sendDynamicSystemMessage(user.getEntityRowId(), "PROGRESS_DEATH_PENALTY_COMPLETE");
}
// consume SpeedUpDPLoss services
while (1)
{
const CStaticItem * form = CItemServiceManager::getInstance()->removePersistentService(ITEM_SERVICE_TYPE::SpeedUpDPLoss, &user);
if (form == NULL)
break;
SM_STATIC_PARAMS_1(params, STRING_MANAGER::item);
params[0].SheetId = form->SheetId;
PHRASE_UTILITIES::sendDynamicSystemMessage(user.getEntityRowId(), "ITEM_SERVICE_CONSUMED", params);
}
}
else
{
// Don't send message to user if the xp was penalty resorption
if (usedSkill!=SKILLS::unknown)
{
SM_STATIC_PARAMS_4(params, STRING_MANAGER::integer, STRING_MANAGER::skill, STRING_MANAGER::integer, STRING_MANAGER::integer);
params[0].Int = sint32(100*xpRaw);
params[1].Enum = usedSkill;
params[2].Int = sint32(10*xp);
params[3].Int = sint32(10*(_DeathXPToGain-_CurrentDeathXP) );
PHRASE_UTILITIES::sendDynamicSystemMessage(user.getEntityRowId(), "PROGRESS_DEATH_PENALTY_PAYBACK", params);
}
xp = 0.0;
updataDb(user);
}
}
CDeathPenaltiesTimerEvent::CDeathPenaltiesTimerEvent(CCharacter *parent)
{
_Parent = parent;
}
void CDeathPenaltiesTimerEvent::timerCallback(CTimer* owner)
{
H_AUTO(CDeathPenaltiesTimerEvent);
uint32 nextUpdate = _Parent->updateDeathPenaltyResorption();
owner->setRemaining(nextUpdate, this);
}