Merge branch 'master' of https://github.com/EQEmu/Server into bots_updater

This commit is contained in:
Uleat 2015-10-09 21:39:05 -04:00
commit 531cbf79f5
18 changed files with 367 additions and 315 deletions

View File

@ -493,7 +493,7 @@ bool Database::CheckDatabaseConversions() {
/* Check for a new version of this script, the arg passed
would have to be higher than the copy they have downloaded
locally and they will re fetch */
system("perl eqemu_update.pl V 10");
system("perl eqemu_update.pl V 11");
/* Run Automatic Database Upgrade Script */
system("perl eqemu_update.pl ran_from_world");

View File

@ -1659,27 +1659,29 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
sp[tempid].directional_start = static_cast<float>(atoi(row[194]));
sp[tempid].directional_end = static_cast<float>(atoi(row[195]));
sp[tempid].sneak = atoi(row[196]) != 0;
sp[tempid].not_extendable = atoi(row[197]) != 0;
sp[tempid].not_focusable = atoi(row[197]) != 0;
sp[tempid].no_detrimental_spell_aggro = atoi(row[198]) != 0;
sp[tempid].suspendable = atoi(row[200]) != 0;
sp[tempid].viral_range = atoi(row[201]);
sp[tempid].songcap = atoi(row[202]);
sp[tempid].no_block = atoi(row[205]);
sp[tempid].spellgroup=atoi(row[207]);
sp[tempid].rank = atoi(row[208]);
sp[tempid].powerful_flag=atoi(row[209]);
sp[tempid].no_resist=atoi(row[209]);
sp[tempid].CastRestriction = atoi(row[211]);
sp[tempid].AllowRest = atoi(row[212]) != 0;
sp[tempid].InCombat = atoi(row[213]) != 0;
sp[tempid].OutofCombat = atoi(row[214]) != 0;
sp[tempid].override_crit_chance = atoi(row[217]);
sp[tempid].aemaxtargets = atoi(row[218]);
sp[tempid].maxtargets = atoi(row[219]);
sp[tempid].no_heal_damage_item_mod = atoi(row[219]);
sp[tempid].persistdeath = atoi(row[224]) != 0;
sp[tempid].min_dist = atof(row[227]);
sp[tempid].min_dist_mod = atof(row[228]);
sp[tempid].max_dist = atof(row[229]);
sp[tempid].max_dist_mod = atof(row[230]);
sp[tempid].min_range = static_cast<float>(atoi(row[231]));
sp[tempid].no_remove = atoi(row[232]) != 0;
sp[tempid].DamageShieldType = 0;
}

View File

