diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a2964aca..9f3f22ab 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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): @@ -30,34 +30,34 @@ Example (shortened from ActionHandler.cpp): ```cpp switch( commandId ) { - case 0x01: // Toggle sheathe - { - if ( param11 == 1 ) - pPlayer->setStance( Entity::Actor::Stance::Active ); - else - { - pPlayer->setStance( Entity::Actor::Stance::Passive ); - pPlayer->setAutoattack( false ); - } + case 0x01: // Toggle sheathe + { + if ( param11 == 1 ) + pPlayer->setStance( Entity::Actor::Stance::Active ); + else + { + pPlayer->setStance( Entity::Actor::Stance::Passive ); + pPlayer->setAutoattack( false ); + } - pPlayer->sendToInRangeSet( ActorControlPacket142( pPlayer->getId(), 0, param11, 1 ) ); + pPlayer->sendToInRangeSet( ActorControlPacket142( pPlayer->getId(), 0, param11, 1 ) ); - break; - } - case 0x03: // Change target - { - uint64_t targetId = inPacket.getValAt< uint64_t >( 0x24 ); - pPlayer->changeTarget( targetId ); - break; - } - default: - { - break; - } + break; + } + case 0x03: // Change target + { + uint64_t targetId = inPacket.getValAt< uint64_t >( 0x24 ); + pPlayer->changeTarget( targetId ); + break; + } + default: + { + break; + } } ``` ### Feature implementation Please make sure edge cases have been tested, behavior is aligned with retail and (if applicable) your queries make sense. -Any changes to the SQL base should be noted (and reflected in the update.sql file in rootDirectory/sql). \ No newline at end of file +Any changes to the SQL base should be noted (and reflected in the update.sql file in rootDirectory/sql). diff --git a/bin/config/settings_rest.xml b/bin/config/settings_rest.xml index af0c2fb9..ddadaf67 100644 --- a/bin/config/settings_rest.xml +++ b/bin/config/settings_rest.xml @@ -3,15 +3,16 @@ 54994 54998 - + 127.0.0.1 C:\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn\\game\\sqpack\\ffxiv + 127.0.0.1 - + 127.0.0.1 - + default 80 @@ -28,4 +29,4 @@ 255 - \ No newline at end of file + diff --git a/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h b/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h index 701176ab..0724bae5 100644 --- a/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h +++ b/src/servers/Server_Common/Network/PacketDef/Zone/ServerZoneDef.h @@ -855,7 +855,7 @@ struct FFXIVIpcPlayerStats : FFXIVIpcBasePacket 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 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 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 struct FFXIVIpcPlayerClassInfo : FFXIVIpcBasePacket { 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]; }; /** diff --git a/src/servers/Server_REST/SapphireAPI.cpp b/src/servers/Server_REST/SapphireAPI.cpp index d3181696..5fbc108e 100644 --- a/src/servers/Server_REST/SapphireAPI.cpp +++ b/src/servers/Server_REST/SapphireAPI.cpp @@ -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 ) diff --git a/src/servers/Server_Zone/Actor/Actor.cpp b/src/servers/Server_Zone/Actor/Actor.cpp index 02d9543d..6d3f87df 100644 --- a/src/servers/Server_Zone/Actor/Actor.cpp +++ b/src/servers/Server_Zone/Actor/Actor.cpp @@ -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; +} diff --git a/src/servers/Server_Zone/Actor/Actor.h b/src/servers/Server_Zone/Actor/Actor.h index 6e14f8c0..2ba456e5 100644 --- a/src/servers/Server_Zone/Actor/Actor.h +++ b/src/servers/Server_Zone/Actor/Actor.h @@ -7,6 +7,7 @@ #include "src/servers/Server_Zone/Forwards.h" #include #include +#include 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; diff --git a/src/servers/Server_Zone/Actor/BattleNpc.cpp b/src/servers/Server_Zone/Actor/BattleNpc.cpp index 0bd002f7..17160397 100644 --- a/src/servers/Server_Zone/Actor/BattleNpc.cpp +++ b/src/servers/Server_Zone/Actor/BattleNpc.cpp @@ -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 ); diff --git a/src/servers/Server_Zone/Actor/Player.cpp b/src/servers/Server_Zone/Actor/Player.cpp index f4300417..a3c63893 100644 --- a/src/servers/Server_Zone/Actor/Player.cpp +++ b/src/servers/Server_Zone/Actor/Player.cpp @@ -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 ), @@ -237,12 +236,13 @@ void Core::Entity::Player::calculateStats() m_baseStats.mnd = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_mnd ) / 100 ) + tribeInfo.mod_mnd ); m_baseStats.pie = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_pie ) / 100 ) + tribeInfo.mod_pie ); - m_baseStats.skillSpeed = paramGrowthInfo.base_secondary; - m_baseStats.spellSpeed = paramGrowthInfo.base_secondary; - m_baseStats.accuracy = paramGrowthInfo.base_secondary; - m_baseStats.critHitRate = paramGrowthInfo.base_secondary; - m_baseStats.attackPotMagic = paramGrowthInfo.base_secondary; + m_baseStats.skillSpeed = paramGrowthInfo.base_secondary; + m_baseStats.spellSpeed = paramGrowthInfo.base_secondary; + m_baseStats.accuracy = paramGrowthInfo.base_secondary; + 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 ) { diff --git a/src/servers/Server_Zone/Actor/Player.h b/src/servers/Server_Zone/Actor/Player.h index 40015bcf..35db1533 100644 --- a/src/servers/Server_Zone/Actor/Player.h +++ b/src/servers/Server_Zone/Actor/Player.h @@ -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; diff --git a/src/servers/Server_Zone/Actor/PlayerInventory.cpp b/src/servers/Server_Zone/Actor/PlayerInventory.cpp index 8eaf65c9..b1d03721 100644 --- a/src/servers/Server_Zone/Actor/PlayerInventory.cpp +++ b/src/servers/Server_Zone/Actor/PlayerInventory.cpp @@ -1,17 +1,21 @@ #include +#include +#include +#include #include "Player.h" #include "src/servers/Server_Zone/Zone/ZoneMgr.h" #include "src/servers/Server_Zone/Zone/Zone.h" -#include - +#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 diff --git a/src/servers/Server_Zone/Actor/PlayerSql.cpp b/src/servers/Server_Zone/Actor/PlayerSql.cpp index 46fdd8d8..7e9cfd71 100644 --- a/src/servers/Server_Zone/Actor/PlayerSql.cpp +++ b/src/servers/Server_Zone/Actor/PlayerSql.cpp @@ -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 @@ -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(); @@ -508,4 +506,4 @@ void Core::Entity::Player::insertQuest( uint16_t questId, uint8_t index, uint8_t stmt->setInt( 11, 0 ); stmt->setInt( 12, 0 ); g_charaDb.execute( stmt ); -} \ No newline at end of file +} diff --git a/src/servers/Server_Zone/Inventory/Inventory.cpp b/src/servers/Server_Zone/Inventory/Inventory.cpp index 116ffd51..c03c9c00 100644 --- a/src/servers/Server_Zone/Inventory/Inventory.cpp +++ b/src/servers/Server_Zone/Inventory/Inventory.cpp @@ -13,6 +13,7 @@ #include "src/servers/Server_Zone/Network/PacketWrappers/ServerNoticePacket.h" #include +#include #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; diff --git a/src/servers/Server_Zone/Inventory/Inventory.h b/src/servers/Server_Zone/Inventory/Inventory.h index 1fb690a4..b4663aa7 100644 --- a/src/servers/Server_Zone/Inventory/Inventory.h +++ b/src/servers/Server_Zone/Inventory/Inventory.h @@ -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; }; diff --git a/src/servers/Server_Zone/Inventory/Item.cpp b/src/servers/Server_Zone/Inventory/Item.cpp index 59171a82..a5e8dd84 100644 --- a/src/servers/Server_Zone/Inventory/Item.cpp +++ b/src/servers/Server_Zone/Inventory/Item.cpp @@ -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; diff --git a/src/servers/Server_Zone/Inventory/Item.h b/src/servers/Server_Zone/Inventory/Item.h index 0daa4c9a..198607f5 100644 --- a/src/servers/Server_Zone/Inventory/Item.h +++ b/src/servers/Server_Zone/Inventory/Item.h @@ -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; }; diff --git a/src/servers/Server_Zone/Network/Handlers/ActionHandler.cpp b/src/servers/Server_Zone/Network/Handlers/ActionHandler.cpp index 94aa4e71..2acde44d 100644 --- a/src/servers/Server_Zone/Network/Handlers/ActionHandler.cpp +++ b/src/servers/Server_Zone/Network/Handlers/ActionHandler.cpp @@ -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; } } } diff --git a/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h b/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h index 859af3ad..07c16ec1 100644 --- a/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h +++ b/src/servers/Server_Zone/Network/PacketWrappers/PlayerSpawnPacket.h @@ -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(); } @@ -138,4 +138,4 @@ namespace Server { } } -#endif /*_PlayerSpawn_H*/ \ No newline at end of file +#endif /*_PlayerSpawn_H*/ diff --git a/src/servers/Server_Zone/ServerZone.cpp b/src/servers/Server_Zone/ServerZone.cpp index 67a47dd9..bf16a446 100644 --- a/src/servers/Server_Zone/ServerZone.cpp +++ b/src/servers/Server_Zone/ServerZone.cpp @@ -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 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 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 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(); } diff --git a/src/servers/Server_Zone/ServerZone.h b/src/servers/Server_Zone/ServerZone.h index 632409e1..33d6a329 100644 --- a/src/servers/Server_Zone/ServerZone.h +++ b/src/servers/Server_Zone/ServerZone.h @@ -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; diff --git a/src/servers/Server_Zone/StatusEffect/StatusEffectContainer.cpp b/src/servers/Server_Zone/StatusEffect/StatusEffectContainer.cpp deleted file mode 100644 index 6c623abc..00000000 --- a/src/servers/Server_Zone/StatusEffect/StatusEffectContainer.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include -#include - -#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; -} \ No newline at end of file diff --git a/src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h b/src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h deleted file mode 100644 index 22a43aae..00000000 --- a/src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef _STATUSEFFECTCONTAINER_H_ -#define _STATUSEFFECTCONTAINER_H_ - -#include - -#include -#include - -#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 diff --git a/src/servers/Server_Zone/Zone/Cell.cpp b/src/servers/Server_Zone/Zone/Cell.cpp index 08e886b3..7a598ae7 100644 --- a/src/servers/Server_Zone/Zone/Cell.cpp +++ b/src/servers/Server_Zone/Zone/Cell.cpp @@ -47,7 +47,6 @@ namespace Core { entry->setCurrentZone( m_pZone ); - entry->getAsBattleNpc()->initStatusEffectContainer(); m_pZone->pushActor( entry ); } @@ -170,4 +169,4 @@ namespace Core m_bUnloadPending = false; } -} \ No newline at end of file +}