mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-16 22:58:34 +00:00
Merge remote-tracking branch 'origin/master' into Development
This commit is contained in:
@@ -119,7 +119,6 @@ SET(zone_sources
|
||||
zone_logsys.cpp
|
||||
zone_config.cpp
|
||||
zonedb.cpp
|
||||
zonedbasync.cpp
|
||||
zoning.cpp
|
||||
)
|
||||
|
||||
@@ -207,7 +206,6 @@ SET(zone_headers
|
||||
zone.h
|
||||
zone_config.h
|
||||
zonedb.h
|
||||
zonedbasync.h
|
||||
zonedump.h
|
||||
)
|
||||
|
||||
|
||||
+207
-47
@@ -18,6 +18,8 @@ Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net)
|
||||
|
||||
// Test 1
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "../common/debug.h"
|
||||
#include "aa.h"
|
||||
#include "mob.h"
|
||||
@@ -300,7 +302,7 @@ void Client::ActivateAA(aaID activate){
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if(!CastSpell(caa->spell_id, target_id, 10, -1, -1, 0, -1, AATimerID + pTimerAAStart, timer_base, 1)) {
|
||||
if (!CastSpell(caa->spell_id, target_id, USE_ITEM_SPELL_SLOT, -1, -1, 0, -1, AATimerID + pTimerAAStart, timer_base, 1)) {
|
||||
//Reset on failed cast
|
||||
SendAATimer(AATimerID, 0, 0xFFFFFF);
|
||||
Message_StringID(15,ABILITY_FAILED);
|
||||
@@ -316,13 +318,14 @@ void Client::ActivateAA(aaID activate){
|
||||
}
|
||||
}
|
||||
// Check if AA is expendable
|
||||
if (aas_send[activate - activate_val]->special_category == 7)
|
||||
{
|
||||
if (aas_send[activate - activate_val]->special_category == 7) {
|
||||
|
||||
// Add the AA cost to the extended profile to track overall total
|
||||
m_epp.expended_aa += aas_send[activate]->cost;
|
||||
|
||||
SetAA(activate, 0);
|
||||
|
||||
Save();
|
||||
SaveAA(); /* Save Character AA */
|
||||
SendAA(activate);
|
||||
SendAATable();
|
||||
}
|
||||
@@ -525,7 +528,7 @@ void Client::HandleAAAction(aaID activate) {
|
||||
//cast the spell, if we have one
|
||||
if(IsValidSpell(spell_id)) {
|
||||
int aatid = GetAATimerID(activate);
|
||||
if(!CastSpell(spell_id, target_id , 10, -1, -1, 0, -1, pTimerAAStart + aatid , CalcAAReuseTimer(caa), 1)) {
|
||||
if (!CastSpell(spell_id, target_id, USE_ITEM_SPELL_SLOT, -1, -1, 0, -1, pTimerAAStart + aatid, CalcAAReuseTimer(caa), 1)) {
|
||||
SendAATimer(aatid, 0, 0xFFFFFF);
|
||||
Message_StringID(15,ABILITY_FAILED);
|
||||
p_timers.Clear(&database, pTimerAAStart + aatid);
|
||||
@@ -1035,8 +1038,7 @@ void Client::BuyAA(AA_Action* action)
|
||||
uint32 real_cost;
|
||||
std::map<uint32, AALevelCost_Struct>::iterator RequiredLevel = AARequiredLevelAndCost.find(action->ability);
|
||||
|
||||
if(RequiredLevel != AARequiredLevelAndCost.end())
|
||||
{
|
||||
if(RequiredLevel != AARequiredLevelAndCost.end()) {
|
||||
real_cost = RequiredLevel->second.Cost;
|
||||
}
|
||||
else
|
||||
@@ -1049,7 +1051,11 @@ void Client::BuyAA(AA_Action* action)
|
||||
|
||||
m_pp.aapoints -= real_cost;
|
||||
|
||||
Save();
|
||||
/* Do Player Profile rank calculations and set player profile */
|
||||
SaveAA();
|
||||
/* Save to Database to avoid having to write the whole AA array to the profile, only write changes*/
|
||||
// database.SaveCharacterAA(this->CharacterID(), aa2->id, (cur_level + 1));
|
||||
|
||||
if ((RuleB(AA, Stacking) && (GetClientVersionBit() >= 4) && (aa2->hotkey_sid == 4294967295u))
|
||||
&& ((aa2->max_level == (cur_level + 1)) && aa2->sof_next_id)){
|
||||
SendAA(aa2->id);
|
||||
@@ -1060,8 +1066,10 @@ void Client::BuyAA(AA_Action* action)
|
||||
|
||||
SendAATable();
|
||||
|
||||
//we are building these messages ourself instead of using the stringID to work around patch discrepencies
|
||||
//these are AA_GAIN_ABILITY (410) & AA_IMPROVE (411), respectively, in both Titanium & SoF. not sure about 6.2
|
||||
/*
|
||||
We are building these messages ourself instead of using the stringID to work around patch discrepencies
|
||||
these are AA_GAIN_ABILITY (410) & AA_IMPROVE (411), respectively, in both Titanium & SoF. not sure about 6.2
|
||||
*/
|
||||
|
||||
/* Initial purchase of an AA ability */
|
||||
if (cur_level < 1){
|
||||
@@ -1084,8 +1092,6 @@ void Client::BuyAA(AA_Action* action)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
SendAAStats();
|
||||
|
||||
CalcBonuses();
|
||||
@@ -1514,11 +1520,15 @@ bool ZoneDatabase::LoadAAEffects2() {
|
||||
return true;
|
||||
}
|
||||
void Client::ResetAA(){
|
||||
RefundAA();
|
||||
uint32 i;
|
||||
for(i=0;i<MAX_PP_AA_ARRAY;i++){
|
||||
aa[i]->AA = 0;
|
||||
aa[i]->value = 0;
|
||||
m_pp.aa_array[MAX_PP_AA_ARRAY].AA = 0;
|
||||
m_pp.aa_array[MAX_PP_AA_ARRAY].value = 0;
|
||||
}
|
||||
|
||||
std::map<uint32,uint8>::iterator itr;
|
||||
for(itr=aa_points.begin();itr!=aa_points.end();++itr)
|
||||
aa_points[itr->first] = 0;
|
||||
@@ -1530,10 +1540,51 @@ void Client::ResetAA(){
|
||||
m_pp.raid_leadership_points = 0;
|
||||
m_pp.group_leadership_exp = 0;
|
||||
m_pp.raid_leadership_exp = 0;
|
||||
|
||||
database.DeleteCharacterAAs(this->CharacterID());
|
||||
SaveAA();
|
||||
SendAATable();
|
||||
database.DeleteCharacterLeadershipAAs(this->CharacterID());
|
||||
Kick();
|
||||
}
|
||||
|
||||
int Client::GroupLeadershipAAHealthEnhancement()
|
||||
{
|
||||
if (IsRaidGrouped()) {
|
||||
int bonus = 0;
|
||||
Raid *raid = GetRaid();
|
||||
if (!raid)
|
||||
return 0;
|
||||
uint32 group_id = raid->GetGroup(this);
|
||||
if (group_id < 12 && raid->GroupCount(group_id) >= 3) {
|
||||
switch (raid->GetLeadershipAA(groupAAHealthEnhancement, group_id)) {
|
||||
case 1:
|
||||
bonus = 30;
|
||||
break;
|
||||
case 2:
|
||||
bonus = 60;
|
||||
break;
|
||||
case 3:
|
||||
bonus = 100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (raid->RaidCount() >= 18) {
|
||||
switch (raid->GetLeadershipAA(raidAAHealthEnhancement)) {
|
||||
case 1:
|
||||
bonus += 30;
|
||||
break;
|
||||
case 2:
|
||||
bonus += 60;
|
||||
break;
|
||||
case 3:
|
||||
bonus += 100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bonus;
|
||||
}
|
||||
|
||||
Group *g = GetGroup();
|
||||
|
||||
if(!g || (g->GroupCount() < 3))
|
||||
@@ -1556,6 +1607,41 @@ int Client::GroupLeadershipAAHealthEnhancement()
|
||||
|
||||
int Client::GroupLeadershipAAManaEnhancement()
|
||||
{
|
||||
if (IsRaidGrouped()) {
|
||||
int bonus = 0;
|
||||
Raid *raid = GetRaid();
|
||||
if (!raid)
|
||||
return 0;
|
||||
uint32 group_id = raid->GetGroup(this);
|
||||
if (group_id < 12 && raid->GroupCount(group_id) >= 3) {
|
||||
switch (raid->GetLeadershipAA(groupAAManaEnhancement, group_id)) {
|
||||
case 1:
|
||||
bonus = 30;
|
||||
break;
|
||||
case 2:
|
||||
bonus = 60;
|
||||
break;
|
||||
case 3:
|
||||
bonus = 100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (raid->RaidCount() >= 18) {
|
||||
switch (raid->GetLeadershipAA(raidAAManaEnhancement)) {
|
||||
case 1:
|
||||
bonus += 30;
|
||||
break;
|
||||
case 2:
|
||||
bonus += 60;
|
||||
break;
|
||||
case 3:
|
||||
bonus += 100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bonus;
|
||||
}
|
||||
|
||||
Group *g = GetGroup();
|
||||
|
||||
if(!g || (g->GroupCount() < 3))
|
||||
@@ -1578,6 +1664,41 @@ int Client::GroupLeadershipAAManaEnhancement()
|
||||
|
||||
int Client::GroupLeadershipAAHealthRegeneration()
|
||||
{
|
||||
if (IsRaidGrouped()) {
|
||||
int bonus = 0;
|
||||
Raid *raid = GetRaid();
|
||||
if (!raid)
|
||||
return 0;
|
||||
uint32 group_id = raid->GetGroup(this);
|
||||
if (group_id < 12 && raid->GroupCount(group_id) >= 3) {
|
||||
switch (raid->GetLeadershipAA(groupAAHealthRegeneration, group_id)) {
|
||||
case 1:
|
||||
bonus = 4;
|
||||
break;
|
||||
case 2:
|
||||
bonus = 6;
|
||||
break;
|
||||
case 3:
|
||||
bonus = 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (raid->RaidCount() >= 18) {
|
||||
switch (raid->GetLeadershipAA(raidAAHealthRegeneration)) {
|
||||
case 1:
|
||||
bonus += 4;
|
||||
break;
|
||||
case 2:
|
||||
bonus += 6;
|
||||
break;
|
||||
case 3:
|
||||
bonus += 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bonus;
|
||||
}
|
||||
|
||||
Group *g = GetGroup();
|
||||
|
||||
if(!g || (g->GroupCount() < 3))
|
||||
@@ -1600,6 +1721,53 @@ int Client::GroupLeadershipAAHealthRegeneration()
|
||||
|
||||
int Client::GroupLeadershipAAOffenseEnhancement()
|
||||
{
|
||||
if (IsRaidGrouped()) {
|
||||
int bonus = 0;
|
||||
Raid *raid = GetRaid();
|
||||
if (!raid)
|
||||
return 0;
|
||||
uint32 group_id = raid->GetGroup(this);
|
||||
if (group_id < 12 && raid->GroupCount(group_id) >= 3) {
|
||||
switch (raid->GetLeadershipAA(groupAAOffenseEnhancement, group_id)) {
|
||||
case 1:
|
||||
bonus = 10;
|
||||
break;
|
||||
case 2:
|
||||
bonus = 19;
|
||||
break;
|
||||
case 3:
|
||||
bonus = 28;
|
||||
break;
|
||||
case 4:
|
||||
bonus = 34;
|
||||
break;
|
||||
case 5:
|
||||
bonus = 40;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (raid->RaidCount() >= 18) {
|
||||
switch (raid->GetLeadershipAA(raidAAOffenseEnhancement)) {
|
||||
case 1:
|
||||
bonus += 10;
|
||||
break;
|
||||
case 2:
|
||||
bonus += 19;
|
||||
break;
|
||||
case 3:
|
||||
bonus += 28;
|
||||
break;
|
||||
case 4:
|
||||
bonus += 34;
|
||||
break;
|
||||
case 5:
|
||||
bonus += 40;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bonus;
|
||||
}
|
||||
|
||||
Group *g = GetGroup();
|
||||
|
||||
if(!g || (g->GroupCount() < 3))
|
||||
@@ -1625,29 +1793,26 @@ int Client::GroupLeadershipAAOffenseEnhancement()
|
||||
|
||||
void Client::InspectBuffs(Client* Inspector, int Rank)
|
||||
{
|
||||
if(!Inspector || (Rank == 0)) return;
|
||||
// At some point the removed the restriction of being a group member for this to work
|
||||
// not sure when, but the way it's coded now, it wouldn't work with mobs.
|
||||
if (!Inspector || Rank == 0)
|
||||
return;
|
||||
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_InspectBuffs, sizeof(InspectBuffs_Struct));
|
||||
InspectBuffs_Struct *ib = (InspectBuffs_Struct *)outapp->pBuffer;
|
||||
|
||||
Inspector->Message_StringID(0, CURRENT_SPELL_EFFECTS, GetName());
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (uint32 i = 0; i < buff_count; ++i)
|
||||
{
|
||||
if (buffs[i].spellid != SPELL_UNKNOWN)
|
||||
{
|
||||
if(Rank == 1)
|
||||
Inspector->Message(0, "%s", spells[buffs[i].spellid].name);
|
||||
else
|
||||
{
|
||||
if (spells[buffs[i].spellid].buffdurationformula == DF_Permanent)
|
||||
Inspector->Message(0, "%s (Permanent)", spells[buffs[i].spellid].name);
|
||||
else {
|
||||
char *TempString = nullptr;
|
||||
MakeAnyLenString(&TempString, "%.1f", static_cast<float>(buffs[i].ticsremaining) / 10.0f);
|
||||
Inspector->Message_StringID(0, BUFF_MINUTES_REMAINING, spells[buffs[i].spellid].name, TempString);
|
||||
safe_delete_array(TempString);
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32 packet_index = 0;
|
||||
for (uint32 i = 0; i < buff_count; i++) {
|
||||
if (buffs[i].spellid == SPELL_UNKNOWN)
|
||||
continue;
|
||||
ib->spell_id[packet_index] = buffs[i].spellid;
|
||||
if (Rank > 1)
|
||||
ib->tics_remaining[packet_index] = spells[buffs[i].spellid].buffdurationformula == DF_Permanent ? 0xFFFFFFFF : buffs[i].ticsremaining;
|
||||
packet_index++;
|
||||
}
|
||||
|
||||
Inspector->FastQueuePacket(&outapp);
|
||||
}
|
||||
|
||||
//this really need to be renamed to LoadAAActions()
|
||||
@@ -1735,19 +1900,15 @@ void ZoneDatabase::FillAAEffects(SendAA_Struct* aa_struct){
|
||||
if(!aa_struct)
|
||||
return;
|
||||
|
||||
std::string query = StringFormat("SELECT effectid, base1, base2, slot from aa_effects where aaid=%i order by slot asc", aa_struct->id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in Client::FillAAEffects query: '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row, ++index) {
|
||||
aa_struct->abilities[index].skill_id=atoi(row[0]);
|
||||
aa_struct->abilities[index].base1=atoi(row[1]);
|
||||
aa_struct->abilities[index].base2=atoi(row[2]);
|
||||
aa_struct->abilities[index].slot=atoi(row[3]);
|
||||
auto it = aa_effects.find(aa_struct->id);
|
||||
if (it != aa_effects.end()) {
|
||||
for (int slot = 0; slot < aa_struct->total_abilities; slot++) {
|
||||
// aa_effects is a map of a map, so the slot reference does not start at 0
|
||||
aa_struct->abilities[slot].skill_id = it->second[slot + 1].skill_id;
|
||||
aa_struct->abilities[slot].base1 = it->second[slot + 1].base1;
|
||||
aa_struct->abilities[slot].base2 = it->second[slot + 1].base2;
|
||||
aa_struct->abilities[slot].slot = it->second[slot + 1].slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1818,8 +1979,7 @@ void ZoneDatabase::LoadAAs(SendAA_Struct **load){
|
||||
}
|
||||
|
||||
AALevelCost_Struct aalcs;
|
||||
for (auto row = results.begin(); row != results.end(); ++row)
|
||||
{
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
aalcs.Level = atoi(row[1]);
|
||||
aalcs.Cost = atoi(row[2]);
|
||||
AARequiredLevelAndCost[atoi(row[0])] = aalcs;
|
||||
|
||||
+72
-38
@@ -3315,7 +3315,10 @@ int32 Mob::AffectMagicalDamage(int32 damage, uint16 spell_id, const bool iBuffTi
|
||||
|
||||
if(damage < 1)
|
||||
return 0;
|
||||
|
||||
|
||||
//Regular runes absorb spell damage (except dots) - Confirmed on live.
|
||||
if (spellbonuses.MeleeRune[0] && spellbonuses.MeleeRune[1] >= 0)
|
||||
damage = RuneAbsorb(damage, SE_Rune);
|
||||
|
||||
if (spellbonuses.AbsorbMagicAtt[0] && spellbonuses.AbsorbMagicAtt[1] >= 0)
|
||||
damage = RuneAbsorb(damage, SE_AbsorbMagicAtt);
|
||||
@@ -3331,10 +3334,13 @@ int32 Mob::ReduceAllDamage(int32 damage)
|
||||
if(damage <= 0)
|
||||
return damage;
|
||||
|
||||
if(spellbonuses.ManaAbsorbPercentDamage[0] && (GetMana() > damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100)) {
|
||||
damage -= (damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100);
|
||||
SetMana(GetMana() - damage);
|
||||
TryTriggerOnValueAmount(false, true);
|
||||
if(spellbonuses.ManaAbsorbPercentDamage[0]) {
|
||||
int32 mana_reduced = damage * spellbonuses.ManaAbsorbPercentDamage[0] / 100;
|
||||
if (GetMana() >= mana_reduced){
|
||||
damage -= mana_reduced;
|
||||
SetMana(GetMana() - mana_reduced);
|
||||
TryTriggerOnValueAmount(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
CheckNumHitsRemaining(NUMHIT_IncomingDamage);
|
||||
@@ -4197,24 +4203,26 @@ void Mob::TryCriticalHit(Mob *defender, uint16 skill, int32 &damage, ExtraAttack
|
||||
}
|
||||
#endif //BOTS
|
||||
|
||||
|
||||
float critChance = 0.0f;
|
||||
bool IsBerskerSPA = false;
|
||||
|
||||
//1: Try Slay Undead
|
||||
if(defender && defender->GetBodyType() == BT_Undead || defender->GetBodyType() == BT_SummonedUndead || defender->GetBodyType() == BT_Vampire){
|
||||
|
||||
if (defender && (defender->GetBodyType() == BT_Undead ||
|
||||
defender->GetBodyType() == BT_SummonedUndead || defender->GetBodyType() == BT_Vampire)) {
|
||||
int16 SlayRateBonus = aabonuses.SlayUndead[0] + itembonuses.SlayUndead[0] + spellbonuses.SlayUndead[0];
|
||||
|
||||
if (SlayRateBonus) {
|
||||
|
||||
critChance += (float(SlayRateBonus)/100.0f);
|
||||
critChance /= 100.0f;
|
||||
|
||||
if(MakeRandomFloat(0, 1) < critChance){
|
||||
float slayChance = static_cast<float>(SlayRateBonus) / 10000.0f;
|
||||
if (MakeRandomFloat(0, 1) < slayChance) {
|
||||
int16 SlayDmgBonus = aabonuses.SlayUndead[1] + itembonuses.SlayUndead[1] + spellbonuses.SlayUndead[1];
|
||||
damage = (damage*SlayDmgBonus*2.25)/100;
|
||||
entity_list.MessageClose(this, false, 200, MT_CritMelee, "%s cleanses %s target!(%d)", GetCleanName(), this->GetGender() == 0 ? "his" : this->GetGender() == 1 ? "her" : "its", damage);
|
||||
damage = (damage * SlayDmgBonus * 2.25) / 100;
|
||||
if (GetGender() == 1) // female
|
||||
entity_list.FilteredMessageClose_StringID(this, false, 200,
|
||||
MT_CritMelee, FilterMeleeCrits, FEMALE_SLAYUNDEAD,
|
||||
GetCleanName(), itoa(damage));
|
||||
else // males and neuter I guess
|
||||
entity_list.FilteredMessageClose_StringID(this, false, 200,
|
||||
MT_CritMelee, FilterMeleeCrits, MALE_SLAYUNDEAD,
|
||||
GetCleanName(), itoa(damage));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -4804,6 +4812,26 @@ void Mob::CommonBreakInvisible()
|
||||
improved_hidden = false;
|
||||
}
|
||||
|
||||
/* Dev quotes:
|
||||
* Old formula
|
||||
* Final delay = (Original Delay / (haste mod *.01f)) + ((Hundred Hands / 100) * Original Delay)
|
||||
* New formula
|
||||
* Final delay = (Original Delay / (haste mod *.01f)) + ((Hundred Hands / 1000) * (Original Delay / (haste mod *.01f))
|
||||
* Base Delay 20 25 30 37
|
||||
* Haste 2.25 2.25 2.25 2.25
|
||||
* HHE (old) -17 -17 -17 -17
|
||||
* Final Delay 5.488888889 6.861111111 8.233333333 10.15444444
|
||||
*
|
||||
* Base Delay 20 25 30 37
|
||||
* Haste 2.25 2.25 2.25 2.25
|
||||
* HHE (new) -383 -383 -383 -383
|
||||
* Final Delay 5.484444444 6.855555556 8.226666667 10.14622222
|
||||
*
|
||||
* Difference -0.004444444 -0.005555556 -0.006666667 -0.008222222
|
||||
*
|
||||
* These times are in 10th of a second
|
||||
*/
|
||||
|
||||
void Mob::SetAttackTimer()
|
||||
{
|
||||
attack_timer.SetAtTrigger(4000, true);
|
||||
@@ -4811,7 +4839,7 @@ void Mob::SetAttackTimer()
|
||||
|
||||
void Client::SetAttackTimer()
|
||||
{
|
||||
float PermaHaste = GetPermaHaste();
|
||||
float haste_mod = GetHaste() * 0.01f;
|
||||
|
||||
//default value for attack timer in case they have
|
||||
//an invalid weapon equipped:
|
||||
@@ -4876,28 +4904,30 @@ void Client::SetAttackTimer()
|
||||
}
|
||||
}
|
||||
|
||||
int16 DelayMod = std::max(itembonuses.HundredHands + spellbonuses.HundredHands, -99);
|
||||
int hhe = itembonuses.HundredHands + spellbonuses.HundredHands;
|
||||
int speed = 0;
|
||||
int delay = 36;
|
||||
float quiver_haste = 0.0f;
|
||||
|
||||
//if we have no weapon..
|
||||
if (ItemToUse == nullptr) {
|
||||
//above checks ensure ranged weapons do not fall into here
|
||||
// Work out if we're a monk
|
||||
if ((GetClass() == MONK) || (GetClass() == BEASTLORD))
|
||||
speed = static_cast<int>((GetMonkHandToHandDelay() * (100 + DelayMod) / 100) * PermaHaste);
|
||||
else
|
||||
speed = static_cast<int>((36 * (100 + DelayMod) / 100) * PermaHaste);
|
||||
if (GetClass() == MONK || GetClass() == BEASTLORD)
|
||||
delay = GetMonkHandToHandDelay();
|
||||
} else {
|
||||
//we have a weapon, use its delay
|
||||
// Convert weapon delay to timer resolution (milliseconds)
|
||||
//delay * 100
|
||||
speed = static_cast<int>((ItemToUse->Delay * (100 + DelayMod) / 100) * PermaHaste);
|
||||
if (ItemToUse->ItemType == ItemTypeBow || ItemToUse->ItemType == ItemTypeLargeThrowing) {
|
||||
float quiver_haste = GetQuiverHaste();
|
||||
if (quiver_haste > 0)
|
||||
speed *= quiver_haste;
|
||||
}
|
||||
delay = ItemToUse->Delay;
|
||||
if (ItemToUse->ItemType == ItemTypeBow || ItemToUse->ItemType == ItemTypeLargeThrowing)
|
||||
quiver_haste = GetQuiverHaste();
|
||||
}
|
||||
if (RuleB(Spells, Jun182014HundredHandsRevamp))
|
||||
speed = static_cast<int>(((delay / haste_mod) + ((hhe / 1000.0f) * (delay / haste_mod))) * 100);
|
||||
else
|
||||
speed = static_cast<int>(((delay / haste_mod) + ((hhe / 100.0f) * delay)) * 100);
|
||||
// this is probably wrong
|
||||
if (quiver_haste > 0)
|
||||
speed *= quiver_haste;
|
||||
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true);
|
||||
|
||||
if (i == MainPrimary)
|
||||
@@ -4907,13 +4937,24 @@ void Client::SetAttackTimer()
|
||||
|
||||
void NPC::SetAttackTimer()
|
||||
{
|
||||
float PermaHaste = GetPermaHaste();
|
||||
float haste_mod = GetHaste() * 0.01f;
|
||||
|
||||
//default value for attack timer in case they have
|
||||
//an invalid weapon equipped:
|
||||
attack_timer.SetAtTrigger(4000, true);
|
||||
|
||||
Timer *TimerToUse = nullptr;
|
||||
int hhe = itembonuses.HundredHands + spellbonuses.HundredHands;
|
||||
|
||||
// Technically NPCs should do some logic for weapons, but the effect is minimal
|
||||
// What they do is take the lower of their set delay and the weapon's
|
||||
// ex. Mob's delay set to 20, weapon set to 19, delay 19
|
||||
// Mob's delay set to 20, weapon set to 21, delay 20
|
||||
int speed = 0;
|
||||
if (RuleB(Spells, Jun182014HundredHandsRevamp))
|
||||
speed = static_cast<int>(((attack_delay / haste_mod) + ((hhe / 1000.0f) * (attack_delay / haste_mod))) * 100);
|
||||
else
|
||||
speed = static_cast<int>(((attack_delay / haste_mod) + ((hhe / 100.0f) * attack_delay)) * 100);
|
||||
|
||||
for (int i = MainRange; i <= MainSecondary; i++) {
|
||||
//pick a timer
|
||||
@@ -4935,13 +4976,6 @@ void NPC::SetAttackTimer()
|
||||
}
|
||||
}
|
||||
|
||||
int16 DelayMod = std::max(itembonuses.HundredHands + spellbonuses.HundredHands, -99);
|
||||
|
||||
// Technically NPCs should do some logic for weapons, but the effect is minimal
|
||||
// What they do is take the lower of their set delay and the weapon's
|
||||
// ex. Mob's delay set to 20, weapon set to 19, delay 19
|
||||
// Mob's delay set to 20, weapon set to 21, delay 20
|
||||
int speed = static_cast<int>((attack_delay * (100 + DelayMod) / 100) * PermaHaste);
|
||||
TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true);
|
||||
}
|
||||
}
|
||||
|
||||
+17
-4
@@ -104,6 +104,8 @@ void Client::CalcBonuses()
|
||||
CalcMaxMana();
|
||||
CalcMaxEndurance();
|
||||
|
||||
SetAttackTimer();
|
||||
|
||||
rooted = FindType(SE_Root);
|
||||
|
||||
XPRate = 100 + spellbonuses.XPRateMod;
|
||||
@@ -174,8 +176,6 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
||||
|
||||
if(newbon->EnduranceRegen > CalcEnduranceRegenCap())
|
||||
newbon->EnduranceRegen = CalcEnduranceRegenCap();
|
||||
|
||||
SetAttackTimer();
|
||||
}
|
||||
|
||||
void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug, bool isTribute) {
|
||||
@@ -1546,6 +1546,11 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_AttackSpeed4:
|
||||
{
|
||||
// These don't generate the IMMUNE_ATKSPEED message and the icon shows up
|
||||
// but have no effect on the mobs attack speed
|
||||
if (GetSpecialAbility(UNSLOWABLE))
|
||||
break;
|
||||
|
||||
if (effect_value < 0) //A few spells use negative values(Descriptions all indicate it should be a slow)
|
||||
effect_value = effect_value * -1;
|
||||
|
||||
@@ -2467,7 +2472,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case SE_ManaAbsorbPercentDamage:
|
||||
{
|
||||
if (newbon->ManaAbsorbPercentDamage[0] < effect_value){
|
||||
@@ -2488,7 +2493,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
case SE_ShieldBlock:
|
||||
newbon->ShieldBlock += effect_value;
|
||||
break;
|
||||
|
||||
|
||||
case SE_ShieldEquipHateMod:
|
||||
newbon->ShieldEquipHateMod += effect_value;
|
||||
break;
|
||||
@@ -2502,6 +2507,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
newbon->BlockBehind += effect_value;
|
||||
break;
|
||||
|
||||
case SE_Blind:
|
||||
newbon->IsBlind = true;
|
||||
break;
|
||||
|
||||
case SE_Fear:
|
||||
newbon->IsFeared = true;
|
||||
break;
|
||||
@@ -4081,6 +4090,10 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
itembonuses.BlockBehind = effect_value;
|
||||
break;
|
||||
|
||||
case SE_Blind:
|
||||
spellbonuses.IsBlind = false;
|
||||
break;
|
||||
|
||||
case SE_Fear:
|
||||
spellbonuses.IsFeared = false;
|
||||
break;
|
||||
|
||||
+891
-1300
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -311,11 +311,11 @@ public:
|
||||
virtual float GetAOERange(uint16 spell_id);
|
||||
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100);
|
||||
virtual void DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster = 0);
|
||||
virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr);
|
||||
virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr);
|
||||
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar);
|
||||
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
|
||||
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center, CastAction_type &CastAction);
|
||||
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF);
|
||||
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF);
|
||||
|
||||
// Bot Action Command Methods
|
||||
bool MesmerizeTarget(Mob* target);
|
||||
|
||||
+313
-417
File diff suppressed because it is too large
Load Diff
+20
-13
@@ -37,6 +37,7 @@ class Client;
|
||||
#include "../common/item_struct.h"
|
||||
#include "../common/clientversions.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "zonedb.h"
|
||||
#include "errno.h"
|
||||
#include "mob.h"
|
||||
@@ -102,11 +103,6 @@ enum { //scribing argument to MemorizeSpell
|
||||
memSpellSpellbar = 3
|
||||
};
|
||||
|
||||
#define USE_ITEM_SPELL_SLOT 10
|
||||
#define POTION_BELT_SPELL_SLOT 11
|
||||
#define DISCIPLINE_SPELL_SLOT 10
|
||||
#define ABILITY_SPELL_SLOT 9
|
||||
|
||||
//Modes for the zoning state of the client.
|
||||
typedef enum {
|
||||
ZoneToSafeCoords, // Always send ZonePlayerToBind_Struct to client: Succor/Evac
|
||||
@@ -240,8 +236,6 @@ public:
|
||||
bool KeyRingCheck(uint32 item_id);
|
||||
void KeyRingList();
|
||||
virtual bool IsClient() const { return true; }
|
||||
virtual void DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw);
|
||||
bool FinishConnState2(DBAsyncWork* dbaw);
|
||||
void CompleteConnect();
|
||||
bool TryStacking(ItemInst* item, uint8 type = ItemPacketTrade, bool try_worn = true, bool try_cursor = true);
|
||||
void SendTraderPacket(Client* trader, uint32 Unknown72 = 51);
|
||||
@@ -260,6 +254,8 @@ public:
|
||||
const char *message5 = nullptr, const char *message6 = nullptr,
|
||||
const char *message7 = nullptr, const char *message8 = nullptr,
|
||||
const char *message9 = nullptr);
|
||||
void Tell_StringID(uint32 string_id, const char *who, const char *message);
|
||||
void SendColoredText(uint32 color, std::string message);
|
||||
void SendBazaarResults(uint32 trader_id,uint32 class_,uint32 race,uint32 stat,uint32 slot,uint32 type,char name[64],uint32 minprice,uint32 maxprice);
|
||||
void SendTraderItem(uint32 item_id,uint16 quantity);
|
||||
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
|
||||
@@ -315,6 +311,10 @@ public:
|
||||
bool Save(uint8 iCommitNow); // 0 = delayed, 1=async now, 2=sync now
|
||||
void SaveBackup();
|
||||
|
||||
/* New PP Save Functions */
|
||||
bool SaveCurrency(){ return database.SaveCharacterCurrency(this->CharacterID(), &m_pp); }
|
||||
bool SaveAA();
|
||||
|
||||
inline bool ClientDataLoaded() const { return client_data_loaded; }
|
||||
inline bool Connected() const { return (client_state == CLIENT_CONNECTED); }
|
||||
inline bool InZone() const { return (client_state == CLIENT_CONNECTED || client_state == CLIENT_LINKDEAD); }
|
||||
@@ -559,6 +559,9 @@ public:
|
||||
void SendLeadershipEXPUpdate();
|
||||
bool IsLeadershipEXPOn();
|
||||
inline int GetLeadershipAA(int AAID) { return m_pp.leader_abilities.ranks[AAID]; }
|
||||
inline LeadershipAA_Struct &GetLeadershipAA() { return m_pp.leader_abilities; }
|
||||
inline GroupLeadershipAA_Struct &GetGroupLeadershipAA() { return m_pp.leader_abilities.group; }
|
||||
inline RaidLeadershipAA_Struct &GetRaidLeadershipAA() { return m_pp.leader_abilities.raid; }
|
||||
int GroupLeadershipAAHealthEnhancement();
|
||||
int GroupLeadershipAAManaEnhancement();
|
||||
int GroupLeadershipAAHealthRegeneration();
|
||||
@@ -585,6 +588,7 @@ public:
|
||||
bool CheckLoreConflict(const Item_Struct* item);
|
||||
void ChangeLastName(const char* in_lastname);
|
||||
void GetGroupAAs(GroupLeadershipAA_Struct *into) const;
|
||||
void GetRaidAAs(RaidLeadershipAA_Struct *into) const;
|
||||
void ClearGroupAAs();
|
||||
void UpdateGroupAAs(int32 points, uint32 type);
|
||||
void SacrificeConfirm(Client* caster);
|
||||
@@ -657,12 +661,12 @@ public:
|
||||
|
||||
void OnDisconnect(bool hard_disconnect);
|
||||
|
||||
uint16 GetSkillPoints() {return m_pp.points;}
|
||||
void SetSkillPoints(int inp) {m_pp.points = inp;}
|
||||
uint16 GetSkillPoints() { return m_pp.points;}
|
||||
void SetSkillPoints(int inp) { m_pp.points = inp;}
|
||||
|
||||
void IncreaseSkill(int skill_id, int value = 1) { if (skill_id <= HIGHEST_SKILL) { m_pp.skills[skill_id] += value; } }
|
||||
void IncreaseLanguageSkill(int skill_id, int value = 1);
|
||||
virtual uint16 GetSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return((itembonuses.skillmod[skill_id] > 0)? m_pp.skills[skill_id]*(100 + itembonuses.skillmod[skill_id])/100 : m_pp.skills[skill_id]); } return 0; }
|
||||
virtual uint16 GetSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return((itembonuses.skillmod[skill_id] > 0) ? m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100 : m_pp.skills[skill_id]); } return 0; }
|
||||
uint32 GetRawSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return(m_pp.skills[skill_id]); } return 0; }
|
||||
bool HasSkill(SkillUseTypes skill_id) const;
|
||||
bool CanHaveSkill(SkillUseTypes skill_id) const;
|
||||
@@ -681,7 +685,7 @@ public:
|
||||
inline uint16 MaxSkill(SkillUseTypes skillid) const { return MaxSkill(skillid, GetClass(), GetLevel()); }
|
||||
uint8 SkillTrainLevel(SkillUseTypes skillid, uint16 class_);
|
||||
|
||||
void TradeskillSearchResults(const char *query, unsigned long qlen, unsigned long objtype, unsigned long someid);
|
||||
void TradeskillSearchResults(const std::string query, unsigned long objtype, unsigned long someid);
|
||||
void SendTradeskillDetails(uint32 recipe_id);
|
||||
bool TradeskillExecute(DBTradeskillRecipe_Struct *spec);
|
||||
void CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float skillup_modifier, uint16 success_modifier, SkillUseTypes tradeskill);
|
||||
@@ -785,6 +789,7 @@ public:
|
||||
int16 acmod();
|
||||
|
||||
// Item methods
|
||||
void EVENT_ITEM_ScriptStopReturn();
|
||||
uint32 NukeItem(uint32 itemnum, uint8 where_to_check =
|
||||
(invWhereWorn | invWherePersonal | invWhereBank | invWhereSharedBank | invWhereTrading | invWhereCursor));
|
||||
void SetTint(int16 slot_id, uint32 color);
|
||||
@@ -895,7 +900,8 @@ public:
|
||||
|
||||
//This is used to later set the buff duration of the spell, in slot to duration.
|
||||
//Doesn't appear to work directly after the client recieves an action packet.
|
||||
void SendBuffDurationPacket(uint16 spell_id, int duration, int inlevel);
|
||||
void SendBuffDurationPacket(Buffs_Struct &buff);
|
||||
void SendBuffNumHitPacket(Buffs_Struct &buff, int slot);
|
||||
|
||||
void ProcessInspectRequest(Client* requestee, Client* requester);
|
||||
bool ClientFinishedLoading() { return (conn_state == ClientConnectFinished); }
|
||||
@@ -1154,6 +1160,7 @@ public:
|
||||
const char* GetClassPlural(Client* client);
|
||||
void SendWebLink(const char* website);
|
||||
void SendMarqueeMessage(uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, std::string msg);
|
||||
void SendSpellAnim(uint16 targetid, uint16 spell_id);
|
||||
|
||||
void DuplicateLoreMessage(uint32 ItemID);
|
||||
void GarbleMessage(char *, uint8);
|
||||
@@ -1449,7 +1456,7 @@ private:
|
||||
unsigned int RestRegenHP;
|
||||
unsigned int RestRegenMana;
|
||||
unsigned int RestRegenEndurance;
|
||||
|
||||
|
||||
bool EngagedRaidTarget;
|
||||
uint32 SavedRaidRestTimer;
|
||||
|
||||
|
||||
@@ -33,14 +33,12 @@ void ClientLogs::subscribe(EQEMuLog::LogIDs id, Client *c) {
|
||||
if(c == nullptr)
|
||||
return;
|
||||
|
||||
//make sure they arnt allready subscribed.
|
||||
|
||||
std::vector<Client *>::iterator cur,end;
|
||||
cur = entries[id].begin();
|
||||
end = entries[id].end();
|
||||
for(; cur != end; ++cur) {
|
||||
if(*cur == c) {
|
||||
printf("%s was allready subscribed to %d\n", c->GetName(), id);
|
||||
printf("%s was already subscribed to %d\n", c->GetName(), id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -100,6 +98,7 @@ void ClientLogs::msg(EQEMuLog::LogIDs id, const char *buf) {
|
||||
for(; cur != end; ++cur) {
|
||||
if(!(*cur)->InZone())
|
||||
continue;
|
||||
|
||||
(*cur)->Message(CLIENT_LOG_CHANNEL, buf);
|
||||
}
|
||||
}
|
||||
|
||||
+40
-15
@@ -1341,12 +1341,45 @@ int16 Client::CalcCHA() {
|
||||
return(CHA);
|
||||
}
|
||||
|
||||
int Client::CalcHaste() {
|
||||
int h = spellbonuses.haste + spellbonuses.hastetype2;
|
||||
int Client::CalcHaste()
|
||||
{
|
||||
/* Tests: (based on results in newer char window)
|
||||
* 68 v1 + 46 item + 25 over + 35 inhib = 204%
|
||||
* 46 item + 5 v2 + 25 over + 35 inhib = 65%
|
||||
* 68 v1 + 46 item + 5 v2 + 25 over + 35 inhib = 209%
|
||||
* 75% slow + 35 inhib = 25%
|
||||
* 35 inhib = 65%
|
||||
* 75% slow = 25%
|
||||
* Conclusions:
|
||||
* the bigger effect in slow v. inhib wins
|
||||
* slow negates all other hastes
|
||||
* inhib will only negate all other hastes if you don't have v1 (ex. VQ)
|
||||
*/
|
||||
// slow beats all! Besides a better inhibit
|
||||
if (spellbonuses.haste < 0) {
|
||||
if (-spellbonuses.haste <= spellbonuses.inhibitmelee)
|
||||
Haste = 100 - spellbonuses.inhibitmelee;
|
||||
else
|
||||
Haste = 100 + spellbonuses.haste;
|
||||
return Haste;
|
||||
}
|
||||
|
||||
// No haste and inhibit, kills all other hastes
|
||||
if (spellbonuses.haste == 0 && spellbonuses.inhibitmelee) {
|
||||
Haste = 100 - spellbonuses.inhibitmelee;
|
||||
return Haste;
|
||||
}
|
||||
|
||||
int h = 0;
|
||||
int cap = 0;
|
||||
int overhaste = 0;
|
||||
int level = GetLevel();
|
||||
|
||||
// we know we have a haste spell and not slowed, no extra inhibit melee checks needed
|
||||
if (spellbonuses.haste)
|
||||
h += spellbonuses.haste - spellbonuses.inhibitmelee;
|
||||
if (spellbonuses.hastetype2 && level > 49) // type 2 is capped at 10% and only available to 50+
|
||||
h += spellbonuses.hastetype2 > 10 ? 10 : spellbonuses.hastetype2;
|
||||
|
||||
// 26+ no cap, 1-25 10
|
||||
if (level > 25) // 26+
|
||||
h += itembonuses.haste;
|
||||
@@ -1368,24 +1401,16 @@ int Client::CalcHaste() {
|
||||
|
||||
// 51+ 25 (despite there being higher spells...), 1-50 10
|
||||
if (level > 50) // 51+
|
||||
overhaste = spellbonuses.hastetype3 > 25 ? 25 : spellbonuses.hastetype3;
|
||||
h += spellbonuses.hastetype3 > 25 ? 25 : spellbonuses.hastetype3;
|
||||
else // 1-50
|
||||
overhaste = spellbonuses.hastetype3 > 10 ? 10 : spellbonuses.hastetype3;
|
||||
h += spellbonuses.hastetype3 > 10 ? 10 : spellbonuses.hastetype3;
|
||||
|
||||
h += overhaste;
|
||||
h += ExtraHaste; //GM granted haste.
|
||||
|
||||
h = mod_client_haste(h);
|
||||
|
||||
if (spellbonuses.inhibitmelee) {
|
||||
if (h >= 0)
|
||||
h -= spellbonuses.inhibitmelee;
|
||||
else
|
||||
h -= ((100 + h) * spellbonuses.inhibitmelee / 100);
|
||||
}
|
||||
|
||||
Haste = h;
|
||||
return(Haste);
|
||||
Haste = 100 + h;
|
||||
return Haste;
|
||||
}
|
||||
|
||||
//The AA multipliers are set to be 5, but were 2 on WR
|
||||
|
||||
+12173
-12049
File diff suppressed because it is too large
Load Diff
+281
-278
@@ -1,292 +1,295 @@
|
||||
void Handle_Connect_OP_SetDataRate(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SetServerFilter(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SendAATable(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SendTributes(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SendGuildTributes(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SendAAStats(const EQApplicationPacket *app);
|
||||
// connecting opcode handlers
|
||||
void Handle_Connect_0x3e33(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ApproveZone(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ClientError(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ClientReady(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ClientUpdate(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ReqClientSpawn(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ReqNewZone(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SendAAStats(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SendAATable(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SendExpZonein(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SendGuildTributes(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SendTributes(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SetDataRate(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SetServerFilter(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SpawnAppearance(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_TGB(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_UpdateAA(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_WearChange(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_WorldObjectsSent(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ZoneComplete(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ReqNewZone(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_SpawnAppearance(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_WearChange(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ClientUpdate(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ClientError(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ApproveZone(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ClientReady(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_UpdateAA(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_TGB(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClientUpdate(const EQApplicationPacket *app);
|
||||
void Handle_OP_AutoAttack(const EQApplicationPacket *app);
|
||||
void Handle_OP_AutoAttack2(const EQApplicationPacket *app);
|
||||
void Handle_OP_Consent(const EQApplicationPacket *app);
|
||||
void Handle_OP_ConsentDeny(const EQApplicationPacket *app);
|
||||
void Handle_OP_TargetMouse(const EQApplicationPacket *app);
|
||||
void Handle_OP_TargetCommand(const EQApplicationPacket *app);
|
||||
void Handle_OP_Shielding(const EQApplicationPacket *app);
|
||||
void Handle_OP_Jump(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNButton(const EQApplicationPacket *app);
|
||||
void Handle_OP_LeaveAdventure(const EQApplicationPacket *app);
|
||||
void Handle_OP_Consume(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureMerchantRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureMerchantPurchase(const EQApplicationPacket *app);
|
||||
void Handle_OP_ConsiderCorpse(const EQApplicationPacket *app);
|
||||
void Handle_OP_Consider(const EQApplicationPacket *app);
|
||||
void Handle_OP_Begging(const EQApplicationPacket *app);
|
||||
void Handle_OP_TestBuff(const EQApplicationPacket *app);
|
||||
void Handle_OP_Surname(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClearSurname(const EQApplicationPacket *app);
|
||||
void Handle_OP_YellForHelp(const EQApplicationPacket *app);
|
||||
void Handle_OP_Assist(const EQApplicationPacket *app);
|
||||
void Handle_OP_AssistGroup(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMTraining(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMEndTraining(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMTrainSkill(const EQApplicationPacket *app);
|
||||
void Handle_OP_DuelResponse(const EQApplicationPacket *app);
|
||||
void Handle_OP_DuelResponse2(const EQApplicationPacket *app);
|
||||
void Handle_OP_RequestDuel(const EQApplicationPacket *app);
|
||||
void Handle_OP_SpawnAppearance(const EQApplicationPacket *app);
|
||||
void Handle_OP_BazaarInspect(const EQApplicationPacket *app);
|
||||
void Handle_OP_Death(const EQApplicationPacket *app);
|
||||
void Handle_OP_MoveCoin(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemLinkClick(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemLinkResponse(const EQApplicationPacket *app);
|
||||
void Handle_OP_MoveItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_Camp(const EQApplicationPacket *app);
|
||||
void Handle_OP_Logout(const EQApplicationPacket *app);
|
||||
void Handle_OP_SenseHeading(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNOpen(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNDisarmTraps(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNSenseTraps(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNInspect(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNPickLock(const EQApplicationPacket *app);
|
||||
void Handle_OP_FeignDeath(const EQApplicationPacket *app);
|
||||
void Handle_OP_Sneak(const EQApplicationPacket *app);
|
||||
void Handle_OP_Hide(const EQApplicationPacket *app);
|
||||
void Handle_OP_ChannelMessage(const EQApplicationPacket *app);
|
||||
void Handle_OP_WearChange(const EQApplicationPacket *app);
|
||||
void Handle_OP_ZoneChange(const EQApplicationPacket *app);
|
||||
void Handle_OP_DeleteSpawn(const EQApplicationPacket *app);
|
||||
void Handle_OP_SaveOnZoneReq(const EQApplicationPacket *app);
|
||||
void Handle_OP_Save(const EQApplicationPacket *app);
|
||||
void Handle_OP_WhoAllRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMZoneRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMZoneRequest2(const EQApplicationPacket *app);
|
||||
void Handle_OP_EndLootRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_LootRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_Dye(const EQApplicationPacket *app);
|
||||
void Handle_OP_LootItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildDelete(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildPublicNote(const EQApplicationPacket *app);
|
||||
void Handle_OP_GetGuildsList(const EQApplicationPacket *app);
|
||||
void Handle_OP_SetGuildMOTD(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildPeace(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildWar(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildLeader(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildDemote(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildPromote(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildInvite(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildRemove(const EQApplicationPacket *app);
|
||||
void Handle_OP_GetGuildMOTD(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildManageBanker(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildInviteAccept(const EQApplicationPacket *app);
|
||||
void Handle_OP_ManaChange(const EQApplicationPacket *app);
|
||||
void Handle_OP_MemorizeSpell(const EQApplicationPacket *app);
|
||||
void Handle_OP_SwapSpell(const EQApplicationPacket *app);
|
||||
void Handle_OP_CastSpell(const EQApplicationPacket *app);
|
||||
void Handle_OP_DeleteItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_CombatAbility(const EQApplicationPacket *app);
|
||||
void Handle_OP_Taunt(const EQApplicationPacket *app);
|
||||
void Handle_OP_InstillDoubt(const EQApplicationPacket *app);
|
||||
void Handle_OP_RezzAnswer(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMSummon(const EQApplicationPacket *app);
|
||||
void Handle_OP_TradeRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_TradeRequestAck(const EQApplicationPacket *app);
|
||||
void Handle_OP_CancelTrade(const EQApplicationPacket *app);
|
||||
void Handle_OP_TradeAcceptClick(const EQApplicationPacket *app);
|
||||
void Handle_OP_BoardBoat(const EQApplicationPacket *app);
|
||||
void Handle_OP_LeaveBoat(const EQApplicationPacket *app);
|
||||
void Handle_OP_RandomReq(const EQApplicationPacket *app);
|
||||
void Handle_OP_Buff(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMHideMe(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMNameChange(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMKill(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMLastName(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMToggle(const EQApplicationPacket *app);
|
||||
void Handle_OP_LFGCommand(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMGoto(const EQApplicationPacket *app);
|
||||
void Handle_OP_TraderShop(const EQApplicationPacket *app);
|
||||
void Handle_OP_ShopRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_BazaarSearch(const EQApplicationPacket *app);
|
||||
void Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app);
|
||||
void Handle_OP_ShopPlayerSell(const EQApplicationPacket *app);
|
||||
void Handle_OP_ShopEnd(const EQApplicationPacket *app);
|
||||
// void Handle_OP_CloseContainer(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClickObjectAction(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClickObject(const EQApplicationPacket *app);
|
||||
void Handle_OP_RecipesFavorite(const EQApplicationPacket *app);
|
||||
void Handle_OP_RecipesSearch(const EQApplicationPacket *app);
|
||||
void Handle_OP_RecipeDetails(const EQApplicationPacket *app);
|
||||
void Handle_OP_RecipeAutoCombine(const EQApplicationPacket *app);
|
||||
void Handle_OP_TradeSkillCombine(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemName(const EQApplicationPacket *app);
|
||||
void Handle_OP_AugmentItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClickDoor(const EQApplicationPacket *app);
|
||||
void Handle_OP_CreateObject(const EQApplicationPacket *app);
|
||||
void Handle_OP_FaceChange(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupInvite(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupInvite2(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupAcknowledge(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupCancelInvite(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupFollow(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupFollow2(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupDisband(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupDelete(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMEmoteZone(const EQApplicationPacket *app);
|
||||
void Handle_OP_InspectRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_InspectAnswer(const EQApplicationPacket *app);
|
||||
void Handle_OP_InspectMessageUpdate(const EQApplicationPacket *app);
|
||||
void Handle_OP_Medding(const EQApplicationPacket *app);
|
||||
void Handle_OP_DeleteSpell(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionBug(const EQApplicationPacket *app);
|
||||
void Handle_OP_Bug(const EQApplicationPacket *app);
|
||||
void Handle_OP_Petition(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionCheckIn(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionResolve(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionDelete(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetCommands(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionUnCheckout(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionQue(const EQApplicationPacket *app);
|
||||
void Handle_OP_PDeletePetition(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionCheckout(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionRefresh(const EQApplicationPacket *app);
|
||||
void Handle_OP_ReadBook(const EQApplicationPacket *app);
|
||||
void Handle_OP_Emote(const EQApplicationPacket *app);
|
||||
void Handle_OP_Animation(const EQApplicationPacket *app);
|
||||
void Handle_OP_SetServerFilter(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMDelCorpse(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMKick(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMServers(const EQApplicationPacket *app);
|
||||
void Handle_OP_Illusion(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMBecomeNPC(const EQApplicationPacket *app);
|
||||
void Handle_OP_Fishing(const EQApplicationPacket *app);
|
||||
void Handle_OP_Forage(const EQApplicationPacket *app);
|
||||
void Handle_OP_Mend(const EQApplicationPacket *app);
|
||||
void Handle_OP_EnvDamage(const EQApplicationPacket *app);
|
||||
void Handle_OP_Damage(const EQApplicationPacket *app);
|
||||
void Handle_OP_AAAction(const EQApplicationPacket *app);
|
||||
void Handle_OP_TraderBuy(const EQApplicationPacket *app);
|
||||
void Handle_OP_Trader(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMFind(const EQApplicationPacket *app);
|
||||
void Handle_OP_PickPocket(const EQApplicationPacket *app);
|
||||
void Handle_OP_Bind_Wound(const EQApplicationPacket *app);
|
||||
void Handle_OP_TrackTarget(const EQApplicationPacket *app);
|
||||
void Handle_OP_Track(const EQApplicationPacket *app);
|
||||
void Handle_OP_TrackUnknown(const EQApplicationPacket *app);
|
||||
void Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app);
|
||||
// connected opcode handlers
|
||||
void Handle_0x0193(const EQApplicationPacket *app);
|
||||
void Handle_0x01e7(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClientError(const EQApplicationPacket *app);
|
||||
void Handle_OP_ReloadUI(const EQApplicationPacket *app);
|
||||
void Handle_OP_TGB(const EQApplicationPacket *app);
|
||||
void Handle_OP_Split(const EQApplicationPacket *app);
|
||||
void Handle_OP_SenseTraps(const EQApplicationPacket *app);
|
||||
void Handle_OP_DisarmTraps(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenTributeMaster(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenGuildTributeMaster(const EQApplicationPacket *app);
|
||||
void Handle_OP_TributeItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_TributeMoney(const EQApplicationPacket *app);
|
||||
void Handle_OP_SelectTribute(const EQApplicationPacket *app);
|
||||
void Handle_OP_TributeUpdate(const EQApplicationPacket *app);
|
||||
void Handle_OP_TributeToggle(const EQApplicationPacket *app);
|
||||
void Handle_OP_TributeNPC(const EQApplicationPacket *app);
|
||||
void Handle_OP_ConfirmDelete(const EQApplicationPacket *app);
|
||||
void Handle_OP_CrashDump(const EQApplicationPacket *app);
|
||||
void Handle_OP_ControlBoat(const EQApplicationPacket *app);
|
||||
void Handle_OP_DumpName(const EQApplicationPacket *app);
|
||||
void Handle_OP_SetRunMode(const EQApplicationPacket *app);
|
||||
void Handle_OP_SafeFallSuccess(const EQApplicationPacket *app);
|
||||
void Handle_OP_Heartbeat(const EQApplicationPacket *app);
|
||||
void Handle_OP_SafePoint(const EQApplicationPacket *app);
|
||||
void Handle_OP_FindPersonRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_BankerChange(const EQApplicationPacket *app);
|
||||
void Handle_OP_LeadershipExpToggle(const EQApplicationPacket *app);
|
||||
void Handle_OP_SetTitle(const EQApplicationPacket *app);
|
||||
void Handle_OP_RequestTitles(const EQApplicationPacket *app);
|
||||
void Handle_OP_PurchaseLeadershipAA(const EQApplicationPacket *app);
|
||||
void Handle_OP_Ignore(const EQApplicationPacket *app);
|
||||
void Handle_OP_LoadSpellSet(const EQApplicationPacket *app);
|
||||
void Handle_OP_AutoFire(const EQApplicationPacket *app);
|
||||
void Handle_OP_Rewind(const EQApplicationPacket *app);
|
||||
void Handle_OP_RaidCommand(const EQApplicationPacket *app);
|
||||
void Handle_OP_Translocate(const EQApplicationPacket *app);
|
||||
void Handle_OP_Sacrifice(const EQApplicationPacket *app);
|
||||
void Handle_OP_AAAction(const EQApplicationPacket *app);
|
||||
void Handle_OP_AcceptNewTask(const EQApplicationPacket *app);
|
||||
void Handle_OP_CancelTask(const EQApplicationPacket *app);
|
||||
void Handle_OP_TaskHistoryRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_KeyRing(const EQApplicationPacket *app);
|
||||
void Handle_OP_FriendsWho(const EQApplicationPacket *app);
|
||||
void Handle_OP_Bandolier(const EQApplicationPacket *app);
|
||||
void Handle_OP_PopupResponse(const EQApplicationPacket *app);
|
||||
void Handle_OP_PotionBelt(const EQApplicationPacket *app);
|
||||
void Handle_OP_LFGGetMatchesRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_LFPCommand(const EQApplicationPacket *app);
|
||||
void Handle_OP_LFPGetMatchesRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_Barter(const EQApplicationPacket *app);
|
||||
void Handle_OP_VoiceMacroIn(const EQApplicationPacket *app);
|
||||
void Handle_OP_DoGroupLeadershipAbility(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClearNPCMarks(const EQApplicationPacket *app);
|
||||
void Handle_OP_DelegateAbility(const EQApplicationPacket *app);
|
||||
void Handle_OP_ApplyPoison(const EQApplicationPacket *app);
|
||||
void Handle_OP_AugmentInfo(const EQApplicationPacket *app);
|
||||
void Handle_OP_PVPLeaderBoardRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_PVPLeaderBoardDetailsRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureMerchantSell(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureStatsRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureInfoRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureLeaderboardRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_RespawnWindow(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupUpdate(const EQApplicationPacket *app);
|
||||
void Handle_OP_SetStartCity(const EQApplicationPacket *app);
|
||||
void Handle_OP_Report(const EQApplicationPacket *app);
|
||||
void Handle_OP_VetClaimRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMSearchCorpse(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildBank(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupRoles(const EQApplicationPacket *app);
|
||||
void Handle_OP_HideCorpse(const EQApplicationPacket *app);
|
||||
void Handle_OP_TradeBusy(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildUpdateURLAndChannel(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildStatus(const EQApplicationPacket *app);
|
||||
void Handle_OP_BlockedBuffs(const EQApplicationPacket *app);
|
||||
void Handle_OP_RemoveBlockedBuffs(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClearBlockedBuffs(const EQApplicationPacket *app);
|
||||
void Handle_OP_BuffRemoveRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_CorpseDrag(const EQApplicationPacket *app);
|
||||
void Handle_OP_CorpseDrop(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupMakeLeader(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildCreate(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureMerchantPurchase(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureMerchantRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureMerchantSell(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AdventureStatsRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AltCurrencyMerchantRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_AltCurrencySellSelection(const EQApplicationPacket *app);
|
||||
void Handle_OP_AltCurrencyPurchase(const EQApplicationPacket *app);
|
||||
void Handle_OP_AltCurrencyReclaim(const EQApplicationPacket *app);
|
||||
void Handle_OP_AltCurrencySell(const EQApplicationPacket *app);
|
||||
void Handle_OP_CrystalReclaim(const EQApplicationPacket *app);
|
||||
void Handle_OP_CrystalCreate(const EQApplicationPacket *app);
|
||||
void Handle_OP_LFGuild(const EQApplicationPacket *app);
|
||||
void Handle_OP_XTargetRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_XTargetAutoAddHaters(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemPreview(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenaryDataRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenaryHire(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenaryCommand(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenaryDataUpdateRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenarySuspendRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenaryDismiss(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenaryTimerRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenInventory(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenContainer(const EQApplicationPacket *app);
|
||||
void Handle_OP_AltCurrencySellSelection(const EQApplicationPacket *app);
|
||||
void Handle_OP_Animation(const EQApplicationPacket *app);
|
||||
void Handle_OP_ApplyPoison(const EQApplicationPacket *app);
|
||||
void Handle_OP_Assist(const EQApplicationPacket *app);
|
||||
void Handle_OP_AssistGroup(const EQApplicationPacket *app);
|
||||
void Handle_OP_AugmentInfo(const EQApplicationPacket *app);
|
||||
void Handle_OP_AugmentItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_AutoAttack(const EQApplicationPacket *app);
|
||||
void Handle_OP_AutoAttack2(const EQApplicationPacket *app);
|
||||
void Handle_OP_AutoFire(const EQApplicationPacket *app);
|
||||
void Handle_OP_Bandolier(const EQApplicationPacket *app);
|
||||
void Handle_OP_BankerChange(const EQApplicationPacket *app);
|
||||
void Handle_OP_Barter(const EQApplicationPacket *app);
|
||||
void Handle_OP_BazaarInspect(const EQApplicationPacket *app);
|
||||
void Handle_OP_BazaarSearch(const EQApplicationPacket *app);
|
||||
void Handle_OP_Begging(const EQApplicationPacket *app);
|
||||
void Handle_OP_Bind_Wound(const EQApplicationPacket *app);
|
||||
void Handle_OP_BlockedBuffs(const EQApplicationPacket *app);
|
||||
void Handle_OP_BoardBoat(const EQApplicationPacket *app);
|
||||
void Handle_OP_Buff(const EQApplicationPacket *app);
|
||||
void Handle_OP_BuffRemoveRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_Bug(const EQApplicationPacket *app);
|
||||
void Handle_OP_Camp(const EQApplicationPacket *app);
|
||||
void Handle_OP_CancelTask(const EQApplicationPacket *app);
|
||||
void Handle_OP_CancelTrade(const EQApplicationPacket *app);
|
||||
void Handle_OP_CastSpell(const EQApplicationPacket *app);
|
||||
void Handle_OP_ChannelMessage(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClearBlockedBuffs(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClearNPCMarks(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClearSurname(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClickDoor(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClickObject(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClickObjectAction(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClientError(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClientTimeStamp(const EQApplicationPacket *app);
|
||||
void Handle_OP_ClientUpdate(const EQApplicationPacket *app);
|
||||
// void Handle_OP_CloseContainer(const EQApplicationPacket *app);
|
||||
void Handle_OP_CombatAbility(const EQApplicationPacket *app);
|
||||
void Handle_OP_ConfirmDelete(const EQApplicationPacket *app);
|
||||
void Handle_OP_Consent(const EQApplicationPacket *app);
|
||||
void Handle_OP_ConsentDeny(const EQApplicationPacket *app);
|
||||
void Handle_OP_Consider(const EQApplicationPacket *app);
|
||||
void Handle_OP_ConsiderCorpse(const EQApplicationPacket *app);
|
||||
void Handle_OP_Consume(const EQApplicationPacket *app);
|
||||
void Handle_OP_ControlBoat(const EQApplicationPacket *app);
|
||||
void Handle_OP_CorpseDrag(const EQApplicationPacket *app);
|
||||
void Handle_OP_CorpseDrop(const EQApplicationPacket *app);
|
||||
void Handle_OP_CrashDump(const EQApplicationPacket *app);
|
||||
void Handle_OP_CreateObject(const EQApplicationPacket *app);
|
||||
void Handle_OP_CrystalCreate(const EQApplicationPacket *app);
|
||||
void Handle_OP_CrystalReclaim(const EQApplicationPacket *app);
|
||||
void Handle_OP_Damage(const EQApplicationPacket *app);
|
||||
void Handle_OP_Death(const EQApplicationPacket *app);
|
||||
void Handle_OP_DelegateAbility(const EQApplicationPacket *app);
|
||||
void Handle_OP_DeleteItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_DeleteSpawn(const EQApplicationPacket *app);
|
||||
void Handle_OP_DeleteSpell(const EQApplicationPacket *app);
|
||||
void Handle_OP_DisarmTraps(const EQApplicationPacket *app);
|
||||
void Handle_OP_DoGroupLeadershipAbility(const EQApplicationPacket *app);
|
||||
void Handle_OP_DuelResponse(const EQApplicationPacket *app);
|
||||
void Handle_OP_DuelResponse2(const EQApplicationPacket *app);
|
||||
void Handle_OP_DumpName(const EQApplicationPacket *app);
|
||||
void Handle_OP_Dye(const EQApplicationPacket *app);
|
||||
void Handle_OP_Emote(const EQApplicationPacket *app);
|
||||
void Handle_OP_EndLootRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_EnvDamage(const EQApplicationPacket *app);
|
||||
void Handle_OP_FaceChange(const EQApplicationPacket *app);
|
||||
void Handle_OP_FeignDeath(const EQApplicationPacket *app);
|
||||
void Handle_OP_FindPersonRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_Fishing(const EQApplicationPacket *app);
|
||||
void Handle_OP_Forage(const EQApplicationPacket *app);
|
||||
void Handle_OP_FriendsWho(const EQApplicationPacket *app);
|
||||
void Handle_OP_GetGuildMOTD(const EQApplicationPacket *app);
|
||||
void Handle_OP_GetGuildsList(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMBecomeNPC(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMDelCorpse(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMEmoteZone(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMEndTraining(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMFind(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMGoto(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMHideMe(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMKick(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMKill(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMLastName(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMNameChange(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMSearchCorpse(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMServers(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMSummon(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMToggle(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMTraining(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMTrainSkill(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMZoneRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_GMZoneRequest2(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupAcknowledge(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupCancelInvite(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupDelete(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupDisband(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupFollow(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupFollow2(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupInvite(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupInvite2(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupMakeLeader(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupMentor(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupRoles(const EQApplicationPacket *app);
|
||||
void Handle_OP_GroupUpdate(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildBank(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildCreate(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildDelete(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildDemote(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildInvite(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildInviteAccept(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildLeader(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildManageBanker(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildPeace(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildPromote(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildPublicNote(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildRemove(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildStatus(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildUpdateURLAndChannel(const EQApplicationPacket *app);
|
||||
void Handle_OP_GuildWar(const EQApplicationPacket *app);
|
||||
void Handle_OP_Heartbeat(const EQApplicationPacket *app);
|
||||
void Handle_OP_Hide(const EQApplicationPacket *app);
|
||||
void Handle_OP_HideCorpse(const EQApplicationPacket *app);
|
||||
void Handle_OP_Ignore(const EQApplicationPacket *app);
|
||||
void Handle_OP_Illusion(const EQApplicationPacket *app);
|
||||
void Handle_OP_InspectAnswer(const EQApplicationPacket *app);
|
||||
void Handle_OP_InspectMessageUpdate(const EQApplicationPacket *app);
|
||||
void Handle_OP_InspectRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_InstillDoubt(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemLinkClick(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemLinkResponse(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemName(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemPreview(const EQApplicationPacket *app);
|
||||
void Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_Jump(const EQApplicationPacket *app);
|
||||
void Handle_OP_KeyRing(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNButton(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNDisarmTraps(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNInspect(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNOpen(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNPickLock(const EQApplicationPacket *app);
|
||||
void Handle_OP_LDoNSenseTraps(const EQApplicationPacket *app);
|
||||
void Handle_OP_LeadershipExpToggle(const EQApplicationPacket *app);
|
||||
void Handle_OP_LeaveAdventure(const EQApplicationPacket *app);
|
||||
void Handle_OP_LeaveBoat(const EQApplicationPacket *app);
|
||||
void Handle_OP_LFGCommand(const EQApplicationPacket *app);
|
||||
void Handle_OP_LFGGetMatchesRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_LFGuild(const EQApplicationPacket *app);
|
||||
void Handle_OP_LFPCommand(const EQApplicationPacket *app);
|
||||
void Handle_OP_LFPGetMatchesRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_LoadSpellSet(const EQApplicationPacket *app);
|
||||
void Handle_OP_Logout(const EQApplicationPacket *app);
|
||||
void Handle_OP_LootItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_LootRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_ManaChange(const EQApplicationPacket *app);
|
||||
void Handle_OP_Medding(const EQApplicationPacket *app);
|
||||
void Handle_OP_MemorizeSpell(const EQApplicationPacket *app);
|
||||
void Handle_OP_Mend(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenaryCommand(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenaryDataRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenaryDataUpdateRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenaryDismiss(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenaryHire(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenarySuspendRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_MercenaryTimerRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_MoveCoin(const EQApplicationPacket *app);
|
||||
void Handle_OP_MoveItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenContainer(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenGuildTributeMaster(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenInventory(const EQApplicationPacket *app);
|
||||
void Handle_OP_OpenTributeMaster(const EQApplicationPacket *app);
|
||||
void Handle_OP_PDeletePetition(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetCommands(const EQApplicationPacket *app);
|
||||
void Handle_OP_Petition(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionBug(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionCheckIn(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionCheckout(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionDelete(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionQue(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionRefresh(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionResolve(const EQApplicationPacket *app);
|
||||
void Handle_OP_PetitionUnCheckout(const EQApplicationPacket *app);
|
||||
void Handle_OP_PickPocket(const EQApplicationPacket *app);
|
||||
void Handle_OP_PopupResponse(const EQApplicationPacket *app);
|
||||
void Handle_OP_PotionBelt(const EQApplicationPacket *app);
|
||||
void Handle_OP_PurchaseLeadershipAA(const EQApplicationPacket *app);
|
||||
void Handle_OP_PVPLeaderBoardDetailsRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_PVPLeaderBoardRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_RaidCommand(const EQApplicationPacket *app);
|
||||
void Handle_OP_RandomReq(const EQApplicationPacket *app);
|
||||
void Handle_OP_ReadBook(const EQApplicationPacket *app);
|
||||
void Handle_OP_RecipeAutoCombine(const EQApplicationPacket *app);
|
||||
void Handle_OP_RecipeDetails(const EQApplicationPacket *app);
|
||||
void Handle_OP_RecipesFavorite(const EQApplicationPacket *app);
|
||||
void Handle_OP_RecipesSearch(const EQApplicationPacket *app);
|
||||
void Handle_OP_ReloadUI(const EQApplicationPacket *app);
|
||||
void Handle_OP_RemoveBlockedBuffs(const EQApplicationPacket *app);
|
||||
void Handle_OP_Report(const EQApplicationPacket *app);
|
||||
void Handle_OP_RequestDuel(const EQApplicationPacket *app);
|
||||
void Handle_OP_RequestTitles(const EQApplicationPacket *app);
|
||||
void Handle_OP_RespawnWindow(const EQApplicationPacket *app);
|
||||
void Handle_OP_Rewind(const EQApplicationPacket *app);
|
||||
void Handle_OP_RezzAnswer(const EQApplicationPacket *app);
|
||||
void Handle_OP_Sacrifice(const EQApplicationPacket *app);
|
||||
void Handle_OP_SafeFallSuccess(const EQApplicationPacket *app);
|
||||
void Handle_OP_SafePoint(const EQApplicationPacket *app);
|
||||
void Handle_OP_Save(const EQApplicationPacket *app);
|
||||
void Handle_OP_SaveOnZoneReq(const EQApplicationPacket *app);
|
||||
void Handle_OP_SelectTribute(const EQApplicationPacket *app);
|
||||
void Handle_OP_SenseHeading(const EQApplicationPacket *app);
|
||||
void Handle_OP_SenseTraps(const EQApplicationPacket *app);
|
||||
void Handle_OP_SetGuildMOTD(const EQApplicationPacket *app);
|
||||
void Handle_OP_SetRunMode(const EQApplicationPacket *app);
|
||||
void Handle_OP_SetServerFilter(const EQApplicationPacket *app);
|
||||
void Handle_OP_SetStartCity(const EQApplicationPacket *app);
|
||||
void Handle_OP_SetTitle(const EQApplicationPacket *app);
|
||||
void Handle_OP_Shielding(const EQApplicationPacket *app);
|
||||
void Handle_OP_ShopEnd(const EQApplicationPacket *app);
|
||||
void Handle_OP_ShopPlayerBuy(const EQApplicationPacket *app);
|
||||
void Handle_OP_ShopPlayerSell(const EQApplicationPacket *app);
|
||||
void Handle_OP_ShopRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_Sneak(const EQApplicationPacket *app);
|
||||
void Handle_OP_SpawnAppearance(const EQApplicationPacket *app);
|
||||
void Handle_OP_Split(const EQApplicationPacket *app);
|
||||
void Handle_OP_Surname(const EQApplicationPacket *app);
|
||||
void Handle_OP_SwapSpell(const EQApplicationPacket *app);
|
||||
void Handle_OP_TargetCommand(const EQApplicationPacket *app);
|
||||
void Handle_OP_TargetMouse(const EQApplicationPacket *app);
|
||||
void Handle_OP_TaskHistoryRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_Taunt(const EQApplicationPacket *app);
|
||||
void Handle_OP_TestBuff(const EQApplicationPacket *app);
|
||||
void Handle_OP_TGB(const EQApplicationPacket *app);
|
||||
void Handle_OP_Track(const EQApplicationPacket *app);
|
||||
void Handle_OP_TrackTarget(const EQApplicationPacket *app);
|
||||
void Handle_OP_TrackUnknown(const EQApplicationPacket *app);
|
||||
void Handle_OP_TradeAcceptClick(const EQApplicationPacket *app);
|
||||
void Handle_OP_TradeBusy(const EQApplicationPacket *app);
|
||||
void Handle_OP_Trader(const EQApplicationPacket *app);
|
||||
void Handle_OP_TraderBuy(const EQApplicationPacket *app);
|
||||
void Handle_OP_TradeRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_TradeRequestAck(const EQApplicationPacket *app);
|
||||
void Handle_OP_TraderShop(const EQApplicationPacket *app);
|
||||
void Handle_OP_TradeSkillCombine(const EQApplicationPacket *app);
|
||||
void Handle_OP_Translocate(const EQApplicationPacket *app);
|
||||
void Handle_OP_TributeItem(const EQApplicationPacket *app);
|
||||
void Handle_OP_TributeMoney(const EQApplicationPacket *app);
|
||||
void Handle_OP_TributeNPC(const EQApplicationPacket *app);
|
||||
void Handle_OP_TributeToggle(const EQApplicationPacket *app);
|
||||
void Handle_OP_TributeUpdate(const EQApplicationPacket *app);
|
||||
void Handle_OP_VetClaimRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_VoiceMacroIn(const EQApplicationPacket *app);
|
||||
void Handle_OP_WearChange(const EQApplicationPacket *app);
|
||||
void Handle_OP_WhoAllRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_XTargetAutoAddHaters(const EQApplicationPacket *app);
|
||||
void Handle_OP_XTargetRequest(const EQApplicationPacket *app);
|
||||
void Handle_OP_YellForHelp(const EQApplicationPacket *app);
|
||||
void Handle_OP_ZoneChange(const EQApplicationPacket *app);
|
||||
|
||||
+56
-47
@@ -967,93 +967,96 @@ void Client::BulkSendInventoryItems()
|
||||
|
||||
void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
||||
const Item_Struct* handyitem = nullptr;
|
||||
uint32 numItemSlots=80; //The max number of items passed in the transaction.
|
||||
uint32 numItemSlots = 80; //The max number of items passed in the transaction.
|
||||
const Item_Struct *item;
|
||||
std::list<MerchantList> merlist = zone->merchanttable[merchant_id];
|
||||
std::list<MerchantList>::const_iterator itr;
|
||||
Mob* merch = entity_list.GetMobByNpcTypeID(npcid);
|
||||
if(merlist.size()==0){ //Attempt to load the data, it might have been missed if someone spawned the merchant after the zone was loaded
|
||||
if (merlist.size() == 0) { //Attempt to load the data, it might have been missed if someone spawned the merchant after the zone was loaded
|
||||
zone->LoadNewMerchantData(merchant_id);
|
||||
merlist = zone->merchanttable[merchant_id];
|
||||
if(merlist.size()==0)
|
||||
if (merlist.size() == 0)
|
||||
return;
|
||||
}
|
||||
std::list<TempMerchantList> tmp_merlist = zone->tmpmerchanttable[npcid];
|
||||
std::list<TempMerchantList>::iterator tmp_itr;
|
||||
|
||||
uint32 i=1;
|
||||
uint32 i = 1;
|
||||
uint8 handychance = 0;
|
||||
for (itr = merlist.begin(); itr != merlist.end() && i < numItemSlots; ++itr) {
|
||||
for (itr = merlist.begin(); itr != merlist.end() && i <= numItemSlots; ++itr) {
|
||||
MerchantList ml = *itr;
|
||||
if (merch->CastToNPC()->GetMerchantProbability() > ml.probability)
|
||||
continue;
|
||||
|
||||
if(GetLevel() < ml.level_required)
|
||||
|
||||
if (GetLevel() < ml.level_required)
|
||||
continue;
|
||||
|
||||
if (!(ml.classes_required & (1 << (GetClass() - 1))))
|
||||
continue;
|
||||
|
||||
int32 fac = merch ? merch->GetPrimaryFaction() : 0;
|
||||
if(fac != 0 && GetModCharacterFactionLevel(fac) < ml.faction_required)
|
||||
if (fac != 0 && GetModCharacterFactionLevel(fac) < ml.faction_required)
|
||||
continue;
|
||||
|
||||
handychance = MakeRandomInt(0, merlist.size() + tmp_merlist.size() - 1 );
|
||||
handychance = MakeRandomInt(0, merlist.size() + tmp_merlist.size() - 1);
|
||||
|
||||
item = database.GetItem(ml.item);
|
||||
if(item) {
|
||||
if(handychance==0)
|
||||
handyitem=item;
|
||||
if (item) {
|
||||
if (handychance == 0)
|
||||
handyitem = item;
|
||||
else
|
||||
handychance--;
|
||||
int charges=1;
|
||||
if(item->ItemClass==ItemClassCommon)
|
||||
charges=item->MaxCharges;
|
||||
int charges = 1;
|
||||
if (item->ItemClass == ItemClassCommon)
|
||||
charges = item->MaxCharges;
|
||||
ItemInst* inst = database.CreateItem(item, charges);
|
||||
if (inst) {
|
||||
if (RuleB(Merchant, UsePriceMod)){
|
||||
inst->SetPrice((item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate*Client::CalcPriceMod(merch,false)));
|
||||
if (RuleB(Merchant, UsePriceMod)) {
|
||||
inst->SetPrice((item->Price * (RuleR(Merchant, SellCostMod)) * item->SellRate * Client::CalcPriceMod(merch, false)));
|
||||
}
|
||||
else
|
||||
inst->SetPrice((item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate));
|
||||
inst->SetPrice((item->Price * (RuleR(Merchant, SellCostMod)) * item->SellRate));
|
||||
inst->SetMerchantSlot(ml.slot);
|
||||
inst->SetMerchantCount(-1); //unlimited
|
||||
if(charges > 0)
|
||||
if (charges > 0)
|
||||
inst->SetCharges(charges);
|
||||
else
|
||||
inst->SetCharges(1);
|
||||
|
||||
SendItemPacket(ml.slot-1, inst, ItemPacketMerchant);
|
||||
SendItemPacket(ml.slot - 1, inst, ItemPacketMerchant);
|
||||
safe_delete(inst);
|
||||
}
|
||||
}
|
||||
// Account for merchant lists with gaps.
|
||||
if(ml.slot >= i)
|
||||
if (ml.slot >= i) {
|
||||
if (ml.slot > i)
|
||||
LogFile->write(EQEMuLog::Debug, "(WARNING) Merchantlist contains gap at slot %d. Merchant: %d, NPC: %d", i, merchant_id, npcid);
|
||||
i = ml.slot + 1;
|
||||
}
|
||||
}
|
||||
std::list<TempMerchantList> origtmp_merlist = zone->tmpmerchanttable[npcid];
|
||||
tmp_merlist.clear();
|
||||
for(tmp_itr = origtmp_merlist.begin();tmp_itr != origtmp_merlist.end() && i<numItemSlots;++tmp_itr){
|
||||
for (tmp_itr = origtmp_merlist.begin(); tmp_itr != origtmp_merlist.end() && i <= numItemSlots; ++tmp_itr) {
|
||||
TempMerchantList ml = *tmp_itr;
|
||||
item=database.GetItem(ml.item);
|
||||
ml.slot=i;
|
||||
item = database.GetItem(ml.item);
|
||||
ml.slot = i;
|
||||
if (item) {
|
||||
if(handychance==0)
|
||||
handyitem=item;
|
||||
if (handychance == 0)
|
||||
handyitem = item;
|
||||
else
|
||||
handychance--;
|
||||
int charges=1;
|
||||
int charges = 1;
|
||||
//if(item->ItemClass==ItemClassCommon && (int16)ml.charges <= item->MaxCharges)
|
||||
// charges=ml.charges;
|
||||
//else
|
||||
charges = item->MaxCharges;
|
||||
ItemInst* inst = database.CreateItem(item, charges);
|
||||
if (inst) {
|
||||
if (RuleB(Merchant, UsePriceMod)){
|
||||
inst->SetPrice((item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate*Client::CalcPriceMod(merch,false)));
|
||||
if (RuleB(Merchant, UsePriceMod)) {
|
||||
inst->SetPrice((item->Price * (RuleR(Merchant, SellCostMod)) * item->SellRate * Client::CalcPriceMod(merch, false)));
|
||||
}
|
||||
else
|
||||
inst->SetPrice((item->Price*(RuleR(Merchant, SellCostMod))*item->SellRate));
|
||||
inst->SetPrice((item->Price * (RuleR(Merchant, SellCostMod)) * item->SellRate));
|
||||
inst->SetMerchantSlot(ml.slot);
|
||||
inst->SetMerchantCount(ml.charges);
|
||||
if(charges > 0)
|
||||
@@ -1069,32 +1072,32 @@ void Client::BulkSendMerchantInventory(int merchant_id, int npcid) {
|
||||
}
|
||||
//this resets the slot
|
||||
zone->tmpmerchanttable[npcid] = tmp_merlist;
|
||||
if(merch != nullptr && handyitem){
|
||||
char handy_id[8]={0};
|
||||
int greeting=MakeRandomInt(0, 4);
|
||||
int greet_id=0;
|
||||
switch(greeting){
|
||||
if (merch != nullptr && handyitem) {
|
||||
char handy_id[8] = { 0 };
|
||||
int greeting = MakeRandomInt(0, 4);
|
||||
int greet_id = 0;
|
||||
switch (greeting) {
|
||||
case 1:
|
||||
greet_id=MERCHANT_GREETING;
|
||||
greet_id = MERCHANT_GREETING;
|
||||
break;
|
||||
case 2:
|
||||
greet_id=MERCHANT_HANDY_ITEM1;
|
||||
greet_id = MERCHANT_HANDY_ITEM1;
|
||||
break;
|
||||
case 3:
|
||||
greet_id=MERCHANT_HANDY_ITEM2;
|
||||
greet_id = MERCHANT_HANDY_ITEM2;
|
||||
break;
|
||||
case 4:
|
||||
greet_id=MERCHANT_HANDY_ITEM3;
|
||||
greet_id = MERCHANT_HANDY_ITEM3;
|
||||
break;
|
||||
default:
|
||||
greet_id=MERCHANT_HANDY_ITEM4;
|
||||
greet_id = MERCHANT_HANDY_ITEM4;
|
||||
}
|
||||
sprintf(handy_id,"%i",greet_id);
|
||||
sprintf(handy_id, "%i", greet_id);
|
||||
|
||||
if(greet_id!=MERCHANT_GREETING)
|
||||
Message_StringID(10,GENERIC_STRINGID_SAY,merch->GetCleanName(),handy_id,this->GetName(),handyitem->Name);
|
||||
if (greet_id != MERCHANT_GREETING)
|
||||
Message_StringID(10, GENERIC_STRINGID_SAY, merch->GetCleanName(), handy_id, this->GetName(), handyitem->Name);
|
||||
else
|
||||
Message_StringID(10,GENERIC_STRINGID_SAY,merch->GetCleanName(),handy_id,this->GetName());
|
||||
Message_StringID(10, GENERIC_STRINGID_SAY, merch->GetCleanName(), handy_id, this->GetName());
|
||||
|
||||
merch->CastToNPC()->FaceTarget(this->CastToMob());
|
||||
}
|
||||
@@ -1547,7 +1550,12 @@ void Client::OPMoveCoin(const EQApplicationPacket* app)
|
||||
if (from_bucket == &m_pp.platinum_shared)
|
||||
amount_to_add = 0 - amount_to_take;
|
||||
|
||||
database.SetSharedPlatinum(AccountID(),amount_to_add);
|
||||
database.SetSharedPlatinum(AccountID(),amount_to_add);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (to_bucket == &m_pp.platinum_shared || from_bucket == &m_pp.platinum_shared){
|
||||
this->Message(13, "::: WARNING! ::: SHARED BANK IS DISABLED AND YOUR PLATINUM WILL BE DESTROYED IF YOU PUT IT HERE");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1580,7 +1588,7 @@ void Client::OPMoveCoin(const EQApplicationPacket* app)
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
Save();
|
||||
SaveCurrency();
|
||||
}
|
||||
|
||||
void Client::OPGMTraining(const EQApplicationPacket *app)
|
||||
@@ -1715,6 +1723,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
uint16 skilllevel = GetRawSkill(skill);
|
||||
|
||||
if(skilllevel == 0) {
|
||||
//this is a new skill..
|
||||
uint16 t_level = SkillTrainLevel(skill, GetClass());
|
||||
@@ -1724,7 +1733,7 @@ void Client::OPGMTrainSkill(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
SetSkill(skill, t_level);
|
||||
} else {
|
||||
} else {
|
||||
switch(skill) {
|
||||
case SkillBrewing:
|
||||
case SkillMakePoison:
|
||||
|
||||
+2542
-3104
File diff suppressed because it is too large
Load Diff
@@ -125,7 +125,6 @@ void command_worldshutdown(Client *c, const Seperator *sep);
|
||||
void command_sendzonespawns(Client *c, const Seperator *sep);
|
||||
void command_zsave(Client *c, const Seperator *sep);
|
||||
void command_dbspawn2(Client *c, const Seperator *sep);
|
||||
void command_copychar(Client *c, const Seperator *sep);
|
||||
void command_shutdown(Client *c, const Seperator *sep);
|
||||
void command_delacct(Client *c, const Seperator *sep);
|
||||
void command_setpass(Client *c, const Seperator *sep);
|
||||
@@ -151,7 +150,6 @@ void command_texture(Client *c, const Seperator *sep);
|
||||
void command_npctypespawn(Client *c, const Seperator *sep);
|
||||
void command_heal(Client *c, const Seperator *sep);
|
||||
void command_appearance(Client *c, const Seperator *sep);
|
||||
void command_charbackup(Client *c, const Seperator *sep);
|
||||
void command_nukeitem(Client *c, const Seperator *sep);
|
||||
void command_peekinv(Client *c, const Seperator *sep);
|
||||
void command_findnpctype(Client *c, const Seperator *sep);
|
||||
@@ -217,7 +215,6 @@ void command_guild(Client *c, const Seperator *sep);
|
||||
bool helper_guild_edit(Client *c, uint32 dbid, uint32 eqid, uint8 rank, const char* what, const char* value);
|
||||
void command_zonestatus(Client *c, const Seperator *sep);
|
||||
void command_manaburn(Client *c, const Seperator *sep);
|
||||
void command_viewmessage(Client *c, const Seperator *sep);
|
||||
void command_doanim(Client *c, const Seperator *sep);
|
||||
void command_randomfeatures(Client *c, const Seperator *sep);
|
||||
void command_face(Client *c, const Seperator *sep);
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
#define _NPCPET(x) (x && x->IsNPC() && x->CastToMob()->GetOwner() && x->CastToMob()->GetOwner()->IsNPC())
|
||||
#define _BECOMENPCPET(x) (x && x->CastToMob()->GetOwner() && x->CastToMob()->GetOwner()->IsClient() && x->CastToMob()->GetOwner()->CastToClient()->IsBecomeNPC())
|
||||
|
||||
#define USE_ITEM_SPELL_SLOT 10
|
||||
#define POTION_BELT_SPELL_SLOT 11
|
||||
#define DISCIPLINE_SPELL_SLOT 10
|
||||
#define ABILITY_SPELL_SLOT 9
|
||||
|
||||
//LOS Parameters:
|
||||
#define HEAD_POSITION 0.9f //ratio of GetSize() where NPCs see from
|
||||
@@ -290,6 +294,7 @@ struct StatBonuses {
|
||||
int16 ResistFearChance; //i
|
||||
bool Fearless; //i
|
||||
bool IsFeared; //i
|
||||
bool IsBlind; //i
|
||||
int16 StunResist; //i
|
||||
int16 MeleeSkillCheck; //i
|
||||
uint8 MeleeSkillCheckSkill;
|
||||
|
||||
+107
-9
@@ -97,6 +97,7 @@ Corpse* Corpse::LoadFromDBData(uint32 in_dbid, uint32 in_charid, char* in_charna
|
||||
for (unsigned int i=0; i < dbpcs->itemcount; i++) {
|
||||
tmp = new ServerLootItem_Struct;
|
||||
memcpy(tmp, &dbpcs->items[i], sizeof(player_lootitem::ServerLootItem_Struct));
|
||||
tmp->equipSlot = CorpseToServerSlot(tmp->equipSlot); // temp hack until corpse blobs are removed
|
||||
itemlist.push_back(tmp);
|
||||
}
|
||||
|
||||
@@ -147,6 +148,7 @@ Corpse* Corpse::LoadFromDBData(uint32 in_dbid, uint32 in_charid, char* in_charna
|
||||
for (unsigned int i=0; i < dbpc->itemcount; i++) {
|
||||
tmp = new ServerLootItem_Struct;
|
||||
memcpy(tmp, &dbpc->items[i], sizeof(player_lootitem::ServerLootItem_Struct));
|
||||
tmp->equipSlot = CorpseToServerSlot(tmp->equipSlot); // temp hack until corpse blobs are removed
|
||||
itemlist.push_back(tmp);
|
||||
}
|
||||
|
||||
@@ -600,6 +602,7 @@ bool Corpse::Save() {
|
||||
end = itemlist.end();
|
||||
for(; cur != end; ++cur) {
|
||||
ServerLootItem_Struct* item = *cur;
|
||||
item->equipSlot = ServerToCorpseSlot(item->equipSlot); // temp hack until corpse blobs are removed
|
||||
memcpy((char*) &dbpc->items[x++], (char*) item, sizeof(player_lootitem::ServerLootItem_Struct));
|
||||
}
|
||||
|
||||
@@ -971,8 +974,7 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
|
||||
}
|
||||
|
||||
RemoveCash();
|
||||
Save();
|
||||
client->Save();
|
||||
Save();
|
||||
}
|
||||
|
||||
outapp->priority = 6;
|
||||
@@ -2064,15 +2066,111 @@ void Corpse::LoadPlayerCorpseDecayTime(uint32 dbid){
|
||||
}
|
||||
|
||||
/*
|
||||
uint32 Corpse::ServerToCorpseSlot(int16 server_slot) {
|
||||
// reserved
|
||||
}
|
||||
** Corpse slot translations are needed until corpse database blobs are converted
|
||||
**
|
||||
** To account for the addition of MainPowerSource, MainGeneral9 and MainGeneral10 into
|
||||
** the contiguous possessions slot enumeration, the following designations will be used:
|
||||
**
|
||||
** Designatiom Server Corpse Offset
|
||||
** --------------------------------------------------
|
||||
** MainCharm 0 0 0
|
||||
** ... ... ... 0
|
||||
** MainWaist 20 20 0
|
||||
** MainPowerSource 21 9999 +9978
|
||||
** MainAmmo 22 21 -1
|
||||
**
|
||||
** MainGeneral1 23 22 -1
|
||||
** ... ... ... -1
|
||||
** MainGeneral8 30 29 -1
|
||||
** MainGeneral9 31 9997 +9966
|
||||
** MainGeneral10 32 9998 +9966
|
||||
**
|
||||
** MainCursor 33 30 -3
|
||||
**
|
||||
** MainGeneral1_1 251 251 0
|
||||
** ... ... ... 0
|
||||
** MainGeneral8_10 330 330 0
|
||||
** MainGeneral9_1 331 341 +10
|
||||
** ... ... ... +10
|
||||
** MainGeneral10_10 350 360 +10
|
||||
**
|
||||
** MainCursor_1 351 331 -20
|
||||
** ... ... ... -20
|
||||
** MainCursor_10 360 340 -20
|
||||
**
|
||||
** (Not all slot designations are valid to all clients..see <client>##_constants.h files for valid slot enumerations)
|
||||
*/
|
||||
/*
|
||||
int16 Corpse::CorpseToServerSlot(uint32 corpse_slot) {
|
||||
// reserved
|
||||
int16 Corpse::ServerToCorpseSlot(int16 server_slot)
|
||||
{
|
||||
return server_slot; // temporary return
|
||||
|
||||
/*
|
||||
switch (server_slot)
|
||||
{
|
||||
case MainPowerSource:
|
||||
return 9999;
|
||||
case MainGeneral9:
|
||||
return 9997;
|
||||
case MainGeneral10:
|
||||
return 9998;
|
||||
case MainCursor:
|
||||
return 30;
|
||||
case MainAmmo:
|
||||
case MainGeneral1:
|
||||
case MainGeneral2:
|
||||
case MainGeneral3:
|
||||
case MainGeneral4:
|
||||
case MainGeneral5:
|
||||
case MainGeneral6:
|
||||
case MainGeneral7:
|
||||
case MainGeneral8:
|
||||
return server_slot - 1;
|
||||
default:
|
||||
if (server_slot >= EmuConstants::CURSOR_BAG_BEGIN && server_slot <= EmuConstants::CURSOR_BAG_END)
|
||||
return server_slot - 20;
|
||||
else if (server_slot >= EmuConstants::GENERAL_BAGS_END - 19 && server_slot <= EmuConstants::GENERAL_BAGS_END)
|
||||
return server_slot + 10;
|
||||
else
|
||||
return server_slot;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
int16 Corpse::CorpseToServerSlot(int16 corpse_slot)
|
||||
{
|
||||
return corpse_slot; // temporary return
|
||||
|
||||
/*
|
||||
switch (corpse_slot)
|
||||
{
|
||||
case 9999:
|
||||
return MainPowerSource;
|
||||
case 9997:
|
||||
return MainGeneral9;
|
||||
case 9998:
|
||||
return MainGeneral10;
|
||||
case 30:
|
||||
return MainCursor;
|
||||
case 21: // old SLOT_AMMO
|
||||
case 22: // old PERSONAL_BEGIN
|
||||
case 23:
|
||||
case 24:
|
||||
case 25:
|
||||
case 26:
|
||||
case 27:
|
||||
case 28:
|
||||
case 29: // old PERSONAL_END
|
||||
return corpse_slot + 1;
|
||||
default:
|
||||
if (corpse_slot >= 331 && corpse_slot <= 340)
|
||||
return corpse_slot + 20;
|
||||
else if (corpse_slot >= 341 && corpse_slot <= 360)
|
||||
return corpse_slot - 10;
|
||||
else
|
||||
return corpse_slot;
|
||||
}
|
||||
*/
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
void Corpse::CastRezz(uint16 spellid, Mob* Caster){
|
||||
|
||||
+2
-2
@@ -112,8 +112,8 @@ public:
|
||||
inline int GetRezzExp() { return rezzexp; }
|
||||
|
||||
// these are a temporary work-around until corpse inventory is removed from the database blob
|
||||
//static uint32 ServerToCorpseSlot(int16 server_slot); // encode
|
||||
//static int16 CorpseToServerSlot(uint32 corpse_slot); // decode
|
||||
static int16 ServerToCorpseSlot(int16 server_slot); // encode
|
||||
static int16 CorpseToServerSlot(int16 corpse_slot); // decode
|
||||
|
||||
protected:
|
||||
std::list<uint32> MoveItemToCorpse(Client *client, ItemInst *item, int16 equipslot);
|
||||
|
||||
+3
-6
@@ -56,7 +56,7 @@ int32 NPC::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
value -= target->GetFcDamageAmtIncoming(this, spell_id)/spells[spell_id].buffduration;
|
||||
}
|
||||
|
||||
value += dmg*SpellFocusDMG/100;
|
||||
value += dmg*GetSpellFocusDMG()/100;
|
||||
|
||||
if (AI_HasSpellsEffects()){
|
||||
int16 chance = 0;
|
||||
@@ -275,7 +275,7 @@ int32 NPC::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
//Scale all NPC spell healing via SetSpellFocusHeal(value)
|
||||
|
||||
value += value*SpellFocusHeal/100;
|
||||
value += value*GetSpellFocusHeal()/100;
|
||||
|
||||
if (target) {
|
||||
value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id);
|
||||
@@ -606,6 +606,7 @@ bool Client::TrainDiscipline(uint32 itemid) {
|
||||
return(false);
|
||||
} else if(m_pp.disciplines.values[r] == 0) {
|
||||
m_pp.disciplines.values[r] = spell_id;
|
||||
database.SaveCharacterDisc(this->CharacterID(), r, spell_id);
|
||||
SendDisciplineUpdate();
|
||||
Message(0, "You have learned a new discipline!");
|
||||
return(true);
|
||||
@@ -616,13 +617,9 @@ bool Client::TrainDiscipline(uint32 itemid) {
|
||||
}
|
||||
|
||||
void Client::SendDisciplineUpdate() {
|
||||
//this dosent seem to work right now
|
||||
|
||||
EQApplicationPacket app(OP_DisciplineUpdate, sizeof(Disciplines_Struct));
|
||||
Disciplines_Struct *d = (Disciplines_Struct*)app.pBuffer;
|
||||
//dunno why I dont just send the one from m_pp
|
||||
memcpy(d, &m_pp.disciplines, sizeof(m_pp.disciplines));
|
||||
|
||||
QueuePacket(&app);
|
||||
}
|
||||
|
||||
|
||||
+38
-1
@@ -3402,6 +3402,41 @@ XS(XS__qs_player_event)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonesetentityvariablebynpctypeid);
|
||||
XS(XS__crosszonesetentityvariablebynpctypeid)
|
||||
{
|
||||
dXSARGS;
|
||||
|
||||
if (items != 3)
|
||||
Perl_croak(aTHX_ "Usage: crosszonesetentityvariablebynpctypeid(npctype_id, id, m_var)");
|
||||
|
||||
if (items == 3) {
|
||||
uint32 npctype_id = (uint32)SvIV(ST(0));
|
||||
const char *id = (const char *)SvPV_nolen(ST(1));
|
||||
const char *m_var = (const char *)SvPV_nolen(ST(2));
|
||||
quest_manager.CrossZoneSetEntityVariableByNPCTypeID(npctype_id, id, m_var);
|
||||
}
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__crosszonesignalnpcbynpctypeid);
|
||||
XS(XS__crosszonesignalnpcbynpctypeid)
|
||||
{
|
||||
dXSARGS;
|
||||
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: crosszonesignalnpcbynpctypeid(npctype_id, data)");
|
||||
|
||||
if (items == 2) {
|
||||
uint32 npctype_id = (uint32)SvIV(ST(0));
|
||||
uint32 data = (uint32)SvIV(ST(1));
|
||||
quest_manager.CrossZoneSignalNPCByNPCTypeID(npctype_id, data);
|
||||
}
|
||||
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
/*
|
||||
This is the callback perl will look for to setup the
|
||||
quest package's XSUBs
|
||||
@@ -3624,7 +3659,9 @@ EXTERN_C XS(boot_quest)
|
||||
newXS(strcpy(buf, "disablerecipe"), XS__disablerecipe, file);
|
||||
newXS(strcpy(buf, "clear_npctype_cache"), XS__clear_npctype_cache, file);
|
||||
newXS(strcpy(buf, "qs_send_query"), XS__qs_send_query, file);
|
||||
newXS(strcpy(buf, "qs_player_event"), XS__qs_player_event, file);
|
||||
newXS(strcpy(buf, "qs_player_event"), XS__qs_player_event, file);
|
||||
newXS(strcpy(buf, "crosszonesetentityvariablebynpctypeid"), XS__crosszonesetentityvariablebynpctypeid, file);
|
||||
newXS(strcpy(buf, "crosszonesignalnpcbynpctypeid"), XS__crosszonesignalnpcbynpctypeid, file);
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
|
||||
+61
-39
@@ -40,7 +40,6 @@
|
||||
#include "../common/spdat.h"
|
||||
#include "../common/features.h"
|
||||
#include "string_ids.h"
|
||||
#include "../common/dbasync.h"
|
||||
#include "guild_mgr.h"
|
||||
#include "raids.h"
|
||||
#include "quest_parser_collection.h"
|
||||
@@ -57,7 +56,6 @@ extern WorldServer worldserver;
|
||||
extern NetConnection net;
|
||||
extern uint32 numclients;
|
||||
extern PetitionList petition_list;
|
||||
extern DBAsync *dbasync;
|
||||
|
||||
extern char errorname[32];
|
||||
extern uint16 adverrornum;
|
||||
@@ -65,12 +63,11 @@ extern uint16 adverrornum;
|
||||
Entity::Entity()
|
||||
{
|
||||
id = 0;
|
||||
pDBAsyncWorkID = 0;
|
||||
}
|
||||
|
||||
Entity::~Entity()
|
||||
{
|
||||
dbasync->CancelWork(pDBAsyncWorkID);
|
||||
|
||||
}
|
||||
|
||||
Client *Entity::CastToClient()
|
||||
@@ -493,23 +490,36 @@ void EntityList::MobProcess()
|
||||
#endif
|
||||
auto it = mob_list.begin();
|
||||
while (it != mob_list.end()) {
|
||||
if (!it->second) {
|
||||
uint16 id = it->first;
|
||||
Mob *mob = it->second;
|
||||
|
||||
size_t sz = mob_list.size();
|
||||
bool p_val = mob->Process();
|
||||
size_t a_sz = mob_list.size();
|
||||
|
||||
if(a_sz > sz) {
|
||||
//increased size can potentially screw with iterators so reset it to current value
|
||||
//if buckets are re-orderered we may skip a process here and there but since
|
||||
//process happens so often it shouldn't matter much
|
||||
it = mob_list.find(id);
|
||||
++it;
|
||||
} else {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
if (!it->second->Process()) {
|
||||
Mob *mob = it->second;
|
||||
uint16 tempid = it->first;
|
||||
++it; // we don't erase here because the destructor will
|
||||
if (mob->IsNPC()) {
|
||||
entity_list.RemoveNPC(mob->CastToNPC()->GetID());
|
||||
} else if (mob->IsMerc()) {
|
||||
entity_list.RemoveMerc(mob->CastToMerc()->GetID());
|
||||
|
||||
if(!p_val) {
|
||||
if(mob->IsNPC()) {
|
||||
entity_list.RemoveNPC(id);
|
||||
}
|
||||
else if(mob->IsMerc()) {
|
||||
entity_list.RemoveMerc(id);
|
||||
#ifdef BOTS
|
||||
} else if (mob->IsBot()) {
|
||||
entity_list.RemoveBot(mob->CastToBot()->GetID());
|
||||
}
|
||||
else if(mob->IsBot()) {
|
||||
entity_list.RemoveBot(id);
|
||||
#endif
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
#ifdef _WINDOWS
|
||||
struct in_addr in;
|
||||
in.s_addr = mob->CastToClient()->GetIP();
|
||||
@@ -517,20 +527,19 @@ void EntityList::MobProcess()
|
||||
#endif
|
||||
zone->StartShutdownTimer();
|
||||
Group *g = GetGroupByMob(mob);
|
||||
if (g) {
|
||||
if(g) {
|
||||
LogFile->write(EQEMuLog::Error, "About to delete a client still in a group.");
|
||||
g->DelMember(mob);
|
||||
}
|
||||
Raid *r = entity_list.GetRaidByClient(mob->CastToClient());
|
||||
if (r) {
|
||||
if(r) {
|
||||
LogFile->write(EQEMuLog::Error, "About to delete a client still in a raid.");
|
||||
r->MemberZoned(mob->CastToClient());
|
||||
}
|
||||
entity_list.RemoveClient(mob->GetID());
|
||||
entity_list.RemoveClient(id);
|
||||
}
|
||||
entity_list.RemoveMob(tempid);
|
||||
} else {
|
||||
++it;
|
||||
|
||||
entity_list.RemoveMob(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1342,7 +1351,7 @@ void EntityList::RefreshClientXTargets(Client *c)
|
||||
}
|
||||
|
||||
void EntityList::QueueClientsByTarget(Mob *sender, const EQApplicationPacket *app,
|
||||
bool iSendToSender, Mob *SkipThisMob, bool ackreq, bool HoTT, uint32 ClientVersionBits)
|
||||
bool iSendToSender, Mob *SkipThisMob, bool ackreq, bool HoTT, uint32 ClientVersionBits, bool inspect_buffs)
|
||||
{
|
||||
auto it = client_list.begin();
|
||||
while (it != client_list.end()) {
|
||||
@@ -1356,8 +1365,7 @@ void EntityList::QueueClientsByTarget(Mob *sender, const EQApplicationPacket *ap
|
||||
|
||||
Mob *TargetsTarget = nullptr;
|
||||
|
||||
if (Target)
|
||||
TargetsTarget = Target->GetTarget();
|
||||
TargetsTarget = Target->GetTarget();
|
||||
|
||||
bool Send = false;
|
||||
|
||||
@@ -1369,11 +1377,30 @@ void EntityList::QueueClientsByTarget(Mob *sender, const EQApplicationPacket *ap
|
||||
Send = true;
|
||||
|
||||
if (c != sender) {
|
||||
if (Target == sender)
|
||||
Send = true;
|
||||
else if (HoTT)
|
||||
if (TargetsTarget == sender)
|
||||
if (Target == sender) {
|
||||
if (inspect_buffs) { // if inspect_buffs is true we're sending a mob's buffs to those with the LAA
|
||||
if (c->IsRaidGrouped()) {
|
||||
Raid *raid = c->GetRaid();
|
||||
if (!raid)
|
||||
continue;
|
||||
uint32 gid = raid->GetGroup(c);
|
||||
if (gid > 11 || raid->GroupCount(gid) < 3)
|
||||
continue;
|
||||
if (raid->GetLeadershipAA(groupAAInspectBuffs, gid))
|
||||
Send = true;
|
||||
} else {
|
||||
Group *group = c->GetGroup();
|
||||
if (!group || group->GroupCount() < 3)
|
||||
continue;
|
||||
if (group->GetLeadershipAA(groupAAInspectBuffs))
|
||||
Send = true;
|
||||
}
|
||||
} else {
|
||||
Send = true;
|
||||
}
|
||||
} else if (HoTT && TargetsTarget == sender) {
|
||||
Send = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (Send && (c->GetClientVersionBit() & ClientVersionBits))
|
||||
@@ -4111,15 +4138,10 @@ void EntityList::UnMarkNPC(uint16 ID)
|
||||
// each group to remove the dead mobs entity ID from the groups list of NPCs marked via the
|
||||
// Group Leadership AA Mark NPC ability.
|
||||
//
|
||||
auto it = client_list.begin();
|
||||
while (it != client_list.end()) {
|
||||
if (it->second) {
|
||||
Group *g = nullptr;
|
||||
g = it->second->GetGroup();
|
||||
|
||||
if (g)
|
||||
g->UnMarkNPC(ID);
|
||||
}
|
||||
auto it = group_list.begin();
|
||||
while (it != group_list.end()) {
|
||||
if (*it)
|
||||
(*it)->UnMarkNPC(ID);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -28,7 +28,6 @@
|
||||
|
||||
#include "zonedb.h"
|
||||
#include "zonedump.h"
|
||||
#include "zonedbasync.h"
|
||||
#include "qglobals.h"
|
||||
|
||||
class EQApplicationPacket;
|
||||
@@ -53,7 +52,7 @@ class Bot;
|
||||
class BotRaids;
|
||||
#endif
|
||||
|
||||
extern EntityList entity_list;
|
||||
extern EntityList entity_list;
|
||||
|
||||
class Entity
|
||||
{
|
||||
@@ -100,7 +99,6 @@ public:
|
||||
inline const uint16& GetID() const { return id; }
|
||||
|
||||
virtual const char* GetName() { return ""; }
|
||||
virtual void DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw) { pDBAsyncWorkID = 0; }
|
||||
bool CheckCoordLosNoZLeaps(float cur_x, float cur_y, float cur_z, float trg_x, float trg_y, float trg_z, float perwalk=1);
|
||||
|
||||
#ifdef BOTS
|
||||
@@ -299,7 +297,7 @@ public:
|
||||
void QueueClientsGuild(Mob* sender, const EQApplicationPacket* app, bool ignore_sender = false, uint32 guildeqid = 0);
|
||||
void QueueClientsGuildBankItemUpdate(const GuildBankItemUpdate_Struct *gbius, uint32 GuildID);
|
||||
void QueueClientsByTarget(Mob* sender, const EQApplicationPacket* app, bool iSendToSender = true, Mob* SkipThisMob = 0, bool ackreq = true,
|
||||
bool HoTT = true, uint32 ClientVersionBits = 0xFFFFFFFF);
|
||||
bool HoTT = true, uint32 ClientVersionBits = 0xFFFFFFFF, bool inspect_buffs = false);
|
||||
|
||||
void QueueClientsByXTarget(Mob* sender, const EQApplicationPacket* app, bool iSendToSender = true);
|
||||
void QueueToGroupsForNPCHealthAA(Mob* sender, const EQApplicationPacket* app);
|
||||
|
||||
+51
-28
@@ -51,14 +51,7 @@ static uint32 MaxBankedRaidLeadershipPoints(int Level)
|
||||
|
||||
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
|
||||
/* Set a timestamp in an entity variable for plugin check_handin.pl in return_items
|
||||
This will stopgap players from items being returned if global_npc.pl has a catch all return_items
|
||||
*/
|
||||
struct timeval read_time;
|
||||
char buffer[50];
|
||||
gettimeofday(&read_time, 0);
|
||||
sprintf(buffer, "%li.%li \n", read_time.tv_sec, read_time.tv_usec);
|
||||
this->SetEntityVariable("Stop_Return", buffer);
|
||||
this->EVENT_ITEM_ScriptStopReturn();
|
||||
|
||||
uint32 add_exp = in_add_exp;
|
||||
|
||||
@@ -140,30 +133,60 @@ void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||
}
|
||||
}
|
||||
|
||||
if(IsLeadershipEXPOn() && ((conlevel == CON_BLUE) || (conlevel == CON_WHITE) || (conlevel == CON_YELLOW) || (conlevel == CON_RED))) {
|
||||
if (IsLeadershipEXPOn() && (conlevel == CON_BLUE || conlevel == CON_WHITE || conlevel == CON_YELLOW || conlevel == CON_RED)) {
|
||||
add_exp = static_cast<uint32>(static_cast<float>(add_exp) * 0.8f);
|
||||
|
||||
if(GetGroup())
|
||||
{
|
||||
if((m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel()))
|
||||
&& (RuleI(Character, KillsPerGroupLeadershipAA) > 0))
|
||||
{
|
||||
AddLeadershipEXP(GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA), 0);
|
||||
Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
||||
}
|
||||
else
|
||||
if (GetGroup()) {
|
||||
if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel())
|
||||
&& RuleI(Character, KillsPerGroupLeadershipAA) > 0) {
|
||||
uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA);
|
||||
Client *mentoree = GetGroup()->GetMentoree();
|
||||
if (GetGroup()->GetMentorPercent() && mentoree &&
|
||||
mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel())) {
|
||||
uint32 mentor_exp = exp * (GetGroup()->GetMentorPercent() / 100.0f);
|
||||
exp -= mentor_exp;
|
||||
mentoree->AddLeadershipEXP(mentor_exp, 0); // ends up rounded down
|
||||
mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
||||
}
|
||||
if (exp > 0) { // possible if you mentor 100% to the other client
|
||||
AddLeadershipEXP(exp, 0); // ends up rounded up if mentored, no idea how live actually does it
|
||||
Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
||||
}
|
||||
} else {
|
||||
Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if((m_pp.raid_leadership_points < MaxBankedRaidLeadershipPoints(GetLevel()))
|
||||
&& (RuleI(Character, KillsPerRaidLeadershipAA) > 0))
|
||||
{
|
||||
AddLeadershipEXP(0, RAID_EXP_PER_POINT / RuleI(Character, KillsPerRaidLeadershipAA));
|
||||
Message_StringID(MT_Leadership, GAIN_RAID_LEADERSHIP_EXP);
|
||||
}
|
||||
else
|
||||
Message_StringID(MT_Leadership, MAX_RAID_LEADERSHIP_POINTS);
|
||||
} else {
|
||||
Raid *raid = GetRaid();
|
||||
// Raid leaders CAN NOT gain group AA XP, other group leaders can though!
|
||||
if (raid->IsLeader(this)) {
|
||||
if (m_pp.raid_leadership_points < MaxBankedRaidLeadershipPoints(GetLevel())
|
||||
&& RuleI(Character, KillsPerRaidLeadershipAA) > 0) {
|
||||
AddLeadershipEXP(0, RAID_EXP_PER_POINT / RuleI(Character, KillsPerRaidLeadershipAA));
|
||||
Message_StringID(MT_Leadership, GAIN_RAID_LEADERSHIP_EXP);
|
||||
} else {
|
||||
Message_StringID(MT_Leadership, MAX_RAID_LEADERSHIP_POINTS);
|
||||
}
|
||||
} else {
|
||||
if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel())
|
||||
&& RuleI(Character, KillsPerGroupLeadershipAA) > 0) {
|
||||
uint32 group_id = raid->GetGroup(this);
|
||||
uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA);
|
||||
Client *mentoree = raid->GetMentoree(group_id);
|
||||
if (raid->GetMentorPercent(group_id) && mentoree &&
|
||||
mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel())) {
|
||||
uint32 mentor_exp = exp * (raid->GetMentorPercent(group_id) / 100.0f);
|
||||
exp -= mentor_exp;
|
||||
mentoree->AddLeadershipEXP(mentor_exp, 0);
|
||||
mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
||||
}
|
||||
if (exp > 0) {
|
||||
AddLeadershipEXP(exp, 0);
|
||||
Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
||||
}
|
||||
} else {
|
||||
Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+18
-31
@@ -31,12 +31,10 @@
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
|
||||
extern Zone* zone;
|
||||
|
||||
#define FEAR_PATHING_DEBUG
|
||||
|
||||
|
||||
//this is called whenever we are damaged to process possible fleeing
|
||||
void Mob::CheckFlee() {
|
||||
//if were allready fleeing, dont need to check more...
|
||||
@@ -55,7 +53,7 @@ void Mob::CheckFlee() {
|
||||
float ratio = GetHPRatio();
|
||||
float fleeratio = GetSpecialAbility(FLEE_PERCENT);
|
||||
fleeratio = fleeratio > 0 ? fleeratio : RuleI(Combat, FleeHPRatio);
|
||||
|
||||
|
||||
if(ratio >= fleeratio)
|
||||
return;
|
||||
|
||||
@@ -101,12 +99,13 @@ void Mob::CheckFlee() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Mob::ProcessFlee() {
|
||||
void Mob::ProcessFlee()
|
||||
{
|
||||
|
||||
//Stop fleeing if effect is applied after they start to run.
|
||||
//When ImmuneToFlee effect fades it will turn fear back on and check if it can still flee.
|
||||
if(flee_mode && (GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) && !spellbonuses.IsFeared){
|
||||
if (flee_mode && (GetSpecialAbility(IMMUNE_FLEEING) || spellbonuses.ImmuneToFlee) &&
|
||||
!spellbonuses.IsFeared && !spellbonuses.IsBlind) {
|
||||
curfp = false;
|
||||
return;
|
||||
}
|
||||
@@ -114,40 +113,42 @@ void Mob::ProcessFlee() {
|
||||
//see if we are still dying, if so, do nothing
|
||||
float fleeratio = GetSpecialAbility(FLEE_PERCENT);
|
||||
fleeratio = fleeratio > 0 ? fleeratio : RuleI(Combat, FleeHPRatio);
|
||||
if(GetHPRatio() < fleeratio)
|
||||
if (GetHPRatio() < fleeratio)
|
||||
return;
|
||||
|
||||
//we are not dying anymore... see what we do next
|
||||
|
||||
flee_mode = false;
|
||||
|
||||
//see if we are legitimately feared now
|
||||
if(!spellbonuses.IsFeared) {
|
||||
//not feared... were done...
|
||||
//see if we are legitimately feared or blind now
|
||||
if (!spellbonuses.IsFeared && !spellbonuses.IsBlind) {
|
||||
//not feared or blind... were done...
|
||||
curfp = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float Mob::GetFearSpeed() {
|
||||
if(flee_mode) {
|
||||
float Mob::GetFearSpeed()
|
||||
{
|
||||
if (flee_mode) {
|
||||
//we know ratio < FLEE_HP_RATIO
|
||||
float speed = GetBaseRunspeed();
|
||||
float ratio = GetHPRatio();
|
||||
float multiplier = RuleR(Combat, FleeMultiplier);
|
||||
|
||||
if(GetSnaredAmount() > 40)
|
||||
if (GetSnaredAmount() > 40)
|
||||
multiplier = multiplier / 6.0f;
|
||||
|
||||
speed = speed * ratio * multiplier / 100;
|
||||
|
||||
//NPC will eventually stop. Snares speeds this up.
|
||||
if(speed < 0.09)
|
||||
if (speed < 0.09)
|
||||
speed = 0.0001f;
|
||||
|
||||
return(speed);
|
||||
|
||||
return speed;
|
||||
}
|
||||
return(GetRunspeed());
|
||||
// fear and blind use their normal run speed
|
||||
return GetRunspeed();
|
||||
}
|
||||
|
||||
void Mob::CalculateNewFearpoint()
|
||||
@@ -209,17 +210,3 @@ void Mob::CalculateNewFearpoint()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+112
-108
@@ -46,6 +46,7 @@ Group::Group(uint32 gid)
|
||||
: GroupIDConsumer(gid)
|
||||
{
|
||||
leader = nullptr;
|
||||
mentoree = nullptr;
|
||||
memset(members,0,sizeof(Mob*) * MAX_GROUP_MEMBERS);
|
||||
AssistTargetID = 0;
|
||||
TankTargetID = 0;
|
||||
@@ -81,6 +82,7 @@ Group::Group(Mob* leader)
|
||||
TankTargetID = 0;
|
||||
PullerTargetID = 0;
|
||||
memset(&LeaderAbilities, 0, sizeof(GroupLeadershipAA_Struct));
|
||||
mentoree = nullptr;
|
||||
uint32 i;
|
||||
for(i=0;i<MAX_GROUP_MEMBERS;i++)
|
||||
{
|
||||
@@ -195,7 +197,7 @@ void Group::SplitMoney(uint32 copper, uint32 silver, uint32 gold, uint32 platinu
|
||||
if (members[i] != nullptr && members[i]->IsClient()) { // If Group Member is Client
|
||||
Client *c = members[i]->CastToClient();
|
||||
//I could not get MoneyOnCorpse to work, so we use this
|
||||
c->AddMoneyToPP(cpsplit, spsplit, gpsplit, ppsplit, true);
|
||||
c->AddMoneyToPP(cpsplit, spsplit, gpsplit, ppsplit, true);
|
||||
c->Message(2, msg.c_str());
|
||||
}
|
||||
}
|
||||
@@ -467,6 +469,11 @@ bool Group::UpdatePlayer(Mob* update){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// mentoree isn't set, the name has a length and the name is ours! update the pointer
|
||||
if (update->IsClient() && !mentoree && mentoree_name.length() && !mentoree_name.compare(update->GetName()))
|
||||
mentoree = update->CastToClient();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -500,6 +507,9 @@ void Group::MemberZoned(Mob* removemob) {
|
||||
|
||||
if(removemob->IsClient() && HasRole(removemob, RolePuller))
|
||||
SetGroupPullerTarget(0);
|
||||
|
||||
if (removemob->IsClient() && removemob == mentoree)
|
||||
mentoree = nullptr;
|
||||
}
|
||||
|
||||
bool Group::DelMemberOOZ(const char *Name) {
|
||||
@@ -528,6 +538,8 @@ bool Group::DelMemberOOZ(const char *Name) {
|
||||
}
|
||||
ClearAllNPCMarks();
|
||||
}
|
||||
if (Name == mentoree_name)
|
||||
ClearGroupMentor();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -642,6 +654,9 @@ bool Group::DelMember(Mob* oldmember,bool ignoresender)
|
||||
UnDelegatePuller(oldmember->GetName());
|
||||
}
|
||||
|
||||
if (oldmember->GetName() == mentoree_name)
|
||||
ClearGroupMentor();
|
||||
|
||||
if(oldmember->IsClient())
|
||||
SendMarkedNPCsToMember(oldmember->CastToClient(), true);
|
||||
|
||||
@@ -969,31 +984,28 @@ void Group::TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float
|
||||
}
|
||||
|
||||
bool Group::LearnMembers() {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "SELECT name FROM group_id WHERE groupid=%lu", (unsigned long)GetID()),
|
||||
errbuf,&result)){
|
||||
safe_delete_array(query);
|
||||
if(mysql_num_rows(result) < 1) { //could prolly be 2
|
||||
mysql_free_result(result);
|
||||
LogFile->write(EQEMuLog::Error, "Error getting group members for group %lu: %s", (unsigned long)GetID(), errbuf);
|
||||
return(false);
|
||||
}
|
||||
int i = 0;
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
if(!row[0])
|
||||
continue;
|
||||
members[i] = nullptr;
|
||||
strn0cpy(membername[i], row[0], 64);
|
||||
std::string query = StringFormat("SELECT name FROM group_id WHERE groupid = %lu", (unsigned long)GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
i++;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
if (results.RowCount() == 0) {
|
||||
LogFile->write(EQEMuLog::Error, "Error getting group members for group %lu: %s", (unsigned long)GetID(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
int memberIndex = 0;
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
if(!row[0])
|
||||
continue;
|
||||
|
||||
members[memberIndex] = nullptr;
|
||||
strn0cpy(membername[memberIndex], row[0], 64);
|
||||
|
||||
memberIndex++;
|
||||
}
|
||||
|
||||
return(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Group::VerifyGroup() {
|
||||
@@ -1077,7 +1089,7 @@ void Group::HealGroup(uint32 heal_amt, Mob* caster, int32 range)
|
||||
|
||||
if (!range)
|
||||
range = 200;
|
||||
|
||||
|
||||
float distance;
|
||||
float range2 = range*range;
|
||||
|
||||
@@ -1114,10 +1126,10 @@ void Group::BalanceHP(int32 penalty, int32 range, Mob* caster, int32 limit)
|
||||
return;
|
||||
|
||||
if (!range)
|
||||
range = 200;
|
||||
|
||||
range = 200;
|
||||
|
||||
int dmgtaken = 0, numMem = 0, dmgtaken_tmp = 0;
|
||||
|
||||
|
||||
float distance;
|
||||
float range2 = range*range;
|
||||
|
||||
@@ -1164,16 +1176,16 @@ void Group::BalanceMana(int32 penalty, int32 range, Mob* caster, int32 limit)
|
||||
return;
|
||||
|
||||
if (!range)
|
||||
range = 200;
|
||||
range = 200;
|
||||
|
||||
float distance;
|
||||
float range2 = range*range;
|
||||
|
||||
|
||||
int manataken = 0, numMem = 0, manataken_tmp = 0;
|
||||
unsigned int gi = 0;
|
||||
for(; gi < MAX_GROUP_MEMBERS; gi++)
|
||||
{
|
||||
if(members[gi] && (members[gi]->GetMaxMana() > 0)){
|
||||
if(members[gi] && (members[gi]->GetMaxMana() > 0)){
|
||||
distance = caster->DistNoRoot(*members[gi]);
|
||||
if(distance <= range2){
|
||||
|
||||
@@ -1341,15 +1353,12 @@ void Group::DelegateMainTank(const char *NewMainTankName, uint8 toggle)
|
||||
}
|
||||
|
||||
if(updateDB) {
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char *Query = nullptr;
|
||||
|
||||
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET maintank='%s' WHERE gid=%i LIMIT 1",
|
||||
MainTankName.c_str(), GetID()), errbuff))
|
||||
LogFile->write(EQEMuLog::Error, "Unable to set group main tank: %s\n", errbuff);
|
||||
|
||||
safe_delete_array(Query);
|
||||
std::string query = StringFormat("UPDATE group_leaders SET maintank = '%s' WHERE gid = %i LIMIT 1",
|
||||
MainTankName.c_str(), GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to set group main tank: %s\n", results.ErrorMessage().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1390,15 +1399,13 @@ void Group::DelegateMainAssist(const char *NewMainAssistName, uint8 toggle)
|
||||
}
|
||||
|
||||
if(updateDB) {
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char *Query = nullptr;
|
||||
std::string query = StringFormat("UPDATE group_leaders SET assist = '%s' WHERE gid = %i LIMIT 1",
|
||||
MainAssistName.c_str(), GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to set group main assist: %s\n", results.ErrorMessage().c_str());
|
||||
|
||||
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET assist='%s' WHERE gid=%i LIMIT 1",
|
||||
MainAssistName.c_str(), GetID()), errbuff))
|
||||
LogFile->write(EQEMuLog::Error, "Unable to set group main assist: %s\n", errbuff);
|
||||
|
||||
safe_delete_array(Query);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1439,15 +1446,13 @@ void Group::DelegatePuller(const char *NewPullerName, uint8 toggle)
|
||||
}
|
||||
|
||||
if(updateDB) {
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char *Query = nullptr;
|
||||
std::string query = StringFormat("UPDATE group_leaders SET puller = '%s' WHERE gid = %i LIMIT 1",
|
||||
PullerName.c_str(), GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to set group main puller: %s\n", results.ErrorMessage().c_str());
|
||||
|
||||
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET puller='%s' WHERE gid=%i LIMIT 1",
|
||||
PullerName.c_str(), GetID()), errbuff))
|
||||
LogFile->write(EQEMuLog::Error, "Unable to set group main puller: %s\n", errbuff);
|
||||
|
||||
safe_delete_array(Query);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1593,15 +1598,11 @@ void Group::UnDelegateMainTank(const char *OldMainTankName, uint8 toggle)
|
||||
// informing them of the change and update the group_leaders table.
|
||||
//
|
||||
if(OldMainTankName == MainTankName) {
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char *Query = 0;
|
||||
|
||||
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET maintank='' WHERE gid=%i LIMIT 1",
|
||||
GetID()), errbuff))
|
||||
LogFile->write(EQEMuLog::Error, "Unable to clear group main tank: %s\n", errbuff);
|
||||
|
||||
safe_delete_array(Query);
|
||||
std::string query = StringFormat("UPDATE group_leaders SET maintank = '' WHERE gid = %i LIMIT 1", GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to clear group main tank: %s\n", results.ErrorMessage().c_str());
|
||||
|
||||
if(!toggle) {
|
||||
for(uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) {
|
||||
@@ -1647,15 +1648,10 @@ void Group::UnDelegateMainAssist(const char *OldMainAssistName, uint8 toggle)
|
||||
|
||||
safe_delete(outapp);
|
||||
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char *Query = 0;
|
||||
|
||||
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET assist='' WHERE gid=%i LIMIT 1",
|
||||
GetID()), errbuff))
|
||||
LogFile->write(EQEMuLog::Error, "Unable to clear group main assist: %s\n", errbuff);
|
||||
|
||||
safe_delete_array(Query);
|
||||
std::string query = StringFormat("UPDATE group_leaders SET assist = '' WHERE gid = %i LIMIT 1", GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to clear group main assist: %s\n", results.ErrorMessage().c_str());
|
||||
|
||||
if(!toggle)
|
||||
{
|
||||
@@ -1679,15 +1675,11 @@ void Group::UnDelegatePuller(const char *OldPullerName, uint8 toggle)
|
||||
// informing them of the change and update the group_leaders table.
|
||||
//
|
||||
if(OldPullerName == PullerName) {
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char *Query = 0;
|
||||
|
||||
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET puller='' WHERE gid=%i LIMIT 1",
|
||||
GetID()), errbuff))
|
||||
LogFile->write(EQEMuLog::Error, "Unable to clear group main puller: %s\n", errbuff);
|
||||
|
||||
safe_delete_array(Query);
|
||||
std::string query = StringFormat("UPDATE group_leaders SET puller = '' WHERE gid = %i LIMIT 1", GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to clear group main puller: %s\n", results.ErrorMessage().c_str());
|
||||
|
||||
if(!toggle) {
|
||||
for(uint32 i = 0; i < MAX_GROUP_MEMBERS; ++i) {
|
||||
@@ -1759,6 +1751,31 @@ void Group::SetGroupPullerTarget(Mob *m)
|
||||
}
|
||||
}
|
||||
|
||||
void Group::SetGroupMentor(int percent, char *name)
|
||||
{
|
||||
mentoree_name = name;
|
||||
mentor_percent = percent;
|
||||
Client *client = entity_list.GetClientByName(name);
|
||||
|
||||
mentoree = client ? client : nullptr;
|
||||
std::string query = StringFormat("UPDATE group_leaders SET mentoree = '%s', mentor_percent = %i WHERE gid = %i LIMIT 1",
|
||||
mentoree_name.c_str(), mentor_percent, GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to set group mentor: %s\n", results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
void Group::ClearGroupMentor()
|
||||
{
|
||||
mentoree_name.clear();
|
||||
mentor_percent = 0;
|
||||
mentoree = nullptr;
|
||||
std::string query = StringFormat("UPDATE group_leaders SET mentoree = '', mentor_percent = 0 WHERE gid = %i LIMIT 1", GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to clear group mentor: %s\n", results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
void Group::NotifyAssistTarget(Client *c)
|
||||
{
|
||||
// Send a packet to the specified client notifying them of the group target selected by the Main Assist.
|
||||
@@ -1822,16 +1839,11 @@ void Group::DelegateMarkNPC(const char *NewNPCMarkerName)
|
||||
if(members[i] && members[i]->IsClient())
|
||||
NotifyMarkNPC(members[i]->CastToClient());
|
||||
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char *Query = 0;
|
||||
|
||||
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET marknpc='%s' WHERE gid=%i LIMIT 1",
|
||||
NewNPCMarkerName, GetID()), errbuff))
|
||||
LogFile->write(EQEMuLog::Error, "Unable to set group mark npc: %s\n", errbuff);
|
||||
|
||||
safe_delete_array(Query);
|
||||
|
||||
std::string query = StringFormat("UPDATE group_leaders SET marknpc = '%s' WHERE gid = %i LIMIT 1",
|
||||
NewNPCMarkerName, GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to set group mark npc: %s\n", results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
void Group::NotifyMarkNPC(Client *c)
|
||||
@@ -1908,37 +1920,29 @@ void Group::UnDelegateMarkNPC(const char *OldNPCMarkerName)
|
||||
|
||||
NPCMarkerName.clear();
|
||||
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
char *Query = 0;
|
||||
std::string query = StringFormat("UPDATE group_leaders SET marknpc = '' WHERE gid = %i LIMIT 1", GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to clear group marknpc: %s\n", results.ErrorMessage().c_str());
|
||||
|
||||
if (!database.RunQuery(Query, MakeAnyLenString(&Query, "UPDATE group_leaders SET marknpc='' WHERE gid=%i LIMIT 1",
|
||||
GetID()), errbuff))
|
||||
LogFile->write(EQEMuLog::Error, "Unable to clear group marknpc: %s\n", errbuff);
|
||||
|
||||
safe_delete_array(Query);
|
||||
}
|
||||
|
||||
void Group::SaveGroupLeaderAA()
|
||||
{
|
||||
// Stores the Group Leaders Leadership AA data from the Player Profile as a blob in the group_leaders table.
|
||||
// This is done so that group members not in the same zone as the Leader still have access to this information.
|
||||
char *queryBuffer = new char[sizeof(GroupLeadershipAA_Struct) * 2 + 1];
|
||||
database.DoEscapeString(queryBuffer, (char*)&LeaderAbilities, sizeof(GroupLeadershipAA_Struct));
|
||||
|
||||
char *Query = new char[200 + sizeof(GroupLeadershipAA_Struct)*2];
|
||||
std::string query = "UPDATE group_leaders SET leadershipaa = '";
|
||||
query += queryBuffer;
|
||||
query += StringFormat("' WHERE gid = %i LIMIT 1", GetID());
|
||||
safe_delete_array(queryBuffer);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to store LeadershipAA: %s\n", results.ErrorMessage().c_str());
|
||||
|
||||
char *End = Query;
|
||||
|
||||
End += sprintf(End, "UPDATE group_leaders SET leadershipaa='");
|
||||
|
||||
End += database.DoEscapeString(End, (char*)&LeaderAbilities, sizeof(GroupLeadershipAA_Struct));
|
||||
|
||||
End += sprintf(End,"' WHERE gid=%i LIMIT 1", GetID());
|
||||
|
||||
char errbuff[MYSQL_ERRMSG_SIZE];
|
||||
if (!database.RunQuery(Query, End - Query, errbuff))
|
||||
LogFile->write(EQEMuLog::Error, "Unable to store LeadershipAA: %s\n", errbuff);
|
||||
|
||||
safe_delete_array(Query);
|
||||
}
|
||||
|
||||
void Group::UnMarkNPC(uint16 ID)
|
||||
|
||||
@@ -132,6 +132,11 @@ public:
|
||||
const char *GetClientNameByIndex(uint8 index);
|
||||
void UpdateXTargetMarkedNPC(uint32 Number, Mob *m);
|
||||
|
||||
void SetGroupMentor(int percent, char *name);
|
||||
void ClearGroupMentor();
|
||||
inline int GetMentorPercent() { return mentor_percent; }
|
||||
inline Client *GetMentoree() { return mentoree; }
|
||||
|
||||
Mob* members[MAX_GROUP_MEMBERS];
|
||||
char membername[MAX_GROUP_MEMBERS][64];
|
||||
uint8 MemberRoles[MAX_GROUP_MEMBERS];
|
||||
@@ -151,6 +156,9 @@ private:
|
||||
uint16 PullerTargetID;
|
||||
uint16 MarkedNPCs[MAX_MARKED_NPCS];
|
||||
|
||||
std::string mentoree_name;
|
||||
Client *mentoree;
|
||||
int mentor_percent;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,59 +24,6 @@
|
||||
#include "client.h"
|
||||
#include "entity.h"
|
||||
|
||||
/*
|
||||
|
||||
CREATE TABLE guilds (
|
||||
id MEDIUMINT UNSIGNED NOT NULL,
|
||||
name VARCHAR(32) NOT NULL,
|
||||
leader int NOT NULL,
|
||||
minstatus SMALLINT NOT NULL,
|
||||
tribute INT UNSIGNED NOT NULL,
|
||||
motd TEXT NOT NULL DEFAULT '',
|
||||
PRIMARY KEY(id),
|
||||
UNIQUE KEY(name),
|
||||
UNIQUE KEY(leader)
|
||||
);
|
||||
|
||||
CREATE TABLE guild_ranks (
|
||||
guild_id MEDIUMINT UNSIGNED NOT NULL,
|
||||
rank TINYINT UNSIGNED NOT NULL,
|
||||
title VARCHAR(128) NOT NULL,
|
||||
can_hear TINYINT UNSIGNED NOT NULL,
|
||||
can_speak TINYINT UNSIGNED NOT NULL,
|
||||
can_invite TINYINT UNSIGNED NOT NULL,
|
||||
can_remove TINYINT UNSIGNED NOT NULL,
|
||||
can_promote TINYINT UNSIGNED NOT NULL,
|
||||
can_demote TINYINT UNSIGNED NOT NULL,
|
||||
can_motd TINYINT UNSIGNED NOT NULL,
|
||||
can_warpeace TINYINT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY(guild_id,rank)
|
||||
);
|
||||
|
||||
# guild1 < guild2 by definition.
|
||||
CREATE TABLE guild_relations (
|
||||
guild1 MEDIUMINT UNSIGNED NOT NULL,
|
||||
guild2 MEDIUMINT UNSIGNED NOT NULL,
|
||||
relation TINYINT NOT NULL,
|
||||
PRIMARY KEY(guild1, guild1)
|
||||
);
|
||||
|
||||
CREATE TABLE guild_members (
|
||||
char_id INT NOT NULL,
|
||||
guild_id MEDIUMINT UNSIGNED NOT NULL,
|
||||
rank TINYINT UNSIGNED NOT NULL,
|
||||
tribute_enable TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
total_tribute INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
last_tribute INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
banker TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
public_note TEXT NOT NULL DEFAULT '',
|
||||
PRIMARY KEY(char_id)
|
||||
);
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
ZoneGuildManager guild_mgr;
|
||||
GuildBankManager *GuildBanks;
|
||||
|
||||
|
||||
+10
-20
@@ -200,14 +200,7 @@ bool Client::CheckLoreConflict(const Item_Struct* item) {
|
||||
}
|
||||
|
||||
bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2, uint32 aug3, uint32 aug4, uint32 aug5, bool attuned, uint16 to_slot) {
|
||||
/* Set a timestamp in an entity variable for plugin check_handin.pl in return_items
|
||||
This will stopgap players from items being returned if global_npc.pl has a catch all return_items
|
||||
*/
|
||||
struct timeval read_time;
|
||||
char buffer[50];
|
||||
gettimeofday(&read_time, 0);
|
||||
sprintf(buffer, "%li.%li \n", read_time.tv_sec, read_time.tv_usec);
|
||||
this->SetEntityVariable("Recieved_Item", buffer);
|
||||
this->EVENT_ITEM_ScriptStopReturn();
|
||||
|
||||
// TODO: update calling methods and script apis to handle a failure return
|
||||
|
||||
@@ -1877,7 +1870,9 @@ void Client::DyeArmor(DyeStruct* dye){
|
||||
uint8 slot2=SlotConvert(i);
|
||||
ItemInst* inst = this->m_inv.GetItem(slot2);
|
||||
if(inst){
|
||||
inst->SetColor((dye->dye[i].rgb.red*65536)+(dye->dye[i].rgb.green*256)+(dye->dye[i].rgb.blue));
|
||||
uint32 armor_color = (dye->dye[i].rgb.red * 65536) + (dye->dye[i].rgb.green * 256) + (dye->dye[i].rgb.blue);
|
||||
inst->SetColor(armor_color);
|
||||
database.SaveCharacterMaterialColor(this->CharacterID(), i, armor_color);
|
||||
database.SaveInventory(CharacterID(),inst,slot2);
|
||||
if(dye->dye[i].rgb.use_tint)
|
||||
m_pp.item_tint[i].rgb.use_tint = 0xFF;
|
||||
@@ -1898,7 +1893,7 @@ void Client::DyeArmor(DyeStruct* dye){
|
||||
EQApplicationPacket* outapp=new EQApplicationPacket(OP_Dye,0);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
Save();
|
||||
|
||||
}
|
||||
|
||||
/*bool Client::DecreaseByItemType(uint32 type, uint8 amt) {
|
||||
@@ -2417,10 +2412,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;
|
||||
const Item_Struct *BaseItem;
|
||||
int16 WeaponSlot;
|
||||
|
||||
for(int BandolierSlot = bandolierMainHand; BandolierSlot <= bandolierAmmo; BandolierSlot++) {
|
||||
@@ -2431,6 +2424,7 @@ void Client::CreateBandolier(const EQApplicationPacket *app) {
|
||||
_log(INVENTORY__BANDOLIER, "Char: %s adding item %s to slot %i", GetName(),BaseItem->Name, WeaponSlot);
|
||||
m_pp.bandoliers[bs->number].items[BandolierSlot].item_id = BaseItem->ID;
|
||||
m_pp.bandoliers[bs->number].items[BandolierSlot].icon = BaseItem->Icon;
|
||||
database.SaveCharacterBandolier(this->CharacterID(), bs->number, BandolierSlot, m_pp.bandoliers[bs->number].items[BandolierSlot].item_id, m_pp.bandoliers[bs->number].items[BandolierSlot].icon, bs->name);
|
||||
}
|
||||
else {
|
||||
_log(INVENTORY__BANDOLIER, "Char: %s no item in slot %i", GetName(), WeaponSlot);
|
||||
@@ -2438,21 +2432,17 @@ void Client::CreateBandolier(const EQApplicationPacket *app) {
|
||||
m_pp.bandoliers[bs->number].items[BandolierSlot].icon = 0;
|
||||
}
|
||||
}
|
||||
Save();
|
||||
}
|
||||
|
||||
void Client::RemoveBandolier(const EQApplicationPacket *app) {
|
||||
|
||||
// Delete bandolier with the specified number
|
||||
|
||||
BandolierDelete_Struct *bds = (BandolierDelete_Struct*)app->pBuffer;
|
||||
_log(INVENTORY__BANDOLIER, "Char: %s removing set", GetName(), bds->number);
|
||||
memset(m_pp.bandoliers[bds->number].name, 0, 32);
|
||||
for(int i = bandolierMainHand; i <= bandolierAmmo; i++) {
|
||||
m_pp.bandoliers[bds->number].items[i].item_id = 0;
|
||||
m_pp.bandoliers[bds->number].items[i].icon = 0;
|
||||
m_pp.bandoliers[bds->number].items[i].icon = 0;
|
||||
}
|
||||
Save();
|
||||
database.DeleteCharacterBandolier(this->CharacterID(), bds->number);
|
||||
}
|
||||
|
||||
void Client::SetBandolier(const EQApplicationPacket *app) {
|
||||
|
||||
@@ -1239,6 +1239,11 @@ void Lua_Client::SendMarqueeMessage(uint32 type, uint32 priority, uint32 fade_in
|
||||
self->SendMarqueeMessage(type, priority, fade_in, fade_out, duration, msg);
|
||||
}
|
||||
|
||||
void Lua_Client::SendColoredText(uint32 type, std::string msg) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SendColoredText(type, msg);
|
||||
}
|
||||
|
||||
void Lua_Client::PlayMP3(std::string file)
|
||||
{
|
||||
Lua_Safe_Call_Void();
|
||||
@@ -1492,6 +1497,7 @@ luabind::scope lua_register_client() {
|
||||
.def("SetThirst", (void(Lua_Client::*)(int))&Lua_Client::SetThirst)
|
||||
.def("SetConsumption", (void(Lua_Client::*)(int, int))&Lua_Client::SetConsumption)
|
||||
.def("SendMarqueeMessage", (void(Lua_Client::*)(uint32, uint32, uint32, uint32, uint32, std::string))&Lua_Client::SendMarqueeMessage)
|
||||
.def("SendColoredText", (void(Lua_Client::*)(uint32, std::string))&Lua_Client::SendColoredText)
|
||||
.def("PlayMP3", (void(Lua_Client::*)(std::string))&Lua_Client::PlayMP3);
|
||||
}
|
||||
|
||||
|
||||
@@ -275,6 +275,7 @@ public:
|
||||
void SetThirst(int in_thirst);
|
||||
void SetConsumption(int in_hunger, int in_thirst);
|
||||
void SendMarqueeMessage(uint32 type, uint32 priority, uint32 fade_in, uint32 fade_out, uint32 duration, std::string msg);
|
||||
void SendColoredText(uint32 type, std::string msg);
|
||||
void PlayMP3(std::string file);
|
||||
};
|
||||
|
||||
|
||||
+13
-1
@@ -407,8 +407,18 @@ void Lua_NPC::SetSpellFocusHeal(int focus) {
|
||||
self->SetSpellFocusHeal(focus);
|
||||
}
|
||||
|
||||
float Lua_NPC::GetSlowMitigation() {
|
||||
int Lua_NPC::GetSpellFocusDMG() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetSpellFocusDMG();
|
||||
}
|
||||
|
||||
int Lua_NPC::GetSpellFocusHeal() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->GetSpellFocusHeal();
|
||||
}
|
||||
|
||||
float Lua_NPC::GetSlowMitigation() {
|
||||
Lua_Safe_Call_Real();
|
||||
return self->GetSlowMitigation();
|
||||
}
|
||||
|
||||
@@ -535,6 +545,8 @@ luabind::scope lua_register_npc() {
|
||||
.def("RemoveAISpell", (void(Lua_NPC::*)(int))&Lua_NPC::RemoveAISpell)
|
||||
.def("SetSpellFocusDMG", (void(Lua_NPC::*)(int))&Lua_NPC::SetSpellFocusDMG)
|
||||
.def("SetSpellFocusHeal", (void(Lua_NPC::*)(int))&Lua_NPC::SetSpellFocusHeal)
|
||||
.def("GetSpellFocusDMG", (void(Lua_NPC::*)(int))&Lua_NPC::GetSpellFocusDMG)
|
||||
.def("GetSpellFocusHeal", (void(Lua_NPC::*)(int))&Lua_NPC::GetSpellFocusHeal)
|
||||
.def("GetSlowMitigation", (int(Lua_NPC::*)(void))&Lua_NPC::GetSlowMitigation)
|
||||
.def("GetAttackSpeed", (float(Lua_NPC::*)(void))&Lua_NPC::GetAttackSpeed)
|
||||
.def("GetAccuracyRating", (int(Lua_NPC::*)(void))&Lua_NPC::GetAccuracyRating)
|
||||
|
||||
@@ -107,6 +107,8 @@ public:
|
||||
void RemoveAISpell(int spell_id);
|
||||
void SetSpellFocusDMG(int focus);
|
||||
void SetSpellFocusHeal(int focus);
|
||||
int GetSpellFocusDMG();
|
||||
int GetSpellFocusHeal();
|
||||
float GetSlowMitigation();
|
||||
float GetAttackSpeed();
|
||||
int GetAccuracyRating();
|
||||
|
||||
+44
-6
@@ -14,14 +14,31 @@ Lua_Packet::Lua_Packet(int opcode, int size) {
|
||||
owned_ = true;
|
||||
}
|
||||
|
||||
Lua_Packet::Lua_Packet(int opcode, int size, bool raw) {
|
||||
if(raw) {
|
||||
SetLuaPtrData(new EQApplicationPacket(OP_Unknown, size));
|
||||
owned_ = true;
|
||||
|
||||
EQApplicationPacket *self = reinterpret_cast<EQApplicationPacket*>(d_);
|
||||
self->SetOpcodeBypass(opcode);
|
||||
} else {
|
||||
SetLuaPtrData(new EQApplicationPacket(static_cast<EmuOpcode>(opcode), size));
|
||||
owned_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
Lua_Packet& Lua_Packet::operator=(const Lua_Packet& o) {
|
||||
if(o.owned_) {
|
||||
owned_ = true;
|
||||
EQApplicationPacket *app = reinterpret_cast<EQApplicationPacket*>(o.d_);
|
||||
if(app)
|
||||
if(app) {
|
||||
d_ = new EQApplicationPacket(app->GetOpcode(), app->pBuffer, app->size);
|
||||
else
|
||||
|
||||
EQApplicationPacket *self = reinterpret_cast<EQApplicationPacket*>(d_);
|
||||
self->SetOpcodeBypass(app->GetOpcodeBypass());
|
||||
} else {
|
||||
d_ = nullptr;
|
||||
}
|
||||
} else {
|
||||
owned_ = false;
|
||||
d_ = o.d_;
|
||||
@@ -33,10 +50,14 @@ Lua_Packet::Lua_Packet(const Lua_Packet& o) {
|
||||
if(o.owned_) {
|
||||
owned_ = true;
|
||||
EQApplicationPacket *app = reinterpret_cast<EQApplicationPacket*>(o.d_);
|
||||
if(app)
|
||||
if(app) {
|
||||
d_ = new EQApplicationPacket(app->GetOpcode(), app->pBuffer, app->size);
|
||||
else
|
||||
|
||||
EQApplicationPacket *self = reinterpret_cast<EQApplicationPacket*>(d_);
|
||||
self->SetOpcodeBypass(app->GetOpcodeBypass());
|
||||
} else {
|
||||
d_ = nullptr;
|
||||
}
|
||||
} else {
|
||||
owned_ = false;
|
||||
d_ = o.d_;
|
||||
@@ -54,6 +75,16 @@ int Lua_Packet::GetOpcode() {
|
||||
}
|
||||
|
||||
void Lua_Packet::SetOpcode(int op) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetOpcodeBypass(static_cast<uint16>(op));
|
||||
}
|
||||
|
||||
int Lua_Packet::GetRawOpcode() {
|
||||
Lua_Safe_Call_Int();
|
||||
return static_cast<int>(self->GetOpcodeBypass());
|
||||
}
|
||||
|
||||
void Lua_Packet::SetRawOpcode(int op) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->SetOpcode(static_cast<EmuOpcode>(op));
|
||||
}
|
||||
@@ -244,11 +275,14 @@ luabind::scope lua_register_packet() {
|
||||
return luabind::class_<Lua_Packet>("Packet")
|
||||
.def(luabind::constructor<>())
|
||||
.def(luabind::constructor<int,int>())
|
||||
.def(luabind::constructor<int,int,bool>())
|
||||
.property("null", &Lua_Packet::Null)
|
||||
.property("valid", &Lua_Packet::Valid)
|
||||
.def("GetSize", &Lua_Packet::GetSize)
|
||||
.def("GetOpcode", &Lua_Packet::GetOpcode)
|
||||
.def("SetOpcode", &Lua_Packet::SetOpcode)
|
||||
.def("GetRawOpcode", &Lua_Packet::GetRawOpcode)
|
||||
.def("SetRawOpcode", &Lua_Packet::SetRawOpcode)
|
||||
.def("WriteInt8", &Lua_Packet::WriteInt8)
|
||||
.def("WriteInt16", &Lua_Packet::WriteInt16)
|
||||
.def("WriteInt32", &Lua_Packet::WriteInt32)
|
||||
@@ -267,6 +301,7 @@ luabind::scope lua_register_packet() {
|
||||
.def("ReadFixedLengthString", &Lua_Packet::ReadFixedLengthString);
|
||||
}
|
||||
|
||||
//TODO: Reorder these to match emu_oplist.h again
|
||||
luabind::scope lua_register_packet_opcodes() {
|
||||
return luabind::class_<Opcodes>("Opcode")
|
||||
.enum_("constants")
|
||||
@@ -412,7 +447,7 @@ luabind::scope lua_register_packet_opcodes() {
|
||||
luabind::value("YellForHelp", static_cast<int>(OP_YellForHelp)),
|
||||
luabind::value("SafePoint", static_cast<int>(OP_SafePoint)),
|
||||
luabind::value("Buff", static_cast<int>(OP_Buff)),
|
||||
luabind::value("BuffFadeMsg", static_cast<int>(OP_BuffFadeMsg)),
|
||||
luabind::value("ColoredText", static_cast<int>(OP_ColoredText)),
|
||||
luabind::value("SpecialMesg", static_cast<int>(OP_SpecialMesg)),
|
||||
luabind::value("Consent", static_cast<int>(OP_Consent)),
|
||||
luabind::value("ConsentResponse", static_cast<int>(OP_ConsentResponse)),
|
||||
@@ -809,7 +844,10 @@ luabind::scope lua_register_packet_opcodes() {
|
||||
luabind::value("MercenaryDismiss", static_cast<int>(OP_MercenaryDismiss)),
|
||||
luabind::value("MercenaryTimerRequest", static_cast<int>(OP_MercenaryTimerRequest)),
|
||||
luabind::value("OpenInventory", static_cast<int>(OP_OpenInventory)),
|
||||
luabind::value("OpenContainer", static_cast<int>(OP_OpenContainer))
|
||||
luabind::value("OpenContainer", static_cast<int>(OP_OpenContainer)),
|
||||
luabind::value("Marquee", static_cast<int>(OP_Marquee)),
|
||||
luabind::value("ClientTimeStamp", static_cast<int>(OP_ClientTimeStamp)),
|
||||
luabind::value("GuildPromote", static_cast<int>(OP_GuildPromote))
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
Lua_Packet() : Lua_Ptr(nullptr), owned_(false) { }
|
||||
Lua_Packet(EQApplicationPacket *d) : Lua_Ptr(d), owned_(false) { }
|
||||
Lua_Packet(int opcode, int size);
|
||||
Lua_Packet(int opcode, int size, bool raw);
|
||||
Lua_Packet& operator=(const Lua_Packet& o);
|
||||
Lua_Packet(const Lua_Packet& o);
|
||||
virtual ~Lua_Packet() { if(owned_) { EQApplicationPacket *ptr = GetLuaPtrData(); if(ptr) { delete ptr; } } }
|
||||
@@ -28,6 +29,8 @@ public:
|
||||
int GetSize();
|
||||
int GetOpcode();
|
||||
void SetOpcode(int op);
|
||||
int GetRawOpcode();
|
||||
void SetRawOpcode(int op);
|
||||
void WriteInt8(int offset, int value);
|
||||
void WriteInt16(int offset, int value);
|
||||
void WriteInt32(int offset, int value);
|
||||
|
||||
@@ -419,6 +419,56 @@ bool Lua_Spell::GetAllowRest() {
|
||||
return self->AllowRest;
|
||||
}
|
||||
|
||||
bool Lua_Spell::GetInCombat() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->InCombat;
|
||||
}
|
||||
|
||||
bool Lua_Spell::GetOutOfCombat() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->OutofCombat;
|
||||
}
|
||||
|
||||
int Lua_Spell::GetAEMaxTargets() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->aemaxtargets;
|
||||
}
|
||||
|
||||
int Lua_Spell::GetMaxTargets() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->maxtargets;
|
||||
}
|
||||
|
||||
bool Lua_Spell::GetPersistDeath() {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->persistdeath;
|
||||
}
|
||||
|
||||
float Lua_Spell::GetMinDist() {
|
||||
Lua_Safe_Call_Real();
|
||||
return self->min_dist;
|
||||
}
|
||||
|
||||
float Lua_Spell::GetMinDistMod() {
|
||||
Lua_Safe_Call_Real();
|
||||
return self->min_dist_mod;
|
||||
}
|
||||
|
||||
float Lua_Spell::GetMaxDist() {
|
||||
Lua_Safe_Call_Real();
|
||||
return self->max_dist;
|
||||
}
|
||||
|
||||
float Lua_Spell::GetMaxDistMod() {
|
||||
Lua_Safe_Call_Real();
|
||||
return self->max_dist_mod;
|
||||
}
|
||||
|
||||
float Lua_Spell::GetMinRange() {
|
||||
Lua_Safe_Call_Real();
|
||||
return self->min_range;
|
||||
}
|
||||
|
||||
int Lua_Spell::GetDamageShieldType() {
|
||||
Lua_Safe_Call_Int();
|
||||
return self->DamageShieldType;
|
||||
@@ -501,6 +551,16 @@ luabind::scope lua_register_spell() {
|
||||
.def("PowerfulFlag", &Lua_Spell::GetPowerfulFlag)
|
||||
.def("CastRestriction", &Lua_Spell::GetCastRestriction)
|
||||
.def("AllowRest", &Lua_Spell::GetAllowRest)
|
||||
.def("InCombat", &Lua_Spell::GetInCombat)
|
||||
.def("OutOfCombat", &Lua_Spell::GetOutOfCombat)
|
||||
.def("AEMaxTargets", &Lua_Spell::GetAEMaxTargets)
|
||||
.def("MaxTargets", &Lua_Spell::GetMaxTargets)
|
||||
.def("PersistDeath", &Lua_Spell::GetPersistDeath)
|
||||
.def("MinDist", &Lua_Spell::GetMinDist)
|
||||
.def("MinDistMod", &Lua_Spell::GetMinDistMod)
|
||||
.def("MaxDist", &Lua_Spell::GetMaxDist)
|
||||
.def("MaxDistMod", &Lua_Spell::GetMaxDistMod)
|
||||
.def("MinRange", &Lua_Spell::GetMinRange)
|
||||
.def("DamageShieldType", &Lua_Spell::GetDamageShieldType);
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,16 @@ public:
|
||||
int GetPowerfulFlag();
|
||||
int GetCastRestriction();
|
||||
bool GetAllowRest();
|
||||
bool GetInCombat();
|
||||
bool GetOutOfCombat();
|
||||
int GetAEMaxTargets();
|
||||
int GetMaxTargets();
|
||||
bool GetPersistDeath();
|
||||
float GetMinDist();
|
||||
float GetMinDistMod();
|
||||
float GetMaxDist();
|
||||
float GetMaxDistMod();
|
||||
float GetMinRange();
|
||||
int GetDamageShieldType();
|
||||
};
|
||||
|
||||
|
||||
+2
-8
@@ -4619,13 +4619,7 @@ void Merc::DoClassAttacks(Mob *target) {
|
||||
if(!ca_time)
|
||||
return;
|
||||
|
||||
float HasteModifier = 0;
|
||||
if(GetHaste() > 0)
|
||||
HasteModifier = 10000 / (100 + GetHaste());
|
||||
else if(GetHaste() < 0)
|
||||
HasteModifier = (100 - GetHaste());
|
||||
else
|
||||
HasteModifier = 100;
|
||||
float HasteModifier = GetHaste() * 0.01f;
|
||||
|
||||
int level = GetLevel();
|
||||
int reuse = TauntReuseTime * 1000; //make this very long since if they dont use it once, they prolly never will
|
||||
@@ -4689,7 +4683,7 @@ void Merc::DoClassAttacks(Mob *target) {
|
||||
}
|
||||
}
|
||||
|
||||
classattack_timer.Start(reuse*HasteModifier/100);
|
||||
classattack_timer.Start(reuse / HasteModifier);
|
||||
}
|
||||
|
||||
bool Merc::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts)
|
||||
|
||||
+153
-48
@@ -1932,6 +1932,7 @@ void Mob::SetZone(uint32 zone_id, uint32 instance_id)
|
||||
{
|
||||
CastToClient()->GetPP().zone_id = zone_id;
|
||||
CastToClient()->GetPP().zoneInstance = instance_id;
|
||||
CastToClient()->Save();
|
||||
}
|
||||
Save();
|
||||
}
|
||||
@@ -2734,12 +2735,29 @@ uint32 Mob::GetZoneID() const {
|
||||
return(zone->GetZoneID());
|
||||
}
|
||||
|
||||
int Mob::GetHaste() {
|
||||
int h = spellbonuses.haste + spellbonuses.hastetype2;
|
||||
int Mob::GetHaste()
|
||||
{
|
||||
// See notes in Client::CalcHaste
|
||||
// Need to check if the effect of inhibit melee differs for NPCs
|
||||
if (spellbonuses.haste < 0) {
|
||||
if (-spellbonuses.haste <= spellbonuses.inhibitmelee)
|
||||
return 100 - spellbonuses.inhibitmelee;
|
||||
else
|
||||
return 100 + spellbonuses.haste;
|
||||
}
|
||||
|
||||
if (spellbonuses.haste == 0 && spellbonuses.inhibitmelee)
|
||||
return 100 - spellbonuses.inhibitmelee;
|
||||
|
||||
int h = 0;
|
||||
int cap = 0;
|
||||
int overhaste = 0;
|
||||
int level = GetLevel();
|
||||
|
||||
if (spellbonuses.haste)
|
||||
h += spellbonuses.haste - spellbonuses.inhibitmelee;
|
||||
if (spellbonuses.hastetype2 && level > 49)
|
||||
h += spellbonuses.hastetype2 > 10 ? 10 : spellbonuses.hastetype2;
|
||||
|
||||
// 26+ no cap, 1-25 10
|
||||
if (level > 25) // 26+
|
||||
h += itembonuses.haste;
|
||||
@@ -2759,21 +2777,13 @@ int Mob::GetHaste() {
|
||||
|
||||
// 51+ 25 (despite there being higher spells...), 1-50 10
|
||||
if (level > 50) // 51+
|
||||
overhaste = spellbonuses.hastetype3 > 25 ? 25 : spellbonuses.hastetype3;
|
||||
h += spellbonuses.hastetype3 > 25 ? 25 : spellbonuses.hastetype3;
|
||||
else // 1-50
|
||||
overhaste = spellbonuses.hastetype3 > 10 ? 10 : spellbonuses.hastetype3;
|
||||
h += spellbonuses.hastetype3 > 10 ? 10 : spellbonuses.hastetype3;
|
||||
|
||||
h += overhaste;
|
||||
h += ExtraHaste; //GM granted haste.
|
||||
|
||||
if (spellbonuses.inhibitmelee) {
|
||||
if (h >= 0)
|
||||
h -= spellbonuses.inhibitmelee;
|
||||
else
|
||||
h -= ((100 + h) * spellbonuses.inhibitmelee / 100);
|
||||
}
|
||||
|
||||
return(h);
|
||||
return 100 + h;
|
||||
}
|
||||
|
||||
void Mob::SetTarget(Mob* mob) {
|
||||
@@ -3030,12 +3040,11 @@ void Mob::TriggerOnCast(uint32 focus_spell, uint32 spell_id, bool aa_trigger)
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::TrySpellTrigger(Mob *target, uint32 spell_id)
|
||||
bool Mob::TrySpellTrigger(Mob *target, uint32 spell_id, int effect)
|
||||
{
|
||||
if(target == nullptr || !IsValidSpell(spell_id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(!target || !IsValidSpell(spell_id))
|
||||
return false;
|
||||
|
||||
int spell_trig = 0;
|
||||
// Count all the percentage chances to trigger for all effects
|
||||
for(int i = 0; i < EFFECT_COUNT; i++)
|
||||
@@ -3054,8 +3063,10 @@ void Mob::TrySpellTrigger(Mob *target, uint32 spell_id)
|
||||
if(MakeRandomInt(0, trig_chance) <= spells[spell_id].base[i])
|
||||
{
|
||||
// If we trigger an effect then its over.
|
||||
SpellFinished(spells[spell_id].base2[i], target, 10, 0, -1, spells[spell_id].ResistDiff);
|
||||
break;
|
||||
if (IsValidSpell(spells[spell_id].base2[i])){
|
||||
SpellFinished(spells[spell_id].base2[i], target, 10, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3069,37 +3080,15 @@ void Mob::TrySpellTrigger(Mob *target, uint32 spell_id)
|
||||
// if the chances don't add to 100, then each effect gets a chance to fire, chance for no trigger as well.
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < EFFECT_COUNT; i++)
|
||||
if(MakeRandomInt(0, 100) <= spells[spell_id].base[effect])
|
||||
{
|
||||
if (spells[spell_id].effectid[i] == SE_SpellTrigger)
|
||||
{
|
||||
if(MakeRandomInt(0, 100) <= spells[spell_id].base[i])
|
||||
{
|
||||
SpellFinished(spells[spell_id].base2[i], target, 10, 0, -1, spells[spell_id].ResistDiff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::TryApplyEffect(Mob *target, uint32 spell_id)
|
||||
{
|
||||
if(target == nullptr || !IsValidSpell(spell_id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i = 0; i < EFFECT_COUNT; i++)
|
||||
{
|
||||
if (spells[spell_id].effectid[i] == SE_ApplyEffect)
|
||||
{
|
||||
if(MakeRandomInt(0, 100) <= spells[spell_id].base[i])
|
||||
{
|
||||
if(target)
|
||||
SpellFinished(spells[spell_id].base2[i], target, 10, 0, -1, spells[spell_id].ResistDiff);
|
||||
if (IsValidSpell(spells[spell_id].base2[effect])){
|
||||
SpellFinished(spells[spell_id].base2[effect], target, 10, 0, -1, spells[spells[spell_id].base2[effect]].ResistDiff);
|
||||
return true; //Only trigger once of these per spell effect.
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Mob::TryTriggerOnValueAmount(bool IsHP, bool IsMana, bool IsEndur, bool IsPet)
|
||||
@@ -5013,3 +5002,119 @@ float Mob::HeadingAngleToMob(Mob *other)
|
||||
return (90.0 - angle + 270.0) * 511.5 * 0.0027777778;
|
||||
}
|
||||
|
||||
int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot)
|
||||
{
|
||||
if (!IsValidSpell(spell_id))
|
||||
return 0;
|
||||
|
||||
if (!identifier)
|
||||
return 0;
|
||||
|
||||
int32 stat = 0;
|
||||
|
||||
if (slot > 0)
|
||||
slot = slot - 1;
|
||||
|
||||
std::string id = identifier;
|
||||
for(int i = 0; i < id.length(); ++i)
|
||||
{
|
||||
id[i] = tolower(id[i]);
|
||||
}
|
||||
|
||||
if (slot < 16){
|
||||
if (id == "classes") {stat = spells[spell_id].classes[slot]; }
|
||||
else if (id == "dieties") {stat = spells[spell_id].deities[slot];}
|
||||
}
|
||||
|
||||
if (slot < 12){
|
||||
if (id == "base") {stat = spells[spell_id].base[slot];}
|
||||
else if (id == "base2") {stat = spells[spell_id].base2[slot];}
|
||||
else if (id == "max") {stat = spells[spell_id].max[slot];}
|
||||
else if (id == "formula") {spells[spell_id].formula[slot];}
|
||||
else if (id == "effectid") {spells[spell_id].effectid[slot];}
|
||||
}
|
||||
|
||||
if (slot < 4){
|
||||
if (id == "components") { spells[spell_id].components[slot];}
|
||||
else if (id == "component_counts") {spells[spell_id].component_counts[slot];}
|
||||
else if (id == "NoexpendReagent") {spells[spell_id].NoexpendReagent[slot];}
|
||||
}
|
||||
|
||||
if (id == "range") {stat = spells[spell_id].range; }
|
||||
else if (id == "aoerange") {stat = spells[spell_id].aoerange;}
|
||||
else if (id == "pushback") {stat = spells[spell_id].pushback;}
|
||||
else if (id == "pushup") {stat = spells[spell_id].pushup;}
|
||||
else if (id == "cast_time") {stat = spells[spell_id].cast_time;}
|
||||
else if (id == "recovery_time") {stat = spells[spell_id].recovery_time;}
|
||||
else if (id == "recast_time") {stat = spells[spell_id].recast_time;}
|
||||
else if (id == "buffdurationformula") {stat = spells[spell_id].buffdurationformula;}
|
||||
else if (id == "buffduration") {stat = spells[spell_id].buffduration;}
|
||||
else if (id == "AEDuration") {stat = spells[spell_id].AEDuration;}
|
||||
else if (id == "mana") {stat = spells[spell_id].mana;}
|
||||
//else if (id == "LightType") {stat = spells[spell_id].LightType;} - Not implemented
|
||||
else if (id == "goodEffect") {stat = spells[spell_id].goodEffect;}
|
||||
else if (id == "Activated") {stat = spells[spell_id].Activated;}
|
||||
else if (id == "resisttype") {stat = spells[spell_id].resisttype;}
|
||||
else if (id == "targettype") {stat = spells[spell_id].targettype;}
|
||||
else if (id == "basedeiff") {stat = spells[spell_id].basediff;}
|
||||
else if (id == "skill") {stat = spells[spell_id].skill;}
|
||||
else if (id == "zonetype") {stat = spells[spell_id].zonetype;}
|
||||
else if (id == "EnvironmentType") {stat = spells[spell_id].EnvironmentType;}
|
||||
else if (id == "TimeOfDay") {stat = spells[spell_id].TimeOfDay;}
|
||||
else if (id == "CastingAnim") {stat = spells[spell_id].CastingAnim;}
|
||||
else if (id == "SpellAffectIndex") {stat = spells[spell_id].SpellAffectIndex; }
|
||||
else if (id == "disallow_sit") {stat = spells[spell_id].disallow_sit; }
|
||||
//else if (id == "spellanim") {stat = spells[spell_id].spellanim; } - Not implemented
|
||||
else if (id == "uninterruptable") {stat = spells[spell_id].uninterruptable; }
|
||||
else if (id == "ResistDiff") {stat = spells[spell_id].ResistDiff; }
|
||||
else if (id == "dot_stacking_exemp") {stat = spells[spell_id].dot_stacking_exempt; }
|
||||
else if (id == "RecourseLink") {stat = spells[spell_id].RecourseLink; }
|
||||
else if (id == "no_partial_resist") {stat = spells[spell_id].no_partial_resist; }
|
||||
else if (id == "short_buff_box") {stat = spells[spell_id].short_buff_box; }
|
||||
else if (id == "descnum") {stat = spells[spell_id].descnum; }
|
||||
else if (id == "effectdescnum") {stat = spells[spell_id].effectdescnum; }
|
||||
else if (id == "npc_no_los") {stat = spells[spell_id].npc_no_los; }
|
||||
else if (id == "reflectable") {stat = spells[spell_id].reflectable; }
|
||||
else if (id == "bonushate") {stat = spells[spell_id].bonushate; }
|
||||
else if (id == "EndurCost") {stat = spells[spell_id].EndurCost; }
|
||||
else if (id == "EndurTimerIndex") {stat = spells[spell_id].EndurTimerIndex; }
|
||||
else if (id == "IsDisciplineBuf") {stat = spells[spell_id].IsDisciplineBuff; }
|
||||
else if (id == "HateAdded") {stat = spells[spell_id].HateAdded; }
|
||||
else if (id == "EndurUpkeep") {stat = spells[spell_id].EndurUpkeep; }
|
||||
else if (id == "numhitstype") {stat = spells[spell_id].numhitstype; }
|
||||
else if (id == "numhits") {stat = spells[spell_id].numhits; }
|
||||
else if (id == "pvpresistbase") {stat = spells[spell_id].pvpresistbase; }
|
||||
else if (id == "pvpresistcalc") {stat = spells[spell_id].pvpresistcalc; }
|
||||
else if (id == "pvpresistcap") {stat = spells[spell_id].pvpresistcap; }
|
||||
else if (id == "spell_category") {stat = spells[spell_id].spell_category; }
|
||||
else if (id == "can_mgb") {stat = spells[spell_id].can_mgb; }
|
||||
else if (id == "dispel_flag") {stat = spells[spell_id].dispel_flag; }
|
||||
else if (id == "MinResist") {stat = spells[spell_id].MinResist; }
|
||||
else if (id == "MaxResist") {stat = spells[spell_id].MaxResist; }
|
||||
else if (id == "viral_targets") {stat = spells[spell_id].viral_targets; }
|
||||
else if (id == "viral_timer") {stat = spells[spell_id].viral_timer; }
|
||||
else if (id == "NimbusEffect") {stat = spells[spell_id].NimbusEffect; }
|
||||
else if (id == "directional_start") {stat = spells[spell_id].directional_start; }
|
||||
else if (id == "directional_end") {stat = spells[spell_id].directional_end; }
|
||||
else if (id == "not_extendable") {stat = spells[spell_id].not_extendable; }
|
||||
else if (id == "suspendable") {stat = spells[spell_id].suspendable; }
|
||||
else if (id == "viral_range") {stat = spells[spell_id].viral_range; }
|
||||
else if (id == "spellgroup") {stat = spells[spell_id].spellgroup; }
|
||||
else if (id == "rank") {stat = spells[spell_id].rank; }
|
||||
else if (id == "powerful_flag") {stat = spells[spell_id].powerful_flag; }
|
||||
else if (id == "CastRestriction") {stat = spells[spell_id].CastRestriction; }
|
||||
else if (id == "AllowRest") {stat = spells[spell_id].AllowRest; }
|
||||
else if (id == "InCombat") {stat = spells[spell_id].InCombat; }
|
||||
else if (id == "OutofCombat") {stat = spells[spell_id].OutofCombat; }
|
||||
else if (id == "aemaxtargets") {stat = spells[spell_id].aemaxtargets; }
|
||||
else if (id == "maxtargets") {stat = spells[spell_id].maxtargets; }
|
||||
else if (id == "persistdeath") {stat = spells[spell_id].persistdeath; }
|
||||
else if (id == "min_dist") {stat = spells[spell_id].min_dist; }
|
||||
else if (id == "min_dist_mod") {stat = spells[spell_id].min_dist_mod; }
|
||||
else if (id == "max_dist") {stat = spells[spell_id].max_dist; }
|
||||
else if (id == "min_range") {stat = spells[spell_id].min_range; }
|
||||
else if (id == "DamageShieldType") {stat = spells[spell_id].DamageShieldType; }
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -205,7 +205,7 @@ public:
|
||||
void SendSpellBarEnable(uint16 spellid);
|
||||
void ZeroCastingVars();
|
||||
virtual void SpellProcess();
|
||||
virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1,
|
||||
virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1,
|
||||
int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF,
|
||||
uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0, uint32 type = 0, int16 *resist_adjust = nullptr);
|
||||
virtual bool DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot = 10, int32 casttime = -1,
|
||||
@@ -526,7 +526,7 @@ public:
|
||||
|
||||
|
||||
//More stuff to sort:
|
||||
virtual bool IsRaidTarget() { return false; };
|
||||
virtual bool IsRaidTarget() const { return false; };
|
||||
virtual bool IsAttackAllowed(Mob *target, bool isSpellAttack = false);
|
||||
bool IsTargeted() const { return (targeted > 0); }
|
||||
inline void IsTargeted(int in_tar) { targeted += in_tar; if(targeted < 0) targeted = 0;}
|
||||
@@ -579,8 +579,7 @@ public:
|
||||
void DoBuffWearOffEffect(uint32 index);
|
||||
void TryTriggerOnCast(uint32 spell_id, bool aa_trigger);
|
||||
void TriggerOnCast(uint32 focus_spell, uint32 spell_id, bool aa_trigger);
|
||||
void TrySpellTrigger(Mob *target, uint32 spell_id);
|
||||
void TryApplyEffect(Mob *target, uint32 spell_id);
|
||||
bool TrySpellTrigger(Mob *target, uint32 spell_id, int effect);
|
||||
void TryTriggerOnValueAmount(bool IsHP = false, bool IsMana = false, bool IsEndur = false, bool IsPet = false);
|
||||
void TryTwincast(Mob *caster, Mob *target, uint32 spell_id);
|
||||
void TrySympatheticProc(Mob *target, uint32 spell_id);
|
||||
@@ -621,6 +620,7 @@ public:
|
||||
void CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster = nullptr);
|
||||
inline int16 GetSpellPowerDistanceMod() const { return SpellPowerDistanceMod; };
|
||||
inline void SetSpellPowerDistanceMod(int16 value) { SpellPowerDistanceMod = value; };
|
||||
int32 GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot = 0);
|
||||
|
||||
void ModSkillDmgTaken(SkillUseTypes skill_num, int value);
|
||||
int16 GetModSkillDmgTaken(const SkillUseTypes skill_num);
|
||||
@@ -684,7 +684,6 @@ public:
|
||||
inline bool GetInvul(void) { return invulnerable; }
|
||||
inline void SetExtraHaste(int Haste) { ExtraHaste = Haste; }
|
||||
virtual int GetHaste();
|
||||
inline float GetPermaHaste() { return GetHaste() ? 100.0f / (1.0f + static_cast<float>(GetHaste()) / 100.0f) : 100.0f; }
|
||||
|
||||
uint8 GetWeaponDamageBonus(const Item_Struct* Weapon);
|
||||
uint16 GetDamageTable(SkillUseTypes skillinuse);
|
||||
@@ -769,6 +768,7 @@ public:
|
||||
inline void StartFleeing() { flee_mode = true; CalculateNewFearpoint(); }
|
||||
void ProcessFlee();
|
||||
void CheckFlee();
|
||||
inline bool IsBlind() { return spellbonuses.IsBlind; }
|
||||
|
||||
inline bool CheckAggro(Mob* other) {return hate_list.IsOnHateList(other);}
|
||||
float CalculateHeadingToTarget(float in_x, float in_y);
|
||||
|
||||
+4
-2
@@ -1040,7 +1040,7 @@ void Mob::AI_Process() {
|
||||
//
|
||||
if(RuleB(Combat, EnableFearPathing)){
|
||||
if(curfp) {
|
||||
if(IsRooted()) {
|
||||
if(IsRooted() || (IsBlind() && CombatRange(hate_list.GetClosest(this)))) {
|
||||
//make sure everybody knows were not moving, for appearance sake
|
||||
if(IsMoving())
|
||||
{
|
||||
@@ -1087,7 +1087,9 @@ void Mob::AI_Process() {
|
||||
|
||||
if (engaged)
|
||||
{
|
||||
if (IsRooted())
|
||||
// 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() || IsBlind())
|
||||
SetTarget(hate_list.GetClosest(this));
|
||||
else
|
||||
{
|
||||
|
||||
@@ -97,8 +97,6 @@ extern Zone* zone;
|
||||
EQStreamFactory eqsf(ZoneStream);
|
||||
npcDecayTimes_Struct npcCorpseDecayTimes[100];
|
||||
TitleManager title_manager;
|
||||
DBAsyncFinishedQueue MTdbafq;
|
||||
DBAsync *dbasync = nullptr;
|
||||
QueryServ *QServ = 0;
|
||||
TaskManager *taskmanager = 0;
|
||||
QuestParserCollection *parse = 0;
|
||||
@@ -168,8 +166,6 @@ int main(int argc, char** argv) {
|
||||
_log(ZONE__INIT_ERR, "Cannot continue without a database connection.");
|
||||
return 1;
|
||||
}
|
||||
dbasync = new DBAsync(&database);
|
||||
dbasync->AddFQ(&MTdbafq);
|
||||
guild_mgr.SetDatabase(&database);
|
||||
|
||||
GuildBanks = nullptr;
|
||||
@@ -444,10 +440,6 @@ int main(int argc, char** argv) {
|
||||
|
||||
}
|
||||
}
|
||||
DBAsyncWork* dbaw = 0;
|
||||
while ((dbaw = MTdbafq.Pop())) {
|
||||
DispatchFinishedDBAsync(dbaw);
|
||||
}
|
||||
if (InterserverTimer.Check()) {
|
||||
InterserverTimer.Start();
|
||||
database.ping();
|
||||
@@ -507,8 +499,6 @@ int main(int argc, char** argv) {
|
||||
//Fix for Linux world server problem.
|
||||
eqsf.Close();
|
||||
worldserver.Disconnect();
|
||||
dbasync->CommitWrites();
|
||||
dbasync->StopThread();
|
||||
safe_delete(taskmanager);
|
||||
command_deinit();
|
||||
safe_delete(parse);
|
||||
|
||||
+333
-221
@@ -965,240 +965,352 @@ NPC* NPC::SpawnNPC(const char* spawncommand, float in_x, float in_y, float in_z,
|
||||
}
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::NPCSpawnDB(uint8 command, const char* zone, uint32 zone_version, Client *c, NPC* spawn, uint32 extra) {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
uint32 tmp = 0;
|
||||
uint32 tmp2 = 0;
|
||||
uint32 ZoneDatabase::CreateNewNPCCommand(const char* zone, uint32 zone_version,Client *client, NPC* spawn, uint32 extra) {
|
||||
|
||||
uint32 npc_type_id = 0;
|
||||
|
||||
if (extra && client && client->GetZoneID())
|
||||
{
|
||||
// Set an npc_type ID within the standard range for the current zone if possible (zone_id * 1000)
|
||||
int starting_npc_id = client->GetZoneID() * 1000;
|
||||
|
||||
std::string query = StringFormat("SELECT MAX(id) FROM npc_types WHERE id >= %i AND id < %i",
|
||||
starting_npc_id, starting_npc_id + 1000);
|
||||
auto results = QueryDatabase(query);
|
||||
if (results.Success()) {
|
||||
if (results.RowCount() != 0)
|
||||
{
|
||||
auto row = results.begin();
|
||||
npc_type_id = atoi(row[0]) + 1;
|
||||
// Prevent the npc_type id from exceeding the range for this zone
|
||||
if (npc_type_id >= (starting_npc_id + 1000))
|
||||
npc_type_id = 0;
|
||||
}
|
||||
else // No npc_type IDs set in this range yet
|
||||
npc_type_id = starting_npc_id;
|
||||
}
|
||||
}
|
||||
|
||||
char tmpstr[64];
|
||||
EntityList::RemoveNumbers(strn0cpy(tmpstr, spawn->GetName(), sizeof(tmpstr)));
|
||||
std::string query;
|
||||
if (npc_type_id)
|
||||
{
|
||||
query = StringFormat("INSERT INTO npc_types (id, name, level, race, class, hp, gender, "
|
||||
"texture, helmtexture, size, loottable_id, merchant_id, face, "
|
||||
"runspeed, prim_melee_type, sec_melee_type) "
|
||||
"VALUES(%i, \"%s\" , %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
|
||||
npc_type_id, tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
|
||||
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
|
||||
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
|
||||
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
npc_type_id = results.LastInsertedID();
|
||||
}
|
||||
else
|
||||
{
|
||||
query = StringFormat("INSERT INTO npc_types (name, level, race, class, hp, gender, "
|
||||
"texture, helmtexture, size, loottable_id, merchant_id, face, "
|
||||
"runspeed, prim_melee_type, sec_melee_type) "
|
||||
"VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
|
||||
tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
|
||||
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
|
||||
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
|
||||
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
npc_type_id = results.LastInsertedID();
|
||||
}
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
query = StringFormat("INSERT INTO spawngroup (id, name) VALUES(%i, '%s-%s')", 0, zone, spawn->GetName());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
uint32 spawngroupid = results.LastInsertedID();
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
|
||||
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
|
||||
zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), 1200,
|
||||
spawn->GetHeading(), spawngroupid);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) VALUES(%i, %i, %i)",
|
||||
spawngroupid, npc_type_id, 100);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::AddNewNPCSpawnGroupCommand(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 respawnTime) {
|
||||
uint32 last_insert_id = 0;
|
||||
|
||||
std::string query = StringFormat("INSERT INTO spawngroup (name) VALUES('%s%s%i')",
|
||||
zone, spawn->GetName(), Timer::GetCurrentTime());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "CreateNewNPCSpawnGroupCommand Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
last_insert_id = results.LastInsertedID();
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
uint32 respawntime = 0;
|
||||
uint32 spawnid = 0;
|
||||
if (respawnTime)
|
||||
respawntime = respawnTime;
|
||||
else if(spawn->respawn2 && spawn->respawn2->RespawnTimer() != 0)
|
||||
respawntime = spawn->respawn2->RespawnTimer();
|
||||
else
|
||||
respawntime = 1200;
|
||||
|
||||
query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
|
||||
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
|
||||
zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), respawntime,
|
||||
spawn->GetHeading(), last_insert_id);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "CreateNewNPCSpawnGroupCommand Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
spawnid = results.LastInsertedID();
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
query = StringFormat("INSERT INTO spawnentry (spawngroupID, npcID, chance) VALUES(%i, %i, %i)",
|
||||
last_insert_id, spawn->GetNPCTypeID(), 100);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "CreateNewNPCSpawnGroupCommand Error: %s %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
return spawnid;
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::UpdateNPCTypeAppearance(Client *client, NPC* spawn) {
|
||||
|
||||
std::string query = StringFormat("UPDATE npc_types SET name = \"%s\", level = %i, race = %i, class = %i, "
|
||||
"hp = %i, gender = %i, texture = %i, helmtexture = %i, size = %i, "
|
||||
"loottable_id = %i, merchant_id = %i, face = %i, WHERE id = %i",
|
||||
spawn->GetName(), spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
|
||||
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
|
||||
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
|
||||
spawn->MerchantType, spawn->GetNPCTypeID());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success() && client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
return results.Success() == true? 1: 0;
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::DeleteSpawnLeaveInNPCTypeTable(const char* zone, Client *client, NPC* spawn) {
|
||||
uint32 id = 0;
|
||||
uint32 spawngroupID = 0;
|
||||
|
||||
std::string query = StringFormat("SELECT id, spawngroupID FROM spawn2 WHERE "
|
||||
"zone='%s' AND spawngroupID=%i", zone, spawn->GetSp2());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
if (row[0])
|
||||
id = atoi(row[0]);
|
||||
|
||||
if (row[1])
|
||||
spawngroupID = atoi(row[1]);
|
||||
|
||||
query = StringFormat("DELETE FROM spawn2 WHERE id = '%i'", id);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
query = StringFormat("DELETE FROM spawngroup WHERE id = '%i'", spawngroupID);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
query = StringFormat("DELETE FROM spawnentry WHERE spawngroupID = '%i'", spawngroupID);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::DeleteSpawnRemoveFromNPCTypeTable(const char* zone, uint32 zone_version, Client *client, NPC* spawn) {
|
||||
|
||||
uint32 id = 0;
|
||||
uint32 spawngroupID = 0;
|
||||
|
||||
std::string query = StringFormat("SELECT id, spawngroupID FROM spawn2 WHERE zone = '%s' "
|
||||
"AND version = %u AND spawngroupID = %i",
|
||||
zone, zone_version, spawn->GetSp2());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if (results.RowCount() == 0)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
if (row[0])
|
||||
id = atoi(row[0]);
|
||||
|
||||
if (row[1])
|
||||
spawngroupID = atoi(row[1]);
|
||||
|
||||
query = StringFormat("DELETE FROM spawn2 WHERE id = '%i'", id);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
query = StringFormat("DELETE FROM spawngroup WHERE id = '%i'", spawngroupID);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
query = StringFormat("DELETE FROM spawnentry WHERE spawngroupID = '%i'", spawngroupID);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
query = StringFormat("DELETE FROM npc_types WHERE id = '%i'", spawn->GetNPCTypeID());
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::AddSpawnFromSpawnGroup(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 spawnGroupID) {
|
||||
|
||||
uint32 last_insert_id = 0;
|
||||
std::string query = StringFormat("INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) "
|
||||
"VALUES('%s', %u, %f, %f, %f, %i, %f, %i)",
|
||||
zone, zone_version, client->GetX(), client->GetY(), client->GetZ(),
|
||||
120, client->GetHeading(), spawnGroupID);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::AddNPCTypes(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 spawnGroupID) {
|
||||
|
||||
uint32 npc_type_id;
|
||||
char numberlessName[64];
|
||||
|
||||
EntityList::RemoveNumbers(strn0cpy(numberlessName, spawn->GetName(), sizeof(numberlessName)));
|
||||
std::string query = StringFormat("INSERT INTO npc_types (name, level, race, class, hp, gender, "
|
||||
"texture, helmtexture, size, loottable_id, merchant_id, face, "
|
||||
"runspeed, prim_melee_type, sec_melee_type) "
|
||||
"VALUES(\"%s\", %i, %i, %i, %i, %i, %i, %i, %f, %i, %i, %i, %f, %i, %i)",
|
||||
numberlessName, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(),
|
||||
spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(),
|
||||
spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(),
|
||||
spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return 0;
|
||||
npc_type_id = results.LastInsertedID();
|
||||
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
if(client)
|
||||
client->Message(0, "%s npc_type ID %i created successfully!", numberlessName, npc_type_id);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32 ZoneDatabase::NPCSpawnDB(uint8 command, const char* zone, uint32 zone_version, Client *c, NPC* spawn, uint32 extra) {
|
||||
|
||||
switch (command) {
|
||||
case 0: { // Create a new NPC and add all spawn related data
|
||||
uint32 npc_type_id = 0;
|
||||
uint32 spawngroupid;
|
||||
if (extra && c && c->GetZoneID())
|
||||
{
|
||||
// Set an npc_type ID within the standard range for the current zone if possible (zone_id * 1000)
|
||||
int starting_npc_id = c->GetZoneID() * 1000;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT MAX(id) FROM npc_types WHERE id >= %i AND id < %i", starting_npc_id, (starting_npc_id + 1000)), errbuf, &result)) {
|
||||
row = mysql_fetch_row(result);
|
||||
if(row)
|
||||
{
|
||||
if (row[0])
|
||||
{
|
||||
npc_type_id = atoi(row[0]) + 1;
|
||||
// Prevent the npc_type id from exceeding the range for this zone
|
||||
if (npc_type_id >= (starting_npc_id + 1000))
|
||||
{
|
||||
npc_type_id = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// row[0] is nullptr - No npc_type IDs set in this range yet
|
||||
npc_type_id = starting_npc_id;
|
||||
}
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
mysql_free_result(result);
|
||||
}
|
||||
}
|
||||
char tmpstr[64];
|
||||
EntityList::RemoveNumbers(strn0cpy(tmpstr, spawn->GetName(), sizeof(tmpstr)));
|
||||
if (npc_type_id)
|
||||
{
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO npc_types (id, name, level, race, class, hp, gender, texture, helmtexture, size, loottable_id, merchant_id, face, runspeed, prim_melee_type, sec_melee_type) values(%i,\"%s\",%i,%i,%i,%i,%i,%i,%i,%f,%i,%i,%i,%f,%i,%i)", npc_type_id, tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(), spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28), errbuf, 0, 0, &npc_type_id)) {
|
||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO npc_types (name, level, race, class, hp, gender, texture, helmtexture, size, loottable_id, merchant_id, face, runspeed, prim_melee_type, sec_melee_type) values(\"%s\",%i,%i,%i,%i,%i,%i,%i,%f,%i,%i,%i,%f,%i,%i)", tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(), spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28), errbuf, 0, 0, &npc_type_id)) {
|
||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
snprintf(tmpstr, sizeof(tmpstr), "%s-%s", zone, spawn->GetName());
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawngroup (id, name) values(%i, '%s')", tmp, tmpstr), errbuf, 0, 0, &spawngroupid)) {
|
||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) values('%s', %u, %f, %f, %f, %i, %f, %i)", zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), 1200, spawn->GetHeading(), spawngroupid), errbuf, 0, 0, &tmp)) {
|
||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawnentry (spawngroupID, npcID, chance) values(%i, %i, %i)", spawngroupid, npc_type_id, 100), errbuf, 0)) {
|
||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
return true;
|
||||
break;
|
||||
return CreateNewNPCCommand(zone, zone_version, c, spawn, extra);
|
||||
}
|
||||
case 1:{ // Add new spawn group and spawn point for an existing NPC Type ID
|
||||
tmp2 = spawn->GetNPCTypeID();
|
||||
char tmpstr[64];
|
||||
snprintf(tmpstr, sizeof(tmpstr), "%s%s%i", zone, spawn->GetName(),Timer::GetCurrentTime());
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawngroup (name) values('%s')", tmpstr), errbuf, 0, 0, &last_insert_id)) {
|
||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
|
||||
uint32 respawntime = 0;
|
||||
uint32 spawnid = 0;
|
||||
if (extra)
|
||||
respawntime = extra;
|
||||
else if(spawn->respawn2 && spawn->respawn2->RespawnTimer() != 0)
|
||||
respawntime = spawn->respawn2->RespawnTimer();
|
||||
else
|
||||
respawntime = 1200;
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) values('%s', %u, %f, %f, %f, %i, %f, %i)", zone, zone_version, spawn->GetX(), spawn->GetY(), spawn->GetZ(), respawntime, spawn->GetHeading(), last_insert_id), errbuf, 0, 0, &spawnid)) {
|
||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawnentry (spawngroupID, npcID, chance) values(%i, %i, %i)", last_insert_id, tmp2, 100), errbuf, 0)) {
|
||||
LogFile->write(EQEMuLog::Error, "NPCSpawnDB Error: %s %s", query, errbuf);
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
return spawnid;
|
||||
break;
|
||||
return AddNewNPCSpawnGroupCommand(zone, zone_version, c, spawn, extra);
|
||||
}
|
||||
case 2: { // Update npc_type appearance and other data on targeted spawn
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE npc_types SET name=\"%s\", level=%i, race=%i, class=%i, hp=%i, gender=%i, texture=%i, helmtexture=%i, size=%i, loottable_id=%i, merchant_id=%i, face=%i, WHERE id=%i", spawn->GetName(), spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(), spawn->MerchantType, spawn->GetNPCTypeID()), errbuf, 0)) {
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
safe_delete_array(query);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
return UpdateNPCTypeAppearance(c, spawn);
|
||||
}
|
||||
case 3: { // delete spawn from spawning, but leave in npc_types table
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "SELECT id,spawngroupID from spawn2 where zone='%s' AND spawngroupID=%i", zone, spawn->GetSp2()), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
return 0;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
if (row == nullptr) return false;
|
||||
if (row[0]) tmp = atoi(row[0]);
|
||||
if (row[1]) tmp2 = atoi(row[1]);
|
||||
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM spawn2 WHERE id='%i'", tmp), errbuf,0)) {
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM spawngroup WHERE id='%i'", tmp2), errbuf,0)) {
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM spawnentry WHERE spawngroupID='%i'", tmp2), errbuf,0)) {
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
return true;
|
||||
|
||||
|
||||
break;
|
||||
return DeleteSpawnLeaveInNPCTypeTable(zone, c, spawn);
|
||||
}
|
||||
case 4: { //delete spawn from DB (including npc_type)
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "SELECT id,spawngroupID from spawn2 where zone='%s' AND version=%u AND spawngroupID=%i", zone, zone_version, spawn->GetSp2()), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
return(0);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
if (row == nullptr) return false;
|
||||
if (row[0]) tmp = atoi(row[0]);
|
||||
if (row[1]) tmp2 = atoi(row[1]);
|
||||
mysql_free_result(result);
|
||||
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM spawn2 WHERE id='%i'", tmp), errbuf,0)) {
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM spawngroup WHERE id='%i'", tmp2), errbuf,0)) {
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM spawnentry WHERE spawngroupID='%i'", tmp2), errbuf,0)) {
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "DELETE FROM npc_types WHERE id='%i'", spawn->GetNPCTypeID()), errbuf,0)) {
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
return true;
|
||||
break;
|
||||
return DeleteSpawnRemoveFromNPCTypeTable(zone, zone_version, c, spawn);
|
||||
}
|
||||
case 5: { // add a spawn from spawngroup
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO spawn2 (zone, version, x, y, z, respawntime, heading, spawngroupID) values('%s', %u, %f, %f, %f, %i, %f, %i)", zone, zone_version, c->GetX(), c->GetY(), c->GetZ(), 120, c->GetHeading(), extra), errbuf, 0, 0, &tmp)) {
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
return AddSpawnFromSpawnGroup(zone, zone_version, c, spawn, extra);
|
||||
}
|
||||
case 6: { // add npc_type
|
||||
uint32 npc_type_id;
|
||||
char tmpstr[64];
|
||||
EntityList::RemoveNumbers(strn0cpy(tmpstr, spawn->GetName(), sizeof(tmpstr)));
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "INSERT INTO npc_types (name, level, race, class, hp, gender, texture, helmtexture, size, loottable_id, merchant_id, face, runspeed, prim_melee_type, sec_melee_type) values(\"%s\",%i,%i,%i,%i,%i,%i,%i,%f,%i,%i,%i,%f,%i,%i)", tmpstr, spawn->GetLevel(), spawn->GetRace(), spawn->GetClass(), spawn->GetMaxHP(), spawn->GetGender(), spawn->GetTexture(), spawn->GetHelmTexture(), spawn->GetSize(), spawn->GetLoottableID(), spawn->MerchantType, 0, spawn->GetRunspeed(), 28, 28), errbuf, 0, 0, &npc_type_id)) {
|
||||
safe_delete(query);
|
||||
return false;
|
||||
}
|
||||
if(c) c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
if(c) c->Message(0, "%s npc_type ID %i created successfully!", tmpstr, npc_type_id);
|
||||
return true;
|
||||
break;
|
||||
return AddNPCTypes(zone, zone_version, c, spawn, extra);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -1743,7 +1855,7 @@ void NPC::FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho)
|
||||
else
|
||||
ns->spawn.IsMercenary = 0;
|
||||
}
|
||||
|
||||
|
||||
//Not recommended if using above (However, this will work better on older clients).
|
||||
if (RuleB(Pets, UnTargetableSwarmPet)) {
|
||||
if(GetOwnerID() || GetSwarmOwner()) {
|
||||
|
||||
+8
-4
@@ -136,10 +136,6 @@ public:
|
||||
|
||||
int32 GetActSpellDamage(uint16 spell_id, int32 value, Mob* target = nullptr);
|
||||
int32 GetActSpellHealing(uint16 spell_id, int32 value, Mob* target = nullptr);
|
||||
inline void SetSpellFocusDMG(int32 NewSpellFocusDMG) {SpellFocusDMG = NewSpellFocusDMG;}
|
||||
inline void SetSpellFocusHeal(int32 NewSpellFocusHeal) {SpellFocusHeal = NewSpellFocusHeal;}
|
||||
int32 SpellFocusDMG;
|
||||
int32 SpellFocusHeal;
|
||||
|
||||
virtual void SetTarget(Mob* mob);
|
||||
virtual uint16 GetSkill(SkillUseTypes skill_num) const { if (skill_num <= HIGHEST_SKILL) { return skills[skill_num]; } return 0; }
|
||||
@@ -387,6 +383,12 @@ public:
|
||||
|
||||
inline void SetHealScale(float amt) { healscale = amt; }
|
||||
inline float GetHealScale() { return healscale; }
|
||||
|
||||
inline void SetSpellFocusDMG(int32 NewSpellFocusDMG) {SpellFocusDMG = NewSpellFocusDMG;}
|
||||
inline int32 GetSpellFocusDMG() const { return SpellFocusDMG;}
|
||||
|
||||
inline void SetSpellFocusHeal(int32 NewSpellFocusHeal) {SpellFocusHeal = NewSpellFocusHeal;}
|
||||
inline int32 GetSpellFocusHeal() const {return SpellFocusHeal;}
|
||||
|
||||
uint32 GetSpawnKillCount();
|
||||
int GetScore();
|
||||
@@ -452,6 +454,8 @@ protected:
|
||||
uint32 npc_mana;
|
||||
float spellscale;
|
||||
float healscale;
|
||||
int32 SpellFocusDMG;
|
||||
int32 SpellFocusHeal;
|
||||
|
||||
//pet crap:
|
||||
uint16 pet_spell_id;
|
||||
|
||||
@@ -5072,6 +5072,35 @@ XS(XS_Client_UpdateTaskActivity)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Client_GetTaskActivityDoneCount); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_GetTaskActivityDoneCount)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 3)
|
||||
Perl_croak(aTHX_ "Usage: Client::GetTaskActivityDoneCount(THIS, TaskID, ActivityID)");
|
||||
{
|
||||
Client * THIS;
|
||||
int RETVAL;
|
||||
int TaskID = (int)SvIV(ST(1));
|
||||
int ActivityID = (int)SvIV(ST(2));
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Client")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Client *, tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Client");
|
||||
if (THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
|
||||
RETVAL = THIS->GetTaskActivityDoneCountFromTaskID(TaskID, ActivityID);
|
||||
XSprePUSH; PUSHi((IV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Client_AssignTask); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_AssignTask)
|
||||
{
|
||||
@@ -5991,6 +6020,58 @@ XS(XS_Client_SendMarqueeMessage)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Client_SendColoredText); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_SendColoredText)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 3)
|
||||
Perl_croak(aTHX_ "Usage: Client::SendColoredText(color, message)");
|
||||
{
|
||||
Client * THIS;
|
||||
uint32 color = (uint32)SvUV(ST(1));
|
||||
std::string msg = (std::string)SvPV_nolen(ST(2));
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Client")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Client *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Client");
|
||||
if(THIS == NULL)
|
||||
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||
|
||||
THIS->SendColoredText(color, msg);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_Client_SendSpellAnim); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Client_SendSpellAnim)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 3)
|
||||
Perl_croak(aTHX_ "Usage: SendSpellAnim(uint16 spell_id, uint32 seq)");
|
||||
{
|
||||
Client * THIS;
|
||||
uint16 targetid = (uint16)SvUV(ST(1));
|
||||
uint16 spell_id = (uint16)SvUV(ST(2));
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Client")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Client *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Client");
|
||||
if(THIS == NULL)
|
||||
Perl_croak(aTHX_ "THIS is NULL, avoiding crash.");
|
||||
|
||||
THIS->SendSpellAnim(targetid,spell_id);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
@@ -6199,6 +6280,7 @@ XS(boot_Client)
|
||||
newXSproto(strcpy(buf, "IsTaskCompleted"), XS_Client_IsTaskCompleted, file, "$$");
|
||||
newXSproto(strcpy(buf, "IsTaskActive"), XS_Client_IsTaskActive, file, "$$");
|
||||
newXSproto(strcpy(buf, "IsTaskActivityActive"), XS_Client_IsTaskActivityActive, file, "$$$");
|
||||
newXSproto(strcpy(buf, "GetTaskActivityDoneCount"), XS_Client_GetTaskActivityDoneCount, file, "$$$");
|
||||
newXSproto(strcpy(buf, "GetCorpseCount"), XS_Client_GetCorpseCount, file, "$");
|
||||
newXSproto(strcpy(buf, "GetCorpseID"), XS_Client_GetCorpseID, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetCorpseItemAt"), XS_Client_GetCorpseItemAt, file, "$$$");
|
||||
@@ -6229,6 +6311,9 @@ XS(boot_Client)
|
||||
newXSproto(strcpy(buf, "SendTargetCommand"), XS_Client_SendTargetCommand, file, "$$");
|
||||
newXSproto(strcpy(buf, "ExpeditionMessage"), XS_Client_ExpeditionMessage, file, "$$$");
|
||||
newXSproto(strcpy(buf, "SendMarqueeMessage"), XS_Client_SendMarqueeMessage, file, "$$$$$$$");
|
||||
newXSproto(strcpy(buf, "SendColoredText"), XS_Client_SendColoredText, file, "$$$");
|
||||
newXSproto(strcpy(buf, "SendSpellAnim"), XS_Client_SendSpellAnim, file, "$$$");
|
||||
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
|
||||
@@ -8137,6 +8137,39 @@ XS(XS_Mob_GetFlurryChance)
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_Mob_GetSpellStat); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_Mob_GetSpellStat)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items < 3 || items > 4)
|
||||
Perl_croak(aTHX_ "Usage: Mob::GetSpellStat(THIS, itemid, stat, slot)");
|
||||
{
|
||||
Mob * THIS;
|
||||
int32 RETVAL;
|
||||
uint32 spellid = (uint32)SvUV(ST(1));
|
||||
Const_char * stat = (Const_char *)SvPV_nolen(ST(2));
|
||||
uint8 slot = (uint8)SvUV(ST(3));
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "Mob")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(Mob *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type Mob");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (items > 4) { slot = 0; }
|
||||
|
||||
|
||||
RETVAL = THIS->GetSpellStat(spellid, stat, slot);
|
||||
XSprePUSH; PUSHi((IV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
@@ -8436,6 +8469,7 @@ XS(boot_Mob)
|
||||
newXSproto(strcpy(buf, "IsMeleeDisabled"), XS_Mob_IsMeleeDisabled, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetFlurryChance"), XS_Mob_SetFlurryChance, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetFlurryChance"), XS_Mob_GetFlurryChance, file, "$");
|
||||
newXSproto(strcpy(buf, "GetSpellStat"), XS_Mob_GetSpellStat, file, "$$$$");
|
||||
|
||||
XSRETURN_YES;
|
||||
}
|
||||
|
||||
+56
-2
@@ -1991,6 +1991,32 @@ XS(XS_NPC_SetSpellFocusDMG)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_NPC_GetSpellFocusDMG); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_NPC_GetSpellFocusDMG)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: NPC::GetSpellFocusDMG(THIS)");
|
||||
{
|
||||
NPC * THIS;
|
||||
int32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "NPC")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(NPC *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetSpellFocusDMG();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_NPC_SetSpellFocusHeal); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_NPC_SetSpellFocusHeal)
|
||||
{
|
||||
@@ -2015,6 +2041,32 @@ XS(XS_NPC_SetSpellFocusHeal)
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS_NPC_GetSpellFocusHeal); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_NPC_GetSpellFocusHeal)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: NPC::GetSpellFocusHeal(THIS)");
|
||||
{
|
||||
NPC * THIS;
|
||||
int32 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
if (sv_derived_from(ST(0), "NPC")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(NPC *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type NPC");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->GetSpellFocusHeal();
|
||||
XSprePUSH; PUSHu((UV)RETVAL);
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_NPC_GetSlowMitigation); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_NPC_GetSlowMitigation)
|
||||
{
|
||||
@@ -2286,8 +2338,10 @@ XS(boot_NPC)
|
||||
newXSproto(strcpy(buf, "RemoveAISpell"), XS_NPC_RemoveSpellFromNPCList, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetSpellFocusDMG"), XS_NPC_SetSpellFocusDMG, file, "$$");
|
||||
newXSproto(strcpy(buf, "SetSpellFocusHeal"), XS_NPC_SetSpellFocusHeal, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetSlowMitigation"), XS_NPC_GetAttackSpeed, file, "$");
|
||||
newXSproto(strcpy(buf, "GetAttackSpeed"), XS_NPC_GetSlowMitigation, file, "$");
|
||||
newXSproto(strcpy(buf, "GetSpellFocusDMG"), XS_NPC_GetSpellFocusDMG, file, "$");
|
||||
newXSproto(strcpy(buf, "GetSpellFocusHeal"), XS_NPC_GetSpellFocusHeal, file, "$");
|
||||
newXSproto(strcpy(buf, "GetSlowMitigation"), XS_NPC_GetSlowMitigation, file, "$");
|
||||
newXSproto(strcpy(buf, "GetAttackSpeed"), XS_NPC_GetAttackSpeed, file, "$");
|
||||
newXSproto(strcpy(buf, "GetAccuracyRating"), XS_NPC_GetAccuracyRating, file, "$");
|
||||
newXSproto(strcpy(buf, "GetSpawnKillCount"), XS_NPC_GetSpawnKillCount, file, "$");
|
||||
newXSproto(strcpy(buf, "GetScore"), XS_NPC_GetScore, file, "$");
|
||||
|
||||
+166
-189
@@ -172,7 +172,7 @@ void QuestManager::EndQuest() {
|
||||
cur = QTimerList.erase(cur);
|
||||
else
|
||||
++cur;
|
||||
}
|
||||
}
|
||||
run.owner->Depop();
|
||||
}
|
||||
quests_running_.pop();
|
||||
@@ -447,7 +447,7 @@ void QuestManager::settimer(const char *timer_name, int seconds) {
|
||||
|
||||
end = QTimerList.end();
|
||||
while (cur != end) {
|
||||
if(cur->mob && cur->mob == owner && cur->name == timer_name)
|
||||
if(cur->mob && cur->mob == owner && cur->name == timer_name)
|
||||
{
|
||||
cur->Timer_.Enable();
|
||||
cur->Timer_.Start(seconds * 1000, false);
|
||||
@@ -471,7 +471,7 @@ void QuestManager::settimerMS(const char *timer_name, int milliseconds) {
|
||||
|
||||
end = QTimerList.end();
|
||||
while (cur != end) {
|
||||
if(cur->mob && cur->mob == owner && cur->name == timer_name)
|
||||
if(cur->mob && cur->mob == owner && cur->name == timer_name)
|
||||
{
|
||||
cur->Timer_.Enable();
|
||||
cur->Timer_.Start(milliseconds, false);
|
||||
@@ -946,7 +946,7 @@ uint16 QuestManager::traindiscs(uint8 max_level, uint8 min_level) {
|
||||
uint16 count;
|
||||
uint16 curspell;
|
||||
|
||||
uint16 Char_ID = initiator->CharacterID();
|
||||
uint32 Char_ID = initiator->CharacterID();
|
||||
bool SpellGlobalRule = RuleB(Spells, EnableSpellGlobals);
|
||||
bool SpellGlobalCheckResult = 0;
|
||||
|
||||
@@ -960,7 +960,7 @@ uint16 QuestManager::traindiscs(uint8 max_level, uint8 min_level) {
|
||||
spells[curspell].skill != 52 &&
|
||||
( !RuleB(Spells, UseCHAScribeHack) || spells[curspell].effectid[EFFECT_COUNT - 1] != 10 )
|
||||
)
|
||||
{
|
||||
{
|
||||
if(IsDiscipline(curspell)){
|
||||
//we may want to come up with a function like Client::GetNextAvailableSpellBookSlot() to help speed this up a little
|
||||
for(uint32 r = 0; r < MAX_PP_DISCIPLINES; r++) {
|
||||
@@ -974,18 +974,20 @@ uint16 QuestManager::traindiscs(uint8 max_level, uint8 min_level) {
|
||||
SpellGlobalCheckResult = initiator->SpellGlobalCheck(curspell, Char_ID);
|
||||
if (SpellGlobalCheckResult) {
|
||||
initiator->GetPP().disciplines.values[r] = curspell;
|
||||
database.SaveCharacterDisc(Char_ID, r, curspell);
|
||||
initiator->SendDisciplineUpdate();
|
||||
initiator->Message(0, "You have learned a new discipline!");
|
||||
count++; //success counter
|
||||
}
|
||||
break; //continue the 1st loop
|
||||
break; //continue the 1st loop
|
||||
}
|
||||
else {
|
||||
initiator->GetPP().disciplines.values[r] = curspell;
|
||||
initiator->SendDisciplineUpdate();
|
||||
initiator->Message(0, "You have learned a new discipline!");
|
||||
count++; //success counter
|
||||
break; //continue the 1st loop
|
||||
initiator->GetPP().disciplines.values[r] = curspell;
|
||||
database.SaveCharacterDisc(Char_ID, r, curspell);
|
||||
initiator->SendDisciplineUpdate();
|
||||
initiator->Message(0, "You have learned a new discipline!");
|
||||
count++; //success counter
|
||||
break; //continue the 1st loop
|
||||
}
|
||||
} //if we get to this point, there's already a discipline in this slot, so we skip it
|
||||
}
|
||||
@@ -1308,7 +1310,7 @@ void QuestManager::setglobal(const char *varname, const char *newvalue, int opti
|
||||
|
||||
if (initiator && initiator->IsClient()){ // some events like waypoint and spawn don't have a player involved
|
||||
qgCharid=initiator->CharacterID();
|
||||
}
|
||||
}
|
||||
else {
|
||||
qgCharid=-qgNpcid; // make char id negative npc id as a fudge
|
||||
}
|
||||
@@ -1335,81 +1337,69 @@ void QuestManager::setglobal(const char *varname, const char *newvalue, int opti
|
||||
|
||||
/* Inserts global variable into quest_globals table */
|
||||
int QuestManager::InsertQuestGlobal(int charid, int npcid, int zoneid, const char *varname, const char *varvalue, int duration) {
|
||||
char *query = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
// Make duration string either "unix_timestamp(now()) + xxx" or "NULL"
|
||||
std::stringstream duration_ss;
|
||||
if (duration == INT_MAX) {
|
||||
duration_ss << "NULL";
|
||||
}
|
||||
else {
|
||||
duration_ss << "unix_timestamp(now()) + " << duration;
|
||||
}
|
||||
std::string durationText = (duration == INT_MAX)? "NULL": StringFormat("unix_timestamp(now()) + %i", duration);
|
||||
|
||||
/*
|
||||
NOTE: this should be escaping the contents of arglist
|
||||
npcwise a malicious script can arbitrarily alter the DB
|
||||
*/
|
||||
uint32 last_id = 0;
|
||||
if (!database.RunQuery(query, MakeAnyLenString(&query,
|
||||
"REPLACE INTO quest_globals (charid, npcid, zoneid, name, value, expdate)"
|
||||
"VALUES (%i, %i, %i, '%s', '%s', %s)",
|
||||
charid, npcid, zoneid, varname, varvalue, duration_ss.str().c_str()
|
||||
), errbuf, nullptr, nullptr, &last_id))
|
||||
{
|
||||
std::cerr << "setglobal error inserting " << varname << " : " << errbuf << std::endl;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
if(zone) {
|
||||
/* Delete existing qglobal data and update zone processes */
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
|
||||
ServerQGlobalDelete_Struct *qgd = (ServerQGlobalDelete_Struct*)pack->pBuffer;
|
||||
qgd->npc_id = npcid;
|
||||
qgd->char_id = charid;
|
||||
qgd->zone_id = zoneid;
|
||||
qgd->from_zone_id = zone->GetZoneID();
|
||||
qgd->from_instance_id = zone->GetInstanceID();
|
||||
strcpy(qgd->name, varname);
|
||||
std::string query = StringFormat("REPLACE INTO quest_globals "
|
||||
"(charid, npcid, zoneid, name, value, expdate)"
|
||||
"VALUES (%i, %i, %i, '%s', '%s', %s)",
|
||||
charid, npcid, zoneid, varname, varvalue, durationText.c_str());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
std::cerr << "setglobal error inserting " << varname << " : " << results.ErrorMessage() << std::endl;
|
||||
|
||||
entity_list.DeleteQGlobal(std::string((char*)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id);
|
||||
zone->DeleteQGlobal(std::string((char*)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id);
|
||||
if(!zone)
|
||||
return 0;
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
/* Delete existing qglobal data and update zone processes */
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
|
||||
ServerQGlobalDelete_Struct *qgd = (ServerQGlobalDelete_Struct*)pack->pBuffer;
|
||||
qgd->npc_id = npcid;
|
||||
qgd->char_id = charid;
|
||||
qgd->zone_id = zoneid;
|
||||
qgd->from_zone_id = zone->GetZoneID();
|
||||
qgd->from_instance_id = zone->GetInstanceID();
|
||||
strcpy(qgd->name, varname);
|
||||
|
||||
/* Create new qglobal data and update zone processes */
|
||||
pack = new ServerPacket(ServerOP_QGlobalUpdate, sizeof(ServerQGlobalUpdate_Struct));
|
||||
ServerQGlobalUpdate_Struct *qgu = (ServerQGlobalUpdate_Struct*)pack->pBuffer;
|
||||
qgu->npc_id = npcid;
|
||||
qgu->char_id = charid;
|
||||
qgu->zone_id = zoneid;
|
||||
if(duration == INT_MAX) {
|
||||
qgu->expdate = 0xFFFFFFFF;
|
||||
}
|
||||
else {
|
||||
qgu->expdate = Timer::GetTimeSeconds() + duration;
|
||||
}
|
||||
strcpy((char*)qgu->name, varname);
|
||||
strn0cpy((char*)qgu->value, varvalue, 128);
|
||||
qgu->id = last_id;
|
||||
qgu->from_zone_id = zone->GetZoneID();
|
||||
qgu->from_instance_id = zone->GetInstanceID();
|
||||
entity_list.DeleteQGlobal(std::string((char*)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id);
|
||||
zone->DeleteQGlobal(std::string((char*)qgd->name), qgd->npc_id, qgd->char_id, qgd->zone_id);
|
||||
|
||||
QGlobal temp;
|
||||
temp.npc_id = npcid;
|
||||
temp.char_id = charid;
|
||||
temp.zone_id = zoneid;
|
||||
temp.expdate = qgu->expdate;
|
||||
temp.name.assign(qgu->name);
|
||||
temp.value.assign(qgu->value);
|
||||
entity_list.UpdateQGlobal(qgu->id, temp);
|
||||
zone->UpdateQGlobal(qgu->id, temp);
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
/* Create new qglobal data and update zone processes */
|
||||
pack = new ServerPacket(ServerOP_QGlobalUpdate, sizeof(ServerQGlobalUpdate_Struct));
|
||||
ServerQGlobalUpdate_Struct *qgu = (ServerQGlobalUpdate_Struct*)pack->pBuffer;
|
||||
qgu->npc_id = npcid;
|
||||
qgu->char_id = charid;
|
||||
qgu->zone_id = zoneid;
|
||||
|
||||
qgu->expdate = (duration == INT_MAX)? 0xFFFFFFFF: Timer::GetTimeSeconds() + duration;
|
||||
|
||||
strcpy((char*)qgu->name, varname);
|
||||
strn0cpy((char*)qgu->value, varvalue, 128);
|
||||
qgu->id = results.LastInsertedID();
|
||||
qgu->from_zone_id = zone->GetZoneID();
|
||||
qgu->from_instance_id = zone->GetInstanceID();
|
||||
|
||||
QGlobal temp;
|
||||
temp.npc_id = npcid;
|
||||
temp.char_id = charid;
|
||||
temp.zone_id = zoneid;
|
||||
temp.expdate = qgu->expdate;
|
||||
temp.name.assign(qgu->name);
|
||||
temp.value.assign(qgu->value);
|
||||
entity_list.UpdateQGlobal(qgu->id, temp);
|
||||
zone->UpdateQGlobal(qgu->id, temp);
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1420,22 +1410,14 @@ void QuestManager::targlobal(const char *varname, const char *value, const char
|
||||
|
||||
void QuestManager::delglobal(const char *varname) {
|
||||
QuestManagerCurrentQuestVars();
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
int qgZoneid=zone->GetZoneID();
|
||||
int qgCharid=0;
|
||||
int qgNpcid=owner->GetNPCTypeID();
|
||||
|
||||
|
||||
|
||||
if (initiator && initiator->IsClient()) // some events like waypoint and spawn don't have a player involved
|
||||
{
|
||||
qgCharid=initiator->CharacterID();
|
||||
}
|
||||
|
||||
else {
|
||||
if (initiator && initiator->IsClient()) // some events like waypoint and spawn don't have a player involved
|
||||
qgCharid=initiator->CharacterID();
|
||||
else
|
||||
qgCharid=-qgNpcid; // make char id negative npc id as a fudge
|
||||
}
|
||||
|
||||
/* QS: PlayerLogQGlobalUpdate */
|
||||
if (RuleB(QueryServ, PlayerLogQGlobalUpdate) && qgCharid && qgCharid > 0 && initiator && initiator->IsClient()){
|
||||
@@ -1443,31 +1425,32 @@ void QuestManager::delglobal(const char *varname) {
|
||||
QServ->PlayerLogEvent(Player_Log_QGlobal_Update, qgCharid, event_desc);
|
||||
}
|
||||
|
||||
if (!database.RunQuery(query,
|
||||
MakeAnyLenString(&query,
|
||||
"DELETE FROM quest_globals WHERE name='%s'"
|
||||
" && (npcid=0 || npcid=%i) && (charid=0 || charid=%i) && (zoneid=%i || zoneid=0)",
|
||||
varname,qgNpcid,qgCharid,qgZoneid),errbuf))
|
||||
{
|
||||
std::cerr << "delglobal error deleting " << varname << " : " << errbuf << std::endl;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("DELETE FROM quest_globals "
|
||||
"WHERE name = '%s' "
|
||||
"&& (npcid=0 || npcid=%i) "
|
||||
"&& (charid=0 || charid=%i) "
|
||||
"&& (zoneid=%i || zoneid=0)",
|
||||
varname, qgNpcid, qgCharid, qgZoneid);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
std::cerr << "delglobal error deleting " << varname << " : " << results.ErrorMessage() << std::endl;
|
||||
|
||||
if(zone) {
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
|
||||
ServerQGlobalDelete_Struct *qgu = (ServerQGlobalDelete_Struct*)pack->pBuffer;
|
||||
if(!zone)
|
||||
return;
|
||||
|
||||
qgu->npc_id = qgNpcid;
|
||||
qgu->char_id = qgCharid;
|
||||
qgu->zone_id = qgZoneid;
|
||||
strcpy(qgu->name, varname);
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_QGlobalDelete, sizeof(ServerQGlobalDelete_Struct));
|
||||
ServerQGlobalDelete_Struct *qgu = (ServerQGlobalDelete_Struct*)pack->pBuffer;
|
||||
|
||||
entity_list.DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id);
|
||||
zone->DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id);
|
||||
qgu->npc_id = qgNpcid;
|
||||
qgu->char_id = qgCharid;
|
||||
qgu->zone_id = qgZoneid;
|
||||
strcpy(qgu->name, varname);
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
entity_list.DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id);
|
||||
zone->DeleteQGlobal(std::string((char*)qgu->name), qgu->npc_id, qgu->char_id, qgu->zone_id);
|
||||
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
// Converts duration string to duration value (in seconds)
|
||||
@@ -1688,11 +1671,6 @@ void QuestManager::showgrid(int grid) {
|
||||
if(initiator == nullptr)
|
||||
return;
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
FindPerson_Point pt;
|
||||
std::vector<FindPerson_Point> pts;
|
||||
|
||||
@@ -1702,22 +1680,25 @@ void QuestManager::showgrid(int grid) {
|
||||
pts.push_back(pt);
|
||||
|
||||
// Retrieve all waypoints for this grid
|
||||
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `x`,`y`,`z` FROM grid_entries WHERE `gridid`=%i AND `zoneid`=%i ORDER BY `number`",grid,zone->GetZoneID()),errbuf,&result)) {
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
pt.x = atof(row[0]);
|
||||
pt.y = atof(row[1]);
|
||||
pt.z = atof(row[2]);
|
||||
pts.push_back(pt);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
initiator->SendPathPacket(pts);
|
||||
}
|
||||
else // DB query error!
|
||||
{
|
||||
LogFile->write(EQEMuLog::Quest, "Error loading grid %d for showgrid(): %s", grid, errbuf);
|
||||
std::string query = StringFormat("SELECT `x`,`y`,`z` FROM grid_entries "
|
||||
"WHERE `gridid` = %i AND `zoneid` = %i "
|
||||
"ORDER BY `number`", grid, zone->GetZoneID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Quest, "Error loading grid %d for showgrid(): %s", grid, results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
pt.x = atof(row[0]);
|
||||
pt.y = atof(row[1]);
|
||||
pt.z = atof(row[2]);
|
||||
|
||||
pts.push_back(pt);
|
||||
}
|
||||
|
||||
initiator->SendPathPacket(pts);
|
||||
|
||||
}
|
||||
|
||||
//change the value of a spawn condition
|
||||
@@ -2293,19 +2274,19 @@ bool QuestManager::istaskappropriate(int task) {
|
||||
}
|
||||
|
||||
void QuestManager::clearspawntimers() {
|
||||
if(zone) {
|
||||
//TODO: Dec 19, 2008, replace with code updated for current spawn timers.
|
||||
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
|
||||
iterator.Reset();
|
||||
while (iterator.MoreElements())
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
database.RunQuery(query, MakeAnyLenString(&query, "DELETE FROM respawn_times WHERE id=%lu AND "
|
||||
"instance_id=%lu",(unsigned long)iterator.GetData()->GetID(), (unsigned long)zone->GetInstanceID()), errbuf);
|
||||
safe_delete_array(query);
|
||||
iterator.Advance();
|
||||
}
|
||||
if(!zone)
|
||||
return;
|
||||
|
||||
//TODO: Dec 19, 2008, replace with code updated for current spawn timers.
|
||||
LinkedListIterator<Spawn2*> iterator(zone->spawn2_list);
|
||||
iterator.Reset();
|
||||
while (iterator.MoreElements()) {
|
||||
std::string query = StringFormat("DELETE FROM respawn_times "
|
||||
"WHERE id = %lu AND instance_id = %lu",
|
||||
(unsigned long)iterator.GetData()->GetID(),
|
||||
(unsigned long)zone->GetInstanceID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
iterator.Advance();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2682,11 +2663,6 @@ void QuestManager::FlagInstanceByRaidLeader(uint32 zone, int16 version)
|
||||
const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkName) {
|
||||
QuestManagerCurrentQuestVars();
|
||||
|
||||
const char *ERR_MYSQLERROR = "Error in saylink phrase queries";
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
int sayid = 0;
|
||||
|
||||
int sz = strlen(Phrase);
|
||||
@@ -2694,70 +2670,50 @@ const char* QuestManager::saylink(char* Phrase, bool silent, const char* LinkNam
|
||||
database.DoEscapeString(escaped_string, Phrase, sz);
|
||||
|
||||
// Query for an existing phrase and id in the saylink table
|
||||
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `id` FROM `saylink` WHERE `phrase` = '%s'", escaped_string),errbuf,&result))
|
||||
{
|
||||
if (mysql_num_rows(result) >= 1)
|
||||
{
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
std::string query = StringFormat("SELECT `id` FROM `saylink` WHERE `phrase` = '%s'", escaped_string);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success()) {
|
||||
if (results.RowCount() >= 1) {
|
||||
for (auto row = results.begin();row != results.end(); ++row)
|
||||
sayid = atoi(row[0]);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else // Add a new saylink entry to the database and query it again for the new sayid number
|
||||
{
|
||||
safe_delete_array(query);
|
||||
|
||||
database.RunQuery(query,MakeAnyLenString(&query,"INSERT INTO `saylink` (`phrase`) VALUES ('%s')", escaped_string),errbuf);
|
||||
safe_delete_array(query);
|
||||
|
||||
if(database.RunQuery(query,MakeAnyLenString(&query,"SELECT `id` FROM saylink WHERE `phrase` = '%s'", escaped_string),errbuf,&result))
|
||||
{
|
||||
if (mysql_num_rows(result) >= 1)
|
||||
{
|
||||
while((row = mysql_fetch_row(result)))
|
||||
{
|
||||
sayid = atoi(row[0]);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
} else { // Add a new saylink entry to the database and query it again for the new sayid number
|
||||
std::string insert_query = StringFormat("INSERT INTO `saylink` (`phrase`) VALUES ('%s')", escaped_string);
|
||||
results = database.QueryDatabase(insert_query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in saylink phrase queries", results.ErrorMessage().c_str());
|
||||
} else {
|
||||
results = database.QueryDatabase(query);
|
||||
if (results.Success()) {
|
||||
if (results.RowCount() >= 1)
|
||||
for(auto row = results.begin(); row != results.end(); ++row)
|
||||
sayid = atoi(row[0]);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in saylink phrase queries", results.ErrorMessage().c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile->write(EQEMuLog::Error, ERR_MYSQLERROR, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
}
|
||||
}
|
||||
safe_delete_array(query);
|
||||
safe_delete_array(escaped_string);
|
||||
|
||||
if(silent)
|
||||
if (silent)
|
||||
sayid = sayid + 750000;
|
||||
else
|
||||
sayid = sayid + 500000;
|
||||
|
||||
//Create the say link as an item link hash
|
||||
char linktext[250];
|
||||
//Create the say link as an item link hash
|
||||
char linktext[250];
|
||||
|
||||
if(initiator)
|
||||
{
|
||||
if (initiator) {
|
||||
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 RoF saylink, since older clients handle RoF ones better than RoF handles older ones.
|
||||
} else { // If no initiator, create an RoF saylink, since older clients handle RoF ones better than RoF handles older ones.
|
||||
sprintf(linktext,"%c%06X%s%s%c",0x12,sayid,"0000000000000000000000000000000000000000000000000",LinkName,0x12);
|
||||
}
|
||||
|
||||
strcpy(Phrase,linktext);
|
||||
return Phrase;
|
||||
|
||||
@@ -2949,6 +2905,15 @@ const char* QuestManager::GetZoneLongName(const char *zone) {
|
||||
return ln.c_str();
|
||||
}
|
||||
|
||||
void QuestManager::CrossZoneSignalNPCByNPCTypeID(uint32 npctype_id, uint32 data){
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_CZSignalNPC, sizeof(CZNPCSignal_Struct));
|
||||
CZNPCSignal_Struct* CZSN = (CZNPCSignal_Struct*)pack->pBuffer;
|
||||
CZSN->npctype_id = npctype_id;
|
||||
CZSN->data = data;
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
void QuestManager::CrossZoneSignalPlayerByCharID(int charid, uint32 data){
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_CZSignalClient, sizeof(CZClientSignal_Struct));
|
||||
CZClientSignal_Struct* CZSC = (CZClientSignal_Struct*) pack->pBuffer;
|
||||
@@ -2966,7 +2931,7 @@ void QuestManager::CrossZoneSignalPlayerByName(const char *CharName, uint32 data
|
||||
CZSC->data = data;
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
}
|
||||
|
||||
void QuestManager::CrossZoneMessagePlayerByName(uint32 Type, const char *CharName, const char *Message){
|
||||
uint32 message_len = strlen(CharName) + 1;
|
||||
@@ -2976,6 +2941,18 @@ void QuestManager::CrossZoneMessagePlayerByName(uint32 Type, const char *CharNam
|
||||
CZSC->Type = Type;
|
||||
strn0cpy(CZSC->CharName, CharName, 64);
|
||||
strn0cpy(CZSC->Message, Message, 512);
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
void QuestManager::CrossZoneSetEntityVariableByNPCTypeID(uint32 npctype_id, const char *id, const char *m_var){
|
||||
uint32 message_len = strlen(id) + 1;
|
||||
uint32 message_len2 = strlen(m_var) + 1;
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_CZSetEntityVariableByNPCTypeID, sizeof(CZSetEntVarByNPCTypeID_Struct) + message_len + message_len2);
|
||||
CZSetEntVarByNPCTypeID_Struct* CZSNBYNID = (CZSetEntVarByNPCTypeID_Struct*)pack->pBuffer;
|
||||
CZSNBYNID->npctype_id = npctype_id;
|
||||
strn0cpy(CZSNBYNID->id, id, 256);
|
||||
strn0cpy(CZSNBYNID->m_var, m_var, 256);
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
+3
-1
@@ -239,8 +239,10 @@ public:
|
||||
uint16 CreateDoor( const char* model, float x, float y, float z, float heading, uint8 opentype, uint16 size);
|
||||
int32 GetZoneID(const char *zone);
|
||||
const char *GetZoneLongName(const char *zone);
|
||||
void CrossZoneSignalPlayerByCharID(int charid, uint32 data);
|
||||
void CrossZoneSignalPlayerByCharID(int charid, uint32 data);
|
||||
void CrossZoneSignalNPCByNPCTypeID(uint32 npctype_id, uint32 data);
|
||||
void CrossZoneSignalPlayerByName(const char *CharName, uint32 data);
|
||||
void CrossZoneSetEntityVariableByNPCTypeID(uint32 npctype_id, const char *id, const char *m_var);
|
||||
void CrossZoneMessagePlayerByName(uint32 Type, const char *CharName, const char *Message);
|
||||
bool EnableRecipe(uint32 recipe_id);
|
||||
bool DisableRecipe(uint32 recipe_id);
|
||||
|
||||
+339
-193
@@ -29,6 +29,12 @@ Raid::Raid(uint32 raidID)
|
||||
: GroupIDConsumer(raidID)
|
||||
{
|
||||
memset(members ,0, (sizeof(RaidMember)*MAX_RAID_MEMBERS));
|
||||
memset(&raid_aa, 0, sizeof(RaidLeadershipAA_Struct));
|
||||
memset(group_aa, 0, sizeof(GroupLeadershipAA_Struct) * MAX_RAID_GROUPS);
|
||||
for (int i = 0; i < MAX_RAID_GROUPS; i++) {
|
||||
group_mentor[i].mentor_percent = 0;
|
||||
group_mentor[i].mentoree = nullptr;
|
||||
}
|
||||
leader = nullptr;
|
||||
memset(leadername, 0, 64);
|
||||
locked = false;
|
||||
@@ -39,6 +45,12 @@ Raid::Raid(Client* nLeader)
|
||||
: GroupIDConsumer()
|
||||
{
|
||||
memset(members ,0, (sizeof(RaidMember)*MAX_RAID_MEMBERS));
|
||||
memset(&raid_aa, 0, sizeof(RaidLeadershipAA_Struct));
|
||||
memset(group_aa, 0, sizeof(GroupLeadershipAA_Struct) * MAX_RAID_GROUPS);
|
||||
for (int i = 0; i < MAX_RAID_GROUPS; i++) {
|
||||
group_mentor[i].mentor_percent = 0;
|
||||
group_mentor[i].mentoree = nullptr;
|
||||
}
|
||||
leader = nLeader;
|
||||
memset(leadername, 0, 64);
|
||||
strn0cpy(leadername, nLeader->GetName(), 64);
|
||||
@@ -74,21 +86,32 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
|
||||
if(!c)
|
||||
return;
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "INSERT INTO raid_members SET raidid=%lu, charid=%lu, groupid=%lu, _class=%d, level=%d, name='%s', isgroupleader=%d, israidleader=%d, islooter=%d", (unsigned long)GetID(), (unsigned long)c->CharacterID(), (unsigned long)group, c->GetClass(), c->GetLevel(), c->GetName(), groupleader, rleader, looter ),errbuf,&result)){
|
||||
mysql_free_result(result);
|
||||
}
|
||||
std::string query = StringFormat("INSERT INTO raid_members SET raidid = %lu, charid = %lu, "
|
||||
"groupid = %lu, _class = %d, level = %d, name = '%s', "
|
||||
"isgroupleader = %d, israidleader = %d, islooter = %d",
|
||||
(unsigned long)GetID(), (unsigned long)c->CharacterID(),
|
||||
(unsigned long)group, c->GetClass(), c->GetLevel(),
|
||||
c->GetName(), groupleader, rleader, looter);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
safe_delete_array(query);
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
if (rleader) {
|
||||
database.SetRaidGroupLeaderInfo(RAID_GROUPLESS, GetID());
|
||||
UpdateRaidAAs();
|
||||
}
|
||||
if (group != RAID_GROUPLESS && groupleader) {
|
||||
database.SetRaidGroupLeaderInfo(group, GetID());
|
||||
UpdateGroupAAs(group);
|
||||
}
|
||||
if(group < 12)
|
||||
GroupUpdate(group);
|
||||
else // get raid AAs, GroupUpdate will handles it otherwise
|
||||
SendGroupLeadershipAA(c, RAID_GROUPLESS);
|
||||
SendRaidAddAll(c->GetName());
|
||||
|
||||
c->SetRaidGrouped(true);
|
||||
SendRaidMOTD(c);
|
||||
|
||||
ServerPacket *pack = new ServerPacket(ServerOP_RaidAdd, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
@@ -100,32 +123,26 @@ void Raid::AddMember(Client *c, uint32 group, bool rleader, bool groupleader, bo
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
void Raid::RemoveMember(const char *c)
|
||||
void Raid::RemoveMember(const char *characterName)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "DELETE FROM raid_members where name='%s'", c ),errbuf,&result)){
|
||||
mysql_free_result(result);
|
||||
}
|
||||
std::string query = StringFormat("DELETE FROM raid_members where name='%s'", characterName);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
Client *m = entity_list.GetClientByName(c);
|
||||
safe_delete_array(query);
|
||||
Client *client = entity_list.GetClientByName(characterName);
|
||||
disbandCheck = true;
|
||||
SendRaidRemoveAll(c);
|
||||
SendRaidDisband(m);
|
||||
SendRaidRemoveAll(characterName);
|
||||
SendRaidDisband(client);
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
|
||||
if(m){
|
||||
m->SetRaidGrouped(false);
|
||||
}
|
||||
if(client)
|
||||
client->SetRaidGrouped(false);
|
||||
|
||||
ServerPacket *pack = new ServerPacket(ServerOP_RaidRemove, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
strn0cpy(rga->playername, c, 64);
|
||||
strn0cpy(rga->playername, characterName, 64);
|
||||
rga->zoneid = zone->GetZoneID();
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
@@ -133,14 +150,9 @@ void Raid::RemoveMember(const char *c)
|
||||
|
||||
void Raid::DisbandRaid()
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "DELETE FROM raid_members WHERE raidid=%lu", (unsigned long)GetID()),errbuf,&result)){
|
||||
mysql_free_result(result);
|
||||
}
|
||||
std::string query = StringFormat("DELETE FROM raid_members WHERE raidid = %lu", (unsigned long)GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
safe_delete_array(query);
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
SendRaidDisbandAll();
|
||||
@@ -159,14 +171,10 @@ void Raid::DisbandRaid()
|
||||
|
||||
void Raid::MoveMember(const char *name, uint32 newGroup)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "UPDATE raid_members SET groupid=%lu WHERE name='%s'", (unsigned long)newGroup, name),errbuf,&result)){
|
||||
mysql_free_result(result);
|
||||
}
|
||||
std::string query = StringFormat("UPDATE raid_members SET groupid = %lu WHERE name = '%s'",
|
||||
(unsigned long)newGroup, name);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
safe_delete_array(query);
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
SendRaidMoveAll(name);
|
||||
@@ -183,21 +191,13 @@ void Raid::MoveMember(const char *name, uint32 newGroup)
|
||||
|
||||
void Raid::SetGroupLeader(const char *who, bool glFlag)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "UPDATE raid_members SET isgroupleader=%lu WHERE name='%s'", (unsigned long)glFlag, who),errbuf,&result)){
|
||||
mysql_free_result(result);
|
||||
}
|
||||
std::string query = StringFormat("UPDATE raid_members SET isgroupleader = %lu WHERE name = '%s'",
|
||||
(unsigned long)glFlag, who);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
safe_delete_array(query);
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
|
||||
//if(glFlag == true){ //we're setting the flag
|
||||
//this->SendMakeGroupLeaderPacket(who);
|
||||
//}
|
||||
|
||||
ServerPacket *pack = new ServerPacket(ServerOP_RaidGroupLeader, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
@@ -208,27 +208,29 @@ void Raid::SetGroupLeader(const char *who, bool glFlag)
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
Client *Raid::GetGroupLeader(uint32 group_id)
|
||||
{
|
||||
if (group_id == RAID_GROUPLESS)
|
||||
return nullptr;
|
||||
|
||||
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++)
|
||||
if (members[i].member && members[i].IsGroupLeader && members[i].GroupNumber == group_id)
|
||||
return members[i].member;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Raid::SetRaidLeader(const char *wasLead, const char *name)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
if (!database.RunQuery(query,MakeAnyLenString(&query, "UPDATE raid_members SET israidleader=0 WHERE name='%s'", wasLead),errbuf,&result)){
|
||||
printf("Set Raid Leader error: %s\n", errbuf);
|
||||
}
|
||||
else
|
||||
mysql_free_result(result);
|
||||
std::string query = StringFormat("UPDATE raid_members SET israidleader = 0 WHERE name = '%s'", wasLead);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
printf("Set Raid Leader error: %s\n", results.ErrorMessage().c_str());
|
||||
|
||||
safe_delete_array(query);
|
||||
query = 0;
|
||||
|
||||
if (!database.RunQuery(query,MakeAnyLenString(&query, "UPDATE raid_members SET israidleader=1 WHERE name='%s'", name),errbuf,&result)){
|
||||
printf("Set Raid Leader error: %s\n", errbuf);
|
||||
}
|
||||
else
|
||||
mysql_free_result(result);
|
||||
|
||||
safe_delete_array(query);
|
||||
query = StringFormat("UPDATE raid_members SET israidleader = 1 WHERE name = '%s'", name);
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
printf("Set Raid Leader error: %s\n", results.ErrorMessage().c_str());
|
||||
|
||||
strn0cpy(leadername, name, 64);
|
||||
|
||||
@@ -250,6 +252,58 @@ void Raid::SetRaidLeader(const char *wasLead, const char *name)
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
void Raid::SaveGroupLeaderAA(uint32 gid)
|
||||
{
|
||||
char *queryBuffer = new char[sizeof(GroupLeadershipAA_Struct) * 2 + 1];
|
||||
database.DoEscapeString(queryBuffer, (char*)&group_aa[gid], sizeof(GroupLeadershipAA_Struct));
|
||||
|
||||
std::string query = "UPDATE raid_leaders SET leadershipaa = '";
|
||||
query += queryBuffer;
|
||||
query += StringFormat("' WHERE gid = %lu AND rid = %lu LIMIT 1", gid, GetID());
|
||||
safe_delete_array(queryBuffer);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to store LeadershipAA: %s\n", results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
void Raid::SaveRaidLeaderAA()
|
||||
{
|
||||
char *queryBuffer = new char[sizeof(RaidLeadershipAA_Struct) * 2 + 1];
|
||||
database.DoEscapeString(queryBuffer, (char*)&raid_aa, sizeof(RaidLeadershipAA_Struct));
|
||||
|
||||
std::string query = "UPDATE raid_leaders SET leadershipaa = '";
|
||||
query += queryBuffer;
|
||||
query += StringFormat("' WHERE gid = %lu AND rid = %lu LIMIT 1", RAID_GROUPLESS, GetID());
|
||||
safe_delete_array(queryBuffer);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to store LeadershipAA: %s\n", results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
void Raid::UpdateGroupAAs(uint32 gid)
|
||||
{
|
||||
Client *gl = GetGroupLeader(gid);
|
||||
|
||||
if (gl)
|
||||
gl->GetGroupAAs(&group_aa[gid]);
|
||||
else
|
||||
memset(&group_aa[gid], 0, sizeof(GroupLeadershipAA_Struct));
|
||||
|
||||
SaveGroupLeaderAA(gid);
|
||||
}
|
||||
|
||||
void Raid::UpdateRaidAAs()
|
||||
{
|
||||
Client *rl = GetLeader();
|
||||
|
||||
if (rl)
|
||||
rl->GetRaidAAs(&raid_aa);
|
||||
else
|
||||
memset(&raid_aa, 0, sizeof(RaidLeadershipAA_Struct));
|
||||
|
||||
SaveRaidLeaderAA();
|
||||
}
|
||||
|
||||
bool Raid::IsGroupLeader(const char *who)
|
||||
{
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
@@ -264,14 +318,10 @@ bool Raid::IsGroupLeader(const char *who)
|
||||
|
||||
void Raid::UpdateLevel(const char *name, int newLevel)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "UPDATE raid_members SET level=%lu WHERE name='%s'", (unsigned long)newLevel, name),errbuf,&result)){
|
||||
mysql_free_result(result);
|
||||
}
|
||||
std::string query = StringFormat("UPDATE raid_members SET level = %lu WHERE name = '%s'",
|
||||
(unsigned long)newLevel, name);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
safe_delete_array(query);
|
||||
LearnMembers();
|
||||
VerifyRaid();
|
||||
}
|
||||
@@ -514,7 +564,7 @@ void Raid::BalanceHP(int32 penalty, uint32 gid, int32 range, Mob* caster, int32
|
||||
|
||||
int dmgtaken = 0, numMem = 0, dmgtaken_tmp = 0;
|
||||
int gi = 0;
|
||||
|
||||
|
||||
float distance;
|
||||
float range2 = range*range;
|
||||
|
||||
@@ -567,7 +617,7 @@ void Raid::BalanceMana(int32 penalty, uint32 gid, int32 range, Mob* caster, int3
|
||||
|
||||
if (!range)
|
||||
range = 200;
|
||||
|
||||
|
||||
float distance;
|
||||
float range2 = range*range;
|
||||
|
||||
@@ -775,27 +825,16 @@ void Raid::TeleportRaid(Mob* sender, uint32 zoneID, uint16 instance_id, float x,
|
||||
|
||||
void Raid::ChangeLootType(uint32 type)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "UPDATE raid_details SET loottype=%lu WHERE raidid=%lu", (unsigned long)type, (unsigned long)GetID()),errbuf,&result)){
|
||||
mysql_free_result(result);
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("UPDATE raid_details SET loottype = %lu WHERE raidid = %lu",
|
||||
(unsigned long)type, (unsigned long)GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
LootType = type;
|
||||
}
|
||||
|
||||
void Raid::AddRaidLooter(const char* looter)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "UPDATE raid_members SET islooter=1 WHERE name='%s'", looter),errbuf,&result)){
|
||||
mysql_free_result(result);
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("UPDATE raid_members SET islooter = 1 WHERE name = '%s'", looter);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
{
|
||||
@@ -812,36 +851,19 @@ void Raid::AddRaidLooter(const char* looter)
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
|
||||
/* For reference only at this time. This code adds a looter to the Raid Options Window.
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct));
|
||||
RaidGeneral_Struct *rgs = (RaidGeneral_Struct*)outapp->pBuffer;
|
||||
rgs->action = 33;
|
||||
strcpy(rgs->leader_name, looter);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp); */
|
||||
}
|
||||
|
||||
void Raid::RemoveRaidLooter(const char* looter)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "UPDATE raid_members SET islooter=0 WHERE name='%s'", looter),errbuf,&result)){
|
||||
mysql_free_result(result);
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("UPDATE raid_members SET islooter = 0 WHERE name = '%s'", looter);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
{
|
||||
if(strcmp(looter, members[x].membername) == 0)
|
||||
{
|
||||
if(strcmp(looter, members[x].membername) == 0) {
|
||||
members[x].IsLooter = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ServerPacket *pack = new ServerPacket(ServerOP_DetailsChange, sizeof(ServerRaidGeneralAction_Struct));
|
||||
ServerRaidGeneralAction_Struct *rga = (ServerRaidGeneralAction_Struct*)pack->pBuffer;
|
||||
rga->rid = GetID();
|
||||
@@ -849,15 +871,6 @@ void Raid::RemoveRaidLooter(const char* looter)
|
||||
rga->instance_id = zone->GetInstanceID();
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
|
||||
/* For reference only at this time. This code removes a looter from the Raid Options Window.
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct));
|
||||
RaidGeneral_Struct *rgs = (RaidGeneral_Struct*)outapp->pBuffer;
|
||||
rgs->action = 34;
|
||||
strcpy(rgs->leader_name, looter);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp); */
|
||||
}
|
||||
|
||||
bool Raid::IsRaidMember(const char *name){
|
||||
@@ -1089,12 +1102,12 @@ void Raid::QueuePacket(const EQApplicationPacket *app, bool ack_req)
|
||||
|
||||
void Raid::SendMakeLeaderPacket(const char *who) //30
|
||||
{
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct));
|
||||
RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer;
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
|
||||
RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer;
|
||||
rg->action = raidMakeLeader;
|
||||
strn0cpy(rg->leader_name, who, 64);
|
||||
strn0cpy(rg->player_name, who, 64);
|
||||
rg->parameter = 0;
|
||||
memcpy(&rg->raid, &raid_aa, sizeof(RaidLeadershipAA_Struct));
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
@@ -1104,12 +1117,12 @@ void Raid::SendMakeLeaderPacketTo(const char *who, Client *to)
|
||||
if(!to)
|
||||
return;
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidGeneral_Struct));
|
||||
RaidGeneral_Struct *rg = (RaidGeneral_Struct*)outapp->pBuffer;
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
|
||||
RaidLeadershipUpdate_Struct *rg = (RaidLeadershipUpdate_Struct*)outapp->pBuffer;
|
||||
rg->action = raidMakeLeader;
|
||||
strn0cpy(rg->leader_name, who, 64);
|
||||
strn0cpy(rg->player_name, who, 64);
|
||||
rg->parameter = 0;
|
||||
memcpy(&rg->raid, &raid_aa, sizeof(RaidLeadershipAA_Struct));
|
||||
to->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
@@ -1167,6 +1180,7 @@ void Raid::SendGroupUpdate(Client *to)
|
||||
strn0cpy(gu->leadersname, to->GetName(), 64);
|
||||
}
|
||||
strn0cpy(gu->yourname, to->GetName(), 64);
|
||||
memcpy(&gu->leader_aas, &group_aa[grp], sizeof(GroupLeadershipAA_Struct));
|
||||
|
||||
to->FastQueuePacket(&outapp);
|
||||
}
|
||||
@@ -1179,8 +1193,10 @@ void Raid::GroupUpdate(uint32 gid, bool initial)
|
||||
{
|
||||
if(strlen(members[x].membername) > 0){
|
||||
if(members[x].GroupNumber == gid){
|
||||
if(members[x].member)
|
||||
if(members[x].member) {
|
||||
SendGroupUpdate(members[x].member);
|
||||
SendGroupLeadershipAA(members[x].member, gid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1279,16 +1295,78 @@ void Raid::SendRaidGroupRemove(const char *who, uint32 gid)
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
void Raid::SendRaidMOTD(Client *c)
|
||||
{
|
||||
if (!c || motd.empty())
|
||||
return;
|
||||
|
||||
size_t size = motd.size() + 1;
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidMOTD_Struct) + size);
|
||||
RaidMOTD_Struct *rmotd = (RaidMOTD_Struct *)outapp->pBuffer;
|
||||
rmotd->general.action = raidSetMotd;
|
||||
strn0cpy(rmotd->general.player_name, c->GetName(), 64);
|
||||
strn0cpy(rmotd->motd, motd.c_str(), size);
|
||||
c->FastQueuePacket(&outapp);
|
||||
}
|
||||
|
||||
void Raid::SendRaidMOTD()
|
||||
{
|
||||
if (motd.empty())
|
||||
return;
|
||||
|
||||
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++)
|
||||
if (members[i].member)
|
||||
SendRaidMOTD(members[i].member);
|
||||
}
|
||||
|
||||
void Raid::SendRaidMOTDToWorld()
|
||||
{
|
||||
if (motd.empty())
|
||||
return;
|
||||
|
||||
size_t size = motd.size() + 1;
|
||||
ServerPacket *pack = new ServerPacket(ServerOP_RaidMOTD, sizeof(ServerRaidMOTD_Struct) + size);
|
||||
ServerRaidMOTD_Struct *smotd = (ServerRaidMOTD_Struct *)pack->pBuffer;
|
||||
smotd->rid = GetID();
|
||||
strn0cpy(smotd->motd, motd.c_str(), size);
|
||||
worldserver.SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
}
|
||||
|
||||
void Raid::SendGroupLeadershipAA(Client *c, uint32 gid)
|
||||
{
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_RaidUpdate, sizeof(RaidLeadershipUpdate_Struct));
|
||||
RaidLeadershipUpdate_Struct *rlaa = (RaidLeadershipUpdate_Struct *)outapp->pBuffer;
|
||||
rlaa->action = raidSetLeaderAbilities;
|
||||
strn0cpy(rlaa->leader_name, c->GetName(), 64);
|
||||
strn0cpy(rlaa->player_name, c->GetName(), 64);
|
||||
if (gid != RAID_GROUPLESS)
|
||||
memcpy(&rlaa->group, &group_aa[gid], sizeof(GroupLeadershipAA_Struct));
|
||||
memcpy(&rlaa->raid, &raid_aa, sizeof(RaidLeadershipAA_Struct));
|
||||
c->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Raid::SendGroupLeadershipAA(uint32 gid)
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++)
|
||||
if (members[i].member && members[i].GroupNumber == gid)
|
||||
SendGroupLeadershipAA(members[i].member, gid);
|
||||
}
|
||||
|
||||
void Raid::SendAllRaidLeadershipAA()
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_RAID_MEMBERS; i++)
|
||||
if (members[i].member)
|
||||
SendGroupLeadershipAA(members[i].member, members[i].GroupNumber);
|
||||
}
|
||||
|
||||
void Raid::LockRaid(bool lockFlag)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "UPDATE raid_details SET locked=%d WHERE raidid=%lu", lockFlag, (unsigned long)GetID()),errbuf,&result)){
|
||||
mysql_free_result(result);
|
||||
}
|
||||
std::string query = StringFormat("UPDATE raid_details SET locked = %d WHERE raidid = %lu",
|
||||
lockFlag, (unsigned long)GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
safe_delete_array(query);
|
||||
locked = lockFlag;
|
||||
if(lockFlag)
|
||||
SendRaidLock();
|
||||
@@ -1307,74 +1385,79 @@ void Raid::LockRaid(bool lockFlag)
|
||||
|
||||
void Raid::SetRaidDetails()
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "INSERT INTO raid_details SET raidid=%lu, loottype=4, locked=0", (unsigned long)GetID()),errbuf,&result)){
|
||||
mysql_free_result(result);
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("INSERT INTO raid_details SET raidid = %lu, loottype = 4, locked = 0, motd = ''",
|
||||
(unsigned long)GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
void Raid::GetRaidDetails()
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "SELECT locked, loottype FROM raid_details WHERE raidid=%lu", (unsigned long)GetID()),errbuf,&result)){
|
||||
safe_delete_array(query);
|
||||
if(mysql_num_rows(result) < 1) {
|
||||
mysql_free_result(result);
|
||||
LogFile->write(EQEMuLog::Error, "Error getting raid details for raid %lu: %s", (unsigned long)GetID(), errbuf);
|
||||
return;
|
||||
}
|
||||
row = mysql_fetch_row(result);
|
||||
if(row){
|
||||
locked = atoi(row[0]);
|
||||
LootType = atoi(row[1]);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
std::string query = StringFormat("SELECT locked, loottype, motd FROM raid_details WHERE raidid = %lu",
|
||||
(unsigned long)GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return;
|
||||
|
||||
if (results.RowCount() == 0) {
|
||||
LogFile->write(EQEMuLog::Error, "Error getting raid details for raid %lu: %s", (unsigned long)GetID(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
locked = atoi(row[0]);
|
||||
LootType = atoi(row[1]);
|
||||
motd = std::string(row[2]);
|
||||
}
|
||||
|
||||
void Raid::SaveRaidMOTD()
|
||||
{
|
||||
std::string query = StringFormat("UPDATE raid_details SET motd = '%s' WHERE raidid = %lu",
|
||||
EscapeString(motd).c_str(), (unsigned long)GetID());
|
||||
|
||||
auto results = database.QueryDatabase(query);
|
||||
}
|
||||
|
||||
bool Raid::LearnMembers()
|
||||
{
|
||||
memset(members, 0, (sizeof(RaidMember)*MAX_RAID_MEMBERS));
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "SELECT name, groupid, _class, level, isgroupleader, israidleader, islooter FROM raid_members WHERE raidid=%lu", (unsigned long)GetID()),errbuf,&result)){
|
||||
safe_delete_array(query);
|
||||
if(mysql_num_rows(result) < 1) {
|
||||
mysql_free_result(result);
|
||||
LogFile->write(EQEMuLog::Error, "Error getting raid members for raid %lu: %s", (unsigned long)GetID(), errbuf);
|
||||
disbandCheck = true;
|
||||
return(false);
|
||||
}
|
||||
int i = 0;
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
if(!row[0])
|
||||
continue;
|
||||
members[i].member = nullptr;
|
||||
strn0cpy(members[i].membername, row[0], 64);
|
||||
int GroupNum = atoi(row[1]);
|
||||
if(GroupNum > 11)
|
||||
members[i].GroupNumber = 0xFFFFFFFF;
|
||||
else
|
||||
members[i].GroupNumber = GroupNum;
|
||||
members[i]._class = atoi(row[2]);
|
||||
members[i].level = atoi(row[3]);
|
||||
members[i].IsGroupLeader = atoi(row[4]);
|
||||
members[i].IsRaidLeader = atoi(row[5]);
|
||||
members[i].IsLooter = atoi(row[6]);
|
||||
i++;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
return(true);
|
||||
|
||||
std::string query = StringFormat("SELECT name, groupid, _class, level, "
|
||||
"isgroupleader, israidleader, islooter "
|
||||
"FROM raid_members WHERE raidid = %lu",
|
||||
(unsigned long)GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
if(results.RowCount() == 0) {
|
||||
LogFile->write(EQEMuLog::Error, "Error getting raid members for raid %lu: %s", (unsigned long)GetID(), results.ErrorMessage().c_str());
|
||||
disbandCheck = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
if(!row[0])
|
||||
continue;
|
||||
|
||||
members[index].member = nullptr;
|
||||
strn0cpy(members[index].membername, row[0], 64);
|
||||
int groupNum = atoi(row[1]);
|
||||
if(groupNum > 11)
|
||||
members[index].GroupNumber = 0xFFFFFFFF;
|
||||
else
|
||||
members[index].GroupNumber = groupNum;
|
||||
|
||||
members[index]._class = atoi(row[2]);
|
||||
members[index].level = atoi(row[3]);
|
||||
members[index].IsGroupLeader = atoi(row[4]);
|
||||
members[index].IsRaidLeader = atoi(row[5]);
|
||||
members[index].IsLooter = atoi(row[6]);
|
||||
++index;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Raid::VerifyRaid()
|
||||
@@ -1407,13 +1490,19 @@ void Raid::MemberZoned(Client *c)
|
||||
if(!c)
|
||||
return;
|
||||
|
||||
// Raid::GetGroup() goes over the members as well, this way we go over once
|
||||
uint32 gid = RAID_GROUPLESS;
|
||||
for(int x = 0; x < MAX_RAID_MEMBERS; x++)
|
||||
{
|
||||
if(members[x].member == c)
|
||||
{
|
||||
members[x].member = nullptr;
|
||||
gid = members[x].GroupNumber;
|
||||
}
|
||||
}
|
||||
|
||||
if (gid < 12 && group_mentor[gid].mentoree == c)
|
||||
group_mentor[gid].mentoree = nullptr;
|
||||
}
|
||||
|
||||
void Raid::SendHPPacketsTo(Client *c)
|
||||
@@ -1518,3 +1607,60 @@ void Raid::RaidMessage_StringID(Mob* sender, uint32 type, uint32 string_id, cons
|
||||
}
|
||||
}
|
||||
|
||||
void Raid::LoadLeadership()
|
||||
{
|
||||
database.GetRaidLeadershipInfo(GetID(), nullptr, nullptr, nullptr, nullptr, &raid_aa);
|
||||
|
||||
char mentor_name[64];
|
||||
for (uint32 group_id = 0; group_id < MAX_RAID_GROUPS; group_id++) {
|
||||
database.GetGroupLeadershipInfo(group_id, GetID(), nullptr, nullptr, nullptr, nullptr,
|
||||
mentor_name, &group_mentor[group_id].mentor_percent, &group_aa[group_id]);
|
||||
if (strlen(mentor_name)) {
|
||||
group_mentor[group_id].name = mentor_name;
|
||||
mentor_name[0] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Raid::SetGroupMentor(uint32 group_id, int percent, char *name)
|
||||
{
|
||||
if (group_id > 11)
|
||||
return;
|
||||
group_mentor[group_id].name = name;
|
||||
group_mentor[group_id].mentor_percent = percent;
|
||||
Client *client = entity_list.GetClientByName(name);
|
||||
group_mentor[group_id].mentoree = client ? client : nullptr;
|
||||
|
||||
std::string query = StringFormat("UPDATE raid_leaders SET mentoree = '%s', mentor_percent = %i WHERE gid = %i AND rid = %i LIMIT 1",
|
||||
name, percent, group_id, GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to set raid group mentor: %s\n", results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
void Raid::ClearGroupMentor(uint32 group_id)
|
||||
{
|
||||
if (group_id > 11)
|
||||
return;
|
||||
group_mentor[group_id].name.clear();
|
||||
group_mentor[group_id].mentor_percent = 0;
|
||||
group_mentor[group_id].mentoree = nullptr;
|
||||
|
||||
std::string query = StringFormat("UPDATE raid_leaders SET mentoree = '', mentor_percent = 0 WHERE gid = %i AND rid = %i LIMIT 1",
|
||||
group_id, GetID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Unable to clear raid group mentor: %s\n", results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
// there isn't a nice place to add this in another function, unlike groups
|
||||
// so we do it here instead
|
||||
void Raid::CheckGroupMentor(uint32 group_id, Client *c)
|
||||
{
|
||||
if (!c || group_id > 11)
|
||||
return;
|
||||
|
||||
if (group_mentor[group_id].name == c->GetName())
|
||||
group_mentor[group_id].mentoree = c;
|
||||
}
|
||||
|
||||
|
||||
+44
-3
@@ -38,13 +38,13 @@ enum { //raid packet types:
|
||||
raidMembers = 6, //len 395+, details + members list
|
||||
raidNoAssignLeadership = 7,
|
||||
raidCreate = 8, //len 72
|
||||
raidUnknown = 9,
|
||||
raidUnknown = 9, // unused?
|
||||
raidNoRaid = 10, //parameter=0
|
||||
raidChangeLootType = 11,
|
||||
raidStringID = 12,
|
||||
raidChangeGroupLeader = 13, //136 raid leader, new group leader, group_id?
|
||||
raidBecomeGroupLeader = 14, //472
|
||||
raidUnknown2 = 15,
|
||||
raidSetLeaderAbilities = 14, //472
|
||||
raidSetLeaderData = 15, // 14,15 SoE names, not sure on difference, 14 packet has 0x100 bytes 15 0x214 in addition to raid general
|
||||
raidChangeGroup = 16, //?? len 136 old leader, new leader, 0 (preceeded with a remove2)
|
||||
raidLock = 17, //len 136 leader?, leader, 0
|
||||
raidUnlock = 18, //len 136 leader?, leader, 0
|
||||
@@ -79,6 +79,7 @@ enum { //raid command types
|
||||
|
||||
#define MAX_RAID_GROUPS 12
|
||||
#define MAX_RAID_MEMBERS 72
|
||||
const uint32 RAID_GROUPLESS = 0xFFFFFFFF;
|
||||
|
||||
struct RaidMember{
|
||||
char membername[64];
|
||||
@@ -91,6 +92,12 @@ struct RaidMember{
|
||||
bool IsLooter;
|
||||
};
|
||||
|
||||
struct GroupMentor {
|
||||
std::string name;
|
||||
Client *mentoree;
|
||||
int mentor_percent;
|
||||
};
|
||||
|
||||
class Raid : public GroupIDConsumer {
|
||||
public:
|
||||
Raid(Client *nLeader);
|
||||
@@ -111,6 +118,7 @@ public:
|
||||
void DisbandRaid();
|
||||
void MoveMember(const char *name, uint32 newGroup);
|
||||
void SetGroupLeader(const char *who, bool glFlag = true);
|
||||
Client *GetGroupLeader(uint32 group_id);
|
||||
void RemoveGroupLeader(const char *who);
|
||||
bool IsGroupLeader(const char *who);
|
||||
bool IsRaidMember(const char *name);
|
||||
@@ -130,6 +138,8 @@ public:
|
||||
void AddRaidLooter(const char* looter);
|
||||
void RemoveRaidLooter(const char* looter);
|
||||
|
||||
inline void SetRaidMOTD(std::string in_motd) { motd = in_motd; };
|
||||
|
||||
//util func
|
||||
//keeps me from having to keep iterating through the list
|
||||
//when I want lots of data from the same entry
|
||||
@@ -160,6 +170,7 @@ public:
|
||||
//also learns raid structure based on db.
|
||||
void SetRaidDetails();
|
||||
void GetRaidDetails();
|
||||
void SaveRaidMOTD();
|
||||
bool LearnMembers();
|
||||
void VerifyRaid();
|
||||
void MemberZoned(Client *c);
|
||||
@@ -194,9 +205,34 @@ public:
|
||||
void SendMakeGroupLeaderPacketAll();
|
||||
void SendMakeGroupLeaderPacket(const char *who); //13
|
||||
void SendMakeGroupLeaderPacketTo(const char *who, Client *to);
|
||||
void SendRaidMOTD(Client *c);
|
||||
void SendRaidMOTD();
|
||||
void SendRaidMOTDToWorld();
|
||||
|
||||
void QueuePacket(const EQApplicationPacket *app, bool ack_req = true);
|
||||
|
||||
// Leadership
|
||||
void UpdateGroupAAs(uint32 gid);
|
||||
void SaveGroupLeaderAA(uint32 gid);
|
||||
void UpdateRaidAAs();
|
||||
void SaveRaidLeaderAA();
|
||||
void SendGroupLeadershipAA(Client *c, uint32 gid);
|
||||
void SendGroupLeadershipAA(uint32 gid);
|
||||
void SendAllRaidLeadershipAA();
|
||||
void LoadLeadership();
|
||||
inline int GetLeadershipAA(int AAID, uint32 gid = 0)
|
||||
{ if (AAID >= 16) return raid_aa.ranks[AAID - 16]; else return group_aa[gid].ranks[AAID]; }
|
||||
inline void SetGroupAAs(uint32 gid, GroupLeadershipAA_Struct *glaa)
|
||||
{ memcpy(&group_aa[gid], glaa, sizeof(GroupLeadershipAA_Struct)); }
|
||||
inline void SetRaidAAs(RaidLeadershipAA_Struct *rlaa)
|
||||
{ memcpy(&raid_aa, rlaa, sizeof(RaidLeadershipAA_Struct)); }
|
||||
|
||||
void SetGroupMentor(uint32 group_id, int percent, char *name);
|
||||
void ClearGroupMentor(uint32 group_id);
|
||||
void CheckGroupMentor(uint32 group_id, Client *c); // this just checks if we should be fixing the pointer in group mentor struct on zone
|
||||
inline int GetMentorPercent(uint32 group_id) { return group_mentor[group_id].mentor_percent; }
|
||||
inline Client *GetMentoree(uint32 group_id) { return group_mentor[group_id].mentoree; }
|
||||
|
||||
RaidMember members[MAX_RAID_MEMBERS];
|
||||
char leadername[64];
|
||||
protected:
|
||||
@@ -206,6 +242,11 @@ protected:
|
||||
uint32 LootType;
|
||||
bool disbandCheck;
|
||||
bool forceDisband;
|
||||
std::string motd;
|
||||
RaidLeadershipAA_Struct raid_aa;
|
||||
GroupLeadershipAA_Struct group_aa[MAX_RAID_GROUPS];
|
||||
|
||||
GroupMentor group_mentor[MAX_RAID_GROUPS];
|
||||
};
|
||||
|
||||
|
||||
|
||||
+40
-41
@@ -26,6 +26,7 @@
|
||||
#include "string_ids.h"
|
||||
#include "../common/misc_functions.h"
|
||||
#include "../common/rulesys.h"
|
||||
#include "../common/string_util.h"
|
||||
|
||||
|
||||
int Mob::GetKickDamage() {
|
||||
@@ -346,15 +347,23 @@ void Client::OPCombatAbility(const EQApplicationPacket *app) {
|
||||
ReuseTime = MonkSpecialAttack(GetTarget(), ca_atk->m_skill) - 1 - skill_reduction;
|
||||
|
||||
//Live AA - Technique of Master Wu
|
||||
uint16 bDoubleSpecialAttack = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
|
||||
if (bDoubleSpecialAttack && (bDoubleSpecialAttack >= 100 || bDoubleSpecialAttack > MakeRandomInt(0, 99))) {
|
||||
|
||||
int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick };
|
||||
MonkSpecialAttack(GetTarget(), MonkSPA[MakeRandomInt(0, 4)]);
|
||||
|
||||
// always 1/4 of the double attack chance, 25% at rank 5 (100/4)
|
||||
if ((bDoubleSpecialAttack / 4) > MakeRandomInt(0, 99))
|
||||
MonkSpecialAttack(GetTarget(), MonkSPA[MakeRandomInt(0, 4)]);
|
||||
int wuchance = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
|
||||
if (wuchance) {
|
||||
if (wuchance >= 100 || wuchance > MakeRandomInt(0, 99)) {
|
||||
int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick };
|
||||
int extra = 1;
|
||||
// always 1/4 of the double attack chance, 25% at rank 5 (100/4)
|
||||
if (wuchance / 4 > MakeRandomInt(0, 99))
|
||||
extra++;
|
||||
// They didn't add a string ID for this.
|
||||
std::string msg = StringFormat("The spirit of Master Wu fills you! You gain %d additional attack(s).", extra);
|
||||
// live uses 400 here -- not sure if it's the best for all clients though
|
||||
SendColoredText(400, msg);
|
||||
while (extra) {
|
||||
MonkSpecialAttack(GetTarget(), MonkSPA[MakeRandomInt(0, 4)]);
|
||||
extra--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ReuseTime < 100) {
|
||||
@@ -1412,11 +1421,7 @@ void NPC::DoClassAttacks(Mob *target) {
|
||||
if(!ca_time)
|
||||
return;
|
||||
|
||||
float HasteModifier = 0;
|
||||
if (GetHaste())
|
||||
HasteModifier = 10000 / (100 + GetHaste());
|
||||
else
|
||||
HasteModifier = 100;
|
||||
float HasteModifier = GetHaste() * 0.01f;
|
||||
|
||||
int level = GetLevel();
|
||||
int reuse = TauntReuseTime * 1000; //make this very long since if they dont use it once, they prolly never will
|
||||
@@ -1568,7 +1573,7 @@ void NPC::DoClassAttacks(Mob *target) {
|
||||
}
|
||||
}
|
||||
|
||||
classattack_timer.Start(reuse*HasteModifier/100);
|
||||
classattack_timer.Start(reuse / HasteModifier);
|
||||
}
|
||||
|
||||
void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
@@ -1592,20 +1597,13 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
}
|
||||
|
||||
int ReuseTime = 0;
|
||||
int ClientHaste = GetHaste();
|
||||
int HasteMod = 0;
|
||||
float HasteMod = GetHaste() * 0.01f;
|
||||
|
||||
if(ClientHaste >= 0){
|
||||
HasteMod = (10000/(100+ClientHaste)); //+100% haste = 2x as many attacks
|
||||
}
|
||||
else{
|
||||
HasteMod = (100-ClientHaste); //-100% haste = 1/2 as many attacks
|
||||
}
|
||||
int32 dmg = 0;
|
||||
|
||||
uint16 skill_to_use = -1;
|
||||
|
||||
if (skill == -1){
|
||||
if (skill == -1){
|
||||
switch(GetClass()){
|
||||
case WARRIOR:
|
||||
case RANGER:
|
||||
@@ -1677,8 +1675,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
}
|
||||
}
|
||||
|
||||
ReuseTime = BashReuseTime-1;
|
||||
ReuseTime = (ReuseTime*HasteMod)/100;
|
||||
ReuseTime = (BashReuseTime - 1) / HasteMod;
|
||||
|
||||
DoSpecialAttackDamage(ca_target, SkillBash, dmg, 1,-1,ReuseTime);
|
||||
|
||||
@@ -1705,8 +1702,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
if (min_dmg > max_dmg)
|
||||
max_dmg = min_dmg;
|
||||
|
||||
ReuseTime = FrenzyReuseTime-1;
|
||||
ReuseTime = (ReuseTime*HasteMod)/100;
|
||||
ReuseTime = (FrenzyReuseTime - 1) / HasteMod;
|
||||
|
||||
//Live parses show around 55% Triple 35% Double 10% Single, you will always get first hit.
|
||||
while(AtkRounds > 0) {
|
||||
@@ -1756,18 +1752,21 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
return;
|
||||
|
||||
//Live AA - Technique of Master Wu
|
||||
uint16 bDoubleSpecialAttack = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
|
||||
if( bDoubleSpecialAttack && (bDoubleSpecialAttack >= 100 || bDoubleSpecialAttack > MakeRandomInt(0,100))) {
|
||||
|
||||
int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick };
|
||||
MonkSpecialAttack(ca_target, MonkSPA[MakeRandomInt(0,4)]);
|
||||
|
||||
int TripleChance = 25;
|
||||
if (bDoubleSpecialAttack > 100)
|
||||
TripleChance += TripleChance*(100-bDoubleSpecialAttack)/100;
|
||||
|
||||
if(TripleChance > MakeRandomInt(0,100)) {
|
||||
MonkSpecialAttack(ca_target, MonkSPA[MakeRandomInt(0,4)]);
|
||||
int wuchance = itembonuses.DoubleSpecialAttack + spellbonuses.DoubleSpecialAttack + aabonuses.DoubleSpecialAttack;
|
||||
if (wuchance) {
|
||||
if (wuchance >= 100 || wuchance > MakeRandomInt(0, 99)) {
|
||||
int MonkSPA [5] = { SkillFlyingKick, SkillDragonPunch, SkillEagleStrike, SkillTigerClaw, SkillRoundKick };
|
||||
int extra = 1;
|
||||
if (wuchance / 4 > MakeRandomInt(0, 99))
|
||||
extra++;
|
||||
// They didn't add a string ID for this.
|
||||
std::string msg = StringFormat("The spirit of Master Wu fills you! You gain %d additional attack(s).", extra);
|
||||
// live uses 400 here -- not sure if it's the best for all clients though
|
||||
SendColoredText(400, msg);
|
||||
while (extra) {
|
||||
MonkSpecialAttack(ca_target, MonkSPA[MakeRandomInt(0, 4)]);
|
||||
extra--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1781,7 +1780,7 @@ void Client::DoClassAttacks(Mob *ca_target, uint16 skill, bool IsRiposte)
|
||||
TryBackstab(ca_target,ReuseTime);
|
||||
}
|
||||
|
||||
ReuseTime = (ReuseTime*HasteMod)/100;
|
||||
ReuseTime = ReuseTime / HasteMod;
|
||||
if(ReuseTime > 0 && !IsRiposte){
|
||||
p_timers.Start(pTimerCombatAbility, ReuseTime);
|
||||
}
|
||||
|
||||
+101
-70
@@ -188,6 +188,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
|
||||
if (!IsPowerDistModSpell(spell_id))
|
||||
SetSpellPowerDistanceMod(0);
|
||||
|
||||
bool SE_SpellTrigger_HasCast = false;
|
||||
|
||||
// iterate through the effects in the spell
|
||||
for (i = 0; i < EFFECT_COUNT; i++)
|
||||
@@ -1265,10 +1267,11 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Blind: %+i", effect_value);
|
||||
#endif
|
||||
if (spells[spell_id].base[i] == 1)
|
||||
// this should catch the cures
|
||||
if (BeneficialSpell(spell_id) && spells[spell_id].buffduration == 0)
|
||||
BuffFadeByEffect(SE_Blind);
|
||||
// handled by client
|
||||
// TODO: blind flag?
|
||||
else if (!IsClient())
|
||||
CalculateNewFearpoint();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2729,6 +2732,25 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
Message(10, "The power of your next illusion spell will flow to your grouped target in your place.");
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_ApplyEffect: {
|
||||
|
||||
if (caster && IsValidSpell(spells[spell_id].base2[i])){
|
||||
|
||||
if(MakeRandomInt(0, 100) <= spells[spell_id].base[i])
|
||||
caster->SpellFinished(spells[spell_id].base2[i], this, 10, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_SpellTrigger: {
|
||||
|
||||
if (!SE_SpellTrigger_HasCast) {
|
||||
if (caster && caster->TrySpellTrigger(this, spell_id, i))
|
||||
SE_SpellTrigger_HasCast = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Handled Elsewhere
|
||||
case SE_ImmuneFleeing:
|
||||
@@ -2839,8 +2861,6 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_HealRate:
|
||||
case SE_SkillDamageTaken:
|
||||
case SE_FcSpellVulnerability:
|
||||
case SE_SpellTrigger:
|
||||
case SE_ApplyEffect:
|
||||
case SE_FcTwincast:
|
||||
case SE_DelayDeath:
|
||||
case SE_CastOnFadeEffect:
|
||||
@@ -3185,55 +3205,55 @@ snare has both of them negative, yet their range should work the same:
|
||||
case 124: // check sign
|
||||
result = ubase;
|
||||
if (caster_level > 50)
|
||||
result += caster_level - 50;
|
||||
result += updownsign * (caster_level - 50);
|
||||
break;
|
||||
|
||||
case 125: // check sign
|
||||
result = ubase;
|
||||
if (caster_level > 50)
|
||||
result += 2 * (caster_level - 50);
|
||||
result += updownsign * 2 * (caster_level - 50);
|
||||
break;
|
||||
|
||||
case 126: // check sign
|
||||
result = ubase;
|
||||
if (caster_level > 50)
|
||||
result += 3 * (caster_level - 50);
|
||||
result += updownsign * 3 * (caster_level - 50);
|
||||
break;
|
||||
|
||||
case 127: // check sign
|
||||
result = ubase;
|
||||
if (caster_level > 50)
|
||||
result += 4 * (caster_level - 50);
|
||||
result += updownsign * 4 * (caster_level - 50);
|
||||
break;
|
||||
|
||||
case 128: // check sign
|
||||
result = ubase;
|
||||
if (caster_level > 50)
|
||||
result += 5 * (caster_level - 50);
|
||||
result += updownsign * 5 * (caster_level - 50);
|
||||
break;
|
||||
|
||||
case 129: // check sign
|
||||
result = ubase;
|
||||
if (caster_level > 50)
|
||||
result += 10 * (caster_level - 50);
|
||||
result += updownsign * 10 * (caster_level - 50);
|
||||
break;
|
||||
|
||||
case 130: // check sign
|
||||
result = ubase;
|
||||
if (caster_level > 50)
|
||||
result += 15 * (caster_level - 50);
|
||||
result += updownsign * 15 * (caster_level - 50);
|
||||
break;
|
||||
|
||||
case 131: // check sign
|
||||
result = ubase;
|
||||
if (caster_level > 50)
|
||||
result += 20 * (caster_level - 50);
|
||||
result += updownsign * 20 * (caster_level - 50);
|
||||
break;
|
||||
|
||||
case 132: // check sign
|
||||
result = ubase;
|
||||
if (caster_level > 50)
|
||||
result += 25 * (caster_level - 50);
|
||||
result += updownsign * 25 * (caster_level - 50);
|
||||
break;
|
||||
|
||||
case 137: // used in berserker AA desperation
|
||||
@@ -3375,7 +3395,10 @@ void Mob::BuffProcess()
|
||||
{
|
||||
if(buffs[buffs_i].UpdateClient == true)
|
||||
{
|
||||
CastToClient()->SendBuffDurationPacket(buffs[buffs_i].spellid, buffs[buffs_i].ticsremaining, buffs[buffs_i].casterlevel);
|
||||
CastToClient()->SendBuffDurationPacket(buffs[buffs_i]);
|
||||
// Hack to get UF to play nicer, RoF seems fine without it
|
||||
if (CastToClient()->GetClientVersion() == EQClientUnderfoot && buffs[buffs_i].numhits > 0)
|
||||
CastToClient()->SendBuffNumHitPacket(buffs[buffs_i], buffs_i);
|
||||
buffs[buffs_i].UpdateClient = false;
|
||||
}
|
||||
}
|
||||
@@ -3976,6 +3999,11 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Blind:
|
||||
if (curfp && !FindType(SE_Fear))
|
||||
curfp = false;
|
||||
break;
|
||||
|
||||
case SE_Fear:
|
||||
{
|
||||
if(RuleB(Combat, EnableFearPathing)){
|
||||
@@ -4140,6 +4168,12 @@ void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
if (IsNPC()) {
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket();
|
||||
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, BIT_SoDAndLater, true);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
if(IsClient() && CastToClient()->GetClientVersionBit() & BIT_UnderfootAndLater)
|
||||
{
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket(false);
|
||||
@@ -5534,92 +5568,85 @@ void Mob::CheckNumHitsRemaining(uint8 type, uint32 buff_slot, uint16 spell_id)
|
||||
uint32 buff_max = GetMaxTotalSlots();
|
||||
|
||||
//Spell specific procs [Type 7,10,11]
|
||||
if (IsValidSpell(spell_id)){
|
||||
|
||||
for(uint32 d = 0; d < buff_max; d++) {
|
||||
|
||||
if((buffs[d].spellid == spell_id) && (buffs[d].numhits > 0) && (spells[buffs[d].spellid].numhitstype == type)){
|
||||
|
||||
if(--buffs[d].numhits == 0) {
|
||||
if (IsValidSpell(spell_id)) {
|
||||
for (uint32 d = 0; d < buff_max; d++) {
|
||||
if (buffs[d].spellid == spell_id && buffs[d].numhits > 0 &&
|
||||
spells[buffs[d].spellid].numhitstype == type) {
|
||||
if (--buffs[d].numhits == 0) {
|
||||
CastOnNumHitFade(buffs[d].spellid);
|
||||
if(!TryFadeEffect(d))
|
||||
if (!TryFadeEffect(d))
|
||||
BuffFadeBySlot(d, true);
|
||||
} else if (IsClient()) { // still have numhits and client, update
|
||||
CastToClient()->SendBuffNumHitPacket(buffs[d], d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (type == 7){
|
||||
if (buff_slot > 0){
|
||||
|
||||
if(--buffs[buff_slot].numhits == 0) {
|
||||
} else if (type == 7) {
|
||||
if (buff_slot > 0) {
|
||||
if (--buffs[buff_slot].numhits == 0) {
|
||||
CastOnNumHitFade(buffs[buff_slot].spellid);
|
||||
if(!TryFadeEffect(buff_slot))
|
||||
if (!TryFadeEffect(buff_slot))
|
||||
BuffFadeBySlot(buff_slot , true);
|
||||
}
|
||||
} else if (IsClient()) { // still have numhits and client, update
|
||||
CastToClient()->SendBuffNumHitPacket(buffs[buff_slot], buff_slot);
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
for(int d = 0; d < buff_max; d++) {
|
||||
|
||||
if(!m_spellHitsLeft[d])
|
||||
} else {
|
||||
for (int d = 0; d < buff_max; d++) {
|
||||
if (!m_spellHitsLeft[d])
|
||||
continue;
|
||||
|
||||
if ((IsValidSpell(buffs[d].spellid)) && (m_spellHitsLeft[d] == buffs[d].spellid)) {
|
||||
if(--buffs[d].numhits == 0) {
|
||||
if (IsValidSpell(buffs[d].spellid) && m_spellHitsLeft[d] == buffs[d].spellid) {
|
||||
if (--buffs[d].numhits == 0) {
|
||||
CastOnNumHitFade(buffs[d].spellid);
|
||||
m_spellHitsLeft[d] = 0;
|
||||
if(!TryFadeEffect(d))
|
||||
if (!TryFadeEffect(d))
|
||||
BuffFadeBySlot(d, true);
|
||||
} else if (IsClient()) { // still have numhits and client, update
|
||||
CastToClient()->SendBuffNumHitPacket(buffs[d], d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
else{
|
||||
|
||||
for(uint32 d = 0; d < buff_max; d++) {
|
||||
|
||||
if((IsValidSpell(buffs[d].spellid)) && (buffs[d].numhits > 0) && (spells[buffs[d].spellid].numhitstype == type)){
|
||||
|
||||
if(--buffs[d].numhits == 0) {
|
||||
} else {
|
||||
for (uint32 d = 0; d < buff_max; d++) {
|
||||
if (IsValidSpell(buffs[d].spellid) && buffs[d].numhits > 0 &&
|
||||
spells[buffs[d].spellid].numhitstype == type) {
|
||||
if (--buffs[d].numhits == 0) {
|
||||
CastOnNumHitFade(buffs[d].spellid);
|
||||
if(!TryFadeEffect(d)){
|
||||
if (!TryFadeEffect(d))
|
||||
BuffFadeBySlot(d, true);
|
||||
}
|
||||
} else if (IsClient()) { // still have numhits and client, update
|
||||
CastToClient()->SendBuffNumHitPacket(buffs[d], d);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//for some stupid reason SK procs return theirs one base off...
|
||||
uint16 Mob::GetProcID(uint16 spell_id, uint8 effect_index) {
|
||||
uint16 Mob::GetProcID(uint16 spell_id, uint8 effect_index)
|
||||
{
|
||||
if (!RuleB(Spells, SHDProcIDOffByOne)) // UF+ spell files
|
||||
return spells[spell_id].base[effect_index];
|
||||
|
||||
// We should actually just be checking if the mob is SHD, but to not force
|
||||
// custom servers to create new spells, we will still do this
|
||||
bool sk = false;
|
||||
bool other = false;
|
||||
for(int x = 0; x < 16; x++)
|
||||
{
|
||||
if(x == 4){
|
||||
if(spells[spell_id].classes[4] < 255)
|
||||
for (int x = 0; x < 16; x++) {
|
||||
if (x == 4) {
|
||||
if (spells[spell_id].classes[4] < 255)
|
||||
sk = true;
|
||||
}
|
||||
else{
|
||||
if(spells[spell_id].classes[x] < 255)
|
||||
} else {
|
||||
if (spells[spell_id].classes[x] < 255)
|
||||
other = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(sk && !other)
|
||||
{
|
||||
return(spells[spell_id].base[effect_index] + 1);
|
||||
}
|
||||
else{
|
||||
return(spells[spell_id].base[effect_index]);
|
||||
}
|
||||
if (sk && !other)
|
||||
return spells[spell_id].base[effect_index] + 1;
|
||||
else
|
||||
return spells[spell_id].base[effect_index];
|
||||
}
|
||||
|
||||
bool Mob::TryDivineSave()
|
||||
@@ -6453,8 +6480,12 @@ void Mob::ResourceTap(int32 damage, uint16 spellid){
|
||||
if (spells[spellid].max[i] && (damage > spells[spellid].max[i]))
|
||||
damage = spells[spellid].max[i];
|
||||
|
||||
if (spells[spellid].base2[i] == 0) //HP Tap
|
||||
SetHP((GetHP()+ damage));
|
||||
if (spells[spellid].base2[i] == 0){ //HP Tap
|
||||
if (damage > 0)
|
||||
HealDamage(damage);
|
||||
else
|
||||
Damage(this, -damage,0, SkillEvocation,false);
|
||||
}
|
||||
|
||||
if (spells[spellid].base2[i] == 1) //Mana Tap
|
||||
SetMana(GetMana() + damage);
|
||||
|
||||
+72
-112
@@ -2215,6 +2215,12 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
ItemInst *itm = CastToClient()->GetInv().GetItem(inventory_slot);
|
||||
if(itm && itm->GetItem()->RecastDelay > 0){
|
||||
CastToClient()->GetPTimers().Start((pTimerItemStart + itm->GetItem()->RecastType), itm->GetItem()->RecastDelay);
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_ItemRecastDelay, sizeof(ItemRecastDelay_Struct));
|
||||
ItemRecastDelay_Struct *ird = (ItemRecastDelay_Struct *)outapp->pBuffer;
|
||||
ird->recast_delay = itm->GetItem()->RecastDelay;
|
||||
ird->recast_type = itm->GetItem()->RecastType;
|
||||
CastToClient()->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3122,6 +3128,12 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
if (IsNPC()) {
|
||||
EQApplicationPacket *outapp = MakeBuffsPacket();
|
||||
entity_list.QueueClientsByTarget(this, outapp, false, nullptr, true, false, BIT_SoDAndLater, true);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
// recalculate bonuses since we stripped/added buffs
|
||||
CalcBonuses();
|
||||
|
||||
@@ -3606,108 +3618,9 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
spell_effectiveness = 100;
|
||||
}
|
||||
|
||||
// Recourse means there is a spell linked to that spell in that the recourse spell will
|
||||
// be automatically casted on the casters group or the caster only depending on Targettype
|
||||
// this is for things like dark empathy, shadow vortex
|
||||
int recourse_spell=0;
|
||||
recourse_spell = spells[spell_id].RecourseLink;
|
||||
if(recourse_spell)
|
||||
{
|
||||
if(spells[recourse_spell].targettype == ST_Group || spells[recourse_spell].targettype == ST_GroupTeleport)
|
||||
{
|
||||
if(IsGrouped())
|
||||
{
|
||||
Group *g = entity_list.GetGroupByMob(this);
|
||||
if(g)
|
||||
g->CastGroupSpell(this, recourse_spell);
|
||||
else{
|
||||
SpellOnTarget(recourse_spell, this);
|
||||
#ifdef GROUP_BUFF_PETS
|
||||
if (GetPet())
|
||||
SpellOnTarget(recourse_spell, GetPet());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if(IsRaidGrouped() && IsClient())
|
||||
{
|
||||
Raid *r = entity_list.GetRaidByClient(CastToClient());
|
||||
uint32 gid = 0xFFFFFFFF;
|
||||
if(r)
|
||||
gid = r->GetGroup(GetName());
|
||||
else
|
||||
gid = 13; // Forces ungrouped spell casting
|
||||
|
||||
if(gid < 12)
|
||||
{
|
||||
r->CastGroupSpell(this, recourse_spell, gid);
|
||||
}
|
||||
else{
|
||||
SpellOnTarget(recourse_spell, this);
|
||||
#ifdef GROUP_BUFF_PETS
|
||||
if (GetPet())
|
||||
SpellOnTarget(recourse_spell, GetPet());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if(HasOwner())
|
||||
{
|
||||
if(GetOwner()->IsGrouped())
|
||||
{
|
||||
Group *g = entity_list.GetGroupByMob(GetOwner());
|
||||
if(g)
|
||||
g->CastGroupSpell(this, recourse_spell);
|
||||
else{
|
||||
SpellOnTarget(recourse_spell, GetOwner());
|
||||
SpellOnTarget(recourse_spell, this);
|
||||
}
|
||||
}
|
||||
else if(GetOwner()->IsRaidGrouped() && GetOwner()->IsClient())
|
||||
{
|
||||
Raid *r = entity_list.GetRaidByClient(GetOwner()->CastToClient());
|
||||
uint32 gid = 0xFFFFFFFF;
|
||||
if(r)
|
||||
gid = r->GetGroup(GetOwner()->GetName());
|
||||
else
|
||||
gid = 13; // Forces ungrouped spell casting
|
||||
|
||||
if(gid < 12)
|
||||
{
|
||||
r->CastGroupSpell(this, recourse_spell, gid);
|
||||
}
|
||||
else
|
||||
{
|
||||
SpellOnTarget(recourse_spell, GetOwner());
|
||||
SpellOnTarget(recourse_spell, this);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SpellOnTarget(recourse_spell, GetOwner());
|
||||
SpellOnTarget(recourse_spell, this);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SpellOnTarget(recourse_spell, this);
|
||||
#ifdef GROUP_BUFF_PETS
|
||||
if (GetPet())
|
||||
SpellOnTarget(recourse_spell, GetPet());
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
SpellOnTarget(recourse_spell, this);
|
||||
}
|
||||
}
|
||||
|
||||
if(spelltar->spellbonuses.SpellDamageShield && IsDetrimentalSpell(spell_id))
|
||||
spelltar->DamageShield(this, true);
|
||||
|
||||
TrySpellTrigger(spelltar, spell_id);
|
||||
TryApplyEffect(spelltar, spell_id);
|
||||
|
||||
if (spelltar->IsAIControlled() && IsDetrimentalSpell(spell_id) && !IsHarmonySpell(spell_id)) {
|
||||
int32 aggro_amount = CheckAggroAmount(spell_id, isproc);
|
||||
mlog(SPELLS__CASTING, "Spell %d cast on %s generated %d hate", spell_id, spelltar->GetName(), aggro_amount);
|
||||
@@ -3746,7 +3659,9 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (IsValidSpell(spells[spell_id].RecourseLink))
|
||||
SpellFinished(spells[spell_id].RecourseLink, this, 10, 0, -1, spells[spells[spell_id].RecourseLink].ResistDiff);
|
||||
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
|
||||
CheckNumHitsRemaining(NUMHIT_OutgoingSpells);
|
||||
@@ -4817,8 +4732,8 @@ void Client::MakeBuffFadePacket(uint16 spell_id, int slot_id, bool send_message)
|
||||
if(send_message)
|
||||
{
|
||||
const char *fadetext = spells[spell_id].spell_fades;
|
||||
outapp = new EQApplicationPacket(OP_BuffFadeMsg, sizeof(BuffFadeMsg_Struct) + strlen(fadetext));
|
||||
BuffFadeMsg_Struct *bfm = (BuffFadeMsg_Struct *) outapp->pBuffer;
|
||||
outapp = new EQApplicationPacket(OP_ColoredText, sizeof(ColoredText_Struct) + strlen(fadetext));
|
||||
ColoredText_Struct *bfm = (ColoredText_Struct *) outapp->pBuffer;
|
||||
bfm->color = MT_Spells;
|
||||
memcpy(bfm->msg, fadetext, strlen(fadetext));
|
||||
QueuePacket(outapp);
|
||||
@@ -4841,6 +4756,8 @@ void Client::MemSpell(uint16 spell_id, int slot, bool update_client)
|
||||
m_pp.mem_spells[slot] = spell_id;
|
||||
mlog(CLIENT__SPELLS, "Spell %d memorized into slot %d", spell_id, slot);
|
||||
|
||||
database.SaveCharacterMemorizedSpell(this->CharacterID(), m_pp.mem_spells[slot], slot);
|
||||
|
||||
if(update_client)
|
||||
{
|
||||
MemorizeSpell(slot, spell_id, memSpellMemorize);
|
||||
@@ -4855,6 +4772,8 @@ void Client::UnmemSpell(int slot, bool update_client)
|
||||
mlog(CLIENT__SPELLS, "Spell %d forgotten from slot %d", m_pp.mem_spells[slot], slot);
|
||||
m_pp.mem_spells[slot] = 0xFFFFFFFF;
|
||||
|
||||
database.DeleteCharacterMemorizedSpell(this->CharacterID(), m_pp.mem_spells[slot], slot);
|
||||
|
||||
if(update_client)
|
||||
{
|
||||
MemorizeSpell(slot, m_pp.mem_spells[slot], memSpellForget);
|
||||
@@ -4882,6 +4801,7 @@ void Client::ScribeSpell(uint16 spell_id, int slot, bool update_client)
|
||||
}
|
||||
|
||||
m_pp.spell_book[slot] = spell_id;
|
||||
database.SaveCharacterSpell(this->CharacterID(), spell_id, slot);
|
||||
mlog(CLIENT__SPELLS, "Spell %d scribed into spell book slot %d", spell_id, slot);
|
||||
|
||||
if(update_client)
|
||||
@@ -4897,7 +4817,8 @@ void Client::UnscribeSpell(int slot, bool update_client)
|
||||
|
||||
mlog(CLIENT__SPELLS, "Spell %d erased from spell book slot %d", m_pp.spell_book[slot], slot);
|
||||
m_pp.spell_book[slot] = 0xFFFFFFFF;
|
||||
|
||||
|
||||
database.DeleteCharacterSpell(this->CharacterID(), m_pp.spell_book[slot], slot);
|
||||
if(update_client)
|
||||
{
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_DeleteSpell, sizeof(DeleteSpell_Struct));
|
||||
@@ -4925,8 +4846,9 @@ void Client::UntrainDisc(int slot, bool update_client)
|
||||
if(slot >= MAX_PP_DISCIPLINES || slot < 0)
|
||||
return;
|
||||
|
||||
mlog(CLIENT__SPELLS, "Discipline %d untrained from slot %d", m_pp.disciplines.values[slot], slot);
|
||||
mlog(CLIENT__SPELLS, "Discipline %d untrained from slot %d", m_pp.disciplines.values[slot], slot);
|
||||
m_pp.disciplines.values[slot] = 0;
|
||||
database.DeleteCharacterDisc(this->CharacterID(), slot);
|
||||
|
||||
if(update_client)
|
||||
{
|
||||
@@ -5241,20 +5163,40 @@ void Mob::_StopSong()
|
||||
//Thus I use this in the buff process to update the correct duration once after casting
|
||||
//this allows AAs and focus effects that increase buff duration to work correctly, but could probably
|
||||
//be used for other things as well
|
||||
void Client::SendBuffDurationPacket(uint16 spell_id, int duration, int inlevel)
|
||||
void Client::SendBuffDurationPacket(Buffs_Struct &buff)
|
||||
{
|
||||
EQApplicationPacket* outapp;
|
||||
outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffFade_Struct));
|
||||
SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*) outapp->pBuffer;
|
||||
|
||||
sbf->entityid = GetID();
|
||||
sbf->slot=2;
|
||||
sbf->spellid=spell_id;
|
||||
sbf->slotid=0;
|
||||
sbf->effect = inlevel > 0 ? inlevel : GetLevel();
|
||||
sbf->level = inlevel > 0 ? inlevel : GetLevel();
|
||||
sbf->slot = 2;
|
||||
sbf->spellid = buff.spellid;
|
||||
sbf->slotid = 0;
|
||||
sbf->effect = buff.casterlevel > 0 ? buff.casterlevel : GetLevel();
|
||||
sbf->level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel();
|
||||
sbf->bufffade = 0;
|
||||
sbf->duration = duration;
|
||||
sbf->duration = buff.ticsremaining;
|
||||
sbf->num_hits = buff.numhits;
|
||||
FastQueuePacket(&outapp);
|
||||
}
|
||||
|
||||
void Client::SendBuffNumHitPacket(Buffs_Struct &buff, int slot)
|
||||
{
|
||||
// UF+ use this packet
|
||||
if (GetClientVersion() < EQClientUnderfoot)
|
||||
return;
|
||||
EQApplicationPacket *outapp;
|
||||
outapp = new EQApplicationPacket(OP_BuffCreate, sizeof(BuffIcon_Struct) + sizeof(BuffIconEntry_Struct));
|
||||
BuffIcon_Struct *bi = (BuffIcon_Struct *)outapp->pBuffer;
|
||||
bi->entity_id = GetID();
|
||||
bi->count = 1;
|
||||
bi->all_buffs = 0;
|
||||
|
||||
bi->entries[0].buff_slot = slot;
|
||||
bi->entries[0].spell_id = buff.spellid;
|
||||
bi->entries[0].tics_remaining = buff.ticsremaining;
|
||||
bi->entries[0].num_hits = buff.numhits;
|
||||
FastQueuePacket(&outapp);
|
||||
}
|
||||
|
||||
@@ -5329,6 +5271,7 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target)
|
||||
BuffIcon_Struct *buff = (BuffIcon_Struct*)outapp->pBuffer;
|
||||
buff->entity_id = GetID();
|
||||
buff->count = count;
|
||||
buff->all_buffs = 1;
|
||||
|
||||
uint32 index = 0;
|
||||
for(unsigned int i = 0; i < buff_count; ++i)
|
||||
@@ -5338,6 +5281,7 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target)
|
||||
buff->entries[index].buff_slot = i;
|
||||
buff->entries[index].spell_id = buffs[i].spellid;
|
||||
buff->entries[index].tics_remaining = buffs[i].ticsremaining;
|
||||
buff->entries[index].num_hits = buffs[i].numhits;
|
||||
++index;
|
||||
}
|
||||
}
|
||||
@@ -5355,7 +5299,7 @@ void Mob::BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration)
|
||||
buffs[i].ticsremaining = newDuration;
|
||||
if(IsClient())
|
||||
{
|
||||
CastToClient()->SendBuffDurationPacket(buffs[i].spellid, buffs[i].ticsremaining, buffs[i].casterlevel);
|
||||
CastToClient()->SendBuffDurationPacket(buffs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5406,3 +5350,19 @@ void NPC::UninitializeBuffSlots()
|
||||
safe_delete_array(buffs);
|
||||
}
|
||||
|
||||
void Client::SendSpellAnim(uint16 targetid, uint16 spell_id)
|
||||
{
|
||||
if (!targetid || !IsValidSpell(spell_id))
|
||||
return;
|
||||
|
||||
EQApplicationPacket app(OP_Action, sizeof(Action_Struct));
|
||||
Action_Struct* a = (Action_Struct*)app.pBuffer;
|
||||
a->target = targetid;
|
||||
a->source = this->GetID();
|
||||
a->type = 231;
|
||||
a->spell = spell_id;
|
||||
a->sequence = 231;
|
||||
|
||||
app.priority = 1;
|
||||
entity_list.QueueCloseClients(this, &app);
|
||||
}
|
||||
|
||||
@@ -163,6 +163,8 @@
|
||||
#define CANNOT_WAKE 555 //%1 tells you, 'I am unable to wake %2, master.'
|
||||
#define GUILD_NAME_IN_USE 711 //You cannot create a guild with that name, that guild already exists on this server.
|
||||
#define GM_GAINXP 1002 //[GM] You have gained %1 AXP and %2 EXP (%3).
|
||||
#define MALE_SLAYUNDEAD 1007 //%1's holy blade cleanses his target!(%2)
|
||||
#define FEMALE_SLAYUNDEAD 1008 //%1's holy blade cleanses her target!(%2)
|
||||
#define FINISHING_BLOW 1009 //%1 scores a Finishing Blow!!
|
||||
#define ASSASSINATES 1016 //%1 ASSASSINATES their victim!!
|
||||
#define CRIPPLING_BLOW 1021 //%1 lands a Crippling Blow!(%2)
|
||||
@@ -249,6 +251,8 @@
|
||||
#define PLAYER_CHARMED 1461 //You lose control of yourself!
|
||||
#define TRADER_BUSY 1468 //That Trader is currently with a customer. Please wait until their transaction is finished.
|
||||
#define SENSE_CORPSE_DIRECTION 1563 //You sense a corpse in this direction.
|
||||
#define QUEUED_TELL 2458 //[queued]
|
||||
#define QUEUE_TELL_FULL 2459 //[zoing and queue is full]
|
||||
#define SUSPEND_MINION_UNSUSPEND 3267 //%1 tells you, 'I live again...'
|
||||
#define SUSPEND_MINION_SUSPEND 3268 //%1 tells you, 'By your command, master.'
|
||||
#define ONLY_SUMMONED_PETS 3269 //3269 This effect only works with summoned pets.
|
||||
@@ -269,8 +273,11 @@
|
||||
#define CORPSEDRAG_STOP 4066 //You stop dragging the corpse.
|
||||
#define TARGET_TOO_CLOSE 4602 //You are too close to your target. Get farther away.
|
||||
#define WHOALL_NO_RESULTS 5029 //There are no players in EverQuest that match those who filters.
|
||||
#define TELL_QUEUED_MESSAGE 5045 //You told %1 '%T2. %3'
|
||||
#define TOLD_NOT_ONLINE 5046 //%1 is not online at this time.
|
||||
#define PETITION_NO_DELETE 5053 //You do not have a petition in the queue.
|
||||
#define PETITION_DELETED 5054 //Your petition was successfully deleted.
|
||||
#define ALREADY_IN_RAID 5060 //%1 is already in a raid.
|
||||
#define GAIN_RAIDEXP 5085 //You gained raid experience!
|
||||
#define DUNGEON_SEALED 5141 //The gateway to the dungeon is sealed off to you. Perhaps you would be able to enter if you needed to adventure there.
|
||||
#define ADVENTURE_COMPLETE 5147 //You received %1 points for successfully completing the adventure.
|
||||
|
||||
+617
-818
File diff suppressed because it is too large
Load Diff
+287
-409
@@ -142,7 +142,7 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme
|
||||
// Adding augment
|
||||
if (in_augment->augment_slot == -1)
|
||||
{
|
||||
if (((slot=tobe_auged->AvailableAugmentSlot(auged_with->GetAugmentType()))!=-1) &&
|
||||
if (((slot=tobe_auged->AvailableAugmentSlot(auged_with->GetAugmentType()))!=-1) &&
|
||||
(tobe_auged->AvailableWearSlot(auged_with->GetItem()->Slots)))
|
||||
{
|
||||
tobe_auged->PutAugment(slot, *auged_with);
|
||||
@@ -424,38 +424,28 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
char *query = 0;
|
||||
|
||||
uint32 qlen = 0;
|
||||
uint8 qcount = 0;
|
||||
|
||||
//pull the list of components
|
||||
qlen = MakeAnyLenString(&query, "SELECT tre.item_id,tre.componentcount "
|
||||
" FROM tradeskill_recipe_entries AS tre "
|
||||
" WHERE tre.componentcount > 0 AND tre.recipe_id=%u", rac->recipe_id);
|
||||
|
||||
if (!database.RunQuery(query, qlen, errbuf, &result)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in HandleAutoCombine query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
//pull the list of components
|
||||
std::string query = StringFormat("SELECT tre.item_id, tre.componentcount "
|
||||
"FROM tradeskill_recipe_entries AS tre "
|
||||
"WHERE tre.componentcount > 0 AND tre.recipe_id = %u",
|
||||
rac->recipe_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in HandleAutoCombine query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
user->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
qcount = mysql_num_rows(result);
|
||||
if(qcount < 1) {
|
||||
if(results.RowCount() < 1) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in HandleAutoCombine: no components returned");
|
||||
user->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
}
|
||||
if(qcount > 10) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in HandleAutoCombine: too many components returned (%u)", qcount);
|
||||
|
||||
if(results.RowCount() > 10) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in HandleAutoCombine: too many components returned (%u)", results.RowCount());
|
||||
user->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
return;
|
||||
@@ -466,17 +456,15 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac
|
||||
uint8 counts[10];
|
||||
memset(counts, 0, sizeof(counts));
|
||||
|
||||
|
||||
//search for all the items in their inventory
|
||||
Inventory& user_inv = user->GetInv();
|
||||
uint8 count = 0;
|
||||
uint8 needcount = 0;
|
||||
uint8 r,k;
|
||||
|
||||
std::list<int> MissingItems;
|
||||
|
||||
for(r = 0; r < qcount; r++) {
|
||||
row = mysql_fetch_row(result);
|
||||
uint8 needItemIndex = 0;
|
||||
for (auto row = results.begin(); row != results.end(); ++row, ++needItemIndex) {
|
||||
uint32 item = (uint32)atoi(row[0]);
|
||||
uint8 num = (uint8) atoi(row[1]);
|
||||
|
||||
@@ -491,10 +479,9 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac
|
||||
MissingItems.push_back(item);
|
||||
|
||||
//dont start deleting anything until we have found it all.
|
||||
items[r] = item;
|
||||
counts[r] = num;
|
||||
items[needItemIndex] = item;
|
||||
counts[needItemIndex] = num;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
|
||||
//make sure we found it all...
|
||||
if(count != needcount)
|
||||
@@ -520,12 +507,12 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac
|
||||
|
||||
//remove all the items from the players inventory, with updates...
|
||||
int16 slot;
|
||||
for(r = 0; r < qcount; r++) {
|
||||
for(uint8 r = 0; r < results.RowCount(); r++) {
|
||||
if(items[r] == 0 || counts[r] == 0)
|
||||
continue; //skip empties, could prolly break here
|
||||
|
||||
//we have to loop here to delete 1 at a time in case its in multiple stacks.
|
||||
for(k = 0; k < counts[r]; k++) {
|
||||
for(uint8 k = 0; k < counts[r]; k++) {
|
||||
slot = user_inv.HasItem(items[r], 1, invWherePersonal);
|
||||
if (slot == INVALID_INDEX) {
|
||||
//WTF... I just checked this above, but just to be sure...
|
||||
@@ -539,19 +526,14 @@ void Object::HandleAutoCombine(Client* user, const RecipeAutoCombine_Struct* rac
|
||||
const ItemInst* inst = user_inv.GetItem(slot);
|
||||
|
||||
if (inst && !inst->IsStackable())
|
||||
{
|
||||
user->DeleteItemInInventory(slot, 0, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
user->DeleteItemInInventory(slot, 1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//otherwise, we found it all...
|
||||
outp->reply_code = 0x00000000; //success for finding it...
|
||||
|
||||
user->QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
@@ -654,34 +636,26 @@ SkillUseTypes Object::TypeToSkill(uint32 type)
|
||||
return TradeskillUnknown;
|
||||
}
|
||||
|
||||
void Client::TradeskillSearchResults(const char *query, unsigned long qlen, unsigned long objtype, unsigned long someid) {
|
||||
void Client::TradeskillSearchResults(const std::string query, unsigned long objtype, unsigned long someid) {
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
if (!database.RunQuery(query, qlen, errbuf, &result)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in TradeskillSearchResults query '%s': %s", query, errbuf);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in TradeskillSearchResults query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 qcount = 0;
|
||||
if(results.RowCount() < 1)
|
||||
return; //search gave no results... not an error
|
||||
|
||||
qcount = mysql_num_rows(result);
|
||||
if(qcount < 1) {
|
||||
//search gave no results... not an error
|
||||
return;
|
||||
}
|
||||
if(mysql_num_fields(result) != 6) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in TradeskillSearchResults query '%s': Invalid column count in result", query);
|
||||
if(results.ColumnCount() != 6) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in TradeskillSearchResults query '%s': Invalid column count in result", query.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 r;
|
||||
for(r = 0; r < qcount; r++) {
|
||||
row = mysql_fetch_row(result);
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
if(row == nullptr || row[0] == nullptr || row[1] == nullptr || row[2] == nullptr || row[3] == nullptr || row[5] == nullptr)
|
||||
continue;
|
||||
|
||||
uint32 recipe = (uint32)atoi(row[0]);
|
||||
const char *name = row[1];
|
||||
uint32 trivial = (uint32) atoi(row[2]);
|
||||
@@ -691,14 +665,10 @@ void Client::TradeskillSearchResults(const char *query, unsigned long qlen, unsi
|
||||
// Skip the recipes that exceed the threshold in skill difference
|
||||
// Recipes that have either been made before or were
|
||||
// explicitly learned are excempt from that limit
|
||||
if (RuleB(Skills, UseLimitTradeskillSearchSkillDiff)) {
|
||||
if (((int32)trivial - (int32)GetSkill((SkillUseTypes)tradeskill)) > RuleI(Skills, MaxTradeskillSearchSkillDiff)
|
||||
&& row[4] == nullptr)
|
||||
{
|
||||
if (RuleB(Skills, UseLimitTradeskillSearchSkillDiff)
|
||||
&& ((int32)trivial - (int32)GetSkill((SkillUseTypes)tradeskill)) > RuleI(Skills, MaxTradeskillSearchSkillDiff)
|
||||
&& row[4] == nullptr)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_RecipeReply, sizeof(RecipeReply_Struct));
|
||||
RecipeReply_Struct *reply = (RecipeReply_Struct *) outapp->pBuffer;
|
||||
@@ -711,39 +681,30 @@ void Client::TradeskillSearchResults(const char *query, unsigned long qlen, unsi
|
||||
strn0cpy(reply->recipe_name, name, sizeof(reply->recipe_name));
|
||||
FastQueuePacket(&outapp);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
|
||||
}
|
||||
|
||||
void Client::SendTradeskillDetails(uint32 recipe_id) {
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
char *query = 0;
|
||||
|
||||
uint32 qlen = 0;
|
||||
uint8 qcount = 0;
|
||||
|
||||
//pull the list of components
|
||||
qlen = MakeAnyLenString(&query, "SELECT tre.item_id,tre.componentcount,i.icon,i.Name "
|
||||
" FROM tradeskill_recipe_entries AS tre "
|
||||
" LEFT JOIN items AS i ON tre.item_id = i.id "
|
||||
" WHERE tre.componentcount > 0 AND tre.recipe_id=%u", recipe_id);
|
||||
|
||||
if (!database.RunQuery(query, qlen, errbuf, &result)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in SendTradeskillDetails query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
//pull the list of components
|
||||
std::string query = StringFormat("SELECT tre.item_id,tre.componentcount,i.icon,i.Name "
|
||||
"FROM tradeskill_recipe_entries AS tre "
|
||||
"LEFT JOIN items AS i ON tre.item_id = i.id "
|
||||
"WHERE tre.componentcount > 0 AND tre.recipe_id = %u",
|
||||
recipe_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in SendTradeskillDetails query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
qcount = mysql_num_rows(result);
|
||||
if(qcount < 1) {
|
||||
if(results.RowCount() < 1) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in SendTradeskillDetails: no components returned");
|
||||
return;
|
||||
}
|
||||
if(qcount > 10) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in SendTradeskillDetails: too many components returned (%u)", qcount);
|
||||
|
||||
if(results.RowCount() > 10) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in SendTradeskillDetails: too many components returned (%u)", results.RowCount());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -773,20 +734,18 @@ void Client::SendTradeskillDetails(uint32 recipe_id) {
|
||||
uint32 len;
|
||||
uint32 datalen = 0;
|
||||
uint8 count = 0;
|
||||
for(r = 0; r < qcount; r++) {
|
||||
row = mysql_fetch_row(result);
|
||||
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
|
||||
//watch for references to items which are not in the
|
||||
//items table, which the left join will make nullptr...
|
||||
if(row[2] == nullptr || row[3] == nullptr) {
|
||||
if(row[2] == nullptr || row[3] == nullptr)
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 item = (uint32)atoi(row[0]);
|
||||
uint8 num = (uint8) atoi(row[1]);
|
||||
|
||||
|
||||
uint32 icon = (uint32) atoi(row[2]);
|
||||
|
||||
const char *name = row[3];
|
||||
len = strlen(name);
|
||||
if(len > 63)
|
||||
@@ -816,7 +775,6 @@ void Client::SendTradeskillDetails(uint32 recipe_id) {
|
||||
}
|
||||
|
||||
}
|
||||
mysql_free_result(result);
|
||||
|
||||
//now move the item data over top of the FFFFs
|
||||
uint8 dist = sizeof(uint32) * (10 - count);
|
||||
@@ -1094,7 +1052,7 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
|
||||
++itr;
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
/* Tradeskill Fail */
|
||||
else {
|
||||
success_modifier = 2; // Halves the chance
|
||||
@@ -1172,7 +1130,7 @@ void Client::CheckIncreaseTradeskill(int16 bonusstat, int16 stat_modifier, float
|
||||
chance_stage2 = 12.5 - (.08 * (current_raw_skill - 175));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
chance_stage2 = mod_tradeskill_skillup(chance_stage2);
|
||||
|
||||
if (chance_stage2 > MakeRandomFloat(0, 99)) {
|
||||
@@ -1191,249 +1149,212 @@ 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)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
char *query = 0;
|
||||
char buf2[4096];
|
||||
|
||||
uint32 sum = 0;
|
||||
uint32 count = 0;
|
||||
uint32 qcount = 0;
|
||||
uint32 qlen = 0;
|
||||
|
||||
// make where clause segment for container(s)
|
||||
char containers[30];
|
||||
if (some_id == 0) {
|
||||
// world combiner so no item number
|
||||
snprintf(containers,29, "= %u", c_type);
|
||||
} else {
|
||||
// container in inventory
|
||||
snprintf(containers,29, "in (%u,%u)", c_type, some_id);
|
||||
}
|
||||
|
||||
buf2[0] = '\0';
|
||||
std::string containers;// make where clause segment for container(s)
|
||||
if (some_id == 0)
|
||||
containers = StringFormat("= %u", c_type); // world combiner so no item number
|
||||
else
|
||||
containers = StringFormat("IN (%u,%u)", c_type, some_id); // container in inventory
|
||||
|
||||
//Could prolly watch for stacks in this loop and handle them properly...
|
||||
//just increment sum and count accordingly
|
||||
bool first = true;
|
||||
uint8 i;
|
||||
char *pos = buf2;
|
||||
for (i = 0; i < 10; i++) { // <watch> TODO: need to determine if this is bound to world/item container size
|
||||
std::string buf2;
|
||||
uint32 count = 0;
|
||||
uint32 sum = 0;
|
||||
for (uint8 i = 0; i < 10; i++) { // <watch> TODO: need to determine if this is bound to world/item container size
|
||||
const ItemInst* inst = container->GetItem(i);
|
||||
if (inst) {
|
||||
const Item_Struct* item = GetItem(inst->GetItem()->ID);
|
||||
if (item) {
|
||||
if(first) {
|
||||
pos += snprintf(pos, 19, "%d", item->ID);
|
||||
first = false;
|
||||
} else {
|
||||
pos += snprintf(pos, 19, ",%d", item->ID);
|
||||
}
|
||||
sum += item->ID;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
*pos = '\0';
|
||||
if (!inst)
|
||||
continue;
|
||||
|
||||
if(count < 1) {
|
||||
return(false); //no items == no recipe
|
||||
const Item_Struct* item = GetItem(inst->GetItem()->ID);
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
if(first) {
|
||||
buf2 += StringFormat("%d", item->ID);
|
||||
first = false;
|
||||
} else
|
||||
buf2 += StringFormat(",%d", item->ID);
|
||||
|
||||
sum += item->ID;
|
||||
count++;
|
||||
}
|
||||
|
||||
qlen = MakeAnyLenString(&query, "SELECT tre.recipe_id "
|
||||
" FROM tradeskill_recipe_entries AS tre"
|
||||
" INNER JOIN tradeskill_recipe AS tr ON (tre.recipe_id = tr.id) "
|
||||
" WHERE tr.enabled AND (( tre.item_id IN(%s) AND tre.componentcount>0 )"
|
||||
" OR ( tre.item_id %s AND tre.iscontainer=1 ))"
|
||||
" GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u"
|
||||
" AND sum(tre.item_id * tre.componentcount) = %u", buf2, containers, count, sum);
|
||||
if(count == 0)
|
||||
return false; //no items == no recipe
|
||||
|
||||
if (!RunQuery(query, qlen, errbuf, &result)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe search, query: %s", query);
|
||||
safe_delete_array(query);
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe search, error: %s", errbuf);
|
||||
return(false);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
qcount = mysql_num_rows(result);
|
||||
if(qcount > 1) {
|
||||
//multiple recipes, partial match... do an extra query to get it exact.
|
||||
//this happens when combining components for a smaller recipe
|
||||
//which is completely contained within another recipe
|
||||
|
||||
first = true;
|
||||
pos = buf2;
|
||||
for (i = 0; i < qcount; i++) {
|
||||
row = mysql_fetch_row(result);
|
||||
uint32 recipeid = (uint32)atoi(row[0]);
|
||||
if(first) {
|
||||
pos += snprintf(pos, 19, "%u", recipeid);
|
||||
first = false;
|
||||
} else {
|
||||
pos += snprintf(pos, 19, ",%u", recipeid);
|
||||
}
|
||||
//length limit on buf2
|
||||
if(i == 214) { //Maximum number of recipe matches (19 * 215 = 4096)
|
||||
LogFile->write(EQEMuLog::Error, "GetTradeRecipe warning: Too many matches. Unable to search all recipe entries. Searched %u of %u possible entries.", i + 1, qcount);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qlen = MakeAnyLenString(&query, "SELECT tre.recipe_id"
|
||||
" FROM tradeskill_recipe_entries AS tre"
|
||||
" WHERE tre.recipe_id IN (%s)"
|
||||
" GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u"
|
||||
" AND sum(tre.item_id * tre.componentcount) = %u", buf2, count, sum);
|
||||
|
||||
if (!RunQuery(query, qlen, errbuf, &result)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, re-query: %s", query);
|
||||
safe_delete_array(query);
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", errbuf);
|
||||
return(false);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
qcount = mysql_num_rows(result);
|
||||
std::string query = StringFormat("SELECT tre.recipe_id "
|
||||
"FROM tradeskill_recipe_entries AS tre "
|
||||
"INNER JOIN tradeskill_recipe AS tr ON (tre.recipe_id = tr.id) "
|
||||
"WHERE tr.enabled AND (( tre.item_id IN(%s) AND tre.componentcount > 0) "
|
||||
"OR ( tre.item_id %s AND tre.iscontainer=1 ))"
|
||||
"GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u "
|
||||
"AND sum(tre.item_id * tre.componentcount) = %u",
|
||||
buf2.c_str(), containers.c_str(), count, sum);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe search, query: %s", query.c_str());
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe search, error: %s", results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(qcount < 1)
|
||||
return(false);
|
||||
if (results.RowCount() > 1) {
|
||||
//multiple recipes, partial match... do an extra query to get it exact.
|
||||
//this happens when combining components for a smaller recipe
|
||||
//which is completely contained within another recipe
|
||||
first = true;
|
||||
uint32 index = 0;
|
||||
buf2 = "";
|
||||
for (auto row = results.begin(); row != results.end(); ++row, ++index) {
|
||||
uint32 recipeid = (uint32)atoi(row[0]);
|
||||
if(first) {
|
||||
buf2 += StringFormat("%u", recipeid);
|
||||
first = false;
|
||||
} else
|
||||
buf2 += StringFormat(",%u", recipeid);
|
||||
|
||||
if(qcount > 1)
|
||||
{
|
||||
//length limit on buf2
|
||||
if(index == 214) { //Maximum number of recipe matches (19 * 215 = 4096)
|
||||
LogFile->write(EQEMuLog::Error, "GetTradeRecipe warning: Too many matches. Unable to search all recipe entries. Searched %u of %u possible entries.", index + 1, results.RowCount());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
query = StringFormat("SELECT tre.recipe_id "
|
||||
"FROM tradeskill_recipe_entries AS tre "
|
||||
"WHERE tre.recipe_id IN (%s) "
|
||||
"GROUP BY tre.recipe_id HAVING sum(tre.componentcount) = %u "
|
||||
"AND sum(tre.item_id * tre.componentcount) = %u", buf2.c_str(), count, sum);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, re-query: %s", query.c_str());
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (results.RowCount() < 1)
|
||||
return false;
|
||||
|
||||
if(results.RowCount() > 1) {
|
||||
//The recipe is not unique, so we need to compare the container were using.
|
||||
|
||||
uint32 containerId = 0;
|
||||
|
||||
if(some_id) { //Standard container
|
||||
if(some_id) //Standard container
|
||||
containerId = some_id;
|
||||
}
|
||||
else if(c_type) { //World container
|
||||
else if(c_type)//World container
|
||||
containerId = c_type;
|
||||
}
|
||||
else { //Invalid container
|
||||
return(false);
|
||||
else //Invalid container
|
||||
return false;
|
||||
|
||||
query = StringFormat("SELECT tre.recipe_id "
|
||||
"FROM tradeskill_recipe_entries AS tre "
|
||||
"WHERE tre.recipe_id IN (%s) "
|
||||
"AND tre.item_id = %u;", buf2.c_str(), containerId);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, re-query: %s", query.c_str());
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
qlen = MakeAnyLenString(&query,"SELECT tre.recipe_id FROM tradeskill_recipe_entries as tre WHERE tre.recipe_id IN (%s)"
|
||||
" AND tre.item_id = %u;",buf2,containerId);
|
||||
|
||||
if (!RunQuery(query, qlen, errbuf, &result)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, re-query: %s", query);
|
||||
safe_delete_array(query);
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", errbuf);
|
||||
return(false);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
uint32 resultRowTotal = mysql_num_rows(result);
|
||||
|
||||
if(resultRowTotal == 0) { //Recipe contents matched more than 1 recipe, but not in this container
|
||||
if(results.RowCount() == 0) { //Recipe contents matched more than 1 recipe, but not in this container
|
||||
LogFile->write(EQEMuLog::Error, "Combine error: Incorrect container is being used!");
|
||||
return(false);
|
||||
}
|
||||
if(resultRowTotal > 1) { //Recipe contents matched more than 1 recipe in this container
|
||||
LogFile->write(EQEMuLog::Error, "Combine error: Recipe is not unique! %u matches found for container %u. Continuing with first recipe match.", resultRowTotal, containerId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (results.RowCount() > 1) //Recipe contents matched more than 1 recipe in this container
|
||||
LogFile->write(EQEMuLog::Error, "Combine error: Recipe is not unique! %u matches found for container %u. Continuing with first recipe match.", results.RowCount(), containerId);
|
||||
|
||||
}
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
auto row = results.begin();
|
||||
uint32 recipe_id = (uint32)atoi(row[0]);
|
||||
mysql_free_result(result);
|
||||
|
||||
//Right here we verify that we actually have ALL of the tradeskill components..
|
||||
//instead of part which is possible with experimentation.
|
||||
//This is here because something's up with the query above.. it needs to be rethought out
|
||||
bool has_components = true;
|
||||
char TSerrbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *TSquery = 0;
|
||||
MYSQL_RES *TSresult;
|
||||
MYSQL_ROW TSrow;
|
||||
if (RunQuery(TSquery, MakeAnyLenString(&TSquery, "SELECT item_id, componentcount from tradeskill_recipe_entries where recipe_id=%i AND componentcount > 0", recipe_id), TSerrbuf, &TSresult)) {
|
||||
while((TSrow = mysql_fetch_row(TSresult))!=nullptr) {
|
||||
int ccnt = 0;
|
||||
for(int x = MAIN_BEGIN; x < EmuConstants::MAP_WORLD_SIZE; x++) {
|
||||
const ItemInst* inst = container->GetItem(x);
|
||||
if(inst){
|
||||
const Item_Struct* item = GetItem(inst->GetItem()->ID);
|
||||
if (item) {
|
||||
if(item->ID == atoi(TSrow[0])){
|
||||
ccnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ccnt != atoi(TSrow[1]))
|
||||
has_components = false;
|
||||
}
|
||||
mysql_free_result(TSresult);
|
||||
} else {
|
||||
LogFile->write(EQEMuLog::Error, "Error in tradeskill verify query: '%s': %s", TSquery, TSerrbuf);
|
||||
}
|
||||
safe_delete_array(TSquery);
|
||||
if(has_components == false){
|
||||
query = StringFormat("SELECT item_id, componentcount "
|
||||
"FROM tradeskill_recipe_entries "
|
||||
"WHERE recipe_id = %i AND componentcount > 0",
|
||||
recipe_id);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in tradeskill verify query: '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if (results.RowCount() == 0)
|
||||
return GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec);
|
||||
|
||||
return(GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec));
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
int ccnt = 0;
|
||||
|
||||
for(int x = MAIN_BEGIN; x < EmuConstants::MAP_WORLD_SIZE; x++) {
|
||||
const ItemInst* inst = container->GetItem(x);
|
||||
if(!inst)
|
||||
continue;
|
||||
|
||||
const Item_Struct* item = GetItem(inst->GetItem()->ID);
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
if(item->ID == atoi(row[0]))
|
||||
ccnt++;
|
||||
}
|
||||
|
||||
if(ccnt != atoi(row[1]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetTradeRecipe(recipe_id, c_type, some_id, char_id, spec);
|
||||
}
|
||||
|
||||
bool ZoneDatabase::GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id,
|
||||
uint32 char_id, DBTradeskillRecipe_Struct *spec)
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
char *query = 0;
|
||||
|
||||
uint32 qcount = 0;
|
||||
uint32 qlen;
|
||||
|
||||
// make where clause segment for container(s)
|
||||
char containers[30];
|
||||
if (some_id == 0) {
|
||||
// world combiner so no item number
|
||||
snprintf(containers,29, "= %u", c_type);
|
||||
} else {
|
||||
// container in inventory
|
||||
snprintf(containers,29, "in (%u,%u)", c_type, some_id);
|
||||
std::string containers;
|
||||
if (some_id == 0)
|
||||
containers = StringFormat("= %u", c_type); // world combiner so no item number
|
||||
else
|
||||
containers = StringFormat("IN (%u,%u)", c_type, some_id); // container in inventory
|
||||
|
||||
std::string query = StringFormat("SELECT tr.id, tr.tradeskill, tr.skillneeded, "
|
||||
"tr.trivial, tr.nofail, tr.replace_container, "
|
||||
"tr.name, tr.must_learn, tr.quest, crl.madecount "
|
||||
"FROM tradeskill_recipe AS tr "
|
||||
"INNER JOIN tradeskill_recipe_entries AS tre "
|
||||
"ON tr.id = tre.recipe_id "
|
||||
"LEFT JOIN (SELECT recipe_id, madecount "
|
||||
"FROM char_recipe_list WHERE char_id = %u) AS crl "
|
||||
"ON tr.id = crl.recipe_id "
|
||||
"WHERE tr.id = %lu AND tre.item_id %s AND tr.enabled "
|
||||
"GROUP BY tr.id",
|
||||
char_id, (unsigned long)recipe_id, containers.c_str());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, query: %s", query.c_str());
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
qlen = MakeAnyLenString(&query, "SELECT tr.id, tr.tradeskill, tr.skillneeded,"
|
||||
" tr.trivial, tr.nofail, tr.replace_container, tr.name, tr.must_learn, tr.quest, crl.madecount"
|
||||
" FROM tradeskill_recipe AS tr inner join tradeskill_recipe_entries as tre"
|
||||
" ON tr.id = tre.recipe_id"
|
||||
" LEFT JOIN (SELECT recipe_id, madecount from char_recipe_list WHERE char_id = %u) AS crl "
|
||||
" ON tr.id = crl.recipe_id "
|
||||
" WHERE tr.id = %lu AND tre.item_id %s AND tr.enabled "
|
||||
" GROUP BY tr.id", char_id, (unsigned long)recipe_id, containers);
|
||||
if(results.RowCount() != 1)
|
||||
return false;//just not found i guess..
|
||||
|
||||
if (!RunQuery(query, qlen, errbuf, &result)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, query: %s", query);
|
||||
safe_delete_array(query);
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecipe, error: %s", errbuf);
|
||||
return(false);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
qcount = mysql_num_rows(result);
|
||||
if(qcount != 1) {
|
||||
//just not found i guess..
|
||||
return(false);
|
||||
}
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
spec->tradeskill = (SkillUseTypes)atoi(row[1]);
|
||||
spec->skill_needed = (int16)atoi(row[2]);
|
||||
spec->trivial = (uint16)atoi(row[3]);
|
||||
spec->nofail = atoi(row[4]) ? true : false;
|
||||
auto row = results.begin();
|
||||
spec->tradeskill = (SkillUseTypes)atoi(row[1]);
|
||||
spec->skill_needed = (int16)atoi(row[2]);
|
||||
spec->trivial = (uint16)atoi(row[3]);
|
||||
spec->nofail = atoi(row[4]) ? true : false;
|
||||
spec->replace_container = atoi(row[5]) ? true : false;
|
||||
spec->name = row[6];
|
||||
spec->must_learn = (uint8)atoi(row[7]);
|
||||
spec->quest = atoi(row[8]) ? true : false;
|
||||
|
||||
if (row[9] == nullptr) {
|
||||
spec->has_learnt = false;
|
||||
spec->madecount = 0;
|
||||
@@ -1442,141 +1363,109 @@ bool ZoneDatabase::GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id
|
||||
spec->madecount = (uint32)atoul(row[9]);
|
||||
}
|
||||
spec->recipe_id = recipe_id;
|
||||
mysql_free_result(result);
|
||||
|
||||
//Pull the on-success items...
|
||||
qlen = MakeAnyLenString(&query, "SELECT item_id,successcount FROM tradeskill_recipe_entries"
|
||||
" WHERE successcount>0 AND recipe_id=%u", recipe_id);
|
||||
|
||||
if (!RunQuery(query, qlen, errbuf, &result)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecept success query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
return(false);
|
||||
query = StringFormat("SELECT item_id,successcount FROM tradeskill_recipe_entries "
|
||||
"WHERE successcount > 0 AND recipe_id = %u", recipe_id);
|
||||
results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecept success query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return false;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
qcount = mysql_num_rows(result);
|
||||
if(qcount < 1) {
|
||||
if(results.RowCount() < 1) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in GetTradeRecept success: no success items returned");
|
||||
return(false);
|
||||
return false;
|
||||
}
|
||||
uint8 r;
|
||||
|
||||
spec->onsuccess.clear();
|
||||
for(r = 0; r < qcount; r++) {
|
||||
row = mysql_fetch_row(result);
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint32 item = (uint32)atoi(row[0]);
|
||||
uint8 num = (uint8) atoi(row[1]);
|
||||
spec->onsuccess.push_back(std::pair<uint32,uint8>(item, num));
|
||||
}
|
||||
mysql_free_result(result);
|
||||
|
||||
spec->onfail.clear();
|
||||
//Pull the on-fail items...
|
||||
qlen = MakeAnyLenString(&query, "SELECT item_id,failcount FROM tradeskill_recipe_entries"
|
||||
" WHERE failcount>0 AND recipe_id=%u", recipe_id);
|
||||
|
||||
spec->onfail.clear();
|
||||
if (RunQuery(query, qlen, errbuf, &result)) {
|
||||
|
||||
qcount = mysql_num_rows(result);
|
||||
uint8 r;
|
||||
for(r = 0; r < qcount; r++) {
|
||||
row = mysql_fetch_row(result);
|
||||
query = StringFormat("SELECT item_id, failcount FROM tradeskill_recipe_entries "
|
||||
"WHERE failcount > 0 AND recipe_id = %u", recipe_id);
|
||||
results = QueryDatabase(query);
|
||||
if (results.Success())
|
||||
for(auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint32 item = (uint32)atoi(row[0]);
|
||||
uint8 num = (uint8) atoi(row[1]);
|
||||
spec->onfail.push_back(std::pair<uint32,uint8>(item, num));
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
|
||||
spec->salvage.clear();
|
||||
|
||||
// Don't bother with the query if TS is nofail
|
||||
if (spec->nofail)
|
||||
return true;
|
||||
|
||||
// Pull the salvage list
|
||||
qlen = MakeAnyLenString(&query, "SELECT item_id,salvagecount FROM tradeskill_recipe_entries WHERE salvagecount>0 AND recipe_id=%u", recipe_id);
|
||||
|
||||
spec->salvage.clear();
|
||||
// Don't bother with the query if TS is nofail
|
||||
if (!spec->nofail && RunQuery(query, qlen, errbuf, &result)) {
|
||||
qcount = mysql_num_rows(result);
|
||||
uint8 r;
|
||||
for(r = 0; r < qcount; r++) {
|
||||
row = mysql_fetch_row(result);
|
||||
query = StringFormat("SELECT item_id, salvagecount "
|
||||
"FROM tradeskill_recipe_entries "
|
||||
"WHERE salvagecount > 0 AND recipe_id = %u", recipe_id);
|
||||
results = QueryDatabase(query);
|
||||
if (results.Success())
|
||||
for(auto row = results.begin(); row != results.begin(); ++row) {
|
||||
uint32 item = (uint32)atoi(row[0]);
|
||||
uint8 num = (uint8)atoi(row[1]);
|
||||
spec->salvage.push_back(std::pair<uint32,uint8>(item, num));
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
|
||||
safe_delete_array(query);
|
||||
|
||||
return(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZoneDatabase::UpdateRecipeMadecount(uint32 recipe_id, uint32 char_id, uint32 madecount)
|
||||
void ZoneDatabase::UpdateRecipeMadecount(uint32 recipe_id, uint32 char_id, uint32 madeCount)
|
||||
{
|
||||
char *query = 0;
|
||||
uint32 qlen;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
qlen = MakeAnyLenString(&query, "INSERT INTO char_recipe_list "
|
||||
" SET recipe_id = %u, char_id = %u, madecount = %u "
|
||||
" ON DUPLICATE KEY UPDATE madecount = %u;"
|
||||
, recipe_id, char_id, madecount, madecount);
|
||||
|
||||
if (!RunQuery(query, qlen, errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in UpdateRecipeMadecount query '%s': %s", query, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("INSERT INTO char_recipe_list "
|
||||
"SET recipe_id = %u, char_id = %u, madecount = %u "
|
||||
"ON DUPLICATE KEY UPDATE madecount = %u;",
|
||||
recipe_id, char_id, madeCount, madeCount);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error in UpdateRecipeMadecount query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
}
|
||||
|
||||
void Client::LearnRecipe(uint32 recipeID)
|
||||
{
|
||||
char *query = 0;
|
||||
uint32 qlen;
|
||||
uint32 qcount = 0;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
qlen = MakeAnyLenString(&query, "SELECT tr.name, crl.madecount "
|
||||
" FROM tradeskill_recipe as tr "
|
||||
" LEFT JOIN (SELECT recipe_id, madecount FROM char_recipe_list WHERE char_id = %u) AS crl "
|
||||
" ON tr.id = crl.recipe_id "
|
||||
" WHERE tr.id = %u ;", CharacterID(), recipeID);
|
||||
|
||||
if (!database.RunQuery(query, qlen, errbuf, &result)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in Client::LearnRecipe query '%s': %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
std::string query = StringFormat("SELECT tr.name, crl.madecount "
|
||||
"FROM tradeskill_recipe AS tr "
|
||||
"LEFT JOIN (SELECT recipe_id, madecount "
|
||||
"FROM char_recipe_list WHERE char_id = %u) AS crl "
|
||||
"ON tr.id = crl.recipe_id "
|
||||
"WHERE tr.id = %u ;", CharacterID(), recipeID);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in Client::LearnRecipe query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
qcount = mysql_num_rows(result);
|
||||
if (qcount != 1) {
|
||||
LogFile->write(EQEMuLog::Normal, "Client::LearnRecipe - RecipeID: %d had %d occurences.", recipeID, qcount);
|
||||
mysql_free_result(result);
|
||||
safe_delete_array(query);
|
||||
if (results.RowCount() != 1) {
|
||||
LogFile->write(EQEMuLog::Normal, "Client::LearnRecipe - RecipeID: %d had %d occurences.", recipeID, results.RowCount());
|
||||
return;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
auto row = results.begin();
|
||||
|
||||
if (row != nullptr && row[0] != nullptr) {
|
||||
// Only give Learn message if character doesn't know the recipe
|
||||
if (row[1] == nullptr) {
|
||||
Message_StringID(4, TRADESKILL_LEARN_RECIPE, row[0]);
|
||||
// Actually learn the recipe now
|
||||
qlen = MakeAnyLenString(&query, "INSERT INTO char_recipe_list "
|
||||
" SET recipe_id = %u, char_id = %u, madecount = 0 "
|
||||
" ON DUPLICATE KEY UPDATE madecount = madecount;"
|
||||
, recipeID, CharacterID());
|
||||
if (row[0] == nullptr)
|
||||
return;
|
||||
|
||||
if (!database.RunQuery(query, qlen, errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LearnRecipe query '%s': %s", query, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
}
|
||||
}
|
||||
// Only give Learn message if character doesn't know the recipe
|
||||
if (row[1] != nullptr)
|
||||
return;
|
||||
|
||||
mysql_free_result(result);
|
||||
Message_StringID(4, TRADESKILL_LEARN_RECIPE, row[0]);
|
||||
// Actually learn the recipe now
|
||||
query = StringFormat("INSERT INTO char_recipe_list "
|
||||
"SET recipe_id = %u, char_id = %u, madecount = 0 "
|
||||
"ON DUPLICATE KEY UPDATE madecount = madecount;",
|
||||
recipeID, CharacterID());
|
||||
results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error in LearnRecipe query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
|
||||
}
|
||||
|
||||
@@ -1622,33 +1511,22 @@ bool Client::CanIncreaseTradeskill(SkillUseTypes tradeskill) {
|
||||
|
||||
bool ZoneDatabase::EnableRecipe(uint32 recipe_id)
|
||||
{
|
||||
char *query = 0;
|
||||
uint32 qlen;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
uint32 affected_rows = 0;
|
||||
std::string query = StringFormat("UPDATE tradeskill_recipe SET enabled = 1 "
|
||||
"WHERE id = %u;", recipe_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error in EnableRecipe query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
|
||||
qlen = MakeAnyLenString(&query, "UPDATE tradeskill_recipe SET enabled = 1 WHERE id = %u;", recipe_id);
|
||||
|
||||
if (!RunQuery(query, qlen, errbuf, 0, &affected_rows)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in EnableRecipe query '%s': %s", query, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
return (affected_rows > 0);
|
||||
return results.RowsAffected() > 0;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::DisableRecipe(uint32 recipe_id)
|
||||
{
|
||||
char *query = 0;
|
||||
uint32 qlen;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
uint32 affected_rows = 0;
|
||||
std::string query = StringFormat("UPDATE tradeskill_recipe SET enabled = 0 "
|
||||
"WHERE id = %u;", recipe_id);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
LogFile->write(EQEMuLog::Error, "Error in DisableRecipe query '%s': %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
|
||||
qlen = MakeAnyLenString(&query, "UPDATE tradeskill_recipe SET enabled = 0 WHERE id = %u;", recipe_id);
|
||||
|
||||
if (!RunQuery(query, qlen, errbuf, 0, &affected_rows)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in DisableRecipe query '%s': %s", query, errbuf);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
return (affected_rows > 0);
|
||||
return results.RowsAffected() > 0;
|
||||
}
|
||||
|
||||
+329
-404
@@ -133,7 +133,7 @@ void Trade::AddEntity(uint16 trade_slot_id, uint32 stack_size) {
|
||||
client->Kick();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SendItemData(inst, trade_slot_id);
|
||||
|
||||
_log(TRADING__HOLDER, "%s added item '%s' to trade slot %i", owner->GetName(), inst->GetItem()->Name, trade_slot_id);
|
||||
@@ -451,13 +451,13 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
||||
mlog(TRADING__CLIENT, "Finishing trade with client %s", other->GetName());
|
||||
|
||||
this->AddMoneyToPP(other->trade->cp, other->trade->sp, other->trade->gp, other->trade->pp, true);
|
||||
|
||||
|
||||
// step 0: pre-processing
|
||||
// QS code
|
||||
if (RuleB(QueryServ, PlayerLogTrades) && event_entry && event_details) {
|
||||
qs_audit = (QSPlayerLogTrade_Struct*)event_entry;
|
||||
qs_log = true;
|
||||
|
||||
|
||||
if (finalizer) {
|
||||
qs_audit->char2_id = this->character_id;
|
||||
|
||||
@@ -506,7 +506,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
||||
detail->aug_5 = inst->GetAugmentItemID(5);
|
||||
|
||||
event_details->push_back(detail);
|
||||
|
||||
|
||||
if (finalizer)
|
||||
qs_audit->char2_count += detail->charges;
|
||||
else
|
||||
@@ -886,7 +886,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
||||
if (baginst) {
|
||||
const Item_Struct* bagitem = baginst->GetItem();
|
||||
if (bagitem && (GetGM() || (bagitem->NoDrop != 0 && baginst->IsInstNoDrop() == false))) {
|
||||
tradingWith->CastToNPC()->AddLootDrop(bagitem, &tradingWith->CastToNPC()->itemlist,
|
||||
tradingWith->CastToNPC()->AddLootDrop(bagitem, &tradingWith->CastToNPC()->itemlist,
|
||||
baginst->GetCharges(), 1, 127, true, true);
|
||||
}
|
||||
else if (RuleB(NPC, ReturnNonQuestNoDropItems)) {
|
||||
@@ -895,8 +895,8 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tradingWith->CastToNPC()->AddLootDrop(item, &tradingWith->CastToNPC()->itemlist,
|
||||
|
||||
tradingWith->CastToNPC()->AddLootDrop(item, &tradingWith->CastToNPC()->itemlist,
|
||||
inst->GetCharges(), 1, 127, true, true);
|
||||
}
|
||||
// Return NO DROP and Attuned items being handed into a non-quest NPC if the rule is true
|
||||
@@ -913,14 +913,7 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
||||
if(!tradingWith->IsMoving())
|
||||
tradingWith->FaceTarget(this);
|
||||
|
||||
/* Set a timestamp in an entity variable for plugin check_handin.pl in return_items
|
||||
This will stopgap players from items being returned if global_npc.pl has a catch all return_items
|
||||
*/
|
||||
struct timeval read_time;
|
||||
char buffer[50];
|
||||
gettimeofday(&read_time, 0);
|
||||
sprintf(buffer, "%li.%li \n", read_time.tv_sec, read_time.tv_usec);
|
||||
this->SetEntityVariable("Stop_Return", buffer);
|
||||
this->EVENT_ITEM_ScriptStopReturn();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -938,12 +931,12 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
||||
parse->AddVar(temp1, temp2);
|
||||
snprintf(temp1, 100, "platinum.%d", tradingWith->GetNPCTypeID());
|
||||
snprintf(temp2, 100, "%u", trade->pp);
|
||||
parse->AddVar(temp1, temp2);
|
||||
parse->AddVar(temp1, temp2);
|
||||
|
||||
if(tradingWith->GetAppearance() != eaDead) {
|
||||
tradingWith->FaceTarget(this);
|
||||
}
|
||||
|
||||
|
||||
ItemInst *insts[4] = { 0 };
|
||||
for(int i = EmuConstants::TRADE_BEGIN; i <= EmuConstants::TRADE_NPC_END; ++i) {
|
||||
insts[i - EmuConstants::TRADE_BEGIN] = m_inv.PopItem(i);
|
||||
@@ -1475,18 +1468,16 @@ void Client::TradeRequestFailed(const EQApplicationPacket* app) {
|
||||
}
|
||||
|
||||
|
||||
static void BazaarAuditTrail(const char *Seller, const char *Buyer, const char *ItemName, int Quantity, int TotalCost, int TranType) {
|
||||
static void BazaarAuditTrail(const char *seller, const char *buyer, const char *itemName, int quantity, int totalCost, int tranType) {
|
||||
|
||||
const char *AuditQuery="INSERT INTO `trader_audit` (`time`, `seller`, `buyer`, `itemname`, `quantity`, `totalcost`, `trantype`) "
|
||||
"VALUES (NOW(), '%s', '%s', '%s', %i, %i, %i)";
|
||||
std::string query = StringFormat("INSERT INTO `trader_audit` "
|
||||
"(`time`, `seller`, `buyer`, `itemname`, `quantity`, `totalcost`, `trantype`) "
|
||||
"VALUES (NOW(), '%s', '%s', '%s', %i, %i, %i)",
|
||||
seller, buyer, itemName, quantity, totalCost, tranType);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if(!results.Success())
|
||||
_log(TRADING__CLIENT, "Audit write error: %s : %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
|
||||
if(!database.RunQuery(query, MakeAnyLenString(&query, AuditQuery, Seller, Buyer, ItemName, Quantity, TotalCost, TranType), errbuf))
|
||||
_log(TRADING__CLIENT, "Audit write error: %s : %s", query, errbuf);
|
||||
|
||||
safe_delete_array(query);
|
||||
}
|
||||
|
||||
|
||||
@@ -1624,365 +1615,326 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs,Client* Trader,const EQApplicat
|
||||
|
||||
}
|
||||
|
||||
void Client::SendBazaarWelcome(){
|
||||
void Client::SendBazaarWelcome()
|
||||
{
|
||||
const std::string query = "SELECT COUNT(DISTINCT char_id), count(char_id) FROM trader";
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (results.Success() && results.RowCount() == 1){
|
||||
auto row = results.begin();
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarWelcome_Struct));
|
||||
|
||||
char* query = 0;
|
||||
memset(outapp->pBuffer,0,outapp->size);
|
||||
|
||||
MYSQL_RES *result;
|
||||
BazaarWelcome_Struct* bws = (BazaarWelcome_Struct*)outapp->pBuffer;
|
||||
|
||||
MYSQL_ROW row;
|
||||
bws->Beginning.Action = BazaarWelcome;
|
||||
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "select count(distinct char_id),count(char_id) from trader"),errbuf,&result)){
|
||||
if(mysql_num_rows(result)==1){
|
||||
bws->Traders = atoi(row[0]);
|
||||
bws->Items = atoi(row[1]);
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
QueuePacket(outapp);
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarWelcome_Struct));
|
||||
|
||||
memset(outapp->pBuffer,0,outapp->size);
|
||||
|
||||
BazaarWelcome_Struct* bws = (BazaarWelcome_Struct*)outapp->pBuffer;
|
||||
|
||||
bws->Beginning.Action = BazaarWelcome;
|
||||
|
||||
bws->Items = atoi(row[1]);
|
||||
|
||||
bws->Traders = atoi(row[0]);
|
||||
|
||||
QueuePacket(outapp);
|
||||
|
||||
safe_delete(outapp);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
|
||||
if (database.RunQuery(query,MakeAnyLenString(&query, "select count(distinct charid) from buyer"),errbuf,&result)){
|
||||
if(mysql_num_rows(result)==1) {
|
||||
const std::string buyerCountQuery = "SELECT COUNT(DISTINCT charid) FROM buyer";
|
||||
results = database.QueryDatabase(buyerCountQuery);
|
||||
if (!results.Success() || results.RowCount() != 1)
|
||||
return;
|
||||
|
||||
row = mysql_fetch_row(result);
|
||||
|
||||
Message(10, "There are %i Buyers waiting to purchase your loot. Type /barter to search for them,"
|
||||
" or use /buyer to set up your own Buy Lines.", atoi(row[0]));
|
||||
}
|
||||
mysql_free_result(result);
|
||||
}
|
||||
safe_delete_array(query);
|
||||
auto row = results.begin();
|
||||
Message(10, "There are %i Buyers waiting to purchase your loot. Type /barter to search for them, "
|
||||
"or use /buyer to set up your own Buy Lines.", atoi(row[0]));
|
||||
}
|
||||
|
||||
void Client::SendBazaarResults(uint32 TraderID, uint32 Class_, uint32 Race, uint32 ItemStat, uint32 Slot, uint32 Type,
|
||||
char Name[64], uint32 MinPrice, uint32 MaxPrice) {
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* Query = 0;
|
||||
std::string Search, Values;
|
||||
MYSQL_RES *Result;
|
||||
MYSQL_ROW Row;
|
||||
char Tmp[100] = {0};
|
||||
std::string searchValues = " COUNT(item_id), trader.*, items.name ";
|
||||
std::string searchCriteria = " WHERE trader.item_id = items.id ";
|
||||
|
||||
Values.append("count(item_id),trader.*,items.name");
|
||||
if(TraderID > 0) {
|
||||
Client* trader = entity_list.GetClientByID(TraderID);
|
||||
|
||||
Search.append("where trader.item_id=items.id");
|
||||
if(trader)
|
||||
searchCriteria.append(StringFormat(" AND trader.char_id = %i", trader->CharacterID()));
|
||||
}
|
||||
|
||||
if(TraderID > 0){
|
||||
Client* Trader = entity_list.GetClientByID(TraderID);
|
||||
if(MinPrice != 0)
|
||||
searchCriteria.append(StringFormat(" AND trader.item_cost >= %i", MinPrice));
|
||||
|
||||
if(Trader){
|
||||
sprintf(Tmp," and trader.char_id=%i",Trader->CharacterID());
|
||||
Search.append(Tmp);
|
||||
}
|
||||
if(MaxPrice != 0)
|
||||
searchCriteria.append(StringFormat(" AND trader.item_cost <= %i", MaxPrice));
|
||||
|
||||
if(strlen(Name) > 0) {
|
||||
char *safeName = RemoveApostrophes(Name);
|
||||
searchCriteria.append(StringFormat(" AND items.name LIKE '%%%s%%'", safeName));
|
||||
safe_delete_array(safeName);
|
||||
}
|
||||
std::string SearchrResults;
|
||||
|
||||
if(MinPrice != 0){
|
||||
sprintf(Tmp, " and trader.item_cost>=%i", MinPrice);
|
||||
Search.append(Tmp);
|
||||
}
|
||||
if(MaxPrice != 0){
|
||||
sprintf(Tmp, " and trader.item_cost<=%i", MaxPrice);
|
||||
Search.append(Tmp);
|
||||
}
|
||||
if(strlen(Name) > 0){
|
||||
char *SafeName = RemoveApostrophes(Name);
|
||||
sprintf(Tmp, " and items.name like '%%%s%%'", SafeName);
|
||||
safe_delete_array(SafeName);
|
||||
Search.append(Tmp);
|
||||
}
|
||||
if(Class_ != 0xFFFFFFFF){
|
||||
sprintf(Tmp, " and mid(reverse(bin(items.classes)),%i,1)=1", Class_);
|
||||
Search.append(Tmp);
|
||||
}
|
||||
if(Race!=0xFFFFFFFF){
|
||||
sprintf(Tmp, " and mid(reverse(bin(items.races)),%i,1)=1", Race);
|
||||
Search.append(Tmp);
|
||||
}
|
||||
if(Slot!=0xFFFFFFFF){
|
||||
sprintf(Tmp, " and mid(reverse(bin(items.slots)),%i,1)=1", Slot + 1);
|
||||
Search.append(Tmp);
|
||||
}
|
||||
if(Type!=0xFFFFFFFF){
|
||||
if(Class_ != 0xFFFFFFFF)
|
||||
searchCriteria.append(StringFormat(" AND MID(REVERSE(BIN(items.classes)), %i, 1) = 1", Class_));
|
||||
|
||||
switch(Type){
|
||||
if(Race != 0xFFFFFFFF)
|
||||
searchCriteria.append(StringFormat(" AND MID(REVERSE(BIN(items.races)), %i, 1) = 1", Race));
|
||||
|
||||
case 0:
|
||||
// 1H Slashing
|
||||
Search.append(" and items.itemtype=0 and damage>0");
|
||||
break;
|
||||
case 31:
|
||||
Search.append(" and items.itemclass=2");
|
||||
break;
|
||||
case 46:
|
||||
Search.append(" and items.spellid>0 and items.spellid<65000");
|
||||
break;
|
||||
case 47:
|
||||
Search.append(" and items.spellid=998");
|
||||
break;
|
||||
case 48:
|
||||
Search.append(" and items.spellid>=1298 and items.spellid<=1307");
|
||||
break;
|
||||
case 49:
|
||||
Search.append(" and items.focuseffect>0");
|
||||
break;
|
||||
default:
|
||||
sprintf(Tmp, " and items.itemtype=%i", Type);
|
||||
Search.append(Tmp);
|
||||
}
|
||||
}
|
||||
if(Slot != 0xFFFFFFFF)
|
||||
searchCriteria.append(StringFormat(" AND MID(REVERSE(BIN(items.slots)), %i, 1) = 1", Slot + 1));
|
||||
|
||||
switch(Type){
|
||||
case 0xFFFFFFFF:
|
||||
break;
|
||||
case 0:
|
||||
// 1H Slashing
|
||||
searchCriteria.append(" AND items.itemtype = 0 AND damage > 0");
|
||||
break;
|
||||
case 31:
|
||||
searchCriteria.append(" AND items.itemclass = 2");
|
||||
break;
|
||||
case 46:
|
||||
searchCriteria.append(" AND items.spellid > 0 AND items.spellid < 65000");
|
||||
break;
|
||||
case 47:
|
||||
searchCriteria.append(" AND items.spellid = 998");
|
||||
break;
|
||||
case 48:
|
||||
searchCriteria.append(" AND items.spellid >= 1298 AND items.spellid <= 1307");
|
||||
break;
|
||||
case 49:
|
||||
searchCriteria.append(" AND items.focuseffect > 0");
|
||||
break;
|
||||
|
||||
default:
|
||||
searchCriteria.append(StringFormat(" AND items.itemtype = %i", Type));
|
||||
}
|
||||
|
||||
switch(ItemStat) {
|
||||
|
||||
case STAT_AC:
|
||||
Search.append(" and items.ac>0");
|
||||
Values.append(",items.ac");
|
||||
searchCriteria.append(" AND items.ac > 0");
|
||||
searchValues.append(", items.ac");
|
||||
break;
|
||||
|
||||
case STAT_AGI:
|
||||
Search.append(" and items.aagi>0");
|
||||
Values.append(",items.aagi");
|
||||
searchCriteria.append(" AND items.aagi > 0");
|
||||
searchValues.append(", items.aagi");
|
||||
break;
|
||||
|
||||
case STAT_CHA:
|
||||
Search.append(" and items.acha>0");
|
||||
Values.append(",items.acha");
|
||||
searchCriteria.append(" AND items.acha > 0");
|
||||
searchValues.append(", items.acha");
|
||||
break;
|
||||
|
||||
case STAT_DEX:
|
||||
Search.append(" and items.adex>0");
|
||||
Values.append(",items.adex");
|
||||
searchCriteria.append(" AND items.adex > 0");
|
||||
searchValues.append(", items.adex");
|
||||
break;
|
||||
|
||||
case STAT_INT:
|
||||
Search.append(" and items.aint>0");
|
||||
Values.append(",items.aint");
|
||||
searchCriteria.append(" AND items.aint > 0");
|
||||
searchValues.append(", items.aint");
|
||||
break;
|
||||
|
||||
case STAT_STA:
|
||||
Search.append(" and items.asta>0");
|
||||
Values.append(",items.asta");
|
||||
searchCriteria.append(" AND items.asta > 0");
|
||||
searchValues.append(", items.asta");
|
||||
break;
|
||||
|
||||
case STAT_STR:
|
||||
Search.append(" and items.astr>0");
|
||||
Values.append(",items.astr");
|
||||
searchCriteria.append(" AND items.astr > 0");
|
||||
searchValues.append(", items.astr");
|
||||
break;
|
||||
|
||||
case STAT_WIS:
|
||||
Search.append(" and items.awis>0");
|
||||
Values.append(",items.awis");
|
||||
searchCriteria.append(" AND items.awis > 0");
|
||||
searchValues.append(", items.awis");
|
||||
break;
|
||||
|
||||
case STAT_COLD:
|
||||
Search.append(" and items.cr>0");
|
||||
Values.append(",items.cr");
|
||||
searchCriteria.append(" AND items.cr > 0");
|
||||
searchValues.append(", items.cr");
|
||||
break;
|
||||
|
||||
case STAT_DISEASE:
|
||||
Search.append(" and items.dr>0");
|
||||
Values.append(",items.dr");
|
||||
searchCriteria.append(" AND items.dr > 0");
|
||||
searchValues.append(", items.dr");
|
||||
break;
|
||||
|
||||
case STAT_FIRE:
|
||||
Search.append(" and items.fr>0");
|
||||
Values.append(",items.fr");
|
||||
searchCriteria.append(" AND items.fr > 0");
|
||||
searchValues.append(", items.fr");
|
||||
break;
|
||||
|
||||
case STAT_MAGIC:
|
||||
Values.append(",items.mr");
|
||||
Search.append(" and items.mr>0");
|
||||
searchCriteria.append(" AND items.mr > 0");
|
||||
searchValues.append(", items.mr");
|
||||
break;
|
||||
|
||||
case STAT_POISON:
|
||||
Search.append(" and items.pr>0");
|
||||
Values.append(",items.pr");
|
||||
searchCriteria.append(" AND items.pr > 0");
|
||||
searchValues.append(", items.pr");
|
||||
break;
|
||||
|
||||
case STAT_HP:
|
||||
Search.append(" and items.hp>0");
|
||||
Values.append(",items.hp");
|
||||
searchCriteria.append(" AND items.hp > 0");
|
||||
searchValues.append(", items.hp");
|
||||
break;
|
||||
|
||||
case STAT_MANA:
|
||||
Search.append(" and items.mana>0");
|
||||
Values.append(",items.mana");
|
||||
searchCriteria.append(" AND items.mana > 0");
|
||||
searchValues.append(", items.mana");
|
||||
break;
|
||||
|
||||
case STAT_ENDURANCE:
|
||||
Search.append(" and items.endur>0");
|
||||
Values.append(",items.endur");
|
||||
searchCriteria.append(" AND items.endur > 0");
|
||||
searchValues.append(", items.endur");
|
||||
break;
|
||||
|
||||
case STAT_ATTACK:
|
||||
Search.append(" and items.attack>0");
|
||||
Values.append(",items.attack");
|
||||
searchCriteria.append(" AND items.attack > 0");
|
||||
searchValues.append(", items.attack");
|
||||
break;
|
||||
|
||||
case STAT_HP_REGEN:
|
||||
Search.append(" and items.regen>0");
|
||||
Values.append(",items.regen");
|
||||
searchCriteria.append(" AND items.regen > 0");
|
||||
searchValues.append(", items.regen");
|
||||
break;
|
||||
|
||||
case STAT_MANA_REGEN:
|
||||
Search.append(" and items.manaregen>0");
|
||||
Values.append(",items.manaregen");
|
||||
searchCriteria.append(" AND items.manaregen > 0");
|
||||
searchValues.append(", items.manaregen");
|
||||
break;
|
||||
|
||||
case STAT_HASTE:
|
||||
Search.append(" and items.haste>0");
|
||||
Values.append(",items.haste");
|
||||
searchCriteria.append(" AND items.haste > 0");
|
||||
searchValues.append(", items.haste");
|
||||
break;
|
||||
|
||||
case STAT_DAMAGE_SHIELD:
|
||||
Search.append(" and items.damageshield>00");
|
||||
Values.append(",items.damageshield");
|
||||
searchCriteria.append(" AND items.damageshield > 0");
|
||||
searchValues.append(", items.damageshield");
|
||||
break;
|
||||
|
||||
default:
|
||||
Values.append(",0");
|
||||
searchValues.append(", 0");
|
||||
break;
|
||||
}
|
||||
|
||||
Values.append(",sum(charges), items.stackable ");
|
||||
std::string query = StringFormat("SELECT %s, SUM(charges), items.stackable "
|
||||
"FROM trader, items %s GROUP BY items.id, charges, char_id LIMIT %i",
|
||||
searchValues.c_str(), searchCriteria.c_str(), RuleI(Bazaar, MaxSearchResults));
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(TRADING__CLIENT, "Failed to retrieve Bazaar Search!! %s %s\n", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (database.RunQuery(Query,MakeAnyLenString(&Query, "select %s from trader,items %s group by items.id,charges,char_id limit %i",
|
||||
Values.c_str(),Search.c_str(), RuleI(Bazaar, MaxSearchResults)),errbuf,&Result)){
|
||||
_log(TRADING__CLIENT, "SRCH: %s", query.c_str());
|
||||
|
||||
_log(TRADING__CLIENT, "SRCH: %s", Query);
|
||||
safe_delete_array(Query);
|
||||
int Size = 0;
|
||||
uint32 ID = 0;
|
||||
|
||||
int Size = 0;
|
||||
uint32 ID = 0;
|
||||
|
||||
if(mysql_num_rows(Result) == static_cast<unsigned long>(RuleI(Bazaar, MaxSearchResults)))
|
||||
if (results.RowCount() == static_cast<unsigned long>(RuleI(Bazaar, MaxSearchResults)))
|
||||
Message(15, "Your search reached the limit of %i results. Please narrow your search down by selecting more options.",
|
||||
RuleI(Bazaar, MaxSearchResults));
|
||||
|
||||
if(mysql_num_rows(Result) == 0){
|
||||
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarReturnDone_Struct));
|
||||
BazaarReturnDone_Struct* brds = (BazaarReturnDone_Struct*)outapp2->pBuffer;
|
||||
brds->TraderID = ID;
|
||||
brds->Type = BazaarSearchDone;
|
||||
brds->Unknown008 = 0xFFFFFFFF;
|
||||
brds->Unknown012 = 0xFFFFFFFF;
|
||||
brds->Unknown016 = 0xFFFFFFFF;
|
||||
this->QueuePacket(outapp2);
|
||||
_pkt(TRADING__PACKETS,outapp2);
|
||||
safe_delete(outapp2);
|
||||
mysql_free_result(Result);
|
||||
return;
|
||||
}
|
||||
Size = mysql_num_rows(Result) * sizeof(BazaarSearchResults_Struct);
|
||||
uchar *buffer = new uchar[Size];
|
||||
uchar *bufptr = buffer;
|
||||
memset(buffer, 0, Size);
|
||||
|
||||
int Action = BazaarSearchResults;
|
||||
uint32 Cost = 0;
|
||||
int32 SerialNumber = 0;
|
||||
char Name[64] = {0};
|
||||
int Count = 0;
|
||||
uint32 StatValue=0;
|
||||
|
||||
while ((Row = mysql_fetch_row(Result))) {
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Action);
|
||||
Count = atoi(Row[0]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Count);
|
||||
SerialNumber = atoi(Row[3]);
|
||||
VARSTRUCT_ENCODE_TYPE(int32, bufptr, SerialNumber);
|
||||
Client* Trader2=entity_list.GetClientByCharID(atoi(Row[1]));
|
||||
if(Trader2){
|
||||
ID = Trader2->GetID();
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, ID);
|
||||
}
|
||||
else{
|
||||
_log(TRADING__CLIENT, "Unable to find trader: %i\n",atoi(Row[1]));
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 0);
|
||||
}
|
||||
Cost = atoi(Row[5]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Cost);
|
||||
StatValue = atoi(Row[8]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, StatValue);
|
||||
bool Stackable = atoi(Row[10]);
|
||||
if(Stackable) {
|
||||
int Charges = atoi(Row[9]);
|
||||
sprintf(Name, "%s(%i)", Row[7], Charges);
|
||||
}
|
||||
else
|
||||
sprintf(Name,"%s(%i)",Row[7], Count);
|
||||
|
||||
memcpy(bufptr,&Name, strlen(Name));
|
||||
|
||||
bufptr += 64;
|
||||
|
||||
// Extra fields for SoD+
|
||||
//
|
||||
if(Trader2)
|
||||
sprintf(Name, "%s", Trader2->GetName());
|
||||
else
|
||||
sprintf(Name, "Unknown");
|
||||
|
||||
memcpy(bufptr,&Name, strlen(Name));
|
||||
|
||||
bufptr += 64;
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, atoi(Row[1])); // ItemID
|
||||
}
|
||||
mysql_free_result(Result);
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, Size);
|
||||
|
||||
memcpy(outapp->pBuffer, buffer, Size);
|
||||
|
||||
this->QueuePacket(outapp);
|
||||
|
||||
_pkt(TRADING__PACKETS,outapp);
|
||||
|
||||
safe_delete(outapp);
|
||||
safe_delete_array(buffer);
|
||||
|
||||
if(results.RowCount() == 0) {
|
||||
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarReturnDone_Struct));
|
||||
BazaarReturnDone_Struct* brds = (BazaarReturnDone_Struct*)outapp2->pBuffer;
|
||||
|
||||
brds->TraderID = ID;
|
||||
brds->Type = BazaarSearchDone;
|
||||
|
||||
brds->Unknown008 = 0xFFFFFFFF;
|
||||
brds->Unknown012 = 0xFFFFFFFF;
|
||||
brds->Unknown016 = 0xFFFFFFFF;
|
||||
|
||||
this->QueuePacket(outapp2);
|
||||
|
||||
_pkt(TRADING__PACKETS,outapp2);
|
||||
safe_delete(outapp2);
|
||||
|
||||
}
|
||||
else{
|
||||
_log(TRADING__CLIENT, "Failed to retrieve Bazaar Search!! %s %s\n", Query, errbuf);
|
||||
safe_delete_array(Query);
|
||||
return;
|
||||
}
|
||||
|
||||
Size = results.RowCount() * sizeof(BazaarSearchResults_Struct);
|
||||
uchar *buffer = new uchar[Size];
|
||||
uchar *bufptr = buffer;
|
||||
memset(buffer, 0, Size);
|
||||
|
||||
int Action = BazaarSearchResults;
|
||||
uint32 Cost = 0;
|
||||
int32 SerialNumber = 0;
|
||||
char temp_buffer[64] = {0};
|
||||
int Count = 0;
|
||||
uint32 StatValue=0;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Action);
|
||||
Count = atoi(row[0]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Count);
|
||||
SerialNumber = atoi(row[3]);
|
||||
VARSTRUCT_ENCODE_TYPE(int32, bufptr, SerialNumber);
|
||||
Client* Trader2=entity_list.GetClientByCharID(atoi(row[1]));
|
||||
if(Trader2){
|
||||
ID = Trader2->GetID();
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, ID);
|
||||
}
|
||||
else{
|
||||
_log(TRADING__CLIENT, "Unable to find trader: %i\n",atoi(row[1]));
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, 0);
|
||||
}
|
||||
Cost = atoi(row[5]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, Cost);
|
||||
StatValue = atoi(row[8]);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, StatValue);
|
||||
bool Stackable = atoi(row[10]);
|
||||
if(Stackable) {
|
||||
int Charges = atoi(row[9]);
|
||||
sprintf(temp_buffer, "%s(%i)", row[7], Charges);
|
||||
}
|
||||
else
|
||||
sprintf(temp_buffer,"%s(%i)",row[7], Count);
|
||||
|
||||
memcpy(bufptr,&temp_buffer, strlen(temp_buffer));
|
||||
|
||||
bufptr += 64;
|
||||
|
||||
// Extra fields for SoD+
|
||||
//
|
||||
if(Trader2)
|
||||
sprintf(temp_buffer, "%s", Trader2->GetName());
|
||||
else
|
||||
sprintf(temp_buffer, "Unknown");
|
||||
|
||||
memcpy(bufptr,&temp_buffer, strlen(temp_buffer));
|
||||
|
||||
bufptr += 64;
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, bufptr, atoi(row[1])); // ItemID
|
||||
}
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_BazaarSearch, Size);
|
||||
|
||||
memcpy(outapp->pBuffer, buffer, Size);
|
||||
|
||||
this->QueuePacket(outapp);
|
||||
|
||||
_pkt(TRADING__PACKETS,outapp);
|
||||
|
||||
safe_delete(outapp);
|
||||
safe_delete_array(buffer);
|
||||
|
||||
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_BazaarSearch, sizeof(BazaarReturnDone_Struct));
|
||||
BazaarReturnDone_Struct* brds = (BazaarReturnDone_Struct*)outapp2->pBuffer;
|
||||
|
||||
brds->TraderID = ID;
|
||||
brds->Type = BazaarSearchDone;
|
||||
|
||||
brds->Unknown008 = 0xFFFFFFFF;
|
||||
brds->Unknown012 = 0xFFFFFFFF;
|
||||
brds->Unknown016 = 0xFFFFFFFF;
|
||||
|
||||
this->QueuePacket(outapp2);
|
||||
|
||||
_pkt(TRADING__PACKETS,outapp2);
|
||||
safe_delete(outapp2);
|
||||
}
|
||||
|
||||
static void UpdateTraderCustomerItemsAdded(uint32 CustomerID, TraderCharges_Struct* gis, uint32 ItemID) {
|
||||
@@ -2304,103 +2256,92 @@ void Client::HandleTraderPriceUpdate(const EQApplicationPacket *app) {
|
||||
|
||||
}
|
||||
|
||||
void Client::SendBuyerResults(char* SearchString, uint32 SearchID) {
|
||||
void Client::SendBuyerResults(char* searchString, uint32 searchID) {
|
||||
|
||||
// This method is called when a potential seller in the /barter window searches for matching buyers
|
||||
//
|
||||
_log(TRADING__BARTER, "Client::SendBuyerResults %s\n", SearchString);
|
||||
_log(TRADING__BARTER, "Client::SendBuyerResults %s\n", searchString);
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* Query = 0;
|
||||
char ItemName[64];
|
||||
std::string Search, Values;
|
||||
MYSQL_RES *Result;
|
||||
MYSQL_ROW Row;
|
||||
char* escSearchString = new char[strlen(searchString) * 2 + 1];
|
||||
database.DoEscapeString(escSearchString, searchString, strlen(searchString));
|
||||
|
||||
char*EscSearchString = new char[strlen(SearchString) * 2 + 1];
|
||||
database.DoEscapeString(EscSearchString, SearchString, strlen(SearchString));
|
||||
std::string query = StringFormat("SELECT * FROM buyer WHERE itemname LIKE '%%%s%%' ORDER BY charid LIMIT %i",
|
||||
escSearchString, RuleI(Bazaar, MaxBarterSearchResults));
|
||||
safe_delete_array(escSearchString);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
_log(TRADING__CLIENT, "Failed to retrieve Barter Search!! %s %s\n", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (database.RunQuery(Query,MakeAnyLenString(&Query, "select * from buyer where itemname like '%%%s%%' order by charid limit %i",
|
||||
EscSearchString, RuleI(Bazaar, MaxBarterSearchResults)), errbuf, &Result)) {
|
||||
int numberOfRows = results.RowCount();
|
||||
|
||||
int NumberOfRows = mysql_num_rows(Result);
|
||||
if(numberOfRows == RuleI(Bazaar, MaxBarterSearchResults))
|
||||
Message(15, "Your search found too many results; some are not displayed.");
|
||||
else if(strlen(searchString) == 0)
|
||||
Message(10, "There are %i Buy Lines.", numberOfRows);
|
||||
else
|
||||
Message(10, "There are %i Buy Lines that match the search string '%s'.", numberOfRows, searchString);
|
||||
|
||||
if(NumberOfRows == RuleI(Bazaar, MaxBarterSearchResults))
|
||||
Message(15, "Your search found too many results; some are not displayed.");
|
||||
else {
|
||||
if(strlen(SearchString) == 0)
|
||||
Message(10, "There are %i Buy Lines.", NumberOfRows);
|
||||
else
|
||||
Message(10, "There are %i Buy Lines that match the search string '%s'.",
|
||||
NumberOfRows, SearchString);
|
||||
if(numberOfRows == 0)
|
||||
return;
|
||||
|
||||
uint32 lastCharID = 0;
|
||||
Client *buyer = nullptr;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
char itemName[64];
|
||||
|
||||
uint32 charID = atoi(row[0]);
|
||||
uint32 buySlot = atoi(row[1]);
|
||||
uint32 itemID = atoi(row[2]);
|
||||
strcpy(itemName, row[3]);
|
||||
uint32 quantity = atoi(row[4]);
|
||||
uint32 price = atoi(row[5]);
|
||||
|
||||
// Each item in the search results is sent as a single fixed length packet, although the position of
|
||||
// the fields varies due to the use of variable length strings. The reason the packet is so big, is
|
||||
// to allow item compensation, e.g. a buyer could offer to buy a Blade Of Carnage for 10000pp plus
|
||||
// other items in exchange. Item compensation is not currently supported in EQEmu.
|
||||
//
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, 940);
|
||||
|
||||
char *buf = (char *)outapp->pBuffer;
|
||||
|
||||
const Item_Struct* item = database.GetItem(itemID);
|
||||
|
||||
if(!item)
|
||||
continue;
|
||||
|
||||
// Save having to scan the client list when dealing with multiple buylines for the same Character.
|
||||
if(charID != lastCharID) {
|
||||
buyer = entity_list.GetClientByCharID(charID);
|
||||
lastCharID = charID;
|
||||
}
|
||||
|
||||
if(NumberOfRows == 0) {
|
||||
mysql_free_result(Result);
|
||||
safe_delete_array(Query);
|
||||
return;
|
||||
}
|
||||
if(!buyer)
|
||||
continue;
|
||||
|
||||
uint32 LastCharID = 0;
|
||||
Client *Buyer = nullptr;
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, buf, Barter_BuyerSearchResults); // Command
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, buf, searchID); // Match up results with the request
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, buf, buySlot); // Slot in this Buyer's list
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, buf, 0x01); // Unknown - probably a flag field
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, buf, itemID); // ItemID
|
||||
VARSTRUCT_ENCODE_STRING(buf, itemName); // Itemname
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, buf, item->Icon); // Icon
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, buf, quantity); // Quantity
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, buf, 0x01); // Unknown - probably a flag field
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, buf, price); // Price
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, buf, buyer->GetID()); // Entity ID
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, buf, 0); // Flag for + Items , probably ItemCount
|
||||
VARSTRUCT_ENCODE_STRING(buf, buyer->GetName()); // Seller Name
|
||||
|
||||
while ((Row = mysql_fetch_row(Result))) {
|
||||
_pkt(TRADING__BARTER, outapp);
|
||||
|
||||
uint32 CharID = atoi(Row[0]);
|
||||
uint32 BuySlot = atoi(Row[1]);
|
||||
uint32 ItemID = atoi(Row[2]);
|
||||
strcpy(ItemName, Row[3]);
|
||||
uint32 Quantity = atoi(Row[4]);
|
||||
uint32 Price = atoi(Row[5]);
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
// Each item in the search results is sent as a single fixed length packet, although the position of
|
||||
// the fields varies due to the use of variable length strings. The reason the packet is so big, is
|
||||
// to allow item compensation, e.g. a buyer could offer to buy a Blade Of Carnage for 10000pp plus
|
||||
// other items in exchange. Item compensation is not currently supported in EQEmu.
|
||||
//
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, 940);
|
||||
|
||||
char *Buf = (char *)outapp->pBuffer;
|
||||
|
||||
const Item_Struct* item = database.GetItem(ItemID);
|
||||
|
||||
if(!item) continue;
|
||||
|
||||
// Save having to scan the client list when dealing with multiple buylines for the same Character.
|
||||
if(CharID != LastCharID) {
|
||||
Buyer = entity_list.GetClientByCharID(CharID);
|
||||
LastCharID = CharID;
|
||||
}
|
||||
|
||||
if(!Buyer) continue;
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerSearchResults); // Command
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, SearchID); // Match up results with the request
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot); // Slot in this Buyer's list
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0x01); // Unknown - probably a flag field
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, ItemID); // ItemID
|
||||
VARSTRUCT_ENCODE_STRING(Buf, ItemName); // Itemname
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon); // Icon
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity); // Quantity
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0x01); // Unknown - probably a flag field
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price); // Price
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Buyer->GetID()); // Entity ID
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0); // Flag for + Items , probably ItemCount
|
||||
VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName()); // Seller Name
|
||||
|
||||
_pkt(TRADING__BARTER, outapp);
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
mysql_free_result(Result);
|
||||
}
|
||||
else{
|
||||
_log(TRADING__CLIENT, "Failed to retrieve Barter Search!! %s %s\n", Query, errbuf);
|
||||
}
|
||||
safe_delete_array(Query);
|
||||
safe_delete_array(EscSearchString);
|
||||
}
|
||||
|
||||
void Client::ShowBuyLines(const EQApplicationPacket *app) {
|
||||
@@ -2443,60 +2384,44 @@ void Client::ShowBuyLines(const EQApplicationPacket *app) {
|
||||
|
||||
safe_delete(outapp);
|
||||
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* Query = 0;
|
||||
char ItemName[64];
|
||||
std::string Search, Values;
|
||||
MYSQL_RES *Result;
|
||||
MYSQL_ROW Row;
|
||||
std::string query = StringFormat("SELECT * FROM buyer WHERE charid = %i", Buyer->CharacterID());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success() || results.RowCount() == 0)
|
||||
return;
|
||||
|
||||
if (database.RunQuery(Query,MakeAnyLenString(&Query, "select * from buyer where charid = %i",
|
||||
Buyer->CharacterID()),errbuf,&Result)){
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
char ItemName[64];
|
||||
uint32 BuySlot = atoi(row[1]);
|
||||
uint32 ItemID = atoi(row[2]);
|
||||
strcpy(ItemName, row[3]);
|
||||
uint32 Quantity = atoi(row[4]);
|
||||
uint32 Price = atoi(row[5]);
|
||||
|
||||
if(mysql_num_rows(Result) == 0) {
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, 936);
|
||||
|
||||
safe_delete_array(Query);
|
||||
char *Buf = (char *)outapp->pBuffer;
|
||||
|
||||
mysql_free_result(Result);
|
||||
const Item_Struct* item = database.GetItem(ItemID);
|
||||
|
||||
return;
|
||||
}
|
||||
if(!item)
|
||||
continue;
|
||||
|
||||
while ((Row = mysql_fetch_row(Result))) {
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerInspectWindow);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // Flag
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, ItemID);
|
||||
VARSTRUCT_ENCODE_STRING(Buf, ItemName);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // Flag
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Buyer->GetID());
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0);
|
||||
VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName());
|
||||
|
||||
uint32 BuySlot = atoi(Row[1]);
|
||||
uint32 ItemID = atoi(Row[2]);
|
||||
strcpy(ItemName, Row[3]);
|
||||
uint32 Quantity = atoi(Row[4]);
|
||||
uint32 Price = atoi(Row[5]);
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, 936);
|
||||
|
||||
char *Buf = (char *)outapp->pBuffer;
|
||||
|
||||
const Item_Struct* item = database.GetItem(ItemID);
|
||||
|
||||
if(!item) continue;
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerInspectWindow);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // Flag
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, ItemID);
|
||||
VARSTRUCT_ENCODE_STRING(Buf, ItemName);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity);
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // Flag
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Buyer->GetID());
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0);
|
||||
VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName());
|
||||
|
||||
_pkt(TRADING__BARTER, outapp);
|
||||
QueuePacket(outapp);
|
||||
}
|
||||
mysql_free_result(Result);
|
||||
}
|
||||
safe_delete_array(Query);
|
||||
_pkt(TRADING__BARTER, outapp);
|
||||
QueuePacket(outapp);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::SellToBuyer(const EQApplicationPacket *app) {
|
||||
|
||||
+6
-4
@@ -254,8 +254,10 @@ int32 Client::TributeItem(uint32 slot, uint32 quantity) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
//make sure they have enough of them
|
||||
//and remove it from inventory
|
||||
/*
|
||||
Make sure they have enough of them
|
||||
and remove it from inventory
|
||||
*/
|
||||
if(inst->IsStackable()) {
|
||||
if(inst->GetCharges() < (int32)quantity) //dont have enough....
|
||||
return(0);
|
||||
@@ -267,7 +269,7 @@ int32 Client::TributeItem(uint32 slot, uint32 quantity) {
|
||||
|
||||
pts *= quantity;
|
||||
|
||||
//add the tribute value in points
|
||||
/* Add the tribute value in points */
|
||||
AddTributePoints(pts);
|
||||
return(pts);
|
||||
}
|
||||
@@ -279,7 +281,7 @@ int32 Client::TributeMoney(uint32 platinum) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
//add the tribute value in points
|
||||
/* Add the tribute value in points */
|
||||
AddTributePoints(platinum);
|
||||
return(platinum);
|
||||
}
|
||||
|
||||
+9
-6
@@ -1084,14 +1084,14 @@ void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid)
|
||||
|
||||
// how much it's allowed to be off by
|
||||
#define _GASSIGN_TOLERANCE 1.0
|
||||
if(results.RowCount() == 0) // try a fuzzy match if that didn't find it
|
||||
if (results.RowCount() == 0) // try a fuzzy match if that didn't find it
|
||||
{
|
||||
query = StringFormat("SELECT id,x,y FROM spawn2 WHERE zone='%s' AND "
|
||||
"ABS( ABS(x) - ABS(%f) ) < %f AND "
|
||||
"ABS( ABS(y) - ABS(%f) ) < %f",
|
||||
zone->GetShortName(), x, _GASSIGN_TOLERANCE, y, _GASSIGN_TOLERANCE);
|
||||
results = QueryDatabase(query);
|
||||
if(!results.Success()) {
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error querying fuzzy spawn2 '%s': '%s'", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
@@ -1100,12 +1100,13 @@ void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid)
|
||||
matches = results.RowCount();
|
||||
}
|
||||
|
||||
if (matches == 0) {
|
||||
if (matches == 0)
|
||||
{
|
||||
client->Message(0, "ERROR: Unable to assign grid - can't find it in spawn2");
|
||||
return;
|
||||
}
|
||||
|
||||
if(matches == 1)
|
||||
if(matches > 1)
|
||||
{
|
||||
client->Message(0, "ERROR: Unable to assign grid - multiple spawn2 rows match");
|
||||
return;
|
||||
@@ -1125,7 +1126,8 @@ void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid)
|
||||
return;
|
||||
}
|
||||
|
||||
if (results.RowsAffected() != 1) {
|
||||
if (results.RowsAffected() != 1)
|
||||
{
|
||||
client->Message(0, "ERROR: found spawn2 id %d but the update query failed", spawn2id);
|
||||
return;
|
||||
}
|
||||
@@ -1133,7 +1135,8 @@ void ZoneDatabase::AssignGrid(Client *client, float x, float y, uint32 grid)
|
||||
if(client)
|
||||
client->LogSQL(query.c_str());
|
||||
|
||||
if(!fuzzy) {
|
||||
if (!fuzzy)
|
||||
{
|
||||
client->Message(0, "Grid assign: spawn2 id = %d updated - exact match", spawn2id);
|
||||
return;
|
||||
}
|
||||
|
||||
+66
-10
@@ -168,18 +168,24 @@ void WorldServer::Process() {
|
||||
break;
|
||||
}
|
||||
case ServerOP_ChannelMessage: {
|
||||
if (!ZoneLoaded) break;
|
||||
if (!ZoneLoaded)
|
||||
break;
|
||||
ServerChannelMessage_Struct* scm = (ServerChannelMessage_Struct*) pack->pBuffer;
|
||||
if (scm->deliverto[0] == 0) {
|
||||
entity_list.ChannelMessageFromWorld(scm->from, scm->to, scm->chan_num, scm->guilddbid, scm->language, scm->message);
|
||||
}
|
||||
else {
|
||||
Client* client;
|
||||
client = entity_list.GetClientByName(scm->deliverto);
|
||||
if (client != 0) {
|
||||
} else {
|
||||
Client* client = entity_list.GetClientByName(scm->deliverto);
|
||||
if (client) {
|
||||
if (client->Connected()) {
|
||||
client->ChannelMessageSend(scm->from, scm->to, scm->chan_num, scm->language, scm->message);
|
||||
if (!scm->noreply && scm->chan_num!=2) { //dont echo on group chat
|
||||
if (scm->queued == 1) // tell was queued
|
||||
client->Tell_StringID(QUEUED_TELL, scm->to, scm->message);
|
||||
else if (scm->queued == 2) // tell queue was full
|
||||
client->Tell_StringID(QUEUE_TELL_FULL, scm->to, scm->message);
|
||||
else if (scm->queued == 3) // person was offline
|
||||
client->Message_StringID(MT_TellEcho, TOLD_NOT_ONLINE, scm->to);
|
||||
else // normal stuff
|
||||
client->ChannelMessageSend(scm->from, scm->to, scm->chan_num, scm->language, scm->message);
|
||||
if (!scm->noreply && scm->chan_num != 2) { //dont echo on group chat
|
||||
// if it's a tell, echo back so it shows up
|
||||
scm->noreply = true;
|
||||
scm->chan_num = 14;
|
||||
@@ -322,7 +328,7 @@ void WorldServer::Process() {
|
||||
|
||||
entity->CastToMob()->SetZone(ztz->requested_zone_id, ztz->requested_instance_id);
|
||||
|
||||
if(ztz->ignorerestrictions == 3)
|
||||
if(ztz->ignorerestrictions == 3)
|
||||
entity->CastToClient()->GoToSafeCoords(ztz->requested_zone_id, ztz->requested_instance_id);
|
||||
}
|
||||
|
||||
@@ -995,9 +1001,11 @@ void WorldServer::Process() {
|
||||
char AssistName[64];
|
||||
char PullerName[64];
|
||||
char NPCMarkerName[64];
|
||||
char mentoree_name[64];
|
||||
int mentor_percent;
|
||||
GroupLeadershipAA_Struct GLAA;
|
||||
memset(ln, 0, 64);
|
||||
strcpy(ln, database.GetGroupLeadershipInfo(group->GetID(), ln, MainTankName, AssistName, PullerName, NPCMarkerName, &GLAA));
|
||||
strcpy(ln, database.GetGroupLeadershipInfo(group->GetID(), ln, MainTankName, AssistName, PullerName, NPCMarkerName, mentoree_name, &mentor_percent, &GLAA));
|
||||
Client *lc = entity_list.GetClientByName(ln);
|
||||
if(lc)
|
||||
group->SetLeader(lc);
|
||||
@@ -1007,6 +1015,7 @@ void WorldServer::Process() {
|
||||
group->SetPuller(PullerName);
|
||||
group->SetNPCMarker(NPCMarkerName);
|
||||
group->SetGroupAAs(&GLAA);
|
||||
group->SetGroupMentor(mentor_percent, mentoree_name);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1366,6 +1375,18 @@ void WorldServer::Process() {
|
||||
break;
|
||||
}
|
||||
|
||||
case ServerOP_RaidMOTD: {
|
||||
ServerRaidMOTD_Struct *rmotd = (ServerRaidMOTD_Struct *)pack->pBuffer;
|
||||
if (!zone)
|
||||
break;
|
||||
Raid *r = entity_list.GetRaidByID(rmotd->rid);
|
||||
if (!r)
|
||||
break;
|
||||
r->SetRaidMOTD(std::string(rmotd->motd));
|
||||
r->SendRaidMOTD();
|
||||
break;
|
||||
}
|
||||
|
||||
case ServerOP_SpawnPlayerCorpse: {
|
||||
SpawnPlayerCorpse_Struct* s = (SpawnPlayerCorpse_Struct*)pack->pBuffer;
|
||||
Corpse* NewCorpse = database.LoadPlayerCorpse(s->player_corpse_id);
|
||||
@@ -1777,6 +1798,24 @@ void WorldServer::Process() {
|
||||
|
||||
break;
|
||||
}
|
||||
case ServerOP_CZSetEntityVariableByNPCTypeID:
|
||||
{
|
||||
CZSetEntVarByNPCTypeID_Struct* CZM = (CZSetEntVarByNPCTypeID_Struct*)pack->pBuffer;
|
||||
NPC* n = entity_list.GetNPCByNPCTypeID(CZM->npctype_id);
|
||||
if (n != 0) {
|
||||
n->SetEntityVariable(CZM->id, CZM->m_var);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_CZSignalNPC:
|
||||
{
|
||||
CZNPCSignal_Struct* CZCN = (CZNPCSignal_Struct*)pack->pBuffer;
|
||||
NPC* n = entity_list.GetNPCByNPCTypeID(CZCN->npctype_id);
|
||||
if (n != 0) {
|
||||
n->SignalNPC(CZCN->data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ServerOP_CZSignalClient:
|
||||
{
|
||||
CZClientSignal_Struct* CZCS = (CZClientSignal_Struct*) pack->pBuffer;
|
||||
@@ -1856,6 +1895,7 @@ bool WorldServer::SendChannelMessage(Client* from, const char* to, uint8 chan_nu
|
||||
scm->chan_num = chan_num;
|
||||
scm->guilddbid = guilddbid;
|
||||
scm->language = language;
|
||||
scm->queued = 0;
|
||||
strcpy(scm->message, buffer);
|
||||
|
||||
pack->Deflate();
|
||||
@@ -2180,3 +2220,19 @@ void WorldServer::HandleLFPMatches(ServerPacket *pack) {
|
||||
safe_delete(outapp);
|
||||
}
|
||||
}
|
||||
|
||||
void WorldServer::RequestTellQueue(const char *who)
|
||||
{
|
||||
if (!who)
|
||||
return;
|
||||
|
||||
ServerPacket* pack = new ServerPacket(ServerOP_RequestTellQueue, sizeof(ServerRequestTellQueue_Struct));
|
||||
ServerRequestTellQueue_Struct* rtq = (ServerRequestTellQueue_Struct*) pack->pBuffer;
|
||||
|
||||
strn0cpy(rtq->name, who, sizeof(rtq->name));
|
||||
|
||||
SendPacket(pack);
|
||||
safe_delete(pack);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@ public:
|
||||
void HandleLFGMatches(ServerPacket *pack);
|
||||
void HandleLFPMatches(ServerPacket *pack);
|
||||
|
||||
void RequestTellQueue(const char *who);
|
||||
|
||||
private:
|
||||
virtual void OnConnected();
|
||||
|
||||
|
||||
+78
-143
@@ -77,8 +77,6 @@ extern bool staticzone;
|
||||
Zone* zone = 0;
|
||||
volatile bool ZoneLoaded = false;
|
||||
extern QuestParserCollection* parse;
|
||||
extern DBAsyncFinishedQueue MTdbafq;
|
||||
extern DBAsync *dbasync;
|
||||
|
||||
bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) {
|
||||
const char* zonename = database.GetZoneName(iZoneID);
|
||||
@@ -105,7 +103,7 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool iStaticZone) {
|
||||
}
|
||||
zone->zonemap = Map::LoadMapFile(zone->map_name);
|
||||
zone->watermap = WaterMap::LoadWaterMapfile(zone->map_name);
|
||||
zone->pathing = PathManager::LoadPathFile(zone->map_name);
|
||||
zone->pathing = PathManager::LoadPathFile(zone->map_name);
|
||||
|
||||
char tmp[10];
|
||||
if (database.GetVariable("loglevel",tmp, 9)) {
|
||||
@@ -309,41 +307,40 @@ bool Zone::LoadGroundSpawns() {
|
||||
return(true);
|
||||
}
|
||||
|
||||
int Zone::SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold){
|
||||
int Zone::SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold) {
|
||||
int freeslot = 0;
|
||||
std::list<MerchantList> merlist = merchanttable[merchantid];
|
||||
std::list<MerchantList>::const_iterator itr;
|
||||
uint32 i = 1;
|
||||
for (itr = merlist.begin(); itr != merlist.end(); ++itr) {
|
||||
MerchantList ml = *itr;
|
||||
if(ml.item == item)
|
||||
if (ml.item == item)
|
||||
return 0;
|
||||
|
||||
// Account for merchant lists with gaps in them.
|
||||
if(ml.slot >= i)
|
||||
if (ml.slot >= i)
|
||||
i = ml.slot + 1;
|
||||
|
||||
}
|
||||
std::list<TempMerchantList> tmp_merlist = tmpmerchanttable[npcid];
|
||||
std::list<TempMerchantList>::const_iterator tmp_itr;
|
||||
bool update_charges = false;
|
||||
TempMerchantList ml;
|
||||
while(freeslot == 0 && !update_charges){
|
||||
while (freeslot == 0 && !update_charges) {
|
||||
freeslot = i;
|
||||
for (tmp_itr = tmp_merlist.begin(); tmp_itr != tmp_merlist.end(); ++tmp_itr) {
|
||||
ml = *tmp_itr;
|
||||
if(ml.item == item){
|
||||
if (ml.item == item) {
|
||||
update_charges = true;
|
||||
freeslot = 0;
|
||||
break;
|
||||
}
|
||||
if((ml.slot == i) || (ml.origslot==i)) {
|
||||
freeslot=0;
|
||||
if ((ml.slot == i) || (ml.origslot == i)) {
|
||||
freeslot = 0;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if(update_charges){
|
||||
if (update_charges) {
|
||||
tmp_merlist.clear();
|
||||
std::list<TempMerchantList> oldtmp_merlist = tmpmerchanttable[npcid];
|
||||
for (tmp_itr = oldtmp_merlist.begin(); tmp_itr != oldtmp_merlist.end(); ++tmp_itr) {
|
||||
@@ -351,27 +348,27 @@ int Zone::SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charg
|
||||
if(ml2.item != item)
|
||||
tmp_merlist.push_back(ml2);
|
||||
}
|
||||
if(sold)
|
||||
if (sold)
|
||||
ml.charges = ml.charges + charges;
|
||||
else
|
||||
ml.charges = charges;
|
||||
if(!ml.origslot)
|
||||
if (!ml.origslot)
|
||||
ml.origslot = ml.slot;
|
||||
if(charges>0){
|
||||
if (charges > 0) {
|
||||
database.SaveMerchantTemp(npcid, ml.origslot, item, ml.charges);
|
||||
tmp_merlist.push_back(ml);
|
||||
}
|
||||
else{
|
||||
database.DeleteMerchantTemp(npcid,ml.origslot);
|
||||
else {
|
||||
database.DeleteMerchantTemp(npcid, ml.origslot);
|
||||
}
|
||||
tmpmerchanttable[npcid] = tmp_merlist;
|
||||
|
||||
if(sold)
|
||||
if (sold)
|
||||
return ml.slot;
|
||||
|
||||
}
|
||||
if(freeslot){
|
||||
if(charges<0) //sanity check only, shouldnt happen
|
||||
if (freeslot) {
|
||||
if (charges < 0) //sanity check only, shouldnt happen
|
||||
charges = 0x7FFF;
|
||||
database.SaveMerchantTemp(npcid, freeslot, item, charges);
|
||||
tmp_merlist = tmpmerchanttable[npcid];
|
||||
@@ -393,48 +390,42 @@ uint32 Zone::GetTempMerchantQuantity(uint32 NPCID, uint32 Slot) {
|
||||
std::list<TempMerchantList>::const_iterator Iterator;
|
||||
|
||||
for (Iterator = TmpMerchantList.begin(); Iterator != TmpMerchantList.end(); ++Iterator)
|
||||
if((*Iterator).slot == Slot)
|
||||
if ((*Iterator).slot == Slot)
|
||||
return (*Iterator).charges;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Zone::LoadTempMerchantData(){
|
||||
void Zone::LoadTempMerchantData() {
|
||||
LogFile->write(EQEMuLog::Status, "Loading Temporary Merchant Lists...");
|
||||
|
||||
char* query = 0;
|
||||
uint32_breakdown workpt;
|
||||
workpt.b4() = DBA_b4_Zone;
|
||||
workpt.w2_3() = 0;
|
||||
workpt.b1() = DBA_b1_Zone_MerchantListsTemp;
|
||||
DBAsyncWork* dbaw = new DBAsyncWork(&database, &MTdbafq, workpt, DBAsync::Read);
|
||||
dbaw->AddQuery(1, &query, MakeAnyLenString(&query,
|
||||
"select ml.npcid,ml.slot,ml.itemid,ml.charges "
|
||||
"from "
|
||||
" merchantlist_temp ml, "
|
||||
" spawnentry se, "
|
||||
" spawn2 s2 "
|
||||
"where "
|
||||
" ml.npcid=se.npcid "
|
||||
" and se.spawngroupid=s2.spawngroupid "
|
||||
" and s2.zone='%s' and s2.version=%u", GetShortName(), GetInstanceVersion()));
|
||||
if (!(pQueuedMerchantsWorkID = dbasync->AddWork(&dbaw))) {
|
||||
safe_delete(dbaw);
|
||||
LogFile->write(EQEMuLog::Error, "dbasync->AddWork() failed adding merchant list query");
|
||||
std::string query = StringFormat(
|
||||
"SELECT "
|
||||
"ml.npcid, "
|
||||
"ml.slot, "
|
||||
"ml.charges, "
|
||||
"ml.itemid "
|
||||
"FROM "
|
||||
"merchantlist_temp ml, "
|
||||
"spawnentry se, "
|
||||
"spawn2 s2 "
|
||||
"WHERE "
|
||||
"ml.npcid = se.npcid "
|
||||
"AND se.spawngroupid = s2.spawngroupid "
|
||||
"AND s2.zone = '%s' AND s2.version = %i "
|
||||
"ORDER BY ml.slot ", GetShortName(), GetInstanceVersion());
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadTempMerchantData query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Zone::LoadTempMerchantData_result(MYSQL_RES* result) {
|
||||
MYSQL_ROW row;
|
||||
std::map<uint32,std::list<TempMerchantList> >::iterator cur;
|
||||
std::map<uint32, std::list<TempMerchantList> >::iterator cur;
|
||||
uint32 npcid = 0;
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
TempMerchantList ml;
|
||||
ml.npcid = atoul(row[0]);
|
||||
if(npcid != ml.npcid){
|
||||
if (npcid != ml.npcid){
|
||||
cur = tmpmerchanttable.find(ml.npcid);
|
||||
if(cur == tmpmerchanttable.end()) {
|
||||
if (cur == tmpmerchanttable.end()) {
|
||||
std::list<TempMerchantList> empty;
|
||||
tmpmerchanttable[ml.npcid] = empty;
|
||||
cur = tmpmerchanttable.find(ml.npcid);
|
||||
@@ -442,19 +433,19 @@ void Zone::LoadTempMerchantData_result(MYSQL_RES* result) {
|
||||
npcid = ml.npcid;
|
||||
}
|
||||
ml.slot = atoul(row[1]);
|
||||
ml.item = atoul(row[2]);
|
||||
ml.charges = atoul(row[3]);
|
||||
ml.charges = atoul(row[2]);
|
||||
ml.item = atoul(row[3]);
|
||||
ml.origslot = ml.slot;
|
||||
cur->second.push_back(ml);
|
||||
}
|
||||
pQueuedMerchantsWorkID = 0;
|
||||
}
|
||||
|
||||
//there should prolly be a temp counterpart of this...
|
||||
void Zone::LoadNewMerchantData(uint32 merchantid){
|
||||
void Zone::LoadNewMerchantData(uint32 merchantid) {
|
||||
|
||||
std::list<MerchantList> merlist;
|
||||
std::string query = StringFormat("SELECT item, slot, faction_required, level_required, alt_currency_cost, "
|
||||
"classes_required FROM merchantlist WHERE merchantid=%d", merchantid);
|
||||
"classes_required FROM merchantlist WHERE merchantid=%d ORDER BY slot", merchantid);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in LoadNewMerchantData query '%s' %s", query.c_str(), results.ErrorMessage().c_str());
|
||||
@@ -476,16 +467,39 @@ void Zone::LoadNewMerchantData(uint32 merchantid){
|
||||
merchanttable[merchantid] = merlist;
|
||||
}
|
||||
|
||||
void Zone::LoadMerchantData_result(MYSQL_RES* result) {
|
||||
MYSQL_ROW row;
|
||||
std::map<uint32,std::list<MerchantList> >::iterator cur;
|
||||
void Zone::GetMerchantDataForZoneLoad() {
|
||||
LogFile->write(EQEMuLog::Status, "Loading Merchant Lists...");
|
||||
std::string query = StringFormat(
|
||||
"SELECT "
|
||||
"ml.merchantid, "
|
||||
"ml.slot, "
|
||||
"ml.item, "
|
||||
"ml.faction_required, "
|
||||
"ml.level_required, "
|
||||
"ml.alt_currency_cost, "
|
||||
"ml.classes_required, "
|
||||
"ml.probability "
|
||||
"FROM "
|
||||
"merchantlist AS ml, "
|
||||
"npc_types AS nt, "
|
||||
"spawnentry AS se, "
|
||||
"spawn2 AS s2 "
|
||||
"WHERE nt.merchant_id = ml.merchantid AND nt.id = se.npcid "
|
||||
"AND se.spawngroupid = s2.spawngroupid AND s2.zone = '%s' AND s2.version = %i "
|
||||
"ORDER BY ml.slot ", GetShortName(), GetInstanceVersion());
|
||||
auto results = database.QueryDatabase(query);
|
||||
std::map<uint32, std::list<MerchantList> >::iterator cur;
|
||||
uint32 npcid = 0;
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
if (results.RowCount() == 0) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in loading Merchant Data for zone");
|
||||
return;
|
||||
}
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
MerchantList ml;
|
||||
ml.id = atoul(row[0]);
|
||||
if(npcid != ml.id){
|
||||
if (npcid != ml.id) {
|
||||
cur = merchanttable.find(ml.id);
|
||||
if(cur == merchanttable.end()) {
|
||||
if (cur == merchanttable.end()) {
|
||||
std::list<MerchantList> empty;
|
||||
merchanttable[ml.id] = empty;
|
||||
cur = merchanttable.find(ml.id);
|
||||
@@ -495,15 +509,15 @@ void Zone::LoadMerchantData_result(MYSQL_RES* result) {
|
||||
|
||||
std::list<MerchantList>::iterator iter = cur->second.begin();
|
||||
bool found = false;
|
||||
while(iter != cur->second.end()) {
|
||||
if((*iter).item == ml.id) {
|
||||
while (iter != cur->second.end()) {
|
||||
if ((*iter).item == ml.id) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
|
||||
if(found) {
|
||||
if (found) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -516,28 +530,7 @@ void Zone::LoadMerchantData_result(MYSQL_RES* result) {
|
||||
ml.probability = atoul(row[7]);
|
||||
cur->second.push_back(ml);
|
||||
}
|
||||
}
|
||||
|
||||
void Zone::GetMerchantDataForZoneLoad(){
|
||||
LogFile->write(EQEMuLog::Status, "Loading Merchant Lists...");
|
||||
char* query = 0;
|
||||
uint32_breakdown workpt;
|
||||
workpt.b4() = DBA_b4_Zone;
|
||||
workpt.w2_3() = 0;
|
||||
workpt.b1() = DBA_b1_Zone_MerchantLists;
|
||||
DBAsyncWork* dbaw = new DBAsyncWork(&database, &MTdbafq, workpt, DBAsync::Read);
|
||||
dbaw->AddQuery(1, &query, MakeAnyLenString(&query,
|
||||
"select ml.merchantid,ml.slot,ml.item,ml.faction_required,ml.level_required,ml.alt_currency_cost,ml.classes_required,ml.probability "
|
||||
"from merchantlist ml, npc_types nt, spawnentry se, spawn2 s2 "
|
||||
"where nt.merchant_id=ml.merchantid and nt.id=se.npcid "
|
||||
"and se.spawngroupid=s2.spawngroupid and s2.zone='%s' and s2.version=%u "
|
||||
//"group by ml.merchantid,slot order by merchantid,slot asc" //this made the query use a temp table/filesort (very slow)... so we handle unsorted data on our end.
|
||||
, GetShortName(), GetInstanceVersion()));
|
||||
if (!(pQueuedMerchantsWorkID = dbasync->AddWork(&dbaw))) {
|
||||
safe_delete(dbaw);
|
||||
LogFile->write(EQEMuLog::Error,"dbasync->AddWork() failed adding merchant list query");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Zone::LoadMercTemplates(){
|
||||
@@ -665,61 +658,6 @@ void Zone::LoadMercSpells(){
|
||||
|
||||
}
|
||||
|
||||
void Zone::DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw) {
|
||||
// LogFile->write(EQEMuLog::Debug, "Zone work complete...");
|
||||
switch (workpt_b1) {
|
||||
case DBA_b1_Zone_MerchantLists: {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES* result = 0;
|
||||
DBAsyncQuery* dbaq = dbaw->PopAnswer();
|
||||
if(dbaq == nullptr) {
|
||||
LogFile->write(EQEMuLog::Error, "nullptr answer provided for async merchant list load.");
|
||||
break;
|
||||
}
|
||||
if(!dbaq->GetAnswer(errbuf, &result)) {
|
||||
LogFile->write(EQEMuLog::Error, "Zone::DBAWComplete(): Unable to get results for merchant lists");
|
||||
break;
|
||||
}
|
||||
if(dbaq->QPT() != 1) {
|
||||
LogFile->write(EQEMuLog::Error, "Zone::DBAWComplete(): Invalid query part for merchant lists");
|
||||
break;
|
||||
}
|
||||
|
||||
LoadMerchantData_result(result);
|
||||
|
||||
pQueuedMerchantsWorkID = 0;
|
||||
break;
|
||||
}
|
||||
case DBA_b1_Zone_MerchantListsTemp: {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES* result = 0;
|
||||
DBAsyncQuery* dbaq = dbaw->PopAnswer();
|
||||
if(dbaq == nullptr) {
|
||||
LogFile->write(EQEMuLog::Error, "nullptr answer provided for async temp merchant list load.");
|
||||
break;
|
||||
}
|
||||
if(!dbaq->GetAnswer(errbuf, &result)) {
|
||||
LogFile->write(EQEMuLog::Error, "Zone::DBAWComplete(): Unable to get results for temp merchant lists");
|
||||
break;
|
||||
}
|
||||
if(dbaq->QPT() != 1) {
|
||||
LogFile->write(EQEMuLog::Error, "Zone::DBAWComplete(): Invalid query part for temp merchant lists");
|
||||
break;
|
||||
}
|
||||
|
||||
LoadTempMerchantData_result(result);
|
||||
|
||||
pQueuedMerchantsWorkID = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
LogFile->write(EQEMuLog::Error, "Zone::DBAWComplete(): Unknown workpt_b1");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Zone::IsLoaded() {
|
||||
return ZoneLoaded;
|
||||
}
|
||||
@@ -772,7 +710,6 @@ void Zone::Shutdown(bool quite)
|
||||
|
||||
zone->ResetAuth();
|
||||
safe_delete(zone);
|
||||
dbasync->CommitWrites();
|
||||
entity_list.ClearAreas();
|
||||
parse->ReloadQuests(true);
|
||||
UpdateWindowTitle();
|
||||
@@ -911,8 +848,6 @@ Zone::Zone(uint32 in_zoneid, uint32 in_instanceid, const char* in_short_name)
|
||||
}
|
||||
|
||||
Zone::~Zone() {
|
||||
if(pQueuedMerchantsWorkID != 0)
|
||||
dbasync->CancelWork(pQueuedMerchantsWorkID);
|
||||
spawn2_list.Clear();
|
||||
safe_delete(zonemap);
|
||||
safe_delete(watermap);
|
||||
|
||||
@@ -166,7 +166,6 @@ public:
|
||||
void SetStaticZone(bool sz) { staticzone = sz; }
|
||||
inline bool IsStaticZone() { return staticzone; }
|
||||
inline void GotCurTime(bool time) { gottime = time; }
|
||||
void DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw);
|
||||
|
||||
void SpawnConditionChanged(const SpawnCondition &c, int16 old_value);
|
||||
|
||||
@@ -174,8 +173,6 @@ public:
|
||||
void LoadNewMerchantData(uint32 merchantid);
|
||||
void LoadTempMerchantData();
|
||||
uint32 GetTempMerchantQuantity(uint32 NPCID, uint32 Slot);
|
||||
void LoadTempMerchantData_result(MYSQL_RES* result);
|
||||
void LoadMerchantData_result(MYSQL_RES* result);
|
||||
int SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold=false);
|
||||
void LoadMercTemplates();
|
||||
void LoadMercSpells();
|
||||
|
||||
+1008
-240
File diff suppressed because it is too large
Load Diff
+84
-96
@@ -6,6 +6,8 @@
|
||||
#include "../common/loottable.h"
|
||||
#include "zonedump.h"
|
||||
#include "../common/faction.h"
|
||||
#include <limits>
|
||||
|
||||
//#include "doors.h"
|
||||
|
||||
struct wplist {
|
||||
@@ -212,9 +214,7 @@ public:
|
||||
ZoneDatabase(const char* host, const char* user, const char* passwd, const char* database,uint32 port);
|
||||
virtual ~ZoneDatabase();
|
||||
|
||||
/*
|
||||
* Objects and World Containers
|
||||
*/
|
||||
/* Objects and World Containers */
|
||||
void LoadWorldContainer(uint32 parentid, ItemInst* container);
|
||||
void SaveWorldContainer(uint32 zone_id, uint32 parent_id, const ItemInst* container);
|
||||
void DeleteWorldContainer(uint32 parent_id,uint32 zone_id);
|
||||
@@ -223,10 +223,7 @@ public:
|
||||
void DeleteObject(uint32 id);
|
||||
Ground_Spawns* LoadGroundSpawns(uint32 zone_id, int16 version, Ground_Spawns* gs);
|
||||
|
||||
/*
|
||||
* Traders
|
||||
*/
|
||||
|
||||
/* Traders */
|
||||
void SaveTraderItem(uint32 char_id,uint32 itemid,uint32 uniqueid, int32 charges,uint32 itemcost,uint8 slot);
|
||||
void UpdateTraderItemCharges(int char_id, uint32 ItemInstID, int32 charges);
|
||||
void UpdateTraderItemPrice(int CharID, uint32 ItemID, uint32 Charges, uint32 NewPrice);
|
||||
@@ -236,38 +233,67 @@ public:
|
||||
Trader_Struct* LoadTraderItem(uint32 char_id);
|
||||
TraderCharges_Struct* LoadTraderItemWithCharges(uint32 char_id);
|
||||
|
||||
// Buyer/Barter
|
||||
//
|
||||
/* Buyer/Barter */
|
||||
void AddBuyLine(uint32 CharID, uint32 BuySlot, uint32 ItemID, const char *ItemName, uint32 Quantity, uint32 Price);
|
||||
void RemoveBuyLine(uint32 CharID, uint32 BuySlot);
|
||||
void DeleteBuyLines(uint32 CharID);
|
||||
void UpdateBuyLine(uint32 CharID, uint32 BuySlot, uint32 Quantity);
|
||||
|
||||
/*
|
||||
* General Character Related Stuff
|
||||
*/
|
||||
void StoreCharacterLookup(uint32 char_id);
|
||||
bool GetAccountInfoForLogin_result(MYSQL_RES* result, int16* admin = 0, char* account_name = 0,
|
||||
uint32* lsaccountid = 0, uint8* gmspeed = 0, bool* revoked = 0, bool* gmhideme = nullptr,
|
||||
uint32* account_creation = 0);
|
||||
bool GetCharacterInfoForLogin_result(MYSQL_RES* result, uint32* character_id = 0, char* current_zone = 0,
|
||||
PlayerProfile_Struct* pp = 0, Inventory* inv = 0, ExtendedProfile_Struct *ext = 0, uint32* pplen = 0,
|
||||
uint32* guilddbid = 0, uint8* guildrank = 0, uint8 *class_= 0, uint8 *level = 0, bool *LFP = 0,
|
||||
bool *LFG = 0, uint8 *NumXTargets = 0, uint8* firstlogon = 0);
|
||||
/* General Character Related Stuff */
|
||||
bool SetServerFilters(char* name, ServerSideFilters_Struct *ssfs);
|
||||
uint32 GetServerFilters(char* name, ServerSideFilters_Struct *ssfs);
|
||||
|
||||
void SaveBuffs(Client *c);
|
||||
void LoadBuffs(Client *c);
|
||||
void LoadPetInfo(Client *c);
|
||||
void SavePetInfo(Client *c);
|
||||
void RemoveTempFactions(Client *c);
|
||||
|
||||
/*
|
||||
* Character Inventory
|
||||
*/
|
||||
/* Character Data Loaders */
|
||||
bool LoadCharacterFactionValues(uint32 character_id, faction_map & val_list);
|
||||
bool LoadCharacterSpellBook(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterMemmedSpells(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterLanguages(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterDisciplines(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterSkills(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterData(uint32 character_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp);
|
||||
bool LoadCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterMaterialColor(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool LoadCharacterLeadershipAA(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
|
||||
/* Character Data Saves */
|
||||
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
|
||||
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp);
|
||||
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
|
||||
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
|
||||
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
|
||||
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
|
||||
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
|
||||
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
|
||||
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
|
||||
bool SaveCharacterLeadershipAA(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
|
||||
/* Character Data Deletes */
|
||||
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
|
||||
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
|
||||
bool DeleteCharacterLeadershipAAs(uint32 character_id);
|
||||
bool DeleteCharacterAAs(uint32 character_id);
|
||||
bool DeleteCharacterDye(uint32 character_id);
|
||||
|
||||
/* Character Inventory */
|
||||
bool NoRentExpired(const char* name);
|
||||
|
||||
/*
|
||||
* Corpses
|
||||
*/
|
||||
/* Corpses */
|
||||
bool GetDecayTimes(npcDecayTimes_Struct* npcCorpseDecayTimes);
|
||||
uint32 CreatePlayerCorpse(uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, uchar* data, uint32 datasize, float x, float y, float z, float heading);
|
||||
bool CreatePlayerCorpseBackup(uint32 dbid, uint32 charid, const char* charname, uint32 zoneid, uint16 instanceid, uchar* data, uint32 datasize, float x, float y, float z, float heading);
|
||||
@@ -293,21 +319,15 @@ public:
|
||||
uint32 GetPlayerCorpseItemAt(uint32 corpse_id, uint16 slotid);
|
||||
uint32 GetPlayerCorpseTimeLeft(uint8 corpse, uint8 type);
|
||||
|
||||
/*
|
||||
* Faction
|
||||
*/
|
||||
/* Faction */
|
||||
bool GetNPCFactionList(uint32 npcfaction_id, int32* faction_id, int32* value, uint8* temp, int32* primary_faction = 0);
|
||||
bool GetFactionData(FactionMods* fd, uint32 class_mod, uint32 race_mod, uint32 deity_mod, int32 faction_id); //rembrant, needed for factions Dec, 16 2001
|
||||
bool GetFactionName(int32 faction_id, char* name, uint32 buflen); // rembrant, needed for factions Dec, 16 2001
|
||||
bool GetFactionIdsForNPC(uint32 nfl_id, std::list<struct NPCFaction*> *faction_list, int32* primary_faction = 0); // neotokyo: improve faction handling
|
||||
bool SetCharacterFactionLevel(uint32 char_id, int32 faction_id, int32 value, uint8 temp, faction_map &val_list); // rembrant, needed for factions Dec, 16 2001
|
||||
bool LoadFactionData();
|
||||
bool LoadFactionValues(uint32 char_id, faction_map & val_list);
|
||||
bool LoadFactionValues_result(MYSQL_RES* result, faction_map & val_list);
|
||||
|
||||
/*
|
||||
* AAs
|
||||
*/
|
||||
/* AAs */
|
||||
bool LoadAAEffects();
|
||||
bool LoadAAEffects2();
|
||||
bool LoadSwarmSpells();
|
||||
@@ -319,9 +339,7 @@ public:
|
||||
uint32 CountAAEffects();
|
||||
void FillAAEffects(SendAA_Struct* aa_struct);
|
||||
|
||||
/*
|
||||
* Zone related
|
||||
*/
|
||||
/* Zone related */
|
||||
bool GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct *data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, bool &allow_mercs, uint8 &zone_type, int &ruleset, char **map_filename);
|
||||
bool SaveZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct* zd);
|
||||
bool LoadStaticZonePoints(LinkedList<ZonePoint*>* zone_point_list,const char* zonename, uint32 version);
|
||||
@@ -329,9 +347,7 @@ public:
|
||||
uint8 GetUseCFGSafeCoords();
|
||||
int getZoneShutDownDelay(uint32 zoneID, uint32 version);
|
||||
|
||||
/*
|
||||
* Spawns and Spawn Points
|
||||
*/
|
||||
/* Spawns and Spawn Points */
|
||||
bool LoadSpawnGroups(const char* zone_name, uint16 version, SpawnGroupList* spawn_group_list);
|
||||
bool LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_group_list);
|
||||
bool PopulateZoneSpawnList(uint32 zoneid, LinkedList<Spawn2*> &spawn2_list, int16 version, uint32 repopdelay = 0);
|
||||
@@ -341,9 +357,7 @@ public:
|
||||
uint32 GetSpawnTimeLeft(uint32 id, uint16 instance_id);
|
||||
void UpdateSpawn2Status(uint32 id, uint8 new_status);
|
||||
|
||||
/*
|
||||
* Grids/Paths
|
||||
*/
|
||||
/* Grids/Paths */
|
||||
uint32 GetFreeGrid(uint16 zoneid);
|
||||
void DeleteGrid(Client *c, uint32 sg2, uint32 grid_num, bool grid_too,uint16 zoneid);
|
||||
void DeleteWaypoint(Client *c, uint32 grid_num, uint32 wp_num,uint16 zoneid);
|
||||
@@ -359,11 +373,16 @@ public:
|
||||
int GetHighestGrid(uint32 zoneid);
|
||||
int GetHighestWaypoint(uint32 zoneid, uint32 gridid);
|
||||
|
||||
/*
|
||||
* NPCs
|
||||
*/
|
||||
/* NPCs */
|
||||
const NPCType* GetNPCType(uint32 id);
|
||||
uint32 NPCSpawnDB(uint8 command, const char* zone, uint32 zone_version, Client *c, NPC* spawn = 0, uint32 extra = 0); // 0 = Create 1 = Add; 2 = Update; 3 = Remove; 4 = Delete
|
||||
uint32 CreateNewNPCCommand(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 extra);
|
||||
uint32 AddNewNPCSpawnGroupCommand(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 respawnTime);
|
||||
uint32 DeleteSpawnLeaveInNPCTypeTable(const char* zone, Client *client, NPC* spawn);
|
||||
uint32 DeleteSpawnRemoveFromNPCTypeTable(const char* zone, uint32 zone_version, Client *client, NPC* spawn);
|
||||
uint32 AddSpawnFromSpawnGroup(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 spawnGroupID);
|
||||
uint32 AddNPCTypes(const char* zone, uint32 zone_version, Client *client, NPC* spawn, uint32 spawnGroupID);
|
||||
uint32 UpdateNPCTypeAppearance(Client *client, NPC* spawn);
|
||||
bool SetSpecialAttkFlag(uint8 id, const char* flag);
|
||||
bool GetPetEntry(const char *pet_type, PetRecord *into);
|
||||
bool GetPoweredPetEntry(const char *pet_type, int16 petpower, PetRecord *into);
|
||||
@@ -375,9 +394,7 @@ public:
|
||||
DBnpcspells_Struct* GetNPCSpells(uint32 iDBSpellsID);
|
||||
DBnpcspellseffects_Struct* GetNPCSpellsEffects(uint32 iDBSpellsEffectsID);
|
||||
|
||||
/*
|
||||
* Mercs
|
||||
*/
|
||||
/* Mercs */
|
||||
const NPCType* GetMercType(uint32 id, uint16 raceid, uint32 clientlevel);
|
||||
void LoadMercEquipment(Merc *merc);
|
||||
void SaveMercBuffs(Merc *merc);
|
||||
@@ -389,9 +406,7 @@ public:
|
||||
//void LoadMercTypesForMercMerchant(NPC *merchant);
|
||||
//void LoadMercsForMercMerchant(NPC *merchant);
|
||||
|
||||
/*
|
||||
* Petitions
|
||||
*/
|
||||
/* Petitions */
|
||||
void UpdateBug(BugStruct* bug);
|
||||
void UpdateBug(PetitionBug_Struct* bug);
|
||||
void DeletePetitionFromDB(Petition* wpet);
|
||||
@@ -399,16 +414,11 @@ public:
|
||||
void InsertPetitionToDB(Petition* wpet);
|
||||
void RefreshPetitionsFromDB();
|
||||
|
||||
|
||||
/*
|
||||
* Merchants
|
||||
*/
|
||||
/* Merchants */
|
||||
void SaveMerchantTemp(uint32 npcid, uint32 slot, uint32 item, uint32 charges);
|
||||
void DeleteMerchantTemp(uint32 npcid, uint32 slot);
|
||||
|
||||
/*
|
||||
* Tradeskills
|
||||
*/
|
||||
/* Tradeskills */
|
||||
bool GetTradeRecipe(const ItemInst* container, uint8 c_type, uint32 some_id, uint32 char_id, DBTradeskillRecipe_Struct *spec);
|
||||
bool GetTradeRecipe(uint32 recipe_id, uint8 c_type, uint32 some_id, uint32 char_id, DBTradeskillRecipe_Struct *spec);
|
||||
uint32 GetZoneForage(uint32 ZoneID, uint8 skill); /* for foraging */
|
||||
@@ -417,14 +427,10 @@ public:
|
||||
bool EnableRecipe(uint32 recipe_id);
|
||||
bool DisableRecipe(uint32 recipe_id);
|
||||
|
||||
/*
|
||||
* Tribute
|
||||
*/
|
||||
/* Tribute */
|
||||
bool LoadTributes();
|
||||
|
||||
/*
|
||||
* Doors
|
||||
*/
|
||||
/* Doors */
|
||||
bool DoorIsOpen(uint8 door_id,const char* zone_name);
|
||||
void SetDoorPlace(uint8 value,uint8 door_id,const char* zone_name);
|
||||
bool LoadDoors(int32 iDoorCount, Door *into, const char *zone_name, int16 version);
|
||||
@@ -437,64 +443,46 @@ public:
|
||||
int32 GetDoorsDBCountPlusOne(const char *zone_name, int16 version);
|
||||
void InsertDoor(uint32 did, uint16 ddoorid, const char* ddoor_name, float dxpos, float dypos, float dzpos, float dheading, uint8 dopentype, uint16 dguildid, uint32 dlockpick, uint32 dkeyitem, uint8 ddoor_param, uint8 dinvert, int dincline, uint16 dsize);
|
||||
|
||||
/*
|
||||
* Blocked Spells
|
||||
*/
|
||||
|
||||
/* Blocked Spells */
|
||||
int32 GetBlockedSpellsCount(uint32 zoneid);
|
||||
bool LoadBlockedSpells(int32 blockedSpellsCount, ZoneSpellsBlocked* into, uint32 zoneid);
|
||||
|
||||
/*
|
||||
* Traps
|
||||
*/
|
||||
/* Traps */
|
||||
bool LoadTraps(const char* zonename, int16 version);
|
||||
char* GetTrapMessage(uint32 trap_id);
|
||||
|
||||
/*
|
||||
* Time
|
||||
*/
|
||||
/* Time */
|
||||
uint32 GetZoneTZ(uint32 zoneid, uint32 version);
|
||||
bool SetZoneTZ(uint32 zoneid, uint32 version, uint32 tz);
|
||||
|
||||
/*
|
||||
* Group
|
||||
*/
|
||||
/* Group */
|
||||
void RefreshGroupFromDB(Client *c);
|
||||
uint8 GroupCount(uint32 groupid);
|
||||
/*
|
||||
* Raid
|
||||
*/
|
||||
|
||||
/* Raid */
|
||||
uint8 RaidGroupCount(uint32 raidid, uint32 groupid);
|
||||
|
||||
/*
|
||||
* Instancing
|
||||
*/
|
||||
/* Instancing */
|
||||
void ListAllInstances(Client* c, uint32 charid);
|
||||
|
||||
/*
|
||||
* QGlobals
|
||||
*/
|
||||
/* QGlobals */
|
||||
void QGlobalPurge();
|
||||
|
||||
/*
|
||||
* Alternate Currency
|
||||
*/
|
||||
/* Alternate Currency */
|
||||
void LoadAltCurrencyValues(uint32 char_id, std::map<uint32, uint32> ¤cy);
|
||||
void UpdateAltCurrencyValue(uint32 char_id, uint32 currency_id, uint32 value);
|
||||
|
||||
/*
|
||||
* Misc stuff.
|
||||
* PLEASE DO NOT ADD TO THIS COLLECTION OF CRAP UNLESS YOUR METHOD
|
||||
* REALLY HAS NO BETTER SECTION
|
||||
* Misc stuff.
|
||||
* PLEASE DO NOT ADD TO THIS COLLECTION OF CRAP UNLESS YOUR METHOD
|
||||
* REALLY HAS NO BETTER SECTION
|
||||
*/
|
||||
bool logevents(const char* accountname,uint32 accountid,uint8 status,const char* charname,const char* target, const char* descriptiontype, const char* description,int event_nid);
|
||||
void GetEventLogs(const char* name,char* target,uint32 account_id=0,uint8 eventid=0,char* detail=0,char* timestamp=0, CharacterEventLog_Struct* cel=0);
|
||||
uint32 GetKarma(uint32 acct_id);
|
||||
void UpdateKarma(uint32 acct_id, uint32 amount);
|
||||
|
||||
/*
|
||||
* Things which really dont belong here...
|
||||
*/
|
||||
/* Things which really dont belong here... */
|
||||
int16 CommandRequirement(const char* commandname);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
#include "../common/debug.h"
|
||||
#include <iostream>
|
||||
#include "entity.h"
|
||||
#include "masterentity.h"
|
||||
#include "../common/string_util.h"
|
||||
#include "../common/breakdowns.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
extern EntityList entity_list;
|
||||
|
||||
void DispatchFinishedDBAsync(DBAsyncWork* dbaw) {
|
||||
uint32_breakdown workpt;
|
||||
workpt = dbaw->WPT();
|
||||
switch (workpt.b4()) {
|
||||
/* case DBA_b4_Main: {
|
||||
switch (workpt.i24_1()) {
|
||||
case DBA_i24_1_Main_LoadVariables: {
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
MYSQL_RES* result;
|
||||
DBAsyncQuery* dbaq = dbaw->PopAnswer();
|
||||
if (dbaq->GetAnswer(errbuf, result))
|
||||
database.LoadVariables_result(result);
|
||||
else
|
||||
std::cout << "Async DB.LoadVariables() failed: '" << errbuf << "'" << std::endl;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
std::cout << "Error: DispatchFinishedDBAsync(): Unknown workpt.b4" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
case DBA_b4_Zone: {
|
||||
if(zone == nullptr)
|
||||
break;
|
||||
zone->DBAWComplete(workpt.b1(), dbaw);
|
||||
break;
|
||||
}
|
||||
case DBA_b4_Entity: {
|
||||
Entity* entity = entity_list.GetID(workpt.w2_3());
|
||||
if (!entity)
|
||||
break;
|
||||
entity->DBAWComplete(workpt.b1(), dbaw);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
std::cout << "Error: DispatchFinishedDBAsync(): Unknown workpt.b4: " << (int) workpt.b4() << ", workpt=" << workpt << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
safe_delete(dbaw);
|
||||
}
|
||||
|
||||
#define MAX_TO_DELETE 10
|
||||
#define MAX_BACKUPS 5
|
||||
bool DBAsyncCB_CharacterBackup(DBAsyncWork* iWork) { // return true means delete data
|
||||
char errbuf[MYSQL_ERRMSG_SIZE] = "dbaq == 0";
|
||||
MYSQL_RES* result = 0;
|
||||
MYSQL_ROW row;
|
||||
char* query = 0;
|
||||
uint32 i;
|
||||
uint8 ToDeleteIndex = 0;
|
||||
uint32 ToDelete[MAX_TO_DELETE];
|
||||
memset(ToDelete, 0, sizeof(ToDelete));
|
||||
|
||||
uint32 BackupAges[MAX_BACKUPS]; // must be sorted, highest value in lowest index
|
||||
memset(BackupAges, 0, sizeof(BackupAges));
|
||||
|
||||
bool FoundBackup[MAX_BACKUPS];
|
||||
memset(FoundBackup, 0, sizeof(FoundBackup));
|
||||
|
||||
BackupAges[0] = 86400;
|
||||
BackupAges[1] = 3600;
|
||||
|
||||
DBAsyncQuery* dbaq = iWork->PopAnswer();
|
||||
if (dbaq && dbaq->GetAnswer(errbuf, &result)) {
|
||||
while ((row = mysql_fetch_row(result))) {
|
||||
for (i=0; i<MAX_BACKUPS; i++) {
|
||||
if (BackupAges[i] == 0 || (uint32)atoi(row[1]) > BackupAges[i])
|
||||
i = MAX_BACKUPS;
|
||||
else if (!FoundBackup[i]) {
|
||||
FoundBackup[i] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= MAX_BACKUPS)
|
||||
ToDelete[ToDeleteIndex++] = atoi(row[0]);
|
||||
if (ToDeleteIndex >= MAX_TO_DELETE)
|
||||
break;
|
||||
}
|
||||
if (ToDelete[0]) {
|
||||
uint32 len = 0, size = 0;
|
||||
AppendAnyLenString(&query, &size, &len, "Delete from character_backup where id=%u", ToDelete[0]);
|
||||
for (uint8 i=1; i<ToDeleteIndex; i++) {
|
||||
AppendAnyLenString(&query, &size, &len, " or id=%u", ToDelete[i]);
|
||||
}
|
||||
if (!database.RunQuery(query, len, errbuf)) {
|
||||
LogFile->write(EQEMuLog::Error, "Error in DBAsyncCB_CharacterBackup query2 '%s' %s", query, errbuf);
|
||||
safe_delete_array(query);
|
||||
return true;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
}
|
||||
bool needtoinsert = false;
|
||||
for (i=0; i<MAX_BACKUPS; i++) {
|
||||
if (BackupAges[i] != 0 && !FoundBackup[i])
|
||||
needtoinsert = true;
|
||||
}
|
||||
if (needtoinsert) {
|
||||
if (!database.RunQuery(query, MakeAnyLenString(&query,
|
||||
"Insert Delayed into character_backup (charid, account_id, name, profile, level, class, x, y, z, zoneid) "
|
||||
"select id, account_id, name, profile, level, class, x, y, z, zoneid "
|
||||
"from character_ where id=%u", iWork->WPT()), errbuf)) {
|
||||
std::cout << "Error in DBAsyncCB_CharacterBackup query3 '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
return true;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// std::cout << "Error in DBAsyncCB_CharacterBackup query1 '" << query << "' " << errbuf << std::endl;
|
||||
safe_delete_array(query);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef ZONEDBASYNC_H
|
||||
#define ZONEDBASYNC_H
|
||||
|
||||
#include "../common/dbasync.h"
|
||||
void DispatchFinishedDBAsync(DBAsyncWork* iDBAW);
|
||||
bool DBAsyncCB_CharacterBackup(DBAsyncWork* iWork);
|
||||
|
||||
#define DBA_b4_Main 1
|
||||
#define DBA_b4_Worldserver 2
|
||||
#define DBA_b4_Zone 3
|
||||
#define DBA_b4_Entity 4
|
||||
|
||||
#define DBA_b1_Entity_SeeQPT 0
|
||||
#define DBA_b1_Entity_Client_InfoForLogin 1
|
||||
#define DBA_b1_Entity_Client_Save 2
|
||||
#define DBA_b1_Entity_Client_Backup 3
|
||||
#define DBA_b1_Entity_Corpse_Backup 4
|
||||
#define DBA_b1_Zone_MerchantLists 5
|
||||
#define DBA_b1_Zone_MerchantListsTemp 6
|
||||
|
||||
#endif
|
||||
|
||||
+2
-1
@@ -354,7 +354,7 @@ void Client::DoZoneSuccess(ZoneChange_Struct *zc, uint16 zone_id, uint32 instanc
|
||||
m_pp.zoneInstance = instance_id;
|
||||
|
||||
//Force a save so its waiting for them when they zone
|
||||
Save(2);
|
||||
Save(2);
|
||||
|
||||
if (zone_id == zone->GetZoneID() && instance_id == zone->GetInstanceID()) {
|
||||
// No need to ask worldserver if we're zoning to ourselves (most
|
||||
@@ -704,6 +704,7 @@ void Client::SetBindPoint(int to_zone, float new_x, float new_y, float new_z) {
|
||||
m_pp.binds[0].y = new_y;
|
||||
m_pp.binds[0].z = new_z;
|
||||
}
|
||||
database.SaveCharacterBindPoint(this->CharacterID(), m_pp.binds[0].zoneId, 0, m_pp.binds[0].x, m_pp.binds[0].y, m_pp.binds[0].z, 0, 0);
|
||||
}
|
||||
|
||||
void Client::GoToBind(uint8 bindnum) {
|
||||
|
||||
Reference in New Issue
Block a user