@ -1092,6 +1092,14 @@ bool DetrimentalSpellAllowsRest(uint16 spell_id)
return false;
}
bool NoDetrimentalSpellAggro(uint16 spell_id)
{
if (IsValidSpell(spell_id))
return spells[spell_id].no_detrimental_spell_aggro;
return false;
}
uint32 GetNimbusEffect(uint16 spell_id)
{
if (IsValidSpell(spell_id))

View File

@ -381,7 +381,7 @@ typedef enum {
#define SE_GiveDoubleAttack 225 // implemented[AA] - Allow any class to double attack with set chance.
#define SE_TwoHandBash 226 // *not implemented as bonus
#define SE_ReduceSkillTimer 227 // implemented
#define SE_ReduceFallDamage 228 // not implented as bonus - reduce the damage that you take from falling
#define SE_ReduceFallDamage 228 // implented - reduce the damage that you take from falling
#define SE_PersistantCasting 229 // implemented
#define SE_ExtendedShielding 230 // not used as bonus - increase range of /shield ability
#define SE_StunBashChance 231 // implemented - increase chance to stun from bash.
@ -400,7 +400,7 @@ typedef enum {
#define SE_RootBreakChance 244 // implemented[AA] reduce the chance that your root will break.
#define SE_TrapCircumvention 245 // *not implemented[AA] - decreases the chance that you will set off a trap when opening a chest
#define SE_SetBreathLevel 246 // *not implemented as bonus
#define SE_RaiseSkillCap 247 // *not implemented[AA] - adds skill over the skill cap.
#define SE_RaiseSkillCap 247 // implemented[AA] - adds skill over the skill cap.
#define SE_SecondaryForte 248 // not implemented as bonus(gives you a 2nd specialize skill that can go past 50 to 100)
#define SE_SecondaryDmgInc 249 // implemented[AA] Allows off hand weapon to recieve a damage bonus (Sinister Strikes)
#define SE_SpellProcChance 250 // implemented - Increase chance to proc from melee proc spells (ie Spirit of Panther)
@ -409,19 +409,19 @@ typedef enum {
#define SE_FrontalBackstabMinDmg 253 // implemented[AA] - allow a frontal backstab for mininum damage.
#define SE_Blank 254 // implemented
#define SE_ShieldDuration 255 // not implemented as bonus - increases duration of /shield
#define SE_ShroudofStealth 256 // not implemented as bonus - rogue improved invs
#define SE_ShroudofStealth 256 // implemented
#define SE_PetDiscipline 257 // not implemented as bonus - /pet hold
#define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab
#define SE_CombatStability 259 // implemented[AA] - damage mitigation
#define SE_AddSingingMod 260 // implemented[AA] - Instrument/Singing Mastery, base1 is the mod, base2 is the ItemType
#define SE_SongModCap 261 // implemented[AA] - Song Mod cap increase (no longer used on live)
#define SE_RaiseStatCap 262 // implemented
#define SE_TradeSkillMastery 263 // not implemented - lets you raise more than one tradeskill above master.
#define SE_TradeSkillMastery 263 // implemented - lets you raise more than one tradeskill above master.
#define SE_HastenedAASkill 264 // implemented
#define SE_MasteryofPast 265 // implemented[AA] - Spells less than effect values level can not be fizzled
#define SE_ExtraAttackChance 266 // implemented - increase chance to score an extra attack with a 2-Handed Weapon.
#define SE_PetDiscipline2 267 // *not implemented - /pet focus, /pet no cast
#define SE_ReduceTradeskillFail 268 // *not implemented? - reduces chance to fail with given tradeskill by a percent chance
#define SE_ReduceTradeskillFail 268 // implemented - reduces chance to fail with given tradeskill by a percent chance
#define SE_MaxBindWound 269 // implemented[AA] - Increase max HP you can bind wound.
#define SE_BardSongRange 270 // implemented[AA] - increase range of beneficial bard songs (Sionachie's Crescendo)
#define SE_BaseMovementSpeed 271 // implemented[AA] - mods basemove speed, doesn't stack with other move mods
@ -478,7 +478,7 @@ typedef enum {
#define SE_GateToHomeCity 322 // implemented
#define SE_DefensiveProc 323 // implemented
#define SE_HPToMana 324 // implemented
//#define SE_ChanceInvsBreakToAoE 325 // *not implemented[AA] - [AA Nerves of Steel] increasing chance to remain hidden when they are an indirect target of an AoE spell.
//#define SE_NoBreakAESneak 325 // *not implemented[AA] - [AA Nerves of Steel] increasing chance to remain hidden when they are an indirect target of an AoE spell.
#define SE_SpellSlotIncrease 326 // *not implemented as bonus - increases your spell slot availability
#define SE_MysticalAttune 327 // implemented - increases amount of buffs that a player can have
#define SE_DelayDeath 328 // implemented - increases how far you can fall below 0 hp before you die
@ -486,7 +486,7 @@ typedef enum {
#define SE_CriticalDamageMob 330 // implemented
#define SE_Salvage 331 // implemented - chance to recover items that would be destroyed in failed tradeskill combine
//#define SE_SummonToCorpse 332 // *not implemented AA - Call of the Wild (Druid/Shaman Res spell with no exp)
#define SE_CastOnRuneFadeEffect 333 // implemented
#define SE_CastOnRuneFadeEffect 333 // implemented
#define SE_BardAEDot 334 // implemented
#define SE_BlockNextSpellFocus 335 // implemented - base1 chance to block next spell ie Puratus (8494)
//#define SE_IllusionaryTarget 336 // not used
@ -619,7 +619,7 @@ typedef enum {
//#define SE_Shield_Target 463 //
#define SE_PC_Pet_Rampage 464 // implemented - Base1 % chance to do rampage for base2 % of damage each melee round
//#define SE_PC_Pet_AE_Rampage 465 // Would assume as above but need to confirm.
//#define SE_PC_Pet_Flurry_Chance 466 //
#define SE_PC_Pet_Flurry_Chance 466 // implemented - Base1 % chance to do flurry from double attack hit.
//#define SE_DS_Mitigation_Amount 467 //
//#define SE_DS_Mitigation_Percentage 468 //
//#define SE_Chance_Best_in_Spell_Grp 469 //
@ -744,8 +744,9 @@ struct SPDat_Spell_Struct
/* 194 */ float directional_start; //Cone Start Angle:
/* 195 */ float directional_end; // Cone End Angle:
/* 196 */ bool sneak; // effect can only be used if sneaking (rogue 'Daggerfall' ect)
/* 197 */ bool not_extendable;
/* 198- 199 */
/* 197 */ bool not_focusable; //prevents focus effects from being applied to spell
/* 198 */ bool no_detrimental_spell_aggro;
/* 199 */
/* 200 */ bool suspendable; // buff is suspended in suspended buff zones
/* 201 */ int viral_range;
/* 202 */ int songcap; // individual song cap
@ -755,7 +756,7 @@ struct SPDat_Spell_Struct
/* 206 */
/* 207 */ int spellgroup;
/* 208 */ int rank; //increments AA effects with same name
/* 209 */ int powerful_flag; // Need more investigation to figure out what to call this, for now we know -1 makes charm spells not break before their duration is complete, it does alot more though
/* 209 */ int no_resist; //makes spells unresistable, which makes charms unbreakable as well.
/* 210 */ // bool DurationFrozen; ???
/* 211 */ int CastRestriction; //Various restriction categories for spells most seem targetable race related but have also seen others for instance only castable if target hp 20% or lower or only if target out of combat
/* 212 */ bool AllowRest;
@ -764,7 +765,7 @@ struct SPDat_Spell_Struct
/* 215 - 216 */
/* 217 */ int override_crit_chance; //Places a cap on the max chance to critical
/* 218 */ int aemaxtargets; //Is used for various AE effects
/* 219 */ int maxtargets; //Is used for beam and ring spells for target # limits (not implemented)
/* 219 */ int no_heal_damage_item_mod;
/* 220 - 223 */
/* 224 */ bool persistdeath; // buff doesn't get stripped on death
/* 225 - 226 */
@ -773,7 +774,8 @@ struct SPDat_Spell_Struct
/* 229 */ float max_dist; //spell power modified by distance from caster (Max Distance)
/* 230 */ float max_dist_mod; //spell power modified by distance from caster (Modifier at Max Distance)
/* 231 */ float min_range; //Min casting range
/* 232 - 236 */
/* 232 */ bool no_remove; //prevents buff from being removed by click
/* 233 - 236 */
uint8 DamageShieldType; // This field does not exist in spells_us.txt
};
@ -879,6 +881,7 @@ uint32 GetPartialMeleeRuneReduction(uint32 spell_id);
uint32 GetPartialMagicRuneReduction(uint32 spell_id);
uint32 GetPartialMeleeRuneAmount(uint32 spell_id);
uint32 GetPartialMagicRuneAmount(uint32 spell_id);
bool NoDetrimentalSpellAggro(uint16 spell_id);
int CalcPetHp(int levelb, int classb, int STA = 75);
const char *GetRandPetName();

View File

@ -14,6 +14,7 @@ use POSIX qw(strftime);
use File::Path;
use File::Find;
use URI::Escape;
use Time::HiRes qw(usleep);
$time_stamp = strftime('%m-%d-%Y', gmtime());
@ -22,7 +23,7 @@ if($Config{osname}=~/linux/i){ $OS = "Linux"; }
if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; }
#::: If current version is less than what world is reporting, then download a new one...
$current_version = 10;
$current_version = 11;
if($ARGV[0] eq "V"){
if($ARGV[1] > $current_version){
@ -49,9 +50,6 @@ no warnings;
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime();
#::: Cleanup staged folder...
rmtree("updates_staged/");
my $confile = "eqemu_config.xml"; #default
open(F, "<$confile");
my $indb = 0;
@ -103,12 +101,40 @@ if($OS eq "Linux"){
}
#::: Path not found, error and exit
if($path eq ""){
if($path eq ""){
print "MySQL path not found, please add the path for automatic database upgrading to continue... \n\n";
print "script_exiting...\n";
exit;
}
if($ARGV[0] eq "installer"){
print "Running EQEmu Server installer routines...\n";
mkdir('logs');
mkdir('updates_staged');
fetch_latest_windows_binaries();
map_files_fetch_bulk();
opcodes_fetch();
plugins_fetch();
quest_files_fetch();
lua_modules_fetch();
get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/lua51.dll", "lua51.dll", 1);
#::: Database Routines
print "MariaDB :: Creating Database 'peq'\n";
print `"$path" --host $host --user $user --password="$pass" -N -B -e "DROP DATABASE peq;CREATE DATABASE peq"`;
if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); }
if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); }
$bin_db_ver = trim($db_version[1]);
check_db_version_table();
$local_db_ver = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1"));
fetch_peq_db_full();
print "\nFetching Latest Database Updates...\n";
main_db_management();
print "\nApplying Latest Database Updates...\n";
main_db_management();
exit;
}
#::: Create db_update working directory if not created
mkdir('db_update');
@ -118,15 +144,19 @@ if(trim(get_mysql_result("SHOW COLUMNS FROM db_version LIKE 'Revision'")) ne ""
print "Old db_version table present, dropping...\n\n";
}
if(get_mysql_result("SHOW TABLES LIKE 'db_version'") eq "" && $db){
print get_mysql_result("
CREATE TABLE db_version (
version int(11) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO db_version (version) VALUES ('1000');");
print "Table 'db_version' does not exists.... Creating...\n\n";
sub check_db_version_table{
if(get_mysql_result("SHOW TABLES LIKE 'db_version'") eq "" && $db){
print get_mysql_result("
CREATE TABLE db_version (
version int(11) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO db_version (version) VALUES ('1000');");
print "Table 'db_version' does not exists.... Creating...\n\n";
}
}
check_db_version_table();
if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); }
if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); }
@ -184,13 +214,13 @@ sub show_menu_prompt {
1 => \&database_dump,
2 => \&database_dump_compress,
3 => \&main_db_management,
4 => \&aa_fetch,
4 => \&bots_db_management,
5 => \&opcodes_fetch,
6 => \&map_files_fetch,
7 => \&plugins_fetch,
8 => \&quest_files_fetch,
9 => \&lua_modules_fetch,
10 => \&bots_db_management,
10 => \&aa_fetch,
20 => \&do_update_self,
0 => \&script_exit,
);
@ -241,31 +271,33 @@ sub menu_options {
$bots_management = "Install bots database pre-requisites (Requires bots server binaries)";
}
else{
$bots_management = "Check for Bot pending REQUIRED database updates...";
$bots_management = "Check for Bot pending REQUIRED database updates... (Must have bots enabled)";
}
}
}
else{
$option[3] = "Check and stage pending REQUIRED Database updates";
$bots_management = "Check for Bot REQUIRED database updates...";
$bots_management = "Check for Bot REQUIRED database updates... (Must have bots enabled)";
}
return <<EO_MENU;
EQEmu Update Utility Menu:
1) Backup Database - (Saves to Backups folder)
2) Backup Database Compressed - (Saves to Backups folder)
3) $option[3]
4) AAs - Download Latest AA's from PEQ (This overwrites existing data)
5) OPCodes - Download latest opcodes
6) Maps - Download latest map and water files
7) Plugins - Download latest Perl plugins
8) Quests - Download latest PEQ quests and stage updates
9) LUA Modules - Download latest LUA Modules (Required for Lua)
10) $bots_management
20) Force update this script (Redownload)
0) Exit
Enter numbered option and press enter...
============================================================
#::: EQEmu Update Utility Menu: (eqemu_update.pl)
============================================================
1) [Backup Database] :: (Saves to Backups folder)
2) [Backup Database Compressed] :: (Saves to Backups folder)
3) [EQEmu DB Schema] :: $option[3]
4) [EQEmu DB Bots Schema] $bots_management
5) [OPCodes] :: Download latest opcodes for each EQ Client
6) [Maps] :: Download latest map and water files
7) [Plugins (Perl)] :: Download latest Perl plugins
8) [Quests (Perl/LUA)] :: Download latest PEQ quests and stage updates
9) [LUA Modules] :: Download latest LUA Modules (Required for Lua)
10) [DB Data : Alternate Advancement] :: Download Latest AA's from PEQ (This overwrites existing data)
20) [Update the updater] Force update this script (Redownload)
0) Exit
Enter numbered option and press enter...
EO_MENU
}
@ -295,7 +327,11 @@ sub database_dump_compress {
print `perl db_dumper.pl database="$db" loc="backups" compress`;
}
sub script_exit{ }
sub script_exit{
#::: Cleanup staged folder...
rmtree("updates_staged/");
exit;
}
#::: Returns Tab Delimited MySQL Result from Command Line
sub get_mysql_result{
@ -345,35 +381,48 @@ sub get_remote_file{
if($OS eq "Windows"){
#::: For non-text type requests...
if($content_type == 1){
use LWP::Simple qw(getstore);
if(!getstore($URL, $Dest_File)){
print "Error, no connection or failed request...\n\n";
}
else{
print " o URL: (" . $URL . ")\n";
print " o Saved: (" . $Dest_File . ") \n";
$break = 0;
while($break == 0) {
use LWP::Simple qw(getstore);
if(!getstore($URL, $Dest_File)){
# print "Error, no connection or failed request...\n\n";
}
# sleep(1);
#::: Make sure the file exists before continuing...
if(-e $Dest_File) {
$break = 1;
print " [URL] :: " . $URL . "\n";
print " [Saved] :: " . $Dest_File . "\n";
} else { $break = 0; }
usleep(500);
}
}
else{
require LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->timeout(10);
$ua->env_proxy;
my $response = $ua->get($URL);
if ($response->is_success){
open (FILE, '> ' . $Dest_File . '');
print FILE $response->decoded_content;
close (FILE);
print " o URL: (" . $URL . ")\n";
print " o Saved: (" . $Dest_File . ") \n";
}
else {
print "Error, no connection or failed request...\n\n";
$break = 0;
while($break == 0) {
require LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->timeout(10);
$ua->env_proxy;
my $response = $ua->get($URL);
if ($response->is_success){
open (FILE, '> ' . $Dest_File . '');
print FILE $response->decoded_content;
close (FILE);
}
else {
# print "Error, no connection or failed request...\n\n";
}
if(-e $Dest_File) {
$break = 1;
print " [URL] :: " . $URL . "\n";
print " [Saved] :: " . $Dest_File . "\n";
} else { $break = 0; }
usleep(500);
}
}
}
if($OS eq "Linux"){
if($OS eq "Linux"){
#::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt
$wget = `wget --no-check-certificate --quiet -O $Dest_File $URL`;
print " o URL: (" . $URL . ")\n";
@ -461,6 +510,75 @@ sub copy_file{
copy $l_source_file, $l_dest_file;
}
sub fetch_latest_windows_binaries{
print "\n --- Fetching Latest Windows Binaries... --- \n";
get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/master_windows_build.zip", "updates_staged/master_windows_build.zip", 1);
print "\n --- Fetched Latest Windows Binaries... --- \n";
print "\n --- Extracting... --- \n";
unzip('updates_staged/master_windows_build.zip', 'updates_staged/binaries/');
my @files;
my $start_dir = "updates_staged/binaries";
find(
sub { push @files, $File::Find::name unless -d; },
$start_dir
);
for my $file (@files) {
$dest_file = $file;
$dest_file =~s/updates_staged\/binaries\///g;
print "Installing :: " . $dest_file . "\n";
copy_file($file, $dest_file);
}
print "\n --- Done... --- \n";
rmtree('updates_staged');
}
sub fetch_peq_db_full{
print "Downloading latest PEQ Database... Please wait...\n";
get_remote_file("http://edit.peqtgc.com/weekly/peq_beta.zip", "updates_staged/peq_beta.zip", 1);
print "Downloaded latest PEQ Database... Extracting...\n";
unzip('updates_staged/peq_beta.zip', 'updates_staged/peq_db/');
my $start_dir = "updates_staged\\peq_db";
find(
sub { push @files, $File::Find::name unless -d; },
$start_dir
);
for my $file (@files) {
$dest_file = $file;
$dest_file =~s/updates_staged\\peq_db\///g;
if($file=~/peqbeta|player_tables/i){
print "MariaDB :: Installing :: " . $dest_file . "\n";
get_mysql_result_from_file($file);
}
if($file=~/eqtime/i){
print "Installing eqtime.cfg\n";
copy_file($file, "eqtime.cfg");
}
}
}
sub map_files_fetch_bulk{
print "\n --- Fetching Latest Maps... (This could take a few minutes...) --- \n";
get_remote_file("http://github.com/Akkadius/EQEmuMaps/archive/master.zip", "maps/maps.zip", 1);
unzip('maps/maps.zip', 'maps/');
my @files;
my $start_dir = "maps\\EQEmuMaps-master\\maps";
find(
sub { push @files, $File::Find::name unless -d; },
$start_dir
);
for my $file (@files) {
$dest_file = $file;
$dest_file =~s/maps\\EQEmuMaps-master\\maps\///g;
print "Installing :: " . $dest_file . "\n";
copy_file($file, "maps/" . $new_file);
}
print "\n --- Fetched Latest Maps... --- \n";
rmtree('maps/EQEmuMaps-master');
unlink('maps/maps.zip');
}
sub map_files_fetch{
print "\n --- Fetching Latest Maps --- \n";
@ -549,6 +667,8 @@ sub quest_files_fetch{
}
}
rmtree('updates_staged');
if($fc == 0){
print "\nNo Quest Updates found... \n\n";
}

View File

@ -960,6 +960,9 @@ bool Mob::CheckLosFN(float posX, float posY, float posZ, float mobSize) {
//offensive spell aggro
int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc)
{
if (NoDetrimentalSpellAggro(spell_id))
return 0;
int32 AggroAmount = 0;
int32 nonModifiedAggro = 0;
uint16 slevel = GetLevel();
@ -1240,7 +1243,7 @@ bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) {
if(IsCharmSpell(spell_id)) {
if (spells[spell_id].powerful_flag == -1) //If charm spell has this set(-1), it can not break till end of duration.
if (spells[spell_id].no_resist) //If charm spell has this set(-1), it can not break till end of duration.
return true;
//1: The mob has a default 25% chance of being allowed a resistance check against the charm.

View File

@ -2410,7 +2410,7 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack
return true;
}
void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/)
void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, bool iYellForHelp /*= true*/, bool bFrenzy /*= false*/, bool iBuffTic /*= false*/, uint16 spell_id)
{
if(!other)
return;
@ -2466,6 +2466,9 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
if(IsFamiliar() || GetSpecialAbility(IMMUNE_AGGRO))
return;
if (spell_id != SPELL_UNKNOWN && NoDetrimentalSpellAggro(spell_id))
return;
if (other == myowner)
return;
@ -3139,15 +3142,15 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
if(!RuleB(Combat, EXPFromDmgShield)) {
// Damage shield damage shouldn't count towards who gets EXP
if(!attacker->CastToClient()->GetFeigned() && !FromDamageShield)
AddToHateList(attacker, 0, damage, true, false, iBuffTic);
AddToHateList(attacker, 0, damage, true, false, iBuffTic, spell_id);
}
else {
if(!attacker->CastToClient()->GetFeigned())
AddToHateList(attacker, 0, damage, true, false, iBuffTic);
AddToHateList(attacker, 0, damage, true, false, iBuffTic, spell_id);
}
}
else
AddToHateList(attacker, 0, damage, true, false, iBuffTic);
AddToHateList(attacker, 0, damage, true, false, iBuffTic, spell_id);
}
if(damage > 0) {
@ -3172,7 +3175,7 @@ void Mob::CommonDamage(Mob* attacker, int32 &damage, const uint16 spell_id, cons
{
if (!pet->IsHeld()) {
Log.Out(Logs::Detail, Logs::Aggro, "Sending pet %s into battle due to attack.", pet->GetName());
pet->AddToHateList(attacker, 1);
pet->AddToHateList(attacker, 1,0, true, false, false, spell_id);
pet->SetTarget(attacker);
Message_StringID(10, PET_ATTACKING, pet->GetCleanName(), attacker->GetCleanName());
}
@ -4760,8 +4763,15 @@ void Mob::DoMainHandAttackRounds(Mob *target, ExtraAttackOptions *opts, int spec
// A "quad" on live really is just a successful dual wield where both double attack
// The mobs that could triple lost the ability to when the triple attack skill was added in
Attack(target, MainPrimary, false, false, false, opts, special);
if (CanThisClassDoubleAttack() && CheckDoubleAttack())
if (CanThisClassDoubleAttack() && CheckDoubleAttack()){
Attack(target, MainPrimary, false, false, false, opts, special);
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()){
int chance = spellbonuses.PC_Pet_Flurry + itembonuses.PC_Pet_Flurry + aabonuses.PC_Pet_Flurry;
if (chance && zone->random.Roll(chance))
Flurry(nullptr);
}
}
return;
}
@ -4811,8 +4821,15 @@ void Mob::DoOffHandAttackRounds(Mob *target, ExtraAttackOptions *opts, int speci
GetEquipment(MaterialSecondary) != 0) {
if (CheckDualWield()) {
Attack(target, MainSecondary, false, false, false, opts, special);
if (CanThisClassDoubleAttack() && GetLevel() > 35 && CheckDoubleAttack())
if (CanThisClassDoubleAttack() && GetLevel() > 35 && CheckDoubleAttack()){
Attack(target, MainSecondary, false, false, false, opts, special);
if ((IsPet() || IsTempPet()) && IsPetOwnerClient()){
int chance = spellbonuses.PC_Pet_Flurry + itembonuses.PC_Pet_Flurry + aabonuses.PC_Pet_Flurry;
if (chance && zone->random.Roll(chance))
Flurry(nullptr);
}
}
}
}
}

View File

@ -1199,13 +1199,14 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
break;
}
// Kayen: Not sure best way to implement this yet.
// Physically raises skill cap ie if 55/55 it will raise to 55/60
case SE_RaiseSkillCap: {
if (newbon->RaiseSkillCap[0] < base1) {
newbon->RaiseSkillCap[0] = base1; // value
newbon->RaiseSkillCap[1] = base2; // skill
}
if (base2 > HIGHEST_SKILL)
break;
if (newbon->RaiseSkillCap[base2] < base1)
newbon->RaiseSkillCap[base2] = base1;
break;
}
@ -1423,22 +1424,45 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
if (newbon->PC_Pet_Rampage[1] < base2)
newbon->PC_Pet_Rampage[1] = base2; //Damage modifer - take highest
break;
}
}
case SE_PC_Pet_Flurry_Chance:
newbon->PC_Pet_Flurry += base1; //Chance to Flurry
break;
case SE_ShroudofStealth:
newbon->ShroudofStealth = true;
break;
case SE_ReduceFallDamage:
newbon->ReduceFallDamage += base1;
break;
case SE_ReduceTradeskillFail:{
if (base2 > HIGHEST_SKILL)
break;
newbon->ReduceTradeskillFail[base2] += base1;
break;
}
case SE_TradeSkillMastery:
if (newbon->TradeSkillMastery < base1)
newbon->TradeSkillMastery = base1;
break;
// to do
case SE_PetDiscipline:
break;
case SE_PetDiscipline2:
break;
case SE_ReduceTradeskillFail:
break;
case SE_PotionBeltSlots:
break;
case SE_BandolierSlots:
break;
case SE_ForageSkill:
break;
case SE_TradeSkillMastery:
break;
case SE_SecondaryForte:
break;
case SE_FeignedCastOnChance:
@ -1453,13 +1477,9 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
break;
case SE_TrapCircumvention:
break;
case SE_ShroudofStealth:
break;
case SE_FeignedMinion:
break;
// handled client side
case SE_ReduceFallDamage:
// not handled here
case SE_HastenedAASkill:
// not handled here but don't want to clutter debug log -- these may need to be verified to ignore
@ -3132,8 +3152,43 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
if (new_bonus->PC_Pet_Rampage[1] < base2)
new_bonus->PC_Pet_Rampage[1] = base2; //Damage modifer - take highest
break;
}
}
case SE_PC_Pet_Flurry_Chance:
new_bonus->PC_Pet_Flurry += effect_value; //Chance to Flurry
break;
case SE_ShroudofStealth:
new_bonus->ShroudofStealth = true;
break;
case SE_ReduceFallDamage:
new_bonus->ReduceFallDamage += effect_value;
break;
case SE_ReduceTradeskillFail:{
if (base2 > HIGHEST_SKILL)
break;
new_bonus->ReduceTradeskillFail[base2] += effect_value;
break;
}
case SE_TradeSkillMastery:
if (new_bonus->TradeSkillMastery < effect_value)
new_bonus->TradeSkillMastery = effect_value;
break;
case SE_RaiseSkillCap: {
if (base2 > HIGHEST_SKILL)
break;
if (new_bonus->RaiseSkillCap[base2] < effect_value)
new_bonus->RaiseSkillCap[base2] = effect_value;
break;
}
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
if (IsAISpellEffect) {

View File

@ -2439,18 +2439,8 @@ uint16 Client::GetMaxSkillAfterSpecializationRules(SkillUseTypes skillid, uint16
}
}
// This should possibly be handled by bonuses rather than here.
switch(skillid)
{
case SkillTracking:
{
Result += ((GetAA(aaAdvancedTracking) * 10) + (GetAA(aaTuneofPursuance) * 10));
break;
}
default:
break;
}
Result += spellbonuses.RaiseSkillCap[skillid] + itembonuses.RaiseSkillCap[skillid] + aabonuses.RaiseSkillCap[skillid];
return Result;
}

View File

@ -3734,7 +3734,7 @@ void Client::Handle_OP_BuffRemoveRequest(const EQApplicationPacket *app)
uint16 SpellID = m->GetSpellIDFromSlot(brrs->SlotID);
if (SpellID && IsBeneficialSpell(SpellID))
if (SpellID && IsBeneficialSpell(SpellID) && !spells[SpellID].no_remove)
m->BuffFadeBySlot(brrs->SlotID, true);
}
@ -5076,18 +5076,12 @@ void Client::Handle_OP_DisarmTraps(const EQApplicationPacket *app)
Message(13, "Ability recovery time not yet met.");
return;
}
int reuse = DisarmTrapsReuseTime;
switch (GetAA(aaAdvTrapNegotiation)) {
case 1:
reuse -= 1;
break;
case 2:
reuse -= 3;
break;
case 3:
reuse -= 5;
break;
}
int reuse = DisarmTrapsReuseTime - GetSkillReuseTime(SkillDisarmTraps);
if (reuse < 1)
reuse = 1;
p_timers.Start(pTimerDisarmTraps, reuse - 1);
Trap* trap = entity_list.FindNearbyTrap(this, 60);
@ -5359,17 +5353,9 @@ void Client::Handle_OP_EnvDamage(const EQApplicationPacket *app)
if (ed->dmgtype == 252) {
switch (GetAA(aaAcrobatics)) { //Don't know what acrobatics effect is yet but it should be done client side via aa effect.. till then
case 1:
damage = damage * 95 / 100;
break;
case 2:
damage = damage * 90 / 100;
break;
case 3:
damage = damage * 80 / 100;
break;
}
int mod = spellbonuses.ReduceFallDamage + itembonuses.ReduceFallDamage + aabonuses.ReduceFallDamage;
damage -= damage * mod / 100;
}
if (damage < 0)
@ -5443,19 +5429,13 @@ void Client::Handle_OP_FeignDeath(const EQApplicationPacket *app)
Message(13, "Ability recovery time not yet met.");
return;
}
int reuse = FeignDeathReuseTime;
switch (GetAA(aaRapidFeign))
{
case 1:
reuse -= 1;
break;
case 2:
reuse -= 2;
break;
case 3:
reuse -= 5;
break;
}
reuse -= GetSkillReuseTime(SkillFeignDeath);
if (reuse < 1)
reuse = 1;
p_timers.Start(pTimerFeignDeath, reuse - 1);
//BreakInvis();
@ -7762,7 +7742,11 @@ void Client::Handle_OP_Hide(const EQApplicationPacket *app)
Message(13, "Ability recovery time not yet met.");
return;
}
int reuse = HideReuseTime - GetAA(209);
int reuse = HideReuseTime - GetSkillReuseTime(SkillHide);
if (reuse < 1)
reuse = 1;
p_timers.Start(pTimerHide, reuse - 1);
float hidechance = ((GetSkill(SkillHide) / 250.0f) + .25) * 100;
@ -7776,7 +7760,7 @@ void Client::Handle_OP_Hide(const EQApplicationPacket *app)
sa_out->parameter = 1;
entity_list.QueueClients(this, outapp, true);
safe_delete(outapp);
if (GetAA(aaShroudofStealth)){
if (spellbonuses.ShroudofStealth || aabonuses.ShroudofStealth || itembonuses.ShroudofStealth){
improved_hidden = true;
hidden = true;
}
@ -11698,18 +11682,12 @@ void Client::Handle_OP_SenseTraps(const EQApplicationPacket *app)
Message(13, "Ability recovery time not yet met.");
return;
}
int reuse = SenseTrapsReuseTime;
switch (GetAA(aaAdvTrapNegotiation)) {
case 1:
reuse -= 1;
break;
case 2:
reuse -= 3;
break;
case 3:
reuse -= 5;
break;
}
int reuse = SenseTrapsReuseTime - GetSkillReuseTime(SkillSenseTraps);
if (reuse < 1)
reuse = 1;
p_timers.Start(pTimerSenseTraps, reuse - 1);
Trap* trap = entity_list.FindNearbyTrap(this, 800);

View File

@ -408,6 +408,7 @@ struct StatBonuses {
uint32 SkillProc[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs.
uint32 SkillProcSuccess[MAX_SKILL_PROCS]; // Max number of spells containing skill_procs_success.
uint32 PC_Pet_Rampage[2]; // 0= % chance to rampage, 1=damage modifier
uint32 PC_Pet_Flurry; // Percent chance flurry from double attack
// AAs
int8 Packrat; //weight reduction for items, 1 point = 10%
@ -438,7 +439,7 @@ struct StatBonuses {
int32 CombatStability; // Melee damage mitigation.
int32 DoubleRiposte; // Chance to double riposte
int32 GiveDoubleRiposte[3]; // 0=Regular Chance, 1=Skill Attack Chance, 2=Skill
uint32 RaiseSkillCap[2]; // Raise a specific skill cap (1 = value, 2=skill)
uint32 RaiseSkillCap[HIGHEST_SKILL+1]; // Raise a specific skill cap (base1= value, base2=skill)
int32 Ambidexterity; // Increase chance to duel wield by adding bonus 'skill'.
int32 PetMaxHP; // Increase the max hp of your pet.
int32 PetFlurry; // Chance for pet to flurry.
@ -466,6 +467,10 @@ struct StatBonuses {
int32 PetMeleeMitigation; // Add AC to owner's pet.
bool IllusionPersistence; // Causes illusions not to fade.
uint16 extra_xtargets; // extra xtarget entries
bool ShroudofStealth; // rogue improved invisiblity
uint16 ReduceFallDamage; // reduce fall damage by percent
int32 ReduceTradeskillFail[HIGHEST_SKILL+1]; // Reduces chance for trade skills to fail by percent.
uint8 TradeSkillMastery; // Allow number of tradeskills to exceed 200 skill.
};
typedef struct

View File

@ -112,7 +112,7 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
value -= GetFocusEffect(focusFcDamageAmt2, spell_id);
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100;
else if (IsNPC() && CastToNPC()->GetSpellScale())
@ -145,7 +145,7 @@ int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
value -= GetFocusEffect(focusFcDamageAmt2, spell_id);
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value);
if (IsNPC() && CastToNPC()->GetSpellScale())
@ -287,7 +287,7 @@ int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
value += GetFocusEffect(focusFcHealAmt, spell_id);
value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id);
if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
if(!spells[spell_id].no_heal_damage_item_mod && itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier;
value += value*target->GetHealRate(spell_id, this)/100;
@ -430,9 +430,6 @@ int32 Client::GetActSpellCost(uint16 spell_id, int32 cost)
int32 Mob::GetActSpellDuration(uint16 spell_id, int32 duration)
{
if (spells[spell_id].not_extendable)
return duration;
int increase = 100;
increase += GetFocusEffect(focusSpellDuration, spell_id);
int tic_inc = 0;

View File

@ -406,7 +406,7 @@ int Lua_Spell::GetSpellGroup() {
int Lua_Spell::GetPowerfulFlag() {
Lua_Safe_Call_Int();
return self->powerful_flag;
return self->no_resist;
}
int Lua_Spell::GetCastRestriction() {
@ -436,7 +436,7 @@ int Lua_Spell::GetAEMaxTargets() {
int Lua_Spell::GetMaxTargets() {
Lua_Safe_Call_Int();
return self->maxtargets;
return self->no_heal_damage_item_mod;
}
bool Lua_Spell::GetPersistDeath() {

View File

@ -5598,18 +5598,18 @@ int32 Mob::GetSpellStat(uint32 spell_id, const char *identifier, uint8 slot)
else if (id == "NimbusEffect") {return spells[spell_id].NimbusEffect; }
else if (id == "directional_start") {return static_cast<int32>(spells[spell_id].directional_start); }
else if (id == "directional_end") {return static_cast<int32>(spells[spell_id].directional_end); }
else if (id == "not_extendable") {return spells[spell_id].not_extendable; }
else if (id == "not_focusable") {return spells[spell_id].not_focusable; }
else if (id == "suspendable") {return spells[spell_id].suspendable; }
else if (id == "viral_range") {return spells[spell_id].viral_range; }
else if (id == "spellgroup") {return spells[spell_id].spellgroup; }
else if (id == "rank") {return spells[spell_id].rank; }
else if (id == "powerful_flag") {return spells[spell_id].powerful_flag; }
else if (id == "no_resist") {return spells[spell_id].no_resist; }
else if (id == "CastRestriction") {return spells[spell_id].CastRestriction; }
else if (id == "AllowRest") {return spells[spell_id].AllowRest; }
else if (id == "InCombat") {return spells[spell_id].InCombat; }
else if (id == "OutofCombat") {return spells[spell_id].OutofCombat; }
else if (id == "aemaxtargets") {return spells[spell_id].aemaxtargets; }
else if (id == "maxtargets") {return spells[spell_id].maxtargets; }
else if (id == "no_heal_damage_item_mod") {return spells[spell_id].no_heal_damage_item_mod; }
else if (id == "persistdeath") {return spells[spell_id].persistdeath; }
else if (id == "min_dist") {return static_cast<int32>(spells[spell_id].min_dist); }
else if (id == "min_dist_mod") {return static_cast<int32>(spells[spell_id].min_dist_mod); }

View File

@ -489,7 +489,7 @@ public:
inline uint32 GetLevelCon(uint8 iOtherLevel) const {
return this ? GetLevelCon(GetLevel(), iOtherLevel) : CON_GREEN; }
virtual void AddToHateList(Mob* other, uint32 hate = 0, int32 damage = 0, bool iYellForHelp = true,
bool bFrenzy = false, bool iBuffTic = false);
bool bFrenzy = false, bool iBuffTic = false, uint16 spell_id = SPELL_UNKNOWN);
bool RemoveFromHateList(Mob* mob);
void SetHateAmountOnEnt(Mob* other, int32 hate = 0, int32 damage = 0) { hate_list.SetHateAmountOnEnt(other,hate,damage);}
void HalveAggro(Mob *other) { uint32 in_hate = GetHateAmount(other); SetHateAmountOnEnt(other, (in_hate > 1 ? in_hate / 2 : 1)); }

View File

@ -780,7 +780,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
// define spells with fixed duration
// charm spells with -1 in field 209 are all of fixed duration, so lets use that instead of spell_ids
if(spells[spell_id].powerful_flag == -1)
if(spells[spell_id].no_resist)
bBreak = true;
if (!bBreak)
@ -5228,6 +5228,9 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id)
if (IsBardSong(spell_id) && type != focusFcBaseEffects && type != focusSpellDuration)
return 0;
if (spells[spell_id].not_focusable)
return 0;
int16 realTotal = 0;
int16 realTotal2 = 0;
int16 realTotal3 = 0;
@ -5499,6 +5502,9 @@ int16 Client::GetFocusEffect(focusType type, uint16 spell_id)
int16 NPC::GetFocusEffect(focusType type, uint16 spell_id) {
if (spells[spell_id].not_focusable)
return 0;
int16 realTotal = 0;
int16 realTotal2 = 0;
bool rand_effectiveness = false;

View File

@ -750,14 +750,6 @@ bool Client::CheckFizzle(uint16 spell_id)
// always at least 1% chance to fail or 5% to succeed
fizzlechance = fizzlechance < 1 ? 1 : (fizzlechance > 95 ? 95 : fizzlechance);
/*
if(IsBardSong(spell_id))
{
//This was a channel chance modifier - no evidence for fizzle reduction
fizzlechance -= GetAA(aaInternalMetronome) * 1.5f;
}
*/
float fizzle_roll = zone->random.Real(0, 100);
Log.Out(Logs::Detail, Logs::Spells, "Check Fizzle %s spell %d fizzlechance: %0.2f%% diff: %0.2f roll: %0.2f", GetName(), spell_id, fizzlechance, diff, fizzle_roll);
@ -4067,7 +4059,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
if(aggro > 0) {
AddToHateList(caster, aggro);
} else {
AddToHateList(caster, 1);
AddToHateList(caster, 1,0,true,false,false,spell_id);
}
return true;
}
@ -4094,7 +4086,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
if(aggro > 0) {
AddToHateList(caster, aggro);
} else {
AddToHateList(caster, 1);
AddToHateList(caster, 1,0,true,false,false,spell_id);
}
return true;
}
@ -4110,7 +4102,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
if(aggro > 0) {
AddToHateList(caster, aggro);
} else {
AddToHateList(caster, 1);
AddToHateList(caster, 1,0,true,false,false,spell_id);
}
return true;
} else if(IsClient() && caster->IsClient() && (caster->CastToClient()->GetGM() == false))
@ -4127,7 +4119,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
if (aggro > 0) {
AddToHateList(caster, aggro);
} else {
AddToHateList(caster, 1);
AddToHateList(caster, 1,0,true,false,false,spell_id);
}
return true;
}
@ -4150,7 +4142,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
if(aggro > 0) {
AddToHateList(caster, aggro);
} else {
AddToHateList(caster, 1);
AddToHateList(caster, 1,0,true,false,false,spell_id);
}
return true;
}
@ -4190,7 +4182,7 @@ bool Mob::IsImmuneToSpell(uint16 spell_id, Mob *caster)
if(aggro > 0) {
AddToHateList(caster, aggro);
} else {
AddToHateList(caster, 1);
AddToHateList(caster, 1,0,true,false,false,spell_id);
}
return true;
}
@ -4298,7 +4290,7 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
}
//Get the resist chance for the target
if(resist_type == RESIST_NONE)
if(resist_type == RESIST_NONE || spells[spell_id].no_resist)
{
Log.Out(Logs::Detail, Logs::Spells, "Spell was unresistable");
return 100;

View File

@ -941,135 +941,10 @@ bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
float res = zone->random.Real(0, 99);
int aa_chance = 0;
//AA modifiers
//can we do this with nested switches?
if(spec->tradeskill == SkillAlchemy){
switch(GetAA(aaAlchemyMastery)){
case 1:
aa_chance = 10;
break;
case 2:
aa_chance = 25;
break;
case 3:
aa_chance = 50;
break;
}
}
aa_chance = spellbonuses.ReduceTradeskillFail[spec->tradeskill] + itembonuses.ReduceTradeskillFail[spec->tradeskill] + aabonuses.ReduceTradeskillFail[spec->tradeskill];
if(spec->tradeskill == SkillJewelryMaking){
switch(GetAA(aaJewelCraftMastery)){
case 1:
aa_chance = 10;
break;
case 2:
aa_chance = 25;
break;
case 3:
aa_chance = 50;
break;
}
}
const Item_Struct* item = nullptr;
if (spec->tradeskill == SkillBlacksmithing) {
switch(GetAA(aaBlacksmithingMastery)) {
case 1:
aa_chance = 10;
break;
case 2:
aa_chance = 25;
break;
case 3:
aa_chance = 50;
break;
}
}
if (spec->tradeskill == SkillBaking) {
switch(GetAA(aaBakingMastery)) {
case 1:
aa_chance = 10;
break;
case 2:
aa_chance = 25;
break;
case 3:
aa_chance = 50;
break;
}
}
if (spec->tradeskill == SkillBrewing) {
switch(GetAA(aaBrewingMastery)) {
case 1:
aa_chance = 10;
break;
case 2:
aa_chance = 25;
break;
case 3:
aa_chance = 50;
break;
}
}
if (spec->tradeskill == SkillFletching) {
switch(GetAA(aaFletchingMastery2)) {
case 1:
aa_chance = 10;
break;
case 2:
aa_chance = 25;
break;
case 3:
aa_chance = 50;
break;
}
}
if (spec->tradeskill == SkillPottery) {
switch(GetAA(aaPotteryMastery)) {
case 1:
aa_chance = 10;
break;
case 2:
aa_chance = 25;
break;
case 3:
aa_chance = 50;
break;
}
}
if (spec->tradeskill == SkillTailoring) {
switch(GetAA(aaTailoringMastery)) {
case 1:
aa_chance = 10;
break;
case 2:
aa_chance = 25;
break;
case 3:
aa_chance = 50;
break;
}
}
if (spec->tradeskill == SkillResearch) {
switch(GetAA(aaArcaneTongues)) {
case 1:
aa_chance = 10;
break;
case 2:
aa_chance = 25;
break;
case 3:
aa_chance = 50;
break;
}
}
chance = mod_tradeskill_chance(chance, spec);
if (((spec->tradeskill==75) || GetGM() || (chance > res)) || zone->random.Roll(aa_chance)) {
@ -1528,8 +1403,9 @@ bool Client::CanIncreaseTradeskill(SkillUseTypes tradeskill) {
uint8 Pottery = (GetRawSkill(SkillPottery) > 200) ? 1 : 0;
uint8 Tailoring = (GetRawSkill(SkillTailoring) > 200) ? 1 : 0;
uint8 SkillTotal = Baking + Smithing + Brewing + Fletching + Jewelry + Pottery + Tailoring; //Tradeskills above 200
uint32 aaLevel = GetAA(aaNewTanaanCraftingMastery); //New Tanaan AA: Each level allows an additional tradeskill above 200 (first one is free)
//New Tanaan AA: Each level allows an additional tradeskill above 200 (first one is free)
uint8 aaLevel = spellbonuses.TradeSkillMastery + itembonuses.TradeSkillMastery + aabonuses.TradeSkillMastery;
switch (tradeskill) {
case SkillBaking:
case SkillBlacksmithing: