1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-26 14:37:44 +00:00

Merge remote-tracking branch 'origin/ThreePointOh' into ThreePointThree

This commit is contained in:
Mordred 2023-01-19 21:20:33 +01:00
commit f1e7752515
31 changed files with 2821 additions and 159 deletions

2
.gitignore vendored
View file

@ -27,6 +27,8 @@ src/tools/bin/generated/*
build/
build-*/
cmake-build-*/
bin/
out/
# Prerequisites
*.d

View file

@ -1000,6 +1000,216 @@ namespace Sapphire::Common
InvincibilityIgnoreDamage,
};
namespace Achievement
{
enum class Type : uint8_t
{
None,
General,
LinkedAchievement,
Classjob,
Unknown_4,// Materia related? id 304
Unknown_5,// Hunt related? id 1259
QuestUnk_6,
Unknown_7,
Unknown_8,// Map discovery related
QuestUnk_9,
ChocoboRank,
PvPRank,
WolvesDenMatches,
WolvesDenWins,
InstanceContent,
BeastTribeReputation,
Unknown_16,
FrontlineMatches,
FrontlineWinsGC,
FrontlineWinsAll,
AetherCurrent,
};
namespace GeneralSubtype
{
enum AchievementGeneralSubtype : int32_t
{
EnemyDefeatCount = 11,
GilEnemySource = 12,
GilLevequestSource = 13,
FactionLevequestCompleted = 14,
GuildhestCompleted = 15,
MateriaAffixCount = 16,
SpiritboundMateriaCount = 17,
RegionalBattleLevequestCompleted = 18,
LocalTradeLevequestCompleted = 19,
// Legacy subtypes - skipping
#pragma region Synth 1 -50 Recipes
SynthWoodworkingLv01to10Recipes = 23,
SynthWoodworkingLv11to20Recipes = 24,
SynthWoodworkingLv21to30Recipes = 25,
SynthWoodworkingLv31to40Recipes = 26,
SynthWoodworkingLv41to50Recipes = 27,
SynthSmithingLv01to10Recipes = 28,
SynthSmithingLv11to20Recipes = 29,
SynthSmithingLv21to30Recipes = 30,
SynthSmithingLv31to40Recipes = 31,
SynthSmithingLv41to50Recipes = 32,
SynthArmorcraftLv01to10Recipes = 33,
SynthArmorcraftLv11to20Recipes = 34,
SynthArmorcraftLv21to30Recipes = 35,
SynthArmorcraftLv31to40Recipes = 36,
SynthArmorcraftLv41to50Recipes = 37,
SynthGoldsmithingLv01to10Recipes = 38,
SynthGoldsmithingLv11to20Recipes = 39,
SynthGoldsmithingLv21to30Recipes = 40,
SynthGoldsmithingLv31to40Recipes = 41,
SynthGoldsmithingLv41to50Recipes = 42,
SynthLeatherworkingLv01to10Recipes = 43,
SynthLeatherworkingLv11to20Recipes = 44,
SynthLeatherworkingLv21to30Recipes = 45,
SynthLeatherworkingLv31to40Recipes = 46,
SynthLeatherworkingLv41to50Recipes = 47,
SynthClothcraftLv01to10Recipes = 48,
SynthClothcraftLv11to20Recipes = 49,
SynthClothcraftLv21to30Recipes = 50,
SynthClothcraftLv31to40Recipes = 51,
SynthClothcraftLv41to50Recipes = 52,
SynthAlchemyLv01to10Recipes = 53,
SynthAlchemyLv11to20Recipes = 54,
SynthAlchemyLv21to30Recipes = 55,
SynthAlchemyLv31to40Recipes = 56,
SynthAlchemyLv41to50Recipes = 57,
SynthCookingLv01to10Recipes = 58,
SynthCookingLv11to20Recipes = 59,
SynthCookingLv21to30Recipes = 60,
SynthCookingLv31to40Recipes = 61,
SynthCookingLv41to50Recipes = 62,
#pragma endregion
// TODO: Map gathering subtypes 63 to 128
GCStormSeals = 138,
GCSerpentSeals = 139,
GCFlameSeals = 140,
MaelstromLevequestCompleted = 141,
TwinAdderLevequestCompleted = 142,
ImmortalFlamesLevequestCompleted = 143,
MaelstromSupplyCompleted = 144,
TwinAdderSupplyCompleted = 145,
ImmortalFlamesSupplyCompleted = 146,
MaelstromProvisioningCompleted = 147,
TwinAdderProvisioningCompleted = 148,
ImmortalFlamesProvisioningCompleted = 149,
// Legacy subtypes - skipping
FieldLevequestCompleted = 179,
UniqueBattleLevequestCompleted = 180,
// TODO: Map leve subtypes 181 to 201
UniqueFishCaughtCount = 202,
// TODO: Map craft subtypes 203 to 213
UniqueQuestsCompleted = 214,
InstanceContentCompleted = 215, // Instanced dungeons, raids or trials
UniqueInstanceContentCompleted = 216,// Unique instanced dungeons, raids or trials
BindingCoilCompleted = 217,
UniqueGuildhestCompleted = 218,
FateCompleted = 219,
// TODO: Map subtypes 220 to 235
ChocoboRidePimpedOut = 236,
MaelstromUniqueLeveCompleted = 238,
TwinAdderUniqueLeveCompleted = 239,
ImmortalFlamesUniqueLeveCompleted = 240,
EnlistGCMaelstrom = 241,
EnlistGCTwinAdder = 242,
EnlistGCImmortalFlames = 243,
CommendationCount = 244,
// TODO: Map subtypes 245 to 250
ResurrectStrangers = 251,
SecondCoilCompleted = 266,
UniqueBigFishCaught = 267,
RetainerVentureCompleted = 268,
HighLvlDutyPaladinCompleted = 277,
HighLvlDutyWarriorCompleted = 278,
RelicAnimus = 279,
RelicNovus = 280,
HigherGradeMateriaFromTransmutation = 281,
ARRSightseeingLogCount = 284,
InterceptorDroneDefeated = 285,
InterceptorNodeDefeated = 286,
TrainAnotherChocoboCount = 287,
HuntRankBDefeated = 290,
HuntRankADefeated = 291,
HuntRankSDefeated = 292,
LootCofferLeatherMap = 293,
DesynthesizeItemCount = 294,
RelicNexus = 347,
FinalCoilCompleted = 348,
RelicZodiac = 349,
RelicZeta = 350,
TripleTriadUniqueCardCount = 352,
TripleTriadNPCDefeatedCount = 353,
TripleTriadRouletteWin = 354,
TripleTriadTournamentWin = 355,
MgpGoldSaucerAttractionSource = 356,
ChocoboRaceCount = 357,
ChocoboRaceWin = 358,
ChocoboCovering = 359,
ChocoboPedigreeLevel = 360,
ChocoboRating = 361,
FrontlineEnemyDispatched = 362,
GATECompleted = 363,
// TODO: Map subtypes 364 to 368
HighLvlDutyDarkKnightCompleted = 369,
GordiasCompleted = 370,
GordiasSavageCompleted = 371,
// TODO: Map subtypes 372 to X
};
}
}
union AchievementDataKey
{
uint32_t u32;
struct AchievementPackedKey {
uint8_t type;
uint16_t subtype;
uint8_t padding0;
} key;
};
enum HierarchyType : uint8_t
{
NONE_2 = 0x0,

View file

@ -2,6 +2,7 @@
#include "DbWorker.h"
#include <MySqlConnector.h>
#include "Logging/Logger.h"
#include <cassert>
#include "PreparedStatement.h"

View file

@ -235,11 +235,12 @@ namespace Sapphire::Network::ActorControl
ArmoryErrorMsg = 0x201,
AchievementPopup = 0x203,
AchievementSetRate = 0x202,
AchievementComplete = 0x203,
SetCutsceneFlag = 0x204,
LogMsg = 0x205, // LogMessage?
AchievementMsg = 0x206,
AchievementObtainMsg = 0x206,
SetItemLevel = 0x209,

View file

@ -328,6 +328,12 @@ namespace Sapphire::Network::Packets::WorldPackets::Server
uint32_t Result;
};
struct FFXIVIpcAchievement : FFXIVIpcBasePacket< Achievement >
{
uint8_t complete[256]; // bitmask of achievements, up to 8 * 256 (2048) achvs
uint16_t history[5]; // last 5 achievement IDs
};
struct ZoneProtoDownLetterBoxAppendItemBase
{
uint32_t CatalogID;

View file

@ -1,5 +1,8 @@
#include <ScriptObject.h>
#include <Territory/QuestBattle.h>
#include <Actor/Player.h>
#include <Actor/GameObject.h>
#include <Actor/BNpc.h>
using namespace Sapphire;
@ -16,6 +19,14 @@ private:
static constexpr auto INIT_P_POP_01 = 4083622;
static constexpr auto CUT_SCENE_01 = 133;
static constexpr auto HOW_TO_QIB = 79;
static constexpr auto TEXT_YSHTOLA_BATTLETALK_01 = 82;
enum Variables : uint8_t
{
SET_1_SPAWNED,
SET_2_SPAWNED,
SUCCESS_CALLED
};
public:
LurkersintheGrotto() : Sapphire::ScriptAPI::QuestBattleScript( 35 )
@ -135,15 +146,106 @@ public:
}
void onPlayerSetup( Sapphire::QuestBattle& instance, Entity::Player& player ) override
{
player.setRot( 0 );
player.setPos( { -60, 25, -135 } );
}
void onUpdate( QuestBattle& instance, uint64_t tickCount ) override
{
auto set1Spawned = instance.getDirectorVar( Variables::SET_1_SPAWNED );
auto set2Spawned = instance.getDirectorVar( Variables::SET_2_SPAWNED );
auto successCalled = instance.getDirectorVar( Variables::SUCCESS_CALLED );
auto boss = instance.getActiveBNpcByLayoutId( INIT_POP_BOSS );
auto ysthola = instance.getActiveBNpcByLayoutId( INIT_P_POP_01 );
auto pPlayer = instance.getPlayerPtr();
auto bossHp = boss ? boss->getHpPercent() : 0;
if( pPlayer && !pPlayer->isAlive() )
{
instance.fail();
return;
}
if( !set1Spawned && bossHp <= 75 )
{
auto a1 = instance.createBNpcFromLayoutId( INIT_POP_01_01, 100, Common::BNpcType::Enemy );
auto a2 = instance.createBNpcFromLayoutId( INIT_POP_01_02, 100, Common::BNpcType::Enemy );
a1->setFlag( Entity::NoDeaggro );
a2->setFlag( Entity::NoDeaggro );
a1->hateListAdd( pPlayer, 1 );
a2->hateListAdd( pPlayer, 1 );
instance.setDirectorVar( Variables::SET_1_SPAWNED, true );
}
if( !set2Spawned && bossHp <= 25 )
{
auto a3 = instance.createBNpcFromLayoutId( INIT_POP_02_01, 150, Common::BNpcType::Enemy );
auto a4 = instance.createBNpcFromLayoutId( INIT_POP_02_02, 150, Common::BNpcType::Enemy );
auto a5 = instance.createBNpcFromLayoutId( INIT_POP_02_03, 100, Common::BNpcType::Enemy );
auto a6 = instance.createBNpcFromLayoutId( INIT_POP_02_04, 100, Common::BNpcType::Enemy );
a3->setFlag( Entity::NoDeaggro );
a4->setFlag( Entity::NoDeaggro );
a5->setFlag( Entity::NoDeaggro );
a6->setFlag( Entity::NoDeaggro );
a3->hateListAdd( pPlayer, 1 );
a4->hateListAdd( pPlayer, 1 );
a5->hateListAdd( pPlayer, 1 );
a6->hateListAdd( pPlayer, 1 );
instance.setDirectorVar( Variables::SET_2_SPAWNED, true );
}
if( !successCalled && instance.getCountEnemyBNpc() == 0 )
{
instance.setDirectorVar( Variables::SUCCESS_CALLED, true );
instance.success();
}
}
void onEnterTerritory( QuestBattle& instance, Entity::Player& player, uint32_t eventId, uint16_t param1,
uint16_t param2 ) override
{
eventMgr().playScene( player, instance.getDirectorId(), 1,
NO_DEFAULT_CAMERA | CONDITION_CUTSCENE | SILENT_ENTER_TERRI_ENV |
HIDE_HOTBAR | SILENT_ENTER_TERRI_BGM | SILENT_ENTER_TERRI_SE |
DISABLE_STEALTH | 0x00100000 | LOCK_HUD | LOCK_HOTBAR |
// todo: wtf is 0x00100000
DISABLE_CANCEL_EMOTE, [ & ]( Entity::Player& player, const Event::SceneResult& result )
{
player.setOnEnterEventDone( true );
} );
}
void onDutyComplete( QuestBattle& instance, Entity::Player& player ) override
{
auto idx = player.getQuestIndex( instance.getQuestId() );
if( idx == -1 )
return;
auto& quest = player.getQuestByIndex( idx );
quest.setSeq( 2 );
}
void onDutyCommence( QuestBattle& instance, Entity::Player& player ) override
{
auto boss = instance.createBNpcFromLayoutId( INIT_POP_BOSS, 2000, Common::BNpcType::Enemy );
auto ysthola = instance.createBNpcFromLayoutId( INIT_P_POP_01, 27780, Common::BNpcType::Friendly );
boss->setFlag( Entity::NoDeaggro );
ysthola->setFlag( Entity::NoDeaggro );
boss->hateListAdd( ysthola, 10000 );
boss->hateListAdd( player.getAsPlayer(), 1 );
ysthola->hateListAdd( boss, 10000 );
}
};

View file

@ -36,7 +36,7 @@ private:
// Entities found in the script data of the quest
static constexpr auto Actor0 = 1003988;
static constexpr auto Actor1 = 1002279;
static constexpr auto Actor2 = 1003908;
static constexpr auto Actor2 = 1003908;
static constexpr auto Actor20 = 1001637;
static constexpr auto Actor3 = 1001353;
static constexpr auto Aetheryte0 = 9;
@ -53,17 +53,21 @@ private:
static constexpr auto Poprange0 = 4110794;
static constexpr auto Reward0 = 1;
static constexpr auto Screenimage0 = 14;
static constexpr auto Seq0Actor0Lq = 50;
static constexpr auto Territorytype0 = 130;
public:
ManWil004() : Sapphire::ScriptAPI::QuestScript( 66106 )
{
};
static constexpr auto SEQ_0_ACTOR0 = 0;
static constexpr auto SEQ_1_ACTOR1 = 1;
static constexpr auto SEQ_1_ACTOR2 = 2;
static constexpr auto SEQ_1_ACTOR3 = 3;
static constexpr auto SEQ_1_ACTOR4 = 4;
static constexpr auto SEQ_1_ACTOR5 = 5;
static constexpr auto SEQ_1_ACTOR8 = 8;
static constexpr auto SEQ_0_ACTOR0_LQ = 50;
~ManWil004()
{
};
public:
ManWil004() : Sapphire::ScriptAPI::QuestScript( 66106 ){};
~ManWil004(){};
void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
{
@ -85,21 +89,22 @@ public:
}
else if( actorId == Aetheryte0 )
{
eventMgr().eventActionStart( player, 0x050002, 0x13,
[ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional )
{
eventMgr().sendEventNotice( player, 0x050002, 0, 1, 0, 0 );
player.registerAetheryte( 2 );
player.setRewardFlag( Common::UnlockEntry::Return );
Scene00001( player );
},
nullptr, getId() );
eventMgr().eventActionStart(
player, 0x050002, 0x13,
[ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) {
eventMgr().sendEventNotice( player, 0x050002, 0, 1, 0, 0 );
player.registerAetheryte( 2 );
player.setRewardFlag( Common::UnlockEntry::Return );
Scene00051( quest, player );
},
nullptr, getId() );
}
}
private:
void checkQuestCompletion( Entity::Player& player, uint32_t varIdx )
//varIdx refers to the noticeId
void checkQuestCompletion( World::Quest& quest, Entity::Player& player, uint32_t varIdx )
{
if( varIdx == 1 )
{
@ -114,141 +119,121 @@ private:
eventMgr().sendEventNotice( player, getId(), 0, 0, 0, 0 );
}
auto pQuest = player.getQuest( getId() );
if( !pQuest )
return;
auto QUEST_VAR_ATTUNE = pQuest->getUI8AL();
auto QUEST_VAR_CLASS = pQuest->getUI8BH();
auto QUEST_VAR_TRADE = pQuest->getUI8BL();
auto var_attuned = quest.getUI8AL();
auto var_class = quest.getUI8BH();
auto var_trade = quest.getUI8BL();
if( QUEST_VAR_ATTUNE == 1 && QUEST_VAR_CLASS == 1 && QUEST_VAR_TRADE == 1 )
if( var_attuned == 1 && var_class == 1 && var_trade == 1 )
{
pQuest->setSeq( SeqFinish );
quest.setSeq( SeqFinish );
}
}
void Scene00000( Entity::Player& player )
{
eventMgr().playScene( player, getId(), 0, HIDE_HOTBAR,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 ) // accept quest
{
Scene00050( player );
}
} );
eventMgr().playQuestScene( player, getId(), SEQ_0_ACTOR0, HIDE_HOTBAR, bindSceneReturn( &ManWil004::Scene00000Return ) );
}
void Scene00001( Entity::Player& player )
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().playScene( player, getId(), 1, HIDE_HOTBAR,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
Scene00002( player );
} );
if( result.getResult( 0 ) == 1 )// accept quest
Scene00050( player );
}
void Scene00001( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), SEQ_1_ACTOR1, 0x0EFB, bindSceneReturn( &ManWil004::Scene00001Return ) );
}
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
Scene00002( player );
}
void Scene00051( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestSceneChain( player, getId(), 51, NONE, bindQuestScene( &ManWil004::Scene00001 ) );
}
void Scene00002( Entity::Player& player )
{
eventMgr().playScene( player, getId(), 2, SET_EOBJ_BASE | HIDE_HOTBAR | INVIS_EOBJ,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
auto pQuest = player.getQuest( getId() );
if( !pQuest )
return;
eventMgr().playQuestScene( player, getId(), SEQ_1_ACTOR2, NONE, bindSceneReturn( &ManWil004::Scene00002Return ) );
}
pQuest->setUI8BL( 1 );
checkQuestCompletion( player, 0 );
} );
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setUI8BL( 1 );
checkQuestCompletion( quest, player, 0 );
}
void Scene00003( Entity::Player& player )
{
eventMgr().playScene( player, getId(), 3, HIDE_HOTBAR,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
auto pQuest = player.getQuest( getId() );
if( !pQuest )
return;
eventMgr().playQuestScene( player, getId(), SEQ_1_ACTOR3, HIDE_HOTBAR, bindSceneReturn( &ManWil004::Scene00003Return ) );
}
pQuest->setUI8AL( 1 );
checkQuestCompletion( player, 1 );
} );
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setUI8AL( 1 );
checkQuestCompletion( quest, player, 1 );
}
void Scene00004( Entity::Player& player )
{
eventMgr().playScene( player, getId(), 4, HIDE_HOTBAR,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
{
Scene00005( player );
}
else
return;
} );
eventMgr().playQuestScene( player, getId(), SEQ_1_ACTOR4, HIDE_HOTBAR, bindSceneReturn( &ManWil004::Scene00004Return ) );
}
void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
{
Scene00005( player );
}
else
{
return;
}
}
void Scene00005( Entity::Player& player )
{
eventMgr().playScene( player, getId(), 5, SET_EOBJ_BASE | HIDE_HOTBAR | INVIS_EOBJ,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
auto pQuest = player.getQuest( getId() );
if( !pQuest )
return;
pQuest->setUI8CH( 0 );
pQuest->setUI8BH( 1 );
checkQuestCompletion( player, 2 );
} );
eventMgr().playQuestScene( player, getId(), SEQ_1_ACTOR5, SET_EOBJ_BASE | HIDE_HOTBAR | INVIS_EOBJ, bindSceneReturn( &ManWil004::Scene00005Return ) );
}
void Scene00006( Entity::Player& player )
void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().playScene( player, getId(), 6, HIDE_HOTBAR,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
} );
}
void Scene00007( Entity::Player& player )
{
eventMgr().playScene( player, getId(), 7, HIDE_HOTBAR,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
} );
quest.setUI8CH( 0 );
quest.setUI8BH( 1 );
checkQuestCompletion( quest, player, 2 );
}
void Scene00008( Entity::Player& player )
{
eventMgr().playScene( player, getId(), 8, SET_EOBJ_BASE | HIDE_HOTBAR | INVIS_EOBJ,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
{
player.finishQuest( getId(), result.getResult( 1 ) );
}
} );
eventMgr().playQuestScene( player, getId(), SEQ_1_ACTOR8, SET_EOBJ_BASE | HIDE_HOTBAR | INVIS_EOBJ, bindSceneReturn( &ManWil004::Scene00008Return ) );
}
void Scene00008Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
{
player.finishQuest( getId(), result.getResult( 1 ) );
}
}
void Scene00050( Entity::Player& player )
{
eventMgr().playScene( player, getId(), 50, FADE_OUT | CONDITION_CUTSCENE | HIDE_UI,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
auto pQuest = player.getQuest( getId() );
if( !pQuest )
return;
// on quest accept
pQuest->setSeq( Seq1 );
pQuest->setUI8CH( 1 ); // receive key item
eventMgr().playQuestScene( player, getId(), SEQ_0_ACTOR0_LQ, FADE_OUT | CONDITION_CUTSCENE | HIDE_UI, bindSceneReturn( &ManWil004::Scene00050Return ) );
}
// teleport to real ul'dah
player.forceZoneing( 130 );
} );
void Scene00050Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
// on quest accept
quest.setSeq( Seq1 );
quest.setUI8CH( 1 );// receive key item
// teleport to real Uldah
player.forceZoneing( Territorytype0 );
}
};

View file

@ -122,8 +122,7 @@ public:
void onPlayerDeath( World::Quest& quest, Sapphire::Entity::Player& player ) override
{
auto& teriMgr = Common::Service< Sapphire::World::Manager::TerritoryMgr >::ref();
auto& instance = teriMgr.getTerritoryByGuId( player.getTerritoryId() );
auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() );
auto enem0 = instance->getActiveBNpcByLayoutIdAndTriggerOwner( Enemy0, player.getId() );
auto enem1 = instance->getActiveBNpcByLayoutIdAndTriggerOwner( Enemy1, player.getId() );
@ -175,8 +174,7 @@ private:
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
auto& teriMgr = Common::Service< Sapphire::World::Manager::TerritoryMgr >::ref();
auto& instance = teriMgr.getTerritoryByGuId( player.getTerritoryId() );
auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() );
bool enemy0Spawned = instance->getActiveBNpcByLayoutIdAndTriggerOwner( Enemy0, player.getId() ) != nullptr;
bool enemy1Spawned = instance->getActiveBNpcByLayoutIdAndTriggerOwner( Enemy1, player.getId() ) != nullptr;
@ -222,7 +220,7 @@ private:
void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().sendEventNotice( player, getId(), 0, 0 );
//TODO: Show the "Your communion has furthered your potentional as a white mage." message. Is it that logmessage0 var?
playerMgr().sendLogMessage( player, Logmessage0 );
quest.setSeq( SeqFinish );
}

View file

@ -215,7 +215,7 @@ private:
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().sendEventNotice( player, getId(), 0, 0 );//TODO:Item Icon, Cleric's Gloves
//TODO: Show "Your Garb is not blessed with the power of A-Towa-Cant." message (Logmessage0?)
playerMgr().sendLogMessage( player, Logmessage0 );
quest.setUI8AL( 1 );
quest.setUI8CH( 0 );
checkQuestCompletion( quest, player );
@ -242,7 +242,7 @@ private:
void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().sendEventNotice( player, getId(), 1, 0 );//TODO:Item Icon, Cleric's Culottes
//TODO: Show "Your Garb is not blessed with the power of A-Towa-Cant." message (Logmessage0?)
playerMgr().sendLogMessage( player, Logmessage0 );
quest.setUI8BH( 1 );
quest.setUI8CL( 0 );
checkQuestCompletion( quest, player );
@ -269,7 +269,7 @@ private:
void Scene00007Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().sendEventNotice( player, getId(), 2, 0 );//TODO:Item Icon, Cleric's Boots
//TODO: Show "Your Garb is not blessed with the power of A-Towa-Cant." message (Logmessage0?)
playerMgr().sendLogMessage( player, Logmessage0 );
quest.setUI8BL( 1 );
quest.setUI8DH( 0 );
checkQuestCompletion( quest, player );
@ -437,7 +437,7 @@ private:
void Scene00021Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().sendEventNotice( player, getId(), 6, 0 );//TODO:Item Icon, Cleric's Circlet
//TODO: Show "Your Garb is not blessed with the power of A-Towa-Cant." message (Logmessage0?)
playerMgr().sendLogMessage( player, Logmessage0 );
quest.setSeq( SeqFinish );
quest.setUI8BH( 0 );
}

View file

@ -0,0 +1,681 @@
// This is an automatically generated C++ script template
// Content needs to be added by hand to make it function
// In order for this script to be loaded, move it to the correct folder in <root>/scripts/
#include "Manager/EventMgr.h"
#include <Actor/Player.h>
#include <ScriptObject.h>
#include <Service.h>
// Quest Script: BanIxa001_01486
// Quest Name: A Bad Bladder
// Quest ID: 67022
// Start NPC: 1009294
// End NPC: 1009199
using namespace Sapphire;
class BanIxa001 : public Sapphire::ScriptAPI::QuestScript
{
private:
// Basic quest information
// Quest vars / flags used
// BitFlag8
// UI8AL
// UI8BH
/// Countable Num: 1 Seq: 1 Event: 1 Listener: 1000612
/// Countable Num: 1 Seq: 2 Event: 1 Listener: 1009294
/// Countable Num: 1 Seq: 3 Event: 1 Listener: 2004442
/// Countable Num: 1 Seq: 4 Event: 1 Listener: 2004519
/// Countable Num: 1 Seq: 255 Event: 1 Listener: 2004520
// 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,
Seq3 = 3,
Seq4 = 4,
SeqFinish = 255,
};
// Entities found in the script data of the quest
static constexpr auto Actor0 = 1009294;//Scarlet <<Serpet Lieutenant>>
static constexpr auto Actor1 = 1000612;//Guithrit
static constexpr auto Actor2 = 1009199;
static constexpr auto Eobject0 = 2004442;//War Balloon Debris
static constexpr auto Eobject1 = 2004519;
static constexpr auto Eobject2 = 2004520;
static constexpr auto Eobject3 = 2004521;
static constexpr auto Eobject4 = 2004443;//Izal Storage Pot
static constexpr auto Eobject5 = 2004444;
static constexpr auto EventActionProcessUpperMiddle = 32;
static constexpr auto EventActionSearch = 1;
static constexpr auto EventActionSearchMiddle = 3;
static constexpr auto Item0 = 2001363;
static constexpr auto LocActor0 = 1009592;
static constexpr auto LocActor1 = 1009593;
static constexpr auto LocBgm1 = 78;
static constexpr auto LocPosActor0 = 4892133;
static constexpr auto MotEventActTalk = 972;
static constexpr auto MotEventCatfight = 970;
static constexpr auto MotEventDirection = 971;
static constexpr auto MotEventJoy = 953;
public:
BanIxa001() : Sapphire::ScriptAPI::QuestScript( 67022 ){};
~BanIxa001() = default;
//////////////////////////////////////////////////////////////////////
// Event Handlers
void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
{
switch( actorId )
{
case Actor0:
{
if( quest.getSeq() == Seq0 )
Scene00000( quest, player );
else if( quest.getSeq() == Seq1 )
Scene00003( quest, player );
else if( quest.getSeq() == Seq2 )
Scene00012( quest, player );
else if( quest.getSeq() == Seq3 )
Scene00016( quest, player );
else if( quest.getSeq() == Seq4 )
Scene00025( quest, player );
else if( quest.getSeq() == SeqFinish )
Scene00037( quest, player );
break;
}
case Actor1:
{
if( quest.getSeq() == Seq1 )
Scene00002( quest, player );
else if( quest.getSeq() == Seq2 )
Scene00013( quest, player );
else if( quest.getSeq() == Seq3 )
Scene00014( quest, player );
else if( quest.getSeq() == Seq4 )
Scene00026( quest, player );
else if( quest.getSeq() == SeqFinish )
Scene00038( quest, player );
break;
}
case Actor2:
{
if( quest.getSeq() == SeqFinish )
Scene00035( quest, player );
break;
}
case Eobject0:
{
eventMgr().eventActionStart(
player, getId(), EventActionSearchMiddle,
[ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) {
Scene00005( quest, player );
},
nullptr, 0 );
break;
}
case Eobject4:
{
eventMgr().eventActionStart(
player, getId(), EventActionProcessUpperMiddle,
[ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) {
Scene00024( quest, player );
},
nullptr, 0 );
break;
}
}
}
private:
//////////////////////////////////////////////////////////////////////
// Available Scenes in this quest, not necessarly all are used
//////////////////////////////////////////////////////////////////////
void Scene00000( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 0, NONE, bindSceneReturn( &BanIxa001::Scene00000Return ) );
}
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )// accept quest
{
Scene00001( quest, player );
}
}
//////////////////////////////////////////////////////////////////////
void Scene00001( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00001Return ) );
}
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setSeq( Seq1 );
}
//////////////////////////////////////////////////////////////////////
void Scene00002( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00002Return ) );
}
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().sendEventNotice( player, getId(), 0, 0 );
quest.setSeq( Seq2 );
}
//////////////////////////////////////////////////////////////////////
void Scene00003( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 3, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00003Return ) );
}
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00004( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 4, NONE, bindSceneReturn( &BanIxa001::Scene00004Return ) );
}
void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00005( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 5, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00005Return ) );
}
void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setUI8BH( 1 );
eventMgr().sendEventNotice( player, getId(), 1, 0 );
quest.setSeq( Seq3 );
}
//////////////////////////////////////////////////////////////////////
void Scene00006( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 6, NONE, bindSceneReturn( &BanIxa001::Scene00006Return ) );
}
void Scene00006Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00007( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 7, NONE, bindSceneReturn( &BanIxa001::Scene00007Return ) );
}
void Scene00007Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00008( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 8, NONE, bindSceneReturn( &BanIxa001::Scene00008Return ) );
}
void Scene00008Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00009( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 9, NONE, bindSceneReturn( &BanIxa001::Scene00009Return ) );
}
void Scene00009Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00010( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 10, NONE, bindSceneReturn( &BanIxa001::Scene00010Return ) );
}
void Scene00010Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00011( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 11, NONE, bindSceneReturn( &BanIxa001::Scene00011Return ) );
}
void Scene00011Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00012( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 12, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00012Return ) );
}
void Scene00012Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00013( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 13, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00013Return ) );
}
void Scene00013Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00014( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 14, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00014Return ) );
}
void Scene00014Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
Scene00015( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00015( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 15, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00015Return ) );
}
void Scene00015Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().sendEventNotice( player, getId(), 2, 0 );
quest.setSeq( Seq4 );
}
//////////////////////////////////////////////////////////////////////
void Scene00016( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 16, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00016Return ) );
}
void Scene00016Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00017( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 17, NONE, bindSceneReturn( &BanIxa001::Scene00017Return ) );
}
void Scene00017Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00018( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 18, NONE, bindSceneReturn( &BanIxa001::Scene00018Return ) );
}
void Scene00018Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00019( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 19, NONE, bindSceneReturn( &BanIxa001::Scene00019Return ) );
}
void Scene00019Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00020( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 20, NONE, bindSceneReturn( &BanIxa001::Scene00020Return ) );
}
void Scene00020Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00021( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 21, NONE, bindSceneReturn( &BanIxa001::Scene00021Return ) );
}
void Scene00021Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00022( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 22, NONE, bindSceneReturn( &BanIxa001::Scene00022Return ) );
}
void Scene00022Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00023( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 23, NONE, bindSceneReturn( &BanIxa001::Scene00023Return ) );
}
void Scene00023Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00024( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 24, FADE_OUT | CONDITION_CUTSCENE | HIDE_UI, bindSceneReturn( &BanIxa001::Scene00024Return ) );
}
void Scene00024Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().sendEventNotice( player, getId(), 3, 0 );
quest.setSeq( SeqFinish );
}
//////////////////////////////////////////////////////////////////////
void Scene00025( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 25, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00025Return ) );
}
void Scene00025Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00026( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 26, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00026Return ) );
}
void Scene00026Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00027( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 27, NONE, bindSceneReturn( &BanIxa001::Scene00027Return ) );
}
void Scene00027Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00028( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 28, NONE, bindSceneReturn( &BanIxa001::Scene00028Return ) );
}
void Scene00028Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00029( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 29, NONE, bindSceneReturn( &BanIxa001::Scene00029Return ) );
}
void Scene00029Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00030( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 30, NONE, bindSceneReturn( &BanIxa001::Scene00030Return ) );
}
void Scene00030Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00031( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 31, NONE, bindSceneReturn( &BanIxa001::Scene00031Return ) );
}
void Scene00031Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00032( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 32, NONE, bindSceneReturn( &BanIxa001::Scene00032Return ) );
}
void Scene00032Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00033( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 33, NONE, bindSceneReturn( &BanIxa001::Scene00033Return ) );
}
void Scene00033Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00034( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 34, NONE, bindSceneReturn( &BanIxa001::Scene00034Return ) );
}
void Scene00034Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00035( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 35, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00035Return ) );
}
void Scene00035Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
Scene00036( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00036( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 36, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00036Return ) );
}
void Scene00036Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
{
player.finishQuest( getId() );
}
}
//////////////////////////////////////////////////////////////////////
void Scene00037( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 37, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00037Return ) );
}
void Scene00037Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00038( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 38, HIDE_HOTBAR, bindSceneReturn( &BanIxa001::Scene00038Return ) );
}
void Scene00038Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00039( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 39, NONE, bindSceneReturn( &BanIxa001::Scene00039Return ) );
}
void Scene00039Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00040( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 40, NONE, bindSceneReturn( &BanIxa001::Scene00040Return ) );
}
void Scene00040Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00041( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 41, NONE, bindSceneReturn( &BanIxa001::Scene00041Return ) );
}
void Scene00041Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00042( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 42, NONE, bindSceneReturn( &BanIxa001::Scene00042Return ) );
}
void Scene00042Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00043( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 43, NONE, bindSceneReturn( &BanIxa001::Scene00043Return ) );
}
void Scene00043Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00044( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 44, NONE, bindSceneReturn( &BanIxa001::Scene00044Return ) );
}
void Scene00044Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00045( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 45, NONE, bindSceneReturn( &BanIxa001::Scene00045Return ) );
}
void Scene00045Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00046( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 46, NONE, bindSceneReturn( &BanIxa001::Scene00046Return ) );
}
void Scene00046Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
};
EXPOSE_SCRIPT( BanIxa001 );

View file

@ -0,0 +1,162 @@
// This is an automatically generated C++ script template
// Content needs to be added by hand to make it function
// In order for this script to be loaded, move it to the correct folder in <root>/scripts/
#include "Manager/EventMgr.h"
#include <Actor/Player.h>
#include <ScriptObject.h>
#include <Service.h>
// Quest Script: BanSyl001_01252
// Quest Name: Seeking Solace
// Quest ID: 66788
// Start NPC: 1000168
// End NPC: 1005564
using namespace Sapphire;
class BanSyl001 : public Sapphire::ScriptAPI::QuestScript
{
private:
// Basic quest information
// Quest vars / flags used
// UI8AL
/// Countable Num: 0 Seq: 1 Event: 1 Listener: 1005564
/// Countable Num: 0 Seq: 2 Event: 1 Listener: 1005577
/// Countable Num: 0 Seq: 255 Event: 1 Listener: 1005564
// 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,
};
// Entities found in the script data of the quest
static constexpr auto Actor0 = 1000168;//Vorsaile Heuloix <<Serpent Commander>>
static constexpr auto Actor1 = 1005564;//Olmxio
static constexpr auto Actor2 = 1005577;//Frixio
static constexpr auto MotEventJoy = 953;
public:
BanSyl001() : Sapphire::ScriptAPI::QuestScript( 66788 ){};
~BanSyl001() = default;
//////////////////////////////////////////////////////////////////////
// Event Handlers
void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
{
switch( actorId )
{
case Actor0:
{
if( quest.getSeq() == Seq0 )
Scene00000( quest, player );
break;
}
case Actor1:
{
if( quest.getSeq() == Seq1 )
Scene00002( quest, player );
else if( quest.getSeq() == SeqFinish )
Scene00004( quest, player );
break;
}
case Actor2:
{
if( quest.getSeq() == Seq2 )
Scene00003( quest, player );
else if( quest.getSeq() == SeqFinish )
Scene00005( quest, player );
break;
}
}
}
private:
//////////////////////////////////////////////////////////////////////
// Available Scenes in this quest, not necessarly all are used
//////////////////////////////////////////////////////////////////////
void Scene00000( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 0, HIDE_HOTBAR, bindSceneReturn( &BanSyl001::Scene00000Return ) );
}
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )// accept quest
Scene00001( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00001( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &BanSyl001::Scene00001Return ) );
}
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setSeq( Seq1 );
}
//////////////////////////////////////////////////////////////////////
void Scene00002( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &BanSyl001::Scene00002Return ) );
}
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().sendEventNotice( player, getId(), 0, 0 );
quest.setSeq( Seq2 );
}
//////////////////////////////////////////////////////////////////////
void Scene00003( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 3, HIDE_HOTBAR, bindSceneReturn( &BanSyl001::Scene00003Return ) );
}
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().sendEventNotice( player, getId(), 1, 0 );
quest.setSeq( SeqFinish );
}
//////////////////////////////////////////////////////////////////////
void Scene00004( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 4, HIDE_HOTBAR, bindSceneReturn( &BanSyl001::Scene00004Return ) );
}
void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
{
player.finishQuest( getId() );
}
}
//////////////////////////////////////////////////////////////////////
void Scene00005( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 5, HIDE_HOTBAR, bindSceneReturn( &BanSyl001::Scene00005Return ) );
}
void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
};
EXPOSE_SCRIPT( BanSyl001 );

View file

@ -0,0 +1,128 @@
// This is an automatically generated C++ script template
// Content needs to be added by hand to make it function
// In order for this script to be loaded, move it to the correct folder in <root>/scripts/
#include "Manager/EventMgr.h"
#include <Actor/Player.h>
#include <ScriptObject.h>
#include <Service.h>
// Quest Script: GaiUsa907_00802
// Quest Name: Broadening Horizons
// Quest ID: 66338
// Start NPC: 1006259
// End NPC: 1000171
using namespace Sapphire;
class GaiUsa907 : public Sapphire::ScriptAPI::QuestScript
{
private:
// Basic quest information
// Quest vars / flags used
// UI8AL
// UI8BH
/// Countable Num: 0 Seq: 255 Event: 1 Listener: 1000171
// Steps in this quest ( 0 is before accepting,
// 1 is first, 255 means ready for turning it in
enum Sequence : uint8_t
{
Seq0 = 0,
SeqFinish = 255,
};
// Entities found in the script data of the quest
static constexpr auto Actor0 = 1006259;//Tyoh Moui
static constexpr auto Actor1 = 1000171;//Franchemontiaux <<Gatekeep>>
static constexpr auto Item0 = 2000791;
public:
GaiUsa907() : Sapphire::ScriptAPI::QuestScript( 66338 ){};
~GaiUsa907() = default;
//////////////////////////////////////////////////////////////////////
// Event Handlers
void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
{
switch( actorId )
{
case Actor0:
{
if( quest.getSeq() == Seq0 )
Scene00000( quest, player );
break;
}
case Actor1:
{
if( quest.getSeq() == SeqFinish )
Scene00002( quest, player );
break;
}
}
}
private:
//////////////////////////////////////////////////////////////////////
// Available Scenes in this quest, not necessarly all are used
//////////////////////////////////////////////////////////////////////
void Scene00000( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 0, NONE, bindSceneReturn( &GaiUsa907::Scene00000Return ) );
}
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )// accept quest
{
Scene00001( quest, player );
}
}
//////////////////////////////////////////////////////////////////////
void Scene00001( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 1, NONE, bindSceneReturn( &GaiUsa907::Scene00001Return ) );
}
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setSeq( SeqFinish );
quest.setUI8BH( 1 );
}
//////////////////////////////////////////////////////////////////////
void Scene00002( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 2, NONE, bindSceneReturn( &GaiUsa907::Scene00002Return ) );
}
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
Scene00003( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00003( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &GaiUsa907::Scene00003Return ) );
}
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
{
player.registerAetheryte(54);
player.finishQuest( getId() );
}
}
};
EXPOSE_SCRIPT( GaiUsa907 );

View file

@ -0,0 +1,293 @@
// This is an automatically generated C++ script template
// Content needs to be added by hand to make it function
// In order for this script to be loaded, move it to the correct folder in <root>/scripts/
#include "Manager/EventMgr.h"
#include <Actor/Player.h>
#include <ScriptObject.h>
#include <Service.h>
#include "Actor/BNpc.h"
#include "Manager/TerritoryMgr.h"
#include "Territory/Territory.h"
// Quest Script: GaiUsa908_00803
// Quest Name: Beneath the Planks
// Quest ID: 66339
// Start NPC: 1006694
// End NPC: 1006260
using namespace Sapphire;
class GaiUsa908 : public Sapphire::ScriptAPI::QuestScript
{
private:
// Basic quest information
// Quest vars / flags used
// BitFlag8
// UI8AH
// UI8AL
// UI8BH
// UI8BL
/// Countable Num: 0 Seq: 1 Event: 1 Listener: 1006260
/// Countable Num: 0 Seq: 2 Event: 1 Listener: 2002000
/// Countable Num: 0 Seq: 255 Event: 1 Listener: 2002001
// 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,
};
// Entities found in the script data of the quest
static constexpr auto Actor0 = 1006694;//ROUSTEBANT
static constexpr auto Actor1 = 1006260;//Thievenaix
static constexpr auto Enemy0 = 4287003;
static constexpr auto Eobject0 = 2002000;//Damp Scaffolding
static constexpr auto Eobject1 = 2002001;//Damp Scaffolding
static constexpr auto Eobject2 = 2002002;//Damp Scaffolding
static constexpr auto EventActionSearch = 1;
public:
GaiUsa908() : Sapphire::ScriptAPI::QuestScript( 66339 ){};
~GaiUsa908() = default;
//////////////////////////////////////////////////////////////////////
// Event Handlers
void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
{
switch( actorId )
{
case Actor0:
{
if( quest.getSeq() == Seq0 )
Scene00000( quest, player );
break;
}
case Actor1:
{
if( quest.getSeq() == Seq1 )
Scene00002( quest, player );
else if( quest.getSeq() == SeqFinish )
Scene00009( quest, player );
break;
}
case Eobject0:
{
eventMgr().eventActionStart(
player, getId(), EventActionSearch,
[ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) {
Scene00004( quest, player );
},
nullptr, 0 );
break;
}
case Eobject1:
{
eventMgr().eventActionStart(
player, getId(), EventActionSearch,
[ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) {
Scene00006( quest, player );
},
nullptr, 0 );
break;
}
case Eobject2:
{
eventMgr().eventActionStart(
player, getId(), EventActionSearch,
[ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) {
Scene00008( quest, player );
},
nullptr, 0 );
break;
}
}
}
void onBNpcKill( World::Quest& quest, Sapphire::Entity::BNpc& bnpc, Sapphire::Entity::Player& player ) override
{
switch( bnpc.getLayoutId() )
{
case Enemy0:
{
quest.setUI8AH( quest.getUI8AH() + 1 );
quest.setUI8BL( 1 );
eventMgr().sendEventNotice( player, getId(), 1, 2, quest.getUI8AH(), 3 );
checkQuestCompletion( quest, player );
break;
}
}
}
void onPlayerDeath( World::Quest& quest, Sapphire::Entity::Player& player ) override
{
auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() );
auto enem0 = instance->getActiveBNpcByLayoutIdAndTriggerOwner( Enemy0, player.getId() );
if( enem0 != nullptr ) instance->removeActor( enem0 );
quest.setBitFlag8( 3, false );
}
private:
void checkQuestCompletion( World::Quest& quest, Entity::Player& player )
{
if( quest.getUI8AH() >= 3 )
{
quest.setUI8AH( 0 );
quest.setUI8AL( 0 );
quest.setUI8BH( 0 );
quest.setUI8BL( 0 );
quest.setBitFlag8( 1, false );
quest.setBitFlag8( 2, false );
quest.setBitFlag8( 3, false );
quest.setSeq( SeqFinish );
}
}
//////////////////////////////////////////////////////////////////////
// Available Scenes in this quest, not necessarly all are used
//////////////////////////////////////////////////////////////////////
void Scene00000( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 0, NONE, bindSceneReturn( &GaiUsa908::Scene00000Return ) );
}
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )// accept quest
{
Scene00001( quest, player );
}
}
//////////////////////////////////////////////////////////////////////
void Scene00001( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &GaiUsa908::Scene00001Return ) );
}
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setSeq( Seq1 );
}
//////////////////////////////////////////////////////////////////////
void Scene00002( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &GaiUsa908::Scene00002Return ) );
}
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().sendEventNotice( player, getId(), 0, 0 );
quest.setSeq( Seq2 );
}
//////////////////////////////////////////////////////////////////////
void Scene00003( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &GaiUsa908::Scene00003Return ) );
}
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00004( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 4, NONE, bindSceneReturn( &GaiUsa908::Scene00004Return ) );
}
void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setUI8AH( quest.getUI8AH() + 1 );
quest.setUI8AL( 1 );
quest.setBitFlag8( 1, true );
eventMgr().sendEventNotice( player, getId(), 1, 2, quest.getUI8AH(), 3 );
checkQuestCompletion( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00005( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 5, NONE, bindSceneReturn( &GaiUsa908::Scene00005Return ) );
}
void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00006( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 6, NONE, bindSceneReturn( &GaiUsa908::Scene00006Return ) );
}
void Scene00006Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setUI8AH( quest.getUI8AH() + 1 );
quest.setUI8BH( 1 );
quest.setBitFlag8( 2, true );
eventMgr().sendEventNotice( player, getId(), 1, 2, quest.getUI8AH(), 3 );
checkQuestCompletion( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00007( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 7, NONE, bindSceneReturn( &GaiUsa908::Scene00007Return ) );
}
void Scene00007Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00008( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 8, NONE, bindSceneReturn( &GaiUsa908::Scene00008Return ) );
}
void Scene00008Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() );
auto enemy = instance->createBNpcFromLayoutId( Enemy0, 1220 /*Find the right value*/, Common::BNpcType::Enemy, player.getId() );
enemy->hateListAddDelayed( player.getAsPlayer(), 1 );
quest.setBitFlag8( 3, true );
}
//////////////////////////////////////////////////////////////////////
void Scene00009( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 9, NONE, bindSceneReturn( &GaiUsa908::Scene00009Return ) );
}
void Scene00009Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
{
player.finishQuest( getId(), result.getResult( 1 ) );
}
}
};
EXPOSE_SCRIPT( GaiUsa908 );

