From ea72975e6909dd21f3eac19714928820b96fee0a Mon Sep 17 00:00:00 2001 From: badcaptain Date: Fri, 1 Mar 2013 00:01:27 -0500 Subject: [PATCH] Fixed Merc duplicate save bug, focus items, spell_scale and heal_scale now work implemented, new merc equipment (with focus items), added checks during merc hire, unsuspend, & timer update for states where a merc can't be hired, unsuspended, or can't be retained due to insufficient funds, no room in group, in raid, invalid merc data, etc, and give appropriate feedback, added rules for charging of merc purchase and upkeep costs. --- changelog.txt | 8 + common/ruletypes.h | 4 +- .../2013_02_29_Merc_Rules_and_Equipment.sql | 88 +++ zone/client.cpp | 10 +- zone/client.h | 3 + zone/client_packet.cpp | 58 +- zone/merc.cpp | 637 ++++++++++++++++-- zone/merc.h | 15 +- zone/zone.cpp | 6 +- zone/zone.h | 2 + zone/zonedb.cpp | 109 ++- zone/zonedb.h | 4 +- 12 files changed, 865 insertions(+), 79 deletions(-) create mode 100644 utils/sql/git/required/2013_02_29_Merc_Rules_and_Equipment.sql diff --git a/changelog.txt b/changelog.txt index d21a8629d..28e1589fe 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,13 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 02/29/2013 == +Bad_Captain: Fixed Merc duplicate save bug. +Bad_Captain: Focus items, spell_scale and heal_scale now work implemented and new merc equipment (with focus items). +Bad_Captain: Added checks during merc hire, unsuspend, & timer update for states where a merc can't be hired, unsuspended, or can't be retained due to insufficient funds, no room in group, in raid, invalid merc data, etc, and give appropriate feedback. +Bad_Captain: Added rules for charging of merc purchase and upkeep costs. + +REQUIRED SQL: 2013_02_29_Merc_Rules_and_Equipment.sql + == 02/27/2013 == KLS: Changed how shared memory works: Instead of System V/windows pagefile shared memory we now have shared memory that's backed by the filesystem. diff --git a/common/ruletypes.h b/common/ruletypes.h index e5c0158f4..c7a7eb854 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -103,7 +103,9 @@ RULE_INT (Mercs, SuspendIntervalMS, 10000) RULE_INT (Mercs, UpkeepIntervalMS, 180000) RULE_INT (Mercs, SuspendIntervalS, 10) RULE_INT (Mercs, UpkeepIntervalS, 180) -RULE_BOOL ( Mercs, AllowMercs, false ) +RULE_BOOL (Mercs, AllowMercs, false) +RULE_BOOL (Mercs, ChargeMercPurchaseCost, false) +RULE_BOOL (Mercs, ChargeMercUpkeepCost, false) RULE_INT (Mercs, AggroRadius, 100) // Determines the distance from which a merc will aggro group member's target(also used to determine the distance at which a healer merc will begin healing a group member) RULE_INT (Mercs, AggroRadiusPuller, 25) // Determines the distance from which a merc will aggro group member's target, if they have the group role of puller (also used to determine the distance at which a healer merc will begin healing a group member, if they have the group role of puller) RULE_INT (Mercs, ResurrectRadius, 50) // Determines the distance from which a healer merc will attempt to resurrect a group member's corpse diff --git a/utils/sql/git/required/2013_02_29_Merc_Rules_and_Equipment.sql b/utils/sql/git/required/2013_02_29_Merc_Rules_and_Equipment.sql new file mode 100644 index 000000000..178d5fbf0 --- /dev/null +++ b/utils/sql/git/required/2013_02_29_Merc_Rules_and_Equipment.sql @@ -0,0 +1,88 @@ +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Mercs:ChargeMercPurchaseCost', 'false', 'Turns Mercenary purchase costs on or off.'); +INSERT INTO `rule_values` (`ruleset_id`, `rule_name`, `rule_value`, `notes`) VALUES (1, 'Mercs:ChargeMercUpkeepCost', 'false', 'Turns Mercenary upkeep costs on or off.'); + +UPDATE merc_stats SET spellscale = 100, healscale = 100; + +REPLACE INTO items (`id`, `minstatus`, `Name`, `aagi`, `ac`, `accuracy`, `acha`, `adex`, `aint`, `artifactflag`, `asta`, `astr`, `attack`, `augrestrict`, `augslot1type`, `augslot1visible`, `augslot2type`, `augslot2visible`, `augslot3type`, `augslot3visible`, `augslot4type`, `augslot4visible`, `augslot5type`, `augslot5visible`, `augtype`, `avoidance`, `awis`, `bagsize`, `bagslots`, `bagtype`, `bagwr`, `banedmgamt`, `banedmgraceamt`, `banedmgbody`, `banedmgrace`, `bardtype`, `bardvalue`, `book`, `casttime`, `casttime_`, `charmfile`, `charmfileid`, `classes`, `color`, `combateffects`, `extradmgskill`, `extradmgamt`, `price`, `cr`, `damage`, `damageshield`, `deity`, `delay`, `augdistiller`, `dotshielding`, `dr`, `clicktype`, `clicklevel2`, `elemdmgtype`, `elemdmgamt`, `endur`, `factionamt1`, `factionamt2`, `factionamt3`, `factionamt4`, `factionmod1`, `factionmod2`, `factionmod3`, `factionmod4`, `filename`, `focuseffect`, `fr`, `fvnodrop`, `haste`, `clicklevel`, `hp`, `regen`, `icon`, `idfile`, `itemclass`, `itemtype`, `ldonprice`, `ldontheme`, `ldonsold`, `light`, `lore`, `loregroup`, `magic`, `mana`, `manaregen`, `enduranceregen`, `material`, `maxcharges`, `mr`, `nodrop`, `norent`, `pendingloreflag`, `pr`, `procrate`, `races`, `range`, `reclevel`, `recskill`, `reqlevel`, `sellrate`, `shielding`, `size`, `skillmodtype`, `skillmodvalue`, `slots`, `clickeffect`, `spellshield`, `strikethrough`, `stunresist`, `summonedflag`, `tradeskills`, `favor`, `weight`, `UNK012`, `UNK013`, `benefitflag`, `UNK054`, `UNK059`, `booktype`, `recastdelay`, `recasttype`, `guildfavor`, `UNK123`, `UNK124`, `attuneable`, `nopet`, `updated`, `comment`, `UNK127`, `pointtype`, `potionbelt`, `potionbeltslots`, `stacksize`, `notransfer`, `stackable`, `UNK134`, `UNK137`, `proceffect`, `proctype`, `proclevel2`, `proclevel`, `UNK142`, `worneffect`, `worntype`, `wornlevel2`, `wornlevel`, `UNK147`, `focustype`, `focuslevel2`, `focuslevel`, `UNK152`, `scrolleffect`, `scrolltype`, `scrolllevel2`, `scrolllevel`, `UNK157`, `serialized`, `verified`, `serialization`, `source`, `UNK033`, `lorefile`, `UNK014`, `svcorruption`, `UNK038`, `UNK060`, `augslot1unk2`, `augslot2unk2`, `augslot3unk2`, `augslot4unk2`, `augslot5unk2`, `UNK120`, `UNK121`, `questitemflag`, `UNK132`, `clickunk5`, `clickunk6`, `clickunk7`, `procunk1`, `procunk2`, `procunk3`, `procunk4`, `procunk6`, `procunk7`, `wornunk1`, `wornunk2`, `wornunk3`, `wornunk4`, `wornunk5`, `wornunk6`, `wornunk7`, `focusunk1`, `focusunk2`, `focusunk3`, `focusunk4`, `focusunk5`, `focusunk6`, `focusunk7`, `scrollunk1`, `scrollunk2`, `scrollunk3`, `scrollunk4`, `scrollunk5`, `scrollunk6`, `scrollunk7`, `UNK193`, `purity`, `evolvinglevel`, `clickname`, `procname`, `wornname`, `focusname`, `scrollname`, `dsmitigation`, `heroic_str`, `heroic_int`, `heroic_wis`, `heroic_agi`, `heroic_dex`, `heroic_sta`, `heroic_cha`, `heroic_pr`, `heroic_dr`, `heroic_fr`, `heroic_cr`, `heroic_mr`, `heroic_svcorrup`, `healamt`, `spelldmg`, `clairvoyance`, `backstabdmg`, `created`, `elitematerial`, `ldonsellbackrate`, `scriptfileid`, `expendablearrow`, `powersourcecapacity`, `bardeffect`, `bardeffecttype`, `bardlevel2`, `bardlevel`, `bardunk1`, `bardunk2`, `bardunk3`, `bardunk4`, `bardunk5`, `bardname`, `bardunk7`, `UNK214`, `UNK219`, `UNK220`, `UNK221`, `UNK222`, `UNK223`, `UNK224`, `UNK225`, `UNK226`, `UNK227`, `UNK228`, `UNK229`, `UNK230`, `UNK231`, `UNK232`, `UNK233`, `UNK234`, `UNK235`, `UNK236`, `UNK237`, `UNK238`, `UNK239`, `UNK240`, `UNK241`, `UNK242`) +VALUES + (51735, 0, 'MRC - CT Focus - Tier I - 5%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17158, 0, 1, 0, 0, 0, 0, 1983, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51736, 0, 'MRC - CT Focus - Tier II - 10%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17159, 0, 1, 0, 0, 0, 0, 1983, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51737, 0, 'MRC - CT Focus - Tier III - 15%', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17160, 0, 1, 0, 0, 0, 0, 1983, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51738, 0, 'MRC - CT Focus - Tier IV - 20%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17161, 0, 1, 0, 0, 0, 0, 1983, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51739, 0, 'MRC - CT Focus - Tier V - 25%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17162, 0, 1, 0, 0, 0, 0, 2001, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-09 18:53:11', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + + (51740, 0, 'MRC - ID Focus - Tier I - 10%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17163, 0, 1, 0, 0, 0, 0, 1989, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51741, 0, 'MRC - ID Focus - Tier II - 20%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17164, 0, 1, 0, 0, 0, 0, 1989, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51742, 0, 'MRC - ID Focus - Tier III - 30%', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17165, 0, 1, 0, 0, 0, 0, 1989, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51743, 0, 'MRC - ID Focus - Tier IV - 40%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17166, 0, 1, 0, 0, 0, 0, 1989, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51744, 0, 'MRC - ID Focus - Tier V - 50%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17167, 0, 1, 0, 0, 0, 0, 2002, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + + (51745, 0, 'MRC - IH Focus - Tier I - 15%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17168, 0, 1, 0, 0, 0, 0, 1941, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51746, 0, 'MRC - IH Focus - Tier II - 30%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17169, 0, 1, 0, 0, 0, 0, 1941, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51747, 0, 'MRC - IH Focus - Tier III - 45%', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17170, 0, 1, 0, 0, 0, 0, 1941, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51748, 0, 'MRC - IH Focus - Tier IV - 60%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17171, 0, 1, 0, 0, 0, 0, 1941, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51749, 0, 'MRC - IH Focus - Tier V - 75%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17172, 0, 1, 0, 0, 0, 0, 1994, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + + (51750, 0, 'MRC - MC Focus - Tier I - 5%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17173, 0, 1, 0, 0, 0, 0, 1965, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51751, 0, 'MRC - MC Focus - Tier II - 10%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17174, 0, 1, 0, 0, 0, 0, 1965, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51752, 0, 'MRC - MC Focus - Tier III - 15%', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17175, 0, 1, 0, 0, 0, 0, 1965, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51753, 0, 'MRC - MC Focus - Tier IV - 20%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17176, 0, 1, 0, 0, 0, 0, 1965, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + (51754, 0, 'MRC - MC Focus - Tier V - 25%' , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', '0', 65535, 4278190080, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 17177, 0, 1, 0, 0, 0, 0, 1998, 'IT63', 0, 10, 0, 0, 0, 0, '', 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 65535, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2011-10-03 10:49:31', '', 0, 0, 0, 0, 1, 1, 0, '', 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 6, 0, 0, 0, -1, 0, 0, 0, 0, '', '2009-05-03 03:13:17', '', '13THFLOOR', 0, '', 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, '0000000000000000000', 0, '', -1, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '2008-11-23 02:58:34', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, '', -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + +ALTER TABLE mercbuffs RENAME TO merc_buffs; + +DROP TABLE IF EXISTS merc_inventory; + +CREATE TABLE merc_inventory ( + merc_inventory_id int(10) unsigned NOT NULL auto_increment, + merc_subtype_id int(10) unsigned NOT NULL default '0', + item_id int(11) unsigned NOT NULL default '0', + min_level int(10) unsigned NOT NULL default '0', + max_level int(10) unsigned NOT NULL default '0', + PRIMARY KEY (merc_inventory_id), + KEY FK_merc_inventory_1 (merc_subtype_id), + CONSTRAINT FK_merc_inventory_1 FOREIGN KEY (merc_subtype_id) REFERENCES merc_subtypes (merc_subtype_id) +); + +INSERT INTO merc_inventory (merc_subtype_id, item_id, min_level, max_level) VALUES +(6, 51735, 1, 85), +(7, 51736, 1, 85), +(8, 51737, 1, 85), +(9, 51738, 1, 85), +(10, 51739, 1, 85), +(6, 51740, 1, 85), +(7, 51741, 1, 85), +(8, 51742, 1, 85), +(9, 51743, 1, 85), +(10, 51744, 1, 85), +(6, 51745, 1, 85), +(7, 51746, 1, 85), +(8, 51747, 1, 85), +(9, 51748, 1, 85), +(10, 51749, 1, 85), +(6, 51750, 1, 85), +(7, 51751, 1, 85), +(8, 51752, 1, 85), +(9, 51753, 1, 85), +(10, 51754, 1, 85), +(16, 51735, 1, 85), +(17, 51736, 1, 85), +(18, 51737, 1, 85), +(19, 51738, 1, 85), +(20, 51739, 1, 85), +(10, 51739, 1, 85), +(16, 51740, 1, 85), +(17, 51741, 1, 85), +(18, 51742, 1, 85), +(19, 51743, 1, 85), +(20, 51744, 1, 85), +(16, 51745, 1, 85), +(17, 51746, 1, 85), +(18, 51747, 1, 85), +(19, 51748, 1, 85), +(20, 51749, 1, 85), +(16, 51750, 1, 85), +(17, 51751, 1, 85), +(18, 51752, 1, 85), +(19, 51753, 1, 85), +(20, 51754, 1, 85); \ No newline at end of file diff --git a/zone/client.cpp b/zone/client.cpp index b0740bf01..8033367ab 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -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; diff --git a/zone/client.h b/zone/client.h index a834b4e5f..ed6b1db0a 100644 --- a/zone/client.h +++ b/zone/client.h @@ -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; } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index e71f023ec..07771f1e7 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -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) { diff --git a/zone/merc.cpp b/zone/merc.cpp index b2549caa9..dec3c1bcc 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -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= 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(); diff --git a/zone/merc.h b/zone/merc.h index 3c8cdea61..a404672cd 100644 --- a/zone/merc.h +++ b/zone/merc.h @@ -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 merc_spells; std::map timers; diff --git a/zone/zone.cpp b/zone/zone.cpp index 6bf964681..bbee3e5f3 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -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; diff --git a/zone/zone.h b/zone/zone.h index 856362edc..8a8e2a9bf 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -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; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 09cd3dec8..16b4537af 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -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]; diff --git a/zone/zonedb.h b/zone/zonedb.h index c2e7b12b6..9863d8fe0 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -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_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);