diff options
Diffstat (limited to 'src/game/Vehicle.cpp')
-rw-r--r-- | src/game/Vehicle.cpp | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/src/game/Vehicle.cpp b/src/game/Vehicle.cpp new file mode 100644 index 00000000000..dee2a57a1fa --- /dev/null +++ b/src/game/Vehicle.cpp @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "Common.h" +#include "Log.h" +#include "ObjectMgr.h" +#include "Vehicle.h" +#include "Unit.h" +#include "Util.h" +#include "WorldPacket.h" + +#include "Chat.h" + +Vehicle::Vehicle() : Creature(), m_vehicleInfo(NULL) +{ + m_summonMask |= SUMMON_MASK_VEHICLE; + m_updateFlag = (UPDATEFLAG_LOWGUID | UPDATEFLAG_HIGHGUID | UPDATEFLAG_LIVING | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_VEHICLE); +} + +Vehicle::~Vehicle() +{ +} + +void Vehicle::AddToWorld() +{ + if(!IsInWorld()) + { + ObjectAccessor::Instance().AddObject(this); + Unit::AddToWorld(); + AIM_Initialize(); + } +} + +void Vehicle::RemoveFromWorld() +{ + if(IsInWorld()) + { + ///- Don't call the function for Creature, normal mobs + totems go in a different storage + Unit::RemoveFromWorld(); + ObjectAccessor::Instance().RemoveObject(this); + } +} + +void Vehicle::setDeathState(DeathState s) // overwrite virtual Creature::setDeathState and Unit::setDeathState +{ + for(SeatMap::iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr) + if(itr->second.passenger) + RemovePassenger(itr->second.passenger); + Creature::setDeathState(s); +} + +void Vehicle::Update(uint32 diff) +{ + Creature::Update(diff); +} + +bool Vehicle::Create(uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 vehicleId, uint32 team) +{ + //sLog.outError("create vehicle begin"); + SetMapId(map->GetId()); + SetInstanceId(map->GetInstanceId()); + + Object::_Create(guidlow, Entry, HIGHGUID_VEHICLE); + + if(!InitEntry(Entry, team)) + return false; + + m_defaultMovementType = IDLE_MOTION_TYPE; + + SetVehicleId(vehicleId); + + SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); + + CreatureInfo const *ci = GetCreatureInfo(); + setFaction(team == ALLIANCE ? ci->faction_A : ci->faction_H); + SetMaxHealth(ci->maxhealth); + SelectLevel(ci); + SetHealth(GetMaxHealth()); + + //sLog.outError("create vehicle end"); + return true; +} + +void Vehicle::SetVehicleId(uint32 id) +{ + if(m_vehicleInfo && id == m_vehicleInfo->m_ID) + return; + + VehicleEntry const *ve = sVehicleStore.LookupEntry(id); + if(!ve) + return; + + m_vehicleInfo = ve; + for(SeatMap::iterator itr = m_Seats.begin(); itr != m_Seats.end(); ++itr) + if(itr->second.passenger) + RemovePassenger(itr->second.passenger); + m_Seats.clear(); + + for(uint32 i = 0; i < 8; ++i) + { + uint32 seatId = m_vehicleInfo->m_seatID[i]; + if(seatId) + if(VehicleSeatEntry const *veSeat = sVehicleSeatStore.LookupEntry(seatId)) + m_Seats.insert(std::make_pair(i, VehicleSeat(veSeat))); + } +} + +void Vehicle::AddPassenger(Unit *unit) +{ + sLog.outDebug("Unit %s enter vehicle entry %u id %u dbguid %u", unit->GetName(), GetEntry(), m_vehicleInfo->m_ID, GetDBTableGUIDLow()); + + if(unit->m_Vehicle) + unit->m_Vehicle->RemovePassenger(unit); + unit->m_Vehicle = this; + + Player *player = NULL; + if(unit->GetTypeId() == TYPEID_PLAYER) + player = (Player*)unit; + + SeatMap::iterator seat = m_Seats.begin(); + uint32 seatnum = 0; + if(seat->second.passenger) + { + if(m_Seats.size() <= 1) + return; + seatnum = rand()%(m_Seats.size()-1) + 1; + advance(seat, seatnum); + if(seat->second.passenger) + return; + //RemovePassenger(seat->second.passenger); + } + seat->second.passenger = unit; + + bool driver = (seat == m_Seats.begin()); + + //RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24); + setFaction(unit->getFaction()); + + if(player) + { + player->StopCastingCharm(); + player->StopCastingBindSight(); + + if(driver) + { + player->SetCharm(this, true); + player->SetViewpoint(this, true); + player->SetMover(this); + player->VehicleSpellInitialize(); + } + player->SetClientControl(this, 1); + } + + unit->addUnitState(UNIT_STAT_ONVEHICLE); + unit->Relocate(this); + unit->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + + VehicleSeatEntry const *veSeat = seat->second.seatInfo; + unit->m_movementInfo.t_x = veSeat->m_attachmentOffsetX; + unit->m_movementInfo.t_y = veSeat->m_attachmentOffsetY; + unit->m_movementInfo.t_z = veSeat->m_attachmentOffsetZ; + unit->m_movementInfo.t_o = 0; + unit->m_movementInfo.t_time = 4; + unit->m_movementInfo.t_seat = seat->first; + + WorldPacket data; + if(player) + { + //ChatHandler(player).PSendSysMessage("Enter seat %u %u", veSeat->m_ID, seat->first); + + data.Initialize(SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA, 0); + player->GetSession()->SendPacket(&data); + + player->BuildTeleportAckMsg(&data, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation()); + player->GetSession()->SendPacket(&data); + } + + unit->BuildHeartBeatMsg(&data); + unit->SendMessageToSet(&data, player ? false : true); +} + +void Vehicle::RemovePassenger(Unit *unit) +{ + SeatMap::iterator seat; + for(seat = m_Seats.begin(); seat != m_Seats.end(); ++seat) + { + if(seat->second.passenger == unit) + { + seat->second.passenger = NULL; + break; + } + } + + if(seat == m_Seats.end()) + return; + + sLog.outDebug("Unit %s exit vehicle entry %u id %u dbguid %u", unit->GetName(), GetEntry(), m_vehicleInfo->m_ID, GetDBTableGUIDLow()); + + bool driver = (seat == m_Seats.begin()); + + Player *player = NULL; + if(unit->GetTypeId() == TYPEID_PLAYER) + player = (Player*)unit; + + //SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNK_24); + //setFaction((GetTeam() == ALLIANCE) ? GetCreatureInfo()->faction_A : GetCreatureInfo()->faction_H); + + if(player) + { + if(driver) + { + player->SetCharm(this, false); + player->SetViewpoint(this, false); + player->SetMover(player); + player->SendRemoveControlBar(); + } + player->SetClientControl(player, 1); + } + + unit->clearUnitState(UNIT_STAT_ONVEHICLE); + unit->Relocate(this); + unit->RemoveUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); + unit->m_movementInfo.t_x = 0; + unit->m_movementInfo.t_y = 0; + unit->m_movementInfo.t_z = 0; + unit->m_movementInfo.t_o = 0; + unit->m_movementInfo.t_time = 0; + unit->m_movementInfo.t_seat = 0; + + unit->m_Vehicle = NULL; + + WorldPacket data; + if(player) + { + player->BuildTeleportAckMsg(&data, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation()); + player->GetSession()->SendPacket(&data); + } + + unit->BuildHeartBeatMsg(&data); + unit->SendMessageToSet(&data, player ? false : true); + + // only for flyable vehicles? + //CastSpell(this, 45472, true); // Parachute + + //if(!vehicle->GetDBTableGUIDLow()) + if(GetOwnerGUID() == unit->GetGUID()) + Dismiss(); +} + +void Vehicle::Dismiss() +{ + SendObjectDeSpawnAnim(GetGUID()); + CombatStop(); + CleanupsBeforeDelete(); + AddObjectToRemoveList(); +} + +bool Vehicle::LoadFromDB(uint32 guid, Map *map) +{ + CreatureData const* data = objmgr.GetCreatureData(guid); + + if(!data) + { + sLog.outErrorDb("Creature (GUID: %u) not found in table `creature`, can't load. ",guid); + return false; + } + + uint32 id = 0; + if(const CreatureInfo *cInfo = objmgr.GetCreatureTemplate(data->id)) + id = cInfo->VehicleId; + if(!id || !sVehicleStore.LookupEntry(id)) + return false; + + m_DBTableGuid = guid; + if (map->GetInstanceId() != 0) guid = objmgr.GenerateLowGuid(HIGHGUID_VEHICLE); + + uint16 team = 0; + if(!Create(guid,map,data->phaseMask,data->id,id,team)) + return false; + + Relocate(data->posX,data->posY,data->posZ,data->orientation); + + if(!IsPositionValid()) + { + sLog.outError("Creature (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)",GetGUIDLow(),GetEntry(),GetPositionX(),GetPositionY()); + return false; + } + //We should set first home position, because then AI calls home movement + SetHomePosition(data->posX,data->posY,data->posZ,data->orientation); + + m_respawnradius = data->spawndist; + + m_respawnDelay = data->spawntimesecs; + m_isDeadByDefault = data->is_dead; + m_deathState = m_isDeadByDefault ? DEAD : ALIVE; + + m_respawnTime = objmgr.GetCreatureRespawnTime(m_DBTableGuid,GetInstanceId()); + if(m_respawnTime > time(NULL)) // not ready to respawn + { + m_deathState = DEAD; + if(canFly()) + { + float tz = GetMap()->GetHeight(data->posX,data->posY,data->posZ,false); + if(data->posZ - tz > 0.1) + Relocate(data->posX,data->posY,tz); + } + } + else if(m_respawnTime) // respawn time set but expired + { + m_respawnTime = 0; + objmgr.SaveCreatureRespawnTime(m_DBTableGuid,GetInstanceId(),0); + } + + uint32 curhealth = data->curhealth; + if(curhealth) + { + curhealth = uint32(curhealth*_GetHealthMod(GetCreatureInfo()->rank)); + if(curhealth < 1) + curhealth = 1; + } + + SetHealth(m_deathState == ALIVE ? curhealth : 0); + SetPower(POWER_MANA,data->curmana); + + // checked at creature_template loading + m_defaultMovementType = MovementGeneratorType(data->movementType); + + return true; +} |