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:
H0zen 2016-05-20 23:26:37 +03:00 committed by Antz
parent 6bc64bf5c4
commit 6a947449c3
7 changed files with 160 additions and 29 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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();

View File

@ -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())

View File

@ -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:

View File

@ -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);