mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-03 09:17:47 +00:00
Merge branch 'develop' of https://github.com/SapphireMordred/Sapphire into develop
This commit is contained in:
commit
0d9923f82e
28 changed files with 542 additions and 114 deletions
|
@ -584,3 +584,21 @@ CREATE TABLE `landplaceditems` (
|
|||
)
|
||||
COLLATE='latin1_swedish_ci' ENGINE=InnoDB;
|
||||
|
||||
|
||||
CREATE TABLE `charamonsternote` (
|
||||
`CharacterId` int(20) NOT NULL,
|
||||
`Category_0` binary(41) DEFAULT NULL,
|
||||
`Category_1` binary(41) DEFAULT NULL,
|
||||
`Category_2` binary(41) DEFAULT NULL,
|
||||
`Category_3` binary(41) DEFAULT NULL,
|
||||
`Category_4` binary(41) DEFAULT NULL,
|
||||
`Category_5` binary(41) DEFAULT NULL,
|
||||
`Category_6` binary(41) DEFAULT NULL,
|
||||
`Category_7` binary(41) DEFAULT NULL,
|
||||
`Category_8` binary(41) DEFAULT NULL,
|
||||
`Category_9` binary(41) DEFAULT NULL,
|
||||
`Category_10` binary(41) DEFAULT NULL,
|
||||
`Category_11` binary(41) DEFAULT NULL,
|
||||
`UPDATE_DATE` datetime DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY(`CharacterId`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
|
|
@ -187,6 +187,7 @@ void PlayerMinimal::saveAsNew()
|
|||
std::vector< uint8_t > orchestrion( 40 );
|
||||
std::vector< uint8_t > modelEquip( 40 );
|
||||
std::vector< uint8_t > questTracking8( 10 );
|
||||
std::vector< uint8_t > monsterNote( 41 );
|
||||
std::vector< int16_t > questTracking = { -1, -1, -1, -1, -1 };
|
||||
|
||||
memset( questComplete.data(), 0, questComplete.size() );
|
||||
|
@ -328,6 +329,12 @@ void PlayerMinimal::saveAsNew()
|
|||
createInvDbContainer( InventoryType::Currency );
|
||||
createInvDbContainer( InventoryType::Crystal );
|
||||
|
||||
auto stmtMonsterNote = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_MONSTERNOTE_INS );
|
||||
stmtMonsterNote->setInt( 1, m_id );
|
||||
for( uint8_t i = 1; i <= 12; ++i )
|
||||
stmtMonsterNote->setBinary( i + 1, monsterNote );
|
||||
g_charaDb.directExecute( stmtMonsterNote );
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// SETUP EQUIPMENT / STARTING GEAR
|
||||
auto classJobInfo = g_exdDataGen.get< Sapphire::Data::ClassJob >( m_class );
|
||||
|
|
|
@ -263,6 +263,14 @@ namespace Sapphire::Common
|
|||
|
||||
};
|
||||
|
||||
enum class UnlockEntry : uint16_t
|
||||
{
|
||||
Return = 1,
|
||||
Teleport = 4,
|
||||
GearSets = 6,
|
||||
HuntingLog = 21,
|
||||
};
|
||||
|
||||
enum ContainerType : uint16_t
|
||||
{
|
||||
Unknown = 0,
|
||||
|
@ -579,6 +587,13 @@ namespace Sapphire::Common
|
|||
TpLoss = 12,
|
||||
TpGain = 13,
|
||||
GpGain = 14,
|
||||
/*!
|
||||
* @brief Tells the client that it should show combo indicators on actions.
|
||||
*
|
||||
* @param flags Required to be 128, doesn't show combo rings on hotbars otherwise
|
||||
* @param value The actionid that starts/continues the combo. eg, 3617 will start a spinning slash and/or syphon strike combo
|
||||
*/
|
||||
StartActionCombo = 28,
|
||||
Knockback = 33,
|
||||
Mount = 38,
|
||||
VFX = 59, // links to VFX sheet
|
||||
|
@ -596,7 +611,8 @@ namespace Sapphire::Common
|
|||
|
||||
enum ItemActionType : uint16_t
|
||||
{
|
||||
ItemActionVFX = 944,
|
||||
ItemActionVFX = 852,
|
||||
ItemActionVFX2 = 944,
|
||||
};
|
||||
|
||||
enum ActionEffectDisplayType : uint8_t
|
||||
|
@ -931,6 +947,18 @@ namespace Sapphire::Common
|
|||
uint16_t cost;
|
||||
};
|
||||
|
||||
enum LevelTableEntry : uint8_t
|
||||
{
|
||||
PIE,
|
||||
MP,
|
||||
MAIN,
|
||||
SUB,
|
||||
DIV,
|
||||
HP,
|
||||
ELMT,
|
||||
THREAT
|
||||
};
|
||||
|
||||
using PlayerStateFlagList = std::vector< PlayerStateFlag >;
|
||||
|
||||
}
|
||||
|
|
|
@ -175,6 +175,31 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
|
|||
"INSERT INTO charaglobalitem ( CharacterId, ItemId, catalogId, stack, UPDATE_DATE ) VALUES ( ?, ?, ?, ?, NOW() );",
|
||||
CONNECTION_SYNC );
|
||||
|
||||
/// CHARA MONSTERNOTE
|
||||
prepareStatement( CHARA_MONSTERNOTE_INS,
|
||||
"INSERT INTO charamonsternote ( CharacterId, Category_0, Category_1, Category_2,"
|
||||
" Category_3, Category_4, Category_5, Category_6,"
|
||||
" Category_7, Category_8, Category_9, Category_10,"
|
||||
" Category_11, UPDATE_DATE ) "
|
||||
" VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW() );",
|
||||
CONNECTION_SYNC );
|
||||
|
||||
prepareStatement( CHARA_MONSTERNOTE_UP, "UPDATE charamonsternote "
|
||||
" SET Category_0 = ?,"
|
||||
" Category_1 = ?,"
|
||||
" Category_2 = ?,"
|
||||
" Category_3 = ?,"
|
||||
" Category_4 = ?,"
|
||||
" Category_5 = ?,"
|
||||
" Category_6 = ?,"
|
||||
" Category_7 = ?,"
|
||||
" Category_8 = ?,"
|
||||
" Category_9 = ?,"
|
||||
" Category_10 = ?,"
|
||||
" Category_11 = ?"
|
||||
" WHERE CharacterId = ?;",
|
||||
CONNECTION_ASYNC );
|
||||
|
||||
/// ZONE QUERIES
|
||||
prepareStatement( ZONE_SEL_BNPCTEMPLATES,
|
||||
"SELECT Id, Name, bNPCBaseId, bNPCNameId, mainWeaponModel, "
|
||||
|
|
|
@ -76,6 +76,9 @@ namespace Sapphire::Db
|
|||
CHARA_ITEMGLOBAL_UP,
|
||||
CHARA_ITEMGLOBAL_DELETE,
|
||||
|
||||
CHARA_MONSTERNOTE_INS,
|
||||
CHARA_MONSTERNOTE_UP,
|
||||
|
||||
ZONE_SEL_BNPCTEMPLATES,
|
||||
ZONE_SEL_SPAWNGROUPS,
|
||||
ZONE_SEL_SPAWNPOINTS,
|
||||
|
|
|
@ -155,6 +155,8 @@ namespace Sapphire::Network::Packets
|
|||
InventoryActionAck = 0x019D, // updated 4.5
|
||||
UpdateInventorySlot = 0x019E, // updated 4.5
|
||||
|
||||
HuntingLogEntry = 0x01A9, // added 4.5
|
||||
|
||||
EventPlay = 0x01AB, // updated 4.5
|
||||
DirectorPlayScene = 0x01AF, // updated 4.5
|
||||
EventOpenGilShop = 0x01B2, // updated 4.5
|
||||
|
|
|
@ -1228,6 +1228,20 @@ struct FFXIVIpcEventStart :
|
|||
/* 0014 */ uint32_t padding1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Structural representation of the packet sent by the server
|
||||
* to fill a huntin log entry
|
||||
*/
|
||||
struct FFXIVIpcHuntingLogEntry : FFXIVIpcBasePacket< HuntingLogEntry >
|
||||
{
|
||||
int32_t u0; // -1 for all normal classes
|
||||
uint8_t rank; // starting from 0
|
||||
uint8_t index; // classes and gcs
|
||||
uint8_t entries[10][4];
|
||||
uint16_t pad;
|
||||
uint64_t completeFlags; // 4 bit for each potential entry and the 5th bit for completion of the section
|
||||
uint64_t pad1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Structural representation of the packet sent by the server
|
||||
|
|
22
src/scripts/action/darkknight/ActionHardSlash3617.cpp
Normal file
22
src/scripts/action/darkknight/ActionHardSlash3617.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <Script/NativeScriptApi.h>
|
||||
#include <ScriptObject.h>
|
||||
#include <Actor/Player.h>
|
||||
#include <Action/Action.h>
|
||||
|
||||
class ActionHardSlash3617 :
|
||||
public Sapphire::ScriptAPI::ActionScript
|
||||
{
|
||||
public:
|
||||
ActionHardSlash3617() :
|
||||
Sapphire::ScriptAPI::ActionScript( 3617 )
|
||||
{
|
||||
}
|
||||
|
||||
void onExecute( Sapphire::Action::Action& action ) override
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( ActionHardSlash3617 );
|
22
src/scripts/action/darkknight/ActionPowerSlash3627.cpp
Normal file
22
src/scripts/action/darkknight/ActionPowerSlash3627.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <Script/NativeScriptApi.h>
|
||||
#include <ScriptObject.h>
|
||||
#include <Actor/Player.h>
|
||||
#include <Action/Action.h>
|
||||
|
||||
class ActionPowerSlash3627 :
|
||||
public Sapphire::ScriptAPI::ActionScript
|
||||
{
|
||||
public:
|
||||
ActionPowerSlash3627() :
|
||||
Sapphire::ScriptAPI::ActionScript( 3627 )
|
||||
{
|
||||
}
|
||||
|
||||
void onExecute( Sapphire::Action::Action& action ) override
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( ActionPowerSlash3627 );
|
22
src/scripts/action/darkknight/ActionSpinningSlash3619.cpp
Normal file
22
src/scripts/action/darkknight/ActionSpinningSlash3619.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <Script/NativeScriptApi.h>
|
||||
#include <ScriptObject.h>
|
||||
#include <Actor/Player.h>
|
||||
#include <Action/Action.h>
|
||||
|
||||
class ActionSpinningSlash3619 :
|
||||
public Sapphire::ScriptAPI::ActionScript
|
||||
{
|
||||
public:
|
||||
ActionSpinningSlash3619() :
|
||||
Sapphire::ScriptAPI::ActionScript( 3619 )
|
||||
{
|
||||
}
|
||||
|
||||
void onExecute( Sapphire::Action::Action& action ) override
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( ActionSpinningSlash3619 );
|
22
src/scripts/action/darkknight/ActionSyphonStrike3623.cpp
Normal file
22
src/scripts/action/darkknight/ActionSyphonStrike3623.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <Script/NativeScriptApi.h>
|
||||
#include <ScriptObject.h>
|
||||
#include <Actor/Player.h>
|
||||
#include <Action/Action.h>
|
||||
|
||||
class ActionSyphonStrike3623 :
|
||||
public Sapphire::ScriptAPI::ActionScript
|
||||
{
|
||||
public:
|
||||
ActionSyphonStrike3623() :
|
||||
Sapphire::ScriptAPI::ActionScript( 3623 )
|
||||
{
|
||||
}
|
||||
|
||||
void onExecute( Sapphire::Action::Action& action ) override
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( ActionSyphonStrike3623 );
|
|
@ -31,7 +31,7 @@ private:
|
|||
// buy
|
||||
if( result.param2 == 1 )
|
||||
{
|
||||
auto shopMgr = getFramework()->get< Sapphire::World::Manager::ShopMgr >();
|
||||
auto shopMgr = framework()->get< Sapphire::World::Manager::ShopMgr >();
|
||||
|
||||
shopMgr->purchaseGilShopItem( player, result.eventId, result.param3, result.param4 );
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ public:
|
|||
|
||||
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
auto pExdData = getFramework()->get< Sapphire::Data::ExdDataGenerated >();
|
||||
auto pExdData = framework()->get< Sapphire::Data::ExdDataGenerated >();
|
||||
if( !pExdData )
|
||||
return;
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ public:
|
|||
{
|
||||
player.playScene( eventId, 0, HIDE_HOTBAR | NO_DEFAULT_CAMERA, [this, eventId]( Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
auto pExdData = getFramework()->get< Sapphire::Data::ExdDataGenerated >();
|
||||
auto pExdData = framework()->get< Sapphire::Data::ExdDataGenerated >();
|
||||
if( !pExdData )
|
||||
return;
|
||||
|
||||
|
@ -42,7 +42,7 @@ public:
|
|||
// moving a player inside an event will crash the game so we end it hre
|
||||
player.eventFinish( eventId, 1 );
|
||||
|
||||
auto playerMgr = getFramework()->get< Sapphire::World::Manager::PlayerMgr >();
|
||||
auto playerMgr = framework()->get< Sapphire::World::Manager::PlayerMgr >();
|
||||
playerMgr->movePlayerToLandDestination( player, pHousingAethernet->level, housingZone->getWardNum() );
|
||||
} );
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
if( result.param2 != 1 )
|
||||
return;
|
||||
|
||||
auto terriMgr = getFramework()->get< Sapphire::World::Manager::TerritoryMgr >();
|
||||
auto terriMgr = framework()->get< Sapphire::World::Manager::TerritoryMgr >();
|
||||
if( !terriMgr )
|
||||
return;
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
{
|
||||
auto callback = [ this ]( Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
auto pFw = getFramework();
|
||||
auto pFw = framework();
|
||||
if( !pFw )
|
||||
return LandPurchaseResult::ERR_INTERNAL;
|
||||
// Purchase Land
|
||||
|
|
|
@ -27,12 +27,12 @@ public:
|
|||
player.eventFinish( 1310721, 0 );
|
||||
player.eventFinish( getId(), 1 );
|
||||
|
||||
auto exdData = getFramework()->get< Sapphire::Data::ExdDataGenerated >();
|
||||
auto exdData = framework()->get< Sapphire::Data::ExdDataGenerated >();
|
||||
auto warp = exdData->get< Sapphire::Data::Warp >( getId() );
|
||||
if( !warp )
|
||||
return;
|
||||
|
||||
auto playerMgr = getFramework()->get< Sapphire::World::Manager::PlayerMgr >();
|
||||
auto playerMgr = framework()->get< Sapphire::World::Manager::PlayerMgr >();
|
||||
playerMgr->movePlayerToLandDestination( player, warp->level, result.param3 );
|
||||
}
|
||||
else
|
||||
|
@ -56,7 +56,7 @@ public:
|
|||
|
||||
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
auto exdData = getFramework()->get< Sapphire::Data::ExdDataGenerated >();
|
||||
auto exdData = framework()->get< Sapphire::Data::ExdDataGenerated >();
|
||||
if( !exdData )
|
||||
return;
|
||||
|
||||
|
|
174
src/scripts/quest/classquest/ClsLnc000.cpp
Normal file
174
src/scripts/quest/classquest/ClsLnc000.cpp
Normal file
|
@ -0,0 +1,174 @@
|
|||
#include <Actor/Player.h>
|
||||
#include "Manager/EventMgr.h"
|
||||
#include <ScriptObject.h>
|
||||
#include "Framework.h"
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
// Quest Script: ClsLnc000_00023
|
||||
// Quest Name: Way of the Lancer
|
||||
// Quest ID: 65559
|
||||
// Start NPC: 1000251
|
||||
// End NPC: 1000254
|
||||
|
||||
class ClsLnc000 : public Sapphire::ScriptAPI::EventScript
|
||||
{
|
||||
private:
|
||||
// Basic quest information
|
||||
// Quest vars / flags used
|
||||
// GetQuestUI8AL
|
||||
// GetQuestUI8BH
|
||||
// GetQuestUI8BL
|
||||
|
||||
// Steps in this quest ( 0 is before accepting,
|
||||
// 1 is first, 255 means ready for turning it in
|
||||
enum Sequence : uint8_t
|
||||
{
|
||||
Seq0 = 0,
|
||||
Seq1 = 1,
|
||||
Seq2 = 2,
|
||||
SeqFinish = 255,
|
||||
};
|
||||
|
||||
// Quest rewards
|
||||
static constexpr auto RewardExpFactor = 100;
|
||||
static constexpr auto RewardItem = { 4639, 0, 0, 0, 0, 0 };
|
||||
static constexpr auto RewardItemCount = { 5, 0, 0, 0, 0, 0 };
|
||||
static constexpr auto RewardItemOptional = { 0, 0, 0, 0, 0 };
|
||||
static constexpr auto RewardItemOptionalCount = { 0, 0, 0, 0, 0 };
|
||||
|
||||
// Entities found in the script data of the quest
|
||||
static constexpr auto Actor0 = 1000251;
|
||||
static constexpr auto Actor1 = 1000254;
|
||||
static constexpr auto Enemy0 = 37;
|
||||
static constexpr auto Enemy1 = 49;
|
||||
static constexpr auto Enemy2 = 47;
|
||||
static constexpr auto LogmessageMonsterNotePageUnlock = 1007;
|
||||
static constexpr auto Seq0Actor0 = 0;
|
||||
static constexpr auto Seq1Actor1 = 1;
|
||||
static constexpr auto Seq3Actor1 = 2;
|
||||
static constexpr auto UnlockImageMonsterNote = 32;
|
||||
|
||||
public:
|
||||
ClsLnc000() : Sapphire::ScriptAPI::EventScript( 65559 ){};
|
||||
~ClsLnc000(){};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Event Handlers
|
||||
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
auto pEventMgr = framework()->get< World::Manager::EventMgr >();
|
||||
auto actor = pEventMgr->mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
|
||||
|
||||
if( actor == Actor0 )
|
||||
{
|
||||
if( !player.hasQuest( getId() ) )
|
||||
Scene00000( player );
|
||||
else
|
||||
Scene00002( player );
|
||||
|
||||
}
|
||||
else if( actor == Actor1 && player.getQuestSeq( getId() ) != SeqFinish)
|
||||
{
|
||||
Scene00001( player );
|
||||
}
|
||||
else if( actor == Actor1 && player.getQuestSeq( getId() ) == SeqFinish )
|
||||
{
|
||||
Scene00002( player );
|
||||
}
|
||||
}
|
||||
|
||||
bool checkCompletion( Entity::Player& player )
|
||||
{
|
||||
auto al = player.getQuestUI8AL( getId() );
|
||||
auto bh = player.getQuestUI8BH( getId() );
|
||||
auto bl = player.getQuestUI8BL( getId() );
|
||||
return al == 3 && bh == 3 && bl == 3;
|
||||
}
|
||||
|
||||
void onBNpcKill( uint32_t npcId, Entity::Player& player ) override
|
||||
{
|
||||
|
||||
auto al = player.getQuestUI8AL( getId() );
|
||||
auto bh = player.getQuestUI8BH( getId() );
|
||||
auto bl = player.getQuestUI8BL( getId() );
|
||||
|
||||
switch( npcId )
|
||||
{
|
||||
case Enemy0:
|
||||
if( al < 3 )
|
||||
{
|
||||
player.setQuestUI8AL( getId(), ++al );
|
||||
player.sendQuestMessage( getId(), 0, 2, al, 3 );
|
||||
}
|
||||
|
||||
break;
|
||||
case Enemy1:
|
||||
if( bh < 3 )
|
||||
{
|
||||
player.setQuestUI8BH( getId(), ++bh );
|
||||
player.sendQuestMessage( getId(), 1, 2, bh, 3 );
|
||||
}
|
||||
|
||||
break;
|
||||
case Enemy2:
|
||||
if( bl < 3 )
|
||||
{
|
||||
player.setQuestUI8BL( getId(), ++bl );
|
||||
player.sendQuestMessage( getId(), 2, 2, bl, 3 );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if( checkCompletion( player ) )
|
||||
{
|
||||
player.updateQuest( getId(), SeqFinish );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Available Scenes in this quest, not necessarly all are used
|
||||
void Scene00000( Entity::Player& player )
|
||||
{
|
||||
player.playScene( getId(), 0, HIDE_HOTBAR,
|
||||
[ & ]( Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.param2 == 1 ) // accept quest
|
||||
player.updateQuest( getId(), Seq1 );
|
||||
|
||||
} );
|
||||
}
|
||||
|
||||
void Scene00001( Entity::Player& player )
|
||||
{
|
||||
player.playScene( getId(), 1, FADE_OUT | HIDE_HOTBAR | CONDITION_CUTSCENE | HIDE_UI,
|
||||
[ & ]( Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.param1 == 256 ) // accept quest
|
||||
player.updateQuest( getId(), Seq2 );
|
||||
} );
|
||||
}
|
||||
|
||||
void Scene00002( Entity::Player& player )
|
||||
{
|
||||
player.playScene( getId(), 2, HIDE_HOTBAR,
|
||||
[ & ]( Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.param2 == 1 )
|
||||
{
|
||||
if( player.giveQuestRewards( getId(), 0 ) )
|
||||
{
|
||||
player.finishQuest( getId() );
|
||||
player.learnAction( 21 );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( ClsLnc000 );
|
|
@ -62,7 +62,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void onMobKill( Entity::Player& player, uint64_t npcId )
|
||||
void onBNpcKill( uint32_t npcId, Entity::Player& player ) override
|
||||
{
|
||||
if( npcId != Enemy0 )
|
||||
return;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "Framework.h"
|
||||
#include "Script/ScriptMgr.h"
|
||||
|
||||
#include <Math/CalcStats.h>
|
||||
|
||||
#include "Actor/Player.h"
|
||||
#include "Actor/BNpc.h"
|
||||
|
||||
|
@ -279,6 +281,13 @@ void Sapphire::Action::Action::execute()
|
|||
}
|
||||
}
|
||||
|
||||
if( isComboAction() )
|
||||
{
|
||||
auto player = m_pSource->getAsPlayer();
|
||||
|
||||
player->sendDebug( "action combo success from action#{0}", player->getLastComboActionId() );
|
||||
}
|
||||
|
||||
if( !hasClientsideTarget() )
|
||||
{
|
||||
pScriptMgr->onExecute( *this );
|
||||
|
@ -288,6 +297,13 @@ void Sapphire::Action::Action::execute()
|
|||
pScriptMgr->onEObjHit( *player, m_targetId, getId() );
|
||||
return;
|
||||
}
|
||||
|
||||
// set currently casted action as the combo action if it interrupts a combo
|
||||
// ignore it otherwise (ogcds, etc.)
|
||||
if( !m_actionData->preservesCombo )
|
||||
{
|
||||
m_pSource->setLastComboActionId( getId() );
|
||||
}
|
||||
}
|
||||
|
||||
void Sapphire::Action::Action::calculateActionCost()
|
||||
|
@ -302,7 +318,8 @@ void Sapphire::Action::Action::calculateActionCost()
|
|||
}
|
||||
case ActionPrimaryCostType::MagicPoints:
|
||||
{
|
||||
calculateMPCost( m_primaryCost );
|
||||
// todo: not sure if we should store the final value like this?
|
||||
m_primaryCost = Math::CalcStats::calculateMpCost( *m_pSource, m_primaryCost );
|
||||
break;
|
||||
}
|
||||
case ActionPrimaryCostType::TacticsPoints:
|
||||
|
@ -325,88 +342,6 @@ void Sapphire::Action::Action::calculateActionCost()
|
|||
// todo: secondary cost type needs to be handled
|
||||
}
|
||||
|
||||
// todo: this shouldn't be in action and instead be in some general stat calc util
|
||||
void Sapphire::Action::Action::calculateMPCost( uint16_t baseCost )
|
||||
{
|
||||
auto level = m_pSource->getLevel();
|
||||
|
||||
// each level range is 1-10, 11-20, 21-30, ... therefore:
|
||||
// level 50 should be in the 4th group, not the 5th
|
||||
// dividing by 10 on the border will break this unless we subtract 1
|
||||
auto levelGroup = std::max< uint8_t >( level - 1, 1 ) / 10;
|
||||
|
||||
float cost = baseCost;
|
||||
|
||||
// thanks to andrew for helping me figure this shit out, should be pretty accurate
|
||||
switch( levelGroup )
|
||||
{
|
||||
// level 1-10
|
||||
case 0:
|
||||
{
|
||||
// r^2 = 0.9999
|
||||
cost = 0.0952f * level + 0.9467f;
|
||||
break;
|
||||
}
|
||||
|
||||
// level 11-20
|
||||
case 1:
|
||||
{
|
||||
// r^2 = 1
|
||||
cost = 0.19f * level;
|
||||
break;
|
||||
}
|
||||
|
||||
// level 21-30
|
||||
case 2:
|
||||
{
|
||||
// r^2 = 1
|
||||
cost = 0.38f * level - 3.8f;
|
||||
break;
|
||||
}
|
||||
|
||||
// level 31-40
|
||||
case 3:
|
||||
{
|
||||
// r^2 = 1
|
||||
cost = 0.6652f * level - 12.358f;
|
||||
break;
|
||||
}
|
||||
|
||||
// level 41-50
|
||||
case 4:
|
||||
{
|
||||
// r^2 = 1
|
||||
cost = 1.2352f * level - 35.159f;
|
||||
break;
|
||||
}
|
||||
|
||||
// level 51-60
|
||||
case 5:
|
||||
{
|
||||
// r^2 = 1
|
||||
cost = 0.0654f * std::exp( 0.1201f * level );
|
||||
break;
|
||||
}
|
||||
|
||||
// level 61-70
|
||||
case 6:
|
||||
{
|
||||
// r^2 = 0.9998
|
||||
cost = 0.2313f * ( level * level ) - 26.98f * level + 875.21f;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// m_primaryCost is the base cost, cost is the multiplier for the current player level
|
||||
m_primaryCost = static_cast< uint16_t >( std::round( cost * baseCost ) );
|
||||
|
||||
if( auto player = m_pSource->getAsPlayer() )
|
||||
player->sendDebug( "calculated mp cost: {0}", m_primaryCost );
|
||||
}
|
||||
|
||||
bool Sapphire::Action::Action::precheck()
|
||||
{
|
||||
if( auto player = m_pSource->getAsPlayer() )
|
||||
|
@ -478,4 +413,16 @@ uint32_t Sapphire::Action::Action::getAdditionalData() const
|
|||
void Sapphire::Action::Action::setAdditionalData( uint32_t data )
|
||||
{
|
||||
m_additionalData = data;
|
||||
}
|
||||
|
||||
bool Sapphire::Action::Action::isComboAction() const
|
||||
{
|
||||
auto lastActionId = m_pSource->getLastComboActionId();
|
||||
|
||||
if( lastActionId == 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_actionData->actionCombo == lastActionId;
|
||||
}
|
|
@ -45,6 +45,8 @@ namespace Sapphire::Action
|
|||
uint32_t getAdditionalData() const;
|
||||
void setAdditionalData( uint32_t data );
|
||||
|
||||
bool isComboAction() const;
|
||||
|
||||
/*!
|
||||
* @brief Checks if the action *may* target a resident instead of an actor
|
||||
* @return true if the target *may* be a resident and not an actor, otherwise false.
|
||||
|
|
|
@ -658,3 +658,13 @@ int64_t Sapphire::Entity::Chara::getLastUpdateTime() const
|
|||
{
|
||||
return m_lastUpdate;
|
||||
}
|
||||
|
||||
void Sapphire::Entity::Chara::setLastComboActionId( uint32_t actionId )
|
||||
{
|
||||
m_lastComboActionId = actionId;
|
||||
}
|
||||
|
||||
uint32_t Sapphire::Entity::Chara::getLastComboActionId() const
|
||||
{
|
||||
return m_lastComboActionId;
|
||||
}
|
||||
|
|
|
@ -102,6 +102,8 @@ namespace Sapphire::Entity
|
|||
uint64_t m_targetId;
|
||||
/*! Ptr to a queued action */
|
||||
Action::ActionPtr m_pCurrentAction;
|
||||
/*! the id of the last combo action used (IgnoresCombo) */
|
||||
uint32_t m_lastComboActionId;
|
||||
/*! Invincibility type */
|
||||
Common::InvincibilityType m_invincibilityType;
|
||||
|
||||
|
@ -243,6 +245,9 @@ namespace Sapphire::Entity
|
|||
|
||||
void setCurrentAction( Action::ActionPtr pAction );
|
||||
|
||||
uint32_t getLastComboActionId() const;
|
||||
void setLastComboActionId( uint32_t actionId );
|
||||
|
||||
uint32_t getBonusStat( Common::BaseParam bonus ) const;
|
||||
|
||||
};
|
||||
|
|
|
@ -77,6 +77,7 @@ void World::Manager::ActionMgr::handleItemAction( Sapphire::Entity::Player& play
|
|||
}
|
||||
|
||||
case Common::ItemActionType::ItemActionVFX:
|
||||
case Common::ItemActionType::ItemActionVFX2:
|
||||
{
|
||||
handleItemActionVFX( player, itemId, itemActionData->data[ 0 ] );
|
||||
|
||||
|
|
|
@ -13,9 +13,10 @@
|
|||
using namespace Sapphire::Math;
|
||||
using namespace Sapphire::Entity;
|
||||
|
||||
const int levelTable[70][7] =
|
||||
const int levelTable[71][7] =
|
||||
{
|
||||
// PIE, MP, MAIN,SUB,DIV,HP,ELMT,THREAT
|
||||
{ 1, 1, 1, 1, 1, 1, 1 },
|
||||
{ 50, 104, 20, 56, 56, 0, 52 },
|
||||
{ 55, 114, 21, 57, 57, 0, 54 },
|
||||
{ 60, 123, 22, 60, 60, 0, 56 },
|
||||
|
@ -184,16 +185,96 @@ uint32_t CalcStats::calculateMaxMp( PlayerPtr pPlayer, Sapphire::FrameworkPtr pF
|
|||
return result;
|
||||
}
|
||||
|
||||
float CalcStats::pBlk( const Entity::Chara& chara )
|
||||
uint16_t CalcStats::calculateMpCost( const Sapphire::Entity::Chara& chara, uint16_t baseCost )
|
||||
{
|
||||
auto level = chara.getLevel();
|
||||
|
||||
// each level range is 1-10, 11-20, 21-30, ... therefore:
|
||||
// level 50 should be in the 4th group, not the 5t
|
||||
// dividing by 10 on the border will break this unless we subtract 1
|
||||
auto levelGroup = std::max< uint8_t >( level - 1, 1 ) / 10;
|
||||
|
||||
float cost = baseCost;
|
||||
|
||||
// thanks to andrew for helping me figure this shit out
|
||||
// played with this some more and it seems to be accurate for everything i've tried
|
||||
switch( levelGroup )
|
||||
{
|
||||
// level 1-10
|
||||
case 0:
|
||||
{
|
||||
// r^2 = 0.9999
|
||||
cost = 0.0952f * level + 0.9467f;
|
||||
break;
|
||||
}
|
||||
|
||||
// level 11-20
|
||||
case 1:
|
||||
{
|
||||
// r^2 = 1
|
||||
cost = 0.19f * level;
|
||||
break;
|
||||
}
|
||||
|
||||
// level 21-30
|
||||
case 2:
|
||||
{
|
||||
// r^2 = 1
|
||||
cost = 0.38f * level - 3.8f;
|
||||
break;
|
||||
}
|
||||
|
||||
// level 31-40
|
||||
case 3:
|
||||
{
|
||||
// r^2 = 1
|
||||
cost = 0.6652f * level - 12.358f;
|
||||
break;
|
||||
}
|
||||
|
||||
// level 41-50
|
||||
case 4:
|
||||
{
|
||||
// r^2 = 1
|
||||
cost = 1.2352f * level - 35.159f;
|
||||
break;
|
||||
}
|
||||
|
||||
// level 51-60
|
||||
case 5:
|
||||
{
|
||||
// r^2 = 1
|
||||
cost = 0.0654f * std::exp( 0.1201f * level );
|
||||
break;
|
||||
}
|
||||
|
||||
// level 61-70
|
||||
case 6:
|
||||
{
|
||||
// r^2 = 0.9998
|
||||
cost = 0.2313f * ( level * level ) - 26.98f * level + 875.21f;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast< uint16_t >( std::round( cost * baseCost ) );
|
||||
}
|
||||
|
||||
float CalcStats::pBlk( const Chara& chara )
|
||||
{
|
||||
auto level = chara.getLevel();
|
||||
float blockRate = static_cast< float >( chara.getBonusStat( Common::BaseParam::BlockRate ) );
|
||||
float levelVal = static_cast< float >( levelTable[ level ][ 4 ] );
|
||||
float levelVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
||||
|
||||
return std::floor( ( 30 * blockRate ) / levelVal + 10 );
|
||||
}
|
||||
|
||||
float CalcStats::pDhr( const Entity::Chara& chara )
|
||||
float CalcStats::pDhr( const Chara& chara )
|
||||
{
|
||||
const auto& baseStats = chara.getStats();
|
||||
auto level = chara.getLevel();
|
||||
|
@ -201,13 +282,13 @@ float CalcStats::pDhr( const Entity::Chara& chara )
|
|||
float dhRate = static_cast< float >( chara.getBonusStat( Common::BaseParam::DirectHitRate ) ) +
|
||||
baseStats.accuracy;
|
||||
|
||||
float divVal = static_cast< float >( levelTable[ level ][ 4 ] );
|
||||
float subVal = static_cast< float >( levelTable[ level ][ 3 ] );
|
||||
float divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
||||
float subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
|
||||
|
||||
return std::floor( 550.f * ( dhRate - subVal ) / divVal ) / 10.f;
|
||||
}
|
||||
|
||||
float CalcStats::pChr( const Entity::Chara& chara )
|
||||
float CalcStats::pChr( const Chara& chara )
|
||||
{
|
||||
const auto& baseStats = chara.getStats();
|
||||
auto level = chara.getLevel();
|
||||
|
@ -215,8 +296,8 @@ float CalcStats::pChr( const Entity::Chara& chara )
|
|||
float chRate = static_cast< float >( chara.getBonusStat( Common::BaseParam::CriticalHit ) ) +
|
||||
baseStats.critHitRate;
|
||||
|
||||
float divVal = static_cast< float >( levelTable[ level ][ 4 ] );
|
||||
float subVal = static_cast< float >( levelTable[ level ][ 3 ] );
|
||||
float divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] );
|
||||
float subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] );
|
||||
|
||||
return std::floor( 200.f * ( chRate - subVal ) / divVal + 50.f ) / 10.f;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,32 @@ namespace Sapphire::Math
|
|||
|
||||
static uint32_t calculateMaxHp( Sapphire::Entity::PlayerPtr pPlayer, FrameworkPtr pFw );
|
||||
|
||||
/*!
|
||||
* @brief Calculates the MP cost of a spell given its base cost
|
||||
* @param chara The Chara that is casting the action
|
||||
* @param baseCost The action cost
|
||||
* @return The total MP to be consumed by a successful cast
|
||||
*/
|
||||
static uint16_t calculateMpCost( const Sapphire::Entity::Chara& chara, uint16_t baseCost );
|
||||
|
||||
/*!
|
||||
* @brief Calculates the probability of a block happening
|
||||
* @return
|
||||
*/
|
||||
static float pBlk( const Sapphire::Entity::Chara& );
|
||||
|
||||
/*!
|
||||
* @brief Calculates the probability of a direct hit happening
|
||||
* @return
|
||||
*/
|
||||
static float pDhr( const Sapphire::Entity::Chara& );
|
||||
|
||||
/*!
|
||||
* @brief Calculates the probability of a critical hit happening
|
||||
* @return
|
||||
*/
|
||||
static float pChr( const Sapphire::Entity::Chara& );
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace Sapphire::ScriptAPI
|
|||
m_framework = fw;
|
||||
}
|
||||
|
||||
Sapphire::Framework* ScriptObject::getFramework() const
|
||||
Sapphire::Framework* ScriptObject::framework() const
|
||||
{
|
||||
return m_framework;
|
||||
}
|
||||
|
@ -102,8 +102,8 @@ namespace Sapphire::ScriptAPI
|
|||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
EventScript::EventScript( uint32_t questId ) :
|
||||
ScriptObject( questId, typeid( EventScript ).hash_code() )
|
||||
EventScript::EventScript( uint32_t eventId ) :
|
||||
ScriptObject( eventId, typeid( EventScript ).hash_code() )
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -131,8 +131,8 @@ namespace Sapphire::ScriptAPI
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
EventScript::onEventItem( Entity::Player& player, uint32_t eventItemId, uint32_t eventId, uint32_t castTime, uint64_t targetId )
|
||||
void EventScript::onEventItem( Entity::Player& player, uint32_t eventItemId, uint32_t eventId, uint32_t castTime,
|
||||
uint64_t targetId )
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace Sapphire::ScriptAPI
|
|||
*
|
||||
* @return A pointer to Core::Framework
|
||||
*/
|
||||
virtual Sapphire::Framework* getFramework() const;
|
||||
virtual Sapphire::Framework* framework() const;
|
||||
};
|
||||
|
||||
|
||||
|
@ -161,7 +161,7 @@ namespace Sapphire::ScriptAPI
|
|||
}
|
||||
|
||||
public:
|
||||
explicit EventScript( uint32_t questId );
|
||||
explicit EventScript( uint32_t eventId );
|
||||
|
||||
virtual void onTalk( uint32_t eventId, Sapphire::Entity::Player& player, uint64_t actorId );
|
||||
|
||||
|
@ -171,12 +171,12 @@ namespace Sapphire::ScriptAPI
|
|||
|
||||
virtual void onEnterTerritory( Sapphire::Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 );
|
||||
|
||||
virtual void onWithinRange( Sapphire::Entity::Player& player, uint32_t eventId, uint32_t param1, float x, float y, float z );
|
||||
virtual void onWithinRange( Sapphire::Entity::Player& player, uint32_t eventId, uint32_t param1,float x, float y, float z );
|
||||
|
||||
virtual void onOutsideRange( Sapphire::Entity::Player& player, uint32_t eventId, uint32_t param1, float x, float y, float z );
|
||||
|
||||
virtual void
|
||||
onEventItem( Sapphire::Entity::Player& player, uint32_t eventItemId, uint32_t eventId, uint32_t castTime, uint64_t targetId );
|
||||
virtual void onEventItem( Sapphire::Entity::Player& player, uint32_t eventItemId, uint32_t eventId, uint32_t castTime,
|
||||
uint64_t targetId );
|
||||
|
||||
virtual void onEventHandlerTradeReturn( Sapphire::Entity::Player& player, uint32_t eventId, uint16_t subEvent, uint16_t param,
|
||||
uint32_t catalogId );
|
||||
|
@ -228,7 +228,7 @@ namespace Sapphire::ScriptAPI
|
|||
virtual void onUpdate( Sapphire::InstanceContent& instance, uint32_t currTime );
|
||||
|
||||
virtual void onEnterTerritory( Sapphire::InstanceContent& instance, Sapphire::Entity::Player& player, uint32_t eventId,
|
||||
uint16_t param1, uint16_t param2 );
|
||||
uint16_t param1, uint16_t param2 );
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue