Hunter fixes (#126)
* Hunter fixes -RevivePet will now properly revive the pet -CallPet will detect if the pet is dead; TODO: what if the pet is dismissed or stabled? -Player who TeleportTo will not carry the corpse of the dead pet with him * Correction: summoners' pets are always saved alive into db * Minor corrections -Now CallPet detects if the hunter doesn't have a current pet, spawned or not
This commit is contained in:
parent
6bc64bf5c4
commit
6a947449c3
@ -523,7 +523,7 @@ class WorldObject : public Object
|
||||
void GetClosePoint(float& x, float& y, float& z, float bounding_radius, float distance2d = 0.0f, float angle = 0.0f, const WorldObject* obj = NULL) const
|
||||
{
|
||||
// angle calculated from current orientation
|
||||
GetNearPoint(obj, x, y, z, bounding_radius, distance2d + GetObjectBoundingRadius() + bounding_radius, GetOrientation() + angle);
|
||||
GetNearPoint(obj, x, y, z, bounding_radius, distance2d, GetOrientation() + angle);
|
||||
}
|
||||
/** Gives a "free" spot for a searcher in contact-range of "this" (including bounding-radius calculation)
|
||||
* @param x, y, z - position for the found spot
|
||||
|
@ -254,9 +254,9 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
|
||||
uint32 savedpower = fields[14].GetUInt32();
|
||||
|
||||
// set current pet as current
|
||||
// 0=current
|
||||
// 1..MAX_PET_STABLES in stable slot
|
||||
// PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning))
|
||||
// 0 = current
|
||||
// 1..MAX_PET_STABLES = in stable slot
|
||||
// PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning) or hunter pet dead
|
||||
if (fields[10].GetUInt32() != 0)
|
||||
{
|
||||
CharacterDatabase.BeginTransaction();
|
||||
@ -327,6 +327,10 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petentry, uint32 petnumber, bool c
|
||||
{
|
||||
SetHealth(savedhealth > GetMaxHealth() ? GetMaxHealth() : savedhealth);
|
||||
SetPower(powerType, savedpower > GetMaxPower(powerType) ? GetMaxPower(powerType) : savedpower);
|
||||
|
||||
if (getPetType() == HUNTER_PET && savedhealth == 0)
|
||||
SetDeathState(JUST_DIED);
|
||||
|
||||
}
|
||||
|
||||
AIM_Initialize();
|
||||
@ -390,6 +394,13 @@ void Pet::SavePetToDB(PetSaveMode mode)
|
||||
}
|
||||
|
||||
uint32 curhealth = GetHealth();
|
||||
|
||||
if (getPetType() != HUNTER_PET)
|
||||
{
|
||||
if (curhealth < 1)
|
||||
curhealth = 1;
|
||||
}
|
||||
|
||||
uint32 curpower = GetPower(GetPowerType());
|
||||
|
||||
// stable and not in slot saves
|
||||
@ -450,7 +461,7 @@ void Pet::SavePetToDB(PetSaveMode mode)
|
||||
savePet.addUInt32(uint32(mode));
|
||||
savePet.addString(m_name);
|
||||
savePet.addUInt32(uint32(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_RENAME) ? 0 : 1));
|
||||
savePet.addUInt32((curhealth < 1 ? 1 : curhealth));
|
||||
savePet.addUInt32((curhealth));
|
||||
savePet.addUInt32(curpower);
|
||||
savePet.addUInt32(GetPower(POWER_HAPPINESS));
|
||||
|
||||
@ -551,7 +562,11 @@ void Pet::Update(uint32 update_diff, uint32 diff)
|
||||
{
|
||||
case CORPSE:
|
||||
{
|
||||
Unsummon(PET_SAVE_NOT_IN_SLOT);
|
||||
if (getPetType() != HUNTER_PET || m_corpseRemoveTime <= time(NULL))
|
||||
{
|
||||
Unsummon(PET_SAVE_NOT_IN_SLOT);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ALIVE:
|
||||
@ -986,7 +1001,6 @@ bool Pet::CreateBaseAtCreature(Creature* creature)
|
||||
|
||||
uint32 guid = creature->GetMap()->GenerateLocalLowGuid(HIGHGUID_PET);
|
||||
|
||||
BASIC_LOG("Create pet");
|
||||
uint32 pet_number = sObjectMgr.GeneratePetNumber();
|
||||
if (!Create(guid, pos, creature->GetCreatureInfo(), pet_number))
|
||||
{ return false; }
|
||||
@ -2137,3 +2151,44 @@ void Pet::UpdateSpeed(UnitMoveType mtype, bool forced, float ratio)
|
||||
|
||||
SetSpeedRate(mtype, speed * ratio, forced);
|
||||
}
|
||||
|
||||
PetDatabaseStatus Pet::GetStatusFromDB(Player* owner)
|
||||
{
|
||||
PetDatabaseStatus status = PET_DB_NO_PET;
|
||||
|
||||
uint32 ownerid = owner->GetGUIDLow();
|
||||
|
||||
QueryResult* result;
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
||||
result = CharacterDatabase.PQuery("SELECT id, entry, owner, modelid, level, exp, Reactstate, loyaltypoints, loyalty, trainpoint, slot, name, renamed, curhealth, curmana, curhappiness, abdata, TeachSpelldata, savetime, resettalents_cost, resettalents_time, CreatedBySpell, PetType "
|
||||
"FROM character_pet WHERE owner = '%u' AND (slot = '%u') ",
|
||||
ownerid, PET_SAVE_AS_CURRENT);
|
||||
if (!result)
|
||||
{ return status; }
|
||||
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 petentry = fields[1].GetUInt32();
|
||||
|
||||
if (!petentry)
|
||||
{
|
||||
delete result;
|
||||
return status;
|
||||
}
|
||||
|
||||
CreatureInfo const* creatureInfo = ObjectMgr::GetCreatureTemplate(petentry);
|
||||
if (!creatureInfo)
|
||||
{
|
||||
delete result;
|
||||
return status;
|
||||
}
|
||||
|
||||
uint32 savedHP = fields[13].GetUInt32();
|
||||
delete result;
|
||||
if (savedHP > 0)
|
||||
status = PET_DB_ALIVE;
|
||||
else
|
||||
status = PET_DB_DEAD;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -52,6 +52,13 @@ enum PetSaveMode
|
||||
PET_SAVE_REAGENTS = 101 // PET_SAVE_NOT_IN_SLOT with reagents return
|
||||
};
|
||||
|
||||
enum PetDatabaseStatus
|
||||
{
|
||||
PET_DB_NO_PET = 0,
|
||||
PET_DB_DEAD = 1,
|
||||
PET_DB_ALIVE = 2,
|
||||
};
|
||||
|
||||
// There might be a lot more
|
||||
enum PetModeFlags
|
||||
{
|
||||
@ -174,7 +181,9 @@ class Pet : public Creature
|
||||
bool LoadPetFromDB(Player* owner, uint32 petentry = 0, uint32 petnumber = 0, bool current = false);
|
||||
void SavePetToDB(PetSaveMode mode);
|
||||
void Unsummon(PetSaveMode mode, Unit* owner = NULL);
|
||||
|
||||
static void DeleteFromDB(uint32 guidlow, bool separate_transaction = true);
|
||||
static PetDatabaseStatus GetStatusFromDB(Player*);
|
||||
|
||||
void SetDeathState(DeathState s) override; // overwrite virtual Creature::SetDeathState and Unit::SetDeathState
|
||||
void Update(uint32 update_diff, uint32 diff) override; // overwrite virtual Creature::Update and Unit::Update
|
||||
|
@ -1609,8 +1609,21 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
|
||||
if (!(options & TELE_TO_NOT_UNSUMMON_PET))
|
||||
{
|
||||
// same map, only remove pet if out of range for new position
|
||||
if (pet && !pet->IsWithinDist3d(x, y, z, GetMap()->GetVisibilityDistance()))
|
||||
{ UnsummonPetTemporaryIfAny(); }
|
||||
if (pet)
|
||||
{
|
||||
if (!pet->IsWithinDist3d(x, y, z, GetMap()->GetVisibilityDistance()))
|
||||
{
|
||||
if (pet->IsAlive())
|
||||
{
|
||||
UnsummonPetTemporaryIfAny();
|
||||
}
|
||||
else
|
||||
{
|
||||
pet->Unsummon(PET_SAVE_NOT_IN_SLOT);
|
||||
pet = GetPet();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(options & TELE_TO_NOT_LEAVE_COMBAT))
|
||||
@ -1678,8 +1691,17 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
|
||||
|
||||
// remove pet on map change
|
||||
if (pet)
|
||||
{ UnsummonPetTemporaryIfAny(); }
|
||||
|
||||
{
|
||||
if (pet->IsAlive())
|
||||
{
|
||||
UnsummonPetTemporaryIfAny();
|
||||
}
|
||||
else
|
||||
{
|
||||
pet->Unsummon(PET_SAVE_NOT_IN_SLOT);
|
||||
pet = GetPet();
|
||||
}
|
||||
}
|
||||
// remove all dyn objects
|
||||
RemoveAllDynObjects();
|
||||
|
||||
|
@ -2087,6 +2087,7 @@ bool Map::GetHeightInRange(float x, float y, float& z, float maxSearchDist /*= 4
|
||||
{
|
||||
float height, vmapHeight, mapHeight;
|
||||
vmapHeight = VMAP_INVALID_HEIGHT_VALUE;
|
||||
mapHeight = INVALID_HEIGHT_VALUE;
|
||||
|
||||
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
||||
if (!vmgr->isLineOfSightCalcEnabled())
|
||||
|
@ -5028,12 +5028,26 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
case SPELL_EFFECT_SUMMON_DEAD_PET:
|
||||
{
|
||||
Creature* pet = m_caster->GetPet();
|
||||
if (!pet)
|
||||
{ return SPELL_FAILED_NO_PET; }
|
||||
|
||||
if (pet->IsAlive())
|
||||
if (pet && pet->IsAlive())
|
||||
{ return SPELL_FAILED_ALREADY_HAVE_SUMMON; }
|
||||
|
||||
if (!pet)
|
||||
{
|
||||
if (Player* player = m_caster->ToPlayer())
|
||||
{
|
||||
PetDatabaseStatus status = Pet::GetStatusFromDB(player);
|
||||
if (status == PET_DB_NO_PET)
|
||||
return SPELL_FAILED_NO_PET;
|
||||
else if (status == PET_DB_ALIVE)
|
||||
return SPELL_FAILED_TARGET_NOT_DEAD;
|
||||
}
|
||||
else
|
||||
{
|
||||
return SPELL_FAILED_NO_PET;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
// Don't make this check for SPELL_EFFECT_SUMMON_CRITTER, SPELL_EFFECT_SUMMON_WILD or SPELL_EFFECT_SUMMON_GUARDIAN.
|
||||
@ -5053,22 +5067,27 @@ SpellCastResult Spell::CheckCast(bool strict)
|
||||
}
|
||||
case SPELL_EFFECT_SUMMON_PET:
|
||||
{
|
||||
Player* plr = m_caster->ToPlayer();
|
||||
if (m_caster->GetPetGuid()) // let warlock do a replacement summon
|
||||
{
|
||||
Pet* pet = ((Player*)m_caster)->GetPet();
|
||||
Pet* pet = m_caster->GetPet();
|
||||
|
||||
if (m_caster->GetTypeId() == TYPEID_PLAYER && m_caster->getClass() == CLASS_WARLOCK)
|
||||
{
|
||||
if (strict) // Summoning Disorientation, trigger pet stun (cast by pet so it doesn't attack player)
|
||||
{ pet->CastSpell(pet, 32752, true, NULL, NULL, pet->GetObjectGuid()); }
|
||||
}
|
||||
else
|
||||
if (plr && m_caster->getClass() != CLASS_WARLOCK)
|
||||
{ return SPELL_FAILED_ALREADY_HAVE_SUMMON; }
|
||||
}
|
||||
|
||||
if (m_caster->GetCharmGuid())
|
||||
{ return SPELL_FAILED_ALREADY_HAVE_CHARM; }
|
||||
|
||||
if (plr)
|
||||
{
|
||||
PetDatabaseStatus status = Pet::GetStatusFromDB(plr);
|
||||
if (status == PET_DB_DEAD)
|
||||
return SPELL_FAILED_TARGETS_DEAD;
|
||||
else if ((plr->getClass() == CLASS_HUNTER) && (status == PET_DB_NO_PET))
|
||||
return SPELL_FAILED_NO_PET;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SPELL_EFFECT_SUMMON_PLAYER:
|
||||
|
@ -4884,16 +4884,41 @@ void Spell::EffectDispelMechanic(SpellEffectIndex eff_idx)
|
||||
|
||||
void Spell::EffectSummonDeadPet(SpellEffectIndex /*eff_idx*/)
|
||||
{
|
||||
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
||||
Player* _player = m_caster->ToPlayer();
|
||||
|
||||
if (!_player || damage < 0)
|
||||
{ return; }
|
||||
Player* _player = (Player*)m_caster;
|
||||
|
||||
Pet* pet = _player->GetPet();
|
||||
if (!pet)
|
||||
{ return; }
|
||||
if (pet->IsAlive())
|
||||
{ return; }
|
||||
if (damage < 0)
|
||||
{ return; }
|
||||
|
||||
bool hadPet = true;
|
||||
|
||||
if (pet)
|
||||
{
|
||||
if (pet->IsAlive())
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Pet* newPet = new Pet;
|
||||
if (!newPet->LoadPetFromDB(_player))
|
||||
{
|
||||
delete newPet;
|
||||
return;
|
||||
}
|
||||
hadPet = false;
|
||||
}
|
||||
|
||||
pet = _player->GetPet();
|
||||
if (!pet || pet->IsAlive())
|
||||
return;
|
||||
|
||||
if (hadPet)
|
||||
{
|
||||
float px, py, pz;
|
||||
_player->GetClosePoint(px, py, pz, pet->GetObjectBoundingRadius(), _player->GetObjectBoundingRadius());
|
||||
pet->NearTeleportTo(px, py, pz, PET_FOLLOW_ANGLE);
|
||||
}
|
||||
|
||||
pet->SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE);
|
||||
pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
|
||||
|
Loading…
x
Reference in New Issue
Block a user