1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-03 17:27:47 +00:00

Cleanups in player

This commit is contained in:
Mordred 2025-01-02 09:22:10 +01:00
parent 4a46b3dd80
commit 168cfb1a36
11 changed files with 196 additions and 147 deletions

View file

@ -38,6 +38,7 @@ namespace Sapphire::Common
const uint16_t ARRSIZE_ORCHESTRION = 40u;
const uint16_t ARRSIZE_MONSTERNOTE = 12u;
const uint16_t ARRSIZE_BORROWACTION = 10u;
const uint16_t ARRSIZE_CONDITION = 12u;
const uint8_t TOWN_COUNT = 6;

View file

@ -707,7 +707,7 @@ void BNpc::onDeath()
if( pPlayer )
{
playerMgr.onMobKill( *pPlayer, *this );
pPlayer->gainExp( paramGrowthInfo->data().BaseExp );
playerMgr.onGainExp( *pPlayer, paramGrowthInfo->data().BaseExp );
}
}

View file

@ -474,60 +474,6 @@ Player::Discovery& Player::getDiscoveryBitmask()
return m_discovery;
}
void Player::discover( int16_t mapId, int16_t subId )
{
auto& exdData = Common::Service< Data::ExdData >::ref();
int32_t offset;
auto info = exdData.getRow< Excel::Map >( mapId );
if( !info )
{
PlayerMgr::sendDebug( *this, "discover(): Could not obtain map data for map_id == {0}", mapId );
return;
}
const auto& mapData = info->data();
if( mapData.IsUint16Discovery )
offset = 2 * mapData.DiscoveryIndex;
else
offset = 320 + 4 * mapData.DiscoveryIndex;
uint16_t index;
uint8_t value;
Util::valueToFlagByteIndexValue( subId, value, index );
m_discovery[ offset + index ] |= value;
uint16_t level = getLevel();
uint32_t exp = ( exdData.getRow< Excel::ParamGrow >( level )->data().NextExp * 5 / 100 );
gainExp( exp );
// gain 10x additional EXP if entire map is completed
uint32_t mask = mapData.DiscoveryFlag;
uint32_t discoveredAreas;
if( info->data().IsUint16Discovery )
{
discoveredAreas = ( m_discovery[ offset + 1 ] << 8 ) | m_discovery[ offset ];
}
else
{
discoveredAreas = ( m_discovery[ offset + 3 ] << 24 ) |
( m_discovery[ offset + 2 ] << 16 ) |
( m_discovery[ offset + 1 ] << 8 ) |
m_discovery[ offset ];
}
bool allDiscovered = ( ( discoveredAreas & mask ) == mask );
if( allDiscovered )
{
gainExp( exp * 10 );
}
}
bool Player::isNewAdventurer() const
{
return m_bNewAdventurer;
@ -621,13 +567,13 @@ bool Player::hasMount( uint32_t mountId ) const
void Player::gainExp( uint32_t amount )
{
uint32_t currentExp = getExp();
uint32_t currentExp = getCurrentExp();
uint16_t level = getLevel();
auto currentClass = static_cast< uint8_t >( getClass() );
if( level >= Common::MAX_PLAYER_LEVEL )
{
setExp( 0 );
setCurrentExp( 0 );
if( currentExp != 0 )
Network::Util::Packet::sendActorControlSelf( *this, getId(), UpdateUiExp, currentClass, 0 );
@ -647,14 +593,14 @@ void Player::gainExp( uint32_t amount )
if( level + 1 >= Common::MAX_PLAYER_LEVEL )
amount = 0;
setExp( amount );
setCurrentExp( amount );
levelUp();
}
else
setExp( currentExp + amount );
setCurrentExp( currentExp + amount );
Network::Util::Packet::sendActorControlSelf( *this, getId(), GainExpMsg, currentClass, amount );
Network::Util::Packet::sendActorControlSelf( *this, getId(), UpdateUiExp, currentClass, getExp() );
Network::Util::Packet::sendActorControlSelf( *this, getId(), UpdateUiExp, currentClass, getCurrentExp() );
}
void Player::levelUp()
@ -696,14 +642,14 @@ bool Player::isClassJobUnlocked( Common::ClassJob classJob ) const
return getLevelForClass( classJob ) != 0;
}
uint32_t Player::getExp() const
uint32_t Player::getCurrentExp() const
{
auto& exdData = Common::Service< Data::ExdData >::ref();
uint8_t classJobIndex = exdData.getRow< Excel::ClassJob >( static_cast< uint8_t >( getClass() ) )->data().WorkIndex;
return m_expArray[ classJobIndex ];
}
void Player::setExp( uint32_t amount )
void Player::setCurrentExp( uint32_t amount )
{
auto& exdData = Common::Service< Data::ExdData >::ref();
uint8_t classJobIndex = exdData.getRow< Excel::ClassJob >( static_cast< uint8_t >( getClass() ) )->data().WorkIndex;
@ -1591,75 +1537,6 @@ Sapphire::Common::HuntingLogEntry& Player::getHuntingLogEntry( uint8_t index )
return m_huntingLogEntries[ index ];
}
void Player::updateHuntingLog( uint16_t id )
{
std::vector< uint32_t > rankRewards{ 2500, 10000, 20000, 30000, 40000 };
const auto maxRank = 4;
auto& pExdData = Common::Service< Data::ExdData >::ref();
// make sure we get the matching base-class if a job is being used
auto classJobInfo = pExdData.getRow< Excel::ClassJob >( static_cast< uint8_t >( getClass() ) );
if( !classJobInfo )
return;
auto currentClassId = classJobInfo->data().MainClass;
auto& logEntry = m_huntingLogEntries[ currentClassId - 1 ];
bool logChanged = false;
bool allSectionsComplete = true;
for( int i = 1; i <= 10; ++i )
{
bool sectionComplete = true;
bool sectionChanged = false;
auto monsterNoteId = static_cast< uint32_t >( classJobInfo->data().MainClass * 10000 + logEntry.rank * 10 + i );
auto note = pExdData.getRow< Excel::MonsterNote >( monsterNoteId );
// for classes that don't have entries, if the first fails the rest will fail
if( !note )
break;
for( auto x = 0; x < 4; ++x )
{
auto note1 = pExdData.getRow< Excel::MonsterNoteTarget >( note->data().Target[ x ] );
if( note1->data().Monster == id && logEntry.entries[ i - 1 ][ x ] < note->data().NeededKills[ x ] )
{
logEntry.entries[ i - 1 ][ x ]++;
Network::Util::Packet::sendActorControlSelf( *this, getId(), HuntingLogEntryUpdate, monsterNoteId, x, logEntry.entries[ i - 1 ][ x ] );
logChanged = true;
sectionChanged = true;
}
if( logEntry.entries[ i - 1 ][ x ] != note->data().NeededKills[ x ] )
sectionComplete = false;
}
if( logChanged && sectionComplete && sectionChanged )
{
Network::Util::Packet::sendActorControlSelf( *this, getId(), HuntingLogSectionFinish, monsterNoteId, i, 0 );
gainExp( note->data().RewardExp );
}
if( !sectionComplete )
{
allSectionsComplete = false;
}
}
if( logChanged && allSectionsComplete )
{
Network::Util::Packet::sendActorControlSelf( *this, getId(), HuntingLogRankFinish, 4 );
gainExp( rankRewards[ logEntry.rank ] );
if( logEntry.rank < 4 )
{
logEntry.rank++;
memset( logEntry.entries, 0, 40 );
Network::Util::Packet::sendActorControlSelf( *this, getId(), HuntingLogRankUnlock, currentClassId, logEntry.rank + 1, 0 );
}
}
if( logChanged )
Network::Util::Packet::sendHuntingLog( *this );
}
void Player::setActiveLand( uint8_t land, uint8_t ward )
{
m_activeLand.plot = land;

View file

@ -34,7 +34,7 @@ namespace Sapphire::Entity
using AetheryteList = std::array< uint8_t, Common::ARRSIZE_AETHERYTES >;
using UnlockList = std::array< uint8_t, Common::ARRSIZE_UNLOCKS >;
using OrchestrionList = std::array< uint8_t, Common::ARRSIZE_ORCHESTRION >;
using Condition = std::array< uint8_t, 12 >;
using Condition = std::array< uint8_t, Common::ARRSIZE_CONDITION >;
using ClassList = std::array< uint16_t, Common::ARRSIZE_CLASSJOB >;
using ExpList = std::array< uint32_t, Common::ARRSIZE_CLASSJOB >;
@ -215,10 +215,10 @@ namespace Sapphire::Entity
bool isClassJobUnlocked( Common::ClassJob classJob ) const;
/*! returns the exp of the currently active class / job */
uint32_t getExp() const;
uint32_t getCurrentExp() const;
/*! sets the exp of the currently active class / job */
void setExp( uint32_t amount );
void setCurrentExp( uint32_t amount );
/*! adds exp to the currently active class / job */
void gainExp( uint32_t amount );
@ -423,9 +423,6 @@ namespace Sapphire::Entity
/*! get homepoint */
uint8_t getHomepoint() const;
/*! discover subarea subid fo map map_id, also send udpate packet */
void discover( int16_t mapId, int16_t subId );
/*! return a reference to the discovery bitmask array */
Discovery& getDiscoveryBitmask();
@ -781,8 +778,6 @@ namespace Sapphire::Entity
Common::HuntingLogEntry& getHuntingLogEntry( uint8_t index );
void updateHuntingLog( uint16_t id );
uint64_t getPartyId() const;
void setPartyId( uint64_t partyId );

View file

@ -493,7 +493,7 @@ void Player::updateDbClass() const
//Exp = ?, Lvl = ?, BorrowAction = ? WHERE CharacterId = ? AND ClassIdx = ?
auto stmtS = db.getPreparedStatement( Db::CHARA_CLASS_UP );
stmtS->setInt( 1, getExp() );
stmtS->setInt( 1, getCurrentExp() );
stmtS->setInt( 2, getLevel() );
std::vector< uint8_t > borrowActionVec( borrowAction.size() * 4 );

View file

@ -3,7 +3,7 @@
#include <Service.h>
#include <Exd/ExdData.h>
#include <Util/Util.h>
#include <Territory/Land.h>
#include <Manager/TerritoryMgr.h>
@ -206,7 +206,7 @@ void PlayerMgr::onMobKill( Entity::Player& player, Entity::BNpc& bnpc )
scriptMgr.onBNpcKill( player, bnpc );
if( player.hasReward( Common::UnlockEntry::HuntingLog ) )
player.updateHuntingLog( bnpc.getBNpcNameId() );
onUpdateHuntingLog( player, bnpc.getBNpcNameId() );
}
void PlayerMgr::sendLoginMessage( Entity::Player& player )
@ -341,6 +341,99 @@ void PlayerMgr::checkAutoAttack( Entity::Player& player, uint64_t tickCount ) co
}
void PlayerMgr::onGainExp( Entity::Player& player, uint32_t exp )
{
uint32_t currentExp = player.getCurrentExp();
uint16_t level = player.getLevel();
auto currentClass = static_cast< uint8_t >( player.getClass() );
if( level >= Common::MAX_PLAYER_LEVEL )
{
player.setCurrentExp( 0 );
if( currentExp != 0 )
Network::Util::Packet::sendActorControlSelf( player, player.getId(), UpdateUiExp, currentClass, 0 );
return;
}
auto& exdData = Common::Service< Data::ExdData >::ref();
uint32_t neededExpToLevel = exdData.getRow< Excel::ParamGrow >( level )->data().NextExp;
uint32_t neededExpToLevelPlus1 = exdData.getRow< Excel::ParamGrow >( level + 1 )->data().NextExp;
if( ( currentExp + exp ) >= neededExpToLevel )
{
// levelup
exp = ( currentExp + exp - neededExpToLevel ) > neededExpToLevelPlus1 ? neededExpToLevelPlus1 - 1 : ( currentExp + exp - neededExpToLevel );
if( level + 1 >= Common::MAX_PLAYER_LEVEL )
exp = 0;
player.setCurrentExp( exp );
player.levelUp();
}
else
player.setCurrentExp( currentExp + exp );
Network::Util::Packet::sendActorControlSelf( player, player.getId(), GainExpMsg, currentClass, exp );
Network::Util::Packet::sendActorControlSelf( player, player.getId(), UpdateUiExp, currentClass, player.getCurrentExp() );
}
void PlayerMgr::onDiscoverArea( Entity::Player& player, int16_t mapId, int16_t subId )
{
auto& exdData = Common::Service< Data::ExdData >::ref();
int32_t offset;
auto info = exdData.getRow< Excel::Map >( mapId );
if( !info )
{
sendDebug( player, "discover(): Could not obtain map data for map_id == {0}", mapId );
return;
}
const auto& mapData = info->data();
if( mapData.IsUint16Discovery )
offset = 2 * mapData.DiscoveryIndex;
else
offset = 320 + 4 * mapData.DiscoveryIndex;
uint16_t index;
uint8_t value;
Common::Util::valueToFlagByteIndexValue( subId, value, index );
auto& discovery = player.getDiscoveryBitmask();
discovery[ offset + index ] |= value;
uint16_t level = player.getLevel();
uint32_t exp = ( exdData.getRow< Excel::ParamGrow >( level )->data().NextExp * 5 / 100 );
onGainExp( player, exp );
// gain 10x additional EXP if entire map is completed
uint32_t mask = mapData.DiscoveryFlag;
uint32_t discoveredAreas;
if( info->data().IsUint16Discovery )
{
discoveredAreas = ( discovery[ offset + 1 ] << 8 ) | discovery[ offset ];
}
else
{
discoveredAreas = ( discovery[ offset + 3 ] << 24 ) |
( discovery[ offset + 2 ] << 16 ) |
( discovery[ offset + 1 ] << 8 ) |
discovery[ offset ];
}
bool allDiscovered = ( ( discoveredAreas & mask ) == mask );
if( allDiscovered )
{
onGainExp( player, exp * 10 );
}
}
////////// Helper ///////////
@ -364,3 +457,75 @@ void PlayerMgr::sendLogMessage( Entity::Player& player, uint32_t messageId, uint
{
Network::Util::Packet::sendActorControlTarget( player, player.getId(), LogMsg, messageId, param2, param3, param4, param5, param6 );
}
void PlayerMgr::onUpdateHuntingLog( Entity::Player& player, uint8_t id )
{
std::vector< uint32_t > rankRewards{ 2500, 10000, 20000, 30000, 40000 };
const auto maxRank = 4;
auto& pExdData = Common::Service< Data::ExdData >::ref();
// make sure we get the matching base-class if a job is being used
auto classJobInfo = pExdData.getRow< Excel::ClassJob >( static_cast< uint8_t >( player.getClass() ) );
if( !classJobInfo )
return;
auto currentClassId = classJobInfo->data().MainClass;
auto& logEntry = player.getHuntingLogEntry( currentClassId - 1 );
bool logChanged = false;
bool allSectionsComplete = true;
for( int i = 1; i <= 10; ++i )
{
bool sectionComplete = true;
bool sectionChanged = false;
auto monsterNoteId = static_cast< uint32_t >( classJobInfo->data().MainClass * 10000 + logEntry.rank * 10 + i );
auto note = pExdData.getRow< Excel::MonsterNote >( monsterNoteId );
// for classes that don't have entries, if the first fails the rest will fail
if( !note )
break;
for( auto x = 0; x < 4; ++x )
{
auto note1 = pExdData.getRow< Excel::MonsterNoteTarget >( note->data().Target[ x ] );
if( note1->data().Monster == id && logEntry.entries[ i - 1 ][ x ] < note->data().NeededKills[ x ] )
{
logEntry.entries[ i - 1 ][ x ]++;
Network::Util::Packet::sendActorControlSelf( player, player.getId(), HuntingLogEntryUpdate, monsterNoteId, x, logEntry.entries[ i - 1 ][ x ] );
logChanged = true;
sectionChanged = true;
}
if( logEntry.entries[ i - 1 ][ x ] != note->data().NeededKills[ x ] )
sectionComplete = false;
}
if( logChanged && sectionComplete && sectionChanged )
{
Network::Util::Packet::sendActorControlSelf( player, player.getId(), HuntingLogSectionFinish, monsterNoteId, i, 0 );
onGainExp( player, note->data().RewardExp );
}
if( !sectionComplete )
{
allSectionsComplete = false;
}
}
if( logChanged && allSectionsComplete )
{
Network::Util::Packet::sendActorControlSelf( player, player.getId(), HuntingLogRankFinish, 4 );
onGainExp( player, rankRewards[ logEntry.rank ] );
if( logEntry.rank < 4 )
{
logEntry.rank++;
memset( logEntry.entries, 0, 40 );
Network::Util::Packet::sendActorControlSelf( player, player.getId(), HuntingLogRankUnlock, currentClassId, logEntry.rank + 1, 0 );
}
}
if( logChanged )
Network::Util::Packet::sendHuntingLog( player );
}

View file

@ -34,6 +34,12 @@ namespace Sapphire::World::Manager
void onUpdate( Sapphire::Entity::Player& player, uint64_t tickCount );
void onGainExp( Sapphire::Entity::Player& player, uint32_t exp );
void onDiscoverArea( Sapphire::Entity::Player& player, int16_t mapId, int16_t subId );
void onUpdateHuntingLog( Sapphire::Entity::Player& player, uint8_t id );
//////////// Helpers
static void sendServerNotice( Sapphire::Entity::Player& player, const std::string& message );

View file

@ -9,6 +9,8 @@
#include "Network/GameConnection.h"
#include <Manager/PlayerMgr.h>
#include "QuestMgr.h"
#include "AchievementMgr.h"
@ -60,6 +62,7 @@ void QuestMgr::onRemoveQuest( Entity::Player &player, uint8_t questIndex )
bool QuestMgr::giveQuestRewards( Entity::Player& player, uint16_t questId, uint32_t optionalChoice )
{
auto& playerMgr = Common::Service< World::Manager::PlayerMgr >::ref();
auto& exdData = Common::Service< Data::ExdData >::ref();
auto questInfo = exdData.getRow< Excel::Quest >( static_cast< uint32_t >( Event::EventHandler::EventHandlerType::Quest ) << 16 | questId );
@ -71,7 +74,9 @@ bool QuestMgr::giveQuestRewards( Entity::Player& player, uint16_t questId, uint3
// TODO: check if there is room in inventory, else return false;
if( exp > 0 )
player.gainExp( exp );
{
playerMgr.onGainExp( player, exp );
}
for( uint32_t i = 0; i < 6; i++ )
{

View file

@ -225,7 +225,7 @@ void Sapphire::Network::GameConnection::gmCommandHandler( const Packets::FFXIVAR
targetPlayer->getTerritoryTypeId(),
static_cast< uint8_t >( targetPlayer->getClass() ),
targetPlayer->getLevel(),
targetPlayer->getExp(),
targetPlayer->getCurrentExp(),
targetPlayer->getSearchMessage(),
targetPlayer->getPlayTime() );
break;
@ -307,7 +307,7 @@ void Sapphire::Network::GameConnection::gmCommandHandler( const Packets::FFXIVAR
}
case GmCommand::Exp:
{
targetPlayer->gainExp( param1 );
playerMgr().onGainExp( *targetPlayer, param1 );
PlayerMgr::sendServerNotice( player, "{0} Exp was added to {1}", param1, targetPlayer->getName());
break;
}

View file

@ -318,7 +318,7 @@ void Sapphire::Network::GameConnection::newDiscoveryHandler( const Packets::FFXI
discoveryPacket->data().mapId = tInfo->data().Map;
discoveryPacket->data().mapPartId = pRefInfo->data.discoveryIndex;
server().queueForPlayer( player.getCharacterId(), discoveryPacket );
player.discover( tInfo->data().Map, pRefInfo->data.discoveryIndex );
playerMgr().onDiscoverArea( player, tInfo->data().Map, pRefInfo->data.discoveryIndex );
}

View file

@ -84,7 +84,7 @@ void Util::Packet::sendStatusUpdate( Entity::Player& player )
playerStatusUpdate->data().Lv = player.getLevel();
playerStatusUpdate->data().Lv1 = player.getLevel();
playerStatusUpdate->data().LvSync = 0; //player.getLevelSync();
playerStatusUpdate->data().Exp = player.getExp();
playerStatusUpdate->data().Exp = player.getCurrentExp();
server().queueForPlayer( player.getCharacterId(), playerStatusUpdate );
}