[Crash] Add Checks for valid pointers or fix existing. (#3164)

This commit is contained in:
Aeadoin 2023-04-01 12:44:00 -04:00 committed by GitHub
parent 4c2271ff69
commit 0d509a7f3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 228 additions and 179 deletions

View File

@ -1436,7 +1436,7 @@ void Mob::ClearFeignMemory() {
while (remembered_feigned_mobid != feign_memory_list.end()) while (remembered_feigned_mobid != feign_memory_list.end())
{ {
Mob* remembered_mob = entity_list.GetMob(*remembered_feigned_mobid); Mob* remembered_mob = entity_list.GetMob(*remembered_feigned_mobid);
if (remembered_mob->IsClient() && remembered_mob != nullptr) { //Still in zone if (remembered_mob && remembered_mob->IsClient()) { //Still in zone
remembered_mob->CastToClient()->RemoveXTarget(this, false); remembered_mob->CastToClient()->RemoveXTarget(this, false);
} }
++remembered_feigned_mobid; ++remembered_feigned_mobid;

View File

@ -2835,8 +2835,9 @@ bool NPC::Death(Mob* killer_mob, int64 damage, uint16 spell, EQ::skills::SkillTy
if (emote_id) { if (emote_id) {
oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id); oos->CastToNPC()->DoNPCEmote(EQ::constants::EmoteEventTypes::KilledNPC, emote_id);
} }
if (killer_mob) {
killer_mob->TrySpellOnKill(killed_level, spell); killer_mob->TrySpellOnKill(killed_level, spell);
}
} }
} }

View File

