diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 02d6157798a..62478708cd1 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -445,3 +445,8 @@ Defining a buddy could be done in several way: * datalong = string_id id * apply = 0 remove, 1 add +56 SCRIPT_COMMAND_RECALL_OR_RESPAWN_ACCESSORIES Recalls or respawns source vehicle accessories + * datalong = 0x1 recall, 0x2 respawn, 0x3 recall and respawn + * datalong2 = max distance for recall, of 0 any distance + * dataint = seat index for recall or respawn, if -1, all seats per vehicle accessory template + diff --git a/src/game/DBScripts/ScriptMgr.cpp b/src/game/DBScripts/ScriptMgr.cpp index 25970959cb2..4b667a92e73 100644 --- a/src/game/DBScripts/ScriptMgr.cpp +++ b/src/game/DBScripts/ScriptMgr.cpp @@ -948,6 +948,18 @@ void ScriptMgr::LoadScripts(ScriptMapType scriptType) } break; } + case SCRIPT_COMMAND_RECALL_OR_RESPAWN_ACCESSORIES: // 56 + if (tmp.recallOrRespawnPassenger.recallRespawnFlag > 0x3) + { + sLog.outErrorDb("Table `%s` has invalid recall respawn flags assigned %u", tablename, tmp.recallOrRespawnPassenger.recallRespawnFlag); + continue; + } + if (tmp.textId[0] >= MAX_VEHICLE_SEAT || tmp.textId[0] < -1) + { + sLog.outErrorDb("Table `%s` has seat index assigned %d", tablename, tmp.textId[0]); + continue; + } + break; default: { sLog.outErrorDb("Table `%s` unknown command %u, skipping.", tablename, tmp.command); @@ -3278,6 +3290,26 @@ bool ScriptAction::ExecuteDbscriptCommand(WorldObject* pSource, WorldObject* pTa pSource->SetStringId(m_script->stringId.stringId, m_script->stringId.apply); break; } + case SCRIPT_COMMAND_RECALL_OR_RESPAWN_ACCESSORIES: + { + if (LogIfNotUnit(pSource)) + break; + + if (!static_cast(pSource)->IsVehicle()) + { + sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u source is not vehicle.", + m_table, m_script->id, m_script->command); + } + uint32 flags = m_script->recallOrRespawnPassenger.recallRespawnFlag; + int32 seatIndex = m_script->textId[0]; + if (flags == 1) + static_cast(pSource)->GetVehicleInfo()->RecallAccessories(m_script->recallOrRespawnPassenger.searchRadius, seatIndex); + else if (flags == 2) + static_cast(pSource)->GetVehicleInfo()->RespawnAccessories(seatIndex); + else if (flags == 3) + static_cast(pSource)->GetVehicleInfo()->RecallAndRespawnAccessories(m_script->recallOrRespawnPassenger.searchRadius, seatIndex); + break; + } default: sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u unknown command used.", m_table, m_script->id, m_script->command); diff --git a/src/game/DBScripts/ScriptMgr.h b/src/game/DBScripts/ScriptMgr.h index 94d32543879..997a3b0db58 100644 --- a/src/game/DBScripts/ScriptMgr.h +++ b/src/game/DBScripts/ScriptMgr.h @@ -139,6 +139,7 @@ enum ScriptCommand // resSource, resTar SCRIPT_COMMAND_SET_WORLDSTATE = 53, // dataint = worldstate id, dataint2 = new value, SCRIPT_COMMAND_SET_SHEATHE = 54, // dataint = worldstate id, dataint2 = new value, SCRIPT_COMMAND_SET_STRING_ID = 55, // datalong = string_id id, datalong2 = 0 unapply, 1 apply + SCRIPT_COMMAND_RECALL_OR_RESPAWN_ACCESSORIES = 56 // datalong = 0x1 recall, 0x2 respawn, 0x3 recall and respawn, datalong2 = search radius for recall }; #define MAX_TEXT_ID 4 // used for SCRIPT_COMMAND_TALK, SCRIPT_COMMAND_EMOTE, SCRIPT_COMMAND_CAST_SPELL, SCRIPT_COMMAND_TERMINATE_SCRIPT @@ -483,6 +484,12 @@ struct ScriptInfo uint32 apply; // datalong2 } stringId; + struct // SCRIPT_COMMAND_RECALL_OR_RESPAWN_ACCESSORIES (56) + { + uint32 recallRespawnFlag; // datalong + uint32 searchRadius; // datalong2 + } recallOrRespawnPassenger; + struct { uint32 data[3]; diff --git a/src/game/Entities/Vehicle.cpp b/src/game/Entities/Vehicle.cpp index fe27311b090..9b31b5a9a64 100644 --- a/src/game/Entities/Vehicle.cpp +++ b/src/game/Entities/Vehicle.cpp @@ -212,13 +212,9 @@ void VehicleInfo::Initialize() SQLMultiStorage::SQLMSIteratorBounds bounds = sVehicleAccessoryStorage.getBounds(m_overwriteNpcEntry); for (SQLMultiStorage::SQLMultiSIterator itr = bounds.first; itr != bounds.second; ++itr) { - if (Creature* summoned = m_owner->SummonCreature(itr->passengerEntry, m_owner->GetPositionX(), m_owner->GetPositionY(), m_owner->GetPositionZ(), 2 * m_owner->GetOrientation(), TEMPSPAWN_DEAD_DESPAWN, 0)) - { - DEBUG_LOG("VehicleInfo(of %s)::Initialize: Load vehicle accessory %s onto seat %u", m_owner->GetGuidStr().c_str(), summoned->GetGuidStr().c_str(), itr->seatId); - m_accessoryGuids.insert(summoned->GetObjectGuid()); - int32 basepoint0 = itr->seatId + 1; - summoned->CastCustomSpell((Unit*)m_owner, SPELL_RIDE_VEHICLE_HARDCODED, &basepoint0, nullptr, nullptr, TRIGGERED_OLD_TRIGGERED); - } + Position pos = m_owner->GetPosition(); + pos.o *= 2; + SummonPassenger(itr->passengerEntry, pos, itr->seatId); } } @@ -251,6 +247,17 @@ void VehicleInfo::Initialize() m_isInitialized = true; } +void VehicleInfo::SummonPassenger(uint32 entry, Position const& pos, uint8 seatId) +{ + if (Creature* summoned = m_owner->SummonCreature(entry, pos.x, pos.y, pos.z, pos.o, TEMPSPAWN_DEAD_DESPAWN, 0)) + { + DEBUG_LOG("VehicleInfo(of %s)::Initialize: Load vehicle accessory %s onto seat %u", m_owner->GetGuidStr().c_str(), summoned->GetGuidStr().c_str(), seatId); + m_accessoryGuids.insert(summoned->GetObjectGuid()); + int32 basepoint0 = seatId + 1; + summoned->CastCustomSpell((Unit*)m_owner, SPELL_RIDE_VEHICLE_HARDCODED, &basepoint0, nullptr, nullptr, TRIGGERED_OLD_TRIGGERED); + } +} + /** * This function will board a passenger onto a vehicle * @@ -487,7 +494,7 @@ void VehicleInfo::UnBoard(Unit* passenger, bool changeVehicle) passenger->m_movementInfo.ClearTransportData(); } - if (passenger->GetTypeId() == TYPEID_PLAYER) + if (passenger->IsPlayer()) { Player* pPlayer = (Player*)passenger; pPlayer->ResummonPetTemporaryUnSummonedIfAny(); @@ -525,13 +532,12 @@ void VehicleInfo::UnBoard(Unit* passenger, bool changeVehicle) init.SetExitVehicle(); init.Launch(); - // Despawn if passenger was accessory - if (passenger->GetTypeId() == TYPEID_UNIT && m_accessoryGuids.find(passenger->GetObjectGuid()) != m_accessoryGuids.end()) + // Remove from list if passenger was accessory + if (passenger->IsCreature() && m_accessoryGuids.find(passenger->GetObjectGuid()) != m_accessoryGuids.end()) { Creature* cPassenger = static_cast(passenger); m_accessoryGuids.erase(passenger->GetObjectGuid()); - - // Note: Most of the creature accessories have to stay on the map if unboarded; despawn events are handled by Creauture_Linking_Template if needed + m_unboardedAccessories.emplace_back(passenger->GetObjectGuid(), seat); } } @@ -647,6 +653,62 @@ void VehicleInfo::TeleportPassengers(uint32 mapId) } } +void VehicleInfo::RecallAndRespawnAccessories(float distance, int32 seatIndex) +{ + RecallAccessories(distance, seatIndex); + RespawnAccessories(seatIndex); +} + +void VehicleInfo::RespawnAccessories(int32 seatIndex) +{ + SQLMultiStorage::SQLMSIteratorBounds bounds = sVehicleAccessoryStorage.getBounds(m_overwriteNpcEntry); + for (SQLMultiStorage::SQLMultiSIterator itr = bounds.first; itr != bounds.second; ++itr) + { + if (seatIndex != -1 && seatIndex != itr->seatId) + continue; + Position pos = m_owner->GetPosition(); + pos.o *= 2; + SummonPassenger(itr->passengerEntry, pos, itr->seatId); + } +} + +void VehicleInfo::RecallAccessories(float distance, int32 seatIndex) +{ + for (auto itr = m_unboardedAccessories.begin(); itr != m_unboardedAccessories.end();) + { + ObjectGuid guid = itr->first; + uint8 seat = itr->second; + if (seatIndex != -1 && seat != seatIndex) + { + ++itr; + continue; + } + if (Creature* creature = m_owner->GetMap()->GetCreature(guid)) + { + if (!creature->IsAlive()) + { + itr = m_unboardedAccessories.erase(itr); + continue; + } + if (distance != 0.f && creature->GetDistance(m_owner, true, DIST_CALC_NONE) > distance * distance) + { + ++itr; + continue; + } + if (!IsSeatAvailableFor(creature, seat)) + { + ++itr; + continue; + } + m_accessoryGuids.insert(creature->GetObjectGuid()); + int32 basepoint0 = seat; + creature->CastCustomSpell(static_cast(m_owner), SPELL_RIDE_VEHICLE_HARDCODED, &basepoint0, nullptr, nullptr, TRIGGERED_OLD_TRIGGERED); + itr = m_unboardedAccessories.erase(itr); + } + else ++itr; + } +} + /* ************************************************************************************************ * Helper function for seat control * ***********************************************************************************************/ diff --git a/src/game/Entities/Vehicle.h b/src/game/Entities/Vehicle.h index 64ee77aad7b..03c26b27e61 100644 --- a/src/game/Entities/Vehicle.h +++ b/src/game/Entities/Vehicle.h @@ -81,6 +81,7 @@ class VehicleInfo : public TransportBase explicit VehicleInfo(Unit* owner, VehicleEntry const* vehicleEntry, uint32 overwriteNpcEntry); void Initialize(); ///< Initializes the accessories bool IsInitialized() const { return m_isInitialized; } + void SummonPassenger(uint32 entry, Position const& pos, uint8 seatId); ~VehicleInfo(); @@ -102,6 +103,10 @@ class VehicleInfo : public TransportBase void DisableAccessoryInit() { m_disabledAccessoryInit = true; } + void RecallAndRespawnAccessories(float distance = 0.f, int32 seatIndex = -1); + void RespawnAccessories(int32 seatIndex = -1); + void RecallAccessories(float distance = 0.f, int32 seatIndex = -1); + private: // Internal use to calculate the boarding position void CalculateBoardingPositionOf(float gx, float gy, float gz, float go, float& lx, float& ly, float& lz, float& lo) const; @@ -122,15 +127,16 @@ class VehicleInfo : public TransportBase void RemoveSeatMods(Unit* passenger, uint32 seatFlags); VehicleEntry const* m_vehicleEntry; - VehicleSeatMap m_vehicleSeats; ///< Stores the available seats of the vehicle (filled in constructor) - uint8 m_creatureSeats; ///< Mask that stores which seats are avaiable for creatures - uint8 m_playerSeats; ///< Mask that stores which seats are avaiable for players + VehicleSeatMap m_vehicleSeats; // Stores the available seats of the vehicle (filled in constructor) + uint8 m_creatureSeats; // Mask that stores which seats are avaiable for creatures + uint8 m_playerSeats; // Mask that stores which seats are avaiable for players uint32 m_overwriteNpcEntry; // Internal use to store the entry with which the vehicle-accessories are fetched bool m_isInitialized; // Internal use to store if the accessory is initialized bool m_disabledAccessoryInit; uint32 m_originalFaction; // Internal use to store the original unit faction before taking control of the unit - GuidSet m_accessoryGuids; ///< Stores the summoned accessories of this vehicle + GuidSet m_accessoryGuids; // Stores the summoned accessories of this vehicle + std::vector> m_unboardedAccessories; // Stores unboarded accessories for purpose of recall }; #endif