Merge branch 'master' of git://github.com/EQEmu/Server

This commit is contained in:
af4t
2013-03-01 00:27:20 -05:00
12 changed files with 865 additions and 79 deletions
+5 -5
View File
@@ -7207,11 +7207,11 @@ void Client::SendMercPersonalInfo()
mml->Mercs[i].MercID = mercData->MercTemplateID;
mml->Mercs[i].MercType = mercData->MercType;
mml->Mercs[i].MercSubType = mercData->MercSubType;
mml->Mercs[i].PurchaseCost = Merc::CalcPurchaseCost(mercData->MercTemplateID, GetLevel(), 0);
mml->Mercs[i].UpkeepCost = Merc::CalcUpkeepCost(mercData->MercTemplateID, GetLevel(), 0);
mml->Mercs[i].Status = 0;
mml->Mercs[i].AltCurrencyCost = Merc::CalcPurchaseCost(mercData->MercTemplateID, GetLevel(), altCurrentType);
mml->Mercs[i].AltCurrencyUpkeep = Merc::CalcPurchaseCost(mercData->MercTemplateID, GetLevel(), altCurrentType);
mml->Mercs[i].PurchaseCost = RuleB(Mercs, ChargeMercPurchaseCost) ? Merc::CalcPurchaseCost(mercData->MercTemplateID, GetLevel(), 0): 0;
mml->Mercs[i].UpkeepCost = RuleB(Mercs, ChargeMercUpkeepCost) ? Merc::CalcUpkeepCost(mercData->MercTemplateID, GetLevel(), 0): 0;
mml->Mercs[i].Status = 0;
mml->Mercs[i].AltCurrencyCost = RuleB(Mercs, ChargeMercPurchaseCost) ? Merc::CalcPurchaseCost(mercData->MercTemplateID, GetLevel(), altCurrentType): 0;
mml->Mercs[i].AltCurrencyUpkeep = RuleB(Mercs, ChargeMercUpkeepCost) ? Merc::CalcUpkeepCost(mercData->MercTemplateID, GetLevel(), altCurrentType): 0;
mml->Mercs[i].AltCurrencyType = altCurrentType;
mml->Mercs[i].MercUnk01 = 0;
mml->Mercs[i].TimeLeft = GetMercInfo().MercTimerRemaining;
+3
View File
@@ -1097,6 +1097,9 @@ public:
void RemoveGroupXTargets();
void ShowXTargets(Client *c);
void InitializeMercInfo();
bool CheckCanHireMerc(Mob* merchant, uint32 template_id);
bool CheckCanRetainMerc(uint32 upkeep);
bool CheckCanUnsuspendMerc();
inline uint32 GetMercID() const { return mercid; }
inline uint8 GetMercSlot() const { return mercSlot; }
void SetMercID( uint32 newmercid) { mercid = newmercid; }
+41 -17
View File
@@ -13546,11 +13546,11 @@ void Client::Handle_OP_MercenaryDataRequest(const EQApplicationPacket *app)
mml->Mercs[i].MercID = mercListItr->MercTemplateID;
mml->Mercs[i].MercType = mercListItr->MercType;
mml->Mercs[i].MercSubType = mercListItr->MercSubType;
mml->Mercs[i].PurchaseCost = Merc::CalcPurchaseCost(mercListItr->MercTemplateID, GetLevel(), 0);
mml->Mercs[i].UpkeepCost = Merc::CalcUpkeepCost(mercListItr->MercTemplateID, GetLevel(), 0);
mml->Mercs[i].PurchaseCost = RuleB(Mercs, ChargeMercPurchaseCost) ? Merc::CalcPurchaseCost(mercListItr->MercTemplateID, GetLevel(), 0): 0;
mml->Mercs[i].UpkeepCost = RuleB(Mercs, ChargeMercUpkeepCost) ? Merc::CalcUpkeepCost(mercListItr->MercTemplateID, GetLevel(), 0): 0;
mml->Mercs[i].Status = 0;
mml->Mercs[i].AltCurrencyCost = Merc::CalcPurchaseCost(mercListItr->MercTemplateID, GetLevel(), altCurrentType);
mml->Mercs[i].AltCurrencyUpkeep = Merc::CalcUpkeepCost(mercListItr->MercTemplateID, GetLevel(), altCurrentType);
mml->Mercs[i].AltCurrencyCost = RuleB(Mercs, ChargeMercPurchaseCost) ? Merc::CalcPurchaseCost(mercListItr->MercTemplateID, GetLevel(), altCurrentType): 0;
mml->Mercs[i].AltCurrencyUpkeep = RuleB(Mercs, ChargeMercUpkeepCost) ? Merc::CalcUpkeepCost(mercListItr->MercTemplateID, GetLevel(), altCurrentType): 0;
mml->Mercs[i].AltCurrencyType = altCurrentType;
mml->Mercs[i].MercUnk01 = 0;
mml->Mercs[i].TimeLeft = -1;
@@ -13612,30 +13612,46 @@ void Client::Handle_OP_MercenaryHire(const EQApplicationPacket *app)
//HirePending = true;
SetHoTT(0);
SendTargetCommand(0);
if(!RuleB(Mercs, AllowMercs))
return;
MercTemplate* merc_template = zone->GetMercTemplate(merc_template_id);
if(merc_template) {
if (GetMercID()) {
// 6 - You must dismiss the mercenary before hiring a new one.
SendMercMerchantResponsePacket(6);
Mob* merchant = entity_list.GetNPCByID(merchant_id);
if(!CheckCanHireMerc(merchant, merc_template_id)) {
return;
}
if(RuleB(Mercs, ChargeMercPurchaseCost)) {
uint32 cost = Merc::CalcPurchaseCost(merc_template->MercTemplateID, GetLevel()) * 100; // Cost is in gold
TakeMoneyFromPP(cost, true);
}
else
{
// 0 is approved hire request
SendMercMerchantResponsePacket(0);
// Set time remaining to max on Hire
GetMercInfo().MercTimerRemaining = RuleI(Mercs, UpkeepIntervalMS);
// Set time remaining to max on Hire
GetMercInfo().MercTimerRemaining = RuleI(Mercs, UpkeepIntervalMS);
// Get merc, assign it to client & spawn
Merc* merc = Merc::LoadMerc(this, merc_template, merchant_id, false);
// Get merc, assign it to client & spawn
Merc* merc = Merc::LoadMerc(this, merc_template, merchant_id, false);
if(merc) {
SpawnMerc(merc, true);
merc->Save();
// 0 is approved hire request
SendMercMerchantResponsePacket(0);
}
else {
//merc failed to spawn
SendMercMerchantResponsePacket(3);
}
}
else {
//merc doesn't exist in db
SendMercMerchantResponsePacket(2);
}
}
void Client::Handle_OP_MercenarySuspendRequest(const EQApplicationPacket *app)
@@ -13655,6 +13671,9 @@ void Client::Handle_OP_MercenarySuspendRequest(const EQApplicationPacket *app)
if(MERC_DEBUG > 0)
Message(7, "Mercenary Debug: Suspend ( %i ) received.", merc_suspend);
if(!RuleB(Mercs, AllowMercs))
return;
// Check if the merc is suspended and if so, unsuspend, otherwise suspend it
SuspendMercCommand();
@@ -13683,6 +13702,9 @@ void Client::Handle_OP_MercenaryCommand(const EQApplicationPacket *app)
if(MERC_DEBUG > 0)
Message(7, "Mercenary Debug: Command %i, Option %i received.", merc_command, option);
if(!RuleB(Mercs, AllowMercs))
return;
// Handle the Command here...
// Will need a list of what every type of command is supposed to do
@@ -13784,7 +13806,9 @@ void Client::Handle_OP_MercenaryTimerRequest(const EQApplicationPacket *app)
}
}
SendMercTimerPacket(entityID, mercState, suspendedTime, RuleI(Mercs, UpkeepIntervalMS), RuleI(Mercs, SuspendIntervalMS));
if(entityID > 0) {
SendMercTimerPacket(entityID, mercState, suspendedTime, RuleI(Mercs, UpkeepIntervalMS), RuleI(Mercs, SuspendIntervalMS));
}
}
void Client::Handle_OP_OpenInventory(const EQApplicationPacket *app) {
+594 -43
View File
@@ -18,6 +18,8 @@ extern volatile bool ZoneLoaded;
Merc::Merc(const NPCType* d, float x, float y, float z, float heading)
: NPC(d, 0, x, y, z, heading, 0, false), endupkeep_timer(1000), rest_timer(1), confidence_timer(6000)
{
base_hp = d->max_hp;
base_mana = d->Mana;
_baseAC = d->AC;
_baseSTR = d->STR;
_baseSTA = d->STA;
@@ -35,6 +37,9 @@ Merc::Merc(const NPCType* d, float x, float y, float z, float heading)
_baseFR = d->FR;
_basePR = d->PR;
_baseCorrup = d->Corrup;
RestRegenHP = 0;
RestRegenMana = 0;
RestRegenEndurance = 0;
_medding = false;
_suspended = false;
@@ -44,6 +49,7 @@ Merc::Merc(const NPCType* d, float x, float y, float z, float heading)
_hatedCount = 0;
ourNPCData = d;
memset(equipment, 0, sizeof(equipment));
SetMercID(0);
SetStance(MercStancePassive);
@@ -331,27 +337,27 @@ void Merc::CalcItemBonuses(StatBonuses* newbon) {
unsigned int i;
//should not include 21 (SLOT_AMMO)
for (i=0; i<SLOT_AMMO; i++) {
const ItemInst* inst = m_inv[i];
if(inst == 0)
if(equipment[i] == 0)
continue;
AddItemBonuses(inst, newbon);
const Item_Struct * itm = database.GetItem(equipment[i]);
AddItemBonuses(itm, newbon);
}
//Power Source Slot
if (GetClientVersion() >= EQClientSoF)
/*if (GetClientVersion() >= EQClientSoF)
{
const ItemInst* inst = m_inv[9999];
if(inst)
AddItemBonuses(inst, newbon);
}
}*/
//tribute items
for (i = 0; i < MAX_PLAYER_TRIBUTES; i++) {
/*for (i = 0; i < MAX_PLAYER_TRIBUTES; i++) {
const ItemInst* inst = m_inv[TRIBUTE_SLOT_START + i];
if(inst == 0)
continue;
AddItemBonuses(inst, newbon, false, true);
}
}*/
// Caps
if(newbon->HPRegen > CalcHPRegenCap())
newbon->HPRegen = CalcHPRegenCap();
@@ -365,24 +371,7 @@ void Merc::CalcItemBonuses(StatBonuses* newbon) {
SetAttackTimer();
}
void Merc::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug, bool isTribute) {
if(!inst || !inst->IsType(ItemClassCommon))
{
return;
}
if(inst->GetAugmentType()==0 && isAug == true)
{
return;
}
const Item_Struct *item = inst->GetItem();
if(!isTribute && !inst->IsEquipable(GetBaseRace(),GetClass()))
{
if(item->ItemType != ItemTypeFood && item->ItemType != ItemTypeDrink)
return;
}
void Merc::AddItemBonuses(const Item_Struct *item, StatBonuses* newbon) {
if(GetLevel() < item->ReqLevel)
{
@@ -711,15 +700,6 @@ void Merc::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug,
else
newbon->SkillDamageAmount[item->ExtraDmgSkill] += item->ExtraDmgAmt;
}
if (!isAug)
{
int i;
for(i = 0; i < MAX_AUGMENT_SLOTS; i++) {
AddItemBonuses(inst->GetAugment(i),newbon,true);
}
}
}
int Merc::GroupLeadershipAAHealthEnhancement()
@@ -1093,7 +1073,6 @@ int32 Merc::CalcBaseManaRegen()
int32 Merc::CalcManaRegen()
{
int32 regen = 0;
//this should be changed so we dont med while camping, etc...
if (IsSitting())
{
BuffFadeBySitModifier();
@@ -1110,6 +1089,13 @@ int32 Merc::CalcManaRegen()
regen = mana_regen + spellbonuses.ManaRegen + itembonuses.ManaRegen;
}
if(GetCasterClass() == 'I')
regen += (itembonuses.HeroicINT / 25);
else if(GetCasterClass() == 'W')
regen += (itembonuses.HeroicWIS / 25);
else
regen = 0;
//AAs
regen += aabonuses.ManaRegen;
@@ -1451,8 +1437,9 @@ bool Merc::Process()
this->stunned_timer.Disable();
}
if (p_depop)
if (GetDepop())
{
SetMercCharacterID(0);
SetOwnerID(0);
SetID(0);
return false;
@@ -2511,6 +2498,414 @@ bool Merc::AICastSpell(int8 iChance, int32 iSpellTypes) {
return castedSpell;
}
int16 Merc::GetFocusEffect(focusType type, uint16 spell_id) {
int16 realTotal = 0;
int16 realTotal2 = 0;
int16 realTotal3 = 0;
bool rand_effectiveness = false;
//Improved Healing, Damage & Mana Reduction are handled differently in that some are random percentages
//In these cases we need to find the most powerful effect, so that each piece of gear wont get its own chance
if((type == focusManaCost || type == focusImprovedHeal || type == focusImprovedDamage)
&& RuleB(Spells, LiveLikeFocusEffects))
{
rand_effectiveness = true;
}
//Check if item focus effect exists for the client.
if (itembonuses.FocusEffects[type]){
const Item_Struct* TempItem = 0;
const Item_Struct* UsedItem = 0;
uint16 UsedFocusID = 0;
int16 Total = 0;
int16 focus_max = 0;
int16 focus_max_real = 0;
//item focus
for(int x=0; x<=MAX_WORN_INVENTORY; x++)
{
TempItem = NULL;
if (equipment[x] == 0)
continue;
TempItem = database.GetItem(equipment[x]);
if (TempItem && TempItem->Focus.Effect > 0 && TempItem->Focus.Effect != SPELL_UNKNOWN) {
if(rand_effectiveness) {
focus_max = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id, true);
if (focus_max > 0 && focus_max_real >= 0 && focus_max > focus_max_real) {
focus_max_real = focus_max;
UsedItem = TempItem;
UsedFocusID = TempItem->Focus.Effect;
} else if (focus_max < 0 && focus_max < focus_max_real) {
focus_max_real = focus_max;
UsedItem = TempItem;
UsedFocusID = TempItem->Focus.Effect;
}
}
else {
Total = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id);
if (Total > 0 && realTotal >= 0 && Total > realTotal) {
realTotal = Total;
UsedItem = TempItem;
UsedFocusID = TempItem->Focus.Effect;
} else if (Total < 0 && Total < realTotal) {
realTotal = Total;
UsedItem = TempItem;
UsedFocusID = TempItem->Focus.Effect;
}
}
}
}
//Tribute Focus
for(int x = TRIBUTE_SLOT_START; x < (TRIBUTE_SLOT_START + MAX_PLAYER_TRIBUTES); ++x)
{
TempItem = NULL;
if (equipment[x] == 0)
continue;
TempItem = database.GetItem(equipment[x]);
if (TempItem && TempItem->Focus.Effect > 0 && TempItem->Focus.Effect != SPELL_UNKNOWN) {
if(rand_effectiveness) {
focus_max = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id, true);
if (focus_max > 0 && focus_max_real >= 0 && focus_max > focus_max_real) {
focus_max_real = focus_max;
UsedItem = TempItem;
UsedFocusID = TempItem->Focus.Effect;
} else if (focus_max < 0 && focus_max < focus_max_real) {
focus_max_real = focus_max;
UsedItem = TempItem;
UsedFocusID = TempItem->Focus.Effect;
}
}
else {
Total = CalcFocusEffect(type, TempItem->Focus.Effect, spell_id);
if (Total > 0 && realTotal >= 0 && Total > realTotal) {
realTotal = Total;
UsedItem = TempItem;
UsedFocusID = TempItem->Focus.Effect;
}
else if (Total < 0 && Total < realTotal) {
realTotal = Total;
UsedItem = TempItem;
UsedFocusID = TempItem->Focus.Effect;
}
}
}
}
if(UsedItem && rand_effectiveness && focus_max_real != 0)
realTotal = CalcFocusEffect(type, UsedFocusID, spell_id);
if (realTotal != 0 && UsedItem)
Message_StringID(MT_Spells, BEGINS_TO_GLOW, UsedItem->Name);
}
//Check if spell focus effect exists for the client.
if (spellbonuses.FocusEffects[type]){
//Spell Focus
int16 Total2 = 0;
int16 focus_max2 = 0;
int16 focus_max_real2 = 0;
int buff_tracker = -1;
int buff_slot = 0;
uint16 focusspellid = 0;
uint16 focusspell_tracker = 0;
uint32 buff_max = GetMaxTotalSlots();
for (buff_slot = 0; buff_slot < buff_max; buff_slot++) {
focusspellid = buffs[buff_slot].spellid;
if (focusspellid == 0 || focusspellid >= SPDAT_RECORDS)
continue;
if(rand_effectiveness) {
focus_max2 = CalcFocusEffect(type, focusspellid, spell_id, true);
if (focus_max2 > 0 && focus_max_real2 >= 0 && focus_max2 > focus_max_real2) {
focus_max_real2 = focus_max2;
buff_tracker = buff_slot;
focusspell_tracker = focusspellid;
} else if (focus_max2 < 0 && focus_max2 < focus_max_real2) {
focus_max_real2 = focus_max2;
buff_tracker = buff_slot;
focusspell_tracker = focusspellid;
}
}
else {
Total2 = CalcFocusEffect(type, focusspellid, spell_id);
if (Total2 > 0 && realTotal2 >= 0 && Total2 > realTotal2) {
realTotal2 = Total2;
buff_tracker = buff_slot;
focusspell_tracker = focusspellid;
} else if (Total2 < 0 && Total2 < realTotal2) {
realTotal2 = Total2;
buff_tracker = buff_slot;
focusspell_tracker = focusspellid;
}
}
}
if(focusspell_tracker && rand_effectiveness && focus_max_real2 != 0)
realTotal2 = CalcFocusEffect(type, focusspell_tracker, spell_id);
// For effects like gift of mana that only fire once, save the spellid into an array that consists of all available buff slots.
if(buff_tracker >= 0 && buffs[buff_tracker].numhits > 0) {
m_spellHitsLeft[buff_tracker] = focusspell_tracker;
}
}
// AA Focus
/*if (aabonuses.FocusEffects[type]){
int16 Total3 = 0;
uint32 slots = 0;
uint32 aa_AA = 0;
uint32 aa_value = 0;
for (int i = 0; i < MAX_PP_AA_ARRAY; i++)
{
aa_AA = this->aa[i]->AA;
aa_value = this->aa[i]->value;
if (aa_AA < 1 || aa_value < 1)
continue;
Total3 = CalcAAFocus(type, aa_AA, spell_id);
if (Total3 > 0 && realTotal3 >= 0 && Total3 > realTotal3) {
realTotal3 = Total3;
}
else if (Total3 < 0 && Total3 < realTotal3) {
realTotal3 = Total3;
}
}
}*/
if(type == focusReagentCost && IsSummonPetSpell(spell_id) && GetAA(aaElementalPact))
return 100;
if(type == focusReagentCost && (IsEffectInSpell(spell_id, SE_SummonItem) || IsSacrificeSpell(spell_id)))
return 0;
//Summon Spells that require reagents are typically imbue type spells, enchant metal, sacrifice and shouldn't be affected
//by reagent conservation for obvious reasons.
return realTotal + realTotal2 + realTotal3;
}
int32 Merc::Additional_SpellDmg(uint16 spell_id, bool bufftick)
{
int32 spell_dmg = 0;
spell_dmg += GetFocusEffect(focusFF_Damage_Amount, spell_id);
spell_dmg += GetFocusEffect(focusSpellDamage, spell_id);
//For DOTs you need to apply the damage over the duration of the dot to each tick (this is how live did it)
if (bufftick){
int duration = CalcBuffDuration(this, this, spell_id);
if (duration > 0)
return spell_dmg /= duration;
else
return 0;
}
return spell_dmg;
}
int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value) {
// Important variables:
// value: the actual damage after resists, passed from Mob::SpellEffect
// modifier: modifier to damage (from spells & focus effects?)
// ratio: % of the modifier to apply (from AAs & natural bonus?)
// chance: critital chance %
int32 modifier = 100;
int16 spell_dmg = 0;
//Dunno if this makes sense:
if (spells[spell_id].resisttype > 0)
modifier += GetFocusEffect((focusType)(0-spells[spell_id].resisttype), spell_id);
int tt = spells[spell_id].targettype;
if (tt == ST_UndeadAE || tt == ST_Undead || tt == ST_Summoned) {
//undead/summoned spells
modifier += GetFocusEffect(focusImprovedUndeadDamage, spell_id);
} else {
//damage spells.
modifier += GetFocusEffect(focusImprovedDamage, spell_id);
modifier += GetFocusEffect(focusSpellEffectiveness, spell_id);
modifier += GetFocusEffect(focusImprovedDamage2, spell_id);
}
//spell crits, dont make sense if cast on self.
if(tt != ST_Self) {
// item SpellDmg bonus
// Formula = SpellDmg * (casttime + recastime) / 7; Cant trigger off spell less than 5 levels below and cant cause more dmg than the spell itself.
if(this->itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) {
spell_dmg = this->itembonuses.SpellDmg * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000;
if(spell_dmg > -value)
spell_dmg = -value;
}
// Spell-based SpellDmg adds directly but it restricted by focuses.
spell_dmg += Additional_SpellDmg(spell_id);
int chance = RuleI(Spells, BaseCritChance);
int32 ratio = RuleI(Spells, BaseCritRatio);
chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;
if(GetClass() == CASTERDPS) {
if (GetLevel() >= RuleI(Spells, WizCritLevel)) {
chance += RuleI(Spells, WizCritChance);
ratio += RuleI(Spells, WizCritRatio);
}
if(aabonuses.SpellCritDmgIncrease > 0) // wizards get an additional bonus
ratio += aabonuses.SpellCritDmgIncrease * 1.5; //108%, 115%, 124%, close to Graffe's 207%, 215%, & 225%
}
if (chance > 0) {
mlog(SPELLS__CRITS, "Attempting spell crit. Spell: %s (%d), Value: %d, Modifier: %d, Chance: %d, Ratio: %d", spells[spell_id].name, spell_id, value, modifier, chance, ratio);
if(MakeRandomInt(0,100) <= chance) {
modifier += modifier*ratio/100;
spell_dmg *= 2;
mlog(SPELLS__CRITS, "Spell crit successful. Final damage modifier: %d, Final Damage: %d", modifier, (value * modifier / 100) - spell_dmg);
entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), (-value * modifier / 100) + spell_dmg);
} else
mlog(SPELLS__CRITS, "Spell crit failed. Final Damage Modifier: %d, Final Damage: %d", modifier, (value * modifier / 100) - spell_dmg);
}
}
spell_dmg = ((value * modifier / 100) - spell_dmg);
spell_dmg = (spell_dmg * GetSpellScale() / 100);
return spell_dmg;
}
int32 Merc::Additional_Heal(uint16 spell_id)
{
int32 heal_amt = 0;
heal_amt += GetFocusEffect(focusAdditionalHeal, spell_id);
heal_amt += GetFocusEffect(focusAdditionalHeal2, spell_id);
if (heal_amt){
int duration = CalcBuffDuration(this, this, spell_id);
if (duration > 0)
return heal_amt /= duration;
}
return heal_amt;
}
int32 Merc::GetActSpellHealing(uint16 spell_id, int32 value) {
int32 modifier = 100;
int16 heal_amt = 0;
modifier += GetFocusEffect(focusImprovedHeal, spell_id);
modifier += GetFocusEffect(focusSpellEffectiveness, spell_id);
heal_amt += Additional_Heal(spell_id);
int chance = 0;
// Instant Heals
if(spells[spell_id].buffduration < 1)
{
// Formula = HealAmt * (casttime + recastime) / 7; Cant trigger off spell less than 5 levels below and cant heal more than the spell itself.
if(this->itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) {
heal_amt = this->itembonuses.HealAmt * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000;
if(heal_amt > value)
heal_amt = value;
}
// Check for buffs that affect the healrate of the target and critical heal rate of target
if(GetTarget()){
value += value * GetHealRate(spell_id) / 100;
chance += GetCriticalHealRate(spell_id);
}
//Live AA - Healing Gift, Theft of Life
chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance;
if(MakeRandomInt(0,99) < chance) {
entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), ((value * modifier / 50) + heal_amt*2));
heal_amt = ((value * modifier / 50) + heal_amt*2);
}
else{
heal_amt = ((value * modifier / 100) + heal_amt);
}
}
// Hots
else {
chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance;
if(MakeRandomInt(0,99) < chance)
heal_amt = ((value * modifier / 50) + heal_amt*2);
}
heal_amt = (heal_amt * GetHealScale() / 100);
return heal_amt;
}
int32 Merc::GetActSpellCost(uint16 spell_id, int32 cost)
{
// Formula = Unknown exact, based off a random percent chance up to mana cost(after focuses) of the cast spell
if(this->itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
{
int16 mana_back = this->itembonuses.Clairvoyance * MakeRandomInt(1, 100) / 100;
// Doesnt generate mana, so best case is a free spell
if(mana_back > cost)
mana_back = cost;
cost -= mana_back;
}
// This formula was derived from the following resource:
// http://www.eqsummoners.com/eq1/specialization-library.html
// WildcardX
float PercentManaReduction = 0;
int16 focus_redux = GetFocusEffect(focusManaCost, spell_id);
if(focus_redux > 0)
{
PercentManaReduction += MakeRandomFloat(1, (double)focus_redux);
}
cost -= (cost * (PercentManaReduction / 100));
// Gift of Mana - reduces spell cost to 1 mana
if(focus_redux >= 100) {
uint32 buff_max = GetMaxTotalSlots();
for (int buffSlot = 0; buffSlot < buff_max; buffSlot++) {
if (buffs[buffSlot].spellid == 0 || buffs[buffSlot].spellid >= SPDAT_RECORDS)
continue;
if(IsEffectInSpell(buffs[buffSlot].spellid, SE_ReduceManaCost)) {
if(CalcFocusEffect(focusManaCost, buffs[buffSlot].spellid, spell_id) == 100)
cost = 1;
}
}
}
if(cost < 0)
cost = 0;
return cost;
}
int32 Merc::GetActSpellCasttime(uint16 spell_id, int32 casttime)
{
int32 cast_reducer = 0;
cast_reducer += GetFocusEffect(focusSpellHaste, spell_id);
if (cast_reducer > RuleI(Spells, MaxCastTimeReduction))
cast_reducer = RuleI(Spells, MaxCastTimeReduction);
casttime = (casttime*(100 - cast_reducer)/100);
return casttime;
}
int8 Merc::GetChanceToCastBySpellType(int16 spellType) {
int mercStance = (int)GetStance();
int8 mercClass = GetClass();
@@ -4180,7 +4575,6 @@ bool Merc::Save() {
}
Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, bool updateFromDB) {
Merc* merc;
if(c) {
if(c->GetMercID()) {
@@ -4226,9 +4620,12 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id,
Merc* merc = new Merc(npc_type, c->GetX(), c->GetY(), c->GetZ(), 0);
merc->SetMercData( merc_template->MercTemplateID );
database.LoadMercEquipment(merc);
merc->UpdateMercStats(c);
if(updateFromDB) {
database.LoadCurrentMerc(c);
merc->SetMercID(c->GetMercInfo().mercid);
snprintf(merc->name, 64, "%s", c->GetMercInfo().merc_name);
snprintf(c->GetEPP().merc_name, 64, "%s", c->GetMercInfo().merc_name);
@@ -4262,6 +4659,7 @@ Merc* Merc::LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id,
void Merc::UpdateMercInfo(Client *c) {
snprintf(c->GetMercInfo().merc_name, 64, "%s", name);
c->GetMercInfo().mercid = GetMercID();
c->GetMercInfo().IsSuspended = IsSuspended();
c->GetMercInfo().Gender = gender;
c->GetMercInfo().hp = GetHP();
@@ -4287,8 +4685,8 @@ void Merc::UpdateMercStats(Client *c) {
{
max_hp = (npc_type->max_hp * npc_type->scalerate) / 100;
base_hp = (npc_type->max_hp * npc_type->scalerate) / 100;
max_mana = (npc_type->max_hp * npc_type->scalerate) / 100;
base_mana = (npc_type->max_hp * npc_type->scalerate) / 100;
max_mana = (npc_type->Mana * npc_type->scalerate) / 100;
base_mana = (npc_type->Mana * npc_type->scalerate) / 100;
hp_regen = (npc_type->hp_regen * npc_type->scalerate) / 100;
mana_regen = (npc_type->mana_regen * npc_type->scalerate) / 100;
level = npc_type->level;
@@ -4326,6 +4724,10 @@ void Merc::UpdateMercStats(Client *c) {
void Merc::UpdateMercAppearance(Client *c) {
}
void Merc::AddItem(uint8 slot, uint32 item_id) {
equipment[slot] = item_id;
}
bool Merc::Spawn(Client *owner) {
if(!RuleB(Mercs, AllowMercs))
return false;
@@ -4370,7 +4772,17 @@ void Client::UpdateMercTimer()
if(merc_timer.Check())
{
uint32 upkeep = Merc::CalcUpkeepCost(merc->GetMercTemplateID(), GetLevel());
//TakeMoneyFromPP((upkeep * 100), true); // Upkeep is in gold
if(CheckCanRetainMerc(upkeep)) {
if(RuleB(Mercs, ChargeMercUpkeepCost)) {
TakeMoneyFromPP((upkeep * 100), true);
}
}
else {
merc->Suspend();
return;
}
GetMercInfo().MercTimerRemaining = RuleI(Mercs, UpkeepIntervalMS);
SendMercTimerPacket(GetMercID(), 5, 0, RuleI(Mercs, UpkeepIntervalMS), RuleI(Mercs, SuspendIntervalMS));
merc_timer.Start(RuleI(Mercs, UpkeepIntervalMS));
@@ -4402,6 +4814,133 @@ void Client::UpdateMercTimer()
}
}
bool Client::CheckCanHireMerc(Mob* merchant, uint32 template_id) {
bool result = true;
//check for valid merchant - can check near area for any merchants
if(!merchant) {
if (GetClientVersion() < EQClientRoF)
SendMercMerchantResponsePacket(14);
else
SendMercMerchantResponsePacket(16);
result = false;
}
//check for merchant too far away
if(DistNoRoot(*merchant) > USE_NPC_RANGE2) {
if (GetClientVersion() < EQClientRoF)
SendMercMerchantResponsePacket(15);
else
SendMercMerchantResponsePacket(17);
result = false;
}
if(GetClientVersion() >= EQClientRoF && GetNumMercs() >= MAXMERCS) {
SendMercMerchantResponsePacket(6);
result = false;
}
else if(GetMerc()) { //check for current merc
if (GetClientVersion() < EQClientRoF)
SendMercMerchantResponsePacket(6);
else
SendMercMerchantResponsePacket(6);
result = false;
}
else if(GetMercInfo().mercid != 0 && GetMercInfo().IsSuspended) { //has suspended merc
if (GetClientVersion() < EQClientRoF)
SendMercMerchantResponsePacket(7);
else
SendMercMerchantResponsePacket(6);
result = false;
}
//check for sufficient funds
if(RuleB(Mercs, ChargeMercPurchaseCost)) {
uint32 cost = Merc::CalcPurchaseCost(template_id, GetLevel()) * 100; // Cost is in gold
if(!HasMoney(cost)) {
SendMercMerchantResponsePacket(1);
result = false;
}
}
//check for raid
if(HasRaid()) {
SendMercMerchantResponsePacket(4);
result = false;
}
//check group size
if(HasGroup() && GetGroup()->GroupCount() == 6) {
if (GetClientVersion() < EQClientRoF)
SendMercMerchantResponsePacket(8);
else
SendMercMerchantResponsePacket(7);
result = false;
}
//check in combat
if(GetClientVersion() >= EQClientRoF && GetAggroCount() > 0) {
SendMercMerchantResponsePacket(8);
result = false;
}
return result;
}
bool Client::CheckCanRetainMerc(uint32 upkeep) {
bool result = true;
Merc* merc = GetMerc();
//check for sufficient funds
if(RuleB(Mercs, ChargeMercPurchaseCost)) {
if(merc) {
if(!HasMoney(upkeep * 100)) {
SendMercMerchantResponsePacket(1);
result = false;
}
}
}
return result;
}
bool Client::CheckCanUnsuspendMerc() {
bool result = true;
//check for raid
if(HasRaid()) {
SendMercMerchantResponsePacket(4);
result = false;
}
//check group size
if(HasGroup() && GetGroup()->GroupCount() == 6) {
if (GetClientVersion() < EQClientRoF)
SendMercMerchantResponsePacket(8);
else
SendMercMerchantResponsePacket(7);
result = false;
}
//check if zone allows mercs
if(!zone->AllowMercs()) {
if (GetClientVersion() < EQClientRoF)
SendMercMerchantResponsePacket(4); // ??
else
SendMercMerchantResponsePacket(4); // ??
}
//check in combat
if(GetClientVersion() >= EQClientRoF && GetAggroCount() > 0) {
SendMercMerchantResponsePacket(8);
result = false;
}
return result;
}
void Client::CheckMercSuspendTimer()
{
if(GetMercInfo().SuspendedTime != 0) {
@@ -4423,17 +4962,26 @@ void Client::SuspendMercCommand()
// Set time remaining to max on unsuspend - there is a charge for unsuspending as well
// GetEPP().mercTimerRemaining = RuleI(Mercs, UpkeepIntervalMS);
if(!CheckCanUnsuspendMerc()){
return;
}
// Get merc, assign it to client & spawn
Merc* merc = Merc::LoadMerc(this, &zone->merc_templates[GetMercInfo().MercTemplateID], 0, false);
SpawnMerc(merc, true);
Merc* merc = Merc::LoadMerc(this, &zone->merc_templates[GetMercInfo().MercTemplateID], 0, true);
if(merc) {
SpawnMerc(merc, true);
}
else {
//merc failed to spawn
SendMercMerchantResponsePacket(3);
}
}
else
{
Merc* CurrentMerc = GetMerc();
if(CurrentMerc && GetMercID()) {
CurrentMerc->Save();
//CurrentMerc->Save();
CurrentMerc->Suspend();
}
}
@@ -4539,6 +5087,8 @@ bool Merc::Unsuspend(bool setMaxStats) {
uint32 suspendedTime = 0;
SetSuspended(false);
mercOwner->GetMercInfo().mercid = GetMercID();
mercOwner->GetMercInfo().IsSuspended = false;
mercOwner->GetMercInfo().SuspendedTime = 0;
@@ -4785,6 +5335,7 @@ void Client::SetMerc(Merc* newmerc) {
newmerc->SetOwnerID(this->GetID());
newmerc->SetMercCharacterID(this->CharacterID());
newmerc->SetClientVersion((uint8)this->GetClientVersion());
GetMercInfo().mercid = newmerc->GetMercID();
GetMercInfo().MercTemplateID = newmerc->GetMercTemplateID();
GetMercInfo().myTemplate = zone->GetMercTemplate(GetMercInfo().MercTemplateID);
GetMercInfo().IsSuspended = newmerc->IsSuspended();
+12 -3
View File
@@ -77,6 +77,12 @@ public:
Corpse* GetGroupMemberCorpse();
// Merc Spell Casting Methods
int32 Additional_SpellDmg(uint16 spell_id, bool bufftick = false);
int32 Additional_Heal(uint16 spell_id);
virtual int32 GetActSpellDamage(uint16 spell_id, int32 value);
virtual int32 GetActSpellHealing(uint16 spell_id, int32 value);
virtual int32 GetActSpellCasttime(uint16 spell_id, int32 casttime);
virtual int32 GetActSpellCost(uint16 spell_id, int32 cost);
int8 GetChanceToCastBySpellType(int16 spellType);
void SetSpellRecastTimer(uint16 timer_id, uint16 spellid, uint32 recast_delay);
void SetDisciplineRecastTimer(uint16 timer_id, uint16 spellid, uint32 recast_delay);
@@ -113,6 +119,7 @@ public:
void UpdateMercInfo(Client *c);
void UpdateMercStats(Client *c);
void UpdateMercAppearance(Client *c);
void AddItem(uint8 slot, uint32 item_id);
static const char *GetRandomName();
bool Spawn(Client *owner);
bool Dismiss();
@@ -221,7 +228,7 @@ public:
// "SET" Class Methods
void SetMercData (uint32 templateID );
void SetMercID( uint32 mercID ) { _MercID = mercID; }
void SetMercCharacterID( uint32 mercID ) { owner_char_id = mercID; }
void SetMercCharacterID( uint32 ownerID ) { owner_char_id = ownerID; }
void SetMercTemplateID( uint32 templateID ) { _MercTemplateID = templateID; }
void SetMercType( uint32 type ) { _MercType = type; }
void SetMercSubType( uint32 subtype ) { _MercSubType = subtype; }
@@ -232,7 +239,7 @@ public:
void SetClientVersion(uint8 clientVersion) { _OwnerClientVersion = clientVersion; }
void SetSuspended(bool suspended) { _suspended = suspended; }
void SetStance( uint32 stance ) { _currentStance = stance; }
void SetHatedCount( uint8 count ) { _hatedCount = count; }
void SetHatedCount( int count ) { _hatedCount = count; }
void Sit();
void Stand();
@@ -248,9 +255,11 @@ public:
protected:
void CalcItemBonuses(StatBonuses* newbon);
void AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAug = false, bool isTribute = false);
void AddItemBonuses(const Item_Struct *item, StatBonuses* newbon);
int CalcRecommendedLevelBonus(uint8 level, uint8 reclevel, int basestat);
int16 GetFocusEffect(focusType type, uint16 spell_id);
std::vector<MercSpell> merc_spells;
std::map<uint32,MercTimer> timers;
+3 -3
View File
@@ -1212,7 +1212,7 @@ bool Zone::LoadZoneCFG(const char* filename, uint16 instance_id, bool DontLoadDe
{
map_name = NULL;
if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind,
can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, default_ruleset, &map_name))
can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, allow_mercs, default_ruleset, &map_name))
{
LogFile->write(EQEMuLog::Error, "Error loading the Zone Config.");
return false;
@@ -1223,11 +1223,11 @@ bool Zone::LoadZoneCFG(const char* filename, uint16 instance_id, bool DontLoadDe
//Fall back to base zone if we don't find the instance version.
map_name = NULL;
if(!database.GetZoneCFG(database.GetZoneID(filename), instance_id, &newzone_data, can_bind,
can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, default_ruleset, &map_name))
can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, allow_mercs, default_ruleset, &map_name))
{
safe_delete_array(map_name);
if(!database.GetZoneCFG(database.GetZoneID(filename), 0, &newzone_data, can_bind,
can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, default_ruleset, &map_name))
can_combat, can_levitate, can_castoutdoor, is_city, is_hotzone, allow_mercs, default_ruleset, &map_name))
{
LogFile->write(EQEMuLog::Error, "Error loading the Zone Config.");
return false;
+2
View File
@@ -219,6 +219,7 @@ public:
bool CanDoCombat() const { return(can_combat); }
bool CanLevitate() const {return(can_levitate); } // Magoth78
bool CanCastOutdoor() const {return(can_castoutdoor);} //qadar
bool AllowMercs() const {return(allow_mercs);}
bool IsHotzone() const { return(is_hotzone); }
inline bool BuffTimersSuspended() const { return newzone_data.SuspendBuffs != 0; };
@@ -269,6 +270,7 @@ private:
bool can_castoutdoor;
bool can_levitate;
bool is_hotzone;
bool allow_mercs;
uint32 pgraveyard_id, pgraveyard_zoneid;
float pgraveyard_x, pgraveyard_y, pgraveyard_z, pgraveyard_heading;
int default_ruleset;
+103 -6
View File
@@ -80,7 +80,7 @@ bool ZoneDatabase::SaveZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct
return true;
}
bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct *zone_data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, int &ruleset, char **map_filename) {
bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct *zone_data, bool &can_bind, bool &can_combat, bool &can_levitate, bool &can_castoutdoor, bool &is_city, bool &is_hotzone, bool &allow_mercs, int &ruleset, char **map_filename) {
char errbuf[MYSQL_ERRMSG_SIZE];
char *query = 0;
MYSQL_RES *result;
@@ -135,6 +135,7 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct
can_levitate = atoi(row[r++])==0?false:true;
can_castoutdoor = atoi(row[r++])==0?false:true;
is_hotzone = atoi(row[r++])==0?false:true;
allow_mercs = true;
ruleset = atoi(row[r++]);
zone_data->SuspendBuffs = atoi(row[r++]);
char *file = row[r++];
@@ -1616,6 +1617,11 @@ bool ZoneDatabase::LoadMercInfo(Client *c) {
else {
while(DataRow = mysql_fetch_row(DatasetResult)) {
uint8 slot = atoi(DataRow[1]);
if(slot >= MAXMERCS) {
continue;
}
c->GetMercInfo(slot).mercid = atoi(DataRow[0]);
c->GetMercInfo(slot).slot = slot;
snprintf(c->GetMercInfo(slot).merc_name, 64, "%s", std::string(DataRow[2]).c_str());
@@ -1650,6 +1656,62 @@ bool ZoneDatabase::LoadMercInfo(Client *c) {
return loaded;
}
bool ZoneDatabase::LoadCurrentMerc(Client *c) {
bool loaded = false;
if(c->GetEPP().merc_name[0] != 0) {
std::string errorMessage;
char* Query = 0;
char TempErrorMessageBuffer[MYSQL_ERRMSG_SIZE];
MYSQL_RES* DatasetResult;
MYSQL_ROW DataRow;
//char name[64];
uint8 slot = c->GetMercSlot();
if(slot > MAXMERCS) {
return false;
}
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT MercID, Name, TemplateID, SuspendedTime, IsSuspended, TimerRemaining, Gender, StanceID, HP, Mana, Endurance, Face, LuclinHairStyle, LuclinHairColor, LuclinEyeColor, LuclinEyeColor2, LuclinBeardColor, LuclinBeard, DrakkinHeritage, DrakkinTattoo, DrakkinDetails FROM mercs WHERE OwnerCharacterID = '%i' AND Slot = '%u'", c->CharacterID(), slot), TempErrorMessageBuffer, &DatasetResult)) {
errorMessage = std::string(TempErrorMessageBuffer);
}
else {
while(DataRow = mysql_fetch_row(DatasetResult)) {
c->GetMercInfo(slot).mercid = atoi(DataRow[0]);
c->GetMercInfo(slot).slot = slot;
snprintf(c->GetMercInfo(slot).merc_name, 64, "%s", std::string(DataRow[1]).c_str());
c->GetMercInfo(slot).MercTemplateID = atoi(DataRow[2]);
c->GetMercInfo(slot).SuspendedTime = atoi(DataRow[3]);
c->GetMercInfo(slot).IsSuspended = atoi(DataRow[4]) == 1 ? true : false;
c->GetMercInfo(slot).MercTimerRemaining = atoi(DataRow[5]);
c->GetMercInfo(slot).Gender = atoi(DataRow[6]);
c->GetMercInfo(slot).State = atoi(DataRow[7]);
c->GetMercInfo(slot).hp = atoi(DataRow[8]);
c->GetMercInfo(slot).mana = atoi(DataRow[9]);
c->GetMercInfo(slot).endurance = atoi(DataRow[10]);
c->GetMercInfo(slot).face = atoi(DataRow[11]);
c->GetMercInfo(slot).luclinHairStyle = atoi(DataRow[12]);
c->GetMercInfo(slot).luclinHairColor = atoi(DataRow[13]);
c->GetMercInfo(slot).luclinEyeColor = atoi(DataRow[14]);
c->GetMercInfo(slot).luclinEyeColor2 = atoi(DataRow[15]);
c->GetMercInfo(slot).luclinBeardColor = atoi(DataRow[16]);
c->GetMercInfo(slot).luclinBeard = atoi(DataRow[17]);
c->GetMercInfo(slot).drakkinHeritage = atoi(DataRow[18]);
c->GetMercInfo(slot).drakkinTattoo = atoi(DataRow[19]);
c->GetMercInfo(slot).drakkinDetails = atoi(DataRow[20]);
loaded = true;
}
mysql_free_result(DatasetResult);
}
safe_delete_array(Query);
}
return loaded;
}
bool ZoneDatabase::SaveMerc(Merc *merc) {
Client *owner = merc->GetMercOwner();
bool Result = false;
@@ -1718,7 +1780,7 @@ void ZoneDatabase::SaveMercBuffs(Merc *merc) {
if(buffs[BuffCount].spellid > 0 && buffs[BuffCount].spellid != SPELL_UNKNOWN) {
if(InsertCount == 0) {
// Remove any existing buff saves
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "DELETE FROM mercbuffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer)) {
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "DELETE FROM merc_buffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer)) {
errorMessage = std::string(TempErrorMessageBuffer);
safe_delete(Query);
Query = 0;
@@ -1733,7 +1795,7 @@ void ZoneDatabase::SaveMercBuffs(Merc *merc) {
else
IsPersistent = 0;
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "INSERT INTO mercbuffs (MercId, SpellId, CasterLevel, DurationFormula, "
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "INSERT INTO merc_buffs (MercId, SpellId, CasterLevel, DurationFormula, "
"TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, "
"DeathSaveSuccessChance, CasterAARank, Persistent) VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u);",
merc->GetMercID(), buffs[BuffCount].spellid, buffs[BuffCount].casterlevel, spells[buffs[BuffCount].spellid].buffdurationformula,
@@ -1776,7 +1838,7 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) {
bool BuffsLoaded = false;
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, DeathSaveSuccessChance, CasterAARank, Persistent FROM mercbuffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer, &DatasetResult)) {
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT SpellId, CasterLevel, DurationFormula, TicsRemaining, PoisonCounters, DiseaseCounters, CurseCounters, CorruptionCounters, HitCount, MeleeRune, MagicRune, DeathSaveSuccessChance, CasterAARank, Persistent FROM merc_buffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer, &DatasetResult)) {
errorMessage = std::string(TempErrorMessageBuffer);
}
else {
@@ -1825,7 +1887,7 @@ void ZoneDatabase::LoadMercBuffs(Merc *merc) {
Query = 0;
if(errorMessage.empty() && BuffsLoaded) {
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "DELETE FROM mercbuffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer)) {
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "DELETE FROM merc_buffs WHERE MercId = %u", merc->GetMercID()), TempErrorMessageBuffer)) {
errorMessage = std::string(TempErrorMessageBuffer);
safe_delete(Query);
Query = 0;
@@ -1848,7 +1910,7 @@ bool ZoneDatabase::DeleteMerc(uint32 merc_id) {
// TODO: These queries need to be ran together as a transaction.. ie, if one or more fail then they all will fail to commit to the database.
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "DELETE FROM mercbuffs WHERE MercID = '%u'", merc_id), TempErrorMessageBuffer)) {
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "DELETE FROM merc_buffs WHERE MercID = '%u'", merc_id), TempErrorMessageBuffer)) {
errorMessage = std::string(TempErrorMessageBuffer);
}
else
@@ -1871,6 +1933,41 @@ bool ZoneDatabase::DeleteMerc(uint32 merc_id) {
return Result;
}
void ZoneDatabase::LoadMercEquipment(Merc *merc) {
std::string errorMessage;
char* Query = 0;
char TempErrorMessageBuffer[MYSQL_ERRMSG_SIZE];
MYSQL_RES* DatasetResult;
MYSQL_ROW DataRow;
if(!database.RunQuery(Query, MakeAnyLenString(&Query, "SELECT item_id FROM merc_inventory WHERE merc_subtype_id = (SELECT merc_subtype_id FROM merc_subtypes WHERE class_id = '%u' AND tier_id = '%u') AND min_level <= %u AND max_level >= %u", merc->GetClass(), merc->GetTierID(), merc->GetLevel(), merc->GetLevel()), TempErrorMessageBuffer, &DatasetResult)) {
errorMessage = std::string(TempErrorMessageBuffer);
}
else {
int itemCount = 0;
while(DataRow = mysql_fetch_row(DatasetResult)) {
if(itemCount == MAX_WORN_INVENTORY)
break;
if(atoi(DataRow[0]) > 0) {
merc->AddItem(itemCount, atoi(DataRow[0]));
itemCount++;
}
}
mysql_free_result(DatasetResult);
}
safe_delete_array(Query);
Query = 0;
if(!errorMessage.empty()) {
LogFile->write(EQEMuLog::Error, "Error Loading Merc Inventory: %s", errorMessage.c_str());
}
}
uint8 ZoneDatabase::GetGridType(uint32 grid, uint32 zoneid ) {
char *query = 0;
char errbuf[MYSQL_ERRMSG_SIZE];
+3 -1
View File
@@ -293,7 +293,7 @@ public:
/*
* 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, int &ruleset, char **map_filename);
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, int &ruleset, char **map_filename);
bool SaveZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct* zd);
bool DumpZoneState();
int8 LoadZoneState(const char* zonename, LinkedList<Spawn2*>& spawn2_list);
@@ -350,9 +350,11 @@ public:
* Mercs
*/
const NPCType* GetMercType(uint32 id, uint16 raceid, uint32 clientlevel);
void LoadMercEquipment(Merc *merc);
void SaveMercBuffs(Merc *merc);
void LoadMercBuffs(Merc *merc);
bool LoadMercInfo(Client *c);
bool LoadCurrentMerc(Client *c);
bool SaveMerc(Merc *merc);
bool DeleteMerc(uint32 merc_id);
//void LoadMercTypesForMercMerchant(NPC *merchant);