Skip to content
This repository has been archived by the owner on Jan 18, 2024. It is now read-only.

Commit

Permalink
Core/Creatures: re-implement temporary summons (WIP)
Browse files Browse the repository at this point in the history
- reworked the summon slot assignment behavior
- isolated controlled summons from charmed units
- dropped old summon type API and replaced it with a all-new version based on the enumerated strings leak
- made summon accessing type- and moronsafe
- converted some pet-related packets to packet class
- implement SPELL_EFFECT_ALLOW_CONTROL_PET
- removed summon despawn behavior type arguments and fully determine it based on summon property flags and static flags
- allow any summon to use levelstats and passive auras if available
  • Loading branch information
Ovahlord committed Sep 25, 2023
1 parent f27bc21 commit 6d22559
Show file tree
Hide file tree
Showing 67 changed files with 2,545 additions and 1,970 deletions.
36 changes: 14 additions & 22 deletions src/server/database/Database/Implementation/CharacterDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"subject, deliver_time, expire_time, money, has_items FROM mail WHERE receiver = ? ", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_MAIL_LIST_ITEMS, "SELECT itemEntry,count FROM item_instance WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_ENUM, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.level, c.zone, c.map, c.position_x, c.position_y, c.position_z, "
"gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, cb.guid, c.slot "
"FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.active = 1 LEFT JOIN guild_member AS gm ON c.guid = gm.guid "
"gm.guildid, c.playerFlags, c.at_login, cp.CreatureId, cp.TamedCreatureId, cp.DisplayId, c.equipmentCache, cb.guid, c.slot "
"FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.Guid AND cp.IsActive = 1 LEFT JOIN guild_member AS gm ON c.guid = gm.guid "
"LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_ENUM_DECLINED_NAME, "SELECT c.guid, c.name, c.race, c.class, c.gender, c.skin, c.face, c.hairStyle, c.hairColor, c.facialStyle, c.level, c.zone, c.map, "
"c.position_x, c.position_y, c.position_z, gm.guildid, c.playerFlags, c.at_login, cp.entry, cp.modelid, cp.level, c.equipmentCache, "
"cb.guid, c.slot, cd.genitive FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.owner AND cp.active = 1 "
"c.position_x, c.position_y, c.position_z, gm.guildid, c.playerFlags, c.at_login, cp.CreatureId, cp.TamedCreatureId, cp.DisplayId, c.equipmentCache, "
"cb.guid, c.slot, cd.genitive FROM characters AS c LEFT JOIN character_pet AS cp ON c.guid = cp.Guid AND cp.IsActive = 1 "
"LEFT JOIN character_declinedname AS cd ON c.guid = cd.guid LEFT JOIN guild_member AS gm ON c.guid = gm.guid "
"LEFT JOIN character_banned AS cb ON c.guid = cb.guid AND cb.active = 1 WHERE c.account = ? AND c.deleteInfos_Name IS NULL", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_FREE_NAME, "SELECT guid, name, at_login FROM characters WHERE guid = ? AND account = ? AND NOT EXISTS (SELECT NULL FROM characters WHERE name = ?)", CONNECTION_ASYNC);
Expand Down Expand Up @@ -611,19 +611,13 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_CALENDAR_INVITE, "DELETE FROM calendar_invites WHERE id = ?", CONNECTION_ASYNC);

