Core/Achievements: Implemented ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS

This commit is contained in:
Shauren
2011-05-14 12:26:49 +02:00
parent b71b2896b6
commit 24a8cc24da
7 changed files with 198 additions and 91 deletions
@@ -101,6 +101,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL:
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: // only Children's Week achievements
case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: // only Children's Week achievements
case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
break;
default:
sLog->outErrorDb("Table `achievement_criteria_data` has data for non-supported criteria type (Entry: %u Type: %u), ignored.", criteria->ID, criteria->requiredType);
@@ -1479,10 +1480,12 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
}
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL:
case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL:
case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
{
// skip login update
if (!miscValue1)
continue;
// those requirements couldn't be found in the dbc
AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
if (!data || !data->Meets(GetPlayer(), unit))
@@ -1540,7 +1543,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA:
case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA:
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK:
case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
case ACHIEVEMENT_CRITERIA_TYPE_EARNED_PVP_TITLE:
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE:
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL:
@@ -1695,6 +1697,8 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
return progress->counter >= 9000;
case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS:
return progress->counter >= achievementCriteria->use_lfg.dungeonsComplete;
case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
return progress->counter >= achievementCriteria->get_killing_blow.killCount;
// handle all statistic-only criteria here
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND:
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
@@ -2327,6 +2331,8 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
continue;
break;
}
case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS:
break;
default: // type not use DB data, ignore
continue;
}
+7 -1
View File
@@ -371,13 +371,19 @@ struct AchievementCriteriaEntry
} do_emote;
// ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE = 13
// ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE = 55
// ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56
struct
{
uint32 unused; // 3
uint32 count; // 4
} healing_done;
// ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS = 56
struct
{
uint32 unused;
uint32 killCount;
} get_killing_blow;
// ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM = 57
struct
{
+88 -87
View File
@@ -15127,44 +15127,44 @@ bool Unit::HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura)
return true;
}
void Unit::Kill(Unit *pVictim, bool durabilityLoss)
void Unit::Kill(Unit* victim, bool durabilityLoss)
{
// Prevent killing unit twice (and giving reward from kill twice)
if (!pVictim->GetHealth())
if (!victim->GetHealth())
return;
// Inform pets (if any) when player kills target)
if (this->ToPlayer())
if (Player* plr = this->ToPlayer())
{
Pet *pPet = this->ToPlayer()->GetPet();
if (pPet && pPet->isAlive() && pPet->isControlled())
pPet->AI()->KilledUnit(pVictim);
Pet* pet = plr->GetPet();
if (pet && pet->isAlive() && pet->isControlled())
pet->AI()->KilledUnit(victim);
}
// find player: owner of controlled `this` or `this` itself maybe
Player *player = GetCharmerOrOwnerPlayerOrPlayerItself();
Creature *creature = pVictim->ToCreature();
Player* player = GetCharmerOrOwnerPlayerOrPlayerItself();
Creature* creature = victim->ToCreature();
bool bRewardIsAllowed = true;
bool isRewardAllowed = true;
if (creature)
{
bRewardIsAllowed = creature->IsDamageEnoughForLootingAndReward();
if (!bRewardIsAllowed)
isRewardAllowed = creature->IsDamageEnoughForLootingAndReward();
if (!isRewardAllowed)
creature->SetLootRecipient(NULL);
}
if (bRewardIsAllowed && creature && creature->GetLootRecipient())
if (isRewardAllowed && creature && creature->GetLootRecipient())
player = creature->GetLootRecipient();
// Reward player, his pets, and group/raid members
// call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
if (bRewardIsAllowed && player && player != pVictim)
if (isRewardAllowed && player && player != victim)
{
WorldPacket data(SMSG_PARTYKILLLOG, (8+8)); //send event PARTY_KILL
data << uint64(player->GetGUID()); //player with killing blow
data << uint64(pVictim->GetGUID()); //victim
data << uint64(victim->GetGUID()); //victim
Player* pLooter = player;
Player* looter = player;
if (Group *group = player->GetGroup())
{
@@ -15175,11 +15175,11 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
group->UpdateLooterGuid(creature, true);
if (group->GetLooterGuid())
{
pLooter = sObjectMgr->GetPlayer(group->GetLooterGuid());
if (pLooter)
looter = sObjectMgr->GetPlayer(group->GetLooterGuid());
if (looter)
{
creature->SetLootRecipient(pLooter); // update creature loot recipient to the allowed looter.
group->SendLooter(creature, pLooter);
creature->SetLootRecipient(looter); // update creature loot recipient to the allowed looter.
group->SendLooter(creature, looter);
}
else
group->SendLooter(creature, NULL);
@@ -15196,7 +15196,7 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
if (creature)
{
WorldPacket data2(SMSG_LOOT_LIST, (8+1+1));
WorldPacket data2(SMSG_LOOT_LIST, 8 + 1 + 1);
data2 << uint64(creature->GetGUID());
data2 << uint8(0); // unk1
data2 << uint8(0); // no group looter
@@ -15212,85 +15212,90 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
loot->clear();
if (uint32 lootid = creature->GetCreatureInfo()->lootid)
loot->FillLoot(lootid, LootTemplates_Creature, pLooter, false, false, creature->GetLootMode());
loot->FillLoot(lootid, LootTemplates_Creature, looter, false, false, creature->GetLootMode());
loot->generateMoneyLoot(creature->GetCreatureInfo()->mingold, creature->GetCreatureInfo()->maxgold);
}
player->RewardPlayerAndGroupAtKill(pVictim, false);
player->RewardPlayerAndGroupAtKill(victim, false);
}
// Do KILL and KILLED procs. KILL proc is called only for the unit who landed the killing blow (and its owner - for pets and totems) regardless of who tapped the victim
if (isPet() || isTotem())
if (Unit *owner = GetOwner())
owner->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0);
if (Unit* owner = GetOwner())
owner->ProcDamageAndSpell(victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0);
if (pVictim->GetCreatureType() != CREATURE_TYPE_CRITTER)
ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
if (victim->GetCreatureType() != CREATURE_TYPE_CRITTER)
ProcDamageAndSpell(victim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
// Proc auras on death - must be before aura/combat remove
pVictim->ProcDamageAndSpell(NULL, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, BASE_ATTACK, 0);
victim->ProcDamageAndSpell(NULL, PROC_FLAG_DEATH, PROC_FLAG_NONE, PROC_EX_NONE, 0, BASE_ATTACK, 0);
// update get killing blow achievements, must be done before setDeathState to be able to require auras on target
// and before Spirit of Redemption as it also removes auras
if (player)
player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, 1, 0, victim);
// if talent known but not triggered (check priest class for speedup check)
bool SpiritOfRedemption = false;
if (pVictim->GetTypeId() == TYPEID_PLAYER && pVictim->getClass() == CLASS_PRIEST)
bool spiritOfRedemption = false;
if (victim->GetTypeId() == TYPEID_PLAYER && victim->getClass() == CLASS_PRIEST)
{
AuraEffectList const& vDummyAuras = pVictim->GetAuraEffectsByType(SPELL_AURA_DUMMY);
for (AuraEffectList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); ++itr)
AuraEffectList const& dummyAuras = victim->GetAuraEffectsByType(SPELL_AURA_DUMMY);
for (AuraEffectList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
{
if ((*itr)->GetSpellProto()->SpellIconID == 1654)
{
AuraEffect * aurEff = *itr;
AuraEffect const* aurEff = *itr;
// save value before aura remove
uint32 ressSpellId = pVictim->GetUInt32Value(PLAYER_SELF_RES_SPELL);
uint32 ressSpellId = victim->GetUInt32Value(PLAYER_SELF_RES_SPELL);
if (!ressSpellId)
ressSpellId = pVictim->ToPlayer()->GetResurrectionSpellId();
ressSpellId = victim->ToPlayer()->GetResurrectionSpellId();
//Remove all expected to remove at death auras (most important negative case like DoT or periodic triggers)
pVictim->RemoveAllAurasOnDeath();
victim->RemoveAllAurasOnDeath();
// restore for use at real death
pVictim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId);
victim->SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId);
// FORM_SPIRITOFREDEMPTION and related auras
pVictim->CastSpell(pVictim, 27827, true, NULL, aurEff);
SpiritOfRedemption = true;
victim->CastSpell(victim, 27827, true, NULL, aurEff);
spiritOfRedemption = true;
break;
}
}
}
if (!SpiritOfRedemption)
if (!spiritOfRedemption)
{
sLog->outStaticDebug("SET JUST_DIED");
pVictim->setDeathState(JUST_DIED);
victim->setDeathState(JUST_DIED);
}
// 10% durability loss on death
// clean InHateListOf
if (pVictim->GetTypeId() == TYPEID_PLAYER)
if (Player* plrVictim = victim->ToPlayer())
{
// remember victim PvP death for corpse type and corpse reclaim delay
// at original death (not at SpiritOfRedemtionTalent timeout)
pVictim->ToPlayer()->SetPvPDeath(player != NULL);
plrVictim->SetPvPDeath(player != NULL);
// only if not player and not controlled by player pet. And not at BG
if ((durabilityLoss && !player && !pVictim->ToPlayer()->InBattleground()) || (player && sWorld->getBoolConfig(CONFIG_DURABILITY_LOSS_IN_PVP)))
if ((durabilityLoss && !player && !victim->ToPlayer()->InBattleground()) || (player && sWorld->getBoolConfig(CONFIG_DURABILITY_LOSS_IN_PVP)))
{
sLog->outStaticDebug("We are dead, losing %f percent durability", sWorld->getRate(RATE_DURABILITY_LOSS_ON_DEATH));
pVictim->ToPlayer()->DurabilityLossAll(sWorld->getRate(RATE_DURABILITY_LOSS_ON_DEATH), false);
plrVictim->DurabilityLossAll(sWorld->getRate(RATE_DURABILITY_LOSS_ON_DEATH), false);
// durability lost message
WorldPacket data(SMSG_DURABILITY_DAMAGE_DEATH, 0);
pVictim->ToPlayer()->GetSession()->SendPacket(&data);
plrVictim->GetSession()->SendPacket(&data);
}
// Call KilledUnit for creatures
if (GetTypeId() == TYPEID_UNIT && this->ToCreature()->IsAIEnabled)
this->ToCreature()->AI()->KilledUnit(pVictim);
if (GetTypeId() == TYPEID_UNIT && IsAIEnabled)
this->ToCreature()->AI()->KilledUnit(victim);
// last damage from non duel opponent or opponent controlled creature
if (pVictim->ToPlayer()->duel)
if (plrVictim->duel)
{
pVictim->ToPlayer()->duel->opponent->CombatStopWithPets(true);
pVictim->ToPlayer()->CombatStopWithPets(true);
pVictim->ToPlayer()->DuelComplete(DUEL_INTERRUPTED);
plrVictim->duel->opponent->CombatStopWithPets(true);
plrVictim->CombatStopWithPets(true);
plrVictim->DuelComplete(DUEL_INTERRUPTED);
}
}
else // creature died
@@ -15306,35 +15311,31 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
}
// Call KilledUnit for creatures, this needs to be called after the lootable flag is set
if (GetTypeId() == TYPEID_UNIT && this->ToCreature()->IsAIEnabled)
this->ToCreature()->AI()->KilledUnit(pVictim);
if (GetTypeId() == TYPEID_UNIT && IsAIEnabled)
this->ToCreature()->AI()->KilledUnit(victim);
// Call creature just died function
if (creature->IsAIEnabled)
creature->AI()->JustDied(this);
if (creature->ToTempSummon())
{
if (Unit* pSummoner = creature->ToTempSummon()->GetSummoner())
{
if (pSummoner->ToCreature() && pSummoner->ToCreature()->IsAIEnabled)
pSummoner->ToCreature()->AI()->SummonedCreatureDies(creature, this);
}
}
if (TempSummon* summon = creature->ToTempSummon())
if (Unit* summoner = summon->GetSummoner())
if (summoner->ToCreature() && summoner->IsAIEnabled)
summoner->ToCreature()->AI()->SummonedCreatureDies(creature, this);
// Dungeon specific stuff, only applies to players killing creatures
if (creature->GetInstanceId())
{
Map *m = creature->GetMap();
Player *creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself();
Map* instanceMap = creature->GetMap();
Player* creditedPlayer = GetCharmerOrOwnerPlayerOrPlayerItself();
// TODO: do instance binding anyway if the charmer/owner is offline
if (m->IsDungeon() && creditedPlayer)
if (instanceMap->IsDungeon() && creditedPlayer)
{
if (m->IsRaidOrHeroicDungeon())
if (instanceMap->IsRaidOrHeroicDungeon())
{
if (creature->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_INSTANCE_BIND)
((InstanceMap *)m)->PermBindAllPlayers(creditedPlayer);
((InstanceMap*)instanceMap)->PermBindAllPlayers(creditedPlayer);
}
else
{
@@ -15350,9 +15351,9 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
// outdoor pvp things, do these after setting the death state, else the player activity notify won't work... doh...
// handle player kill only if not suicide (spirit of redemption for example)
if (player && this != pVictim)
if (player && this != victim)
if (OutdoorPvP * pvp = player->GetOutdoorPvP())
pvp->HandleKill(player, pVictim);
pvp->HandleKill(player, victim);
//if (pVictim->GetTypeId() == TYPEID_PLAYER)
// if (OutdoorPvP * pvp = pVictim->ToPlayer()->GetOutdoorPvP())
@@ -15361,52 +15362,52 @@ void Unit::Kill(Unit *pVictim, bool durabilityLoss)
// battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
if (player && player->InBattleground())
{
if (Battleground *bg = player->GetBattleground())
if (Battleground* bg = player->GetBattleground())
{
if (pVictim->GetTypeId() == TYPEID_PLAYER)
bg->HandleKillPlayer((Player*)pVictim, player);
if (victim->GetTypeId() == TYPEID_PLAYER)
bg->HandleKillPlayer((Player*)victim, player);
else
bg->HandleKillUnit(pVictim->ToCreature(), player);
bg->HandleKillUnit(victim->ToCreature(), player);
}
}
// achievement stuff
if (pVictim->GetTypeId() == TYPEID_PLAYER)
if (victim->GetTypeId() == TYPEID_PLAYER)
{
if (GetTypeId() == TYPEID_UNIT)
pVictim->ToPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry());
else if (GetTypeId() == TYPEID_PLAYER && pVictim != this)
pVictim->ToPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, this->ToPlayer()->GetTeam());
victim->ToPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE, GetEntry());
else if (GetTypeId() == TYPEID_PLAYER && victim != this)
victim->ToPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER, 1, this->ToPlayer()->GetTeam());
}
//Hook for OnPVPKill Event
if (this->GetTypeId() == TYPEID_PLAYER)
if (GetTypeId() == TYPEID_PLAYER)
{
if (pVictim->GetTypeId() == TYPEID_PLAYER)
if (victim->GetTypeId() == TYPEID_PLAYER)
{
Player *killer = this->ToPlayer();
Player *killed = pVictim->ToPlayer();
Player* killer = this->ToPlayer();
Player* killed = victim->ToPlayer();
sScriptMgr->OnPVPKill(killer, killed);
}
else if (pVictim->GetTypeId() == TYPEID_UNIT)
else if (victim->GetTypeId() == TYPEID_UNIT)
{
Player *killer = this->ToPlayer();
Creature *killed = pVictim->ToCreature();
Creature *killed = victim->ToCreature();
sScriptMgr->OnCreatureKill(killer, killed);
}
}
else if (this->GetTypeId() == TYPEID_UNIT)
else if (GetTypeId() == TYPEID_UNIT)
{
if (pVictim->GetTypeId() == TYPEID_PLAYER)
if (victim->GetTypeId() == TYPEID_PLAYER)
{
Creature *killer = this->ToCreature();
Player *killed = pVictim->ToPlayer();
Player *killed = victim->ToPlayer();
sScriptMgr->OnPlayerKilledByCreature(killer, killed);
}
}
if (pVictim->GetVehicle())
pVictim->ExitVehicle();
if (victim->GetVehicle())
victim->ExitVehicle();
}
void Unit::SetControlled(bool apply, UnitState state)