@ -963,6 +963,10 @@ bool ZoneDatabase::GetAuraEntry(uint16 spell_id, AuraRecord &record)
void Mob::AddAura(Aura *aura, AuraRecord &record) void Mob::AddAura(Aura *aura, AuraRecord &record)
{ {
if (!aura) {
return;
}
LogAura( LogAura(
"aura owner [{}] spawn_id [{}] aura_name [{}]", "aura owner [{}] spawn_id [{}] aura_name [{}]",
GetCleanName(), GetCleanName(),
@ -971,7 +975,6 @@ void Mob::AddAura(Aura *aura, AuraRecord &record)
); );
// this is called only when it's safe // this is called only when it's safe
assert(aura != nullptr);
strn0cpy(aura_mgr.auras[aura_mgr.count].name, aura->GetCleanName(), 64); strn0cpy(aura_mgr.auras[aura_mgr.count].name, aura->GetCleanName(), 64);
aura_mgr.auras[aura_mgr.count].spawn_id = aura->GetID(); aura_mgr.auras[aura_mgr.count].spawn_id = aura->GetID();
aura_mgr.auras[aura_mgr.count].aura = aura; aura_mgr.auras[aura_mgr.count].aura = aura;
@ -998,6 +1001,10 @@ void Mob::AddAura(Aura *aura, AuraRecord &record)
void Mob::AddTrap(Aura *aura, AuraRecord &record) void Mob::AddTrap(Aura *aura, AuraRecord &record)
{ {
if (!aura) {
return;
}
LogAura( LogAura(
"aura owner [{}] spawn_id [{}] aura_name [{}]", "aura owner [{}] spawn_id [{}] aura_name [{}]",
GetCleanName(), GetCleanName(),
@ -1006,7 +1013,6 @@ void Mob::AddTrap(Aura *aura, AuraRecord &record)
); );
// this is called only when it's safe // this is called only when it's safe
assert(aura != nullptr);
strn0cpy(trap_mgr.auras[trap_mgr.count].name, aura->GetCleanName(), 64); strn0cpy(trap_mgr.auras[trap_mgr.count].name, aura->GetCleanName(), 64);
trap_mgr.auras[trap_mgr.count].spawn_id = aura->GetID(); trap_mgr.auras[trap_mgr.count].spawn_id = aura->GetID();
trap_mgr.auras[trap_mgr.count].aura = aura; trap_mgr.auras[trap_mgr.count].aura = aura;

View File

@ -4637,7 +4637,9 @@ void Bot::Damage(Mob *from, int64 damage, uint16 spell_id, EQ::skills::SkillType
int64 healed = GetActSpellHealing(spell_id, damage); int64 healed = GetActSpellHealing(spell_id, damage);
LogCombatDetail("Applying lifetap heal of [{}] to [{}]", healed, GetCleanName()); LogCombatDetail("Applying lifetap heal of [{}] to [{}]", healed, GetCleanName());
HealDamage(healed); HealDamage(healed);
entity_list.FilteredMessageClose(this, true, RuleI(Range, SpellMessages), Chat::Emote, FilterSocials, "%s beams a smile at %s", GetCleanName(), from->GetCleanName() ); if (from) {
entity_list.FilteredMessageClose(this, true, RuleI(Range, SpellMessages), Chat::Emote, FilterSocials, "%s beams a smile at %s", GetCleanName(), from->GetCleanName());
}
} }
CommonDamage(from, damage, spell_id, attack_skill, avoidable, buffslot, iBuffTic, special); CommonDamage(from, damage, spell_id, attack_skill, avoidable, buffslot, iBuffTic, special);
@ -8552,22 +8554,25 @@ std::vector<Mob*> Bot::GetApplySpellList(
if (apply_type == ApplySpellType::Raid && IsRaidGrouped()) { if (apply_type == ApplySpellType::Raid && IsRaidGrouped()) {
auto* r = GetRaid(); auto* r = GetRaid();
auto group_id = r->GetGroup(GetCleanName()); if (r) {
if (r && EQ::ValueWithin(group_id, 0, (MAX_RAID_GROUPS - 1))) { auto group_id = r->GetGroup(GetCleanName());
for (const auto& m : r->members) { if (EQ::ValueWithin(group_id, 0, (MAX_RAID_GROUPS - 1))) {
if (m.is_bot) { for (const auto& m: r->members) {
continue; if (m.is_bot) {
} continue;
if (m.member && m.member->IsClient() && (!is_raid_group_only || r->GetGroup(m.member) == group_id)) {
l.push_back(m.member);
if (allow_pets && m.member->HasPet()) {
l.push_back(m.member->GetPet());
} }
if (m.member && m.member->IsClient() &&
(!is_raid_group_only || r->GetGroup(m.member) == group_id)) {
l.push_back(m.member);
const auto& sbl = entity_list.GetBotListByCharacterID(m.member->CharacterID()); if (allow_pets && m.member->HasPet()) {
for (const auto& b : sbl) { l.push_back(m.member->GetPet());
l.push_back(b); }
const auto& sbl = entity_list.GetBotListByCharacterID(m.member->CharacterID());
for (const auto& b: sbl) {
l.push_back(b);
}
} }
} }
} }

View File

@ -1888,11 +1888,15 @@ bool Bot::AIHealRotation(Mob* tar, bool useFastHeals) {
std::list<BotSpell> Bot::GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect) { std::list<BotSpell> Bot::GetBotSpellsForSpellEffect(Bot* botCaster, int spellEffect) {
std::list<BotSpell> result; std::list<BotSpell> result;
if (!botCaster) {
return result;
}
if (auto bot_owner = botCaster->GetBotOwner(); !bot_owner) { if (auto bot_owner = botCaster->GetBotOwner(); !bot_owner) {
return result; return result;
} }
if (botCaster && botCaster->AI_HasSpells()) { if (botCaster->AI_HasSpells()) {
std::vector<BotSpells_Struct> botSpellList = botCaster->AIBot_spells; std::vector<BotSpells_Struct> botSpellList = botCaster->AIBot_spells;
for (int i = botSpellList.size() - 1; i >= 0; i--) { for (int i = botSpellList.size() - 1; i >= 0; i--) {
@ -1919,11 +1923,15 @@ std::list<BotSpell> Bot::GetBotSpellsForSpellEffect(Bot* botCaster, int spellEff
std::list<BotSpell> Bot::GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType) { std::list<BotSpell> Bot::GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster, int spellEffect, SpellTargetType targetType) {
std::list<BotSpell> result; std::list<BotSpell> result;
if (!botCaster) {
return result;
}
if (auto bot_owner = botCaster->GetBotOwner(); !bot_owner) { if (auto bot_owner = botCaster->GetBotOwner(); !bot_owner) {
return result; return result;
} }
if (botCaster && botCaster->AI_HasSpells()) { if (botCaster->AI_HasSpells()) {
std::vector<BotSpells_Struct> botSpellList = botCaster->AIBot_spells; std::vector<BotSpells_Struct> botSpellList = botCaster->AIBot_spells;
for (int i = botSpellList.size() - 1; i >= 0; i--) { for (int i = botSpellList.size() - 1; i >= 0; i--) {
@ -1955,11 +1963,15 @@ std::list<BotSpell> Bot::GetBotSpellsForSpellEffectAndTargetType(Bot* botCaster,
std::list<BotSpell> Bot::GetBotSpellsBySpellType(Bot* botCaster, uint32 spellType) { std::list<BotSpell> Bot::GetBotSpellsBySpellType(Bot* botCaster, uint32 spellType) {
std::list<BotSpell> result; std::list<BotSpell> result;
if (!botCaster) {
return result;
}
if (auto bot_owner = botCaster->GetBotOwner(); !bot_owner) { if (auto bot_owner = botCaster->GetBotOwner(); !bot_owner) {
return result; return result;
} }
if (botCaster && botCaster->AI_HasSpells()) { if (botCaster->AI_HasSpells()) {
std::vector<BotSpells_Struct> botSpellList = botCaster->AIBot_spells; std::vector<BotSpells_Struct> botSpellList = botCaster->AIBot_spells;
for (int i = botSpellList.size() - 1; i >= 0; i--) { for (int i = botSpellList.size() - 1; i >= 0; i--) {
@ -2694,21 +2706,22 @@ BotSpell Bot::GetBestBotSpellForResistDebuff(Bot* botCaster, Mob *tar) {
result.SpellIndex = 0; result.SpellIndex = 0;
result.ManaCost = 0; result.ManaCost = 0;
if (!tar) if (!tar || !botCaster) {
return result; return result;
}
int level_mod = (tar->GetLevel() - botCaster->GetLevel())* (tar->GetLevel() - botCaster->GetLevel()) / 2; int level_mod = (tar->GetLevel() - botCaster->GetLevel())* (tar->GetLevel() - botCaster->GetLevel()) / 2;
if (tar->GetLevel() - botCaster->GetLevel() < 0) if (tar->GetLevel() - botCaster->GetLevel() < 0) {
{
level_mod = -level_mod; level_mod = -level_mod;
} }
bool needsMagicResistDebuff = (tar->GetMR() + level_mod) > 100; bool needsMagicResistDebuff = (tar->GetMR() + level_mod) > 100;
bool needsColdResistDebuff = (tar->GetCR() + level_mod) > 100; bool needsColdResistDebuff = (tar->GetCR() + level_mod) > 100;
bool needsFireResistDebuff = (tar->GetFR() + level_mod) > 100; bool needsFireResistDebuff = (tar->GetFR() + level_mod) > 100;
bool needsPoisonResistDebuff = (tar->GetPR() + level_mod) > 100; bool needsPoisonResistDebuff = (tar->GetPR() + level_mod) > 100;
bool needsDiseaseResistDebuff = (tar->GetDR() + level_mod) > 100; bool needsDiseaseResistDebuff = (tar->GetDR() + level_mod) > 100;
if (botCaster && botCaster->AI_HasSpells()) { if (botCaster->AI_HasSpells()) {
std::vector<BotSpells_Struct> botSpellList = botCaster->AIBot_spells; std::vector<BotSpells_Struct> botSpellList = botCaster->AIBot_spells;
for (int i = botSpellList.size() - 1; i >= 0; i--) { for (int i = botSpellList.size() - 1; i >= 0; i--) {

View File

@ -7470,15 +7470,17 @@ const char* Client::GetClassPlural(Client* client) {
void Client::SendWebLink(const char *website) void Client::SendWebLink(const char *website)
{ {
size_t len = strlen(website) + 1; if (website) {
if(website != 0 && len > 1) size_t len = strlen(website) + 1;
{ if (len > 1)
auto outapp = new EQApplicationPacket(OP_Weblink, sizeof(Weblink_Struct) + len); {
Weblink_Struct *wl = (Weblink_Struct*)outapp->pBuffer; auto outapp = new EQApplicationPacket(OP_Weblink, sizeof(Weblink_Struct) + len);
memcpy(wl->weblink, website, len); Weblink_Struct* wl = (Weblink_Struct*)outapp->pBuffer;
wl->weblink[len] = '\0'; memcpy(wl->weblink, website, len);
wl->weblink[len] = '\0';
FastQueuePacket(&outapp); FastQueuePacket(&outapp);
}
} }
} }
@ -11734,20 +11736,22 @@ std::vector<Mob*> Client::GetApplySpellList(
if (apply_type == ApplySpellType::Raid && IsRaidGrouped()) { if (apply_type == ApplySpellType::Raid && IsRaidGrouped()) {
auto* r = GetRaid(); auto* r = GetRaid();
auto group_id = r->GetGroup(this); if (r) {
if (r && EQ::ValueWithin(group_id, 0, (MAX_RAID_GROUPS - 1))) { auto group_id = r->GetGroup(this);
for (const auto& m : r->members) { if (EQ::ValueWithin(group_id, 0, (MAX_RAID_GROUPS - 1))) {
if (m.member && m.member->IsClient() && (!is_raid_group_only || r->GetGroup(m.member) == group_id)) { for (const auto& m : r->members) {
l.push_back(m.member); if (m.member && m.member->IsClient() && (!is_raid_group_only || r->GetGroup(m.member) == group_id)) {
l.push_back(m.member);
if (allow_pets && m.member->HasPet()) { if (allow_pets && m.member->HasPet()) {
l.push_back(m.member->GetPet()); l.push_back(m.member->GetPet());
} }
if (allow_bots) { if (allow_bots) {
const auto& sbl = entity_list.GetBotListByCharacterID(m.member->CharacterID()); const auto& sbl = entity_list.GetBotListByCharacterID(m.member->CharacterID());
for (const auto& b : sbl) { for (const auto& b : sbl) {
l.push_back(b); l.push_back(b);
}
} }
} }
} }

View File

@ -11775,13 +11775,13 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket* app)
Bot* player_to_invite = nullptr; Bot* player_to_invite = nullptr;
if (RuleB(Bots, Enabled) && entity_list.GetBotByBotName(raid_command_packet->player_name)) { if (RuleB(Bots, Enabled) && entity_list.GetBotByBotName(raid_command_packet->player_name)) {
Bot* player_to_invite = entity_list.GetBotByBotName(raid_command_packet->player_name);
Group* player_to_invite_group = player_to_invite->GetGroup();
if (!player_to_invite) { if (!player_to_invite) {
break; break;
} }
Bot* player_to_invite = entity_list.GetBotByBotName(raid_command_packet->player_name);
Group* player_to_invite_group = player_to_invite->GetGroup();
if (player_to_invite_group && player_to_invite_group->IsGroupMember(this)) { if (player_to_invite_group && player_to_invite_group->IsGroupMember(this)) {
MessageString(Chat::Red, ALREADY_IN_PARTY); MessageString(Chat::Red, ALREADY_IN_PARTY);
break; break;

View File

@ -1145,6 +1145,7 @@ void Client::OPMemorizeSpell(const EQApplicationPacket* app)
const auto* item = inst->GetItem(); const auto* item = inst->GetItem();
if ( if (
item &&
RuleB(Character, RestrictSpellScribing) && RuleB(Character, RestrictSpellScribing) &&
!item->IsEquipable(GetRace(), GetClass()) !item->IsEquipable(GetRace(), GetClass())
) { ) {

View File

@ -520,8 +520,6 @@ bool PerlembParser::SpellHasQuestSub(uint32 spell_id, QuestEventID evt)
bool PerlembParser::ItemHasQuestSub(EQ::ItemInstance *itm, QuestEventID evt) bool PerlembParser::ItemHasQuestSub(EQ::ItemInstance *itm, QuestEventID evt)
{ {
std::stringstream package_name;
package_name << "qst_item_" << itm->GetID();
if (!perl) { if (!perl) {
return false; return false;
@ -535,6 +533,9 @@ bool PerlembParser::ItemHasQuestSub(EQ::ItemInstance *itm, QuestEventID evt)
return false; return false;
} }
std::stringstream package_name;
package_name << "qst_item_" << itm->GetID();
const char *subname = QuestEventSubroutines[evt]; const char *subname = QuestEventSubroutines[evt];
auto iter = item_quest_status_.find(itm->GetID()); auto iter = item_quest_status_.find(itm->GetID());

View File

@ -298,7 +298,7 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
} }
//put existing group member(s) into the new member's list //put existing group member(s) into the new member's list
if(InZone && newmember->IsClient()) if(InZone && newmember && newmember->IsClient())
{ {
if(IsLeader(members[i])) if(IsLeader(members[i]))
{ {
@ -307,13 +307,13 @@ bool Group::AddMember(Mob* newmember, const char *NewMemberName, uint32 Characte
else else
{ {
strcpy(newmember->CastToClient()->GetPP().groupMembers[x], members[i]->GetCleanName()); strcpy(newmember->CastToClient()->GetPP().groupMembers[x], members[i]->GetCleanName());
x++; ++x;
} }
} }
} }
} }
if(InZone) if(InZone && newmember)
{ {
//put new member in his own list. //put new member in his own list.
newmember->SetGrouped(true); newmember->SetGrouped(true);

View File

@ -483,20 +483,22 @@ Mob *HateList::GetEntWithMostHateOnList(Mob *center, Mob *skip, bool skip_mezzed
while (iterator != list.end()) while (iterator != list.end())
{ {
struct_HateList *cur = (*iterator); struct_HateList *cur = (*iterator);
if (cur->entity_on_hatelist == skip) { if (cur) {
++iterator; if (cur->entity_on_hatelist == skip) {
continue; ++iterator;
} continue;
}
if (skip_mezzed && cur->entity_on_hatelist->IsMezzed()) { if (skip_mezzed && cur->entity_on_hatelist->IsMezzed()) {
++iterator; ++iterator;
continue; continue;
} }
if (cur->entity_on_hatelist != nullptr && ((cur->stored_hate_amount > hate) || cur->is_entity_frenzy)) if (cur->entity_on_hatelist != nullptr && ((cur->stored_hate_amount > hate) || cur->is_entity_frenzy))
{ {
top_hate = cur->entity_on_hatelist; top_hate = cur->entity_on_hatelist;
hate = cur->stored_hate_amount; hate = cur->stored_hate_amount;
}
} }
++iterator; ++iterator;
} }
@ -516,24 +518,27 @@ Mob *HateList::GetEntWithMostHateOnList(bool skip_mezzed){
while (iterator != list.end()) while (iterator != list.end())
{ {
struct_HateList *cur = (*iterator); struct_HateList *cur = (*iterator);
LogHateDetail(
"Looping GetEntWithMostHateOnList1 [{}] cur [{}] hate [{}] calc [{}]",
cur->entity_on_hatelist->GetMobDescription(),
cur->stored_hate_amount,
hate,
(cur->stored_hate_amount > hate)
);
if (cur && cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate)) if (cur) {
{
LogHateDetail( LogHateDetail(
"Looping GetEntWithMostHateOnList2 [{}]", "Looping GetEntWithMostHateOnList1 [{}] cur [{}] hate [{}] calc [{}]",
cur->entity_on_hatelist->GetMobDescription() cur->entity_on_hatelist->GetMobDescription(),
cur->stored_hate_amount,
hate,
(cur->stored_hate_amount > hate)
); );
if (!skip_mezzed || !cur->entity_on_hatelist->IsMezzed()) { if (cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate))
top = cur->entity_on_hatelist; {
hate = cur->stored_hate_amount; LogHateDetail(
"Looping GetEntWithMostHateOnList2 [{}]",
cur->entity_on_hatelist->GetMobDescription()
);
if (!skip_mezzed || !cur->entity_on_hatelist->IsMezzed()) {
top = cur->entity_on_hatelist;
hate = cur->stored_hate_amount;
}
} }
} }
++iterator; ++iterator;

View File

@ -717,12 +717,15 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2,
EQ::ItemInstance* inst = database.CreateItem(item, charges); EQ::ItemInstance* inst = database.CreateItem(item, charges);
auto timestamps = database.GetItemRecastTimestamps(CharacterID()); auto timestamps = database.GetItemRecastTimestamps(CharacterID());
const auto* d = inst->GetItem(); if (inst) {
if (d->RecastDelay) { const auto* d = inst->GetItem();
if (d->RecastType != RECAST_TYPE_UNLINKED_ITEM) { if (d->RecastDelay) {
inst->SetRecastTimestamp(timestamps.count(d->RecastType) ? timestamps.at(d->RecastType) : 0); if (d->RecastType != RECAST_TYPE_UNLINKED_ITEM) {
} else { inst->SetRecastTimestamp(timestamps.count(d->RecastType) ? timestamps.at(d->RecastType) : 0);
inst->SetRecastTimestamp(timestamps.count(d->ID) ? timestamps.at(d->ID) : 0); }
else {
inst->SetRecastTimestamp(timestamps.count(d->ID) ? timestamps.at(d->ID) : 0);
}
} }
} }
@ -2043,8 +2046,8 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
} }
if ((srcbagid && srcbag->GetItem()->BagType == EQ::item::BagTypeTradersSatchel) || if ((srcbagid && srcbag->GetItem()->BagType == EQ::item::BagTypeTradersSatchel) ||
(dstbagid && dstbag->GetItem()->BagType == EQ::item::BagTypeTradersSatchel) || (dstbagid && dstbag->GetItem()->BagType == EQ::item::BagTypeTradersSatchel) ||
(srcitemid && src_inst->GetItem()->BagType == EQ::item::BagTypeTradersSatchel) || (srcitemid && src_inst && src_inst->GetItem()->BagType == EQ::item::BagTypeTradersSatchel) ||
(dstitemid && dst_inst->GetItem()->BagType == EQ::item::BagTypeTradersSatchel)) { (dstitemid && dst_inst && dst_inst->GetItem()->BagType == EQ::item::BagTypeTradersSatchel)) {
Trader_EndTrader(); Trader_EndTrader();
Message(Chat::Red,"You cannot move your Trader Satchels, or items inside them, while Trading."); Message(Chat::Red,"You cannot move your Trader Satchels, or items inside them, while Trading.");
} }

View File

@ -3261,6 +3261,10 @@ MercSpell Merc::GetBestMercSpellForTargetedAENuke(Merc* caster, Mob* tar) {
result.proc_chance = 0; result.proc_chance = 0;
result.time_cancast = 0; result.time_cancast = 0;
if (!caster) {
return result;
}
switch(caster->GetStance()) switch(caster->GetStance())
{ {
case EQ::constants::stanceBurnAE: case EQ::constants::stanceBurnAE:
@ -3272,28 +3276,26 @@ MercSpell Merc::GetBestMercSpellForTargetedAENuke(Merc* caster, Mob* tar) {
break; break;
} }
if(caster) { std::list<MercSpell> mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke);
std::list<MercSpell> mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke);
for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end();
++mercSpellListItr) { ++mercSpellListItr) {
// Assuming all the spells have been loaded into this list by level and in descending order // Assuming all the spells have been loaded into this list by level and in descending order
if(IsAENukeSpell(mercSpellListItr->spellid) && !IsAERainNukeSpell(mercSpellListItr->spellid) if(IsAENukeSpell(mercSpellListItr->spellid) && !IsAERainNukeSpell(mercSpellListItr->spellid)
&& !IsPBAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { && !IsPBAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) {
uint8 numTargets = 0; uint8 numTargets = 0;
if(CheckAENuke(caster, tar, mercSpellListItr->spellid, numTargets)) { if(CheckAENuke(caster, tar, mercSpellListItr->spellid, numTargets)) {
if(numTargets >= numTargetsCheck && zone->random.Roll(castChance)) { if(numTargets >= numTargetsCheck && zone->random.Roll(castChance)) {
result.spellid = mercSpellListItr->spellid; result.spellid = mercSpellListItr->spellid;
result.stance = mercSpellListItr->stance; result.stance = mercSpellListItr->stance;
result.type = mercSpellListItr->type; result.type = mercSpellListItr->type;
result.slot = mercSpellListItr->slot; result.slot = mercSpellListItr->slot;
result.proc_chance = mercSpellListItr->proc_chance; result.proc_chance = mercSpellListItr->proc_chance;
result.time_cancast = mercSpellListItr->time_cancast; result.time_cancast = mercSpellListItr->time_cancast;
}
} }
}
break; break;
}
} }
} }
@ -3313,6 +3315,10 @@ MercSpell Merc::GetBestMercSpellForPBAENuke(Merc* caster, Mob* tar) {
result.proc_chance = 0; result.proc_chance = 0;
result.time_cancast = 0; result.time_cancast = 0;
if (!caster) {
return result;
}
switch(caster->GetStance()) switch(caster->GetStance())
{ {
case EQ::constants::stanceBurnAE: case EQ::constants::stanceBurnAE:
@ -3324,27 +3330,25 @@ MercSpell Merc::GetBestMercSpellForPBAENuke(Merc* caster, Mob* tar) {
break; break;
} }
if(caster) { std::list<MercSpell> mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke);
std::list<MercSpell> mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke);
for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end();
++mercSpellListItr) { ++mercSpellListItr) {
// Assuming all the spells have been loaded into this list by level and in descending order // Assuming all the spells have been loaded into this list by level and in descending order
if(IsPBAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { if(IsPBAENukeSpell(mercSpellListItr->spellid) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) {
uint8 numTargets = 0; uint8 numTargets = 0;
if(CheckAENuke(caster, caster, mercSpellListItr->spellid, numTargets)) { if(CheckAENuke(caster, caster, mercSpellListItr->spellid, numTargets)) {
if(numTargets >= numTargetsCheck && zone->random.Roll(castChance)) { if(numTargets >= numTargetsCheck && zone->random.Roll(castChance)) {
result.spellid = mercSpellListItr->spellid; result.spellid = mercSpellListItr->spellid;
result.stance = mercSpellListItr->stance; result.stance = mercSpellListItr->stance;
result.type = mercSpellListItr->type; result.type = mercSpellListItr->type;
result.slot = mercSpellListItr->slot; result.slot = mercSpellListItr->slot;
result.proc_chance = mercSpellListItr->proc_chance; result.proc_chance = mercSpellListItr->proc_chance;
result.time_cancast = mercSpellListItr->time_cancast; result.time_cancast = mercSpellListItr->time_cancast;
}
} }
break;
} }
break;
} }
} }
@ -3364,6 +3368,10 @@ MercSpell Merc::GetBestMercSpellForAERainNuke(Merc* caster, Mob* tar) {
result.proc_chance = 0; result.proc_chance = 0;
result.time_cancast = 0; result.time_cancast = 0;
if (!caster) {
return result;
}
switch(caster->GetStance()) switch(caster->GetStance())
{ {
case EQ::constants::stanceBurnAE: case EQ::constants::stanceBurnAE:
@ -3375,27 +3383,25 @@ MercSpell Merc::GetBestMercSpellForAERainNuke(Merc* caster, Mob* tar) {
break; break;
} }
if(caster) { std::list<MercSpell> mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke);
std::list<MercSpell> mercSpellList = GetMercSpellsBySpellType(caster, SpellType_Nuke);
for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end(); for (auto mercSpellListItr = mercSpellList.begin(); mercSpellListItr != mercSpellList.end();
++mercSpellListItr) { ++mercSpellListItr) {
// Assuming all the spells have been loaded into this list by level and in descending order // Assuming all the spells have been loaded into this list by level and in descending order
if(IsAERainNukeSpell(mercSpellListItr->spellid) && zone->random.Roll(castChance) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) { if(IsAERainNukeSpell(mercSpellListItr->spellid) && zone->random.Roll(castChance) && CheckSpellRecastTimers(caster, mercSpellListItr->spellid)) {
uint8 numTargets = 0; uint8 numTargets = 0;
if(CheckAENuke(caster, tar, mercSpellListItr->spellid, numTargets)) { if(CheckAENuke(caster, tar, mercSpellListItr->spellid, numTargets)) {
if(numTargets >= numTargetsCheck) { if(numTargets >= numTargetsCheck) {
result.spellid = mercSpellListItr->spellid; result.spellid = mercSpellListItr->spellid;
result.stance = mercSpellListItr->stance; result.stance = mercSpellListItr->stance;
result.type = mercSpellListItr->type; result.type = mercSpellListItr->type;
result.slot = mercSpellListItr->slot; result.slot = mercSpellListItr->slot;
result.proc_chance = mercSpellListItr->proc_chance; result.proc_chance = mercSpellListItr->proc_chance;
result.time_cancast = mercSpellListItr->time_cancast; result.time_cancast = mercSpellListItr->time_cancast;
}
} }
break;
} }
break;
} }
} }
@ -4302,7 +4308,12 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id,
if(merc_template) if(merc_template)
{ {
//TODO: Maybe add a way of updating client merc stats in a seperate function? like, for example, on leveling up. //TODO: Maybe add a way of updating client merc stats in a seperate function? like, for example, on leveling up.
const NPCType* npc_type_to_copy = content_db.GetMercType(merc_template->MercNPCID, merc_template->RaceID, c->GetLevel());
const NPCType* npc_type_to_copy = nullptr;
if (c) {
const NPCType* npc_type_to_copy = content_db.GetMercType(merc_template->MercNPCID, merc_template->RaceID, c->GetLevel());
}
if(npc_type_to_copy != nullptr) if(npc_type_to_copy != nullptr)
{ {
//This is actually a very terrible method of assigning stats, and should be changed at some point. See the comment in merc's deconstructor. //This is actually a very terrible method of assigning stats, and should be changed at some point. See the comment in merc's deconstructor.

View File

@ -5109,6 +5109,10 @@ void Mob::TarGlobal(const char *varname, const char *value, const char *duration
void Mob::DelGlobal(const char *varname) { void Mob::DelGlobal(const char *varname) {
if (!zone) {
return;
}
int qgZoneid=zone->GetZoneID(); int qgZoneid=zone->GetZoneID();
int qgCharid=0; int qgCharid=0;
int qgNpcid=0; int qgNpcid=0;
@ -5129,22 +5133,19 @@ void Mob::DelGlobal(const char *varname) {
database.QueryDatabase(query); database.QueryDatabase(query);
if(zone) auto pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
{ ServerQGlobalDelete_Struct *qgu = (ServerQGlobalDelete_Struct*)pack->pBuffer;
auto pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
ServerQGlobalDelete_Struct *qgu = (ServerQGlobalDelete_Struct*)pack->pBuffer;
qgu->npc_id = qgNpcid; qgu->npc_id = qgNpcid;
qgu->char_id = qgCharid; qgu->char_id = qgCharid;
qgu->zone_id = qgZoneid; qgu->zone_id = qgZoneid;
strcpy(qgu->name, varname); strcpy(qgu->name, varname);
entity_list.DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id); entity_list.DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id);
zone->DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id); zone->DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id);
worldserver.SendPacket(pack); worldserver.SendPacket(pack);
safe_delete(pack); safe_delete(pack);
}
} }
// Inserts global variable into quest_globals table // Inserts global variable into quest_globals table

View File

@ -445,7 +445,7 @@ Pet::Pet(NPCType *type_data, Mob *owner, PetType type, uint16 spell_id, int16 po
GiveNPCTypeData(type_data); GiveNPCTypeData(type_data);
typeofpet = type; typeofpet = type;
petpower = power; petpower = power;
SetOwnerID(owner->GetID()); SetOwnerID(owner ? owner->GetID() : 0);
SetPetSpellID(spell_id); SetPetSpellID(spell_id);
// All pets start at false on newer clients. The client // All pets start at false on newer clients. The client

View File

@ -150,7 +150,7 @@ bool Spawn2::Process() {
//grab our spawn group //grab our spawn group
SpawnGroup *spawn_group = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_); SpawnGroup *spawn_group = zone->spawn_group_list.GetSpawnGroup(spawngroup_id_);
if (NPCPointerValid() && (spawn_group->despawn == 0 || condition_id != 0)) { if (NPCPointerValid() && (spawn_group && spawn_group->despawn == 0 || condition_id != 0)) {
return true; return true;
} }

View File

@ -147,9 +147,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
if (spells[spell_id].hit_number > 0) { if (spells[spell_id].hit_number > 0) {
int numhit = spells[spell_id].hit_number; int numhit = spells[spell_id].hit_number;
if (caster) {
numhit += numhit * caster->GetFocusEffect(focusFcLimitUse, spell_id) / 100; numhit += numhit * caster->GetFocusEffect(focusFcLimitUse, spell_id) / 100;
numhit += caster->GetFocusEffect(focusIncreaseNumHits, spell_id); numhit += caster->GetFocusEffect(focusIncreaseNumHits, spell_id);
}
buffs[buffslot].hit_number = numhit; buffs[buffslot].hit_number = numhit;
} }
@ -262,7 +263,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
// SE_CurrentHP is calculated at first tick if its a dot/buff // SE_CurrentHP is calculated at first tick if its a dot/buff
if (buffslot >= 0) { if (buffslot >= 0) {
//This is here so dots with hit counters tic down on initial cast. //This is here so dots with hit counters tic down on initial cast.
if (effect_value < 0) { if (caster && effect_value < 0) {
caster->GetActDoTDamage(spell_id, effect_value, this, false); caster->GetActDoTDamage(spell_id, effect_value, this, false);
} }
break; break;
@ -1766,7 +1767,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
gid = r->GetGroup(caster->GetName()); gid = r->GetGroup(caster->GetName());
if(gid < 11) if(gid < 11)
{ {
if(r->GetGroup(TargetClient->GetName()) != gid) { if (TargetClient && r->GetGroup(TargetClient->GetName()) != gid) {
Message(Chat::Red, "Your target must be a group member for this spell."); Message(Chat::Red, "Your target must be a group member for this spell.");
break; break;
} }
@ -1817,7 +1818,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
{ {
if (IsClient()) { if (IsClient()) {
Client* client_target = CastToClient(); Client* client_target = CastToClient();
if (client_target->IsGrouped()) { if (client_target && client_target->IsGrouped()) {
Group* group = client_target->GetGroup(); Group* group = client_target->GetGroup();
if (!group->IsGroupMember(caster)) { if (!group->IsGroupMember(caster)) {
if (caster != this) { if (caster != this) {
@ -1830,7 +1831,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
Raid *raid = caster->GetRaid(); Raid *raid = caster->GetRaid();
uint32 group_id = raid->GetGroup(caster->GetName()); uint32 group_id = raid->GetGroup(caster->GetName());
if (group_id > 0 && group_id < MAX_RAID_GROUPS) { if (group_id > 0 && group_id < MAX_RAID_GROUPS) {
if (raid->GetGroup(client_target->GetName()) != group_id) { if (client_target && raid->GetGroup(client_target->GetName()) != group_id) {
caster->MessageString(Chat::Red, SUMMON_ONLY_GROUP_CORPSE); caster->MessageString(Chat::Red, SUMMON_ONLY_GROUP_CORPSE);
break; break;
} }
@ -2963,10 +2964,10 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
if (caster && !caster->IsClient()) if (caster && !caster->IsClient())
break; break;
if (zone->random.Roll(spells[spell_id].base_value[i])) { if (caster && zone->random.Roll(spells[spell_id].base_value[i])) {
uint32 best_spell_id = caster->CastToClient()->GetHighestScribedSpellinSpellGroup(spells[spell_id].limit_value[i]); uint32 best_spell_id = caster->CastToClient()->GetHighestScribedSpellinSpellGroup(spells[spell_id].limit_value[i]);
if (caster && IsValidSpell(best_spell_id)) if (IsValidSpell(best_spell_id))
caster->SpellFinished(best_spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[best_spell_id].resist_difficulty); caster->SpellFinished(best_spell_id, this, EQ::spells::CastingSlot::Item, 0, -1, spells[best_spell_id].resist_difficulty);
} }
break; break;

View File

@ -209,8 +209,7 @@ void Trap::Trigger(Mob* trigger)
{ {
entity_list.MessageClose(trigger,false,100,13,"%s",message.c_str()); entity_list.MessageClose(trigger,false,100,13,"%s",message.c_str());
} }
if(trigger->IsClient()) if (trigger && trigger->IsClient()) {
{
auto outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct)); auto outapp = new EQApplicationPacket(OP_Damage, sizeof(CombatDamage_Struct));
CombatDamage_Struct* a = (CombatDamage_Struct*)outapp->pBuffer; CombatDamage_Struct* a = (CombatDamage_Struct*)outapp->pBuffer;
int64 dmg = zone->random.Int(effectvalue, effectvalue2); int64 dmg = zone->random.Int(effectvalue, effectvalue2);
@ -226,8 +225,7 @@ void Trap::Trigger(Mob* trigger)
} }
} }
if (trigger && trigger->IsClient()) if (trigger && trigger->IsClient()) {
{
trigger->CastToClient()->trapid = trap_id; trigger->CastToClient()->trapid = trap_id;
charid = trigger->CastToClient()->CharacterID(); charid = trigger->CastToClient()->CharacterID();
} }

View File

@ -2027,13 +2027,12 @@ ZonePoint* Zone::GetClosestZonePoint(const glm::vec3& location, uint32 to, Clien
// if we have a water map and it says we're in a zoneline, lets assume it's just a really big zone line // if we have a water map and it says we're in a zoneline, lets assume it's just a really big zone line
// this shouldn't open up any exploits since those situations are detected later on // this shouldn't open up any exploits since those situations are detected later on
if ((zone->HasWaterMap() && !zone->watermap->InZoneLine(glm::vec3(client->GetPosition()))) || (!zone->HasWaterMap() && closest_dist > 400.0f && closest_dist < max_distance2)) if ((client && zone->HasWaterMap() && !zone->watermap->InZoneLine(glm::vec3(client->GetPosition()))) || (!zone->HasWaterMap() && closest_dist > 400.0f && closest_dist < max_distance2))
{ {
if (client) { if (!client->cheat_manager.GetExemptStatus(Port)) {
if (!client->cheat_manager.GetExemptStatus(Port)) { client->cheat_manager.CheatDetected(MQZoneUnknownDest, location);
client->cheat_manager.CheatDetected(MQZoneUnknownDest, location);
}
} }
LogInfo("WARNING: Closest zone point for zone id [{}] is [{}], you might need to update your zone_points table if you dont arrive at the right spot", to, closest_dist); LogInfo("WARNING: Closest zone point for zone id [{}] is [{}], you might need to update your zone_points table if you dont arrive at the right spot", to, closest_dist);
LogInfo("<Real Zone Points>. [{}]", to_string(location).c_str()); LogInfo("<Real Zone Points>. [{}]", to_string(location).c_str());
} }