diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index d77838cfe..89051e9f8 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -157,6 +157,7 @@ ChatCommand * ChatHandler::getCommandTable() { "sellerr", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSellErrorCommand, "", NULL }, { "buyerr", SEC_ADMINISTRATOR, false, &ChatHandler::HandleBuyErrorCommand, "", NULL }, { "sendopcode", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSendOpcodeCommand, "", NULL }, + { "spawnvehicle", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSpawnVehicle, "", NULL }, { "uws", SEC_ADMINISTRATOR, false, &ChatHandler::HandleUpdateWorldStateCommand, "", NULL }, { "ps", SEC_ADMINISTRATOR, false, &ChatHandler::HandlePlaySound2Command, "", NULL }, { "scn", SEC_ADMINISTRATOR, false, &ChatHandler::HandleSendChannelNotifyCommand, "", NULL }, diff --git a/src/game/Chat.h b/src/game/Chat.h index 86f310ee5..1b7db35d6 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -427,6 +427,7 @@ class ChatHandler bool HandleSaveAllCommand(const char* args); bool HandleGetItemState(const char * args); bool HandleGetLootRecipient(const char * args); + bool HandleSpawnVehicle(const char * args); Player* getSelectedPlayer(); Creature* getSelectedCreature(); diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index d03b1d416..1caca9270 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -1696,7 +1696,7 @@ void Creature::CallAssistence() void Creature::SaveRespawnTime() { - if(isPet() || !m_DBTableGuid) + if(isPet() || isVehicle() || !m_DBTableGuid) return; if(m_respawnTime > time(NULL)) // dead (no corpse) diff --git a/src/game/Creature.h b/src/game/Creature.h index 4f5dd1d51..a95a3998b 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -410,6 +410,7 @@ class MANGOS_DLL_SPEC Creature : public Unit uint32 GetEquipmentId() const { return m_equipmentId; } bool isPet() const { return m_isPet; } + bool isVehicle() const { return m_isVehicle; } void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; } bool isTotem() const { return m_isTotem; } bool isRacialLeader() const { return GetCreatureInfo()->RacialLeader; } @@ -618,6 +619,7 @@ class MANGOS_DLL_SPEC Creature : public Unit uint8 m_emoteState; bool m_isPet; // set only in Pet::Pet + bool m_isVehicle; // set only in Vehicle::Vehicle bool m_isTotem; // set only in Totem::Totem void RegenerateMana(); void RegenerateHealth(); diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp index c9b3b351d..b86d648f8 100644 --- a/src/game/Level2.cpp +++ b/src/game/Level2.cpp @@ -949,7 +949,7 @@ bool ChatHandler::HandleNpcDeleteCommand(const char* args) else unit = getSelectedCreature(); - if(!unit || unit->isPet() || unit->isTotem()) + if(!unit || unit->isPet() || unit->isTotem() || unit->isVehicle()) { SendSysMessage(LANG_SELECT_CREATURE); SetSentErrorMessage(true); diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 029c59719..061fb0d31 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -253,7 +253,7 @@ template<> void Map::AddToGrid(Creature* obj, NGridType *grid, Cell const& cell) { // add to world object registry in grid - if(obj->isPet()) + if(obj->isPet() || obj->isVehicle()) { (*grid)(cell.CellX(), cell.CellY()).AddWorldObject(obj, obj->GetGUID()); obj->SetCurrentCell(cell); @@ -297,7 +297,7 @@ template<> void Map::RemoveFromGrid(Creature* obj, NGridType *grid, Cell const& cell) { // remove from world object registry in grid - if(obj->isPet()) + if(obj->isPet() || obj->isVehicle()) { (*grid)(cell.CellX(), cell.CellY()).RemoveWorldObject(obj, obj->GetGUID()); } diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp index b5d970bf4..eb0ed5c2f 100644 --- a/src/game/MiscHandler.cpp +++ b/src/game/MiscHandler.cpp @@ -1661,15 +1661,16 @@ void WorldSession::HandleSpellClick( WorldPacket & recv_data ) uint64 guid; recv_data >> guid; - Unit *vehicle = ObjectAccessor::GetUnit(*_player, guid); + Vehicle *vehicle = ObjectAccessor::GetVehicle(guid); if(!vehicle) return; - _player->SetClientControl(vehicle, 1); - _player->CastSpell(_player, 43768, true); - _player->SetUInt64Value(UNIT_FIELD_CHARM, guid); - _player->SetUInt64Value(PLAYER_FARSIGHT, guid); + //_player->SetClientControl(vehicle, 1); + //_player->CastSpell(_player, 43768, true); + //_player->SetUInt64Value(UNIT_FIELD_CHARM, guid); + //_player->SetUInt64Value(PLAYER_FARSIGHT, guid); + _player->EnterVehicle(vehicle); } void WorldSession::HandleInspectAchievements( WorldPacket & recv_data ) diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp index 229aff452..cd7e4a81d 100644 --- a/src/game/MovementHandler.cpp +++ b/src/game/MovementHandler.cpp @@ -201,7 +201,7 @@ void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) recv_data >> movementInfo.t_z; recv_data >> movementInfo.t_o; recv_data >> movementInfo.t_time; - recv_data >> movementInfo.t_unk; + recv_data >> movementInfo.t_seat; } if((MovementFlags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING2)) || (movementInfo.unk1 & 0x20)) diff --git a/src/game/Object.cpp b/src/game/Object.cpp index 81a29276b..42b5833ba 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -258,6 +258,10 @@ void Object::DestroyForPlayer(Player *target) const void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2) const { uint16 unk_flags = ((GetTypeId() == TYPEID_PLAYER) ? ((Player*)this)->m_movementInfo.unk1 : 0); + + if(GetTypeId() == TYPEID_UNIT) + if(((Creature*)this)->isVehicle()) + unk_flags |= 0x20; // always allow pitch *data << (uint8)flags; // update flags @@ -331,7 +335,7 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2) *data << (float)((Player*)this)->GetTransOffsetZ(); *data << (float)((Player*)this)->GetTransOffsetO(); *data << (uint32)((Player*)this)->GetTransTime(); - *data << (uint8)((Player*)this)->GetTransUnk(); + *data << (int8)((Player*)this)->GetTransSeat(); } //MaNGOS currently not have support for other than player on transport } @@ -544,7 +548,7 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2) // 0x80 if(flags & UPDATEFLAG_VEHICLE) // unused for now { - *data << uint32(0); // vehicle id + *data << uint32(((Vehicle*)this)->GetVehicleId()); // vehicle id *data << float(0); // facing adjustment } } diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index febb0148e..61c92db3d 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -132,6 +132,9 @@ ObjectAccessor::GetCreatureOrPet(WorldObject const &u, uint64 guid) if(Creature *unit = GetPet(guid)) return unit; + if(Creature *unit = GetVehicle(guid)) + return unit; + return GetCreature(u, guid); } @@ -367,6 +370,12 @@ ObjectAccessor::GetPet(uint64 guid) return GetObjectInWorld(guid, (Pet*)NULL); } +Vehicle* +ObjectAccessor::GetVehicle(uint64 guid) +{ + return GetObjectInWorld(guid, (Vehicle*)NULL); +} + Corpse* ObjectAccessor::GetCorpseForPlayerGUID(uint64 guid) { diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h index c6f9815e7..fbf60baaf 100644 --- a/src/game/ObjectAccessor.h +++ b/src/game/ObjectAccessor.h @@ -149,6 +149,7 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::SingletongetSource(); - assert(!c->isPet() && "ObjectGridRespawnMover don't must be called for pets"); + assert((!c->isPet() || !c->isVehicle()) && "ObjectGridRespawnMover don't must be called for pets"); Cell const& cur_cell = c->GetCurrentCell(); diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 6c7c9997a..61db3b8b2 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -18596,3 +18596,72 @@ void Player::InitGlyphsForLevel() SetUInt32Value(PLAYER_GLYPHS_ENABLED, value); } + +void Player::EnterVehicle(Vehicle *vehicle) +{ + vehicle->SetCharmerGUID(GetGUID()); + vehicle->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + vehicle->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + vehicle->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5); + vehicle->setFaction(getFaction()); + + SetCharm(vehicle); + SetUInt64Value(PLAYER_FARSIGHT, vehicle->GetGUID()); + + SetClientControl(vehicle, 1); + + WorldPacket data(SMSG_UNKNOWN_1181, 0); + GetSession()->SendPacket(&data); + + data.Initialize(MSG_MOVE_TELEPORT_ACK, 30); + data.append(GetPackGUID()); + data << uint32(0); // counter? + data << uint32(MOVEMENTFLAG_ONTRANSPORT); // transport + data << uint16(0); // special flags + data << uint32(getMSTime()); // time + data << vehicle->GetPositionX(); // x + data << vehicle->GetPositionY(); // y + data << vehicle->GetPositionZ(); // z + data << vehicle->GetOrientation(); // o + // transport part + data << vehicle->GetGUID(); // transport guid + data << float(0); // transport offsetX + data << float(0); // transport offsetY + data << float(1); // transport offsetZ + data << float(0); // transport orientation + data << uint32(getMSTime()); // transport time + data << uint8(0); // seat + // end of transport part + data << uint32(0); // fall time + GetSession()->SendPacket(&data); +} + +void Player::ExitVehicle(Vehicle *vehicle) +{ + vehicle->SetCharmerGUID(0); + vehicle->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + vehicle->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); + vehicle->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5); + vehicle->setFaction((GetTeam() == ALLIANCE) ? vehicle->GetCreatureInfo()->faction_A : vehicle->GetCreatureInfo()->faction_H); + + SetCharm(NULL); + SetUInt64Value(PLAYER_FARSIGHT, 0); + + SetClientControl(vehicle, 0); + + WorldPacket data(MSG_MOVE_TELEPORT_ACK, 30); + data.append(GetPackGUID()); + data << uint32(0); // counter? + data << uint32(MOVEMENTFLAG_FLY_UNK1); // fly unk + data << uint16(0x40); // special flags + data << uint32(getMSTime()); // time + data << vehicle->GetPositionX(); // x + data << vehicle->GetPositionY(); // y + data << vehicle->GetPositionZ(); // z + data << vehicle->GetOrientation(); // o + data << uint32(0); // fall time + GetSession()->SendPacket(&data); + + // only for flyable vehicles? + CastSpell(this, 45472, true); // Parachute +} diff --git a/src/game/Player.h b/src/game/Player.h index e640524c3..d38bb079d 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -47,6 +47,7 @@ class Transport; class UpdateMask; class PlayerSocial; class AchievementMgr; +class Vehicle; typedef std::deque PlayerMails; @@ -736,7 +737,7 @@ struct MovementInfo uint64 t_guid; float t_x, t_y, t_z, t_o; uint32 t_time; - uint8 t_unk; + int8 t_seat; // swimming and unknown float s_pitch; // last fall time @@ -1950,6 +1951,9 @@ class MANGOS_DLL_SPEC Player : public Unit void SetClientControl(Unit* target, uint8 allowMove); + void EnterVehicle(Vehicle *vehicle); + void ExitVehicle(Vehicle *vehicle); + // Transports Transport * GetTransport() const { return m_transport; } void SetTransport(Transport * t) { m_transport = t; } @@ -1959,7 +1963,7 @@ class MANGOS_DLL_SPEC Player : public Unit float GetTransOffsetZ() const { return m_movementInfo.t_z; } float GetTransOffsetO() const { return m_movementInfo.t_o; } uint32 GetTransTime() const { return m_movementInfo.t_time; } - uint8 GetTransUnk() const { return m_movementInfo.t_unk; } + int8 GetTransSeat() const { return m_movementInfo.t_seat; } uint32 GetSaveTimer() const { return m_nextSave; } void SetSaveTimer(uint32 timer) { m_nextSave = timer; } diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 2aa7b27fb..da1894338 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -9061,7 +9061,7 @@ bool Unit::CanHaveThreatList() const return false; // pets and totems can not have threat list - if( ((Creature*)this)->isPet() || ((Creature*)this)->isTotem() ) + if( ((Creature*)this)->isPet() || ((Creature*)this)->isTotem() || ((Creature*)this)->isVehicle() ) return false; return true; diff --git a/src/game/Vehicle.cpp b/src/game/Vehicle.cpp index acfd00f58..f61e14cbb 100644 --- a/src/game/Vehicle.cpp +++ b/src/game/Vehicle.cpp @@ -28,8 +28,9 @@ #include "Unit.h" #include "Util.h" -Vehicle::Vehicle() : Creature() +Vehicle::Vehicle() : Creature(), m_vehicleId(0) { + m_isVehicle = true; m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_LIVING | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_VEHICLE); } @@ -64,15 +65,29 @@ void Vehicle::Update(uint32 diff) Creature::Update(diff); } -bool Vehicle::Create(uint32 guidlow, Map *map, uint32 Entry) +bool Vehicle::Create(uint32 guidlow, Map *map, uint32 Entry, uint32 vehicleId, uint32 team) { SetMapId(map->GetId()); SetInstanceId(map->GetInstanceId()); Object::_Create(guidlow, Entry, HIGHGUID_VEHICLE); - if(!InitEntry(Entry)) + if(!InitEntry(Entry, team)) return false; + m_defaultMovementType = IDLE_MOTION_TYPE; + + AIM_Initialize(); + + SetVehicleId(vehicleId); + + SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + + CreatureInfo const *ci = GetCreatureInfo(); + setFaction(team == ALLIANCE ? ci->faction_A : ci->faction_H); + SetMaxHealth(ci->maxhealth); + SelectLevel(ci); + SetHealth(GetMaxHealth()); + return true; } diff --git a/src/game/Vehicle.h b/src/game/Vehicle.h index 75ff3375c..0479d96f8 100644 --- a/src/game/Vehicle.h +++ b/src/game/Vehicle.h @@ -32,12 +32,16 @@ class Vehicle : public Creature void AddToWorld(); void RemoveFromWorld(); - bool Create (uint32 guidlow, Map *map, uint32 Entry); + bool Create (uint32 guidlow, Map *map, uint32 Entry, uint32 vehicleId, uint32 team); void setDeathState(DeathState s); // overwrite virtual Creature::setDeathState and Unit::setDeathState void Update(uint32 diff); // overwrite virtual Creature::Update and Unit::Update + uint32 GetVehicleId() { return m_vehicleId; } + void SetVehicleId(uint32 vehicleid) { m_vehicleId = vehicleid; } + protected: + uint32 m_vehicleId; private: void SaveToDB(uint32, uint8) // overwrited of Creature::SaveToDB - don't must be called diff --git a/src/game/debugcmds.cpp b/src/game/debugcmds.cpp index b81ad0a63..fe6b88760 100644 --- a/src/game/debugcmds.cpp +++ b/src/game/debugcmds.cpp @@ -31,6 +31,7 @@ #include "Language.h" #include "MapManager.h" #include +#include "ObjectMgr.h" bool ChatHandler::HandleDebugInArcCommand(const char* /*args*/) { @@ -518,3 +519,45 @@ bool ChatHandler::HandleGetItemState(const char* args) return true; } + +bool ChatHandler::HandleSpawnVehicle(const char* args) +{ + if(!args) + return false; + + char* e = strtok((char*)args, " "); + char* i = strtok(NULL, " "); + + if (!e || !i) + return false; + + uint32 entry = (uint32)atoi(e); + uint32 id = (uint32)atoi(i); + + // TODO: check entry, id... + + Vehicle *v = new Vehicle; + Map *map = m_session->GetPlayer()->GetMap(); + if(!v->Create(objmgr.GenerateLowGuid(HIGHGUID_VEHICLE), map, entry, id, m_session->GetPlayer()->GetTeam())) + { + delete v; + return false; + } + + float px, py, pz; + m_session->GetPlayer()->GetClosePoint(px, py, pz, m_session->GetPlayer()->GetObjectSize()); + + v->Relocate(px, py, pz, m_session->GetPlayer()->GetOrientation()); + + if(!v->IsPositionValid()) + { + sLog.outError("ERROR: Vehicle (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)", + v->GetGUIDLow(), v->GetEntry(), v->GetPositionX(), v->GetPositionY()); + delete v; + return false; + } + + map->Add((Creature*)v); + + return true; +}