mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-19 08:32:25 +00:00
Merge branch 'master' into raycast
This commit is contained in:
commit
629f9863ae
@ -1,7 +1,27 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
|
||||
== 02/27/2014 ==
|
||||
cavedude: Exported TrainDisc to Lua.
|
||||
|
||||
== 02/26/2014 ==
|
||||
Kayen: Implemented SE_FrenziedDevestation - increase critical spell chacnce and 2x mana cost for DD spells
|
||||
Kayen: Fixed SE_SpellProcChance - Now works on spell dervived procs
|
||||
cavedude: Added two new NPC special_abilities. ALWAYS_FLEE, which forces the NPC to always flee ignoring FleeIfNotAlone and FLEE_PERCENT which allows you to change the HP an individual NPC will flee at. If no value is set, the rule is used as normal.
|
||||
cavedude: Fixed an issue where rectangular roamboxes could cause an NPC to get stuck on a single coord.
|
||||
cavedude: Added a new roambox column, mindelay allowing you to have more control over the roambox delay.
|
||||
Uleat: Fix for 'sqrt' failure on vs2010 clients
|
||||
image: Added idle zone timer to save CPU cycles.
|
||||
|
||||
Required SQL: utils/sql/git/required/2014_02_26_roambox_update.sql
|
||||
|
||||
== 02/24/2014 ==
|
||||
cavedude: Better flee runspeed calculation. Added rule Combat:FleeMultiplier to alter this behavior.
|
||||
Sorvani: Updated GetUnusedInstanceID to not recycle instance ID's unless it has reached max (65535)
|
||||
|
||||
== 02/23/2014 ==
|
||||
Secrets: Exported the client object SendTargetCommand to Perl.
|
||||
cavedude: Merchants will now keep better track of charges.
|
||||
|
||||
== 02/20/2014 ==
|
||||
Kayen: Implemented SE_MitigateDotDamage - dot spell mitigation rune with max value
|
||||
|
||||
@ -2516,30 +2516,53 @@ bool Database::GetUnusedInstanceID(uint16 &instance_id)
|
||||
MYSQL_RES *result;
|
||||
MYSQL_ROW row;
|
||||
|
||||
uint32 count = RuleI(Zone, ReservedInstances) + 1;
|
||||
uint32 count = RuleI(Zone, ReservedInstances);
|
||||
uint32 max = 65535;
|
||||
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_list where id >= %i ORDER BY id", count), errbuf, &result)) {
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u", count,count), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) != 0) {
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
if(count < atoi(row[0])) {
|
||||
instance_id = count;
|
||||
mysql_free_result(result);
|
||||
return true;
|
||||
} else if(count > max) {
|
||||
instance_id = 0;
|
||||
mysql_free_result(result);
|
||||
return false;
|
||||
row = mysql_fetch_row(result);
|
||||
mysql_free_result(result);
|
||||
if(atoi(row[0]) <= max) {
|
||||
count = atoi(row[0]);
|
||||
} else {
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_list where id > %u ORDER BY id", count), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
if (mysql_num_rows(result) != 0) {
|
||||
count++;
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
if(count < atoi(row[0])) {
|
||||
instance_id = count;
|
||||
mysql_free_result(result);
|
||||
return true;
|
||||
} else if(count > max) {
|
||||
instance_id = 0;
|
||||
mysql_free_result(result);
|
||||
return false;
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
instance_id = 0;
|
||||
mysql_free_result(result);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
count++;
|
||||
safe_delete_array(query);
|
||||
instance_id = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
instance_id = 0;
|
||||
mysql_free_result(result);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
safe_delete_array(query);
|
||||
instance_id = 0;
|
||||
return false;
|
||||
}
|
||||
instance_id = count;
|
||||
return true;
|
||||
|
||||
@ -310,8 +310,8 @@ RULE_INT ( Combat, ClientBaseCritChance, 0 ) //The base crit chance for all clie
|
||||
RULE_BOOL ( Combat, UseIntervalAC, true)
|
||||
RULE_INT ( Combat, PetAttackMagicLevel, 30)
|
||||
RULE_BOOL ( Combat, EnableFearPathing, true)
|
||||
RULE_INT ( Combat, FleeHPRatio, 25)
|
||||
RULE_INT ( Combat, FleeSnareHPRatio, 11) // HP at which snare will halt movement of a fleeing NPC.
|
||||
RULE_REAL ( Combat, FleeMultiplier, 2.0) // Determines how quickly a NPC will slow down while fleeing. Decrease multiplier to slow NPC down quicker.
|
||||
RULE_INT ( Combat, FleeHPRatio, 25) //HP % when a NPC begins to flee.
|
||||
RULE_BOOL ( Combat, FleeIfNotAlone, false) // If false, mobs won't flee if other mobs are in combat with it.
|
||||
RULE_BOOL ( Combat, AdjustProcPerMinute, true)
|
||||
RULE_REAL ( Combat, AvgProcsPerMinute, 2.0)
|
||||
@ -466,6 +466,8 @@ RULE_INT ( Merchant, PriceBonusPct, 4) // Determines maximum price bonus from ha
|
||||
RULE_INT ( Merchant, PricePenaltyPct, 4) // Determines maximum price penalty from having bad faction/CHA. Value is a percent.
|
||||
RULE_REAL( Merchant, ChaBonusMod, 3.45) // Determines CHA cap, from 104 CHA. 3.45 is 132 CHA at apprehensive. 0.34 is 400 CHA at apprehensive.
|
||||
RULE_REAL ( Merchant, ChaPenaltyMod, 1.52) // Determines CHA bottom, up to 102 CHA. 1.52 is 37 CHA at apprehensive. 0.98 is 0 CHA at apprehensive.
|
||||
RULE_BOOL ( Merchant, EnableAltCurrencySell, true) // Enables the ability to resell items to alternate currency merchants
|
||||
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY ( Bazaar )
|
||||
|
||||
@ -359,7 +359,7 @@ typedef enum {
|
||||
#define SE_DispelBeneficial 209 // implemented
|
||||
//#define SE_PetShield 210 // *not implemented
|
||||
#define SE_AEMelee 211 // implemented
|
||||
//#define SE_CastingSkills 212 // *not implemented -Include/Exclude Casting Skill type. (*no longer used on live)
|
||||
#define SE_FrenziedDevastation 212 // implemented - increase spell criticals + all DD spells cast 2x mana.
|
||||
#define SE_PetMaxHP 213 // implemented[AA] - increases the maximum hit points of your pet
|
||||
#define SE_MaxHPChange 214 // implemented
|
||||
#define SE_PetAvoidance 215 // implemented[AA] - increases pet ability to avoid melee damage
|
||||
@ -397,7 +397,7 @@ typedef enum {
|
||||
#define SE_RaiseSkillCap 247 // *not 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 sympathetic proc by %
|
||||
#define SE_SpellProcChance 250 // implemented - Increase chance to proc from melee proc spells (ie Spirit of Panther)
|
||||
#define SE_ConsumeProjectile 251 // implemented[AA] - chance to not consume an arrow (ConsumeProjectile = 100)
|
||||
#define SE_FrontalBackstabChance 252 // implemented[AA] - chance to perform a full damage backstab from front.
|
||||
#define SE_FrontalBackstabMinDmg 253 // implemented[AA] - allow a frontal backstab for mininum damage.
|
||||
|
||||
2
utils/sql/git/required/2014_02_26_roambox_update.sql
Normal file
2
utils/sql/git/required/2014_02_26_roambox_update.sql
Normal file
@ -0,0 +1,2 @@
|
||||
alter table `spawngroup` add column `mindelay` int(11) not null default 15000 AFTER delay;
|
||||
alter table `spawngroup` change `delay` `delay` int(11) not null default 45000;
|
||||
8
utils/sql/git/required/2014_02_26_virulentvenomAA.sql
Normal file
8
utils/sql/git/required/2014_02_26_virulentvenomAA.sql
Normal file
@ -0,0 +1,8 @@
|
||||
-- Virulent Venom
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('888', '1', '250', '10', '0');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('889', '1', '250', '20', '0');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('890', '1', '250', '30', '0');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('891', '1', '250', '40', '0');
|
||||
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('892', '1', '250', '50', '0');
|
||||
|
||||
|
||||
@ -94,7 +94,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) {
|
||||
dist2 <= spells[AIspells[i].spellid].range*spells[AIspells[i].spellid].range
|
||||
)
|
||||
&& (mana_cost <= GetMana() || GetMana() == GetMaxMana())
|
||||
&& (AIspells[i].time_cancast+(MakeRandomInt(0, 4))) <= Timer::GetCurrentTime() //break up the spelling casting over a period of time.
|
||||
&& (AIspells[i].time_cancast + (MakeRandomInt(0, 4) * 1000)) <= Timer::GetCurrentTime() //break up the spelling casting over a period of time.
|
||||
) {
|
||||
|
||||
#if MobAI_DEBUG_Spells >= 21
|
||||
@ -125,21 +125,19 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) {
|
||||
break;
|
||||
}
|
||||
case SpellType_Root: {
|
||||
if (
|
||||
!tar->IsRooted()
|
||||
&& dist2 >= 900
|
||||
&& MakeRandomInt(0, 99) < 50
|
||||
&& tar->DontRootMeBefore() < Timer::GetCurrentTime()
|
||||
&& tar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0
|
||||
Mob *rootee = GetHateRandom();
|
||||
if (rootee && !rootee->IsRooted() && MakeRandomInt(0, 99) < 50
|
||||
&& rootee->DontRootMeBefore() < Timer::GetCurrentTime()
|
||||
&& rootee->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0
|
||||
) {
|
||||
if(!checked_los) {
|
||||
if(!CheckLosFN(tar))
|
||||
if(!CheckLosFN(rootee))
|
||||
return(false); //cannot see target... we assume that no spell is going to work since we will only be casting detrimental spells in this call
|
||||
checked_los = true;
|
||||
}
|
||||
uint32 tempTime = 0;
|
||||
AIDoSpellCast(i, tar, mana_cost, &tempTime);
|
||||
tar->SetDontRootMeBefore(tempTime);
|
||||
AIDoSpellCast(i, rootee, mana_cost, &tempTime);
|
||||
rootee->SetDontRootMeBefore(tempTime);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@ -167,7 +165,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) {
|
||||
}
|
||||
|
||||
case SpellType_InCombatBuff: {
|
||||
if(MakeRandomInt(0,100) < 50)
|
||||
if(MakeRandomInt(0, 99) < 50)
|
||||
{
|
||||
AIDoSpellCast(i, tar, mana_cost);
|
||||
return true;
|
||||
@ -184,7 +182,20 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) {
|
||||
break;
|
||||
}
|
||||
case SpellType_Slow:
|
||||
case SpellType_Debuff:
|
||||
case SpellType_Debuff: {
|
||||
Mob * debuffee = GetHateRandom();
|
||||
if (debuffee && manaR >= 10 && MakeRandomInt(0, 99 < 70) &&
|
||||
debuffee->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0) {
|
||||
if (!checked_los) {
|
||||
if (!CheckLosFN(debuffee))
|
||||
return false;
|
||||
checked_los = true;
|
||||
}
|
||||
AIDoSpellCast(i, debuffee, mana_cost);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SpellType_Nuke: {
|
||||
if (
|
||||
manaR >= 10 && MakeRandomInt(0, 99) < 70
|
||||
@ -201,7 +212,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) {
|
||||
break;
|
||||
}
|
||||
case SpellType_Dispel: {
|
||||
if(MakeRandomInt(0, 100) < 15)
|
||||
if(MakeRandomInt(0, 99) < 15)
|
||||
{
|
||||
if(!checked_los) {
|
||||
if(!CheckLosFN(tar))
|
||||
@ -444,6 +455,7 @@ void NPC::AI_Init() {
|
||||
roambox_distance = 0;
|
||||
roambox_movingto_x = 0;
|
||||
roambox_movingto_y = 0;
|
||||
roambox_min_delay = 2500;
|
||||
roambox_delay = 2500;
|
||||
}
|
||||
|
||||
@ -1579,14 +1591,17 @@ void NPC::AI_DoMovement() {
|
||||
movey *= MakeRandomInt(0, 1) ? 1 : -1;
|
||||
roambox_movingto_x = GetX() + movex;
|
||||
roambox_movingto_y = GetY() + movey;
|
||||
//Try to calculate new coord using distance.
|
||||
if (roambox_movingto_x > roambox_max_x || roambox_movingto_x < roambox_min_x)
|
||||
roambox_movingto_x -= movex * 2;
|
||||
if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y)
|
||||
roambox_movingto_y -= movey * 2;
|
||||
//New coord is still invalid, ignore distance and just pick a new random coord.
|
||||
//If we're here we may have a roambox where one side is shorter than the specified distance. Commons, Wkarana, etc.
|
||||
if (roambox_movingto_x > roambox_max_x || roambox_movingto_x < roambox_min_x)
|
||||
roambox_movingto_x = roambox_max_x;
|
||||
roambox_movingto_x = MakeRandomFloat(roambox_min_x+1,roambox_max_x-1);
|
||||
if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y)
|
||||
roambox_movingto_y = roambox_max_y;
|
||||
roambox_movingto_y = MakeRandomFloat(roambox_min_y+1,roambox_max_y-1);
|
||||
}
|
||||
|
||||
mlog(AI__WAYPOINTS, "Roam Box: d=%.3f (%.3f->%.3f,%.3f->%.3f): Go To (%.3f,%.3f)",
|
||||
@ -1594,7 +1609,7 @@ void NPC::AI_DoMovement() {
|
||||
if (!CalculateNewPosition2(roambox_movingto_x, roambox_movingto_y, GetZ(), walksp, true))
|
||||
{
|
||||
roambox_movingto_x = roambox_max_x + 1; // force update
|
||||
pLastFightingDelayMoving = Timer::GetCurrentTime() + RandomTimer(roambox_delay, roambox_delay + 5000);
|
||||
pLastFightingDelayMoving = Timer::GetCurrentTime() + RandomTimer(roambox_min_delay, roambox_delay);
|
||||
SetMoving(false);
|
||||
SendPosition(); // makes mobs stop clientside
|
||||
}
|
||||
@ -1870,7 +1885,7 @@ bool NPC::AI_EngagedCastCheck() {
|
||||
// try casting a heal on nearby
|
||||
if (!entity_list.AICheckCloseBeneficialSpells(this, 25, MobAISpellRange, SpellType_Heal)) {
|
||||
//nobody to heal, try some detrimental spells.
|
||||
if(!AICastSpell(GetTarget(), 20, SpellType_Nuke | SpellType_Lifetap | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff | SpellType_Charm)) {
|
||||
if(!AICastSpell(GetTarget(), 20, SpellType_Nuke | SpellType_Lifetap | SpellType_DOT | SpellType_Dispel | SpellType_Mez | SpellType_Slow | SpellType_Debuff | SpellType_Charm | SpellType_Root)) {
|
||||
//no spell to cast, try again soon.
|
||||
AIautocastspell_timer->Start(RandomTimer(500, 1000), false);
|
||||
}
|
||||
|
||||
@ -125,6 +125,8 @@
|
||||
#define YOU_ARE_PROTECTED 424 //%1 tries to cast a spell on you, but you are protected.
|
||||
#define TARGET_RESISTED 425 //Your target resisted the %1 spell.
|
||||
#define YOU_RESIST 426 //You resist the %1 spell!
|
||||
#define YOU_CRIT_HEAL 427 //You perform an exceptional heal! (%1)
|
||||
#define YOU_CRIT_BLAST 428 //You deliver a critical blast! (%1)
|
||||
#define SUMMONING_CORPSE 429 //Summoning your corpse.
|
||||
#define SUMMONING_CORPSE_OTHER 430 //Summoning %1's corpse.
|
||||
#define MISSING_SPELL_COMP_ITEM 433 //You are missing %1.
|
||||
@ -168,6 +170,8 @@
|
||||
#define OTHER_REGAIN_CAST 1033 //%1 regains concentration and continues casting.
|
||||
#define GENERIC_SHOUT 1034 //%1 shouts '%2'
|
||||
#define GENERIC_EMOTE 1036 //%1 %2
|
||||
#define OTHER_CRIT_HEAL 1039 //%1 performs an exceptional heal! (%2)
|
||||
#define OTHER_CRIT_BLAST 1040 //%1 delivers a critical blast! (%2)
|
||||
#define NPC_ENRAGE_START 1042 //%1 has become ENRAGED.
|
||||
#define NPC_ENRAGE_END 1043 //%1 is no longer enraged.
|
||||
#define NPC_RAMPAGE 1044 //%1 goes on a RAMPAGE!
|
||||
@ -222,6 +226,9 @@
|
||||
#define SUSPEND_MINION_SUSPEND 3268 //%1 tells you, 'By your command, master.'
|
||||
#define ONLY_SUMMONED_PETS 3269 //3269 This effect only works with summoned pets.
|
||||
#define SUSPEND_MINION_FIGHTING 3270 //Your pet must be at peace, first.
|
||||
#define ALREADY_SHIELDED 3279 //Either you or your target is already being shielded.
|
||||
#define START_SHIELDING 3281 //%1 begins to use %2 as a living shield!
|
||||
#define END_SHIELDING 3282 //%1 ceases protecting %2.
|
||||
#define TRADESKILL_MISSING_ITEM 3455 //You are missing a %1.
|
||||
#define TRADESKILL_MISSING_COMPONENTS 3456 //Sorry, but you don't have everything you need for this recipe in your general inventory.
|
||||
#define TRADESKILL_LEARN_RECIPE 3457 //You have learned the recipe %1!
|
||||
|
||||
@ -1222,7 +1222,7 @@ bool Mob::PassCharismaCheck(Mob* caster, Mob* spellTarget, uint16 spell_id) {
|
||||
if (caster->IsClient())
|
||||
{
|
||||
//3: At maxed ability, Total Domination has a 50% chance of preventing the charm break that otherwise would have occurred.
|
||||
uint16 TotalDominationBonus = caster->aabonuses.CharmBreakChance + caster->spellbonuses.CharmBreakChance + caster->itembonuses.CharmBreakChance;
|
||||
int16 TotalDominationBonus = caster->aabonuses.CharmBreakChance + caster->spellbonuses.CharmBreakChance + caster->itembonuses.CharmBreakChance;
|
||||
|
||||
if (MakeRandomInt(0, 99) < TotalDominationBonus)
|
||||
return true;
|
||||
|
||||
324
zone/attack.cpp
324
zone/attack.cpp
@ -2004,6 +2004,7 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool
|
||||
|
||||
if(!bRiposte && other->GetHP() > 0 ) {
|
||||
TryWeaponProc(nullptr, weapon, other, Hand); //no weapon
|
||||
TrySpellProc(nullptr, weapon, other, Hand);
|
||||
}
|
||||
|
||||
TriggerDefensiveProcs(nullptr, other, Hand, damage);
|
||||
@ -3851,24 +3852,17 @@ void Mob::HealDamage(uint32 amount, Mob* caster) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(amount > (maxhp - curhp))
|
||||
acthealed = (maxhp - curhp);
|
||||
else
|
||||
acthealed = amount;
|
||||
|
||||
char *TempString = nullptr;
|
||||
|
||||
MakeAnyLenString(&TempString, "%d", acthealed);
|
||||
|
||||
if(acthealed > 100){
|
||||
if(caster){
|
||||
Message_StringID(MT_NonMelee, YOU_HEALED, caster->GetCleanName(), TempString);
|
||||
if(caster != this){
|
||||
caster->Message_StringID(MT_NonMelee, YOU_HEAL, GetCleanName(), TempString);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (acthealed > 100) {
|
||||
if (caster) {
|
||||
Message_StringID(MT_NonMelee, YOU_HEALED, caster->GetCleanName(), itoa(acthealed));
|
||||
if (caster != this)
|
||||
caster->Message_StringID(MT_NonMelee, YOU_HEAL, GetCleanName(), itoa(acthealed));
|
||||
} else {
|
||||
Message(MT_NonMelee, "You have been healed for %d points of damage.", acthealed);
|
||||
}
|
||||
}
|
||||
@ -3882,22 +3876,15 @@ void Mob::HealDamage(uint32 amount, Mob* caster) {
|
||||
|
||||
SendHPUpdate();
|
||||
}
|
||||
safe_delete_array(TempString);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//proc chance includes proc bonus
|
||||
float Mob::GetProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_speed, uint16 hand) {
|
||||
float Mob::GetProcChances(float ProcBonus, uint16 weapon_speed, uint16 hand)
|
||||
{
|
||||
int mydex = GetDEX();
|
||||
float AABonus = 0;
|
||||
ProcBonus = 0;
|
||||
ProcChance = 0;
|
||||
float ProcChance = 0.0f;
|
||||
|
||||
if (aabonuses.ProcChance)
|
||||
AABonus = float(aabonuses.ProcChance) / 100.0f;
|
||||
|
||||
switch(hand){
|
||||
switch (hand) {
|
||||
case 13:
|
||||
weapon_speed = attack_timer.GetDuration();
|
||||
break;
|
||||
@ -3909,24 +3896,20 @@ float Mob::GetProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_spe
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//calculate the weapon speed in ms, so we can use the rule to compare against.
|
||||
|
||||
if(weapon_speed < RuleI(Combat, MinHastedDelay)) // fast as a client can swing, so should be the floor of the proc chance
|
||||
// fast as a client can swing, so should be the floor of the proc chance
|
||||
if (weapon_speed < RuleI(Combat, MinHastedDelay))
|
||||
weapon_speed = RuleI(Combat, MinHastedDelay);
|
||||
|
||||
ProcBonus += (float(itembonuses.ProcChance + spellbonuses.ProcChance) / 1000.0f + AABonus);
|
||||
|
||||
if(RuleB(Combat, AdjustProcPerMinute) == true)
|
||||
{
|
||||
ProcChance = ((float)weapon_speed * RuleR(Combat, AvgProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms
|
||||
ProcBonus += float(mydex) * RuleR(Combat, ProcPerMinDexContrib) / 100.0f;
|
||||
ProcChance = ProcChance + (ProcChance * ProcBonus);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcChance = RuleR(Combat, BaseProcChance) + float(mydex) / RuleR(Combat, ProcDexDivideBy);
|
||||
ProcChance = ProcChance + (ProcChance * ProcBonus);
|
||||
if (RuleB(Combat, AdjustProcPerMinute)) {
|
||||
ProcChance = (static_cast<float>(weapon_speed) *
|
||||
RuleR(Combat, AvgProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms
|
||||
ProcBonus += static_cast<float>(mydex) * RuleR(Combat, ProcPerMinDexContrib);
|
||||
ProcChance += ProcChance * ProcBonus / 100.0f;
|
||||
} else {
|
||||
ProcChance = RuleR(Combat, BaseProcChance) +
|
||||
static_cast<float>(mydex) / RuleR(Combat, ProcDexDivideBy);
|
||||
ProcChance += ProcChance * ProcBonus / 100.0f;
|
||||
}
|
||||
|
||||
mlog(COMBAT__PROCS, "Proc chance %.2f (%.2f from bonuses)", ProcChance, ProcBonus);
|
||||
@ -3950,16 +3933,6 @@ float Mob::GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 w
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
float PermaHaste;
|
||||
if(GetHaste() > 0)
|
||||
PermaHaste = 1 / (1 + (float)GetHaste()/100);
|
||||
else if(GetHaste() < 0)
|
||||
PermaHaste = 1 * (1 - (float)GetHaste()/100);
|
||||
else
|
||||
PermaHaste = 1.0f;
|
||||
*/
|
||||
|
||||
//calculate the weapon speed in ms, so we can use the rule to compare against.
|
||||
//weapon_speed = ((int)(weapon_speed*(100.0f+attack_speed)*PermaHaste));
|
||||
if(weapon_speed < RuleI(Combat, MinHastedDelay)) // fast as a client can swing, so should be the floor of the proc chance
|
||||
@ -4039,159 +4012,180 @@ void Mob::TryWeaponProc(const ItemInst* weapon_g, Mob *on, uint16 hand) {
|
||||
}
|
||||
|
||||
if(!weapon_g) {
|
||||
TryWeaponProc(nullptr, (const Item_Struct*)nullptr, on, hand);
|
||||
TrySpellProc(nullptr, (const Item_Struct*)nullptr, on);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!weapon_g->IsType(ItemClassCommon)) {
|
||||
TryWeaponProc(nullptr, (const Item_Struct*) nullptr, on, hand);
|
||||
TrySpellProc(nullptr, (const Item_Struct*)nullptr, on);
|
||||
return;
|
||||
}
|
||||
|
||||
//do main procs
|
||||
// Innate + aug procs from weapons
|
||||
// TODO: powersource procs
|
||||
TryWeaponProc(weapon_g, weapon_g->GetItem(), on, hand);
|
||||
// Procs from Buffs and AA both melee and range
|
||||
TrySpellProc(weapon_g, weapon_g->GetItem(), on, hand);
|
||||
|
||||
|
||||
//we have to calculate these again, oh well
|
||||
int ourlevel = GetLevel();
|
||||
float ProcChance, ProcBonus;
|
||||
GetProcChances(ProcBonus, ProcChance, weapon_g->GetItem()->Delay, hand);
|
||||
if(hand != 13)
|
||||
{
|
||||
ProcChance /= 2;
|
||||
}
|
||||
|
||||
//do augment procs
|
||||
int r;
|
||||
for(r = 0; r < MAX_AUGMENT_SLOTS; r++) {
|
||||
const ItemInst* aug_i = weapon_g->GetAugment(r);
|
||||
if(!aug_i)
|
||||
continue;
|
||||
const Item_Struct* aug = aug_i->GetItem();
|
||||
if(!aug)
|
||||
continue;
|
||||
|
||||
if (aug->Proc.Type == ET_CombatProc) {
|
||||
ProcChance = ProcChance*(100+aug->ProcRate)/100;
|
||||
if (MakeRandomFloat(0, 1) < ProcChance) {
|
||||
if(aug->Proc.Level > ourlevel) {
|
||||
Mob * own = GetOwner();
|
||||
if(own != nullptr) {
|
||||
own->Message_StringID(13,PROC_PETTOOLOW);
|
||||
} else {
|
||||
Message_StringID(13,PROC_TOOLOW);
|
||||
}
|
||||
} else {
|
||||
ExecWeaponProc(aug_i, aug->Proc.Effect, on);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct* weapon, Mob *on, uint16 hand) {
|
||||
void Mob::TryWeaponProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, uint16 hand)
|
||||
{
|
||||
if (!weapon)
|
||||
return;
|
||||
uint16 skillinuse = 28;
|
||||
int ourlevel = GetLevel();
|
||||
float ProcChance, ProcBonus;
|
||||
if(weapon!=nullptr)
|
||||
GetProcChances(ProcBonus, ProcChance, weapon->Delay, hand);
|
||||
else
|
||||
GetProcChances(ProcBonus, ProcChance);
|
||||
float ProcBonus = static_cast<float>(aabonuses.ProcChanceSPA +
|
||||
spellbonuses.ProcChanceSPA + itembonuses.ProcChanceSPA);
|
||||
ProcBonus += static_cast<float>(itembonuses.ProcChance) / 10.0f; // Combat Effects
|
||||
float ProcChance = GetProcChances(ProcBonus, weapon->Delay, hand);
|
||||
|
||||
if(hand != 13) //Is Archery intended to proc at 50% rate?
|
||||
if (hand != 13) //Is Archery intened to proc at 50% rate?
|
||||
ProcChance /= 2;
|
||||
|
||||
//give weapon a chance to proc first.
|
||||
if(weapon != nullptr) {
|
||||
skillinuse = GetSkillByItemType(weapon->ItemType);
|
||||
if (weapon->Proc.Type == ET_CombatProc) {
|
||||
float WPC = ProcChance*(100.0f+(float)weapon->ProcRate)/100.0f;
|
||||
if (MakeRandomFloat(0, 1) <= WPC) { // 255 dex = 0.084 chance of proc. No idea what this number should be really.
|
||||
if(weapon->Proc.Level > ourlevel) {
|
||||
mlog(COMBAT__PROCS, "Tried to proc (%s), but our level (%d) is lower than required (%d)", weapon->Name, ourlevel, weapon->Proc.Level);
|
||||
Mob * own = GetOwner();
|
||||
if(own != nullptr) {
|
||||
own->Message_StringID(13,PROC_PETTOOLOW);
|
||||
} else {
|
||||
Message_StringID(13,PROC_TOOLOW);
|
||||
}
|
||||
// Try innate proc on weapon
|
||||
// We can proc once here, either weapon or one aug
|
||||
bool proced = false; // silly bool to prevent augs from going if weapon does
|
||||
skillinuse = GetSkillByItemType(weapon->ItemType);
|
||||
if (weapon->Proc.Type == ET_CombatProc) {
|
||||
float WPC = ProcChance * (100.0f + // Proc chance for this weapon
|
||||
static_cast<float>(weapon->ProcRate)) / 100.0f;
|
||||
if (MakeRandomFloat(0, 1) <= WPC) { // 255 dex = 0.084 chance of proc. No idea what this number should be really.
|
||||
if (weapon->Proc.Level > ourlevel) {
|
||||
mlog(COMBAT__PROCS,
|
||||
"Tried to proc (%s), but our level (%d) is lower than required (%d)",
|
||||
weapon->Name, ourlevel, weapon->Proc.Level);
|
||||
if (IsPet()) {
|
||||
Mob *own = GetOwner();
|
||||
if (own)
|
||||
own->Message_StringID(13, PROC_PETTOOLOW);
|
||||
} else {
|
||||
mlog(COMBAT__PROCS, "Attacking weapon (%s) successfully procing spell %d (%.2f percent chance)", weapon->Name, weapon->Proc.Effect, ProcChance*100);
|
||||
ExecWeaponProc(inst, weapon->Proc.Effect, on);
|
||||
Message_StringID(13, PROC_TOOLOW);
|
||||
}
|
||||
} else {
|
||||
mlog(COMBAT__PROCS, "Attacking weapon (%s) did no proc (%.2f percent chance).", weapon->Name, ProcChance*100);
|
||||
mlog(COMBAT__PROCS,
|
||||
"Attacking weapon (%s) successfully procing spell %d (%.2f percent chance)",
|
||||
weapon->Name, weapon->Proc.Effect, WPC * 100);
|
||||
ExecWeaponProc(inst, weapon->Proc.Effect, on);
|
||||
proced = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ProcBonus == -1) {
|
||||
LogFile->write(EQEMuLog::Error, "ProcBonus was -1 value!");
|
||||
return;
|
||||
}
|
||||
if (!proced && inst) {
|
||||
for (int r = 0; r < MAX_AUGMENT_SLOTS; r++) {
|
||||
const ItemInst *aug_i = inst->GetAugment(r);
|
||||
if (!aug_i) // no aug, try next slot!
|
||||
continue;
|
||||
const Item_Struct *aug = aug_i->GetItem();
|
||||
if (!aug)
|
||||
continue;
|
||||
|
||||
bool bRangedAttack = false;
|
||||
if (weapon != nullptr) {
|
||||
if (weapon->ItemType == ItemTypeBow || weapon->ItemType == ItemTypeLargeThrowing || weapon->ItemType == ItemTypeSmallThrowing) {
|
||||
bRangedAttack = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool isRanged = false;
|
||||
if(weapon)
|
||||
{
|
||||
if(weapon->ItemType == ItemTypeArrow ||
|
||||
weapon->ItemType == ItemTypeLargeThrowing ||
|
||||
weapon->ItemType == ItemTypeSmallThrowing ||
|
||||
weapon->ItemType == ItemTypeBow)
|
||||
{
|
||||
isRanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 i;
|
||||
for(i = 0; i < MAX_PROCS; i++) {
|
||||
if (PermaProcs[i].spellID != SPELL_UNKNOWN) {
|
||||
if(MakeRandomInt(0, 100) < PermaProcs[i].chance) {
|
||||
mlog(COMBAT__PROCS, "Permanent proc %d procing spell %d (%d percent chance)", i, PermaProcs[i].spellID, PermaProcs[i].chance);
|
||||
ExecWeaponProc(nullptr, PermaProcs[i].spellID, on);
|
||||
} else {
|
||||
mlog(COMBAT__PROCS, "Permanent proc %d failed to proc %d (%d percent chance)", i, PermaProcs[i].spellID, PermaProcs[i].chance);
|
||||
if (aug->Proc.Type == ET_CombatProc) {
|
||||
float APC = ProcChance * (100.0f + // Proc chance for this aug
|
||||
static_cast<float>(aug->ProcRate)) / 100.0f;
|
||||
if (MakeRandomFloat(0, 1) <= APC) {
|
||||
if (aug->Proc.Level > ourlevel) {
|
||||
if (IsPet()) {
|
||||
Mob *own = GetOwner();
|
||||
if (own)
|
||||
own->Message_StringID(13, PROC_PETTOOLOW);
|
||||
} else {
|
||||
Message_StringID(13, PROC_TOOLOW);
|
||||
}
|
||||
} else {
|
||||
ExecWeaponProc(aug_i, aug->Proc.Effect, on);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Powersource procs
|
||||
if (HasSkillProcs())
|
||||
TrySkillProc(on, skillinuse, ProcChance);
|
||||
|
||||
if(!isRanged)
|
||||
{
|
||||
if(IsPet() && hand != 13) //Pets can only proc spell procs from their primay hand (ie; beastlord pets)
|
||||
{
|
||||
//Maybe implement this later if pets are ever given dual procs?
|
||||
return;
|
||||
}
|
||||
|
||||
void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, uint16 hand)
|
||||
{
|
||||
float ProcBonus = static_cast<float>(spellbonuses.SpellProcChance +
|
||||
itembonuses.SpellProcChance + aabonuses.SpellProcChance);
|
||||
float ProcChance = 0.0f;
|
||||
if (weapon)
|
||||
ProcChance = GetProcChances(ProcBonus, weapon->Delay, hand);
|
||||
else
|
||||
ProcChance = GetProcChances(ProcBonus);
|
||||
|
||||
if (hand != 13) //Is Archery intened to proc at 50% rate?
|
||||
ProcChance /= 2;
|
||||
|
||||
bool rangedattk = false;
|
||||
if (weapon && hand == 11) {
|
||||
if (weapon->ItemType == ItemTypeArrow ||
|
||||
weapon->ItemType == ItemTypeLargeThrowing ||
|
||||
weapon->ItemType == ItemTypeSmallThrowing ||
|
||||
weapon->ItemType == ItemTypeBow)
|
||||
rangedattk = true;
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < MAX_PROCS; i++) {
|
||||
if (IsPet() && hand != 13) //Pets can only proc spell procs from their primay hand (ie; beastlord pets)
|
||||
continue; // If pets ever can proc from off hand, this will need to change
|
||||
|
||||
// Not ranged
|
||||
if (!rangedattk) {
|
||||
// Perma procs (AAs)
|
||||
if (PermaProcs[i].spellID != SPELL_UNKNOWN) {
|
||||
if (MakeRandomInt(0, 99) < PermaProcs[i].chance) { // TODO: Do these get spell bonus?
|
||||
mlog(COMBAT__PROCS,
|
||||
"Permanent proc %d procing spell %d (%d percent chance)",
|
||||
i, PermaProcs[i].spellID, PermaProcs[i].chance);
|
||||
ExecWeaponProc(nullptr, PermaProcs[i].spellID, on);
|
||||
} else {
|
||||
mlog(COMBAT__PROCS,
|
||||
"Permanent proc %d failed to proc %d (%d percent chance)",
|
||||
i, PermaProcs[i].spellID, PermaProcs[i].chance);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int chance = ProcChance * (SpellProcs[i].chance);
|
||||
if(MakeRandomInt(0, 100) < chance) {
|
||||
mlog(COMBAT__PROCS, "Spell proc %d procing spell %d (%d percent chance)", i, SpellProcs[i].spellID, chance);
|
||||
|
||||
// Spell procs (buffs)
|
||||
if (SpellProcs[i].spellID != SPELL_UNKNOWN) {
|
||||
float chance = ProcChance * (SpellProcs[i].chance / 100.0f);
|
||||
if (MakeRandomFloat(0, 1) <= chance) {
|
||||
mlog(COMBAT__PROCS,
|
||||
"Spell proc %d procing spell %d (%.2f percent chance)",
|
||||
i, SpellProcs[i].spellID, chance);
|
||||
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on);
|
||||
CheckNumHitsRemaining(11, 0, SpellProcs[i].base_spellID);
|
||||
} else {
|
||||
mlog(COMBAT__PROCS, "Spell proc %d failed to proc %d (%d percent chance)", i, SpellProcs[i].spellID, chance);
|
||||
mlog(COMBAT__PROCS,
|
||||
"Spell proc %d failed to proc %d (%.2f percent chance)",
|
||||
i, SpellProcs[i].spellID, chance);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bRangedAttack) {
|
||||
int chance = ProcChance * RangedProcs[i].chance;
|
||||
if(MakeRandomInt(0, 100) < chance) {
|
||||
mlog(COMBAT__PROCS, "Ranged proc %d procing spell %d", i, RangedProcs[i].spellID, RangedProcs[i].chance);
|
||||
ExecWeaponProc(nullptr, RangedProcs[i].spellID, on);
|
||||
CheckNumHitsRemaining(11, 0, RangedProcs[i].base_spellID);
|
||||
} else {
|
||||
mlog(COMBAT__PROCS, "Ranged proc %d failed to proc %d", i, RangedProcs[i].spellID, RangedProcs[i].chance);
|
||||
} else if (rangedattk) { // ranged only
|
||||
// ranged spell procs (buffs)
|
||||
if (RangedProcs[i].spellID != SPELL_UNKNOWN) {
|
||||
float chance = ProcChance * (RangedProcs[i].chance / 100.0f);
|
||||
if (MakeRandomFloat(0, 1) <= chance) {
|
||||
mlog(COMBAT__PROCS,
|
||||
"Ranged proc %d procing spell %d (%.2f percent chance)",
|
||||
i, RangedProcs[i].spellID, chance);
|
||||
ExecWeaponProc(nullptr, RangedProcs[i].spellID, on);
|
||||
CheckNumHitsRemaining(11, 0, RangedProcs[i].base_spellID);
|
||||
} else {
|
||||
mlog(COMBAT__PROCS,
|
||||
"Ranged proc %d failed to proc %d (%.2f percent chance)",
|
||||
i, RangedProcs[i].spellID, chance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HasSkillProcs())
|
||||
TrySkillProc(on, skillinuse, ProcChance);
|
||||
return;
|
||||
}
|
||||
|
||||
void Mob::TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage)
|
||||
|
||||
@ -963,7 +963,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
newbon->GiveDoubleAttack += base1;
|
||||
break;
|
||||
case SE_ProcChance:
|
||||
newbon->ProcChance += base1;
|
||||
newbon->ProcChanceSPA += base1;
|
||||
break;
|
||||
case SE_RiposteChance:
|
||||
newbon->RiposteChance += base1;
|
||||
@ -1228,6 +1228,14 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_FrenziedDevastation:
|
||||
newbon->FrenziedDevastation += base2;
|
||||
break;
|
||||
|
||||
case SE_SpellProcChance:
|
||||
newbon->SpellProcChance += base1;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1882,17 +1890,14 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_ProcChance:
|
||||
{
|
||||
//multiplier is to be compatible with item effects,watching for overflow too
|
||||
effect_value = effect_value<3000? effect_value : 3000;
|
||||
|
||||
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||
newbon->ProcChance += effect_value;
|
||||
newbon->ProcChanceSPA += effect_value;
|
||||
|
||||
else if((effect_value < 0) && (newbon->DoubleAttackChance > effect_value))
|
||||
newbon->ProcChance = effect_value;
|
||||
else if((effect_value < 0) && (newbon->ProcChanceSPA > effect_value))
|
||||
newbon->ProcChanceSPA = effect_value;
|
||||
|
||||
if(newbon->ProcChance < effect_value)
|
||||
newbon->ProcChance = effect_value;
|
||||
if(newbon->ProcChanceSPA < effect_value)
|
||||
newbon->ProcChanceSPA = effect_value;
|
||||
|
||||
break;
|
||||
}
|
||||
@ -2524,6 +2529,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
newbon->DistanceRemoval = true;
|
||||
break;
|
||||
|
||||
case SE_FrenziedDevastation:
|
||||
newbon->FrenziedDevastation += spells[spell_id].base2[i];
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3311,9 +3320,9 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
break;
|
||||
|
||||
case SE_ProcChance:
|
||||
spellbonuses.ProcChance = effect_value;
|
||||
aabonuses.ProcChance = effect_value;
|
||||
itembonuses.ProcChance = effect_value;
|
||||
spellbonuses.ProcChanceSPA = effect_value;
|
||||
aabonuses.ProcChanceSPA = effect_value;
|
||||
itembonuses.ProcChanceSPA = effect_value;
|
||||
break;
|
||||
|
||||
case SE_ExtraAttackChance:
|
||||
@ -3866,7 +3875,13 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
spellbonuses.ImprovedTaunt[0] = effect_value;
|
||||
spellbonuses.ImprovedTaunt[1] = effect_value;
|
||||
spellbonuses.ImprovedTaunt[2] = -1;
|
||||
|
||||
break;
|
||||
|
||||
case SE_FrenziedDevastation:
|
||||
spellbonuses.FrenziedDevastation += effect_value;
|
||||
aabonuses.FrenziedDevastation += effect_value;
|
||||
itembonuses.FrenziedDevastation += effect_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
37
zone/bot.cpp
37
zone/bot.cpp
@ -7705,16 +7705,11 @@ int16 Bot::CalcBotFocusEffect(BotfocusType bottype, uint16 focus_id, uint16 spel
|
||||
}
|
||||
|
||||
//proc chance includes proc bonus
|
||||
float Bot::GetProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_speed, uint16 hand) {
|
||||
float Bot::GetProcChances(float ProcBonus, uint16 weapon_speed, uint16 hand) {
|
||||
int mydex = GetDEX();
|
||||
float AABonus = 0;
|
||||
ProcBonus = 0;
|
||||
ProcChance = 0;
|
||||
float ProcChance = 0.0f;
|
||||
|
||||
if (aabonuses.ProcChance)
|
||||
AABonus = float(aabonuses.ProcChance) / 100.0f;
|
||||
|
||||
switch(hand){
|
||||
switch (hand) {
|
||||
case SLOT_PRIMARY:
|
||||
weapon_speed = attack_timer.GetDuration();
|
||||
break;
|
||||
@ -7726,24 +7721,20 @@ float Bot::GetProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_spe
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//calculate the weapon speed in ms, so we can use the rule to compare against.
|
||||
|
||||
if(weapon_speed < RuleI(Combat, MinHastedDelay)) // fast as a client can swing, so should be the floor of the proc chance
|
||||
// fast as a client can swing, so should be the floor of the proc chance
|
||||
if (weapon_speed < RuleI(Combat, MinHastedDelay))
|
||||
weapon_speed = RuleI(Combat, MinHastedDelay);
|
||||
|
||||
ProcBonus += (float(itembonuses.ProcChance + spellbonuses.ProcChance) / 1000.0f + AABonus);
|
||||
|
||||
if(RuleB(Combat, AdjustProcPerMinute) == true)
|
||||
{
|
||||
ProcChance = ((float)weapon_speed * RuleR(Combat, AvgProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms
|
||||
ProcBonus += float(mydex) * RuleR(Combat, ProcPerMinDexContrib) / 100.0f;
|
||||
ProcChance = ProcChance + (ProcChance * ProcBonus);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcChance = RuleR(Combat, BaseProcChance) + float(mydex) / RuleR(Combat, ProcDexDivideBy);
|
||||
ProcChance = ProcChance + (ProcChance * ProcBonus);
|
||||
if (RuleB(Combat, AdjustProcPerMinute)) {
|
||||
ProcChance = (static_cast<float>(weapon_speed) *
|
||||
RuleR(Combat, AvgProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms
|
||||
ProcBonus += static_cast<float>(mydex) * RuleR(Combat, ProcPerMinDexContrib);
|
||||
ProcChance += ProcChance * ProcBonus / 100.0f;
|
||||
} else {
|
||||
ProcChance = RuleR(Combat, BaseProcChance) +
|
||||
static_cast<float>(mydex) / RuleR(Combat, ProcDexDivideBy);
|
||||
ProcChance += ProcChance*ProcBonus / 100.0f;
|
||||
}
|
||||
|
||||
mlog(COMBAT__PROCS, "Proc chance %.2f (%.2f from bonuses)", ProcChance, ProcBonus);
|
||||
|
||||
@ -167,7 +167,7 @@ public:
|
||||
uint16 BotGetSpells(int spellslot) { return AIspells[spellslot].spellid; }
|
||||
uint16 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; }
|
||||
uint16 BotGetSpellPriority(int spellslot) { return AIspells[spellslot].priority; }
|
||||
virtual float GetProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_speed, uint16 hand);
|
||||
virtual float GetProcChances(float ProcBonus, uint16 weapon_speed, uint16 hand);
|
||||
virtual bool AvoidDamage(Mob* other, int32 &damage, bool CanRiposte);
|
||||
virtual int GetMonkHandToHandDamage(void);
|
||||
virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse);
|
||||
|
||||
@ -2963,6 +2963,101 @@ void Client::Message_StringID(uint32 type, uint32 string_id, const char* message
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
// helper function, returns true if we should see the message
|
||||
bool Client::FilteredMessageCheck(Mob *sender, eqFilterType filter)
|
||||
{
|
||||
eqFilterMode mode = GetFilter(filter);
|
||||
// easy ones first
|
||||
if (mode == FilterShow)
|
||||
return true;
|
||||
else if (mode == FilterHide)
|
||||
return false;
|
||||
|
||||
if (!sender && mode == FilterHide) {
|
||||
return false;
|
||||
} else if (sender) {
|
||||
if (this == sender) {
|
||||
if (mode == FilterHide) // don't need to check others
|
||||
return false;
|
||||
} else if (mode == FilterShowSelfOnly) { // we know sender isn't us
|
||||
return false;
|
||||
} else if (mode == FilterShowGroupOnly) {
|
||||
Group *g = GetGroup();
|
||||
if (!g || !g->IsGroupMember(sender))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// we passed our checks
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::FilteredMessage_StringID(Mob *sender, uint32 type,
|
||||
eqFilterType filter, uint32 string_id)
|
||||
{
|
||||
if (!FilteredMessageCheck(sender, filter))
|
||||
return;
|
||||
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_SimpleMessage, 12);
|
||||
SimpleMessage_Struct *sms = (SimpleMessage_Struct *)outapp->pBuffer;
|
||||
sms->color = type;
|
||||
sms->string_id = string_id;
|
||||
|
||||
sms->unknown8 = 0;
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::FilteredMessage_StringID(Mob *sender, uint32 type, eqFilterType filter, uint32 string_id,
|
||||
const char *message1, const char *message2, const char *message3,
|
||||
const char *message4, const char *message5, const char *message6,
|
||||
const char *message7, const char *message8, const char *message9)
|
||||
{
|
||||
if (!FilteredMessageCheck(sender, filter))
|
||||
return;
|
||||
|
||||
int i, argcount, length;
|
||||
char *bufptr;
|
||||
const char *message_arg[9] = {0};
|
||||
|
||||
if (type == MT_Emote)
|
||||
type = 4;
|
||||
|
||||
if (!message1) {
|
||||
Message_StringID(type, string_id); // use the simple message instead
|
||||
return;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
message_arg[i++] = message1;
|
||||
message_arg[i++] = message2;
|
||||
message_arg[i++] = message3;
|
||||
message_arg[i++] = message4;
|
||||
message_arg[i++] = message5;
|
||||
message_arg[i++] = message6;
|
||||
message_arg[i++] = message7;
|
||||
message_arg[i++] = message8;
|
||||
message_arg[i++] = message9;
|
||||
|
||||
for (argcount = length = 0; message_arg[argcount]; argcount++)
|
||||
length += strlen(message_arg[argcount]) + 1;
|
||||
|
||||
EQApplicationPacket *outapp = new EQApplicationPacket(OP_FormattedMessage, length+13);
|
||||
FormattedMessage_Struct *fm = (FormattedMessage_Struct *)outapp->pBuffer;
|
||||
fm->string_id = string_id;
|
||||
fm->type = type;
|
||||
bufptr = fm->message;
|
||||
for (i = 0; i < argcount; i++) {
|
||||
strcpy(bufptr, message_arg[i]);
|
||||
bufptr += strlen(message_arg[i]) + 1;
|
||||
}
|
||||
|
||||
QueuePacket(outapp);
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
void Client::SetTint(int16 in_slot, uint32 color) {
|
||||
Color_Struct new_color;
|
||||
|
||||
@ -250,6 +250,14 @@ public:
|
||||
uint8 SlotConvert(uint8 slot,bool bracer=false);
|
||||
void Message_StringID(uint32 type, uint32 string_id, uint32 distance = 0);
|
||||
void Message_StringID(uint32 type, uint32 string_id, const char* message,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0, uint32 distance = 0);
|
||||
bool FilteredMessageCheck(Mob *sender, eqFilterType filter);
|
||||
void FilteredMessage_StringID(Mob *sender, uint32 type, eqFilterType filter, uint32 string_id);
|
||||
void FilteredMessage_StringID(Mob *sender, uint32 type, eqFilterType filter,
|
||||
uint32 string_id, const char *message1, const char *message2 = nullptr,
|
||||
const char *message3 = nullptr, const char *message4 = nullptr,
|
||||
const char *message5 = nullptr, const char *message6 = nullptr,
|
||||
const char *message7 = nullptr, const char *message8 = nullptr,
|
||||
const char *message9 = nullptr);
|
||||
void SendBazaarResults(uint32 trader_id,uint32 class_,uint32 race,uint32 stat,uint32 slot,uint32 type,char name[64],uint32 minprice,uint32 maxprice);
|
||||
void SendTraderItem(uint32 item_id,uint16 quantity);
|
||||
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
|
||||
|
||||
@ -1615,7 +1615,8 @@ void Client::Handle_OP_Shielding(const EQApplicationPacket *app)
|
||||
|
||||
if (shield_target)
|
||||
{
|
||||
entity_list.MessageClose(this,false,100,0,"%s ceases shielding %s.",GetName(),shield_target->GetName());
|
||||
entity_list.MessageClose_StringID(this, false, 100, 0,
|
||||
END_SHIELDING, GetName(), shield_target->GetName());
|
||||
for (int y = 0; y < 2; y++)
|
||||
{
|
||||
if (shield_target->shielder[y].shielder_id == GetID())
|
||||
@ -1640,7 +1641,8 @@ void Client::Handle_OP_Shielding(const EQApplicationPacket *app)
|
||||
{
|
||||
if (shield_target->shielder[x].shielder_id == 0)
|
||||
{
|
||||
entity_list.MessageClose(this,false,100,0,"%s uses their shield to guard %s.",GetName(),shield_target->GetName());
|
||||
entity_list.MessageClose_StringID(this ,false, 100, 0,
|
||||
START_SHIELDING, GetName(), shield_target->GetName());
|
||||
shield_target->shielder[x].shielder_id = GetID();
|
||||
int shieldbonus = shield->AC*2;
|
||||
switch (GetAA(197))
|
||||
@ -1677,7 +1679,7 @@ void Client::Handle_OP_Shielding(const EQApplicationPacket *app)
|
||||
}
|
||||
if (!ack)
|
||||
{
|
||||
Message(0, "No more than two warriors may shield the same being.");
|
||||
Message_StringID(0, ALREADY_SHIELDED);
|
||||
shield_target = 0;
|
||||
return;
|
||||
}
|
||||
@ -12618,32 +12620,38 @@ void Client::Handle_OP_AltCurrencySellSelection(const EQApplicationPacket *app)
|
||||
uint32 cost = 0;
|
||||
uint32 current_currency = GetAlternateCurrencyValue(alt_cur_id);
|
||||
uint32 merchant_id = tar->MerchantType;
|
||||
bool found = false;
|
||||
std::list<MerchantList> merlist = zone->merchanttable[merchant_id];
|
||||
std::list<MerchantList>::const_iterator itr;
|
||||
for(itr = merlist.begin(); itr != merlist.end(); ++itr) {
|
||||
MerchantList ml = *itr;
|
||||
if(GetLevel() < ml.level_required) {
|
||||
continue;
|
||||
|
||||
if (RuleB(Merchant, EnableAltCurrencySell)) {
|
||||
bool found = false;
|
||||
std::list<MerchantList> merlist = zone->merchanttable[merchant_id];
|
||||
std::list<MerchantList>::const_iterator itr;
|
||||
for (itr = merlist.begin(); itr != merlist.end(); ++itr) {
|
||||
MerchantList ml = *itr;
|
||||
if (GetLevel() < ml.level_required) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int32 fac = tar->GetPrimaryFaction();
|
||||
if (fac != 0 && GetModCharacterFactionLevel(fac) < ml.faction_required) {
|
||||
continue;
|
||||
}
|
||||
|
||||
item = database.GetItem(ml.item);
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
if (item->ID == inst->GetItem()->ID) {
|
||||
cost = ml.alt_currency_cost;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int32 fac = tar->GetPrimaryFaction();
|
||||
if(fac != 0 && GetModCharacterFactionLevel(fac) < ml.faction_required) {
|
||||
continue;
|
||||
}
|
||||
|
||||
item = database.GetItem(ml.item);
|
||||
if(!item)
|
||||
continue;
|
||||
|
||||
if(item->ID == inst->GetItem()->ID) {
|
||||
cost = ml.alt_currency_cost;
|
||||
found = true;
|
||||
break;
|
||||
if (!found) {
|
||||
cost = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
else {
|
||||
cost = 0;
|
||||
}
|
||||
|
||||
@ -12793,6 +12801,10 @@ void Client::Handle_OP_AltCurrencySell(const EQApplicationPacket *app) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!RuleB(Merchant, EnableAltCurrencySell)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Item_Struct* item = nullptr;
|
||||
uint32 cost = 0;
|
||||
uint32 current_currency = GetAlternateCurrencyValue(alt_cur_id);
|
||||
@ -12815,7 +12827,7 @@ void Client::Handle_OP_AltCurrencySell(const EQApplicationPacket *app) {
|
||||
if(!item)
|
||||
continue;
|
||||
|
||||
if(item->ID == inst->GetItem()->ID) {
|
||||
if(item->ID == inst->GetItem()->ID) {
|
||||
cost = ml.alt_currency_cost;
|
||||
found = true;
|
||||
break;
|
||||
|
||||
@ -581,7 +581,8 @@ bool Client::Process() {
|
||||
{
|
||||
if (!CombatRange(shield_target))
|
||||
{
|
||||
entity_list.MessageClose(this,false,100,0,"%s ceases shielding %s.",GetCleanName(),shield_target->GetCleanName());
|
||||
entity_list.MessageClose_StringID(this, false, 100, 0,
|
||||
END_SHIELDING, GetCleanName(), shield_target->GetCleanName());
|
||||
for (int y = 0; y < 2; y++)
|
||||
{
|
||||
if (shield_target->shielder[y].shielder_id == GetID())
|
||||
|
||||
@ -2085,21 +2085,27 @@ void command_ai(Client *c, const Seperator *sep)
|
||||
}
|
||||
else if (strcasecmp(sep->arg[1], "roambox") == 0) {
|
||||
if (target && target->IsAIControlled() && target->IsNPC()) {
|
||||
if ((sep->argnum == 6 || sep->argnum == 7) && sep->IsNumber(2) && sep->IsNumber(3) && sep->IsNumber(4) && sep->IsNumber(5) && sep->IsNumber(6)) {
|
||||
if ((sep->argnum == 6 || sep->argnum == 7 || sep->argnum == 8) && sep->IsNumber(2) && sep->IsNumber(3) && sep->IsNumber(4) && sep->IsNumber(5) && sep->IsNumber(6)) {
|
||||
uint32 tmp = 2500;
|
||||
uint32 tmp2 = 2500;
|
||||
if (sep->IsNumber(7))
|
||||
tmp = atoi(sep->arg[7]);
|
||||
target->CastToNPC()->AI_SetRoambox(atof(sep->arg[2]), atof(sep->arg[3]), atof(sep->arg[4]), atof(sep->arg[5]), atof(sep->arg[6]), tmp);
|
||||
if (sep->IsNumber(8))
|
||||
tmp2 = atoi(sep->arg[8]);
|
||||
target->CastToNPC()->AI_SetRoambox(atof(sep->arg[2]), atof(sep->arg[3]), atof(sep->arg[4]), atof(sep->arg[5]), atof(sep->arg[6]), tmp, tmp2);
|
||||
}
|
||||
else if ((sep->argnum == 3 || sep->argnum == 4) && sep->IsNumber(2) && sep->IsNumber(3)) {
|
||||
uint32 tmp = 2500;
|
||||
uint32 tmp2 = 2500;
|
||||
if (sep->IsNumber(4))
|
||||
tmp = atoi(sep->arg[4]);
|
||||
target->CastToNPC()->AI_SetRoambox(atof(sep->arg[2]), atof(sep->arg[3]), tmp);
|
||||
if (sep->IsNumber(5))
|
||||
tmp2 = atoi(sep->arg[5]);
|
||||
target->CastToNPC()->AI_SetRoambox(atof(sep->arg[2]), atof(sep->arg[3]), tmp, tmp2);
|
||||
}
|
||||
else {
|
||||
c->Message(0, "Usage: #ai roambox dist max_x min_x max_y min_y [delay]");
|
||||
c->Message(0, "Usage: #ai roambox dist roamdist [delay]");
|
||||
c->Message(0, "Usage: #ai roambox dist max_x min_x max_y min_y [delay] [mindelay]");
|
||||
c->Message(0, "Usage: #ai roambox dist roamdist [delay] [mindelay]");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@ -122,7 +122,10 @@ enum {
|
||||
TETHER = 33,
|
||||
DESTRUCTIBLE_OBJECT = 34,
|
||||
NO_HARM_FROM_CLIENT = 35,
|
||||
MAX_SPECIAL_ATTACK = 36
|
||||
ALWAYS_FLEE = 36,
|
||||
FLEE_PERCENT = 37,
|
||||
MAX_SPECIAL_ATTACK = 38
|
||||
|
||||
};
|
||||
|
||||
typedef enum { //fear states
|
||||
@ -274,6 +277,7 @@ struct StatBonuses {
|
||||
int16 DamageModifier[HIGHEST_SKILL+2]; //i
|
||||
int16 MinDamageModifier[HIGHEST_SKILL+2]; //i
|
||||
int16 ProcChance; // ProcChance/10 == % increase i = CombatEffects
|
||||
int16 ProcChanceSPA; // ProcChance from spell effects
|
||||
int16 ExtraAttackChance;
|
||||
int16 DoTShielding;
|
||||
int16 DivineSaveChance[2]; // Second Chance (base1 = chance, base2 = spell on trigger)
|
||||
@ -311,8 +315,8 @@ struct StatBonuses {
|
||||
//uint16 BlockSpellEffect[EFFECT_COUNT]; // Prevents spells with certain effects from landing on you *no longer used
|
||||
bool ImmuneToFlee; // Bypass the fleeing flag
|
||||
uint16 VoiceGraft; // Stores the ID of the mob with which to talk through
|
||||
uint16 SpellProcChance; // chance to proc from sympathetic spell effects
|
||||
uint16 CharmBreakChance; // chance to break charm
|
||||
int16 SpellProcChance; // chance to proc from sympathetic spell effects
|
||||
int16 CharmBreakChance; // chance to break charm
|
||||
int16 SongRange; // increases range of beneficial bard songs
|
||||
uint16 HPToManaConvert; // Uses HP to cast spells at specific conversion
|
||||
uint16 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have.
|
||||
@ -335,6 +339,7 @@ struct StatBonuses {
|
||||
bool DivineAura; // invulnerability
|
||||
bool DistanceRemoval; // Check if Cancle if Moved effect is present
|
||||
int16 ImprovedTaunt[3]; // 0 = Max Level 1 = Aggro modifier 2 = buffid
|
||||
int16 FrenziedDevastation; // base1= AArank(used) base2= chance increase spell criticals + all DD spells 2x mana.
|
||||
//bool AbsorbMagicAtt; // Magic Rune *Need to be implemented for NegateEffect
|
||||
//bool MeleeRune; // Melee Rune *Need to be implemented for NegateEffect
|
||||
|
||||
|
||||
117
zone/effects.cpp
117
zone/effects.cpp
@ -62,7 +62,7 @@ int32 NPC::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
}
|
||||
|
||||
int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
|
||||
if (spells[spell_id].targettype == ST_Self)
|
||||
return value;
|
||||
|
||||
@ -74,22 +74,24 @@ int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
// Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40.
|
||||
if ( (spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) && GetLevel() > 40)
|
||||
value -= (GetLevel() - 40) * 20;
|
||||
|
||||
|
||||
//This adds the extra damage from the AA Unholy Touch, 450 per level to the AA Improved Harm TOuch.
|
||||
if (spell_id == SPELL_IMP_HARM_TOUCH) //Improved Harm Touch
|
||||
value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch
|
||||
|
||||
|
||||
int chance = RuleI(Spells, BaseCritChance);
|
||||
chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
|
||||
|
||||
|
||||
chance += itembonuses.FrenziedDevastation + spellbonuses.FrenziedDevastation + aabonuses.FrenziedDevastation;
|
||||
|
||||
if (chance > 0){
|
||||
|
||||
|
||||
int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals.
|
||||
|
||||
//Improved Harm Touch is a guaranteed crit if you have at least one level of SCF.
|
||||
if (spell_id == SPELL_IMP_HARM_TOUCH && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0))
|
||||
chance = 100;
|
||||
|
||||
|
||||
if (MakeRandomInt(1,100) <= chance){
|
||||
Critical = true;
|
||||
ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;
|
||||
@ -102,53 +104,55 @@ int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
}
|
||||
|
||||
ratio += RuleI(Spells, WizCritRatio); //Default is zero
|
||||
|
||||
|
||||
if (Critical){
|
||||
|
||||
value = value_BaseEffect*ratio/100;
|
||||
value = value_BaseEffect*ratio/100;
|
||||
|
||||
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
|
||||
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
|
||||
|
||||
value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
|
||||
|
||||
if (target) {
|
||||
value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
|
||||
value -= target->GetFcDamageAmtIncoming(this, spell_id);
|
||||
value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
|
||||
value -= target->GetFcDamageAmtIncoming(this, spell_id);
|
||||
}
|
||||
|
||||
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100;
|
||||
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100;
|
||||
|
||||
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
|
||||
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
|
||||
|
||||
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100;
|
||||
|
||||
entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), -value);
|
||||
entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits,
|
||||
OTHER_CRIT_BLAST, GetName(), itoa(-value));
|
||||
Message_StringID(MT_SpellCrits, YOU_CRIT_BLAST, itoa(-value));
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
value = value_BaseEffect;
|
||||
|
||||
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
|
||||
|
||||
value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
|
||||
value = value_BaseEffect;
|
||||
|
||||
if (target) {
|
||||
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
|
||||
|
||||
value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
|
||||
|
||||
if (target) {
|
||||
value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100;
|
||||
value -= target->GetFcDamageAmtIncoming(this, spell_id);
|
||||
}
|
||||
value -= target->GetFcDamageAmtIncoming(this, spell_id);
|
||||
}
|
||||
|
||||
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id);
|
||||
value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id);
|
||||
|
||||
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
|
||||
|
||||
value -= GetFocusEffect(focusFcDamageAmt, spell_id);
|
||||
|
||||
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value);
|
||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
@ -255,7 +259,7 @@ int32 NPC::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
||||
}
|
||||
|
||||
int32 Client::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
|
||||
if (target == nullptr)
|
||||
target = this;
|
||||
|
||||
@ -263,54 +267,57 @@ int32 Client::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
||||
int16 chance = 0;
|
||||
int8 modifier = 1;
|
||||
bool Critical = false;
|
||||
|
||||
value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);
|
||||
|
||||
|
||||
value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);
|
||||
|
||||
value = value_BaseEffect;
|
||||
|
||||
value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id)/100);
|
||||
|
||||
value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id)/100);
|
||||
|
||||
// Instant Heals
|
||||
if(spells[spell_id].buffduration < 1) {
|
||||
|
||||
chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance;
|
||||
chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance;
|
||||
|
||||
chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);
|
||||
|
||||
chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);
|
||||
|
||||
if (spellbonuses.CriticalHealDecay)
|
||||
chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay);
|
||||
|
||||
chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay);
|
||||
|
||||
if(chance && (MakeRandomInt(0,99) < chance)) {
|
||||
Critical = true;
|
||||
modifier = 2; //At present time no critical heal amount modifier SPA exists.
|
||||
}
|
||||
|
||||
|
||||
value *= modifier;
|
||||
value += GetFocusEffect(focusFcHealAmtCrit, spell_id) * modifier;
|
||||
value += GetFocusEffect(focusFcHealAmt, spell_id);
|
||||
value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id);
|
||||
|
||||
value += GetFocusEffect(focusFcHealAmtCrit, spell_id) * modifier;
|
||||
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)
|
||||
value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier;
|
||||
|
||||
value += value*target->GetHealRate(spell_id, this)/100;
|
||||
value += value*target->GetHealRate(spell_id, this)/100;
|
||||
|
||||
if (Critical)
|
||||
entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), value);
|
||||
if (Critical) {
|
||||
entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits,
|
||||
OTHER_CRIT_HEAL, GetName(), itoa(value));
|
||||
Message_StringID(MT_SpellCrits, YOU_CRIT_HEAL, itoa(value));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
//Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value]
|
||||
else {
|
||||
|
||||
chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime;
|
||||
|
||||
chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);
|
||||
|
||||
chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime;
|
||||
|
||||
chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);
|
||||
|
||||
if (spellbonuses.CriticalRegenDecay)
|
||||
chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay);
|
||||
|
||||
|
||||
if(chance && (MakeRandomInt(0,99) < chance))
|
||||
return (value * 2);
|
||||
}
|
||||
@ -321,6 +328,12 @@ int32 Client::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
int32 Client::GetActSpellCost(uint16 spell_id, int32 cost)
|
||||
{
|
||||
//FrenziedDevastation doubles mana cost of all DD spells
|
||||
int16 FrenziedDevastation = itembonuses.FrenziedDevastation + spellbonuses.FrenziedDevastation + aabonuses.FrenziedDevastation;
|
||||
|
||||
if (FrenziedDevastation && IsPureNukeSpell(spell_id))
|
||||
cost *= 2;
|
||||
|
||||
// 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)
|
||||
{
|
||||
@ -426,7 +439,7 @@ int32 Client::GetActSpellDuration(uint16 spell_id, int32 duration)
|
||||
|
||||
// Only need this for clients, since the change was for bard songs, I assume we should keep non bard songs getting +1
|
||||
// However if its bard or not and is mez, charm or fear, we need to add 1 so that client is in sync
|
||||
if (!IsShortDurationBuff(spell_id) ||
|
||||
if (!(IsShortDurationBuff(spell_id) && IsBardSong(spell_id)) ||
|
||||
IsFearSpell(spell_id) ||
|
||||
IsCharmSpell(spell_id) ||
|
||||
IsMezSpell(spell_id) ||
|
||||
|
||||
@ -1012,6 +1012,22 @@ Mob *EntityList::GetMobByNpcTypeID(uint32 get_id)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool EntityList::IsMobSpawnedByNpcTypeID(uint32 get_id)
|
||||
{
|
||||
if (get_id == 0 || npc_list.empty())
|
||||
return false;
|
||||
|
||||
auto it = npc_list.begin();
|
||||
while (it != npc_list.end()) {
|
||||
// Mobs will have a 0 as their GetID() if they're dead
|
||||
if (it->second->GetNPCTypeID() == get_id && it->second->GetID() != 0)
|
||||
return true;
|
||||
++it;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Object *EntityList::GetObjectByDBID(uint32 id)
|
||||
{
|
||||
if (id == 0 || object_list.empty())
|
||||
@ -1891,6 +1907,24 @@ void EntityList::MessageClose_StringID(Mob *sender, bool skipsender, float dist,
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::FilteredMessageClose_StringID(Mob *sender, bool skipsender,
|
||||
float dist, uint32 type, eqFilterType filter, uint32 string_id,
|
||||
const char *message1, const char *message2, const char *message3,
|
||||
const char *message4, const char *message5, const char *message6,
|
||||
const char *message7, const char *message8, const char *message9)
|
||||
{
|
||||
Client *c;
|
||||
float dist2 = dist * dist;
|
||||
|
||||
for (auto it = client_list.begin(); it != client_list.end(); ++it) {
|
||||
c = it->second;
|
||||
if (c && c->DistNoRoot(*sender) <= dist2 && (!skipsender || c != sender))
|
||||
c->FilteredMessage_StringID(sender, type, filter, string_id,
|
||||
message1, message2, message3, message4, message5,
|
||||
message6, message7, message8, message9);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::Message_StringID(Mob *sender, bool skipsender, uint32 type, uint32 string_id, const char* message1,const char* message2,const char* message3,const char* message4,const char* message5,const char* message6,const char* message7,const char* message8,const char* message9)
|
||||
{
|
||||
Client *c;
|
||||
@ -1902,6 +1936,23 @@ void EntityList::Message_StringID(Mob *sender, bool skipsender, uint32 type, uin
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::FilteredMessage_StringID(Mob *sender, bool skipsender,
|
||||
uint32 type, eqFilterType filter, uint32 string_id,
|
||||
const char *message1, const char *message2, const char *message3,
|
||||
const char *message4, const char *message5, const char *message6,
|
||||
const char *message7, const char *message8, const char *message9)
|
||||
{
|
||||
Client *c;
|
||||
|
||||
for (auto it = client_list.begin(); it != client_list.end(); ++it) {
|
||||
c = it->second;
|
||||
if (c && (!skipsender || c != sender))
|
||||
c->FilteredMessage_StringID(sender, type, filter, string_id,
|
||||
message1, message2, message3, message4, message5, message6,
|
||||
message7, message8, message9);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityList::MessageClose(Mob* sender, bool skipsender, float dist, uint32 type, const char* message, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
|
||||
@ -135,6 +135,7 @@ public:
|
||||
inline Mob *GetMobID(uint16 id) { return(GetMob(id)); } //for perl
|
||||
Mob *GetMob(const char* name);
|
||||
Mob *GetMobByNpcTypeID(uint32 get_id);
|
||||
bool IsMobSpawnedByNpcTypeID(uint32 get_id);
|
||||
Mob *GetTargetForVirus(Mob* spreader);
|
||||
inline NPC *GetNPCByID(uint16 id)
|
||||
{ return npc_list.count(id) ? npc_list.at(id) : nullptr; }
|
||||
@ -266,7 +267,9 @@ public:
|
||||
void MessageStatus(uint32 to_guilddbid, int to_minstatus, uint32 type, const char* message, ...);
|
||||
void MessageClose(Mob* sender, bool skipsender, float dist, uint32 type, const char* message, ...);
|
||||
void Message_StringID(Mob *sender, bool skipsender, uint32 type, uint32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
|
||||
void FilteredMessage_StringID(Mob *sender, bool skipsender, uint32 type, eqFilterType filter, uint32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
|
||||
void MessageClose_StringID(Mob *sender, bool skipsender, float dist, uint32 type, uint32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
|
||||
void FilteredMessageClose_StringID(Mob *sender, bool skipsender, float dist, uint32 type, eqFilterType filter, uint32 string_id, const char* message1=0,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0);
|
||||
void ChannelMessageFromWorld(const char* from, const char* to, uint8 chan_num, uint32 guilddbid, uint8 language, const char* message);
|
||||
void ChannelMessage(Mob* from, uint8 chan_num, uint8 language, const char* message, ...);
|
||||
void ChannelMessage(Mob* from, uint8 chan_num, uint8 language, uint8 lang_skill, const char* message, ...);
|
||||
|
||||
@ -53,7 +53,10 @@ void Mob::CheckFlee() {
|
||||
|
||||
//see if were possibly hurt enough
|
||||
float ratio = GetHPRatio();
|
||||
if(ratio >= RuleI(Combat, FleeHPRatio))
|
||||
float fleeratio = GetSpecialAbility(FLEE_PERCENT);
|
||||
fleeratio = fleeratio > 0 ? fleeratio : RuleI(Combat, FleeHPRatio);
|
||||
|
||||
if(ratio >= fleeratio)
|
||||
return;
|
||||
|
||||
//we might be hurt enough, check con now..
|
||||
@ -77,25 +80,24 @@ void Mob::CheckFlee() {
|
||||
switch(con) {
|
||||
//these values are not 100% researched
|
||||
case CON_GREEN:
|
||||
run_ratio = RuleI(Combat, FleeHPRatio);
|
||||
run_ratio = fleeratio;
|
||||
break;
|
||||
case CON_LIGHTBLUE:
|
||||
run_ratio = RuleI(Combat, FleeHPRatio) * 8 / 10;
|
||||
run_ratio = fleeratio * 9 / 10;
|
||||
break;
|
||||
case CON_BLUE:
|
||||
run_ratio = RuleI(Combat, FleeHPRatio) * 6 / 10;
|
||||
run_ratio = fleeratio * 8 / 10;
|
||||
break;
|
||||
default:
|
||||
run_ratio = RuleI(Combat, FleeHPRatio) * 4 / 10;
|
||||
run_ratio = fleeratio * 7 / 10;
|
||||
break;
|
||||
}
|
||||
if(ratio < run_ratio)
|
||||
{
|
||||
if (RuleB(Combat, FleeIfNotAlone) ||
|
||||
(!RuleB(Combat, FleeIfNotAlone) &&
|
||||
(entity_list.GetHatedCount(hate_top, this) == 0)))
|
||||
GetSpecialAbility(ALWAYS_FLEE) ||
|
||||
(!RuleB(Combat, FleeIfNotAlone) && (entity_list.GetHatedCount(hate_top, this) == 0)))
|
||||
StartFleeing();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,7 +112,9 @@ void Mob::ProcessFlee() {
|
||||
}
|
||||
|
||||
//see if we are still dying, if so, do nothing
|
||||
if(GetHPRatio() < (float)RuleI(Combat, FleeHPRatio))
|
||||
float fleeratio = GetSpecialAbility(FLEE_PERCENT);
|
||||
fleeratio = fleeratio > 0 ? fleeratio : RuleI(Combat, FleeHPRatio);
|
||||
if(GetHPRatio() < fleeratio)
|
||||
return;
|
||||
|
||||
//we are not dying anymore... see what we do next
|
||||
@ -128,19 +132,19 @@ void Mob::ProcessFlee() {
|
||||
float Mob::GetFearSpeed() {
|
||||
if(flee_mode) {
|
||||
//we know ratio < FLEE_HP_RATIO
|
||||
float speed = GetRunspeed();
|
||||
float speed = GetBaseRunspeed();
|
||||
float ratio = GetHPRatio();
|
||||
float multiplier = RuleR(Combat, FleeMultiplier);
|
||||
|
||||
// mob's movement will halt with a decent snare at HP specified by rule.
|
||||
if (ratio <= RuleI(Combat, FleeSnareHPRatio) && GetSnaredAmount() > 40) {
|
||||
return 0.0001f;
|
||||
}
|
||||
if(GetSnaredAmount() > 40)
|
||||
multiplier = multiplier / 6.0f;
|
||||
|
||||
if (ratio < FLEE_HP_MINSPEED)
|
||||
ratio = FLEE_HP_MINSPEED;
|
||||
|
||||
speed = speed * 0.5 * ratio / 100;
|
||||
speed = speed * ratio * multiplier / 100;
|
||||
|
||||
//NPC will eventually stop. Snares speeds this up.
|
||||
if(speed < 0.09)
|
||||
speed = 0.0001f;
|
||||
|
||||
return(speed);
|
||||
}
|
||||
return(GetRunspeed());
|
||||
|
||||
@ -560,6 +560,11 @@ void Lua_Client::UnscribeSpellAll(bool update_client) {
|
||||
self->UnscribeSpellAll(update_client);
|
||||
}
|
||||
|
||||
void Lua_Client::TrainDisc(int itemid) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->TrainDiscipline(itemid);
|
||||
}
|
||||
|
||||
void Lua_Client::UntrainDisc(int slot) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->UntrainDisc(slot);
|
||||
@ -1352,6 +1357,7 @@ luabind::scope lua_register_client() {
|
||||
.def("UnscribeSpell", (void(Lua_Client::*)(int,bool))&Lua_Client::UnscribeSpell)
|
||||
.def("UnscribeSpellAll", (void(Lua_Client::*)(void))&Lua_Client::UnscribeSpellAll)
|
||||
.def("UnscribeSpellAll", (void(Lua_Client::*)(bool))&Lua_Client::UnscribeSpellAll)
|
||||
.def("TrainDisc", (void(Lua_Client::*)(int))&Lua_Client::TrainDisc)
|
||||
.def("UntrainDisc", (void(Lua_Client::*)(int))&Lua_Client::UntrainDisc)
|
||||
.def("UntrainDisc", (void(Lua_Client::*)(int,bool))&Lua_Client::UntrainDisc)
|
||||
.def("UntrainDiscAll", (void(Lua_Client::*)(void))&Lua_Client::UntrainDiscAll)
|
||||
|
||||
@ -138,6 +138,7 @@ public:
|
||||
void UnscribeSpell(int slot, bool update_client);
|
||||
void UnscribeSpellAll();
|
||||
void UnscribeSpellAll(bool update_client);
|
||||
void TrainDisc(int itemid);
|
||||
void UntrainDisc(int slot);
|
||||
void UntrainDisc(int slot, bool update_client);
|
||||
void UntrainDiscAll();
|
||||
|
||||
@ -65,6 +65,11 @@ Lua_Mob Lua_EntityList::GetMobByNpcTypeID(int npc_type) {
|
||||
return Lua_Mob(self->GetMobByNpcTypeID(npc_type));
|
||||
}
|
||||
|
||||
bool Lua_EntityList::IsMobSpawnedByNpcTypeID(int npc_type) {
|
||||
Lua_Safe_Call_Bool();
|
||||
return self->IsMobSpawnedByNpcTypeID(npc_type);
|
||||
}
|
||||
|
||||
Lua_NPC Lua_EntityList::GetNPCByID(int id) {
|
||||
Lua_Safe_Call_Class(Lua_NPC);
|
||||
return Lua_NPC(self->GetNPCByID(id));
|
||||
@ -420,6 +425,7 @@ luabind::scope lua_register_entity_list() {
|
||||
.def("GetMob", (Lua_Mob(Lua_EntityList::*)(const char*))&Lua_EntityList::GetMob)
|
||||
.def("GetMob", (Lua_Mob(Lua_EntityList::*)(int))&Lua_EntityList::GetMob)
|
||||
.def("GetMobByNpcTypeID", (Lua_Mob(Lua_EntityList::*)(int))&Lua_EntityList::GetMobByNpcTypeID)
|
||||
.def("IsMobSpawnedByNpcTypeID", (bool(Lua_EntityList::*)(int))&Lua_EntityList::IsMobSpawnedByNpcTypeID)
|
||||
.def("GetNPCByID", (Lua_NPC(Lua_EntityList::*)(int))&Lua_EntityList::GetNPCByID)
|
||||
.def("GetNPCByNPCTypeID", (Lua_NPC(Lua_EntityList::*)(int))&Lua_EntityList::GetNPCByNPCTypeID)
|
||||
.def("GetClientByName", (Lua_Client(Lua_EntityList::*)(const char*))&Lua_EntityList::GetClientByName)
|
||||
|
||||
@ -51,6 +51,7 @@ public:
|
||||
Lua_Mob GetMob(const char *name);
|
||||
Lua_Mob GetMob(int id);
|
||||
Lua_Mob GetMobByNpcTypeID(int npc_type);
|
||||
bool IsMobSpawnedByNpcTypeID(int npc_type);
|
||||
Lua_NPC GetNPCByID(int id);
|
||||
Lua_NPC GetNPCByNPCTypeID(int npc_type);
|
||||
Lua_Client GetClientByName(const char *name);
|
||||
|
||||
@ -2166,7 +2166,9 @@ luabind::scope lua_register_special_abilities() {
|
||||
luabind::value("leash", static_cast<int>(LEASH)),
|
||||
luabind::value("tether", static_cast<int>(TETHER)),
|
||||
luabind::value("destructible_object", static_cast<int>(DESTRUCTIBLE_OBJECT)),
|
||||
luabind::value("no_harm_from_client", static_cast<int>(NO_HARM_FROM_CLIENT))
|
||||
luabind::value("no_harm_from_client", static_cast<int>(NO_HARM_FROM_CLIENT)),
|
||||
luabind::value("always_flee", static_cast<int>(ALWAYS_FLEE)),
|
||||
luabind::value("flee_percent", static_cast<int>(FLEE_PERCENT))
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -297,9 +297,9 @@ void Lua_NPC::AI_SetRoambox(float dist, float max_x, float min_x, float max_y, f
|
||||
self->AI_SetRoambox(dist, max_x, min_x, max_y, min_y);
|
||||
}
|
||||
|
||||
void Lua_NPC::AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y, uint32 delay) {
|
||||
void Lua_NPC::AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y, uint32 delay, uint32 mindelay) {
|
||||
Lua_Safe_Call_Void();
|
||||
self->AI_SetRoambox(dist, max_x, min_x, max_y, min_y, delay);
|
||||
self->AI_SetRoambox(dist, max_x, min_x, max_y, min_y, delay, mindelay);
|
||||
}
|
||||
|
||||
int Lua_NPC::GetNPCSpellsID() {
|
||||
@ -494,7 +494,7 @@ luabind::scope lua_register_npc() {
|
||||
.def("SaveGuardSpot", (void(Lua_NPC::*)(bool))&Lua_NPC::SaveGuardSpot)
|
||||
.def("IsGuarding", (bool(Lua_NPC::*)(void))&Lua_NPC::IsGuarding)
|
||||
.def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float))&Lua_NPC::AI_SetRoambox)
|
||||
.def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float,uint32))&Lua_NPC::AI_SetRoambox)
|
||||
.def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float,uint32,uint32))&Lua_NPC::AI_SetRoambox)
|
||||
.def("GetNPCSpellsID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID)
|
||||
.def("GetSpawnPointID", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointID)
|
||||
.def("GetSpawnPointX", (float(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointX)
|
||||
|
||||
@ -85,7 +85,7 @@ public:
|
||||
void SaveGuardSpot(bool clear);
|
||||
bool IsGuarding();
|
||||
void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y);
|
||||
void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y, uint32 delay);
|
||||
void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y, uint32 delay, uint32 mindelay);
|
||||
int GetNPCSpellsID();
|
||||
int GetSpawnPointID();
|
||||
float GetSpawnPointX();
|
||||
|
||||
@ -2824,7 +2824,8 @@ int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
|
||||
value = (value * GetSpellScale() / 100);
|
||||
|
||||
entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), -value);
|
||||
entity_list.MessageClose_StringID(this, false, 100, MT_SpellCrits,
|
||||
OTHER_CRIT_BLAST, GetName(), itoa(-value));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
10
zone/mob.h
10
zone/mob.h
@ -523,6 +523,13 @@ public:
|
||||
virtual void Message_StringID(uint32 type, uint32 string_id, const char* message, const char* message2 = 0,
|
||||
const char* message3 = 0, const char* message4 = 0, const char* message5 = 0, const char* message6 = 0,
|
||||
const char* message7 = 0, const char* message8 = 0, const char* message9 = 0, uint32 distance = 0) { }
|
||||
virtual void FilteredMessage_StringID(Mob *sender, uint32 type, eqFilterType filter, uint32 string_id) { }
|
||||
virtual void FilteredMessage_StringID(Mob *sender, uint32 type, eqFilterType filter,
|
||||
uint32 string_id, const char *message1, const char *message2 = nullptr,
|
||||
const char *message3 = nullptr, const char *message4 = nullptr,
|
||||
const char *message5 = nullptr, const char *message6 = nullptr,
|
||||
const char *message7 = nullptr, const char *message8 = nullptr,
|
||||
const char *message9 = nullptr) { }
|
||||
void Say(const char *format, ...);
|
||||
void Say_StringID(uint32 string_id, const char *message3 = 0, const char *message4 = 0, const char *message5 = 0,
|
||||
const char *message6 = 0, const char *message7 = 0, const char *message8 = 0, const char *message9 = 0);
|
||||
@ -968,9 +975,10 @@ protected:
|
||||
bool PassLimitClass(uint32 Classes_, uint16 Class_);
|
||||
void TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand = 13, int damage=0);
|
||||
void TryWeaponProc(const ItemInst* inst, const Item_Struct* weapon, Mob *on, uint16 hand = 13);
|
||||
void TrySpellProc(const ItemInst* inst, const Item_Struct* weapon, Mob *on, uint16 hand = 13);
|
||||
void TryWeaponProc(const ItemInst* weapon, Mob *on, uint16 hand = 13);
|
||||
void ExecWeaponProc(const ItemInst* weapon, uint16 spell_id, Mob *on);
|
||||
virtual float GetProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_speed = 30, uint16 hand = 13);
|
||||
virtual float GetProcChances(float ProcBonus, uint16 weapon_speed = 30, uint16 hand = 13);
|
||||
virtual float GetDefensiveProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_speed = 30, uint16 hand = 13);
|
||||
int GetWeaponDamage(Mob *against, const Item_Struct *weapon_item);
|
||||
int GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate = nullptr);
|
||||
|
||||
15
zone/net.cpp
15
zone/net.cpp
@ -336,8 +336,10 @@ int main(int argc, char** argv) {
|
||||
bool worldwasconnected = worldserver.Connected();
|
||||
EQStream* eqss;
|
||||
EQStreamInterface *eqsi;
|
||||
Timer temp_timer(10);
|
||||
temp_timer.Start();
|
||||
uint8 IDLEZONEUPDATE = 200;
|
||||
uint8 ZONEUPDATE = 10;
|
||||
Timer zoneupdate_timer(ZONEUPDATE);
|
||||
zoneupdate_timer.Start();
|
||||
while(RunLoops) {
|
||||
{ //profiler block to omit the sleep from times
|
||||
|
||||
@ -381,6 +383,13 @@ int main(int argc, char** argv) {
|
||||
entity_list.AddClient(client);
|
||||
}
|
||||
|
||||
if ( numclients < 1 && zoneupdate_timer.GetDuration() != IDLEZONEUPDATE )
|
||||
zoneupdate_timer.SetTimer(IDLEZONEUPDATE);
|
||||
else if ( numclients > 0 && zoneupdate_timer.GetDuration() == IDLEZONEUPDATE )
|
||||
{
|
||||
zoneupdate_timer.SetTimer(ZONEUPDATE);
|
||||
zoneupdate_timer.Trigger();
|
||||
}
|
||||
|
||||
//check for timeouts in other threads
|
||||
timeout_manager.CheckTimeouts();
|
||||
@ -394,7 +403,7 @@ int main(int argc, char** argv) {
|
||||
worldwasconnected = false;
|
||||
}
|
||||
|
||||
if (ZoneLoaded && temp_timer.Check()) {
|
||||
if (ZoneLoaded && zoneupdate_timer.Check()) {
|
||||
{
|
||||
if(net.group_timer.Enabled() && net.group_timer.Check())
|
||||
entity_list.GroupProcess();
|
||||
|
||||
16
zone/npc.cpp
16
zone/npc.cpp
@ -216,6 +216,7 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float
|
||||
roambox_min_y = -2;
|
||||
roambox_movingto_x = -2;
|
||||
roambox_movingto_y = -2;
|
||||
roambox_min_delay = 1000;
|
||||
roambox_delay = 1000;
|
||||
org_heading = heading;
|
||||
p_depop = false;
|
||||
@ -1526,6 +1527,12 @@ void Mob::NPCSpecialAttacks(const char* parse, int permtag, bool reset, bool rem
|
||||
case 'i':
|
||||
SetSpecialAbility(IMMUNE_TAUNT, remove ? 0 : 1);
|
||||
break;
|
||||
case 'e':
|
||||
SetSpecialAbility(ALWAYS_FLEE, remove ? 0 : 1);
|
||||
break;
|
||||
case 'h':
|
||||
SetSpecialAbility(FLEE_PERCENT, remove ? 0 : 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
@ -1686,7 +1693,14 @@ bool Mob::HasNPCSpecialAtk(const char* parse) {
|
||||
HasAllAttacks = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
if(!GetSpecialAbility(ALWAYS_FLEE))
|
||||
HasAllAttacks = false;
|
||||
break;
|
||||
case 'h':
|
||||
if(!GetSpecialAbility(FLEE_PERCENT))
|
||||
HasAllAttacks = false;
|
||||
break;
|
||||
default:
|
||||
HasAllAttacks = false;
|
||||
break;
|
||||
|
||||
@ -265,8 +265,8 @@ public:
|
||||
inline bool IsGuarding() const { return(guard_heading != 0); }
|
||||
void SaveGuardSpotCharm();
|
||||
void RestoreGuardSpotCharm();
|
||||
void AI_SetRoambox(float iDist, float iRoamDist, uint32 iDelay = 2500);
|
||||
void AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay = 2500);
|
||||
void AI_SetRoambox(float iDist, float iRoamDist, uint32 iDelay = 2500, uint32 iMinDelay = 2500);
|
||||
void AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay = 2500, uint32 iMinDelay = 2500);
|
||||
|
||||
//mercenary stuff
|
||||
void LoadMercTypes();
|
||||
@ -430,6 +430,7 @@ protected:
|
||||
float roambox_movingto_x;
|
||||
float roambox_movingto_y;
|
||||
uint32 roambox_delay;
|
||||
uint32 roambox_min_delay;
|
||||
|
||||
uint16 skills[HIGHEST_SKILL+1];
|
||||
uint32 equipment[MAX_WORN_INVENTORY]; //this is an array of item IDs
|
||||
|
||||
@ -150,6 +150,33 @@ XS(XS_EntityList_GetMobByNpcTypeID)
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_EntityList_IsMobSpawnedByNpcTypeID); /* prototype pass -Wmissing-prototypes */
|
||||
XS(XS_EntityList_IsMobSpawnedByNpcTypeID)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items != 2)
|
||||
Perl_croak(aTHX_ "Usage: EntityList::ValidMobByNpcTypeID(THIS, get_id)");
|
||||
{
|
||||
EntityList * THIS;
|
||||
bool RETVAL;
|
||||
uint32 get_id = (uint32)SvUV(ST(1));
|
||||
|
||||
if (sv_derived_from(ST(0), "EntityList")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
THIS = INT2PTR(EntityList *,tmp);
|
||||
}
|
||||
else
|
||||
Perl_croak(aTHX_ "THIS is not of type EntityList");
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
RETVAL = THIS->IsMobSpawnedByNpcTypeID(get_id);
|
||||
ST(0) = boolSV(RETVAL);
|
||||
sv_2mortal(ST(0));
|
||||
}
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS_EntityList_GetNPCByID); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_EntityList_GetNPCByID)
|
||||
{
|
||||
@ -2127,6 +2154,7 @@ XS(boot_EntityList)
|
||||
newXSproto(strcpy(buf, "GetMob"), XS_EntityList_GetMob, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetMobByID"), XS_EntityList_GetMobByID, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetMobByNpcTypeID"), XS_EntityList_GetMobByNpcTypeID, file, "$$");
|
||||
newXSproto(strcpy(buf, "IsMobSpawnedByNpcTypeID"), XS_EntityList_IsMobSpawnedByNpcTypeID, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetNPCByID"), XS_EntityList_GetNPCByID, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetNPCByNPCTypeID"), XS_EntityList_GetNPCByNPCTypeID, file, "$$");
|
||||
newXSproto(strcpy(buf, "GetClientByName"), XS_EntityList_GetClientByName, file, "$$");
|
||||
|
||||
@ -1433,8 +1433,8 @@ XS(XS_NPC_AI_SetRoambox); /* prototype to pass -Wmissing-prototypes */
|
||||
XS(XS_NPC_AI_SetRoambox)
|
||||
{
|
||||
dXSARGS;
|
||||
if (items < 6 || items > 7)
|
||||
Perl_croak(aTHX_ "Usage: NPC::AI_SetRoambox(THIS, iDist, iMaxX, iMinX, iMaxY, iMinY, iDelay= 2500)");
|
||||
if (items < 6 || items > 8)
|
||||
Perl_croak(aTHX_ "Usage: NPC::AI_SetRoambox(THIS, iDist, iMaxX, iMinX, iMaxY, iMinY, iDelay= 2500, iMinDelay= 2500)");
|
||||
{
|
||||
NPC * THIS;
|
||||
float iDist = (float)SvNV(ST(1));
|
||||
@ -1443,6 +1443,7 @@ XS(XS_NPC_AI_SetRoambox)
|
||||
float iMaxY = (float)SvNV(ST(4));
|
||||
float iMinY = (float)SvNV(ST(5));
|
||||
uint32 iDelay;
|
||||
uint32 iMinDelay;
|
||||
|
||||
if (sv_derived_from(ST(0), "NPC")) {
|
||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||
@ -1453,13 +1454,20 @@ XS(XS_NPC_AI_SetRoambox)
|
||||
if(THIS == nullptr)
|
||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||
|
||||
if (items < 7)
|
||||
if (items < 7){
|
||||
iMinDelay = 2500;
|
||||
iDelay = 2500;
|
||||
else {
|
||||
}
|
||||
else if (items < 8){
|
||||
iMinDelay = 2500;
|
||||
iDelay = (uint32)SvUV(ST(6));
|
||||
}
|
||||
else {
|
||||
iDelay = (uint32)SvUV(ST(6));
|
||||
iMinDelay = (uint32)SvUV(ST(7));
|
||||
}
|
||||
|
||||
THIS->AI_SetRoambox(iDist, iMaxX, iMinX, iMaxY, iMinY, iDelay);
|
||||
THIS->AI_SetRoambox(iDist, iMaxX, iMinX, iMaxY, iMinY, iDelay, iMinDelay);
|
||||
}
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
@ -2208,7 +2216,7 @@ XS(boot_NPC)
|
||||
newXSproto(strcpy(buf, "NextGuardPosition"), XS_NPC_NextGuardPosition, file, "$");
|
||||
newXSproto(strcpy(buf, "SaveGuardSpot"), XS_NPC_SaveGuardSpot, file, "$;$");
|
||||
newXSproto(strcpy(buf, "IsGuarding"), XS_NPC_IsGuarding, file, "$");
|
||||
newXSproto(strcpy(buf, "AI_SetRoambox"), XS_NPC_AI_SetRoambox, file, "$$$$$$;$");
|
||||
newXSproto(strcpy(buf, "AI_SetRoambox"), XS_NPC_AI_SetRoambox, file, "$$$$$$;$$");
|
||||
newXSproto(strcpy(buf, "GetNPCSpellsID"), XS_NPC_GetNPCSpellsID, file, "$");
|
||||
newXSproto(strcpy(buf, "GetSpawnPointID"), XS_NPC_GetSpawnPointID, file, "$");
|
||||
newXSproto(strcpy(buf, "GetSpawnPointX"), XS_NPC_GetSpawnPointX, file, "$");
|
||||
|
||||
@ -347,8 +347,8 @@ Mob* QuestManager::spawn_from_spawn2(uint32 spawn2_id)
|
||||
entity_list.AddNPC(npc);
|
||||
entity_list.LimitAddNPC(npc);
|
||||
|
||||
if(sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay)
|
||||
npc->AI_SetRoambox(sg->roamdist,sg->roambox[0],sg->roambox[1],sg->roambox[2],sg->roambox[3],sg->delay);
|
||||
if(sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay && sg->min_delay)
|
||||
npc->AI_SetRoambox(sg->roamdist,sg->roambox[0],sg->roambox[1],sg->roambox[2],sg->roambox[3],sg->delay,sg->min_delay);
|
||||
if(zone->InstantGrids())
|
||||
{
|
||||
found_spawn->LoadGrid();
|
||||
|
||||
@ -229,8 +229,8 @@ bool Spawn2::Process() {
|
||||
entity_list.AddNPC(npc);
|
||||
//this limit add must be done after the AddNPC since we need the entity ID.
|
||||
entity_list.LimitAddNPC(npc);
|
||||
if(sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay)
|
||||
npc->AI_SetRoambox(sg->roamdist,sg->roambox[0],sg->roambox[1],sg->roambox[2],sg->roambox[3],sg->delay);
|
||||
if(sg->roamdist && sg->roambox[0] && sg->roambox[1] && sg->roambox[2] && sg->roambox[3] && sg->delay && sg->min_delay)
|
||||
npc->AI_SetRoambox(sg->roamdist,sg->roambox[0],sg->roambox[1],sg->roambox[2],sg->roambox[3],sg->delay,sg->min_delay);
|
||||
if(zone->InstantGrids()) {
|
||||
_log(SPAWNS__MAIN, "Spawn2 %d: Group %d spawned %s (%d) at (%.3f, %.3f, %.3f).", spawn2_id, spawngroup_id_, npc->GetName(), npcid, x, y, z);
|
||||
LoadGrid();
|
||||
|
||||
@ -35,7 +35,7 @@ SpawnEntry::SpawnEntry( uint32 in_NPCType, int in_chance, uint8 in_npc_spawn_lim
|
||||
npc_spawn_limit = in_npc_spawn_limit;
|
||||
}
|
||||
|
||||
SpawnGroup::SpawnGroup( uint32 in_id, char* name, int in_group_spawn_limit, float dist, float maxx, float minx, float maxy, float miny, int delay_in, int despawn_in, uint32 despawn_timer_in ) {
|
||||
SpawnGroup::SpawnGroup( uint32 in_id, char* name, int in_group_spawn_limit, float dist, float maxx, float minx, float maxy, float miny, int delay_in, int despawn_in, uint32 despawn_timer_in, int min_delay_in ) {
|
||||
id = in_id;
|
||||
strn0cpy( name_, name, 120);
|
||||
group_spawn_limit = in_group_spawn_limit;
|
||||
@ -44,6 +44,7 @@ SpawnGroup::SpawnGroup( uint32 in_id, char* name, int in_group_spawn_limit, floa
|
||||
roambox[2]=maxy;
|
||||
roambox[3]=miny;
|
||||
roamdist=dist;
|
||||
min_delay=min_delay_in;
|
||||
delay=delay_in;
|
||||
despawn=despawn_in;
|
||||
despawn_timer=despawn_timer_in;
|
||||
@ -150,11 +151,11 @@ bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, uint16 version, SpawnG
|
||||
|
||||
// CODER new spawn code
|
||||
query = 0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT(spawngroupID), spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer FROM spawn2,spawngroup WHERE spawn2.spawngroupID=spawngroup.ID and spawn2.version=%u and zone='%s'", version, zone_name), errbuf, &result))
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT(spawngroupID), spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay FROM spawn2,spawngroup WHERE spawn2.spawngroupID=spawngroup.ID and spawn2.version=%u and zone='%s'", version, zone_name), errbuf, &result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]));
|
||||
SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11]));
|
||||
spawn_group_list->AddSpawnGroup(newSpawnGroup);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
@ -205,11 +206,11 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_g
|
||||
|
||||
// CODER new spawn code
|
||||
query = 0;
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT spawngroup.id, spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer FROM spawngroup WHERE spawngroup.ID='%i'", spawngroupid), errbuf, &result))
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT DISTINCT spawngroup.id, spawngroup.name, spawngroup.spawn_limit, spawngroup.dist, spawngroup.max_x, spawngroup.min_x, spawngroup.max_y, spawngroup.min_y, spawngroup.delay, spawngroup.despawn, spawngroup.despawn_timer, spawngroup.mindelay FROM spawngroup WHERE spawngroup.ID='%i'", spawngroupid), errbuf, &result))
|
||||
{
|
||||
safe_delete_array(query);
|
||||
while((row = mysql_fetch_row(result))) {
|
||||
SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]));
|
||||
SpawnGroup* newSpawnGroup = new SpawnGroup( atoi(row[0]), row[1], atoi(row[2]), atof(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atoi(row[8]), atoi(row[9]), atoi(row[10]), atoi(row[11]));
|
||||
spawn_group_list->AddSpawnGroup(newSpawnGroup);
|
||||
}
|
||||
mysql_free_result(result);
|
||||
|
||||
@ -39,13 +39,14 @@ public:
|
||||
class SpawnGroup
|
||||
{
|
||||
public:
|
||||
SpawnGroup(uint32 in_id, char* name, int in_group_spawn_limit, float dist, float maxx, float minx, float maxy, float miny, int delay_in, int despawn_in, uint32 despawn_timer_in );
|
||||
SpawnGroup(uint32 in_id, char* name, int in_group_spawn_limit, float dist, float maxx, float minx, float maxy, float miny, int delay_in, int despawn_in, uint32 despawn_timer_in, int min_delay_in );
|
||||
~SpawnGroup();
|
||||
uint32 GetNPCType();
|
||||
void AddSpawnEntry( SpawnEntry* newEntry );
|
||||
uint32 id;
|
||||
float roamdist;
|
||||
float roambox[4];
|
||||
int min_delay;
|
||||
int delay;
|
||||
int despawn;
|
||||
uint32 despawn_timer;
|
||||
|
||||
@ -2826,6 +2826,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_CriticalMend:
|
||||
case SE_LimitCastTimeMax:
|
||||
case SE_TriggerOnReqCaster:
|
||||
case SE_FrenziedDevastation:
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -3418,13 +3419,11 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
|
||||
{
|
||||
if (spellbonuses.DistanceRemoval){
|
||||
|
||||
int distance = sqrt(
|
||||
((int(GetX()) - buffs[slot].caston_x) * (int(GetX()) - buffs[slot].caston_x)) +
|
||||
((int(GetY()) - buffs[slot].caston_y) * (int(GetY()) - buffs[slot].caston_y)) +
|
||||
((int(GetZ()) - buffs[slot].caston_z) * (int(GetZ()) - buffs[slot].caston_z))
|
||||
);
|
||||
int distance = ((int(GetX()) - buffs[slot].caston_x) * (int(GetX()) - buffs[slot].caston_x)) +
|
||||
((int(GetY()) - buffs[slot].caston_y) * (int(GetY()) - buffs[slot].caston_y)) +
|
||||
((int(GetZ()) - buffs[slot].caston_z) * (int(GetZ()) - buffs[slot].caston_z));
|
||||
|
||||
if (distance > spells[spell_id].base[i]){
|
||||
if (distance > (spells[spell_id].base[i] * spells[spell_id].base[i])){
|
||||
|
||||
if(!TryFadeEffect(slot))
|
||||
BuffFadeBySlot(slot , true);
|
||||
@ -5396,14 +5395,12 @@ bool Mob::AffectedBySpellExcludingSlot(int slot, int effect)
|
||||
|
||||
float Mob::GetSympatheticProcChances(float &ProcBonus, float &ProcChance, int32 cast_time, int16 ProcRateMod) {
|
||||
|
||||
ProcBonus = spellbonuses.SpellProcChance + itembonuses.SpellProcChance;
|
||||
ProcChance = 0;
|
||||
|
||||
if(cast_time > 0)
|
||||
{
|
||||
ProcChance = ((float)cast_time * RuleR(Casting, AvgSpellProcsPerMinute) / 60000.0f);
|
||||
ProcChance = ProcChance * (float)(ProcRateMod/100);
|
||||
ProcChance = ProcChance+(ProcChance*ProcBonus/100);
|
||||
}
|
||||
return ProcChance;
|
||||
}
|
||||
|
||||
@ -445,7 +445,8 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
||||
|
||||
casting_spell_resist_adjust = resist_adjust;
|
||||
|
||||
mlog(SPELLS__CASTING, "Spell %d: Casting time %d (orig %d), mana cost %d", orgcasttime, cast_time, mana_cost);
|
||||
mlog(SPELLS__CASTING, "Spell %d: Casting time %d (orig %d), mana cost %d",
|
||||
spell_id, cast_time, orgcasttime, mana_cost);
|
||||
|
||||
// cast time is 0, just finish it right now and be done with it
|
||||
if(cast_time == 0) {
|
||||
@ -461,8 +462,9 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
||||
if (IsAIControlled())
|
||||
{
|
||||
SetRunAnimSpeed(0);
|
||||
if(this != pMob)
|
||||
this->FaceTarget(pMob);
|
||||
pMob = entity_list.GetMob(target_id);
|
||||
if (pMob && this != pMob)
|
||||
FaceTarget(pMob);
|
||||
}
|
||||
|
||||
// if we got here we didn't fizzle, and are starting our cast
|
||||
|
||||
@ -47,11 +47,11 @@ static inline float ABS(float x) {
|
||||
return(x);
|
||||
}
|
||||
|
||||
void NPC::AI_SetRoambox(float iDist, float iRoamDist, uint32 iDelay) {
|
||||
AI_SetRoambox(iDist, GetX()+iRoamDist, GetX()-iRoamDist, GetY()+iRoamDist, GetY()-iRoamDist, iDelay);
|
||||
void NPC::AI_SetRoambox(float iDist, float iRoamDist, uint32 iDelay, uint32 iMinDelay) {
|
||||
AI_SetRoambox(iDist, GetX()+iRoamDist, GetX()-iRoamDist, GetY()+iRoamDist, GetY()-iRoamDist, iDelay, iMinDelay);
|
||||
}
|
||||
|
||||
void NPC::AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay) {
|
||||
void NPC::AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay, uint32 iMinDelay) {
|
||||
roambox_distance = iDist;
|
||||
roambox_max_x = iMaxX;
|
||||
roambox_min_x = iMinX;
|
||||
@ -59,6 +59,7 @@ void NPC::AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, floa
|
||||
roambox_min_y = iMinY;
|
||||
roambox_movingto_x = roambox_max_x + 1; // this will trigger a recalc
|
||||
roambox_delay = iDelay;
|
||||
roambox_min_delay = iMinDelay;
|
||||
}
|
||||
|
||||
void NPC::DisplayWaypointInfo(Client *c) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user