Merge remote-tracking branch 'remotes/origin/master' into web_interface

Conflicts:
	common/shareddb.cpp
This commit is contained in:
Akkadius
2015-01-04 06:45:50 -06:00
85 changed files with 2703 additions and 2329 deletions
+8 -2
View File
@@ -606,6 +606,9 @@ void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, u
//the target of these swarm pets will take offense to being cast on...
if(targ != nullptr)
targ->AddToHateList(this, 1, 0);
// The other pointers we make are handled elsewhere.
delete made_npc;
}
void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_override, uint32 duration_override, bool followme, bool sticktarg) {
@@ -698,6 +701,9 @@ void Mob::TypesTemporaryPets(uint32 typesid, Mob *targ, const char *name_overrid
entity_list.AddNPC(npca, true, true);
summon_count--;
}
// The other pointers we make are handled elsewhere.
delete made_npc;
}
void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
@@ -844,8 +850,8 @@ void Mob::WakeTheDead(uint16 spell_id, Mob *target, uint32 duration)
make_npc->loottable_id = 0;
make_npc->merchanttype = 0;
make_npc->d_meele_texture1 = 0;
make_npc->d_meele_texture2 = 0;
make_npc->d_melee_texture1 = 0;
make_npc->d_melee_texture2 = 0;
NPC* npca = new NPC(make_npc, 0, GetX(), GetY(), GetZ(), GetHeading(), FlyMode3);
+1 -1
View File
@@ -1298,7 +1298,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) {
void Mob::RogueEvade(Mob *other)
{
int amount = other->GetHateAmount(this) - (GetLevel() * 13);
other->SetHate(this, std::max(1, amount));
other->SetHateAmountOnEnt(this, std::max(1, amount));
return;
}
+17 -15
View File
@@ -1519,7 +1519,7 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes att
}
entity_list.RemoveFromTargets(this);
hate_list.RemoveEnt(this);
hate_list.RemoveEntFromHateList(this);
RemoveAutoXTargets();
//remove ourself from all proximities
@@ -2080,12 +2080,12 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
if (killerMob) {
if(GetClass() != LDON_TREASURE)
hate_list.Add(killerMob, damage);
hate_list.AddEntToHateList(killerMob, damage);
}
safe_delete(app);
Mob *give_exp = hate_list.GetDamageTop(this);
Mob *give_exp = hate_list.GetDamageTopOnHateList(this);
if(give_exp == nullptr)
give_exp = killer;
@@ -2415,7 +2415,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
return true;
}
void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic) {
void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/)
{
assert(other != nullptr);
@@ -2428,7 +2429,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
bool wasengaged = IsEngaged();
Mob* owner = other->GetOwner();
Mob* mypet = this->GetPet();
Mob* mypet = this->GetPet();
Mob* myowner = this->GetOwner();
Mob* targetmob = this->GetTarget();
@@ -2503,7 +2504,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
&& other && (buffs[spellbonuses.ImprovedTaunt[2]].casterid != other->GetID()))
hate = (hate*spellbonuses.ImprovedTaunt[1])/100;
hate_list.Add(other, hate, damage, bFrenzy, !iBuffTic);
hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic);
if(other->IsClient())
other->CastToClient()->AddAutoXTarget(this);
@@ -2515,8 +2516,8 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
AddFeignMemory(other->CastToBot()->GetBotOwner()->CastToClient());
}
else {
if(!hate_list.IsOnHateList(other->CastToBot()->GetBotOwner()))
hate_list.Add(other->CastToBot()->GetBotOwner(), 0, 0, false, true);
if(!hate_list.IsEntOnHateList(other->CastToBot()->GetBotOwner()))
hate_list.AddEntToHateList(other->CastToBot()->GetBotOwner(), 0, 0, false, true);
}
}
#endif //BOTS
@@ -2527,8 +2528,8 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
AddFeignMemory(other->CastToMerc()->GetMercOwner()->CastToClient());
}
else {
if(!hate_list.IsOnHateList(other->CastToMerc()->GetMercOwner()))
hate_list.Add(other->CastToMerc()->GetMercOwner(), 0, 0, false, true);
if(!hate_list.IsEntOnHateList(other->CastToMerc()->GetMercOwner()))
hate_list.AddEntToHateList(other->CastToMerc()->GetMercOwner(), 0, 0, false, true);
}
} //MERC
@@ -2543,7 +2544,7 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
// owner must get on list, but he's not actually gained any hate yet
if(!owner->GetSpecialAbility(IMMUNE_AGGRO))
{
hate_list.Add(owner, 0, 0, false, !iBuffTic);
hate_list.AddEntToHateList(owner, 0, 0, false, !iBuffTic);
if(owner->IsClient())
owner->CastToClient()->AddAutoXTarget(this);
}
@@ -2552,10 +2553,10 @@ void Mob::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp,
if (mypet && (!(GetAA(aaPetDiscipline) && mypet->IsHeld()))) { // I have a pet, add other to it
if(!mypet->IsFamiliar() && !mypet->GetSpecialAbility(IMMUNE_AGGRO))
mypet->hate_list.Add(other, 0, 0, bFrenzy);
mypet->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
} else if (myowner) { // I am a pet, add other to owner if it's NPC/LD
if (myowner->IsAIControlled() && !myowner->GetSpecialAbility(IMMUNE_AGGRO))
myowner->hate_list.Add(other, 0, 0, bFrenzy);
myowner->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
}
if (other->GetTempPetCount())
@@ -3905,6 +3906,7 @@ float Mob::GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 h
return ProcChance;
}
// argument 'weapon' not used
void Mob::TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand) {
if (!on) {
@@ -4947,7 +4949,7 @@ void Client::SetAttackTimer()
// this is probably wrong
if (quiver_haste > 0)
speed *= quiver_haste;
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true);
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true);
if (i == MainPrimary)
PrimaryWeapon = ItemToUse;
@@ -4995,6 +4997,6 @@ void NPC::SetAttackTimer()
}
}
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true);
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true);
}
}
+446 -446
View File
File diff suppressed because it is too large Load Diff
+53 -130
View File
@@ -234,45 +234,28 @@ void Bot::SetBotSpellID(uint32 newSpellID) {
this->npc_spells_id = newSpellID;
}
uint32 Bot::GetBotArcheryRange() {
uint32 result = 0;
uint32 Bot::GetBotArcheryRange()
{
const ItemInst *range_inst = GetBotItem(MainRange);
const ItemInst *ammo_inst = GetBotItem(MainAmmo);
ItemInst* rangeItem = GetBotItem(MainRange);
if(!rangeItem)
// empty slots
if (!range_inst || !ammo_inst)
return 0;
const Item_Struct* botweapon = rangeItem->GetItem();
const Item_Struct *range_item = range_inst->GetItem();
const Item_Struct *ammo_item = ammo_inst->GetItem();
uint32 archeryMaterial;
uint32 archeryColor;
uint32 archeryBowID;
uint32 archeryAmmoID;
// no item struct for whatever reason
if (!range_item || !ammo_item)
return 0;
if(botweapon && botweapon->ItemType == ItemTypeBow) {
uint32 range = 0;
// bad item types
if (range_item->ItemType != ItemTypeBow || ammo_item->ItemType != ItemTypeArrow)
return 0;
archeryMaterial = atoi(botweapon->IDFile + 2);
archeryBowID = botweapon->ID;
archeryColor = botweapon->Color;
range =+ botweapon->Range;
rangeItem = GetBotItem(MainAmmo);
if(rangeItem)
botweapon = rangeItem->GetItem();
if(!botweapon || (botweapon->ItemType != ItemTypeArrow)) {
return 0;
}
range += botweapon->Range;
archeryAmmoID = botweapon->ID;
result = range;
}
return result;
// everything is good!
return range_item->Range + ammo_item->Range;
}
void Bot::ChangeBotArcherWeapons(bool isArcher) {
@@ -386,8 +369,8 @@ NPCType Bot::FillNPCTypeStruct(uint32 botSpellsID, std::string botName, std::str
BotNPCType.npc_id = 0;
BotNPCType.texture = 0;
BotNPCType.d_meele_texture1 = 0;
BotNPCType.d_meele_texture2 = 0;
BotNPCType.d_melee_texture1 = 0;
BotNPCType.d_melee_texture2 = 0;
BotNPCType.qglobal = false;
BotNPCType.attack_speed = 0;
BotNPCType.runspeed = 1.25;
@@ -431,8 +414,8 @@ NPCType Bot::CreateDefaultNPCTypeStructForBot(std::string botName, std::string b
Result.hp_regen = 1;
Result.mana_regen = 1;
Result.texture = 0;
Result.d_meele_texture1 = 0;
Result.d_meele_texture2 = 0;
Result.d_melee_texture1 = 0;
Result.d_melee_texture2 = 0;
Result.qglobal = false;
Result.npc_spells_id = 0;
Result.attack_speed = 0;
@@ -3439,9 +3422,9 @@ void Bot::AI_Process() {
rest_timer.Disable();
if(IsRooted())
SetTarget(hate_list.GetClosest(this));
SetTarget(hate_list.GetClosestEntOnHateList(this));
else
SetTarget(hate_list.GetTop(this));
SetTarget(hate_list.GetEntWithMostHateOnList(this));
if(!GetTarget())
return;
@@ -3808,9 +3791,9 @@ void Bot::PetAIProcess() {
if (IsEngaged()) {
if (botPet->IsRooted())
botPet->SetTarget(hate_list.GetClosest(botPet));
botPet->SetTarget(hate_list.GetClosestEntOnHateList(botPet));
else
botPet->SetTarget(hate_list.GetTop(botPet));
botPet->SetTarget(hate_list.GetEntWithMostHateOnList(botPet));
// Let's check if we have a los with our target.
// If we don't, our hate_list is wiped.
@@ -5871,7 +5854,7 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, SkillUseTypes att
Save();
Mob *give_exp = hate_list.GetDamageTop(this);
Mob *give_exp = hate_list.GetDamageTopOnHateList(this);
Client *give_exp_client = nullptr;
if(give_exp && give_exp->IsClient())
@@ -6025,7 +6008,7 @@ void Bot::Damage(Mob *from, int32 damage, uint16 spell_id, SkillUseTypes attack_
}
}
void Bot::AddToHateList(Mob* other, int32 hate, int32 damage, bool iYellForHelp, bool bFrenzy, bool iBuffTic)
void Bot::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/)
{
Mob::AddToHateList(other, hate, damage, iYellForHelp, bFrenzy, iBuffTic);
}
@@ -11716,106 +11699,47 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
const char* equipped[EmuConstants::EQUIPMENT_SIZE] = {"Charm", "Left Ear", "Head", "Face", "Right Ear", "Neck", "Shoulders", "Arms", "Back",
"Left Wrist", "Right Wrist", "Range", "Hands", "Primary Hand", "Secondary Hand",
"Left Finger", "Right Finger", "Chest", "Legs", "Feet", "Waist", "Ammo" };
const ItemInst* item1 = nullptr;
const Item_Struct* item2 = nullptr;
const ItemInst* inst = nullptr;
const Item_Struct* item = nullptr;
bool is2Hweapon = false;
for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i)
{
std::string item_link;
Client::TextLink linker;
linker.SetLinkType(linker.linkItemInst);
linker.SetClientVersion(c->GetClientVersion());
for(int i = EmuConstants::EQUIPMENT_BEGIN; i <= EmuConstants::EQUIPMENT_END; ++i) {
if((i == MainSecondary) && is2Hweapon) {
continue;
}
item1 = b->CastToBot()->GetBotItem(i);
if(item1)
item2 = item1->GetItem();
inst = b->CastToBot()->GetBotItem(i);
if (inst)
item = inst->GetItem();
else
item2 = nullptr;
item = nullptr;
if(!TempErrorMessage.empty()) {
c->Message(13, "Database Error: %s", TempErrorMessage.c_str());
return;
}
if(item2 == 0) {
if(item == nullptr) {
c->Message(15, "I need something for my %s (Item %i)", equipped[i], i);
continue;
}
if((i == MainPrimary) && ((item2->ItemType == ItemType2HSlash) || (item2->ItemType == ItemType2HBlunt) || (item2->ItemType == ItemType2HPiercing))) {
if((i == MainPrimary) && ((item->ItemType == ItemType2HSlash) || (item->ItemType == ItemType2HBlunt) || (item->ItemType == ItemType2HPiercing))) {
is2Hweapon = true;
}
char* itemLink = 0;
if((i == MainCharm) || (i == MainRange) || (i == MainPrimary) || (i == MainSecondary) || (i == MainAmmo)) {
if (c->GetClientVersion() >= EQClientSoF)
{
MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X",
0,
item2->ID,
item1->GetAugmentItemID(0),
item1->GetAugmentItemID(1),
item1->GetAugmentItemID(2),
item1->GetAugmentItemID(3),
item1->GetAugmentItemID(4),
0,
0,
0,
0,
0
);
c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i);
}
else
{
MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X",
0,
item2->ID,
item1->GetAugmentItemID(0),
item1->GetAugmentItemID(1),
item1->GetAugmentItemID(2),
item1->GetAugmentItemID(3),
item1->GetAugmentItemID(4),
0,
0,
0,
0);
c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i);
}
}
else {
if (c->GetClientVersion() >= EQClientSoF)
{
MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X",
0,
item2->ID,
item1->GetAugmentItemID(0),
item1->GetAugmentItemID(1),
item1->GetAugmentItemID(2),
item1->GetAugmentItemID(3),
item1->GetAugmentItemID(4),
0,
0,
0,
0,
0
);
c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i);
}
else
{
MakeAnyLenString(&itemLink, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X",
0,
item2->ID,
item1->GetAugmentItemID(0),
item1->GetAugmentItemID(1),
item1->GetAugmentItemID(2),
item1->GetAugmentItemID(3),
item1->GetAugmentItemID(4),
0,
0,
0,
0);
c->Message(15, "Using %c%s%s%c in my %s (Item %i)", 0x12, itemLink, item2->Name, 0x12, equipped[i], i);
}
}
// I could not find a difference between the criteria positive code and the criteria negative code..
// ..so, I deleted the check (old criteria: i = { MainCharm, MainRange, MainPrimary, MainSecondary, MainAmmo })
linker.SetItemInst(inst);
item_link = linker.GenerateLink();
c->Message(15, "Using %s in my %s (Item %i)", item_link.c_str(), equipped[i], i);
}
}
else {
@@ -14364,8 +14288,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
return;
}
std::list<BotGroup>::iterator botGroupItr = botGroup.begin();
for(botGroupItr; botGroupItr != botGroup.end(); ++botGroupItr) {
for(auto botGroupItr = botGroup.begin(); botGroupItr != botGroup.end(); ++botGroupItr) {
// Don't try to re-spawn the botgroup's leader.
if(botGroupItr->BotID == botGroupLeader->GetBotID()) { continue; }
@@ -15474,7 +15397,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
else {
Mob *target = c->GetTarget();
if(target->IsBot() && (c == target->GetOwner()->CastToClient())) {
if(target && target->IsBot() && (c == target->GetOwner()->CastToClient())) {
const InspectMessage_Struct& playermessage = c->GetInspectMessage();
InspectMessage_Struct& botmessage = target->CastToBot()->GetInspectMessage();
@@ -15504,7 +15427,7 @@ void Bot::ProcessBotCommands(Client *c, const Seperator *sep) {
Mob *target = c->GetTarget();
if(target->IsBot() && (c == target->GetOwner()->CastToClient())) {
if(target && target->IsBot() && (c == target->GetOwner()->CastToClient())) {
Bot* bardBot = target->CastToBot();
if(bardBot) {
+1 -1
View File
@@ -208,7 +208,7 @@ public:
bool DoFinishedSpellGroupTarget(uint16 spell_id, Mob* spellTarget, uint16 slot, bool &stopLogic);
void SendBotArcheryWearChange(uint8 material_slot, uint32 material, uint32 color);
void Camp(bool databaseSave = true);
virtual void AddToHateList(Mob* other, int32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false);
virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true, bool bFrenzy = false, bool iBuffTic = false);
virtual void SetTarget(Mob* mob);
virtual void Zone();
std::vector<AISpells_Struct> GetBotSpells() { return AIspells; }
+236 -40
View File
@@ -1817,45 +1817,8 @@ void Client::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
}
ns->spawn.size = 0; // Changing size works, but then movement stops! (wth?)
ns->spawn.runspeed = (gmspeed == 0) ? runspeed : 3.125f;
if (!m_pp.showhelm) ns->spawn.showhelm = 0;
ns->spawn.showhelm = m_pp.showhelm ? 1 : 0;
/*
// Equipment/Weapons already set from Mob::FillSpawnStruct
// Commenting this out for now
const Item_Struct* item = nullptr;
const ItemInst* inst = nullptr;
int16 invslot;
for (uint32 matslot = 0; matslot < _MaterialCount; matslot++)
{
// Only Player Races Wear Armor
if (IsPlayerRace(race) || matslot > 6)
{
invslot = Inventory::CalcSlotFromMaterial(matslot);
if (invslot == INVALID_INDEX)
continue;
if ((inst = m_inv[invslot]) && inst->IsType(ItemClassCommon))
{
item = inst->GetItem();
if (matslot > 6)
{
// Weapon Models
ns->spawn.equipment[matslot].material = GetEquipmentMaterial(matslot);
}
else
{
// Armor Materials/Models
ns->spawn.equipment[matslot].material = item->Material;
ns->spawn.equipment[matslot].elitematerial = item->EliteMaterial;
ns->spawn.equipment[matslot].heroforgemodel = GetHerosForgeModel(matslot);
ns->spawn.colors[matslot].color = m_pp.item_tint[matslot].rgb.use_tint ? m_pp.item_tint[matslot].color : item->Color;
}
}
}
}
*/
}
bool Client::GMHideMe(Client* client) {
@@ -6305,8 +6268,8 @@ void Client::Doppelganger(uint16 spell_id, Mob *target, const char *name_overrid
made_npc->drakkin_heritage = GetDrakkinHeritage();
made_npc->drakkin_tattoo = GetDrakkinTattoo();
made_npc->drakkin_details = GetDrakkinDetails();
made_npc->d_meele_texture1 = GetEquipmentMaterial(MaterialPrimary);
made_npc->d_meele_texture2 = GetEquipmentMaterial(MaterialSecondary);
made_npc->d_melee_texture1 = GetEquipmentMaterial(MaterialPrimary);
made_npc->d_melee_texture2 = GetEquipmentMaterial(MaterialSecondary);
for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++) {
made_npc->armor_tint[i] = GetEquipmentColor(i);
}
@@ -8295,3 +8258,236 @@ void Client::SendColoredText(uint32 color, std::string message)
safe_delete(outapp);
}
//
// class Client::TextLink
//
std::string Client::TextLink::GenerateLink()
{
m_Link.clear();
m_LinkBody.clear();
m_LinkText.clear();
generate_body();
generate_text();
if (m_LinkBody.length() && m_LinkText.length()) {
m_Link.append(StringFormat("%c", 0x12));
m_Link.append(m_LinkBody);
m_Link.append(m_LinkText);
m_Link.append(StringFormat("%c", 0x12));
}
if ((m_Link.length() == 0) || (m_Link.length() > 250)) {
m_Error = true;
m_Link = "<LINKER ERROR>";
_log(CHANNELS__ERROR, "TextLink::GenerateLink() failed to generate a useable text link (LinkType: %i, Lengths: {l: %u, b: %u, t: %u})",
m_LinkType, m_Link.length(), m_LinkBody.length(), m_LinkText.length());
}
return m_Link;
}
const char* Client::TextLink::GetLink()
{
if (m_Link.length() == 0)
return nullptr;
return m_Link.c_str();
}
const char* Client::TextLink::GetLinkBody()
{
if (m_LinkBody.length() == 0)
return nullptr;
return m_LinkBody.c_str();
}
const char* Client::TextLink::GetLinkText()
{
if (m_LinkText.length() == 0)
return nullptr;
return m_LinkText.c_str();
}
std::string Client::TextLink::GetLinkString()
{
if (m_Link.length() == 0)
return "";
return m_Link;
}
std::string Client::TextLink::GetLinkBodyString()
{
if (m_LinkBody.length() == 0)
return "";
return m_LinkBody;
}
std::string Client::TextLink::GetLinkTextString()
{
if (m_LinkText.length() == 0)
return "";
return m_LinkText;
}
void Client::TextLink::Reset()
{
m_LinkType = linkBlank;
m_ItemData = nullptr;
m_LootData = nullptr;
m_ItemInst = nullptr;
m_ProxyItemID = NOT_USED;
m_ProxyText = nullptr;
m_TaskUse = false;
m_Link.clear();
m_LinkBody.clear();
m_LinkText.clear();
m_ClientVersion = EQClientUnknown;
m_Error = false;
}
void Client::TextLink::generate_body()
{
enum { field_0 = 0, field_1, field_2, field_3, field_4, field_5, field_6, field_7, field_8, field_9, field_10, field_11, field_12, field_13 };
static const int field_count = 14;
static const bool field_use[_EQClientCount][field_count] = {
// 6.2: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X"
// SoF: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X"
// RoF: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X"
// RoF2: MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%1X" "%04X" "%1X" "%05X" "%08X"
//(RoF2) %01x %05x %05x %05x %05x %05x %05x %05x %01x %01x %04x %01x %05x %08x
{ true, true, true, true, true, true, true, true, true, true, true, true, true, true }, // EQClientUnknown
{ true, true, true, true, true, true, true, false, false, true, true, true, false, true }, // EQClient6.2
{ true, true, true, true, true, true, true, false, false, true, true, true, false, true }, // EQClientTitanium
{ true, true, true, true, true, true, true, false, false, true, true, true, true, true }, // EQClientSoF
{ true, true, true, true, true, true, true, false, false, true, true, true, true, true }, // EQClientSoD
{ true, true, true, true, true, true, true, false, false, true, true, true, true, true }, // EQClientUnderfoot
{ true, true, true, true, true, true, true, true, false, true, true, true, true, true }, // EQClientRoF
{ true, true, true, true, true, true, true, true, true, true, true, true, true, true } // EQClientRoF2
};
/*%01X*/ uint8 unknown_0 = NOT_USED;
/*%05X*/ uint32 item_id = NOT_USED;
/*%05X*/ uint32 augment_0 = NOT_USED;
/*%05X*/ uint32 augment_1 = NOT_USED;
/*%05X*/ uint32 augment_2 = NOT_USED;
/*%05X*/ uint32 augment_3 = NOT_USED;
/*%05X*/ uint32 augment_4 = NOT_USED;
/*%05X*/ uint32 augment_5 = NOT_USED;
/*%01X*/ uint8 unknown_8 = NOT_USED;
/*%01X*/ uint8 unknown_9 = NOT_USED;
/*%04X*/ uint32 unknown_10 = NOT_USED;
/*%01X*/ uint8 unknown_11 = NOT_USED;
/*%05X*/ uint32 unknown_12 = NOT_USED;
/*%08X*/ int hash = NOT_USED;
switch (m_LinkType) {
case linkBlank:
break;
case linkItemData:
if (m_ItemData != nullptr) {
item_id = m_ItemData->ID;
// TODO: add hash call
}
break;
case linkLootItem:
if (m_LootData != nullptr) {
const Item_Struct* item_data = database.GetItem(m_LootData->item_id);
if (item_data == nullptr) { break; }
item_id = item_data->ID;
augment_0 = m_LootData->aug_1;
augment_1 = m_LootData->aug_2;
augment_2 = m_LootData->aug_3;
augment_3 = m_LootData->aug_4;
augment_4 = m_LootData->aug_5;
augment_5 = m_LootData->aug_6;
// TODO: add hash call
}
break;
case linkItemInst:
if (m_ItemInst != nullptr) {
if (m_ItemInst->GetItem() == nullptr) { break; }
item_id = m_ItemInst->GetItem()->ID;
augment_0 = m_ItemInst->GetAugmentItemID(0);
augment_1 = m_ItemInst->GetAugmentItemID(1);
augment_2 = m_ItemInst->GetAugmentItemID(2);
augment_3 = m_ItemInst->GetAugmentItemID(3);
augment_4 = m_ItemInst->GetAugmentItemID(4);
augment_5 = m_ItemInst->GetAugmentItemID(5);
// TODO: add hash call
}
break;
default:
break;
}
if (m_ProxyItemID != NOT_USED) {
item_id = m_ProxyItemID;
}
if (m_TaskUse) {
hash = 0x0000000014505DC2;
}
if (field_use[m_ClientVersion][field_0]) { m_LinkBody.append(StringFormat("%01x", unknown_0)); }
if (field_use[m_ClientVersion][field_1]) { m_LinkBody.append(StringFormat("%05x", item_id)); }
if (field_use[m_ClientVersion][field_2]) { m_LinkBody.append(StringFormat("%05x", augment_0)); }
if (field_use[m_ClientVersion][field_3]) { m_LinkBody.append(StringFormat("%05x", augment_1)); }
if (field_use[m_ClientVersion][field_4]) { m_LinkBody.append(StringFormat("%05x", augment_2)); }
if (field_use[m_ClientVersion][field_5]) { m_LinkBody.append(StringFormat("%05x", augment_3)); }
if (field_use[m_ClientVersion][field_6]) { m_LinkBody.append(StringFormat("%05x", augment_4)); }
if (field_use[m_ClientVersion][field_7]) { m_LinkBody.append(StringFormat("%05x", augment_5)); }
if (field_use[m_ClientVersion][field_8]) { m_LinkBody.append(StringFormat("%01x", unknown_8)); }
if (field_use[m_ClientVersion][field_9]) { m_LinkBody.append(StringFormat("%01x", unknown_9)); }
if (field_use[m_ClientVersion][field_10]) { m_LinkBody.append(StringFormat("%04x", unknown_10)); }
if (field_use[m_ClientVersion][field_11]) { m_LinkBody.append(StringFormat("%01x", unknown_11)); }
if (field_use[m_ClientVersion][field_12]) { m_LinkBody.append(StringFormat("%05x", unknown_12)); }
if (field_use[m_ClientVersion][field_13]) { m_LinkBody.append(StringFormat("%08x", hash)); }
}
void Client::TextLink::generate_text()
{
if (m_ProxyText != nullptr) {
m_LinkText = m_ProxyText;
return;
}
switch (m_LinkType) {
case linkBlank:
break;
case linkItemData:
if (m_ItemData != nullptr) {
m_LinkText = m_ItemData->Name;
return;
}
break;
case linkLootItem:
if (m_LootData != nullptr) {
const Item_Struct* item_data = database.GetItem(m_LootData->item_id);
if (item_data != nullptr) {
m_LinkText = item_data->Name;
return;
}
}
break;
case linkItemInst:
if (m_ItemInst != nullptr) {
if (m_ItemInst->GetItem() != nullptr) {
m_LinkText = m_ItemInst->GetItem()->Name;
return;
}
}
break;
default:
break;
}
m_LinkText = "null";
}
+58 -8
View File
@@ -804,6 +804,7 @@ public:
int32 GetAugmentIDAt(int16 slot_id, uint8 augslot);
bool PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update = false);
bool PushItemOnCursor(const ItemInst& inst, bool client_update = false);
void SendCursorBuffer();
void DeleteItemInInventory(int16 slot_id, int8 quantity = 0, bool client_update = false, bool update_db = true);
bool SwapItem(MoveItem_Struct* move_in);
void SwapItemResync(MoveItem_Struct* move_slots);
@@ -814,8 +815,57 @@ public:
void SetStats(uint8 type,int16 set_val);
void IncStats(uint8 type,int16 increase_val);
void DropItem(int16 slot_id);
bool MakeItemLink(char* &ret_link, const ItemInst* inst);
int GetItemLinkHash(const ItemInst* inst);
//
// class Client::TextLink
//
class TextLink {
public:
enum LinkType { linkBlank = 0, linkItemData, linkLootItem, linkItemInst };
TextLink() { Reset(); }
void SetLinkType(LinkType linkType) { m_LinkType = linkType; }
void SetItemData(const Item_Struct* itemData) { m_ItemData = itemData; }
void SetLootData(const ServerLootItem_Struct* lootData) { m_LootData = lootData; }
void SetItemInst(const ItemInst* itemInst) { m_ItemInst = itemInst; }
void SetProxyItemID(uint32 proxyItemID) { m_ProxyItemID = proxyItemID; } // mainly for saylinks..but, not limited to
void SetProxyText(const char* proxyText) { m_ProxyText = proxyText; } // overrides standard text use
void SetTaskUse() { m_TaskUse = true; }
void SetClientVersion(EQClientVersion clientVersion) { m_ClientVersion = EQLimits::ValidateClientVersion(clientVersion); }
std::string GenerateLink();
bool LinkError() { return m_Error; }
const char* GetLink(); // contains full format: '/12x' '<LinkBody>' '<LinkText>' '/12x'
const char* GetLinkBody(); // contains format: '<LinkBody>'
const char* GetLinkText(); // contains format: '<LinkText>'
std::string GetLinkString();
std::string GetLinkBodyString();
std::string GetLinkTextString();
void Reset();
private:
void generate_body();
void generate_text();
int m_LinkType;
const Item_Struct* m_ItemData;
const ServerLootItem_Struct* m_LootData;
const ItemInst* m_ItemInst;
uint32 m_ProxyItemID;
const char* m_ProxyText;
bool m_TaskUse;
std::string m_Link;
std::string m_LinkBody;
std::string m_LinkText;
EQClientVersion m_ClientVersion;
bool m_Error;
};
int GetItemLinkHash(const ItemInst* inst); // move to Item_Struct..or make use of the pre-calculated database field
void SendItemLink(const ItemInst* inst, bool sendtoall=false);
void SendLootItemInPacket(const ItemInst* inst, int16 slot_id);
void SendItemPacket(int16 slot_id, const ItemInst* inst, ItemPacketType packet_type);
@@ -832,11 +882,11 @@ public:
bool Hungry() const {if (GetGM()) return false; return m_pp.hunger_level <= 3000;}
bool Thirsty() const {if (GetGM()) return false; return m_pp.thirst_level <= 3000;}
int32 GetHunger() const { return m_pp.hunger_level; }
int32 GetThirst() const { return m_pp.thirst_level; }
void SetHunger(int32 in_hunger);
void SetThirst(int32 in_thirst);
void SetConsumption(int32 in_hunger, int32 in_thirst);
int32 GetHunger() const { return m_pp.hunger_level; }
int32 GetThirst() const { return m_pp.thirst_level; }
void SetHunger(int32 in_hunger);
void SetThirst(int32 in_thirst);
void SetConsumption(int32 in_hunger, int32 in_thirst);
bool CheckTradeLoreConflict(Client* other);
void LinkDead();
@@ -937,7 +987,7 @@ void SetConsumption(int32 in_hunger, int32 in_thirst);
inline bool IsTaskActive(int TaskID) { return (taskstate ? taskstate->IsTaskActive(TaskID) : false); }
inline bool IsTaskActivityActive(int TaskID, int ActivityID) { return (taskstate ? taskstate->IsTaskActivityActive(TaskID, ActivityID) : false); }
inline ActivityState GetTaskActivityState(int index, int ActivityID) { return (taskstate ? taskstate->GetTaskActivityState(index, ActivityID) : ActivityHidden); }
inline void UpdateTaskActivity(int TaskID, int ActivityID, int Count) { if(taskstate) taskstate->UpdateTaskActivity(this, TaskID, ActivityID, Count); }
inline void UpdateTaskActivity(int TaskID, int ActivityID, int Count, bool ignore_quest_update = false) { if (taskstate) taskstate->UpdateTaskActivity(this, TaskID, ActivityID, Count, ignore_quest_update); }
inline void ResetTaskActivity(int TaskID, int ActivityID) { if(taskstate) taskstate->ResetTaskActivity(this, TaskID, ActivityID); }
inline void UpdateTasksOnKill(int NPCTypeID) { if(taskstate) taskstate->UpdateTasksOnKill(this, NPCTypeID); }
inline void UpdateTasksForItem(ActivityType Type, int ItemID, int Count=1) { if(taskstate) taskstate->UpdateTasksForItem(this, Type, ItemID, Count); }
+33 -39
View File
@@ -1364,7 +1364,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
database.LoadCharacterFactionValues(cid, factionvalues);
/* Load Character Account Data: Temp until I move */
query = StringFormat("SELECT `status`, `name`, `lsaccount_id`, `gmspeed`, `revoked`, `hideme` FROM `account` WHERE `id` = %u", this->AccountID());
query = StringFormat("SELECT `status`, `name`, `lsaccount_id`, `gmspeed`, `revoked`, `hideme`, `time_creation` FROM `account` WHERE `id` = %u", this->AccountID());
auto results = database.QueryDatabase(query);
for (auto row = results.begin(); row != results.end(); ++row) {
admin = atoi(row[0]);
@@ -1373,7 +1373,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
gmspeed = atoi(row[3]);
revoked = atoi(row[4]);
gmhideme = atoi(row[5]);
if (account_creation){ account_creation = atoul(row[6]); }
account_creation = atoul(row[6]);
}
/* Load Character Data */
@@ -1388,7 +1388,8 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
if (LFP){ LFP = atoi(row[0]); }
if (LFG){ LFG = atoi(row[1]); }
if (firstlogon){ firstlogon = atoi(row[3]); }
if (row[3])
firstlogon = atoi(row[3]);
}
if (RuleB(Character, SharedBankPlat))
@@ -3090,7 +3091,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
// Adding augment
if (in_augment->augment_action == 0)
{
ItemInst *tobe_auged, *auged_with = nullptr;
ItemInst *tobe_auged = nullptr, *auged_with = nullptr;
int8 slot = -1;
Inventory& user_inv = GetInv();
@@ -3160,7 +3161,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
}
else if (in_augment->augment_action == 1)
{
ItemInst *tobe_auged, *auged_with = nullptr;
ItemInst *tobe_auged = nullptr, *auged_with = nullptr;
int8 slot = -1;
Inventory& user_inv = GetInv();
@@ -5258,7 +5259,7 @@ void Client::Handle_OP_DeleteSpawn(const EQApplicationPacket *app)
entity_list.QueueClients(this, outapp, false);
safe_delete(outapp);
hate_list.RemoveEnt(this->CastToMob());
hate_list.RemoveEntFromHateList(this->CastToMob());
Disconnect();
return;
@@ -7009,37 +7010,28 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app)
if (!CursorItem->NoDrop || CursorItemInst->IsAttuned())
{
Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT);
Allowed = false;
}
else if (CursorItemInst->IsNoneEmptyContainer())
{
Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT);
Allowed = false;
}
else if (CursorItemInst->IsAugmented())
{
Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT);
Allowed = false;
}
else if (CursorItem->NoRent == 0)
{
Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT);
Allowed = false;
}
else if (CursorItem->LoreFlag && GuildBanks->HasItem(GuildID(), CursorItem->ID))
{
Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT);
Allowed = false;
}
if (!Allowed)
{
Message_StringID(13, GUILD_BANK_CANNOT_DEPOSIT);
GuildBankDepositAck(true);
return;
@@ -9210,12 +9202,6 @@ void Client::Handle_OP_LootItem(const EQApplicationPacket *app)
LogFile->write(EQEMuLog::Error, "Wrong size: OP_LootItem, size=%i, expected %i", app->size, sizeof(LootingItem_Struct));
return;
}
/*
** fixed the looting code so that it sends the correct opcodes
** and now correctly removes the looted item the player selected
** as well as gives the player the proper item.
** Also fixed a few UI lock ups that would occur.
*/
EQApplicationPacket* outapp = 0;
Entity* entity = entity_list.GetID(*((uint16*)app->pBuffer));
@@ -9802,7 +9788,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
}
}
// Illegal bagslot useage checks. Currently, user only receives a message if this check is triggered.
// Illegal bagslot usage checks. Currently, user only receives a message if this check is triggered.
bool mi_hack = false;
if (mi->from_slot >= EmuConstants::GENERAL_BAGS_BEGIN && mi->from_slot <= EmuConstants::CURSOR_BAG_END) {
@@ -9825,7 +9811,7 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
}
}
if (mi_hack) { Message(15, "Caution: Illegal use of inaccessable bag slots!"); }
if (mi_hack) { Message(15, "Caution: Illegal use of inaccessible bag slots!"); }
if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) {
SwapItemResync(mi);
@@ -12361,22 +12347,30 @@ void Client::Handle_OP_ShopPlayerSell(const EQApplicationPacket *app)
int freeslot = 0;
if (charges > 0 && (freeslot = zone->SaveTempItem(vendor->CastToNPC()->MerchantType, vendor->GetNPCTypeID(), itemid, charges, true)) > 0){
ItemInst* inst2 = inst->Clone();
if (RuleB(Merchant, UsePriceMod)){
inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate*Client::CalcPriceMod(vendor, false));
while (true) {
if (inst2 == nullptr)
break;
if (RuleB(Merchant, UsePriceMod)){
inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate*Client::CalcPriceMod(vendor, false));
}
else
inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate);
inst2->SetMerchantSlot(freeslot);
uint32 MerchantQuantity = zone->GetTempMerchantQuantity(vendor->GetNPCTypeID(), freeslot);
if (inst2->IsStackable()) {
inst2->SetCharges(MerchantQuantity);
}
inst2->SetMerchantCount(MerchantQuantity);
SendItemPacket(freeslot - 1, inst2, ItemPacketMerchant);
safe_delete(inst2);
break;
}
else
inst2->SetPrice(item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate);
inst2->SetMerchantSlot(freeslot);
uint32 MerchantQuantity = zone->GetTempMerchantQuantity(vendor->GetNPCTypeID(), freeslot);
if (inst2->IsStackable()) {
inst2->SetCharges(MerchantQuantity);
}
inst2->SetMerchantCount(MerchantQuantity);
SendItemPacket(freeslot - 1, inst2, ItemPacketMerchant);
safe_delete(inst2);
}
// start QS code
+438 -565
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -135,7 +135,8 @@ enum {
NPC_CHASE_DISTANCE = 40,
ALLOW_TO_TANK = 41,
IGNORE_ROOT_AGGRO_RULES = 42,
MAX_SPECIAL_ATTACK = 43
CASTING_RESIST_DIFF = 43,
MAX_SPECIAL_ATTACK = 44
};
typedef enum { //fear states
+20 -15
View File
@@ -1214,7 +1214,7 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
parse->EventPlayer(EVENT_LOOT, client, buf, 0, &args);
parse->EventItem(EVENT_LOOT, client, inst, this, buf, 0);
if ((RuleB(Character, EnableDiscoveredItems))) {
if (!IsPlayerCorpse() && RuleB(Character, EnableDiscoveredItems)) {
if (client && !client->GetGM() && !client->IsDiscovered(inst->GetItem()->ID))
client->DiscoverItem(inst->GetItem()->ID);
}
@@ -1261,33 +1261,38 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
}
}
if (GetPlayerKillItem() != -1){
if (GetPlayerKillItem() != -1) {
SetPlayerKillItemID(0);
}
/* Send message with item link to groups and such */
char *link = 0, *link2 = 0; //just like a db query :-)
client->MakeItemLink(link2, inst);
MakeAnyLenString(&link, "%c" "%s" "%s" "%c",
0x12,
link2,
item->Name,
0x12);
safe_delete_array(link2);
Client::TextLink linker;
linker.SetLinkType(linker.linkItemInst);
linker.SetItemInst(inst);
linker.SetClientVersion(client->GetClientVersion());
auto item_link = linker.GenerateLink();
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str());
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, link);
if(!IsPlayerCorpse()) {
// When sending to multiple/unknown client types, we set for the highest client..
// ..which is processed when 'EQClientUnknown,' or default value, is selected.
// This should help with any current issues..or it may create more! O.o
linker.SetClientVersion(EQClientUnknown);
item_link = linker.GenerateLink();
Group *g = client->GetGroup();
if(g != nullptr) {
g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), link);
} else {
g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str());
}
else {
Raid *r = client->GetRaid();
if(r != nullptr) {
r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), link);
r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str());
}
}
}
safe_delete_array(link);
}
else {
SendEndLootErrorPacket(client);
+10
View File
@@ -232,6 +232,7 @@ int PerlembParser::EventGlobalPlayer(QuestEventID evt, Client *client, std::stri
int PerlembParser::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers) {
// needs pointer validation on 'item' argument
return EventCommon(evt, item->GetID(), nullptr, nullptr, item, client, extra_data, false, extra_pointers);
}
@@ -335,6 +336,9 @@ bool PerlembParser::ItemHasQuestSub(ItemInst *itm, QuestEventID evt) {
if(!perl)
return false;
if (itm == nullptr)
return false;
if(evt >= _LargestEventID)
return false;
@@ -449,6 +453,9 @@ void PerlembParser::LoadGlobalPlayerScript(std::string filename) {
}
void PerlembParser::LoadItemScript(std::string filename, ItemInst *item) {
if (item == nullptr)
return;
std::stringstream package_name;
package_name << "qst_item_" << item->GetID();
@@ -855,6 +862,7 @@ void PerlembParser::GetQuestPackageName(bool &isPlayerQuest, bool &isGlobalPlaye
}
}
else if(isItemQuest) {
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
const Item_Struct* item = iteminst->GetItem();
package_name = "qst_item_";
package_name += itoa(item->ID);
@@ -1292,6 +1300,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
case EVENT_SCALE_CALC:
case EVENT_ITEM_ENTER_ZONE: {
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
ExportVar(package_name.c_str(), "itemid", objid);
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
break;
@@ -1299,6 +1308,7 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID
case EVENT_ITEM_CLICK_CAST:
case EVENT_ITEM_CLICK: {
// need a valid ItemInst pointer check here..unsure how to cancel this process -U
ExportVar(package_name.c_str(), "itemid", objid);
ExportVar(package_name.c_str(), "itemname", iteminst->GetItem()->Name);
ExportVar(package_name.c_str(), "slotid", extradata);
+5 -3
View File
@@ -2277,18 +2277,20 @@ XS(XS__updatetaskactivity);
XS(XS__updatetaskactivity)
{
dXSARGS;
unsigned int task, activity;
unsigned int task, activity, ignore_quest_update;
int count = 1;
ignore_quest_update = 0;
if(items == 2) {
task = (int)SvIV(ST(0));
activity = (int)SvIV(ST(1));
quest_manager.updatetaskactivity(task, activity, count);
quest_manager.updatetaskactivity(task, activity, count, false);
}
else if(items == 3) {
task = (int)SvIV(ST(0));
activity = (int)SvIV(ST(1));
count = (int)SvIV(ST(2));
quest_manager.updatetaskactivity(task, activity, count);
bool ignore_quest_update = (bool)SvTRUE(ST(3));
quest_manager.updatetaskactivity(task, activity, count, ignore_quest_update);
} else {
Perl_croak(aTHX_ "Usage: updatetaskactivity(task, activity [,count])");
}
+2
View File
@@ -210,6 +210,8 @@ Embperl::~Embperl()
" if(tied *STDERR) { untie(*STDERR); }"
,FALSE);
#endif
PL_perl_destruct_level = 1;
perl_destruct(my_perl);
perl_free(my_perl);
PERL_SYS_TERM();
my_perl = NULL;
+26 -25
View File
@@ -2043,13 +2043,16 @@ void EntityList::RemoveAllNPCs()
void EntityList::RemoveAllMercs()
{
// doesn't clear the data
merc_list.clear();
}
void EntityList::RemoveAllGroups()
{
while (group_list.size())
while (group_list.size()) {
safe_delete(group_list.front());
group_list.pop_front();
}
#if EQDEBUG >= 5
CheckGroupList (__FILE__, __LINE__);
#endif
@@ -2057,8 +2060,10 @@ void EntityList::RemoveAllGroups()
void EntityList::RemoveAllRaids()
{
while (raid_list.size())
while (raid_list.size()) {
safe_delete(raid_list.front());
raid_list.pop_front();
}
}
void EntityList::RemoveAllDoors()
@@ -2268,7 +2273,8 @@ bool EntityList::RemoveGroup(uint32 delete_id)
while(iterator != group_list.end())
{
if((*iterator)->GetID() == delete_id) {
group_list.remove (*iterator);
safe_delete(*iterator);
group_list.remove(*iterator);
#if EQDEBUG >= 5
CheckGroupList (__FILE__, __LINE__);
#endif
@@ -2291,7 +2297,8 @@ bool EntityList::RemoveRaid(uint32 delete_id)
while(iterator != raid_list.end())
{
if((*iterator)->GetID() == delete_id) {
raid_list.remove (*iterator);
safe_delete(*iterator);
raid_list.remove(*iterator);
return true;
}
++iterator;
@@ -2462,7 +2469,7 @@ void EntityList::RemoveFromHateLists(Mob *mob, bool settoone)
if (!settoone)
it->second->RemoveFromHateList(mob);
else
it->second->SetHate(mob, 1);
it->second->SetHateAmountOnEnt(mob, 1);
}
++it;
}
@@ -2846,7 +2853,7 @@ void EntityList::DoubleAggro(Mob *who)
auto it = npc_list.begin();
while (it != npc_list.end()) {
if (it->second->CheckAggro(who))
it->second->SetHate(who, it->second->CastToNPC()->GetHateAmount(who),
it->second->SetHateAmountOnEnt(who, it->second->CastToNPC()->GetHateAmount(who),
it->second->CastToNPC()->GetHateAmount(who) * 2);
++it;
}
@@ -2857,7 +2864,7 @@ void EntityList::HalveAggro(Mob *who)
auto it = npc_list.begin();
while (it != npc_list.end()) {
if (it->second->CastToNPC()->CheckAggro(who))
it->second->CastToNPC()->SetHate(who, it->second->CastToNPC()->GetHateAmount(who) / 2);
it->second->CastToNPC()->SetHateAmountOnEnt(who, it->second->CastToNPC()->GetHateAmount(who) / 2);
++it;
}
}
@@ -2872,9 +2879,9 @@ void EntityList::Evade(Mob *who)
amt = it->second->CastToNPC()->GetHateAmount(who);
amt -= flatval;
if (amt > 0)
it->second->CastToNPC()->SetHate(who, amt);
it->second->CastToNPC()->SetHateAmountOnEnt(who, amt);
else
it->second->CastToNPC()->SetHate(who, 0);
it->second->CastToNPC()->SetHateAmountOnEnt(who, 0);
}
++it;
}
@@ -2942,7 +2949,7 @@ void EntityList::ClearZoneFeignAggro(Client *targ)
}
}
void EntityList::AggroZone(Mob *who, int hate)
void EntityList::AggroZone(Mob *who, uint32 hate)
{
auto it = npc_list.begin();
while (it != npc_list.end()) {
@@ -2963,11 +2970,6 @@ void EntityList::SignalMobsByNPCID(uint32 snpc, int signal_id)
}
}
bool tracking_compare(const std::pair<Mob *, float> &a, const std::pair<Mob *, float> &b)
{
return a.first->GetSpawnTimeStamp() > b.first->GetSpawnTimeStamp();
}
bool EntityList::MakeTrackPacket(Client *client)
{
std::list<std::pair<Mob *, float> > tracking_list;
@@ -2985,8 +2987,6 @@ bool EntityList::MakeTrackPacket(Client *client)
if (distance < 300)
distance = 300;
Group *g = client->GetGroup();
for (auto it = mob_list.cbegin(); it != mob_list.cend(); ++it) {
if (!it->second || it->second == client || !it->second->IsTrackable() ||
it->second->IsInvisible(client))
@@ -2999,7 +2999,10 @@ bool EntityList::MakeTrackPacket(Client *client)
tracking_list.push_back(std::make_pair(it->second, MobDistance));
}
tracking_list.sort(tracking_compare);
tracking_list.sort(
[](const std::pair<Mob *, float> &a, const std::pair<Mob *, float> &b) {
return a.first->GetSpawnTimeStamp() > b.first->GetSpawnTimeStamp();
});
EQApplicationPacket *outapp = new EQApplicationPacket(OP_Track, sizeof(Track_Struct) * tracking_list.size());
Tracking_Struct *outtrack = (Tracking_Struct *)outapp->pBuffer;
outapp->priority = 6;
@@ -3007,15 +3010,13 @@ bool EntityList::MakeTrackPacket(Client *client)
int index = 0;
for (auto it = tracking_list.cbegin(); it != tracking_list.cend(); ++it, ++index) {
Mob *cur_entity = it->first;
outtrack->Entrys[index].entityid = cur_entity->GetID();
outtrack->Entrys[index].entityid = (uint32)cur_entity->GetID();
outtrack->Entrys[index].distance = it->second;
outtrack->Entrys[index].level = cur_entity->GetLevel();
outtrack->Entrys[index].NPC = !cur_entity->IsClient();
if (g && cur_entity->IsClient() && g->IsGroupMember(cur_entity->CastToMob()))
outtrack->Entrys[index].GroupMember = 1;
else
outtrack->Entrys[index].GroupMember = 0;
outtrack->Entrys[index].is_npc = !cur_entity->IsClient();
strn0cpy(outtrack->Entrys[index].name, cur_entity->GetName(), sizeof(outtrack->Entrys[index].name));
outtrack->Entrys[index].is_pet = cur_entity->IsPet();
outtrack->Entrys[index].is_merc = cur_entity->IsMerc();
}
client->QueuePacket(outapp);
@@ -3681,7 +3682,7 @@ void EntityList::AddTempPetsToHateList(Mob *owner, Mob* other, bool bFrenzy)
if (n->GetSwarmInfo()) {
if (n->GetSwarmInfo()->owner_id == owner->GetID()) {
if (!n->GetSpecialAbility(IMMUNE_AGGRO))
n->hate_list.Add(other, 0, 0, bFrenzy);
n->hate_list.AddEntToHateList(other, 0, 0, bFrenzy);
}
}
++it;
+1 -1
View File
@@ -355,7 +355,7 @@ public:
void ClearAggro(Mob* targ);
void ClearFeignAggro(Mob* targ);
void ClearZoneFeignAggro(Client* targ);
void AggroZone(Mob* who, int hate = 0);
void AggroZone(Mob* who, uint32 hate = 0);
bool Fighting(Mob* targ);
void RemoveFromHateLists(Mob* mob, bool settoone = false);
+1 -1
View File
@@ -249,7 +249,7 @@ void Client::GoFish()
Bait = m_inv.GetItem(bslot);
//if the bait isnt equipped, need to add its skill bonus
if(bslot >= EmuConstants::GENERAL_BEGIN && Bait->GetItem()->SkillModType == SkillFishing) {
if(bslot >= EmuConstants::GENERAL_BEGIN && Bait != nullptr && Bait->GetItem()->SkillModType == SkillFishing) {
fishing_skill += Bait->GetItem()->SkillModValue;
}
+2 -1
View File
@@ -122,7 +122,8 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu
uint32 i;
uint8 membercount = 0;
for (i = 0; i < MAX_GROUP_MEMBERS; i++) {
if (members[i] != nullptr) {
// Don't split with Mercs or Bots
if (members[i] != nullptr && members[i]->IsClient()) {
membercount++;
}
}
+226 -227
View File
@@ -1,19 +1,19 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "client.h"
@@ -36,7 +36,7 @@ extern Zone *zone;
HateList::HateList()
{
owner = nullptr;
hate_owner = nullptr;
}
HateList::~HateList()
@@ -45,29 +45,29 @@ HateList::~HateList()
// added for frenzy support
// checks if target still is in frenzy mode
void HateList::CheckFrenzyHate()
void HateList::IsEntityInFrenzyMode()
{
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
if ((*iterator)->ent->GetHPRatio() >= 20)
(*iterator)->bFrenzy = false;
if ((*iterator)->entity_on_hatelist->GetHPRatio() >= 20)
(*iterator)->is_entity_frenzy = false;
++iterator;
}
}
void HateList::Wipe()
void HateList::WipeHateList()
{
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
Mob* m = (*iterator)->ent;
if(m)
Mob* m = (*iterator)->entity_on_hatelist;
if (m)
{
parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), m, "0", 0);
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), m, "0", 0);
if(m->IsClient())
if (m->IsClient())
m->CastToClient()->DecrementAggroCount();
}
delete (*iterator);
@@ -76,38 +76,38 @@ void HateList::Wipe()
}
}
bool HateList::IsOnHateList(Mob *mob)
bool HateList::IsEntOnHateList(Mob *mob)
{
if(Find(mob))
if (Find(mob))
return true;
return false;
}
tHateEntry *HateList::Find(Mob *ent)
struct_HateList *HateList::Find(Mob *in_entity)
{
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
if((*iterator)->ent == ent)
if ((*iterator)->entity_on_hatelist == in_entity)
return (*iterator);
++iterator;
}
return nullptr;
}
void HateList::Set(Mob* other, uint32 in_hate, uint32 in_dam)
void HateList::SetHateAmountOnEnt(Mob* other, uint32 in_hate, uint32 in_damage)
{
tHateEntry *p = Find(other);
if(p)
struct_HateList *entity = Find(other);
if (entity)
{
if(in_dam > 0)
p->damage = in_dam;
if(in_hate > 0)
p->hate = in_hate;
if (in_damage > 0)
entity->hatelist_damage = in_damage;
if (in_hate > 0)
entity->stored_hate_amount = in_hate;
}
}
Mob* HateList::GetDamageTop(Mob* hater)
Mob* HateList::GetDamageTopOnHateList(Mob* hater)
{
Mob* current = nullptr;
Group* grp = nullptr;
@@ -115,119 +115,117 @@ Mob* HateList::GetDamageTop(Mob* hater)
uint32 dmg_amt = 0;
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
grp = nullptr;
r = nullptr;
if((*iterator)->ent && (*iterator)->ent->IsClient()){
r = entity_list.GetRaidByClient((*iterator)->ent->CastToClient());
if ((*iterator)->entity_on_hatelist && (*iterator)->entity_on_hatelist->IsClient()){
r = entity_list.GetRaidByClient((*iterator)->entity_on_hatelist->CastToClient());
}
grp = entity_list.GetGroupByMob((*iterator)->ent);
grp = entity_list.GetGroupByMob((*iterator)->entity_on_hatelist);
if((*iterator)->ent && r){
if(r->GetTotalRaidDamage(hater) >= dmg_amt)
if ((*iterator)->entity_on_hatelist && r){
if (r->GetTotalRaidDamage(hater) >= dmg_amt)
{
current = (*iterator)->ent;
current = (*iterator)->entity_on_hatelist;
dmg_amt = r->GetTotalRaidDamage(hater);
}
}
else if ((*iterator)->ent != nullptr && grp != nullptr)
else if ((*iterator)->entity_on_hatelist != nullptr && grp != nullptr)
{
if (grp->GetTotalGroupDamage(hater) >= dmg_amt)
{
current = (*iterator)->ent;
current = (*iterator)->entity_on_hatelist;
dmg_amt = grp->GetTotalGroupDamage(hater);
}
}
else if ((*iterator)->ent != nullptr && (uint32)(*iterator)->damage >= dmg_amt)
else if ((*iterator)->entity_on_hatelist != nullptr && (uint32)(*iterator)->hatelist_damage >= dmg_amt)
{
current = (*iterator)->ent;
dmg_amt = (*iterator)->damage;
current = (*iterator)->entity_on_hatelist;
dmg_amt = (*iterator)->hatelist_damage;
}
++iterator;
}
return current;
}
Mob* HateList::GetClosest(Mob *hater) {
Mob* close = nullptr;
float closedist = 99999.9f;
float thisdist;
Mob* HateList::GetClosestEntOnHateList(Mob *hater) {
Mob* close_entity = nullptr;
float close_distance = 99999.9f;
float this_distance;
auto iterator = list.begin();
while(iterator != list.end()) {
thisdist = (*iterator)->ent->DistNoRootNoZ(*hater);
if((*iterator)->ent != nullptr && thisdist <= closedist) {
closedist = thisdist;
close = (*iterator)->ent;
while (iterator != list.end()) {
this_distance = (*iterator)->entity_on_hatelist->DistNoRootNoZ(*hater);
if ((*iterator)->entity_on_hatelist != nullptr && this_distance <= close_distance) {
close_distance = this_distance;
close_entity = (*iterator)->entity_on_hatelist;
}
++iterator;
}
if ((!close && hater->IsNPC()) || (close && close->DivineAura()))
close = hater->CastToNPC()->GetHateTop();
if ((!close_entity && hater->IsNPC()) || (close_entity && close_entity->DivineAura()))
close_entity = hater->CastToNPC()->GetHateTop();
return close;
return close_entity;
}
// a few comments added, rearranged code for readability
void HateList::Add(Mob *ent, int32 in_hate, int32 in_dam, bool bFrenzy, bool iAddIfNotExist)
void HateList::AddEntToHateList(Mob *in_entity, int32 in_hate, int32 in_damage, bool in_is_entity_frenzied, bool iAddIfNotExist)
{
if(!ent)
if (!in_entity)
return;
if(ent->IsCorpse())
if (in_entity->IsCorpse())
return;
if(ent->IsClient() && ent->CastToClient()->IsDead())
if (in_entity->IsClient() && in_entity->CastToClient()->IsDead())
return;
tHateEntry *p = Find(ent);
if (p)
struct_HateList *entity = Find(in_entity);
if (entity)
{
p->damage+=(in_dam>=0)?in_dam:0;
p->hate+=in_hate;
p->bFrenzy = bFrenzy;
entity->hatelist_damage += (in_damage >= 0) ? in_damage : 0;
entity->stored_hate_amount += in_hate;
entity->is_entity_frenzy = in_is_entity_frenzied;
}
else if (iAddIfNotExist) {
p = new tHateEntry;
p->ent = ent;
p->damage = (in_dam>=0)?in_dam:0;
p->hate = in_hate;
p->bFrenzy = bFrenzy;
list.push_back(p);
parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), ent, "1", 0);
entity = new struct_HateList;
entity->entity_on_hatelist = in_entity;
entity->hatelist_damage = (in_damage >= 0) ? in_damage : 0;
entity->stored_hate_amount = in_hate;
entity->is_entity_frenzy = in_is_entity_frenzied;
list.push_back(entity);
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "1", 0);
if (ent->IsClient()) {
if (owner->CastToNPC()->IsRaidTarget())
ent->CastToClient()->SetEngagedRaidTarget(true);
ent->CastToClient()->IncrementAggroCount();
if (in_entity->IsClient()) {
if (hate_owner->CastToNPC()->IsRaidTarget())
in_entity->CastToClient()->SetEngagedRaidTarget(true);
in_entity->CastToClient()->IncrementAggroCount();
}
}
}
bool HateList::RemoveEnt(Mob *ent)
bool HateList::RemoveEntFromHateList(Mob *in_entity)
{
if (!ent)
if (!in_entity)
return false;
bool found = false;
bool is_found = false;
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
if((*iterator)->ent == ent)
if ((*iterator)->entity_on_hatelist == in_entity)
{
if(ent)
parse->EventNPC(EVENT_HATE_LIST, owner->CastToNPC(), ent, "0", 0);
found = true;
if (in_entity)
parse->EventNPC(EVENT_HATE_LIST, hate_owner->CastToNPC(), in_entity, "0", 0);
is_found = true;
if(ent && ent->IsClient())
ent->CastToClient()->DecrementAggroCount();
if (in_entity && in_entity->IsClient())
in_entity->CastToClient()->DecrementAggroCount();
delete (*iterator);
iterator = list.erase(iterator);
@@ -236,123 +234,127 @@ bool HateList::RemoveEnt(Mob *ent)
else
++iterator;
}
return found;
return is_found;
}
void HateList::DoFactionHits(int32 nfl_id) {
if (nfl_id <= 0)
void HateList::DoFactionHits(int32 npc_faction_level_id) {
if (npc_faction_level_id <= 0)
return;
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
Client *p;
Client *client;
if ((*iterator)->ent && (*iterator)->ent->IsClient())
p = (*iterator)->ent->CastToClient();
if ((*iterator)->entity_on_hatelist && (*iterator)->entity_on_hatelist->IsClient())
client = (*iterator)->entity_on_hatelist->CastToClient();
else
p = nullptr;
client = nullptr;
if (p)
p->SetFactionLevel(p->CharacterID(), nfl_id, p->GetBaseClass(), p->GetBaseRace(), p->GetDeity());
if (client)
client->SetFactionLevel(client->CharacterID(), npc_faction_level_id, client->GetBaseClass(), client->GetBaseRace(), client->GetDeity());
++iterator;
}
}
int HateList::SummonedPetCount(Mob *hater) {
int HateList::GetSummonedPetCountOnHateList(Mob *hater) {
//Function to get number of 'Summoned' pets on a targets hate list to allow calculations for certian spell effects.
//Unclear from description that pets are required to be 'summoned body type'. Will not require at this time.
int petcount = 0;
int pet_count = 0;
auto iterator = list.begin();
while(iterator != list.end()) {
while (iterator != list.end()) {
if((*iterator)->ent != nullptr && (*iterator)->ent->IsNPC() && ((*iterator)->ent->CastToNPC()->IsPet() || ((*iterator)->ent->CastToNPC()->GetSwarmOwner() > 0)))
if ((*iterator)->entity_on_hatelist != nullptr && (*iterator)->entity_on_hatelist->IsNPC() && ((*iterator)->entity_on_hatelist->CastToNPC()->IsPet() || ((*iterator)->entity_on_hatelist->CastToNPC()->GetSwarmOwner() > 0)))
{
++petcount;
++pet_count;
}
++iterator;
}
return petcount;
return pet_count;
}
Mob *HateList::GetTop(Mob *center)
Mob *HateList::GetEntWithMostHateOnList(Mob *center)
{
Mob* top = nullptr;
int32 hate = -1;
if(center == nullptr)
// hack fix for zone shutdown crashes on some servers
if (!zone->IsLoaded())
return nullptr;
if (RuleB(Aggro,SmartAggroList)){
Mob* topClientTypeInRange = nullptr;
int32 hateClientTypeInRange = -1;
Mob* top_hate = nullptr;
int32 hate = -1;
if (center == nullptr)
return nullptr;
if (RuleB(Aggro, SmartAggroList)){
Mob* top_client_type_in_range = nullptr;
int32 hate_client_type_in_range = -1;
int skipped_count = 0;
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
tHateEntry *cur = (*iterator);
int16 aggroMod = 0;
struct_HateList *cur = (*iterator);
int16 aggro_mod = 0;
if(!cur){
if (!cur){
++iterator;
continue;
}
if(!cur->ent){
if (!cur->entity_on_hatelist){
++iterator;
continue;
}
if(center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if(!zone->watermap->InLiquid(cur->ent->GetX(), cur->ent->GetY(), cur->ent->GetZ())) {
if (center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if (!zone->watermap->InLiquid(cur->entity_on_hatelist->GetX(), cur->entity_on_hatelist->GetY(), cur->entity_on_hatelist->GetZ())) {
skipped_count++;
++iterator;
continue;
}
}
if (cur->ent->Sanctuary()) {
if(hate == -1)
if (cur->entity_on_hatelist->Sanctuary()) {
if (hate == -1)
{
top = cur->ent;
top_hate = cur->entity_on_hatelist;
hate = 1;
}
++iterator;
continue;
}
if(cur->ent->DivineAura() || cur->ent->IsMezzed() || cur->ent->IsFeared()){
if(hate == -1)
if (cur->entity_on_hatelist->DivineAura() || cur->entity_on_hatelist->IsMezzed() || cur->entity_on_hatelist->IsFeared()){
if (hate == -1)
{
top = cur->ent;
top_hate = cur->entity_on_hatelist;
hate = 0;
}
++iterator;
continue;
}
int32 currentHate = cur->hate;
int32 current_hate = cur->stored_hate_amount;
if(cur->ent->IsClient()){
if (cur->entity_on_hatelist->IsClient()){
if(cur->ent->CastToClient()->IsSitting()){
aggroMod += RuleI(Aggro, SittingAggroMod);
if (cur->entity_on_hatelist->CastToClient()->IsSitting()){
aggro_mod += RuleI(Aggro, SittingAggroMod);
}
if(center){
if(center->GetTarget() == cur->ent)
aggroMod += RuleI(Aggro, CurrentTargetAggroMod);
if(RuleI(Aggro, MeleeRangeAggroMod) != 0)
if (center){
if (center->GetTarget() == cur->entity_on_hatelist)
aggro_mod += RuleI(Aggro, CurrentTargetAggroMod);
if (RuleI(Aggro, MeleeRangeAggroMod) != 0)
{
if(center->CombatRange(cur->ent)){
aggroMod += RuleI(Aggro, MeleeRangeAggroMod);
if (center->CombatRange(cur->entity_on_hatelist)){
aggro_mod += RuleI(Aggro, MeleeRangeAggroMod);
if(currentHate > hateClientTypeInRange || cur->bFrenzy){
hateClientTypeInRange = currentHate;
topClientTypeInRange = cur->ent;
if (current_hate > hate_client_type_in_range || cur->is_entity_frenzy){
hate_client_type_in_range = current_hate;
top_client_type_in_range = cur->entity_on_hatelist;
}
}
}
@@ -360,112 +362,112 @@ Mob *HateList::GetTop(Mob *center)
}
else{
if(center){
if(center->GetTarget() == cur->ent)
aggroMod += RuleI(Aggro, CurrentTargetAggroMod);
if(RuleI(Aggro, MeleeRangeAggroMod) != 0)
if (center){
if (center->GetTarget() == cur->entity_on_hatelist)
aggro_mod += RuleI(Aggro, CurrentTargetAggroMod);
if (RuleI(Aggro, MeleeRangeAggroMod) != 0)
{
if(center->CombatRange(cur->ent)){
aggroMod += RuleI(Aggro, MeleeRangeAggroMod);
if (center->CombatRange(cur->entity_on_hatelist)){
aggro_mod += RuleI(Aggro, MeleeRangeAggroMod);
}
}
}
}
if(cur->ent->GetMaxHP() != 0 && ((cur->ent->GetHP()*100/cur->ent->GetMaxHP()) < 20)){
aggroMod += RuleI(Aggro, CriticallyWoundedAggroMod);
if (cur->entity_on_hatelist->GetMaxHP() != 0 && ((cur->entity_on_hatelist->GetHP() * 100 / cur->entity_on_hatelist->GetMaxHP()) < 20)){
aggro_mod += RuleI(Aggro, CriticallyWoundedAggroMod);
}
if(aggroMod){
currentHate += (currentHate * aggroMod / 100);
if (aggro_mod){
current_hate += (current_hate * aggro_mod / 100);
}
if(currentHate > hate || cur->bFrenzy){
hate = currentHate;
top = cur->ent;
if (current_hate > hate || cur->is_entity_frenzy){
hate = current_hate;
top_hate = cur->entity_on_hatelist;
}
++iterator;
}
if(topClientTypeInRange != nullptr && top != nullptr) {
bool isTopClientType = top->IsClient();
if (top_client_type_in_range != nullptr && top_hate != nullptr) {
bool isTopClientType = top_hate->IsClient();
#ifdef BOTS
if(!isTopClientType) {
if(top->IsBot()) {
if (!isTopClientType) {
if (top_hate->IsBot()) {
isTopClientType = true;
topClientTypeInRange = top;
top_client_type_in_range = top_hate;
}
}
#endif //BOTS
if(!isTopClientType) {
if(top->IsMerc()) {
if (!isTopClientType) {
if (top_hate->IsMerc()) {
isTopClientType = true;
topClientTypeInRange = top;
top_client_type_in_range = top_hate;
}
}
if (!isTopClientType) {
if (top->GetSpecialAbility(ALLOW_TO_TANK)){
if (top_hate->GetSpecialAbility(ALLOW_TO_TANK)){
isTopClientType = true;
topClientTypeInRange = top;
top_client_type_in_range = top_hate;
}
}
if(!isTopClientType)
return topClientTypeInRange ? topClientTypeInRange : nullptr;
if (!isTopClientType)
return top_client_type_in_range ? top_client_type_in_range : nullptr;
return top ? top : nullptr;
return top_hate ? top_hate : nullptr;
}
else {
if(top == nullptr && skipped_count > 0) {
if (top_hate == nullptr && skipped_count > 0) {
return center->GetTarget() ? center->GetTarget() : nullptr;
}
return top ? top : nullptr;
return top_hate ? top_hate : nullptr;
}
}
else{
auto iterator = list.begin();
int skipped_count = 0;
while(iterator != list.end())
while (iterator != list.end())
{
tHateEntry *cur = (*iterator);
if(center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if(!zone->watermap->InLiquid(cur->ent->GetX(), cur->ent->GetY(), cur->ent->GetZ())) {
struct_HateList *cur = (*iterator);
if (center->IsNPC() && center->CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if (!zone->watermap->InLiquid(cur->entity_on_hatelist->GetX(), cur->entity_on_hatelist->GetY(), cur->entity_on_hatelist->GetZ())) {
skipped_count++;
++iterator;
continue;
}
}
if(cur->ent != nullptr && ((cur->hate > hate) || cur->bFrenzy ))
if (cur->entity_on_hatelist != nullptr && ((cur->stored_hate_amount > hate) || cur->is_entity_frenzy))
{
top = cur->ent;
hate = cur->hate;
top_hate = cur->entity_on_hatelist;
hate = cur->stored_hate_amount;
}
++iterator;
}
if(top == nullptr && skipped_count > 0) {
if (top_hate == nullptr && skipped_count > 0) {
return center->GetTarget() ? center->GetTarget() : nullptr;
}
return top ? top : nullptr;
return top_hate ? top_hate : nullptr;
}
return nullptr;
}
Mob *HateList::GetMostHate(){
Mob *HateList::GetEntWithMostHateOnList(){
Mob* top = nullptr;
int32 hate = -1;
auto iterator = list.begin();
while(iterator != list.end())
while (iterator != list.end())
{
tHateEntry *cur = (*iterator);
if(cur->ent != nullptr && (cur->hate > hate))
struct_HateList *cur = (*iterator);
if (cur->entity_on_hatelist != nullptr && (cur->stored_hate_amount > hate))
{
top = cur->ent;
hate = cur->hate;
top = cur->entity_on_hatelist;
hate = cur->stored_hate_amount;
}
++iterator;
}
@@ -473,16 +475,16 @@ Mob *HateList::GetMostHate(){
}
Mob *HateList::GetRandom()
Mob *HateList::GetRandomEntOnHateList()
{
int count = list.size();
if(count == 0) //If we don't have any entries it'll crash getting a random 0, -1 position.
if (count == 0) //If we don't have any entries it'll crash getting a random 0, -1 position.
return NULL;
if(count == 1) //No need to do all that extra work if we only have one hate entry
if (count == 1) //No need to do all that extra work if we only have one hate entry
{
if(*list.begin()) // Just in case tHateEntry is invalidated somehow...
return (*list.begin())->ent;
if (*list.begin()) // Just in case tHateEntry is invalidated somehow...
return (*list.begin())->entity_on_hatelist;
return NULL;
}
@@ -492,38 +494,36 @@ Mob *HateList::GetRandom()
for (int i = 0; i < random; i++)
++iterator;
return (*iterator)->ent;
return (*iterator)->entity_on_hatelist;
}
int32 HateList::GetEntHate(Mob *ent, bool damage)
int32 HateList::GetEntHateAmount(Mob *in_entity, bool damage)
{
tHateEntry *p;
struct_HateList *entity;
p = Find(ent);
entity = Find(in_entity);
if ( p && damage)
return p->damage;
else if (p)
return p->hate;
if (entity && damage)
return entity->hatelist_damage;
else if (entity)
return entity->stored_hate_amount;
else
return 0;
}
//looking for any mob with hate > -1
bool HateList::IsEmpty() {
bool HateList::IsHateListEmpty() {
return(list.size() == 0);
}
// Prints hate list to a client
void HateList::PrintToClient(Client *c)
void HateList::PrintHateListToClient(Client *c)
{
auto iterator = list.begin();
while (iterator != list.end())
{
tHateEntry *e = (*iterator);
struct_HateList *e = (*iterator);
c->Message(0, "- name: %s, damage: %d, hate: %d",
(e->ent && e->ent->GetName()) ? e->ent->GetName() : "(null)",
e->damage, e->hate);
(e->entity_on_hatelist && e->entity_on_hatelist->GetName()) ? e->entity_on_hatelist->GetName() : "(null)",
e->hatelist_damage, e->stored_hate_amount);
++iterator;
}
@@ -531,7 +531,7 @@ void HateList::PrintToClient(Client *c)
int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOptions *opts)
{
if(!target || !caster)
if (!target || !caster)
return 0;
int ret = 0;
@@ -539,25 +539,25 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption
auto iterator = list.begin();
while (iterator != list.end())
{
tHateEntry *h = (*iterator);
struct_HateList *h = (*iterator);
++iterator;
if(h && h->ent && h->ent != caster)
if (h && h->entity_on_hatelist && h->entity_on_hatelist != caster)
{
if(caster->CombatRange(h->ent))
if (caster->CombatRange(h->entity_on_hatelist))
{
id_list.push_back(h->ent->GetID());
id_list.push_back(h->entity_on_hatelist->GetID());
++ret;
}
}
}
std::list<uint32>::iterator iter = id_list.begin();
while(iter != id_list.end())
while (iter != id_list.end())
{
Mob *cur = entity_list.GetMobID((*iter));
if(cur)
if (cur)
{
for(int i = 0; i < count; ++i) {
for (int i = 0; i < count; ++i) {
caster->Attack(cur, MainPrimary, false, false, false, opts);
}
}
@@ -569,7 +569,7 @@ int HateList::AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOption
void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_center)
{
if(!caster)
if (!caster)
return;
Mob* center = caster;
@@ -588,33 +588,32 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range, Mob* ae_cent
auto iterator = list.begin();
while (iterator != list.end())
{
tHateEntry *h = (*iterator);
if(range > 0)
struct_HateList *h = (*iterator);
if (range > 0)
{
dist_targ = center->DistNoRoot(*h->ent);
if(dist_targ <= range && dist_targ >= min_range2)
dist_targ = center->DistNoRoot(*h->entity_on_hatelist);
if (dist_targ <= range && dist_targ >= min_range2)
{
id_list.push_back(h->ent->GetID());
h->ent->CalcSpellPowerDistanceMod(spell_id, dist_targ);
id_list.push_back(h->entity_on_hatelist->GetID());
h->entity_on_hatelist->CalcSpellPowerDistanceMod(spell_id, dist_targ);
}
}
else
{
id_list.push_back(h->ent->GetID());
h->ent->CalcSpellPowerDistanceMod(spell_id, 0, caster);
id_list.push_back(h->entity_on_hatelist->GetID());
h->entity_on_hatelist->CalcSpellPowerDistanceMod(spell_id, 0, caster);
}
++iterator;
}
std::list<uint32>::iterator iter = id_list.begin();
while(iter != id_list.end())
while (iter != id_list.end())
{
Mob *cur = entity_list.GetMobID((*iter));
if(cur)
if (cur)
{
caster->SpellOnTarget(spell_id, cur);
}
iter++;
}
}
+41 -55
View File
@@ -1,19 +1,19 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef HATELIST_H
@@ -25,11 +25,12 @@ class Mob;
class Raid;
struct ExtraAttackOptions;
struct tHateEntry
struct struct_HateList
{
Mob *ent;
int32 damage, hate;
bool bFrenzy;
Mob *entity_on_hatelist;
int32 hatelist_damage;
uint32 stored_hate_amount;
bool is_entity_frenzy;
};
class HateList
@@ -38,53 +39,38 @@ public:
HateList();
~HateList();
// adds a mob to the hatelist
void Add(Mob *ent, int32 in_hate=0, int32 in_dam=0, bool bFrenzy = false, bool iAddIfNotExist = true);
// sets existing hate
void Set(Mob *other, uint32 in_hate, uint32 in_dam);
// removes mobs from hatelist
bool RemoveEnt(Mob *ent);
// Remove all
void Wipe();
// ???
void DoFactionHits(int32 nfl_id);
// Gets Hate amount for mob
int32 GetEntHate(Mob *ent, bool damage = false);
// gets top hated mob
Mob *GetTop(Mob *center);
// gets any on the list
Mob *GetRandom();
// get closest mob or nullptr if list empty
Mob *GetClosest(Mob *hater);
// gets top mob or nullptr if hate list empty
Mob *GetDamageTop(Mob *hater);
// used to check if mob is on hatelist
bool IsOnHateList(Mob *);
// used to remove or add frenzy hate
void CheckFrenzyHate();
//Gets the target with the most hate regardless of things like frenzy etc.
Mob* GetMostHate();
// Count 'Summoned' pets on hatelist
int SummonedPetCount(Mob *hater);
Mob *GetClosestEntOnHateList(Mob *hater);
Mob *GetDamageTopOnHateList(Mob *hater);
Mob *GetEntWithMostHateOnList(Mob *center);
Mob *GetRandomEntOnHateList();
Mob* GetEntWithMostHateOnList();
bool IsEntOnHateList(Mob *mob);
bool IsHateListEmpty();
bool RemoveEntFromHateList(Mob *ent);
int AreaRampage(Mob *caster, Mob *target, int count, ExtraAttackOptions *opts);
int GetSummonedPetCountOnHateList(Mob *hater);
void SpellCast(Mob *caster, uint32 spell_id, float range, Mob *ae_center = nullptr);
int32 GetEntHateAmount(Mob *ent, bool in_damage = false);
bool IsEmpty();
void PrintToClient(Client *c);
std::list<struct_HateList*>& GetHateList() { return list; }
//For accessing the hate list via perl; don't use for anything else
std::list<tHateEntry*>& GetHateList() { return list; }
void AddEntToHateList(Mob *ent, int32 in_hate = 0, int32 in_damage = 0, bool in_is_frenzied = false, bool add_to_hate_list_if_not_exist = true);
void DoFactionHits(int32 npc_faction_level_id);
void IsEntityInFrenzyMode();
void PrintHateListToClient(Client *c);
void SetHateAmountOnEnt(Mob *other, uint32 in_hate, uint32 in_damage);
void SetHateOwner(Mob *new_hate_owner) { hate_owner = new_hate_owner; }
void SpellCast(Mob *caster, uint32 spell_id, float range, Mob *ae_center = nullptr);
void WipeHateList();
//setting owner
void SetOwner(Mob *newOwner) { owner = newOwner; }
protected:
tHateEntry* Find(Mob *ent);
struct_HateList* Find(Mob *ent);
private:
std::list<tHateEntry*> list;
Mob *owner;
std::list<struct_HateList*> list;
Mob *hate_owner;
};
#endif
#endif
+126 -76
View File
@@ -617,6 +617,7 @@ void Client::DropItem(int16 slot_id)
// Save client inventory change to database
if (slot_id == MainCursor) {
SendCursorBuffer();
std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
database.SaveCursor(CharacterID(), s, e);
} else {
@@ -678,6 +679,23 @@ int32 Client::GetAugmentIDAt(int16 slot_id, uint8 augslot) {
return INVALID_ID;
}
void Client::SendCursorBuffer() {
// Temporary work-around for the RoF+ Client Buffer
// Instead of dealing with client moving items in cursor buffer,
// we can just send the next item in the cursor buffer to the cursor.
if (GetClientVersion() >= EQClientRoF)
{
if (!GetInv().CursorEmpty())
{
const ItemInst* inst = GetInv().GetCursorItem();
if (inst)
{
SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
}
}
}
}
// Remove item from inventory
void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_update, bool update_db) {
#if (EQDEBUG >= 5)
@@ -794,10 +812,6 @@ void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_upd
}
}
// Puts an item into the person's inventory
// Any items already there will be removed from user's inventory
// (Also saves changes back to the database: this may be optimized in the future)
// client_update: Sends packet to client
bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
{
mlog(INVENTORY__SLOTS, "Putting item %s (%d) on the cursor", inst.GetItem()->Name, inst.GetItem()->ID);
@@ -811,6 +825,10 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
return database.SaveCursor(CharacterID(), s, e);
}
// Puts an item into the person's inventory
// Any items already there will be removed from user's inventory
// (Also saves changes back to the database: this may be optimized in the future)
// client_update: Sends packet to client
bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client_update) {
mlog(INVENTORY__SLOTS, "Putting item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id);
@@ -908,7 +926,7 @@ bool Client::TryStacking(ItemInst* item, uint8 type, bool try_worn, bool try_cur
bool Client::AutoPutLootInInventory(ItemInst& inst, bool try_worn, bool try_cursor, ServerLootItem_Struct** bag_item_data)
{
// #1: Try to auto equip
if (try_worn && inst.IsEquipable(GetBaseRace(), GetClass()) && inst.GetItem()->ReqLevel<=level && !inst.GetItem()->Attuneable && inst.GetItem()->ItemType != ItemTypeAugmentation)
if (try_worn && inst.IsEquipable(GetBaseRace(), GetClass()) && inst.GetItem()->ReqLevel<=level && (!inst.GetItem()->Attuneable || inst.IsAttuned()) && inst.GetItem()->ItemType != ItemTypeAugmentation)
{
// too messy as-is... <watch>
for (int16 i = EmuConstants::EQUIPMENT_BEGIN; i < MainPowerSource; i++) // originally (i < 22)
@@ -1009,105 +1027,113 @@ void Client::MoveItemCharges(ItemInst &from, int16 to_slot, uint8 type)
}
}
bool Client::MakeItemLink(char* &ret_link, const ItemInst *inst) {
// TODO: needs clean-up to save references
bool MakeItemLink(char* &ret_link, const Item_Struct *item, uint32 aug0, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, uint8 evolving, uint8 evolvedlevel) {
//we're sending back the entire "link", minus the null characters & item name
//that way, we can use it for regular links & Task links
//note: initiator needs to pass us ret_link
/*
/*
--- Usage ---
Chat: "%c" "%s" "%s" "%c", 0x12, ret_link, inst->GetItem()->name, 0x12
Task: "<a WndNotify=\"27," "%s" "\">" "%s" "</a>", ret_link, inst->GetItem()->name
<a WndNotify="27,00960F000000000000000000000000000000000000000">Master's Book of Wood Elven Culture</a>
http://eqitems.13th-floor.org/phpBB2/viewtopic.php?p=510#510
*/
<a WndNotify="27,00960F000000000000000000000000000000000000000">Master's Book of Wood Elven Culture</a>
http://eqitems.13th-floor.org/phpBB2/viewtopic.php?p=510#510
*/
if (!inst) //have to have an item to make the link
if (!item) //have to have an item to make the link
return false;
const Item_Struct* item = inst->GetItem();
//format:
//0 itemid aug1 aug2 aug3 aug4 aug5 evolving? loregroup evolved level hash
//0 00000 00000 00000 00000 00000 00000 0 0000 0 00000000
//length:
//1 5 5 5 5 5 5 1 4 1 8 = 45
//evolving item info: http://eqitems.13th-floor.org/phpBB2/viewtopic.php?t=145#558
uint8 evolving = 0;
uint16 loregroup = 0;
uint8 evolvedlevel = 0;
int hash = 0;
//int hash = GetItemLinkHash(inst); //eventually this will work (currently crashes zone), but for now we'll skip the extra overhead
if (GetClientVersion() >= EQClientRoF2)
{
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%01X" "%1X" "%04X" "%1X" "%05X" "%08X",
int hash = NOT_USED;
// Tested with UF and RoF..there appears to be a problem with using non-augment arguments below...
// Currently, enabling them causes misalignments in what the client expects. I haven't looked
// into it further to determine the cause..but, the function is setup to accept the parameters.
// Note: some links appear with '00000' in front of the name..so, it's likely we need to send
// some additional information when certain parameters are true -U
//switch (GetClientVersion()) {
switch (0) {
case EQClientRoF2:
// This operator contains 14 parameter masks..but, only 13 parameter values.
// Even so, the client link appears ok... Need to figure out the discrepancy -U
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%1X" "%04X" "%1X" "%05X" "%08X",
0,
item->ID,
inst->GetAugmentItemID(0),
inst->GetAugmentItemID(1),
inst->GetAugmentItemID(2),
inst->GetAugmentItemID(3),
inst->GetAugmentItemID(4),
inst->GetAugmentItemID(5),
evolving,
loregroup,
evolvedlevel,
aug0,
aug1,
aug2,
aug3,
aug4,
aug5,
0,//evolving,
0,//item->LoreGroup,
0,//evolvedlevel,
0,
hash
);
}
else if (GetClientVersion() >= EQClientRoF)
{
return true;
case EQClientRoF:
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X",
0,
item->ID,
inst->GetAugmentItemID(0),
inst->GetAugmentItemID(1),
inst->GetAugmentItemID(2),
inst->GetAugmentItemID(3),
inst->GetAugmentItemID(4),
inst->GetAugmentItemID(5),
evolving,
loregroup,
evolvedlevel,
aug0,
aug1,
aug2,
aug3,
aug4,
aug5,
0,//evolving,
0,//item->LoreGroup,
0,//evolvedlevel,
0,
hash
);
}
else if (GetClientVersion() >= EQClientSoF)
{
);
return true;
case EQClientUnderfoot:
case EQClientSoD:
case EQClientSoF:
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%05X" "%08X",
0,
item->ID,
inst->GetAugmentItemID(0),
inst->GetAugmentItemID(1),
inst->GetAugmentItemID(2),
inst->GetAugmentItemID(3),
inst->GetAugmentItemID(4),
evolving,
loregroup,
evolvedlevel,
aug0,
aug1,
aug2,
aug3,
aug4,
0,//evolving,
0,//item->LoreGroup,
0,//evolvedlevel,
0,
hash
);
}
else
{
);
return true;
case EQClientTitanium:
MakeAnyLenString(&ret_link, "%1X" "%05X" "%05X" "%05X" "%05X" "%05X" "%05X" "%1X" "%04X" "%1X" "%08X",
0,
item->ID,
inst->GetAugmentItemID(0),
inst->GetAugmentItemID(1),
inst->GetAugmentItemID(2),
inst->GetAugmentItemID(3),
inst->GetAugmentItemID(4),
evolving,
loregroup,
evolvedlevel,
aug0,
aug1,
aug2,
aug3,
aug4,
0,//evolving,
0,//item->LoreGroup,
0,//evolvedlevel,
hash
);
);
return true;
case EQClient62:
default:
return false;
}
return true;
}
int Client::GetItemLinkHash(const ItemInst* inst) {
@@ -1198,6 +1224,7 @@ int Client::GetItemLinkHash(const ItemInst* inst) {
return hash;
}
// This appears to still be in use... The core of this should be incorporated into class Client::TextLink
void Client::SendItemLink(const ItemInst* inst, bool send_to_all)
{
/*
@@ -1299,7 +1326,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
// This could be expounded upon at some point to let the server know that
// the client has moved a buffered cursor item onto the active cursor -U
if (move_in->from_slot == move_in->to_slot) { // Item summon, no further proccessing needed
if (move_in->from_slot == move_in->to_slot) { // Item summon, no further processing needed
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
return true;
}
@@ -1315,13 +1342,15 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
}
DeleteItemInInventory(move_in->from_slot);
SendCursorBuffer();
return true; // Item destroyed by client
}
else {
mlog(INVENTORY__SLOTS, "Deleted item from slot %d as a result of an inventory container tradeskill combine.", move_in->from_slot);
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
DeleteItemInInventory(move_in->from_slot);
return true; // Item deletetion
return true; // Item deletion
}
}
if(auto_attack && (move_in->from_slot == MainPrimary || move_in->from_slot == MainSecondary || move_in->from_slot == MainRange))
@@ -1363,7 +1392,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
//SetTint(dst_slot_id,src_inst->GetColor());
if (src_inst->GetCharges() > 0 && (src_inst->GetCharges() < (int16)move_in->number_in_stack || move_in->number_in_stack > src_inst->GetItem()->StackSize))
{
Message(13,"Error: Insufficent number in stack.");
Message(13,"Error: Insufficient number in stack.");
return false;
}
}
@@ -1520,11 +1549,19 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
}
safe_delete(world_inst);
if (src_slot_id == MainCursor) {
std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
if (src_slot_id == MainCursor)
{
if (dstitemid == 0)
{
SendCursorBuffer();
}
std::list<ItemInst*>::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end();
database.SaveCursor(character_id, s, e);
} else
}
else
{
database.SaveInventory(character_id, m_inv[src_slot_id], src_slot_id);
}
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in, true); } // QS Audit
@@ -1551,6 +1588,10 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
trade->AddEntity(dst_slot_id, move_in->number_in_stack);
if (dstitemid == 0)
{
SendCursorBuffer();
}
return true;
} else {
@@ -1563,6 +1604,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
}
}
bool all_to_stack = false;
// Step 5: Swap (or stack) items
if (move_in->number_in_stack > 0) {
// Determine if charged items can stack
@@ -1593,6 +1635,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
mlog(INVENTORY__SLOTS, "Dest (%d) now has %d charges, source (%d) was entirely consumed. (%d moved)", dst_slot_id, dst_inst->GetCharges(), src_slot_id, usedcharges);
database.SaveInventory(CharacterID(),nullptr,src_slot_id);
m_inv.DeleteItem(src_slot_id);
all_to_stack = true;
} else {
mlog(INVENTORY__SLOTS, "Dest (%d) now has %d charges, source (%d) has %d (%d moved)", dst_slot_id, dst_inst->GetCharges(), src_slot_id, src_inst->GetCharges(), usedcharges);
}
@@ -1666,6 +1709,11 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
// Step 7: Save change to the database
if (src_slot_id == MainCursor){
// If not swapping another item to cursor and stacking items were depleted
if (dstitemid == 0 || all_to_stack == true)
{
SendCursorBuffer();
}
std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
database.SaveCursor(character_id, s, e);
} else
@@ -1968,7 +2016,7 @@ void Client::DyeArmor(DyeStruct* dye){
bool Client::DecreaseByID(uint32 type, uint8 amt) {
const Item_Struct* TempItem = 0;
ItemInst* ins;
ItemInst* ins = nullptr;
int x;
int num = 0;
for(x = EmuConstants::EQUIPMENT_BEGIN; x <= EmuConstants::GENERAL_BAGS_END; x++)
@@ -2104,6 +2152,7 @@ void Client::RemoveNoRent(bool client_update) {
std::list<ItemInst*>::iterator iter = local.begin();
while (iter != local.end()) {
inst = *iter;
// should probably put a check here for valid pointer..but, that was checked when the item was put into inventory -U
if (!inst->GetItem()->NoRent)
mlog(INVENTORY__SLOTS, "NoRent Timer Lapse: Deleting %s from `Limbo`", inst->GetItem()->Name);
else
@@ -2229,6 +2278,7 @@ void Client::RemoveDuplicateLore(bool client_update) {
std::list<ItemInst*>::iterator iter = local.begin();
while (iter != local.end()) {
inst = *iter;
// probably needs a valid pointer check -U
if (CheckLoreConflict(inst->GetItem())) {
mlog(INVENTORY__ERROR, "Lore Duplication Error: Deleting %s from `Limbo`", inst->GetItem()->Name);
safe_delete(*iter);
@@ -2431,8 +2481,8 @@ void Client::CreateBandolier(const EQApplicationPacket *app) {
_log(INVENTORY__BANDOLIER, "Char: %s Creating Bandolier Set %i, Set Name: %s", GetName(), bs->number, bs->name);
strcpy(m_pp.bandoliers[bs->number].name, bs->name);
const ItemInst* InvItem;
const Item_Struct *BaseItem;
const ItemInst* InvItem = nullptr;
const Item_Struct *BaseItem = nullptr;
int16 WeaponSlot;
for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
+1 -1
View File
@@ -324,7 +324,7 @@ void NPC::AddLootDrop(const Item_Struct *item2, ItemList* itemlist, int16 charge
what was this about???
if (((npc->GetRace()==127) && (npc->CastToMob()->GetOwnerID()!=0)) && (item2->Slots==24576) || (item2->Slots==8192) || (item2->Slots==16384)){
npc->d_meele_texture2=atoi(newid);
npc->d_melee_texture2=atoi(newid);
wc->wear_slot_id=8;
if (item2->Material >0)
wc->material=item2->Material;
+2 -2
View File
@@ -1354,8 +1354,8 @@ void lua_create_npc(luabind::adl::object table, float x, float y, float z, float
LuaCreateNPCParse(max_dmg, uint32, 4);
LuaCreateNPCParse(attack_count, int16, 0);
LuaCreateNPCParseString(special_abilities, 512, "");
LuaCreateNPCParse(d_meele_texture1, uint16, 0);
LuaCreateNPCParse(d_meele_texture2, uint16, 0);
LuaCreateNPCParse(d_melee_texture1, uint16, 0);
LuaCreateNPCParse(d_melee_texture2, uint16, 0);
LuaCreateNPCParseString(ammo_idfile, 32, "");
LuaCreateNPCParse(prim_melee_type, uint8, 0);
LuaCreateNPCParse(sec_melee_type, uint8, 0);
+8 -8
View File
@@ -12,42 +12,42 @@
Lua_Mob Lua_HateEntry::GetEnt() {
Lua_Safe_Call_Class(Lua_Mob);
return Lua_Mob(self->ent);
return Lua_Mob(self->entity_on_hatelist);
}
void Lua_HateEntry::SetEnt(Lua_Mob e) {
Lua_Safe_Call_Void();
self->ent = e;
self->entity_on_hatelist = e;
}
int Lua_HateEntry::GetDamage() {
Lua_Safe_Call_Int();
return self->damage;
return self->hatelist_damage;
}
void Lua_HateEntry::SetDamage(int value) {
Lua_Safe_Call_Void();
self->damage = value;
self->hatelist_damage = value;
}
int Lua_HateEntry::GetHate() {
Lua_Safe_Call_Int();
return self->hate;
return self->stored_hate_amount;
}
void Lua_HateEntry::SetHate(int value) {
Lua_Safe_Call_Void();
self->hate = value;
self->stored_hate_amount = value;
}
int Lua_HateEntry::GetFrenzy() {
Lua_Safe_Call_Int();
return self->bFrenzy;
return self->is_entity_frenzy;
}
void Lua_HateEntry::SetFrenzy(bool value) {
Lua_Safe_Call_Void();
self->bFrenzy = value;
self->is_entity_frenzy = value;
}
luabind::scope lua_register_hate_entry() {
+4 -4
View File
@@ -5,17 +5,17 @@
#include "lua_ptr.h"
class Lua_Mob;
struct tHateEntry;
struct struct_HateList;
luabind::scope lua_register_hate_entry();
luabind::scope lua_register_hate_list();
class Lua_HateEntry : public Lua_Ptr<tHateEntry>
class Lua_HateEntry : public Lua_Ptr<struct_HateList>
{
typedef tHateEntry NativeType;
typedef struct_HateList NativeType;
public:
Lua_HateEntry() : Lua_Ptr(nullptr) { }
Lua_HateEntry(tHateEntry *d) : Lua_Ptr(d) { }
Lua_HateEntry(struct_HateList *d) : Lua_Ptr(d) { }
virtual ~Lua_HateEntry() { }
Lua_Mob GetEnt();
+3 -3
View File
@@ -895,17 +895,17 @@ void Lua_Mob::AddToHateList(Lua_Mob other, int hate, int damage, bool yell_for_h
void Lua_Mob::SetHate(Lua_Mob other) {
Lua_Safe_Call_Void();
self->SetHate(other);
self->SetHateAmountOnEnt(other);
}
void Lua_Mob::SetHate(Lua_Mob other, int hate) {
Lua_Safe_Call_Void();
self->SetHate(other, hate);
self->SetHateAmountOnEnt(other, hate);
}
void Lua_Mob::SetHate(Lua_Mob other, int hate, int damage) {
Lua_Safe_Call_Void();
self->SetHate(other, hate, damage);
self->SetHateAmountOnEnt(other, hate, damage);
}
void Lua_Mob::HalveAggro(Lua_Mob other) {
+5
View File
@@ -695,6 +695,9 @@ bool LuaParser::SpellHasQuestSub(uint32 spell_id, QuestEventID evt) {
}
bool LuaParser::ItemHasQuestSub(ItemInst *itm, QuestEventID evt) {
if (itm == nullptr) {
return false;
}
evt = ConvertLuaEvent(evt);
if(evt >= _LargestEventID) {
return false;
@@ -738,6 +741,8 @@ void LuaParser::LoadGlobalPlayerScript(std::string filename) {
}
void LuaParser::LoadItemScript(std::string filename, ItemInst *item) {
if (item == nullptr)
return;
std::string package_name = "item_";
package_name += std::to_string(static_cast<long long>(item->GetID()));
+2 -1
View File
@@ -58,6 +58,7 @@ Map::Map() {
Map::~Map() {
if(imp) {
imp->rm->release();
safe_delete(imp);
}
}
@@ -887,4 +888,4 @@ void Map::TranslateVertex(Vertex &v, float tx, float ty, float tz) {
v.x = v.x + tx;
v.y = v.y + ty;
v.z = v.z + tz;
}
}
+6 -11
View File
@@ -1385,7 +1385,7 @@ void Merc::AI_Process() {
rest_timer.Disable();
if(IsRooted())
SetTarget(hate_list.GetClosest(this));
SetTarget(hate_list.GetClosestEntOnHateList(this));
else
FindTarget();
@@ -2454,11 +2454,11 @@ void Merc::CheckHateList() {
Mob* groupMember = g->members[counter];
if(groupMember) {
if(npc->IsOnHatelist(groupMember)) {
if(!hate_list.IsOnHateList(npc)) {
if(!hate_list.IsEntOnHateList(npc)) {
float range = g->HasRole(groupMember, RolePuller) ? RuleI(Mercs, AggroRadiusPuller) : RuleI(Mercs, AggroRadius);
range *= range;
if(npc->DistNoRootNoZ(*this) < range) {
hate_list.Add(npc, 1);
hate_list.AddEntToHateList(npc, 1);
}
}
}
@@ -4644,13 +4644,6 @@ const char* Merc::GetRandomName(){
return name;
}
bool Compare_Merc_Spells(MercSpell i, MercSpell j);
bool Compare_Merc_Spells(MercSpell i, MercSpell j)
{
return(i.slot > j.slot);
}
bool Merc::LoadMercSpells() {
// loads mercs spells into list
merc_spells.clear();
@@ -4683,7 +4676,9 @@ bool Merc::LoadMercSpells() {
AddProcToWeapon(mercSpellEntryItr->spellid, true, mercSpellEntryItr->proc_chance);
}
}
std::sort(merc_spells.begin(), merc_spells.end(), Compare_Merc_Spells);
std::sort(merc_spells.begin(), merc_spells.end(), [](const MercSpell& a, const MercSpell& b) {
return a.slot > b.slot;
});
if (merc_spells.size() == 0)
AIautocastspell_timer->Disable();
+2 -2
View File
@@ -287,8 +287,8 @@ protected:
uint16 skills[HIGHEST_SKILL+1];
uint32 equipment[EmuConstants::EQUIPMENT_SIZE]; //this is an array of item IDs
uint16 d_meele_texture1; //this is an item Material value
uint16 d_meele_texture2; //this is an item Material value (offhand)
uint16 d_melee_texture1; //this is an item Material value
uint16 d_melee_texture2; //this is an item Material value (offhand)
uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation
uint8 sec_melee_type; //Sets the Secondary Weapon attack message and animation
+27 -14
View File
@@ -401,7 +401,7 @@ Mob::Mob(const char* in_name,
PathingRouteUpdateTimerLong = new Timer(RuleI(Pathing, RouteUpdateFrequencyLong));
DistractedFromGrid = false;
PathingTraversedNodes = 0;
hate_list.SetOwner(this);
hate_list.SetHateOwner(this);
m_AllowBeneficial = false;
m_DisableMelee = false;
@@ -925,7 +925,7 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
ns->spawn.animation = 0;
ns->spawn.findable = findable?1:0;
ns->spawn.light = light;
ns->spawn.showhelm = 1;
ns->spawn.showhelm = (helmtexture && helmtexture != 0xFF) ? 1 : 0;
ns->spawn.invis = (invisible || hidden) ? 1 : 0; // TODO: load this before spawning players
ns->spawn.NPC = IsClient() ? 0 : 1;
@@ -945,11 +945,11 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
ns->spawn.drakkin_heritage = drakkin_heritage;
ns->spawn.drakkin_tattoo = drakkin_tattoo;
ns->spawn.drakkin_details = drakkin_details;
ns->spawn.equip_chest2 = texture;
ns->spawn.equip_chest2 = GetHerosForgeModel(1) != 0 ? 0xff : texture;
// ns->spawn.invis2 = 0xff;//this used to be labeled beard.. if its not FF it will turn mob invis
if(helmtexture && helmtexture != 0xFF)
if (helmtexture && helmtexture != 0xFF && GetHerosForgeModel(0) == 0)
{
ns->spawn.helm=helmtexture;
} else {
@@ -978,7 +978,8 @@ void Mob::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
strn0cpy(ns->spawn.lastName, lastname, sizeof(ns->spawn.lastName));
for (i = 0; i < _MaterialCount; i++)
//for (i = 0; i < _MaterialCount; i++)
for (i = 0; i < 9; i++)
{
// Only Player Races Wear Armor
if (Mob::IsPlayerRace(race) || i > 6)
@@ -2571,8 +2572,8 @@ bool Mob::RemoveFromHateList(Mob* mob)
bool bFound = false;
if(IsEngaged())
{
bFound = hate_list.RemoveEnt(mob);
if(hate_list.IsEmpty())
bFound = hate_list.RemoveEntFromHateList(mob);
if(hate_list.IsHateListEmpty())
{
AI_Event_NoLongerEngaged();
zone->DelAggroMob();
@@ -2580,7 +2581,7 @@ bool Mob::RemoveFromHateList(Mob* mob)
}
if(GetTarget() == mob)
{
SetTarget(hate_list.GetTop(this));
SetTarget(hate_list.GetEntWithMostHateOnList(this));
}
return bFound;
@@ -2590,12 +2591,12 @@ void Mob::WipeHateList()
{
if(IsEngaged())
{
hate_list.Wipe();
hate_list.WipeHateList();
AI_Event_NoLongerEngaged();
}
else
{
hate_list.Wipe();
hate_list.WipeHateList();
}
}
@@ -2749,7 +2750,6 @@ int32 Mob::GetEquipmentMaterial(uint8 material_slot) const
int32 Mob::GetHerosForgeModel(uint8 material_slot) const
{
uint32 HeroModel = 0;
if (material_slot >= 0 && material_slot < MaterialPrimary)
{
@@ -2760,7 +2760,7 @@ int32 Mob::GetHerosForgeModel(uint8 material_slot) const
if (item != 0 && invslot != INVALID_INDEX)
{
if (this->IsClient())
if (IsClient())
{
const ItemInst* inst = CastToClient()->m_inv[invslot];
if (inst)
@@ -2782,9 +2782,22 @@ int32 Mob::GetHerosForgeModel(uint8 material_slot) const
HeroModel = item->HerosForgeModel;
}
}
if (IsNPC())
{
HeroModel = CastToNPC()->GetHeroForgeModel();
// Robes require full model number, and should only be sent to chest, arms, wrists, and legs slots
if (HeroModel > 1000 && material_slot != 1 && material_slot != 2 && material_slot != 3 && material_slot != 5)
{
HeroModel = 0;
}
}
}
if (HeroModel > 0)
// Auto-Convert Hero Model to match the slot
// Otherwise, use the exact Model if model is > 999
// Robes for example are 11607 to 12107 in RoF
if (HeroModel > 0 && HeroModel < 1000)
{
HeroModel *= 100;
HeroModel += material_slot;
@@ -3504,7 +3517,7 @@ void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsP
}
else if (IsPet){
int count = hate_list.SummonedPetCount(this);
int count = hate_list.GetSummonedPetCountOnHateList(this);
if ((base2 >= 220 && base2 <= 250) && count >= (base2 - 220)){
use_spell = true;
}
+14 -14
View File
@@ -452,19 +452,19 @@ public:
static uint32 GetLevelCon(uint8 mylevel, uint8 iOtherLevel);
inline uint32 GetLevelCon(uint8 iOtherLevel) const {
return this ? GetLevelCon(GetLevel(), iOtherLevel) : CON_GREEN; }
virtual void AddToHateList(Mob* other, int32 hate = 0, int32 damage = 0, bool iYellForHelp = true,
virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true,
bool bFrenzy = false, bool iBuffTic = false);
bool RemoveFromHateList(Mob* mob);
void SetHate(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.Set(other,hate,damage);}
void HalveAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate > 1 ? in_hate / 2 : 1)); }
void DoubleAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHate(other, (in_hate ? in_hate * 2 : 1)); }
uint32 GetHateAmount(Mob* tmob, bool is_dam = false) { return hate_list.GetEntHate(tmob,is_dam);}
uint32 GetDamageAmount(Mob* tmob) { return hate_list.GetEntHate(tmob, true);}
Mob* GetHateTop() { return hate_list.GetTop(this);}
Mob* GetHateDamageTop(Mob* other) { return hate_list.GetDamageTop(other);}
Mob* GetHateRandom() { return hate_list.GetRandom();}
Mob* GetHateMost() { return hate_list.GetMostHate();}
bool IsEngaged() { return(!hate_list.IsEmpty()); }
void SetHateAmountOnEnt(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.SetHateAmountOnEnt(other,hate,damage);}
void HalveAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHateAmountOnEnt(other, (in_hate > 1 ? in_hate / 2 : 1)); }
void DoubleAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHateAmountOnEnt(other, (in_hate ? in_hate * 2 : 1)); }
uint32 GetHateAmount(Mob* tmob, bool is_dam = false) { return hate_list.GetEntHateAmount(tmob,is_dam);}
uint32 GetDamageAmount(Mob* tmob) { return hate_list.GetEntHateAmount(tmob, true);}
Mob* GetHateTop() { return hate_list.GetEntWithMostHateOnList(this);}
Mob* GetHateDamageTop(Mob* other) { return hate_list.GetDamageTopOnHateList(other);}
Mob* GetHateRandom() { return hate_list.GetRandomEntOnHateList();}
Mob* GetHateMost() { return hate_list.GetEntWithMostHateOnList();}
bool IsEngaged() { return(!hate_list.IsHateListEmpty()); }
bool HateSummon();
void FaceTarget(Mob* MobToFace = 0);
void SetHeading(float iHeading) { if(heading != iHeading) { pLastChange = Timer::GetCurrentTime();
@@ -473,8 +473,8 @@ public:
void AddFeignMemory(Client* attacker);
void RemoveFromFeignMemory(Client* attacker);
void ClearFeignMemory();
void PrintHateListToClient(Client *who) { hate_list.PrintToClient(who); }
std::list<tHateEntry*>& GetHateList() { return hate_list.GetHateList(); }
void PrintHateListToClient(Client *who) { hate_list.PrintHateListToClient(who); }
std::list<struct_HateList*>& GetHateList() { return hate_list.GetHateList(); }
bool CheckLosFN(Mob* other);
bool CheckLosFN(float posX, float posY, float posZ, float mobSize);
inline void SetChanged() { pLastChange = Timer::GetCurrentTime(); }
@@ -798,7 +798,7 @@ public:
void CheckFlee();
inline bool IsBlind() { return spellbonuses.IsBlind; }
inline bool CheckAggro(Mob* other) {return hate_list.IsOnHateList(other);}
inline bool CheckAggro(Mob* other) {return hate_list.IsEntOnHateList(other);}
float CalculateHeadingToTarget(float in_x, float in_y);
bool CalculateNewPosition(float x, float y, float z, float speed, bool checkZ = false);
virtual bool CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ = true);
+12 -16
View File
@@ -493,7 +493,7 @@ void Mob::AI_Start(uint32 iMoveDelay) {
pAggroRange = 70;
if (GetAssistRange() == 0)
pAssistRange = 70;
hate_list.Wipe();
hate_list.WipeHateList();
delta_heading = 0;
delta_x = 0;
@@ -553,7 +553,7 @@ void Mob::AI_Stop() {
safe_delete(AIscanarea_timer);
safe_delete(AIfeignremember_timer);
hate_list.Wipe();
hate_list.WipeHateList();
}
void NPC::AI_Stop() {
@@ -816,12 +816,12 @@ void Client::AI_Process()
if (engaged)
{
if (IsRooted())
SetTarget(hate_list.GetClosest(this));
SetTarget(hate_list.GetClosestEntOnHateList(this));
else
{
if(AItarget_check_timer->Check())
{
SetTarget(hate_list.GetTop(this));
SetTarget(hate_list.GetEntWithMostHateOnList(this));
}
}
@@ -1041,7 +1041,7 @@ void Mob::AI_Process() {
//
if(RuleB(Combat, EnableFearPathing)){
if(curfp) {
if(IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosest(this)))) {
if(IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosestEntOnHateList(this)))) {
//make sure everybody knows were not moving, for appearance sake
if(IsMoving())
{
@@ -1091,18 +1091,18 @@ void Mob::AI_Process() {
// we are prevented from getting here if we are blind and don't have a target in range
// from above, so no extra blind checks needed
if ((IsRooted() && !GetSpecialAbility(IGNORE_ROOT_AGGRO_RULES)) || IsBlind())
SetTarget(hate_list.GetClosest(this));
SetTarget(hate_list.GetClosestEntOnHateList(this));
else
{
if(AItarget_check_timer->Check())
{
if (IsFocused()) {
if (!target) {
SetTarget(hate_list.GetTop(this));
SetTarget(hate_list.GetEntWithMostHateOnList(this));
}
} else {
if (!ImprovedTaunt())
SetTarget(hate_list.GetTop(this));
SetTarget(hate_list.GetEntWithMostHateOnList(this));
}
}
@@ -1376,7 +1376,7 @@ void Mob::AI_Process() {
//underwater stuff only works with water maps in the zone!
if(IsNPC() && CastToNPC()->IsUnderwaterOnly() && zone->HasWaterMap()) {
if(!zone->watermap->InLiquid(target->GetX(), target->GetY(), target->GetZ())) {
Mob *tar = hate_list.GetTop(this);
Mob *tar = hate_list.GetEntWithMostHateOnList(this);
if(tar == target) {
WipeHateList();
Heal();
@@ -2354,7 +2354,6 @@ create table npc_spells_entries (
bool IsSpellInList(DBnpcspells_Struct* spell_list, int16 iSpellID);
bool IsSpellEffectInList(DBnpcspellseffects_Struct* spelleffect_list, uint16 iSpellEffectID, int32 base, int32 limit, int32 max);
bool Compare_AI_Spells(AISpells_Struct i, AISpells_Struct j);
bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) {
// ok, this function should load the list, and the parent list then shove them into the struct and sort
@@ -2479,7 +2478,9 @@ bool NPC::AI_AddNPCSpells(uint32 iDBSpellsID) {
spell_list->entries[i].resist_adjust);
}
}
std::sort(AIspells.begin(), AIspells.end(), Compare_AI_Spells);
std::sort(AIspells.begin(), AIspells.end(), [](const AISpells_Struct& a, const AISpells_Struct& b) {
return a.priority > b.priority;
});
if (IsValidSpell(attack_proc_spell))
AddProcToWeapon(attack_proc_spell, true, proc_chance);
@@ -2619,11 +2620,6 @@ bool IsSpellInList(DBnpcspells_Struct* spell_list, int16 iSpellID) {
return false;
}
bool Compare_AI_Spells(AISpells_Struct i, AISpells_Struct j)
{
return(i.priority > j.priority);
}
// adds a spell to the list, taking into account priority and resorting list as needed.
void NPC::AddSpellToNPCList(int16 iPriority, int16 iSpellID, uint16 iType,
int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust)
+30 -32
View File
@@ -261,8 +261,10 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float
if(!IsMerc())
AI_Start();
d_meele_texture1 = d->d_meele_texture1;
d_meele_texture2 = d->d_meele_texture2;
d_melee_texture1 = d->d_melee_texture1;
d_melee_texture2 = d->d_melee_texture2;
herosforgemodel = d->herosforgemodel;
ammo_idfile = d->ammo_idfile;
memset(equipment, 0, sizeof(equipment));
prim_melee_type = d->prim_melee_type;
@@ -270,9 +272,9 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float
ranged_type = d->ranged_type;
// If Melee Textures are not set, set attack type to Hand to Hand as default
if(!d_meele_texture1)
if(!d_melee_texture1)
prim_melee_type = 28;
if(!d_meele_texture2)
if(!d_melee_texture2)
sec_melee_type = 28;
//give NPCs skill values...
@@ -498,32 +500,28 @@ void NPC::ClearItemList() {
itemlist.clear();
}
void NPC::QueryLoot(Client* to) {
int x = 0;
void NPC::QueryLoot(Client* to)
{
to->Message(0, "Coin: %ip %ig %is %ic", platinum, gold, silver, copper);
ItemList::iterator cur,end;
cur = itemlist.begin();
end = itemlist.end();
for(; cur != end; ++cur) {
int x = 0;
for(ItemList::iterator cur = itemlist.begin(); cur != itemlist.end(); ++cur, ++x) {
const Item_Struct* item = database.GetItem((*cur)->item_id);
if (item)
if (to->GetClientVersion() >= EQClientRoF)
{
to->Message(0, "minlvl: %i maxlvl: %i %i: %c%06X0000000000000000000000000000000000000000000000000%s%c",(*cur)->min_level, (*cur)->max_level, (int) item->ID,0x12, item->ID, item->Name, 0x12);
}
else if (to->GetClientVersion() >= EQClientSoF)
{
to->Message(0, "minlvl: %i maxlvl: %i %i: %c%06X00000000000000000000000000000000000000000000%s%c",(*cur)->min_level, (*cur)->max_level, (int) item->ID,0x12, item->ID, item->Name, 0x12);
}
else
{
to->Message(0, "minlvl: %i maxlvl: %i %i: %c%06X000000000000000000000000000000000000000%s%c",(*cur)->min_level, (*cur)->max_level, (int) item->ID,0x12, item->ID, item->Name, 0x12);
}
else
if (item == nullptr) {
LogFile->write(EQEMuLog::Error, "Database error, invalid item");
x++;
continue;
}
Client::TextLink linker;
linker.SetLinkType(linker.linkItemData);
linker.SetItemData(item);
linker.SetClientVersion(to->GetClientVersion());
auto item_link = linker.GenerateLink();
to->Message(0, "%s, ID: %u, Level: (min: %u, max: %u)", item_link.c_str(), item->ID, (*cur)->min_level, (*cur)->max_level);
}
to->Message(0, "%i items on %s.", x, GetName());
}
@@ -924,8 +922,8 @@ NPC* NPC::SpawnNPC(const char* spawncommand, float in_x, float in_y, float in_z,
npc_type->texture = atoi(sep.arg[3]);
npc_type->light = 0;
npc_type->runspeed = 1.25;
npc_type->d_meele_texture1 = atoi(sep.arg[7]);
npc_type->d_meele_texture2 = atoi(sep.arg[8]);
npc_type->d_melee_texture1 = atoi(sep.arg[7]);
npc_type->d_melee_texture2 = atoi(sep.arg[8]);
npc_type->merchanttype = atoi(sep.arg[9]);
npc_type->bodytype = atoi(sep.arg[10]);
@@ -957,7 +955,7 @@ NPC* NPC::SpawnNPC(const char* spawncommand, float in_x, float in_y, float in_z,
client->Message(0, "Current/Max HP: %i", npc->max_hp);
client->Message(0, "Gender: %u", npc->gender);
client->Message(0, "Class: %u", npc->class_);
client->Message(0, "Weapon Item Number: %u/%u", npc->d_meele_texture1, npc->d_meele_texture2);
client->Message(0, "Weapon Item Number: %u/%u", npc->d_melee_texture1, npc->d_melee_texture2);
client->Message(0, "MerchantID: %u", npc->MerchantType);
client->Message(0, "Bodytype: %u", npc->bodytype);
}
@@ -1335,9 +1333,9 @@ int32 NPC::GetEquipmentMaterial(uint8 material_slot) const
case MaterialChest:
return texture;
case MaterialPrimary:
return d_meele_texture1;
return d_melee_texture1;
case MaterialSecondary:
return d_meele_texture2;
return d_melee_texture2;
default:
//they have nothing in the slot, and its not a special slot... they get nothing.
return(0);
@@ -2136,10 +2134,10 @@ uint32 NPC::GetSpawnPointID() const
void NPC::NPCSlotTexture(uint8 slot, uint16 texture)
{
if (slot == 7) {
d_meele_texture1 = texture;
d_melee_texture1 = texture;
}
else if (slot == 8) {
d_meele_texture2 = texture;
d_melee_texture2 = texture;
}
else if (slot < 6) {
// Reserved for texturing individual armor slots
+9 -4
View File
@@ -249,8 +249,8 @@ public:
inline int32 GetNPCFactionID() const { return npc_faction_id; }
inline int32 GetPrimaryFaction() const { return primary_faction; }
int32 GetNPCHate(Mob* in_ent) {return hate_list.GetEntHate(in_ent);}
bool IsOnHatelist(Mob*p) { return hate_list.IsOnHateList(p);}
int32 GetNPCHate(Mob* in_ent) {return hate_list.GetEntHateAmount(in_ent);}
bool IsOnHatelist(Mob*p) { return hate_list.IsEntOnHateList(p);}
void SetNPCFactionID(int32 in) { npc_faction_id = in; database.GetFactionIdsForNPC(npc_faction_id, &faction_list, &primary_faction); }
@@ -403,6 +403,9 @@ public:
void mod_npc_killed(Mob* oos);
void AISpellsList(Client *c);
uint32 GetHeroForgeModel() const { return herosforgemodel; }
void SetHeroForgeModel(uint32 model) { herosforgemodel = model; }
bool IsRaidTarget() const { return raid_target; };
protected:
@@ -492,8 +495,10 @@ protected:
uint16 skills[HIGHEST_SKILL+1];
uint32 equipment[EmuConstants::EQUIPMENT_SIZE]; //this is an array of item IDs
uint16 d_meele_texture1; //this is an item Material value
uint16 d_meele_texture2; //this is an item Material value (offhand)
uint32 herosforgemodel; //this is the Hero Forge Armor Model (i.e 63 or 84 or 203)
uint16 d_melee_texture1; //this is an item Material value
uint16 d_melee_texture2; //this is an item Material value (offhand)
const char* ammo_idfile; //this determines projectile graphic "IT###" (see item field 'idfile')
uint8 prim_melee_type; //Sets the Primary Weapon attack message and animation
uint8 sec_melee_type; //Sets the Secondary Weapon attack message and animation
+9 -1
View File
@@ -118,7 +118,15 @@ Object::Object(Client* client, const ItemInst* inst)
m_data.heading = client->GetHeading();
m_data.x = client->GetX();
m_data.y = client->GetY();
m_data.z = client->GetZ();
if (client->GetClientVersion() >= EQClientRoF2)
{
// RoF2 places items at player's Z, which is 0.625 of their height.
m_data.z = client->GetZ() - (client->GetSize() * 0.625f);
}
else
{
m_data.z = client->GetZ();
}
m_data.zone_id = zone->GetZoneID();
decay_timer.Start();
+12 -12
View File
@@ -345,10 +345,10 @@ bool CheckLOSBetweenPoints(Map::Vertex start, Map::Vertex end) {
return true;
}
bool SortPathNodesByDistance(PathNodeSortStruct n1, PathNodeSortStruct n2)
auto path_compare = [](const PathNodeSortStruct& a, const PathNodeSortStruct& b)
{
return n1.Distance < n2.Distance;
}
return a.Distance < b.Distance;
};
std::deque<int> PathManager::FindRoute(Map::Vertex Start, Map::Vertex End)
{
@@ -382,7 +382,7 @@ std::deque<int> PathManager::FindRoute(Map::Vertex Start, Map::Vertex End)
}
}
std::sort(SortedByDistance.begin(), SortedByDistance.end(), SortPathNodesByDistance);
std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare);
for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator)
{
@@ -420,7 +420,7 @@ std::deque<int> PathManager::FindRoute(Map::Vertex Start, Map::Vertex End)
}
}
std::sort(SortedByDistance.begin(), SortedByDistance.end(), SortPathNodesByDistance);
std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare);
for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator)
{
@@ -573,8 +573,8 @@ void PathManager::SpawnPathNodes()
npc_type->texture = 1;
npc_type->light = 0;
npc_type->runspeed = 0;
npc_type->d_meele_texture1 = 1;
npc_type->d_meele_texture2 = 1;
npc_type->d_melee_texture1 = 1;
npc_type->d_melee_texture2 = 1;
npc_type->merchanttype = 1;
npc_type->bodytype = 1;
@@ -1120,7 +1120,7 @@ int PathManager::FindNearestPathNode(Map::Vertex Position)
}
}
std::sort(SortedByDistance.begin(), SortedByDistance.end(), SortPathNodesByDistance);
std::sort(SortedByDistance.begin(), SortedByDistance.end(), path_compare);
for(auto Iterator = SortedByDistance.begin(); Iterator != SortedByDistance.end(); ++Iterator)
{
@@ -1561,8 +1561,8 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques
npc_type->texture = 1;
npc_type->light = 0;
npc_type->runspeed = 0;
npc_type->d_meele_texture1 = 1;
npc_type->d_meele_texture2 = 1;
npc_type->d_melee_texture1 = 1;
npc_type->d_melee_texture2 = 1;
npc_type->merchanttype = 1;
npc_type->bodytype = 1;
npc_type->STR = 150;
@@ -1621,8 +1621,8 @@ int32 PathManager::AddNode(float x, float y, float z, float best_z, int32 reques
npc_type->texture = 1;
npc_type->light = 0;
npc_type->runspeed = 0;
npc_type->d_meele_texture1 = 1;
npc_type->d_meele_texture2 = 1;
npc_type->d_melee_texture1 = 1;
npc_type->d_melee_texture2 = 1;
npc_type->merchanttype = 1;
npc_type->bodytype = 1;
npc_type->STR = 150;
+11 -4
View File
@@ -5057,14 +5057,21 @@ XS(XS_Client_UpdateTaskActivity); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_UpdateTaskActivity)
{
dXSARGS;
if (items != 4)
Perl_croak(aTHX_ "Usage: Client::UpdateTaskActivity(THIS, TaskID, ActivityID, Count)");
if (items < 4)
Perl_croak(aTHX_ "Usage: Client::UpdateTaskActivity(THIS, TaskID, ActivityID, Count, [ignore_quest_update])");
{
bool ignore_quest_update = false;
Client * THIS;
int TaskID = (int)SvIV(ST(1));
int ActivityID = (int)SvIV(ST(2));
int Count = (int)SvUV(ST(3));
if (items == 5){
ignore_quest_update = (bool)SvTRUE(ST(4));
}
if (sv_derived_from(ST(0), "Client")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Client *,tmp);
@@ -5074,7 +5081,7 @@ XS(XS_Client_UpdateTaskActivity)
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
THIS->UpdateTaskActivity(TaskID, ActivityID, Count);
THIS->UpdateTaskActivity(TaskID, ActivityID, Count, ignore_quest_update);
}
XSRETURN_EMPTY;
}
@@ -6305,7 +6312,7 @@ XS(boot_Client)
newXSproto(strcpy(buf, "ClearCompassMark"), XS_Client_ClearCompassMark, file, "$");
newXSproto(strcpy(buf, "GetFreeSpellBookSlot"), XS_Client_GetFreeSpellBookSlot, file, "$;$");
newXSproto(strcpy(buf, "GetSpellBookSlotBySpellID"), XS_Client_GetSpellBookSlotBySpellID, file, "$$");
newXSproto(strcpy(buf, "UpdateTaskActivity"), XS_Client_UpdateTaskActivity, file, "$$$$");
newXSproto(strcpy(buf, "UpdateTaskActivity"), XS_Client_UpdateTaskActivity, file, "$$$$;$");
newXSproto(strcpy(buf, "AssignTask"), XS_Client_AssignTask, file, "$$$");
newXSproto(strcpy(buf, "FailTask"), XS_Client_FailTask, file, "$$");
newXSproto(strcpy(buf, "IsTaskCompleted"), XS_Client_IsTaskCompleted, file, "$$");
+9 -9
View File
@@ -40,19 +40,19 @@ XS(XS_HateEntry_GetEnt)
if (items != 1)
Perl_croak(aTHX_ "Usage: HateEntry::GetData(THIS)");
{
tHateEntry * THIS;
struct_HateList * THIS;
Mob * RETVAL;
if (sv_derived_from(ST(0), "HateEntry")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(tHateEntry *,tmp);
THIS = INT2PTR(struct_HateList *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type tHateEntry");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->ent;
RETVAL = THIS->entity_on_hatelist;
ST(0) = sv_newmortal();
sv_setref_pv(ST(0), "Mob", (void*)RETVAL);
}
@@ -66,20 +66,20 @@ XS(XS_HateEntry_GetHate)
if (items != 1)
Perl_croak(aTHX_ "Usage: HateEntry::GetHate(THIS)");
{
tHateEntry * THIS;
struct_HateList * THIS;
int32 RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "HateEntry")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(tHateEntry *,tmp);
THIS = INT2PTR(struct_HateList *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type tHateEntry");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->hate;
RETVAL = THIS->stored_hate_amount;
XSprePUSH; PUSHi((IV)RETVAL);
}
XSRETURN(1);
@@ -92,20 +92,20 @@ XS(XS_HateEntry_GetDamage)
if (items != 1)
Perl_croak(aTHX_ "Usage: HateEntry::GetDamage(THIS)");
{
tHateEntry * THIS;
struct_HateList * THIS;
int32 RETVAL;
dXSTARG;
if (sv_derived_from(ST(0), "HateEntry")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(tHateEntry *,tmp);
THIS = INT2PTR(struct_HateList *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type tHateEntry");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->damage;
RETVAL = THIS->hatelist_damage;
XSprePUSH; PUSHi((IV)RETVAL);
}
XSRETURN(1);
+2 -2
View File
@@ -5354,7 +5354,7 @@ XS(XS_Mob_SetHate)
damage = (int32)SvIV(ST(3));
}
THIS->SetHate(other, hate, damage);
THIS->SetHateAmountOnEnt(other, hate, damage);
}
XSRETURN_EMPTY;
}
@@ -6599,7 +6599,7 @@ XS(XS_Mob_GetHateList)
while(iter != hate_list.end())
{
tHateEntry *entry = (*iter);
struct_HateList *entry = (*iter);
ST(0) = sv_newmortal();
sv_setref_pv(ST(0), "HateEntry", (void*)entry);
XPUSHs(ST(0));
+1
View File
@@ -393,6 +393,7 @@ void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
npc_type->gender = monster->gender;
npc_type->luclinface = monster->luclinface;
npc_type->helmtexture = monster->helmtexture;
npc_type->herosforgemodel = monster->herosforgemodel;
} else
LogFile->write(EQEMuLog::Error, "Error loading NPC data for monster summoning pet (NPC ID %d)", monsterid);
+5
View File
@@ -200,6 +200,9 @@ bool QuestParserCollection::SpellHasQuestSub(uint32 spell_id, QuestEventID evt)
}
bool QuestParserCollection::ItemHasQuestSub(ItemInst *itm, QuestEventID evt) {
if (itm == nullptr)
return false;
std::string item_script;
if(itm->GetItem()->ScriptFileID != 0) {
item_script = "script_";
@@ -350,6 +353,8 @@ int QuestParserCollection::EventPlayerGlobal(QuestEventID evt, Client *client, s
int QuestParserCollection::EventItem(QuestEventID evt, Client *client, ItemInst *item, Mob *mob, std::string data, uint32 extra_data,
std::vector<EQEmu::Any> *extra_pointers) {
// needs pointer validation check on 'item' argument
std::string item_script;
if(item->GetItem()->ScriptFileID != 0) {
item_script = "script_";
+35 -34
View File
@@ -1227,13 +1227,18 @@ void QuestManager::settime(uint8 new_hour, uint8 new_min) {
void QuestManager::itemlink(int item_id) {
QuestManagerCurrentQuestVars();
if (initiator) {
const ItemInst* inst = database.CreateItem(item_id);
char* link = 0;
if (initiator->MakeItemLink(link, inst))
initiator->Message(0, "%s tells you, %c%s%s%c", owner->GetCleanName(),
0x12, link, inst->GetItem()->Name, 0x12);
safe_delete_array(link);
safe_delete(inst);
const Item_Struct* item = database.GetItem(item_id);
if (item == nullptr)
return;
Client::TextLink linker;
linker.SetLinkType(linker.linkItemData);
linker.SetItemData(item);
linker.SetClientVersion(initiator->GetClientVersion());
auto item_link = linker.GenerateLink();
initiator->Message(0, "%s tells you, %s", owner->GetCleanName(), item_link.c_str());
}
}
@@ -2103,11 +2108,12 @@ int QuestManager::gettaskactivitydonecount(int task, int activity) {
}
void QuestManager::updatetaskactivity(int task, int activity, int count) {
void QuestManager::updatetaskactivity(int task, int activity, int count, bool ignore_quest_update /*= false*/)
{
QuestManagerCurrentQuestVars();
if(RuleB(TaskSystem, EnableTaskSystem) && initiator)
initiator->UpdateTaskActivity(task, activity, count);
initiator->UpdateTaskActivity(task, activity, count, ignore_quest_update);
}
void QuestManager::resettaskactivity(int task, int activity) {
@@ -2336,7 +2342,7 @@ int QuestManager::collectitems_processSlot(int16 slot_id, uint32 item_id,
bool remove)
{
QuestManagerCurrentQuestVars();
ItemInst *item;
ItemInst *item = nullptr;
int quantity = 0;
item = initiator->GetInv().GetItem(slot_id);
@@ -2461,16 +2467,19 @@ uint32 QuestManager::MerchantCountItem(uint32 NPCid, uint32 itemid) {
// Item Link for use in Variables - "my $example_link = quest::varlink(item_id);"
const char* QuestManager::varlink(char* perltext, int item_id) {
QuestManagerCurrentQuestVars();
const ItemInst* inst = database.CreateItem(item_id);
if (!inst)
const Item_Struct* item = database.GetItem(item_id);
if (!item)
return "INVALID ITEM ID IN VARLINK";
char* link = 0;
char* tempstr = 0;
if (initiator->MakeItemLink(link, inst)) { // make a link to the item
snprintf(perltext, 250, "%c%s%s%c", 0x12, link, inst->GetItem()->Name, 0x12);
}
safe_delete_array(link); // MakeItemLink() uses new also
safe_delete(inst);
Client::TextLink linker;
linker.SetLinkType(linker.linkItemData);
linker.SetItemData(item);
if (initiator)
linker.SetClientVersion(initiator->GetClientVersion());
auto item_link = linker.GenerateLink();
strcpy(perltext, item_link.c_str()); // link length is currently ranged from 1 to 250 in TextLink::GenerateLink()
return perltext;
}
@@ -2656,24 +2665,16 @@ const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkNam
sayid = sayid + 500000;
//Create the say link as an item link hash
char linktext[250];
Client::TextLink linker;
linker.SetProxyItemID(sayid);
linker.SetProxyText(LinkName);
if (initiator)
linker.SetClientVersion(initiator->GetClientVersion());
if (initiator) {
if (initiator->GetClientVersion() >= EQClientRoF2)
sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "00000000000000000000000000000000000000000000000000", LinkName, 0x12);
else if (initiator->GetClientVersion() >= EQClientRoF)
sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "0000000000000000000000000000000000000000000000000", LinkName, 0x12);
else if (initiator->GetClientVersion() >= EQClientSoF)
sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "00000000000000000000000000000000000000000000", LinkName, 0x12);
else
sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "000000000000000000000000000000000000000", LinkName, 0x12);
} else { // If no initiator, create an RoF2 saylink, since older clients handle RoF2 ones better than RoF2 handles older ones.
sprintf(linktext, "%c%06X%s%s%c", 0x12, sayid, "00000000000000000000000000000000000000000000000000", LinkName, 0x12);
}
auto say_link = linker.GenerateLink();
strcpy(Phrase, say_link.c_str()); // link length is currently ranged from 1 to 250 in TextLink::GenerateLink()
strcpy(Phrase,linktext);
return Phrase;
}
const char* QuestManager::getguildnamebyid(int guild_id) {
+1 -1
View File
@@ -183,7 +183,7 @@ public:
bool istaskactive(int task);
bool istaskactivityactive(int task, int activity);
int gettaskactivitydonecount(int task, int activity);
void updatetaskactivity(int task, int activity, int count);
void updatetaskactivity(int task, int activity, int count, bool ignore_quest_update = false);
void resettaskactivity(int task, int activity);
void taskexploredarea(int exploreid);
void assigntask(int taskid);
+4 -4
View File
@@ -106,7 +106,7 @@ void Mob::DoSpecialAttackDamage(Mob *who, SkillUseTypes skill, int32 max_damage,
if(who->GetInvul() || who->GetSpecialAbility(IMMUNE_MELEE) || who->GetSpecialAbility(IMMUNE_MELEE_EXCEPT_BANE))
return; //-5?
int32 hate = max_damage;
uint32 hate = max_damage;
if(hate_override > -1)
hate = hate_override;
@@ -583,7 +583,7 @@ void Mob::RogueBackstab(Mob* other, bool min_damage, int ReuseTime)
int32 ndamage = 0;
int32 max_hit = 0;
int32 min_hit = 0;
int32 hate = 0;
uint32 hate = 0;
int32 primaryweapondamage = 0;
int32 backstab_dmg = 0;
@@ -889,7 +889,7 @@ void Mob::DoArcheryAttackDmg(Mob* other, const ItemInst* RangeWeapon, const Ite
if (HeadShot_Dmg)
HeadShot = true;
int32 hate = 0;
uint32 hate = 0;
int32 TotalDmg = 0;
int16 WDmg = 0;
int16 ADmg = 0;
@@ -2354,7 +2354,7 @@ void Mob::DoMeleeSkillAttackDmg(Mob* other, uint16 weapon_damage, SkillUseTypes
skillinuse = SkillOffense;
int damage = 0;
int32 hate = 0;
uint32 hate = 0;
int Hand = MainPrimary;
if (hate == 0 && weapon_damage > 1) hate = weapon_damage;
+17 -13
View File
@@ -1897,10 +1897,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
if (CalculatePoisonCounters(buffs[j].spellid) == 0)
continue;
if (effect_value >= static_cast<int>(buffs[j].counters)) {
if (caster)
if (caster) {
caster->Message(MT_Spells,"You have cured your target of %s!",spells[buffs[j].spellid].name);
caster->CastOnCurer(buffs[j].spellid);
CastOnCure(buffs[j].spellid);
}
effect_value -= buffs[j].counters;
buffs[j].counters = 0;
BuffFadeBySlot(j);
@@ -1930,10 +1931,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
continue;
if (effect_value >= static_cast<int>(buffs[j].counters))
{
if (caster)
if (caster) {
caster->Message(MT_Spells,"You have cured your target of %s!",spells[buffs[j].spellid].name);
caster->CastOnCurer(buffs[j].spellid);
CastOnCure(buffs[j].spellid);
}
effect_value -= buffs[j].counters;
buffs[j].counters = 0;
BuffFadeBySlot(j);
@@ -1965,10 +1967,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
continue;
if (effect_value >= static_cast<int>(buffs[j].counters))
{
if (caster)
if (caster) {
caster->Message(MT_Spells,"You have cured your target of %s!",spells[buffs[j].spellid].name);
caster->CastOnCurer(buffs[j].spellid);
CastOnCure(buffs[j].spellid);
}
effect_value -= buffs[j].counters;
buffs[j].counters = 0;
BuffFadeBySlot(j);
@@ -1999,10 +2002,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
if (CalculateCorruptionCounters(buffs[j].spellid) == 0)
continue;
if (effect_value >= static_cast<int>(buffs[j].counters)) {
if (caster)
if (caster) {
caster->Message(MT_Spells,"You have cured your target of %s!",spells[buffs[j].spellid].name);
caster->CastOnCurer(buffs[j].spellid);
CastOnCure(buffs[j].spellid);
}
effect_value -= buffs[j].counters;
buffs[j].counters = 0;
BuffFadeBySlot(j);
@@ -2658,7 +2662,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
caster->Taunt(this->CastToNPC(), false, static_cast<float>(spell.base[i]));
if (spell.base2[i] > 0)
CastToNPC()->SetHate(caster, (CastToNPC()->GetHateAmount(caster) + spell.base2[i]));
CastToNPC()->SetHateAmountOnEnt(caster, (CastToNPC()->GetHateAmount(caster) + spell.base2[i]));
}
break;
}
@@ -2689,7 +2693,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
if (new_hate <= 0)
new_hate = 1;
CastToNPC()->SetHate(caster, new_hate);
CastToNPC()->SetHateAmountOnEnt(caster, new_hate);
}
break;
}
@@ -2710,9 +2714,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
}else{
int32 newhate = GetHateAmount(caster) + effect_value;
if (newhate < 1)
SetHate(caster,1);
SetHateAmountOnEnt(caster,1);
else
SetHate(caster,newhate);
SetHateAmountOnEnt(caster,newhate);
}
}
break;
@@ -3542,9 +3546,9 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
}else{
int32 newhate = GetHateAmount(caster) + effect_value;
if (newhate < 1) {
SetHate(caster,1);
SetHateAmountOnEnt(caster,1);
} else {
SetHate(caster,newhate);
SetHateAmountOnEnt(caster,newhate);
}
}
}
@@ -3724,11 +3728,11 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
case SE_AddHateOverTimePct:
{
if (IsNPC()){
int32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100;
uint32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100;
if (new_hate <= 0)
new_hate = 1;
CastToNPC()->SetHate(caster, new_hate);
CastToNPC()->SetHateAmountOnEnt(caster, new_hate);
}
break;
}
@@ -6420,7 +6424,7 @@ bool Mob::PassCastRestriction(bool UseCastRestriction, int16 value, bool IsDama
//Limit to amount of pets
if (value >= 221 && value <= 249){
int count = hate_list.SummonedPetCount(this);
int count = hate_list.GetSummonedPetCountOnHateList(this);
for (int base2_value = 221; base2_value <= 249; ++base2_value){
if (value == base2_value){
+34 -19
View File
@@ -1195,22 +1195,29 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
uint32 recastdelay = 0;
uint32 recasttype = 0;
for (int r = 0; r < EmuConstants::ITEM_COMMON_SIZE; r++) {
const ItemInst* aug_i = inst->GetAugment(r);
if(!aug_i)
continue;
const Item_Struct* aug = aug_i->GetItem();
if(!aug)
continue;
if ( aug->Click.Effect == spell_id )
{
recastdelay = aug_i->GetItem()->RecastDelay;
recasttype = aug_i->GetItem()->RecastType;
fromaug = true;
while (true) {
if (inst == nullptr)
break;
for (int r = AUG_BEGIN; r < EmuConstants::ITEM_COMMON_SIZE; r++) {
const ItemInst* aug_i = inst->GetAugment(r);
if (!aug_i)
continue;
const Item_Struct* aug = aug_i->GetItem();
if (!aug)
continue;
if (aug->Click.Effect == spell_id)
{
recastdelay = aug_i->GetItem()->RecastDelay;
recasttype = aug_i->GetItem()->RecastType;
fromaug = true;
break;
}
}
break;
}
//Test the aug recast delay
@@ -3649,11 +3656,11 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
spelltar->AddToHateList(this, aggro);
}
else{
int32 newhate = spelltar->GetHateAmount(this) + aggro;
uint32 newhate = spelltar->GetHateAmount(this) + aggro;
if (newhate < 1) {
spelltar->SetHate(this,1);
spelltar->SetHateAmountOnEnt(this,1);
} else {
spelltar->SetHate(this,newhate);
spelltar->SetHateAmountOnEnt(this,newhate);
}
}
}
@@ -3681,9 +3688,9 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
spelltar->AddToHateList(this, aggro_amount); else{
int32 newhate = spelltar->GetHateAmount(this) + aggro_amount;
if (newhate < 1) {
spelltar->SetHate(this,1);
spelltar->SetHateAmountOnEnt(this,1);
} else {
spelltar->SetHate(this,newhate);
spelltar->SetHateAmountOnEnt(this,newhate);
}
}
}
@@ -3896,6 +3903,8 @@ void Mob::BuffFadeDetrimental() {
BuffFadeBySlot(j, false);
}
}
//we tell BuffFadeBySlot not to recalc, so we can do it only once when were done
CalcBonuses();
}
void Mob::BuffFadeDetrimentalByCaster(Mob *caster)
@@ -3916,6 +3925,8 @@ void Mob::BuffFadeDetrimentalByCaster(Mob *caster)
}
}
}
//we tell BuffFadeBySlot not to recalc, so we can do it only once when were done
CalcBonuses();
}
void Mob::BuffFadeBySitModifier()
@@ -4195,6 +4206,10 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
//Get resist modifier and adjust it based on focus 2 resist about eq to 1% resist chance
int resist_modifier = (use_resist_override) ? resist_override : spells[spell_id].ResistDiff;
if(caster->GetSpecialAbility(CASTING_RESIST_DIFF))
resist_modifier += caster->GetSpecialAbilityParam(CASTING_RESIST_DIFF, 0);
int focus_resist = caster->GetFocusEffect(focusResistRate, spell_id);
resist_modifier -= 2 * focus_resist;
+34 -72
View File
@@ -1786,7 +1786,7 @@ void ClientTaskState::UpdateTasksOnTouch(Client *c, int ZoneID) {
return;
}
void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int TaskIndex, int ActivityID, int Count) {
void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int TaskIndex, int ActivityID, int Count, bool ignore_quest_update) {
_log(TASKS__UPDATE, "IncrementDoneCount");
@@ -1795,10 +1795,12 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T
if(ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount > Task->Activity[ActivityID].GoalCount)
ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount = Task->Activity[ActivityID].GoalCount;
char buf[24];
snprintf(buf, 23, "%d %d %d", ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID, ActiveTasks[TaskIndex].TaskID);
buf[23] = '\0';
parse->EventPlayer(EVENT_TASK_UPDATE, c, buf, 0);
if (!ignore_quest_update){
char buf[24];
snprintf(buf, 23, "%d %d %d", ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID, ActiveTasks[TaskIndex].TaskID);
buf[23] = '\0';
parse->EventPlayer(EVENT_TASK_UPDATE, c, buf, 0);
}
ActiveTasks[TaskIndex].Activity[ActivityID].Updated=true;
// Have we reached the goal count for this activity ?
@@ -1821,11 +1823,12 @@ void ClientTaskState::IncrementDoneCount(Client *c, TaskInformation* Task, int T
c->Message(0, "Your task '%s' has been updated.", Task->Title);
if(Task->Activity[ActivityID].GoalMethod != METHODQUEST) {
char buf[24];
snprintf(buf, 23, "%d %d", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID);
buf[23] = '\0';
parse->EventPlayer(EVENT_TASK_STAGE_COMPLETE, c, buf, 0);
if (!ignore_quest_update){
char buf[24];
snprintf(buf, 23, "%d %d", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID);
buf[23] = '\0';
parse->EventPlayer(EVENT_TASK_STAGE_COMPLETE, c, buf, 0);
}
/* QS: PlayerLogTaskUpdates :: Update */
if (RuleB(QueryServ, PlayerLogTaskUpdates)){
std::string event_desc = StringFormat("Task Stage Complete :: taskid:%i activityid:%i donecount:%i in zoneid:%i instid:%i", ActiveTasks[TaskIndex].TaskID, ActiveTasks[TaskIndex].Activity[ActivityID].ActivityID, ActiveTasks[TaskIndex].Activity[ActivityID].DoneCount, c->GetZoneID(), c->GetInstanceID());
@@ -2039,7 +2042,8 @@ bool ClientTaskState::IsTaskActivityActive(int TaskID, int ActivityID) {
}
void ClientTaskState::UpdateTaskActivity(Client *c, int TaskID, int ActivityID, int Count) {
void ClientTaskState::UpdateTaskActivity(Client *c, int TaskID, int ActivityID, int Count, bool ignore_quest_update /*= false*/)
{
_log(TASKS__UPDATE, "ClientTaskState UpdateTaskActivity(%i, %i, %i).", TaskID, ActivityID, Count);
@@ -2048,8 +2052,8 @@ void ClientTaskState::UpdateTaskActivity(Client *c, int TaskID, int ActivityID,
int ActiveTaskIndex = -1;
for(int i=0; i<MAXACTIVETASKS; i++) {
if(ActiveTasks[i].TaskID==TaskID) {
for (int i = 0; i < MAXACTIVETASKS; i++) {
if (ActiveTasks[i].TaskID == TaskID) {
ActiveTaskIndex = i;
break;
}
@@ -2069,7 +2073,7 @@ void ClientTaskState::UpdateTaskActivity(Client *c, int TaskID, int ActivityID,
// The Activity is not currently active
if(ActiveTasks[ActiveTaskIndex].Activity[ActivityID].State != ActivityActive) return;
_log(TASKS__UPDATE, "Increment done count on UpdateTaskActivity");
IncrementDoneCount(c, Task, ActiveTaskIndex, ActivityID, Count);
IncrementDoneCount(c, Task, ActiveTaskIndex, ActivityID, Count, ignore_quest_update);
}
@@ -2743,17 +2747,17 @@ void TaskManager::SendSingleActiveTaskToClient(Client *c, int TaskIndex, bool Ta
}
}
void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceNumber, int StartTime, int Duration, bool BringUpTaskJournal) {
if((TaskID<1) || (TaskID>=MAXTASKS) || !Tasks[TaskID]) return;
void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceNumber, int StartTime, int Duration, bool BringUpTaskJournal)
{
if ((TaskID < 1) || (TaskID >= MAXTASKS) || !Tasks[TaskID])
return;
int PacketLength = sizeof(TaskDescriptionHeader_Struct) + strlen(Tasks[TaskID]->Title) + 1
+ sizeof(TaskDescriptionData1_Struct) + strlen(Tasks[TaskID]->Description) + 1
+ sizeof(TaskDescriptionData2_Struct) + 1 + sizeof(TaskDescriptionTrailer_Struct);
std::string RewardText;
int ItemID = 0;
int ItemID = NOT_USED;
// If there is an item make the Reward text into a link to the item (only the first item if a list
// is specified). I have been unable to get multiple item links to work.
@@ -2768,62 +2772,20 @@ void TaskManager::SendActiveTaskDescription(Client *c, int TaskID, int SequenceN
if(ItemID < 0)
ItemID = 0;
}
if(ItemID) {
char *RewardTmp = 0;
if(strlen(Tasks[TaskID]->Reward) != 0) {
const Item_Struct* reward_item = database.GetItem(ItemID);
switch(c->GetClientVersion()) {
case EQClientTitanium:
{
MakeAnyLenString(&RewardTmp, "%c%06X000000000000000000000000000000014505DC2%s%c",
0x12, ItemID, Tasks[TaskID]->Reward,0x12);
break;
}
case EQClientRoF:
{
MakeAnyLenString(&RewardTmp, "%c%06X0000000000000000000000000000000000000000014505DC2%s%c",
0x12, ItemID, Tasks[TaskID]->Reward,0x12);
break;
}
default:
{
// All clients after Titanium
MakeAnyLenString(&RewardTmp, "%c%06X00000000000000000000000000000000000014505DC2%s%c",
0x12, ItemID, Tasks[TaskID]->Reward,0x12);
}
}
Client::TextLink linker;
linker.SetLinkType(linker.linkItemData);
linker.SetItemData(reward_item);
linker.SetClientVersion(c->GetClientVersion());
linker.SetTaskUse();
if (strlen(Tasks[TaskID]->Reward) != 0)
linker.SetProxyText(Tasks[TaskID]->Reward);
}
else {
const Item_Struct *Item = database.GetItem(ItemID);
if(Item) {
switch(c->GetClientVersion()) {
case EQClientTitanium:
{
MakeAnyLenString(&RewardTmp, "%c%06X000000000000000000000000000000014505DC2%s%c",
0x12, ItemID, Item->Name ,0x12);
break;
}
case EQClientRoF:
{
MakeAnyLenString(&RewardTmp, "%c%06X0000000000000000000000000000000000000000014505DC2%s%c",
0x12, ItemID, Item->Name ,0x12);
break;
}
default:
{
// All clients after Titanium
MakeAnyLenString(&RewardTmp, "%c%06X00000000000000000000000000000000000014505DC2%s%c",
0x12, ItemID, Item->Name ,0x12);
}
}
}
}
if(RewardTmp) RewardText += RewardTmp;
safe_delete_array(RewardTmp);
auto reward_link = linker.GenerateLink();
RewardText += reward_link.c_str();
}
else {
RewardText += Tasks[TaskID]->Reward;
+2 -2
View File
@@ -175,7 +175,7 @@ public:
bool IsTaskActive(int TaskID);
bool IsTaskActivityActive(int TaskID, int ActivityID);
ActivityState GetTaskActivityState(int index, int ActivityID);
void UpdateTaskActivity(Client *c, int TaskID, int ActivityID, int Count);
void UpdateTaskActivity(Client *c, int TaskID, int ActivityID, int Count, bool ignore_quest_update = false);
void ResetTaskActivity(Client *c, int TaskID, int ActivityID);
void CancelTask(Client *c, int SequenceNumber, bool RemoveFromDB = true);
void CancelAllTasks(Client *c);
@@ -204,7 +204,7 @@ public:
private:
bool UnlockActivities(int CharID, int TaskIndex);
void IncrementDoneCount(Client *c, TaskInformation *Task, int TaskIndex, int ActivityID, int Count=1);
void IncrementDoneCount(Client *c, TaskInformation *Task, int TaskIndex, int ActivityID, int Count = 1, bool ignore_quest_update = false);
int ActiveTaskCount;
ClientTaskInformation ActiveTasks[MAXACTIVETASKS];
std::vector<int>EnabledTasks;
+3 -1
View File
@@ -94,7 +94,7 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme
return;
}
ItemInst *tobe_auged, *auged_with = nullptr;
ItemInst *tobe_auged = nullptr, *auged_with = nullptr;
int8 slot=-1;
// Verify 2 items in the augmentation device
@@ -1185,6 +1185,8 @@ void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float
bool ZoneDatabase::GetTradeRecipe(const ItemInst* container, uint8 c_type, uint32 some_id,
uint32 char_id, DBTradeskillRecipe_Struct *spec)
{
if (container == nullptr)
return false;
std::string containers;// make where clause segment for container(s)
if (some_id == 0)
+3
View File
@@ -159,6 +159,9 @@ Mob* Trade::With()
// Private Method: Send item data for trade item to other person involved in trade
void Trade::SendItemData(const ItemInst* inst, int16 dest_slot_id)
{
if (inst == nullptr)
return;
// @merth: This needs to be redone with new item classes
Mob* mob = With();
if (!mob->IsClient())
+2 -2
View File
@@ -315,8 +315,8 @@ void Trap::CreateHiddenTrigger()
make_npc->gender = 0;
make_npc->loottable_id = 0;
make_npc->npc_spells_id = 0;
make_npc->d_meele_texture1 = 0;
make_npc->d_meele_texture2 = 0;
make_npc->d_melee_texture1 = 0;
make_npc->d_melee_texture2 = 0;
make_npc->trackable = 0;
make_npc->level = level;
strcpy(make_npc->special_abilities, "19,1^20,1^24,1^25,1");
+3 -3
View File
@@ -21,15 +21,15 @@ class WaterMap
{
public:
WaterMap() { }
~WaterMap() { }
virtual ~WaterMap() { }
static WaterMap* LoadWaterMapfile(std::string zone_name);
virtual WaterRegionType ReturnRegionType(float y, float x, float z) const { return RegionTypeNormal; }
virtual bool InWater(float y, float x, float z) const { return false; }
virtual bool InVWater(float y, float x, float z) const { return false; }
virtual bool InLava(float y, float x, float z) const { return false; }
virtual bool InLiquid(float y, float x, float z) const { return false; }
protected:
virtual bool Load(FILE *fp) { return false; }
};
+4 -2
View File
@@ -391,7 +391,9 @@ void NPC::GetClosestWaypoint(std::list<wplist> &wp_list, int count, float m_x, f
w_dist.index = i;
distances.push_back(w_dist);
}
distances.sort(wp_distance_pred);
distances.sort([](const wp_distance& a, const wp_distance& b) {
return a.dist < b.dist;
});
std::list<wp_distance>::iterator iter = distances.begin();
for(int i = 0; i < count; ++i)
@@ -694,7 +696,7 @@ bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, b
{
Map::Vertex dest(x_pos, y_pos, z_pos);
float newz = zone->zonemap->FindBestZ(dest, nullptr); + 2.0f;
float newz = zone->zonemap->FindBestZ(dest, nullptr);
mlog(AI__WAYPOINTS, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz,x_pos,y_pos,z_pos);
+4 -1
View File
@@ -2234,7 +2234,10 @@ void Zone::LoadNPCEmotes(LinkedList<NPC_Emote_Struct*>* NPCEmoteList)
}
void Zone::ReloadWorld(uint32 Option){
if(Option == 1){
if (Option == 0) {
entity_list.ClearAreas();
parse->ReloadQuests();
} else if(Option == 1) {
zone->Repop(0);
entity_list.ClearAreas();
parse->ReloadQuests();
+108 -99
View File
@@ -1740,15 +1740,15 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
// according to spawn2.
std::string query = StringFormat("SELECT npc_types.id, npc_types.name, npc_types.level, npc_types.race, "
"npc_types.class, npc_types.hp, npc_types.mana, npc_types.gender, "
"npc_types.texture, npc_types.helmtexture, npc_types.size, "
"npc_types.texture, npc_types.helmtexture, npc_types.herosforgemodel, npc_types.size, "
"npc_types.loottable_id, npc_types.merchant_id, npc_types.alt_currency_id, "
"npc_types.adventure_template_id, npc_types.trap_template, npc_types.attack_speed, "
"npc_types.STR, npc_types.STA, npc_types.DEX, npc_types.AGI, npc_types._INT, "
"npc_types.WIS, npc_types.CHA, npc_types.MR, npc_types.CR, npc_types.DR, "
"npc_types.FR, npc_types.PR, npc_types.Corrup, npc_types.PhR,"
"npc_types.mindmg, npc_types.maxdmg, npc_types.attack_count, npc_types.special_abilities,"
"npc_types.npc_spells_id, npc_types.npc_spells_effects_id, npc_types.d_meele_texture1,"
"npc_types.d_meele_texture2, npc_types.ammo_idfile, npc_types.prim_melee_type,"
"npc_types.npc_spells_id, npc_types.npc_spells_effects_id, npc_types.d_melee_texture1,"
"npc_types.d_melee_texture2, npc_types.ammo_idfile, npc_types.prim_melee_type,"
"npc_types.sec_melee_type, npc_types.ranged_type, npc_types.runspeed, npc_types.findable,"
"npc_types.trackable, npc_types.hp_regen_rate, npc_types.mana_regen_rate, "
"npc_types.aggroradius, npc_types.assistradius, npc_types.bodytype, npc_types.npc_faction_id, "
@@ -1790,88 +1790,86 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
tmpNPCType->gender = atoi(row[7]);
tmpNPCType->texture = atoi(row[8]);
tmpNPCType->helmtexture = atoi(row[9]);
tmpNPCType->size = atof(row[10]);
tmpNPCType->loottable_id = atoi(row[11]);
tmpNPCType->merchanttype = atoi(row[12]);
tmpNPCType->alt_currency_type = atoi(row[13]);
tmpNPCType->adventure_template = atoi(row[14]);
tmpNPCType->trap_template = atoi(row[15]);
tmpNPCType->attack_speed = atof(row[16]);
tmpNPCType->STR = atoi(row[17]);
tmpNPCType->STA = atoi(row[18]);
tmpNPCType->DEX = atoi(row[19]);
tmpNPCType->AGI = atoi(row[20]);
tmpNPCType->INT = atoi(row[21]);
tmpNPCType->WIS = atoi(row[22]);
tmpNPCType->CHA = atoi(row[23]);
tmpNPCType->MR = atoi(row[24]);
tmpNPCType->CR = atoi(row[25]);
tmpNPCType->DR = atoi(row[26]);
tmpNPCType->FR = atoi(row[27]);
tmpNPCType->PR = atoi(row[28]);
tmpNPCType->Corrup = atoi(row[29]);
tmpNPCType->PhR = atoi(row[30]);
tmpNPCType->min_dmg = atoi(row[31]);
tmpNPCType->max_dmg = atoi(row[32]);
tmpNPCType->attack_count = atoi(row[33]);
tmpNPCType->herosforgemodel = atoul(row[10]);
tmpNPCType->size = atof(row[11]);
tmpNPCType->loottable_id = atoi(row[12]);
tmpNPCType->merchanttype = atoi(row[13]);
tmpNPCType->alt_currency_type = atoi(row[14]);
tmpNPCType->adventure_template = atoi(row[15]);
tmpNPCType->trap_template = atoi(row[16]);
tmpNPCType->attack_speed = atof(row[17]);
tmpNPCType->STR = atoi(row[18]);
tmpNPCType->STA = atoi(row[19]);
tmpNPCType->DEX = atoi(row[20]);
tmpNPCType->AGI = atoi(row[21]);
tmpNPCType->INT = atoi(row[22]);
tmpNPCType->WIS = atoi(row[23]);
tmpNPCType->CHA = atoi(row[24]);
tmpNPCType->MR = atoi(row[25]);
tmpNPCType->CR = atoi(row[26]);
tmpNPCType->DR = atoi(row[27]);
tmpNPCType->FR = atoi(row[28]);
tmpNPCType->PR = atoi(row[29]);
tmpNPCType->Corrup = atoi(row[30]);
tmpNPCType->PhR = atoi(row[31]);
tmpNPCType->min_dmg = atoi(row[32]);
tmpNPCType->max_dmg = atoi(row[33]);
tmpNPCType->attack_count = atoi(row[34]);
if (row[34] != nullptr)
strn0cpy(tmpNPCType->special_abilities, row[34], 512);
if (row[35] != nullptr)
strn0cpy(tmpNPCType->special_abilities, row[35], 512);
else
tmpNPCType->special_abilities[0] = '\0';
tmpNPCType->npc_spells_id = atoi(row[35]);
tmpNPCType->npc_spells_effects_id = atoi(row[36]);
tmpNPCType->d_meele_texture1 = atoi(row[37]);
tmpNPCType->d_meele_texture2 = atoi(row[38]);
strn0cpy(tmpNPCType->ammo_idfile, row[39], 30);
tmpNPCType->prim_melee_type = atoi(row[40]);
tmpNPCType->sec_melee_type = atoi(row[41]);
tmpNPCType->ranged_type = atoi(row[42]);
tmpNPCType->runspeed= atof(row[43]);
tmpNPCType->findable = atoi(row[44]) == 0? false : true;
tmpNPCType->trackable = atoi(row[45]) == 0? false : true;
tmpNPCType->hp_regen = atoi(row[46]);
tmpNPCType->mana_regen = atoi(row[47]);
tmpNPCType->npc_spells_id = atoi(row[36]);
tmpNPCType->npc_spells_effects_id = atoi(row[37]);
tmpNPCType->d_melee_texture1 = atoi(row[38]);
tmpNPCType->d_melee_texture2 = atoi(row[39]);
strn0cpy(tmpNPCType->ammo_idfile, row[40], 30);
tmpNPCType->prim_melee_type = atoi(row[41]);
tmpNPCType->sec_melee_type = atoi(row[42]);
tmpNPCType->ranged_type = atoi(row[43]);
tmpNPCType->runspeed= atof(row[44]);
tmpNPCType->findable = atoi(row[45]) == 0? false : true;
tmpNPCType->trackable = atoi(row[46]) == 0? false : true;
tmpNPCType->hp_regen = atoi(row[47]);
tmpNPCType->mana_regen = atoi(row[48]);
// set defaultvalue for aggroradius
tmpNPCType->aggroradius = (int32)atoi(row[48]);
// set default value for aggroradius
tmpNPCType->aggroradius = (int32)atoi(row[49]);
if (tmpNPCType->aggroradius <= 0)
tmpNPCType->aggroradius = 70;
tmpNPCType->assistradius = (int32)atoi(row[49]);
tmpNPCType->assistradius = (int32)atoi(row[50]);
if (tmpNPCType->assistradius <= 0)
tmpNPCType->assistradius = tmpNPCType->aggroradius;
if (row[50] && strlen(row[50]))
tmpNPCType->bodytype = (uint8)atoi(row[50]);
if (row[51] && strlen(row[51]))
tmpNPCType->bodytype = (uint8)atoi(row[51]);
else
tmpNPCType->bodytype = 0;
tmpNPCType->npc_faction_id = atoi(row[51]);
tmpNPCType->npc_faction_id = atoi(row[52]);
tmpNPCType->luclinface = atoi(row[52]);
tmpNPCType->hairstyle = atoi(row[53]);
tmpNPCType->haircolor = atoi(row[54]);
tmpNPCType->eyecolor1 = atoi(row[55]);
tmpNPCType->eyecolor2 = atoi(row[56]);
tmpNPCType->beardcolor = atoi(row[57]);
tmpNPCType->beard = atoi(row[58]);
tmpNPCType->drakkin_heritage = atoi(row[59]);
tmpNPCType->drakkin_tattoo = atoi(row[60]);
tmpNPCType->drakkin_details = atoi(row[61]);
tmpNPCType->luclinface = atoi(row[53]);
tmpNPCType->hairstyle = atoi(row[54]);
tmpNPCType->haircolor = atoi(row[55]);
tmpNPCType->eyecolor1 = atoi(row[56]);
tmpNPCType->eyecolor2 = atoi(row[57]);
tmpNPCType->beardcolor = atoi(row[58]);
tmpNPCType->beard = atoi(row[59]);
tmpNPCType->drakkin_heritage = atoi(row[60]);
tmpNPCType->drakkin_tattoo = atoi(row[61]);
tmpNPCType->drakkin_details = atoi(row[62]);
uint32 armor_tint_id = atoi(row[62]);
uint32 armor_tint_id = atoi(row[63]);
tmpNPCType->armor_tint[0] = (atoi(row[63]) & 0xFF) << 16;
tmpNPCType->armor_tint[0] |= (atoi(row[64]) & 0xFF) << 8;
tmpNPCType->armor_tint[0] |= (atoi(row[65]) & 0xFF);
tmpNPCType->armor_tint[0] = (atoi(row[64]) & 0xFF) << 16;
tmpNPCType->armor_tint[0] |= (atoi(row[65]) & 0xFF) << 8;
tmpNPCType->armor_tint[0] |= (atoi(row[66]) & 0xFF);
tmpNPCType->armor_tint[0] |= (tmpNPCType->armor_tint[0]) ? (0xFF << 24) : 0;
if (armor_tint_id == 0)
for (int index = MaterialChest; index <= EmuConstants::MATERIAL_END; index++)
tmpNPCType->armor_tint[index] = tmpNPCType->armor_tint[0];
else if (tmpNPCType->armor_tint[0] == 0)
if (armor_tint_id != 0)
{
std::string armortint_query = StringFormat("SELECT red1h, grn1h, blu1h, "
"red2c, grn2c, blu2c, "
@@ -1886,46 +1884,57 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
armor_tint_id);
auto armortint_results = QueryDatabase(armortint_query);
if (!armortint_results.Success() || armortint_results.RowCount() == 0)
armor_tint_id = 0;
else {
{
armor_tint_id = 0;
}
else
{
auto armorTint_row = armortint_results.begin();
for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++) {
for (int index = EmuConstants::MATERIAL_BEGIN; index <= EmuConstants::MATERIAL_END; index++)
{
tmpNPCType->armor_tint[index] = atoi(armorTint_row[index * 3]) << 16;
tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 1]) << 8;
tmpNPCType->armor_tint[index] |= atoi(armorTint_row[index * 3 + 2]);
tmpNPCType->armor_tint[index] |= (tmpNPCType->armor_tint[index]) ? (0xFF << 24) : 0;
}
}
} else
armor_tint_id = 0;
}
// Try loading npc_types tint fields if armor tint is 0 or query failed to get results
if (armor_tint_id == 0)
{
for (int index = MaterialChest; index < _MaterialCount; index++)
{
tmpNPCType->armor_tint[index] = tmpNPCType->armor_tint[0];
}
}
tmpNPCType->see_invis = atoi(row[66]);
tmpNPCType->see_invis_undead = atoi(row[67]) == 0? false: true; // Set see_invis_undead flag
if (row[68] != nullptr)
strn0cpy(tmpNPCType->lastname, row[68], 32);
tmpNPCType->see_invis = atoi(row[67]);
tmpNPCType->see_invis_undead = atoi(row[68]) == 0? false: true; // Set see_invis_undead flag
if (row[69] != nullptr)
strn0cpy(tmpNPCType->lastname, row[69], 32);
tmpNPCType->qglobal = atoi(row[69]) == 0? false: true; // qglobal
tmpNPCType->AC = atoi(row[70]);
tmpNPCType->npc_aggro = atoi(row[71]) == 0? false: true;
tmpNPCType->spawn_limit = atoi(row[72]);
tmpNPCType->see_hide = atoi(row[73]) == 0? false: true;
tmpNPCType->see_improved_hide = atoi(row[74]) == 0? false: true;
tmpNPCType->ATK = atoi(row[75]);
tmpNPCType->accuracy_rating = atoi(row[76]);
tmpNPCType->avoidance_rating = atoi(row[77]);
tmpNPCType->slow_mitigation = atoi(row[78]);
tmpNPCType->maxlevel = atoi(row[79]);
tmpNPCType->scalerate = atoi(row[80]);
tmpNPCType->private_corpse = atoi(row[81]) == 1 ? true: false;
tmpNPCType->unique_spawn_by_name = atoi(row[82]) == 1 ? true: false;
tmpNPCType->underwater = atoi(row[83]) == 1 ? true: false;
tmpNPCType->emoteid = atoi(row[84]);
tmpNPCType->spellscale = atoi(row[85]);
tmpNPCType->healscale = atoi(row[86]);
tmpNPCType->no_target_hotkey = atoi(row[87]) == 1 ? true: false;
tmpNPCType->raid_target = atoi(row[88]) == 0 ? false: true;
tmpNPCType->attack_delay = atoi(row[89]);
tmpNPCType->qglobal = atoi(row[70]) == 0? false: true; // qglobal
tmpNPCType->AC = atoi(row[71]);
tmpNPCType->npc_aggro = atoi(row[72]) == 0? false: true;
tmpNPCType->spawn_limit = atoi(row[73]);
tmpNPCType->see_hide = atoi(row[74]) == 0? false: true;
tmpNPCType->see_improved_hide = atoi(row[75]) == 0? false: true;
tmpNPCType->ATK = atoi(row[76]);
tmpNPCType->accuracy_rating = atoi(row[77]);
tmpNPCType->avoidance_rating = atoi(row[78]);
tmpNPCType->slow_mitigation = atoi(row[79]);
tmpNPCType->maxlevel = atoi(row[80]);
tmpNPCType->scalerate = atoi(row[81]);
tmpNPCType->private_corpse = atoi(row[82]) == 1 ? true: false;
tmpNPCType->unique_spawn_by_name = atoi(row[83]) == 1 ? true: false;
tmpNPCType->underwater = atoi(row[84]) == 1 ? true: false;
tmpNPCType->emoteid = atoi(row[85]);
tmpNPCType->spellscale = atoi(row[86]);
tmpNPCType->healscale = atoi(row[87]);
tmpNPCType->no_target_hotkey = atoi(row[88]) == 1 ? true: false;
tmpNPCType->raid_target = atoi(row[89]) == 0 ? false: true;
tmpNPCType->attack_delay = atoi(row[90]);
// If NPC with duplicate NPC id already in table,
// free item we attempted to add.
@@ -1968,7 +1977,7 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
"vwMercNpcTypes.CR, vwMercNpcTypes.DR, vwMercNpcTypes.FR, vwMercNpcTypes.PR, "
"vwMercNpcTypes.Corrup, vwMercNpcTypes.mindmg, vwMercNpcTypes.maxdmg, "
"vwMercNpcTypes.attack_count, vwMercNpcTypes.special_abilities, "
"vwMercNpcTypes.d_meele_texture1, vwMercNpcTypes.d_meele_texture2, "
"vwMercNpcTypes.d_melee_texture1, vwMercNpcTypes.d_melee_texture2, "
"vwMercNpcTypes.prim_melee_type, vwMercNpcTypes.sec_melee_type, "
"vwMercNpcTypes.runspeed, vwMercNpcTypes.hp_regen_rate, vwMercNpcTypes.mana_regen_rate, "
"vwMercNpcTypes.bodytype, vwMercNpcTypes.armortint_id, "
@@ -2027,8 +2036,8 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
else
tmpNPCType->special_abilities[0] = '\0';
tmpNPCType->d_meele_texture1 = atoi(row[28]);
tmpNPCType->d_meele_texture2 = atoi(row[29]);
tmpNPCType->d_melee_texture1 = atoi(row[28]);
tmpNPCType->d_melee_texture2 = atoi(row[29]);
tmpNPCType->prim_melee_type = atoi(row[30]);
tmpNPCType->sec_melee_type = atoi(row[31]);
tmpNPCType->runspeed= atof(row[32]);
+3 -2
View File
@@ -49,6 +49,7 @@ struct NPCType
uint32 npc_id;
uint8 texture;
uint8 helmtexture;
uint32 herosforgemodel;
uint32 loottable_id;
uint32 npc_spells_id;
uint32 npc_spells_effects_id;
@@ -90,8 +91,8 @@ struct NPCType
uint32 max_dmg;
int16 attack_count;
char special_abilities[512];
uint16 d_meele_texture1;
uint16 d_meele_texture2;
uint16 d_melee_texture1;
uint16 d_melee_texture2;
char ammo_idfile[30];
uint8 prim_melee_type;
uint8 sec_melee_type;