View file

@ -0,0 +1,222 @@
// This is an automatically generated C++ script template
// Content needs to be added by hand to make it function
// In order for this script to be loaded, move it to the correct folder in <root>/scripts/
#include "Manager/EventMgr.h"
#include <Actor/Player.h>
#include <ScriptObject.h>
#include <Service.h>
// Quest Script: SubFst012_00038
// Quest Name: Parsemontrenomics
// Quest ID: 65574
// Start NPC: 1000768
// End NPC: 1000248
using namespace Sapphire;
class SubFst012 : public Sapphire::ScriptAPI::QuestScript
{
private:
// Basic quest information
// Quest vars / flags used
// BitFlag8
// UI8AL
// UI8BH
// UI8BL
// UI8CH
// UI8CL
// UI8DH
/// Countable Num: 1 Seq: 1 Event: 1 Listener: 1000214
/// Countable Num: 1 Seq: 1 Event: 1 Listener: 1000218
/// Countable Num: 1 Seq: 1 Event: 1 Listener: 1000238
/// Countable Num: 1 Seq: 255 Event: 1 Listener: 1000248
// 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,
SeqFinish = 255,
};
// Entities found in the script data of the quest
static constexpr auto Actor0 = 1000768;//Parsemontret
static constexpr auto Actor1 = 1000214;//Gurthcid
static constexpr auto Actor2 = 1000218;//Admiranda <<Tool Supplier>>
static constexpr auto Actor3 = 1000238;//Alaric <<Independent Tinker>>
static constexpr auto Actor4 = 1000248;//Ceinguled
static constexpr auto Item0 = 2000081;
static constexpr auto Item1 = 2000082;
static constexpr auto Item2 = 2000083;
static constexpr auto Seq0Actor0 = 0;
static constexpr auto Seq1Actor1 = 1;
static constexpr auto Seq1Actor2 = 2;
static constexpr auto Seq1Actor3 = 3;
static constexpr auto Seq2Actor4 = 4;
static constexpr auto Seq2Actor4Npctradeno = 99;
static constexpr auto Seq2Actor4Npctradeok = 100;
public:
SubFst012() : Sapphire::ScriptAPI::QuestScript( 65574 ){};
~SubFst012() = default;
//////////////////////////////////////////////////////////////////////
// Event Handlers
void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
{
switch( actorId )
{
case Actor0:
{
if( quest.getSeq() == Seq0 )
Scene00000( quest, player );
break;
}
case Actor1:
{
if( quest.getSeq() == Seq1 )
Scene00001( quest, player );
break;
}
case Actor2:
{
if( quest.getSeq() == Seq1 )
Scene00002( quest, player );
break;
}
case Actor3:
{
if( quest.getSeq() == Seq1 )
Scene00003( quest, player );
break;
}
case Actor4:
{
if( quest.getSeq() == SeqFinish )
Scene00004( quest, player );
break;
}
}
}
private:
void checkQuestCompletion( World::Quest& quest, Entity::Player& player )
{
if( quest.getUI8AL() && quest.getUI8BH() && quest.getUI8BL() )
{
quest.setSeq( SeqFinish );
quest.setUI8AL( 0 );
quest.setUI8BH( 1 );
quest.setUI8BL( 1 );
quest.setUI8CH( 1 );
quest.setUI8CL( 0 );
quest.setUI8DH( 0 );
}
}
//////////////////////////////////////////////////////////////////////
// Available Scenes in this quest, not necessarly all are used
//////////////////////////////////////////////////////////////////////
void Scene00000( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 0, HIDE_HOTBAR, bindSceneReturn( &SubFst012::Scene00000Return ) );
}
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )// accept quest
{
quest.setSeq( Seq1 );
}
}
//////////////////////////////////////////////////////////////////////
void Scene00001( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &SubFst012::Scene00001Return ) );
}
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setUI8AL( 1 );
quest.setUI8CH( 1 );
eventMgr().sendEventNotice( player, getId(), 0, 0 );
checkQuestCompletion( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00002( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &SubFst012::Scene00002Return ) );
}
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setUI8BH( 1 );
quest.setUI8CL( 1 );
eventMgr().sendEventNotice( player, getId(), 1, 0 );
checkQuestCompletion( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00003( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 3, HIDE_HOTBAR, bindSceneReturn( &SubFst012::Scene00003Return ) );
}
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setUI8BL( 1 );
quest.setUI8DH( 1 );
eventMgr().sendEventNotice( player, getId(), 2, 0 );
checkQuestCompletion( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00004( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 4, HIDE_HOTBAR, bindSceneReturn( &SubFst012::Scene00004Return ) );
}
void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
Scene00100( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00099( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 99, NONE, bindSceneReturn( &SubFst012::Scene00099Return ) );
}
void Scene00099Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00100( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 100, HIDE_HOTBAR, bindSceneReturn( &SubFst012::Scene00100Return ) );
}
void Scene00100Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
{
player.finishQuest( getId() );
}
}
};
EXPOSE_SCRIPT( SubFst012 );

View file

