mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-22 20:57:46 +00:00
[3.x] WIP: Initial Action and StatusEffect implementation (#958)
* Check statuses to determine valid lut entry * Add duration field to statuses * Rename buildEffects to make more sense * Add basic generic handler for applying statuseffects * Add more modifiers * Add basic modifier impl for Chara * Apply/remove modifiers for statuseffects * Add some example statuses to lut * Fix windows build error * Don't clear tick effect * Add status entry for Maim * Apply status effects properly for self when having a target * Fix hasStatusEffect to prevent duplicates * Basic dot/hot ticks implemented * Update HP on tick effects * Apply effect to correct target * Add method to simplify applying statuses to self * Add job actions for warrior * Add some actions and statuses for war * Add even more modifiers * Add statuseffect cost type * Add option to not send statusremove order * Change delModifier assert to return early instead * Add option for scripts to enable the generic/lut handler * Add enums for common action values * fix indentation * Fix modifier name for Defiance * Remove status tick logging * Move modifiers to statuseffect * Add ParryPercent modifier * Remove wrath when Defiance ends * Apply modifiers in applyStatus * Remove unused method * Persistence for cross-class skills * Add flags to StatusEffects * Some exd struct fixes * Some aoe work * Add flags to lut * Add missing changeclass * Add SET_STATUS_ME to ActionIntegrity * Improve offensive action check * Add flag to overloaded applyStatusEffectSelf * indentation fix * Some calculation work * Null-check ActionResultBuilder --------- Co-authored-by: Lucy <44952533+Skyliegirl33@users.noreply.github.com> Co-authored-by: Mordred <30826167+SapphireMordred@users.noreply.github.com>
This commit is contained in:
parent
5189042247
commit
7bfd9538c9
37 changed files with 902 additions and 87 deletions
|
@ -398,7 +398,18 @@
|
||||||
"restorePercentage": 0,
|
"restorePercentage": 0,
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [
|
||||||
|
{
|
||||||
|
"id": 83,
|
||||||
|
"duration": 20000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "DefensePercent",
|
||||||
|
"value": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"target": []
|
"target": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -414,7 +425,18 @@
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [],
|
||||||
"target": []
|
"target": [
|
||||||
|
{
|
||||||
|
"id": 244,
|
||||||
|
"duration": 30000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "TickDamage",
|
||||||
|
"value": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"34": {
|
"34": {
|
||||||
|
@ -478,7 +500,18 @@
|
||||||
45
|
45
|
||||||
],
|
],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [
|
||||||
|
{
|
||||||
|
"id": 85,
|
||||||
|
"duration": 24000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "DamageDealtPercent",
|
||||||
|
"value": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"target": []
|
"target": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -493,7 +526,18 @@
|
||||||
"restorePercentage": 0,
|
"restorePercentage": 0,
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [
|
||||||
|
{
|
||||||
|
"id": 86,
|
||||||
|
"duration": 20000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "AttackPowerPercent",
|
||||||
|
"value": 50
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"target": []
|
"target": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -523,7 +567,18 @@
|
||||||
"restorePercentage": 0,
|
"restorePercentage": 0,
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [
|
||||||
|
{
|
||||||
|
"id": 87,
|
||||||
|
"duration": 20000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "HPPercent",
|
||||||
|
"value": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"target": []
|
"target": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -574,7 +629,7 @@
|
||||||
},
|
},
|
||||||
"44": {
|
"44": {
|
||||||
"name": "Vengeance",
|
"name": "Vengeance",
|
||||||
"potency": 50,
|
"potency": 0,
|
||||||
"comboPotency": 0,
|
"comboPotency": 0,
|
||||||
"flankPotency": 0,
|
"flankPotency": 0,
|
||||||
"frontPotency": 0,
|
"frontPotency": 0,
|
||||||
|
@ -583,7 +638,18 @@
|
||||||
"restorePercentage": 0,
|
"restorePercentage": 0,
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [
|
||||||
|
{
|
||||||
|
"id": 89,
|
||||||
|
"duration": 20000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "ReflectPhysical",
|
||||||
|
"value": 50
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"target": []
|
"target": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -643,7 +709,34 @@
|
||||||
"restorePercentage": 0,
|
"restorePercentage": 0,
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [
|
||||||
|
{
|
||||||
|
"id": 91,
|
||||||
|
"duration": 0,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "HPPercent",
|
||||||
|
"value": 25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"modifier": "DamageDealtPercent",
|
||||||
|
"value": -25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"modifier": "HealingMagicRecoveryPercent",
|
||||||
|
"value": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"modifier": "AccuracyPercent",
|
||||||
|
"value": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"modifier": "EnmityPercent",
|
||||||
|
"value": 20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"target": []
|
"target": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -703,7 +796,12 @@
|
||||||
"restorePercentage": 0,
|
"restorePercentage": 0,
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [
|
||||||
|
{
|
||||||
|
"id": 97,
|
||||||
|
"duration": 30000
|
||||||
|
}
|
||||||
|
],
|
||||||
"target": []
|
"target": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1176,7 +1274,19 @@
|
||||||
"restorePercentage": 0,
|
"restorePercentage": 0,
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [
|
||||||
|
{
|
||||||
|
"id": 116,
|
||||||
|
"duration": 10000,
|
||||||
|
"flag": 4096,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "CriticalHitPercent",
|
||||||
|
"value": 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
"target": []
|
"target": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -2454,7 +2564,38 @@
|
||||||
"nextCombo": [],
|
"nextCombo": [],
|
||||||
"statuses": {
|
"statuses": {
|
||||||
"caster": [],
|
"caster": [],
|
||||||
"target": []
|
"target": [
|
||||||
|
{
|
||||||
|
"id": 180,
|
||||||
|
"duration": 24000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "TickDamage",
|
||||||
|
"value": 35
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 191,
|
||||||
|
"duration": 24000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "HealingRecoveryPercent",
|
||||||
|
"value": -20
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 240,
|
||||||
|
"duration": 24000,
|
||||||
|
"modifiers": [
|
||||||
|
{
|
||||||
|
"modifier": "HeavyPercent",
|
||||||
|
"value": 40
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"169": {
|
"169": {
|
||||||
|
|
13
deps/datReader/Exd/Structs.h
vendored
13
deps/datReader/Exd/Structs.h
vendored
|
@ -391,14 +391,14 @@ namespace Excel
|
||||||
uint8_t EffectWidth;
|
uint8_t EffectWidth;
|
||||||
uint8_t CostType;
|
uint8_t CostType;
|
||||||
uint8_t Cond;
|
uint8_t Cond;
|
||||||
uint8_t RecastGroup;
|
|
||||||
uint8_t Element;
|
uint8_t Element;
|
||||||
uint8_t ProcStatus;
|
uint8_t ProcStatus;
|
||||||
uint8_t UseClassJob;
|
uint8_t ClassJobCategory;
|
||||||
|
uint8_t RecastGroup;
|
||||||
uint8_t Init;
|
uint8_t Init;
|
||||||
uint8_t Omen;
|
uint8_t Omen;
|
||||||
uint8_t Unknown;
|
uint8_t Learn;
|
||||||
int8_t Learn;
|
int8_t UseClassJob;
|
||||||
int8_t SelectRange;
|
int8_t SelectRange;
|
||||||
int8_t SelectCorpse;
|
int8_t SelectCorpse;
|
||||||
int8_t AttackType;
|
int8_t AttackType;
|
||||||
|
@ -430,7 +430,7 @@ namespace Excel
|
||||||
uint8_t HideCastBar : 1;
|
uint8_t HideCastBar : 1;
|
||||||
uint8_t IsTargetLine : 1;
|
uint8_t IsTargetLine : 1;
|
||||||
|
|
||||||
int8_t padding0;
|
int8_t unknown : 8;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* 75653 */
|
/* 75653 */
|
||||||
|
@ -2054,7 +2054,8 @@ namespace Excel
|
||||||
uint8_t NotControl : 1;
|
uint8_t NotControl : 1;
|
||||||
uint8_t NotAction : 1;
|
uint8_t NotAction : 1;
|
||||||
uint8_t NotMove : 1;
|
uint8_t NotMove : 1;
|
||||||
uint8_t padding0 : 6;
|
uint8_t padding0 : 5;
|
||||||
|
uint8_t CanOff : 1;
|
||||||
uint8_t SemiTransparent : 1;
|
uint8_t SemiTransparent : 1;
|
||||||
uint8_t FcAction : 1;
|
uint8_t FcAction : 1;
|
||||||
int8_t padding1[2];
|
int8_t padding1[2];
|
||||||
|
|
1
sql/migrations/20230309164293_AddBorrowAction.sql
Normal file
1
sql/migrations/20230309164293_AddBorrowAction.sql
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE `characlass` ADD `BorrowAction` binary(40) DEFAULT NULL NULL AFTER `Lvl`;
|
|
@ -256,12 +256,14 @@ void PlayerMinimal::saveAsNew()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CharacterId, ClassIdx, Exp, Lvl
|
// CharacterId, ClassIdx, Exp, Lvl, BorrowAction
|
||||||
auto stmtClass = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_CLASS_INS );
|
auto stmtClass = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_CLASS_INS );
|
||||||
stmtClass->setUInt64( 1, m_characterId );
|
stmtClass->setUInt64( 1, m_characterId );
|
||||||
stmtClass->setInt( 2, g_exdData.getRow< Excel::ClassJob >( m_class )->data().WorkIndex );
|
stmtClass->setInt( 2, g_exdData.getRow< Excel::ClassJob >( m_class )->data().WorkIndex );
|
||||||
stmtClass->setInt( 3, 0 );
|
stmtClass->setInt( 3, 0 );
|
||||||
stmtClass->setInt( 4, 1 );
|
stmtClass->setInt( 4, 1 );
|
||||||
|
std::vector< uint8_t > borrowActionVec( Common::ARRSIZE_BORROWACTION * 4 );
|
||||||
|
stmtClass->setBinary( 5, borrowActionVec );
|
||||||
g_charaDb.directExecute( stmtClass );
|
g_charaDb.directExecute( stmtClass );
|
||||||
|
|
||||||
auto stmtSearchInfo = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_SEARCHINFO_INS );
|
auto stmtSearchInfo = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_SEARCHINFO_INS );
|
||||||
|
|
|
@ -37,6 +37,7 @@ namespace Sapphire::Common
|
||||||
const uint16_t ARRSIZE_UNLOCKS = 64u;
|
const uint16_t ARRSIZE_UNLOCKS = 64u;
|
||||||
const uint16_t ARRSIZE_ORCHESTRION = 40u;
|
const uint16_t ARRSIZE_ORCHESTRION = 40u;
|
||||||
const uint16_t ARRSIZE_MONSTERNOTE = 12u;
|
const uint16_t ARRSIZE_MONSTERNOTE = 12u;
|
||||||
|
const uint16_t ARRSIZE_BORROWACTION = 10u;
|
||||||
|
|
||||||
const uint8_t TOWN_COUNT = 6;
|
const uint8_t TOWN_COUNT = 6;
|
||||||
|
|
||||||
|
@ -887,22 +888,55 @@ namespace Sapphire::Common
|
||||||
Perception = 73,
|
Perception = 73,
|
||||||
|
|
||||||
// Unique modifiers
|
// Unique modifiers
|
||||||
HPPercent = 1000,
|
TickHeal = 1000,
|
||||||
MPPercent = 1001,
|
TickDamage = 1001,
|
||||||
TPPercent = 1002,
|
StrengthPercent = 1002,
|
||||||
GPPercent = 1003,
|
DexterityPercent = 1003,
|
||||||
CPPercent = 1004,
|
VitalityPercent = 1004,
|
||||||
PhysicalDamagePercent = 1005,
|
IntelligencePercent = 1005,
|
||||||
MagicDamagePercent = 1006,
|
MindPercent = 1006,
|
||||||
AttackPowerPercent = 1007,
|
PietyPercent = 1007,
|
||||||
DefensePercent = 1008,
|
HPPercent = 1008,
|
||||||
AccuracyPercent = 1009,
|
MPPercent = 1009,
|
||||||
EvasionPercent = 1010,
|
TPPercent = 1010,
|
||||||
MagicDefensePercent = 1011,
|
GPPercent = 1011,
|
||||||
CriticalHitPowerPercent = 1012,
|
CPPercent = 1012,
|
||||||
CriticalHitResiliencePercent = 1013,
|
PhysicalDamagePercent = 1013,
|
||||||
CriticalHitPercent = 1014,
|
MagicDamagePercent = 1014,
|
||||||
EnmityPercent = 1015
|
AttackPowerPercent = 1015,
|
||||||
|
DefensePercent = 1016,
|
||||||
|
AccuracyPercent = 1017,
|
||||||
|
EvasionPercent = 1018,
|
||||||
|
MagicDefensePercent = 1019,
|
||||||
|
CriticalHitPowerPercent = 1020,
|
||||||
|
CriticalHitResiliencePercent = 1021,
|
||||||
|
CriticalHitPercent = 1022,
|
||||||
|
EnmityPercent = 1023,
|
||||||
|
DamageDealtPercent = 1024,
|
||||||
|
DamageTakenPercent = 1025,
|
||||||
|
HealingMagicRecoveryPercent = 1026,
|
||||||
|
SlashingResistancePercent = 1027,
|
||||||
|
PiercingResistancePercent = 1028,
|
||||||
|
BluntResistancePercent = 1029,
|
||||||
|
ProjectileResistancePercent = 1030,
|
||||||
|
ParryPercent = 1031
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class StatusEffectFlag : uint32_t
|
||||||
|
{
|
||||||
|
BuffCategory = 1,
|
||||||
|
DebuffCategory = 2,
|
||||||
|
Permanent = 4,
|
||||||
|
IsGaze = 8,
|
||||||
|
Transfiguration = 16,
|
||||||
|
CanDispel = 32,
|
||||||
|
LockActions = 64,
|
||||||
|
LockControl = 128,
|
||||||
|
LockMovement = 256,
|
||||||
|
Invisibilty = 512,
|
||||||
|
CanStatusOff = 1024,
|
||||||
|
FcBuff = 2048,
|
||||||
|
RemoveOnSuccessfulHit = 4096
|
||||||
};
|
};
|
||||||
|
|
||||||
enum struct ActionAspect : uint8_t
|
enum struct ActionAspect : uint8_t
|
||||||
|
@ -923,6 +957,7 @@ namespace Sapphire::Common
|
||||||
MagicPoints = 3,
|
MagicPoints = 3,
|
||||||
TacticsPoints = 5,
|
TacticsPoints = 5,
|
||||||
TacticsPoints1 = 6,
|
TacticsPoints1 = 6,
|
||||||
|
StatusEffect = 10,
|
||||||
Sprint = 18,
|
Sprint = 18,
|
||||||
// WARGauge = 22,
|
// WARGauge = 22,
|
||||||
// DRKGauge = 25,
|
// DRKGauge = 25,
|
||||||
|
@ -1830,8 +1865,8 @@ namespace Sapphire::Common
|
||||||
{
|
{
|
||||||
SingleTarget = 1,
|
SingleTarget = 1,
|
||||||
CircularAOE = 2,
|
CircularAOE = 2,
|
||||||
Type3 = 3, // another single target? no idea how to call it
|
RectangularAOE = 3,
|
||||||
RectangularAOE = 4,
|
ConeAOE = 4,
|
||||||
CircularAoEPlaced = 7
|
CircularAoEPlaced = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -161,11 +161,11 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
|
||||||
prepareStatement( CHARA_SEL_QUEST, "SELECT * FROM charaquest WHERE CharacterId = ?;", CONNECTION_SYNC );
|
prepareStatement( CHARA_SEL_QUEST, "SELECT * FROM charaquest WHERE CharacterId = ?;", CONNECTION_SYNC );
|
||||||
|
|
||||||
/// CLASS INFO
|
/// CLASS INFO
|
||||||
prepareStatement( CHARA_CLASS_SEL, "SELECT ClassIdx, Exp, Lvl FROM characlass WHERE CharacterId = ?;",
|
prepareStatement( CHARA_CLASS_SEL, "SELECT ClassIdx, Exp, Lvl, BorrowAction FROM characlass WHERE CharacterId = ?;",
|
||||||
CONNECTION_SYNC );
|
CONNECTION_SYNC );
|
||||||
prepareStatement( CHARA_CLASS_INS, "INSERT INTO characlass ( CharacterId, ClassIdx, Exp, Lvl ) VALUES( ?,?,?,? );",
|
prepareStatement( CHARA_CLASS_INS, "INSERT INTO characlass ( CharacterId, ClassIdx, Exp, Lvl, BorrowAction ) VALUES( ?,?,?,?,? );",
|
||||||
CONNECTION_BOTH );
|
CONNECTION_BOTH );
|
||||||
prepareStatement( CHARA_CLASS_UP, "UPDATE characlass SET Exp = ?, Lvl = ? WHERE CharacterId = ? AND ClassIdx = ?;",
|
prepareStatement( CHARA_CLASS_UP, "UPDATE characlass SET Exp = ?, Lvl = ?, BorrowAction = ? WHERE CharacterId = ? AND ClassIdx = ?;",
|
||||||
CONNECTION_ASYNC );
|
CONNECTION_ASYNC );
|
||||||
prepareStatement( CHARA_CLASS_DEL, "DELETE FROM characlass WHERE CharacterId = ?;", CONNECTION_ASYNC );
|
prepareStatement( CHARA_CLASS_DEL, "DELETE FROM characlass WHERE CharacterId = ?;", CONNECTION_ASYNC );
|
||||||
|
|
||||||
|
|
47
src/scripts/action/war/ActionInnerBeast.cpp
Normal file
47
src/scripts/action/war/ActionInnerBeast.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#include <Script/NativeScriptApi.h>
|
||||||
|
#include <ScriptObject.h>
|
||||||
|
#include <Actor/Player.h>
|
||||||
|
#include <Action/CommonAction.h>
|
||||||
|
#include <Action/Action.h>
|
||||||
|
#include <StatusEffect/StatusEffect.h>
|
||||||
|
|
||||||
|
using namespace Sapphire;
|
||||||
|
using namespace Sapphire::World::Action;
|
||||||
|
|
||||||
|
class ActionInnerBeast : public Sapphire::ScriptAPI::ActionScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ActionInnerBeast() : Sapphire::ScriptAPI::ActionScript( 49 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto Potency = 300;
|
||||||
|
|
||||||
|
void onExecute( Sapphire::World::Action::Action& action ) override
|
||||||
|
{
|
||||||
|
auto pPlayer = action.getSourceChara()->getAsPlayer();
|
||||||
|
auto pSource = action.getSourceChara();
|
||||||
|
auto pTarget = action.getHitChara();
|
||||||
|
auto pActionBuilder = action.getActionResultBuilder();
|
||||||
|
|
||||||
|
if( !pPlayer || !pActionBuilder )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( auto status = pPlayer->getStatusEffectById( Defiance ); status )
|
||||||
|
status->setModifier( Common::ParamModifier::DamageDealtPercent, 0 );
|
||||||
|
|
||||||
|
auto dmg = action.calcDamage( Potency );
|
||||||
|
pActionBuilder->damage( pSource, pTarget, dmg.first, dmg.second );
|
||||||
|
pActionBuilder->heal( pTarget, pSource, dmg.first, Common::CalcResultType::TypeRecoverHp, Common::ActionResultFlag::EffectOnSource );
|
||||||
|
|
||||||
|
pActionBuilder->applyStatusEffectSelf( InnerBeast, 15000, 0, { StatusModifier{ Common::ParamModifier::DamageTakenPercent, -20 } } );
|
||||||
|
|
||||||
|
if( !pPlayer->hasStatusEffect( Unchained ) )
|
||||||
|
{
|
||||||
|
if( auto status = pPlayer->getStatusEffectById( Defiance ); status )
|
||||||
|
status->setModifier( Common::ParamModifier::DamageDealtPercent, -25 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPOSE_SCRIPT( ActionInnerBeast );
|
33
src/scripts/action/war/ActionUnchained.cpp
Normal file
33
src/scripts/action/war/ActionUnchained.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include <Script/NativeScriptApi.h>
|
||||||
|
#include <ScriptObject.h>
|
||||||
|
#include <Actor/Player.h>
|
||||||
|
#include <Action/CommonAction.h>
|
||||||
|
#include <Action/Action.h>
|
||||||
|
#include <StatusEffect/StatusEffect.h>
|
||||||
|
|
||||||
|
using namespace Sapphire;
|
||||||
|
using namespace Sapphire::World::Action;
|
||||||
|
|
||||||
|
class ActionUnchained : public Sapphire::ScriptAPI::ActionScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ActionUnchained() : Sapphire::ScriptAPI::ActionScript( 50 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void onExecute( Sapphire::World::Action::Action& action ) override
|
||||||
|
{
|
||||||
|
auto pPlayer = action.getSourceChara()->getAsPlayer();
|
||||||
|
auto pActionBuilder = action.getActionResultBuilder();
|
||||||
|
|
||||||
|
if( !pPlayer || !pActionBuilder )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( auto status = pPlayer->getStatusEffectById( Defiance ); status )
|
||||||
|
status->setModifier( Common::ParamModifier::DamageDealtPercent, 0 );
|
||||||
|
|
||||||
|
pActionBuilder->applyStatusEffectSelf( Unchained, 20000, 0 );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPOSE_SCRIPT( ActionUnchained );
|
27
src/scripts/statuseffect/StatusEffectDefiance.cpp
Normal file
27
src/scripts/statuseffect/StatusEffectDefiance.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include <Script/NativeScriptApi.h>
|
||||||
|
#include <ScriptObject.h>
|
||||||
|
#include <Actor/Player.h>
|
||||||
|
#include <Action/CommonAction.h>
|
||||||
|
|
||||||
|
using namespace Sapphire;
|
||||||
|
using namespace Sapphire::World::Action;
|
||||||
|
|
||||||
|
class StatusEffectDefiance : public Sapphire::ScriptAPI::StatusEffectScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StatusEffectDefiance() : Sapphire::ScriptAPI::StatusEffectScript( 91 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void onExpire( Entity::Chara& actor ) override
|
||||||
|
{
|
||||||
|
actor.removeSingleStatusEffectById( Unchained );
|
||||||
|
actor.removeSingleStatusEffectById( Wrath );
|
||||||
|
actor.removeSingleStatusEffectById( WrathII );
|
||||||
|
actor.removeSingleStatusEffectById( WrathIII );
|
||||||
|
actor.removeSingleStatusEffectById( WrathIV );
|
||||||
|
actor.removeSingleStatusEffectById( Infuriated );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPOSE_SCRIPT( StatusEffectDefiance );
|
24
src/scripts/statuseffect/StatusEffectUnchained.cpp
Normal file
24
src/scripts/statuseffect/StatusEffectUnchained.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include <Script/NativeScriptApi.h>
|
||||||
|
#include <ScriptObject.h>
|
||||||
|
#include <Actor/Player.h>
|
||||||
|
#include <Action/CommonAction.h>
|
||||||
|
#include <StatusEffect/StatusEffect.h>
|
||||||
|
|
||||||
|
using namespace Sapphire;
|
||||||
|
using namespace Sapphire::World::Action;
|
||||||
|
|
||||||
|
class StatusEffectUnchained : public Sapphire::ScriptAPI::StatusEffectScript
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StatusEffectUnchained() : Sapphire::ScriptAPI::StatusEffectScript( 92 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void onExpire( Entity::Chara& actor ) override
|
||||||
|
{
|
||||||
|
if( auto status = actor.getStatusEffectById( Defiance ); status )
|
||||||
|
status->setModifier( Common::ParamModifier::DamageDealtPercent, -25 );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPOSE_SCRIPT( StatusEffectUnchained );
|
|
@ -40,6 +40,8 @@ struct StatusModifier
|
||||||
struct StatusEntry
|
struct StatusEntry
|
||||||
{
|
{
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
|
int32_t duration;
|
||||||
|
uint32_t flag;
|
||||||
std::vector< StatusModifier > modifiers;
|
std::vector< StatusModifier > modifiers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,6 +78,8 @@ void to_json( nlohmann::ordered_json& j, const StatusEntry& statusEntry )
|
||||||
{
|
{
|
||||||
j = nlohmann::ordered_json{
|
j = nlohmann::ordered_json{
|
||||||
{ "id", statusEntry.id },
|
{ "id", statusEntry.id },
|
||||||
|
{ "duration", statusEntry.duration },
|
||||||
|
{ "flag", statusEntry.flag },
|
||||||
{ "modifiers", statusEntry.modifiers }
|
{ "modifiers", statusEntry.modifiers }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@
|
||||||
#include <Service.h>
|
#include <Service.h>
|
||||||
#include "WorldServer.h"
|
#include "WorldServer.h"
|
||||||
|
|
||||||
|
#include "Job/Warrior.h"
|
||||||
|
|
||||||
using namespace Sapphire;
|
using namespace Sapphire;
|
||||||
using namespace Sapphire::Common;
|
using namespace Sapphire::Common;
|
||||||
using namespace Sapphire::Network;
|
using namespace Sapphire::Network;
|
||||||
|
@ -100,6 +102,7 @@ bool Action::Action::init()
|
||||||
m_cooldownGroup = m_actionData->data().RecastGroup;
|
m_cooldownGroup = m_actionData->data().RecastGroup;
|
||||||
m_range = m_actionData->data().SelectRange;
|
m_range = m_actionData->data().SelectRange;
|
||||||
m_effectRange = m_actionData->data().EffectRange;
|
m_effectRange = m_actionData->data().EffectRange;
|
||||||
|
m_effectWidth = m_actionData->data().EffectWidth;
|
||||||
m_category = static_cast< Common::ActionCategory >( m_actionData->data().Category );
|
m_category = static_cast< Common::ActionCategory >( m_actionData->data().Category );
|
||||||
m_castType = static_cast< Common::CastType >( m_actionData->data().EffectType );
|
m_castType = static_cast< Common::CastType >( m_actionData->data().EffectType );
|
||||||
m_aspect = static_cast< Common::ActionAspect >( m_actionData->data().AttackType );
|
m_aspect = static_cast< Common::ActionAspect >( m_actionData->data().AttackType );
|
||||||
|
@ -131,7 +134,7 @@ bool Action::Action::init()
|
||||||
m_primaryCostType = static_cast< Common::ActionPrimaryCostType >( m_actionData->data().CostType );
|
m_primaryCostType = static_cast< Common::ActionPrimaryCostType >( m_actionData->data().CostType );
|
||||||
m_primaryCost = m_actionData->data().CostValue;
|
m_primaryCost = m_actionData->data().CostValue;
|
||||||
|
|
||||||
/*if( !m_actionData->targetArea )
|
if( !m_actionData->data().SelectGround )
|
||||||
{
|
{
|
||||||
// override pos to target position
|
// override pos to target position
|
||||||
// todo: this is kinda dirty
|
// todo: this is kinda dirty
|
||||||
|
@ -143,7 +146,7 @@ bool Action::Action::init()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
// todo: add missing rows for secondaryCostType/secondaryCostType and rename the current rows to primaryCostX
|
// todo: add missing rows for secondaryCostType/secondaryCostType and rename the current rows to primaryCostX
|
||||||
|
|
||||||
|
@ -503,17 +506,21 @@ void Action::Action::buildActionResults()
|
||||||
|
|
||||||
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
||||||
auto hasLutEntry = hasValidLutEntry();
|
auto hasLutEntry = hasValidLutEntry();
|
||||||
|
auto hasScript = scriptMgr.onExecute( *this );
|
||||||
|
|
||||||
if( !scriptMgr.onExecute( *this ) && !hasLutEntry )
|
if( !hasScript && !hasLutEntry )
|
||||||
{
|
{
|
||||||
if( auto player = m_pSource->getAsPlayer() )
|
if( auto player = m_pSource->getAsPlayer() )
|
||||||
Manager::PlayerMgr::sendUrgent( *player, "missing lut entry for action#{}", getId() );
|
Manager::PlayerMgr::sendUrgent( *player, "missing lut entry for action#{}", getId() );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !hasScript )
|
||||||
|
m_enableGenericHandler = true;
|
||||||
|
|
||||||
Network::Util::Packet::sendHudParam( *m_pSource );
|
Network::Util::Packet::sendHudParam( *m_pSource );
|
||||||
|
|
||||||
if( !hasLutEntry || m_hitActors.empty() )
|
if( !m_enableGenericHandler || !hasLutEntry || m_hitActors.empty() )
|
||||||
{
|
{
|
||||||
// send any effect packet added by script or an empty one just to play animation for other players
|
// send any effect packet added by script or an empty one just to play animation for other players
|
||||||
m_actionResultBuilder->sendActionResults( {} );
|
m_actionResultBuilder->sendActionResults( {} );
|
||||||
|
@ -583,6 +590,18 @@ void Action::Action::buildActionResults()
|
||||||
shouldRestoreMP = false;
|
shouldRestoreMP = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we hit an enemy
|
||||||
|
if( m_hitActors.size() > 0 && getHitChara()->getObjKind() != m_pSource->getObjKind() )
|
||||||
|
{
|
||||||
|
m_pSource->removeStatusEffectByFlag( Common::StatusEffectFlag::RemoveOnSuccessfulHit );
|
||||||
|
}
|
||||||
|
|
||||||
|
handleJobAction();
|
||||||
|
|
||||||
|
if( m_lutEntry.statuses.caster.size() > 0 || m_lutEntry.statuses.target.size() > 0 )
|
||||||
|
handleStatusEffects();
|
||||||
|
|
||||||
m_actionResultBuilder->sendActionResults( m_hitActors );
|
m_actionResultBuilder->sendActionResults( m_hitActors );
|
||||||
|
|
||||||
// TODO: disabled, reset kills our queued actions
|
// TODO: disabled, reset kills our queued actions
|
||||||
|
@ -590,6 +609,53 @@ void Action::Action::buildActionResults()
|
||||||
// m_effectBuilder.reset();
|
// m_effectBuilder.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Action::Action::handleStatusEffects()
|
||||||
|
{
|
||||||
|
auto pActionBuilder = getActionResultBuilder();
|
||||||
|
|
||||||
|
if( !pActionBuilder )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( isComboAction() && !isCorrectCombo() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// handle caster statuses
|
||||||
|
if( m_lutEntry.statuses.caster.size() > 0 )
|
||||||
|
{
|
||||||
|
for( auto& status : m_lutEntry.statuses.caster )
|
||||||
|
{
|
||||||
|
pActionBuilder->applyStatusEffectSelf( status.id, status.duration, 0, status.modifiers, status.flag, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle hit actor statuses
|
||||||
|
if( m_lutEntry.statuses.target.size() > 0 && m_hitActors.size() > 0 )
|
||||||
|
{
|
||||||
|
for( auto& actor : m_hitActors )
|
||||||
|
{
|
||||||
|
for( auto& status : m_lutEntry.statuses.target )
|
||||||
|
{
|
||||||
|
pActionBuilder->applyStatusEffect( actor, status.id, status.duration, 0, status.modifiers, status.flag, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( actor->getStatusEffectMap().size() > 0 )
|
||||||
|
actor->onActionHostile( m_pSource );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Action::Action::handleJobAction()
|
||||||
|
{
|
||||||
|
switch( m_pSource->getClass() )
|
||||||
|
{
|
||||||
|
case ClassJob::Warrior:
|
||||||
|
{
|
||||||
|
Warrior::onAction( *m_pSource->getAsPlayer(), *this );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Action::Action::preCheck()
|
bool Action::Action::preCheck()
|
||||||
{
|
{
|
||||||
if( auto player = m_pSource->getAsPlayer() )
|
if( auto player = m_pSource->getAsPlayer() )
|
||||||
|
@ -712,6 +778,17 @@ bool Action::Action::primaryCostCheck( bool subtractCosts )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Common::ActionPrimaryCostType::StatusEffect:
|
||||||
|
{
|
||||||
|
if( !m_pSource->hasStatusEffect( m_primaryCost ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( subtractCosts )
|
||||||
|
m_pSource->removeSingleStatusEffectById( m_primaryCost );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// free casts, likely just pure ogcds
|
// free casts, likely just pure ogcds
|
||||||
case Common::ActionPrimaryCostType::None:
|
case Common::ActionPrimaryCostType::None:
|
||||||
{
|
{
|
||||||
|
@ -780,7 +857,6 @@ void Action::Action::addDefaultActorFilters()
|
||||||
switch( m_castType )
|
switch( m_castType )
|
||||||
{
|
{
|
||||||
case Common::CastType::SingleTarget:
|
case Common::CastType::SingleTarget:
|
||||||
case Common::CastType::Type3:
|
|
||||||
{
|
{
|
||||||
auto filter = std::make_shared< World::Util::ActorFilterSingleTarget >( static_cast< uint32_t >( m_targetId ) );
|
auto filter = std::make_shared< World::Util::ActorFilterSingleTarget >( static_cast< uint32_t >( m_targetId ) );
|
||||||
addActorFilter( filter );
|
addActorFilter( filter );
|
||||||
|
@ -849,7 +925,8 @@ Entity::CharaPtr Action::Action::getHitChara()
|
||||||
bool Action::Action::hasValidLutEntry() const
|
bool Action::Action::hasValidLutEntry() const
|
||||||
{
|
{
|
||||||
return m_lutEntry.potency != 0 || m_lutEntry.comboPotency != 0 || m_lutEntry.flankPotency != 0 || m_lutEntry.frontPotency != 0 ||
|
return m_lutEntry.potency != 0 || m_lutEntry.comboPotency != 0 || m_lutEntry.flankPotency != 0 || m_lutEntry.frontPotency != 0 ||
|
||||||
m_lutEntry.rearPotency != 0 || m_lutEntry.curePotency != 0 || m_lutEntry.restoreMPPercentage != 0;
|
m_lutEntry.rearPotency != 0 || m_lutEntry.curePotency != 0 || m_lutEntry.restoreMPPercentage != 0 ||
|
||||||
|
m_lutEntry.statuses.caster.size() > 0 || m_lutEntry.statuses.target.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Action::ActionResultBuilderPtr Action::Action::getActionResultBuilder()
|
Action::ActionResultBuilderPtr Action::Action::getActionResultBuilder()
|
||||||
|
@ -876,3 +953,8 @@ uint64_t Action::Action::getCastTimeRest() const
|
||||||
{
|
{
|
||||||
return m_castTimeRestMs;
|
return m_castTimeRestMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Action::Action::enableGenericHandler()
|
||||||
|
{
|
||||||
|
m_enableGenericHandler = true;
|
||||||
|
}
|
|
@ -55,6 +55,8 @@ namespace Sapphire::World::Action
|
||||||
|
|
||||||
uint64_t getCastTimeRest() const;
|
uint64_t getCastTimeRest() const;
|
||||||
|
|
||||||
|
void enableGenericHandler();
|
||||||
|
|
||||||
std::shared_ptr< Excel::ExcelStruct< Excel::Action > > getActionData() const;
|
std::shared_ptr< Excel::ExcelStruct< Excel::Action > > getActionData() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -111,6 +113,10 @@ namespace Sapphire::World::Action
|
||||||
|
|
||||||
void buildActionResults();
|
void buildActionResults();
|
||||||
|
|
||||||
|
void handleStatusEffects();
|
||||||
|
|
||||||
|
void handleJobAction();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* @brief Adds an actor filter to this action.
|
* @brief Adds an actor filter to this action.
|
||||||
* @param filter The ptr to the ActorFilter to add
|
* @param filter The ptr to the ActorFilter to add
|
||||||
|
@ -190,6 +196,7 @@ namespace Sapphire::World::Action
|
||||||
uint8_t m_cooldownGroup{};
|
uint8_t m_cooldownGroup{};
|
||||||
int8_t m_range{};
|
int8_t m_range{};
|
||||||
uint8_t m_effectRange{};
|
uint8_t m_effectRange{};
|
||||||
|
uint8_t m_effectWidth{};
|
||||||
uint8_t m_xAxisModifier{};
|
uint8_t m_xAxisModifier{};
|
||||||
Common::ActionAspect m_aspect;
|
Common::ActionAspect m_aspect;
|
||||||
Common::CastType m_castType;
|
Common::CastType m_castType;
|
||||||
|
@ -206,6 +213,7 @@ namespace Sapphire::World::Action
|
||||||
bool m_canTargetFriendly{};
|
bool m_canTargetFriendly{};
|
||||||
bool m_canTargetHostile{};
|
bool m_canTargetHostile{};
|
||||||
bool m_canTargetDead{};
|
bool m_canTargetDead{};
|
||||||
|
bool m_enableGenericHandler{};
|
||||||
|
|
||||||
Common::ActionInterruptType m_interruptType;
|
Common::ActionInterruptType m_interruptType;
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,8 @@ bool ActionLut::validEntryExists( uint16_t actionId )
|
||||||
|
|
||||||
// if all of the fields are 0, it's not 'valid' due to parse error or no useful data in the tooltip
|
// if all of the fields are 0, it's not 'valid' due to parse error or no useful data in the tooltip
|
||||||
return entry.potency != 0 || entry.comboPotency != 0 || entry.flankPotency != 0 || entry.frontPotency != 0 ||
|
return entry.potency != 0 || entry.comboPotency != 0 || entry.flankPotency != 0 || entry.frontPotency != 0 ||
|
||||||
entry.rearPotency != 0 || entry.curePotency != 0;
|
entry.rearPotency != 0 || entry.curePotency != 0 ||
|
||||||
|
entry.statuses.caster.size() > 0 || entry.statuses.target.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ActionEntry& ActionLut::getEntry( uint16_t actionId )
|
const ActionEntry& ActionLut::getEntry( uint16_t actionId )
|
||||||
|
|
|
@ -17,6 +17,8 @@ namespace Sapphire::World::Action
|
||||||
struct StatusEntry
|
struct StatusEntry
|
||||||
{
|
{
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
|
int32_t duration;
|
||||||
|
uint32_t flag;
|
||||||
std::vector< StatusModifier > modifiers;
|
std::vector< StatusModifier > modifiers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,14 @@ std::unordered_map< std::string, Common::ParamModifier > ActionLutData::m_modifi
|
||||||
{ "Control", Common::ParamModifier::Control },
|
{ "Control", Common::ParamModifier::Control },
|
||||||
{ "Gathering", Common::ParamModifier::Gathering },
|
{ "Gathering", Common::ParamModifier::Gathering },
|
||||||
{ "Perception", Common::ParamModifier::Perception },
|
{ "Perception", Common::ParamModifier::Perception },
|
||||||
|
{ "TickHeal", Common::ParamModifier::TickHeal },
|
||||||
|
{ "TickDamage", Common::ParamModifier::TickDamage },
|
||||||
|
{ "StrengthPercent", Common::ParamModifier::StrengthPercent },
|
||||||
|
{ "DexterityPercent", Common::ParamModifier::DexterityPercent },
|
||||||
|
{ "VitalityPercent", Common::ParamModifier::VitalityPercent },
|
||||||
|
{ "IntelligencePercent", Common::ParamModifier::IntelligencePercent },
|
||||||
|
{ "MindPercent", Common::ParamModifier::MindPercent },
|
||||||
|
{ "PietyPercent", Common::ParamModifier::PietyPercent },
|
||||||
{ "HPPercent", Common::ParamModifier::HPPercent },
|
{ "HPPercent", Common::ParamModifier::HPPercent },
|
||||||
{ "MPPercent", Common::ParamModifier::MPPercent },
|
{ "MPPercent", Common::ParamModifier::MPPercent },
|
||||||
{ "TPPercent", Common::ParamModifier::TPPercent },
|
{ "TPPercent", Common::ParamModifier::TPPercent },
|
||||||
|
@ -100,7 +108,15 @@ std::unordered_map< std::string, Common::ParamModifier > ActionLutData::m_modifi
|
||||||
{ "CriticalHitPowerPercent", Common::ParamModifier::CriticalHitPowerPercent },
|
{ "CriticalHitPowerPercent", Common::ParamModifier::CriticalHitPowerPercent },
|
||||||
{ "CriticalHitResiliencePercent", Common::ParamModifier::CriticalHitResiliencePercent },
|
{ "CriticalHitResiliencePercent", Common::ParamModifier::CriticalHitResiliencePercent },
|
||||||
{ "CriticalHitPercent", Common::ParamModifier::CriticalHitPercent },
|
{ "CriticalHitPercent", Common::ParamModifier::CriticalHitPercent },
|
||||||
{ "EnmityPercent", Common::ParamModifier::EnmityPercent }
|
{ "EnmityPercent", Common::ParamModifier::EnmityPercent },
|
||||||
|
{ "DamageDealtPercent", Common::ParamModifier::DamageDealtPercent },
|
||||||
|
{ "DamageTakenPercent", Common::ParamModifier::DamageTakenPercent },
|
||||||
|
{ "HealingMagicRecoveryPercent", Common::ParamModifier::HealingMagicRecoveryPercent },
|
||||||
|
{ "SlashingResistancePercent", Common::ParamModifier::SlashingResistancePercent },
|
||||||
|
{ "PiercingResistancePercent", Common::ParamModifier::PiercingResistancePercent },
|
||||||
|
{ "BluntResistancePercent", Common::ParamModifier::BluntResistancePercent },
|
||||||
|
{ "ProjectileResistancePercent", Common::ParamModifier::ProjectileResistancePercent },
|
||||||
|
{ "ParryPercent", Common::ParamModifier::ParryPercent }
|
||||||
};
|
};
|
||||||
|
|
||||||
bool ActionLutData::cacheActions()
|
bool ActionLutData::cacheActions()
|
||||||
|
|
|
@ -32,6 +32,9 @@ namespace Sapphire::World::Action
|
||||||
inline void from_json( const nlohmann::json& j, StatusEntry& statusEntry )
|
inline void from_json( const nlohmann::json& j, StatusEntry& statusEntry )
|
||||||
{
|
{
|
||||||
j.at( "id" ).get_to( statusEntry.id );
|
j.at( "id" ).get_to( statusEntry.id );
|
||||||
|
j.at( "duration" ).get_to( statusEntry.duration );
|
||||||
|
if( j.contains( "flag" ) )
|
||||||
|
j.at( "flag" ).get_to( statusEntry.flag );
|
||||||
if( j.contains( "modifiers" ) )
|
if( j.contains( "modifiers" ) )
|
||||||
j.at( "modifiers" ).get_to( statusEntry.modifiers );
|
j.at( "modifiers" ).get_to( statusEntry.modifiers );
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,19 @@ void ActionResult::applyStatusEffect( uint32_t id, int32_t duration, Entity::Cha
|
||||||
m_result.Type = CalcResultType::TypeSetStatus;
|
m_result.Type = CalcResultType::TypeSetStatus;
|
||||||
|
|
||||||
m_bOverrideStatus = shouldOverride;
|
m_bOverrideStatus = shouldOverride;
|
||||||
m_pStatus = StatusEffect::make_StatusEffect( id, source.getAsChara(), m_target, duration, 3000 );
|
m_pStatus = Sapphire::StatusEffect::make_StatusEffect( id, source.getAsChara(), m_target, duration, 3000 );
|
||||||
|
m_pStatus->setParam( param );
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionResult::applyStatusEffect( uint32_t id, int32_t duration, Entity::Chara& source, uint8_t param,
|
||||||
|
std::vector< StatusModifier > modifiers, uint32_t flag, bool shouldOverride )
|
||||||
|
{
|
||||||
|
m_result.Value = static_cast< int16_t >( id );
|
||||||
|
m_result.Arg2 = param;
|
||||||
|
m_result.Type = CalcResultType::TypeSetStatus;
|
||||||
|
|
||||||
|
m_bOverrideStatus = shouldOverride;
|
||||||
|
m_pStatus = Sapphire::StatusEffect::make_StatusEffect( id, source.getAsChara(), m_target, duration, modifiers, flag, 3000 );
|
||||||
m_pStatus->setParam( param );
|
m_pStatus->setParam( param );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +101,19 @@ void ActionResult::applyStatusEffectSelf( uint32_t id, int32_t duration, uint8_t
|
||||||
m_pStatus->setParam( param );
|
m_pStatus->setParam( param );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ActionResult::applyStatusEffectSelf( uint32_t id, int32_t duration, uint8_t param, std::vector< World::Action::StatusModifier > modifiers,
|
||||||
|
uint32_t flag, bool shouldOverride )
|
||||||
|
{
|
||||||
|
m_result.Value = static_cast< int16_t >( id );
|
||||||
|
m_result.Arg2 = param;
|
||||||
|
m_result.Type = CalcResultType::TypeSetStatusMe;
|
||||||
|
m_result.Flag = static_cast< uint8_t >( Common::ActionResultFlag::EffectOnSource );
|
||||||
|
|
||||||
|
m_bOverrideStatus = shouldOverride;
|
||||||
|
m_pStatus = Sapphire::StatusEffect::make_StatusEffect( id, m_target, m_target, duration, modifiers, flag, 3000 );
|
||||||
|
m_pStatus->setParam( param );
|
||||||
|
}
|
||||||
|
|
||||||
void ActionResult::mount( uint16_t mountId )
|
void ActionResult::mount( uint16_t mountId )
|
||||||
{
|
{
|
||||||
m_result.Value = static_cast< int16_t >( mountId );
|
m_result.Value = static_cast< int16_t >( mountId );
|
||||||
|
@ -101,7 +126,7 @@ const Common::CalcResultParam& ActionResult::getCalcResultParam() const
|
||||||
return m_result;
|
return m_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StatusEffect::StatusEffectPtr ActionResult::getStatusEffect() const
|
const Sapphire::StatusEffect::StatusEffectPtr ActionResult::getStatusEffect() const
|
||||||
{
|
{
|
||||||
return m_pStatus;
|
return m_pStatus;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <ForwardsZone.h>
|
#include <ForwardsZone.h>
|
||||||
#include <Common.h>
|
#include <Common.h>
|
||||||
|
#include "ActionLut.h"
|
||||||
|
|
||||||
namespace Sapphire::World::Action
|
namespace Sapphire::World::Action
|
||||||
{
|
{
|
||||||
|
@ -20,7 +21,11 @@ namespace Sapphire::World::Action
|
||||||
void startCombo( uint16_t actionId );
|
void startCombo( uint16_t actionId );
|
||||||
void comboSucceed();
|
void comboSucceed();
|
||||||
void applyStatusEffect( uint32_t id, int32_t duration, Entity::Chara& source, uint8_t param, bool shouldOverride );
|
void applyStatusEffect( uint32_t id, int32_t duration, Entity::Chara& source, uint8_t param, bool shouldOverride );
|
||||||
|
void applyStatusEffect( uint32_t id, int32_t duration, Entity::Chara& source, uint8_t param,
|
||||||
|
std::vector< World::Action::StatusModifier > modifiers, uint32_t flag, bool shouldOverride );
|
||||||
void applyStatusEffectSelf( uint32_t id, int32_t duration, uint8_t param, bool shouldOverride );
|
void applyStatusEffectSelf( uint32_t id, int32_t duration, uint8_t param, bool shouldOverride );
|
||||||
|
void applyStatusEffectSelf( uint32_t id, int32_t duration, uint8_t param, std::vector< World::Action::StatusModifier > modifiers,
|
||||||
|
uint32_t flag, bool shouldOverride );
|
||||||
void mount( uint16_t mountId );
|
void mount( uint16_t mountId );
|
||||||
|
|
||||||
Entity::CharaPtr getTarget() const;
|
Entity::CharaPtr getTarget() const;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "ActionResultBuilder.h"
|
#include "ActionResultBuilder.h"
|
||||||
#include "ActionResult.h"
|
#include "ActionResult.h"
|
||||||
|
|
||||||
#include <Actor/Player.h>
|
#include <Actor/Player.h>
|
||||||
|
@ -93,6 +93,14 @@ void ActionResultBuilder::applyStatusEffect( Entity::CharaPtr& target, uint16_t
|
||||||
addResultToActor( target, nextResult );
|
addResultToActor( target, nextResult );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ActionResultBuilder::applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint32_t duration, uint8_t param,
|
||||||
|
std::vector< World::Action::StatusModifier > modifiers, uint32_t flag, bool shouldOverride )
|
||||||
|
{
|
||||||
|
ActionResultPtr nextResult = make_ActionResult( target );
|
||||||
|
nextResult->applyStatusEffect( statusId, duration, *m_sourceChara, param, modifiers, flag, shouldOverride );
|
||||||
|
addResultToActor( target, nextResult );
|
||||||
|
}
|
||||||
|
|
||||||
void ActionResultBuilder::applyStatusEffectSelf( uint16_t statusId, uint32_t duration, uint8_t param, bool shouldOverride )
|
void ActionResultBuilder::applyStatusEffectSelf( uint16_t statusId, uint32_t duration, uint8_t param, bool shouldOverride )
|
||||||
{
|
{
|
||||||
ActionResultPtr nextResult = make_ActionResult( m_sourceChara );
|
ActionResultPtr nextResult = make_ActionResult( m_sourceChara );
|
||||||
|
@ -100,6 +108,14 @@ void ActionResultBuilder::applyStatusEffectSelf( uint16_t statusId, uint32_t dur
|
||||||
addResultToActor( m_sourceChara, nextResult );
|
addResultToActor( m_sourceChara, nextResult );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ActionResultBuilder::applyStatusEffectSelf( uint16_t statusId, uint32_t duration, uint8_t param, std::vector< World::Action::StatusModifier > modifiers,
|
||||||
|
uint32_t flag, bool shouldOverride )
|
||||||
|
{
|
||||||
|
ActionResultPtr nextResult = make_ActionResult( m_sourceChara );
|
||||||
|
nextResult->applyStatusEffectSelf( statusId, duration, param, modifiers, flag, shouldOverride );
|
||||||
|
addResultToActor( m_sourceChara, nextResult );
|
||||||
|
}
|
||||||
|
|
||||||
void ActionResultBuilder::mount( Entity::CharaPtr& target, uint16_t mountId )
|
void ActionResultBuilder::mount( Entity::CharaPtr& target, uint16_t mountId )
|
||||||
{
|
{
|
||||||
ActionResultPtr nextResult = make_ActionResult( target );
|
ActionResultPtr nextResult = make_ActionResult( target );
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <ForwardsZone.h>
|
#include <ForwardsZone.h>
|
||||||
#include <Common.h>
|
#include <Common.h>
|
||||||
|
#include "ActionLut.h"
|
||||||
|
|
||||||
namespace Sapphire::World::Action
|
namespace Sapphire::World::Action
|
||||||
{
|
{
|
||||||
|
@ -25,8 +26,12 @@ namespace Sapphire::World::Action
|
||||||
|
|
||||||
void comboSucceed( Entity::CharaPtr& target );
|
void comboSucceed( Entity::CharaPtr& target );
|
||||||
|
|
||||||
void applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint32_t duration, uint8_t param, bool shouldOverride );
|
void applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint32_t duration, uint8_t param, bool shouldOverride = false );
|
||||||
void applyStatusEffectSelf( uint16_t statusId, uint32_t duration, uint8_t param, bool shouldOverride );
|
void applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint32_t duration, uint8_t param,
|
||||||
|
std::vector< World::Action::StatusModifier > modifiers, uint32_t flag = 0, bool shouldOverride = false );
|
||||||
|
void applyStatusEffectSelf( uint16_t statusId, uint32_t duration, uint8_t param, bool shouldOverride = false );
|
||||||
|
void applyStatusEffectSelf( uint16_t statusId, uint32_t duration, uint8_t param, std::vector< World::Action::StatusModifier > modifiers,
|
||||||
|
uint32_t flag = 0, bool shouldOverride = false );
|
||||||
|
|
||||||
void mount( Entity::CharaPtr& target, uint16_t mountId );
|
void mount( Entity::CharaPtr& target, uint16_t mountId );
|
||||||
|
|
||||||
|
|
30
src/world/Action/CommonAction.h
Normal file
30
src/world/Action/CommonAction.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Sapphire::World::Action
|
||||||
|
{
|
||||||
|
enum ActionSkill
|
||||||
|
{
|
||||||
|
SkullSunder = 35,
|
||||||
|
Maim = 37,
|
||||||
|
StormsPath = 42,
|
||||||
|
StormsEye = 45,
|
||||||
|
ButchersBlock = 47
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ActionStatus
|
||||||
|
{
|
||||||
|
Defiance = 91,
|
||||||
|
Unchained = 92,
|
||||||
|
Wrath = 93,
|
||||||
|
WrathII = 94,
|
||||||
|
WrathIII = 95,
|
||||||
|
WrathIV = 96,
|
||||||
|
Infuriated = 97,
|
||||||
|
InnerBeast = 411,
|
||||||
|
Deliverance = 729
|
||||||
|
};
|
||||||
|
}
|
70
src/world/Action/Job/Warrior.cpp
Normal file
70
src/world/Action/Job/Warrior.cpp
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#include "Warrior.h"
|
||||||
|
|
||||||
|
#include <Action/CommonAction.h>
|
||||||
|
#include <Action/Action.h>
|
||||||
|
#include <Actor/Player.h>
|
||||||
|
|
||||||
|
using namespace Sapphire;
|
||||||
|
using namespace Sapphire::World::Action;
|
||||||
|
|
||||||
|
void Warrior::onAction( Entity::Player& player, Action& action )
|
||||||
|
{
|
||||||
|
switch( action.getId() )
|
||||||
|
{
|
||||||
|
case Maim:
|
||||||
|
case StormsEye:
|
||||||
|
case StormsPath:
|
||||||
|
case SkullSunder:
|
||||||
|
case ButchersBlock:
|
||||||
|
{
|
||||||
|
if( action.isComboAction() && !action.isCorrectCombo() )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if( player.hasStatusEffect( Defiance ) )
|
||||||
|
handleWrath( player, action );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Warrior::handleWrath( Entity::Player& player, Action& action )
|
||||||
|
{
|
||||||
|
auto effectToApply = Wrath;
|
||||||
|
auto parry = 2;
|
||||||
|
auto asChara = player.getAsChara();
|
||||||
|
|
||||||
|
auto pActionBuilder = action.getActionResultBuilder();
|
||||||
|
|
||||||
|
if( !pActionBuilder )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( player.hasStatusEffect( Wrath ) )
|
||||||
|
{
|
||||||
|
player.replaceSingleStatusEffectById( Wrath );
|
||||||
|
effectToApply = WrathII;
|
||||||
|
parry += 2;
|
||||||
|
}
|
||||||
|
else if( player.hasStatusEffect( WrathII ) )
|
||||||
|
{
|
||||||
|
player.replaceSingleStatusEffectById( WrathII );
|
||||||
|
effectToApply = WrathIII;
|
||||||
|
parry += 2;
|
||||||
|
}
|
||||||
|
else if( player.hasStatusEffect( WrathIII ) )
|
||||||
|
{
|
||||||
|
player.replaceSingleStatusEffectById( WrathIII );
|
||||||
|
effectToApply = WrathIV;
|
||||||
|
parry += 2;
|
||||||
|
}
|
||||||
|
else if( player.hasStatusEffect( WrathIV ) )
|
||||||
|
{
|
||||||
|
player.replaceSingleStatusEffectById( WrathIV );
|
||||||
|
effectToApply = Infuriated;
|
||||||
|
parry += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !player.hasStatusEffect( Infuriated ) )
|
||||||
|
{
|
||||||
|
pActionBuilder->applyStatusEffectSelf( effectToApply, 30000, 0, { StatusModifier{ Common::ParamModifier::ParryPercent, parry } }, 0, false );
|
||||||
|
}
|
||||||
|
}
|
20
src/world/Action/Job/Warrior.h
Normal file
20
src/world/Action/Job/Warrior.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Common.h>
|
||||||
|
#include "ForwardsZone.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Sapphire::World::Action
|
||||||
|
{
|
||||||
|
class Warrior
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void onAction( Entity::Player& player, Action& action );
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void handleWrath( Entity::Player& player, Action& action );
|
||||||
|
};
|
||||||
|
}
|
|
@ -5,7 +5,6 @@
|
||||||
#include <Network/CommonActorControl.h>
|
#include <Network/CommonActorControl.h>
|
||||||
#include <Service.h>
|
#include <Service.h>
|
||||||
|
|
||||||
|
|
||||||
#include "Forwards.h"
|
#include "Forwards.h"
|
||||||
|
|
||||||
#include "Territory/Territory.h"
|
#include "Territory/Territory.h"
|
||||||
|
@ -25,6 +24,7 @@
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "Manager/TerritoryMgr.h"
|
#include "Manager/TerritoryMgr.h"
|
||||||
#include "Manager/MgrUtil.h"
|
#include "Manager/MgrUtil.h"
|
||||||
|
#include "Manager/PlayerMgr.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
using namespace Sapphire;
|
using namespace Sapphire;
|
||||||
|
@ -497,9 +497,9 @@ void Chara::addStatusEffect( StatusEffect::StatusEffectPtr pEffect )
|
||||||
if( nextSlot == -1 )
|
if( nextSlot == -1 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pEffect->applyStatus();
|
|
||||||
pEffect->setSlot( nextSlot );
|
pEffect->setSlot( nextSlot );
|
||||||
m_statusEffectMap[ nextSlot ] = pEffect;
|
m_statusEffectMap[ nextSlot ] = pEffect;
|
||||||
|
pEffect->applyStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \param StatusEffectPtr to be applied to the actor */
|
/*! \param StatusEffectPtr to be applied to the actor */
|
||||||
|
@ -515,7 +515,6 @@ void Chara::addStatusEffectByIdIfNotExist( StatusEffect::StatusEffectPtr pStatus
|
||||||
return;
|
return;
|
||||||
|
|
||||||
addStatusEffect( pStatus );
|
addStatusEffect( pStatus );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t Chara::getStatusEffectFreeSlot()
|
int8_t Chara::getStatusEffectFreeSlot()
|
||||||
|
@ -536,6 +535,18 @@ void Chara::statusEffectFreeSlot( uint8_t slotId )
|
||||||
m_statusEffectFreeSlotQueue.push( slotId );
|
m_statusEffectFreeSlotQueue.push( slotId );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Chara::replaceSingleStatusEffectById( uint32_t id )
|
||||||
|
{
|
||||||
|
for( const auto& effectIt : m_statusEffectMap )
|
||||||
|
{
|
||||||
|
if( effectIt.second->getId() == id )
|
||||||
|
{
|
||||||
|
removeStatusEffect( effectIt.first, false );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Chara::removeSingleStatusEffectById( uint32_t id )
|
void Chara::removeSingleStatusEffectById( uint32_t id )
|
||||||
{
|
{
|
||||||
for( const auto& effectIt : m_statusEffectMap )
|
for( const auto& effectIt : m_statusEffectMap )
|
||||||
|
@ -548,7 +559,18 @@ void Chara::removeSingleStatusEffectById( uint32_t id )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map< uint8_t, StatusEffect::StatusEffectPtr >::iterator Chara::removeStatusEffect( uint8_t effectSlotId )
|
void Chara::removeStatusEffectByFlag( Common::StatusEffectFlag flag )
|
||||||
|
{
|
||||||
|
for( auto effectIt = m_statusEffectMap.begin(); effectIt != m_statusEffectMap.end(); )
|
||||||
|
{
|
||||||
|
if( effectIt->second->getFlag() & static_cast< uint32_t >( flag ) )
|
||||||
|
effectIt = removeStatusEffect( effectIt->first );
|
||||||
|
else
|
||||||
|
++effectIt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map< uint8_t, Sapphire::StatusEffect::StatusEffectPtr >::iterator Chara::removeStatusEffect( uint8_t effectSlotId, bool sendOrder )
|
||||||
{
|
{
|
||||||
auto pEffectIt = m_statusEffectMap.find( effectSlotId );
|
auto pEffectIt = m_statusEffectMap.find( effectSlotId );
|
||||||
if( pEffectIt == m_statusEffectMap.end() )
|
if( pEffectIt == m_statusEffectMap.end() )
|
||||||
|
@ -559,7 +581,8 @@ std::map< uint8_t, StatusEffect::StatusEffectPtr >::iterator Chara::removeStatus
|
||||||
auto pEffect = pEffectIt->second;
|
auto pEffect = pEffectIt->second;
|
||||||
pEffect->removeStatus();
|
pEffect->removeStatus();
|
||||||
|
|
||||||
Network::Util::Packet::sendActorControl( getInRangePlayerIds( isPlayer() ), getId(), StatusEffectLose, pEffect->getId() );
|
if( sendOrder )
|
||||||
|
Network::Util::Packet::sendActorControl( getInRangePlayerIds( isPlayer() ), getId(), StatusEffectLose, pEffect->getId() );
|
||||||
|
|
||||||
auto it = m_statusEffectMap.erase( pEffectIt );
|
auto it = m_statusEffectMap.erase( pEffectIt );
|
||||||
Network::Util::Packet::sendHudParam( *this );
|
Network::Util::Packet::sendHudParam( *this );
|
||||||
|
@ -571,6 +594,17 @@ std::map< uint8_t, StatusEffect::StatusEffectPtr > Chara::getStatusEffectMap() c
|
||||||
return m_statusEffectMap;
|
return m_statusEffectMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sapphire::StatusEffect::StatusEffectPtr Chara::getStatusEffectById( uint32_t id ) const
|
||||||
|
{
|
||||||
|
for( const auto& effectIt : m_statusEffectMap )
|
||||||
|
{
|
||||||
|
if( effectIt.second->getId() == id )
|
||||||
|
return effectIt.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
const uint8_t* Chara::getLookArray() const
|
const uint8_t* Chara::getLookArray() const
|
||||||
{
|
{
|
||||||
return m_customize;
|
return m_customize;
|
||||||
|
@ -595,7 +629,6 @@ void Chara::sendStatusEffectUpdate()
|
||||||
{
|
{
|
||||||
uint64_t currentTimeMs = Common::Util::getTimeMs();
|
uint64_t currentTimeMs = Common::Util::getTimeMs();
|
||||||
|
|
||||||
|
|
||||||
auto statusEffectList = makeZonePacket< FFXIVIpcStatus >( getId() );
|
auto statusEffectList = makeZonePacket< FFXIVIpcStatus >( getId() );
|
||||||
uint8_t slot = 0;
|
uint8_t slot = 0;
|
||||||
for( const auto& effectIt : m_statusEffectMap )
|
for( const auto& effectIt : m_statusEffectMap )
|
||||||
|
@ -640,7 +673,13 @@ void Chara::updateStatusEffects()
|
||||||
|
|
||||||
bool Chara::hasStatusEffect( uint32_t id )
|
bool Chara::hasStatusEffect( uint32_t id )
|
||||||
{
|
{
|
||||||
return m_statusEffectMap.find( id ) != m_statusEffectMap.end();
|
for( const auto& [ key, val ] : m_statusEffectMap )
|
||||||
|
{
|
||||||
|
if( val->getId() == id )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t Chara::getLastUpdateTime() const
|
int64_t Chara::getLastUpdateTime() const
|
||||||
|
@ -735,6 +774,27 @@ void Chara::setStatValue( Common::BaseParam baseParam, uint32_t value )
|
||||||
m_baseStats[ index ] = value;
|
m_baseStats[ index ] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Chara::getModifier( Common::ParamModifier paramModifier ) const
|
||||||
|
{
|
||||||
|
auto result = paramModifier >= Common::ParamModifier::StrengthPercent ? 1.0f : 0;
|
||||||
|
|
||||||
|
for( const auto& [ key, status ] : m_statusEffectMap )
|
||||||
|
{
|
||||||
|
for( const auto& [ mod, val ] : status->getModifiers() )
|
||||||
|
{
|
||||||
|
if( mod != paramModifier )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( paramModifier >= Common::ParamModifier::StrengthPercent )
|
||||||
|
result *= 1.0f + ( val / 100.0f );
|
||||||
|
else
|
||||||
|
result += val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void Chara::onTick()
|
void Chara::onTick()
|
||||||
{
|
{
|
||||||
uint32_t thisTickDmg = 0;
|
uint32_t thisTickDmg = 0;
|
||||||
|
@ -745,13 +805,13 @@ void Chara::onTick()
|
||||||
auto thisEffect = effectIt.second->getTickEffect();
|
auto thisEffect = effectIt.second->getTickEffect();
|
||||||
switch( thisEffect.first )
|
switch( thisEffect.first )
|
||||||
{
|
{
|
||||||
case 1:
|
case Common::ParamModifier::TickDamage:
|
||||||
{
|
{
|
||||||
thisTickDmg += thisEffect.second;
|
thisTickDmg += thisEffect.second;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2:
|
case Common::ParamModifier::TickHeal:
|
||||||
{
|
{
|
||||||
thisTickHeal += thisEffect.second;
|
thisTickHeal += thisEffect.second;
|
||||||
break;
|
break;
|
||||||
|
@ -759,11 +819,15 @@ void Chara::onTick()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: don't really like how this is handled
|
||||||
|
// TODO: calculate actual damage from potency
|
||||||
if( thisTickDmg != 0 )
|
if( thisTickDmg != 0 )
|
||||||
{
|
{
|
||||||
takeDamage( thisTickDmg );
|
takeDamage( thisTickDmg );
|
||||||
Network::Util::Packet::sendActorControl( getInRangePlayerIds( isPlayer() ), getId(), HPFloatingText, 0,
|
Network::Util::Packet::sendActorControl( getInRangePlayerIds( isPlayer() ), getId(), HPFloatingText, 0,
|
||||||
CalcResultType::TypeDamageHp, thisTickDmg );
|
CalcResultType::TypeDamageHp, thisTickDmg );
|
||||||
|
|
||||||
|
Network::Util::Packet::sendHudParam( *this );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( thisTickHeal != 0 )
|
if( thisTickHeal != 0 )
|
||||||
|
@ -771,5 +835,7 @@ void Chara::onTick()
|
||||||
heal( thisTickHeal );
|
heal( thisTickHeal );
|
||||||
Network::Util::Packet::sendActorControl( getInRangePlayerIds( isPlayer() ), getId(), HPFloatingText, 0,
|
Network::Util::Packet::sendActorControl( getInRangePlayerIds( isPlayer() ), getId(), HPFloatingText, 0,
|
||||||
CalcResultType::TypeRecoverMp, thisTickHeal );
|
CalcResultType::TypeRecoverMp, thisTickHeal );
|
||||||
|
|
||||||
|
Network::Util::Packet::sendHudParam( *this );
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Common.h>
|
#include <Common.h>
|
||||||
|
#include "Action/ActionLut.h"
|
||||||
|
|
||||||
#include "Forwards.h"
|
#include "Forwards.h"
|
||||||
#include "GameObject.h"
|
#include "GameObject.h"
|
||||||
|
@ -8,6 +9,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
namespace Sapphire::Entity
|
namespace Sapphire::Entity
|
||||||
{
|
{
|
||||||
|
@ -106,10 +108,14 @@ namespace Sapphire::Entity
|
||||||
/// Status effect functions
|
/// Status effect functions
|
||||||
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
|
void addStatusEffect( StatusEffect::StatusEffectPtr pEffect );
|
||||||
|
|
||||||
std::map< uint8_t, StatusEffect::StatusEffectPtr >::iterator removeStatusEffect( uint8_t effectSlotId );
|
std::map< uint8_t, StatusEffect::StatusEffectPtr >::iterator removeStatusEffect( uint8_t effectSlotId, bool sendOrder = true );
|
||||||
|
|
||||||
|
void replaceSingleStatusEffectById( uint32_t id );
|
||||||
|
|
||||||
void removeSingleStatusEffectById( uint32_t id );
|
void removeSingleStatusEffectById( uint32_t id );
|
||||||
|
|
||||||
|
void removeStatusEffectByFlag( Common::StatusEffectFlag flag );
|
||||||
|
|
||||||
void updateStatusEffects();
|
void updateStatusEffects();
|
||||||
|
|
||||||
bool hasStatusEffect( uint32_t id );
|
bool hasStatusEffect( uint32_t id );
|
||||||
|
@ -124,6 +130,8 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
std::map< uint8_t, Sapphire::StatusEffect::StatusEffectPtr > getStatusEffectMap() const;
|
std::map< uint8_t, Sapphire::StatusEffect::StatusEffectPtr > getStatusEffectMap() const;
|
||||||
|
|
||||||
|
Sapphire::StatusEffect::StatusEffectPtr getStatusEffectById( uint32_t id ) const;
|
||||||
|
|
||||||
void sendStatusEffectUpdate();
|
void sendStatusEffectUpdate();
|
||||||
|
|
||||||
/*! return a const pointer to the look array */
|
/*! return a const pointer to the look array */
|
||||||
|
@ -159,6 +167,8 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
void setStatValue( Common::BaseParam baseParam, uint32_t value );
|
void setStatValue( Common::BaseParam baseParam, uint32_t value );
|
||||||
|
|
||||||
|
float getModifier( Common::ParamModifier paramModifier ) const;
|
||||||
|
|
||||||
uint32_t getHp() const;
|
uint32_t getHp() const;
|
||||||
|
|
||||||
uint32_t getHpPercent() const;
|
uint32_t getHpPercent() const;
|
||||||
|
|
|
@ -563,6 +563,22 @@ void Player::setRewardFlag( Common::UnlockEntry unlockId )
|
||||||
Network::Util::Packet::sendActorControlSelf( *this, getId(), SetRewardFlag, unlock, 1 );
|
Network::Util::Packet::sendActorControlSelf( *this, getId(), SetRewardFlag, unlock, 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::setBorrowAction( uint8_t slot, uint32_t action )
|
||||||
|
{
|
||||||
|
if( slot > Common::ARRSIZE_BORROWACTION )
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& borrowAction = getBorrowAction();
|
||||||
|
borrowAction[ slot ] = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player::BorrowAction& Player::getBorrowAction()
|
||||||
|
{
|
||||||
|
auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||||
|
uint8_t classJobIndex = exdData.getRow< Excel::ClassJob >( static_cast<uint8_t>( getClass() ) )->data().WorkIndex;
|
||||||
|
return m_borrowActions[ classJobIndex ];
|
||||||
|
}
|
||||||
|
|
||||||
void Player::learnSong( uint8_t songId, uint32_t itemId )
|
void Player::learnSong( uint8_t songId, uint32_t itemId )
|
||||||
{
|
{
|
||||||
uint16_t index;
|
uint16_t index;
|
||||||
|
@ -712,6 +728,7 @@ void Player::setClassJob( Common::ClassJob classJob )
|
||||||
|
|
||||||
m_tp = 0;
|
m_tp = 0;
|
||||||
|
|
||||||
|
Network::Util::Packet::sendChangeClass( *this );
|
||||||
Network::Util::Packet::sendStatusUpdate( *this );
|
Network::Util::Packet::sendStatusUpdate( *this );
|
||||||
Network::Util::Packet::sendActorControl( getInRangePlayerIds( true ), getId(), ClassJobChange, 4 );
|
Network::Util::Packet::sendActorControl( getInRangePlayerIds( true ), getId(), ClassJobChange, 4 );
|
||||||
Network::Util::Packet::sendHudParam( *this );
|
Network::Util::Packet::sendHudParam( *this );
|
||||||
|
|
|
@ -38,6 +38,7 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
using ClassList = std::array< uint16_t, Common::ARRSIZE_CLASSJOB >;
|
using ClassList = std::array< uint16_t, Common::ARRSIZE_CLASSJOB >;
|
||||||
using ExpList = std::array< uint32_t, Common::ARRSIZE_CLASSJOB >;
|
using ExpList = std::array< uint32_t, Common::ARRSIZE_CLASSJOB >;
|
||||||
|
using BorrowAction = std::array< uint32_t, Common::ARRSIZE_BORROWACTION >;
|
||||||
|
|
||||||
struct AchievementData {
|
struct AchievementData {
|
||||||
std::array< uint8_t, 2048 / 8 > unlockList;
|
std::array< uint8_t, 2048 / 8 > unlockList;
|
||||||
|
@ -440,6 +441,10 @@ namespace Sapphire::Entity
|
||||||
/*! learn an action / update the unlock bitmask. */
|
/*! learn an action / update the unlock bitmask. */
|
||||||
void setRewardFlag( Common::UnlockEntry unlockId );
|
void setRewardFlag( Common::UnlockEntry unlockId );
|
||||||
|
|
||||||
|
void setBorrowAction( uint8_t slot, uint32_t action );
|
||||||
|
|
||||||
|
BorrowAction& getBorrowAction();
|
||||||
|
|
||||||
/*! learn a song / update the unlock bitmask. */
|
/*! learn a song / update the unlock bitmask. */
|
||||||
void learnSong( uint8_t songId, uint32_t itemId );
|
void learnSong( uint8_t songId, uint32_t itemId );
|
||||||
|
|
||||||
|
@ -960,6 +965,8 @@ namespace Sapphire::Entity
|
||||||
|
|
||||||
std::array< Common::HuntingLogEntry, Common::ARRSIZE_MONSTERNOTE > m_huntingLogEntries{};
|
std::array< Common::HuntingLogEntry, Common::ARRSIZE_MONSTERNOTE > m_huntingLogEntries{};
|
||||||
|
|
||||||
|
std::array< BorrowAction, Common::ARRSIZE_CLASSJOB > m_borrowActions{};
|
||||||
|
|
||||||
FriendListIDVec m_friendList{};
|
FriendListIDVec m_friendList{};
|
||||||
FriendListDataVec m_friendInviteList{};
|
FriendListDataVec m_friendInviteList{};
|
||||||
|
|
||||||
|
|
|
@ -258,7 +258,7 @@ bool Player::loadAchievements()
|
||||||
bool Player::loadClassData()
|
bool Player::loadClassData()
|
||||||
{
|
{
|
||||||
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
||||||
// ClassIdx, Exp, Lvl
|
// ClassIdx, Exp, Lvl, BorrowAction
|
||||||
auto stmt = db.getPreparedStatement( Db::ZoneDbStatements::CHARA_CLASS_SEL );
|
auto stmt = db.getPreparedStatement( Db::ZoneDbStatements::CHARA_CLASS_SEL );
|
||||||
stmt->setUInt64( 1, m_characterId );
|
stmt->setUInt64( 1, m_characterId );
|
||||||
auto res = db.query( stmt );
|
auto res = db.query( stmt );
|
||||||
|
@ -268,9 +268,11 @@ bool Player::loadClassData()
|
||||||
auto index = res->getUInt16( 1 );
|
auto index = res->getUInt16( 1 );
|
||||||
auto exp = res->getUInt( 2 );
|
auto exp = res->getUInt( 2 );
|
||||||
auto lvl = res->getUInt8( 3 );
|
auto lvl = res->getUInt8( 3 );
|
||||||
|
auto borrowAction = res->getBlobVector( "BorrowAction" );
|
||||||
|
|
||||||
m_classArray[ index ] = lvl;
|
m_classArray[ index ] = lvl;
|
||||||
m_expArray[ index ] = exp;
|
m_expArray[ index ] = exp;
|
||||||
|
memcpy( m_borrowActions[ index ].data(), borrowAction.data(), borrowAction.size() );
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -487,13 +489,19 @@ void Player::updateDbClass() const
|
||||||
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
||||||
auto& exdData = Common::Service< Data::ExdData >::ref();
|
auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||||
uint8_t classJobIndex = exdData.getRow< Excel::ClassJob >( static_cast<uint8_t>( getClass() ) )->data().WorkIndex;
|
uint8_t classJobIndex = exdData.getRow< Excel::ClassJob >( static_cast<uint8_t>( getClass() ) )->data().WorkIndex;
|
||||||
|
auto& borrowAction = m_borrowActions[ classJobIndex ];
|
||||||
|
|
||||||
//Exp = ?, Lvl = ? WHERE CharacterId = ? AND ClassIdx = ?
|
//Exp = ?, Lvl = ?, BorrowAction = ? WHERE CharacterId = ? AND ClassIdx = ?
|
||||||
auto stmtS = db.getPreparedStatement( Db::CHARA_CLASS_UP );
|
auto stmtS = db.getPreparedStatement( Db::CHARA_CLASS_UP );
|
||||||
stmtS->setInt( 1, getExp() );
|
stmtS->setInt( 1, getExp() );
|
||||||
stmtS->setInt( 2, getLevel() );
|
stmtS->setInt( 2, getLevel() );
|
||||||
stmtS->setUInt64( 3, m_characterId );
|
|
||||||
stmtS->setInt( 4, classJobIndex );
|
std::vector< uint8_t > borrowActionVec( borrowAction.size() * 4 );
|
||||||
|
memcpy( borrowActionVec.data(), borrowAction.data(), borrowAction.size() * 4 );
|
||||||
|
stmtS->setBinary( 3, borrowActionVec );
|
||||||
|
|
||||||
|
stmtS->setUInt64( 4, m_characterId );
|
||||||
|
stmtS->setInt( 5, classJobIndex );
|
||||||
db.execute( stmtS );
|
db.execute( stmtS );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,10 +589,14 @@ void Player::insertDbClass( const uint8_t classJobIndex, uint8_t level ) const
|
||||||
{
|
{
|
||||||
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
auto& db = Common::Service< Db::DbWorkerPool< Db::ZoneDbConnection > >::ref();
|
||||||
auto stmtClass = db.getPreparedStatement( Db::CHARA_CLASS_INS );
|
auto stmtClass = db.getPreparedStatement( Db::CHARA_CLASS_INS );
|
||||||
|
auto& borrowAction = m_borrowActions[ classJobIndex ];
|
||||||
|
|
||||||
stmtClass->setUInt64( 1, m_characterId );
|
stmtClass->setUInt64( 1, m_characterId );
|
||||||
stmtClass->setInt( 2, classJobIndex );
|
stmtClass->setInt( 2, classJobIndex );
|
||||||
stmtClass->setInt( 3, 0 );
|
stmtClass->setInt( 3, 0 );
|
||||||
stmtClass->setInt( 4, level );
|
stmtClass->setInt( 4, level );
|
||||||
|
std::vector< uint8_t > borrowActionVec( borrowAction.size() );
|
||||||
|
stmtClass->setBinary( 5, borrowActionVec );
|
||||||
db.directExecute( stmtClass );
|
db.directExecute( stmtClass );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ file( GLOB SERVER_SOURCE_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
*.cpp
|
*.cpp
|
||||||
Actor/*.cpp
|
Actor/*.cpp
|
||||||
Action/*.cpp
|
Action/*.cpp
|
||||||
|
Action/Job/*.cpp
|
||||||
AI/*.cpp
|
AI/*.cpp
|
||||||
AI/Fsm/*.cpp
|
AI/Fsm/*.cpp
|
||||||
ContentFinder/*.cpp
|
ContentFinder/*.cpp
|
||||||
|
|
|
@ -71,13 +71,6 @@ void ActionMgr::handleTargetedAction( Entity::Chara& src, uint32_t actionId, uin
|
||||||
|
|
||||||
auto actionData = action->getActionData();
|
auto actionData = action->getActionData();
|
||||||
|
|
||||||
// cancel any aoe actions casted with this packet
|
|
||||||
if( actionData->data().EffectRange )
|
|
||||||
{
|
|
||||||
action->interrupt();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bootstrapAction( src, action, actionData );
|
bootstrapAction( src, action, actionData );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,12 +142,15 @@ uint32_t CalcStats::calculateMaxHp( Player& player )
|
||||||
uint16_t hpMod = paramGrowthInfo->data().ParamBase;
|
uint16_t hpMod = paramGrowthInfo->data().ParamBase;
|
||||||
uint16_t jobModHp = classInfo->data().Hp;
|
uint16_t jobModHp = classInfo->data().Hp;
|
||||||
float approxBaseHp = 0.0f; // Read above
|
float approxBaseHp = 0.0f; // Read above
|
||||||
|
float hpModPercent = player.getModifier( Common::ParamModifier::HPPercent );
|
||||||
|
|
||||||
approxBaseHp = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::HP ] );
|
approxBaseHp = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::HP ] );
|
||||||
|
|
||||||
auto result = static_cast< uint32_t >( floor( jobModHp * ( approxBaseHp / 100.0f ) ) +
|
auto result = static_cast< uint32_t >( floor( jobModHp * ( approxBaseHp / 100.0f ) ) +
|
||||||
floor( hpMod / 100.0f * ( vitStat - baseStat ) ) );
|
floor( hpMod / 100.0f * ( vitStat - baseStat ) ) );
|
||||||
|
|
||||||
|
result *= hpModPercent;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -601,6 +604,7 @@ std::pair< float, Sapphire::Common::CalcResultType > CalcStats::calcActionDamage
|
||||||
auto wd = weaponDamage( chara, wepDmg );
|
auto wd = weaponDamage( chara, wepDmg );
|
||||||
auto ap = getPrimaryAttackPower( chara );
|
auto ap = getPrimaryAttackPower( chara );
|
||||||
auto det = determination( chara );
|
auto det = determination( chara );
|
||||||
|
auto damageDealtMod = chara.getModifier( Common::ParamModifier::DamageDealtPercent );
|
||||||
|
|
||||||
auto factor = Common::Util::trunc( pot * wd * ap * det, 0 );
|
auto factor = Common::Util::trunc( pot * wd * ap * det, 0 );
|
||||||
Sapphire::Common::CalcResultType hitType = Sapphire::Common::CalcResultType::TypeDamageHp;
|
Sapphire::Common::CalcResultType hitType = Sapphire::Common::CalcResultType::TypeDamageHp;
|
||||||
|
@ -615,11 +619,14 @@ std::pair< float, Sapphire::Common::CalcResultType > CalcStats::calcActionDamage
|
||||||
|
|
||||||
// todo: buffs
|
// todo: buffs
|
||||||
|
|
||||||
|
factor *= damageDealtMod;
|
||||||
|
|
||||||
constexpr auto format = "dmg: pot: {} ({}) wd: {} ({}) ap: {} det: {} = {}";
|
constexpr auto format = "dmg: pot: {} ({}) wd: {} ({}) ap: {} det: {} = {}";
|
||||||
|
|
||||||
if( auto player = const_cast< Entity::Chara& >( chara ).getAsPlayer() )
|
if( auto player = const_cast< Entity::Chara& >( chara ).getAsPlayer() )
|
||||||
{
|
{
|
||||||
PlayerMgr::sendDebug( *player, format, pot, ptc, wd, wepDmg, ap, det, factor );
|
PlayerMgr::sendDebug( *player, format, pot, ptc, wd, wepDmg, ap, det, factor );
|
||||||
|
PlayerMgr::sendDebug( *player, "DamageDealtPercent: {}", damageDealtMod );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -491,6 +491,11 @@ void Sapphire::Network::GameConnection::commandHandler( const Packets::FFXIVARR_
|
||||||
Network::Util::Packet::sendTitleList( player );
|
Network::Util::Packet::sendTitleList( player );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case PacketCommand::BORROW_ACTION:
|
||||||
|
{
|
||||||
|
player.setBorrowAction( static_cast< uint8_t >( data.Arg1 ), data.Arg2 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
case PacketCommand::SET_HOWTO: // Update howtos seen
|
case PacketCommand::SET_HOWTO: // Update howtos seen
|
||||||
{
|
{
|
||||||
player.updateHowtosSeen( data.Arg0 );
|
player.updateHowtosSeen( data.Arg0 );
|
||||||
|
|
|
@ -307,10 +307,12 @@ void Util::Packet::sendPlayerSetup( Entity::Player& player )
|
||||||
void Util::Packet::sendChangeClass( Entity::Player& player )
|
void Util::Packet::sendChangeClass( Entity::Player& player )
|
||||||
{
|
{
|
||||||
auto classInfo = makeZonePacket< FFXIVIpcChangeClass >( player.getId() );
|
auto classInfo = makeZonePacket< FFXIVIpcChangeClass >( player.getId() );
|
||||||
|
auto& borrowAction = player.getBorrowAction();
|
||||||
classInfo->data().ClassJob = static_cast< uint8_t >( player.getClass() );
|
classInfo->data().ClassJob = static_cast< uint8_t >( player.getClass() );
|
||||||
classInfo->data().Lv = player.getLevel();
|
classInfo->data().Lv = player.getLevel();
|
||||||
classInfo->data().Lv1 = player.getLevel();
|
classInfo->data().Lv1 = player.getLevel();
|
||||||
classInfo->data().Login = player.isLogin() ? 1 : 0;
|
classInfo->data().Login = player.isLogin() ? 1 : 0;
|
||||||
|
memcpy( &classInfo->data().BorrowAction[ 0 ], borrowAction.data(), borrowAction.size() * 4 );
|
||||||
server().queueForPlayer( player.getCharacterId(), classInfo );
|
server().queueForPlayer( player.getCharacterId(), classInfo );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -644,9 +644,6 @@ bool Sapphire::Scripting::ScriptMgr::onStatusTick( Entity::CharaPtr pChara, Sapp
|
||||||
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::StatusEffectScript >( effect.getId() );
|
auto script = m_nativeScriptMgr->getScript< Sapphire::ScriptAPI::StatusEffectScript >( effect.getId() );
|
||||||
if( script )
|
if( script )
|
||||||
{
|
{
|
||||||
if( pChara->isPlayer() )
|
|
||||||
PlayerMgr::sendDebug( *pChara->getAsPlayer(), "Calling status tick for statusid#{0}", effect.getId() );
|
|
||||||
|
|
||||||
script->onTick( *pChara );
|
script->onTick( *pChara );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,26 +6,41 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <Service.h>
|
#include <Service.h>
|
||||||
|
|
||||||
|
#include "Manager/PlayerMgr.h"
|
||||||
|
|
||||||
#include "Actor/Chara.h"
|
#include "Actor/Chara.h"
|
||||||
|
#include "Actor/Player.h"
|
||||||
#include "Actor/GameObject.h"
|
#include "Actor/GameObject.h"
|
||||||
|
|
||||||
#include "Script/ScriptMgr.h"
|
#include "Script/ScriptMgr.h"
|
||||||
|
|
||||||
#include "StatusEffect.h"
|
#include "StatusEffect.h"
|
||||||
|
|
||||||
|
using namespace Sapphire;
|
||||||
using namespace Sapphire::Common;
|
using namespace Sapphire::Common;
|
||||||
using namespace Sapphire::Network::Packets;
|
using namespace Sapphire::Network::Packets;
|
||||||
//using namespace Sapphire::Network::Packets::WorldPackets::Server;
|
//using namespace Sapphire::Network::Packets::WorldPackets::Server;
|
||||||
|
|
||||||
|
Sapphire::StatusEffect::StatusEffect::StatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor,
|
||||||
|
uint32_t duration,std::vector< World::Action::StatusModifier >& modifiers,
|
||||||
|
uint32_t flag, uint32_t tickRate ) :
|
||||||
|
StatusEffect( id, sourceActor, targetActor, duration, tickRate )
|
||||||
|
{
|
||||||
|
m_statusModifiers = std::move( modifiers );
|
||||||
|
m_flag = flag;
|
||||||
|
}
|
||||||
|
|
||||||
Sapphire::StatusEffect::StatusEffect::StatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor,
|
Sapphire::StatusEffect::StatusEffect::StatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor,
|
||||||
uint32_t duration, uint32_t tickRate ) :
|
uint32_t duration, uint32_t tickRate ) :
|
||||||
m_id( id ),
|
m_id( id ),
|
||||||
m_sourceActor( sourceActor ),
|
m_sourceActor( sourceActor ),
|
||||||
m_targetActor( targetActor ),
|
m_targetActor( targetActor ),
|
||||||
m_duration( duration ),
|
m_duration( duration ),
|
||||||
|
m_modifiers( 0 ),
|
||||||
m_startTime( 0 ),
|
m_startTime( 0 ),
|
||||||
m_tickRate( tickRate ),
|
m_tickRate( tickRate ),
|
||||||
m_lastTick( 0 )
|
m_lastTick( 0 ),
|
||||||
|
m_flag( 0 )
|
||||||
{
|
{
|
||||||
auto& exdData = Common::Service< Data::ExdData >::ref();
|
auto& exdData = Common::Service< Data::ExdData >::ref();
|
||||||
auto entry = exdData.getRow< Excel::Status >( id );
|
auto entry = exdData.getRow< Excel::Status >( id );
|
||||||
|
@ -40,6 +55,15 @@ Sapphire::StatusEffect::StatusEffect::StatusEffect( uint32_t id, Entity::CharaPt
|
||||||
Util::eraseAll( m_name, '-' );
|
Util::eraseAll( m_name, '-' );
|
||||||
Util::eraseAll( m_name, '(' );
|
Util::eraseAll( m_name, '(' );
|
||||||
Util::eraseAll( m_name, ')' );
|
Util::eraseAll( m_name, ')' );
|
||||||
|
|
||||||
|
m_flag |= entry->data().Category;
|
||||||
|
m_flag |= static_cast< uint32_t >( entry->data().Forever ) << static_cast< uint32_t >( Common::StatusEffectFlag::Permanent );
|
||||||
|
m_flag |= static_cast< uint32_t >( entry->data().CanOff ) << static_cast< uint32_t >( Common::StatusEffectFlag::CanStatusOff );
|
||||||
|
m_flag |= static_cast< uint32_t >( entry->data().NotAction ) << static_cast< uint32_t >( Common::StatusEffectFlag::LockActions );
|
||||||
|
m_flag |= static_cast< uint32_t >( entry->data().NotControl ) << static_cast< uint32_t >( Common::StatusEffectFlag::LockControl );
|
||||||
|
m_flag |= static_cast< uint32_t >( entry->data().NotMove ) << static_cast< uint32_t >( Common::StatusEffectFlag::LockMovement );
|
||||||
|
m_flag |= static_cast< uint32_t >( entry->data().NotLookAt ) << static_cast< uint32_t >( Common::StatusEffectFlag::IsGaze );
|
||||||
|
m_flag |= static_cast< uint32_t >( entry->data().FcAction ) << static_cast< uint32_t >( Common::StatusEffectFlag::FcBuff );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,16 +71,14 @@ Sapphire::StatusEffect::StatusEffect::~StatusEffect()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::StatusEffect::StatusEffect::registerTickEffect( uint8_t type, uint32_t param )
|
void Sapphire::StatusEffect::StatusEffect::registerTickEffect( ParamModifier type, uint32_t param )
|
||||||
{
|
{
|
||||||
m_currTickEffect = std::make_pair( type, param );
|
m_currTickEffect = std::make_pair( type, param );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair< uint8_t, uint32_t > Sapphire::StatusEffect::StatusEffect::getTickEffect()
|
std::pair< ParamModifier, uint32_t > Sapphire::StatusEffect::StatusEffect::getTickEffect()
|
||||||
{
|
{
|
||||||
auto thisTick = m_currTickEffect;
|
return m_currTickEffect;
|
||||||
m_currTickEffect = std::make_pair( 0, 0 );
|
|
||||||
return thisTick;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::StatusEffect::StatusEffect::onTick()
|
void Sapphire::StatusEffect::StatusEffect::onTick()
|
||||||
|
@ -87,16 +109,60 @@ uint16_t Sapphire::StatusEffect::StatusEffect::getParam() const
|
||||||
return m_param;
|
return m_param;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unordered_map< Common::ParamModifier, int32_t >& Sapphire::StatusEffect::StatusEffect::getModifiers()
|
||||||
|
{
|
||||||
|
return m_modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::StatusEffect::StatusEffect::setModifier( Common::ParamModifier paramModifier, int32_t value )
|
||||||
|
{
|
||||||
|
m_modifiers[ paramModifier ] = value;
|
||||||
|
|
||||||
|
if( auto pPlayer = m_targetActor->getAsPlayer(); pPlayer )
|
||||||
|
Common::Service< World::Manager::PlayerMgr >::ref().sendDebug( *pPlayer, "Modifier: {}, value: {}", static_cast< int32_t >( paramModifier ),
|
||||||
|
pPlayer->getModifier( paramModifier ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::StatusEffect::StatusEffect::delModifier( Common::ParamModifier paramModifier )
|
||||||
|
{
|
||||||
|
if( m_modifiers.find( paramModifier ) == m_modifiers.end() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_modifiers.erase( paramModifier );
|
||||||
|
|
||||||
|
if( auto pPlayer = m_targetActor->getAsPlayer(); pPlayer )
|
||||||
|
Common::Service< World::Manager::PlayerMgr >::ref().sendDebug( *pPlayer, "Modifier: {}, value: {}", static_cast< int32_t >( paramModifier ),
|
||||||
|
pPlayer->getModifier( paramModifier ) );
|
||||||
|
}
|
||||||
|
|
||||||
void Sapphire::StatusEffect::StatusEffect::applyStatus()
|
void Sapphire::StatusEffect::StatusEffect::applyStatus()
|
||||||
{
|
{
|
||||||
m_startTime = Util::getTimeMs();
|
m_startTime = Util::getTimeMs();
|
||||||
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
||||||
|
|
||||||
|
for( const auto& mod : m_statusModifiers )
|
||||||
|
{
|
||||||
|
if( mod.modifier != Common::ParamModifier::TickDamage && mod.modifier != Common::ParamModifier::TickHeal )
|
||||||
|
setModifier( mod.modifier, mod.value );
|
||||||
|
else if( mod.modifier == Common::ParamModifier::TickDamage )
|
||||||
|
registerTickEffect( mod.modifier, mod.value );
|
||||||
|
else if( mod.modifier == Common::ParamModifier::TickHeal )
|
||||||
|
registerTickEffect( mod.modifier, mod.value );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_targetActor->calculateStats();
|
||||||
|
|
||||||
scriptMgr.onStatusReceive( m_targetActor, m_id );
|
scriptMgr.onStatusReceive( m_targetActor, m_id );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sapphire::StatusEffect::StatusEffect::removeStatus()
|
void Sapphire::StatusEffect::StatusEffect::removeStatus()
|
||||||
{
|
{
|
||||||
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
||||||
|
|
||||||
|
m_modifiers.clear();
|
||||||
|
|
||||||
|
m_targetActor->calculateStats();
|
||||||
|
|
||||||
scriptMgr.onStatusTimeOut( m_targetActor, m_id );
|
scriptMgr.onStatusTimeOut( m_targetActor, m_id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +191,21 @@ uint64_t Sapphire::StatusEffect::StatusEffect::getStartTimeMs() const
|
||||||
return m_startTime;
|
return m_startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t Sapphire::StatusEffect::StatusEffect::getFlag() const
|
||||||
|
{
|
||||||
|
return m_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector< World::Action::StatusModifier > Sapphire::StatusEffect::StatusEffect::getStatusModifiers() const
|
||||||
|
{
|
||||||
|
return m_statusModifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::StatusEffect::StatusEffect::setFlag( uint32_t flag )
|
||||||
|
{
|
||||||
|
m_flag = flag;
|
||||||
|
}
|
||||||
|
|
||||||
void Sapphire::StatusEffect::StatusEffect::setLastTick( uint64_t lastTick )
|
void Sapphire::StatusEffect::StatusEffect::setLastTick( uint64_t lastTick )
|
||||||
{
|
{
|
||||||
m_lastTick = lastTick;
|
m_lastTick = lastTick;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define _STATUSEFFECT_H_
|
#define _STATUSEFFECT_H_
|
||||||
|
|
||||||
#include "Forwards.h"
|
#include "Forwards.h"
|
||||||
|
#include "Action/ActionLut.h"
|
||||||
|
|
||||||
namespace Sapphire {
|
namespace Sapphire {
|
||||||
namespace StatusEffect {
|
namespace StatusEffect {
|
||||||
|
@ -10,6 +11,9 @@ namespace StatusEffect {
|
||||||
class StatusEffect
|
class StatusEffect
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
StatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor,
|
||||||
|
uint32_t duration, std::vector< World::Action::StatusModifier >& modifiers, uint32_t flag, uint32_t tickRate );
|
||||||
|
|
||||||
StatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor,
|
StatusEffect( uint32_t id, Entity::CharaPtr sourceActor, Entity::CharaPtr targetActor,
|
||||||
uint32_t duration, uint32_t tickRate );
|
uint32_t duration, uint32_t tickRate );
|
||||||
|
|
||||||
|
@ -17,6 +21,12 @@ public:
|
||||||
|
|
||||||
void onTick();
|
void onTick();
|
||||||
|
|
||||||
|
std::unordered_map< Common::ParamModifier, int32_t >& getModifiers();
|
||||||
|
|
||||||
|
void setModifier( Common::ParamModifier paramModifier, int32_t value );
|
||||||
|
|
||||||
|
void delModifier( Common::ParamModifier paramModifier );
|
||||||
|
|
||||||
void applyStatus();
|
void applyStatus();
|
||||||
|
|
||||||
void removeStatus();
|
void removeStatus();
|
||||||
|
@ -38,13 +48,19 @@ public:
|
||||||
|
|
||||||
uint16_t getParam() const;
|
uint16_t getParam() const;
|
||||||
|
|
||||||
|
uint32_t getFlag() const;
|
||||||
|
|
||||||
|
std::vector< World::Action::StatusModifier > getStatusModifiers() const;
|
||||||
|
|
||||||
void setLastTick( uint64_t lastTick );
|
void setLastTick( uint64_t lastTick );
|
||||||
|
|
||||||
void setParam( uint16_t param );
|
void setParam( uint16_t param );
|
||||||
|
|
||||||
void registerTickEffect( uint8_t type, uint32_t param );
|
void setFlag( uint32_t flag );
|
||||||
|
|
||||||
std::pair< uint8_t, uint32_t > getTickEffect();
|
void registerTickEffect( Common::ParamModifier type, uint32_t param );
|
||||||
|
|
||||||
|
std::pair< Common::ParamModifier, uint32_t > getTickEffect();
|
||||||
|
|
||||||
const std::string& getName() const;
|
const std::string& getName() const;
|
||||||
|
|
||||||
|
@ -60,9 +76,12 @@ private:
|
||||||
uint32_t m_tickRate;
|
uint32_t m_tickRate;
|
||||||
uint64_t m_lastTick;
|
uint64_t m_lastTick;
|
||||||
uint16_t m_param;
|
uint16_t m_param;
|
||||||
|
uint32_t m_flag;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
|
std::pair< Common::ParamModifier, uint32_t > m_currTickEffect;
|
||||||
|
std::vector< World::Action::StatusModifier > m_statusModifiers;
|
||||||
|
std::unordered_map< Common::ParamModifier, int32_t > m_modifiers;
|
||||||
uint8_t m_slot;
|
uint8_t m_slot;
|
||||||
std::pair< uint8_t, uint32_t > m_currTickEffect;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue