diff --git a/deps/datReader/DatCategories/bg/lgb.h b/deps/datReader/DatCategories/bg/lgb.h index c5c99f11f0..d0c3f29bd7 100644 --- a/deps/datReader/DatCategories/bg/lgb.h +++ b/deps/datReader/DatCategories/bg/lgb.h @@ -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 ) - { - 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 + switch( type ) { - 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 ) diff --git a/deps/datReader/Exd.cpp b/deps/datReader/Exd.cpp index 74aae36e03..b1a2a2b5f0 100644 --- a/deps/datReader/Exd.cpp +++ b/deps/datReader/Exd.cpp @@ -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 ) diff --git a/deps/datReader/Exd.h b/deps/datReader/Exd.h index 8cf406589b..e08f6e54b4 100644 --- a/deps/datReader/Exd.h +++ b/deps/datReader/Exd.h @@ -2,6 +2,7 @@ #include #include +#include #include @@ -12,6 +13,49 @@ #include #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( &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; }; diff --git a/src/common/Common.h b/src/common/Common.h index b2f94ab041..cd2db1d6ee 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -983,74 +983,64 @@ namespace Sapphire::Common LimitBreak = 8, }; - enum ActionEffectType : 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, - }; - - enum class ActionHitSeverityType : uint8_t - { - NormalDamage = 0, - CritHeal = 0, - CritDamage = 1, - NormalHeal = 1, - DirectHitDamage = 2, - CritDirectHitDamage = 3 + enum CalcResultType : uint8_t + { + 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 ActionResultFlag : uint8_t @@ -1418,9 +1408,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... diff --git a/src/common/Exd/ExdData.h b/src/common/Exd/ExdData.h index 5ba553e5e7..a4be915693 100644 --- a/src/common/Exd/ExdData.h +++ b/src/common/Exd/ExdData.h @@ -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; diff --git a/src/scripts/action/war/ActionInnerBeast.cpp b/src/scripts/action/war/ActionInnerBeast.cpp index 14a39dbe23..3c25264427 100644 --- a/src/scripts/action/war/ActionInnerBeast.cpp +++ b/src/scripts/action/war/ActionInnerBeast.cpp @@ -31,8 +31,7 @@ class ActionInnerBeast : public Sapphire::ScriptAPI::ActionScript auto dmg = action.calcDamage( Potency ); action.getActionResultBuilder()->damage( pSource, pTarget, dmg.first, dmg.second ); - action.getActionResultBuilder()->heal( pTarget, pSource, dmg.first, Common::ActionHitSeverityType::NormalHeal, - Common::ActionResultFlag::EffectOnSource ); + action.getActionResultBuilder()->heal( pTarget, pSource, dmg.first, Common::CalcResultType::TypeRecoverHp, Common::ActionResultFlag::EffectOnSource ); action.getActionResultBuilder()->applyStatusEffectSelf( InnerBeast, 15000, 0, { StatusModifier{ Common::ParamModifier::DamageTakenPercent, -20 } } ); diff --git a/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp b/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp index f5dc332f45..135be4b5a1 100644 --- a/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp +++ b/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp @@ -1,5 +1,8 @@ #include #include +#include +#include +#include using namespace Sapphire; @@ -100,15 +103,126 @@ class UnderneaththeSultantree : public Sapphire::ScriptAPI::QuestBattleScript 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 ); } diff --git a/src/scripts/quest/ManWil005.cpp b/src/scripts/quest/ManWil005.cpp new file mode 100644 index 0000000000..75ab8a97a3 --- /dev/null +++ b/src/scripts/quest/ManWil005.cpp @@ -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 /scripts/ + +#include +#include "Manager/EventMgr.h" +#include +#include + +// 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 ); \ No newline at end of file diff --git a/src/scripts/quest/classquest/MIN/ClsMin502.cpp b/src/scripts/quest/classquest/MIN/ClsMin502.cpp index ee12385975..05505cdf32 100644 --- a/src/scripts/quest/classquest/MIN/ClsMin502.cpp +++ b/src/scripts/quest/classquest/MIN/ClsMin502.cpp @@ -45,6 +45,7 @@ class ClsMin502 : public Sapphire::ScriptAPI::QuestScript 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 @@ class ClsMin502 : public Sapphire::ScriptAPI::QuestScript 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 ); } diff --git a/src/scripts/quest/classquest/MIN/ClsMin580.cpp b/src/scripts/quest/classquest/MIN/ClsMin580.cpp index 9505ca2f93..716fc95155 100644 --- a/src/scripts/quest/classquest/MIN/ClsMin580.cpp +++ b/src/scripts/quest/classquest/MIN/ClsMin580.cpp @@ -64,6 +64,7 @@ class ClsMin580 : public Sapphire::ScriptAPI::QuestScript 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 @@ class ClsMin580 : public Sapphire::ScriptAPI::QuestScript 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 ) { diff --git a/src/scripts/quest/classquest/MIN/ClsMin600.cpp b/src/scripts/quest/classquest/MIN/ClsMin600.cpp index 7e733494a4..df5fd18f0a 100644 --- a/src/scripts/quest/classquest/MIN/ClsMin600.cpp +++ b/src/scripts/quest/classquest/MIN/ClsMin600.cpp @@ -56,6 +56,7 @@ class ClsMin600 : public Sapphire::ScriptAPI::QuestScript 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 @@ class ClsMin600 : public Sapphire::ScriptAPI::QuestScript 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 ); } diff --git a/src/scripts/quest/classquest/WHM/JobWhm001.cpp b/src/scripts/quest/classquest/WHM/JobWhm001.cpp index 4a809993e0..4fb8ad9962 100644 --- a/src/scripts/quest/classquest/WHM/JobWhm001.cpp +++ b/src/scripts/quest/classquest/WHM/JobWhm001.cpp @@ -101,6 +101,8 @@ class JobWhm001 : public Sapphire::ScriptAPI::QuestScript 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 @@ class JobWhm001 : public Sapphire::ScriptAPI::QuestScript 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 @@ class JobWhm001 : public Sapphire::ScriptAPI::QuestScript 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 @@ class JobWhm001 : public Sapphire::ScriptAPI::QuestScript 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 @@ class JobWhm001 : public Sapphire::ScriptAPI::QuestScript 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 @@ class JobWhm001 : public Sapphire::ScriptAPI::QuestScript } }; -EXPOSE_SCRIPT( JobWhm001 ); \ No newline at end of file +EXPOSE_SCRIPT( JobWhm001 ); diff --git a/src/scripts/quest/classquest/WHM/JobWhm450.cpp b/src/scripts/quest/classquest/WHM/JobWhm450.cpp index 4953a21424..fae06547bf 100644 --- a/src/scripts/quest/classquest/WHM/JobWhm450.cpp +++ b/src/scripts/quest/classquest/WHM/JobWhm450.cpp @@ -80,6 +80,10 @@ class JobWhm450 : public Sapphire::ScriptAPI::QuestScript 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 @@ class JobWhm450 : public Sapphire::ScriptAPI::QuestScript 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 @@ class JobWhm450 : public Sapphire::ScriptAPI::QuestScript 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 @@ class JobWhm450 : public Sapphire::ScriptAPI::QuestScript 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 @@ class JobWhm450 : public Sapphire::ScriptAPI::QuestScript 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 ); diff --git a/src/scripts/quest/subquest/blackshroud_central/SubFst033.cpp b/src/scripts/quest/subquest/blackshroud_central/SubFst033.cpp index 05dafa7b20..eb6b8abb69 100644 --- a/src/scripts/quest/subquest/blackshroud_central/SubFst033.cpp +++ b/src/scripts/quest/subquest/blackshroud_central/SubFst033.cpp @@ -54,6 +54,7 @@ class SubFst033 : public Sapphire::ScriptAPI::QuestScript 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 @@ class SubFst033 : public Sapphire::ScriptAPI::QuestScript 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 ) { diff --git a/src/scripts/quest/subquest/blackshroud_central/SubFst052.cpp b/src/scripts/quest/subquest/blackshroud_central/SubFst052.cpp index ed0a3e022c..f91b170a94 100644 --- a/src/scripts/quest/subquest/blackshroud_central/SubFst052.cpp +++ b/src/scripts/quest/subquest/blackshroud_central/SubFst052.cpp @@ -45,6 +45,8 @@ class SubFst052 : public Sapphire::ScriptAPI::QuestScript 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 @@ class SubFst052 : public Sapphire::ScriptAPI::QuestScript { 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 ) { diff --git a/src/scripts/quest/subquest/blackshroud_central/SubFst067.cpp b/src/scripts/quest/subquest/blackshroud_central/SubFst067.cpp index 6433ed1d3c..a8c3da0feb 100644 --- a/src/scripts/quest/subquest/blackshroud_central/SubFst067.cpp +++ b/src/scripts/quest/subquest/blackshroud_central/SubFst067.cpp @@ -53,6 +53,7 @@ class SubFst067 : public Sapphire::ScriptAPI::QuestScript 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 @@ class SubFst067 : public Sapphire::ScriptAPI::QuestScript 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 ); diff --git a/src/scripts/quest/subquest/blackshroud_central/SubFst069.cpp b/src/scripts/quest/subquest/blackshroud_central/SubFst069.cpp index 855624f108..14a68e7b4f 100644 --- a/src/scripts/quest/subquest/blackshroud_central/SubFst069.cpp +++ b/src/scripts/quest/subquest/blackshroud_central/SubFst069.cpp @@ -39,6 +39,7 @@ class SubFst069 : public Sapphire::ScriptAPI::QuestScript 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 @@ class SubFst069 : public Sapphire::ScriptAPI::QuestScript 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 ); } diff --git a/src/scripts/quest/subquest/blackshroud_north/GaiUsa803.cpp b/src/scripts/quest/subquest/blackshroud_north/GaiUsa803.cpp index 15fcf1da98..341a8e8b51 100644 --- a/src/scripts/quest/subquest/blackshroud_north/GaiUsa803.cpp +++ b/src/scripts/quest/subquest/blackshroud_north/GaiUsa803.cpp @@ -55,6 +55,7 @@ class GaiUsa803 : public Sapphire::ScriptAPI::QuestScript 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 @@ class GaiUsa803 : public Sapphire::ScriptAPI::QuestScript 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() ); diff --git a/src/scripts/quest/subquest/coerthas_central/GaiUsb808.cpp b/src/scripts/quest/subquest/coerthas_central/GaiUsb808.cpp index 5ef10f2344..3630fb8f4d 100644 --- a/src/scripts/quest/subquest/coerthas_central/GaiUsb808.cpp +++ b/src/scripts/quest/subquest/coerthas_central/GaiUsb808.cpp @@ -55,6 +55,7 @@ class GaiUsb808 : public Sapphire::ScriptAPI::QuestScript 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 @@ class GaiUsb808 : public Sapphire::ScriptAPI::QuestScript 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 ); } diff --git a/src/scripts/quest/subquest/gridania/GaiUsc609.cpp b/src/scripts/quest/subquest/gridania/GaiUsc609.cpp index 7b1b10471f..a5cff6f2dd 100644 --- a/src/scripts/quest/subquest/gridania/GaiUsc609.cpp +++ b/src/scripts/quest/subquest/gridania/GaiUsc609.cpp @@ -61,6 +61,8 @@ class GaiUsc609 : public Sapphire::ScriptAPI::QuestScript 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 @@ class GaiUsc609 : public Sapphire::ScriptAPI::QuestScript 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 @@ class GaiUsc609 : public Sapphire::ScriptAPI::QuestScript { 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 } ); } ////////////////////////////////////////////////////////////////////// diff --git a/src/scripts/quest/subquest/lanoscea_outer/GaiUsb406.cpp b/src/scripts/quest/subquest/lanoscea_outer/GaiUsb406.cpp index 176978e3fc..1791396724 100644 --- a/src/scripts/quest/subquest/lanoscea_outer/GaiUsb406.cpp +++ b/src/scripts/quest/subquest/lanoscea_outer/GaiUsb406.cpp @@ -55,6 +55,8 @@ class GaiUsb406 : public Sapphire::ScriptAPI::QuestScript 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 @@ class GaiUsb406 : public Sapphire::ScriptAPI::QuestScript { 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() ); diff --git a/src/scripts/quest/subquest/limsa/SubSea002.cpp b/src/scripts/quest/subquest/limsa/SubSea002.cpp index 406c22d5bd..9ec7229221 100644 --- a/src/scripts/quest/subquest/limsa/SubSea002.cpp +++ b/src/scripts/quest/subquest/limsa/SubSea002.cpp @@ -8,7 +8,7 @@ #include // Quest Script: SubSea002_00112 -// Quest Name: Suspiciously SoberF +// Quest Name: Suspiciously Sober // Quest ID: 65648 // Start NPC: 1003604 (Ahldskyf) // End NPC: 1003275 (Frydwyb) diff --git a/src/scripts/quest/subquest/limsa/SubSea004.cpp b/src/scripts/quest/subquest/limsa/SubSea004.cpp index 6b08ea21df..b3e3ccf6be 100644 --- a/src/scripts/quest/subquest/limsa/SubSea004.cpp +++ b/src/scripts/quest/subquest/limsa/SubSea004.cpp @@ -145,6 +145,7 @@ class SubSea004 : public Sapphire::ScriptAPI::QuestScript { eventMgr().sendEventNotice( player, getId(), 0, 0 ); quest.setUI8AL( 1 ); + quest.setBitFlag8( 1, true ); checkQuestCompletion( quest, player, 1 ); } @@ -159,6 +160,7 @@ class SubSea004 : public Sapphire::ScriptAPI::QuestScript { eventMgr().sendEventNotice( player, getId(), 1, 0 ); quest.setUI8BH( 1 ); + quest.setBitFlag8( 2, true ); checkQuestCompletion( quest, player, 1 ); } @@ -173,6 +175,7 @@ class SubSea004 : public Sapphire::ScriptAPI::QuestScript { eventMgr().sendEventNotice( player, getId(), 2, 0 ); quest.setUI8BL( 1 ); + quest.setBitFlag8( 3, true ); checkQuestCompletion( quest, player, 1 ); } diff --git a/src/scripts/quest/subquest/limsa/SubSea007.cpp b/src/scripts/quest/subquest/limsa/SubSea007.cpp index 26feaf983f..4475010a80 100644 --- a/src/scripts/quest/subquest/limsa/SubSea007.cpp +++ b/src/scripts/quest/subquest/limsa/SubSea007.cpp @@ -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 ); } diff --git a/src/scripts/quest/subquest/limsa/SubSea008.cpp b/src/scripts/quest/subquest/limsa/SubSea008.cpp index 6e7c013ead..6a220f83c5 100644 --- a/src/scripts/quest/subquest/limsa/SubSea008.cpp +++ b/src/scripts/quest/subquest/limsa/SubSea008.cpp @@ -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 @@ class SubSea008 : public Sapphire::ScriptAPI::QuestScript 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 @@ class SubSea008 : public Sapphire::ScriptAPI::QuestScript { eventMgr().sendEventNotice( player, getId(), 1, 0 ); quest.setUI8AL( 1 ); + quest.setBitFlag8( 1, true ); checkQuestCompletion( quest, player, 1 ); } @@ -197,6 +202,7 @@ class SubSea008 : public Sapphire::ScriptAPI::QuestScript { eventMgr().sendEventNotice( player, getId(), 2, 0 ); quest.setUI8BH( 1 ); + quest.setBitFlag8( 2, true ); checkQuestCompletion( quest, player, 1 ); } diff --git a/src/scripts/quest/subquest/limsa/SubSea016.cpp b/src/scripts/quest/subquest/limsa/SubSea016.cpp index bd263eea76..48d8d5c344 100644 --- a/src/scripts/quest/subquest/limsa/SubSea016.cpp +++ b/src/scripts/quest/subquest/limsa/SubSea016.cpp @@ -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 ); } diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil025.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil025.cpp new file mode 100644 index 0000000000..aba1d54dda --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil025.cpp @@ -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 /scripts/ + +#include "Manager/EventMgr.h" +#include +#include +#include + +// 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 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil026.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil026.cpp new file mode 100644 index 0000000000..5ae382c0bd --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil026.cpp @@ -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 /scripts/ + +#include +#include "Manager/EventMgr.h" +#include +#include + +// 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 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil060.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil060.cpp new file mode 100644 index 0000000000..7d04b507a6 --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil060.cpp @@ -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 /scripts/ + +#include +#include "Manager/EventMgr.h" +#include +#include + +// 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 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil062.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil062.cpp new file mode 100644 index 0000000000..ce041da38d --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil062.cpp @@ -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 /scripts/ + +#include "Manager/EventMgr.h" +#include +#include +#include +#include + +// 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 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil063.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil063.cpp new file mode 100644 index 0000000000..e1fec02893 --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil063.cpp @@ -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 /scripts/ + +#include +#include "Manager/EventMgr.h" +#include +#include + +// 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 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil064.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil064.cpp new file mode 100644 index 0000000000..c614aa306d --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil064.cpp @@ -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 /scripts/ + +#include "Manager/EventMgr.h" +#include +#include +#include +#include + +#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 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil070.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil070.cpp new file mode 100644 index 0000000000..92b6931327 --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil070.cpp @@ -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 /scripts/ + +#include +#include "Manager/EventMgr.h" +#include +#include + +// 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 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil073.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil073.cpp new file mode 100644 index 0000000000..857f5c2131 --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil073.cpp @@ -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 /scripts/ + +#include "Manager/EventMgr.h" +#include +#include +#include +#include + +#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 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil080.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil080.cpp new file mode 100644 index 0000000000..9619e8fe8a --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil080.cpp @@ -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 /scripts/ + +#include +#include "Manager/EventMgr.h" +#include +#include + +// 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 ); \ No newline at end of file diff --git a/src/tools/action_parse/main.cpp b/src/tools/action_parse/main.cpp index a5af43f904..1abe3045ef 100644 --- a/src/tools/action_parse/main.cpp +++ b/src/tools/action_parse/main.cpp @@ -161,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 ) { diff --git a/src/tools/wiki_parse/main.cpp b/src/tools/wiki_parse/main.cpp index 914e79831b..ca12c46d72 100644 --- a/src/tools/wiki_parse/main.cpp +++ b/src/tools/wiki_parse/main.cpp @@ -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(); diff --git a/src/world/AI/Fsm/Condition.h b/src/world/AI/Fsm/Condition.h new file mode 100644 index 0000000000..11fb48046b --- /dev/null +++ b/src/world/AI/Fsm/Condition.h @@ -0,0 +1,95 @@ +#include +#include "ForwardsZone.h" +#include "Actor/BNpc.h" +#include +#include + +#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; + } + }; + +} \ No newline at end of file diff --git a/src/world/AI/Fsm/State.h b/src/world/AI/Fsm/State.h new file mode 100644 index 0000000000..d5739e0381 --- /dev/null +++ b/src/world/AI/Fsm/State.h @@ -0,0 +1,43 @@ +#include +#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; + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/StateCombat.cpp b/src/world/AI/Fsm/StateCombat.cpp new file mode 100644 index 0000000000..5bcefd58bd --- /dev/null +++ b/src/world/AI/Fsm/StateCombat.cpp @@ -0,0 +1,79 @@ +#include "StateCombat.h" +#include "Actor/BNpc.h" +#include "Logging/Logger.h" +#include + +#include +#include +#include + +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 ); + } + + if( pNaviProvider->syncPosToChara( bnpc ) ) + bnpc.sendPositionUpdate(); + + if( distance < ( bnpc.getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) + { + if( !bnpc.hasFlag( Entity::TurningDisabled ) && bnpc.face( pHatedActor->getPos() ) ) + bnpc.sendPositionUpdate(); + + if( !bnpc.checkAction() ) + bnpc.processGambits( tickCount ); + + // in combat range. ATTACK! + 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 ); +} + diff --git a/src/world/AI/Fsm/StateCombat.h b/src/world/AI/Fsm/StateCombat.h new file mode 100644 index 0000000000..9030331c93 --- /dev/null +++ b/src/world/AI/Fsm/StateCombat.h @@ -0,0 +1,20 @@ +#include +#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 ); + + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/StateDead.cpp b/src/world/AI/Fsm/StateDead.cpp new file mode 100644 index 0000000000..15b3a66562 --- /dev/null +++ b/src/world/AI/Fsm/StateDead.cpp @@ -0,0 +1,26 @@ +#include "StateDead.h" +#include "Actor/BNpc.h" +#include "Logging/Logger.h" +#include +#include + +#include +#include + +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 ) +{ + +} + diff --git a/src/world/AI/Fsm/StateDead.h b/src/world/AI/Fsm/StateDead.h new file mode 100644 index 0000000000..9051288a26 --- /dev/null +++ b/src/world/AI/Fsm/StateDead.h @@ -0,0 +1,20 @@ +#include +#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 ); + + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/StateIdle.cpp b/src/world/AI/Fsm/StateIdle.cpp new file mode 100644 index 0000000000..957e4c8858 --- /dev/null +++ b/src/world/AI/Fsm/StateIdle.cpp @@ -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 ) +{ +} + diff --git a/src/world/AI/Fsm/StateIdle.h b/src/world/AI/Fsm/StateIdle.h new file mode 100644 index 0000000000..fe145bfe86 --- /dev/null +++ b/src/world/AI/Fsm/StateIdle.h @@ -0,0 +1,20 @@ +#include +#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 ); + + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/StateMachine.cpp b/src/world/AI/Fsm/StateMachine.cpp new file mode 100644 index 0000000000..ac67ab8602 --- /dev/null +++ b/src/world/AI/Fsm/StateMachine.cpp @@ -0,0 +1,38 @@ +#include +#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 ); +} diff --git a/src/world/AI/Fsm/StateMachine.h b/src/world/AI/Fsm/StateMachine.h new file mode 100644 index 0000000000..3156b846c1 --- /dev/null +++ b/src/world/AI/Fsm/StateMachine.h @@ -0,0 +1,23 @@ +#include +#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; + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/StateRetreat.cpp b/src/world/AI/Fsm/StateRetreat.cpp new file mode 100644 index 0000000000..1f1e937dad --- /dev/null +++ b/src/world/AI/Fsm/StateRetreat.cpp @@ -0,0 +1,41 @@ +#include "StateRetreat.h" +#include "Actor/BNpc.h" +#include "Logging/Logger.h" +#include +#include + +#include +#include + +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 ); +} + diff --git a/src/world/AI/Fsm/StateRetreat.h b/src/world/AI/Fsm/StateRetreat.h new file mode 100644 index 0000000000..00cfe42774 --- /dev/null +++ b/src/world/AI/Fsm/StateRetreat.h @@ -0,0 +1,20 @@ +#include +#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 ); + + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/StateRoam.cpp b/src/world/AI/Fsm/StateRoam.cpp new file mode 100644 index 0000000000..1b6848179f --- /dev/null +++ b/src/world/AI/Fsm/StateRoam.cpp @@ -0,0 +1,49 @@ +#include "StateRoam.h" +#include "Actor/BNpc.h" +#include "Logging/Logger.h" +#include +#include + +#include +#include + +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 ); +} + diff --git a/src/world/AI/Fsm/StateRoam.h b/src/world/AI/Fsm/StateRoam.h new file mode 100644 index 0000000000..6f9ba3ca9b --- /dev/null +++ b/src/world/AI/Fsm/StateRoam.h @@ -0,0 +1,20 @@ +#include +#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 ); + + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/Transition.h b/src/world/AI/Fsm/Transition.h new file mode 100644 index 0000000000..f5bd3b2fe4 --- /dev/null +++ b/src/world/AI/Fsm/Transition.h @@ -0,0 +1,22 @@ +#include +#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; + }; +} \ No newline at end of file diff --git a/src/world/AI/GambitPack.cpp b/src/world/AI/GambitPack.cpp new file mode 100644 index 0000000000..03a8e0de5f --- /dev/null +++ b/src/world/AI/GambitPack.cpp @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include +#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() ); +} diff --git a/src/world/AI/GambitPack.h b/src/world/AI/GambitPack.h new file mode 100644 index 0000000000..caf62f9c11 --- /dev/null +++ b/src/world/AI/GambitPack.h @@ -0,0 +1,60 @@ +#include +#include +#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; + }; +} \ No newline at end of file diff --git a/src/world/AI/GambitTargetCondition.h b/src/world/AI/GambitTargetCondition.h index ec0cd7ae07..931b579d63 100644 --- a/src/world/AI/GambitTargetCondition.h +++ b/src/world/AI/GambitTargetCondition.h @@ -18,20 +18,19 @@ namespace Sapphire::World::AI class GambitTargetCondition { public: - GambitTargetCondition( GambitTargetType targetType ) : m_targetType( targetType ) {}; + GambitTargetCondition() = default; virtual ~GambitTargetCondition() = default; virtual bool isConditionMet( Sapphire::Entity::BNpc& src ) { return false; }; Sapphire::Entity::CharaPtr getTarget() const { return m_pTarget; }; protected: - GambitTargetType m_targetType; Sapphire::Entity::CharaPtr m_pTarget; }; class TopHateTargetCondition : public GambitTargetCondition { public: - TopHateTargetCondition() : GambitTargetCondition( PlayerAndAlly ) {}; + TopHateTargetCondition() = default; bool isConditionMet( Sapphire::Entity::BNpc& src ) override { @@ -45,12 +44,12 @@ namespace Sapphire::World::AI }; }; - class HPSelfPctLessThan : public GambitTargetCondition + class HPSelfPctLessThanTargetCondition : public GambitTargetCondition { public: - HPSelfPctLessThan( uint8_t pct ) : GambitTargetCondition( Self ), m_HpPct( pct ) {}; + HPSelfPctLessThanTargetCondition( uint8_t pct ) : m_HpPct( pct ) {}; - virtual bool isConditionMet( Sapphire::Entity::BNpc& src ) + bool isConditionMet( Sapphire::Entity::BNpc& src ) override { if( src.getHpPercent() < m_HpPct ) { diff --git a/src/world/Action/Action.cpp b/src/world/Action/Action.cpp index 44b6cc9f72..2b32970c4a 100644 --- a/src/world/Action/Action.cpp +++ b/src/world/Action/Action.cpp @@ -457,7 +457,7 @@ void Action::Action::execute() } } -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; @@ -481,7 +481,7 @@ std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcDamage( 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; @@ -520,7 +520,7 @@ void Action::Action::buildActionResults() Network::Util::Packet::sendHudParam( *m_pSource ); - if( !m_enableGenericHandler || !hasLutEntry || m_hitActors.empty() ) + if( m_hitActors.empty() ) { // send any effect packet added by script or an empty one just to play animation for other players m_actionResultBuilder->sendActionResults( {} ); @@ -539,56 +539,62 @@ void Action::Action::buildActionResults() bool shouldRestoreMP = true; bool shouldApplyComboSucceedEffect = true; - for( auto& actor : m_hitActors ) + if( m_enableGenericHandler && hasLutEntry ) { - if( m_lutEntry.potency > 0 ) + for( auto& actor : m_hitActors ) { - auto dmg = calcDamage( isCorrectCombo() ? m_lutEntry.comboPotency : m_lutEntry.potency ); - m_actionResultBuilder->damage( m_pSource, actor, dmg.first, dmg.second ); + if( m_lutEntry.potency > 0 ) + { + auto dmg = calcDamage( isCorrectCombo() ? m_lutEntry.comboPotency : m_lutEntry.potency ); + m_actionResultBuilder->damage( m_pSource, actor, dmg.first, dmg.second ); - if( dmg.first > 0 ) - actor->onActionHostile( m_pSource ); + if( dmg.first > 0 ) + actor->onActionHostile( m_pSource ); - if( isCorrectCombo() && shouldApplyComboSucceedEffect ) - { - m_actionResultBuilder->comboSucceed( m_pSource ); - shouldApplyComboSucceedEffect = false; - } + if( isCorrectCombo() && shouldApplyComboSucceedEffect ) + { + m_actionResultBuilder->comboSucceed( m_pSource ); + shouldApplyComboSucceedEffect = false; + } - if( !isComboAction() || isCorrectCombo() ) - { - if( m_lutEntry.curePotency > 0 ) // actions with self heal + if( !isComboAction() || isCorrectCombo() ) { - auto heal = calcHealing( m_lutEntry.curePotency ); - m_actionResultBuilder->heal( actor, m_pSource, heal.first, heal.second, Common::ActionResultFlag::EffectOnSource ); + if( m_lutEntry.curePotency > 0 )// actions with self heal + { + auto heal = calcHealing( m_lutEntry.curePotency ); + m_actionResultBuilder->heal( actor, m_pSource, heal.first, heal.second, Common::ActionResultFlag::EffectOnSource ); + } + + if( m_lutEntry.restoreMPPercentage > 0 && shouldRestoreMP ) + { + 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_actionResultBuilder->startCombo( m_pSource, getId() );// this is on all targets hit } + } + else if( m_lutEntry.curePotency > 0 ) + { + auto heal = calcHealing( m_lutEntry.curePotency ); + m_actionResultBuilder->heal( actor, actor, heal.first, heal.second ); if( m_lutEntry.restoreMPPercentage > 0 && shouldRestoreMP ) { 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_actionResultBuilder->startCombo( m_pSource, getId() ); // this is on all targets hit } - } - else if( m_lutEntry.curePotency > 0 ) - { - auto heal = calcHealing( m_lutEntry.curePotency ); - m_actionResultBuilder->heal( actor, actor, heal.first, heal.second ); - - if( m_lutEntry.restoreMPPercentage > 0 && shouldRestoreMP ) + else if( m_lutEntry.restoreMPPercentage > 0 && shouldRestoreMP ) { 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_actionResultBuilder->restoreMP( actor, m_pSource, m_pSource->getMaxMp() * m_lutEntry.restoreMPPercentage / 100, Common::ActionResultFlag::EffectOnSource ); - shouldRestoreMP = false; - } + + if( m_lutEntry.statuses.caster.size() > 0 || m_lutEntry.statuses.target.size() > 0 ) + handleStatusEffects(); } // If we hit an enemy @@ -599,9 +605,6 @@ void Action::Action::buildActionResults() handleJobAction(); - if( m_lutEntry.statuses.caster.size() > 0 || m_lutEntry.statuses.target.size() > 0 ) - handleStatusEffects(); - m_actionResultBuilder->sendActionResults( m_hitActors ); // TODO: disabled, reset kills our queued actions diff --git a/src/world/Action/Action.h b/src/world/Action/Action.h index 6f2ed0b6a0..e6e714243f 100644 --- a/src/world/Action/Action.h +++ b/src/world/Action/Action.h @@ -128,9 +128,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(); diff --git a/src/world/Action/ActionResult.cpp b/src/world/Action/ActionResult.cpp index 0a0e8d68c2..6dcb38912d 100644 --- a/src/world/Action/ActionResult.cpp +++ b/src/world/Action/ActionResult.cpp @@ -10,19 +10,19 @@ #include "StatusEffect/StatusEffect.h" using namespace Sapphire; +using namespace Sapphire::Common; using namespace Sapphire::World::Action; -ActionResult::ActionResult( Entity::CharaPtr target, uint64_t runAfter ) : - m_target( std::move( target ) ), - m_delayMs( runAfter ) +ActionResult::ActionResult( Entity::CharaPtr target ) : + m_target( std::move( target ) ) { m_result.Arg0 = 0; m_result.Arg1 = 0; m_result.Arg2 = 0; m_result.Value = 0; - m_result.Flag = static_cast< uint8_t >( Common::ActionResultFlag::None ); - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_NONE; + m_result.Flag = static_cast< uint8_t >( ActionResultFlag::None ); + m_result.Type = CalcResultType::TypeNone; } Entity::CharaPtr ActionResult::getTarget() const @@ -30,52 +30,47 @@ Entity::CharaPtr ActionResult::getTarget() const return m_target; } -uint64_t ActionResult::getDelay() +void ActionResult::damage( uint32_t amount, CalcResultType hitType, uint8_t hitEffect, ActionResultFlag flag ) { - return m_delayMs; -} - -void ActionResult::damage( uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag ) -{ - m_result.Arg0 = static_cast< uint8_t >( severity ); + m_result.Arg0 = hitEffect; m_result.Value = static_cast< int16_t >( amount ); m_result.Flag = static_cast< uint8_t >( flag ); - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP; + m_result.Type = hitType; } -void ActionResult::heal( uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag ) +void ActionResult::heal( uint32_t amount, CalcResultType hitType, uint8_t hitEffect, ActionResultFlag flag ) { - m_result.Arg1 = static_cast< uint8_t >( severity ); + m_result.Arg0 = hitEffect; m_result.Value = static_cast< int16_t >( amount ); m_result.Flag = static_cast< uint8_t >( flag ); - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP; + m_result.Type = hitType; } -void ActionResult::restoreMP( uint32_t amount, Common::ActionResultFlag flag ) +void ActionResult::restoreMP( uint32_t amount, ActionResultFlag flag ) { m_result.Value = static_cast< int16_t >( amount ); m_result.Flag = static_cast< uint8_t >( flag ); - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_MP; + m_result.Type = CalcResultType::TypeRecoverMp; } void ActionResult::startCombo( uint16_t actionId ) { m_result.Value = static_cast< int16_t >( actionId ); - m_result.Flag = static_cast< uint8_t >( Common::ActionResultFlag::EffectOnSource ); - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_COMBO; + m_result.Flag = static_cast< uint8_t >( ActionResultFlag::EffectOnSource ); + m_result.Type = CalcResultType::TypeCombo; } void ActionResult::comboSucceed() { // no EffectOnSource flag on this - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_COMBO_HIT; + m_result.Type = CalcResultType::TypeComboHit; } void ActionResult::applyStatusEffect( uint32_t id, int32_t duration, Entity::Chara& source, uint8_t param, bool shouldOverride ) { m_result.Value = static_cast< int16_t >( id ); m_result.Arg2 = param; - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS; + m_result.Type = CalcResultType::TypeSetStatus; m_bOverrideStatus = shouldOverride; m_pStatus = Sapphire::StatusEffect::make_StatusEffect( id, source.getAsChara(), m_target, duration, 3000 ); @@ -87,7 +82,7 @@ void ActionResult::applyStatusEffect( uint32_t id, int32_t duration, Entity::Cha { m_result.Value = static_cast< int16_t >( id ); m_result.Arg2 = param; - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS; + m_result.Type = CalcResultType::TypeSetStatus; m_bOverrideStatus = shouldOverride; m_pStatus = Sapphire::StatusEffect::make_StatusEffect( id, source.getAsChara(), m_target, duration, modifiers, flag, 3000 ); @@ -98,8 +93,8 @@ void ActionResult::applyStatusEffectSelf( uint32_t id, int32_t duration, uint8_t { m_result.Value = static_cast< int16_t >( id ); m_result.Arg2 = param; - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS_ME; - m_result.Flag = static_cast< uint8_t >( Common::ActionResultFlag::EffectOnSource ); + m_result.Type = CalcResultType::TypeSetStatusMe; + m_result.Flag = static_cast< uint8_t >( ActionResultFlag::EffectOnSource ); m_bOverrideStatus = shouldOverride; m_pStatus = Sapphire::StatusEffect::make_StatusEffect( id, m_target, m_target, duration, 3000 ); @@ -111,7 +106,7 @@ void ActionResult::applyStatusEffectSelf( uint32_t id, int32_t duration, uint8_t { m_result.Value = static_cast< int16_t >( id ); m_result.Arg2 = param; - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS_ME; + m_result.Type = CalcResultType::TypeSetStatusMe; m_result.Flag = static_cast< uint8_t >( Common::ActionResultFlag::EffectOnSource ); m_bOverrideStatus = shouldOverride; @@ -123,7 +118,7 @@ void ActionResult::mount( uint16_t mountId ) { m_result.Value = static_cast< int16_t >( mountId ); m_result.Arg0 = 1; - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_MOUNT; + m_result.Type = CalcResultType::TypeMount; } const Common::CalcResultParam& ActionResult::getCalcResultParam() const @@ -143,26 +138,28 @@ void ActionResult::execute() switch( m_result.Type ) { - case Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP: + case CalcResultType::TypeDamageHp: + case CalcResultType::TypeCriticalDamageHp: { m_target->takeDamage( m_result.Value ); break; } - case Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP: + case CalcResultType::TypeRecoverHp: + case CalcResultType::TypeCriticalRecoverHp: { m_target->heal( m_result.Value ); break; } - case Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_MP: + case CalcResultType::TypeRecoverMp: { m_target->restoreMP( m_result.Value ); break; } - case Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS: - case Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS_ME: + case CalcResultType::TypeSetStatus: + case CalcResultType::TypeSetStatusMe: { if( !m_bOverrideStatus ) m_target->addStatusEffectByIdIfNotExist( m_pStatus ); @@ -171,7 +168,7 @@ void ActionResult::execute() break; } - case Common::ActionEffectType::CALC_RESULT_TYPE_MOUNT: + case CalcResultType::TypeMount: { auto pPlayer = m_target->getAsPlayer(); pPlayer->setMount( m_result.Value ); diff --git a/src/world/Action/ActionResult.h b/src/world/Action/ActionResult.h index 69dfa3c39f..0e7421ebea 100644 --- a/src/world/Action/ActionResult.h +++ b/src/world/Action/ActionResult.h @@ -13,10 +13,10 @@ namespace Sapphire::World::Action class ActionResult { public: - explicit ActionResult( Entity::CharaPtr target, uint64_t delayMs ); + explicit ActionResult( Entity::CharaPtr target ); - void damage( uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); - void heal( uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); + void damage( uint32_t amount, Common::CalcResultType hitType, uint8_t hitEffect, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); + void heal( uint32_t amount, Common::CalcResultType hitType, uint8_t hitEffect, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void restoreMP( uint32_t amount, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void startCombo( uint16_t actionId ); void comboSucceed(); @@ -30,16 +30,12 @@ namespace Sapphire::World::Action Entity::CharaPtr getTarget() const; - uint64_t getDelay(); - const Common::CalcResultParam& getCalcResultParam() const; const Sapphire::StatusEffect::StatusEffectPtr getStatusEffect() const; void execute(); private: - uint64_t m_delayMs; - Entity::CharaPtr m_target; Common::CalcResultParam m_result; diff --git a/src/world/Action/ActionResultBuilder.cpp b/src/world/Action/ActionResultBuilder.cpp index bedd3a2ad0..6b58f2d0c0 100644 --- a/src/world/Action/ActionResultBuilder.cpp +++ b/src/world/Action/ActionResultBuilder.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -46,44 +47,48 @@ void ActionResultBuilder::addResultToActor( Entity::CharaPtr& chara, ActionResul it->second.push_back( std::move( result ) ); } -void ActionResultBuilder::heal( Entity::CharaPtr& effectTarget, Entity::CharaPtr& healingTarget, uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag ) +void ActionResultBuilder::heal( Entity::CharaPtr& effectTarget, Entity::CharaPtr& healingTarget, uint32_t amount, Common::CalcResultType hitType, Common::ActionResultFlag flag ) { - ActionResultPtr nextResult = make_ActionResult( healingTarget, 0 ); - nextResult->heal( amount, severity, flag ); + ActionResultPtr nextResult = make_ActionResult( healingTarget ); + auto& exdData = Common::Service< Data::ExdData >::ref(); + auto actionData = exdData.getRow< Excel::Action >( m_actionId ); + nextResult->heal( amount, hitType, std::abs( actionData->data().AttackType ), flag ); addResultToActor( effectTarget, nextResult ); } void ActionResultBuilder::restoreMP( Entity::CharaPtr& target, Entity::CharaPtr& restoringTarget, uint32_t amount, Common::ActionResultFlag flag ) { - ActionResultPtr nextResult = make_ActionResult( restoringTarget, 0 ); // restore mp source actor + ActionResultPtr nextResult = make_ActionResult( restoringTarget ); // restore mp source actor nextResult->restoreMP( amount, flag ); addResultToActor( target, nextResult ); } -void ActionResultBuilder::damage( Entity::CharaPtr& effectTarget, Entity::CharaPtr& damagingTarget, uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag ) +void ActionResultBuilder::damage( Entity::CharaPtr& effectTarget, Entity::CharaPtr& damagingTarget, uint32_t amount, Common::CalcResultType hitType, Common::ActionResultFlag flag ) { - ActionResultPtr nextResult = make_ActionResult( damagingTarget, 0 ); - nextResult->damage( amount, severity, flag ); + ActionResultPtr nextResult = make_ActionResult( damagingTarget ); + auto& exdData = Common::Service< Data::ExdData >::ref(); + auto actionData = exdData.getRow< Excel::Action >( m_actionId ); + nextResult->damage( amount, hitType, std::abs( actionData->data().AttackType ), flag ); addResultToActor( damagingTarget, nextResult ); } void ActionResultBuilder::startCombo( Entity::CharaPtr& target, uint16_t actionId ) { - ActionResultPtr nextResult = make_ActionResult( target, 0 ); + ActionResultPtr nextResult = make_ActionResult( target ); nextResult->startCombo( actionId ); addResultToActor( target, nextResult ); } void ActionResultBuilder::comboSucceed( Entity::CharaPtr& target ) { - ActionResultPtr nextResult = make_ActionResult( target, 0 ); + ActionResultPtr nextResult = make_ActionResult( target ); nextResult->comboSucceed(); addResultToActor( target, nextResult ); } void ActionResultBuilder::applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint32_t duration, uint8_t param, bool shouldOverride ) { - ActionResultPtr nextResult = make_ActionResult( target, 0 ); + ActionResultPtr nextResult = make_ActionResult( target ); nextResult->applyStatusEffect( statusId, duration, *m_sourceChara, param, shouldOverride ); addResultToActor( target, nextResult ); } @@ -91,14 +96,14 @@ void ActionResultBuilder::applyStatusEffect( Entity::CharaPtr& target, uint16_t void ActionResultBuilder::applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint32_t duration, uint8_t param, std::vector< World::Action::StatusModifier > modifiers, uint32_t flag, bool shouldOverride ) { - ActionResultPtr nextResult = make_ActionResult( target, 0 ); + ActionResultPtr nextResult = make_ActionResult( target ); nextResult->applyStatusEffect( statusId, duration, *m_sourceChara, param, modifiers, flag, shouldOverride ); addResultToActor( target, nextResult ); } void ActionResultBuilder::applyStatusEffectSelf( uint16_t statusId, uint32_t duration, uint8_t param, bool shouldOverride ) { - ActionResultPtr nextResult = make_ActionResult( m_sourceChara, 0 ); + ActionResultPtr nextResult = make_ActionResult( m_sourceChara ); nextResult->applyStatusEffectSelf( statusId, duration, param, shouldOverride ); addResultToActor( m_sourceChara, nextResult ); } @@ -106,14 +111,14 @@ void ActionResultBuilder::applyStatusEffectSelf( uint16_t statusId, uint32_t dur void ActionResultBuilder::applyStatusEffectSelf( uint16_t statusId, uint32_t duration, uint8_t param, std::vector< World::Action::StatusModifier > modifiers, uint32_t flag, bool shouldOverride ) { - ActionResultPtr nextResult = make_ActionResult( m_sourceChara, 0 ); + ActionResultPtr nextResult = make_ActionResult( m_sourceChara ); nextResult->applyStatusEffectSelf( statusId, duration, param, modifiers, flag, shouldOverride ); addResultToActor( m_sourceChara, nextResult ); } void ActionResultBuilder::mount( Entity::CharaPtr& target, uint16_t mountId ) { - ActionResultPtr nextResult = make_ActionResult( target, 0 ); + ActionResultPtr nextResult = make_ActionResult( target ); nextResult->mount( mountId ); addResultToActor( target, nextResult ); } @@ -140,19 +145,17 @@ std::shared_ptr< FFXIVPacketBase > ActionResultBuilder::createActionResultPacket if( targetCount > 1 ) // use AoeEffect packets { - auto actionResult = std::make_shared< EffectPacket >( m_sourceChara->getId(), targetList[ 0 ]->getId(), m_actionId ); + auto actionResult = makeEffectPacket( m_sourceChara->getId(), targetList[ 0 ]->getId(), m_actionId ); actionResult->setRotation( Common::Util::floatToUInt16Rot( m_sourceChara->getRot() ) ); actionResult->setRequestId( m_requestId ); actionResult->setResultId( m_resultId ); uint8_t targetIndex = 0; - for( auto it = m_actorResultsMap.begin(); it != m_actorResultsMap.end(); ++it ) + for( auto& [ actor, actorResultList ] : m_actorResultsMap ) { - // get all effect results for an actor - auto actorResultList = it->second; - if( it->first ) - taskMgr.queueTask( World::makeActionIntegrityTask( m_resultId, it->first, actorResultList, 300 ) ); + if( actor ) + taskMgr.queueTask( World::makeActionIntegrityTask( m_resultId, actor, actorResultList, 300 ) ); for( auto& result : actorResultList ) { @@ -173,23 +176,21 @@ std::shared_ptr< FFXIVPacketBase > ActionResultBuilder::createActionResultPacket else // use Effect for single target { uint32_t mainTargetId = targetList.empty() ? m_sourceChara->getId() : targetList[ 0 ]->getId(); - auto actionResult = std::make_shared< EffectPacket1 >( m_sourceChara->getId(), mainTargetId, m_actionId ); + auto actionResult = makeEffectPacket1( m_sourceChara->getId(), mainTargetId, m_actionId ); actionResult->setRotation( Common::Util::floatToUInt16Rot( m_sourceChara->getRot() ) ); actionResult->setRequestId( m_requestId ); actionResult->setResultId( m_resultId ); - for( auto it = m_actorResultsMap.begin(); it != m_actorResultsMap.end(); ++it ) + for( auto& [ actor, actorResultList ] : m_actorResultsMap ) { - // get all effect results for an actor - auto actorResultList = it->second; - - if( it->first ) - taskMgr.queueTask( World::makeActionIntegrityTask( m_resultId, it->first, actorResultList, 300 ) ); + if( actor ) + taskMgr.queueTask( World::makeActionIntegrityTask( m_resultId, actor, actorResultList, 300 ) ); for( auto& result : actorResultList ) { auto effect = result->getCalcResultParam(); - if( result->getTarget() == m_sourceChara && result->getCalcResultParam().Type != Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS_ME ) + if( result->getTarget() == m_sourceChara && + result->getCalcResultParam().Type != Common::CalcResultType::TypeSetStatusMe ) actionResult->addSourceEffect( effect ); else actionResult->addTargetEffect( effect ); diff --git a/src/world/Action/ActionResultBuilder.h b/src/world/Action/ActionResultBuilder.h index 408c8ef932..672f509b75 100644 --- a/src/world/Action/ActionResultBuilder.h +++ b/src/world/Action/ActionResultBuilder.h @@ -12,14 +12,14 @@ namespace Sapphire::World::Action ActionResultBuilder( Entity::CharaPtr source, uint32_t actionId, uint32_t resultId, uint16_t requestId ); void heal( Entity::CharaPtr& effectTarget, Entity::CharaPtr& healingTarget, uint32_t amount, - Common::ActionHitSeverityType severity = Common::ActionHitSeverityType::NormalHeal, + Common::CalcResultType hitType = Common::CalcResultType::TypeRecoverMp, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void restoreMP( Entity::CharaPtr& effectTarget, Entity::CharaPtr& restoringTarget, uint32_t amount, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void damage( Entity::CharaPtr& effectTarget, Entity::CharaPtr& damagingTarget, uint32_t amount, - Common::ActionHitSeverityType severity = Common::ActionHitSeverityType::NormalDamage, + Common::CalcResultType hitType = Common::CalcResultType::TypeDamageHp, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void startCombo( Entity::CharaPtr& target, uint16_t actionId ); diff --git a/src/world/Action/ItemAction.cpp b/src/world/Action/ItemAction.cpp index fdb09aeb27..ed096782d1 100644 --- a/src/world/Action/ItemAction.cpp +++ b/src/world/Action/ItemAction.cpp @@ -78,7 +78,7 @@ void ItemAction::interrupt() void ItemAction::handleVFXItem() { Common::CalcResultParam effect{}; - effect.Type = Common::ActionEffectType::CALC_RESULT_TYPE_CHECK_BARRIER; + effect.Type = Common::CalcResultType::TypeCheckBarrier; effect.Value = m_itemAction->data().Calcu0Arg[ 0 ]; auto effectPacket = std::make_shared< EffectPacket >( getSourceChara()->getId(), getSourceChara()->getId(), getId() ); diff --git a/src/world/Actor/BNpc.cpp b/src/world/Actor/BNpc.cpp index 4a9c95e6ee..9f9429b5bf 100644 --- a/src/world/Actor/BNpc.cpp +++ b/src/world/Actor/BNpc.cpp @@ -46,7 +46,15 @@ #include #include +#include #include +#include +#include +#include +#include +#include +#include +#include using namespace Sapphire; using namespace Sapphire::World; @@ -88,8 +96,7 @@ BNpc::BNpc( uint32_t id, std::shared_ptr< Common::BNPCInstanceObject > pInfo, co m_flags = 0; m_rank = pInfo->BNPCRankId; - if( pInfo->WanderingRange == 0 || pInfo->BoundInstanceID != 0 ) - setFlag( Immobile ); + // Striking Dummy if( pInfo->NameId == 541 ) @@ -107,6 +114,9 @@ BNpc::BNpc( uint32_t id, std::shared_ptr< Common::BNPCInstanceObject > pInfo, co m_modelChara = bNpcBaseData->data().Model; m_enemyType = bNpcBaseData->data().Battalion; + if( pInfo->WanderingRange == 0 || pInfo->BoundInstanceID != 0 || m_enemyType == 0 ) + setFlag( Immobile ); + m_class = ClassJob::Gladiator; m_territoryTypeId = zone.getTerritoryTypeId(); @@ -324,7 +334,7 @@ uint32_t BNpc::getBNpcNameId() const void BNpc::spawn( PlayerPtr pTarget ) { - m_lastRoamTargetReached = Common::Util::getTimeSeconds(); + m_lastRoamTargetReachedTime = Common::Util::getTimeSeconds(); auto& server = Common::Service< World::WorldServer >::ref(); server.queueForPlayer( pTarget->getCharacterId(), std::make_shared< NpcSpawnPacket >( *this, *pTarget ) ); @@ -589,6 +599,11 @@ void BNpc::aggro( const Sapphire::Entity::CharaPtr& pChara ) auto& pRNGMgr = Common::Service< World::Manager::RNGMgr >::ref(); auto variation = static_cast< uint32_t >( pRNGMgr.getRandGenerator< float >( 500, 1000 ).next() ); + if( m_pGambitPack && m_pGambitPack->getAsTimeLine() ) + { + m_pGambitPack->getAsTimeLine()->start(); + } + m_lastAttack = Common::Util::getTimeMs() + variation; setStance( Stance::Active ); @@ -638,165 +653,8 @@ void BNpc::onTick() void BNpc::update( uint64_t tickCount ) { - auto& teriMgr = Common::Service< World::Manager::TerritoryMgr >::ref(); - auto pZone = teriMgr.getTerritoryByGuId( getTerritoryId() ); - - const uint8_t maxDistanceToOrigin = 40; - const uint32_t roamTick = 20; - - auto pNaviProvider = pZone->getNaviProvider(); - - if( !pNaviProvider ) - return; - - if( !checkAction() ) - processGambits( tickCount ); - - switch( m_state ) - { - case BNpcState::Dead: - case BNpcState::JustDied: - return; - - case BNpcState::Retreat: - { - setInvincibilityType( InvincibilityType::InvincibilityIgnoreDamage ); - - if( pNaviProvider ) - pNaviProvider->setMoveTarget( *this, m_spawnPos ); - - if( moveTo( m_spawnPos ) ) - { - setInvincibilityType( InvincibilityType::InvincibilityNone ); - - // retail doesn't seem to roam straight after retreating - // todo: perhaps requires more investigation? - m_lastRoamTargetReached = Common::Util::getTimeSeconds(); - - // resetHp - setHp( getMaxHp() ); - - m_state = BNpcState::Idle; - setOwner( nullptr ); - } - } - break; - - case BNpcState::Roaming: - { - - if( pNaviProvider ) - pNaviProvider->setMoveTarget( *this, m_roamPos ); - - if( moveTo( m_roamPos ) ) - { - m_lastRoamTargetReached = Common::Util::getTimeSeconds(); - m_state = BNpcState::Idle; - } - - checkAggro(); - } - break; - - case BNpcState::Idle: - { - auto pHatedActor = hateListGetHighest(); - if( pHatedActor ) - aggro( pHatedActor ); - - if( pNaviProvider->syncPosToChara( *this ) ) - sendPositionUpdate(); - - if( !hasFlag( Immobile ) && ( Common::Util::getTimeSeconds() - m_lastRoamTargetReached > roamTick ) ) - { - - if( !pNaviProvider ) - { - m_lastRoamTargetReached = Common::Util::getTimeSeconds(); - break; - } - if( m_pInfo->WanderingRange != 0 && getEnemyType() != 0 ) - { - m_roamPos = pNaviProvider->findRandomPositionInCircle( m_spawnPos, m_pInfo->WanderingRange ); - } - else - { - m_roamPos = m_spawnPos; - } - m_state = BNpcState::Roaming; - } - - checkAggro(); - break; - } - - case BNpcState::Combat: - { - auto pHatedActor = hateListGetHighest(); - if( !pHatedActor ) - return; - - pNaviProvider->updateAgentParameters( *this ); - - auto distanceOrig = Common::Util::distance( getPos(), m_spawnPos ); - - if( pHatedActor && !pHatedActor->isAlive() ) - { - hateListRemove( pHatedActor ); - pHatedActor = hateListGetHighest(); - } - - if( pHatedActor ) - { - auto distance = Common::Util::distance( getPos(), pHatedActor->getPos() ); - - if( !hasFlag( NoDeaggro ) && ( ( distanceOrig > maxDistanceToOrigin ) || distance > 30.0f ) ) - { - hateListClear(); - changeTarget( INVALID_GAME_OBJECT_ID64 ); - setStance( Stance::Passive ); - setOwner( nullptr ); - m_state = BNpcState::Retreat; - break; - } - - if( distance > ( getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) - { - if( hasFlag( Immobile ) ) - break; - - if( pNaviProvider ) - pNaviProvider->setMoveTarget( *this, pHatedActor->getPos() ); - - moveTo( *pHatedActor ); - } - - if( pNaviProvider->syncPosToChara( *this ) ) - sendPositionUpdate(); - - if( distance < ( getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) - { - if( !hasFlag( TurningDisabled ) && face( pHatedActor->getPos() ) ) - sendPositionUpdate(); - - // in combat range. ATTACK! - autoAttack( pHatedActor ); - } - } - else - { - changeTarget( INVALID_GAME_OBJECT_ID64 ); - setStance( Stance::Passive ); - //setOwner( nullptr ); - m_state = BNpcState::Retreat; - pNaviProvider->updateAgentParameters( *this ); - } - } - break; - } - - Chara::update( tickCount ); + m_fsm->update( *this, tickCount ); } void BNpc::restHp() @@ -1054,31 +912,98 @@ void BNpc::init() m_maxHp = Math::CalcStats::calculateMaxHp( *getAsChara() ); m_hp = m_maxHp; + m_lastRoamTargetReachedTime = Common::Util::getTimeSeconds(); + //setup a test gambit auto testGambitRule = AI::make_GambitRule( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 88, 0 ), 5000 ); - auto testGambitRule1 = AI::make_GambitRule( AI::make_HPSelfPctLessThan( 50 ), Action::make_Action( getAsChara(), 120, 0 ), 5000 ); - - m_gambits.push_back( testGambitRule ); - m_gambits.push_back( testGambitRule1 ); + auto testGambitRule1 = AI::make_GambitRule( AI::make_HPSelfPctLessThanTargetCondition( 50 ), Action::make_Action( getAsChara(), 120, 0 ), 5000 ); +/* + auto gambitPack = AI::make_GambitRuleSetPack(); + gambitPack->addRule( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 88, 0 ), 5000 ); + gambitPack->addRule( AI::make_HPSelfPctLessThanTargetCondition( 50 ), Action::make_Action( getAsChara(), 120, 0 ), 10000 ); + m_pGambitPack = gambitPack; +*/ + + auto gambitPack = AI::make_GambitTimeLinePack( -1 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 88, 0 ), 2 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 89, 0 ), 4 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 90, 0 ), 6 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 91, 0 ), 8 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 92, 0 ), 10 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 81, 0 ), 12 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 82, 0 ), 14 ); + m_pGambitPack = gambitPack; + + using namespace AI::Fsm; + m_fsm = make_StateMachine(); + auto stateIdle = make_StateIdle(); + auto stateCombat = make_StateCombat(); + auto stateDead = make_StateDead(); + if( !hasFlag( Immobile ) ) + { + auto stateRoam = make_StateRoam(); + stateIdle->addTransition( stateRoam, make_RoamNextTimeReachedCondition() ); + stateRoam->addTransition( stateIdle, make_RoamTargetReachedCondition() ); + stateRoam->addTransition( stateCombat, make_HateListHasEntriesCondition() ); + stateRoam->addTransition( stateDead, make_IsDeadCondition() ); + m_fsm->addState( stateRoam ); + } + stateIdle->addTransition( stateCombat, make_HateListHasEntriesCondition() ); + stateCombat->addTransition( stateIdle, make_HateListEmptyCondition() ); + stateIdle->addTransition( stateDead, make_IsDeadCondition() ); + stateCombat->addTransition( stateDead, make_IsDeadCondition() ); + m_fsm->addState( stateIdle ); + if( !hasFlag( NoDeaggro ) ) + { + auto stateRetreat = make_StateRetreat(); + stateCombat->addTransition( stateRetreat, make_SpawnPointDistanceGtMaxDistanceCondition() ); + stateRetreat->addTransition( stateIdle, make_RoamTargetReachedCondition() ); + } + m_fsm->setCurrentState( stateIdle ); } void BNpc::processGambits( uint64_t tickCount ) { - auto& actionMgr = Common::Service< World::Manager::ActionMgr >::ref(); - for( auto& gambitRule : m_gambits ) - { - if( !gambitRule->isEnabled() ) - continue; + m_tp = 1000; + m_pGambitPack->update( *this, tickCount ); +} - if( ( tickCount - gambitRule->getLastExecutionMs() ) > gambitRule->getCoolDown() ) - { - if( !gambitRule->getGambitTargetCondition()->isConditionMet( *this ) ) - continue; +uint32_t BNpc::getLastRoamTargetReachedTime() const +{ + return m_lastRoamTargetReachedTime; +} - gambitRule->setLastExecutionMs( tickCount ); - actionMgr.handleTargetedAction( *this, gambitRule->getActionPtr()->getId(), gambitRule->getGambitTargetCondition()->getTarget()->getId(), 0 ); - break; - } +void BNpc::setLastRoamTargetReachedTime( uint32_t time ) +{ + m_lastRoamTargetReachedTime = time; +} - } +std::shared_ptr< Common::BNPCInstanceObject > BNpc::getInstanceObjectInfo() const +{ + return m_pInfo; +} + +void BNpc::setRoamTargetReached( bool reached ) +{ + m_roamTargetReached = reached; +} + +bool BNpc::isRoamTargetReached() const +{ + return m_roamTargetReached; +} + +void BNpc::setRoamTargetPos( const FFXIVARR_POSITION3& targetPos ) +{ + m_roamPos = targetPos; +} + +const Common::FFXIVARR_POSITION3& BNpc::getRoamTargetPos() const +{ + return m_roamPos; } + +const Common::FFXIVARR_POSITION3& BNpc::getSpawnPos() const +{ + return m_spawnPos; +} \ No newline at end of file diff --git a/src/world/Actor/BNpc.h b/src/world/Actor/BNpc.h index 095a7ce41e..7076ae6ef9 100644 --- a/src/world/Actor/BNpc.h +++ b/src/world/Actor/BNpc.h @@ -151,6 +151,19 @@ namespace Sapphire::Entity void processGambits( uint64_t tickCount ); + uint32_t getLastRoamTargetReachedTime() const; + void setLastRoamTargetReachedTime( uint32_t time ); + + std::shared_ptr< Common::BNPCInstanceObject > getInstanceObjectInfo() const; + + void setRoamTargetReached( bool reached ); + bool isRoamTargetReached() const; + + void setRoamTargetPos( const Common::FFXIVARR_POSITION3& targetPos ); + + const Common::FFXIVARR_POSITION3& getRoamTargetPos() const; + const Common::FFXIVARR_POSITION3& getSpawnPos() const; + private: uint32_t m_bNpcBaseId; uint32_t m_bNpcNameId; @@ -178,7 +191,8 @@ namespace Sapphire::Entity std::shared_ptr< Common::BNPCInstanceObject > m_pInfo; uint32_t m_timeOfDeath; - uint32_t m_lastRoamTargetReached; + uint32_t m_lastRoamTargetReachedTime; + bool m_roamTargetReached{ false }; Common::FFXIVARR_POSITION3 m_spawnPos; Common::FFXIVARR_POSITION3 m_roamPos; @@ -192,7 +206,9 @@ namespace Sapphire::Entity Common::FFXIVARR_POSITION3 m_naviTarget; CharaPtr m_pOwner; - std::vector< World::AI::GambitRulePtr > m_gambits; + World::AI::GambitPackPtr m_pGambitPack; + + std::shared_ptr< World::AI::Fsm::StateMachine > m_fsm; }; diff --git a/src/world/Actor/Chara.cpp b/src/world/Actor/Chara.cpp index 07194934f8..845f0b1d88 100644 --- a/src/world/Actor/Chara.cpp +++ b/src/world/Actor/Chara.cpp @@ -475,8 +475,8 @@ void Chara::autoAttack( CharaPtr pTarget ) Common::CalcResultParam effectEntry{}; effectEntry.Value = static_cast< int16_t >( damage ); - effectEntry.Type = ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP; - effectEntry.Arg0 = static_cast< uint8_t >( ActionHitSeverityType::NormalDamage ); + effectEntry.Type = CalcResultType::TypeDamageHp; + effectEntry.Arg0 = 1; effectEntry.Arg2 = 0x71; effectPacket->addTargetEffect( effectEntry ); @@ -825,7 +825,7 @@ void Chara::onTick() { takeDamage( thisTickDmg ); Network::Util::Packet::sendActorControl( getInRangePlayerIds( isPlayer() ), getId(), HPFloatingText, 0, - ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP, thisTickDmg ); + CalcResultType::TypeDamageHp, thisTickDmg ); Network::Util::Packet::sendHudParam( *this ); } @@ -834,7 +834,7 @@ void Chara::onTick() { heal( thisTickHeal ); Network::Util::Packet::sendActorControl( getInRangePlayerIds( isPlayer() ), getId(), HPFloatingText, 0, - ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP, thisTickHeal ); + CalcResultType::TypeRecoverMp, thisTickHeal ); Network::Util::Packet::sendHudParam( *this ); } diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index 725ebf7ecc..2652a4ad08 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -658,11 +658,6 @@ void Player::levelUp() m_mp = getMaxMp(); setLevel( getLevel() + 1 ); - Network::Util::Packet::sendActorControl( getInRangePlayerIds( true ), getId(), LevelUpEffect, static_cast< uint8_t >( getClass() ), getLevel(), getLevel() - 1 ); - - auto& achvMgr = Common::Service< World::Manager::AchievementMgr >::ref(); - achvMgr.progressAchievementByType< Common::Achievement::Type::Classjob >( *this, static_cast< uint32_t >( getClass() ) ); - Service< World::Manager::MapMgr >::ref().updateQuests( *this ); } uint8_t Player::getLevel() const @@ -750,6 +745,11 @@ void Player::setLevel( uint8_t level ) Network::Util::Packet::sendBaseParams( *this ); Network::Util::Packet::sendHudParam( *this ); Network::Util::Packet::sendStatusUpdate( *this ); + Network::Util::Packet::sendActorControl( getInRangePlayerIds( true ), getId(), LevelUpEffect, static_cast< uint8_t >( getClass() ), getLevel(), getLevel() - 1 ); + + auto& achvMgr = Common::Service< World::Manager::AchievementMgr >::ref(); + achvMgr.progressAchievementByType< Common::Achievement::Type::Classjob >( *this, static_cast< uint32_t >( getClass() ) ); + Service< World::Manager::MapMgr >::ref().updateQuests( *this ); } void Player::setLevelForClass( uint8_t level, Common::ClassJob classjob ) @@ -1151,6 +1151,7 @@ const std::map< uint32_t, uint8_t >& Player::getActorIdToHateSlotMap() void Player::onMobAggro( const BNpc& bnpc ) { hateListAdd( bnpc ); + setCondition( PlayerCondition::InCombat ); Network::Util::Packet::sendActorControl( *this, getId(), SetBattle, 1 ); } @@ -1158,7 +1159,10 @@ void Player::onMobDeaggro( const BNpc& bnpc ) { hateListRemove( bnpc ); if( m_actorIdTohateSlotMap.empty() ) + { + removeCondition( PlayerCondition::InCombat ); Network::Util::Packet::sendActorControl( *this, getId(), SetBattle, 0 ); + } } bool Player::isLogin() const diff --git a/src/world/CMakeLists.txt b/src/world/CMakeLists.txt index 9f2a4c5f90..129100a8d8 100644 --- a/src/world/CMakeLists.txt +++ b/src/world/CMakeLists.txt @@ -9,6 +9,7 @@ file( GLOB SERVER_SOURCE_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} Action/*.cpp Action/Job/*.cpp AI/*.cpp + AI/Fsm/*.cpp ContentFinder/*.cpp DebugCommand/*.cpp Event/*.cpp diff --git a/src/world/ContentFinder/ContentFinder.cpp b/src/world/ContentFinder/ContentFinder.cpp index 78faebe3f9..8d53c2ea57 100644 --- a/src/world/ContentFinder/ContentFinder.cpp +++ b/src/world/ContentFinder/ContentFinder.cpp @@ -131,12 +131,11 @@ void World::ContentFinder::registerContentRequest( Entity::Player &player, uint3 void World::ContentFinder::registerRandomContentRequest( Entity::Player &player, uint32_t randomContentTypeId ) { auto& exdData = Service< Data::ExdData >::ref(); - auto contentListIds = exdData.getIdList< Excel::ContentFinderCondition >(); + auto contentFinderList = exdData.getRows< Excel::ContentFinderCondition >(); std::vector< uint32_t > idList; - for( auto id : contentListIds ) + for( const auto& [ id, instanceContent ] : contentFinderList ) { - auto instanceContent = exdData.getRow< Excel::ContentFinderCondition >( id ); if( instanceContent->data().RandomContentType == randomContentTypeId ) { if( instanceContent->data().LevelMin <= player.getLevel() ) diff --git a/src/world/ForwardsZone.h b/src/world/ForwardsZone.h index 02bbc8a62c..398e98b84d 100644 --- a/src/world/ForwardsZone.h +++ b/src/world/ForwardsZone.h @@ -51,9 +51,37 @@ namespace World::AI { TYPE_FORWARD( GambitTargetCondition ); TYPE_FORWARD( TopHateTargetCondition ); - TYPE_FORWARD( HPSelfPctLessThan ); + TYPE_FORWARD( HPSelfPctLessThanTargetCondition ); TYPE_FORWARD( GambitRule ); + TYPE_FORWARD( GambitPack ); + TYPE_FORWARD( GambitTimeLinePack ); + TYPE_FORWARD( GambitRuleSetPack ); +} + +namespace World::AI::Fsm +{ + + TYPE_FORWARD( Condition ); + TYPE_FORWARD( State ); + TYPE_FORWARD( Transition ); + TYPE_FORWARD( StateMachine ); + + TYPE_FORWARD( StateIdle ); + TYPE_FORWARD( StateRoam ); + TYPE_FORWARD( StateCombat ); + TYPE_FORWARD( StateRetreat ); + TYPE_FORWARD( StateDead ); + + TYPE_FORWARD( RoamNextTimeReachedCondition ); + TYPE_FORWARD( RoamTargetReachedCondition ); + TYPE_FORWARD( HateListEmptyCondition ); + TYPE_FORWARD( HateListHasEntriesCondition ); + TYPE_FORWARD( SpawnPointDistanceGtMaxDistanceCondition ); + TYPE_FORWARD( IsDeadCondition ); + + + } namespace Inventory diff --git a/src/world/Manager/AchievementMgr.cpp b/src/world/Manager/AchievementMgr.cpp index 191c3f8e8c..2c41e12396 100644 --- a/src/world/Manager/AchievementMgr.cpp +++ b/src/world/Manager/AchievementMgr.cpp @@ -14,12 +14,10 @@ using namespace Sapphire::World::Manager; bool AchievementMgr::cacheAchievements() { auto& exdData = Common::Service< Data::ExdData >::ref(); - auto idList = exdData.getIdList< Excel::Achievement >(); + auto achvDat = exdData.getRows< Excel::Achievement >(); - for( auto id : idList ) + for( const auto& [ id, achvExdData ] : achvDat ) { - auto achvExdData = exdData.getRow< Excel::Achievement >( id ); - uint32_t key = achvExdData->data().ConditionType; auto achvType = static_cast< Common::Achievement::Type >( key ); diff --git a/src/world/Manager/DebugCommandMgr.cpp b/src/world/Manager/DebugCommandMgr.cpp index 7dcbe84cfc..2442c679af 100644 --- a/src/world/Manager/DebugCommandMgr.cpp +++ b/src/world/Manager/DebugCommandMgr.cpp @@ -534,8 +534,8 @@ void DebugCommandMgr::add( char* data, Entity::Player& player, std::shared_ptr< Common::CalcResultParam entry{}; entry.Value = static_cast< int16_t >( param1 ); - entry.Type = Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP; - entry.Arg0 = static_cast< uint8_t >( Common::ActionHitSeverityType::NormalDamage ); + entry.Type = Common::CalcResultType::TypeDamageHp; + entry.Arg0 = 1; effectPacket->addTargetEffect( entry, static_cast< uint64_t >( player.getId() ) ); effectPacket->setResultId( pCurrentZone->getNextActionResultId() ); diff --git a/src/world/Manager/MapMgr.cpp b/src/world/Manager/MapMgr.cpp index 2824f4aed2..f7a18a40ed 100644 --- a/src/world/Manager/MapMgr.cpp +++ b/src/world/Manager/MapMgr.cpp @@ -35,12 +35,10 @@ using namespace Sapphire::World::Manager; bool MapMgr::loadQuests() { auto& exdData = Common::Service< Data::ExdData >::ref(); - auto idList = exdData.getIdList< Excel::Quest >(); + auto questList = exdData.getRows< Excel::Quest >(); - for( auto id : idList ) + for( auto& [ id, questExdData ] : questList ) { - auto questExdData = exdData.getRow< Excel::Quest >( id ); - m_quests.emplace( id, std::move( questExdData ) ); } diff --git a/src/world/Manager/PlayerMgr.cpp b/src/world/Manager/PlayerMgr.cpp index 28636bbb8e..15f7ad51a0 100644 --- a/src/world/Manager/PlayerMgr.cpp +++ b/src/world/Manager/PlayerMgr.cpp @@ -313,7 +313,7 @@ void PlayerMgr::onUpdate( Entity::Player& player, uint64_t tickCount ) void PlayerMgr::checkAutoAttack( Entity::Player& player, uint64_t tickCount ) const { auto mainWeap = player.getItemAt( Common::GearSet0, Common::MainHand ); - if( !mainWeap || !player.isAutoattackOn() || player.checkAction() || !player.getTargetId() || player.getStance() != Common::Active ) + if( !mainWeap || player.checkAction() || !player.isAutoattackOn() || !player.getTargetId() || player.getStance() != Common::Active ) return; for( const auto& actor : player.getInRangeActors() ) diff --git a/src/world/Manager/ShopMgr.cpp b/src/world/Manager/ShopMgr.cpp index 2edeec1c48..7d9c9aa5fa 100644 --- a/src/world/Manager/ShopMgr.cpp +++ b/src/world/Manager/ShopMgr.cpp @@ -12,13 +12,12 @@ using namespace Sapphire::World::Manager; void ShopMgr::cacheShop( uint32_t shopId ) { auto& exdData = Common::Service< Data::ExdData >::ref(); - auto itemShopList = exdData.getIdList< Excel::Shop >(); + auto itemShopList = exdData.getRows< Excel::Shop >(); uint8_t count = 0; - for( auto itemShop : itemShopList ) + for( const auto& [ itemShop, shop ] : itemShopList ) { if( shopId == itemShop ) { - auto shop = exdData.getRow< Excel::Shop >( itemShop ); for( auto shopItemId : shop->data().Item ) { auto shopItem = exdData.getRow< Excel::ShopItem >( shopItemId ); diff --git a/src/world/Manager/TerritoryMgr.cpp b/src/world/Manager/TerritoryMgr.cpp index 540a061769..a7a27a7f5b 100644 --- a/src/world/Manager/TerritoryMgr.cpp +++ b/src/world/Manager/TerritoryMgr.cpp @@ -35,14 +35,12 @@ TerritoryMgr::TerritoryMgr() : void TerritoryMgr::loadTerritoryTypeDetailCache() { auto& exdData = Common::Service< Data::ExdData >::ref(); - auto idList = exdData.getIdList< Excel::TerritoryType >(); + auto teriList = exdData.getRows< Excel::TerritoryType >(); - for( auto id : idList ) + for( const auto& [ id, teri ] : teriList ) { - auto teri1 = exdData.getRow< Excel::TerritoryType >( id ); - - if( !teri1->getString( teri1->data().Name ).empty() && id > 90 ) - m_territoryTypeDetailCacheMap[ id ] = teri1; + if( !teri->getString( teri->data().Name ).empty() && id > 90 ) + m_territoryTypeDetailCacheMap[ id ] = teri; } } @@ -77,12 +75,11 @@ uint32_t TerritoryMgr::getNextInstanceId() Excel::ExcelStructPtr< Excel::TerritoryType > TerritoryMgr::getTerritoryDetail( uint32_t territoryTypeId ) const { - auto& exdData = Common::Service< Data::ExdData >::ref(); - auto teri1 = exdData.getRow< Excel::TerritoryType >( territoryTypeId ); - if( !teri1 ) + auto it = m_territoryTypeDetailCacheMap.find( territoryTypeId ); + if( it == m_territoryTypeDetailCacheMap.end() ) return nullptr; - return teri1; + return it->second; } bool TerritoryMgr::isInstanceContentTerritory( uint32_t territoryTypeId ) const @@ -159,11 +156,10 @@ bool TerritoryMgr::isHousingTerritory( uint32_t territoryTypeId ) const uint32_t TerritoryMgr::getInstanceContentId( uint32_t territoryTypeId ) const { auto& exdData = Common::Service< Data::ExdData >::ref(); - auto contentListIds = exdData.getIdList< Excel::InstanceContent >(); + auto contentFinderList = exdData.getRows< Excel::InstanceContent >(); - for( auto id : contentListIds ) + for( const auto& [ id, instanceContent ] : contentFinderList ) { - auto instanceContent = exdData.getRow< Excel::InstanceContent >( id ); if( instanceContent->data().TerritoryType == territoryTypeId ) { return id; @@ -198,8 +194,6 @@ bool TerritoryMgr::createDefaultTerritories() pPlaceName->getString( pPlaceName->data().Text.SGL ) ); pZone->init(); - std::string bgPath = territoryInfo->getString( territoryData.LVB ); - bool hasNaviMesh = pZone->getNaviProvider() != nullptr; Logger::info( "{0}\t{1}\t{2}\t{3:<10}\t{4}\t{5}\t{6}", @@ -309,10 +303,10 @@ TerritoryPtr TerritoryMgr::createQuestBattle( uint32_t questBattleId ) if( !pQuestInfo || pQuestInfo->getString( pQuestInfo->data().Text.Name ).empty() ) return nullptr; - for( auto& teriId : exdData.getIdList< Excel::TerritoryType >() ) - { + auto teriList = exdData.getRows< Excel::TerritoryType >(); - auto pTeri = exdData.getRow< Excel::TerritoryType >( teriId ); + for( const auto& [ teriId, pTeri ] : teriList ) + { if( !pTeri || pTeri->data().QuestBattle != questBattleId ) continue; @@ -332,8 +326,6 @@ TerritoryPtr TerritoryMgr::createQuestBattle( uint32_t questBattleId ) m_instanceZoneSet.insert( pZone ); return pZone; - - } return nullptr; diff --git a/src/world/Math/CalcStats.cpp b/src/world/Math/CalcStats.cpp index af58dad1b1..d66d4daf79 100644 --- a/src/world/Math/CalcStats.cpp +++ b/src/world/Math/CalcStats.cpp @@ -85,16 +85,14 @@ const int levelTable[61][6] = { 218, 354, 858, 2600, 282, 215 }, }; -std::random_device CalcStats::dev; -std::mt19937 CalcStats::rng( dev() ); -std::uniform_int_distribution< std::mt19937::result_type > CalcStats::range100( 0, 99 ); +std::unique_ptr< RandGenerator< float > > CalcStats::rnd = nullptr; /* Class used for battle-related formulas and calculations. Big thanks to the Theoryjerks group! NOTE: - Formulas here shouldn't be considered final. It's possible that the formula it was based on is correct but + Formulas here shouldn't be considered final. It's possible that the formula it was based on is correct but wasn't implemented correctly here, or approximated things due to limited knowledge of how things work in retail. It's also possible that we're using formulas that were correct for previous patches, but not the current version. @@ -144,12 +142,15 @@ uint32_t CalcStats::calculateMaxHp( Player& player ) uint16_t hpMod = paramGrowthInfo->data().ParamBase; uint16_t jobModHp = classInfo->data().Hp; float approxBaseHp = 0.0f; // Read above + float hpModPercent = player.getModifier( Common::ParamModifier::HPPercent ); approxBaseHp = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::HP ] ); auto result = static_cast< uint32_t >( floor( jobModHp * ( approxBaseHp / 100.0f ) ) + floor( hpMod / 100.0f * ( vitStat - baseStat ) ) ); + result *= hpModPercent; + return result; } @@ -287,19 +288,6 @@ float CalcStats::blockProbability( const Chara& chara ) return std::floor( ( 30 * blockRate ) / levelVal + 10 ); } -float CalcStats::directHitProbability( const Chara& chara ) -{ - const auto& baseStats = chara.getStats(); - auto level = chara.getLevel(); - - auto dhRate = chara.getStatValueFloat( Common::BaseParam::Accuracy ); - - auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] ); - auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] ); - - return std::floor( 550.f * ( dhRate - subVal ) / divVal ) / 10.f; -} - float CalcStats::criticalHitProbability( const Chara& chara ) { const auto& baseStats = chara.getStats(); @@ -564,7 +552,7 @@ float CalcStats::healingMagicPotency( const Sapphire::Entity::Chara& chara ) return std::floor( 100.f * ( chara.getStatValue( Common::BaseParam::HealingMagicPotency ) - 292.f ) / 264.f + 100.f ) / 100.f; } -std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ) +std::pair< float, Sapphire::Common::CalcResultType > CalcStats::calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ) { // D = ⌊ f(ptc) × f(aa) × f(ap) × f(det) × f(tnc) × traits ⌋ × f(ss) ⌋ × // f(chr) ⌋ × f(dhr) ⌋ × rand[ 0.95, 1.05 ] ⌋ × buff_1 ⌋ × buff... ⌋ @@ -577,27 +565,19 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoA // todo: everything after tenacity auto factor = Common::Util::trunc( pot * aa * ap * det, 0 ); - Sapphire::Common::ActionHitSeverityType hitType = Sapphire::Common::ActionHitSeverityType::NormalDamage; + Sapphire::Common::CalcResultType hitType = Sapphire::Common::CalcResultType::TypeDamageHp; // todo: traits factor = std::floor( factor * speed( chara ) ); - if( criticalHitProbability( chara ) > range100( rng ) ) + if( criticalHitProbability( chara ) > getRandomNumber0To100() ) { factor *= criticalHitBonus( chara ); - hitType = Sapphire::Common::ActionHitSeverityType::CritDamage; + hitType = Sapphire::Common::CalcResultType::TypeCriticalDamageHp; } - if( directHitProbability( chara ) > range100( rng ) ) - { - factor *= 1.25f; - hitType = hitType == Sapphire::Common::ActionHitSeverityType::CritDamage ? - Sapphire::Common::ActionHitSeverityType::CritDirectHitDamage : - Sapphire::Common::ActionHitSeverityType::DirectHitDamage; - } - - factor *= 1.0f + ( ( range100( rng ) - 50.0f ) / 1000.0f ); + factor *= 1.0f + ( ( getRandomNumber0To100() - 50.0f ) / 1000.0f ); // todo: buffs @@ -615,7 +595,7 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoA return std::pair( factor, hitType ); } -std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ) +std::pair< float, Sapphire::Common::CalcResultType > CalcStats::calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ) { // D = ⌊ f(pot) × f(wd) × f(ap) × f(det) × f(tnc) × traits ⌋ // × f(chr) ⌋ × f(dhr) ⌋ × rand[ 0.95, 1.05 ] ⌋ buff_1 ⌋ × buff_1 ⌋ × buff... ⌋ @@ -624,33 +604,29 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio auto wd = weaponDamage( chara, wepDmg ); auto ap = getPrimaryAttackPower( chara ); auto det = determination( chara ); + auto damageDealtMod = chara.getModifier( Common::ParamModifier::DamageDealtPercent ); auto factor = Common::Util::trunc( pot * wd * ap * det, 0 ); - Sapphire::Common::ActionHitSeverityType hitType = Sapphire::Common::ActionHitSeverityType::NormalDamage; + Sapphire::Common::CalcResultType hitType = Sapphire::Common::CalcResultType::TypeDamageHp; - if( criticalHitProbability( chara ) > range100( rng ) ) + if( criticalHitProbability( chara ) > getRandomNumber0To100() ) { factor *= criticalHitBonus( chara ); - hitType = Sapphire::Common::ActionHitSeverityType::CritDamage; - } - - if( directHitProbability( chara ) > range100( rng ) ) - { - factor *= 1.25f; - hitType = hitType == Sapphire::Common::ActionHitSeverityType::CritDamage ? - Sapphire::Common::ActionHitSeverityType::CritDirectHitDamage : - Sapphire::Common::ActionHitSeverityType::DirectHitDamage; + hitType = Sapphire::Common::CalcResultType::TypeCriticalDamageHp; } - factor *= 1.0f + ( ( range100( rng ) - 50.0f ) / 1000.0f ); + factor *= 1.0f + ( ( getRandomNumber0To100() - 50.0f ) / 1000.0f ); // todo: buffs + factor *= damageDealtMod; + constexpr auto format = "dmg: pot: {} ({}) wd: {} ({}) ap: {} det: {} = {}"; if( auto player = const_cast< Entity::Chara& >( chara ).getAsPlayer() ) { PlayerMgr::sendDebug( *player, format, pot, ptc, wd, wepDmg, ap, det, factor ); + PlayerMgr::sendDebug( *player, "DamageDealtPercent: {}", damageDealtMod ); } else { @@ -660,22 +636,23 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio return std::pair( factor, hitType ); } -std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActionHealing( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ) +std::pair< float, Sapphire::Common::CalcResultType > CalcStats::calcActionHealing( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ) { // lol just for testing float det = chara.getStatValue( Common::BaseParam::Determination ); float mnd = chara.getStatValue( Common::BaseParam::Mind ); auto factor = std::floor( ( wepDmg * ( mnd / 200 ) + ( det / 10 ) ) * ( ptc / 100 ) * 1.3f ); - Sapphire::Common::ActionHitSeverityType hitType = Sapphire::Common::ActionHitSeverityType::NormalHeal; - if( criticalHitProbability( chara ) > range100( rng ) ) + Sapphire::Common::CalcResultType hitType = Sapphire::Common::CalcResultType::TypeRecoverHp; + + if( criticalHitProbability( chara ) > getRandomNumber0To100() ) { factor *= criticalHitBonus( chara ); - hitType = Sapphire::Common::ActionHitSeverityType::CritHeal; + hitType = Sapphire::Common::CalcResultType::TypeCriticalRecoverHp; } - factor *= 1.0f + ( ( range100( rng ) - 50.0f ) / 1000.0f ); + factor *= 1.0f + ( ( getRandomNumber0To100() - 50.0f ) / 1000.0f ); return std::pair( factor, hitType ); } @@ -683,4 +660,13 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio uint32_t CalcStats::primaryStatValue( const Sapphire::Entity::Chara& chara ) { return chara.getStatValue( chara.getPrimaryStat() ); -} \ No newline at end of file +} + +float CalcStats::getRandomNumber0To100() +{ + if( !rnd ) + { + rnd = std::make_unique< RandGenerator< float > >( Common::Service< RNGMgr >::ref().getRandGenerator< float >( 0, 100 ) ); + } + return rnd->next(); +} diff --git a/src/world/Math/CalcStats.h b/src/world/Math/CalcStats.h index 87625067b7..ad1d5b94f0 100644 --- a/src/world/Math/CalcStats.h +++ b/src/world/Math/CalcStats.h @@ -1,11 +1,12 @@ #pragma once -#include #include #include "Forwards.h" +#include "Manager/RNGMgr.h" namespace Sapphire::Math { + using namespace Sapphire::World::Manager; class CalcStats { @@ -34,11 +35,6 @@ namespace Sapphire::Math */ static float blockProbability( const Sapphire::Entity::Chara& chara ); - /*! - * @brief Calculates the probability of a direct hit happening - */ - static float directHitProbability( const Sapphire::Entity::Chara& chara ); - /*! * @brief Calculates the probability of a critical hit happening */ @@ -140,11 +136,11 @@ namespace Sapphire::Math //////////////////////////////////////////// - static std::pair< float, Common::ActionHitSeverityType > calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ); + static std::pair< float, Common::CalcResultType > calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ); - static std::pair< float, Common::ActionHitSeverityType > calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); + static std::pair< float, Common::CalcResultType > calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); - static std::pair< float, Common::ActionHitSeverityType > calcActionHealing( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); + static std::pair< float, Common::CalcResultType > calcActionHealing( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); static uint32_t primaryStatValue( const Sapphire::Entity::Chara& chara ); private: @@ -156,9 +152,8 @@ namespace Sapphire::Math */ static float calcAttackPower( const Sapphire::Entity::Chara& chara, uint32_t attackPower ); - static std::random_device dev; - static std::mt19937 rng; - static std::uniform_int_distribution< std::mt19937::result_type > range100; + static float getRandomNumber0To100(); + static std::unique_ptr< RandGenerator< float > > rnd; }; } diff --git a/src/world/Network/Handlers/CFHandlers.cpp b/src/world/Network/Handlers/CFHandlers.cpp index 6aef66e0a2..61c0484c49 100644 --- a/src/world/Network/Handlers/CFHandlers.cpp +++ b/src/world/Network/Handlers/CFHandlers.cpp @@ -74,12 +74,12 @@ void Sapphire::Network::GameConnection::find5Contents( const Packets::FFXIVARR_P if( territoryType != 0 ) selectedContent.insert( territoryType ); - auto contentListIds = exdData.getIdList< Excel::InstanceContent >(); - std::vector< uint32_t > idList; - for( auto id : contentListIds ) + + auto contentFinderList = exdData.getRows< Excel::InstanceContent >(); + + for( const auto& [ id, instanceContent ] : contentFinderList ) { - auto instanceContent = exdData.getRow< Excel::InstanceContent >( id ); if( selectedContent.count( instanceContent->data().TerritoryType ) ) { idList.push_back( id ); diff --git a/src/world/Network/Handlers/GMCommandHandlers.cpp b/src/world/Network/Handlers/GMCommandHandlers.cpp index ace19b6d85..a0076141de 100644 --- a/src/world/Network/Handlers/GMCommandHandlers.cpp +++ b/src/world/Network/Handlers/GMCommandHandlers.cpp @@ -506,19 +506,14 @@ void Sapphire::Network::GameConnection::gmCommandHandler( const Packets::FFXIVAR bool doTeleport = false; uint16_t teleport; - auto idList = exdData.getIdList< Excel::Aetheryte >(); + auto aetheryteList = exdData.getRows< Excel::Aetheryte >(); - for( auto i : idList ) + for( const auto& [ id, data ] : aetheryteList ) { - auto data = exdData.getRow< Excel::Aetheryte >( i ); - - if( !data ) - continue; - if( data->data().TerritoryType == param1 && data->data().Telepo ) { doTeleport = true; - teleport = static_cast< uint16_t >( i ); + teleport = static_cast< uint16_t >( id ); break; } diff --git a/src/world/Network/PacketWrappers/EffectPacket.h b/src/world/Network/PacketWrappers/EffectPacket.h index 82f73c1b95..9e190a3446 100644 --- a/src/world/Network/PacketWrappers/EffectPacket.h +++ b/src/world/Network/PacketWrappers/EffectPacket.h @@ -92,4 +92,10 @@ namespace Sapphire::Network::Packets::WorldPackets::Server uint8_t m_sourceEffectCount{ 0 }; }; + template< typename... Args > + std::shared_ptr< EffectPacket > makeEffectPacket( Args... args ) + { + return std::make_shared< EffectPacket >( args... ); + } + } \ No newline at end of file diff --git a/src/world/Network/PacketWrappers/EffectPacket1.h b/src/world/Network/PacketWrappers/EffectPacket1.h index 37393d3701..b6752374dd 100644 --- a/src/world/Network/PacketWrappers/EffectPacket1.h +++ b/src/world/Network/PacketWrappers/EffectPacket1.h @@ -83,5 +83,10 @@ namespace Sapphire::Network::Packets::WorldPackets::Server uint8_t m_sourceEffectCount{ 0 }; }; + template< typename... Args > + std::shared_ptr< EffectPacket1 > makeEffectPacket1( Args... args ) + { + return std::make_shared< EffectPacket1 >( args... ); + } } diff --git a/src/world/Network/PacketWrappers/NpcSpawnPacket.h b/src/world/Network/PacketWrappers/NpcSpawnPacket.h index 1cf3798238..f3ff593c62 100644 --- a/src/world/Network/PacketWrappers/NpcSpawnPacket.h +++ b/src/world/Network/PacketWrappers/NpcSpawnPacket.h @@ -77,6 +77,16 @@ namespace Sapphire::Network::Packets::WorldPackets::Server m_data.NpcId = bnpc.getBNpcBaseId(); m_data.NameId = bnpc.getBNpcNameId(); + if( bnpc.getInstanceObjectInfo() ) + { + m_data.LinkCountLimit = bnpc.getInstanceObjectInfo()->LinkCountLimit; + m_data.LinkFamily = bnpc.getInstanceObjectInfo()->LinkFamily; + m_data.LinkGroup = bnpc.getInstanceObjectInfo()->LinkGroup; + m_data.LinkParent = bnpc.getInstanceObjectInfo()->LinkParent; + m_data.LinkRange = bnpc.getInstanceObjectInfo()->LinkRange; + m_data.LinkReply = bnpc.getInstanceObjectInfo()->LinkReply; + } + assert( target.getId() != bnpc.getId() ); m_data.Index = target.getSpawnIdForActorId( bnpc.getId() ); diff --git a/src/world/Network/Util/PacketUtil.cpp b/src/world/Network/Util/PacketUtil.cpp index d4ea55d600..842fa03c7e 100644 --- a/src/world/Network/Util/PacketUtil.cpp +++ b/src/world/Network/Util/PacketUtil.cpp @@ -52,15 +52,13 @@ void Util::Packet::sendBaseParams( Entity::Player& player ) std::fill( std::begin( statParams ), std::end( statParams ), 0 ); auto& exd = Common::Service< Data::ExdData >::ref(); - auto idList = exd.getIdList< Excel::BaseParam >(); + auto baseParamList = exd.getRows< Excel::BaseParam >(); - for( const auto id : idList ) + for( const auto& [ id, row ] : baseParamList ) { - auto row = exd.getRow< Excel::BaseParam >( id ); - if( !row ) - continue; - if( row->data().PacketIndex < 0 ) + if( !row || row->data().PacketIndex < 0 ) continue; + statParams[ row->data().PacketIndex ] = player.getStatValue( static_cast< Common::BaseParam >( id ) ); } diff --git a/src/world/Task/ActionIntegrityTask.cpp b/src/world/Task/ActionIntegrityTask.cpp index 7443a8396b..3f2d0749c3 100644 --- a/src/world/Task/ActionIntegrityTask.cpp +++ b/src/world/Task/ActionIntegrityTask.cpp @@ -52,8 +52,8 @@ void ActionIntegrityTask::execute() if( actionResult && actionResult->getTarget() ) actionResult->execute(); - if( ( actionResult->getCalcResultParam().Type == Common::CALC_RESULT_TYPE_SET_STATUS ) || - ( actionResult->getCalcResultParam().Type == Common::CALC_RESULT_TYPE_SET_STATUS_ME ) ) + if( ( actionResult->getCalcResultParam().Type == Common::TypeSetStatus ) || + ( actionResult->getCalcResultParam().Type == Common::TypeSetStatusMe ) ) { auto& status = data.Status[ statusIdx++ ]; auto pEffect = actionResult->getStatusEffect(); diff --git a/src/world/Task/MoveTerritoryTask.cpp b/src/world/Task/MoveTerritoryTask.cpp index 30194d9d60..b7d9c061b8 100644 --- a/src/world/Task/MoveTerritoryTask.cpp +++ b/src/world/Task/MoveTerritoryTask.cpp @@ -41,6 +41,10 @@ void MoveTerritoryTask::execute() if( !pPlayer ) return; + pPlayer->setTargetId( 0 ); + pPlayer->setStance( Common::Stance::Passive ); + pPlayer->setAutoattack( false ); + auto inRangePlayerIds = pPlayer->getInRangePlayerIds( true ); auto warpStart = makeActorControlSelf( pPlayer->getId(), WarpStart, m_warpInfo.m_warpType, 1, 0, m_warpInfo.m_targetTerritoryId, 1 ); diff --git a/src/world/Territory/Cell.cpp b/src/world/Territory/Cell.cpp index 2eebc7a780..42bda66743 100644 --- a/src/world/Territory/Cell.cpp +++ b/src/world/Territory/Cell.cpp @@ -102,3 +102,12 @@ void Sapphire::Cell::unload() removeActors(); } +uint32_t Sapphire::Cell::getLastActiveTime() const +{ + return m_lastActiveTime; +} + +void Sapphire::Cell::setLastActiveTime( uint32_t lastActiveTime ) +{ + m_lastActiveTime = lastActiveTime; +} \ No newline at end of file diff --git a/src/world/Territory/Cell.h b/src/world/Territory/Cell.h index 07c0cfc370..4aca5791e5 100644 --- a/src/world/Territory/Cell.h +++ b/src/world/Territory/Cell.h @@ -20,6 +20,7 @@ class Cell bool m_bActive; uint16_t m_playerCount; + uint32_t m_lastActiveTime; public: Cell(); @@ -82,6 +83,9 @@ class Cell { return m_posY; } + + uint32_t getLastActiveTime() const; + void setLastActiveTime( uint32_t lastActiveTime ); }; } diff --git a/src/world/Territory/InstanceObjectCache.cpp b/src/world/Territory/InstanceObjectCache.cpp index 455975b2b7..91ff7a4c3a 100644 --- a/src/world/Territory/InstanceObjectCache.cpp +++ b/src/world/Territory/InstanceObjectCache.cpp @@ -11,27 +11,24 @@ #include #include +#include +#include + #include #include #include Sapphire::InstanceObjectCache::InstanceObjectCache() { - auto& exdData = Common::Service< Sapphire::Data::ExdData >::ref(); - auto idList = exdData.getIdList< Excel::TerritoryType >(); + auto teriList = exdData.getRows< Excel::TerritoryType >(); size_t count = 0; - for( const auto& id : idList ) - { + for( const auto& [ id, territoryType ] : teriList ) { // show some loading indication... if( count++ % 10 == 0 ) std::cout << "."; - auto territoryType = exdData.getRow< Excel::TerritoryType >( id ); - if( !territoryType ) - continue; - auto path = territoryType->getString( territoryType->data().LVB ); if( path.empty() ) @@ -56,7 +53,11 @@ Sapphire::InstanceObjectCache::InstanceObjectCache() try { - bgFile = exdData.getGameData()->getFile( bgLgbPath ); + if( exdData.getGameData()->doesFileExist( bgLgbPath ) ) + bgFile = exdData.getGameData()->getFile( bgLgbPath ); + else + continue; + planmap_file = exdData.getGameData()->getFile( planmapLgbPath ); planevent_file = exdData.getGameData()->getFile( planeventLgbPath ); } @@ -101,49 +102,60 @@ Sapphire::InstanceObjectCache::InstanceObjectCache() { for( const auto& pEntry : group.entries ) { - - if( pEntry->getType() == LgbEntryType::MapRange ) + switch( pEntry->getType() ) { - auto pMapRange = std::reinterpret_pointer_cast< LGB_MAP_RANGE_ENTRY >( pEntry ); - m_mapRangeCache.insert( id, pMapRange ); - } - else if( pEntry->getType() == LgbEntryType::ExitRange ) - { - auto pExitRange = std::reinterpret_pointer_cast< LGB_EXIT_RANGE_ENTRY >( pEntry ); - m_exitRangeCache.insert( id, pExitRange ); - } - else if( pEntry->getType() == LgbEntryType::PopRange ) - { - - auto pPopRange = std::reinterpret_pointer_cast< LGB_POP_RANGE_ENTRY >( pEntry ); - m_popRangeCache.insert( id, pPopRange ); - } - else if( pEntry->getType() == LgbEntryType::CollisionBox ) - { - //auto pEObj = std::reinterpret_pointer_cast< LGB_ENPC_ENTRY >( pEntry ); - - //Logger::debug( "CollisionBox {}", pEntry->header.nameOffset ); - } - else if( pEntry->getType() == LgbEntryType::EventObject ) - { - auto pEObj = std::reinterpret_pointer_cast< LGB_EOBJ_ENTRY >( pEntry ); - m_eobjCache.insert( id, pEObj ); - } - else if( pEntry->getType() == LgbEntryType::EventNpc ) - { - auto pENpc = std::reinterpret_pointer_cast< LGB_ENPC_ENTRY >( pEntry ); - m_enpcCache.insert( id, pENpc ); - } - else if( pEntry->getType() == LgbEntryType::EventRange ) - { - auto pEventRange = std::reinterpret_pointer_cast< LGB_EVENT_RANGE_ENTRY >( pEntry ); - m_eventRangeCache.insert( 0, pEventRange ); + case LgbEntryType::MapRange: + { + auto pMapRange = std::reinterpret_pointer_cast< LGB_MAP_RANGE_ENTRY >( pEntry ); + m_mapRangeCache.insert( id, pMapRange ); + + break; + } + case LgbEntryType::ExitRange: + { + auto pExitRange = std::reinterpret_pointer_cast< LGB_EXIT_RANGE_ENTRY >( pEntry ); + m_exitRangeCache.insert( id, pExitRange ); + + break; + } + case LgbEntryType::PopRange: + { + auto pPopRange = std::reinterpret_pointer_cast< LGB_POP_RANGE_ENTRY >( pEntry ); + m_popRangeCache.insert( id, pPopRange ); + break; + } + case LgbEntryType::CollisionBox: + { + //auto pEObj = std::reinterpret_pointer_cast< LGB_ENPC_ENTRY >( pEntry ); + + //Logger::debug( "CollisionBox {}", pEntry->header.nameOffset ); + break; + } + case LgbEntryType::EventObject: + { + auto pEObj = std::reinterpret_pointer_cast< LGB_EOBJ_ENTRY >( pEntry ); + m_eobjCache.insert( id, pEObj ); + break; + } + case LgbEntryType::EventNpc: + { + auto pENpc = std::reinterpret_pointer_cast< LGB_ENPC_ENTRY >( pEntry ); + m_enpcCache.insert( id, pENpc ); + break; + } + case LgbEntryType::EventRange: + { + auto pEventRange = std::reinterpret_pointer_cast< LGB_EVENT_RANGE_ENTRY >( pEntry ); + m_eventRangeCache.insert( 0, pEventRange ); + break; + } } } } } } - std::cout << "\n"; + + std::cout << std::endl; Logger::debug( "InstanceObjectCache Cached: MapRange: {} ExitRange: {} PopRange: {} EventObj: {} EventNpc: {} EventRange: {}", diff --git a/src/world/Territory/Territory.cpp b/src/world/Territory/Territory.cpp index 375c7071e8..1948a207e1 100644 --- a/src/world/Territory/Territory.cpp +++ b/src/world/Territory/Territory.cpp @@ -528,6 +528,7 @@ bool Territory::isCellActive( uint32_t x, uint32_t y ) uint32_t posY; CellPtr pCell; + uint32_t time = Common::Util::getTimeSeconds(); for( posX = startX; posX <= endX; posX++ ) { @@ -535,7 +536,7 @@ bool Territory::isCellActive( uint32_t x, uint32_t y ) { pCell = getCellPtr( posX, posY ); - if( pCell && ( pCell->hasPlayers() || pCell->isForcedActive() ) ) + if( pCell && ( pCell->hasPlayers() || pCell->isForcedActive() || ( time - pCell->getLastActiveTime() ) < 20 ) ) return true; } } @@ -566,13 +567,13 @@ void Territory::updateCellActivity( uint32_t x, uint32_t y, int32_t radius ) { pCell = create( posX, posY ); pCell->init( posX, posY ); - pCell->setActivity( true ); - + pCell->setLastActiveTime( Common::Util::getTimeSeconds() ); } } else { + pCell->setLastActiveTime( Common::Util::getTimeSeconds() ); //Cell is now active if( isCellActive( posX, posY ) && !pCell->isActive() ) { @@ -581,6 +582,7 @@ void Territory::updateCellActivity( uint32_t x, uint32_t y, int32_t radius ) else if( !isCellActive( posX, posY ) && pCell->isActive() ) pCell->setActivity( false ); } + } } } @@ -834,6 +836,7 @@ Entity::BNpcPtr Territory::createBNpcFromLayoutId( uint32_t layoutId, uint32_t h return nullptr; auto pBNpc = std::make_shared< Entity::BNpc >( getNextActorId(), infoPtr->second, *this, hp, bnpcType ); + pBNpc->init(); pBNpc->setTriggerOwnerId( triggerOwnerId ); pushActor( pBNpc ); return pBNpc; diff --git a/src/world/WorldServer.cpp b/src/world/WorldServer.cpp index 4748e1e94f..c89cf5508c 100644 --- a/src/world/WorldServer.cpp +++ b/src/world/WorldServer.cpp @@ -144,6 +144,11 @@ std::string readFileToString( const std::string& filename ) // Close the file file.close(); + // Remove all newlines from the file contents + fileContents.erase( std::remove( fileContents.begin(), fileContents.end(), '\n' ), fileContents.end() ); + fileContents.erase( std::remove( fileContents.begin(), fileContents.end(), '\r' ), fileContents.end() ); + + // Return the file contents as a string return fileContents; }