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);