1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-25 02:57:45 +00:00

Merge branch 'master' of https://github.com/SapphireMordred/Sapphire into party_crap

This commit is contained in:
Maru 2017-12-07 11:22:09 -02:00
commit 899f0fa272
22 changed files with 424 additions and 395 deletions

View file

@ -22,7 +22,7 @@ When making a PR, please make sure that it follows our style guidelines and good
### Coding style
Indentations are Allman-style based, 4-space, no tabs.
Indentations are Allman-style based, 3-space, no tabs.
Space between arguments in function calls, as well as for types.
Example (shortened from ActionHandler.cpp):

View file

@ -7,6 +7,7 @@
<ListenIp>127.0.0.1</ListenIp>
<!-- Path of FFXIV dat files -->
<DataPath>C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv</DataPath>
<!-- <DataPath>/opt/sapphire_3_15_0/bin/sqpack</DataPath> -->
<!-- IP of the lobby server -->
<LobbyHost>127.0.0.1</LobbyHost>
<!-- IP of the frontier server -->

View file

@ -855,7 +855,7 @@ struct FFXIVIpcPlayerStats : FFXIVIpcBasePacket<PlayerStats>
uint32_t unknown;
uint32_t unknown_1;
uint32_t unknown_2;
uint32_t parry;
uint32_t tenacity;
uint32_t attack;
uint32_t defense;
uint32_t accuracy;
@ -877,7 +877,11 @@ struct FFXIVIpcPlayerStats : FFXIVIpcBasePacket<PlayerStats>
uint32_t skillSpeed;
uint32_t spellSpeed1;
uint32_t spellSpeedMod;
uint32_t unknown_6[5];
uint32_t unknown_6;
uint32_t craftsmanship;
uint32_t control;
uint32_t gathering;
uint32_t perception;
uint32_t resistanceSlow;
uint32_t resistanceSilence;
uint32_t resistanceBlind;
@ -886,7 +890,7 @@ struct FFXIVIpcPlayerStats : FFXIVIpcBasePacket<PlayerStats>
uint32_t resistanceSleep;
uint32_t resistanceBind;
uint32_t resistanceHeavy;
uint32_t unknown_7[9];
uint32_t unknown_7[9]; // possibly level sync stats.
};
/**
@ -921,10 +925,11 @@ struct FFXIVIpcPlayerStateFlags : FFXIVIpcBasePacket<PlayerStateFlags>
struct FFXIVIpcPlayerClassInfo : FFXIVIpcBasePacket<PlayerClassInfo>
{
uint16_t classId;
uint16_t unknown;
uint16_t level;
uint16_t level1;
uint8_t unknownFields[48];
uint8_t unknown;
uint8_t isSpecialist;
uint16_t level; // Locks actions, equipment, prob more
uint16_t level1; // Locks roles, prob more
uint32_t roleActions[10];
};
/**

View file

@ -200,7 +200,7 @@ void Core::Network::SapphireAPI::deleteCharacter( std::string name, uint32_t acc
g_charaDb.execute( "DELETE FROM charaitemcrystal WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charaiteminventory WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charaitemgearset WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charaquest WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
g_charaDb.execute( "DELETE FROM charaquestnew WHERE CharacterId LIKE '" + std::to_string( id ) + "';" );
}
std::vector< Core::PlayerMinimal > Core::Network::SapphireAPI::getCharList( uint32_t accountId )

View file

@ -15,7 +15,6 @@
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket144.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/UpdateHpMpTpPacket.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffect.h"
#include "src/servers/Server_Zone/Action/ActionCollision.h"
#include "src/servers/Server_Zone/ServerZone.h"
@ -33,6 +32,11 @@ using namespace Core::Network::Packets::Server;
Core::Entity::Actor::Actor()
{
// initialize the free slot queue
for( uint8_t i = 0; i < MAX_STATUS_EFFECTS; i++ )
{
m_statusEffectFreeSlotQueue.push( i );
}
}
Core::Entity::Actor::~Actor()
@ -794,7 +798,30 @@ void Core::Entity::Actor::handleScriptSkill( uint32_t type, uint16_t actionId, u
/*! \param StatusEffectPtr to be applied to the actor */
void Core::Entity::Actor::addStatusEffect( StatusEffect::StatusEffectPtr pEffect )
{
m_pStatusEffectContainer->addStatusEffect( pEffect );
int8_t nextSlot = getStatusEffectFreeSlot();
// if there is no slot left, do not add the effect
if( nextSlot == -1 )
return;
pEffect->applyStatus();
m_statusEffectMap[nextSlot] = pEffect;
ZoneChannelPacket< Server::FFXIVIpcAddStatusEffect > statusEffectAdd( getId() );
statusEffectAdd.data().actor_id = pEffect->getTargetActorId();
statusEffectAdd.data().actor_id1 = pEffect->getSrcActorId();
statusEffectAdd.data().current_hp = getHp();
statusEffectAdd.data().current_mp = getMp();
statusEffectAdd.data().current_tp = getTp();
statusEffectAdd.data().duration = static_cast< float >( pEffect->getDuration() ) / 1000;
statusEffectAdd.data().effect_id = pEffect->getId();
statusEffectAdd.data().effect_index = nextSlot;
statusEffectAdd.data().max_hp = getMaxHp();
statusEffectAdd.data().max_mp = getMaxMp();
statusEffectAdd.data().max_something = 1;
//statusEffectAdd.data().unknown2 = 28;
statusEffectAdd.data().param = pEffect->getParam();
sendToInRangeSet( statusEffectAdd, isPlayer() );
}
/*! \param StatusEffectPtr to be applied to the actor */
@ -809,7 +836,7 @@ void Core::Entity::Actor::addStatusEffectById( uint32_t id, int32_t duration, En
/*! \param StatusEffectPtr to be applied to the actor */
void Core::Entity::Actor::addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param )
{
if( !m_pStatusEffectContainer->hasStatusEffect( id ) )
if( !hasStatusEffect( id ) )
{
StatusEffect::StatusEffectPtr effect( new StatusEffect::StatusEffect( id, pSource.shared_from_this(),
shared_from_this(), duration, 3000 ) );
@ -818,17 +845,6 @@ void Core::Entity::Actor::addStatusEffectByIdIfNotExist( uint32_t id, int32_t du
}
}
/*! \param Status that should be removed, based on its ID. */
void Core::Entity::Actor::removeSingleStatusEffectFromId( uint32_t id )
{
m_pStatusEffectContainer->removeSingleStatusEffectFromId( id );
}
Core::StatusEffect::StatusEffectContainerPtr Core::Entity::Actor::getStatusEffectContainer() const
{
return m_pStatusEffectContainer;
}
float Core::Entity::Actor::getRotation() const
{
return m_rot;
@ -838,3 +854,154 @@ void Core::Entity::Actor::setRotation( float rot )
{
m_rot = rot;
}
int8_t Core::Entity::Actor::getStatusEffectFreeSlot()
{
int8_t freeEffectSlot = -1;
if( m_statusEffectFreeSlotQueue.empty() )
return freeEffectSlot;
freeEffectSlot = m_statusEffectFreeSlotQueue.front();
m_statusEffectFreeSlotQueue.pop();
return freeEffectSlot;
}
void Core::Entity::Actor::statusEffectFreeSlot( uint8_t slotId )
{
m_statusEffectFreeSlotQueue.push( slotId );
}
void Core::Entity::Actor::removeSingleStatusEffectById( uint32_t id )
{
for( auto effectIt : m_statusEffectMap )
{
if( effectIt.second->getId() == id )
{
removeStatusEffect( effectIt.first );
break;
}
}
}
void Core::Entity::Actor::removeStatusEffect( uint8_t effectSlotId )
{
auto pEffectIt = m_statusEffectMap.find( effectSlotId );
if( pEffectIt == m_statusEffectMap.end() )
return;
statusEffectFreeSlot( effectSlotId );
auto pEffect = pEffectIt->second;
pEffect->removeStatus();
sendToInRangeSet( ActorControlPacket142( getId(), StatusEffectLose, pEffect->getId() ), isPlayer() );
m_statusEffectMap.erase( effectSlotId );
sendStatusEffectUpdate();
}
std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > Core::Entity::Actor::getStatusEffectMap() const
{
return m_statusEffectMap;
}
void Core::Entity::Actor::sendStatusEffectUpdate()
{
uint64_t currentTimeMs = Util::getTimeMs();
ZoneChannelPacket< Server::FFXIVIpcStatusEffectList > statusEffectList( getId() );
statusEffectList.data().current_hp = getHp();
statusEffectList.data().current_mp = getMp();
statusEffectList.data().currentTp = getTp();
statusEffectList.data().max_hp = getMaxHp();
statusEffectList.data().max_mp = getMaxMp();
uint8_t slot = 0;
for( auto effectIt : m_statusEffectMap )
{
float timeLeft = static_cast< float >( effectIt.second->getDuration() -
( currentTimeMs - effectIt.second->getStartTimeMs() ) ) / 1000;
statusEffectList.data().effect[slot].duration = timeLeft;
statusEffectList.data().effect[slot].effect_id = effectIt.second->getId();
statusEffectList.data().effect[slot].sourceActorId = effectIt.second->getSrcActorId();
slot++;
}
sendToInRangeSet( statusEffectList, isPlayer() );
}
void Core::Entity::Actor::updateStatusEffects()
{
uint64_t currentTimeMs = Util::getTimeMs();
uint32_t thisTickDmg = 0;
uint32_t thisTickHeal = 0;
for( auto effectIt : m_statusEffectMap )
{
uint8_t effectIndex = effectIt.first;
auto effect = effectIt.second;
uint64_t lastTick = effect->getLastTickMs();
uint64_t startTime = effect->getStartTimeMs();
uint32_t duration = effect->getDuration();
uint32_t tickRate = effect->getTickRate();
if( ( currentTimeMs - startTime ) > duration )
{
// remove status effect
removeStatusEffect( effectIndex );
// break because removing invalidates iterators
break;
}
if( ( currentTimeMs - lastTick ) > tickRate )
{
effect->setLastTick( currentTimeMs );
effect->onTick();
auto thisEffect = effect->getTickEffect();
switch( thisEffect.first )
{
case 1:
{
thisTickDmg += thisEffect.second;
break;
}
case 2:
{
thisTickHeal += thisEffect.second;
break;
}
}
}
}
if( thisTickDmg != 0 )
{
takeDamage( thisTickDmg );
sendToInRangeSet( ActorControlPacket142( getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Damage ), thisTickDmg ) );
}
if( thisTickHeal != 0 )
{
heal( thisTickDmg );
sendToInRangeSet( ActorControlPacket142( getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Heal ), thisTickHeal ) );
}
}
bool Core::Entity::Actor::hasStatusEffect( uint32_t id )
{
if( m_statusEffectMap.find( id ) != m_statusEffectMap.end() )
return true;
return false;
}

View file

@ -7,6 +7,7 @@
#include "src/servers/Server_Zone/Forwards.h"
#include <set>
#include <map>
#include <queue>
namespace Core {
namespace Entity {
@ -79,7 +80,7 @@ public:
uint32_t mnd = 0;
uint32_t pie = 0;
uint32_t parry = 0;
uint32_t tenacity = 0;
uint32_t attack = 0;
uint32_t defense = 0;
uint32_t accuracy = 0;
@ -160,11 +161,15 @@ protected:
uint64_t m_targetId;
/*! Ptr to a queued action */
Action::ActionPtr m_pCurrentAction;
/*! Container for status effects */
StatusEffect::StatusEffectContainerPtr m_pStatusEffectContainer;
/*! Invincibility type */
Common::InvincibilityType m_invincibilityType;
/*! Status effects */
const uint8_t MAX_STATUS_EFFECTS = 30;
std::queue< uint8_t > m_statusEffectFreeSlotQueue;
std::vector< std::pair< uint8_t, uint32_t> > m_statusEffectList;
std::map< uint8_t, StatusEffect::StatusEffectPtr > m_statusEffectMap;
public:
Actor();
@ -174,6 +179,30 @@ public:
uint32_t getId() const;
/// Status effect functions
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
void removeStatusEffect( uint8_t effectSlotId );
void removeSingleStatusEffectById( uint32_t id );
void updateStatusEffects();
bool hasStatusEffect( uint32_t id );
int8_t getStatusEffectFreeSlot();
void statusEffectFreeSlot( uint8_t slotId );
std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > getStatusEffectMap() const;
void sendStatusEffectUpdate();
// add a status effect by id
void addStatusEffectById( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 );
// add a status effect by id if it doesn't exist
void addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 );
// remove a status effect by id
void removeSingleStatusEffectFromId( uint32_t id );
/// End Status Effect Functions
void setPosition( const Common::FFXIVARR_POSITION3& pos );
void setPosition( float x, float y, float z );
@ -303,20 +332,6 @@ public:
// set the current cell
void setCell( Cell* pCell );
// add a status effect
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
// add a status effect by id
void addStatusEffectById( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 );
// add a status effect by id if it doesn't exist
void addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 );
// remove a status effect by id
void removeSingleStatusEffectFromId( uint32_t id );
//get the status effect container
StatusEffect::StatusEffectContainerPtr getStatusEffectContainer() const;
// TODO: Why did i even declare them publicly here?!
std::set< ActorPtr > m_inRangeActors;

View file

@ -15,7 +15,6 @@
#include "src/servers/Server_Zone/Network/PacketWrappers/MoveActorPacket.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket142.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h"
using namespace Core::Common;
using namespace Core::Network::Packets;
@ -40,7 +39,7 @@ Core::Entity::BattleNpc::~BattleNpc()
Core::Entity::BattleNpc::BattleNpc( uint16_t modelId, uint16_t nameid, const Common::FFXIVARR_POSITION3& spawnPos,
uint16_t bnpcBaseId, uint32_t type, uint8_t level, uint8_t behaviour,
uint32_t mobType )
uint32_t mobType ) : Actor()
{
BattleNpc::m_nextID++;
m_id = BattleNpc::m_nextID;
@ -87,11 +86,6 @@ Core::Entity::BattleNpc::BattleNpc( uint16_t modelId, uint16_t nameid, const Com
}
void Core::Entity::BattleNpc::initStatusEffectContainer()
{
m_pStatusEffectContainer = StatusEffect::StatusEffectContainerPtr( new StatusEffect::StatusEffectContainer( shared_from_this() ) );
}
// spawn this player for pTarget
void Core::Entity::BattleNpc::spawn( Core::Entity::PlayerPtr pTarget )
{
@ -487,9 +481,7 @@ void Core::Entity::BattleNpc::update( int64_t currTime )
return;
}
if ( !m_pStatusEffectContainer )
initStatusEffectContainer();
m_pStatusEffectContainer->update();
updateStatusEffects();
float distance = Math::Util::distance( m_pos.x, m_pos.y, m_pos.z,
m_posOrigin.x, m_posOrigin.y, m_posOrigin.z );

View file

@ -31,8 +31,6 @@
#include "src/servers/Server_Zone/Script/ScriptManager.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h"
#include "src/servers/Server_Zone/Inventory/Item.h"
#include "src/servers/Server_Zone/Inventory/Inventory.h"
@ -57,6 +55,7 @@ using namespace Core::Network::Packets::Server;
// player constructor
Core::Entity::Player::Player() :
Actor(),
m_lastWrite( 0 ),
m_lastPing( 0 ),
m_bIsLogin( false ),
@ -243,6 +242,7 @@ void Core::Entity::Player::calculateStats()
m_baseStats.critHitRate = paramGrowthInfo.base_secondary;
m_baseStats.attackPotMagic = paramGrowthInfo.base_secondary;
m_baseStats.healingPotMagic = paramGrowthInfo.base_secondary;
m_baseStats.tenacity = paramGrowthInfo.base_secondary;
m_baseStats.max_mp = Math::CalcStats::calculateMaxMp( getAsPlayer() );
@ -440,6 +440,9 @@ void Core::Entity::Player::setZone( uint32_t zoneId )
gcAffPacket.data().gcRank[1] = m_gcRank[1];
gcAffPacket.data().gcRank[2] = m_gcRank[2];
queuePacket( gcAffPacket );
m_itemLevel = getInventory()->calculateEquippedGearItemLevel();
sendItemLevel();
}
ZoneChannelPacket< FFXIVIpcInitZone > initZonePacket( getId() );
@ -1050,7 +1053,7 @@ void Core::Entity::Player::update( int64_t currTime )
if( !isAlive() )
return;
m_pStatusEffectContainer->update();
updateStatusEffects();
m_lastUpdate = currTime;
@ -1583,6 +1586,11 @@ void Core::Entity::Player::setOpeningSequence( uint8_t seq )
m_openingSequence = seq;
}
uint16_t Core::Entity::Player::getItemLevel() const
{
return m_itemLevel;
}
/// Tells client to offset their eorzean time by given timestamp.
void Core::Entity::Player::setEorzeaTimeOffset( uint64_t timestamp )
{

View file

@ -208,6 +208,10 @@ public:
void unequipItem( Inventory::EquipSlot equipSlotId, ItemPtr pItem );
/*! equip a weapon, possibly forcing a job change */
void equipWeapon( ItemPtr pItem );
/*! get player ilvl */
uint16_t getItemLevel() const;
/*! send player ilvl */
void sendItemLevel();
/*! get a const pointer to the inventory object */
InventoryPtr getInventory() const;
/*! get the current main hand model */
@ -599,16 +603,20 @@ private:
uint8_t m_openingSequence;
uint16_t m_itemLevel;
InventoryPtr m_pInventory;
std::map< uint32_t, Event::EventPtr > m_eventMap;
std::map< uint32_t, uint8_t > m_playerIdToSpawnIdMap; // maps player to spawn id
std::queue< uint8_t > m_freeSpawnIdQueue; // queue with spawn ids free to be assigned
std::queue< uint8_t > m_freeHateSlotQueue; // queue with "hate slots" free to be assigned
std::map< uint32_t, uint8_t > m_actorIdTohateSlotMap;
std::map< uint32_t, uint8_t > m_questIdToQuestIdx; // quest mapping, quest id to quest container index
std::map< uint8_t, uint32_t > m_questIdxToQuestId; // quest mapping, quest container index to questId
boost::shared_ptr< Common::QuestActive > m_activeQuests[30];
int16_t m_questTracking[5];
uint8_t m_stateFlags[7];
uint8_t m_gmRank;
uint16_t zoneId;

View file

@ -1,17 +1,21 @@
#include <src/servers/Server_Common/Common.h>
#include <src/servers/Server_Common/Exd/ExdData.h>
#include <src/servers/Server_Common/Network/GamePacket.h>
#include <src/servers/Server_Common/Logging/Logger.h>
#include "Player.h"
#include "src/servers/Server_Zone/Zone/ZoneMgr.h"
#include "src/servers/Server_Zone/Zone/Zone.h"
#include <src/servers/Server_Common/Network/GamePacket.h>
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket142.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h"
#include "src/servers/Server_Zone/Inventory/Inventory.h"
#include "src/servers/Server_Zone/Inventory/Item.h"
extern Core::Logger g_log;
using namespace Core::Common;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;
@ -21,6 +25,11 @@ Core::InventoryPtr Core::Entity::Player::getInventory() const
return m_pInventory;
}
void Core::Entity::Player::sendItemLevel()
{
queuePacket( ActorControlPacket142( getId(), SetItemLevel, getItemLevel(), 0 ) );
}
// TODO: This has to be redone and simplified
void Core::Entity::Player::equipWeapon( Core::ItemPtr pItem )
{
@ -77,10 +86,10 @@ void Core::Entity::Player::equipWeapon( Core::ItemPtr pItem )
}
// equip an item
void Core::Entity::Player::equipItem( Inventory::EquipSlot equipSlotId, Core::ItemPtr pItem, bool sendModel )
void Core::Entity::Player::equipItem( Inventory::EquipSlot equipSlotId, Core::ItemPtr pItem, bool sendUpdate )
{
// Console->outDebOnly("Equipping into slot %i", equipSlotID);
//g_log.debug( "Equipping into slot " + std::to_string( equipSlotId ) );
uint64_t model = pItem->getModelId1();
uint64_t model2 = pItem->getModelId2();
@ -109,14 +118,21 @@ void Core::Entity::Player::equipItem( Inventory::EquipSlot equipSlotId, Core::It
}
if( sendModel )
if( sendUpdate )
{
this->sendModel();
m_itemLevel = getInventory()->calculateEquippedGearItemLevel();
sendItemLevel();
}
}
void Core::Entity::Player::unequipItem( Inventory::EquipSlot equipSlotId, ItemPtr pItem )
{
m_modelEquip[static_cast< uint8_t >( equipSlotId )] = 0;
sendModel();
m_itemLevel = getInventory()->calculateEquippedGearItemLevel();
sendItemLevel();
}
uint32_t Core::Entity::Player::getCurrency( uint8_t type ) const

View file

@ -26,7 +26,6 @@
#include "src/servers/Server_Zone/Network/GameConnection.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/InitUIPacket.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h"
#include "src/servers/Server_Zone/Inventory/Inventory.h"
#include <Server_Common/Database/DatabaseDef.h>
@ -178,7 +177,8 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession )
m_lastTickTime = 0;
auto pPlayer = getAsPlayer();
m_pInventory = InventoryPtr( new Inventory( pPlayer ) );
// TODO: remove Inventory and actually inline it in Player class
m_pInventory = InventoryPtr( new Inventory( pPlayer.get() ) );
pPlayer->calculateStats();
@ -211,8 +211,6 @@ bool Core::Entity::Player::load( uint32_t charId, Core::SessionPtr pSession )
initSpawnIdQueue();
m_pStatusEffectContainer = StatusEffect::StatusEffectContainerPtr( new StatusEffect::StatusEffectContainer( shared_from_this() ) );
if( !m_playerIdToSpawnIdMap.empty() )
m_playerIdToSpawnIdMap.clear();

View file

@ -13,6 +13,7 @@
#include "src/servers/Server_Zone/Network/PacketWrappers/ServerNoticePacket.h"
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/clamp.hpp>
#include "src/servers/Server_Zone/Forwards.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h"
@ -27,7 +28,7 @@ using namespace Core::Network;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;
Core::Inventory::Inventory( Core::Entity::PlayerPtr pOwner )
Core::Inventory::Inventory( Core::Entity::Player* pOwner )
{
m_pOwner = pOwner;
@ -438,6 +439,30 @@ bool Core::Inventory::removeCrystal( CrystalType type, uint32_t amount )
return true;
}
bool Core::Inventory::isOneHandedWeapon( ItemUICategory weaponCategory )
{
switch ( weaponCategory )
{
case ItemUICategory::AlchemistsPrimaryTool:
case ItemUICategory::ArmorersPrimaryTool:
case ItemUICategory::BotanistsPrimaryTool:
case ItemUICategory::CulinariansPrimaryTool:
case ItemUICategory::OnehandedConjurersArm:
case ItemUICategory::CarpentersPrimaryTool:
case ItemUICategory::FishersPrimaryTool:
case ItemUICategory::GladiatorsArm:
case ItemUICategory::GoldsmithsPrimaryTool:
case ItemUICategory::LeatherworkersPrimaryTool:
case ItemUICategory::MinersPrimaryTool:
case ItemUICategory::OnehandedThaumaturgesArm:
case ItemUICategory::WeaversPrimaryTool:
case ItemUICategory::BlacksmithsPrimaryTool:
return true;
default:
return false;
}
}
bool Core::Inventory::isObtainable( uint32_t catalogId, uint8_t quantity )
{
@ -450,7 +475,8 @@ int16_t Core::Inventory::addItem( uint16_t inventoryId, int8_t slotId, uint32_t
auto itemInfo = g_exdData.getItemInfo( catalogId );
if( !itemInfo )
// if item data doesn't exist or it's a blank field
if( !itemInfo || itemInfo->item_level == 0 )
{
return -1;
}
@ -828,6 +854,40 @@ void Core::Inventory::send()
}
uint16_t Core::Inventory::calculateEquippedGearItemLevel()
{
uint32_t iLvlResult = 0;
auto gearSetMap = m_inventoryMap[GearSet0]->getItemMap();
auto it = gearSetMap.begin();
while ( it != gearSetMap.end() )
{
auto currItem = it->second;
if ( currItem )
{
iLvlResult += currItem->getItemLevel();
// If item is weapon and isn't one-handed
if ( currItem->isWeapon() && !isOneHandedWeapon( currItem->getCategory() ) )
{
iLvlResult += currItem->getItemLevel();
}
else
{
g_log.debug( "Is one handed" );
}
}
it++;
}
return boost::algorithm::clamp( iLvlResult / 12, 0, 9999 );
}
uint8_t Core::Inventory::getFreeSlotsInBags()
{
uint8_t slots = 0;

View file

@ -13,7 +13,7 @@ using InventoryMap = std::map< uint16_t, ItemContainerPtr >;
class Inventory
{
public:
Inventory( Entity::PlayerPtr pOwner );
Inventory( Entity::Player* pOwner );
~Inventory();
enum ContainerType : uint16_t
@ -153,6 +153,10 @@ public:
bool updateContainer( uint16_t containerId, uint8_t slotId, ItemPtr pItem );
/*! heck if weapon category qualifies the weapon as onehanded */
bool isOneHandedWeapon( Common::ItemUICategory weaponCategory );
/*! calculate and return player ilvl based off equipped gear */
uint16_t calculateEquippedGearItemLevel();
/*! return the current amount of currency of type */
uint32_t getCurrency( CurrencyType type );
/*! add amount to the current of type */
@ -191,7 +195,7 @@ public:
private:
Entity::PlayerPtr m_pOwner;
Entity::Player* m_pOwner;
InventoryMap m_inventoryMap;
};

View file

@ -30,6 +30,7 @@ Core::Item::Item( uint64_t uId, uint32_t catalogId, uint64_t model1, uint64_t mo
m_magicalDmg = itemInfo->magical_damage;
m_weaponDmg = ( m_physicalDmg != 0 ) ? m_physicalDmg : m_magicalDmg;
m_autoAttackDmg = static_cast< float >( m_weaponDmg * m_delayMs ) / 3000;
m_itemLevel = itemInfo->item_level;
}
Core::Item::~Item()
@ -57,11 +58,21 @@ uint16_t Core::Item::getMagicalDmg() const
return m_magicalDmg;
}
uint16_t Core::Item::getItemLevel() const
{
return m_itemLevel;
}
uint16_t Core::Item::getWeaponDmg() const
{
return m_weaponDmg;
}
bool Core::Item::isWeapon() const
{
return (m_weaponDmg != 0);
}
uint32_t Core::Item::getId() const
{
return m_id;

View file

@ -48,8 +48,12 @@ public:
uint16_t getWeaponDmg() const;
bool isWeapon() const;
float getAutoAttackDmg() const;
uint16_t getItemLevel() const;
protected:
uint32_t m_id;
@ -71,6 +75,7 @@ protected:
uint16_t m_magicalDmg;
uint16_t m_weaponDmg;
float m_autoAttackDmg;
uint16_t m_itemLevel;
};

View file

@ -110,7 +110,7 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in
case 0x68: // Remove status (clicking it off)
{
// todo: check if status can be removed by client from exd
pPlayer->removeSingleStatusEffectFromId( static_cast< uint32_t >( param1 ) );
pPlayer->removeSingleStatusEffectById( static_cast< uint32_t >( param1 ) );
break;
}
case 0x69: // Cancel cast
@ -228,10 +228,15 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in
}
break;
}
case 0x1B5: // Dye item
{
break;
}
default:
{
g_log.debug( "[" + std::to_string( m_pSession->getId() ) + "] Unhandled action: " +
boost::str( boost::format( "%|04X|" ) % (uint32_t) ( commandId & 0xFFFF ) ) );
break;
}
}
}