@ -0,0 +1,396 @@
// This is an automatically generated C++ script template
// Content needs to be added by hand to make it function
// In order for this script to be loaded, move it to the correct folder in <root>/scripts/
#include "Manager/EventMgr.h"
#include <Actor/Player.h>
#include <ScriptObject.h>
#include <Service.h>
// Quest Script: SubFst159_01425
// Quest Name: Saw That One Coming
// Quest ID: 66961
// Start NPC: 1000375
// End NPC: 1007792
using namespace Sapphire;
class SubFst159 : public Sapphire::ScriptAPI::QuestScript
{
private:
// Basic quest information
// Quest vars / flags used
// BitFlag8
// UI8AL
// UI8BH
/// Countable Num: 1 Seq: 1 Event: 1 Listener: 1007792
/// Countable Num: 1 Seq: 2 Event: 1 Listener: 1000153
/// Countable Num: 3 Seq: 3 Event: 1 Listener: 1007792
/// Countable Num: 1 Seq: 255 Event: 1 Listener: 1007793
// 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,
Seq3 = 3,
SeqFinish = 255,
};
// Entities found in the script data of the quest
static constexpr auto Actor0 = 1000375;//Eral
static constexpr auto Actor1 = 1007792;//Yedythe
static constexpr auto Actor2 = 1000153;//Beatine <<Guildmaster>>
static constexpr auto Actor3 = 1007793;//Bubbly Boy
static constexpr auto Actor4 = 1007794;//Gleeful Girl
static constexpr auto Actor5 = 1007795;//Bashful Boy
static constexpr auto Actor6 = 1007969;
static constexpr auto Actor7 = 1007970;
static constexpr auto Actor8 = 1007971;
static constexpr auto EventActionSearch = 1;
static constexpr auto Item0 = 2001249;
static constexpr auto LocActor0 = 1007990;
static constexpr auto LocActor1 = 1007991;
static constexpr auto LocActor2 = 1007992;
static constexpr auto LocActor3 = 1000153;
static constexpr auto LocBgm = 88;
static constexpr auto LocBgm2 = 87;
static constexpr auto LocFace0 = 604;
static constexpr auto LocFace1 = 605;
static constexpr auto LocFace2 = 614;
static constexpr auto LocMotion1 = 571;
static constexpr auto LocMotion2 = 572;
static constexpr auto LocPosActor0 = 4666289;
static constexpr auto LocPosActor1 = 4666740;
static constexpr auto Quest0 = 65741;
public:
SubFst159() : Sapphire::ScriptAPI::QuestScript( 66961 ){};
~SubFst159() = default;
//////////////////////////////////////////////////////////////////////
// Event Handlers
void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
{
switch( actorId )
{
case Actor0:
{
if( quest.getSeq() == Seq0 )
Scene00000( quest, player );
break;
}
case Actor1:
{
if( quest.getSeq() == Seq1 )
Scene00002( quest, player );
else if( quest.getSeq() == Seq2 )
Scene00004( quest, player );
else if( quest.getSeq() == Seq3 )
Scene00014( quest, player );
else if( quest.getSeq() == SeqFinish )
Scene00015( quest, player );
break;
}
case Actor2:
{
if( quest.getSeq() == Seq2 )
Scene00003( quest, player );
break;
}
case Actor3:
{
if( quest.getSeq() == Seq3 )
Scene00005( quest, player );
break;
}
case Actor4:
{
if( quest.getSeq() == Seq3 )
Scene00008( quest, player );
break;
}
case Actor5:
{
if( quest.getSeq() == Seq3 )
Scene00011( quest, player );
break;
}
case Actor6:
{
break;
}
case Actor7:
{
break;
}
case Actor8:
{
break;
}
}
}
private:
void checkQuestCompletion( World::Quest& quest, Entity::Player& player )
{
eventMgr().sendEventNotice( player, getId(), 2, 2, quest.getUI8AL(), 3 );
if( quest.getUI8AL() >= 3 )
{
quest.setUI8AL( 0 );
quest.setBitFlag8( 1, false );
quest.setBitFlag8( 2, false );
quest.setBitFlag8( 3, false );
quest.setSeq( SeqFinish );
}
}
//////////////////////////////////////////////////////////////////////
// Available Scenes in this quest, not necessarly all are used
//////////////////////////////////////////////////////////////////////
void Scene00000( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 0, HIDE_HOTBAR, bindSceneReturn( &SubFst159::Scene00000Return ) );
}
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )// accept quest
{
Scene00001( quest, player );
}
}
//////////////////////////////////////////////////////////////////////
void Scene00001( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &SubFst159::Scene00001Return ) );
}
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setSeq( Seq1 );
}
//////////////////////////////////////////////////////////////////////
void Scene00002( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &SubFst159::Scene00002Return ) );
}
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().sendEventNotice( player, getId(), 0, 0 );
quest.setSeq( Seq2 );
}
//////////////////////////////////////////////////////////////////////
void Scene00003( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 3, HIDE_HOTBAR, bindSceneReturn( &SubFst159::Scene00003Return ) );
}
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
eventMgr().sendEventNotice( player, getId(), 1, 0 );
quest.setSeq( Seq3 );
quest.setUI8BH( 3 );
}
//////////////////////////////////////////////////////////////////////
void Scene00004( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 4, HIDE_HOTBAR, bindSceneReturn( &SubFst159::Scene00004Return ) );
}
void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00005( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 5, HIDE_HOTBAR, bindSceneReturn( &SubFst159::Scene00005Return ) );
}
void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
Scene00006( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00006( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 6, HIDE_HOTBAR, bindSceneReturn( &SubFst159::Scene00006Return ) );
}
void Scene00006Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setUI8AL( quest.getUI8AL() + 1 );
quest.setUI8BH( quest.getUI8BH() - 1 );
quest.setBitFlag8( 1, true );
checkQuestCompletion( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00007( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 7, NONE, bindSceneReturn( &SubFst159::Scene00007Return ) );
}
void Scene00007Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00008( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 8, HIDE_HOTBAR, bindSceneReturn( &SubFst159::Scene00008Return ) );
}
void Scene00008Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
Scene00009( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00009( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 9, HIDE_HOTBAR, bindSceneReturn( &SubFst159::Scene00009Return ) );
}
void Scene00009Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setUI8AL( quest.getUI8AL() + 1 );
quest.setUI8BH( quest.getUI8BH() - 1 );
quest.setBitFlag8( 2, true );
checkQuestCompletion( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00010( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 10, NONE, bindSceneReturn( &SubFst159::Scene00010Return ) );
}
void Scene00010Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00011( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 11, HIDE_HOTBAR, bindSceneReturn( &SubFst159::Scene00011Return ) );
}
void Scene00011Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
Scene00012( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00012( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 12, HIDE_HOTBAR, bindSceneReturn( &SubFst159::Scene00012Return ) );
}
void Scene00012Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
quest.setUI8AL( quest.getUI8AL() + 1 );
quest.setUI8BH( quest.getUI8BH() - 1 );
quest.setBitFlag8( 3, true );
checkQuestCompletion( quest, player );
}
//////////////////////////////////////////////////////////////////////
void Scene00013( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 13, NONE, bindSceneReturn( &SubFst159::Scene00013Return ) );
}
void Scene00013Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00014( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 14, HIDE_HOTBAR, bindSceneReturn( &SubFst159::Scene00014Return ) );
}
void Scene00014Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00015( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 15, FADE_OUT | CONDITION_CUTSCENE | HIDE_UI, bindSceneReturn( &SubFst159::Scene00015Return ) );
}
void Scene00015Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
if( result.getResult( 0 ) == 1 )
{
player.setRewardFlag( Common::UnlockEntry::EmoteHarvestDance );
player.finishQuest( getId() );
}
}
//////////////////////////////////////////////////////////////////////
void Scene00016( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 16, NONE, bindSceneReturn( &SubFst159::Scene00016Return ) );
}
void Scene00016Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00017( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 17, NONE, bindSceneReturn( &SubFst159::Scene00017Return ) );
}
void Scene00017Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
//////////////////////////////////////////////////////////////////////
void Scene00018( World::Quest& quest, Entity::Player& player )
{
eventMgr().playQuestScene( player, getId(), 18, NONE, bindSceneReturn( &SubFst159::Scene00018Return ) );
}
void Scene00018Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
{
}
};
EXPOSE_SCRIPT( SubFst159 );

View file

@ -86,5 +86,5 @@ void ItemAction::handleMountItem()
auto player = getSourceChara()->getAsPlayer();
player->unlockMount( m_itemAction->data().Calcu0Arg[ 0 ] );
player->dropInventoryItem( static_cast< Common::InventoryType >( m_itemSourceContainer ), static_cast< uint8_t >( m_itemSourceSlot ) );
player->discardItem( m_itemSourceContainer, m_itemSourceSlot );
}

View file

