mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-03 17:27:47 +00:00
Merge pull request #928 from hkAlice/bs-stuff
[3.x] (WIP) EncounterFight and state refactor;
This commit is contained in:
commit
f19d3167ca
202 changed files with 12193 additions and 2736 deletions
|
@ -18,28 +18,39 @@ if( UNIX )
|
|||
"preferred path to MySQL (mysql_config)"
|
||||
)
|
||||
|
||||
find_program(MYSQL_CONFIG mysql_config
|
||||
# try mariadb first
|
||||
find_program(MYSQL_CONFIG mariadb_config
|
||||
${MYSQL_CONFIG_PREFER_PATH}
|
||||
/usr/local/mysql/bin/
|
||||
/usr/local/bin/
|
||||
/usr/bin/
|
||||
)
|
||||
|
||||
if( NOT MYSQL_CONFIG )
|
||||
# fallback to mysql
|
||||
find_program(MYSQL_CONFIG mysql_config
|
||||
${MYSQL_CONFIG_PREFER_PATH}
|
||||
/usr/local/mysql/bin/
|
||||
/usr/local/bin/
|
||||
/usr/bin/
|
||||
)
|
||||
endif()
|
||||
|
||||
if( MYSQL_CONFIG )
|
||||
message(STATUS "Using mysql-config: ${MYSQL_CONFIG}")
|
||||
# set INCLUDE_DIR
|
||||
exec_program(${MYSQL_CONFIG}
|
||||
ARGS --include
|
||||
execute_process(COMMAND ${MYSQL_CONFIG} --include
|
||||
OUTPUT_VARIABLE MY_TMP
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
string(REGEX REPLACE "-I([^ ]*)( .*)?" "\\1" MY_TMP "${MY_TMP}")
|
||||
set(MYSQL_ADD_INCLUDE_PATH ${MY_TMP} CACHE FILEPATH INTERNAL)
|
||||
#message("[DEBUG] MYSQL ADD_INCLUDE_PATH : ${MYSQL_ADD_INCLUDE_PATH}")
|
||||
# set LIBRARY_DIR
|
||||
exec_program(${MYSQL_CONFIG}
|
||||
ARGS --libs_r
|
||||
execute_process(COMMAND ${MYSQL_CONFIG} --libs_r
|
||||
OUTPUT_VARIABLE MY_TMP
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
set(MYSQL_ADD_LIBRARIES "")
|
||||
string(REGEX MATCHALL "-l[^ ]*" MYSQL_LIB_LIST "${MY_TMP}")
|
||||
|
|
1082
data/EncounterTimelines/IfritNormal.json
Normal file
1082
data/EncounterTimelines/IfritNormal.json
Normal file
File diff suppressed because it is too large
Load diff
104
data/actions/IfritNormal.json
Normal file
104
data/actions/IfritNormal.json
Normal file
|
@ -0,0 +1,104 @@
|
|||
{
|
||||
"872": {
|
||||
"name": "Auto Attack",
|
||||
"potency": 100,
|
||||
"comboPotency": 0,
|
||||
"flankPotency": 0,
|
||||
"frontPotency": 0,
|
||||
"rearPotency": 0,
|
||||
"curePotency": 0,
|
||||
"restorePercentage": 0,
|
||||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"target": []
|
||||
}
|
||||
},
|
||||
"453": {
|
||||
"name": "Incinerate",
|
||||
"potency": 100,
|
||||
"comboPotency": 0,
|
||||
"flankPotency": 0,
|
||||
"frontPotency": 0,
|
||||
"rearPotency": 0,
|
||||
"curePotency": 0,
|
||||
"restorePercentage": 0,
|
||||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"target": []
|
||||
}
|
||||
},
|
||||
"454": {
|
||||
"name": "Vulcan Burst",
|
||||
"potency": 100,
|
||||
"comboPotency": 0,
|
||||
"flankPotency": 0,
|
||||
"frontPotency": 0,
|
||||
"rearPotency": 0,
|
||||
"curePotency": 0,
|
||||
"restorePercentage": 0,
|
||||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"target": []
|
||||
}
|
||||
},
|
||||
"458": {
|
||||
"name": "Hellfire",
|
||||
"potency": 400,
|
||||
"comboPotency": 0,
|
||||
"flankPotency": 0,
|
||||
"frontPotency": 0,
|
||||
"rearPotency": 0,
|
||||
"curePotency": 0,
|
||||
"restorePercentage": 0,
|
||||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [
|
||||
{
|
||||
"id": 394,
|
||||
"duration": 8000,
|
||||
"modifiers": [
|
||||
{
|
||||
"modifier": "DamageTakenPercent",
|
||||
"value": -100
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"target": []
|
||||
}
|
||||
},
|
||||
"733": {
|
||||
"name": "Eruption",
|
||||
"potency": 200,
|
||||
"comboPotency": 0,
|
||||
"flankPotency": 0,
|
||||
"frontPotency": 0,
|
||||
"rearPotency": 0,
|
||||
"curePotency": 0,
|
||||
"restorePercentage": 0,
|
||||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"target": []
|
||||
}
|
||||
},
|
||||
"734": {
|
||||
"name": "Radiant Plume",
|
||||
"potency": 200,
|
||||
"comboPotency": 0,
|
||||
"flankPotency": 0,
|
||||
"frontPotency": 0,
|
||||
"rearPotency": 0,
|
||||
"curePotency": 0,
|
||||
"restorePercentage": 0,
|
||||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"target": []
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"7": {
|
||||
"name": "Attack",
|
||||
"potency": 0,
|
||||
"potency": 110,
|
||||
"comboPotency": 0,
|
||||
"flankPotency": 0,
|
||||
"frontPotency": 0,
|
||||
|
@ -16,7 +16,7 @@
|
|||
},
|
||||
"8": {
|
||||
"name": "Shot",
|
||||
"potency": 0,
|
||||
"potency": 100,
|
||||
"comboPotency": 0,
|
||||
"flankPotency": 0,
|
||||
"frontPotency": 0,
|
||||
|
@ -398,7 +398,18 @@
|
|||
"restorePercentage": 0,
|
||||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"caster": [
|
||||
{
|
||||
"id": 83,
|
||||
"duration": 20000,
|
||||
"modifiers": [
|
||||
{
|
||||
"modifier": "DefensePercent",
|
||||
"value": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"target": []
|
||||
}
|
||||
},
|
||||
|
@ -414,7 +425,18 @@
|
|||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"target": []
|
||||
"target": [
|
||||
{
|
||||
"id": 244,
|
||||
"duration": 30000,
|
||||
"modifiers": [
|
||||
{
|
||||
"modifier": "TickDamage",
|
||||
"value": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"34": {
|
||||
|
@ -478,7 +500,18 @@
|
|||
45
|
||||
],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"caster": [
|
||||
{
|
||||
"id": 85,
|
||||
"duration": 24000,
|
||||
"modifiers": [
|
||||
{
|
||||
"modifier": "DamageDealtPercent",
|
||||
"value": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"target": []
|
||||
}
|
||||
},
|
||||
|
@ -493,7 +526,18 @@
|
|||
"restorePercentage": 0,
|
||||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"caster": [
|
||||
{
|
||||
"id": 86,
|
||||
"duration": 20000,
|
||||
"modifiers": [
|
||||
{
|
||||
"modifier": "AttackPowerPercent",
|
||||
"value": 50
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"target": []
|
||||
}
|
||||
},
|
||||
|
@ -523,7 +567,18 @@
|
|||
"restorePercentage": 0,
|
||||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"caster": [
|
||||
{
|
||||
"id": 87,
|
||||
"duration": 20000,
|
||||
"modifiers": [
|
||||
{
|
||||
"modifier": "HPPercent",
|
||||
"value": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"target": []
|
||||
}
|
||||
},
|
||||
|
@ -574,7 +629,7 @@
|
|||
},
|
||||
"44": {
|
||||
"name": "Vengeance",
|
||||
"potency": 50,
|
||||
"potency": 0,
|
||||
"comboPotency": 0,
|
||||
"flankPotency": 0,
|
||||
"frontPotency": 0,
|
||||
|
@ -583,7 +638,18 @@
|
|||
"restorePercentage": 0,
|
||||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"caster": [
|
||||
{
|
||||
"id": 89,
|
||||
"duration": 20000,
|
||||
"modifiers": [
|
||||
{
|
||||
"modifier": "ReflectPhysical",
|
||||
"value": 50
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"target": []
|
||||
}
|
||||
},
|
||||
|
@ -643,7 +709,34 @@
|
|||
"restorePercentage": 0,
|
||||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"caster": [
|
||||
{
|
||||
"id": 91,
|
||||
"duration": 0,
|
||||
"modifiers": [
|
||||
{
|
||||
"modifier": "HPPercent",
|
||||
"value": 25
|
||||
},
|
||||
{
|
||||
"modifier": "DamageDealtPercent",
|
||||
"value": -25
|
||||
},
|
||||
{
|
||||
"modifier": "HealingMagicRecoveryPercent",
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"modifier": "AccuracyPercent",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"modifier": "EnmityPercent",
|
||||
"value": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"target": []
|
||||
}
|
||||
},
|
||||
|
@ -703,7 +796,12 @@
|
|||
"restorePercentage": 0,
|
||||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"caster": [
|
||||
{
|
||||
"id": 97,
|
||||
"duration": 30000
|
||||
}
|
||||
],
|
||||
"target": []
|
||||
}
|
||||
},
|
||||
|
@ -1176,7 +1274,19 @@
|
|||
"restorePercentage": 0,
|
||||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"caster": [
|
||||
{
|
||||
"id": 116,
|
||||
"duration": 10000,
|
||||
"flag": 4096,
|
||||
"modifiers": [
|
||||
{
|
||||
"modifier": "CriticalHitPercent",
|
||||
"value": 100
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"target": []
|
||||
}
|
||||
},
|
||||
|
@ -2454,7 +2564,38 @@
|
|||
"nextCombo": [],
|
||||
"statuses": {
|
||||
"caster": [],
|
||||
"target": []
|
||||
"target": [
|
||||
{
|
||||
"id": 180,
|
||||
"duration": 24000,
|
||||
"modifiers": [
|
||||
{
|
||||
"modifier": "TickDamage",
|
||||
"value": 35
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 191,
|
||||
"duration": 24000,
|
||||
"modifiers": [
|
||||
{
|
||||
"modifier": "HealingRecoveryPercent",
|
||||
"value": -20
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 240,
|
||||
"duration": 24000,
|
||||
"modifiers": [
|
||||
{
|
||||
"modifier": "HeavyPercent",
|
||||
"value": 40
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"169": {
|
||||
|
|
82
deps/datReader/DatCategories/bg/lgb.h
vendored
82
deps/datReader/DatCategories/bg/lgb.h
vendored
|
@ -227,6 +227,8 @@ struct LGB_GROUP
|
|||
memcpy( (char*)&refs[0], buf + offset + header.LayerSetRef + layerSetReferencedList.LayerSets, layerSetReferencedList.LayerSetCount * sizeof( LayerSetReferenced ) );
|
||||
}
|
||||
|
||||
entries.reserve( header.entryCount );
|
||||
|
||||
const auto entriesOffset = offset + header.entriesOffset;
|
||||
for( auto i = 0; i < header.entryCount; ++i )
|
||||
{
|
||||
|
@ -235,41 +237,53 @@ struct LGB_GROUP
|
|||
try
|
||||
{
|
||||
const auto type = *reinterpret_cast< LgbEntryType* >( buf + entryOffset );
|
||||
if( type == LgbEntryType::BgParts )
|
||||
switch( type )
|
||||
{
|
||||
entries.push_back( std::make_shared< LGB_BGPARTS_ENTRY >( buf, entryOffset ) );
|
||||
}
|
||||
else if( type == LgbEntryType::Gimmick )
|
||||
{
|
||||
entries.push_back( std::make_shared< LGB_GIMMICK_ENTRY >( buf, entryOffset ) );
|
||||
}
|
||||
else if( type == LgbEntryType::EventNpc )
|
||||
{
|
||||
entries.push_back( std::make_shared< LGB_ENPC_ENTRY >( buf, entryOffset ) );
|
||||
}
|
||||
else if( type == LgbEntryType::EventObject )
|
||||
{
|
||||
entries.push_back( std::make_shared< LGB_EOBJ_ENTRY >( buf, entryOffset ) );
|
||||
}
|
||||
else if( type == LgbEntryType::ExitRange )
|
||||
{
|
||||
entries.push_back( std::make_shared< LGB_EXIT_RANGE_ENTRY >( buf, entryOffset ) );
|
||||
}
|
||||
else if( type == LgbEntryType::EventRange )
|
||||
{
|
||||
entries.push_back( std::make_shared< LGB_EVENT_RANGE_ENTRY >( buf, entryOffset ) );
|
||||
}
|
||||
else if( type == LgbEntryType::PopRange )
|
||||
{
|
||||
entries.push_back( std::make_shared< LGB_POP_RANGE_ENTRY >( buf, entryOffset ) );
|
||||
}
|
||||
else if( type == LgbEntryType::MapRange )
|
||||
{
|
||||
entries.push_back( std::make_shared< LGB_MAP_RANGE_ENTRY >( buf, entryOffset ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
entries.push_back( std::make_shared< LgbEntry >( buf, entryOffset ) );
|
||||
case LgbEntryType::BgParts:
|
||||
{
|
||||
entries.emplace_back( std::make_shared< LGB_BGPARTS_ENTRY >( buf, entryOffset ) );
|
||||
break;
|
||||
}
|
||||
case LgbEntryType::Gimmick:
|
||||
{
|
||||
entries.emplace_back( std::make_shared< LGB_GIMMICK_ENTRY >( buf, entryOffset ) );
|
||||
break;
|
||||
}
|
||||
case LgbEntryType::EventNpc:
|
||||
{
|
||||
entries.emplace_back( std::make_shared< LGB_ENPC_ENTRY >( buf, entryOffset ) );
|
||||
break;
|
||||
}
|
||||
case LgbEntryType::EventObject:
|
||||
{
|
||||
entries.emplace_back( std::make_shared< LGB_EOBJ_ENTRY >( buf, entryOffset ) );
|
||||
break;
|
||||
}
|
||||
case LgbEntryType::ExitRange:
|
||||
{
|
||||
entries.emplace_back( std::make_shared< LGB_EXIT_RANGE_ENTRY >( buf, entryOffset ) );
|
||||
break;
|
||||
}
|
||||
case LgbEntryType::EventRange:
|
||||
{
|
||||
entries.emplace_back( std::make_shared< LGB_EVENT_RANGE_ENTRY >( buf, entryOffset ) );
|
||||
break;
|
||||
}
|
||||
case LgbEntryType::PopRange:
|
||||
{
|
||||
entries.emplace_back( std::make_shared< LGB_POP_RANGE_ENTRY >( buf, entryOffset ) );
|
||||
break;
|
||||
}
|
||||
case LgbEntryType::MapRange:
|
||||
{
|
||||
entries.emplace_back( std::make_shared< LGB_MAP_RANGE_ENTRY >( buf, entryOffset ) );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
entries.emplace_back( std::make_shared< LgbEntry >( buf, entryOffset ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( std::exception& e )
|
||||
|
|
60
deps/datReader/Exd.cpp
vendored
60
deps/datReader/Exd.cpp
vendored
|
@ -7,50 +7,6 @@
|
|||
|
||||
using xiv::utils::bparse::extract;
|
||||
|
||||
|
||||
namespace xiv::exd
|
||||
{
|
||||
struct ExdHeader
|
||||
{
|
||||
char magic[0x4];
|
||||
uint16_t unknown;
|
||||
uint16_t unknown2;
|
||||
uint32_t index_size;
|
||||
};
|
||||
|
||||
struct ExdRecordIndex
|
||||
{
|
||||
uint32_t id;
|
||||
uint32_t offset;
|
||||
};
|
||||
}
|
||||
|
||||
namespace xiv::utils::bparse {
|
||||
template<>
|
||||
inline void reorder< xiv::exd::ExdHeader >( xiv::exd::ExdHeader& i_struct )
|
||||
{
|
||||
for( int32_t i = 0; i < 0x4; ++i )
|
||||
{
|
||||
xiv::utils::bparse::reorder( i_struct.magic[ i ] );
|
||||
}
|
||||
i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown );
|
||||
xiv::utils::bparse::reorder( i_struct.unknown );
|
||||
i_struct.unknown2 = xiv::utils::bparse::byteswap( i_struct.unknown2 );
|
||||
xiv::utils::bparse::reorder( i_struct.unknown2 );
|
||||
i_struct.index_size = xiv::utils::bparse::byteswap( i_struct.index_size );
|
||||
xiv::utils::bparse::reorder( i_struct.index_size );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void reorder< xiv::exd::ExdRecordIndex >( xiv::exd::ExdRecordIndex& i_struct )
|
||||
{
|
||||
i_struct.id = xiv::utils::bparse::byteswap( i_struct.id );
|
||||
xiv::utils::bparse::reorder( i_struct.id );
|
||||
i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset );
|
||||
xiv::utils::bparse::reorder( i_struct.offset );
|
||||
}
|
||||
};
|
||||
|
||||
namespace xiv::exd
|
||||
{
|
||||
Exd::Exd( std::shared_ptr< Exh > i_exh, const std::vector< std::shared_ptr< dat::File>>& i_files )
|
||||
|
@ -68,16 +24,16 @@ namespace xiv::exd
|
|||
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
|
||||
|
||||
// Extract the header and skip to the record indices
|
||||
auto exd_header = extract< ExdHeader >( iss );
|
||||
auto exd_header = extract< ExdHeaderMinimal >( iss );
|
||||
iss.seekg( 0x20 );
|
||||
|
||||
// Preallocate and extract the record_indices
|
||||
const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndex );
|
||||
std::vector< ExdRecordIndex > record_indices;
|
||||
const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndexData );
|
||||
std::vector< ExdRecordIndexData > record_indices;
|
||||
record_indices.reserve( record_count );
|
||||
for( uint32_t i = 0; i < record_count; ++i )
|
||||
{
|
||||
auto recordIndex = extract< ExdRecordIndex >( iss );
|
||||
auto recordIndex = extract< ExdRecordIndexData >( iss );
|
||||
_idCache[ recordIndex.id ] = ExdCacheEntry{ file_ptr, recordIndex.offset };
|
||||
}
|
||||
}
|
||||
|
@ -290,16 +246,16 @@ namespace xiv::exd
|
|||
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
|
||||
|
||||
// Extract the header and skip to the record indices
|
||||
auto exd_header = extract< ExdHeader >( iss );
|
||||
auto exd_header = extract< ExdHeaderMinimal >( iss );
|
||||
iss.seekg( 0x20 );
|
||||
|
||||
// Preallocate and extract the record_indices
|
||||
const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndex );
|
||||
std::vector< ExdRecordIndex > record_indices;
|
||||
const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndexData );
|
||||
std::vector< ExdRecordIndexData > record_indices;
|
||||
record_indices.reserve( record_count );
|
||||
for( uint32_t i = 0; i < record_count; ++i )
|
||||
{
|
||||
record_indices.emplace_back( extract< ExdRecordIndex >( iss ) );
|
||||
record_indices.emplace_back( extract< ExdRecordIndexData >( iss ) );
|
||||
}
|
||||
|
||||
for( auto& record_index : record_indices )
|
||||
|
|
191
deps/datReader/Exd.h
vendored
191
deps/datReader/Exd.h
vendored
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <variant>
|
||||
|
||||
|
@ -12,6 +13,49 @@
|
|||
#include <fstream>
|
||||
#include "Exh.h"
|
||||
#include "bparse.h"
|
||||
|
||||
namespace xiv::exd
|
||||
{
|
||||
struct ExdHeaderMinimal {
|
||||
char magic[ 0x4 ];
|
||||
uint16_t unknown;
|
||||
uint16_t unknown2;
|
||||
uint32_t index_size;
|
||||
};
|
||||
|
||||
struct ExdRecordIndexData {
|
||||
uint32_t id;
|
||||
uint32_t offset;
|
||||
};
|
||||
}
|
||||
|
||||
namespace xiv::utils::bparse
|
||||
{
|
||||
template<>
|
||||
inline void reorder< xiv::exd::ExdHeaderMinimal >( xiv::exd::ExdHeaderMinimal& i_struct )
|
||||
{
|
||||
for( int32_t i = 0; i < 0x4; ++i )
|
||||
{
|
||||
xiv::utils::bparse::reorder( i_struct.magic[ i ] );
|
||||
}
|
||||
i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown );
|
||||
xiv::utils::bparse::reorder( i_struct.unknown );
|
||||
i_struct.unknown2 = xiv::utils::bparse::byteswap( i_struct.unknown2 );
|
||||
xiv::utils::bparse::reorder( i_struct.unknown2 );
|
||||
i_struct.index_size = xiv::utils::bparse::byteswap( i_struct.index_size );
|
||||
xiv::utils::bparse::reorder( i_struct.index_size );
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void reorder< xiv::exd::ExdRecordIndexData >( xiv::exd::ExdRecordIndexData& i_struct )
|
||||
{
|
||||
i_struct.id = xiv::utils::bparse::byteswap( i_struct.id );
|
||||
xiv::utils::bparse::reorder( i_struct.id );
|
||||
i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset );
|
||||
xiv::utils::bparse::reorder( i_struct.offset );
|
||||
}
|
||||
};// namespace xiv::utils::bparse
|
||||
|
||||
namespace xiv::exd
|
||||
{
|
||||
|
||||
|
@ -184,12 +228,153 @@ namespace xiv::exd
|
|||
const std::vector< Field > get_row( uint32_t id, uint32_t subRow );
|
||||
|
||||
// Get all rows
|
||||
const std::map< uint32_t, std::vector< Field>>& get_rows();
|
||||
const std::map< uint32_t, std::vector< Field > >& get_rows();
|
||||
|
||||
// Get all rows
|
||||
template< typename T >
|
||||
const std::unordered_map< uint32_t, std::shared_ptr< Excel::ExcelStruct< T > > > get_sheet_rows()
|
||||
{
|
||||
std::unordered_map< uint32_t, std::shared_ptr< Excel::ExcelStruct< T > > > sheets;
|
||||
|
||||
// Iterates over all the files
|
||||
const uint32_t member_count = static_cast< uint32_t >( _exh->get_members().size() );
|
||||
for( auto& file_ptr : _files )
|
||||
{
|
||||
// Get a stream
|
||||
std::vector< char > dataCpy = file_ptr->get_data_sections().front();
|
||||
std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) );
|
||||
|
||||
// Extract the header and skip to the record indices
|
||||
auto exd_header = xiv::utils::bparse::extract< ExdHeaderMinimal >( iss );
|
||||
iss.seekg( 0x20 );
|
||||
|
||||
// Preallocate and extract the record_indices
|
||||
const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndexData );
|
||||
std::vector< ExdRecordIndexData > record_indices;
|
||||
record_indices.reserve( record_count );
|
||||
for( uint32_t i = 0; i < record_count; ++i )
|
||||
{
|
||||
record_indices.emplace_back( xiv::utils::bparse::extract< ExdRecordIndexData >( iss ) );
|
||||
}
|
||||
|
||||
for( auto& record_index : record_indices )
|
||||
{
|
||||
auto cacheEntryIt = _idCache.find( record_index.id );
|
||||
if( cacheEntryIt == _idCache.end() )
|
||||
throw std::out_of_range( "Id not found: " + std::to_string( record_index.id ) );
|
||||
|
||||
auto pSheet = std::make_shared< Excel::ExcelStruct< T > >();
|
||||
|
||||
// Get the vector fields for the given record and preallocate it
|
||||
auto fields = _data[ record_index.id ];
|
||||
fields.reserve( member_count );
|
||||
iss.seekg( cacheEntryIt->second.offset + 6 );
|
||||
|
||||
iss.read( reinterpret_cast<char*>( &pSheet.get()->_data ), sizeof( T ) );
|
||||
|
||||
int stringCount = 0;
|
||||
for( auto& member_entry : _exh->get_exh_members() )
|
||||
{
|
||||
|
||||
// Seek to the position of the member to extract.
|
||||
// 6 is because we have uint32_t/uint16_t at the start of each record
|
||||
iss.seekg( cacheEntryIt->second.offset + 6 + member_entry.offset );
|
||||
|
||||
// Switch depending on the type to extract
|
||||
switch( member_entry.type )
|
||||
{
|
||||
case DataType::string:
|
||||
// Extract the offset to the actual string
|
||||
// Seek to it then extract the actual string
|
||||
{
|
||||
auto string_offset = xiv::utils::bparse::extract< uint32_t >( iss, "string_offset", false );
|
||||
iss.seekg( cacheEntryIt->second.offset + 6 + _exh->get_header().data_offset + string_offset );
|
||||
std::string value = xiv::utils::bparse::extract_cstring( iss, "string" );
|
||||
auto it = pSheet->_strings.insert( pSheet->_strings.end(), value );
|
||||
*reinterpret_cast< uint32_t* >( pSheet->ptr() + member_entry.offset ) =
|
||||
static_cast< uint32_t >( std::distance( pSheet->_strings.begin(), it ) );
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::boolean:
|
||||
xiv::utils::bparse::extract< bool >( iss, "bool" );
|
||||
break;
|
||||
|
||||
case DataType::int8:
|
||||
xiv::utils::bparse::extract< int8_t >( iss, "int8_t" );
|
||||
break;
|
||||
|
||||
case DataType::uint8:
|
||||
xiv::utils::bparse::extract< uint8_t >( iss, "uint8_t" );
|
||||
break;
|
||||
|
||||
|
||||
case DataType::int16:
|
||||
{
|
||||
int16_t value = xiv::utils::bparse::extract< int16_t >( iss, "int16_t", false );
|
||||
*reinterpret_cast< int16_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::uint16:
|
||||
{
|
||||
uint16_t value = xiv::utils::bparse::extract< uint16_t >( iss, "uint16_t", false );
|
||||
*reinterpret_cast< uint16_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::int32:
|
||||
{
|
||||
int32_t value = xiv::utils::bparse::extract< int32_t >( iss, "int32_t", false );
|
||||
*reinterpret_cast< int32_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::uint32:
|
||||
{
|
||||
uint32_t value = xiv::utils::bparse::extract< uint32_t >( iss, "uint32_t", false );
|
||||
*reinterpret_cast< uint32_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::float32:
|
||||
{
|
||||
float value = xiv::utils::bparse::extract< float >( iss, "float", false );
|
||||
*reinterpret_cast< float* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataType::uint64:
|
||||
{
|
||||
uint64_t value = xiv::utils::bparse::extract< uint64_t >( iss, "uint64_t", false );
|
||||
*reinterpret_cast< uint64_t* >( pSheet->ptr() + member_entry.offset ) = value;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
auto type = static_cast< uint16_t >( member_entry.type );
|
||||
if( type < 0x19 || type > 0x20 )
|
||||
throw std::runtime_error( "Unknown DataType: " + std::to_string( type ) );
|
||||
uint64_t val = xiv::utils::bparse::extract< uint64_t >( iss, "bool" );
|
||||
int32_t shift = type - 0x19;
|
||||
int32_t i = 1 << shift;
|
||||
val &= i;
|
||||
fields.emplace_back( ( val & i ) == i );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sheets[ record_index.id ] = pSheet;
|
||||
}
|
||||
}
|
||||
|
||||
return sheets;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Data indexed by the ID of the row, the vector is field with the same order as exh.members
|
||||
std::map< uint32_t, std::vector< Field>> _data;
|
||||
std::vector< std::shared_ptr< dat::File>> _files;
|
||||
std::map< uint32_t, std::vector< Field > > _data;
|
||||
std::vector< std::shared_ptr< dat::File > > _files;
|
||||
std::shared_ptr< Exh > _exh;
|
||||
std::map< uint32_t, ExdCacheEntry > _idCache;
|
||||
};
|
||||
|
|
18
deps/datReader/Exd/Structs.h
vendored
18
deps/datReader/Exd/Structs.h
vendored
|
@ -302,18 +302,18 @@ namespace Excel
|
|||
uint16_t LimitBreakAction[3];
|
||||
uint16_t PvpLimitBreakAction[3];
|
||||
uint8_t Kind;
|
||||
uint8_t UIPriority;
|
||||
uint8_t Unknown6;
|
||||
uint8_t JobIndex;
|
||||
uint8_t MainClass;
|
||||
uint8_t Role;
|
||||
uint8_t Town;
|
||||
int8_t MonsterNote;
|
||||
int8_t UIPriority;
|
||||
int8_t StartingLevel;
|
||||
uint8_t PartyBuff;
|
||||
int8_t WorkIndex;
|
||||
int8_t BattleClassIndex;
|
||||
int8_t CraftingClassIndex;
|
||||
int8_t Unknown7;
|
||||
int8_t MonsterNote;
|
||||
};
|
||||
|
||||
/* 63507 */
|
||||
|
@ -392,12 +392,13 @@ namespace Excel
|
|||
uint8_t CostType;
|
||||
uint8_t Cond;
|
||||
uint8_t RecastGroup;
|
||||
uint8_t Element;
|
||||
uint8_t ProcStatus;
|
||||
uint8_t UseClassJob;
|
||||
uint8_t Unknown1; // todo: possibly cost type? tp etc?
|
||||
uint8_t ClassJobCategory; // recastgroup
|
||||
uint8_t Init;
|
||||
uint8_t Omen;
|
||||
int8_t Learn;
|
||||
uint8_t Learn;
|
||||
int8_t UseClassJob;
|
||||
int8_t SelectRange;
|
||||
int8_t SelectCorpse;
|
||||
int8_t AttackType;
|
||||
|
@ -429,7 +430,7 @@ namespace Excel
|
|||
uint8_t HideCastBar : 1;
|
||||
uint8_t IsTargetLine : 1;
|
||||
|
||||
int8_t padding0;
|
||||
int8_t unknown;
|
||||
};
|
||||
|
||||
/* 75653 */
|
||||
|
@ -2053,7 +2054,8 @@ namespace Excel
|
|||
uint8_t NotControl : 1;
|
||||
uint8_t NotAction : 1;
|
||||
uint8_t NotMove : 1;
|
||||
uint8_t padding0 : 6;
|
||||
uint8_t padding0 : 5;
|
||||
uint8_t CanOff : 1;
|
||||
uint8_t SemiTransparent : 1;
|
||||
uint8_t FcAction : 1;
|
||||
int8_t padding1[2];
|
||||
|
|
1
deps/datReader/bparse.h
vendored
1
deps/datReader/bparse.h
vendored
|
@ -3,6 +3,7 @@
|
|||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace xiv::utils::bparse
|
||||
{
|
||||
|
|
1
deps/datReaderPs3/bparse.h
vendored
1
deps/datReaderPs3/bparse.h
vendored
|
@ -5,6 +5,7 @@
|
|||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace xivps3::utils::bparse
|
||||
{
|
||||
|
|
1
deps/mysqlConnector/ResultSetBase.h
vendored
1
deps/mysqlConnector/ResultSetBase.h
vendored
|
@ -4,6 +4,7 @@
|
|||
#include <list>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Mysql
|
||||
{
|
||||
|
|
1
deps/mysqlConnector/mysql_util.h
vendored
1
deps/mysqlConnector/mysql_util.h
vendored
|
@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstdint>
|
||||
#include <mysql.h>
|
||||
|
||||
//using MYSQL_FIELD = st_mysql_field;
|
||||
|
|
6
deps/watchdog/Watchdog.h
vendored
6
deps/watchdog/Watchdog.h
vendored
|
@ -32,14 +32,8 @@
|
|||
|
||||
#include <functional>
|
||||
|
||||
// fucking filesystem
|
||||
#if _MSC_VER >= 1925
|
||||
#include <filesystem>
|
||||
namespace ci { namespace fs = std::filesystem; }
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
namespace ci { namespace fs = std::experimental::filesystem; }
|
||||
#endif
|
||||
|
||||
//! Exception for when Watchdog can't locate a file or parse the wildcard
|
||||
class WatchedFileSystemExc : public std::exception {
|
||||
|
|
1
sql/migrations/20230309164293_AddBorrowAction.sql
Normal file
1
sql/migrations/20230309164293_AddBorrowAction.sql
Normal file
|
@ -0,0 +1 @@
|
|||
ALTER TABLE `characlass` ADD `BorrowAction` binary(40) DEFAULT NULL NULL AFTER `Lvl`;
|
|
@ -256,12 +256,14 @@ void PlayerMinimal::saveAsNew()
|
|||
break;
|
||||
}
|
||||
|
||||
// CharacterId, ClassIdx, Exp, Lvl
|
||||
// CharacterId, ClassIdx, Exp, Lvl, BorrowAction
|
||||
auto stmtClass = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_CLASS_INS );
|
||||
stmtClass->setUInt64( 1, m_characterId );
|
||||
stmtClass->setInt( 2, g_exdData.getRow< Excel::ClassJob >( m_class )->data().WorkIndex );
|
||||
stmtClass->setInt( 3, 0 );
|
||||
stmtClass->setInt( 4, 1 );
|
||||
std::vector< uint8_t > borrowActionVec( Common::ARRSIZE_BORROWACTION * 4 );
|
||||
stmtClass->setBinary( 5, borrowActionVec );
|
||||
g_charaDb.directExecute( stmtClass );
|
||||
|
||||
auto stmtSearchInfo = g_charaDb.getPreparedStatement( Db::ZoneDbStatements::CHARA_SEARCHINFO_INS );
|
||||
|
|
|
@ -31,14 +31,8 @@
|
|||
#include <Util/CrashHandler.h>
|
||||
|
||||
|
||||
// fucking filesystem
|
||||
#if _MSC_VER >= 1925
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
#endif
|
||||
|
||||
|
||||
Sapphire::Common::Util::CrashHandler crashHandler;
|
||||
|
@ -244,12 +238,14 @@ void createAccount( shared_ptr< HttpServer::Response > response, shared_ptr< Htt
|
|||
std::string sId;
|
||||
if( g_sapphireAPI.createAccount( user, pass, sId ) )
|
||||
{
|
||||
// todo: construct proper json object here
|
||||
std::string json_string = "{\"sId\":\"" + sId +
|
||||
"\", \"lobbyHost\":\"" +
|
||||
m_config.global.network.lobbyHost +
|
||||
"\", \"frontierHost\":\"" +
|
||||
m_config.global.network.restHost + "\"}";
|
||||
nlohmann::json response_json = {
|
||||
{"sId", sId},
|
||||
{"lobbyHost", m_config.global.network.lobbyHost},
|
||||
{"frontierHost", m_config.global.network.restHost},
|
||||
{"lobbyPort", m_config.global.network.lobbyPort}
|
||||
};
|
||||
|
||||
std::string json_string = response_json.dump();
|
||||
*response << buildHttpResponse( 200, json_string, JSON );
|
||||
}
|
||||
else
|
||||
|
@ -277,12 +273,15 @@ void login( shared_ptr< HttpServer::Response > response, shared_ptr< HttpServer:
|
|||
// reloadConfig();
|
||||
if( g_sapphireAPI.login( user, pass, sId ) )
|
||||
{
|
||||
// todo: build proper json object and stringify it
|
||||
std::string json_string = "{\"sId\":\"" + sId +
|
||||
"\", \"lobbyHost\":\"" +
|
||||
m_config.global.network.lobbyHost +
|
||||
"\", \"frontierHost\":\"" +
|
||||
m_config.global.network.restHost + "\"}";
|
||||
nlohmann::json response_json = {
|
||||
{"sId", sId},
|
||||
{"lobbyHost", m_config.global.network.lobbyHost},
|
||||
{"frontierHost", m_config.global.network.restHost},
|
||||
{"lobbyPort", m_config.global.network.lobbyPort}
|
||||
};
|
||||
|
||||
std::string json_string = response_json.dump();
|
||||
|
||||
*response << buildHttpResponse( 200, json_string, JSON );
|
||||
}
|
||||
else
|
||||
|
@ -294,7 +293,6 @@ void login( shared_ptr< HttpServer::Response > response, shared_ptr< HttpServer:
|
|||
*response << buildHttpResponse( 500 );
|
||||
Logger::error( e.what() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void deleteCharacter( shared_ptr< HttpServer::Response > response, shared_ptr< HttpServer::Request > request )
|
||||
|
|
|
@ -37,6 +37,8 @@ namespace Sapphire::Common
|
|||
const uint16_t ARRSIZE_UNLOCKS = 64u;
|
||||
const uint16_t ARRSIZE_ORCHESTRION = 40u;
|
||||
const uint16_t ARRSIZE_MONSTERNOTE = 12u;
|
||||
const uint16_t ARRSIZE_BORROWACTION = 10u;
|
||||
const uint16_t ARRSIZE_CONDITION = 12u;
|
||||
|
||||
const uint8_t TOWN_COUNT = 6;
|
||||
|
||||
|
@ -887,22 +889,55 @@ namespace Sapphire::Common
|
|||
Perception = 73,
|
||||
|
||||
// Unique modifiers
|
||||
HPPercent = 1000,
|
||||
MPPercent = 1001,
|
||||
TPPercent = 1002,
|
||||
GPPercent = 1003,
|
||||
CPPercent = 1004,
|
||||
PhysicalDamagePercent = 1005,
|
||||
MagicDamagePercent = 1006,
|
||||
AttackPowerPercent = 1007,
|
||||
DefensePercent = 1008,
|
||||
AccuracyPercent = 1009,
|
||||
EvasionPercent = 1010,
|
||||
MagicDefensePercent = 1011,
|
||||
CriticalHitPowerPercent = 1012,
|
||||
CriticalHitResiliencePercent = 1013,
|
||||
CriticalHitPercent = 1014,
|
||||
EnmityPercent = 1015
|
||||
TickHeal = 1000,
|
||||
TickDamage = 1001,
|
||||
StrengthPercent = 1002,
|
||||
DexterityPercent = 1003,
|
||||
VitalityPercent = 1004,
|
||||
IntelligencePercent = 1005,
|
||||
MindPercent = 1006,
|
||||
PietyPercent = 1007,
|
||||
HPPercent = 1008,
|
||||
MPPercent = 1009,
|
||||
TPPercent = 1010,
|
||||
GPPercent = 1011,
|
||||
CPPercent = 1012,
|
||||
PhysicalDamagePercent = 1013,
|
||||
MagicDamagePercent = 1014,
|
||||
AttackPowerPercent = 1015,
|
||||
DefensePercent = 1016,
|
||||
AccuracyPercent = 1017,
|
||||
EvasionPercent = 1018,
|
||||
MagicDefensePercent = 1019,
|
||||
CriticalHitPowerPercent = 1020,
|
||||
CriticalHitResiliencePercent = 1021,
|
||||
CriticalHitPercent = 1022,
|
||||
EnmityPercent = 1023,
|
||||
DamageDealtPercent = 1024,
|
||||
DamageTakenPercent = 1025,
|
||||
HealingMagicRecoveryPercent = 1026,
|
||||
SlashingResistancePercent = 1027,
|
||||
PiercingResistancePercent = 1028,
|
||||
BluntResistancePercent = 1029,
|
||||
ProjectileResistancePercent = 1030,
|
||||
ParryPercent = 1031
|
||||
};
|
||||
|
||||
enum class StatusEffectFlag : uint32_t
|
||||
{
|
||||
BuffCategory = 1,
|
||||
DebuffCategory = 2,
|
||||
Permanent = 4,
|
||||
IsGaze = 8,
|
||||
Transfiguration = 16,
|
||||
CanDispel = 32,
|
||||
LockActions = 64,
|
||||
LockControl = 128,
|
||||
LockMovement = 256,
|
||||
Invisibilty = 512,
|
||||
CanStatusOff = 1024,
|
||||
FcBuff = 2048,
|
||||
RemoveOnSuccessfulHit = 4096
|
||||
};
|
||||
|
||||
enum struct ActionAspect : uint8_t
|
||||
|
@ -923,6 +958,7 @@ namespace Sapphire::Common
|
|||
MagicPoints = 3,
|
||||
TacticsPoints = 5,
|
||||
TacticsPoints1 = 6,
|
||||
StatusEffect = 10,
|
||||
Sprint = 18,
|
||||
// WARGauge = 22,
|
||||
// DRKGauge = 25,
|
||||
|
@ -948,77 +984,67 @@ namespace Sapphire::Common
|
|||
LimitBreak = 8,
|
||||
};
|
||||
|
||||
enum ActionEffectType : uint8_t
|
||||
enum CalcResultType : uint8_t
|
||||
{
|
||||
CALC_RESULT_TYPE_NONE = 0x0,
|
||||
CALC_RESULT_TYPE_MISS = 0x1,
|
||||
CALC_RESULT_TYPE_RESIST = 0x2,
|
||||
CALC_RESULT_TYPE_DAMAGE_HP = 0x3,
|
||||
CALC_RESULT_TYPE_RECOVER_HP = 0x4,
|
||||
CALC_RESULT_TYPE_CRITICAL_DAMAGE_HP = 0x5,
|
||||
CALC_RESULT_TYPE_CRITICAL_RECOVER_HP = 0x6,
|
||||
CALC_RESULT_TYPE_GUARD = 0x7,
|
||||
CALC_RESULT_TYPE_PARRY = 0x8,
|
||||
CALC_RESULT_TYPE_INVALID = 0x9,
|
||||
CALC_RESULT_TYPE_UNEFFECTIVE = 0xA,
|
||||
CALC_RESULT_TYPE_NEGLECT = 0xB,
|
||||
CALC_RESULT_TYPE_DAMAGE_MP = 0xC,
|
||||
CALC_RESULT_TYPE_RECOVER_MP = 0xD,
|
||||
CALC_RESULT_TYPE_DAMAGE_TP = 0xE,
|
||||
CALC_RESULT_TYPE_RECOVER_TP = 0xF,
|
||||
CALC_RESULT_TYPE_RECOVER_GP = 0x10,
|
||||
CALC_RESULT_TYPE_SET_STATUS = 0x11,
|
||||
CALC_RESULT_TYPE_SET_STATUS_ME = 0x12,
|
||||
CALC_RESULT_TYPE_RESET_STATUS = 0x13,
|
||||
CALC_RESULT_TYPE_RESET_STATUS_ME = 0x14,
|
||||
CALC_RESULT_TYPE_RESET_BAD_STATUS = 0x15,
|
||||
CALC_RESULT_TYPE_UNEFFECTIVE_STATUS = 0x16,
|
||||
CALC_RESULT_TYPE_HALF_GOOD_STATUS = 0x17,
|
||||
CALC_RESULT_TYPE_HATE_DIRECT = 0x18,
|
||||
CALC_RESULT_TYPE_HATE_INDIRECTION = 0x19,
|
||||
CALC_RESULT_TYPE_HATE_TOP = 0x1A,
|
||||
CALC_RESULT_TYPE_HATE_ADD = 0x1B,
|
||||
CALC_RESULT_TYPE_HATE_MULT = 0x1C,
|
||||
CALC_RESULT_TYPE_COMBO = 0x1D,
|
||||
CALC_RESULT_TYPE_COMBO_HIT = 0x1E,
|
||||
CALC_RESULT_TYPE_COUNTER = 0x1F,
|
||||
CALC_RESULT_TYPE_DESTRUCT = 0x20,
|
||||
CALC_RESULT_TYPE_PARALYSIS = 0x21,
|
||||
CALC_RESULT_TYPE_KNOCK_BACK = 0x22,
|
||||
CALC_RESULT_TYPE_DRAW_UP_CHAIRS = 0x23,
|
||||
CALC_RESULT_TYPE_SUCKED = 0x24,
|
||||
CALC_RESULT_TYPE_CT_DRAW_UP_CHAIRS = 0x25,
|
||||
CALC_RESULT_TYPE_LIVE_CALLBACK = 0x26,
|
||||
CALC_RESULT_TYPE_MOUNT = 0x27,
|
||||
CALC_RESULT_ARCHER_DOT = 0x28,
|
||||
CALC_RESULT_MASTER_DOT = 0x29,
|
||||
CALC_RESULT_BLESSINGS_OF_GODDESS = 0x2A,
|
||||
CALC_RESULT_BAD_BREATH = 0x2B,
|
||||
CALC_RESULT_REVIVAL = 0x2C,
|
||||
CALC_RESULT_PET = 0x2D,
|
||||
CALC_RESULT_TYPE_BLOW = 0x2E,
|
||||
CALC_RESULT_TYPE_STATUS_RESIST = 0x2F,
|
||||
CALC_RESULT_TYPE_CLEAR_PHYSICAL = 0x30,
|
||||
CALC_RESULT_BNPC_STATE = 0x31,
|
||||
CALC_RESULT_TYPE_VFX = 0x32,
|
||||
CALC_RESULT_TYPE_HARD_CODE = 0x33,
|
||||
CALC_RESULT_CALC_ID = 0x34,
|
||||
CALC_RESULT_TYPE_CLEAR_PVP_POINT = 0x35,
|
||||
CALC_RESULT_TYPE_CHECK_BARRIER = 0x36,
|
||||
CALC_RESULT_TYPE_REFLEC = 0x37,
|
||||
TypeNone = 0x0,
|
||||
TypeMiss = 0x1,
|
||||
TypeResist = 0x2,
|
||||
TypeDamageHp = 0x3,
|
||||
TypeRecoverHp = 0x4,
|
||||
TypeCriticalDamageHp = 0x5,
|
||||
TypeCriticalRecoverHp = 0x6,
|
||||
TypeGuard = 0x7,
|
||||
TypeParry = 0x8,
|
||||
TypeInvalid = 0x9,
|
||||
TypeUneffective = 0xA,
|
||||
TypeNeglect = 0xB,
|
||||
TypeDamageMp = 0xC,
|
||||
TypeRecoverMp = 0xD,
|
||||
TypeDamageTp = 0xE,
|
||||
TypeRecoverTp = 0xF,
|
||||
TypeRecoverGp = 0x10,
|
||||
TypeSetStatus = 0x11,
|
||||
TypeSetStatusMe = 0x12,
|
||||
TypeResetStatus = 0x13,
|
||||
TypeResetStatusMe = 0x14,
|
||||
TypeResetBadStatus = 0x15,
|
||||
TypeUneffectiveStatus = 0x16,
|
||||
TypeHalfGoodStatus = 0x17,
|
||||
TypeHateDirect = 0x18,
|
||||
TypeHateIndirection = 0x19,
|
||||
TypeHateTop = 0x1A,
|
||||
TypeHateAdd = 0x1B,
|
||||
TypeHateMult = 0x1C,
|
||||
TypeCombo = 0x1D,
|
||||
TypeComboHit = 0x1E,
|
||||
TypeCounter = 0x1F,
|
||||
TypeDestruct = 0x20,
|
||||
TypeParalysis = 0x21,
|
||||
TypeKnockBack = 0x22,
|
||||
TypeDrawUpChairs = 0x23,
|
||||
TypeSucked = 0x24,
|
||||
TypeCtDrawUpChairs = 0x25,
|
||||
TypeLiveCallback = 0x26,
|
||||
TypeMount = 0x27,
|
||||
TypeArcherDot = 0x28,
|
||||
TypeMasterDot = 0x29,
|
||||
TypeBlessingOfGoddess = 0x2A,
|
||||
TypeBadBreath = 0x2B,
|
||||
TypeRevival = 0x2C,
|
||||
TypePet = 0x2D,
|
||||
TypeBlow = 0x2E,
|
||||
TypeStatusResist = 0x2F,
|
||||
TypeClearPhysical = 0x30,
|
||||
TypeBNpcState = 0x31,
|
||||
TypeVfx = 0x32,
|
||||
TypeHardCode = 0x33,
|
||||
TypeCalcId = 0x34,
|
||||
TypeClearPvpPoint = 0x35,
|
||||
TypeCheckBarrier = 0x36,
|
||||
TypeReflect = 0x37,
|
||||
};
|
||||
|
||||
enum class ActionHitSeverityType : uint8_t
|
||||
{
|
||||
NormalDamage = 0,
|
||||
CritHeal = 0,
|
||||
CritDamage = 1,
|
||||
NormalHeal = 1,
|
||||
DirectHitDamage = 2,
|
||||
CritDirectHitDamage = 3
|
||||
};
|
||||
|
||||
enum class ActionEffectResultFlag : uint8_t
|
||||
enum class ActionResultFlag : uint8_t
|
||||
{
|
||||
None = 0,
|
||||
Absorbed = 0x04,
|
||||
|
@ -1033,6 +1059,7 @@ namespace Sapphire::Common
|
|||
ItemActionCompanion = 853,
|
||||
ItemActionVFX2 = 944,
|
||||
ItemActionMount = 1322,
|
||||
ItemActionSong = 5845,
|
||||
};
|
||||
|
||||
enum ActionEffectDisplayType : uint8_t
|
||||
|
@ -1383,9 +1410,10 @@ namespace Sapphire::Common
|
|||
{
|
||||
None1 = 0,
|
||||
HideUILockChar = 1, // as the name suggests, hides the ui and logs the char...
|
||||
InCombat = 2, // in Combat, locks gearchange/return/teleport
|
||||
Casting = 3,
|
||||
InNpcEvent = 6, // when talking to an npc, locks ui giving "occupied" message
|
||||
InCombat = 18, // in Combat, locks gearchange/return/teleport
|
||||
Casting = 19,
|
||||
EventAction = 22,
|
||||
InNpcEvent = 24, // when talking to an npc, locks ui giving "occupied" message
|
||||
|
||||
// InNpcEvent1 = 10, // Sent together with InNpcEvent, when waiting for input? just a guess...
|
||||
|
||||
|
@ -1798,6 +1826,7 @@ namespace Sapphire::Common
|
|||
{
|
||||
uint16_t targetAetheryte;
|
||||
uint16_t cost;
|
||||
bool useAetheryteTicket{ false };
|
||||
};
|
||||
|
||||
enum EventSceneError : uint8_t
|
||||
|
@ -1833,12 +1862,13 @@ namespace Sapphire::Common
|
|||
THREAT
|
||||
};
|
||||
|
||||
// todo: fill this out (Action.exd EffectType)
|
||||
enum CastType : uint8_t
|
||||
{
|
||||
SingleTarget = 1,
|
||||
CircularAOE = 2,
|
||||
Type3 = 3, // another single target? no idea how to call it
|
||||
RectangularAOE = 4,
|
||||
RectangularAOE = 3,
|
||||
ConeAOE = 4,
|
||||
CircularAoEPlaced = 7
|
||||
};
|
||||
|
||||
|
@ -1856,6 +1886,7 @@ namespace Sapphire::Common
|
|||
|
||||
using PlayerStateFlagList = std::vector< PlayerCondition >;
|
||||
|
||||
// todo: load BNpcBase and other exd data into this struct
|
||||
struct BNPCInstanceObject
|
||||
{
|
||||
uint16_t territoryType;
|
||||
|
|
|
@ -2,13 +2,8 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#if _MSC_VER >= 1925
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
#endif
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::Common;
|
||||
|
@ -94,4 +89,4 @@ bool ConfigMgr::copyDefaultConfig( const std::string& configName )
|
|||
fs::copy_file( configPath.string() + m_configDefaultSuffix, configPath );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
namespace Sapphire::Common::Util
|
||||
{
|
||||
|
|
|
@ -161,11 +161,11 @@ void Sapphire::Db::ZoneDbConnection::doPrepareStatements()
|
|||
prepareStatement( CHARA_SEL_QUEST, "SELECT * FROM charaquest WHERE CharacterId = ?;", CONNECTION_SYNC );
|
||||
|
||||
/// CLASS INFO
|
||||
prepareStatement( CHARA_CLASS_SEL, "SELECT ClassIdx, Exp, Lvl FROM characlass WHERE CharacterId = ?;",
|
||||
prepareStatement( CHARA_CLASS_SEL, "SELECT ClassIdx, Exp, Lvl, BorrowAction FROM characlass WHERE CharacterId = ?;",
|
||||
CONNECTION_SYNC );
|
||||
prepareStatement( CHARA_CLASS_INS, "INSERT INTO characlass ( CharacterId, ClassIdx, Exp, Lvl ) VALUES( ?,?,?,? );",
|
||||
prepareStatement( CHARA_CLASS_INS, "INSERT INTO characlass ( CharacterId, ClassIdx, Exp, Lvl, BorrowAction ) VALUES( ?,?,?,?,? );",
|
||||
CONNECTION_BOTH );
|
||||
prepareStatement( CHARA_CLASS_UP, "UPDATE characlass SET Exp = ?, Lvl = ? WHERE CharacterId = ? AND ClassIdx = ?;",
|
||||
prepareStatement( CHARA_CLASS_UP, "UPDATE characlass SET Exp = ?, Lvl = ?, BorrowAction = ? WHERE CharacterId = ? AND ClassIdx = ?;",
|
||||
CONNECTION_ASYNC );
|
||||
prepareStatement( CHARA_CLASS_DEL, "DELETE FROM characlass WHERE CharacterId = ?;", CONNECTION_ASYNC );
|
||||
|
||||
|
|
|
@ -91,6 +91,27 @@ namespace Sapphire::Data
|
|||
return ids;
|
||||
}
|
||||
|
||||
template< typename T >
|
||||
std::unordered_map< uint32_t, std::shared_ptr< Excel::ExcelStruct< T > > > getRows()
|
||||
{
|
||||
xiv::exd::Exd sheet;
|
||||
auto needle = m_sheets.find( typeid( T ) );
|
||||
if( needle == m_sheets.end() )
|
||||
{
|
||||
auto sheetName = getSheetName< T >();
|
||||
|
||||
// load sheet
|
||||
auto& cat = m_exd_data->get_category( sheetName );
|
||||
m_sheets[ typeid( T ) ] = sheet = static_cast< xiv::exd::Exd >( cat.get_data( xiv::exd::Language::en ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
sheet = needle->second;
|
||||
}
|
||||
|
||||
return sheet.get_sheet_rows< T >();
|
||||
}
|
||||
|
||||
std::shared_ptr< xiv::dat::GameData > getGameData()
|
||||
{
|
||||
return m_data;
|
||||
|
|
|
@ -8,13 +8,8 @@
|
|||
#include <spdlog/sinks/daily_file_sink.h>
|
||||
|
||||
// #include <iostream>
|
||||
#if _MSC_VER >= 1925
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
#endif
|
||||
|
||||
|
||||
void Sapphire::Logger::init( const std::string& logPath )
|
||||
|
|
|
@ -39,8 +39,12 @@ float Util::distance2D( float x, float y, float x1, float y1 )
|
|||
|
||||
float Util::calcAngTo( float x, float y, float x1, float y1 )
|
||||
{
|
||||
float dx = x - x1;
|
||||
float dy = y - y1;
|
||||
float dx = x1 - x;
|
||||
float dy = y1 - y;
|
||||
|
||||
if( dx == 0.0f && dy == 0.0f )
|
||||
return 0.0f;
|
||||
|
||||
if( dy != 0.0f )
|
||||
{
|
||||
return atan2( dy, dx );
|
||||
|
@ -55,6 +59,10 @@ float Util::calcAngFrom( float x, float y, float x1, float y1 )
|
|||
{
|
||||
float dx = x - x1;
|
||||
float dy = y - y1;
|
||||
|
||||
if( dx == 0.0f && dy == 0.0f )
|
||||
return 0.0f;
|
||||
|
||||
if( dy != 0.0f )
|
||||
{
|
||||
return atan2( dy, dx );
|
||||
|
@ -80,6 +88,39 @@ uint8_t Util::floatToUInt8Rot( float val )
|
|||
return static_cast< uint8_t >( 0x80 * ( ( val + PI ) ) / PI );
|
||||
}
|
||||
|
||||
FFXIVARR_POSITION3 Util::getOffsettedPosition( const FFXIVARR_POSITION3& pos, float rot, float right, float up, float forward )
|
||||
{
|
||||
FFXIVARR_POSITION3 ret{ pos };
|
||||
|
||||
// height
|
||||
ret.y += up;
|
||||
|
||||
// forward
|
||||
float angle = rot + ( PI / 2 );
|
||||
ret.x -= forward * cos( angle );
|
||||
ret.z += forward * sin( angle );
|
||||
|
||||
// side
|
||||
ret.x -= right * cos( rot );
|
||||
ret.z += right * sin( rot );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
FFXIVARR_POSITION3 Util::getKnockbackPosition( const FFXIVARR_POSITION3& origin, const FFXIVARR_POSITION3& pos, float distance )
|
||||
{
|
||||
FFXIVARR_POSITION3 ret{ pos };
|
||||
|
||||
float from = Common::Util::calcAngFrom( origin.x, origin.z, pos.x, pos.z );
|
||||
float angle = PI - from + ( PI / 2 );
|
||||
|
||||
angle = angle + ( PI / 2 );
|
||||
ret.x -= distance * cos( angle );
|
||||
ret.z += distance * sin( angle );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
FFXIVARR_POSITION3 Util::transform( const FFXIVARR_POSITION3& vector, const Matrix33& matrix )
|
||||
{
|
||||
FFXIVARR_POSITION3 dst{};
|
||||
|
@ -143,3 +184,23 @@ float Util::trunc( float value, uint8_t digitsToRemain )
|
|||
|
||||
return std::floor( value * factor ) / factor;
|
||||
}
|
||||
|
||||
float Util::length( const FFXIVARR_POSITION3& vec ) {
|
||||
return std::sqrt( vec.x * vec.x + vec.y * vec.y + vec.z * vec.z );
|
||||
}
|
||||
|
||||
FFXIVARR_POSITION3 Util::normalize( const FFXIVARR_POSITION3& vec ) {
|
||||
float len = length( vec );
|
||||
if( len == 0 ) return FFXIVARR_POSITION3();
|
||||
return FFXIVARR_POSITION3{ vec.x / len, vec.y / len, vec.z / len };
|
||||
}
|
||||
|
||||
float Util::dot( const FFXIVARR_POSITION3& vec1, const FFXIVARR_POSITION3& vec2 )
|
||||
{
|
||||
return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;
|
||||
}
|
||||
|
||||
FFXIVARR_POSITION3 Util::projectY( const FFXIVARR_POSITION3& vec )
|
||||
{
|
||||
return FFXIVARR_POSITION3{ vec.x, 0, vec.z };
|
||||
}
|
|
@ -29,6 +29,10 @@ namespace Sapphire::Common::Util
|
|||
|
||||
uint8_t floatToUInt8Rot( float val );
|
||||
|
||||
FFXIVARR_POSITION3 getOffsettedPosition( const FFXIVARR_POSITION3& pos, float rotation, float right, float up, float forward );
|
||||
|
||||
FFXIVARR_POSITION3 getKnockbackPosition( const FFXIVARR_POSITION3& origin, const FFXIVARR_POSITION3& pos, float distance );
|
||||
|
||||
template < typename T >
|
||||
T clamp( T val, T minimum, T maximum )
|
||||
{
|
||||
|
@ -44,6 +48,14 @@ namespace Sapphire::Common::Util
|
|||
FFXIVARR_POSITION3 transform( const FFXIVARR_POSITION3& vector, const Matrix33& matrix );
|
||||
|
||||
float eulerToDirection( const FFXIVARR_POSITION3& euler );
|
||||
|
||||
float length( const FFXIVARR_POSITION3& vec );
|
||||
|
||||
FFXIVARR_POSITION3 normalize( const FFXIVARR_POSITION3& vec );
|
||||
|
||||
float dot( const FFXIVARR_POSITION3& vec1, const FFXIVARR_POSITION3& vec2 );
|
||||
|
||||
FFXIVARR_POSITION3 projectY( const FFXIVARR_POSITION3& vec );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,8 +7,17 @@ inline bool FFXIVARR_POSITION3::operator == ( const FFXIVARR_POSITION3& target )
|
|||
return x == target.x && y == target.y && z == target.z;
|
||||
}
|
||||
|
||||
FFXIVARR_POSITION3 FFXIVARR_POSITION3::operator - ( const FFXIVARR_POSITION3& target ) const
|
||||
{
|
||||
return FFXIVARR_POSITION3{ x - target.x, y - target.y, z - target.z };
|
||||
}
|
||||
|
||||
inline bool Vector3::operator == ( const Vector3& target ) const
|
||||
{
|
||||
return x == target.x && y == target.y && z == target.z && reserve == target.reserve;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 Vector3::operator - ( const Vector3& target ) const
|
||||
{
|
||||
return Vector3{ x - target.x, y - target.y, z - target.z };
|
||||
}
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
namespace Sapphire::Common
|
||||
{
|
||||
// todo: get rid of this struct and use an actual vector 3 class
|
||||
struct FFXIVARR_POSITION3
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
inline bool operator == ( const FFXIVARR_POSITION3& target ) const;
|
||||
FFXIVARR_POSITION3 operator - ( const FFXIVARR_POSITION3& target ) const;
|
||||
};
|
||||
|
||||
struct Vector3
|
||||
|
@ -17,6 +19,8 @@ namespace Sapphire::Common
|
|||
float z;
|
||||
float reserve;
|
||||
inline bool operator == ( const Vector3& target ) const;
|
||||
inline bool operator == ( const FFXIVARR_POSITION3& target ) const;
|
||||
Vector3 operator - ( const Vector3& target ) const;
|
||||
};
|
||||
|
||||
struct Matrix33
|
||||
|
|
|
@ -11,14 +11,8 @@
|
|||
using namespace Sapphire;
|
||||
using namespace Sapphire::Common;
|
||||
|
||||
// fucking filesystem
|
||||
#if _MSC_VER >= 1925
|
||||
#include <filesystem>
|
||||
namespace fs = std::filesystem;
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
#endif
|
||||
|
||||
|
||||
DbManager::DbManager( const std::string& host, const std::string& database, const std::string& user, const std::string& pw, uint16_t port ) :
|
||||
|
|
|
@ -9,14 +9,8 @@
|
|||
|
||||
Sapphire::Common::Util::CrashHandler crashHandler;
|
||||
|
||||
// fucking filesystem
|
||||
#if _MSC_VER >= 1925
|
||||
#include <filesystem>
|
||||
namespace filesys = std::filesystem;
|
||||
#else
|
||||
#include <experimental/filesystem>
|
||||
namespace filesys = std::experimental::filesystem;
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <streambuf>
|
||||
|
|
|
@ -17,10 +17,7 @@ public:
|
|||
return;
|
||||
|
||||
uint32_t duration = ( sourceChara->getAsPlayer()->getTp() / 50 ) * 1000;
|
||||
|
||||
action.getEffectbuilder()->applyStatusEffect( sourceChara, 50, 30 );
|
||||
|
||||
sourceChara->getAsPlayer()->addStatusEffectByIdIfNotExist( 50, duration, *sourceChara, 30 );
|
||||
action.getActionResultBuilder()->applyStatusEffectSelf( 50, duration, 30, false );
|
||||
sourceChara->getAsPlayer()->setTp( 0 );
|
||||
}
|
||||
};
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
auto teleportQuery = pPlayer->getTeleportQuery();
|
||||
|
||||
if( pPlayer->getCurrency( Common::CurrencyType::Gil ) < teleportQuery.cost ||
|
||||
teleportQuery.useAetheryteTicket && !pPlayer->removeItem( 7569 ) ||
|
||||
teleportQuery.targetAetheryte == 0 )
|
||||
{
|
||||
action.interrupt();
|
||||
|
|
47
src/scripts/action/war/ActionInnerBeast.cpp
Normal file
47
src/scripts/action/war/ActionInnerBeast.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include <Script/NativeScriptApi.h>
|
||||
#include <ScriptObject.h>
|
||||
#include <Actor/Player.h>
|
||||
#include <Action/CommonAction.h>
|
||||
#include <Action/Action.h>
|
||||
#include <StatusEffect/StatusEffect.h>
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::World::Action;
|
||||
|
||||
class ActionInnerBeast : public Sapphire::ScriptAPI::ActionScript
|
||||
{
|
||||
public:
|
||||
ActionInnerBeast() : Sapphire::ScriptAPI::ActionScript( 49 )
|
||||
{
|
||||
}
|
||||
|
||||
static constexpr auto Potency = 300;
|
||||
|
||||
void onExecute( Sapphire::World::Action::Action& action ) override
|
||||
{
|
||||
auto pPlayer = action.getSourceChara()->getAsPlayer();
|
||||
auto pSource = action.getSourceChara();
|
||||
auto pTarget = action.getHitChara();
|
||||
auto pActionBuilder = action.getActionResultBuilder();
|
||||
|
||||
if( !pPlayer || !pActionBuilder )
|
||||
return;
|
||||
|
||||
if( auto status = pPlayer->getStatusEffectById( Defiance ); status )
|
||||
status->setModifier( Common::ParamModifier::DamageDealtPercent, 0 );
|
||||
|
||||
auto dmg = action.calcDamage( Potency );
|
||||
pActionBuilder->damage( pSource, pTarget, dmg.first, dmg.second );
|
||||
pActionBuilder->heal( pTarget, pSource, dmg.first, Common::CalcResultType::TypeRecoverHp, Common::ActionResultFlag::EffectOnSource );
|
||||
|
||||
pActionBuilder->applyStatusEffectSelf( InnerBeast, 15000, 0, { StatusModifier{ Common::ParamModifier::DamageTakenPercent, -20 } } );
|
||||
|
||||
if( !pPlayer->hasStatusEffect( Unchained ) )
|
||||
{
|
||||
if( auto status = pPlayer->getStatusEffectById( Defiance ); status )
|
||||
status->setModifier( Common::ParamModifier::DamageDealtPercent, -25 );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( ActionInnerBeast );
|
33
src/scripts/action/war/ActionUnchained.cpp
Normal file
33
src/scripts/action/war/ActionUnchained.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include <Script/NativeScriptApi.h>
|
||||
#include <ScriptObject.h>
|
||||
#include <Actor/Player.h>
|
||||
#include <Action/CommonAction.h>
|
||||
#include <Action/Action.h>
|
||||
#include <StatusEffect/StatusEffect.h>
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::World::Action;
|
||||
|
||||
class ActionUnchained : public Sapphire::ScriptAPI::ActionScript
|
||||
{
|
||||
public:
|
||||
ActionUnchained() : Sapphire::ScriptAPI::ActionScript( 50 )
|
||||
{
|
||||
}
|
||||
|
||||
void onExecute( Sapphire::World::Action::Action& action ) override
|
||||
{
|
||||
auto pPlayer = action.getSourceChara()->getAsPlayer();
|
||||
auto pActionBuilder = action.getActionResultBuilder();
|
||||
|
||||
if( !pPlayer || !pActionBuilder )
|
||||
return;
|
||||
|
||||
if( auto status = pPlayer->getStatusEffectById( Defiance ); status )
|
||||
status->setModifier( Common::ParamModifier::DamageDealtPercent, 0 );
|
||||
|
||||
pActionBuilder->applyStatusEffectSelf( Unchained, 20000, 0 );
|
||||
}
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( ActionUnchained );
|
|
@ -62,10 +62,18 @@ public:
|
|||
// eventParam4 (or params[1] if using EventPlay8, which is actually used on retail) anything bigger than 1 will show select instance menu item
|
||||
eventMgr().playScene( player, eventId, 0, 1, { 1, 2 }, [ this ]( Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.numOfResults == 1 ) // set homepoint
|
||||
if( result.numOfResults == 1 )
|
||||
{
|
||||
player.setHomepoint( result.eventId & 0xFFFF );
|
||||
eventMgr().sendEventNotice( player, result.eventId, 2, 0xEA, 0, 0 );
|
||||
auto cmd = result.getResult( 0 );
|
||||
if( cmd == 1 ) // set homepoint
|
||||
{
|
||||
player.setHomepoint( result.eventId & 0xFFFF );
|
||||
eventMgr().sendEventNotice( player, result.eventId, 2, 0xEA, 0, 0 );
|
||||
}
|
||||
else if( cmd == 5 )
|
||||
{
|
||||
//TODO: Housing teleport selection
|
||||
}
|
||||
}
|
||||
else if( result.numOfResults == 2 ) // aethernet access
|
||||
{
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
eventMgr().playScene( player, eventId, 1, 0, [this, eobj]( Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) != 1 )
|
||||
player.exitInstance();
|
||||
playerMgr().onExitInstance( player );
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -100,15 +103,126 @@ public:
|
|||
instance.addEObj( "Millioncornseedling", 2001255, 0, 3927161, 4, { -320.576813f, 25.833500f, -527.550171f }, 0.961304f, -0.384837f, 0);
|
||||
|
||||
}
|
||||
enum vars
|
||||
{
|
||||
SET_1_SPAWNED,
|
||||
SET_2_SPAWNED,
|
||||
SUCCESS_CALLED,
|
||||
};
|
||||
|
||||
void onPlayerSetup( Sapphire::QuestBattle& instance, Entity::Player& player ) override
|
||||
{
|
||||
player.setRot( -71.03f );
|
||||
player.setPos( { 198.303f, 14.244f, 538.248f } );
|
||||
}
|
||||
|
||||
void onUpdate( QuestBattle& instance, uint64_t tickCount ) override
|
||||
{
|
||||
auto pair1Spawnd = instance.getDirectorVar( SET_1_SPAWNED );
|
||||
auto pair2Spawnd = instance.getDirectorVar( SET_2_SPAWNED );
|
||||
auto successCalled = instance.getDirectorVar( SUCCESS_CALLED );
|
||||
|
||||
auto boss = instance.getActiveBNpcByLayoutId( INIT_POP_BOSS );
|
||||
auto thancred = instance.getActiveBNpcByLayoutId( INIT_P_POP_01 );
|
||||
auto pPlayer = instance.getPlayerPtr();
|
||||
|
||||
uint32_t bossHpPercent = 0;
|
||||
if( boss )
|
||||
bossHpPercent = boss->getHpPercent();
|
||||
|
||||
if( pPlayer && !pPlayer->isAlive() )
|
||||
{
|
||||
instance.fail();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!thancred)
|
||||
return;
|
||||
|
||||
if( pair1Spawnd == 0 && bossHpPercent <= 70 )
|
||||
{
|
||||
instance.setDirectorVar( SET_1_SPAWNED, 1 );
|
||||
auto a2 = instance.createBNpcFromLayoutId( INIT_POP_01_01, 1440 /*TODO: Find the right value*/, Common::BNpcType::Enemy );
|
||||
auto a3 = instance.createBNpcFromLayoutId( INIT_POP_01_02, 1440 /*TODO: Find the right value*/, Common::BNpcType::Enemy );
|
||||
a2->setFlag( Entity::NoDeaggro );
|
||||
a3->setFlag( Entity::NoDeaggro );
|
||||
|
||||
auto pPlayer = instance.getPlayerPtr();
|
||||
a2->hateListAdd( pPlayer, 1 );
|
||||
a3->hateListAdd( pPlayer, 1 );
|
||||
|
||||
thancred->hateListAdd( a2, 9999 );
|
||||
thancred->hateListAdd( a3, 9999 );
|
||||
}
|
||||
|
||||
if( pair2Spawnd == 0 && bossHpPercent <= 40 )
|
||||
{
|
||||
instance.setDirectorVar( SET_2_SPAWNED, 1 );
|
||||
auto a2 = instance.createBNpcFromLayoutId( INIT_POP_02_01, 1440 /*TODO: Find the right value*/, Common::BNpcType::Enemy );
|
||||
auto a3 = instance.createBNpcFromLayoutId( INIT_POP_02_02, 1440 /*TODO: Find the right value*/, Common::BNpcType::Enemy );
|
||||
auto a4 = instance.createBNpcFromLayoutId( INIT_POP_02_03, 1440 /*TODO: Find the right value*/, Common::BNpcType::Enemy );
|
||||
auto a5 = instance.createBNpcFromLayoutId( INIT_POP_02_04, 1440 /*TODO: Find the right value*/, Common::BNpcType::Enemy );
|
||||
a2->setFlag( Entity::NoDeaggro );
|
||||
a3->setFlag( Entity::NoDeaggro );
|
||||
a4->setFlag( Entity::NoDeaggro );
|
||||
a5->setFlag( Entity::NoDeaggro );
|
||||
|
||||
auto pPlayer = instance.getPlayerPtr();
|
||||
a2->hateListAdd( pPlayer, 1 );
|
||||
a3->hateListAdd( pPlayer, 1 );
|
||||
a4->hateListAdd( pPlayer, 1 );
|
||||
a5->hateListAdd( pPlayer, 1 );
|
||||
|
||||
thancred->hateListAdd( a2, 9999 );
|
||||
thancred->hateListAdd( a3, 9999 );
|
||||
thancred->hateListAdd( a4, 9999 );
|
||||
thancred->hateListAdd( a5, 9999 );
|
||||
}
|
||||
|
||||
if( instance.getCountEnemyBNpc() == 0 && successCalled == 0 )
|
||||
{
|
||||
instance.setDirectorVar( SUCCESS_CALLED, 1 );
|
||||
instance.success();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
// TODO: Change to correct HP values
|
||||
auto boss = instance.createBNpcFromLayoutId( INIT_POP_BOSS, 10571 /*TODO: Find the right value*/, Common::BNpcType::Enemy );
|
||||
auto thancred = instance.createBNpcFromLayoutId( INIT_P_POP_01, 27780 /*TODO: Find the right value*/, Common::BNpcType::Friendly );
|
||||
|
||||
boss->setFlag( Entity::NoDeaggro );
|
||||
thancred->setFlag( Entity::NoDeaggro );
|
||||
|
||||
boss->hateListAdd( thancred, 10000 );
|
||||
boss->hateListAdd( player.getAsPlayer(), 1 );
|
||||
|
||||
thancred->hateListAdd( boss, 10000 );
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -823,7 +823,7 @@ private:
|
|||
quest.setSeq( Seq6 );
|
||||
eventMgr().sendEventNotice( player, getId(), 4, 0 );
|
||||
playerMgr().sendUrgent( player, "QuestBattle Unimplemented, skipping..." );
|
||||
player.exitInstance();
|
||||
playerMgr().onExitInstance( player );
|
||||
travelToPoprange( player, Poprange3, false );
|
||||
}
|
||||
|
||||
|
|
318
src/scripts/quest/ManWil005.cpp
Normal file
318
src/scripts/quest/ManWil005.cpp
Normal file
|
@ -0,0 +1,318 @@
|
|||
// 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 <Actor/Player.h>
|
||||
#include "Manager/EventMgr.h"
|
||||
#include <ScriptObject.h>
|
||||
#include <Service.h>
|
||||
|
||||
// Quest Script: ManWil005_00550
|
||||
// Quest Name: Underneath the Sultantree
|
||||
// Quest ID: 66086
|
||||
// Start NPC: 1003995 (Papashan)
|
||||
// End NPC: 1003995 (Papashan)
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
class ManWil005 : public Sapphire::ScriptAPI::QuestScript
|
||||
{
|
||||
private:
|
||||
// Basic quest information
|
||||
// Quest vars / flags used
|
||||
// BitFlag8
|
||||
// UI8AL
|
||||
|
||||
/// Countable Num: 1 Seq: 1 Event: 1 Listener: 1003996
|
||||
/// Countable Num: 1 Seq: 2 Event: 1 Listener: 2001853
|
||||
/// Countable Num: 0 Seq: 255 Event: 15 Listener: 5020000
|
||||
// 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 = 1003995; // Papashan ( Pos: 75.338402 2.138110 316.362000 Teri: 141 )
|
||||
static constexpr auto Actor1 = 1003996; // Hooded Lalafell ( Pos: 202.662994 14.104900 536.909973 Teri: 141 )
|
||||
static constexpr auto Actor2 = 1003997; // ×次女a ( Pos: 76.674599 2.137120 317.433014 Teri: 141 )
|
||||
static constexpr auto Actor3 = 1003998; // ×近衛a ( Pos: 77.176598 2.137340 315.631989 Teri: 141 )
|
||||
static constexpr auto Actor4 = 1003999; // ×近衛b ( Pos: 77.310501 2.136910 316.973999 Teri: 141 )
|
||||
static constexpr auto Actor5 = 1004000; // ×近衛c ( Pos: 78.402603 2.136520 316.269012 Teri: 141 )
|
||||
static constexpr auto Actor6 = 1004001; // Lilira ( Pos: 76.643402 2.136930 318.191010 Teri: 141 )
|
||||
static constexpr auto Actor20 = 1006171; // Lilira
|
||||
static constexpr auto Actor30 = 1006167; // 侍女a
|
||||
static constexpr auto Actor40 = 1006168; // 近衛a
|
||||
static constexpr auto Actor50 = 1006169; // 近衛b
|
||||
static constexpr auto Actor60 = 1006170; // 近衛c
|
||||
static constexpr auto CutScene02 = 141;
|
||||
static constexpr auto CutScene03 = 56;
|
||||
static constexpr auto CutScene04 = 142;
|
||||
static constexpr auto Eobject0 = 2001853; // ( Pos: 202.638000 14.137900 536.905029 Teri: 141 )
|
||||
static constexpr auto EventActionSearch = 1; // Interaction
|
||||
static constexpr auto Questbattle0 = 37;
|
||||
static constexpr auto Seq0Actor0Lq = 50; // Goblin Thug
|
||||
static constexpr auto Territorytype0 = 270;
|
||||
static constexpr auto Territorytype1 = 141;
|
||||
|
||||
public:
|
||||
ManWil005() : Sapphire::ScriptAPI::QuestScript( 66086 ){};
|
||||
~ManWil005() = 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() == SeqFinish)
|
||||
{
|
||||
Scene00006( quest, player );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Actor1:
|
||||
{
|
||||
if( quest.getSeq() == Seq1 )
|
||||
Scene00002( quest, player );
|
||||
break;
|
||||
}
|
||||
case Actor2:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Actor3:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Actor4:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Actor5:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Actor6:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Actor20:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Actor30:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Actor40:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Actor50:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case Actor60:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onEnterTerritory( World::Quest& quest, Entity::Player& player, uint16_t param1, uint16_t param2 ) override
|
||||
{
|
||||
if( quest.getSeq() == Seq2 )
|
||||
{
|
||||
Scene00005( quest, player );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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( &ManWil005::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, FADE_OUT | CONDITION_CUTSCENE | HIDE_UI, bindSceneReturn( &ManWil005::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, NONE, bindSceneReturn( &ManWil005::Scene00002Return ) );
|
||||
}
|
||||
|
||||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
auto& pTeriMgr = Common::Service< Sapphire::World::Manager::TerritoryMgr >::ref();
|
||||
|
||||
eventMgr().eventFinish( player, result.eventId, 0 );
|
||||
pTeriMgr.createAndJoinQuestBattle( player, Questbattle0 );
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00003( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &ManWil005::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( &ManWil005::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, 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,
|
||||
bindSceneReturn( &ManWil005::Scene00005Return ) );
|
||||
}
|
||||
|
||||
void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
quest.setSeq( SeqFinish );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00006( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 6, FADE_OUT | HIDE_HOTBAR | CONDITION_CUTSCENE | HIDE_UI, bindSceneReturn( &ManWil005::Scene00006Return ) );
|
||||
}
|
||||
|
||||
void Scene00006Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
player.finishQuest( getId(), result.getResult( 1 ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00007( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 7, NONE, bindSceneReturn( &ManWil005::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( &ManWil005::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( &ManWil005::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( &ManWil005::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( &ManWil005::Scene00011Return ) );
|
||||
}
|
||||
|
||||
void Scene00011Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( ManWil005 );
|
105
src/scripts/quest/classquest/CNJ/ClsCnj998.cpp
Normal file
105
src/scripts/quest/classquest/CNJ/ClsCnj998.cpp
Normal file
|
@ -0,0 +1,105 @@
|
|||
// 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: ClsCnj998_00133
|
||||
// Quest Name: Way of the Conjurer
|
||||
// Quest ID: 65669
|
||||
// Start NPC: 1000323 (Madelle)
|
||||
// End NPC: 1000692 (E-Sumi-Yan)
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
class ClsCnj998 : public Sapphire::ScriptAPI::QuestScript
|
||||
{
|
||||
private:
|
||||
// Basic quest information
|
||||
// Quest vars / flags used
|
||||
// UI8AL
|
||||
|
||||
/// Countable Num: 1 Seq: 255 Event: 1 Listener: 1000692
|
||||
// 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 = 1000323;// Madelle ( Pos: -234.028000 -4.000220 -11.062800 Teri: 133 )
|
||||
static constexpr auto Actor1 = 1000692;// E-sumi-yan ( Pos: -258.808014 -5.773500 -27.237400 Teri: 133 )
|
||||
static constexpr auto Classjob = 6;
|
||||
static constexpr auto GearsetUnlock = 1905;
|
||||
static constexpr auto LogmessageMonsterNotePageUnlock = 1009;
|
||||
static constexpr auto UnlockImageClassCnj = 25;
|
||||
|
||||
public:
|
||||
ClsCnj998() : Sapphire::ScriptAPI::QuestScript( 65669 ){};
|
||||
~ClsCnj998() = 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 )
|
||||
Scene00001( 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( &ClsCnj998::Scene00000Return ) );
|
||||
}
|
||||
|
||||
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 )// accept quest
|
||||
{
|
||||
quest.setSeq( SeqFinish );
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00001( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 1, FADE_OUT | HIDE_UI, bindSceneReturn( &ClsCnj998::Scene00001Return ) );
|
||||
}
|
||||
|
||||
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
player.finishQuest( getId() );
|
||||
player.setLevelForClass( 1, Sapphire::Common::ClassJob::Conjurer );
|
||||
player.addGearSet();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( ClsCnj998 );
|
72
src/scripts/quest/classquest/CNJ/ClsCnj999.cpp
Normal file
72
src/scripts/quest/classquest/CNJ/ClsCnj999.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
// 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: ClsCnj999_00182
|
||||
// Quest Name: So You Want to Be a Conjurer
|
||||
// Quest ID: 65718
|
||||
// Start NPC: 1000323 (Madelle)
|
||||
// End NPC: 1000323 (Madelle)
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
class ClsCnj999 : public Sapphire::ScriptAPI::QuestScript
|
||||
{
|
||||
private:
|
||||
// Basic quest information
|
||||
// Quest vars / flags used
|
||||
|
||||
// Steps in this quest ( 0 is before accepting,
|
||||
// 1 is first, 255 means ready for turning it in
|
||||
enum Sequence : uint8_t
|
||||
{
|
||||
};
|
||||
static constexpr auto Actor0 = 1000323;
|
||||
|
||||
|
||||
// Entities found in the script data of the quest
|
||||
|
||||
public:
|
||||
ClsCnj999() : Sapphire::ScriptAPI::QuestScript( 65718 ){};
|
||||
~ClsCnj999() = default;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Event Handlers
|
||||
void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
switch( actorId )
|
||||
{
|
||||
case Actor0:
|
||||
{
|
||||
Scene00000( 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( &ClsCnj999::Scene00000Return ) );
|
||||
}
|
||||
|
||||
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
player.finishQuest( getId(), 0 );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( ClsCnj999 );
|
|
@ -45,6 +45,7 @@ private:
|
|||
static constexpr auto Actor4 = 1013231;//Hatchling
|
||||
static constexpr auto BindActor1 = 5896086;
|
||||
static constexpr auto Item0 = 2001726;
|
||||
static constexpr auto Item0Icon = 26177;
|
||||
static constexpr auto LocBgm1 = 313;
|
||||
|
||||
public:
|
||||
|
@ -137,7 +138,7 @@ private:
|
|||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
quest.setUI8BH( 1 );
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 0 );//TODO: Item Icon, probably
|
||||
eventMgr().sendNotice( player, getId(), 0, { Item0Icon } );
|
||||
quest.setSeq( Seq2 );
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ private:
|
|||
static constexpr auto Eobject2 = 2005950;
|
||||
static constexpr auto EventActionGatherMiddle = 7;
|
||||
static constexpr auto Item0 = 2001728;
|
||||
static constexpr auto Item0Icon = 21223;
|
||||
static constexpr auto LocActor1 = 1013860;
|
||||
static constexpr auto LocActor2 = 1013870;
|
||||
static constexpr auto LocActor3 = 1013871;
|
||||
|
@ -207,7 +208,7 @@ public:
|
|||
private:
|
||||
void checkQuestCompletion( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 1, 2, quest.getUI8AL(), 3 );//TODO: Item Icon, probably
|
||||
eventMgr().sendNotice( player, getId(), 1, { quest.getUI8AL(), 3, Item0Icon } );
|
||||
|
||||
if( quest.getUI8AL() >= 3 )
|
||||
{
|
||||
|
|
|
@ -56,6 +56,7 @@ private:
|
|||
static constexpr auto Actor7 = 1013961;//Goblin Trader (Seq5)
|
||||
static constexpr auto BindActor1 = 5896328;
|
||||
static constexpr auto Item0 = 2001729;
|
||||
static constexpr auto Item0Icon = 25919;
|
||||
static constexpr auto LocActor1 = 1013954;
|
||||
static constexpr auto LocActor2 = 1013955;
|
||||
static constexpr auto LocBgm1 = 313;
|
||||
|
@ -390,7 +391,7 @@ private:
|
|||
|
||||
void Scene00019Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 5, 0 );//TODO: Item Icon?
|
||||
eventMgr().sendNotice( player, getId(), 5, { Item0Icon } );
|
||||
quest.setSeq( SeqFinish );
|
||||
quest.setUI8BH( 0 );
|
||||
}
|
||||
|
|
|
@ -101,6 +101,8 @@ private:
|
|||
static constexpr auto Item4 = 2001029;
|
||||
static constexpr auto Item5 = 2001038;
|
||||
static constexpr auto Item6 = 2001047;
|
||||
static constexpr auto Item0Icon = 21003;
|
||||
static constexpr auto Item3Icon = 26002;
|
||||
static constexpr auto LocAction0 = 858;
|
||||
static constexpr auto LocAction1 = 995;
|
||||
static constexpr auto LocAction2 = 936;
|
||||
|
@ -109,6 +111,7 @@ private:
|
|||
static constexpr auto Ritem0 = 2049;//Madman's Whispering Rod
|
||||
static constexpr auto Ritem1 = 2046;//Unfinished Thyrus
|
||||
static constexpr auto Ritem2 = 6267;//Radz-at-Han Quenching Oil
|
||||
static constexpr auto Ritem1Icon = 32627;
|
||||
|
||||
public:
|
||||
JobWhm001() : Sapphire::ScriptAPI::QuestScript( 66660 ){};
|
||||
|
@ -327,7 +330,7 @@ private:
|
|||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
quest.setUI8BH( 1 );
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 0 );//TODO:Item Icon
|
||||
eventMgr().sendNotice( player, getId(), 0, { Item0Icon } );
|
||||
quest.setSeq( Seq2 );
|
||||
}
|
||||
|
||||
|
@ -469,7 +472,7 @@ private:
|
|||
|
||||
void Scene00013Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 7, 0 );//TODO: Item Icon
|
||||
eventMgr().sendNotice( player, getId(), 7, { Item3Icon } );
|
||||
quest.setSeq( Seq9 );
|
||||
quest.setUI8BH( 1 );
|
||||
}
|
||||
|
@ -497,7 +500,7 @@ private:
|
|||
void Scene00015Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
quest.setUI8BH( 0 );
|
||||
eventMgr().sendEventNotice( player, getId(), 8, 0 );//TODO: Item Icon?
|
||||
eventMgr().sendNotice( player, getId(), 8, { Ritem1Icon } );
|
||||
player.addItem( Ritem1 );
|
||||
quest.setSeq( Seq10 );
|
||||
}
|
||||
|
@ -719,4 +722,4 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( JobWhm001 );
|
||||
EXPOSE_SCRIPT( JobWhm001 );
|
||||
|
|
|
@ -80,6 +80,10 @@ private:
|
|||
static constexpr auto Ritem1 = 3894;
|
||||
static constexpr auto Ritem2 = 3463;
|
||||
static constexpr auto Ritem3 = 2902;
|
||||
static constexpr auto Ritem0Icon = 48242;
|
||||
static constexpr auto Ritem1Icon = 48219;
|
||||
static constexpr auto Ritem2Icon = 45189;
|
||||
static constexpr auto Ritem3Icon = 40616;
|
||||
static constexpr auto VfxReaction = 177;
|
||||
|
||||
public:
|
||||
|
@ -214,7 +218,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
|
||||
eventMgr().sendNotice( player, getId(), 0, { Ritem0Icon } );
|
||||
playerMgr().sendLogMessage( player, Logmessage0 );
|
||||
quest.setUI8AL( 1 );
|
||||
quest.setUI8CH( 0 );
|
||||
|
@ -241,7 +245,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
|
||||
eventMgr().sendNotice( player, getId(), 1, { Ritem2Icon } );
|
||||
playerMgr().sendLogMessage( player, Logmessage0 );
|
||||
quest.setUI8BH( 1 );
|
||||
quest.setUI8CL( 0 );
|
||||
|
@ -268,7 +272,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
|
||||
eventMgr().sendNotice( player, getId(), 2, {Ritem1Icon} );
|
||||
playerMgr().sendLogMessage( player, Logmessage0 );
|
||||
quest.setUI8BL( 1 );
|
||||
quest.setUI8DH( 0 );
|
||||
|
@ -436,7 +440,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
|
||||
eventMgr().sendNotice( player, getId(), 6, { Ritem3Icon } );
|
||||
playerMgr().sendLogMessage( player, Logmessage0 );
|
||||
quest.setSeq( SeqFinish );
|
||||
quest.setUI8BH( 0 );
|
||||
|
|
|
@ -179,7 +179,8 @@ private:
|
|||
|
||||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
player.addStatusEffectById( Status0, 0, player, Transformation0 );
|
||||
// todo - fix status effect without action?
|
||||
//player.addStatusEffectById( Status0, 0, player, Transformation0 );
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 0 );
|
||||
quest.setSeq( Seq2 );
|
||||
}
|
||||
|
@ -294,7 +295,7 @@ private:
|
|||
|
||||
void Scene00010Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
player.addStatusEffectById( Status0, 0, player, Transformation0 );
|
||||
// player.addStatusEffectById( Status0, 0, player, Transformation0 );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -54,6 +54,7 @@ private:
|
|||
static constexpr auto Eobject1 = 2000017;//Decaying Tree (South)
|
||||
static constexpr auto Eobject2 = 2000018;//Decaying Tree (East)
|
||||
static constexpr auto Item0 = 2000061;
|
||||
static constexpr auto Item0Icon = 20661;
|
||||
static constexpr auto Seq0Actor0 = 0;
|
||||
static constexpr auto Seq1Eobject0 = 1;
|
||||
static constexpr auto Seq1Eobject0Useitemno = 99;
|
||||
|
@ -184,7 +185,7 @@ public:
|
|||
private:
|
||||
void checkQuestCompletion( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 2, quest.getUI8AH(), 3 );//TODO: Probably needs item icon
|
||||
eventMgr().sendNotice( player, getId(), 0, { quest.getUI8AH(), 3, Item0Icon } );
|
||||
|
||||
if( quest.getUI8AH() >= 3 )
|
||||
{
|
||||
|
|
|
@ -45,6 +45,8 @@ private:
|
|||
static constexpr auto Enemy0 = 54;//Hornet Swarm (INCORRECT: 57)
|
||||
static constexpr auto Item0 = 2000099;
|
||||
static constexpr auto Item1 = 2000094;
|
||||
static constexpr auto Item0Icon = 22623;
|
||||
static constexpr auto Item1Icon = 24403;
|
||||
static constexpr auto Seq0Actor0 = 0;
|
||||
static constexpr auto Seq2Actor0 = 1;
|
||||
static constexpr auto Seq2Actor0Npctradeno = 99;
|
||||
|
@ -88,7 +90,7 @@ public:
|
|||
{
|
||||
quest.setUI8BH( quest.getUI8BH() + 1 );
|
||||
quest.setUI8AL( quest.getUI8AL() + 1 );
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 2, quest.getUI8AL(), 4 );//TODO: Probably needs item icon
|
||||
eventMgr().sendNotice( player, getId(), 0, { quest.getUI8AL(), 4, Item0Icon } ); // item Icon 2 missing
|
||||
|
||||
if( quest.getUI8AL() >= 4 )
|
||||
{
|
||||
|
|
|
@ -53,6 +53,7 @@ private:
|
|||
static constexpr auto Eventrange0 = 3841476;
|
||||
static constexpr auto EventActionSearch = 1;
|
||||
static constexpr auto Item0 = 2000192;
|
||||
static constexpr auto Item0Icon = 22627;
|
||||
|
||||
public:
|
||||
SubFst067() : Sapphire::ScriptAPI::QuestScript( 65919 ){};
|
||||
|
@ -182,7 +183,7 @@ public:
|
|||
private:
|
||||
void checkQuestCompletion( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 1, 2, quest.getUI8AL(), 3 );//TODO: Item Icon
|
||||
eventMgr().sendNotice( player, getId(), 1, { quest.getUI8AL(), 3, Item0Icon } );
|
||||
if( quest.getUI8AL() >= 3 )
|
||||
{
|
||||
quest.setUI8AL( 0 );
|
||||
|
|
|
@ -39,6 +39,7 @@ private:
|
|||
static constexpr auto Eobject0 = 2000685;//Well-worn Fishing Rod
|
||||
static constexpr auto EventActionSearch = 1;
|
||||
static constexpr auto Item0 = 2000185;
|
||||
static constexpr auto Item0Icon = 38201;
|
||||
static constexpr auto Seq0Actor0 = 0;
|
||||
static constexpr auto Seq1Eobject0 = 1;
|
||||
static constexpr auto Seq1Eobject0Eventactionno = 99;
|
||||
|
@ -169,7 +170,7 @@ private:
|
|||
|
||||
void Scene00100Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 0 );//TODO: Probably Item Icon
|
||||
eventMgr().sendNotice( player, getId(), 0, { Item0Icon } );
|
||||
quest.setUI8BH( 1 );
|
||||
quest.setSeq( SeqFinish );
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ private:
|
|||
static constexpr auto EventActionSearchMiddle = 3;
|
||||
static constexpr auto Item0 = 2000616;
|
||||
static constexpr auto Item1 = 2000617;
|
||||
static constexpr auto Item1Icon = 20005;
|
||||
|
||||
public:
|
||||
GaiUsa803() : Sapphire::ScriptAPI::QuestScript( 66323 ){};
|
||||
|
@ -140,7 +141,7 @@ public:
|
|||
private:
|
||||
void checkQuestCompletion( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 1, 2, quest.getUI8AH(), 5 );//TODO:Show Item Icon
|
||||
eventMgr().sendNotice( player, getId(), 1, { quest.getUI8AH(), 5, Item1Icon } );
|
||||
if( quest.getUI8AH() >= 5 )
|
||||
{
|
||||
quest.setUI8BH( quest.getUI8DH() );
|
||||
|
|
|
@ -55,6 +55,7 @@ private:
|
|||
static constexpr auto Item0 = 2000720;
|
||||
static constexpr auto Item1 = 2000721;
|
||||
static constexpr auto Item2 = 2000722;
|
||||
static constexpr auto Item0Icon = 26002;
|
||||
|
||||
public:
|
||||
GaiUsb808() : Sapphire::ScriptAPI::QuestScript( 66453 ){};
|
||||
|
@ -162,7 +163,7 @@ private:
|
|||
|
||||
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 1, 0 );//TODO:Show Item Icon (Needs func update)
|
||||
eventMgr().sendNotice( player, getId(), 1, { Item0Icon } );
|
||||
quest.setUI8BH( 1 );
|
||||
quest.setSeq( Seq3 );
|
||||
}
|
||||
|
|
|
@ -61,6 +61,8 @@ private:
|
|||
static constexpr auto EventActionSearch = 1;
|
||||
static constexpr auto Item0 = 2000963;
|
||||
static constexpr auto Item1 = 2000965;
|
||||
static constexpr auto Item0Icon = 22614;
|
||||
static constexpr auto Item1Icon = 21452;
|
||||
static constexpr auto Poprange0 = 3884000;
|
||||
static constexpr auto Territorytype0 = 204;
|
||||
|
||||
|
@ -263,7 +265,7 @@ private:
|
|||
|
||||
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 0 );
|
||||
eventMgr().sendNotice( player, getId(), 0, { Item0Icon } );
|
||||
quest.setUI8BH( 1 );
|
||||
quest.setSeq( Seq2 );
|
||||
}
|
||||
|
@ -393,7 +395,7 @@ private:
|
|||
{
|
||||
quest.setSeq( Seq4 );
|
||||
quest.setUI8BH( 1 );
|
||||
eventMgr().sendEventNotice( player, getId(), 2, 0 /*1, Item1*/ );//TODO:Item Icon Event Notice
|
||||
eventMgr().sendNotice( player, getId(), 2, { Item1Icon } );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -96,8 +96,6 @@ class SubFst009 : public Sapphire::ScriptAPI::QuestScript
|
|||
{
|
||||
if (result.getResult(0) == 1)
|
||||
Scene00100(quest, player);
|
||||
else
|
||||
Scene00099(quest, player);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -67,8 +67,11 @@ public:
|
|||
case Enemy0:
|
||||
{
|
||||
auto currentKC = quest.getUI8AL();
|
||||
quest.setUI8AL( currentKC + 1 );
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 2, currentKC + 1, 6 );
|
||||
if( currentKC < 6 )
|
||||
{
|
||||
quest.setUI8AL( currentKC + 1 );
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 2, currentKC + 1, 6 );
|
||||
}
|
||||
|
||||
if( currentKC + 1 >= 6 )
|
||||
quest.setSeq( SeqFinish );
|
||||
|
|
|
@ -55,6 +55,8 @@ private:
|
|||
static constexpr auto EventActionSearch = 1;
|
||||
static constexpr auto Item0 = 2000669;
|
||||
static constexpr auto Item1 = 2000929;
|
||||
static constexpr auto Item0Icon = 27241;
|
||||
static constexpr auto Item1Icon = 22301;
|
||||
|
||||
public:
|
||||
GaiUsb406() : Sapphire::ScriptAPI::QuestScript( 66398 ){};
|
||||
|
@ -143,7 +145,11 @@ private:
|
|||
{
|
||||
if( quest.getSeq() == Seq1 )
|
||||
{
|
||||
eventMgr().sendEventNotice( player, getId(), type, 2, ( type == 0 ) ? quest.getUI8AL() : quest.getUI8BH(), 3 ); //TODO: Item Icons
|
||||
if( type == 0 )
|
||||
eventMgr().sendNotice( player, getId(), type, { quest.getUI8AL(), 3, Item1Icon } );
|
||||
else
|
||||
eventMgr().sendNotice( player, getId(), type, { quest.getUI8BH(), 3, Item0Icon } );
|
||||
|
||||
if( quest.getUI8BL() >= 3 && quest.getUI8CH() >= 3 )
|
||||
{
|
||||
quest.setUI8BH( quest.getUI8BL() );
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <Service.h>
|
||||
|
||||
// Quest Script: SubSea002_00112
|
||||
// Quest Name: Suspiciously SoberF
|
||||
// Quest Name: Suspiciously Sober
|
||||
// Quest ID: 65648
|
||||
// Start NPC: 1003604 (Ahldskyf)
|
||||
// End NPC: 1003275 (Frydwyb)
|
||||
|
|
|
@ -145,6 +145,7 @@ private:
|
|||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 0 );
|
||||
quest.setUI8AL( 1 );
|
||||
quest.setBitFlag8( 1, true );
|
||||
checkQuestCompletion( quest, player, 1 );
|
||||
}
|
||||
|
||||
|
@ -159,6 +160,7 @@ private:
|
|||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 1, 0 );
|
||||
quest.setUI8BH( 1 );
|
||||
quest.setBitFlag8( 2, true );
|
||||
checkQuestCompletion( quest, player, 1 );
|
||||
}
|
||||
|
||||
|
@ -173,6 +175,7 @@ private:
|
|||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 2, 0 );
|
||||
quest.setUI8BL( 1 );
|
||||
quest.setBitFlag8( 3, true );
|
||||
checkQuestCompletion( quest, player, 1 );
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ class SubSea007 : public Sapphire::ScriptAPI::QuestScript
|
|||
static constexpr auto Actor1 = 1000957; // R'sushmo ( Pos: -49.240898 43.991699 -146.380005 Teri: 128 )
|
||||
static constexpr auto Actor2 = 1000937; // Godebert ( Pos: -12.222500 44.998798 -251.850006 Teri: 128 )
|
||||
static constexpr auto Item0 = 2000455;
|
||||
static constexpr auto Item0Icon = 25906;
|
||||
|
||||
public:
|
||||
SubSea007() : Sapphire::ScriptAPI::QuestScript( 65653 ){};
|
||||
|
@ -117,7 +118,7 @@ class SubSea007 : public Sapphire::ScriptAPI::QuestScript
|
|||
|
||||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 0 ); // TODO: Show item icon
|
||||
eventMgr().sendNotice( player, getId(), 0, { Item0Icon } );
|
||||
quest.setUI8BH( 1 );
|
||||
quest.setSeq( Seq2 );
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ class SubSea008 : public Sapphire::ScriptAPI::QuestScript
|
|||
static constexpr auto Actor2 = 1000938; // Ginnade ( Pos: -4.651690 45.018398 -241.815002 Teri: 128 )
|
||||
static constexpr auto Actor3 = 1000947; // Lyngsath ( Pos: -54.642601 43.991699 -151.201996 Teri: 128 )
|
||||
static constexpr auto Item0 = 2000451;
|
||||
static constexpr auto Item0Icon = 25919;
|
||||
|
||||
public:
|
||||
SubSea008() : Sapphire::ScriptAPI::QuestScript( 65654 ){};
|
||||
|
@ -58,7 +59,8 @@ class SubSea008 : public Sapphire::ScriptAPI::QuestScript
|
|||
{
|
||||
case Actor0:
|
||||
{
|
||||
Scene00000( quest, player );
|
||||
if( quest.getSeq() == Seq0 )
|
||||
Scene00000( quest, player );
|
||||
break;
|
||||
}
|
||||
case Actor1:
|
||||
|
@ -71,12 +73,14 @@ class SubSea008 : public Sapphire::ScriptAPI::QuestScript
|
|||
}
|
||||
case Actor2:
|
||||
{
|
||||
Scene00003( quest, player );
|
||||
if( quest.getSeq() == Seq2 )
|
||||
Scene00003( quest, player );
|
||||
break;
|
||||
}
|
||||
case Actor3:
|
||||
{
|
||||
Scene00005( quest, player );
|
||||
if( quest.getSeq() == Seq2 )
|
||||
Scene00005( quest, player );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +141,7 @@ private:
|
|||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
quest.setUI8BL( 1 );
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 0 ); //TODO: add item icon
|
||||
eventMgr().sendNotice( player, getId(), 0, { Item0Icon } );
|
||||
quest.setSeq( Seq2 );
|
||||
}
|
||||
|
||||
|
@ -167,6 +171,7 @@ private:
|
|||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 1, 0 );
|
||||
quest.setUI8AL( 1 );
|
||||
quest.setBitFlag8( 1, true );
|
||||
checkQuestCompletion( quest, player, 1 );
|
||||
|
||||
}
|
||||
|
@ -197,6 +202,7 @@ private:
|
|||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 2, 0 );
|
||||
quest.setUI8BH( 1 );
|
||||
quest.setBitFlag8( 2, true );
|
||||
checkQuestCompletion( quest, player, 1 );
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,8 @@ class SubSea016 : public Sapphire::ScriptAPI::QuestScript
|
|||
}
|
||||
case Actor1:
|
||||
{
|
||||
Scene00002( quest, player );
|
||||
if( quest.getSeq() == Seq1 )
|
||||
Scene00002( quest, player );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -131,6 +132,7 @@ class SubSea016 : public Sapphire::ScriptAPI::QuestScript
|
|||
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 0 );
|
||||
quest.setBitFlag8( 1, true );
|
||||
quest.setSeq( SeqFinish );
|
||||
}
|
||||
|
||||
|
|
324
src/scripts/quest/subquest/thanalan_central/SubWil025.cpp
Normal file
324
src/scripts/quest/subquest/thanalan_central/SubWil025.cpp
Normal file
|
@ -0,0 +1,324 @@
|
|||
// 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: SubWil025_00671
|
||||
// Quest Name: Nothing to See Here
|
||||
// Quest ID: 66207
|
||||
// Start NPC: 1003995 (Papashan)
|
||||
// End NPC: 1003995 (Papashan)
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
class SubWil025 : public Sapphire::ScriptAPI::QuestScript
|
||||
{
|
||||
private:
|
||||
// Basic quest information
|
||||
// Quest vars / flags used
|
||||
// BitFlag8
|
||||
// UI8AH
|
||||
// UI8AL
|
||||
// UI8BH
|
||||
// UI8BL
|
||||
// UI8CH
|
||||
// UI8CL
|
||||
|
||||
/// Countable Num: 0 Seq: 1 Event: 1 Listener: 1004599
|
||||
/// Countable Num: 0 Seq: 255 Event: 1 Listener: 1004600
|
||||
// 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 = 1003995;// Papashan ( Pos: 75.338402 2.138110 316.362000 Teri: 141 )
|
||||
static constexpr auto Actor1 = 1004599;// Stern Sultansworn ( Pos: 89.876198 4.633540 425.415009 Teri: 141 )
|
||||
static constexpr auto Actor2 = 1004600;// Serious Sultansworn ( Pos: 126.024002 14.465300 278.462006 Teri: 141 )
|
||||
static constexpr auto Actor3 = 1004601;// Servile Sultansworn ( Pos: -62.415001 4.641350 261.281006 Teri: 141 )
|
||||
static constexpr auto Item0 = 2000463;
|
||||
|
||||
public:
|
||||
SubWil025() : Sapphire::ScriptAPI::QuestScript( 66207 ){};
|
||||
~SubWil025() = 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() == SeqFinish )
|
||||
Scene00010( quest, player );
|
||||
break;
|
||||
}
|
||||
|
||||
case Actor1:
|
||||
{
|
||||
if( quest.getSeq() == Seq1 )
|
||||
{
|
||||
if( quest.getUI8AL() == 0 )
|
||||
Scene00001( quest, player );
|
||||
else
|
||||
Scene00003( quest, player );
|
||||
}
|
||||
else if( quest.getSeq() == SeqFinish )
|
||||
{
|
||||
Scene00011( quest, player );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Actor2:
|
||||
{
|
||||
if( quest.getSeq() == Seq1 )
|
||||
{
|
||||
if( quest.getUI8BH() == 0 )
|
||||
Scene00004( quest, player );
|
||||
else
|
||||
Scene00006( quest, player );
|
||||
}
|
||||
else if( quest.getSeq() == SeqFinish )
|
||||
{
|
||||
Scene00012( quest, player );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Actor3:
|
||||
{
|
||||
if( quest.getSeq() == Seq1 )
|
||||
{
|
||||
if( quest.getUI8BL() == 0 )
|
||||
Scene00007( quest, player );
|
||||
else
|
||||
Scene00009( quest, player );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void checkQuestCompletion( World::Quest& quest, Entity::Player& player, uint32_t varIdx )
|
||||
{
|
||||
if( varIdx == 1 )
|
||||
{
|
||||
quest.setUI8AH( quest.getUI8AH() + 1 );
|
||||
quest.setUI8CH( quest.getUI8CH() - 1 );
|
||||
auto actor1Talked = quest.getUI8AL();
|
||||
auto actor2Talked = quest.getUI8BH();
|
||||
auto actor3Talked = quest.getUI8BL();
|
||||
if( actor1Talked && actor2Talked && actor3Talked )
|
||||
{
|
||||
quest.setSeq( SeqFinish );
|
||||
}
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 2, quest.getUI8AH(), 3 );
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// 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( &SubWil025::Scene00000Return ) );
|
||||
}
|
||||
|
||||
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 )// accept quest
|
||||
{
|
||||
quest.setSeq( Seq1 );
|
||||
quest.setUI8CH( 3 );
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00001( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00001Return ) );
|
||||
}
|
||||
|
||||
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
Scene00002( quest, player );
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00002( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00002Return ) );
|
||||
}
|
||||
|
||||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
quest.setUI8AL( 1 );
|
||||
quest.setBitFlag8( 1, true );
|
||||
checkQuestCompletion( quest, player, 1 );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00003( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 3, HIDE_HOTBAR, bindSceneReturn( &SubWil025::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, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00004Return ) );
|
||||
}
|
||||
|
||||
void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
Scene00005( quest, player );
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00005( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 5, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00005Return ) );
|
||||
}
|
||||
|
||||
void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
quest.setUI8BH( 1 );
|
||||
quest.setBitFlag8( 2, true );
|
||||
checkQuestCompletion( quest, player, 1 );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00006( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 6, HIDE_HOTBAR, bindSceneReturn( &SubWil025::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, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00007Return ) );
|
||||
}
|
||||
|
||||
void Scene00007Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
Scene00008( quest, player );
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00008( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 8, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00008Return ) );
|
||||
}
|
||||
|
||||
void Scene00008Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
quest.setUI8BL( 1 );
|
||||
quest.setBitFlag8( 3, true );
|
||||
checkQuestCompletion( quest, player, 1 );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00009( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 9, HIDE_HOTBAR, bindSceneReturn( &SubWil025::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, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00010Return ) );
|
||||
}
|
||||
|
||||
void Scene00010Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
player.finishQuest( getId(), result.getResult( 1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00011( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 11, HIDE_HOTBAR, bindSceneReturn( &SubWil025::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( &SubWil025::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( &SubWil025::Scene00013Return ) );
|
||||
}
|
||||
|
||||
void Scene00013Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( SubWil025 );
|
117
src/scripts/quest/subquest/thanalan_central/SubWil026.cpp
Normal file
117
src/scripts/quest/subquest/thanalan_central/SubWil026.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
// 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 <Actor/Player.h>
|
||||
#include "Manager/EventMgr.h"
|
||||
#include <ScriptObject.h>
|
||||
#include <Service.h>
|
||||
|
||||
// Quest Script: SubWil026_00623
|
||||
// Quest Name: Takin' What They're Givin'
|
||||
// Quest ID: 66159
|
||||
// Start NPC: 1001353 (Momodi)
|
||||
// End NPC: 1002065 (Dadanen)
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
class SubWil026 : public Sapphire::ScriptAPI::QuestScript
|
||||
{
|
||||
private:
|
||||
// Basic quest information
|
||||
// Quest vars / flags used
|
||||
// UI8AL
|
||||
|
||||
/// Countable Num: 1 Seq: 255 Event: 1 Listener: 1002065
|
||||
// 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 = 1001353; // Momodi ( Pos: 21.072599 7.450000 -78.782303 Teri: 130 )
|
||||
static constexpr auto Actor1 = 1002065; // Dadanen ( Pos: 60.946701 45.145302 -204.985992 Teri: 140 )
|
||||
|
||||
public:
|
||||
SubWil026() : Sapphire::ScriptAPI::QuestScript( 66159 ){};
|
||||
~SubWil026() = 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 )
|
||||
Scene00001( quest, player );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
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( &SubWil026::Scene00000Return ) );
|
||||
}
|
||||
|
||||
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 ) // accept quest
|
||||
{
|
||||
quest.setUI8AL( 1 );
|
||||
quest.setSeq( SeqFinish );
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00001( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 1, FADE_OUT | CONDITION_CUTSCENE | HIDE_UI, bindSceneReturn( &SubWil026::Scene00001Return ) );
|
||||
}
|
||||
|
||||
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
Scene00002( quest, player );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00002( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &SubWil026::Scene00002Return ) );
|
||||
}
|
||||
|
||||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
player.finishQuest( getId(), result.getResult( 1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( SubWil026 );
|
194
src/scripts/quest/subquest/thanalan_central/SubWil060.cpp
Normal file
194
src/scripts/quest/subquest/thanalan_central/SubWil060.cpp
Normal file
|
@ -0,0 +1,194 @@
|
|||
// 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 <Actor/Player.h>
|
||||
#include "Manager/EventMgr.h"
|
||||
#include <ScriptObject.h>
|
||||
#include <Service.h>
|
||||
|
||||
// Quest Script: SubWil060_00303
|
||||
// Quest Name: Step Nine
|
||||
// Quest ID: 65839
|
||||
// Start NPC: 1001500 (Cicidoa)
|
||||
// End NPC: 1001541 (Roger)
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
class SubWil060 : public Sapphire::ScriptAPI::QuestScript
|
||||
{
|
||||
private:
|
||||
// Basic quest information
|
||||
// Quest vars / flags used
|
||||
// UI8AL
|
||||
// UI8BH
|
||||
// UI8BL
|
||||
|
||||
/// Countable Num: 1 Seq: 1 Event: 1 Listener: 1001455
|
||||
/// Countable Num: 1 Seq: 255 Event: 1 Listener: 1001541
|
||||
// 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 = 1001500; // Cicidoa ( Pos: 81.792099 1.050750 311.240997 Teri: 141 )
|
||||
static constexpr auto Actor1 = 1001455; // Gagari ( Pos: 59.952599 0.999894 255.863998 Teri: 141 )
|
||||
static constexpr auto Actor2 = 1001541; // Roger ( Pos: -99.395401 -11.380900 -41.723999 Teri: 141 )
|
||||
static constexpr auto Item0 = 2000199;
|
||||
static constexpr auto Item1 = 2000238;
|
||||
static constexpr auto Item1Icon = 25210;
|
||||
|
||||
public:
|
||||
SubWil060() : Sapphire::ScriptAPI::QuestScript( 65839 ){};
|
||||
~SubWil060() = 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() == SeqFinish )
|
||||
Scene00004( quest, player );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
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( &SubWil060::Scene00000Return ) );
|
||||
}
|
||||
|
||||
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 ) // accept quest
|
||||
{
|
||||
quest.setUI8BH( 1 );
|
||||
quest.setSeq( Seq1 );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00001( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &SubWil060::Scene00001Return ) );
|
||||
}
|
||||
|
||||
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
Scene00002( quest, player );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00002( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &SubWil060::Scene00002Return ) );
|
||||
}
|
||||
|
||||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
quest.setUI8BH( 0 );
|
||||
quest.setUI8BL( 1 );
|
||||
eventMgr().sendNotice( player, getId(), 0, { Item1Icon } );
|
||||
quest.setSeq( SeqFinish );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00003( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &SubWil060::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, HIDE_HOTBAR, bindSceneReturn( &SubWil060::Scene00004Return ) );
|
||||
}
|
||||
|
||||
void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
Scene00005( quest, player );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00005( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 5, HIDE_HOTBAR, bindSceneReturn( &SubWil060::Scene00005Return ) );
|
||||
}
|
||||
|
||||
void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
player.finishQuest( getId(), result.getResult( 1 ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00006( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 6, NONE, bindSceneReturn( &SubWil060::Scene00006Return ) );
|
||||
}
|
||||
|
||||
void Scene00006Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( SubWil060 );
|
169
src/scripts/quest/subquest/thanalan_central/SubWil062.cpp
Normal file
169
src/scripts/quest/subquest/thanalan_central/SubWil062.cpp
Normal file
|
@ -0,0 +1,169 @@
|
|||
// 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 <Actor/BNpc.h>
|
||||
#include <ScriptObject.h>
|
||||
#include <Service.h>
|
||||
|
||||
// Quest Script: SubWil062_00305
|
||||
// Quest Name: Until a Quieter Time
|
||||
// Quest ID: 65841
|
||||
// Start NPC: 1001541 (Roger)
|
||||
// End NPC: 1001447 (Warin)
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
class SubWil062 : public Sapphire::ScriptAPI::QuestScript
|
||||
{
|
||||
private:
|
||||
// Basic quest information
|
||||
// Quest vars / flags used
|
||||
// UI8AL
|
||||
// UI8BH
|
||||
|
||||
/// Countable Num: 8 Seq: 1 Event: 9 Listener: 432
|
||||
/// Countable Num: 1 Seq: 255 Event: 1 Listener: 1001447
|
||||
// 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 = 1001541; // Roger ( Pos: -99.395401 -11.380900 -41.723999 Teri: 141 )
|
||||
static constexpr auto Actor1 = 1001447; // Warin ( Pos: -32.639099 -1.033260 -148.485992 Teri: 141 )
|
||||
static constexpr auto Enemy0 = 294; // Antling Worker
|
||||
static constexpr auto Item0 = 2000168;
|
||||
static constexpr auto Item0Icon = 22205;
|
||||
|
||||
public:
|
||||
SubWil062() : Sapphire::ScriptAPI::QuestScript( 65841 ){};
|
||||
~SubWil062() = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
}
|
||||
|
||||
void onBNpcKill( World::Quest& quest, Entity::BNpc& bnpc, Entity::Player& player ) override
|
||||
{
|
||||
if( bnpc.getBNpcNameId() != Enemy0 )
|
||||
return;
|
||||
|
||||
unsigned currentKC = quest.getUI8AL() + 1;
|
||||
quest.setUI8BH( currentKC );
|
||||
quest.setUI8AL( currentKC );
|
||||
|
||||
if( currentKC >= 5 )
|
||||
quest.setSeq( SeqFinish );
|
||||
|
||||
eventMgr().sendNotice( player, getId(), 0, { currentKC, 5, Item0Icon } );
|
||||
}
|
||||
|
||||
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( &SubWil062::Scene00000Return ) );
|
||||
}
|
||||
|
||||
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 ) // accept quest
|
||||
{
|
||||
quest.setUI8AL( 0 );
|
||||
quest.setSeq( Seq1 );
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00001( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 1, NONE, bindSceneReturn( &SubWil062::Scene00001Return ) );
|
||||
}
|
||||
|
||||
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00002( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &SubWil062::Scene00002Return ) );
|
||||
}
|
||||
|
||||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
quest.setUI8BH( 0 );
|
||||
Scene00003( quest, player );
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00003( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 3, HIDE_HOTBAR, bindSceneReturn( &SubWil062::Scene00003Return ) );
|
||||
}
|
||||
|
||||
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
player.finishQuest( getId(), result.getResult( 1 ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00004( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 4, NONE, bindSceneReturn( &SubWil062::Scene00004Return ) );
|
||||
}
|
||||
|
||||
void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( SubWil062 );
|
103
src/scripts/quest/subquest/thanalan_central/SubWil063.cpp
Normal file
103
src/scripts/quest/subquest/thanalan_central/SubWil063.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
// 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 <Actor/Player.h>
|
||||
#include "Manager/EventMgr.h"
|
||||
#include <ScriptObject.h>
|
||||
#include <Service.h>
|
||||
|
||||
// Quest Script: SubWil063_00306
|
||||
// Quest Name: Prudence at This Junction
|
||||
// Quest ID: 65842
|
||||
// Start NPC: 1001447 (Warin)
|
||||
// End NPC: 1001447 (Warin)
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
class SubWil063 : public Sapphire::ScriptAPI::QuestScript
|
||||
{
|
||||
private:
|
||||
// Basic quest information
|
||||
// Quest vars / flags used
|
||||
// UI8AL
|
||||
|
||||
/// Countable Num: 1 Seq: 255 Event: 1 Listener: 1001447
|
||||
// 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 = 1001447; // Warin ( Pos: -32.639099 -1.033260 -148.485992 Teri: 141 )
|
||||
static constexpr auto Seq0Actor0 = 0; //
|
||||
static constexpr auto Seq1Actor0 = 1; //
|
||||
|
||||
public:
|
||||
SubWil063() : Sapphire::ScriptAPI::QuestScript( 65842 ){};
|
||||
~SubWil063() = 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() == SeqFinish )
|
||||
Scene00001( quest, player );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
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( &SubWil063::Scene00000Return ) );
|
||||
}
|
||||
|
||||
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 ) // accept quest
|
||||
{
|
||||
quest.setSeq( SeqFinish );
|
||||
eventMgr().sendNotice( player, getId(), 0, {} );
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00001( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &SubWil063::Scene00001Return ) );
|
||||
}
|
||||
|
||||
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
player.finishQuest( getId(), result.getResult( 1 ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( SubWil063 );
|
315
src/scripts/quest/subquest/thanalan_central/SubWil064.cpp
Normal file
315
src/scripts/quest/subquest/thanalan_central/SubWil064.cpp
Normal file
|
@ -0,0 +1,315 @@
|
|||
// 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 <Actor/BNpc.h>
|
||||
#include <ScriptObject.h>
|
||||
#include <Service.h>
|
||||
|
||||
#include "Actor/BNpc.h"
|
||||
#include "Manager/TerritoryMgr.h"
|
||||
#include "Territory/Territory.h"
|
||||
|
||||
// Quest Script: SubWil064_00307
|
||||
// Quest Name: Out of House and Home
|
||||
// Quest ID: 65843
|
||||
// Start NPC: 1001447 (Warin)
|
||||
// End NPC: 1001447 (Warin)
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
class SubWil064 : public Sapphire::ScriptAPI::QuestScript
|
||||
{
|
||||
private:
|
||||
// Basic quest information
|
||||
// Quest vars / flags used
|
||||
// BitFlag8
|
||||
// UI8AL
|
||||
// UI8BH
|
||||
|
||||
/// Countable Num: 0 Seq: 1 Event: 1 Listener: 2000268
|
||||
/// Countable Num: 1 Seq: 255 Event: 8 Listener: 2000268
|
||||
// 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 = 1001447; // Warin ( Pos: -32.639099 -1.033260 -148.485992 Teri: 141 )
|
||||
static constexpr auto Enemy0 = 3785130; //
|
||||
static constexpr auto Enemy1 = 3785131; //
|
||||
static constexpr auto Enemy2 = 3785134; //
|
||||
static constexpr auto Eobject0 = 2000268; // Narrow Fissure ( Pos: 25.690800 13.106300 47.828999 Teri: 141 )
|
||||
static constexpr auto Item0 = 2000212;
|
||||
|
||||
public:
|
||||
SubWil064() : Sapphire::ScriptAPI::QuestScript( 65843 ){};
|
||||
~SubWil064() = 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() == SeqFinish )
|
||||
{
|
||||
Scene00013( quest,player );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
if (actorId == Eobject0)
|
||||
{
|
||||
Scene00002( quest, player );
|
||||
}
|
||||
}
|
||||
|
||||
void onBNpcKill( World::Quest& quest, Entity::BNpc& bnpc, Entity::Player& player ) override
|
||||
{
|
||||
switch( bnpc.getLayoutId() )
|
||||
{
|
||||
case Enemy0:
|
||||
{
|
||||
auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() );
|
||||
auto enemy1 = instance->createBNpcFromLayoutId( Enemy1, 1220 /*Find the right value*/, Common::BNpcType::Enemy );
|
||||
auto enemy2 = instance->createBNpcFromLayoutId( Enemy2, 1220 /*Find the right value*/, Common::BNpcType::Enemy );
|
||||
|
||||
enemy1->setTriggerOwnerId( player.getId() );
|
||||
enemy2->setTriggerOwnerId( player.getId() );
|
||||
enemy1->hateListAddDelayed( player.getAsPlayer(), 1 );
|
||||
enemy2->hateListAddDelayed( player.getAsPlayer(), 1 );
|
||||
quest.setUI8AL( 1 );
|
||||
break;
|
||||
}
|
||||
case Enemy1:
|
||||
case Enemy2:
|
||||
{
|
||||
quest.setUI8AL( quest.getUI8AL() + 1 );
|
||||
if( quest.getUI8AL() >= 4 )
|
||||
{
|
||||
quest.setUI8BH( 0 );
|
||||
quest.setUI8AL( 0 );
|
||||
quest.setSeq( SeqFinish );
|
||||
eventMgr().sendNotice( player, getId(), 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( &SubWil064::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( &SubWil064::Scene00001Return ) );
|
||||
}
|
||||
|
||||
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
quest.setUI8BH( 1 );
|
||||
quest.setSeq( Seq1 );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00002( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 2, NONE, bindSceneReturn( &SubWil064::Scene00002Return ) );
|
||||
}
|
||||
|
||||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
quest.setBitFlag8( 1, true );
|
||||
auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() );
|
||||
auto enemy0 = instance->createBNpcFromLayoutId( Enemy0, 1220 /*Find the right value*/, Common::BNpcType::Enemy );
|
||||
enemy0->setTriggerOwnerId( player.getId() );
|
||||
enemy0->hateListAddDelayed( player.getAsPlayer(), 1 );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00003( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &SubWil064::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( &SubWil064::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, NONE, bindSceneReturn( &SubWil064::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( &SubWil064::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( &SubWil064::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( &SubWil064::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( &SubWil064::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( &SubWil064::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( &SubWil064::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, NONE, bindSceneReturn( &SubWil064::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, NONE, bindSceneReturn( &SubWil064::Scene00013Return ) );
|
||||
}
|
||||
|
||||
void Scene00013Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
player.finishQuest( getId(), result.getResult( 1 ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( SubWil064 );
|
234
src/scripts/quest/subquest/thanalan_central/SubWil070.cpp
Normal file
234
src/scripts/quest/subquest/thanalan_central/SubWil070.cpp
Normal file
|
@ -0,0 +1,234 @@
|
|||
// 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 <Actor/Player.h>
|
||||
#include "Manager/EventMgr.h"
|
||||
#include <ScriptObject.h>
|
||||
#include <Service.h>
|
||||
|
||||
// Quest Script: SubWil070_00324
|
||||
// Quest Name: Disorderly Conduct
|
||||
// Quest ID: 65860
|
||||
// Start NPC: 1001541 (Roger)
|
||||
// End NPC: 1001541 (Roger)
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
class SubWil070 : public Sapphire::ScriptAPI::QuestScript
|
||||
{
|
||||
private:
|
||||
// Basic quest information
|
||||
// Quest vars / flags used
|
||||
// BitFlag8
|
||||
// UI8AL
|
||||
// UI8BH
|
||||
|
||||
/// Countable Num: 4 Seq: 1 Event: 1 Listener: 1001462
|
||||
/// Countable Num: 1 Seq: 255 Event: 1 Listener: 1001463
|
||||
// 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 = 1001541; // Roger ( Pos: -99.395401 -11.380900 -41.723999 Teri: 141 )
|
||||
static constexpr auto Actor1 = 1001462; // Roundelph ( Pos: -93.339500 -11.350300 -41.367199 Teri: 141 )
|
||||
static constexpr auto Actor2 = 1001463; // Adalfuns ( Pos: -72.826401 -12.667800 -54.076199 Teri: 141 )
|
||||
static constexpr auto Actor3 = 1001465; // Solid Trunk ( Pos: -90.043503 -11.398500 -53.666000 Teri: 141 )
|
||||
static constexpr auto Actor4 = 1001466; // Ricard ( Pos: -89.735001 -11.350000 -51.539902 Teri: 141 )
|
||||
static constexpr auto Item0 = 2000234;
|
||||
static constexpr auto Item0Icon = 26153;
|
||||
static constexpr auto Seq0Actor0 = 0;
|
||||
static constexpr auto Seq1Actor1 = 1;
|
||||
static constexpr auto Seq1Actor2 = 2;
|
||||
static constexpr auto Seq1Actor3 = 3;
|
||||
static constexpr auto Seq1Actor4 = 4;
|
||||
static constexpr auto Seq2Actor0 = 5;
|
||||
static constexpr auto Seq2Actor0Npctradeno = 99;
|
||||
static constexpr auto Seq2Actor0Npctradeok = 100;
|
||||
|
||||
public:
|
||||
SubWil070() : Sapphire::ScriptAPI::QuestScript( 65860 ){};
|
||||
~SubWil070() = default;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Event Handlers
|
||||
void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
switch( actorId )
|
||||
{
|
||||
case Actor0:
|
||||
{
|
||||
if( quest.getSeq() == 0 )
|
||||
Scene00000( quest, player );
|
||||
else if( quest.getSeq() == SeqFinish )
|
||||
Scene00005( quest, player );
|
||||
break;
|
||||
}
|
||||
case Actor1:
|
||||
{
|
||||
if( quest.getSeq() == 1 )
|
||||
Scene00001( quest, player );
|
||||
break;
|
||||
}
|
||||
case Actor2:
|
||||
{
|
||||
if( quest.getSeq() == 1 )
|
||||
Scene00002( quest, player );
|
||||
break;
|
||||
}
|
||||
case Actor3:
|
||||
{
|
||||
if( quest.getSeq() == 1 )
|
||||
Scene00003( quest, player );
|
||||
break;
|
||||
}
|
||||
case Actor4:
|
||||
{
|
||||
if( quest.getSeq() == 1 )
|
||||
Scene00004( quest, player );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
void checkQuestCompletion( World::Quest& quest, Entity::Player& player, uint32_t varIdx )
|
||||
{
|
||||
if( varIdx == 1 )
|
||||
{
|
||||
quest.setUI8AL( quest.getUI8AL() + 1 );
|
||||
if (quest.getUI8AL() == 4)
|
||||
quest.setSeq( SeqFinish );
|
||||
}
|
||||
eventMgr().sendNotice( player, getId(), 0, { quest.getUI8AL(), 4, Item0Icon } );
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// 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( &SubWil070::Scene00000Return ) );
|
||||
}
|
||||
|
||||
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 ) // accept quest
|
||||
{
|
||||
quest.setUI8BH( 1 );
|
||||
quest.setSeq( Seq1 );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00001( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &SubWil070::Scene00001Return ) );
|
||||
}
|
||||
|
||||
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
checkQuestCompletion( quest, player, 1 );
|
||||
quest.setBitFlag8( 1, true );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00002( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &SubWil070::Scene00002Return ) );
|
||||
}
|
||||
|
||||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
checkQuestCompletion( quest, player, 1 );
|
||||
quest.setBitFlag8( 2, true );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00003( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 3, HIDE_HOTBAR, bindSceneReturn( &SubWil070::Scene00003Return ) );
|
||||
}
|
||||
|
||||
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
checkQuestCompletion( quest, player, 1 );
|
||||
quest.setBitFlag8( 3, true );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00004( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 4, HIDE_HOTBAR, bindSceneReturn( &SubWil070::Scene00004Return ) );
|
||||
}
|
||||
|
||||
void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
checkQuestCompletion( quest, player, 1 );
|
||||
quest.setBitFlag8( 4, true );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00005( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 5, NONE, bindSceneReturn( &SubWil070::Scene00005Return ) );
|
||||
}
|
||||
|
||||
void Scene00005Return( 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( &SubWil070::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( &SubWil070::Scene00100Return ) );
|
||||
}
|
||||
|
||||
void Scene00100Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
player.finishQuest( getId(), result.getResult( 1 ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( SubWil070 );
|
415
src/scripts/quest/subquest/thanalan_central/SubWil073.cpp
Normal file
415
src/scripts/quest/subquest/thanalan_central/SubWil073.cpp
Normal file
|
@ -0,0 +1,415 @@
|
|||
// 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 <Actor/BNpc.h>
|
||||
#include <ScriptObject.h>
|
||||
#include <Service.h>
|
||||
|
||||
#include "Actor/BNpc.h"
|
||||
#include "Manager/TerritoryMgr.h"
|
||||
#include "Territory/Territory.h"
|
||||
|
||||
// Quest Script: SubWil073_00327
|
||||
// Quest Name: Spriggan Cleaning
|
||||
// Quest ID: 65863
|
||||
// Start NPC: 1001447 (Warin)
|
||||
// End NPC: 1001447 (Warin)
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
class SubWil073 : public Sapphire::ScriptAPI::QuestScript
|
||||
{
|
||||
private:
|
||||
// Basic quest information
|
||||
// Quest vars / flags used
|
||||
// BitFlag8
|
||||
// UI8AH
|
||||
// UI8AL
|
||||
// UI8BH
|
||||
// UI8BL
|
||||
// UI8CH
|
||||
// UI8CL
|
||||
// UI8DH
|
||||
// UI8DL
|
||||
// UI8EH
|
||||
|
||||
/// Countable Num: 4 Seq: 1 Event: 1 Listener: 2000377
|
||||
/// Countable Num: 1 Seq: 255 Event: 5 Listener: 100
|
||||
// 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 = 1001447; // Warin ( Pos: -32.639099 -1.033260 -148.485992 Teri: 141 )
|
||||
static constexpr auto Enemy0 = 3742257; //
|
||||
static constexpr auto Enemy1 = 3742258; //
|
||||
static constexpr auto Enemy2 = 3742259; //
|
||||
static constexpr auto Enemy3 = 3742261; //
|
||||
static constexpr auto Eobject0 = 2000377; // Pockmarked Silver Ore ( Pos: -134.695999 6.168210 -116.594002 Teri: 141 )
|
||||
static constexpr auto Eobject1 = 2000378; // Pockmarked Silver Ore ( Pos: -95.958298 -1.021940 -163.731003 Teri: 141 )
|
||||
static constexpr auto Eobject2 = 2000379; // Pockmarked Silver Ore ( Pos: -103.938004 0.491295 -213.695007 Teri: 141 )
|
||||
static constexpr auto Eobject3 = 2000380; // Pockmarked Silver Ore ( Pos: -1.174590 -1.322410 -111.265999 Teri: 141 )
|
||||
static constexpr auto EventActionSearch = 1;
|
||||
static constexpr auto Seq0Actor0 = 0; //
|
||||
static constexpr auto Seq1Eobject0 = 1; //
|
||||
static constexpr auto Seq1Eobject0Eventactionno = 99; // Hecatoncheir Piledriver
|
||||
static constexpr auto Seq1Eobject0Eventactionok = 100; // Hecatoncheir Blastmaster ( Pos: -135.210007 5.708900 -117.417999 Teri: 141 )
|
||||
static constexpr auto Seq1Eobject1 = 2; // Ruins Runner ( Pos: -5.462710 -1.142520 27.215000 Teri: 5 )
|
||||
static constexpr auto Seq1Eobject1Eventactionno = 97; // Hecatoncheir Stonehauler
|
||||
static constexpr auto Seq1Eobject1Eventactionok = 98; // Hecatoncheir Shockblocker
|
||||
static constexpr auto Seq1Eobject2 = 3; // Antelope Doe
|
||||
static constexpr auto Seq1Eobject2Eventactionno = 95; // Flux Flan
|
||||
static constexpr auto Seq1Eobject2Eventactionok = 96; // Hecatoncheir Overseer
|
||||
static constexpr auto Seq1Eobject3 = 4; // Antelope Stag
|
||||
static constexpr auto Seq1Eobject3Eventactionno = 93; // Sargas
|
||||
static constexpr auto Seq1Eobject3Eventactionok = 94; // Shaula
|
||||
static constexpr auto Seq2Actor0 = 5; // Opo-opo
|
||||
|
||||
public:
|
||||
SubWil073() : Sapphire::ScriptAPI::QuestScript( 65863 ){};
|
||||
~SubWil073() = 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() == SeqFinish )
|
||||
Scene00005( quest, player );
|
||||
break;
|
||||
}
|
||||
case Eobject0:
|
||||
{
|
||||
eventMgr().eventActionStart(
|
||||
player, getId(), EventActionSearch,
|
||||
[ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) {
|
||||
Scene00094( quest, player );
|
||||
},
|
||||
nullptr, 0 );
|
||||
break;
|
||||
|
||||
}
|
||||
case Eobject1:
|
||||
{
|
||||
eventMgr().eventActionStart(
|
||||
player, getId(), EventActionSearch,
|
||||
[ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) {
|
||||
Scene00095( quest, player );
|
||||
},
|
||||
nullptr, 0 );
|
||||
break;
|
||||
}
|
||||
case Eobject2:
|
||||
{
|
||||
eventMgr().eventActionStart(
|
||||
player, getId(), EventActionSearch,
|
||||
[ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) {
|
||||
Scene00096( quest, player );
|
||||
},
|
||||
nullptr, 0 );
|
||||
break;
|
||||
}
|
||||
case Eobject3:
|
||||
{
|
||||
eventMgr().eventActionStart(
|
||||
player, getId(), EventActionSearch,
|
||||
[ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) {
|
||||
Scene00097( quest, player );
|
||||
},
|
||||
nullptr, 0 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
}
|
||||
|
||||
void onBNpcKill( World::Quest& quest, Entity::BNpc& bnpc, Entity::Player& player ) override
|
||||
{
|
||||
switch (bnpc.getLayoutId())
|
||||
{
|
||||
case Enemy0:
|
||||
{
|
||||
quest.setUI8AL( 1 );
|
||||
quest.setUI8BH( 1 );
|
||||
checkQuestCompletion( quest, player );
|
||||
break;
|
||||
}
|
||||
case Enemy1:
|
||||
{
|
||||
quest.setUI8BL( 1 );
|
||||
quest.setUI8CH( 1 );
|
||||
checkQuestCompletion( quest, player );
|
||||
break;
|
||||
}
|
||||
case Enemy2:
|
||||
{
|
||||
quest.setUI8CL( 1 );
|
||||
quest.setUI8DH( 1 );
|
||||
checkQuestCompletion( quest, player );
|
||||
break;
|
||||
}
|
||||
case Enemy3:
|
||||
{
|
||||
quest.setUI8DL( 1 );
|
||||
quest.setUI8EH( 1 );
|
||||
checkQuestCompletion( quest, player );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void checkQuestCompletion( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
quest.setUI8AH( quest.getUI8AH() + 1 );
|
||||
eventMgr().sendEventNotice( player, getId(), 0, 2, quest.getUI8AH(), 4 );
|
||||
|
||||
if( quest.getUI8AH() >= 4 )
|
||||
{
|
||||
quest.setUI8AL( 0 );
|
||||
quest.setUI8BH( 0 );
|
||||
quest.setUI8BL( 0 );
|
||||
quest.setUI8CH( 0 );
|
||||
quest.setUI8CL( 0 );
|
||||
quest.setUI8DH( 0 );
|
||||
quest.setUI8DL( 0 );
|
||||
quest.setUI8EH( 0 );
|
||||
quest.setUI8AH( 0 );
|
||||
quest.setBitFlag8( 1, false );
|
||||
quest.setBitFlag8( 2, false );
|
||||
quest.setBitFlag8( 3, false );
|
||||
quest.setBitFlag8( 4, 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( &SubWil073::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( &SubWil073::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, NONE, bindSceneReturn( &SubWil073::Scene00002Return ) );
|
||||
}
|
||||
|
||||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00003( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &SubWil073::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( &SubWil073::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( &SubWil073::Scene00005Return ) );
|
||||
}
|
||||
|
||||
void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
player.finishQuest( getId(), result.getResult( 1 ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00093( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 93, NONE, bindSceneReturn( &SubWil073::Scene00093Return ) );
|
||||
}
|
||||
|
||||
void Scene00093Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00094( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 94, NONE, bindSceneReturn( &SubWil073::Scene00094Return ) );
|
||||
}
|
||||
|
||||
void Scene00094Return( 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 );
|
||||
|
||||
enemy->setTriggerOwnerId( player.getId() );
|
||||
enemy->hateListAddDelayed( player.getAsPlayer(), 1 );
|
||||
quest.setBitFlag8( 1, true );
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00095( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 95, NONE, bindSceneReturn( &SubWil073::Scene00095Return ) );
|
||||
}
|
||||
|
||||
void Scene00095Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() );
|
||||
auto enemy = instance->createBNpcFromLayoutId( Enemy1, 1220 /*Find the right value*/, Common::BNpcType::Enemy );
|
||||
|
||||
enemy->setTriggerOwnerId( player.getId() );
|
||||
enemy->hateListAddDelayed( player.getAsPlayer(), 1 );
|
||||
quest.setBitFlag8( 2, true );
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00096( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 96, NONE, bindSceneReturn( &SubWil073::Scene00096Return ) );
|
||||
}
|
||||
|
||||
void Scene00096Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() );
|
||||
auto enemy = instance->createBNpcFromLayoutId( Enemy2, 1220 /*Find the right value*/, Common::BNpcType::Enemy );
|
||||
|
||||
enemy->setTriggerOwnerId( player.getId() );
|
||||
enemy->hateListAddDelayed( player.getAsPlayer(), 1 );
|
||||
quest.setBitFlag8( 3, true );
|
||||
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00097( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 97, NONE, bindSceneReturn( &SubWil073::Scene00097Return ) );
|
||||
}
|
||||
|
||||
void Scene00097Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() );
|
||||
auto enemy = instance->createBNpcFromLayoutId( Enemy3, 1220 /*Find the right value*/, Common::BNpcType::Enemy );
|
||||
|
||||
enemy->setTriggerOwnerId( player.getId() );
|
||||
enemy->hateListAddDelayed( player.getAsPlayer(), 1 );
|
||||
quest.setBitFlag8( 4, true );
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00098( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 98, NONE, bindSceneReturn( &SubWil073::Scene00098Return ) );
|
||||
}
|
||||
|
||||
void Scene00098Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00099( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 99, NONE, bindSceneReturn( &SubWil073::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, NONE, bindSceneReturn( &SubWil073::Scene00100Return ) );
|
||||
}
|
||||
|
||||
void Scene00100Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( SubWil073 );
|
136
src/scripts/quest/subquest/thanalan_central/SubWil080.cpp
Normal file
136
src/scripts/quest/subquest/thanalan_central/SubWil080.cpp
Normal file
|
@ -0,0 +1,136 @@
|
|||
// 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 <Actor/Player.h>
|
||||
#include "Manager/EventMgr.h"
|
||||
#include <ScriptObject.h>
|
||||
#include <Service.h>
|
||||
|
||||
// Quest Script: SubWil080_00328
|
||||
// Quest Name: Supply and Demands
|
||||
// Quest ID: 65864
|
||||
// Start NPC: 1002065 (Dadanen)
|
||||
// End NPC: 1002061 (Drunken Stag)
|
||||
|
||||
using namespace Sapphire;
|
||||
|
||||
class SubWil080 : public Sapphire::ScriptAPI::QuestScript
|
||||
{
|
||||
private:
|
||||
// Basic quest information
|
||||
// Quest vars / flags used
|
||||
// UI8AL
|
||||
// UI8BH
|
||||
|
||||
/// Countable Num: 1 Seq: 255 Event: 1 Listener: 1002061
|
||||
// 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 = 1002065; // Dadanen ( Pos: 60.946701 45.145302 -204.985992 Teri: 140 )
|
||||
static constexpr auto Actor1 = 1002061; // Drunken Stag ( Pos: 240.998993 58.318298 -160.998001 Teri: 140 )
|
||||
static constexpr auto Item0 = 2000368;
|
||||
|
||||
public:
|
||||
SubWil080() : Sapphire::ScriptAPI::QuestScript( 65864 ){};
|
||||
~SubWil080() = 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 )
|
||||
Scene00001( quest, player );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
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( &SubWil080::Scene00000Return ) );
|
||||
}
|
||||
|
||||
void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if( result.getResult( 0 ) == 1 ) // accept quest
|
||||
{
|
||||
quest.setUI8BH( 1 );
|
||||
quest.setSeq( SeqFinish );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00001( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &SubWil080::Scene00001Return ) );
|
||||
}
|
||||
|
||||
void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
if (result.getResult(0) == 1)
|
||||
{
|
||||
Scene00002( quest, player );
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00002( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 2, NONE, bindSceneReturn( &SubWil080::Scene00002Return ) );
|
||||
}
|
||||
|
||||
void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
if( result.getResult( 0 ) == 1 )
|
||||
{
|
||||
player.finishQuest( getId(), result.getResult( 1 ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Scene00003( World::Quest& quest, Entity::Player& player )
|
||||
{
|
||||
eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &SubWil080::Scene00003Return ) );
|
||||
}
|
||||
|
||||
void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( SubWil080 );
|
22
src/scripts/statuseffect/StatusEffectDefiance.cpp
Normal file
22
src/scripts/statuseffect/StatusEffectDefiance.cpp
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <Script/NativeScriptApi.h>
|
||||
#include <ScriptObject.h>
|
||||
#include <Actor/Player.h>
|
||||
#include <Action/CommonAction.h>
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::World::Action;
|
||||
|
||||
class StatusEffectDefiance : public Sapphire::ScriptAPI::StatusEffectScript
|
||||
{
|
||||
public:
|
||||
StatusEffectDefiance() : Sapphire::ScriptAPI::StatusEffectScript( 91 )
|
||||
{
|
||||
}
|
||||
|
||||
void onExpire( Entity::Chara& actor ) override
|
||||
{
|
||||
actor.removeStatusEffectById( { Unchained, Wrath, WrathII, WrathIII, WrathIV, Infuriated } );
|
||||
}
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( StatusEffectDefiance );
|
24
src/scripts/statuseffect/StatusEffectUnchained.cpp
Normal file
24
src/scripts/statuseffect/StatusEffectUnchained.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include <Script/NativeScriptApi.h>
|
||||
#include <ScriptObject.h>
|
||||
#include <Actor/Player.h>
|
||||
#include <Action/CommonAction.h>
|
||||
#include <StatusEffect/StatusEffect.h>
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::World::Action;
|
||||
|
||||
class StatusEffectUnchained : public Sapphire::ScriptAPI::StatusEffectScript
|
||||
{
|
||||
public:
|
||||
StatusEffectUnchained() : Sapphire::ScriptAPI::StatusEffectScript( 92 )
|
||||
{
|
||||
}
|
||||
|
||||
void onExpire( Entity::Chara& actor ) override
|
||||
{
|
||||
if( auto status = actor.getStatusEffectById( Defiance ); status )
|
||||
status->setModifier( Common::ParamModifier::DamageDealtPercent, -25 );
|
||||
}
|
||||
};
|
||||
|
||||
EXPOSE_SCRIPT( StatusEffectUnchained );
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"7": {
|
||||
"name": "Attack",
|
||||
"potency": 0,
|
||||
"potency": 110,
|
||||
"comboPotency": 0,
|
||||
"flankPotency": 0,
|
||||
"frontPotency": 0,
|
||||
|
@ -16,7 +16,7 @@
|
|||
},
|
||||
"8": {
|
||||
"name": "Shot",
|
||||
"potency": 0,
|
||||
"potency": 100,
|
||||
"comboPotency": 0,
|
||||
"flankPotency": 0,
|
||||
"frontPotency": 0,
|
||||
|
|
|
@ -40,6 +40,8 @@ struct StatusModifier
|
|||
struct StatusEntry
|
||||
{
|
||||
uint16_t id;
|
||||
uint32_t duration;
|
||||
uint32_t flag;
|
||||
std::vector< StatusModifier > modifiers;
|
||||
};
|
||||
|
||||
|
@ -76,6 +78,8 @@ void to_json( nlohmann::ordered_json& j, const StatusEntry& statusEntry )
|
|||
{
|
||||
j = nlohmann::ordered_json{
|
||||
{ "id", statusEntry.id },
|
||||
{ "duration", statusEntry.duration },
|
||||
{ "flag", statusEntry.flag },
|
||||
{ "modifiers", statusEntry.modifiers }
|
||||
};
|
||||
}
|
||||
|
@ -157,22 +161,20 @@ int main( int argc, char* argv[] )
|
|||
Logger::fatal( "Error setting up EXD data " );
|
||||
return 0;
|
||||
}
|
||||
auto idList = g_exdDataGen.getIdList< Excel::Action >();
|
||||
auto actionList = g_exdDataGen.getRows< Excel::Action >();
|
||||
|
||||
std::map< uint32_t, ActionEntry > actions;
|
||||
std::map< uint32_t, std::vector< uint32_t > > traversedCombos;
|
||||
|
||||
auto total = idList.size();
|
||||
auto total = actionList.size();
|
||||
int cursor = 0;
|
||||
|
||||
for( auto id : idList )
|
||||
for( const auto& [ id, action ] : actionList )
|
||||
{
|
||||
auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f;
|
||||
if( cursor % 50 == 0 && cursor > 0 )
|
||||
Logger::info( "Processing {} actions of {} ({:.2f}%)", cursor, total, done );
|
||||
|
||||
auto action = g_exdDataGen.getRow< Excel::Action >( id );
|
||||
|
||||
//auto actionTransient = g_exdData.get< Sapphire::Data::ActionTransient >( id );
|
||||
if( action )
|
||||
{
|
||||
|
|
|
@ -89,11 +89,11 @@ int main( int argc, char* argv[] )
|
|||
// CFC list
|
||||
{
|
||||
|
||||
auto idList = g_exdDataGen.getIdList< Excel::ContentFinderCondition >();
|
||||
auto cfcList = g_exdDataGen.getRows< Excel::ContentFinderCondition >();
|
||||
|
||||
std::stringstream cfcOutputStream;
|
||||
|
||||
auto total = idList.size();
|
||||
auto total = cfcList.size();
|
||||
int cursor = 0;
|
||||
|
||||
std::map< uint8_t, std::string > instanceContentTypeMap;
|
||||
|
@ -118,7 +118,7 @@ int main( int argc, char* argv[] )
|
|||
cfcOutputStream << "| ID | Instance | Territory | Name | Type |" << std::endl
|
||||
<< "| --- | --- | --- | --- | --- |" << std::endl;
|
||||
|
||||
for( auto id : idList )
|
||||
for( const auto& [ id, cfc ] : cfcList )
|
||||
{
|
||||
auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f;
|
||||
if( cursor % 50 == 0 && cursor > 0 )
|
||||
|
@ -127,8 +127,6 @@ int main( int argc, char* argv[] )
|
|||
if( id == 0 )
|
||||
continue;
|
||||
|
||||
auto cfc = g_exdDataGen.getRow< Excel::ContentFinderCondition >( id );
|
||||
|
||||
if( cfc )
|
||||
{
|
||||
auto& cfcData = cfc->data();
|
||||
|
@ -234,24 +232,22 @@ int main( int argc, char* argv[] )
|
|||
teriTypeIntendedUseMap[ TheFeastArea ] = "TheFeastArea";
|
||||
teriTypeIntendedUseMap[ PrivateEventArea ] = "PrivateEventArea";
|
||||
|
||||
auto idList = g_exdDataGen.getIdList< Excel::TerritoryType >();
|
||||
auto teriList = g_exdDataGen.getRows< Excel::TerritoryType >();
|
||||
|
||||
std::stringstream teritypeOutputStream;
|
||||
|
||||
teritypeOutputStream << "| ID | Place Name | Name | Intended Use |" << std::endl
|
||||
<< "| --- | --- | --- | --- |" << std::endl;
|
||||
|
||||
auto total = idList.size();
|
||||
auto total = teriList.size();
|
||||
int cursor = 0;
|
||||
|
||||
for( auto id : idList )
|
||||
for( const auto& [ id, teriType ] : teriList )
|
||||
{
|
||||
auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f;
|
||||
if( cursor % 50 == 0 && cursor > 0 )
|
||||
Logger::info( "Processing {} teritypes of {} ({:.2f}%)", cursor, total, done );
|
||||
|
||||
auto teriType = g_exdDataGen.getRow< Excel::TerritoryType >( id );
|
||||
|
||||
if( teriType )
|
||||
{
|
||||
auto& teriTypeData = teriType->data();
|
||||
|
@ -291,24 +287,22 @@ int main( int argc, char* argv[] )
|
|||
|
||||
// class/job list
|
||||
{
|
||||
auto idList = g_exdDataGen.getIdList< Excel::ClassJob >();
|
||||
auto classJobList = g_exdDataGen.getRows< Excel::ClassJob >();
|
||||
|
||||
std::stringstream classjobOutputStream;
|
||||
|
||||
classjobOutputStream << "| ID | Name | Short | Main Class |" << std::endl
|
||||
<< "| --- | --- | --- | --- |" << std::endl;
|
||||
|
||||
auto total = idList.size();
|
||||
auto total = classJobList.size();
|
||||
int cursor = 0;
|
||||
|
||||
for( auto id : idList )
|
||||
for( const auto& [ id, classJob ] : classJobList )
|
||||
{
|
||||
auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f;
|
||||
if( cursor % 50 == 0 && cursor > 0 )
|
||||
Logger::info( "Processing {} classjobs of {} ({:.2f}%)", cursor, total, done );
|
||||
|
||||
auto classJob = g_exdDataGen.getRow< Excel::ClassJob >( id );
|
||||
|
||||
if( classJob )
|
||||
{
|
||||
auto& classJobData = classJob->data();
|
||||
|
@ -338,7 +332,7 @@ int main( int argc, char* argv[] )
|
|||
|
||||
// achievement list
|
||||
{
|
||||
auto idList = g_exdDataGen.getIdList< Excel::Achievement >();
|
||||
auto achvList = g_exdDataGen.getRows< Excel::Achievement >();
|
||||
|
||||
enum class Type : uint8_t
|
||||
{
|
||||
|
@ -394,17 +388,15 @@ int main( int argc, char* argv[] )
|
|||
achvOutputStream << "| ID | Name | Type (Subtype) | Description |" << std::endl
|
||||
<< "| --- | --- | --- | --- |" << std::endl;
|
||||
|
||||
auto total = idList.size();
|
||||
auto total = achvList.size();
|
||||
int cursor = 0;
|
||||
|
||||
for( auto id : idList )
|
||||
for( const auto& [ id, pAchv ] : achvList )
|
||||
{
|
||||
auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f;
|
||||
if( cursor % 50 == 0 && cursor > 0 )
|
||||
Logger::info( "Processing {} achievements of {} ({:.2f}%)", cursor, total, done );
|
||||
|
||||
auto pAchv = g_exdDataGen.getRow< Excel::Achievement >( id );
|
||||
|
||||
if( pAchv )
|
||||
{
|
||||
auto& achvData = pAchv->data();
|
||||
|
|
95
src/world/AI/Fsm/Condition.h
Normal file
95
src/world/AI/Fsm/Condition.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
#include <cstdint>
|
||||
#include "ForwardsZone.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include <Util/Util.h>
|
||||
#include <Util/UtilMath.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI::Fsm
|
||||
{
|
||||
class Condition
|
||||
{
|
||||
public:
|
||||
Condition() = default;
|
||||
virtual ~Condition() = default;
|
||||
|
||||
virtual bool isConditionMet( Sapphire::Entity::BNpc& src ) const = 0;
|
||||
virtual bool update( Sapphire::Entity::BNpc& src, float time )
|
||||
{
|
||||
if( isConditionMet( src ) )
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
class RoamNextTimeReachedCondition : public Condition
|
||||
{
|
||||
public:
|
||||
bool isConditionMet( Sapphire::Entity::BNpc& src ) const override
|
||||
{
|
||||
if( ( Common::Util::getTimeSeconds() - src.getLastRoamTargetReachedTime() ) > 20 )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class RoamTargetReachedCondition : public Condition
|
||||
{
|
||||
public:
|
||||
bool isConditionMet( Sapphire::Entity::BNpc& src ) const override
|
||||
{
|
||||
if( src.isRoamTargetReached() )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class HateListEmptyCondition : public Condition
|
||||
{
|
||||
public:
|
||||
bool isConditionMet( Sapphire::Entity::BNpc& src ) const override
|
||||
{
|
||||
if( src.hateListGetHighest() )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class HateListHasEntriesCondition : public Condition
|
||||
{
|
||||
public:
|
||||
bool isConditionMet( Sapphire::Entity::BNpc& src ) const override
|
||||
{
|
||||
if( src.hateListGetHighest() )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class SpawnPointDistanceGtMaxDistanceCondition : public Condition
|
||||
{
|
||||
public:
|
||||
bool isConditionMet( Sapphire::Entity::BNpc& src ) const override
|
||||
{
|
||||
auto distanceOrig = Common::Util::distance( src.getPos(), src.getSpawnPos() );
|
||||
if( distanceOrig > 40 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class IsDeadCondition : public Condition
|
||||
{
|
||||
public:
|
||||
bool isConditionMet( Sapphire::Entity::BNpc& src ) const override
|
||||
{
|
||||
if( !src.isAlive() )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
43
src/world/AI/Fsm/State.h
Normal file
43
src/world/AI/Fsm/State.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include <cstdint>
|
||||
#include "ForwardsZone.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include "Transition.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI::Fsm
|
||||
{
|
||||
class State
|
||||
{
|
||||
public:
|
||||
virtual ~State() = default;
|
||||
|
||||
virtual void onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) = 0;
|
||||
virtual void onEnter( Entity::BNpc& bnpc ) { }
|
||||
virtual void onExit( Entity::BNpc& bnpc ) { }
|
||||
|
||||
void addTransition( TransitionPtr transition )
|
||||
{
|
||||
m_transitions.push_back( transition );
|
||||
}
|
||||
|
||||
void addTransition( StatePtr targetState, ConditionPtr condition )
|
||||
{
|
||||
m_transitions.push_back( make_Transition( targetState, condition ) );
|
||||
}
|
||||
|
||||
|
||||
TransitionPtr getTriggeredTransition( Entity::BNpc& bnpc )
|
||||
{
|
||||
for( auto transition : m_transitions )
|
||||
{
|
||||
if( transition->hasTriggered( bnpc ) )
|
||||
return transition;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector< TransitionPtr > m_transitions;
|
||||
};
|
||||
}
|
80
src/world/AI/Fsm/StateCombat.cpp
Normal file
80
src/world/AI/Fsm/StateCombat.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
#include "StateCombat.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include "Logging/Logger.h"
|
||||
#include <Service.h>
|
||||
|
||||
#include <Manager/TerritoryMgr.h>
|
||||
#include <Territory/Territory.h>
|
||||
#include <Navi/NaviProvider.h>
|
||||
|
||||
using namespace Sapphire::World;
|
||||
|
||||
void AI::Fsm::StateCombat::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount )
|
||||
{
|
||||
|
||||
auto& teriMgr = Common::Service< World::Manager::TerritoryMgr >::ref();
|
||||
auto pZone = teriMgr.getTerritoryByGuId( bnpc.getTerritoryId() );
|
||||
auto pNaviProvider = pZone->getNaviProvider();
|
||||
|
||||
auto pHatedActor = bnpc.hateListGetHighest();
|
||||
if( !pHatedActor )
|
||||
return;
|
||||
|
||||
pNaviProvider->updateAgentParameters( bnpc );
|
||||
|
||||
auto distanceOrig = Common::Util::distance( bnpc.getPos(), bnpc.getSpawnPos() );
|
||||
|
||||
if( !pHatedActor->isAlive() || bnpc.getTerritoryId() != pHatedActor->getTerritoryId() )
|
||||
{
|
||||
bnpc.hateListRemove( pHatedActor );
|
||||
pHatedActor = bnpc.hateListGetHighest();
|
||||
}
|
||||
|
||||
if( !pHatedActor )
|
||||
return;
|
||||
|
||||
auto distance = Common::Util::distance( bnpc.getPos(), pHatedActor->getPos() );
|
||||
|
||||
if( !bnpc.hasFlag( Entity::NoDeaggro ) )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if( !bnpc.hasFlag( Entity::Immobile ) && distance > ( bnpc.getNaviTargetReachedDistance() + pHatedActor->getRadius() ) )
|
||||
{
|
||||
if( pNaviProvider )
|
||||
pNaviProvider->setMoveTarget( bnpc, pHatedActor->getPos() );
|
||||
|
||||
bnpc.moveTo( *pHatedActor );
|
||||
}
|
||||
|
||||
pNaviProvider->syncPosToChara( bnpc );
|
||||
|
||||
if( distance < ( bnpc.getNaviTargetReachedDistance() + pHatedActor->getRadius() ) )
|
||||
{
|
||||
// todo: dont turn if facing
|
||||
if( !bnpc.hasFlag( Entity::TurningDisabled ) )
|
||||
bnpc.face( pHatedActor->getPos() );
|
||||
|
||||
if( !bnpc.checkAction() )
|
||||
bnpc.processGambits( tickCount );
|
||||
|
||||
// in combat range. ATTACK!
|
||||
if( !bnpc.hasFlag( Entity::BNpcFlag::AutoAttackDisabled ) )
|
||||
bnpc.autoAttack( pHatedActor );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AI::Fsm::StateCombat::onEnter( Entity::BNpc& bnpc )
|
||||
{
|
||||
}
|
||||
|
||||
void AI::Fsm::StateCombat::onExit( Entity::BNpc& bnpc )
|
||||
{
|
||||
bnpc.hateListClear();
|
||||
bnpc.changeTarget( Common::INVALID_GAME_OBJECT_ID64 );
|
||||
bnpc.setStance( Common::Stance::Passive );
|
||||
bnpc.setOwner( nullptr );
|
||||
}
|
||||
|
20
src/world/AI/Fsm/StateCombat.h
Normal file
20
src/world/AI/Fsm/StateCombat.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <cstdint>
|
||||
#include "ForwardsZone.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include "State.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI::Fsm
|
||||
{
|
||||
class StateCombat : public State
|
||||
{
|
||||
public:
|
||||
virtual ~StateCombat() = default;
|
||||
|
||||
void onUpdate( Entity::BNpc& bnpc, uint64_t tickCount );
|
||||
void onEnter( Entity::BNpc& bnpc );
|
||||
void onExit( Entity::BNpc& bnpc );
|
||||
|
||||
};
|
||||
}
|
26
src/world/AI/Fsm/StateDead.cpp
Normal file
26
src/world/AI/Fsm/StateDead.cpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include "StateDead.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include "Logging/Logger.h"
|
||||
#include <Service.h>
|
||||
#include <Manager/TerritoryMgr.h>
|
||||
|
||||
#include <Territory/Territory.h>
|
||||
#include <Navi/NaviProvider.h>
|
||||
|
||||
using namespace Sapphire::World;
|
||||
|
||||
void AI::Fsm::StateDead::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AI::Fsm::StateDead::onEnter( Entity::BNpc& bnpc )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AI::Fsm::StateDead::onExit( Entity::BNpc& bnpc )
|
||||
{
|
||||
|
||||
}
|
||||
|
20
src/world/AI/Fsm/StateDead.h
Normal file
20
src/world/AI/Fsm/StateDead.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <cstdint>
|
||||
#include "ForwardsZone.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include "State.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI::Fsm
|
||||
{
|
||||
class StateDead : public State
|
||||
{
|
||||
public:
|
||||
virtual ~StateDead() = default;
|
||||
|
||||
void onUpdate( Entity::BNpc& bnpc, uint64_t tickCount );
|
||||
void onEnter( Entity::BNpc& bnpc );
|
||||
void onExit( Entity::BNpc& bnpc );
|
||||
|
||||
};
|
||||
}
|
20
src/world/AI/Fsm/StateIdle.cpp
Normal file
20
src/world/AI/Fsm/StateIdle.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include "StateIdle.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include "Logging/Logger.h"
|
||||
|
||||
using namespace Sapphire::World;
|
||||
|
||||
void AI::Fsm::StateIdle::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AI::Fsm::StateIdle::onEnter( Entity::BNpc& bnpc )
|
||||
{
|
||||
bnpc.setLastRoamTargetReachedTime( Common::Util::getTimeSeconds() );
|
||||
}
|
||||
|
||||
void AI::Fsm::StateIdle::onExit( Entity::BNpc& bnpc )
|
||||
{
|
||||
}
|
||||
|
20
src/world/AI/Fsm/StateIdle.h
Normal file
20
src/world/AI/Fsm/StateIdle.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <cstdint>
|
||||
#include "ForwardsZone.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include "State.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI::Fsm
|
||||
{
|
||||
class StateIdle : public State
|
||||
{
|
||||
public:
|
||||
virtual ~StateIdle() = default;
|
||||
|
||||
void onUpdate( Entity::BNpc& bnpc, uint64_t tickCount );
|
||||
void onEnter( Entity::BNpc& bnpc );
|
||||
void onExit( Entity::BNpc& bnpc );
|
||||
|
||||
};
|
||||
}
|
38
src/world/AI/Fsm/StateMachine.cpp
Normal file
38
src/world/AI/Fsm/StateMachine.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
#include <cstdint>
|
||||
#include "ForwardsZone.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include "StateMachine.h"
|
||||
#include "State.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::World;
|
||||
|
||||
AI::Fsm::StatePtr AI::Fsm::StateMachine::addState( Fsm::StatePtr state )
|
||||
{
|
||||
m_states.push_back( state );
|
||||
return state;
|
||||
}
|
||||
|
||||
void AI::Fsm::StateMachine::setCurrentState( Fsm::StatePtr state )
|
||||
{
|
||||
m_pCurrentState = state;
|
||||
}
|
||||
|
||||
void AI::Fsm::StateMachine::update( Entity::BNpc& bnpc, uint64_t tickCount )
|
||||
{
|
||||
if( !m_pCurrentState )
|
||||
return;
|
||||
|
||||
TransitionPtr transition = m_pCurrentState->getTriggeredTransition( bnpc );
|
||||
|
||||
if( transition )
|
||||
{
|
||||
m_pCurrentState->onExit( bnpc );
|
||||
m_pCurrentState = transition->getTargetState();
|
||||
m_pCurrentState->onEnter( bnpc );
|
||||
}
|
||||
|
||||
m_pCurrentState->onUpdate( bnpc, tickCount );
|
||||
}
|
23
src/world/AI/Fsm/StateMachine.h
Normal file
23
src/world/AI/Fsm/StateMachine.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include <cstdint>
|
||||
#include "ForwardsZone.h"
|
||||
#include "Actor/BNpc.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI::Fsm
|
||||
{
|
||||
class StateMachine
|
||||
{
|
||||
public:
|
||||
StateMachine() = default;
|
||||
~StateMachine() = default;
|
||||
|
||||
StatePtr addState( StatePtr state );
|
||||
void setCurrentState( StatePtr state );
|
||||
virtual void update( Entity::BNpc& bnpc, uint64_t tickCount );
|
||||
|
||||
protected:
|
||||
std::vector< StatePtr > m_states;
|
||||
StatePtr m_pCurrentState;
|
||||
};
|
||||
}
|
41
src/world/AI/Fsm/StateRetreat.cpp
Normal file
41
src/world/AI/Fsm/StateRetreat.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include "StateRetreat.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include "Logging/Logger.h"
|
||||
#include <Service.h>
|
||||
#include <Manager/TerritoryMgr.h>
|
||||
|
||||
#include <Territory/Territory.h>
|
||||
#include <Navi/NaviProvider.h>
|
||||
|
||||
using namespace Sapphire::World;
|
||||
|
||||
void AI::Fsm::StateRetreat::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount )
|
||||
{
|
||||
if( bnpc.moveTo( bnpc.getSpawnPos() ) )
|
||||
{
|
||||
bnpc.setRoamTargetReached( true );
|
||||
bnpc.setLastRoamTargetReachedTime( Common::Util::getTimeSeconds() );
|
||||
}
|
||||
}
|
||||
|
||||
void AI::Fsm::StateRetreat::onEnter( Entity::BNpc& bnpc )
|
||||
{
|
||||
bnpc.setRoamTargetReached( false );
|
||||
|
||||
auto& teriMgr = Common::Service< World::Manager::TerritoryMgr >::ref();
|
||||
auto pZone = teriMgr.getTerritoryByGuId( bnpc.getTerritoryId() );
|
||||
auto pNaviProvider = pZone->getNaviProvider();
|
||||
|
||||
bnpc.setInvincibilityType( Common::InvincibilityType::InvincibilityIgnoreDamage );
|
||||
|
||||
if( pNaviProvider )
|
||||
pNaviProvider->setMoveTarget( bnpc, bnpc.getSpawnPos() );
|
||||
}
|
||||
|
||||
void AI::Fsm::StateRetreat::onExit( Entity::BNpc& bnpc )
|
||||
{
|
||||
bnpc.setOwner( nullptr );
|
||||
bnpc.setRoamTargetReached( false );
|
||||
bnpc.setInvincibilityType( Common::InvincibilityType::InvincibilityNone );
|
||||
}
|
||||
|
20
src/world/AI/Fsm/StateRetreat.h
Normal file
20
src/world/AI/Fsm/StateRetreat.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <cstdint>
|
||||
#include "ForwardsZone.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include "State.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI::Fsm
|
||||
{
|
||||
class StateRetreat : public State
|
||||
{
|
||||
public:
|
||||
virtual ~StateRetreat() = default;
|
||||
|
||||
void onUpdate( Entity::BNpc& bnpc, uint64_t tickCount );
|
||||
void onEnter( Entity::BNpc& bnpc );
|
||||
void onExit( Entity::BNpc& bnpc );
|
||||
|
||||
};
|
||||
}
|
49
src/world/AI/Fsm/StateRoam.cpp
Normal file
49
src/world/AI/Fsm/StateRoam.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
#include "StateRoam.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include "Logging/Logger.h"
|
||||
#include <Service.h>
|
||||
#include <Manager/TerritoryMgr.h>
|
||||
|
||||
#include <Territory/Territory.h>
|
||||
#include <Navi/NaviProvider.h>
|
||||
|
||||
using namespace Sapphire::World;
|
||||
|
||||
void AI::Fsm::StateRoam::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount )
|
||||
{
|
||||
auto& teriMgr = Common::Service< World::Manager::TerritoryMgr >::ref();
|
||||
auto pZone = teriMgr.getTerritoryByGuId( bnpc.getTerritoryId() );
|
||||
auto pNaviProvider = pZone->getNaviProvider();
|
||||
|
||||
if( pNaviProvider )
|
||||
pNaviProvider->setMoveTarget( bnpc, bnpc.getRoamTargetPos() );
|
||||
|
||||
if( bnpc.moveTo( bnpc.getRoamTargetPos() ) )
|
||||
{
|
||||
bnpc.setRoamTargetReached( true );
|
||||
bnpc.setLastRoamTargetReachedTime( Common::Util::getTimeSeconds() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void AI::Fsm::StateRoam::onEnter( Entity::BNpc& bnpc )
|
||||
{
|
||||
auto& teriMgr = Common::Service< World::Manager::TerritoryMgr >::ref();
|
||||
auto pZone = teriMgr.getTerritoryByGuId( bnpc.getTerritoryId() );
|
||||
auto pNaviProvider = pZone->getNaviProvider();
|
||||
|
||||
if( !pNaviProvider )
|
||||
{
|
||||
bnpc.setRoamTargetReached( true );
|
||||
return;
|
||||
}
|
||||
|
||||
auto pos = pNaviProvider->findRandomPositionInCircle( bnpc.getSpawnPos(), bnpc.getInstanceObjectInfo()->WanderingRange );
|
||||
bnpc.setRoamTargetPos( pos );
|
||||
}
|
||||
|
||||
void AI::Fsm::StateRoam::onExit( Entity::BNpc& bnpc )
|
||||
{
|
||||
bnpc.setRoamTargetReached( false );
|
||||
}
|
||||
|
20
src/world/AI/Fsm/StateRoam.h
Normal file
20
src/world/AI/Fsm/StateRoam.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include <cstdint>
|
||||
#include "ForwardsZone.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include "State.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI::Fsm
|
||||
{
|
||||
class StateRoam : public State
|
||||
{
|
||||
public:
|
||||
virtual ~StateRoam() = default;
|
||||
|
||||
void onUpdate( Entity::BNpc& bnpc, uint64_t tickCount );
|
||||
void onEnter( Entity::BNpc& bnpc );
|
||||
void onExit( Entity::BNpc& bnpc );
|
||||
|
||||
};
|
||||
}
|
22
src/world/AI/Fsm/Transition.h
Normal file
22
src/world/AI/Fsm/Transition.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <cstdint>
|
||||
#include "ForwardsZone.h"
|
||||
#include "Actor/BNpc.h"
|
||||
#include "AI/Fsm/Condition.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI::Fsm
|
||||
{
|
||||
class Transition
|
||||
{
|
||||
public:
|
||||
Transition( StatePtr targetState, ConditionPtr condition ) : m_pTargetState( targetState ), m_pCondition( condition ) { }
|
||||
virtual ~Transition() = default;
|
||||
|
||||
StatePtr getTargetState() { return m_pTargetState; }
|
||||
bool hasTriggered( Entity::BNpc& bnpc ) { return m_pCondition->isConditionMet( bnpc ); }
|
||||
private:
|
||||
StatePtr m_pTargetState;
|
||||
ConditionPtr m_pCondition;
|
||||
};
|
||||
}
|
135
src/world/AI/GambitPack.cpp
Normal file
135
src/world/AI/GambitPack.cpp
Normal file
|
@ -0,0 +1,135 @@
|
|||
#include <cstdint>
|
||||
#include <ForwardsZone.h>
|
||||
#include <Service.h>
|
||||
#include <Manager/ActionMgr.h>
|
||||
#include <Action/Action.h>
|
||||
#include "GambitTargetCondition.h"
|
||||
#include "GambitRule.h"
|
||||
#include "GambitPack.h"
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::World;
|
||||
|
||||
AI::GambitTimeLinePack::GambitTimeLinePack( int8_t loopCount ) :
|
||||
GambitPack( GambitPackType::TimeLine ),
|
||||
m_loopCount( loopCount ),
|
||||
m_currentIndex( 0 ),
|
||||
m_currentLoop( 0 ),
|
||||
m_startTimeMs( 0 )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AI::GambitTimeLinePack::start()
|
||||
{
|
||||
m_startTimeMs = Common::Util::getTimeMs();
|
||||
}
|
||||
|
||||
void AI::GambitTimeLinePack::addTimeLine( const GambitRulePtr& pRule, uint32_t offsetInSeconds )
|
||||
{
|
||||
auto timeLine = std::make_pair( pRule, offsetInSeconds );
|
||||
m_gambits.push_back( timeLine );
|
||||
}
|
||||
|
||||
void AI::GambitTimeLinePack::addTimeLine( const GambitTargetConditionPtr& targetCondition, const Action::ActionPtr& action, uint32_t offsetInSeconds )
|
||||
{
|
||||
auto pRule = make_GambitRule( targetCondition, action, 0 );
|
||||
auto timeLine = std::make_pair( pRule, offsetInSeconds );
|
||||
m_gambits.push_back( timeLine );
|
||||
}
|
||||
|
||||
uint8_t AI::GambitTimeLinePack::getLoopCount() const
|
||||
{
|
||||
return m_loopCount;
|
||||
}
|
||||
|
||||
uint8_t AI::GambitTimeLinePack::getCurrentIndex() const
|
||||
{
|
||||
return m_currentIndex;
|
||||
}
|
||||
|
||||
void AI::GambitTimeLinePack::update( Entity::BNpc& bnpc, uint64_t tickCount )
|
||||
{
|
||||
if( m_startTimeMs == 0 || m_gambits.empty() )
|
||||
return;
|
||||
|
||||
auto& actionMgr = Common::Service< World::Manager::ActionMgr >::ref();
|
||||
|
||||
if( m_gambits.size() <= m_currentIndex )
|
||||
{
|
||||
if( m_currentLoop < m_loopCount || m_loopCount == -1 )
|
||||
{
|
||||
m_currentIndex = 0;
|
||||
m_currentLoop++;
|
||||
m_startTimeMs = Common::Util::getTimeMs();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_startTimeMs = 0;
|
||||
m_currentLoop = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto currentTimeLine = m_gambits.at( m_currentIndex );
|
||||
auto& pRule = currentTimeLine.first;
|
||||
auto offset = currentTimeLine.second * 1000;
|
||||
|
||||
if( tickCount - m_startTimeMs >= offset )
|
||||
{
|
||||
if( pRule->getGambitTargetCondition()->isConditionMet( bnpc ) )
|
||||
{
|
||||
pRule->setLastExecutionMs( tickCount );
|
||||
actionMgr.handleTargetedAction( bnpc, pRule->getActionPtr()->getId(), pRule->getGambitTargetCondition()->getTarget()->getId(), 0 );
|
||||
}
|
||||
m_currentIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AI::GambitRuleSetPack::GambitRuleSetPack() : GambitPack( GambitPackType::RuleSetList )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AI::GambitRuleSetPack::addRule( const GambitRulePtr& pRule )
|
||||
{
|
||||
m_gambits.push_back( pRule );
|
||||
}
|
||||
|
||||
void AI::GambitRuleSetPack::addRule( const GambitTargetConditionPtr& targetCondition, const Action::ActionPtr& action, uint32_t coolDown )
|
||||
{
|
||||
auto pRule = make_GambitRule( targetCondition, action, coolDown );
|
||||
m_gambits.push_back( pRule );
|
||||
}
|
||||
|
||||
void AI::GambitRuleSetPack::update( Entity::BNpc& bnpc, uint64_t tickCount )
|
||||
{
|
||||
auto& actionMgr = Common::Service< World::Manager::ActionMgr >::ref();
|
||||
for( auto& gambitRule : m_gambits )
|
||||
{
|
||||
if( !gambitRule->isEnabled() )
|
||||
continue;
|
||||
|
||||
if( ( tickCount - gambitRule->getLastExecutionMs() ) > gambitRule->getCoolDown() )
|
||||
{
|
||||
if( !gambitRule->getGambitTargetCondition()->isConditionMet( bnpc ) )
|
||||
continue;
|
||||
|
||||
gambitRule->setLastExecutionMs( tickCount );
|
||||
actionMgr.handleTargetedAction( bnpc, gambitRule->getActionPtr()->getId(), gambitRule->getGambitTargetCondition()->getTarget()->getId(), 0 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AI::GambitTimeLinePackPtr AI::GambitPack::getAsTimeLine()
|
||||
{
|
||||
return std::dynamic_pointer_cast< GambitTimeLinePack, GambitPack >( shared_from_this() );
|
||||
}
|
||||
|
||||
AI::GambitRuleSetPackPtr AI::GambitPack::getAsRuleSet()
|
||||
{
|
||||
return std::dynamic_pointer_cast< GambitRuleSetPack, GambitPack >( shared_from_this() );
|
||||
}
|
60
src/world/AI/GambitPack.h
Normal file
60
src/world/AI/GambitPack.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include <cstdint>
|
||||
#include <ForwardsZone.h>
|
||||
#include "GambitTargetCondition.h"
|
||||
#include "GambitRule.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI
|
||||
{
|
||||
enum class GambitPackType : uint8_t
|
||||
{
|
||||
None,
|
||||
RuleSetList,
|
||||
TimeLine
|
||||
};
|
||||
|
||||
class GambitPack : public std::enable_shared_from_this< GambitPack >
|
||||
{
|
||||
public:
|
||||
GambitPack( GambitPackType type ) : m_type( type ) { };
|
||||
virtual ~GambitPack() = default;
|
||||
GambitPackType getType() const { return m_type; }
|
||||
virtual void update( Entity::BNpc& bnpc, uint64_t tickCount ) = 0;
|
||||
GambitTimeLinePackPtr getAsTimeLine();
|
||||
GambitRuleSetPackPtr getAsRuleSet();
|
||||
private:
|
||||
GambitPackType m_type;
|
||||
};
|
||||
|
||||
class GambitTimeLinePack : public GambitPack
|
||||
{
|
||||
public:
|
||||
GambitTimeLinePack( int8_t loopCount );
|
||||
void update( Entity::BNpc& bnpc, uint64_t tickCount );
|
||||
void addTimeLine( const GambitRulePtr& pRule, uint32_t offsetInSeconds );
|
||||
void addTimeLine( const GambitTargetConditionPtr& targetCondition, const Action::ActionPtr& action, uint32_t offsetInSeconds );
|
||||
uint8_t getLoopCount() const;
|
||||
uint8_t getCurrentIndex() const;
|
||||
void start();
|
||||
|
||||
private:
|
||||
std::vector< std::pair< GambitRulePtr, uint32_t > > m_gambits;
|
||||
|
||||
uint64_t m_startTimeMs;
|
||||
uint8_t m_currentIndex;
|
||||
int8_t m_loopCount;
|
||||
uint8_t m_currentLoop;
|
||||
};
|
||||
|
||||
class GambitRuleSetPack : public GambitPack
|
||||
{
|
||||
public:
|
||||
GambitRuleSetPack();
|
||||
void addRule( const GambitRulePtr& pRule );
|
||||
void addRule( const GambitTargetConditionPtr& targetCondition, const Action::ActionPtr& action, uint32_t coolDown );
|
||||
void update( Entity::BNpc& bnpc, uint64_t tickCount );
|
||||
private:
|
||||
std::vector< GambitRulePtr > m_gambits;
|
||||
};
|
||||
}
|
52
src/world/AI/GambitRule.cpp
Normal file
52
src/world/AI/GambitRule.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
#include <cstdint>
|
||||
#include <ForwardsZone.h>
|
||||
#include "GambitTargetCondition.h"
|
||||
#include "GambitRule.h"
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::World;
|
||||
|
||||
AI::GambitRule::GambitRule( const GambitTargetConditionPtr targetCondition, Action::ActionPtr action, uint32_t coolDown ) :
|
||||
m_targetCondition( targetCondition ),
|
||||
m_pAction( std::move( action ) ),
|
||||
m_lastExecutionMs( 0 ),
|
||||
m_coolDownMs( coolDown ),
|
||||
m_isEnabled( true )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AI::GambitRule::toggleEnabled()
|
||||
{
|
||||
m_isEnabled = !m_isEnabled;
|
||||
}
|
||||
|
||||
bool AI::GambitRule::isEnabled() const
|
||||
{
|
||||
return m_isEnabled;
|
||||
}
|
||||
|
||||
uint64_t AI::GambitRule::getLastExecutionMs() const
|
||||
{
|
||||
return m_lastExecutionMs;
|
||||
}
|
||||
|
||||
void AI::GambitRule::setLastExecutionMs( uint64_t lastExecution )
|
||||
{
|
||||
m_lastExecutionMs = lastExecution;
|
||||
}
|
||||
|
||||
uint32_t AI::GambitRule::getCoolDown() const
|
||||
{
|
||||
return m_coolDownMs;
|
||||
}
|
||||
|
||||
AI::GambitTargetConditionPtr AI::GambitRule::getGambitTargetCondition()
|
||||
{
|
||||
return m_targetCondition;
|
||||
}
|
||||
|
||||
Action::ActionPtr AI::GambitRule::getActionPtr()
|
||||
{
|
||||
return m_pAction;
|
||||
}
|
33
src/world/AI/GambitRule.h
Normal file
33
src/world/AI/GambitRule.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include <cstdint>
|
||||
#include <ForwardsZone.h>
|
||||
#include "GambitTargetCondition.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI
|
||||
{
|
||||
class GambitRule
|
||||
{
|
||||
public:
|
||||
GambitRule( GambitTargetConditionPtr targetCondition, Action::ActionPtr action, uint32_t coolDown );
|
||||
~GambitRule() = default;
|
||||
|
||||
bool isEnabled() const;
|
||||
void toggleEnabled();
|
||||
|
||||
uint64_t getLastExecutionMs() const;
|
||||
void setLastExecutionMs( uint64_t lastExecution );
|
||||
|
||||
uint32_t getCoolDown() const;
|
||||
|
||||
GambitTargetConditionPtr getGambitTargetCondition();
|
||||
|
||||
Action::ActionPtr getActionPtr();
|
||||
private:
|
||||
GambitTargetConditionPtr m_targetCondition;
|
||||
Action::ActionPtr m_pAction;
|
||||
uint32_t m_coolDownMs;
|
||||
uint64_t m_lastExecutionMs;
|
||||
bool m_isEnabled;
|
||||
};
|
||||
}
|
65
src/world/AI/GambitTargetCondition.h
Normal file
65
src/world/AI/GambitTargetCondition.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
#include <cstdint>
|
||||
#include <ForwardsZone.h>
|
||||
#include <Actor/BNpc.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Sapphire::World::AI
|
||||
{
|
||||
enum GambitTargetType : uint8_t
|
||||
{
|
||||
Self,
|
||||
Player,
|
||||
PlayerAndAlly,
|
||||
Ally,
|
||||
BNpc
|
||||
};
|
||||
|
||||
class GambitTargetCondition
|
||||
{
|
||||
public:
|
||||
GambitTargetCondition() = default;
|
||||
virtual ~GambitTargetCondition() = default;
|
||||
|
||||
virtual bool isConditionMet( Sapphire::Entity::BNpc& src ) { return false; };
|
||||
Sapphire::Entity::CharaPtr getTarget() const { return m_pTarget; };
|
||||
protected:
|
||||
Sapphire::Entity::CharaPtr m_pTarget;
|
||||
};
|
||||
|
||||
class TopHateTargetCondition : public GambitTargetCondition
|
||||
{
|
||||
public:
|
||||
TopHateTargetCondition() = default;
|
||||
|
||||
bool isConditionMet( Sapphire::Entity::BNpc& src ) override
|
||||
{
|
||||
auto foundChara = src.hateListGetHighest();
|
||||
if( foundChara )
|
||||
{
|
||||
m_pTarget = foundChara;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
class HPSelfPctLessThanTargetCondition : public GambitTargetCondition
|
||||
{
|
||||
public:
|
||||
HPSelfPctLessThanTargetCondition( uint8_t pct ) : m_HpPct( pct ) {};
|
||||
|
||||
bool isConditionMet( Sapphire::Entity::BNpc& src ) override
|
||||
{
|
||||
if( src.getHpPercent() < m_HpPct )
|
||||
{
|
||||
m_pTarget = src.getAsBNpc();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
private:
|
||||
uint8_t m_HpPct;
|
||||
};
|
||||
|
||||
}
|
271
src/world/AI/TargetHelper.cpp
Normal file
271
src/world/AI/TargetHelper.cpp
Normal file
|
@ -0,0 +1,271 @@
|
|||
#include "TargetHelper.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <Actor/BNpc.h>
|
||||
#include <Actor/Chara.h>
|
||||
#include <Actor/Player.h>
|
||||
#include <Manager/PartyMgr.h>
|
||||
#include <Manager/RNGMgr.h>
|
||||
#include <Util/UtilMath.h>
|
||||
#include <Service.h>
|
||||
|
||||
namespace Sapphire::World::AI
|
||||
{
|
||||
|
||||
bool InsideRadiusFilter::isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const
|
||||
{
|
||||
bool ret = Common::Util::distance( pSrc->getPos(), pTarget->getPos() ) <= m_distance;
|
||||
return m_negate ? !ret : ret;
|
||||
}
|
||||
|
||||
bool OutsideRadiusFilter::isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const
|
||||
{
|
||||
bool ret = Common::Util::distance( pSrc->getPos(), pTarget->getPos() ) >= m_distance;
|
||||
return m_negate ? !ret : ret;
|
||||
}
|
||||
|
||||
bool PlayerFilter::isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const
|
||||
{
|
||||
bool ret = pTarget->isPlayer();
|
||||
return m_negate ? !ret : ret;
|
||||
}
|
||||
|
||||
bool AllyFilter::isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const
|
||||
{
|
||||
bool ret = false;
|
||||
// todo: pets, companions, enpc
|
||||
if( pSrc->isPlayer() )
|
||||
{
|
||||
auto pBNpcTarget = pTarget->getAsBNpc();
|
||||
if( pBNpcTarget && pBNpcTarget->getEnemyType() == 0 )
|
||||
ret = true;
|
||||
else if( pTarget->isPlayer() )
|
||||
ret = true;
|
||||
}
|
||||
else if( pSrc->isBattleNpc() )
|
||||
{
|
||||
auto pBNpcTarget = pTarget->getAsBNpc();
|
||||
if( pBNpcTarget && pBNpcTarget->getEnemyType() == 0 )
|
||||
ret = true;
|
||||
else if( pTarget->isPlayer() )
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return m_negate ? !ret : ret;
|
||||
}
|
||||
|
||||
bool OwnBattalionFilter::isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TankFilter::isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const
|
||||
{
|
||||
bool ret = pTarget->getRole() == Common::Role::Tank;
|
||||
return m_negate ? !ret : ret;
|
||||
}
|
||||
|
||||
bool HealerFilter::isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const
|
||||
{
|
||||
bool ret = pTarget->getRole() == Common::Role::Healer;
|
||||
return m_negate ? !ret : ret;
|
||||
}
|
||||
|
||||
bool DpsFilter::isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const
|
||||
{
|
||||
bool ret = true;
|
||||
switch( pTarget->getRole() )
|
||||
{
|
||||
case Common::Role::Melee:
|
||||
case Common::Role::RangedMagical:
|
||||
case Common::Role::RangedPhysical:
|
||||
ret = true;
|
||||
break;
|
||||
default:
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
return m_negate ? !ret : ret;
|
||||
}
|
||||
|
||||
bool HasStatusEffectFilter::isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const
|
||||
{
|
||||
auto ret = pTarget->hasStatusEffect( m_statusId );
|
||||
return m_negate ? !ret : ret;
|
||||
}
|
||||
|
||||
bool TopAggroFilter::isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const
|
||||
{
|
||||
auto pBNpc = pSrc->getAsBNpc();
|
||||
bool ret = false;
|
||||
if( pBNpc )
|
||||
{
|
||||
ret = pBNpc->hateListGetHighest() == pTarget;
|
||||
}
|
||||
return m_negate ? !ret : ret;
|
||||
}
|
||||
|
||||
bool SecondAggroFilter::isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const
|
||||
{
|
||||
auto pBNpc = pSrc->getAsBNpc();
|
||||
bool ret = false;
|
||||
if( pBNpc )
|
||||
{
|
||||
// todo: this is so dumb
|
||||
|
||||
auto hateList = pBNpc->getHateList();
|
||||
std::vector sorted( hateList.begin(), hateList.end() );
|
||||
std::sort( sorted.begin(), sorted.end(), []( Entity::HateListEntryPtr a, Entity::HateListEntryPtr b ) {
|
||||
return a->m_hateAmount > b->m_hateAmount; } );
|
||||
|
||||
Entity::CharaPtr pChara = nullptr;
|
||||
auto topIt = sorted.begin();
|
||||
if( topIt != sorted.end() && ++topIt != sorted.end() )
|
||||
pChara = topIt->get()->m_pChara;
|
||||
|
||||
ret = pChara == pTarget;
|
||||
}
|
||||
return m_negate ? !ret : ret;
|
||||
}
|
||||
|
||||
bool PartyMemberFilter::isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const
|
||||
{
|
||||
bool ret = false;
|
||||
// todo: pets, companions, enpc
|
||||
if( auto pPlayer = pSrc->getAsPlayer() )
|
||||
{
|
||||
if( auto pTargetPlayer = pTarget->getAsPlayer() )
|
||||
{
|
||||
ret = pPlayer->getPartyId() == pTargetPlayer->getPartyId();
|
||||
}
|
||||
else if( auto pBNpc = pTarget->getAsBNpc() )
|
||||
{
|
||||
ret = pBNpc->getBNpcType() == 0;
|
||||
}
|
||||
}
|
||||
else if( auto pBNpc = pSrc->getAsBNpc() )
|
||||
{
|
||||
if( auto pTargetPlayer = pTarget->getAsPlayer() )
|
||||
{
|
||||
ret = pPlayer->getPartyId() == pTargetPlayer->getPartyId();
|
||||
}
|
||||
else if( auto pTargetBNpc = pTarget->getAsBNpc() )
|
||||
{
|
||||
ret = pBNpc->getBNpcType() == pTargetBNpc->getEnemyType();
|
||||
}
|
||||
}
|
||||
return m_negate ? !ret : ret;
|
||||
}
|
||||
|
||||
void Snapshot::createSnapshot( Entity::CharaPtr pSrc, const std::set< Entity::GameObjectPtr >& inRange,
|
||||
uint32_t count, bool fillWithRandom,
|
||||
const std::vector< TargetSelectFilterPtr >& filters,
|
||||
const std::vector< uint32_t >& exclude )
|
||||
{
|
||||
m_results.clear();
|
||||
m_targetIds.clear();
|
||||
|
||||
auto& RNGMgr = Common::Service< World::Manager::RNGMgr >::ref();
|
||||
for( const auto& pActor : inRange )
|
||||
{
|
||||
auto pChara = pActor->getAsChara();
|
||||
if( pChara == nullptr )
|
||||
continue;
|
||||
|
||||
// exclude this character from the result set
|
||||
auto excludeIt = std::find_if( exclude.begin(), exclude.end(),
|
||||
[ pChara ]( uint32_t id ) { return pChara->getId() == id; }
|
||||
);
|
||||
if( excludeIt != exclude.end() )
|
||||
continue;
|
||||
|
||||
bool matches = true;
|
||||
for( const auto& filter : filters )
|
||||
{
|
||||
if( !filter->isApplicable( pSrc, pChara ) )
|
||||
{
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( matches )
|
||||
{
|
||||
CharaEntry entry{};
|
||||
entry.m_entityId = pChara->getId();
|
||||
entry.m_pos = pChara->getPos();
|
||||
entry.m_rot = pChara->getRot();
|
||||
|
||||
m_results.push_back( entry );
|
||||
if( m_results.size() == count ) break;
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to fill with random entries if we dont have enough valid results
|
||||
if( fillWithRandom && m_results.size() < count )
|
||||
{
|
||||
std::vector< Entity::CharaPtr > remaining;
|
||||
for( const auto& pActor : inRange )
|
||||
{
|
||||
auto pChara = pActor->getAsChara();
|
||||
if( pChara == nullptr )
|
||||
continue;
|
||||
|
||||
auto excludeIt = std::find_if( exclude.begin(), exclude.end(),
|
||||
[ pChara ]( uint32_t id ) { return pChara->getId() == id; }
|
||||
);
|
||||
|
||||
if( excludeIt == exclude.end() && std::find_if( m_results.begin(), m_results.end(),
|
||||
[ &pChara ]( CharaEntry entry ) { return entry.m_entityId == pChara->getId(); } ) == m_results.end() )
|
||||
{
|
||||
remaining.push_back( pChara );
|
||||
}
|
||||
}
|
||||
while( m_results.size() < count && !remaining.empty() )
|
||||
{
|
||||
// idk
|
||||
std::shuffle( remaining.begin(), remaining.end(), *RNGMgr.getRNGEngine() );
|
||||
|
||||
auto pChara = remaining.back();
|
||||
CharaEntry entry{};
|
||||
entry.m_entityId = pChara->getId();
|
||||
entry.m_pos = pChara->getPos();
|
||||
entry.m_rot = pChara->getRot();
|
||||
m_results.emplace_back( entry );
|
||||
remaining.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
// sort by distance at the end always
|
||||
const auto& srcPos = pSrc->getPos();
|
||||
std::sort( m_results.begin(), m_results.end(),
|
||||
[ srcPos ]( CharaEntry l, CharaEntry r )
|
||||
{
|
||||
return Common::Util::distance( srcPos, l.m_pos ) < Common::Util::distance( srcPos, r.m_pos );
|
||||
}
|
||||
);
|
||||
|
||||
// we might want the target ids separately
|
||||
m_targetIds.resize( m_results.size() );
|
||||
for( auto i = 0; i < m_results.size(); ++i )
|
||||
m_targetIds[ i ] = m_results[ i ].m_entityId;
|
||||
}
|
||||
|
||||
const std::vector< Snapshot::CharaEntry >& Snapshot::getResults() const
|
||||
{
|
||||
return m_results;
|
||||
}
|
||||
|
||||
const std::vector< uint32_t >& Snapshot::getTargetIds() const
|
||||
{
|
||||
return m_targetIds;
|
||||
}
|
||||
|
||||
void Snapshot::clearResults()
|
||||
{
|
||||
m_results.clear();
|
||||
m_targetIds.clear();
|
||||
}
|
||||
|
||||
};// namespace Sapphire::World::AI
|
249
src/world/AI/TargetHelper.h
Normal file
249
src/world/AI/TargetHelper.h
Normal file
|
@ -0,0 +1,249 @@
|
|||
#ifndef _TARGETHELPER_H
|
||||
#define _TARGETHELPER_H
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <ForwardsZone.h>
|
||||
|
||||
namespace Sapphire::World::AI
|
||||
{
|
||||
//
|
||||
// Filters
|
||||
//
|
||||
class TargetSelectFilter :
|
||||
public std::enable_shared_from_this< TargetSelectFilter >
|
||||
{
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
InsideRadius,
|
||||
OutsideRadius,
|
||||
|
||||
Player,
|
||||
Ally,
|
||||
OwnBattalion,
|
||||
|
||||
Tank,
|
||||
Healer,
|
||||
Dps,
|
||||
|
||||
HasStatusEffect,
|
||||
|
||||
TopAggro,
|
||||
SecondAggro,
|
||||
|
||||
PartyMember,
|
||||
|
||||
AllianceA,
|
||||
AllianceB,
|
||||
AllianceC
|
||||
};
|
||||
|
||||
protected:
|
||||
Type m_type;
|
||||
bool m_negate{ false };
|
||||
|
||||
public:
|
||||
TargetSelectFilter( Type type, bool negate ) :
|
||||
m_type( type ),
|
||||
m_negate( negate )
|
||||
{
|
||||
}
|
||||
virtual ~TargetSelectFilter()
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
bool isNegate() const
|
||||
{
|
||||
return m_negate;
|
||||
}
|
||||
};
|
||||
using TargetSelectFilterPtr = std::shared_ptr< TargetSelectFilter >;
|
||||
|
||||
class InsideRadiusFilter : public TargetSelectFilter
|
||||
{
|
||||
private:
|
||||
float m_distance{ 0 };
|
||||
|
||||
public:
|
||||
InsideRadiusFilter( float distance, bool negate ) :
|
||||
TargetSelectFilter( Type::InsideRadius, negate ),
|
||||
m_distance( distance )
|
||||
{
|
||||
}
|
||||
|
||||
bool isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const override;
|
||||
};
|
||||
|
||||
class OutsideRadiusFilter : public TargetSelectFilter
|
||||
{
|
||||
private:
|
||||
float m_distance{ 0 };
|
||||
public:
|
||||
OutsideRadiusFilter( float distance, bool negate ) :
|
||||
TargetSelectFilter( Type::OutsideRadius, negate ),
|
||||
m_distance( distance )
|
||||
{
|
||||
}
|
||||
|
||||
bool isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const override;
|
||||
};
|
||||
|
||||
class PlayerFilter : public TargetSelectFilter
|
||||
{
|
||||
public:
|
||||
PlayerFilter( bool negate ) :
|
||||
TargetSelectFilter( Type::Player, negate )
|
||||
{
|
||||
}
|
||||
|
||||
bool isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const override;
|
||||
};
|
||||
|
||||
class AllyFilter : public TargetSelectFilter
|
||||
{
|
||||
public:
|
||||
AllyFilter( bool negate ) :
|
||||
TargetSelectFilter( Type::Ally, negate )
|
||||
{
|
||||
}
|
||||
|
||||
bool isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const override;
|
||||
};
|
||||
|
||||
class OwnBattalionFilter : public TargetSelectFilter
|
||||
{
|
||||
public:
|
||||
OwnBattalionFilter( bool negate ) :
|
||||
TargetSelectFilter( Type::OwnBattalion, negate )
|
||||
{
|
||||
}
|
||||
|
||||
bool isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const override;
|
||||
};
|
||||
|
||||
class TankFilter : public TargetSelectFilter
|
||||
{
|
||||
public:
|
||||
TankFilter( bool negate ) :
|
||||
TargetSelectFilter( Type::Tank, negate )
|
||||
{
|
||||
}
|
||||
|
||||
bool isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const override;
|
||||
};
|
||||
|
||||
class HealerFilter : public TargetSelectFilter
|
||||
{
|
||||
public:
|
||||
HealerFilter( bool negate ) :
|
||||
TargetSelectFilter( Type::Healer, negate )
|
||||
{
|
||||
}
|
||||
|
||||
bool isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const override;
|
||||
};
|
||||
|
||||
class DpsFilter : public TargetSelectFilter
|
||||
{
|
||||
public:
|
||||
DpsFilter( bool negate ) :
|
||||
TargetSelectFilter( Type::Dps, negate )
|
||||
{
|
||||
}
|
||||
|
||||
bool isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const override;
|
||||
};
|
||||
|
||||
class HasStatusEffectFilter : public TargetSelectFilter
|
||||
{
|
||||
private:
|
||||
uint32_t m_statusId{ 0 };
|
||||
public:
|
||||
HasStatusEffectFilter( uint32_t statusId, bool negate ) :
|
||||
TargetSelectFilter( Type::HasStatusEffect, negate ),
|
||||
m_statusId( statusId )
|
||||
{
|
||||
}
|
||||
|
||||
bool isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const override;
|
||||
};
|
||||
|
||||
class TopAggroFilter : public TargetSelectFilter
|
||||
{
|
||||
public:
|
||||
TopAggroFilter( bool negate ) :
|
||||
TargetSelectFilter( Type::TopAggro, negate )
|
||||
{
|
||||
}
|
||||
|
||||
bool isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const override;
|
||||
};
|
||||
|
||||
class SecondAggroFilter : public TargetSelectFilter
|
||||
{
|
||||
public:
|
||||
SecondAggroFilter( bool negate ) :
|
||||
TargetSelectFilter( Type::SecondAggro, negate )
|
||||
{
|
||||
}
|
||||
|
||||
bool isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const override;
|
||||
};
|
||||
|
||||
class PartyMemberFilter : public TargetSelectFilter
|
||||
{
|
||||
public:
|
||||
PartyMemberFilter( bool negate ) :
|
||||
TargetSelectFilter( Type::PartyMember, negate )
|
||||
{
|
||||
}
|
||||
|
||||
bool isApplicable( Entity::CharaPtr& pSrc, Entity::CharaPtr& pTarget ) const override;
|
||||
};
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
class Snapshot :
|
||||
public std::enable_shared_from_this< Snapshot >
|
||||
{
|
||||
public:
|
||||
struct CharaEntry
|
||||
{
|
||||
uint32_t m_entityId;
|
||||
Common::FFXIVARR_POSITION3 m_pos;
|
||||
float m_rot;
|
||||
// todo: status effects?
|
||||
};
|
||||
using Results = std::vector< CharaEntry >;
|
||||
using TargetIds = std::vector< uint32_t >;
|
||||
private:
|
||||
std::vector< CharaEntry > m_results;
|
||||
std::vector< uint32_t > m_targetIds;
|
||||
|
||||
public:
|
||||
Snapshot() {}
|
||||
|
||||
void createSnapshot( Entity::CharaPtr pSrc, const std::set< Entity::GameObjectPtr >& inRange,
|
||||
uint32_t count, bool fillWithRandom,
|
||||
const std::vector< TargetSelectFilterPtr >& filters,
|
||||
const std::vector< uint32_t >& exclude = {} );
|
||||
|
||||
// returns actors sorted by distance
|
||||
const std::vector< CharaEntry >& getResults() const;
|
||||
const std::vector< uint32_t >& getTargetIds() const;
|
||||
void clearResults();
|
||||
};
|
||||
using SnapshotPtr = std::shared_ptr< Snapshot >;
|
||||
}// namespace Sapphire::World::AI
|
||||
|
||||
#endif
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include "Manager/PlayerMgr.h"
|
||||
#include "Manager/MgrUtil.h"
|
||||
#include "Manager/TerritoryMgr.h"
|
||||
|
||||
#include "Session.h"
|
||||
#include "Network/GameConnection.h"
|
||||
|
@ -23,7 +24,7 @@
|
|||
#include "Network/PacketWrappers/ActorControlPacket.h"
|
||||
#include "Network/PacketWrappers/ActorControlSelfPacket.h"
|
||||
#include "Network/PacketWrappers/ActorControlTargetPacket.h"
|
||||
#include "Network/Util/PlayerUtil.h"
|
||||
#include "Network/Util/PacketUtil.h"
|
||||
|
||||
#include <Logging/Logger.h>
|
||||
|
||||
|
@ -31,6 +32,8 @@
|
|||
#include <Service.h>
|
||||
#include "WorldServer.h"
|
||||
|
||||
#include "Job/Warrior.h"
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::Common;
|
||||
using namespace Sapphire::Network;
|
||||
|
@ -65,6 +68,16 @@ uint32_t Action::Action::getId() const
|
|||
return m_id;
|
||||
}
|
||||
|
||||
uint32_t Action::Action::getResultId() const
|
||||
{
|
||||
return m_resultId;
|
||||
}
|
||||
|
||||
std::shared_ptr< Excel::ExcelStruct< Excel::Action > > Action::Action::getActionData() const
|
||||
{
|
||||
return m_actionData;
|
||||
}
|
||||
|
||||
bool Action::Action::init()
|
||||
{
|
||||
if( !m_actionData )
|
||||
|
@ -78,14 +91,18 @@ bool Action::Action::init()
|
|||
|
||||
m_actionData = actionData;
|
||||
}
|
||||
auto teriMgr = Common::Service< Manager::TerritoryMgr >::ref();
|
||||
auto zone = teriMgr.getTerritoryByGuId( m_pSource->getTerritoryId() );
|
||||
m_resultId = zone->getNextActionResultId();
|
||||
|
||||
m_effectBuilder = make_EffectBuilder( m_pSource, getId(), m_requestId );
|
||||
m_actionResultBuilder = make_ActionResultBuilder( m_pSource, getId(), m_resultId, m_requestId );
|
||||
|
||||
m_castTimeMs = static_cast< uint32_t >( m_actionData->data().CastTime * 100 );
|
||||
m_recastTimeMs = static_cast< uint32_t >( m_actionData->data().RecastTime * 100 );
|
||||
m_cooldownGroup = m_actionData->data().RecastGroup;
|
||||
m_range = m_actionData->data().SelectRange;
|
||||
m_effectRange = m_actionData->data().EffectRange;
|
||||
m_effectWidth = m_actionData->data().EffectWidth;
|
||||
m_category = static_cast< Common::ActionCategory >( m_actionData->data().Category );
|
||||
m_castType = static_cast< Common::CastType >( m_actionData->data().EffectType );
|
||||
m_aspect = static_cast< Common::ActionAspect >( m_actionData->data().AttackType );
|
||||
|
@ -105,9 +122,9 @@ bool Action::Action::init()
|
|||
{
|
||||
case Common::ClassJob::Bard:
|
||||
case Common::ClassJob::Archer:
|
||||
case Common::ClassJob::Machinist:
|
||||
m_range = 25;
|
||||
break;
|
||||
// anything that isnt ranged
|
||||
default:
|
||||
m_range = 3;
|
||||
break;
|
||||
|
@ -117,7 +134,7 @@ bool Action::Action::init()
|
|||
m_primaryCostType = static_cast< Common::ActionPrimaryCostType >( m_actionData->data().CostType );
|
||||
m_primaryCost = m_actionData->data().CostValue;
|
||||
|
||||
/*if( !m_actionData->targetArea )
|
||||
if( !m_actionData->data().SelectGround )
|
||||
{
|
||||
// override pos to target position
|
||||
// todo: this is kinda dirty
|
||||
|
@ -129,7 +146,7 @@ bool Action::Action::init()
|
|||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
// todo: add missing rows for secondaryCostType/secondaryCostType and rename the current rows to primaryCostX
|
||||
|
||||
|
@ -164,6 +181,16 @@ const Common::FFXIVARR_POSITION3& Action::Action::getPos() const
|
|||
return m_pos;
|
||||
}
|
||||
|
||||
void Action::Action::setRot( float rot )
|
||||
{
|
||||
m_rot = rot;
|
||||
}
|
||||
|
||||
float Action::Action::getRot() const
|
||||
{
|
||||
return m_rot;
|
||||
}
|
||||
|
||||
void Action::Action::setTargetId( uint64_t targetId )
|
||||
{
|
||||
m_targetId = targetId;
|
||||
|
@ -241,34 +268,34 @@ bool Action::Action::update()
|
|||
// todo: check if the target is still in range
|
||||
}
|
||||
|
||||
uint64_t tickCount = Common::Util::getTimeMs();
|
||||
uint32_t castTime = m_castTimeMs;
|
||||
auto tickCount = static_cast< time_t >( Common::Util::getTimeMs() );
|
||||
auto startTime = static_cast< time_t >( m_startTime );
|
||||
uint64_t castTime = m_castTimeMs;
|
||||
|
||||
if( auto player = m_pSource->getAsPlayer() )
|
||||
{
|
||||
uint64_t lastActionTick = player->getLastActionTick();
|
||||
auto lastActionTick = static_cast< time_t >( player->getLastActionTick() );
|
||||
uint32_t lastTickMs = 0;
|
||||
if( lastActionTick > 0 )
|
||||
{
|
||||
lastTickMs = static_cast< uint32_t >( std::difftime( static_cast< time_t >( tickCount ), static_cast< time_t >( lastActionTick ) ) );
|
||||
lastTickMs = static_cast< uint32_t >( std::difftime( tickCount, lastActionTick ) );
|
||||
if( lastTickMs > 100 ) //max 100ms
|
||||
lastTickMs = 100;
|
||||
}
|
||||
|
||||
player->setLastActionTick( tickCount );
|
||||
uint32_t delayMs = 100 - lastTickMs;
|
||||
uint64_t delayMs = 100 - lastTickMs;
|
||||
castTime = ( m_castTimeMs + delayMs );
|
||||
m_castTimeRestMs = static_cast< uint64_t >( m_castTimeMs ) -
|
||||
static_cast< uint64_t >( std::difftime( static_cast< time_t >( tickCount ), static_cast< time_t >( m_startTime ) ) );
|
||||
m_castTimeRestMs = static_cast< uint64_t >( m_castTimeMs ) - static_cast< uint64_t >( std::difftime( tickCount, startTime ) );
|
||||
}
|
||||
|
||||
if( !hasCastTime() || std::difftime( static_cast< time_t >( tickCount ), static_cast< time_t >( m_startTime ) ) > castTime )
|
||||
if( !hasCastTime() || std::difftime( tickCount, startTime ) > castTime )
|
||||
{
|
||||
execute();
|
||||
return true;
|
||||
}
|
||||
|
||||
if( m_pTarget == nullptr && m_targetId != 0 )
|
||||
if( !m_pTarget && m_targetId != 0 )
|
||||
{
|
||||
// try to search for the target actor
|
||||
for( const auto& actor : m_pSource->getInRangeActors( true ) )
|
||||
|
@ -281,7 +308,7 @@ bool Action::Action::update()
|
|||
}
|
||||
}
|
||||
|
||||
if( m_pTarget != nullptr && !m_pTarget->isAlive() )
|
||||
if( m_pTarget && !m_pTarget->isAlive() )
|
||||
{
|
||||
// interrupt the cast if target died
|
||||
setInterrupted( Common::ActionInterruptType::RegularInterrupt );
|
||||
|
@ -310,25 +337,25 @@ void Action::Action::start()
|
|||
data.CastTime = static_cast< float >( m_castTimeMs ) / 1000.f;
|
||||
data.Target = static_cast< uint32_t >( m_targetId );
|
||||
|
||||
data.TargetPos[ 0 ] = Common::Util::floatToUInt16( m_pSource->getPos().x );
|
||||
data.TargetPos[ 1 ] = Common::Util::floatToUInt16( m_pSource->getPos().y );
|
||||
data.TargetPos[ 2 ] = Common::Util::floatToUInt16( m_pSource->getPos().z );
|
||||
data.Dir = m_pSource->getRot();
|
||||
data.TargetPos[ 0 ] = Common::Util::floatToUInt16( m_pos.x );
|
||||
data.TargetPos[ 1 ] = Common::Util::floatToUInt16( m_pos.y );
|
||||
data.TargetPos[ 2 ] = Common::Util::floatToUInt16( m_pos.z );
|
||||
data.Dir = m_rot;
|
||||
|
||||
server().queueForPlayers( m_pSource->getInRangePlayerIds( true ), castPacket );
|
||||
server().queueForPlayers( m_pSource->getInRangePlayerIds( m_pSource->isPlayer() ), castPacket );
|
||||
|
||||
if( player )
|
||||
{
|
||||
player->setCondition( PlayerCondition::Casting );
|
||||
}
|
||||
}
|
||||
|
||||
// todo: m_recastTimeMs needs to be adjusted for player sks/sps
|
||||
auto actionStartPkt = makeActorControlSelf( m_pSource->getId(), ActorControlType::ActionStart, m_cooldownGroup, getId(), m_recastTimeMs / 10 );
|
||||
|
||||
player->setRecastGroup( m_cooldownGroup, static_cast< float >( m_castTimeMs ) / 1000.f );
|
||||
|
||||
server().queueForPlayer( player->getCharacterId(), actionStartPkt );
|
||||
if( player )
|
||||
{
|
||||
player->setRecastGroup( m_cooldownGroup, static_cast< float >( m_castTimeMs ) / 1000.f );
|
||||
server().queueForPlayer( player->getCharacterId(), actionStartPkt );
|
||||
}
|
||||
|
||||
onStart();
|
||||
|
||||
|
@ -362,7 +389,6 @@ void Action::Action::onStart()
|
|||
void Action::Action::interrupt()
|
||||
{
|
||||
assert( m_pSource );
|
||||
|
||||
// things that aren't players don't care about cooldowns and state flags
|
||||
if( m_pSource->isPlayer() )
|
||||
{
|
||||
|
@ -402,25 +428,20 @@ void Action::Action::onInterrupt()
|
|||
void Action::Action::execute()
|
||||
{
|
||||
assert( m_pSource );
|
||||
|
||||
// subtract costs first, if somehow the caster stops meeting those requirements cancel the cast
|
||||
|
||||
if( !consumeResources() )
|
||||
{
|
||||
interrupt();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
||||
|
||||
if( hasCastTime() )
|
||||
if( hasCastTime() && m_pSource->isPlayer() )
|
||||
{
|
||||
if( auto pPlayer = m_pSource->getAsPlayer(); pPlayer )
|
||||
{
|
||||
pPlayer->setLastActionTick( 0 );
|
||||
pPlayer->removeCondition( PlayerCondition::Casting );
|
||||
}
|
||||
auto pPlayer = m_pSource->getAsPlayer();
|
||||
pPlayer->setLastActionTick( 0 );
|
||||
pPlayer->removeCondition( PlayerCondition::Casting );
|
||||
}
|
||||
|
||||
if( isCorrectCombo() )
|
||||
|
@ -430,13 +451,9 @@ void Action::Action::execute()
|
|||
}
|
||||
|
||||
if( !hasClientsideTarget() )
|
||||
{
|
||||
buildEffects();
|
||||
}
|
||||
buildActionResults();
|
||||
else if( auto player = m_pSource->getAsPlayer() )
|
||||
{
|
||||
scriptMgr.onEObjHit( *player, m_targetId, getId() );
|
||||
}
|
||||
|
||||
// set currently casted action as the combo action if it interrupts a combo
|
||||
// ignore it otherwise (ogcds, etc.)
|
||||
|
@ -444,17 +461,13 @@ void Action::Action::execute()
|
|||
{
|
||||
// potential combo starter or correct combo from last action, must hit something to progress combo
|
||||
if( !m_hitActors.empty() && ( !isComboAction() || isCorrectCombo() ) )
|
||||
{
|
||||
m_pSource->setLastComboActionId( getId() );
|
||||
}
|
||||
else // clear last combo action if the combo breaks
|
||||
{
|
||||
m_pSource->setLastComboActionId( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcDamage( uint32_t potency )
|
||||
std::pair< uint32_t, Common::CalcResultType > Action::Action::calcDamage( uint32_t potency )
|
||||
{
|
||||
// todo: what do for npcs?
|
||||
auto wepDmg = 1.f;
|
||||
|
@ -466,19 +479,19 @@ std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcDamage(
|
|||
|
||||
auto role = player->getRole();
|
||||
if( role == Common::Role::RangedMagical || role == Common::Role::Healer )
|
||||
{
|
||||
wepDmg = item->getMagicalDmg();
|
||||
}
|
||||
else
|
||||
{
|
||||
wepDmg = item->getPhysicalDmg();
|
||||
}
|
||||
|
||||
// is auto attack
|
||||
if( getId() == 7 || getId() == 8 )
|
||||
return Math::CalcStats::calcAutoAttackDamage( *m_pSource->getAsPlayer() );
|
||||
}
|
||||
|
||||
return Math::CalcStats::calcActionDamage( *m_pSource, potency, wepDmg );
|
||||
}
|
||||
|
||||
std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcHealing( uint32_t potency )
|
||||
std::pair< uint32_t, Common::CalcResultType > Action::Action::calcHealing( uint32_t potency )
|
||||
{
|
||||
auto wepDmg = 1.f;
|
||||
|
||||
|
@ -489,41 +502,38 @@ std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcHealing
|
|||
|
||||
auto role = player->getRole();
|
||||
if( role == Common::Role::RangedMagical || role == Common::Role::Healer )
|
||||
{
|
||||
wepDmg = item->getMagicalDmg();
|
||||
}
|
||||
else
|
||||
{
|
||||
wepDmg = item->getPhysicalDmg();
|
||||
}
|
||||
}
|
||||
|
||||
return Math::CalcStats::calcActionHealing( *m_pSource, potency, wepDmg );
|
||||
}
|
||||
|
||||
void Action::Action::buildEffects()
|
||||
void Action::Action::buildActionResults()
|
||||
{
|
||||
snapshotAffectedActors( m_hitActors );
|
||||
|
||||
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
||||
auto hasLutEntry = hasValidLutEntry();
|
||||
auto hasScript = scriptMgr.onExecute( *this );
|
||||
|
||||
if( !scriptMgr.onExecute( *this ) && !hasLutEntry )
|
||||
if( !hasScript && !hasLutEntry )
|
||||
{
|
||||
if( auto player = m_pSource->getAsPlayer() )
|
||||
{
|
||||
Manager::PlayerMgr::sendUrgent( *player, "missing lut entry for action#{}", getId() );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Network::Util::Player::sendHudParam( *m_pSource->getAsPlayer() );
|
||||
if( !hasScript )
|
||||
m_enableGenericHandler = true;
|
||||
|
||||
if( !hasLutEntry || m_hitActors.empty() )
|
||||
Network::Util::Packet::sendHudParam( *m_pSource );
|
||||
|
||||
if( !m_enableGenericHandler || !hasLutEntry || m_hitActors.empty() )
|
||||
{
|
||||
// send any effect packet added by script or an empty one just to play animation for other players
|
||||
m_effectBuilder->buildAndSendPackets( m_hitActors );
|
||||
m_actionResultBuilder->sendActionResults( {} );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -544,14 +554,14 @@ void Action::Action::buildEffects()
|
|||
if( m_lutEntry.potency > 0 )
|
||||
{
|
||||
auto dmg = calcDamage( isCorrectCombo() ? m_lutEntry.comboPotency : m_lutEntry.potency );
|
||||
m_effectBuilder->damage( m_pSource, actor, dmg.first, dmg.second );
|
||||
m_actionResultBuilder->damage( m_pSource, actor, dmg.first, dmg.second );
|
||||
|
||||
if( dmg.first > 0 )
|
||||
actor->onActionHostile( m_pSource );
|
||||
|
||||
if( isCorrectCombo() && shouldApplyComboSucceedEffect )
|
||||
{
|
||||
m_effectBuilder->comboSucceed( m_pSource );
|
||||
m_actionResultBuilder->comboSucceed( m_pSource );
|
||||
shouldApplyComboSucceedEffect = false;
|
||||
}
|
||||
|
||||
|
@ -560,46 +570,100 @@ void Action::Action::buildEffects()
|
|||
if( m_lutEntry.curePotency > 0 ) // actions with self heal
|
||||
{
|
||||
auto heal = calcHealing( m_lutEntry.curePotency );
|
||||
m_effectBuilder->heal( actor, m_pSource, heal.first, heal.second, Common::ActionEffectResultFlag::EffectOnSource );
|
||||
m_actionResultBuilder->heal( actor, m_pSource, heal.first, heal.second, Common::ActionResultFlag::EffectOnSource );
|
||||
}
|
||||
|
||||
if( m_lutEntry.restoreMPPercentage > 0 && shouldRestoreMP )
|
||||
{
|
||||
m_effectBuilder->restoreMP( actor, m_pSource, m_pSource->getMaxMp() * m_lutEntry.restoreMPPercentage / 100, Common::ActionEffectResultFlag::EffectOnSource );
|
||||
m_actionResultBuilder->restoreMP( actor, m_pSource, m_pSource->getMaxMp() * m_lutEntry.restoreMPPercentage / 100, Common::ActionResultFlag::EffectOnSource );
|
||||
shouldRestoreMP = false;
|
||||
}
|
||||
|
||||
if( !m_lutEntry.nextCombo.empty() ) // if we have a combo action followup
|
||||
{
|
||||
m_effectBuilder->startCombo( m_pSource, getId() ); // this is on all targets hit
|
||||
}
|
||||
m_actionResultBuilder->startCombo( m_pSource, getId() ); // this is on all targets hit
|
||||
}
|
||||
}
|
||||
else if( m_lutEntry.curePotency > 0 )
|
||||
{
|
||||
auto heal = calcHealing( m_lutEntry.curePotency );
|
||||
m_effectBuilder->heal( actor, actor, heal.first, heal.second );
|
||||
m_actionResultBuilder->heal( actor, actor, heal.first, heal.second );
|
||||
|
||||
if( m_lutEntry.restoreMPPercentage > 0 && shouldRestoreMP )
|
||||
{
|
||||
m_effectBuilder->restoreMP( actor, m_pSource, m_pSource->getMaxMp() * m_lutEntry.restoreMPPercentage / 100, Common::ActionEffectResultFlag::EffectOnSource );
|
||||
m_actionResultBuilder->restoreMP( actor, m_pSource, m_pSource->getMaxMp() * m_lutEntry.restoreMPPercentage / 100, Common::ActionResultFlag::EffectOnSource );
|
||||
shouldRestoreMP = false;
|
||||
}
|
||||
}
|
||||
else if( m_lutEntry.restoreMPPercentage > 0 && shouldRestoreMP )
|
||||
{
|
||||
m_effectBuilder->restoreMP( actor, m_pSource, m_pSource->getMaxMp() * m_lutEntry.restoreMPPercentage / 100, Common::ActionEffectResultFlag::EffectOnSource );
|
||||
m_actionResultBuilder->restoreMP( actor, m_pSource, m_pSource->getMaxMp() * m_lutEntry.restoreMPPercentage / 100, Common::ActionResultFlag::EffectOnSource );
|
||||
shouldRestoreMP = false;
|
||||
}
|
||||
}
|
||||
|
||||
m_effectBuilder->buildAndSendPackets( m_hitActors );
|
||||
// If we hit an enemy
|
||||
if( !m_hitActors.empty() && getHitChara()->getObjKind() != m_pSource->getObjKind() )
|
||||
{
|
||||
m_pSource->removeStatusEffectByFlag( Common::StatusEffectFlag::RemoveOnSuccessfulHit );
|
||||
}
|
||||
|
||||
handleJobAction();
|
||||
handleStatusEffects();
|
||||
|
||||
m_actionResultBuilder->sendActionResults( m_hitActors );
|
||||
|
||||
// TODO: disabled, reset kills our queued actions
|
||||
// at this point we're done with it and no longer need it
|
||||
// m_effectBuilder.reset();
|
||||
}
|
||||
|
||||
void Action::Action::handleStatusEffects()
|
||||
{
|
||||
auto pActionBuilder = getActionResultBuilder();
|
||||
|
||||
if( !pActionBuilder )
|
||||
return;
|
||||
|
||||
if( isComboAction() && !isCorrectCombo() )
|
||||
return;
|
||||
|
||||
// handle caster statuses
|
||||
if( !m_lutEntry.statuses.caster.empty() )
|
||||
{
|
||||
for( auto& status : m_lutEntry.statuses.caster )
|
||||
{
|
||||
pActionBuilder->applyStatusEffectSelf( status.id, status.duration, 0, std::move( status.modifiers ), status.flag, true );
|
||||
}
|
||||
}
|
||||
|
||||
// handle hit actor statuses
|
||||
if( !m_lutEntry.statuses.target.empty() && !m_hitActors.empty() )
|
||||
{
|
||||
for( auto& actor : m_hitActors )
|
||||
{
|
||||
for( auto& status : m_lutEntry.statuses.target )
|
||||
{
|
||||
pActionBuilder->applyStatusEffect( actor, status.id, status.duration, 0, std::move( status.modifiers ), status.flag, true );
|
||||
}
|
||||
|
||||
if( !actor->getStatusEffectMap().empty() )
|
||||
actor->onActionHostile( m_pSource );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Action::Action::handleJobAction()
|
||||
{
|
||||
switch( m_pSource->getClass() )
|
||||
{
|
||||
case ClassJob::Warrior:
|
||||
{
|
||||
Warrior::onAction( *m_pSource->getAsPlayer(), *this );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Action::Action::preCheck()
|
||||
{
|
||||
if( auto player = m_pSource->getAsPlayer() )
|
||||
|
@ -678,9 +742,7 @@ bool Action::Action::isCorrectCombo() const
|
|||
auto lastActionId = m_pSource->getLastComboActionId();
|
||||
|
||||
if( lastActionId == 0 )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_actionData->data().ComboParent == lastActionId;
|
||||
}
|
||||
|
@ -724,6 +786,17 @@ bool Action::Action::primaryCostCheck( bool subtractCosts )
|
|||
return true;
|
||||
}
|
||||
|
||||
case Common::ActionPrimaryCostType::StatusEffect:
|
||||
{
|
||||
if( !m_pSource->hasStatusEffect( m_primaryCost ) )
|
||||
return false;
|
||||
|
||||
if( subtractCosts )
|
||||
m_pSource->removeSingleStatusEffectById( m_primaryCost );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// free casts, likely just pure ogcds
|
||||
case Common::ActionPrimaryCostType::None:
|
||||
{
|
||||
|
@ -791,8 +864,10 @@ void Action::Action::addDefaultActorFilters()
|
|||
{
|
||||
switch( m_castType )
|
||||
{
|
||||
// todo: figure these out and remove 5/RectangularAOE to own handler
|
||||
case( Common::CastType ) 5:
|
||||
case Common::CastType::RectangularAOE:
|
||||
case Common::CastType::SingleTarget:
|
||||
case Common::CastType::Type3:
|
||||
{
|
||||
auto filter = std::make_shared< World::Util::ActorFilterSingleTarget >( static_cast< uint32_t >( m_targetId ) );
|
||||
addActorFilter( filter );
|
||||
|
@ -854,22 +929,20 @@ std::vector< Entity::CharaPtr >& Action::Action::getHitCharas()
|
|||
Entity::CharaPtr Action::Action::getHitChara()
|
||||
{
|
||||
if( !m_hitActors.empty() )
|
||||
{
|
||||
return m_hitActors.at( 0 );
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Action::Action::hasValidLutEntry() const
|
||||
{
|
||||
return m_lutEntry.potency != 0 || m_lutEntry.comboPotency != 0 || m_lutEntry.flankPotency != 0 || m_lutEntry.frontPotency != 0 ||
|
||||
m_lutEntry.rearPotency != 0 || m_lutEntry.curePotency != 0 || m_lutEntry.restoreMPPercentage != 0;
|
||||
m_lutEntry.rearPotency != 0 || m_lutEntry.curePotency != 0 || m_lutEntry.restoreMPPercentage != 0 ||
|
||||
m_lutEntry.statuses.caster.size() > 0 || m_lutEntry.statuses.target.size() > 0;
|
||||
}
|
||||
|
||||
Action::EffectBuilderPtr Action::Action::getEffectbuilder()
|
||||
Action::ActionResultBuilderPtr Action::Action::getActionResultBuilder()
|
||||
{
|
||||
return m_effectBuilder;
|
||||
return m_actionResultBuilder;
|
||||
}
|
||||
|
||||
uint8_t Action::Action::getActionKind() const
|
||||
|
@ -891,3 +964,8 @@ uint64_t Action::Action::getCastTimeRest() const
|
|||
{
|
||||
return m_castTimeRestMs;
|
||||
}
|
||||
|
||||
void Action::Action::enableGenericHandler()
|
||||
{
|
||||
m_enableGenericHandler = true;
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
#include "ActionLut.h"
|
||||
#include "Util/ActorFilter.h"
|
||||
#include "ForwardsZone.h"
|
||||
#include "EffectBuilder.h"
|
||||
#include "ActionResultBuilder.h"
|
||||
#include "Exd/Structs.h"
|
||||
|
||||
namespace Sapphire::World::Action
|
||||
|
@ -23,11 +23,16 @@ namespace Sapphire::World::Action
|
|||
|
||||
uint32_t getId() const;
|
||||
|
||||
uint32_t getResultId() const;
|
||||
|
||||
bool init();
|
||||
|
||||
void setPos( const Common::FFXIVARR_POSITION3& pos );
|
||||
const Common::FFXIVARR_POSITION3& getPos() const;
|
||||
|
||||
void setRot( float rot );
|
||||
float getRot() const;
|
||||
|
||||
void setTargetId( uint64_t targetId );
|
||||
uint64_t getTargetId() const;
|
||||
Entity::CharaPtr getSourceChara() const;
|
||||
|
@ -53,6 +58,10 @@ namespace Sapphire::World::Action
|
|||
|
||||
uint64_t getCastTimeRest() const;
|
||||
|
||||
void enableGenericHandler();
|
||||
|
||||
std::shared_ptr< Excel::ExcelStruct< Excel::Action > > getActionData() const;
|
||||
|
||||
/*!
|
||||
* @brief Checks if a chara has enough resources available to cast the action (tp/mp/etc)
|
||||
* @return true if they have the required resources
|
||||
|
@ -103,9 +112,13 @@ namespace Sapphire::World::Action
|
|||
*/
|
||||
bool snapshotAffectedActors( std::vector< Entity::CharaPtr >& actors );
|
||||
|
||||
EffectBuilderPtr getEffectbuilder();
|
||||
ActionResultBuilderPtr getActionResultBuilder();
|
||||
|
||||
void buildEffects();
|
||||
void buildActionResults();
|
||||
|
||||
void handleStatusEffects();
|
||||
|
||||
void handleJobAction();
|
||||
|
||||
/*!
|
||||
* @brief Adds an actor filter to this action.
|
||||
|
@ -118,9 +131,9 @@ namespace Sapphire::World::Action
|
|||
*/
|
||||
void addDefaultActorFilters();
|
||||
|
||||
std::pair< uint32_t, Common::ActionHitSeverityType > calcDamage( uint32_t potency );
|
||||
std::pair< uint32_t, Common::CalcResultType > calcDamage( uint32_t potency );
|
||||
|
||||
std::pair< uint32_t, Common::ActionHitSeverityType > calcHealing( uint32_t potency );
|
||||
std::pair< uint32_t, Common::CalcResultType > calcHealing( uint32_t potency );
|
||||
|
||||
|
||||
std::vector< Entity::CharaPtr >& getHitCharas();
|
||||
|
@ -172,6 +185,7 @@ namespace Sapphire::World::Action
|
|||
uint8_t m_actionKind{};
|
||||
|
||||
uint16_t m_requestId{};
|
||||
uint32_t m_resultId{};
|
||||
|
||||
Common::ActionPrimaryCostType m_primaryCostType;
|
||||
uint16_t m_primaryCost{};
|
||||
|
@ -185,6 +199,7 @@ namespace Sapphire::World::Action
|
|||
uint8_t m_cooldownGroup{};
|
||||
int8_t m_range{};
|
||||
uint8_t m_effectRange{};
|
||||
uint8_t m_effectWidth{};
|
||||
uint8_t m_xAxisModifier{};
|
||||
Common::ActionAspect m_aspect;
|
||||
Common::CastType m_castType;
|
||||
|
@ -201,14 +216,16 @@ namespace Sapphire::World::Action
|
|||
bool m_canTargetFriendly{};
|
||||
bool m_canTargetHostile{};
|
||||
bool m_canTargetDead{};
|
||||
bool m_enableGenericHandler{};
|
||||
|
||||
Common::ActionInterruptType m_interruptType;
|
||||
|
||||
std::shared_ptr< Excel::ExcelStruct< Excel::Action > > m_actionData;
|
||||
|
||||
Common::FFXIVARR_POSITION3 m_pos{};
|
||||
float m_rot{};
|
||||
|
||||
EffectBuilderPtr m_effectBuilder;
|
||||
ActionResultBuilderPtr m_actionResultBuilder;
|
||||
|
||||
std::vector< World::Util::ActorFilterPtr > m_actorFilters;
|
||||
std::vector< Entity::CharaPtr > m_hitActors;
|
||||
|
|
|
@ -15,7 +15,8 @@ bool ActionLut::validEntryExists( uint16_t actionId )
|
|||
|
||||
// if all of the fields are 0, it's not 'valid' due to parse error or no useful data in the tooltip
|
||||
return entry.potency != 0 || entry.comboPotency != 0 || entry.flankPotency != 0 || entry.frontPotency != 0 ||
|
||||
entry.rearPotency != 0 || entry.curePotency != 0;
|
||||
entry.rearPotency != 0 || entry.curePotency != 0 ||
|
||||
entry.statuses.caster.size() > 0 || entry.statuses.target.size() > 0;
|
||||
}
|
||||
|
||||
const ActionEntry& ActionLut::getEntry( uint16_t actionId )
|
||||
|
|
|
@ -17,6 +17,8 @@ namespace Sapphire::World::Action
|
|||
struct StatusEntry
|
||||
{
|
||||
uint16_t id;
|
||||
uint32_t duration;
|
||||
uint32_t flag;
|
||||
std::vector< StatusModifier > modifiers;
|
||||
};
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue