mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-28 07:07:45 +00:00
Action Collision class (AoE, filtering); Refactoring script handler; Sorted action field + aoe_width property;
This commit is contained in:
parent
67a5717541
commit
64caa88872
14 changed files with 361 additions and 159 deletions
18
scripts/chai/skill/thm/skillDef_147.chai
Normal file
18
scripts/chai/skill/thm/skillDef_147.chai
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Skill Name: Fire II
|
||||||
|
// Skill ID: 147
|
||||||
|
|
||||||
|
class skillDef_147Def
|
||||||
|
{
|
||||||
|
def skillDef_147Def()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
def onFinish( player, target )
|
||||||
|
{
|
||||||
|
player.handleScriptSkill( STD_DAMAGE, 147, 80, 0, target );
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
GLOBAL skillDef_147 = skillDef_147Def();
|
|
@ -1 +1 @@
|
||||||
Subproject commit 4e08821a45adbff969f6c4863bbe156d4229ffda
|
Subproject commit 376501b8f441bd6b6e75b1960b118aabd72fca9d
|
|
@ -562,7 +562,7 @@ namespace Core {
|
||||||
LimitBreak = 8,
|
LimitBreak = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ActionEffectType : uint8_t
|
enum ActionEffectType : uint8_t
|
||||||
{
|
{
|
||||||
Nothing = 0,
|
Nothing = 0,
|
||||||
Miss = 1,
|
Miss = 1,
|
||||||
|
@ -591,16 +591,17 @@ namespace Core {
|
||||||
CritDirectHitDamage = 3
|
CritDirectHitDamage = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class AoeType
|
enum class ActionCollisionType : uint8_t
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
SingleTarget,
|
SingleTarget,
|
||||||
TargetCircle,
|
Circle,
|
||||||
Cone,
|
Cone,
|
||||||
Line,
|
Box,
|
||||||
Unknown,
|
Unknown,
|
||||||
Unknown2,
|
Unknown2,
|
||||||
GroundCircle, // for when you set aoe like asylum
|
PersistentArea, // for when you set aoe like asylum
|
||||||
|
Unknown3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum HandleActionType : uint8_t
|
enum HandleActionType : uint8_t
|
||||||
|
|
|
@ -334,29 +334,23 @@ bool Core::Data::ExdData::loadActionInfo()
|
||||||
bool can_target_friendly = getField< bool >( fields, 16 ); // 16
|
bool can_target_friendly = getField< bool >( fields, 16 ); // 16
|
||||||
bool can_target_enemy = getField< bool >( fields, 17 ); // 17
|
bool can_target_enemy = getField< bool >( fields, 17 ); // 17
|
||||||
|
|
||||||
bool is_aoe = getField< bool >( fields, 20 ); // 20
|
bool is_ground_aoe = getField< bool >( fields, 20 ); // 20
|
||||||
// Column 23: Seems to be related to raising skills (Raise, Resurrection, Reanimate)
|
// Column 23: Seems to be related to raising skills (Raise, Resurrection, Reanimate)
|
||||||
bool can_target_ko = getField< bool >( fields, 24 ); // 24
|
bool can_target_ko = getField< bool >( fields, 24 ); // 24
|
||||||
|
|
||||||
uint8_t aoe_type = getField< uint8_t >( fields, 26 ); // 26
|
uint8_t aoe_type = getField< uint8_t >( fields, 26 ); // 26
|
||||||
uint8_t radius = getField< uint8_t >( fields, 27 ); // 27
|
uint8_t aoe_range = getField< uint8_t >( fields, 27 ); // 27
|
||||||
|
uint8_t aoe_width = getField< uint8_t >( fields, 28 ); // 28
|
||||||
|
|
||||||
uint8_t points_type = getField< uint8_t >( fields, 30 ); // 30
|
uint8_t points_type = getField< uint8_t >( fields, 30 ); // 30
|
||||||
uint16_t points_cost = getField< uint16_t >( fields, 31 ); // 31
|
uint16_t points_cost = getField< uint16_t >( fields, 31 ); // 31
|
||||||
|
|
||||||
uint32_t instantval = getField< bool >( fields, 35 ); // 35
|
bool is_instant = getField< bool >( fields, 35 ); // 35
|
||||||
uint16_t cast_time = getField< uint16_t >( fields, 36 ); // 36
|
uint16_t cast_time = getField< uint16_t >( fields, 36 ); // 36
|
||||||
uint16_t recast_time = getField< uint16_t >( fields, 37 ); // 37
|
uint16_t recast_time = getField< uint16_t >( fields, 37 ); // 37
|
||||||
|
|
||||||
int8_t model = getField< int8_t >( fields, 39 ); // 39: Action model
|
int8_t model = getField< int8_t >( fields, 39 ); // 39
|
||||||
uint8_t aspect = getField< uint8_t >( fields, 40 ); // 40: Action aspect
|
uint8_t aspect = getField< uint8_t >( fields, 40 ); // 40
|
||||||
|
|
||||||
uint8_t typeshift = 0x6;
|
|
||||||
uint8_t mask = 1 << typeshift;
|
|
||||||
instantval &= mask;
|
|
||||||
bool final = ( instantval & mask ) == mask;
|
|
||||||
bool is_instant = final;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
info->id = id;
|
info->id = id;
|
||||||
|
@ -373,10 +367,11 @@ bool Core::Data::ExdData::loadActionInfo()
|
||||||
|
|
||||||
info->can_target_ko = can_target_ko;
|
info->can_target_ko = can_target_ko;
|
||||||
|
|
||||||
info->is_aoe = is_aoe;
|
info->is_ground_aoe = is_ground_aoe;
|
||||||
|
|
||||||
info->aoe_type = aoe_type;
|
info->aoe_type = aoe_type;
|
||||||
info->radius = radius;
|
info->aoe_range = aoe_range;
|
||||||
|
info->aoe_width = aoe_width;
|
||||||
|
|
||||||
info->points_type = points_type;
|
info->points_type = points_type;
|
||||||
info->points_cost = points_cost;
|
info->points_cost = points_cost;
|
||||||
|
|
|
@ -233,12 +233,13 @@ namespace Core {
|
||||||
bool can_target_friendly; // 16
|
bool can_target_friendly; // 16
|
||||||
bool can_target_enemy; // 17
|
bool can_target_enemy; // 17
|
||||||
|
|
||||||
bool is_aoe; // 20
|
bool is_ground_aoe; // 20
|
||||||
|
|
||||||
bool can_target_ko; // 24
|
bool can_target_ko; // 24
|
||||||
|
|
||||||
uint8_t aoe_type; // 26
|
uint8_t aoe_type; // 26
|
||||||
uint8_t radius; // 27
|
uint8_t aoe_range; // 27
|
||||||
|
uint8_t aoe_width; // 28
|
||||||
|
|
||||||
uint8_t points_type; // 30
|
uint8_t points_type; // 30
|
||||||
uint16_t points_cost; // 31
|
uint16_t points_cost; // 31
|
||||||
|
|
133
src/servers/Server_Zone/Action/ActionCollision.cpp
Normal file
133
src/servers/Server_Zone/Action/ActionCollision.cpp
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
#include <src/servers/Server_Common/Util/Util.h>
|
||||||
|
#include <src/servers/Server_Common/Exd/ExdData.h>
|
||||||
|
#include <src/servers/Server_Common/Util/UtilMath.h>
|
||||||
|
|
||||||
|
#include "ActionCollision.h"
|
||||||
|
#include <src/servers/Server_Zone/Actor/Actor.h>
|
||||||
|
#include <src/servers/Server_Zone/Actor/Player.h>
|
||||||
|
#include <cmath>
|
||||||
|
#include <boost/make_shared.hpp>
|
||||||
|
|
||||||
|
using namespace Core::Entity;
|
||||||
|
using namespace Core::Common;
|
||||||
|
|
||||||
|
// todo: add filters for allies, enemies only etc
|
||||||
|
|
||||||
|
bool ActionCollision::isActorCollisionValid( ActorPtr actorPtr, AoeFilter aoeFilter )
|
||||||
|
{
|
||||||
|
bool collisionApplicable = false;
|
||||||
|
switch ( aoeFilter )
|
||||||
|
{
|
||||||
|
case AoeFilter::All:
|
||||||
|
{
|
||||||
|
collisionApplicable = true;
|
||||||
|
}
|
||||||
|
case AoeFilter::Players:
|
||||||
|
{
|
||||||
|
collisionApplicable = actorPtr->isPlayer();
|
||||||
|
}
|
||||||
|
case AoeFilter::Allies:
|
||||||
|
{
|
||||||
|
// todo: implement ally NPCs
|
||||||
|
collisionApplicable = !actorPtr->isMob();
|
||||||
|
}
|
||||||
|
case AoeFilter::Party:
|
||||||
|
{
|
||||||
|
// todo: implement party
|
||||||
|
collisionApplicable = actorPtr->isPlayer();
|
||||||
|
}
|
||||||
|
case AoeFilter::Enemies:
|
||||||
|
{
|
||||||
|
collisionApplicable = actorPtr->isMob();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( collisionApplicable && actorPtr->isAlive() );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set< Core::Entity::ActorPtr > ActionCollision::getActorsHitFromAction( FFXIVARR_POSITION3 aoePosition, std::set< ActorPtr > actorsInRange, boost::shared_ptr< Core::Data::ActionInfo > actionInfo, AoeFilter aoeFilter )
|
||||||
|
{
|
||||||
|
std::set< ActorPtr > actorsCollided;
|
||||||
|
|
||||||
|
switch ( static_cast< ActionCollisionType >( actionInfo->aoe_type ) )
|
||||||
|
{
|
||||||
|
case ActionCollisionType::None:
|
||||||
|
case ActionCollisionType::SingleTarget:
|
||||||
|
{
|
||||||
|
// This is actually needed. There is "splash damage" in actions marked as single target.
|
||||||
|
// Notice how we're using aoe_width. How collision works for SingleTarget is unknown as of now.
|
||||||
|
// TODO: Isn't it possible to stack 2 players in the same spot and glitch the action collision this way? Investigate
|
||||||
|
for ( auto pActor : actorsInRange )
|
||||||
|
{
|
||||||
|
// Make sure actor exists. If it doesn't we done goofed.
|
||||||
|
assert( pActor );
|
||||||
|
|
||||||
|
// Don't bother wasting on collision if actor doesn't apply for it
|
||||||
|
if ( !isActorCollisionValid( pActor, aoeFilter ) )
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Test our collision from actor with the area generated by the action from the AoE data
|
||||||
|
if ( radiusCollision( pActor->getPos(), aoePosition, actionInfo->aoe_width ) )
|
||||||
|
{
|
||||||
|
// Add it to the actors collided with the area
|
||||||
|
actorsCollided.insert( pActor );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ActionCollisionType::Circle:
|
||||||
|
{
|
||||||
|
for ( auto pActor : actorsInRange )
|
||||||
|
{
|
||||||
|
assert( pActor );
|
||||||
|
|
||||||
|
if ( !isActorCollisionValid( pActor, aoeFilter ) )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ( radiusCollision( pActor->getPos(), aoePosition, actionInfo->aoe_range ) )
|
||||||
|
{
|
||||||
|
actorsCollided.insert( pActor );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ActionCollisionType::Box:
|
||||||
|
{
|
||||||
|
for ( auto pActor : actorsInRange )
|
||||||
|
{
|
||||||
|
assert( pActor );
|
||||||
|
|
||||||
|
if ( !isActorCollisionValid( pActor, aoeFilter ) )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ( boxCollision( pActor->getPos(), aoePosition, actionInfo->aoe_width, actionInfo->aoe_range ) )
|
||||||
|
{
|
||||||
|
// todo: does this actually work?
|
||||||
|
|
||||||
|
actorsCollided.insert( pActor );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return actorsCollided;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ActionCollision::radiusCollision( FFXIVARR_POSITION3 actorPosition, FFXIVARR_POSITION3 aoePosition, uint16_t radius )
|
||||||
|
{
|
||||||
|
return Core::Math::Util::distance( actorPosition.x, actorPosition.y, actorPosition.z,
|
||||||
|
aoePosition.x, aoePosition.y, aoePosition.z ) <= radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ActionCollision::boxCollision( FFXIVARR_POSITION3 actorPosition, FFXIVARR_POSITION3 aoePosition, uint16_t width, uint16_t height )
|
||||||
|
{
|
||||||
|
return actorPosition.x < aoePosition.x + width &&
|
||||||
|
actorPosition.x > aoePosition.x &&
|
||||||
|
actorPosition.y < aoePosition.y + height &&
|
||||||
|
actorPosition.y > aoePosition.y;
|
||||||
|
}
|
37
src/servers/Server_Zone/Action/ActionCollision.h
Normal file
37
src/servers/Server_Zone/Action/ActionCollision.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef _ACTIONCOLLISION_H
|
||||||
|
#define _ACTIONCOLLISION_H
|
||||||
|
|
||||||
|
#include <src/servers/Server_Common/Common.h>
|
||||||
|
|
||||||
|
#include <src/servers/Server_Zone/Actor/Actor.h>
|
||||||
|
#include "Action.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
namespace Entity {
|
||||||
|
|
||||||
|
enum class AoeFilter
|
||||||
|
{
|
||||||
|
All, // All actors in the AoE are applicable for collision
|
||||||
|
Players, // Only players
|
||||||
|
Allies, // Only allies (players, ally NPCs)
|
||||||
|
Party, // Only party members
|
||||||
|
Enemies // Only enemies
|
||||||
|
};
|
||||||
|
|
||||||
|
class ActionCollision
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static bool isActorCollisionValid( ActorPtr actorPtr, AoeFilter aoeFilter );
|
||||||
|
static std::set< ActorPtr > getActorsHitFromAction( Common::FFXIVARR_POSITION3 aoePosition, std::set< ActorPtr > actorsInRange, boost::shared_ptr< Data::ActionInfo > actionInfo, AoeFilter aoeFilter );
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool radiusCollision( Common::FFXIVARR_POSITION3 actorPosition, Common::FFXIVARR_POSITION3 aoePosition, uint16_t radius );
|
||||||
|
static bool boxCollision( Common::FFXIVARR_POSITION3 actorPosition, Common::FFXIVARR_POSITION3 aoePosition, uint16_t width, uint16_t height );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,6 +1,7 @@
|
||||||
#include <src/servers/Server_Common/Util/Util.h>
|
#include <src/servers/Server_Common/Util/Util.h>
|
||||||
#include <src/servers/Server_Common/Util/UtilMath.h>
|
#include <src/servers/Server_Common/Util/UtilMath.h>
|
||||||
#include <src/servers/Server_Common/Network/PacketContainer.h>
|
#include <src/servers/Server_Common/Network/PacketContainer.h>
|
||||||
|
#include <src/servers/Server_Common/Exd/ExdData.h>
|
||||||
|
|
||||||
#include "src/servers/Server_Zone/Forwards.h"
|
#include "src/servers/Server_Zone/Forwards.h"
|
||||||
#include "src/servers/Server_Zone/Action/Action.h"
|
#include "src/servers/Server_Zone/Action/Action.h"
|
||||||
|
@ -15,11 +16,14 @@
|
||||||
|
|
||||||
#include "src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h"
|
#include "src/servers/Server_Zone/StatusEffect/StatusEffectContainer.h"
|
||||||
#include "src/servers/Server_Zone/StatusEffect/StatusEffect.h"
|
#include "src/servers/Server_Zone/StatusEffect/StatusEffect.h"
|
||||||
|
#include "src/servers/Server_Zone/Action/ActionCollision.h"
|
||||||
#include "src/servers/Server_Zone/ServerZone.h"
|
#include "src/servers/Server_Zone/ServerZone.h"
|
||||||
#include "src/servers/Server_Zone/Session.h"
|
#include "src/servers/Server_Zone/Session.h"
|
||||||
|
#include "CalcBattle.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
|
|
||||||
extern Core::ServerZone g_serverZone;
|
extern Core::ServerZone g_serverZone;
|
||||||
|
extern Core::Data::ExdData g_exdData;
|
||||||
|
|
||||||
using namespace Core::Common;
|
using namespace Core::Common;
|
||||||
using namespace Core::Network::Packets;
|
using namespace Core::Network::Packets;
|
||||||
|
@ -620,6 +624,112 @@ void Core::Entity::Actor::autoAttack( ActorPtr pTarget )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
ChaiScript Skill Handler.
|
||||||
|
|
||||||
|
\param GamePacketPtr to send
|
||||||
|
\param bool should be send to self?
|
||||||
|
*/
|
||||||
|
void Core::Entity::Actor::handleScriptSkill( uint32_t type, uint32_t actionId, uint64_t param1, uint64_t param2, Entity::Actor& pTarget )
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( isPlayer() )
|
||||||
|
{
|
||||||
|
getAsPlayer()->sendDebug( std::to_string( pTarget.getId() ) );
|
||||||
|
getAsPlayer()->sendDebug( "Handle script skill type: " + std::to_string( type ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
auto actionInfoPtr = g_exdData.getActionInfo( actionId );
|
||||||
|
|
||||||
|
// Prepare packet. This is seemingly common for all packets in the action handler.
|
||||||
|
|
||||||
|
GamePacketNew< FFXIVIpcEffect, ServerZoneIpcType > effectPacket( getId() );
|
||||||
|
effectPacket.data().targetId = pTarget.getId();
|
||||||
|
effectPacket.data().actionAnimationId = actionId;
|
||||||
|
effectPacket.data().unknown_2 = 1; // This seems to have an effect on the "double-cast finish" animation
|
||||||
|
// effectPacket.data().unknown_3 = 1;
|
||||||
|
effectPacket.data().actionTextId = actionId;
|
||||||
|
effectPacket.data().numEffects = 1;
|
||||||
|
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() );
|
||||||
|
effectPacket.data().effectTarget = pTarget.getId();
|
||||||
|
effectPacket.data().effects[0].value = 0;
|
||||||
|
effectPacket.data().effects[0].effectType = ActionEffectType::Damage;
|
||||||
|
effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalDamage;
|
||||||
|
effectPacket.data().effects[0].unknown_3 = 7;
|
||||||
|
|
||||||
|
switch ( type )
|
||||||
|
{
|
||||||
|
|
||||||
|
case ActionEffectType::Damage:
|
||||||
|
{
|
||||||
|
|
||||||
|
effectPacket.data().effects[0].value = static_cast< int16_t >( param1 );
|
||||||
|
effectPacket.data().effects[0].effectType = ActionEffectType::Damage;
|
||||||
|
effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalDamage;
|
||||||
|
|
||||||
|
std::set< ActorPtr > actorsCollided = ActionCollision::getActorsHitFromAction( pTarget.getPos(), getInRangeActors( true ), actionInfoPtr, AoeFilter::Enemies );
|
||||||
|
|
||||||
|
for ( auto pHitActor : actorsCollided )
|
||||||
|
{
|
||||||
|
effectPacket.data().targetId = pHitActor->getId();
|
||||||
|
effectPacket.data().unknown_1 = 1; // the magic trick for getting it to work
|
||||||
|
effectPacket.data().unknown_5 = 1;
|
||||||
|
effectPacket.data().unknown_8 = 1;
|
||||||
|
effectPacket.data().actionTextId = 0;
|
||||||
|
effectPacket.data().effectTarget = pHitActor->getId();
|
||||||
|
effectPacket.data().effects[0].value = param1 + ( rand() % 15 );
|
||||||
|
|
||||||
|
pHitActor->sendToInRangeSet( effectPacket, true ); // todo: send to range of what? ourselves? when mob script hits this is going to be lacking
|
||||||
|
pHitActor->takeDamage( static_cast< uint32_t >( param1 ) );
|
||||||
|
pHitActor->onActionHostile( shared_from_this() );
|
||||||
|
|
||||||
|
if ( isPlayer() )
|
||||||
|
getAsPlayer()->sendDebug( "AoE hit actor " + pHitActor->getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ActionEffectType::Heal:
|
||||||
|
{
|
||||||
|
uint32_t calculatedHeal = Data::CalcBattle::calculateHealValue( getAsPlayer(), static_cast< uint32_t >( param1 ) );
|
||||||
|
|
||||||
|
effectPacket.data().effects[0].value = calculatedHeal;
|
||||||
|
effectPacket.data().effects[0].effectType = ActionEffectType::Heal;
|
||||||
|
effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalHeal;
|
||||||
|
|
||||||
|
sendToInRangeSet( effectPacket, true );
|
||||||
|
|
||||||
|
// todo: get proper packets: the following was just kind of thrown together from what we know
|
||||||
|
|
||||||
|
std::set< ActorPtr > actorsCollided = ActionCollision::getActorsHitFromAction( pTarget.getPos(), getInRangeActors( true ), actionInfoPtr, AoeFilter::Allies );
|
||||||
|
|
||||||
|
for ( auto pHitActor : actorsCollided )
|
||||||
|
{
|
||||||
|
effectPacket.data().targetId = pHitActor->getId();
|
||||||
|
effectPacket.data().unknown_1 = 1; // the magic trick for getting it to work
|
||||||
|
effectPacket.data().unknown_5 = 1;
|
||||||
|
effectPacket.data().unknown_8 = 1;
|
||||||
|
effectPacket.data().actionTextId = 0;
|
||||||
|
effectPacket.data().effectTarget = pHitActor->getId();
|
||||||
|
effectPacket.data().effects[0].value = calculatedHeal + ( rand() % 15 );
|
||||||
|
|
||||||
|
pHitActor->sendToInRangeSet( effectPacket, true );
|
||||||
|
pHitActor->heal( calculatedHeal );
|
||||||
|
|
||||||
|
if ( isPlayer() )
|
||||||
|
getAsPlayer()->sendDebug( "AoE hit actor " + pHitActor->getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*! \param StatusEffectPtr to be applied to the actor */
|
/*! \param StatusEffectPtr to be applied to the actor */
|
||||||
void Core::Entity::Actor::addStatusEffect( StatusEffect::StatusEffectPtr pEffect )
|
void Core::Entity::Actor::addStatusEffect( StatusEffect::StatusEffectPtr pEffect )
|
||||||
{
|
{
|
||||||
|
|
|
@ -231,6 +231,8 @@ public:
|
||||||
|
|
||||||
void setStatus( ActorStatus status );
|
void setStatus( ActorStatus status );
|
||||||
|
|
||||||
|
void handleScriptSkill( uint32_t type, uint32_t actionId, uint64_t param1, uint64_t param2, Entity::Actor& target );
|
||||||
|
|
||||||
virtual void autoAttack( ActorPtr pTarget );
|
virtual void autoAttack( ActorPtr pTarget );
|
||||||
|
|
||||||
virtual void spawn( PlayerPtr pTarget ) {}
|
virtual void spawn( PlayerPtr pTarget ) {}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
using namespace Core::Data;
|
||||||
using namespace Core::Entity;
|
using namespace Core::Entity;
|
||||||
|
|
||||||
extern Core::Data::ExdData g_exdData;
|
extern Core::Data::ExdData g_exdData;
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
|
|
||||||
#include "Actor.h"
|
#include "Actor.h"
|
||||||
|
|
||||||
|
using namespace Core::Entity;
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
namespace Entity {
|
namespace Data {
|
||||||
|
|
||||||
class CalcBattle
|
class CalcBattle
|
||||||
{
|
{
|
||||||
|
|
|
@ -216,7 +216,7 @@ void Core::Entity::Player::calculateStats()
|
||||||
auto paramGrowthInfo = paramGrowthInfoIt->second;
|
auto paramGrowthInfo = paramGrowthInfoIt->second;
|
||||||
|
|
||||||
// TODO: put formula somewhere else...
|
// TODO: put formula somewhere else...
|
||||||
float base = CalcBattle::calculateBaseStat( getAsPlayer() );
|
float base = Data::CalcBattle::calculateBaseStat( getAsPlayer() );
|
||||||
|
|
||||||
m_baseStats.str = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_str ) / 100 ) + tribeInfo.mod_str );
|
m_baseStats.str = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_str ) / 100 ) + tribeInfo.mod_str );
|
||||||
m_baseStats.dex = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_dex ) / 100 ) + tribeInfo.mod_dex );
|
m_baseStats.dex = static_cast< uint32_t >( base * ( static_cast< float >( classInfo.mod_dex ) / 100 ) + tribeInfo.mod_dex );
|
||||||
|
@ -232,9 +232,9 @@ void Core::Entity::Player::calculateStats()
|
||||||
m_baseStats.attackPotMagic = paramGrowthInfo.base_secondary;
|
m_baseStats.attackPotMagic = paramGrowthInfo.base_secondary;
|
||||||
m_baseStats.healingPotMagic = paramGrowthInfo.base_secondary;
|
m_baseStats.healingPotMagic = paramGrowthInfo.base_secondary;
|
||||||
|
|
||||||
m_baseStats.max_mp = CalcBattle::calculateMaxMp( getAsPlayer() );
|
m_baseStats.max_mp = Data::CalcBattle::calculateMaxMp( getAsPlayer() );
|
||||||
|
|
||||||
m_baseStats.max_hp = CalcBattle::calculateMaxHp( getAsPlayer() );
|
m_baseStats.max_hp = Data::CalcBattle::calculateMaxHp( getAsPlayer() );
|
||||||
|
|
||||||
if( m_mp > m_baseStats.max_mp )
|
if( m_mp > m_baseStats.max_mp )
|
||||||
m_mp = m_baseStats.max_mp;
|
m_mp = m_baseStats.max_mp;
|
||||||
|
@ -1514,102 +1514,6 @@ void Core::Entity::Player::autoAttack( ActorPtr pTarget )
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::Entity::Player::handleScriptSkill( uint32_t type, uint32_t actionId, uint64_t param1, uint64_t param2, Entity::Actor& pTarget )
|
|
||||||
{
|
|
||||||
sendDebug( std::to_string( pTarget.getId() ) );
|
|
||||||
sendDebug( "Handle script skill type: " + std::to_string( type ) );
|
|
||||||
|
|
||||||
auto actionInfoPtr = g_exdData.getActionInfo( actionId );
|
|
||||||
|
|
||||||
sendDebug( actionInfoPtr->name );
|
|
||||||
if ( actionInfoPtr->is_aoe )
|
|
||||||
sendDebug( "is aoe: " + std::to_string( actionInfoPtr->is_aoe ) );
|
|
||||||
|
|
||||||
GamePacketNew< FFXIVIpcEffect, ServerZoneIpcType > effectPacket( getId() );
|
|
||||||
effectPacket.data().targetId = pTarget.getId();
|
|
||||||
effectPacket.data().actionAnimationId = actionId;
|
|
||||||
effectPacket.data().unknown_2 = 1; // This seems to have an effect on the "double-cast finish" animation
|
|
||||||
// effectPacket.data().unknown_3 = 1;
|
|
||||||
effectPacket.data().actionTextId = actionId;
|
|
||||||
effectPacket.data().numEffects = 1;
|
|
||||||
effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() );
|
|
||||||
effectPacket.data().effectTarget = pTarget.getId();
|
|
||||||
effectPacket.data().effects[0].value = 0;
|
|
||||||
effectPacket.data().effects[0].effectType = static_cast < ActionEffectType >( type );
|
|
||||||
effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalDamage;
|
|
||||||
effectPacket.data().effects[0].unknown_3 = 7;
|
|
||||||
|
|
||||||
switch ( type )
|
|
||||||
{
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
{
|
|
||||||
sendDebug( "STD_DAMAGE" );
|
|
||||||
|
|
||||||
effectPacket.data().effects[0].value = static_cast< int16_t >( param1 );
|
|
||||||
|
|
||||||
sendToInRangeSet( effectPacket, true );
|
|
||||||
|
|
||||||
if ( !pTarget.isAlive() )
|
|
||||||
break;
|
|
||||||
|
|
||||||
pTarget.takeDamage( static_cast< uint32_t >( param1 ) );
|
|
||||||
pTarget.onActionHostile( shared_from_this() );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 4:
|
|
||||||
{
|
|
||||||
uint32_t calculatedHeal = CalcBattle::calculateHealValue( getAsPlayer(), static_cast< uint32_t >( param1 ) );
|
|
||||||
|
|
||||||
effectPacket.data().effects[0].value = static_cast< int16_t >( calculatedHeal );
|
|
||||||
effectPacket.data().effects[0].effectType = ActionEffectType::Heal;
|
|
||||||
effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalHeal;
|
|
||||||
|
|
||||||
sendDebug( "STD_HEAL" );
|
|
||||||
|
|
||||||
sendToInRangeSet( effectPacket, true );
|
|
||||||
|
|
||||||
if ( !pTarget.isAlive() )
|
|
||||||
break;
|
|
||||||
|
|
||||||
// todo: get proper packets: the following was just kind of thrown together from what we know
|
|
||||||
// also toss AoE to another spot and make it generic
|
|
||||||
sendDebug( actionInfoPtr->name );
|
|
||||||
if ( actionInfoPtr->is_aoe )
|
|
||||||
{
|
|
||||||
sendDebug( "IS AOE LOL" );
|
|
||||||
for ( auto pCurAct : m_inRangePlayers )
|
|
||||||
{
|
|
||||||
assert( pCurAct );
|
|
||||||
if ( !pCurAct->isAlive() )
|
|
||||||
break;
|
|
||||||
|
|
||||||
if ( Math::Util::distance( pTarget.getPos().x, pTarget.getPos().y, pTarget.getPos().z, pCurAct->getPos().x, pCurAct->getPos().y, pCurAct->getPos().z ) <= actionInfoPtr->radius )
|
|
||||||
{
|
|
||||||
effectPacket.data().targetId = pCurAct->getId();
|
|
||||||
effectPacket.data().unknown_1 = 1; // the magic trick for getting it to work
|
|
||||||
effectPacket.data().unknown_8 = 1;
|
|
||||||
effectPacket.data().unknown_5 = 1;
|
|
||||||
effectPacket.data().actionTextId = 0;
|
|
||||||
effectPacket.data().effectTarget = pCurAct->getId();
|
|
||||||
|
|
||||||
pCurAct->sendToInRangeSet( effectPacket, true );
|
|
||||||
pCurAct->heal( calculatedHeal );
|
|
||||||
sendDebug( "AoE hit actor " + pCurAct->getName() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pTarget.heal( calculatedHeal );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
// Content Finder
|
// Content Finder
|
||||||
|
|
|
@ -487,8 +487,6 @@ public:
|
||||||
void setAutoattack( bool mode );
|
void setAutoattack( bool mode );
|
||||||
bool isAutoattackOn() const;
|
bool isAutoattackOn() const;
|
||||||
|
|
||||||
void handleScriptSkill( uint32_t type, uint32_t actionId, uint64_t param1, uint64_t param2, Entity::Actor& target );
|
|
||||||
|
|
||||||
// Content Finder handling
|
// Content Finder handling
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
/*! Get an unix time when the player can register into content finder again. */
|
/*! Get an unix time when the player can register into content finder again. */
|
||||||
|
|
|
@ -218,11 +218,11 @@ void Core::ServerZone::run( int32_t argc, char* argv[] )
|
||||||
Network::HivePtr hive( new Network::Hive() );
|
Network::HivePtr hive( new Network::Hive() );
|
||||||
Network::addServerToHive< Network::GameConnection >( m_ip, m_port, hive );
|
Network::addServerToHive< Network::GameConnection >( m_ip, m_port, hive );
|
||||||
|
|
||||||
g_scriptMgr.init();
|
|
||||||
|
|
||||||
g_log.info( "ZoneMgr: Setting up zones" );
|
g_log.info( "ZoneMgr: Setting up zones" );
|
||||||
g_zoneMgr.createZones();
|
g_zoneMgr.createZones();
|
||||||
|
|
||||||
|
g_scriptMgr.init();
|
||||||
|
|
||||||
std::vector< std::thread > thread_list;
|
std::vector< std::thread > thread_list;
|
||||||
thread_list.push_back( std::thread( std::bind( &Network::Hive::Run, hive.get() ) ) );
|
thread_list.push_back( std::thread( std::bind( &Network::Hive::Run, hive.get() ) ) );
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue