DeathList Creature::getKillers() { DeathList list; CountMap::const_iterator it; Creature* lhc = NULL; if((lhc = g_game.getCreatureByID(lastHitCreature))) { int32_t damage = 0; if((it = damageMap.find(lastHitCreature)) != damageMap.end()) damage = it->second.total; list.push_back(DeathEntry(lhc, damage)); } else list.push_back(DeathEntry(getCombatName(lastDamageSource), 0)); int32_t requiredTime = g_config.getNumber(ConfigManager::DEATHLIST_REQUIRED_TIME); int64_t now = OTSYS_TIME(); CountBlock_t cb; for(it = damageMap.begin(); it != damageMap.end(); ++it) { cb = it->second; if((now - cb.ticks) > requiredTime) continue; Creature* mdc = g_game.getCreatureByID(it->first); if(!mdc || mdc == lhc || (lhc && (mdc->getMaster() == lhc || lhc->getMaster() == mdc))) continue; bool deny = false; for(DeathList::iterator fit = list.begin(); fit != list.end(); ++fit) { if(fit->isNameKill()) continue; Creature* tmp = fit->getKillerCreature(); if(!(mdc->getName() == tmp->getName() && mdc->getMaster() == tmp->getMaster()) && (!mdc->getMaster() || (mdc->getMaster() != tmp && mdc->getMaster() != tmp->getMaster())) && (mdc->getSummonCount() <= 0 || tmp->getMaster() != mdc)) continue; deny = true; break; } if(!deny) list.push_back(DeathEntry(mdc, cb.total)); } if(list.size() > 1) std::sort(list.begin() + 1, list.end(), DeathLessThan()); return list; }
DeathList Creature::getKillers(int32_t assist_count /*= 1*/) { DeathList list; Creature* lhc = g_game.getCreatureByID(lastHitCreature); if(lhc){ list.push_back(DeathEntry(lhc, 0, Combat::isUnjustKill(lhc, this))); // Final Hit killer } else{ list.push_back(DeathEntry(combatTypeToString(lastDamageSource), 0)); } if(assist_count == 0){ return list; } else if(assist_count == 1){ // Optimized case for last hit + one killer Creature* mdc = NULL; int32_t mostDamage = 0; int64_t now = OTSYS_TIME(); for(CountMap::const_iterator it = damageMap.begin(); it != damageMap.end(); ++it){ const CountBlock_t& cb = it->second; if(cb.total > mostDamage && (now - cb.ticks <= g_game.getInFightTicks())){ Creature* tmpDamageCreature = g_game.getCreatureByID(it->first); if(tmpDamageCreature){ mdc = tmpDamageCreature; mostDamage = cb.total; } } } if(mdc && mdc != lhc){ if(lhc && (mdc->getMaster() == lhc || lhc->getMaster() == mdc || (lhc->getMaster() && lhc->getMaster() == mdc->getMaster()))){ return list; } else{ list.push_back(DeathEntry(mdc, mostDamage, Combat::isUnjustKill(mdc, this))); } } } else{ int64_t now = OTSYS_TIME(); // Add all (recent) damagers to the list for(CountMap::const_iterator it = damageMap.begin(); it != damageMap.end(); ++it){ const CountBlock_t& cb = it->second; if(now - cb.ticks <= g_game.getInFightTicks()){ Creature* mdc = g_game.getCreatureByID(it->first); // Player who made last hit is not included in assist list if(mdc && mdc != lhc){ // Check if master is last hit creature, or if our summon is last hit creature if(lhc && (mdc->getMaster() == lhc || lhc->getMaster() == mdc)){ continue; } // Check if master has already been added to the list if(mdc->getMaster()){ bool cont = false; for(DeathList::iterator finder = list.begin(); finder != list.end(); ++finder){ if(finder->isCreatureKill()){ Creature* c = finder->getKillerCreature(); if(mdc->getMaster() == c || mdc->getMaster() == c->getMaster()){ cont = true; break; } } } if(cont){ continue; } } // Check if our summon has already been added to the list if(mdc->getSummonCount() > 0){ bool cont = false; for(DeathList::iterator finder = list.begin(); finder != list.end(); ++finder){ if(finder->isCreatureKill()){ Creature* c = finder->getKillerCreature(); if(c->getMaster() == mdc){ cont = true; break; } } } if(cont){ continue; } } list.push_back(DeathEntry(mdc, cb.total, Combat::isUnjustKill(mdc, this))); } } } // Sort them by damage, first is always final hit killer if(list.size() > 1){ std::sort(list.begin() + 1, list.end(), DeathLessThan()); } } if(list.size() > (uint32_t)assist_count + 1){ // Shrink list to assist_count list.resize(assist_count + 1, DeathEntry("", -1)); } return list; }
bool Creature::onDeath() { DeathList deathList = getKillers(); bool deny = false; CreatureEventList prepareDeathEvents = getCreatureEvents(CREATURE_EVENT_PREPAREDEATH); for(CreatureEventList::iterator it = prepareDeathEvents.begin(); it != prepareDeathEvents.end(); ++it) { if(!(*it)->executePrepareDeath(this, deathList) && !deny) deny = true; } if(deny) return false; int32_t i = 0, size = deathList.size(), limit = g_config.getNumber(ConfigManager::DEATH_ASSISTS) + 1; if(limit > 0 && size > limit) size = limit; Creature* tmp = NULL; CreatureVector justifyVec; for(DeathList::iterator it = deathList.begin(); it != deathList.end(); ++it, ++i) { if(it->isNameKill()) continue; if(it == deathList.begin()) it->setLast(); if(i < size) { if(it->getKillerCreature()->getPlayer()) tmp = it->getKillerCreature(); else if(it->getKillerCreature()->getPlayerMaster()) tmp = it->getKillerCreature()->getMaster(); } if(tmp) { if(std::find(justifyVec.begin(), justifyVec.end(), tmp) == justifyVec.end()) { it->setJustify(); justifyVec.push_back(tmp); } tmp = NULL; } if(!it->getKillerCreature()->onKilledCreature(this, (*it)) && it->isLast()) return false; } for(CountMap::iterator it = damageMap.begin(); it != damageMap.end(); ++it) { if((tmp = g_game.getCreatureByID(it->first))) tmp->onTargetKilled(this); } dropCorpse(deathList); if(master) master->removeSummon(this); return true; }