mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-19 16:52: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)
|
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 ==
|
== 02/23/2014 ==
|
||||||
Secrets: Exported the client object SendTargetCommand to Perl.
|
Secrets: Exported the client object SendTargetCommand to Perl.
|
||||||
|
cavedude: Merchants will now keep better track of charges.
|
||||||
|
|
||||||
== 02/20/2014 ==
|
== 02/20/2014 ==
|
||||||
Kayen: Implemented SE_MitigateDotDamage - dot spell mitigation rune with max value
|
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_RES *result;
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
|
|
||||||
uint32 count = RuleI(Zone, ReservedInstances) + 1;
|
uint32 count = RuleI(Zone, ReservedInstances);
|
||||||
uint32 max = 65535;
|
uint32 max = 65535;
|
||||||
|
if (RunQuery(query, MakeAnyLenString(&query, "SELECT IFNULL(MAX(id),%u)+1 FROM instance_list WHERE id > %u", count,count), errbuf, &result)) {
|
||||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_list where id >= %i ORDER BY id", count), errbuf, &result)) {
|
|
||||||
safe_delete_array(query);
|
safe_delete_array(query);
|
||||||
if (mysql_num_rows(result) != 0) {
|
if (mysql_num_rows(result) != 0) {
|
||||||
while((row = mysql_fetch_row(result))) {
|
row = mysql_fetch_row(result);
|
||||||
if(count < atoi(row[0])) {
|
mysql_free_result(result);
|
||||||
instance_id = count;
|
if(atoi(row[0]) <= max) {
|
||||||
mysql_free_result(result);
|
count = atoi(row[0]);
|
||||||
return true;
|
} else {
|
||||||
} else if(count > max) {
|
if (RunQuery(query, MakeAnyLenString(&query, "SELECT id FROM instance_list where id > %u ORDER BY id", count), errbuf, &result)) {
|
||||||
instance_id = 0;
|
safe_delete_array(query);
|
||||||
mysql_free_result(result);
|
if (mysql_num_rows(result) != 0) {
|
||||||
return false;
|
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 {
|
} else {
|
||||||
count++;
|
safe_delete_array(query);
|
||||||
|
instance_id = 0;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
instance_id = 0;
|
||||||
mysql_free_result(result);
|
mysql_free_result(result);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
safe_delete_array(query);
|
safe_delete_array(query);
|
||||||
|
instance_id = 0;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
instance_id = count;
|
instance_id = count;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -310,8 +310,8 @@ RULE_INT ( Combat, ClientBaseCritChance, 0 ) //The base crit chance for all clie
|
|||||||
RULE_BOOL ( Combat, UseIntervalAC, true)
|
RULE_BOOL ( Combat, UseIntervalAC, true)
|
||||||
RULE_INT ( Combat, PetAttackMagicLevel, 30)
|
RULE_INT ( Combat, PetAttackMagicLevel, 30)
|
||||||
RULE_BOOL ( Combat, EnableFearPathing, true)
|
RULE_BOOL ( Combat, EnableFearPathing, true)
|
||||||
RULE_INT ( Combat, FleeHPRatio, 25)
|
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, FleeSnareHPRatio, 11) // HP at which snare will halt movement of a fleeing NPC.
|
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, FleeIfNotAlone, false) // If false, mobs won't flee if other mobs are in combat with it.
|
||||||
RULE_BOOL ( Combat, AdjustProcPerMinute, true)
|
RULE_BOOL ( Combat, AdjustProcPerMinute, true)
|
||||||
RULE_REAL ( Combat, AvgProcsPerMinute, 2.0)
|
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_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, 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_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_END()
|
||||||
|
|
||||||
RULE_CATEGORY ( Bazaar )
|
RULE_CATEGORY ( Bazaar )
|
||||||
|
|||||||
@ -359,7 +359,7 @@ typedef enum {
|
|||||||
#define SE_DispelBeneficial 209 // implemented
|
#define SE_DispelBeneficial 209 // implemented
|
||||||
//#define SE_PetShield 210 // *not implemented
|
//#define SE_PetShield 210 // *not implemented
|
||||||
#define SE_AEMelee 211 // 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_PetMaxHP 213 // implemented[AA] - increases the maximum hit points of your pet
|
||||||
#define SE_MaxHPChange 214 // implemented
|
#define SE_MaxHPChange 214 // implemented
|
||||||
#define SE_PetAvoidance 215 // implemented[AA] - increases pet ability to avoid melee damage
|
#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_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_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_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_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_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.
|
#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
|
dist2 <= spells[AIspells[i].spellid].range*spells[AIspells[i].spellid].range
|
||||||
)
|
)
|
||||||
&& (mana_cost <= GetMana() || GetMana() == GetMaxMana())
|
&& (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
|
#if MobAI_DEBUG_Spells >= 21
|
||||||
@ -125,21 +125,19 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SpellType_Root: {
|
case SpellType_Root: {
|
||||||
if (
|
Mob *rootee = GetHateRandom();
|
||||||
!tar->IsRooted()
|
if (rootee && !rootee->IsRooted() && MakeRandomInt(0, 99) < 50
|
||||||
&& dist2 >= 900
|
&& rootee->DontRootMeBefore() < Timer::GetCurrentTime()
|
||||||
&& MakeRandomInt(0, 99) < 50
|
&& rootee->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0
|
||||||
&& tar->DontRootMeBefore() < Timer::GetCurrentTime()
|
|
||||||
&& tar->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0
|
|
||||||
) {
|
) {
|
||||||
if(!checked_los) {
|
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
|
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;
|
checked_los = true;
|
||||||
}
|
}
|
||||||
uint32 tempTime = 0;
|
uint32 tempTime = 0;
|
||||||
AIDoSpellCast(i, tar, mana_cost, &tempTime);
|
AIDoSpellCast(i, rootee, mana_cost, &tempTime);
|
||||||
tar->SetDontRootMeBefore(tempTime);
|
rootee->SetDontRootMeBefore(tempTime);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -167,7 +165,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case SpellType_InCombatBuff: {
|
case SpellType_InCombatBuff: {
|
||||||
if(MakeRandomInt(0,100) < 50)
|
if(MakeRandomInt(0, 99) < 50)
|
||||||
{
|
{
|
||||||
AIDoSpellCast(i, tar, mana_cost);
|
AIDoSpellCast(i, tar, mana_cost);
|
||||||
return true;
|
return true;
|
||||||
@ -184,7 +182,20 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SpellType_Slow:
|
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: {
|
case SpellType_Nuke: {
|
||||||
if (
|
if (
|
||||||
manaR >= 10 && MakeRandomInt(0, 99) < 70
|
manaR >= 10 && MakeRandomInt(0, 99) < 70
|
||||||
@ -201,7 +212,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint16 iSpellTypes) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SpellType_Dispel: {
|
case SpellType_Dispel: {
|
||||||
if(MakeRandomInt(0, 100) < 15)
|
if(MakeRandomInt(0, 99) < 15)
|
||||||
{
|
{
|
||||||
if(!checked_los) {
|
if(!checked_los) {
|
||||||
if(!CheckLosFN(tar))
|
if(!CheckLosFN(tar))
|
||||||
@ -444,6 +455,7 @@ void NPC::AI_Init() {
|
|||||||
roambox_distance = 0;
|
roambox_distance = 0;
|
||||||
roambox_movingto_x = 0;
|
roambox_movingto_x = 0;
|
||||||
roambox_movingto_y = 0;
|
roambox_movingto_y = 0;
|
||||||
|
roambox_min_delay = 2500;
|
||||||
roambox_delay = 2500;
|
roambox_delay = 2500;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1579,14 +1591,17 @@ void NPC::AI_DoMovement() {
|
|||||||
movey *= MakeRandomInt(0, 1) ? 1 : -1;
|
movey *= MakeRandomInt(0, 1) ? 1 : -1;
|
||||||
roambox_movingto_x = GetX() + movex;
|
roambox_movingto_x = GetX() + movex;
|
||||||
roambox_movingto_y = GetY() + movey;
|
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)
|
if (roambox_movingto_x > roambox_max_x || roambox_movingto_x < roambox_min_x)
|
||||||
roambox_movingto_x -= movex * 2;
|
roambox_movingto_x -= movex * 2;
|
||||||
if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y)
|
if (roambox_movingto_y > roambox_max_y || roambox_movingto_y < roambox_min_y)
|
||||||
roambox_movingto_y -= movey * 2;
|
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)
|
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)
|
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)",
|
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))
|
if (!CalculateNewPosition2(roambox_movingto_x, roambox_movingto_y, GetZ(), walksp, true))
|
||||||
{
|
{
|
||||||
roambox_movingto_x = roambox_max_x + 1; // force update
|
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);
|
SetMoving(false);
|
||||||
SendPosition(); // makes mobs stop clientside
|
SendPosition(); // makes mobs stop clientside
|
||||||
}
|
}
|
||||||
@ -1870,7 +1885,7 @@ bool NPC::AI_EngagedCastCheck() {
|
|||||||
// try casting a heal on nearby
|
// try casting a heal on nearby
|
||||||
if (!entity_list.AICheckCloseBeneficialSpells(this, 25, MobAISpellRange, SpellType_Heal)) {
|
if (!entity_list.AICheckCloseBeneficialSpells(this, 25, MobAISpellRange, SpellType_Heal)) {
|
||||||
//nobody to heal, try some detrimental spells.
|
//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.
|
//no spell to cast, try again soon.
|
||||||
AIautocastspell_timer->Start(RandomTimer(500, 1000), false);
|
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 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 TARGET_RESISTED 425 //Your target resisted the %1 spell.
|
||||||
#define YOU_RESIST 426 //You resist 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 429 //Summoning your corpse.
|
||||||
#define SUMMONING_CORPSE_OTHER 430 //Summoning %1's corpse.
|
#define SUMMONING_CORPSE_OTHER 430 //Summoning %1's corpse.
|
||||||
#define MISSING_SPELL_COMP_ITEM 433 //You are missing %1.
|
#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 OTHER_REGAIN_CAST 1033 //%1 regains concentration and continues casting.
|
||||||
#define GENERIC_SHOUT 1034 //%1 shouts '%2'
|
#define GENERIC_SHOUT 1034 //%1 shouts '%2'
|
||||||
#define GENERIC_EMOTE 1036 //%1 %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_START 1042 //%1 has become ENRAGED.
|
||||||
#define NPC_ENRAGE_END 1043 //%1 is no longer enraged.
|
#define NPC_ENRAGE_END 1043 //%1 is no longer enraged.
|
||||||
#define NPC_RAMPAGE 1044 //%1 goes on a RAMPAGE!
|
#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 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 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 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_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_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!
|
#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())
|
if (caster->IsClient())
|
||||||
{
|
{
|
||||||
//3: At maxed ability, Total Domination has a 50% chance of preventing the charm break that otherwise would have occurred.
|
//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)
|
if (MakeRandomInt(0, 99) < TotalDominationBonus)
|
||||||
return true;
|
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 ) {
|
if(!bRiposte && other->GetHP() > 0 ) {
|
||||||
TryWeaponProc(nullptr, weapon, other, Hand); //no weapon
|
TryWeaponProc(nullptr, weapon, other, Hand); //no weapon
|
||||||
|
TrySpellProc(nullptr, weapon, other, Hand);
|
||||||
}
|
}
|
||||||
|
|
||||||
TriggerDefensiveProcs(nullptr, other, Hand, damage);
|
TriggerDefensiveProcs(nullptr, other, Hand, damage);
|
||||||
@ -3851,24 +3852,17 @@ void Mob::HealDamage(uint32 amount, Mob* caster) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(amount > (maxhp - curhp))
|
if(amount > (maxhp - curhp))
|
||||||
acthealed = (maxhp - curhp);
|
acthealed = (maxhp - curhp);
|
||||||
else
|
else
|
||||||
acthealed = amount;
|
acthealed = amount;
|
||||||
|
|
||||||
char *TempString = nullptr;
|
if (acthealed > 100) {
|
||||||
|
if (caster) {
|
||||||
MakeAnyLenString(&TempString, "%d", acthealed);
|
Message_StringID(MT_NonMelee, YOU_HEALED, caster->GetCleanName(), itoa(acthealed));
|
||||||
|
if (caster != this)
|
||||||
if(acthealed > 100){
|
caster->Message_StringID(MT_NonMelee, YOU_HEAL, GetCleanName(), itoa(acthealed));
|
||||||
if(caster){
|
} else {
|
||||||
Message_StringID(MT_NonMelee, YOU_HEALED, caster->GetCleanName(), TempString);
|
|
||||||
if(caster != this){
|
|
||||||
caster->Message_StringID(MT_NonMelee, YOU_HEAL, GetCleanName(), TempString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
Message(MT_NonMelee, "You have been healed for %d points of damage.", acthealed);
|
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();
|
SendHPUpdate();
|
||||||
}
|
}
|
||||||
safe_delete_array(TempString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//proc chance includes proc bonus
|
//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();
|
int mydex = GetDEX();
|
||||||
float AABonus = 0;
|
float ProcChance = 0.0f;
|
||||||
ProcBonus = 0;
|
|
||||||
ProcChance = 0;
|
|
||||||
|
|
||||||
if (aabonuses.ProcChance)
|
switch (hand) {
|
||||||
AABonus = float(aabonuses.ProcChance) / 100.0f;
|
|
||||||
|
|
||||||
switch(hand){
|
|
||||||
case 13:
|
case 13:
|
||||||
weapon_speed = attack_timer.GetDuration();
|
weapon_speed = attack_timer.GetDuration();
|
||||||
break;
|
break;
|
||||||
@ -3909,24 +3896,20 @@ float Mob::GetProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_spe
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//calculate the weapon speed in ms, so we can use the rule to compare against.
|
//calculate the weapon speed in ms, so we can use the rule to compare against.
|
||||||
|
// fast as a client can swing, so should be the floor of the proc chance
|
||||||
if(weapon_speed < RuleI(Combat, MinHastedDelay)) // 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);
|
weapon_speed = RuleI(Combat, MinHastedDelay);
|
||||||
|
|
||||||
ProcBonus += (float(itembonuses.ProcChance + spellbonuses.ProcChance) / 1000.0f + AABonus);
|
if (RuleB(Combat, AdjustProcPerMinute)) {
|
||||||
|
ProcChance = (static_cast<float>(weapon_speed) *
|
||||||
if(RuleB(Combat, AdjustProcPerMinute) == true)
|
RuleR(Combat, AvgProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms
|
||||||
{
|
ProcBonus += static_cast<float>(mydex) * RuleR(Combat, ProcPerMinDexContrib);
|
||||||
ProcChance = ((float)weapon_speed * RuleR(Combat, AvgProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms
|
ProcChance += ProcChance * ProcBonus / 100.0f;
|
||||||
ProcBonus += float(mydex) * RuleR(Combat, ProcPerMinDexContrib) / 100.0f;
|
} else {
|
||||||
ProcChance = ProcChance + (ProcChance * ProcBonus);
|
ProcChance = RuleR(Combat, BaseProcChance) +
|
||||||
}
|
static_cast<float>(mydex) / RuleR(Combat, ProcDexDivideBy);
|
||||||
else
|
ProcChance += ProcChance * ProcBonus / 100.0f;
|
||||||
{
|
|
||||||
ProcChance = RuleR(Combat, BaseProcChance) + float(mydex) / RuleR(Combat, ProcDexDivideBy);
|
|
||||||
ProcChance = ProcChance + (ProcChance * ProcBonus);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mlog(COMBAT__PROCS, "Proc chance %.2f (%.2f from bonuses)", ProcChance, ProcBonus);
|
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;
|
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.
|
//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));
|
//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
|
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) {
|
if(!weapon_g) {
|
||||||
TryWeaponProc(nullptr, (const Item_Struct*)nullptr, on, hand);
|
TrySpellProc(nullptr, (const Item_Struct*)nullptr, on);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!weapon_g->IsType(ItemClassCommon)) {
|
if(!weapon_g->IsType(ItemClassCommon)) {
|
||||||
TryWeaponProc(nullptr, (const Item_Struct*) nullptr, on, hand);
|
TrySpellProc(nullptr, (const Item_Struct*)nullptr, on);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//do main procs
|
// Innate + aug procs from weapons
|
||||||
|
// TODO: powersource procs
|
||||||
TryWeaponProc(weapon_g, weapon_g->GetItem(), on, hand);
|
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);
|
||||||
|
|
||||||
|
return;
|
||||||
//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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
uint16 skillinuse = 28;
|
||||||
int ourlevel = GetLevel();
|
int ourlevel = GetLevel();
|
||||||
float ProcChance, ProcBonus;
|
float ProcBonus = static_cast<float>(aabonuses.ProcChanceSPA +
|
||||||
if(weapon!=nullptr)
|
spellbonuses.ProcChanceSPA + itembonuses.ProcChanceSPA);
|
||||||
GetProcChances(ProcBonus, ProcChance, weapon->Delay, hand);
|
ProcBonus += static_cast<float>(itembonuses.ProcChance) / 10.0f; // Combat Effects
|
||||||
else
|
float ProcChance = GetProcChances(ProcBonus, weapon->Delay, hand);
|
||||||
GetProcChances(ProcBonus, ProcChance);
|
|
||||||
|
|
||||||
if(hand != 13) //Is Archery intended to proc at 50% rate?
|
if (hand != 13) //Is Archery intened to proc at 50% rate?
|
||||||
ProcChance /= 2;
|
ProcChance /= 2;
|
||||||
|
|
||||||
//give weapon a chance to proc first.
|
// Try innate proc on weapon
|
||||||
if(weapon != nullptr) {
|
// We can proc once here, either weapon or one aug
|
||||||
skillinuse = GetSkillByItemType(weapon->ItemType);
|
bool proced = false; // silly bool to prevent augs from going if weapon does
|
||||||
if (weapon->Proc.Type == ET_CombatProc) {
|
skillinuse = GetSkillByItemType(weapon->ItemType);
|
||||||
float WPC = ProcChance*(100.0f+(float)weapon->ProcRate)/100.0f;
|
if (weapon->Proc.Type == ET_CombatProc) {
|
||||||
if (MakeRandomFloat(0, 1) <= WPC) { // 255 dex = 0.084 chance of proc. No idea what this number should be really.
|
float WPC = ProcChance * (100.0f + // Proc chance for this weapon
|
||||||
if(weapon->Proc.Level > ourlevel) {
|
static_cast<float>(weapon->ProcRate)) / 100.0f;
|
||||||
mlog(COMBAT__PROCS, "Tried to proc (%s), but our level (%d) is lower than required (%d)", weapon->Name, ourlevel, weapon->Proc.Level);
|
if (MakeRandomFloat(0, 1) <= WPC) { // 255 dex = 0.084 chance of proc. No idea what this number should be really.
|
||||||
Mob * own = GetOwner();
|
if (weapon->Proc.Level > ourlevel) {
|
||||||
if(own != nullptr) {
|
mlog(COMBAT__PROCS,
|
||||||
own->Message_StringID(13,PROC_PETTOOLOW);
|
"Tried to proc (%s), but our level (%d) is lower than required (%d)",
|
||||||
} else {
|
weapon->Name, ourlevel, weapon->Proc.Level);
|
||||||
Message_StringID(13,PROC_TOOLOW);
|
if (IsPet()) {
|
||||||
}
|
Mob *own = GetOwner();
|
||||||
|
if (own)
|
||||||
|
own->Message_StringID(13, PROC_PETTOOLOW);
|
||||||
} else {
|
} else {
|
||||||
mlog(COMBAT__PROCS, "Attacking weapon (%s) successfully procing spell %d (%.2f percent chance)", weapon->Name, weapon->Proc.Effect, ProcChance*100);
|
Message_StringID(13, PROC_TOOLOW);
|
||||||
ExecWeaponProc(inst, weapon->Proc.Effect, on);
|
|
||||||
}
|
}
|
||||||
} else {
|
} 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) {
|
if (!proced && inst) {
|
||||||
LogFile->write(EQEMuLog::Error, "ProcBonus was -1 value!");
|
for (int r = 0; r < MAX_AUGMENT_SLOTS; r++) {
|
||||||
return;
|
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 (aug->Proc.Type == ET_CombatProc) {
|
||||||
if (weapon != nullptr) {
|
float APC = ProcChance * (100.0f + // Proc chance for this aug
|
||||||
if (weapon->ItemType == ItemTypeBow || weapon->ItemType == ItemTypeLargeThrowing || weapon->ItemType == ItemTypeSmallThrowing) {
|
static_cast<float>(aug->ProcRate)) / 100.0f;
|
||||||
bRangedAttack = true;
|
if (MakeRandomFloat(0, 1) <= APC) {
|
||||||
}
|
if (aug->Proc.Level > ourlevel) {
|
||||||
}
|
if (IsPet()) {
|
||||||
|
Mob *own = GetOwner();
|
||||||
bool isRanged = false;
|
if (own)
|
||||||
if(weapon)
|
own->Message_StringID(13, PROC_PETTOOLOW);
|
||||||
{
|
} else {
|
||||||
if(weapon->ItemType == ItemTypeArrow ||
|
Message_StringID(13, PROC_TOOLOW);
|
||||||
weapon->ItemType == ItemTypeLargeThrowing ||
|
}
|
||||||
weapon->ItemType == ItemTypeSmallThrowing ||
|
} else {
|
||||||
weapon->ItemType == ItemTypeBow)
|
ExecWeaponProc(aug_i, aug->Proc.Effect, on);
|
||||||
{
|
break;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// TODO: Powersource procs
|
||||||
|
if (HasSkillProcs())
|
||||||
|
TrySkillProc(on, skillinuse, ProcChance);
|
||||||
|
|
||||||
if(!isRanged)
|
return;
|
||||||
{
|
}
|
||||||
if(IsPet() && hand != 13) //Pets can only proc spell procs from their primay hand (ie; beastlord pets)
|
|
||||||
{
|
void Mob::TrySpellProc(const ItemInst *inst, const Item_Struct *weapon, Mob *on, uint16 hand)
|
||||||
//Maybe implement this later if pets are ever given dual procs?
|
{
|
||||||
|
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
|
|
||||||
{
|
// Spell procs (buffs)
|
||||||
int chance = ProcChance * (SpellProcs[i].chance);
|
if (SpellProcs[i].spellID != SPELL_UNKNOWN) {
|
||||||
if(MakeRandomInt(0, 100) < chance) {
|
float chance = ProcChance * (SpellProcs[i].chance / 100.0f);
|
||||||
mlog(COMBAT__PROCS, "Spell proc %d procing spell %d (%d percent chance)", i, SpellProcs[i].spellID, chance);
|
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);
|
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on);
|
||||||
CheckNumHitsRemaining(11, 0, SpellProcs[i].base_spellID);
|
CheckNumHitsRemaining(11, 0, SpellProcs[i].base_spellID);
|
||||||
} else {
|
} 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (rangedattk) { // ranged only
|
||||||
if (bRangedAttack) {
|
// ranged spell procs (buffs)
|
||||||
int chance = ProcChance * RangedProcs[i].chance;
|
if (RangedProcs[i].spellID != SPELL_UNKNOWN) {
|
||||||
if(MakeRandomInt(0, 100) < chance) {
|
float chance = ProcChance * (RangedProcs[i].chance / 100.0f);
|
||||||
mlog(COMBAT__PROCS, "Ranged proc %d procing spell %d", i, RangedProcs[i].spellID, RangedProcs[i].chance);
|
if (MakeRandomFloat(0, 1) <= chance) {
|
||||||
ExecWeaponProc(nullptr, RangedProcs[i].spellID, on);
|
mlog(COMBAT__PROCS,
|
||||||
CheckNumHitsRemaining(11, 0, RangedProcs[i].base_spellID);
|
"Ranged proc %d procing spell %d (%.2f percent chance)",
|
||||||
} else {
|
i, RangedProcs[i].spellID, chance);
|
||||||
mlog(COMBAT__PROCS, "Ranged proc %d failed to proc %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 (%.2f percent chance)",
|
||||||
|
i, RangedProcs[i].spellID, chance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasSkillProcs())
|
return;
|
||||||
TrySkillProc(on, skillinuse, ProcChance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::TryPetCriticalHit(Mob *defender, uint16 skill, int32 &damage)
|
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;
|
newbon->GiveDoubleAttack += base1;
|
||||||
break;
|
break;
|
||||||
case SE_ProcChance:
|
case SE_ProcChance:
|
||||||
newbon->ProcChance += base1;
|
newbon->ProcChanceSPA += base1;
|
||||||
break;
|
break;
|
||||||
case SE_RiposteChance:
|
case SE_RiposteChance:
|
||||||
newbon->RiposteChance += base1;
|
newbon->RiposteChance += base1;
|
||||||
@ -1228,6 +1228,14 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
|||||||
break;
|
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:
|
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)
|
if (RuleB(Spells, AdditiveBonusValues) && item_bonus)
|
||||||
newbon->ProcChance += effect_value;
|
newbon->ProcChanceSPA += effect_value;
|
||||||
|
|
||||||
else if((effect_value < 0) && (newbon->DoubleAttackChance > effect_value))
|
else if((effect_value < 0) && (newbon->ProcChanceSPA > effect_value))
|
||||||
newbon->ProcChance = effect_value;
|
newbon->ProcChanceSPA = effect_value;
|
||||||
|
|
||||||
if(newbon->ProcChance < effect_value)
|
if(newbon->ProcChanceSPA < effect_value)
|
||||||
newbon->ProcChance = effect_value;
|
newbon->ProcChanceSPA = effect_value;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2524,6 +2529,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
|||||||
newbon->DistanceRemoval = true;
|
newbon->DistanceRemoval = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SE_FrenziedDevastation:
|
||||||
|
newbon->FrenziedDevastation += spells[spell_id].base2[i];
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3311,9 +3320,9 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SE_ProcChance:
|
case SE_ProcChance:
|
||||||
spellbonuses.ProcChance = effect_value;
|
spellbonuses.ProcChanceSPA = effect_value;
|
||||||
aabonuses.ProcChance = effect_value;
|
aabonuses.ProcChanceSPA = effect_value;
|
||||||
itembonuses.ProcChance = effect_value;
|
itembonuses.ProcChanceSPA = effect_value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SE_ExtraAttackChance:
|
case SE_ExtraAttackChance:
|
||||||
@ -3866,7 +3875,13 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
|||||||
spellbonuses.ImprovedTaunt[0] = effect_value;
|
spellbonuses.ImprovedTaunt[0] = effect_value;
|
||||||
spellbonuses.ImprovedTaunt[1] = effect_value;
|
spellbonuses.ImprovedTaunt[1] = effect_value;
|
||||||
spellbonuses.ImprovedTaunt[2] = -1;
|
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
|
//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();
|
int mydex = GetDEX();
|
||||||
float AABonus = 0;
|
float ProcChance = 0.0f;
|
||||||
ProcBonus = 0;
|
|
||||||
ProcChance = 0;
|
|
||||||
|
|
||||||
if (aabonuses.ProcChance)
|
switch (hand) {
|
||||||
AABonus = float(aabonuses.ProcChance) / 100.0f;
|
|
||||||
|
|
||||||
switch(hand){
|
|
||||||
case SLOT_PRIMARY:
|
case SLOT_PRIMARY:
|
||||||
weapon_speed = attack_timer.GetDuration();
|
weapon_speed = attack_timer.GetDuration();
|
||||||
break;
|
break;
|
||||||
@ -7726,24 +7721,20 @@ float Bot::GetProcChances(float &ProcBonus, float &ProcChance, uint16 weapon_spe
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//calculate the weapon speed in ms, so we can use the rule to compare against.
|
//calculate the weapon speed in ms, so we can use the rule to compare against.
|
||||||
|
// fast as a client can swing, so should be the floor of the proc chance
|
||||||
if(weapon_speed < RuleI(Combat, MinHastedDelay)) // 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);
|
weapon_speed = RuleI(Combat, MinHastedDelay);
|
||||||
|
|
||||||
ProcBonus += (float(itembonuses.ProcChance + spellbonuses.ProcChance) / 1000.0f + AABonus);
|
if (RuleB(Combat, AdjustProcPerMinute)) {
|
||||||
|
ProcChance = (static_cast<float>(weapon_speed) *
|
||||||
if(RuleB(Combat, AdjustProcPerMinute) == true)
|
RuleR(Combat, AvgProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms
|
||||||
{
|
ProcBonus += static_cast<float>(mydex) * RuleR(Combat, ProcPerMinDexContrib);
|
||||||
ProcChance = ((float)weapon_speed * RuleR(Combat, AvgProcsPerMinute) / 60000.0f); // compensate for weapon_speed being in ms
|
ProcChance += ProcChance * ProcBonus / 100.0f;
|
||||||
ProcBonus += float(mydex) * RuleR(Combat, ProcPerMinDexContrib) / 100.0f;
|
} else {
|
||||||
ProcChance = ProcChance + (ProcChance * ProcBonus);
|
ProcChance = RuleR(Combat, BaseProcChance) +
|
||||||
}
|
static_cast<float>(mydex) / RuleR(Combat, ProcDexDivideBy);
|
||||||
else
|
ProcChance += ProcChance*ProcBonus / 100.0f;
|
||||||
{
|
|
||||||
ProcChance = RuleR(Combat, BaseProcChance) + float(mydex) / RuleR(Combat, ProcDexDivideBy);
|
|
||||||
ProcChance = ProcChance + (ProcChance * ProcBonus);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mlog(COMBAT__PROCS, "Proc chance %.2f (%.2f from bonuses)", ProcChance, ProcBonus);
|
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 BotGetSpells(int spellslot) { return AIspells[spellslot].spellid; }
|
||||||
uint16 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; }
|
uint16 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; }
|
||||||
uint16 BotGetSpellPriority(int spellslot) { return AIspells[spellslot].priority; }
|
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 bool AvoidDamage(Mob* other, int32 &damage, bool CanRiposte);
|
||||||
virtual int GetMonkHandToHandDamage(void);
|
virtual int GetMonkHandToHandDamage(void);
|
||||||
virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse);
|
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);
|
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) {
|
void Client::SetTint(int16 in_slot, uint32 color) {
|
||||||
Color_Struct new_color;
|
Color_Struct new_color;
|
||||||
|
|||||||
@ -250,6 +250,14 @@ public:
|
|||||||
uint8 SlotConvert(uint8 slot,bool bracer=false);
|
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, 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);
|
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 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);
|
void SendTraderItem(uint32 item_id,uint16 quantity);
|
||||||
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
|
uint16 FindTraderItem(int32 SerialNumber,uint16 Quantity);
|
||||||
|
|||||||
@ -1615,7 +1615,8 @@ void Client::Handle_OP_Shielding(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
if (shield_target)
|
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++)
|
for (int y = 0; y < 2; y++)
|
||||||
{
|
{
|
||||||
if (shield_target->shielder[y].shielder_id == GetID())
|
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)
|
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();
|
shield_target->shielder[x].shielder_id = GetID();
|
||||||
int shieldbonus = shield->AC*2;
|
int shieldbonus = shield->AC*2;
|
||||||
switch (GetAA(197))
|
switch (GetAA(197))
|
||||||
@ -1677,7 +1679,7 @@ void Client::Handle_OP_Shielding(const EQApplicationPacket *app)
|
|||||||
}
|
}
|
||||||
if (!ack)
|
if (!ack)
|
||||||
{
|
{
|
||||||
Message(0, "No more than two warriors may shield the same being.");
|
Message_StringID(0, ALREADY_SHIELDED);
|
||||||
shield_target = 0;
|
shield_target = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -12618,32 +12620,38 @@ void Client::Handle_OP_AltCurrencySellSelection(const EQApplicationPacket *app)
|
|||||||
uint32 cost = 0;
|
uint32 cost = 0;
|
||||||
uint32 current_currency = GetAlternateCurrencyValue(alt_cur_id);
|
uint32 current_currency = GetAlternateCurrencyValue(alt_cur_id);
|
||||||
uint32 merchant_id = tar->MerchantType;
|
uint32 merchant_id = tar->MerchantType;
|
||||||
bool found = false;
|
|
||||||
std::list<MerchantList> merlist = zone->merchanttable[merchant_id];
|
if (RuleB(Merchant, EnableAltCurrencySell)) {
|
||||||
std::list<MerchantList>::const_iterator itr;
|
bool found = false;
|
||||||
for(itr = merlist.begin(); itr != merlist.end(); ++itr) {
|
std::list<MerchantList> merlist = zone->merchanttable[merchant_id];
|
||||||
MerchantList ml = *itr;
|
std::list<MerchantList>::const_iterator itr;
|
||||||
if(GetLevel() < ml.level_required) {
|
for (itr = merlist.begin(); itr != merlist.end(); ++itr) {
|
||||||
continue;
|
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 (!found) {
|
||||||
if(fac != 0 && GetModCharacterFactionLevel(fac) < ml.faction_required) {
|
cost = 0;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
item = database.GetItem(ml.item);
|
|
||||||
if(!item)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(item->ID == inst->GetItem()->ID) {
|
|
||||||
cost = ml.alt_currency_cost;
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
if(!found) {
|
|
||||||
cost = 0;
|
cost = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12793,6 +12801,10 @@ void Client::Handle_OP_AltCurrencySell(const EQApplicationPacket *app) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!RuleB(Merchant, EnableAltCurrencySell)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const Item_Struct* item = nullptr;
|
const Item_Struct* item = nullptr;
|
||||||
uint32 cost = 0;
|
uint32 cost = 0;
|
||||||
uint32 current_currency = GetAlternateCurrencyValue(alt_cur_id);
|
uint32 current_currency = GetAlternateCurrencyValue(alt_cur_id);
|
||||||
@ -12815,7 +12827,7 @@ void Client::Handle_OP_AltCurrencySell(const EQApplicationPacket *app) {
|
|||||||
if(!item)
|
if(!item)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(item->ID == inst->GetItem()->ID) {
|
if(item->ID == inst->GetItem()->ID) {
|
||||||
cost = ml.alt_currency_cost;
|
cost = ml.alt_currency_cost;
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -581,7 +581,8 @@ bool Client::Process() {
|
|||||||
{
|
{
|
||||||
if (!CombatRange(shield_target))
|
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++)
|
for (int y = 0; y < 2; y++)
|
||||||
{
|
{
|
||||||
if (shield_target->shielder[y].shielder_id == GetID())
|
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) {
|
else if (strcasecmp(sep->arg[1], "roambox") == 0) {
|
||||||
if (target && target->IsAIControlled() && target->IsNPC()) {
|
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 tmp = 2500;
|
||||||
|
uint32 tmp2 = 2500;
|
||||||
if (sep->IsNumber(7))
|
if (sep->IsNumber(7))
|
||||||
tmp = atoi(sep->arg[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)) {
|
else if ((sep->argnum == 3 || sep->argnum == 4) && sep->IsNumber(2) && sep->IsNumber(3)) {
|
||||||
uint32 tmp = 2500;
|
uint32 tmp = 2500;
|
||||||
|
uint32 tmp2 = 2500;
|
||||||
if (sep->IsNumber(4))
|
if (sep->IsNumber(4))
|
||||||
tmp = atoi(sep->arg[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 {
|
else {
|
||||||
c->Message(0, "Usage: #ai roambox dist max_x min_x max_y min_y [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]");
|
c->Message(0, "Usage: #ai roambox dist roamdist [delay] [mindelay]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@ -122,7 +122,10 @@ enum {
|
|||||||
TETHER = 33,
|
TETHER = 33,
|
||||||
DESTRUCTIBLE_OBJECT = 34,
|
DESTRUCTIBLE_OBJECT = 34,
|
||||||
NO_HARM_FROM_CLIENT = 35,
|
NO_HARM_FROM_CLIENT = 35,
|
||||||
MAX_SPECIAL_ATTACK = 36
|
ALWAYS_FLEE = 36,
|
||||||
|
FLEE_PERCENT = 37,
|
||||||
|
MAX_SPECIAL_ATTACK = 38
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum { //fear states
|
typedef enum { //fear states
|
||||||
@ -274,6 +277,7 @@ struct StatBonuses {
|
|||||||
int16 DamageModifier[HIGHEST_SKILL+2]; //i
|
int16 DamageModifier[HIGHEST_SKILL+2]; //i
|
||||||
int16 MinDamageModifier[HIGHEST_SKILL+2]; //i
|
int16 MinDamageModifier[HIGHEST_SKILL+2]; //i
|
||||||
int16 ProcChance; // ProcChance/10 == % increase i = CombatEffects
|
int16 ProcChance; // ProcChance/10 == % increase i = CombatEffects
|
||||||
|
int16 ProcChanceSPA; // ProcChance from spell effects
|
||||||
int16 ExtraAttackChance;
|
int16 ExtraAttackChance;
|
||||||
int16 DoTShielding;
|
int16 DoTShielding;
|
||||||
int16 DivineSaveChance[2]; // Second Chance (base1 = chance, base2 = spell on trigger)
|
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
|
//uint16 BlockSpellEffect[EFFECT_COUNT]; // Prevents spells with certain effects from landing on you *no longer used
|
||||||
bool ImmuneToFlee; // Bypass the fleeing flag
|
bool ImmuneToFlee; // Bypass the fleeing flag
|
||||||
uint16 VoiceGraft; // Stores the ID of the mob with which to talk through
|
uint16 VoiceGraft; // Stores the ID of the mob with which to talk through
|
||||||
uint16 SpellProcChance; // chance to proc from sympathetic spell effects
|
int16 SpellProcChance; // chance to proc from sympathetic spell effects
|
||||||
uint16 CharmBreakChance; // chance to break charm
|
int16 CharmBreakChance; // chance to break charm
|
||||||
int16 SongRange; // increases range of beneficial bard songs
|
int16 SongRange; // increases range of beneficial bard songs
|
||||||
uint16 HPToManaConvert; // Uses HP to cast spells at specific conversion
|
uint16 HPToManaConvert; // Uses HP to cast spells at specific conversion
|
||||||
uint16 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have.
|
uint16 FocusEffects[HIGHEST_FOCUS+1]; // Stores the focus effectid for each focustype you have.
|
||||||
@ -335,6 +339,7 @@ struct StatBonuses {
|
|||||||
bool DivineAura; // invulnerability
|
bool DivineAura; // invulnerability
|
||||||
bool DistanceRemoval; // Check if Cancle if Moved effect is present
|
bool DistanceRemoval; // Check if Cancle if Moved effect is present
|
||||||
int16 ImprovedTaunt[3]; // 0 = Max Level 1 = Aggro modifier 2 = buffid
|
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 AbsorbMagicAtt; // Magic Rune *Need to be implemented for NegateEffect
|
||||||
//bool MeleeRune; // Melee Rune *Need to be implemented for NegateEffect
|
//bool MeleeRune; // Melee Rune *Need to be implemented for NegateEffect
|
||||||
|
|
||||||
|
|||||||
@ -82,6 +82,8 @@ int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
|||||||
int chance = RuleI(Spells, BaseCritChance);
|
int chance = RuleI(Spells, BaseCritChance);
|
||||||
chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
|
chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
|
||||||
|
|
||||||
|
chance += itembonuses.FrenziedDevastation + spellbonuses.FrenziedDevastation + aabonuses.FrenziedDevastation;
|
||||||
|
|
||||||
if (chance > 0){
|
if (chance > 0){
|
||||||
|
|
||||||
int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals.
|
int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals.
|
||||||
@ -123,32 +125,34 @@ int32 Client::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
|||||||
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
|
if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
|
||||||
value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100;
|
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;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
value = value_BaseEffect;
|
value = value_BaseEffect;
|
||||||
|
|
||||||
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
|
value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
|
||||||
|
|
||||||
value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
|
value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
|
||||||
|
|
||||||
if (target) {
|
if (target) {
|
||||||
value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100;
|
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)
|
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;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
|
int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||||
|
|
||||||
@ -295,8 +299,11 @@ int32 Client::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
|||||||
|
|
||||||
value += value*target->GetHealRate(spell_id, this)/100;
|
value += value*target->GetHealRate(spell_id, this)/100;
|
||||||
|
|
||||||
if (Critical)
|
if (Critical) {
|
||||||
entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), value);
|
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;
|
return value;
|
||||||
}
|
}
|
||||||
@ -321,6 +328,12 @@ int32 Client::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
|||||||
|
|
||||||
int32 Client::GetActSpellCost(uint16 spell_id, int32 cost)
|
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
|
// 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)
|
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
|
// 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
|
// 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) ||
|
IsFearSpell(spell_id) ||
|
||||||
IsCharmSpell(spell_id) ||
|
IsCharmSpell(spell_id) ||
|
||||||
IsMezSpell(spell_id) ||
|
IsMezSpell(spell_id) ||
|
||||||
|
|||||||
@ -1012,6 +1012,22 @@ Mob *EntityList::GetMobByNpcTypeID(uint32 get_id)
|
|||||||
return nullptr;
|
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)
|
Object *EntityList::GetObjectByDBID(uint32 id)
|
||||||
{
|
{
|
||||||
if (id == 0 || object_list.empty())
|
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)
|
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;
|
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, ...)
|
void EntityList::MessageClose(Mob* sender, bool skipsender, float dist, uint32 type, const char* message, ...)
|
||||||
{
|
{
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
|
|||||||
@ -135,6 +135,7 @@ public:
|
|||||||
inline Mob *GetMobID(uint16 id) { return(GetMob(id)); } //for perl
|
inline Mob *GetMobID(uint16 id) { return(GetMob(id)); } //for perl
|
||||||
Mob *GetMob(const char* name);
|
Mob *GetMob(const char* name);
|
||||||
Mob *GetMobByNpcTypeID(uint32 get_id);
|
Mob *GetMobByNpcTypeID(uint32 get_id);
|
||||||
|
bool IsMobSpawnedByNpcTypeID(uint32 get_id);
|
||||||
Mob *GetTargetForVirus(Mob* spreader);
|
Mob *GetTargetForVirus(Mob* spreader);
|
||||||
inline NPC *GetNPCByID(uint16 id)
|
inline NPC *GetNPCByID(uint16 id)
|
||||||
{ return npc_list.count(id) ? npc_list.at(id) : nullptr; }
|
{ 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 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 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 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 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 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, const char* message, ...);
|
||||||
void ChannelMessage(Mob* from, uint8 chan_num, uint8 language, uint8 lang_skill, 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
|
//see if were possibly hurt enough
|
||||||
float ratio = GetHPRatio();
|
float ratio = GetHPRatio();
|
||||||
if(ratio >= RuleI(Combat, FleeHPRatio))
|
float fleeratio = GetSpecialAbility(FLEE_PERCENT);
|
||||||
|
fleeratio = fleeratio > 0 ? fleeratio : RuleI(Combat, FleeHPRatio);
|
||||||
|
|
||||||
|
if(ratio >= fleeratio)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//we might be hurt enough, check con now..
|
//we might be hurt enough, check con now..
|
||||||
@ -77,25 +80,24 @@ void Mob::CheckFlee() {
|
|||||||
switch(con) {
|
switch(con) {
|
||||||
//these values are not 100% researched
|
//these values are not 100% researched
|
||||||
case CON_GREEN:
|
case CON_GREEN:
|
||||||
run_ratio = RuleI(Combat, FleeHPRatio);
|
run_ratio = fleeratio;
|
||||||
break;
|
break;
|
||||||
case CON_LIGHTBLUE:
|
case CON_LIGHTBLUE:
|
||||||
run_ratio = RuleI(Combat, FleeHPRatio) * 8 / 10;
|
run_ratio = fleeratio * 9 / 10;
|
||||||
break;
|
break;
|
||||||
case CON_BLUE:
|
case CON_BLUE:
|
||||||
run_ratio = RuleI(Combat, FleeHPRatio) * 6 / 10;
|
run_ratio = fleeratio * 8 / 10;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
run_ratio = RuleI(Combat, FleeHPRatio) * 4 / 10;
|
run_ratio = fleeratio * 7 / 10;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(ratio < run_ratio)
|
if(ratio < run_ratio)
|
||||||
{
|
{
|
||||||
if (RuleB(Combat, FleeIfNotAlone) ||
|
if (RuleB(Combat, FleeIfNotAlone) ||
|
||||||
(!RuleB(Combat, FleeIfNotAlone) &&
|
GetSpecialAbility(ALWAYS_FLEE) ||
|
||||||
(entity_list.GetHatedCount(hate_top, this) == 0)))
|
(!RuleB(Combat, FleeIfNotAlone) && (entity_list.GetHatedCount(hate_top, this) == 0)))
|
||||||
StartFleeing();
|
StartFleeing();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +112,9 @@ void Mob::ProcessFlee() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//see if we are still dying, if so, do nothing
|
//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;
|
return;
|
||||||
|
|
||||||
//we are not dying anymore... see what we do next
|
//we are not dying anymore... see what we do next
|
||||||
@ -128,18 +132,18 @@ void Mob::ProcessFlee() {
|
|||||||
float Mob::GetFearSpeed() {
|
float Mob::GetFearSpeed() {
|
||||||
if(flee_mode) {
|
if(flee_mode) {
|
||||||
//we know ratio < FLEE_HP_RATIO
|
//we know ratio < FLEE_HP_RATIO
|
||||||
float speed = GetRunspeed();
|
float speed = GetBaseRunspeed();
|
||||||
float ratio = GetHPRatio();
|
float ratio = GetHPRatio();
|
||||||
|
float multiplier = RuleR(Combat, FleeMultiplier);
|
||||||
|
|
||||||
// mob's movement will halt with a decent snare at HP specified by rule.
|
if(GetSnaredAmount() > 40)
|
||||||
if (ratio <= RuleI(Combat, FleeSnareHPRatio) && GetSnaredAmount() > 40) {
|
multiplier = multiplier / 6.0f;
|
||||||
return 0.0001f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ratio < FLEE_HP_MINSPEED)
|
speed = speed * ratio * multiplier / 100;
|
||||||
ratio = FLEE_HP_MINSPEED;
|
|
||||||
|
|
||||||
speed = speed * 0.5 * ratio / 100;
|
//NPC will eventually stop. Snares speeds this up.
|
||||||
|
if(speed < 0.09)
|
||||||
|
speed = 0.0001f;
|
||||||
|
|
||||||
return(speed);
|
return(speed);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -560,6 +560,11 @@ void Lua_Client::UnscribeSpellAll(bool update_client) {
|
|||||||
self->UnscribeSpellAll(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) {
|
void Lua_Client::UntrainDisc(int slot) {
|
||||||
Lua_Safe_Call_Void();
|
Lua_Safe_Call_Void();
|
||||||
self->UntrainDisc(slot);
|
self->UntrainDisc(slot);
|
||||||
@ -1352,6 +1357,7 @@ luabind::scope lua_register_client() {
|
|||||||
.def("UnscribeSpell", (void(Lua_Client::*)(int,bool))&Lua_Client::UnscribeSpell)
|
.def("UnscribeSpell", (void(Lua_Client::*)(int,bool))&Lua_Client::UnscribeSpell)
|
||||||
.def("UnscribeSpellAll", (void(Lua_Client::*)(void))&Lua_Client::UnscribeSpellAll)
|
.def("UnscribeSpellAll", (void(Lua_Client::*)(void))&Lua_Client::UnscribeSpellAll)
|
||||||
.def("UnscribeSpellAll", (void(Lua_Client::*)(bool))&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))&Lua_Client::UntrainDisc)
|
||||||
.def("UntrainDisc", (void(Lua_Client::*)(int,bool))&Lua_Client::UntrainDisc)
|
.def("UntrainDisc", (void(Lua_Client::*)(int,bool))&Lua_Client::UntrainDisc)
|
||||||
.def("UntrainDiscAll", (void(Lua_Client::*)(void))&Lua_Client::UntrainDiscAll)
|
.def("UntrainDiscAll", (void(Lua_Client::*)(void))&Lua_Client::UntrainDiscAll)
|
||||||
|
|||||||
@ -138,6 +138,7 @@ public:
|
|||||||
void UnscribeSpell(int slot, bool update_client);
|
void UnscribeSpell(int slot, bool update_client);
|
||||||
void UnscribeSpellAll();
|
void UnscribeSpellAll();
|
||||||
void UnscribeSpellAll(bool update_client);
|
void UnscribeSpellAll(bool update_client);
|
||||||
|
void TrainDisc(int itemid);
|
||||||
void UntrainDisc(int slot);
|
void UntrainDisc(int slot);
|
||||||
void UntrainDisc(int slot, bool update_client);
|
void UntrainDisc(int slot, bool update_client);
|
||||||
void UntrainDiscAll();
|
void UntrainDiscAll();
|
||||||
|
|||||||
@ -65,6 +65,11 @@ Lua_Mob Lua_EntityList::GetMobByNpcTypeID(int npc_type) {
|
|||||||
return Lua_Mob(self->GetMobByNpcTypeID(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_NPC Lua_EntityList::GetNPCByID(int id) {
|
||||||
Lua_Safe_Call_Class(Lua_NPC);
|
Lua_Safe_Call_Class(Lua_NPC);
|
||||||
return Lua_NPC(self->GetNPCByID(id));
|
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::*)(const char*))&Lua_EntityList::GetMob)
|
||||||
.def("GetMob", (Lua_Mob(Lua_EntityList::*)(int))&Lua_EntityList::GetMob)
|
.def("GetMob", (Lua_Mob(Lua_EntityList::*)(int))&Lua_EntityList::GetMob)
|
||||||
.def("GetMobByNpcTypeID", (Lua_Mob(Lua_EntityList::*)(int))&Lua_EntityList::GetMobByNpcTypeID)
|
.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("GetNPCByID", (Lua_NPC(Lua_EntityList::*)(int))&Lua_EntityList::GetNPCByID)
|
||||||
.def("GetNPCByNPCTypeID", (Lua_NPC(Lua_EntityList::*)(int))&Lua_EntityList::GetNPCByNPCTypeID)
|
.def("GetNPCByNPCTypeID", (Lua_NPC(Lua_EntityList::*)(int))&Lua_EntityList::GetNPCByNPCTypeID)
|
||||||
.def("GetClientByName", (Lua_Client(Lua_EntityList::*)(const char*))&Lua_EntityList::GetClientByName)
|
.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(const char *name);
|
||||||
Lua_Mob GetMob(int id);
|
Lua_Mob GetMob(int id);
|
||||||
Lua_Mob GetMobByNpcTypeID(int npc_type);
|
Lua_Mob GetMobByNpcTypeID(int npc_type);
|
||||||
|
bool IsMobSpawnedByNpcTypeID(int npc_type);
|
||||||
Lua_NPC GetNPCByID(int id);
|
Lua_NPC GetNPCByID(int id);
|
||||||
Lua_NPC GetNPCByNPCTypeID(int npc_type);
|
Lua_NPC GetNPCByNPCTypeID(int npc_type);
|
||||||
Lua_Client GetClientByName(const char *name);
|
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("leash", static_cast<int>(LEASH)),
|
||||||
luabind::value("tether", static_cast<int>(TETHER)),
|
luabind::value("tether", static_cast<int>(TETHER)),
|
||||||
luabind::value("destructible_object", static_cast<int>(DESTRUCTIBLE_OBJECT)),
|
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);
|
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();
|
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() {
|
int Lua_NPC::GetNPCSpellsID() {
|
||||||
@ -494,7 +494,7 @@ luabind::scope lua_register_npc() {
|
|||||||
.def("SaveGuardSpot", (void(Lua_NPC::*)(bool))&Lua_NPC::SaveGuardSpot)
|
.def("SaveGuardSpot", (void(Lua_NPC::*)(bool))&Lua_NPC::SaveGuardSpot)
|
||||||
.def("IsGuarding", (bool(Lua_NPC::*)(void))&Lua_NPC::IsGuarding)
|
.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))&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("GetNPCSpellsID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID)
|
||||||
.def("GetSpawnPointID", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointID)
|
.def("GetSpawnPointID", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointID)
|
||||||
.def("GetSpawnPointX", (float(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointX)
|
.def("GetSpawnPointX", (float(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointX)
|
||||||
|
|||||||
@ -85,7 +85,7 @@ public:
|
|||||||
void SaveGuardSpot(bool clear);
|
void SaveGuardSpot(bool clear);
|
||||||
bool IsGuarding();
|
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);
|
||||||
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 GetNPCSpellsID();
|
||||||
int GetSpawnPointID();
|
int GetSpawnPointID();
|
||||||
float GetSpawnPointX();
|
float GetSpawnPointX();
|
||||||
|
|||||||
@ -2824,7 +2824,8 @@ int32 Merc::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
|||||||
|
|
||||||
value = (value * GetSpellScale() / 100);
|
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;
|
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,
|
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* 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) { }
|
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(const char *format, ...);
|
||||||
void Say_StringID(uint32 string_id, const char *message3 = 0, const char *message4 = 0, const char *message5 = 0,
|
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);
|
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_);
|
bool PassLimitClass(uint32 Classes_, uint16 Class_);
|
||||||
void TryDefensiveProc(const ItemInst* weapon, Mob *on, uint16 hand = 13, int damage=0);
|
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 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 TryWeaponProc(const ItemInst* weapon, Mob *on, uint16 hand = 13);
|
||||||
void ExecWeaponProc(const ItemInst* weapon, uint16 spell_id, Mob *on);
|
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);
|
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 Item_Struct *weapon_item);
|
||||||
int GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate = nullptr);
|
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();
|
bool worldwasconnected = worldserver.Connected();
|
||||||
EQStream* eqss;
|
EQStream* eqss;
|
||||||
EQStreamInterface *eqsi;
|
EQStreamInterface *eqsi;
|
||||||
Timer temp_timer(10);
|
uint8 IDLEZONEUPDATE = 200;
|
||||||
temp_timer.Start();
|
uint8 ZONEUPDATE = 10;
|
||||||
|
Timer zoneupdate_timer(ZONEUPDATE);
|
||||||
|
zoneupdate_timer.Start();
|
||||||
while(RunLoops) {
|
while(RunLoops) {
|
||||||
{ //profiler block to omit the sleep from times
|
{ //profiler block to omit the sleep from times
|
||||||
|
|
||||||
@ -381,6 +383,13 @@ int main(int argc, char** argv) {
|
|||||||
entity_list.AddClient(client);
|
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
|
//check for timeouts in other threads
|
||||||
timeout_manager.CheckTimeouts();
|
timeout_manager.CheckTimeouts();
|
||||||
@ -394,7 +403,7 @@ int main(int argc, char** argv) {
|
|||||||
worldwasconnected = false;
|
worldwasconnected = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ZoneLoaded && temp_timer.Check()) {
|
if (ZoneLoaded && zoneupdate_timer.Check()) {
|
||||||
{
|
{
|
||||||
if(net.group_timer.Enabled() && net.group_timer.Check())
|
if(net.group_timer.Enabled() && net.group_timer.Check())
|
||||||
entity_list.GroupProcess();
|
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_min_y = -2;
|
||||||
roambox_movingto_x = -2;
|
roambox_movingto_x = -2;
|
||||||
roambox_movingto_y = -2;
|
roambox_movingto_y = -2;
|
||||||
|
roambox_min_delay = 1000;
|
||||||
roambox_delay = 1000;
|
roambox_delay = 1000;
|
||||||
org_heading = heading;
|
org_heading = heading;
|
||||||
p_depop = false;
|
p_depop = false;
|
||||||
@ -1526,6 +1527,12 @@ void Mob::NPCSpecialAttacks(const char* parse, int permtag, bool reset, bool rem
|
|||||||
case 'i':
|
case 'i':
|
||||||
SetSpecialAbility(IMMUNE_TAUNT, remove ? 0 : 1);
|
SetSpecialAbility(IMMUNE_TAUNT, remove ? 0 : 1);
|
||||||
break;
|
break;
|
||||||
|
case 'e':
|
||||||
|
SetSpecialAbility(ALWAYS_FLEE, remove ? 0 : 1);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
SetSpecialAbility(FLEE_PERCENT, remove ? 0 : 1);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -1686,7 +1693,14 @@ bool Mob::HasNPCSpecialAtk(const char* parse) {
|
|||||||
HasAllAttacks = false;
|
HasAllAttacks = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'e':
|
||||||
|
if(!GetSpecialAbility(ALWAYS_FLEE))
|
||||||
|
HasAllAttacks = false;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
if(!GetSpecialAbility(FLEE_PERCENT))
|
||||||
|
HasAllAttacks = false;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
HasAllAttacks = false;
|
HasAllAttacks = false;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -265,8 +265,8 @@ public:
|
|||||||
inline bool IsGuarding() const { return(guard_heading != 0); }
|
inline bool IsGuarding() const { return(guard_heading != 0); }
|
||||||
void SaveGuardSpotCharm();
|
void SaveGuardSpotCharm();
|
||||||
void RestoreGuardSpotCharm();
|
void RestoreGuardSpotCharm();
|
||||||
void AI_SetRoambox(float iDist, float iRoamDist, 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);
|
void AI_SetRoambox(float iDist, float iMaxX, float iMinX, float iMaxY, float iMinY, uint32 iDelay = 2500, uint32 iMinDelay = 2500);
|
||||||
|
|
||||||
//mercenary stuff
|
//mercenary stuff
|
||||||
void LoadMercTypes();
|
void LoadMercTypes();
|
||||||
@ -430,6 +430,7 @@ protected:
|
|||||||
float roambox_movingto_x;
|
float roambox_movingto_x;
|
||||||
float roambox_movingto_y;
|
float roambox_movingto_y;
|
||||||
uint32 roambox_delay;
|
uint32 roambox_delay;
|
||||||
|
uint32 roambox_min_delay;
|
||||||
|
|
||||||
uint16 skills[HIGHEST_SKILL+1];
|
uint16 skills[HIGHEST_SKILL+1];
|
||||||
uint32 equipment[MAX_WORN_INVENTORY]; //this is an array of item IDs
|
uint32 equipment[MAX_WORN_INVENTORY]; //this is an array of item IDs
|
||||||
|
|||||||
@ -150,6 +150,33 @@ XS(XS_EntityList_GetMobByNpcTypeID)
|
|||||||
XSRETURN(1);
|
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); /* prototype to pass -Wmissing-prototypes */
|
||||||
XS(XS_EntityList_GetNPCByID)
|
XS(XS_EntityList_GetNPCByID)
|
||||||
{
|
{
|
||||||
@ -2127,6 +2154,7 @@ XS(boot_EntityList)
|
|||||||
newXSproto(strcpy(buf, "GetMob"), XS_EntityList_GetMob, file, "$$");
|
newXSproto(strcpy(buf, "GetMob"), XS_EntityList_GetMob, file, "$$");
|
||||||
newXSproto(strcpy(buf, "GetMobByID"), XS_EntityList_GetMobByID, file, "$$");
|
newXSproto(strcpy(buf, "GetMobByID"), XS_EntityList_GetMobByID, file, "$$");
|
||||||
newXSproto(strcpy(buf, "GetMobByNpcTypeID"), XS_EntityList_GetMobByNpcTypeID, 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, "GetNPCByID"), XS_EntityList_GetNPCByID, file, "$$");
|
||||||
newXSproto(strcpy(buf, "GetNPCByNPCTypeID"), XS_EntityList_GetNPCByNPCTypeID, file, "$$");
|
newXSproto(strcpy(buf, "GetNPCByNPCTypeID"), XS_EntityList_GetNPCByNPCTypeID, file, "$$");
|
||||||
newXSproto(strcpy(buf, "GetClientByName"), XS_EntityList_GetClientByName, 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)
|
XS(XS_NPC_AI_SetRoambox)
|
||||||
{
|
{
|
||||||
dXSARGS;
|
dXSARGS;
|
||||||
if (items < 6 || items > 7)
|
if (items < 6 || items > 8)
|
||||||
Perl_croak(aTHX_ "Usage: NPC::AI_SetRoambox(THIS, iDist, iMaxX, iMinX, iMaxY, iMinY, iDelay= 2500)");
|
Perl_croak(aTHX_ "Usage: NPC::AI_SetRoambox(THIS, iDist, iMaxX, iMinX, iMaxY, iMinY, iDelay= 2500, iMinDelay= 2500)");
|
||||||
{
|
{
|
||||||
NPC * THIS;
|
NPC * THIS;
|
||||||
float iDist = (float)SvNV(ST(1));
|
float iDist = (float)SvNV(ST(1));
|
||||||
@ -1443,6 +1443,7 @@ XS(XS_NPC_AI_SetRoambox)
|
|||||||
float iMaxY = (float)SvNV(ST(4));
|
float iMaxY = (float)SvNV(ST(4));
|
||||||
float iMinY = (float)SvNV(ST(5));
|
float iMinY = (float)SvNV(ST(5));
|
||||||
uint32 iDelay;
|
uint32 iDelay;
|
||||||
|
uint32 iMinDelay;
|
||||||
|
|
||||||
if (sv_derived_from(ST(0), "NPC")) {
|
if (sv_derived_from(ST(0), "NPC")) {
|
||||||
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
IV tmp = SvIV((SV*)SvRV(ST(0)));
|
||||||
@ -1453,13 +1454,20 @@ XS(XS_NPC_AI_SetRoambox)
|
|||||||
if(THIS == nullptr)
|
if(THIS == nullptr)
|
||||||
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
|
||||||
|
|
||||||
if (items < 7)
|
if (items < 7){
|
||||||
|
iMinDelay = 2500;
|
||||||
iDelay = 2500;
|
iDelay = 2500;
|
||||||
else {
|
}
|
||||||
|
else if (items < 8){
|
||||||
|
iMinDelay = 2500;
|
||||||
iDelay = (uint32)SvUV(ST(6));
|
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;
|
XSRETURN_EMPTY;
|
||||||
}
|
}
|
||||||
@ -2208,7 +2216,7 @@ XS(boot_NPC)
|
|||||||
newXSproto(strcpy(buf, "NextGuardPosition"), XS_NPC_NextGuardPosition, file, "$");
|
newXSproto(strcpy(buf, "NextGuardPosition"), XS_NPC_NextGuardPosition, file, "$");
|
||||||
newXSproto(strcpy(buf, "SaveGuardSpot"), XS_NPC_SaveGuardSpot, file, "$;$");
|
newXSproto(strcpy(buf, "SaveGuardSpot"), XS_NPC_SaveGuardSpot, file, "$;$");
|
||||||
newXSproto(strcpy(buf, "IsGuarding"), XS_NPC_IsGuarding, 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, "GetNPCSpellsID"), XS_NPC_GetNPCSpellsID, file, "$");
|
||||||
newXSproto(strcpy(buf, "GetSpawnPointID"), XS_NPC_GetSpawnPointID, file, "$");
|
newXSproto(strcpy(buf, "GetSpawnPointID"), XS_NPC_GetSpawnPointID, file, "$");
|
||||||
newXSproto(strcpy(buf, "GetSpawnPointX"), XS_NPC_GetSpawnPointX, 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.AddNPC(npc);
|
||||||
entity_list.LimitAddNPC(npc);
|
entity_list.LimitAddNPC(npc);
|
||||||
|
|
||||||
if(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);
|
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())
|
if(zone->InstantGrids())
|
||||||
{
|
{
|
||||||
found_spawn->LoadGrid();
|
found_spawn->LoadGrid();
|
||||||
|
|||||||
@ -229,8 +229,8 @@ bool Spawn2::Process() {
|
|||||||
entity_list.AddNPC(npc);
|
entity_list.AddNPC(npc);
|
||||||
//this limit add must be done after the AddNPC since we need the entity ID.
|
//this limit add must be done after the AddNPC since we need the entity ID.
|
||||||
entity_list.LimitAddNPC(npc);
|
entity_list.LimitAddNPC(npc);
|
||||||
if(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);
|
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()) {
|
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);
|
_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();
|
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;
|
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;
|
id = in_id;
|
||||||
strn0cpy( name_, name, 120);
|
strn0cpy( name_, name, 120);
|
||||||
group_spawn_limit = in_group_spawn_limit;
|
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[2]=maxy;
|
||||||
roambox[3]=miny;
|
roambox[3]=miny;
|
||||||
roamdist=dist;
|
roamdist=dist;
|
||||||
|
min_delay=min_delay_in;
|
||||||
delay=delay_in;
|
delay=delay_in;
|
||||||
despawn=despawn_in;
|
despawn=despawn_in;
|
||||||
despawn_timer=despawn_timer_in;
|
despawn_timer=despawn_timer_in;
|
||||||
@ -150,11 +151,11 @@ bool ZoneDatabase::LoadSpawnGroups(const char* zone_name, uint16 version, SpawnG
|
|||||||
|
|
||||||
// CODER new spawn code
|
// CODER new spawn code
|
||||||
query = 0;
|
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);
|
safe_delete_array(query);
|
||||||
while((row = mysql_fetch_row(result))) {
|
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);
|
spawn_group_list->AddSpawnGroup(newSpawnGroup);
|
||||||
}
|
}
|
||||||
mysql_free_result(result);
|
mysql_free_result(result);
|
||||||
@ -205,11 +206,11 @@ bool ZoneDatabase::LoadSpawnGroupsByID(int spawngroupid, SpawnGroupList* spawn_g
|
|||||||
|
|
||||||
// CODER new spawn code
|
// CODER new spawn code
|
||||||
query = 0;
|
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);
|
safe_delete_array(query);
|
||||||
while((row = mysql_fetch_row(result))) {
|
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);
|
spawn_group_list->AddSpawnGroup(newSpawnGroup);
|
||||||
}
|
}
|
||||||
mysql_free_result(result);
|
mysql_free_result(result);
|
||||||
|
|||||||
@ -39,13 +39,14 @@ public:
|
|||||||
class SpawnGroup
|
class SpawnGroup
|
||||||
{
|
{
|
||||||
public:
|
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();
|
~SpawnGroup();
|
||||||
uint32 GetNPCType();
|
uint32 GetNPCType();
|
||||||
void AddSpawnEntry( SpawnEntry* newEntry );
|
void AddSpawnEntry( SpawnEntry* newEntry );
|
||||||
uint32 id;
|
uint32 id;
|
||||||
float roamdist;
|
float roamdist;
|
||||||
float roambox[4];
|
float roambox[4];
|
||||||
|
int min_delay;
|
||||||
int delay;
|
int delay;
|
||||||
int despawn;
|
int despawn;
|
||||||
uint32 despawn_timer;
|
uint32 despawn_timer;
|
||||||
|
|||||||
@ -2826,6 +2826,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
|||||||
case SE_CriticalMend:
|
case SE_CriticalMend:
|
||||||
case SE_LimitCastTimeMax:
|
case SE_LimitCastTimeMax:
|
||||||
case SE_TriggerOnReqCaster:
|
case SE_TriggerOnReqCaster:
|
||||||
|
case SE_FrenziedDevastation:
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3418,13 +3419,11 @@ void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caste
|
|||||||
{
|
{
|
||||||
if (spellbonuses.DistanceRemoval){
|
if (spellbonuses.DistanceRemoval){
|
||||||
|
|
||||||
int distance = sqrt(
|
int distance = ((int(GetX()) - buffs[slot].caston_x) * (int(GetX()) - buffs[slot].caston_x)) +
|
||||||
((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(GetY()) - buffs[slot].caston_y) * (int(GetY()) - buffs[slot].caston_y)) +
|
((int(GetZ()) - buffs[slot].caston_z) * (int(GetZ()) - buffs[slot].caston_z));
|
||||||
((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))
|
if(!TryFadeEffect(slot))
|
||||||
BuffFadeBySlot(slot , true);
|
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) {
|
float Mob::GetSympatheticProcChances(float &ProcBonus, float &ProcChance, int32 cast_time, int16 ProcRateMod) {
|
||||||
|
|
||||||
ProcBonus = spellbonuses.SpellProcChance + itembonuses.SpellProcChance;
|
|
||||||
ProcChance = 0;
|
ProcChance = 0;
|
||||||
|
|
||||||
if(cast_time > 0)
|
if(cast_time > 0)
|
||||||
{
|
{
|
||||||
ProcChance = ((float)cast_time * RuleR(Casting, AvgSpellProcsPerMinute) / 60000.0f);
|
ProcChance = ((float)cast_time * RuleR(Casting, AvgSpellProcsPerMinute) / 60000.0f);
|
||||||
ProcChance = ProcChance * (float)(ProcRateMod/100);
|
ProcChance = ProcChance * (float)(ProcRateMod/100);
|
||||||
ProcChance = ProcChance+(ProcChance*ProcBonus/100);
|
|
||||||
}
|
}
|
||||||
return ProcChance;
|
return ProcChance;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -445,7 +445,8 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
|||||||
|
|
||||||
casting_spell_resist_adjust = resist_adjust;
|
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
|
// cast time is 0, just finish it right now and be done with it
|
||||||
if(cast_time == 0) {
|
if(cast_time == 0) {
|
||||||
@ -461,8 +462,9 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
|||||||
if (IsAIControlled())
|
if (IsAIControlled())
|
||||||
{
|
{
|
||||||
SetRunAnimSpeed(0);
|
SetRunAnimSpeed(0);
|
||||||
if(this != pMob)
|
pMob = entity_list.GetMob(target_id);
|
||||||
this->FaceTarget(pMob);
|
if (pMob && this != pMob)
|
||||||
|
FaceTarget(pMob);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we got here we didn't fizzle, and are starting our cast
|
// 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);
|
return(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPC::AI_SetRoambox(float iDist, float iRoamDist, uint32 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);
|
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_distance = iDist;
|
||||||
roambox_max_x = iMaxX;
|
roambox_max_x = iMaxX;
|
||||||
roambox_min_x = iMinX;
|
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_min_y = iMinY;
|
||||||
roambox_movingto_x = roambox_max_x + 1; // this will trigger a recalc
|
roambox_movingto_x = roambox_max_x + 1; // this will trigger a recalc
|
||||||
roambox_delay = iDelay;
|
roambox_delay = iDelay;
|
||||||
|
roambox_min_delay = iMinDelay;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NPC::DisplayWaypointInfo(Client *c) {
|
void NPC::DisplayWaypointInfo(Client *c) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user