mirror of
https://github.com/EQEmu/Server.git
synced 2026-05-17 03:08:26 +00:00
Merge branch 'master' of git://github.com/EQEmu/Server
This commit is contained in:
+5
-5
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user