View file

@ -8,7 +8,6 @@
#include "src/servers/Server_Zone/Forwards.h"
#include "src/servers/Server_Zone/Inventory/Inventory.h"
#include "src/servers/Server_Zone/Inventory/Item.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h"
#include "src/servers/Server_Zone/StatusEffect/StatusEffect.h"
namespace Core {
@ -122,10 +121,11 @@ namespace Server {
uint64_t currentTimeMs = Util::getTimeMs();
for( auto const& effect : pPlayer->getStatusEffectContainer()->getEffectMap() )
for( auto const& effect : pPlayer->getStatusEffectMap() )
{
m_data.effect[effect.first].effect_id = effect.second->getId();
m_data.effect[effect.first].duration = static_cast< float >( effect.second->getDuration() - ( currentTimeMs - effect.second->getStartTimeMs() ) ) / 1000;
m_data.effect[effect.first].duration = static_cast< float >( effect.second->getDuration() -
( currentTimeMs - effect.second->getStartTimeMs() ) ) / 1000;
m_data.effect[effect.first].sourceActorId = effect.second->getSrcActorId();
m_data.effect[effect.first].unknown1 = effect.second->getParam();
}

View file

@ -61,7 +61,7 @@ Core::XMLConfigPtr Core::ServerZone::getConfig() const
size_t Core::ServerZone::getSessionCount() const
{
return m_sessionMap.size();
return m_sessionMapById.size();
}
bool Core::ServerZone::registerBnpcTemplate( std::string templateName, uint32_t bnpcBaseId,
@ -263,7 +263,7 @@ void Core::ServerZone::mainLoop()
auto currTime = static_cast< uint32_t >( time( nullptr ) );
lock_guard< std::mutex > lock( this->m_sessionMutex );
for( auto sessionIt : this->m_sessionMap )
for( auto sessionIt : this->m_sessionMapById )
{
auto session = sessionIt.second;
if( session && session->getPlayer() )
@ -284,8 +284,8 @@ void Core::ServerZone::mainLoop()
}
auto it = this->m_sessionMap.begin();
for( ; it != this->m_sessionMap.end(); )
auto it = this->m_sessionMapById.begin();
for( ; it != this->m_sessionMapById.end(); )
{
uint32_t diff = currTime - it->second->getLastDataTime();
@ -298,7 +298,8 @@ void Core::ServerZone::mainLoop()
// if( it->second.unique() )
{
g_log.info("[" + std::to_string(it->second->getId() ) + "] Session removal" );
it = this->m_sessionMap.erase( it );
it = this->m_sessionMapById.erase( it );
removeSession( pPlayer->getName() );
continue;
}
}
@ -310,7 +311,8 @@ void Core::ServerZone::mainLoop()
it->second->close();
// if( it->second.unique() )
{
it = this->m_sessionMap.erase(it );
it = this->m_sessionMapById.erase( it );
removeSession( pPlayer->getName() );
}
}
else
@ -329,9 +331,9 @@ bool Core::ServerZone::createSession( uint32_t sessionId )
const std::string session_id_str = std::to_string( sessionId );
auto it = m_sessionMap.find( sessionId );
auto it = m_sessionMapById.find( sessionId );
if( it != m_sessionMap.end() )
if( it != m_sessionMapById.end() )
{
g_log.error( "[" + session_id_str + "] Error creating session" );
return false;
@ -340,7 +342,7 @@ bool Core::ServerZone::createSession( uint32_t sessionId )
g_log.info( "[" + session_id_str + "] Creating new session" );
boost::shared_ptr<Session> newSession( new Session( sessionId ) );
m_sessionMap[sessionId] = newSession;
m_sessionMapById[sessionId] = newSession;
if( !newSession->loadPlayer() )
{
@ -348,7 +350,7 @@ bool Core::ServerZone::createSession( uint32_t sessionId )
return false;
}
m_playerSessionMap[newSession->getPlayer()->getName()] = newSession;
m_sessionMapByName[newSession->getPlayer()->getName()] = newSession;
return true;
@ -356,15 +358,15 @@ bool Core::ServerZone::createSession( uint32_t sessionId )
void Core::ServerZone::removeSession( uint32_t sessionId )
{
m_sessionMap.erase( sessionId );
m_sessionMapById.erase( sessionId );
}
void Core::ServerZone::updateSession( uint32_t id )
{
std::lock_guard< std::mutex > lock( m_sessionMutex );
auto it = m_sessionMap.find( id );
auto it = m_sessionMapById.find( id );
if( it != m_sessionMap.end() )
if( it != m_sessionMapById.end() )
it->second->loadPlayer();
}
@ -372,9 +374,9 @@ Core::SessionPtr Core::ServerZone::getSession( uint32_t id )
{
//std::lock_guard<std::mutex> lock( m_sessionMutex );
auto it = m_sessionMap.find( id );
auto it = m_sessionMapById.find( id );
if( it != m_sessionMap.end() )
if( it != m_sessionMapById.end() )
return ( it->second );
return nullptr;
@ -384,9 +386,9 @@ Core::SessionPtr Core::ServerZone::getSession( std::string playerName )
{
//std::lock_guard<std::mutex> lock( m_sessionMutex );
auto it = m_playerSessionMap.find( playerName );
auto it = m_sessionMapByName.find( playerName );
if (it != m_playerSessionMap.end())
if (it != m_sessionMapByName.end())
return (it->second);
return nullptr;
@ -394,15 +396,15 @@ Core::SessionPtr Core::ServerZone::getSession( std::string playerName )
void Core::ServerZone::removeSession( std::string playerName )
{
m_playerSessionMap.erase( playerName );
m_sessionMapByName.erase( playerName );
}
void Core::ServerZone::updateSession( std::string playerName )
{
std::lock_guard< std::mutex > lock( m_sessionMutex );
auto it = m_playerSessionMap.find( playerName );
auto it = m_sessionMapByName.find( playerName );
if( it != m_playerSessionMap.end() )
if( it != m_sessionMapByName.end() )
it->second->loadPlayer();
}

View file

@ -61,8 +61,8 @@ namespace Core {
std::mutex m_sessionMutex;
std::map< uint32_t, SessionPtr > m_sessionMap;
std::map< std::string, SessionPtr > m_playerSessionMap;
std::map< uint32_t, SessionPtr > m_sessionMapById;
std::map< std::string, SessionPtr > m_sessionMapByName;
std::map< uint32_t, uint32_t > m_zones;

View file

@ -1,218 +0,0 @@
#include <src/servers/Server_Common/Util/Util.h>
#include <src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h>
#include "src/servers/Server_Zone/Actor/Actor.h"
#include "StatusEffect.h"
#include "StatusEffectContainer.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket142.h"
#include "src/servers/Server_Zone/Network/PacketWrappers/ActorControlPacket143.h"
using namespace Core::Common;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;
Core::StatusEffect::StatusEffectContainer::StatusEffectContainer( Entity::ActorPtr pOwner )
: m_pOwner( pOwner )
{
// initialize the free slot queue
for( uint8_t i = 0; i < MAX_EFFECTS; i++ )
{
m_freeEffectSlotQueue.push( i );
}
}
int8_t Core::StatusEffect::StatusEffectContainer::getFreeSlot()
{
int8_t freeEffectSlot = -1;
if( m_freeEffectSlotQueue.empty() )
return freeEffectSlot;
freeEffectSlot = m_freeEffectSlotQueue.front();
m_freeEffectSlotQueue.pop();
return freeEffectSlot;
}
void Core::StatusEffect::StatusEffectContainer::freeSlot( uint8_t slotId )
{
m_freeEffectSlotQueue.push( slotId );
}
Core::StatusEffect::StatusEffectContainer::~StatusEffectContainer()
{
}
void Core::StatusEffect::StatusEffectContainer::addStatusEffect( StatusEffectPtr pEffect )
{
int8_t nextSlot = getFreeSlot();
// if there is no slot left, do not add the effect
if( nextSlot == -1 )
return;
pEffect->applyStatus();
m_effectMap[nextSlot] = pEffect;
ZoneChannelPacket< Server::FFXIVIpcAddStatusEffect > statusEffectAdd( m_pOwner->getId() );
statusEffectAdd.data().actor_id = pEffect->getTargetActorId();
statusEffectAdd.data().actor_id1 = pEffect->getSrcActorId();
statusEffectAdd.data().current_hp = m_pOwner->getHp();
statusEffectAdd.data().current_mp = m_pOwner->getMp();
statusEffectAdd.data().current_tp = m_pOwner->getTp();
statusEffectAdd.data().duration = static_cast< float >( pEffect->getDuration() ) / 1000;
statusEffectAdd.data().effect_id = pEffect->getId();
statusEffectAdd.data().effect_index = nextSlot;
statusEffectAdd.data().max_hp = m_pOwner->getMaxHp();
statusEffectAdd.data().max_mp = m_pOwner->getMaxMp();
statusEffectAdd.data().max_something = 1;
//statusEffectAdd.data().unknown2 = 28;
statusEffectAdd.data().param = pEffect->getParam();
bool sendToSelf = m_pOwner->isPlayer() ? true : false;
m_pOwner->sendToInRangeSet( statusEffectAdd, sendToSelf );
}
void Core::StatusEffect::StatusEffectContainer::removeSingleStatusEffectFromId( uint32_t id )
{
for (auto effectIt : m_effectMap)
{
if (effectIt.second->getId() == id)
{
removeStatusEffect( effectIt.first );
break;
}
}
}
void Core::StatusEffect::StatusEffectContainer::removeStatusEffect( uint8_t effectSlotId )
{
auto pEffectIt = m_effectMap.find( effectSlotId );
if( pEffectIt == m_effectMap.end() )
return;
freeSlot( effectSlotId );
auto pEffect = pEffectIt->second;
pEffect->removeStatus();
bool sendToSelf = m_pOwner->isPlayer() ? true : false;
m_pOwner->sendToInRangeSet( ActorControlPacket142( m_pOwner->getId(), StatusEffectLose, pEffect->getId() ), sendToSelf );
m_effectMap.erase( effectSlotId );
sendUpdate();
}
std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > Core::StatusEffect::StatusEffectContainer::getEffectMap() const
{
return m_effectMap;
}
void Core::StatusEffect::StatusEffectContainer::sendUpdate()
{
uint64_t currentTimeMs = Util::getTimeMs();
ZoneChannelPacket< Server::FFXIVIpcStatusEffectList > statusEffectList( m_pOwner->getId() );
statusEffectList.data().current_hp = m_pOwner->getHp();
statusEffectList.data().current_mp = m_pOwner->getMp();
statusEffectList.data().currentTp = m_pOwner->getTp();
statusEffectList.data().max_hp = m_pOwner->getMaxHp();
statusEffectList.data().max_mp = m_pOwner->getMaxMp();
uint8_t slot = 0;
for( auto effectIt : m_effectMap )
{
float timeLeft = static_cast< float >( effectIt.second->getDuration() - ( currentTimeMs - effectIt.second->getStartTimeMs() ) ) / 1000;
statusEffectList.data().effect[slot].duration = timeLeft;
statusEffectList.data().effect[slot].effect_id = effectIt.second->getId();
statusEffectList.data().effect[slot].sourceActorId = effectIt.second->getSrcActorId();
slot++;
}
bool sendToSelf = m_pOwner->isPlayer();
m_pOwner->sendToInRangeSet( statusEffectList, sendToSelf );
}
void Core::StatusEffect::StatusEffectContainer::update()
{
uint64_t currentTimeMs = Util::getTimeMs();
uint32_t thisTickDmg = 0;
uint32_t thisTickHeal = 0;
for( auto effectIt : m_effectMap )
{
uint8_t effectIndex = effectIt.first;
auto effect = effectIt.second;
uint64_t lastTick = effect->getLastTickMs();
uint64_t startTime = effect->getStartTimeMs();
uint32_t duration = effect->getDuration();
uint32_t tickRate = effect->getTickRate();
if( ( currentTimeMs - startTime ) > duration )
{
// remove status effect
removeStatusEffect( effectIndex );
// break because removing invalidates iterators
break;
}
if( ( currentTimeMs - lastTick ) > tickRate )
{
effect->setLastTick( currentTimeMs );
effect->onTick();
auto thisEffect = effect->getTickEffect();
switch( thisEffect.first )
{
case 1:
{
thisTickDmg += thisEffect.second;
break;
}
case 2:
{
thisTickHeal += thisEffect.second;
break;
}
}
}
}
if( thisTickDmg != 0 )
{
m_pOwner->takeDamage( thisTickDmg );
m_pOwner->sendToInRangeSet( ActorControlPacket142( m_pOwner->getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Damage ), thisTickDmg ) );
}
if( thisTickHeal != 0 )
{
m_pOwner->heal( thisTickDmg );
m_pOwner->sendToInRangeSet( ActorControlPacket142( m_pOwner->getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Heal ), thisTickHeal ) );
}
}
bool Core::StatusEffect::StatusEffectContainer::hasStatusEffect( uint32_t id )
{
for( auto effectIt : m_effectMap )
{
if( effectIt.second->getId() == id )
{
return true;
}
}
return false;
}

View file

@ -1,49 +0,0 @@
#ifndef _STATUSEFFECTCONTAINER_H_
#define _STATUSEFFECTCONTAINER_H_
#include <boost/shared_ptr.hpp>
#include <queue>
#include <map>
#include "src/servers/Server_Zone/Forwards.h"
namespace Core
{
namespace StatusEffect
{
class StatusEffectContainer
{
public:
StatusEffectContainer( Entity::ActorPtr pOwner );
~StatusEffectContainer();
void addStatusEffect( StatusEffectPtr pEffect );
void removeStatusEffect( uint8_t effectSlotId );
void removeSingleStatusEffectFromId( uint32_t id );
void update();
bool hasStatusEffect( uint32_t id );
int8_t getFreeSlot();
void freeSlot( uint8_t slotId );
std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > getEffectMap() const;
void sendUpdate();
private:
const uint8_t MAX_EFFECTS = 30;
Entity::ActorPtr m_pOwner;
std::queue< uint8_t > m_freeEffectSlotQueue;
std::vector< std::pair< uint8_t, uint32_t> > m_tickEffectList;
std::map< uint8_t, StatusEffectPtr > m_effectMap;
};
}
}
#endif

View file

@ -47,7 +47,6 @@ namespace Core
{
entry->setCurrentZone( m_pZone );
entry->getAsBattleNpc()->initStatusEffectContainer();
m_pZone->pushActor( entry );
}