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