// Pet
PrepareStatement(CHAR_SEL_PET_SLOTS, "SELECT owner, slot FROM character_pet WHERE owner = ? AND slot >= ? AND slot <= ? ORDER BY slot", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_PET_SLOTS_DETAIL, "SELECT slot, id, entry, modelid, level, name FROM character_pet WHERE owner = ? AND slot >= ? AND slot <= ? ORDER BY slot", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_PET_ENTRY, "SELECT entry FROM character_pet WHERE owner = ? AND id = ? AND slot >= ? AND slot <= ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_PET_SLOT_BY_ID, "SELECT slot, id, entry FROM character_pet WHERE owner = ? AND id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_PET_SPELL_LIST, "SELECT DISTINCT pet_spell.spell FROM pet_spell, character_pet WHERE character_pet.owner = ? AND character_pet.id = pet_spell.guid AND character_pet.id <> ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_CHAR_PETS, "SELECT id FROM character_pet WHERE owner = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME_BY_OWNER, "DELETE FROM character_pet_declinedname WHERE owner = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME, "DELETE FROM character_pet_declinedname WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
//PrepareStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME_BY_OWNER, "DELETE FROM character_pet_declinedname WHERE Guid = ?", CONNECTION_ASYNC);
//PrepareStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME, "DELETE FROM character_pet_declinedname WHERE PetNumber = ?", CONNECTION_ASYNC);
//PrepareStatement(CHAR_INS_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (PetNumber, Guid, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_PET_AURA, "SELECT casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, base_amount0, base_amount1, base_amount2, maxDuration, remainTime, remainCharges, critChance, applyResilience FROM pet_aura WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_PET_SPELL, "SELECT spell, active FROM pet_spell WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_PET_SPELL_COOLDOWN, "SELECT spell, time, categoryId, categoryEnd FROM pet_spell_cooldown WHERE guid = ? AND time > UNIX_TIMESTAMP()", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_PET_DECLINED_NAME, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_pet_declinedname WHERE owner = ? AND id = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_PET_DECLINED_NAME, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_pet_declinedname WHERE Guid = ? AND PetNumber = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_PET_AURAS, "DELETE FROM pet_aura WHERE guid = ?", CONNECTION_BOTH);
PrepareStatement(CHAR_DEL_PET_SPELLS, "DELETE FROM pet_spell WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_PET_SPELL_COOLDOWNS, "DELETE FROM pet_spell_cooldown WHERE guid = ?", CONNECTION_BOTH);
Expand All @@ -632,14 +626,12 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_INS_PET_SPELL, "INSERT INTO pet_spell (guid, spell, active) VALUES (?, ?, ?)", CONNECTION_BOTH);
PrepareStatement(CHAR_INS_PET_AURA, "INSERT INTO pet_aura (guid, casterGuid, spell, effectMask, recalculateMask, stackCount, amount0, amount1, amount2, "
"base_amount0, base_amount1, base_amount2, maxDuration, remainTime, remainCharges, critChance, applyResilience) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_BOTH);
PrepareStatement(CHAR_DEL_CHAR_PET_BY_OWNER, "DELETE FROM character_pet WHERE owner = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHAR_PET_NAME, "UPDATE character_pet SET name = ?, renamed = 1 WHERE owner = ? AND id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHAR_PET_SLOT_BY_SLOT, "UPDATE character_pet SET slot = ? WHERE owner = ? AND slot = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID, "UPDATE character_pet SET slot = ? WHERE owner = ? AND id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_PET_BY_ID, "DELETE FROM character_pet WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_PET, "INSERT INTO character_pet (id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, active, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHAR_ALL_PETS_DETAIL, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, active, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType FROM character_pet WHERE owner = ? ORDER BY slot", CONNECTION_ASYNC);

PrepareStatement(CHAR_DEL_CHAR_PETS, "DELETE FROM character_pet WHERE Guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_PET, "DELETE FROM character_pet WHERE PetNumber = ?", CONNECTION_BOTH);
PrepareStatement(CHAR_SEL_CHAR_PET, "SELECT PetNumber, CreatureId, TamedCreatureId, DisplayId, SavedHealth, SavedPower, CreatedBySpellId, LastSaveTime, ReactState, Slot, HasBeenRenamed, IsActive, `Name`, ActionBar FROM character_pet WHERE Guid = ? ORDER BY Slot", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHAR_PET, "UPDATE character_pet SET SavedHealth = ?, SavedPower = ?, LastSaveTime = ?, ReactState = ?, Slot = ?, HasBeenRenamed = ?, IsActive = ?, `Name` = ?, ActionBar = ? WHERE PetNumber = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_CHAR_PET, "INSERT INTO character_pet (Guid, PetNumber, CreatureId, TamedCreatureId, DisplayId, SavedHealth, SavedPower, CreatedBySpellId, LastSaveTime, ReactState, Slot, HasBeenRenamed, IsActive, `Name`, ActionBar) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_BOTH);

// PvPstats
PrepareStatement(CHAR_SEL_PVPSTATS_MAXID, "SELECT MAX(id) FROM pvpstats_battlegrounds", CONNECTION_SYNCH);
Expand Down
23 changes: 6 additions & 17 deletions src/server/database/Database/Implementation/CharacterDatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -529,24 +529,13 @@ enum CharacterDatabaseStatements : uint32
CHAR_DEL_PET_SPELL_BY_SPELL,
CHAR_INS_PET_SPELL,
CHAR_INS_PET_AURA,

CHAR_DEL_PET_SPELLS,
CHAR_DEL_CHAR_PET_BY_OWNER,
CHAR_DEL_CHAR_PET_DECLINEDNAME_BY_OWNER,
CHAR_SEL_PET_SLOTS,
CHAR_SEL_PET_SLOTS_DETAIL,
CHAR_SEL_PET_ENTRY,
CHAR_SEL_PET_SLOT_BY_ID,
CHAR_SEL_PET_SPELL_LIST,
CHAR_SEL_CHAR_PETS,
CHAR_DEL_CHAR_PET_DECLINEDNAME,
CHAR_INS_CHAR_PET_DECLINEDNAME,
CHAR_UPD_CHAR_PET_NAME,
CHAR_UPD_CHAR_PET_SLOT_BY_SLOT,
CHAR_UPD_CHAR_PET_SLOT_BY_ID,
CHAR_DEL_CHAR_PET_BY_ID,
CHAR_INS_PET,
CHAR_SEL_CHAR_ALL_PETS_DETAIL,

CHAR_INS_CHAR_PET,
CHAR_DEL_CHAR_PET,
CHAR_DEL_CHAR_PETS,
CHAR_UPD_CHAR_PET,
CHAR_SEL_CHAR_PET,

CHAR_SEL_ITEMCONTAINER_ITEMS,
CHAR_DEL_ITEMCONTAINER_ITEMS,
Expand Down
56 changes: 9 additions & 47 deletions src/server/game/AI/CreatureAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "SpellMgr.h"
#include "SpellHistory.h"
#include "TemporarySummon.h"
#include "NewTemporarySummon.h"
#include "Vehicle.h"
#include "World.h"

Expand Down Expand Up @@ -93,9 +94,6 @@ void CreatureAI::DoZoneInCombat(Creature* creature /*= nullptr*/)

creature->EngageWithTarget(player);

for (Unit* pet : player->m_Controlled)
creature->EngageWithTarget(pet);

if (Unit* vehicle = player->GetVehicleBase())
creature->EngageWithTarget(vehicle);
}
Expand Down Expand Up @@ -155,56 +153,20 @@ void CreatureAI::TriggerAlert(Unit const* who) const
me->SetFacingTo(me->GetAngle(who));
}

// adapted from logic in Spell:EFfectSummonType before commit 8499434
static bool ShouldFollowOnSpawn(SummonPropertiesEntry const* properties)
{
// Summons without SummonProperties are generally scripted summons that don't belong to any owner
if (!properties)
return false;

switch (properties->Control)
{
case SUMMON_CATEGORY_PET:
return true;
case SUMMON_CATEGORY_WILD:
case SUMMON_CATEGORY_ALLY:
case SUMMON_CATEGORY_UNK:
if (properties->Flags & 512)
return true;

// Guides. They have their own movement
if (properties->Flags & SUMMON_PROP_FLAG_UNK14)
return false;

switch (SummonTitle(properties->Title))
{
case SummonTitle::Pet:
case SummonTitle::Guardian:
case SummonTitle::Runeblade:
case SummonTitle::Minion:
case SummonTitle::Companion:
return true;
default:
return false;
}
default:
return false;
}
}
void CreatureAI::JustAppeared()
{
if (!IsEngaged())
{
if (TempSummon* summon = me->ToTempSummon())
if (!me->IsSummon())
return;

NewTemporarySummon* summon = me->ToTemporarySummon();
if (summon->ShouldJoinSummonerSpawnGroupAfterCreation() || summon->ShouldFollowSummonerAfterCreation() && !summon->GetVehicle())
{
// Only apply this to specific types of summons
if (!summon->GetVehicle() && ShouldFollowOnSpawn(summon->m_Properties))
if (Unit* summoner = summon->GetSummoner())
{
if (Unit* owner = summon->GetCharmerOrOwner())
{
summon->GetMotionMaster()->Clear();
summon->FollowTarget(owner);
}
summon->GetMotionMaster()->Clear();
summon->FollowTarget(summoner); // @todo: ShouldJoinSummonerSpawnGroupAfterCreation should actually make the creature join the target's formation
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/server/game/AI/CreatureAISelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ namespace FactorySelector
CreatureAI* SelectAI(Creature* creature)
{
// special pet case, if a tamed creature uses AIName (example SmartAI) we need to override it
if (creature->IsPet())
return ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PetAI"))->Create(creature);
//if (creature->IsPet())
// return ASSERT_NOTNULL(sCreatureAIRegistry->GetRegistryItem("PetAI"))->Create(creature);

// scriptname in db
try
Expand Down
4 changes: 2 additions & 2 deletions src/server/game/Battlegrounds/Battleground.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,7 @@ void Battleground::RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool Sen
bgTypeId = BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing)

// unsummon current and summon old pet if there was one and there isn't a current pet
player->RemovePet(nullptr, PET_SAVE_DISMISS); player->ResummonPetTemporaryUnSummonedIfAny();
//player->RemovePet(nullptr, PET_SAVE_DISMISS); player->ResummonPetTemporaryUnSummonedIfAny();
}

if (SendPacket)
Expand Down Expand Up @@ -1117,7 +1117,7 @@ void Battleground::AddPlayer(Player* player)
{
player->RemoveArenaEnchantments(TEMP_ENCHANTMENT_SLOT);
player->DestroyConjuredItems(true);
player->UnsummonPetTemporaryIfAny();
//player->UnsummonPetTemporaryIfAny();

if (GetStatus() == STATUS_WAIT_JOIN) // not started yet
{
Expand Down
43 changes: 21 additions & 22 deletions src/server/game/DataStores/DBCEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -679,31 +679,30 @@ enum class SummonPropertiesSlot : int8
AnyAvailableTotem = -1
};

// SummonProperties.dbc, col 5
enum class SummonPropertiesFlags : uint32
{
None = 0x000000,
AttackSummoner = 0x000001,
HelpWhenSummonedInCombat = 0x000002,
UseLevelOffset = 0x000004,
DespawnOnSummonerDeath = 0x000008,
OnlyVisibleToSummoner = 0x000010,
CannotDismissPet = 0x000020,
UseDemonTimeout = 0x000040,
UnlimitedSummons = 0x000080,
UseCreatureLevel = 0x000100,
JoinSummonerSpawnGroup = 0x000200,
DoNotToggle = 0x000400,
DespawnWhenExpired = 0x000800,
UseSummonerFaction = 0x001000,
DoNotFollowMountedSummoner = 0x002000,
SavePetAutocast = 0x004000,
IgnoreSummonerPhase = 0x008000,
OnlyVisibleToSummonerGroup = 0x010000,
DespawnOnSummonerLogout = 0x020000,
CastRideVehicleSpellOnSummoner = 0x040000,
GuardianActsLikePet = 0x080000,
DontSnapSessileToGround = 0x100000
AttackSummoner = 0x000001, // Implemented in TemporarySummon::HandlePostSummonActions
HelpWhenSummonedInCombat = 0x000002, // Implemented in TemporarySummon::HandlePostSummonActions
UseLevelOffset = 0x000004, // NYI
DespawnOnSummonerDeath = 0x000008, // Implemented in Unit::UnsummonAllSummonsDueToDeath
OnlyVisibleToSummoner = 0x000010, // Implemented in Spell::EffectSummonType
CannotDismissPet = 0x000020, // Implemented in PetHandler.cpp HandlePetActionHelper
UseDemonTimeout = 0x000040, // NYI
UnlimitedSummons = 0x000080, // NYI
UseCreatureLevel = 0x000100, // Implemented in TemporarySummon::HandlePreSummonActions
JoinSummonerSpawnGroup = 0x000200, // Implemented in CreatureAI::JustAppeared
DoNotToggle = 0x000400, // NYI
DespawnWhenExpired = 0x000800, // Implemented in TemporarySummon::Update
UseSummonerFaction = 0x001000, // Implemented in TemporarySummon::HandlePreSummonActions
DoNotFollowMountedSummoner = 0x002000, // NYI
SavePetAutocast = 0x004000, // NYI
IgnoreSummonerPhase = 0x008000, // Wild Only - Implemented in Map::SummonCreature
OnlyVisibleToSummonerGroup = 0x010000, // Implemented in Spell::EffectSummonType
DespawnOnSummonerLogout = 0x020000, // Implemented in Unit::UnsummonAllSummonsOnLogout
CastRideVehicleSpellOnSummoner = 0x040000, // NYI
GuardianActsLikePet = 0x080000, // NYI - unused 4.3.4.15595
DontSnapSessileToGround = 0x100000 // NYI
};

DEFINE_ENUM_FLAG(SummonPropertiesFlags);
Expand Down
4 changes: 0 additions & 4 deletions src/server/game/DataStores/DBCStores.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -637,10 +637,6 @@ void DBCManager::LoadStores(const std::string& dataPath, uint32 defaultLocale)
if (!spellInfo)
continue;

SpellLevelsEntry const* levels = sSpellLevelsStore.LookupEntry(spellInfo->LevelsID);
if (spellInfo->LevelsID && (!levels || levels->SpellLevel))
continue;

if (spellInfo && spellInfo->Attributes & SPELL_ATTR0_PASSIVE)
{
for (CreatureFamilyEntry const* cFamily : sCreatureFamilyStore)
Expand Down
16 changes: 7 additions & 9 deletions src/server/game/Entities/Creature/Creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#include "SpellAuraEffects.h"
#include "SpellMgr.h"
#include "TemporarySummon.h"
#include "NewTemporarySummon.h"
#include "Transport.h"
#include "Util.h"
#include "Vehicle.h"
Expand Down Expand Up @@ -454,6 +455,12 @@ void Creature::RemoveCorpse(bool setSpawnTime, bool destroyForNearbyPlayers)
SaveRespawnTime();
}

if (NewTemporarySummon* summon = ToTemporarySummon())
{
summon->Unsummon();
return;
}

if (TempSummon* summon = ToTempSummon())
summon->UnSummon();
else
Expand Down Expand Up @@ -1083,15 +1090,6 @@ Unit* Creature::SelectVictim()
target = owner->getAttackerForHelper();
if (!target)
{
for (ControlList::const_iterator itr = owner->m_Controlled.begin(); itr != owner->m_Controlled.end(); ++itr)
{
if ((*itr)->IsInCombat())
{
target = (*itr)->getAttackerForHelper();
if (target)
break;
}
}
}
}
}
Expand Down
Loading

0 comments on commit 6d22559

Please sign in to comment.