@ -445,7 +445,7 @@ void Player::teleport( uint16_t aetheryteId, uint8_t type )
// if it is a teleport in the same zone, we want to do warp instead of moveTerri
bool sameTerritory = getTerritoryTypeId() == data.TerritoryType;
WarpType warpType;
WarpType warpType = WarpType::WARP_TYPE_NORMAL;
// TODO: this should be simplified and a type created in server_common/common.h.
if( type == 1 || type == 2 ) // teleport
{
@ -822,7 +822,7 @@ void Player::setLevelForClass( uint8_t level, Common::ClassJob classjob )
m_classArray[ classJobIndex ] = level;
queuePacket( makeActorControlSelf( getId(), Network::ActorControl::ClassJobUpdate, static_cast< uint8_t >( classjob ), level ) );
Service< World::Manager::PlayerMgr >::ref().onSetLevelForClass( *this, classjob );
}
void Player::sendModel()
@ -1313,6 +1313,16 @@ void Player::setTitle( uint16_t titleId )
sendToInRangeSet( makeActorControl( getId(), SetTitle, titleId ), true );
}
Player::AchievementList& Player::getAchievementList()
{
return m_achievementList;
}
Player::AchievementDataList& Player::getAchievementDataList()
{
return m_achievementData;
}
void Player::setMaxGearSets( uint8_t amount )
{
if( amount == 1 )
@ -1497,6 +1507,7 @@ void Player::sendZonePackets()
initPacket->data().playerActorId = getId();
queuePacket( initPacket );
sendStatusUpdate();
sendInventory();
if( isLogin() )

View file

@ -25,6 +25,8 @@ namespace Sapphire::Entity
class Player : public Chara
{
public:
using AchievementDataList = std::map< uint32_t, uint32_t >;
using AchievementList = std::array< uint8_t, 2048 / 8 >; // up to 2048 achievements
using TitleList = std::array< uint8_t, 48 >;
using HowToList = std::array< uint8_t, 34 >;
using MinionList = std::array< uint8_t, 40 >;
@ -365,7 +367,13 @@ namespace Sapphire::Entity
/*! send the players title list */
void sendTitleList();
/*! set number of gear sets */
/*! get player's achievement list */
AchievementList& getAchievementList();
/*! get player's achievement data list */
AchievementDataList& getAchievementDataList();
/*! set number of gear sets */
void setMaxGearSets( uint8_t amount );
/*! get number of gear sets */
@ -860,6 +868,8 @@ namespace Sapphire::Entity
uint8_t status;
} m_retainerInfo[8]{};
AchievementList m_achievementList{};
AchievementDataList m_achievementData{};
uint16_t m_activeTitle{};
TitleList m_titleList{};
HowToList m_howTo{};

View file

@ -0,0 +1,192 @@
#include <Exd/ExdData.h>
#include <Util/Util.h>
#include "AchievementMgr.h"
#include "PlayerMgr.h"
using namespace Sapphire;
using namespace Sapphire::Network;
using namespace Sapphire::Network::Packets;
using namespace Sapphire::World::Manager;
bool AchievementMgr::cacheAchievements()
{
auto& exdData = Common::Service< Data::ExdData >::ref();
auto idList = exdData.getIdList< Excel::Achievement >();
for( auto id : idList )
{
auto achvExdData = exdData.getRow< Excel::Achievement >( id );
uint32_t key = achvExdData->data().ConditionType;
auto achvType = static_cast< Common::Achievement::Type >( key );
if( achvType == Common::Achievement::Type::None )
continue;
// verify if achievement type has subtype
if( achvType == Common::Achievement::Type::General ||
achvType == Common::Achievement::Type::Classjob ||
achvType == Common::Achievement::Type::InstanceContent )
{
int32_t subtype = achvExdData->data().ConditionArg[ 0 ];
if( subtype != 0 )
key = ( getKeyFromType( achvType, subtype ) ).u32;
else
continue; // ignore key types with no subtype
}
// map achievement IDs to achv data
m_achievementKeyCacheMap[ key ].emplace_back( id );
// map achievement keys (either type or union key:subtype) to achievement IDs
m_achievementDetailCacheMap[ id ] = std::move( achvExdData );
}
return true;
}
void AchievementMgr::unlockAchievement( Entity::Player& player, uint32_t achievementId )
{
auto& exdData = Common::Service< Data::ExdData >::ref();
auto achvData = exdData.getRow< Excel::Achievement >( achievementId );
// set flag on mask format expected by client
uint16_t index;
uint8_t value;
Common::Util::valueToFlagByteIndexValue( achievementId, value, index );
player.getAchievementList()[ index ] |= value;
// fire packets
Common::Service< World::Manager::PlayerMgr >::ref().onUnlockAchievement( player, achievementId );
// check and add title to player
auto achvTitleId = achvData->data().Title;
if( achvTitleId != 0 )
{
player.addTitle( achvTitleId );
}
handleLinkedAchievementsForId( player, achievementId );
}
bool AchievementMgr::hasAchievementUnlocked( Entity::Player& player, uint32_t achievementId )
{
uint16_t index;
uint8_t value;
Common::Util::valueToFlagByteIndexValue( static_cast< uint16_t >( achievementId ), value, index );
return ( player.getAchievementList()[ index ] & value ) != 0;
}
std::pair< uint32_t, uint32_t > AchievementMgr::getAchievementDataById( Entity::Player& player, uint32_t achievementId )
{
auto& exdData = Common::Service< Data::ExdData >::ref();
auto& achvDataList = player.getAchievementDataList();
auto achvExdData = exdData.getRow< Excel::Achievement >( achievementId )->data();
auto achvType = static_cast< Common::Achievement::Type >( achvExdData.ConditionType );
// get paired type:subtype key for stored data
auto dataKey = getKeyFromType( achvType, achvExdData.ConditionArg[ 0 ] );
// get achievement progress data, if it exists (otherwise pass 0)
uint32_t currProg = 0;
if( achvDataList.count( dataKey.u32 ) )
currProg = achvDataList[ dataKey.u32 ];
// get maximum progress for given achievement, as required by client
uint32_t maxProg = static_cast< uint32_t >( achvExdData.ConditionArg[ 1 ] );
// cap maximum progress display to maximum progress
return { std::min( currProg, maxProg ), maxProg };
}
void AchievementMgr::handleLinkedAchievementsForId( Entity::Player& player, uint32_t achievementId )
{
auto& exdData = Common::Service< Data::ExdData >::ref();
const auto& linkedAchievementIdList = getAchievementIdByType( Common::Achievement::Type::LinkedAchievement );
for( auto& achvId : linkedAchievementIdList )
{
// skip if achievement already unlocked
if( hasAchievementUnlocked( player, achvId ) )
continue;
auto pAchv = getAchievementDetail( achvId );
if( !pAchv )
continue;
auto achvExdData = pAchv->data();
// if achievement has other achievements linked to it
if( achvExdData.ConditionType == static_cast< uint8_t >( Common::Achievement::Type::LinkedAchievement ) )
{
// get all linked achievements needed to unlock
std::set< int32_t > linkedAchv{ std::make_move_iterator( std::begin( achvExdData.ConditionArg ) ),
std::make_move_iterator( std::end( achvExdData.ConditionArg ) ) };
// clear empty achievement links
linkedAchv.erase( 0 );
// check if passed achievement ID is tied to this linked achievement
if( !linkedAchv.count( achievementId ) )
continue;
// verify if player has all the required achievements unlocked
bool hasAllAchievements = true;
for( const auto linkedAchvId : linkedAchv )
{
if( linkedAchvId == 0 )
continue;
if( !hasAchievementUnlocked( player, linkedAchvId ) )
{
hasAllAchievements = false;
break;
}
}
// unlock achievement if linked achievement conditions are met
if( hasAllAchievements )
unlockAchievement( player, achvId );
}
}
}
Common::AchievementDataKey AchievementMgr::getKeyFromType( Common::Achievement::Type achvType, int32_t argument )
{
Common::AchievementDataKey dataKey{ 0 };
dataKey.key.type = static_cast< uint8_t >( achvType );
dataKey.key.subtype = static_cast< uint16_t >( argument );
return dataKey;
}
const std::vector< uint32_t >& AchievementMgr::getAchievementIdByType( Common::Achievement::Type type ) const
{
return getAchievementIdByType( static_cast< uint32_t >( type ) );
}
const std::vector< uint32_t >& AchievementMgr::getAchievementIdByType( uint32_t type ) const
{
auto it = m_achievementKeyCacheMap.find( type );
if( it != std::end( m_achievementKeyCacheMap ) )
return it->second;
else
return {};
}
std::shared_ptr< Excel::ExcelStruct< Excel::Achievement > > AchievementMgr::getAchievementDetail( uint32_t achvId ) const
{
auto it = m_achievementDetailCacheMap.find( achvId );
if( it != std::end( m_achievementDetailCacheMap ) )
return it->second;
else
return nullptr;
}

View file

@ -0,0 +1,122 @@
#pragma once
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <type_traits>
#include <Service.h>
#include <Common.h>
#include "Actor/Player.h"
namespace Sapphire::World::Manager
{
class AchievementMgr
{
public:
AchievementMgr() = default;
~AchievementMgr() = default;
bool cacheAchievements();
template < auto AchievementType >
void progressAchievementByType( Entity::Player& player, int32_t argument, uint32_t progressCount = 1 )
{
progressAchievement< decltype( AchievementType ), AchievementType >( player, argument, progressCount );
}
bool hasAchievementUnlocked( Entity::Player& player, uint32_t achievementId );
void unlockAchievement( Entity::Player& player, uint32_t achievementId );
/// <summary>
/// get a pair of current progress and maximum count for a given achievement ID
/// </summary>
/// <param name="player"></param>
/// <param name="achievementId"></param>
/// <returns>pair of current and maximum progress</returns>
std::pair< uint32_t, uint32_t > getAchievementDataById( Entity::Player& player, uint32_t achievementId );
private:
// map achievement IDs to achv data
using AchievementDetailCache = std::unordered_map< uint32_t, std::shared_ptr< Excel::ExcelStruct< Excel::Achievement > > >;
// map achievement keys (either type or union key:subtype) to achievement IDs
using AchievementKeyCache = std::unordered_map< uint32_t, std::vector< uint32_t > >;
AchievementDetailCache m_achievementDetailCacheMap;
AchievementKeyCache m_achievementKeyCacheMap;
std::shared_ptr< Excel::ExcelStruct< Excel::Achievement > > getAchievementDetail( uint32_t achvId ) const;
const std::vector< uint32_t >& getAchievementIdByType( Common::Achievement::Type type ) const;
const std::vector< uint32_t >& getAchievementIdByType( uint32_t type ) const;
Common::AchievementDataKey getKeyFromType( Common::Achievement::Type achvType, int32_t argument );
void handleLinkedAchievementsForId( Entity::Player& player, uint32_t achievementId );
template< typename AchievementTypeT, AchievementTypeT achievementType >
inline void progressAchievement( Entity::Player& player, int32_t argument, uint32_t progressCount );
};
template<>
inline void AchievementMgr::progressAchievement< Common::Achievement::Type, Common::Achievement::Type::General >( Entity::Player& player, int32_t subtype, uint32_t progressCount )
{
auto& achvDataList = player.getAchievementDataList();
auto dataKey = getKeyFromType( Common::Achievement::Type::General, subtype );
if( !achvDataList.count( dataKey.u32 ) )
achvDataList[ dataKey.u32 ] = 0;
achvDataList[ dataKey.u32 ] += progressCount;
const auto achvIdList = getAchievementIdByType( dataKey.u32 );
for( auto achvId : achvIdList )
{
if( hasAchievementUnlocked( player, achvId ) )
continue;
auto pAchv = getAchievementDetail( achvId );
if( !pAchv )
continue;
auto achvExdData = pAchv->data();
if( achvExdData.ConditionArg[ 1 ] <= achvDataList[ dataKey.u32 ] )
unlockAchievement( player, achvId );
}
}
template<>
inline void AchievementMgr::progressAchievement< Common::Achievement::Type, Common::Achievement::Type::Classjob >( Entity::Player& player, int32_t classJob, uint32_t level )
{
auto& achvDataList = player.getAchievementDataList();
auto dataKey = getKeyFromType( Common::Achievement::Type::Classjob, classJob );
if( !achvDataList.count( dataKey.u32 ) )
achvDataList[ dataKey.u32 ] = 0;
achvDataList[ dataKey.u32 ] = level;
const auto achvIdList = getAchievementIdByType( dataKey.u32 );
for( auto achvId : achvIdList )
{
if( hasAchievementUnlocked( player, achvId ) )
continue;
auto pAchv = getAchievementDetail( achvId );
if( !pAchv )
continue;
auto achvExdData = pAchv->data();
if( achvExdData.ConditionArg[ 1 ] <= achvDataList[ dataKey.u32 ] )
unlockAchievement( player, achvId );
}
}
}

View file

@ -32,20 +32,23 @@
#include "Territory/HousingZone.h"
#include "Territory/InstanceContent.h"
#include "Territory/QuestBattle.h"
#include "Manager/TerritoryMgr.h"
#include "Manager/PlayerMgr.h"
#include "Manager/AchievementMgr.h"
#include "Manager/WarpMgr.h"
#include "Manager/LinkshellMgr.h"
#include "Manager/RNGMgr.h"
#include "Event/EventDefs.h"
#include "ContentFinder/ContentFinder.h"
#include "Manager/LinkshellMgr.h"
#include "Linkshell/Linkshell.h"
#include "Manager/WarpMgr.h"
#include "WorldServer.h"
#include "Session.h"
#include <Manager/RNGMgr.h>
using namespace Sapphire::Network;
using namespace Sapphire::Network::Packets;
@ -554,12 +557,32 @@ void DebugCommandMgr::add( char* data, Entity::Player& player, std::shared_ptr<
pSession->getZoneConnection()->queueOutPacket( effectPacket );
}
else if( subCommand == "achv" )
{
uint32_t achvId;
sscanf( params.c_str(), "%u", &achvId );
auto& achvMgr = Common::Service< Manager::AchievementMgr >::ref();
achvMgr.unlockAchievement( player, achvId );
}
else if( subCommand == "achvGeneral" )
{
uint32_t achvSubtype;
uint32_t progress;
sscanf( params.c_str(), "%u %u", &achvSubtype, &progress );
auto& achvMgr = Common::Service< Manager::AchievementMgr >::ref();
achvMgr.progressAchievementByType< Common::Achievement::Type::General >( player, achvSubtype, progress );
}
else
{
PlayerMgr::sendUrgent( player, "{0} is not a valid ADD command.", subCommand );
}
}
void DebugCommandMgr::get( char* data, Entity::Player& player, std::shared_ptr< DebugCommand > command )

View file

@ -354,18 +354,62 @@ void EventMgr::handleReturnStringEventScene( Entity::Player& player, uint32_t ev
result.sceneId = sceneId;
result.resultString = resultString;
auto eventCallback = pEvent->getEventReturnCallback();
if( eventCallback )
if( eventType == Event::EventHandler::EventHandlerType::Quest )
{
eventCallback( player, result );
auto questId = static_cast< uint16_t >( eventId );
auto eventCallback = pEvent->getQuestEventReturnCallback();
if( eventCallback )
{
World::Quest preQ;
if( player.hasQuest( eventId ) )
{
auto questIdx = player.getQuestIndex( questId );
auto& quest = player.getQuestByIndex( questIdx );
preQ = quest;
eventCallback( quest, player, result );
if( quest != preQ )
player.updateQuest( quest );
}
else
{
auto newQuest = World::Quest( questId, 0, 0 );
preQ = newQuest;
eventCallback( newQuest, player, result );
if( newQuest != preQ )
player.updateQuest( newQuest );
}
}
else if( auto chainCallback = pEvent->getQuestSceneChainCallback() )
{
if( player.hasQuest( eventId ) )
{
auto questIdx = player.getQuestIndex( questId );
auto& quest = player.getQuestByIndex( questIdx );
chainCallback( quest, player );
}
else
{
auto newQuest = World::Quest( questId, 0, 0 );
chainCallback( newQuest, player );
}
}
}
else
{
auto eventCallback = pEvent->getEventReturnCallback();
if( eventCallback )
{
eventCallback( player, result );
}
// we might have a scene chain callback instead so check for that too
else if( auto chainCallback = pEvent->getSceneChainCallback() )
chainCallback( player );
else if( auto chainCallback = pEvent->getSceneChainCallback() )
chainCallback( player );
}
}
checkEvent( player, eventId );
}
void EventMgr::handleReturnIntAndStringEventScene( Entity::Player& player, uint32_t eventId, uint16_t sceneId, const std::string& resultString, uint64_t resultInt )

View file

@ -7,6 +7,7 @@
#include <Territory/Territory.h>
#include <Manager/TerritoryMgr.h>
#include <Manager/AchievementMgr.h>
#include "Script/ScriptMgr.h"
#include "WorldServer.h"
@ -73,6 +74,37 @@ void PlayerMgr::onSendStateFlags( Entity::Player& player, bool updateInRange )
static_cast< uint8_t >( player.getOnlineStatus() ) ), true );
}
void PlayerMgr::onSendAchievementList( Entity::Player& player )
{
auto& server = Common::Service< World::WorldServer >::ref();
auto achvPacket = makeZonePacket< FFXIVIpcAchievement >( player.getId() );
std::memcpy( &achvPacket->data().complete[ 0 ], &player.getAchievementList()[ 0 ], sizeof( &achvPacket->data().complete ) );
server.queueForPlayer( player.getCharacterId(), achvPacket );
}
void PlayerMgr::onSendAchievementProgress( Entity::Player& player, uint32_t achievementId )
{
auto& server = Common::Service< World::WorldServer >::ref();
auto& achvMgr = Common::Service< Manager::AchievementMgr >::ref();
auto achvProgress = achvMgr.getAchievementDataById( player, achievementId );
auto pAchvProgressPacket = makeActorControl( player.getId(), AchievementSetRate, achievementId, achvProgress.first, achvProgress.second );
server.queueForPlayer( player.getCharacterId(), pAchvProgressPacket );
}
void PlayerMgr::onUnlockAchievement( Entity::Player& player, uint32_t achievementId )
{
auto& server = Common::Service< World::WorldServer >::ref();
onSendAchievementList( player );
server.queueForPlayer( player.getCharacterId(), makeActorControl( player.getId(), AchievementComplete, achievementId ) );
server.queueForPlayer( player.getCharacterId(), makeActorControl( player.getId(), AchievementObtainMsg, achievementId ) );
}
void PlayerMgr::onSendStats( Entity::Player& player )
{
std::array< uint32_t, 50 > statParams;
@ -142,8 +174,23 @@ void PlayerMgr::onLevelUp( Entity::Player& player )
player.sendToInRangeSet( makeActorControl( player.getId(), LevelUpEffect, static_cast< uint8_t >( player.getClass() ),
player.getLevel(), player.getLevel() - 1 ), true );
auto& achvMgr = Common::Service< World::Manager::AchievementMgr >::ref();
achvMgr.progressAchievementByType< Common::Achievement::Type::Classjob >( player, static_cast< uint8_t >( player.getClass() ), player.getLevel() );
}
void PlayerMgr::onSetLevelForClass( Entity::Player& player, Common::ClassJob classJob )
{
auto& server = Common::Service< World::WorldServer >::ref();
auto& achvMgr = Common::Service< World::Manager::AchievementMgr >::ref();
server.queueForPlayer( player.getCharacterId(), makeActorControlSelf( player.getId(), Network::ActorControl::ClassJobUpdate,
static_cast< uint8_t >( classJob ), player.getLevelForClass( classJob ) ) );
achvMgr.progressAchievementByType< Common::Achievement::Type::Classjob >( player, static_cast< uint8_t >( classJob ), player.getLevel() );
}
void PlayerMgr::onGainExp( Entity::Player& player, uint32_t exp )
{
auto& server = Common::Service< World::WorldServer >::ref();

View file

@ -22,12 +22,20 @@ class PlayerMgr
void onChangeClass( Sapphire::Entity::Player& player );
void onSendAchievementList( Sapphire::Entity::Player& player );
void onSendAchievementProgress( Sapphire::Entity::Player& player, uint32_t achievementId );
void onUnlockAchievement( Sapphire::Entity::Player& player, uint32_t achievementId );
void onPlayerHpMpTpChanged( Sapphire::Entity::Player& player );
void onPlayerItemLevelUpdate( Sapphire::Entity::Player& player );
void onLevelUp( Sapphire::Entity::Player& player );
void onSetLevelForClass( Sapphire::Entity::Player& player, Common::ClassJob classJob );
void onGainExp( Sapphire::Entity::Player& player, uint32_t exp );
void onUnlockOrchestrion( Sapphire::Entity::Player& player, uint8_t songId, uint32_t itemId );

View file

@ -85,6 +85,7 @@ void WarpMgr::finishWarp( Entity::Player& player )
player.sendToInRangeSet( zoneInPacket );
player.sendToInRangeSet( SetStatusPacket, true );
player.sendStatusUpdate();
auto& server = Common::Service< WorldServer >::ref();
server.queueForPlayer( player.getCharacterId(), zoneInPacket );

View file

@ -537,7 +537,8 @@ void Sapphire::Network::GameConnection::gmCommandHandler( const Packets::FFXIVAR
}
else
{
warpMgr.requestMoveTerritory( *targetPlayer, WarpType::WARP_TYPE_GM, teriMgr.getZoneByTerritoryTypeId( param1 )->getGuId(), targetPlayer->getPos(), 0);
auto& warpMgr = Common::Service< WarpMgr >::ref();
warpMgr.requestMoveTerritory( *targetPlayer, WarpType::WARP_TYPE_GM, teriMgr.getZoneByTerritoryTypeId( param1 )->getGuId(), targetPlayer->getPos(), 0 );
}
PlayerMgr::sendServerNotice( player, "{0} was warped to zone {1}", targetPlayer->getName(), param1, pZone->getName() );

View file

@ -599,7 +599,16 @@ void Sapphire::Network::GameConnection::commandHandler( const Packets::FFXIVARR_
player.setIsLogin( false );
break;
}
case PacketCommand::ACHIEVEMENT_REQUEST_RATE:
{
Service< World::Manager::PlayerMgr >::ref().onSendAchievementProgress( player, param11 );
break;
}
case PacketCommand::ACHIEVEMENT_REQUEST:
{
Service< World::Manager::PlayerMgr >::ref().onSendAchievementList( player );
break;
}
case PacketCommand::TELEPO_INQUIRY: // Teleport
{

View file

@ -25,31 +25,31 @@ bool Sapphire::World::Quest::getBitFlag8( uint8_t index )
bool Sapphire::World::Quest::getBitFlag16( uint8_t index )
{
uint8_t realIdx = 8 - index;
uint8_t realIdx = 16 - index;
return m_data.a.BitFlag16 & ( 1 << realIdx );
}
bool Sapphire::World::Quest::getBitFlag24( uint8_t index )
{
uint8_t realIdx = 8 - index;
uint8_t realIdx = 24 - index;
return m_data.a.BitFlag24 & ( 1 << realIdx );
}
bool Sapphire::World::Quest::getBitFlag32( uint8_t index )
{
uint8_t realIdx = 8 - index;
uint8_t realIdx = 32 - index;
return m_data.a.BitFlag32 & ( 1 << realIdx );
}
bool Sapphire::World::Quest::getBitFlag40( uint8_t index )
{
uint8_t realIdx = 8 - index;
uint8_t realIdx = 40 - index;
return m_data.a.BitFlag40 & ( 1 << realIdx );
}
bool Sapphire::World::Quest::getBitFlag48( uint8_t index )
{
uint8_t realIdx = 8 - index;
uint8_t realIdx = 48 - index;
return m_data.a.BitFlag48 & ( 1 << realIdx );
}
@ -312,7 +312,6 @@ void Sapphire::World::Quest::setUI32A( uint32_t val )
void Sapphire::World::Quest::setBitFlag8( uint8_t index, bool val )
{
uint8_t realIdx = 8 - index;
if( val )
m_data.a.BitFlag8 |= ( 1 << realIdx );
else
@ -321,8 +320,7 @@ void Sapphire::World::Quest::setBitFlag8( uint8_t index, bool val )
void Sapphire::World::Quest::setBitFlag16( uint8_t index, bool val )
{
uint8_t realIdx = 8 - index;
uint8_t realIdx = 16 - index;
if( val )
m_data.a.BitFlag16 |= ( 1 << realIdx );
else
@ -331,8 +329,7 @@ void Sapphire::World::Quest::setBitFlag16( uint8_t index, bool val )
void Sapphire::World::Quest::setBitFlag24( uint8_t index, bool val )
{
uint8_t realIdx = 8 - index;
uint8_t realIdx = 24 - index;
if( val )
m_data.a.BitFlag24 |= ( 1 << realIdx );
else
@ -341,8 +338,7 @@ void Sapphire::World::Quest::setBitFlag24( uint8_t index, bool val )
void Sapphire::World::Quest::setBitFlag32( uint8_t index, bool val )
{
uint8_t realIdx = 8 - index;
uint8_t realIdx = 32 - index;
if( val )
m_data.a.BitFlag32 |= ( 1 << realIdx );
else
@ -351,8 +347,7 @@ void Sapphire::World::Quest::setBitFlag32( uint8_t index, bool val )
void Sapphire::World::Quest::setBitFlag40( uint8_t index, bool val )
{
uint8_t realIdx = 8 - index;
uint8_t realIdx = 40 - index;
if( val )
m_data.a.BitFlag40 |= ( 1 << realIdx );
else
@ -361,8 +356,7 @@ void Sapphire::World::Quest::setBitFlag40( uint8_t index, bool val )
void Sapphire::World::Quest::setBitFlag48( uint8_t index, bool val )
{
uint8_t realIdx = 8 - index;
uint8_t realIdx = 48 - index;
if( val )
m_data.a.BitFlag48 |= ( 1 << realIdx );
else

View file

@ -255,6 +255,8 @@ bool Sapphire::Scripting::ScriptMgr::onTalk( Entity::Player& player, uint64_t ac
return true;
}
}
return false;
}
bool Sapphire::Scripting::ScriptMgr::onEnterTerritory( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 )

View file

@ -490,7 +490,8 @@ void Territory::updateSessions( uint64_t tickCount, bool changedWeather )
}
// this session is not linked to this area anymore, remove it from zone session list
if( pPlayer->getTerritoryId() != m_guId )
// TODO: Retrieving the session is expensive, try to find a better method of removing invalid actors
if( pPlayer->getTerritoryId() != m_guId || !server.getSession( pPlayer->getId() ) )
{
Logger::debug( "[{}] removeActor( pPlayer );", pPlayer->getId() );
removeActor( pPlayer );

View file

@ -19,7 +19,6 @@
#include "Session.h"
#include "Manager/TerritoryMgr.h"
#include "Manager/LinkshellMgr.h"
#include "Manager/TaskMgr.h"
#include "Task/TestTask.h"
@ -29,6 +28,7 @@
#include <Database/ZoneDbConnection.h>
#include <Database/DbWorkerPool.h>
#include <Service.h>
#include "Manager/AchievementMgr.h"
#include "Manager/LinkshellMgr.h"
#include "Manager/TerritoryMgr.h"
#include "Manager/HousingMgr.h"
@ -186,6 +186,16 @@ void WorldServer::run( int32_t argc, char* argv[] )
}
Common::Service< Manager::LinkshellMgr >::set( pLsMgr );
auto pAchvMgr = std::make_shared< Manager::AchievementMgr >();
Logger::info( "AchievementMgr: Caching data" );
if( !pAchvMgr->cacheAchievements() )
{
Logger::fatal( "Unable to cache achievements!" );
return;
}
Common::Service< Manager::AchievementMgr >::set( pAchvMgr );
Logger::info( "Setting up InstanceObjectCache" );
auto pInstanceObjCache = std::make_shared< Sapphire::InstanceObjectCache >();
Common::Service< Sapphire::InstanceObjectCache >::set( pInstanceObjCache );