mirror of
https://github.com/EQEmu/Server.git
synced 2026-02-21 13:42:24 +00:00
Merge branch 'master' of https://github.com/EQEmu/Server
This commit is contained in:
commit
8b7984cf7d
@ -1,5 +1,31 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 11/18/2013 ==
|
||||
demonstar55: Added assistradius to npc_types, defaults to aggroradius if set to 0 (old behaviour)
|
||||
|
||||
== 11/17/2013 ==
|
||||
Sorvani: fixed leash and tether special abilities to use the specified range correctly.
|
||||
demonstar55: Rewrote the Mob::_GetMovementSpeed fix an issue that arose from the change on 11/11
|
||||
- Added the rule Character:BaseRunSpeedCap (default 158) so people can customize what their runspeed cap is. Hardcapped to 225 so stuff doesn't get too crazy.
|
||||
|
||||
== 11/16/2013 ==
|
||||
Leere: Fixed the drinking message for auto-consume, it will again correctly show up for forced consumption instead.
|
||||
demonstar55: Added Mob::DoCastingChecks() which will check for various fail conditions while the casting bar is up. This is called after Mob::DoCastSpell() starts the casting and before it returns.
|
||||
|
||||
== 11/15/2013 ==
|
||||
demonstar55: Fixed Mob::CalcFocusEffect()'s SE_LimitEffect
|
||||
Leere: Fixed a stacking issue for SE_StackingCommand_Block
|
||||
|
||||
== 11/13/2013 ==
|
||||
demonstar55: Implemented bard song effect cap. You can set the base cap with the rule Character:BaseInstrumentSoftCap, defaults to 36 or "3.6" as it is sometimes referred to.
|
||||
demonstar55: Fix Echo of Taelosia and Ayonae's Tutelage to increase the mod cap instead of further improving the instrument mod
|
||||
demonstar55: Implemented Singing/Instrument Mastery as an AA bonus.
|
||||
|
||||
== 11/11/2013 ==
|
||||
demonstar55: Changed the way walk speed is calculated to allow mobs to have their walk speed equal a 100% movement reduction
|
||||
|
||||
== 11/09/2013 ==
|
||||
Leere: Fixed Bard mana regen, they now only are affected by items and AA.
|
||||
|
||||
== 11/07/2013 ==
|
||||
KLS: Added a system to use the BaseData system in the client.
|
||||
|
||||
@ -74,11 +74,11 @@ To use ptimers, you need to create the table below in your DB:
|
||||
Schema:
|
||||
|
||||
CREATE TABLE timers (
|
||||
char_id INT(11) NOT nullptr,
|
||||
type MEDIUMINT UNSIGNED NOT nullptr,
|
||||
start INT UNSIGNED NOT nullptr,
|
||||
duration INT UNSIGNED NOT nullptr,
|
||||
enable TINYINT NOT nullptr,
|
||||
char_id INT(11) NOT NULL,
|
||||
type MEDIUMINT UNSIGNED NOT NULL,
|
||||
start INT UNSIGNED NOT NULL,
|
||||
duration INT UNSIGNED NOT NULL,
|
||||
enable TINYINT NOT NULL,
|
||||
PRIMARY KEY(char_id, type)
|
||||
);
|
||||
|
||||
|
||||
@ -35,17 +35,17 @@ Requred SQL:
|
||||
|
||||
|
||||
CREATE TABLE rule_sets (
|
||||
ruleset_id TINYINT UNSIGNED NOT nullptr auto_increment,
|
||||
name VARCHAR(255) NOT nullptr,
|
||||
ruleset_id TINYINT UNSIGNED NOT NULL auto_increment,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
PRIMARY KEY(ruleset_id)
|
||||
);
|
||||
INSERT INTO rule_sets VALUES(0, "default");
|
||||
UPDATE rule_sets SET ruleset_id=0;
|
||||
|
||||
CREATE TABLE rule_values (
|
||||
ruleset_id TINYINT UNSIGNED NOT nullptr,
|
||||
rule_name VARCHAR(64) NOT nullptr,
|
||||
rule_value VARCHAR(10) NOT nullptr,
|
||||
ruleset_id TINYINT UNSIGNED NOT NULL,
|
||||
rule_name VARCHAR(64) NOT NULL,
|
||||
rule_value VARCHAR(10) NOT NULL,
|
||||
INDEX(ruleset_id),
|
||||
PRIMARY KEY(ruleset_id,rule_name)
|
||||
);
|
||||
|
||||
@ -97,6 +97,8 @@ RULE_BOOL ( Character, EnableDiscoveredItems, true ) // If enabled, it enables E
|
||||
RULE_BOOL ( Character, EnableXTargetting, true) // Enable Extended Targetting Window, for users with UF and later clients.
|
||||
RULE_BOOL ( Character, KeepLevelOverMax, false) // Don't delevel a character that has somehow gone over the level cap
|
||||
RULE_INT ( Character, FoodLossPerUpdate, 35) // How much food/water you lose per stamina update
|
||||
RULE_INT ( Character, BaseInstrumentSoftCap, 36) // Softcap for instrument mods, 36 commonly referred to as "3.6" as well.
|
||||
RULE_INT ( Character, BaseRunSpeedCap, 158) // Base Run Speed Cap, on live it's 158% which will give you a runspeed of 1.580 hard capped to 225.
|
||||
RULE_CATEGORY_END()
|
||||
|
||||
RULE_CATEGORY( Mercs )
|
||||
|
||||
897
common/spdat.cpp
897
common/spdat.cpp
File diff suppressed because it is too large
Load Diff
@ -404,7 +404,7 @@ typedef enum {
|
||||
#define SE_PetDiscipline 257 // not implemented as bonus - /pet hold
|
||||
#define SE_TripleBackstab 258 // implemented[AA] - chance to perform a triple backstab
|
||||
#define SE_CombatStability 259 // implemented[AA] - damage mitigation
|
||||
#define SE_AddSingingMod 260 // *not implemented
|
||||
#define SE_AddSingingMod 260 // implemented[AA] - Instrument/Singing Mastery, base1 is the mod, base2 is the ItemType
|
||||
//#define SE_Unknown261 261 // not used
|
||||
#define SE_RaiseStatCap 262 // implemented
|
||||
#define SE_TradeSkillMastery 263 // implemented - lets you raise more than one tradeskill above master.
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
-- Instrument Mastery
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (213, 1, 260, 2, 23);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (213, 2, 260, 2, 24);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (213, 3, 260, 2, 25);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (213, 4, 260, 2, 26);
|
||||
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (214, 1, 260, 4, 23);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (214, 2, 260, 4, 24);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (214, 3, 260, 4, 25);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (214, 4, 260, 4, 26);
|
||||
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (215, 1, 260, 6, 23);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (215, 2, 260, 6, 24);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (215, 3, 260, 6, 25);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (215, 4, 260, 6, 26);
|
||||
|
||||
-- Improved Instrument Mastery
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (700, 1, 260, 2, 23);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (700, 2, 260, 2, 24);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (700, 3, 260, 2, 25);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (700, 4, 260, 2, 26);
|
||||
|
||||
-- Singing Mastery
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (275, 1, 260, 2, 50);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (276, 1, 260, 4, 50);
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (277, 1, 260, 6, 50);
|
||||
|
||||
-- Improved Singing Mastery
|
||||
REPLACE INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES (701, 1, 260, 2, 50);
|
||||
|
||||
1
utils/sql/git/required/2013_11_18_AssistRadius.sql
Normal file
1
utils/sql/git/required/2013_11_18_AssistRadius.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE `npc_types` ADD `assistradius` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `aggroradius`;
|
||||
@ -1089,17 +1089,17 @@ void Mob::AI_Process() {
|
||||
return;
|
||||
|
||||
if(GetSpecialAbility(TETHER)) {
|
||||
float aggro_range = static_cast<float>(GetSpecialAbilityParam(TETHER, 0));
|
||||
aggro_range = aggro_range > 0.0f ? aggro_range : pAggroRange * pAggroRange;
|
||||
float tether_range = static_cast<float>(GetSpecialAbilityParam(TETHER, 0));
|
||||
tether_range = tether_range > 0.0f ? tether_range * tether_range : pAggroRange * pAggroRange;
|
||||
|
||||
if(DistNoRootNoZ(CastToNPC()->GetSpawnPointX(), CastToNPC()->GetSpawnPointY()) > aggro_range) {
|
||||
if(DistNoRootNoZ(CastToNPC()->GetSpawnPointX(), CastToNPC()->GetSpawnPointY()) > tether_range) {
|
||||
GMMove(CastToNPC()->GetSpawnPointX(), CastToNPC()->GetSpawnPointY(), CastToNPC()->GetSpawnPointZ(), CastToNPC()->GetSpawnPointH());
|
||||
}
|
||||
} else if(GetSpecialAbility(LEASH)) {
|
||||
float aggro_range = static_cast<float>(GetSpecialAbilityParam(LEASH, 0));
|
||||
aggro_range = aggro_range > 0.0f ? aggro_range : pAggroRange * pAggroRange;
|
||||
float leash_range = static_cast<float>(GetSpecialAbilityParam(LEASH, 0));
|
||||
leash_range = leash_range > 0.0f ? leash_range * leash_range : pAggroRange * pAggroRange;
|
||||
|
||||
if(DistNoRootNoZ(CastToNPC()->GetSpawnPointX(), CastToNPC()->GetSpawnPointY()) > aggro_range) {
|
||||
if(DistNoRootNoZ(CastToNPC()->GetSpawnPointX(), CastToNPC()->GetSpawnPointY()) > leash_range) {
|
||||
GMMove(CastToNPC()->GetSpawnPointX(), CastToNPC()->GetSpawnPointY(), CastToNPC()->GetSpawnPointZ(), CastToNPC()->GetSpawnPointH());
|
||||
SetHP(GetMaxHP());
|
||||
BuffFadeAll();
|
||||
|
||||
@ -874,6 +874,26 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
case SE_CombatStability:
|
||||
newbon->CombatStability += base1;
|
||||
break;
|
||||
case SE_AddSingingMod:
|
||||
switch (base2)
|
||||
{
|
||||
case ItemTypeWindInstrument:
|
||||
newbon->windMod += base1;
|
||||
break;
|
||||
case ItemTypeStringedInstrument:
|
||||
newbon->stringedMod += base1;
|
||||
break;
|
||||
case ItemTypeBrassInstrument:
|
||||
newbon->brassMod += base1;
|
||||
break;
|
||||
case ItemTypePercussionInstrument:
|
||||
newbon->percussionMod += base1;
|
||||
break;
|
||||
case ItemTypeSinging:
|
||||
newbon->singingMod += base1;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SE_PetCriticalHit:
|
||||
newbon->PetCriticalHit += base1;
|
||||
break;
|
||||
@ -1188,6 +1208,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
||||
}
|
||||
//this prolly suffer from roundoff error slightly...
|
||||
newbon->AC = newbon->AC * 10 / 34; //ratio determined impirically from client.
|
||||
if (GetClass() == BARD) newbon->ManaRegen = 0; // Bards do not get mana regen from spells.
|
||||
}
|
||||
|
||||
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* newbon, uint16 casterId, bool item_bonus, uint32 ticsremaining, int buffslot)
|
||||
@ -2230,6 +2251,27 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
newbon->CombatStability += effect_value;
|
||||
break;
|
||||
|
||||
case SE_AddSingingMod:
|
||||
switch (spells[spell_id].base2[i])
|
||||
{
|
||||
case ItemTypeWindInstrument:
|
||||
newbon->windMod += effect_value;
|
||||
break;
|
||||
case ItemTypeStringedInstrument:
|
||||
newbon->stringedMod += effect_value;
|
||||
break;
|
||||
case ItemTypeBrassInstrument:
|
||||
newbon->brassMod += effect_value;
|
||||
break;
|
||||
case ItemTypePercussionInstrument:
|
||||
newbon->percussionMod += effect_value;
|
||||
break;
|
||||
case ItemTypeSinging:
|
||||
newbon->singingMod += effect_value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SE_PetAvoidance:
|
||||
newbon->PetAvoidance += effect_value;
|
||||
break;
|
||||
|
||||
@ -8032,7 +8032,7 @@ void Client::Consume(const Item_Struct *item, uint8 type, int16 slot, bool auto_
|
||||
m_pp.thirst_level += tchange;
|
||||
DeleteItemInInventory(slot, 1, false);
|
||||
|
||||
if(auto_consume) //no message if the client consumed for us
|
||||
if(!auto_consume) //no message if the client consumed for us
|
||||
entity_list.MessageClose_StringID(this, true, 50, 0, DRINKING_MESSAGE, GetName(), item->Name);
|
||||
|
||||
#if EQDEBUG >= 1
|
||||
|
||||
@ -1796,6 +1796,7 @@ uint16 Mob::GetInstrumentMod(uint16 spell_id) const {
|
||||
return(10);
|
||||
|
||||
uint16 effectmod = 10;
|
||||
int effectmodcap = RuleI(Character, BaseInstrumentSoftCap);
|
||||
|
||||
//this should never use spell modifiers...
|
||||
//if a spell grants better modifers, they are copied into the item mods
|
||||
@ -1812,6 +1813,7 @@ uint16 Mob::GetInstrumentMod(uint16 spell_id) const {
|
||||
effectmod = itembonuses.percussionMod;
|
||||
else
|
||||
effectmod = spellbonuses.percussionMod;
|
||||
effectmod += aabonuses.percussionMod;
|
||||
break;
|
||||
case SkillStringedInstruments:
|
||||
if(itembonuses.stringedMod == 0 && spellbonuses.stringedMod == 0)
|
||||
@ -1822,6 +1824,7 @@ uint16 Mob::GetInstrumentMod(uint16 spell_id) const {
|
||||
effectmod = itembonuses.stringedMod;
|
||||
else
|
||||
effectmod = spellbonuses.stringedMod;
|
||||
effectmod += aabonuses.stringedMod;
|
||||
break;
|
||||
case SkillWindInstruments:
|
||||
if(itembonuses.windMod == 0 && spellbonuses.windMod == 0)
|
||||
@ -1832,6 +1835,7 @@ uint16 Mob::GetInstrumentMod(uint16 spell_id) const {
|
||||
effectmod = itembonuses.windMod;
|
||||
else
|
||||
effectmod = spellbonuses.windMod;
|
||||
effectmod += aabonuses.windMod;
|
||||
break;
|
||||
case SkillBrassInstruments:
|
||||
if(itembonuses.brassMod == 0 && spellbonuses.brassMod == 0)
|
||||
@ -1842,6 +1846,7 @@ uint16 Mob::GetInstrumentMod(uint16 spell_id) const {
|
||||
effectmod = itembonuses.brassMod;
|
||||
else
|
||||
effectmod = spellbonuses.brassMod;
|
||||
effectmod += aabonuses.brassMod;
|
||||
break;
|
||||
case SkillSinging:
|
||||
if(itembonuses.singingMod == 0 && spellbonuses.singingMod == 0)
|
||||
@ -1850,30 +1855,26 @@ uint16 Mob::GetInstrumentMod(uint16 spell_id) const {
|
||||
effectmod = itembonuses.singingMod;
|
||||
else
|
||||
effectmod = spellbonuses.singingMod;
|
||||
effectmod += aabonuses.singingMod;
|
||||
break;
|
||||
default:
|
||||
effectmod = 10;
|
||||
break;
|
||||
}
|
||||
|
||||
if(spells[spell_id].skill == SkillSinging)
|
||||
{
|
||||
effectmod += 2*GetAA(aaSingingMastery);
|
||||
effectmod += 2*GetAA(aaImprovedSingingMastery);
|
||||
}
|
||||
else
|
||||
{
|
||||
effectmod += 2*GetAA(aaInstrumentMastery);
|
||||
effectmod += 2*GetAA(aaImprovedInstrumentMastery);
|
||||
}
|
||||
effectmod += 2*GetAA(aaAyonaesTutelage); //singing & instruments
|
||||
effectmod += 2*GetAA(aaEchoofTaelosia); //singing & instruments
|
||||
// TODO: These shouldn't be hardcoded.
|
||||
effectmodcap += GetAA(aaAyonaesTutelage);
|
||||
effectmodcap += GetAA(aaEchoofTaelosia);
|
||||
|
||||
|
||||
if(effectmod < 10)
|
||||
effectmod = 10;
|
||||
|
||||
_log(SPELLS__BARDS, "%s::GetInstrumentMod() spell=%d mod=%d\n", GetName(), spell_id, effectmod);
|
||||
if (effectmod > effectmodcap)
|
||||
effectmod = effectmodcap;
|
||||
|
||||
_log(SPELLS__BARDS, "%s::GetInstrumentMod() spell=%d mod=%d modcap=%d\n",
|
||||
GetName(), spell_id, effectmod, effectmodcap);
|
||||
|
||||
return(effectmod);
|
||||
}
|
||||
|
||||
@ -917,7 +917,7 @@ void Client::CheatDetected(CheatTypes CheatType, float x, float y, float z)
|
||||
Message(13, "Large warp detected.");
|
||||
char hString[250];
|
||||
sprintf(hString, "/MQWarp with location %.2f, %.2f, %.2f", GetX(), GetY(), GetZ());
|
||||
database.SetMQDetectionFlag(this->account_name,this->name, hString, zone->GetShortName());
|
||||
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
|
||||
}
|
||||
break;
|
||||
case MQWarpShadowStep:
|
||||
@ -927,7 +927,7 @@ void Client::CheatDetected(CheatTypes CheatType, float x, float y, float z)
|
||||
{
|
||||
char *hString = nullptr;
|
||||
MakeAnyLenString(&hString, "/MQWarp(SS) with location %.2f, %.2f, %.2f, the target was shadow step exempt but we still found this suspicious.", GetX(), GetY(), GetZ());
|
||||
database.SetMQDetectionFlag(this->account_name,this->name, hString, zone->GetShortName());
|
||||
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
|
||||
safe_delete_array(hString);
|
||||
}
|
||||
break;
|
||||
@ -938,7 +938,7 @@ void Client::CheatDetected(CheatTypes CheatType, float x, float y, float z)
|
||||
{
|
||||
char *hString = nullptr;
|
||||
MakeAnyLenString(&hString, "/MQWarp(KB) with location %.2f, %.2f, %.2f, the target was Knock Back exempt but we still found this suspicious.", GetX(), GetY(), GetZ());
|
||||
database.SetMQDetectionFlag(this->account_name,this->name, hString, zone->GetShortName());
|
||||
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
|
||||
safe_delete_array(hString);
|
||||
}
|
||||
break;
|
||||
@ -952,7 +952,7 @@ void Client::CheatDetected(CheatTypes CheatType, float x, float y, float z)
|
||||
{
|
||||
char *hString = nullptr;
|
||||
MakeAnyLenString(&hString, "/MQWarp(LT) with location %.2f, %.2f, %.2f, running fast but not fast enough to get killed, possibly: small warp, speed hack, excessive lag, marked as suspicious.", GetX(), GetY(), GetZ());
|
||||
database.SetMQDetectionFlag(this->account_name,this->name, hString, zone->GetShortName());
|
||||
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
|
||||
safe_delete_array(hString);
|
||||
}
|
||||
}
|
||||
@ -963,7 +963,7 @@ void Client::CheatDetected(CheatTypes CheatType, float x, float y, float z)
|
||||
{
|
||||
char hString[250];
|
||||
sprintf(hString, "/MQZone used at %.2f, %.2f, %.2f to %.2f %.2f %.2f", GetX(), GetY(), GetZ(), x, y, z);
|
||||
database.SetMQDetectionFlag(this->account_name,this->name, hString, zone->GetShortName());
|
||||
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
|
||||
}
|
||||
break;
|
||||
case MQZoneUnknownDest:
|
||||
@ -971,13 +971,15 @@ void Client::CheatDetected(CheatTypes CheatType, float x, float y, float z)
|
||||
{
|
||||
char hString[250];
|
||||
sprintf(hString, "/MQZone used at %.2f, %.2f, %.2f", GetX(), GetY(), GetZ());
|
||||
database.SetMQDetectionFlag(this->account_name,this->name, hString, zone->GetShortName());
|
||||
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
|
||||
}
|
||||
break;
|
||||
case MQGate:
|
||||
if (RuleB(Zone, EnableMQGateDetector)&& ((this->Admin() < RuleI(Zone, MQGateExemptStatus) || (RuleI(Zone, MQGateExemptStatus)) == -1))) {
|
||||
Message(13, "Illegal gate request.");
|
||||
database.SetMQDetectionFlag(this->account_name,this->name, "/MQGate", zone->GetShortName());
|
||||
char hString[250];
|
||||
sprintf(hString, "/MQGate used at %.2f, %.2f, %.2f", GetX(), GetY(), GetZ());
|
||||
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
|
||||
if(zone)
|
||||
{
|
||||
this->SetZone(this->GetZoneID(), zone->GetInstanceID()); //Prevent the player from zoning, place him back in the zone where he tried to originally /gate.
|
||||
@ -991,13 +993,13 @@ void Client::CheatDetected(CheatTypes CheatType, float x, float y, float z)
|
||||
break;
|
||||
case MQGhost: //Not currently implemented, but the framework is in place - just needs detection scenarios identified
|
||||
if (RuleB(Zone, EnableMQGhostDetector) && ((this->Admin() < RuleI(Zone, MQGhostExemptStatus) || (RuleI(Zone, MQGhostExemptStatus)) == -1))) {
|
||||
database.SetMQDetectionFlag(this->account_name,this->name, "/MQGhost", zone->GetShortName());
|
||||
database.SetMQDetectionFlag(this->account_name, this->name, "/MQGhost", zone->GetShortName());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
char *hString = nullptr;
|
||||
MakeAnyLenString(&hString, "Unhandled HackerDetection flag with location %.2f, %.2f, %.2f.", GetX(), GetY(), GetZ());
|
||||
database.SetMQDetectionFlag(this->account_name,this->name, hString, zone->GetShortName());
|
||||
database.SetMQDetectionFlag(this->account_name, this->name, hString, zone->GetShortName());
|
||||
safe_delete_array(hString);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -6647,6 +6647,7 @@ void command_npcedit(Client *c, const Seperator *sep)
|
||||
c->Message(0, "#npcedit Mindmg - Sets an NPCs minimum damage");
|
||||
c->Message(0, "#npcedit Maxdmg - Sets an NPCs maximum damage");
|
||||
c->Message(0, "#npcedit Aggroradius - Sets an NPCs aggro radius");
|
||||
c->Message(0, "#npcedit Assistradius - Sets an NPCs assist radius");
|
||||
c->Message(0, "#npcedit Social - Set to 1 if an NPC should assist others on its faction");
|
||||
c->Message(0, "#npcedit Runspeed - Sets an NPCs run speed");
|
||||
c->Message(0, "#npcedit MR - Sets an NPCs magic resistance");
|
||||
@ -6853,6 +6854,15 @@ void command_npcedit(Client *c, const Seperator *sep)
|
||||
c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
else if ( strcasecmp( sep->arg[1], "assistradius" ) == 0 )
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
c->Message(15,"NPCID %u now has an assist radius of %i",c->GetTarget()->CastToNPC()->GetNPCTypeID(),atoi(sep->arg[2]));
|
||||
database.RunQuery(query, MakeAnyLenString(&query, "update npc_types set assistradius=%i where id=%i",atoi(sep->argplus[2]),c->GetTarget()->CastToNPC()->GetNPCTypeID()), errbuf);
|
||||
c->LogSQL(query);
|
||||
safe_delete_array(query);
|
||||
}
|
||||
else if ( strcasecmp( sep->arg[1], "social" ) == 0 )
|
||||
{
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
|
||||
10
zone/exp.cpp
10
zone/exp.cpp
@ -530,14 +530,8 @@ void Group::SplitExp(uint32 exp, Mob* other) {
|
||||
}
|
||||
|
||||
float groupmod;
|
||||
if (membercount == 2)
|
||||
groupmod = 1.2;
|
||||
else if (membercount == 3)
|
||||
groupmod = 1.4;
|
||||
else if (membercount == 4)
|
||||
groupmod = 1.6;
|
||||
else if (membercount == 5)
|
||||
groupmod = 1.8;
|
||||
if (membercount > 1 && membercount < 6)
|
||||
groupmod = 1 + .2*(membercount - 1); //2members=1.2exp, 3=1.4, 4=1.6, 5=1.8
|
||||
else if (membercount == 6)
|
||||
groupmod = 2.16;
|
||||
else
|
||||
|
||||
@ -56,27 +56,27 @@ very low chance of dropping.
|
||||
|
||||
Schema:
|
||||
CREATE TABLE forage (
|
||||
id int(11) NOT nullptr auto_increment,
|
||||
zoneid int(4) NOT nullptr default '0',
|
||||
Itemid int(11) NOT nullptr default '0',
|
||||
level smallint(6) NOT nullptr default '0',
|
||||
chance smallint(6) NOT nullptr default '0',
|
||||
id int(11) NOT NULL auto_increment,
|
||||
zoneid int(4) NOT NULL default '0',
|
||||
Itemid int(11) NOT NULL default '0',
|
||||
level smallint(6) NOT NULL default '0',
|
||||
chance smallint(6) NOT NULL default '0',
|
||||
PRIMARY KEY (id)
|
||||
) TYPE=MyISAM;
|
||||
|
||||
old table upgrade:
|
||||
alter table forage add chance smallint(6) NOT nullptr default '0';
|
||||
alter table forage add chance smallint(6) NOT NULL default '0';
|
||||
update forage set chance=100;
|
||||
|
||||
|
||||
CREATE TABLE fishing (
|
||||
id int(11) NOT nullptr auto_increment,
|
||||
zoneid int(4) NOT nullptr default '0',
|
||||
Itemid int(11) NOT nullptr default '0',
|
||||
skill_level smallint(6) NOT nullptr default '0',
|
||||
chance smallint(6) NOT nullptr default '0',
|
||||
npc_id int NOT nullptr default 0,
|
||||
npc_chance int NOT nullptr default 0,
|
||||
id int(11) NOT NULL auto_increment,
|
||||
zoneid int(4) NOT NULL default '0',
|
||||
Itemid int(11) NOT NULL default '0',
|
||||
skill_level smallint(6) NOT NULL default '0',
|
||||
chance smallint(6) NOT NULL default '0',
|
||||
npc_id int NOT NULL default 0,
|
||||
npc_chance int NOT NULL default 0,
|
||||
PRIMARY KEY (id)
|
||||
) TYPE=MyISAM;
|
||||
|
||||
|
||||
@ -27,49 +27,49 @@
|
||||
/*
|
||||
|
||||
CREATE TABLE guilds (
|
||||
id MEDIUMINT UNSIGNED NOT nullptr,
|
||||
name VARCHAR(32) NOT nullptr,
|
||||
leader int NOT nullptr,
|
||||
minstatus SMALLINT NOT nullptr,
|
||||
tribute INT UNSIGNED NOT nullptr,
|
||||
motd TEXT NOT nullptr DEFAULT '',
|
||||
id MEDIUMINT UNSIGNED NOT NULL,
|
||||
name VARCHAR(32) NOT NULL,
|
||||
leader int NOT NULL,
|
||||
minstatus SMALLINT NOT NULL,
|
||||
tribute INT UNSIGNED NOT NULL,
|
||||
motd TEXT NOT NULL DEFAULT '',
|
||||
PRIMARY KEY(id),
|
||||
UNIQUE KEY(name),
|
||||
UNIQUE KEY(leader)
|
||||
);
|
||||
|
||||
CREATE TABLE guild_ranks (
|
||||
guild_id MEDIUMINT UNSIGNED NOT nullptr,
|
||||
rank TINYINT UNSIGNED NOT nullptr,
|
||||
title VARCHAR(128) NOT nullptr,
|
||||
can_hear TINYINT UNSIGNED NOT nullptr,
|
||||
can_speak TINYINT UNSIGNED NOT nullptr,
|
||||
can_invite TINYINT UNSIGNED NOT nullptr,
|
||||
can_remove TINYINT UNSIGNED NOT nullptr,
|
||||
can_promote TINYINT UNSIGNED NOT nullptr,
|
||||
can_demote TINYINT UNSIGNED NOT nullptr,
|
||||
can_motd TINYINT UNSIGNED NOT nullptr,
|
||||
can_warpeace TINYINT UNSIGNED NOT nullptr,
|
||||
guild_id MEDIUMINT UNSIGNED NOT NULL,
|
||||
rank TINYINT UNSIGNED NOT NULL,
|
||||
title VARCHAR(128) NOT NULL,
|
||||
can_hear TINYINT UNSIGNED NOT NULL,
|
||||
can_speak TINYINT UNSIGNED NOT NULL,
|
||||
can_invite TINYINT UNSIGNED NOT NULL,
|
||||
can_remove TINYINT UNSIGNED NOT NULL,
|
||||
can_promote TINYINT UNSIGNED NOT NULL,
|
||||
can_demote TINYINT UNSIGNED NOT NULL,
|
||||
can_motd TINYINT UNSIGNED NOT NULL,
|
||||
can_warpeace TINYINT UNSIGNED NOT NULL,
|
||||
PRIMARY KEY(guild_id,rank)
|
||||
);
|
||||
|
||||
# guild1 < guild2 by definition.
|
||||
CREATE TABLE guild_relations (
|
||||
guild1 MEDIUMINT UNSIGNED NOT nullptr,
|
||||
guild2 MEDIUMINT UNSIGNED NOT nullptr,
|
||||
relation TINYINT NOT nullptr,
|
||||
guild1 MEDIUMINT UNSIGNED NOT NULL,
|
||||
guild2 MEDIUMINT UNSIGNED NOT NULL,
|
||||
relation TINYINT NOT NULL,
|
||||
PRIMARY KEY(guild1, guild1)
|
||||
);
|
||||
|
||||
CREATE TABLE guild_members (
|
||||
char_id INT NOT nullptr,
|
||||
guild_id MEDIUMINT UNSIGNED NOT nullptr,
|
||||
rank TINYINT UNSIGNED NOT nullptr,
|
||||
tribute_enable TINYINT UNSIGNED NOT nullptr DEFAULT 0,
|
||||
total_tribute INT UNSIGNED NOT nullptr DEFAULT 0,
|
||||
last_tribute INT UNSIGNED NOT nullptr DEFAULT 0,
|
||||
banker TINYINT UNSIGNED NOT nullptr DEFAULT 0,
|
||||
public_note TEXT NOT nullptr DEFAULT '',
|
||||
char_id INT NOT NULL,
|
||||
guild_id MEDIUMINT UNSIGNED NOT NULL,
|
||||
rank TINYINT UNSIGNED NOT NULL,
|
||||
tribute_enable TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
total_tribute INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
last_tribute INT UNSIGNED NOT NULL DEFAULT 0,
|
||||
banker TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
public_note TEXT NOT NULL DEFAULT '',
|
||||
PRIMARY KEY(char_id)
|
||||
);
|
||||
|
||||
|
||||
93
zone/mob.cpp
93
zone/mob.cpp
@ -517,76 +517,75 @@ bool Mob::IsInvisible(Mob* other) const
|
||||
return(false);
|
||||
}
|
||||
|
||||
float Mob::_GetMovementSpeed(int mod) const {
|
||||
float Mob::_GetMovementSpeed(int mod) const
|
||||
{
|
||||
// List of movement speed modifiers, including AAs & spells:
|
||||
// http://everquest.allakhazam.com/db/item.html?item=1721;page=1;howmany=50#m10822246245352
|
||||
if (IsRooted())
|
||||
return 0.0f;
|
||||
|
||||
float aa_mod = 0.0f;
|
||||
float speed_mod = runspeed;
|
||||
bool has_horse = false;
|
||||
if (IsClient())
|
||||
{
|
||||
if(CastToClient()->GetGMSpeed())
|
||||
{
|
||||
|
||||
// These two cases ignore the cap, be wise in the DB for horses.
|
||||
if (IsClient()) {
|
||||
if (CastToClient()->GetGMSpeed()) {
|
||||
speed_mod = 3.125f;
|
||||
}
|
||||
else
|
||||
{
|
||||
Mob* horse = entity_list.GetMob(CastToClient()->GetHorseId());
|
||||
if(horse)
|
||||
{
|
||||
if (mod != 0)
|
||||
speed_mod += speed_mod * static_cast<float>(mod) / 100.0f;
|
||||
return speed_mod;
|
||||
} else {
|
||||
Mob *horse = entity_list.GetMob(CastToClient()->GetHorseId());
|
||||
if (horse) {
|
||||
speed_mod = horse->GetBaseRunspeed();
|
||||
has_horse = true;
|
||||
if (mod != 0)
|
||||
speed_mod += speed_mod * static_cast<float>(mod) / 100.0f;
|
||||
return speed_mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aa_mod += itembonuses.BaseMovementSpeed + spellbonuses.BaseMovementSpeed + aabonuses.BaseMovementSpeed;
|
||||
|
||||
int spell_mod = spellbonuses.movementspeed + itembonuses.movementspeed;
|
||||
int aa_mod = 0;
|
||||
int spell_mod = 0;
|
||||
int runspeedcap = RuleI(Character,BaseRunSpeedCap);
|
||||
int movemod = 0;
|
||||
float frunspeedcap = 0.0f;
|
||||
|
||||
if(spell_mod < 0)
|
||||
{
|
||||
runspeedcap += itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
|
||||
aa_mod += itembonuses.BaseMovementSpeed + spellbonuses.BaseMovementSpeed + aabonuses.BaseMovementSpeed;
|
||||
spell_mod += spellbonuses.movementspeed + itembonuses.movementspeed;
|
||||
|
||||
// hard cap
|
||||
if (runspeedcap > 225)
|
||||
runspeedcap = 225;
|
||||
|
||||
if (spell_mod < 0)
|
||||
movemod += spell_mod;
|
||||
}
|
||||
else if(spell_mod > (aa_mod))
|
||||
{
|
||||
else if (spell_mod > aa_mod)
|
||||
movemod = spell_mod;
|
||||
}
|
||||
else
|
||||
{
|
||||
movemod = static_cast<int>(aa_mod);
|
||||
}
|
||||
movemod = aa_mod;
|
||||
|
||||
if(movemod < -85) //cap it at moving very very slow
|
||||
// cap negative movemods from snares mostly
|
||||
if (movemod < -85)
|
||||
movemod = -85;
|
||||
|
||||
if (!has_horse && movemod != 0)
|
||||
speed_mod += (speed_mod * float(movemod) / 100.0f);
|
||||
if (movemod != 0)
|
||||
speed_mod += speed_mod * static_cast<float>(movemod) / 100.0f;
|
||||
|
||||
if(mod != 0)
|
||||
speed_mod += (speed_mod * (float)mod / 100.0f);
|
||||
// runspeed caps
|
||||
frunspeedcap = static_cast<float>(runspeedcap) / 100.0f;
|
||||
if (IsClient() && speed_mod > frunspeedcap)
|
||||
speed_mod = frunspeedcap;
|
||||
|
||||
if(speed_mod <= 0.0f)
|
||||
return(0.0001f);
|
||||
// apply final mod such as the -47 for walking
|
||||
// use runspeed since it should stack with snares
|
||||
// and if we get here, we know runspeed was the initial
|
||||
// value before we applied movemod.
|
||||
if (mod != 0)
|
||||
speed_mod += runspeed * static_cast<float>(mod) / 100.0f;
|
||||
|
||||
//runspeed cap.
|
||||
if(IsClient())
|
||||
{
|
||||
if (speed_mod > 1.58){
|
||||
uint8 bonus_IncreaseRunSpeedCap = itembonuses.IncreaseRunSpeedCap + spellbonuses.IncreaseRunSpeedCap + aabonuses.IncreaseRunSpeedCap;
|
||||
if (bonus_IncreaseRunSpeedCap){
|
||||
speed_mod += float(bonus_IncreaseRunSpeedCap)/100.0f;
|
||||
if(speed_mod > 1.74)
|
||||
speed_mod = 1.74;
|
||||
}
|
||||
else
|
||||
speed_mod = 1.58;
|
||||
}
|
||||
}
|
||||
if (speed_mod <= 0.0f)
|
||||
speed_mod = IsClient() ? 0.0001f : 0.0f;
|
||||
|
||||
return speed_mod;
|
||||
}
|
||||
|
||||
@ -198,6 +198,7 @@ public:
|
||||
void InterruptSpell(uint16, uint16, uint16 spellid = SPELL_UNKNOWN);
|
||||
inline bool IsCasting() const { return((casting_spell_id != 0)); }
|
||||
uint16 CastingSpellID() const { return casting_spell_id; }
|
||||
bool DoCastingChecks();
|
||||
|
||||
//Buff
|
||||
void BuffProcess();
|
||||
@ -998,6 +999,7 @@ protected:
|
||||
uint32 casting_spell_timer_duration;
|
||||
uint32 casting_spell_type;
|
||||
int16 casting_spell_resist_adjust;
|
||||
bool casting_spell_checks;
|
||||
uint16 bardsong;
|
||||
uint8 bardsong_slot;
|
||||
uint32 bardsong_target_id;
|
||||
|
||||
@ -148,7 +148,7 @@ NPC::NPC(const NPCType* d, Spawn2* in_respawn, float x, float y, float z, float
|
||||
logging_enabled = NPC_DEFAULT_LOGGING_ENABLED;
|
||||
|
||||
pAggroRange = d->aggroradius;
|
||||
pAssistRange = GetAggroRange();
|
||||
pAssistRange = d->assistradius;
|
||||
findable = d->findable;
|
||||
trackable = d->trackable;
|
||||
|
||||
|
||||
@ -34,33 +34,33 @@ extern WorldServer worldserver;
|
||||
/*
|
||||
|
||||
CREATE TABLE spawn_conditions (
|
||||
zone VARCHAR(16) NOT nullptr,
|
||||
id MEDIUMINT UNSIGNED NOT nullptr DEFAULT '1',
|
||||
value MEDIUMINT NOT nullptr DEFAULT '0',
|
||||
onchange TINYINT UNSIGNED NOT nullptr DEFAULT '0',
|
||||
name VARCHAR(255) NOT nullptr DEFAULT '',
|
||||
zone VARCHAR(16) NOT NULL,
|
||||
id MEDIUMINT UNSIGNED NOT NULL DEFAULT '1',
|
||||
value MEDIUMINT NOT NULL DEFAULT '0',
|
||||
onchange TINYINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
name VARCHAR(255) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY(zone,id)
|
||||
);
|
||||
|
||||
CREATE TABLE spawn_events (
|
||||
#identifiers
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
zone VARCHAR(16) NOT nullptr,
|
||||
cond_id MEDIUMINT UNSIGNED NOT nullptr,
|
||||
name VARCHAR(255) NOT nullptr DEFAULT '',
|
||||
zone VARCHAR(16) NOT NULL,
|
||||
cond_id MEDIUMINT UNSIGNED NOT NULL,
|
||||
name VARCHAR(255) NOT NULL DEFAULT '',
|
||||
|
||||
#timing information
|
||||
period INT UNSIGNED NOT nullptr,
|
||||
next_minute TINYINT UNSIGNED NOT nullptr,
|
||||
next_hour TINYINT UNSIGNED NOT nullptr,
|
||||
next_day TINYINT UNSIGNED NOT nullptr,
|
||||
next_month TINYINT UNSIGNED NOT nullptr,
|
||||
next_year INT UNSIGNED NOT nullptr,
|
||||
enabled TINYINT NOT nullptr DEFAULT '1',
|
||||
period INT UNSIGNED NOT NULL,
|
||||
next_minute TINYINT UNSIGNED NOT NULL,
|
||||
next_hour TINYINT UNSIGNED NOT NULL,
|
||||
next_day TINYINT UNSIGNED NOT NULL,
|
||||
next_month TINYINT UNSIGNED NOT NULL,
|
||||
next_year INT UNSIGNED NOT NULL,
|
||||
enabled TINYINT NOT NULL DEFAULT '1',
|
||||
|
||||
#action:
|
||||
action TINYINT UNSIGNED NOT nullptr DEFAULT '0',
|
||||
argument MEDIUMINT NOT nullptr DEFAULT '0'
|
||||
action TINYINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
argument MEDIUMINT NOT NULL DEFAULT '0'
|
||||
);
|
||||
|
||||
*/
|
||||
|
||||
@ -325,6 +325,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
|
||||
case SE_CurrentMana:
|
||||
{
|
||||
// Bards don't get mana from effects, good or bad.
|
||||
if(GetClass() == BARD)
|
||||
break;
|
||||
if(IsManaTapSpell(spell_id)) {
|
||||
if(GetCasterClass() != 'N') {
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
@ -352,6 +355,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
|
||||
case SE_CurrentManaOnce:
|
||||
{
|
||||
// Bards don't get mana from effects, good or bad.
|
||||
if(GetClass() == BARD)
|
||||
break;
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
snprintf(effect_desc, _EDLEN, "Current Mana Once: %+i", effect_value);
|
||||
#endif
|
||||
@ -2727,6 +2733,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
case SE_ImprovedBindWound:
|
||||
case SE_MaxBindWound:
|
||||
case SE_CombatStability:
|
||||
case SE_AddSingingMod:
|
||||
case SE_PetAvoidance:
|
||||
case SE_GiveDoubleRiposte:
|
||||
case SE_Ambidexterity:
|
||||
@ -4272,7 +4279,7 @@ int16 Mob::CalcFocusEffect(focusType type, uint16 focus_id, uint16 spell_id, boo
|
||||
|
||||
case SE_LimitEffect:
|
||||
if(focus_spell.base[i] < 0){
|
||||
if(IsEffectInSpell(spell_id,focus_spell.base[i])){ //we limit this effect, can't have
|
||||
if(IsEffectInSpell(spell_id,(focus_spell.base[i] * -1))){ //we limit this effect, can't have
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
400
zone/spells.cpp
400
zone/spells.cpp
@ -16,9 +16,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
General outline of spell casting process
|
||||
|
||||
1.
|
||||
@ -64,14 +62,10 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
If this was timed, CastedSpellFinished() will restore the client's
|
||||
spell bar gems.
|
||||
|
||||
|
||||
Most user code should call CastSpell(), with a 0 casting time if needed,
|
||||
and not SpellFinished().
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "../common/debug.h"
|
||||
#include "../common/spdat.h"
|
||||
#include "masterentity.h"
|
||||
@ -88,8 +82,8 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef WIN32
|
||||
#include <stdlib.h>
|
||||
#include "../common/unix.h"
|
||||
#include <stdlib.h>
|
||||
#include "../common/unix.h"
|
||||
#endif
|
||||
|
||||
#ifdef _GOTFRAGS
|
||||
@ -115,7 +109,7 @@ void Mob::SpellProcess()
|
||||
}
|
||||
|
||||
// a timed spell is finished casting
|
||||
if (casting_spell_id != 0 && spellend_timer.Check())
|
||||
if (casting_spell_id != 0 && casting_spell_checks && spellend_timer.Check())
|
||||
{
|
||||
spellend_timer.Disable();
|
||||
delaytimer = false;
|
||||
@ -342,7 +336,6 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
||||
mlog(SPELLS__CASTING, "DoCastSpell called for spell %s (%d) on entity %d, slot %d, time %d, mana %d, from item %d",
|
||||
spell.name, spell_id, target_id, slot, cast_time, mana_cost, item_slot==0xFFFFFFFF?999:item_slot);
|
||||
|
||||
|
||||
casting_spell_id = spell_id;
|
||||
casting_spell_slot = slot;
|
||||
casting_spell_inventory_slot = item_slot;
|
||||
@ -474,9 +467,66 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, uint16 slot,
|
||||
entity_list.QueueCloseClients(this, outapp, false, 200, 0, true); //IsClient() ? FILTER_PCSPELLS : FILTER_NPCSPELLS);
|
||||
safe_delete(outapp);
|
||||
outapp = nullptr;
|
||||
|
||||
if (!DoCastingChecks()) {
|
||||
InterruptSpell();
|
||||
return false;
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some failures should be caught before the spell finishes casting
|
||||
* This is especially helpful to clients when they cast really long things
|
||||
* If this passes it sets casting_spell_checks to true which is checked in
|
||||
* SpellProcess(), if a situation ever arises where a spell is delayed by these
|
||||
* it's probably doing something wrong.
|
||||
*/
|
||||
|
||||
bool Mob::DoCastingChecks()
|
||||
{
|
||||
if (!IsClient() || (IsClient() && CastToClient()->GetGM())) {
|
||||
casting_spell_checks = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16 spell_id = casting_spell_id;
|
||||
Mob *spell_target = entity_list.GetMob(casting_spell_targetid);
|
||||
|
||||
if (RuleB(Spells, BuffLevelRestrictions) &&
|
||||
!spell_target->CheckSpellLevelRestriction(spell_id)) {
|
||||
mlog(SPELLS__BUFFS, "Spell %d failed: recipient did not meet the level restrictions", spell_id);
|
||||
if (!IsBardSong(spell_id))
|
||||
Message_StringID(MT_SpellFailure, SPELL_TOO_POWERFUL);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spells[spell_id].zonetype == 1 && !zone->CanCastOutdoor()) {
|
||||
Message_StringID(13, CAST_OUTDOORS);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsEffectInSpell(spell_id, SE_Levitate) && !zone->CanLevitate()) {
|
||||
Message(13, "You can't levitate in this zone.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (zone->IsSpellBlocked(spell_id, GetX(), GetY(), GetZ())) {
|
||||
const char *msg = zone->GetSpellBlockedMessage(spell_id, GetX(), GetY(), GetZ());
|
||||
if (msg) {
|
||||
Message(13, msg);
|
||||
return false;
|
||||
} else {
|
||||
Message(13, "You can't cast this spell here.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
casting_spell_checks = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16 Mob::GetSpecializeSkillValue(uint16 spell_id) const {
|
||||
switch(spells[spell_id].skill) {
|
||||
case SkillAbjuration:
|
||||
@ -687,6 +737,7 @@ void Mob::ZeroCastingVars()
|
||||
casting_spell_timer_duration = 0;
|
||||
casting_spell_type = 0;
|
||||
casting_spell_resist_adjust = 0;
|
||||
casting_spell_checks = false;
|
||||
delaytimer = false;
|
||||
}
|
||||
|
||||
@ -1107,52 +1158,52 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
|
||||
if(IsClient() && ((slot == USE_ITEM_SPELL_SLOT) || (slot == POTION_BELT_SPELL_SLOT))
|
||||
&& inventory_slot != 0xFFFFFFFF) // 10 is an item
|
||||
{
|
||||
bool fromaug = false;
|
||||
const ItemInst* inst = CastToClient()->GetInv()[inventory_slot];
|
||||
Item_Struct* augitem = 0;
|
||||
uint32 recastdelay = 0;
|
||||
uint32 recasttype = 0;
|
||||
bool fromaug = false;
|
||||
const ItemInst* inst = CastToClient()->GetInv()[inventory_slot];
|
||||
Item_Struct* augitem = 0;
|
||||
uint32 recastdelay = 0;
|
||||
uint32 recasttype = 0;
|
||||
|
||||
for(int r = 0; r < MAX_AUGMENT_SLOTS; r++) {
|
||||
const ItemInst* aug_i = inst->GetAugment(r);
|
||||
for(int r = 0; r < MAX_AUGMENT_SLOTS; r++) {
|
||||
const ItemInst* aug_i = inst->GetAugment(r);
|
||||
|
||||
if(!aug_i)
|
||||
continue;
|
||||
const Item_Struct* aug = aug_i->GetItem();
|
||||
if(!aug)
|
||||
continue;
|
||||
if(!aug_i)
|
||||
continue;
|
||||
const Item_Struct* aug = aug_i->GetItem();
|
||||
if(!aug)
|
||||
continue;
|
||||
|
||||
if ( aug->Click.Effect == spell_id )
|
||||
{
|
||||
recastdelay = aug_i->GetItem()->RecastDelay;
|
||||
recasttype = aug_i->GetItem()->RecastType;
|
||||
fromaug = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( aug->Click.Effect == spell_id )
|
||||
{
|
||||
recastdelay = aug_i->GetItem()->RecastDelay;
|
||||
recasttype = aug_i->GetItem()->RecastType;
|
||||
fromaug = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Test the aug recast delay
|
||||
if(IsClient() && fromaug && recastdelay > 0)
|
||||
{
|
||||
if(!CastToClient()->GetPTimers().Expired(&database, (pTimerItemStart + recasttype), false)) {
|
||||
Message_StringID(13, SPELL_RECAST);
|
||||
mlog(SPELLS__CASTING_ERR, "Casting of %d canceled: item spell reuse timer not expired", spell_id);
|
||||
InterruptSpell();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Can we start the timer here? I don't see why not.
|
||||
CastToClient()->GetPTimers().Start((pTimerItemStart + recasttype), recastdelay);
|
||||
}
|
||||
}
|
||||
//Test the aug recast delay
|
||||
if(IsClient() && fromaug && recastdelay > 0)
|
||||
{
|
||||
if(!CastToClient()->GetPTimers().Expired(&database, (pTimerItemStart + recasttype), false)) {
|
||||
Message_StringID(13, SPELL_RECAST);
|
||||
mlog(SPELLS__CASTING_ERR, "Casting of %d canceled: item spell reuse timer not expired", spell_id);
|
||||
InterruptSpell();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Can we start the timer here? I don't see why not.
|
||||
CastToClient()->GetPTimers().Start((pTimerItemStart + recasttype), recastdelay);
|
||||
}
|
||||
}
|
||||
|
||||
if (inst && inst->IsType(ItemClassCommon) && (inst->GetItem()->Click.Effect == spell_id) && inst->GetCharges() || fromaug)
|
||||
{
|
||||
//const Item_Struct* item = inst->GetItem();
|
||||
int16 charges = inst->GetItem()->MaxCharges;
|
||||
|
||||
if(fromaug) { charges = -1; } //Don't destroy the parent item
|
||||
if(fromaug) { charges = -1; } //Don't destroy the parent item
|
||||
|
||||
if(charges > -1) { // charged item, expend a charge
|
||||
mlog(SPELLS__CASTING, "Spell %d: Consuming a charge from item %s (%d) which had %d/%d charges.", spell_id, inst->GetItem()->Name, inst->GetItem()->ID, inst->GetCharges(), inst->GetItem()->MaxCharges);
|
||||
@ -1729,7 +1780,6 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//determine the type of spell target we have
|
||||
CastAction_type CastAction;
|
||||
if(!DetermineSpellTargets(spell_id, spell_target, ae_center, CastAction))
|
||||
@ -1821,8 +1871,8 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
if(!SpellOnTarget(spell_id, spell_target, false, true, resist_adjust, false)) {
|
||||
if(IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id)) {
|
||||
// Prevent mana usage/timers being set for beneficial buffs
|
||||
if(casting_spell_type == 1)
|
||||
InterruptSpell();
|
||||
if(casting_spell_type == 1)
|
||||
InterruptSpell();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -2103,7 +2153,6 @@ bool Mob::ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, uint16 slot) {
|
||||
SetMana(GetMana() - mana_used);
|
||||
}
|
||||
|
||||
|
||||
// check line of sight to target if it's a detrimental spell
|
||||
if(spell_target && IsDetrimentalSpell(spell_id) && !CheckLosFN(spell_target))
|
||||
{
|
||||
@ -2371,7 +2420,7 @@ int Mob::CalcBuffDuration(Mob *caster, Mob *target, uint16 spell_id, int32 caste
|
||||
castlevel = caster_level_override;
|
||||
|
||||
int res = CalcBuffDuration_formula(castlevel, formula, duration);
|
||||
|
||||
|
||||
res = mod_buff_duration(res, caster, target, spell_id);
|
||||
|
||||
mlog(SPELLS__CASTING, "Spell %d: Casting level %d, formula %d, base_duration %d: result %d",
|
||||
@ -2509,43 +2558,6 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// check for special stacking block command in spell1 against spell2
|
||||
for(i = 0; i < EFFECT_COUNT; i++)
|
||||
{
|
||||
effect1 = sp1.effectid[i];
|
||||
if(effect1 == SE_StackingCommand_Block)
|
||||
{
|
||||
/*
|
||||
The logic here is if you're comparing the same spells they can't block each other
|
||||
from refreshing
|
||||
*/
|
||||
if(spellid1 == spellid2)
|
||||
continue;
|
||||
|
||||
blocked_effect = sp1.base[i];
|
||||
blocked_slot = sp1.formula[i] - 201; //they use base 1 for slots, we use base 0
|
||||
blocked_below_value = sp1.max[i];
|
||||
|
||||
if(sp2.effectid[blocked_slot] == blocked_effect)
|
||||
{
|
||||
sp2_value = CalcSpellEffectValue(spellid2, blocked_slot, caster_level2);
|
||||
|
||||
mlog(SPELLS__STACKING, "%s (%d) blocks effect %d on slot %d below %d. New spell has value %d on that slot/effect. %s.",
|
||||
sp1.name, spellid1, blocked_effect, blocked_slot, blocked_below_value, sp2_value, (sp2_value < blocked_below_value)?"Blocked":"Not blocked");
|
||||
|
||||
if(sp2_value < blocked_below_value)
|
||||
{
|
||||
mlog(SPELLS__STACKING, "Blocking spell because sp2_value < blocked_below_value");
|
||||
return -1; // blocked
|
||||
}
|
||||
} else {
|
||||
mlog(SPELLS__STACKING, "%s (%d) blocks effect %d on slot %d below %d, but we do not have that effect on that slot. Ignored.",
|
||||
sp1.name, spellid1, blocked_effect, blocked_slot, blocked_below_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for special stacking overwrite in spell2 against effects in spell1
|
||||
for(i = 0; i < EFFECT_COUNT; i++)
|
||||
{
|
||||
@ -2588,14 +2600,41 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
||||
// arbitration takes place if 2 spells have the same effect at the same
|
||||
// effect slot, otherwise they're stackable, even if it's the same effect
|
||||
bool will_overwrite = false;
|
||||
bool effect_match = true; // Figure out if we're identical in effects on all slots.
|
||||
for(i = 0; i < EFFECT_COUNT; i++)
|
||||
{
|
||||
if(IsBlankSpellEffect(spellid1, i) || IsBlankSpellEffect(spellid2, i))
|
||||
continue;
|
||||
|
||||
effect1 = sp1.effectid[i];
|
||||
effect2 = sp2.effectid[i];
|
||||
|
||||
/*
|
||||
Quick check, are the effects the same, if so then
|
||||
keep going else ignore it for stacking purposes.
|
||||
*/
|
||||
if(effect1 != effect2) {
|
||||
effect_match = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If both spells have SE_StackingCommand_Block in the slot then we check if
|
||||
// it applies to the same slot and effect type.
|
||||
// This is handled here because IsBlankSpellEffect() would block it otherwise,
|
||||
// but for stacking we need to handle it.
|
||||
if (effect1 == SE_StackingCommand_Block) {
|
||||
if (sp1.formula[i] == sp2.formula[i] && sp1.base[i] == sp2.base[i]) {
|
||||
if(sp1.max[i] > sp2.max[i]) {
|
||||
return(-1);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
effect_match = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(IsBlankSpellEffect(spellid1, i) || IsBlankSpellEffect(spellid2, i))
|
||||
continue;
|
||||
|
||||
//Effects which really aren't going to affect stacking.
|
||||
if(effect1 == SE_CurrentHPOnce ||
|
||||
effect1 == SE_CurseCounter ||
|
||||
@ -2604,13 +2643,6 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
Quick check, are the effects the same, if so then
|
||||
keep going else ignore it for stacking purposes.
|
||||
*/
|
||||
if(effect1 != effect2)
|
||||
continue;
|
||||
|
||||
/*
|
||||
Skip check if effect is SE_Limit*
|
||||
skip checking effect2 since we know they are equal
|
||||
@ -2698,9 +2730,50 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
||||
will_overwrite = true;
|
||||
}
|
||||
|
||||
// check for special stacking block command in spell1 against spell2
|
||||
// This has to happen last so that we don't mess ourselves up for effect identical
|
||||
// spells. They should just overwrite each other without needing the stacking block
|
||||
if (!effect_match)
|
||||
{
|
||||
for(i = 0; i < EFFECT_COUNT; i++)
|
||||
{
|
||||
effect1 = sp1.effectid[i];
|
||||
if(effect1 == SE_StackingCommand_Block)
|
||||
{
|
||||
/*
|
||||
The logic here is if you're comparing the same spells they can't block each other
|
||||
from refreshing
|
||||
*/
|
||||
if(spellid1 == spellid2)
|
||||
continue;
|
||||
|
||||
blocked_effect = sp1.base[i];
|
||||
blocked_slot = sp1.formula[i] - 201; //they use base 1 for slots, we use base 0
|
||||
blocked_below_value = sp1.max[i];
|
||||
|
||||
if(sp2.effectid[blocked_slot] == blocked_effect)
|
||||
{
|
||||
sp2_value = CalcSpellEffectValue(spellid2, blocked_slot, caster_level2);
|
||||
|
||||
mlog(SPELLS__STACKING, "%s (%d) blocks effect %d on slot %d below %d. New spell has value %d on that slot/effect. %s.",
|
||||
sp1.name, spellid1, blocked_effect, blocked_slot, blocked_below_value, sp2_value, (sp2_value < blocked_below_value)?"Blocked":"Not blocked");
|
||||
|
||||
if(sp2_value < blocked_below_value)
|
||||
{
|
||||
mlog(SPELLS__STACKING, "Blocking spell because sp2_value < blocked_below_value");
|
||||
return -1; // blocked
|
||||
}
|
||||
} else {
|
||||
mlog(SPELLS__STACKING, "%s (%d) blocks effect %d on slot %d below %d, but we do not have that effect on that slot. Ignored.",
|
||||
sp1.name, spellid1, blocked_effect, blocked_slot, blocked_below_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if we get here, then none of the values on the new spell are "worse"
|
||||
//so now we see if this new spell is any better, or if its not related at all
|
||||
if(will_overwrite) {
|
||||
if(will_overwrite || effect_match) {
|
||||
mlog(SPELLS__STACKING, "Stacking code decided that %s should overwrite %s.", sp2.name, sp1.name);
|
||||
return(1);
|
||||
}
|
||||
@ -2714,7 +2787,7 @@ int Mob::CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2,
|
||||
// derived from http://samanna.net/eq.general/buffs.shtml
|
||||
// spells 1-50: no restrictons
|
||||
// 51-65: SpellLevel/2+15
|
||||
// 66+L Group Spells 62, Single Target 61
|
||||
// 66+ Group Spells 62, Single Target 61
|
||||
bool Mob::CheckSpellLevelRestriction(uint16 spell_id)
|
||||
{
|
||||
return true;
|
||||
@ -2724,20 +2797,15 @@ bool Client::CheckSpellLevelRestriction(uint16 spell_id)
|
||||
{
|
||||
int SpellLevel = GetMinLevel(spell_id);
|
||||
|
||||
// Only check for beneficial buffs, if it's a bard song, only if it's short duration
|
||||
if(IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id) &&
|
||||
!(IsBardSong(spell_id) && !IsShortDurationBuff(spell_id)))
|
||||
{
|
||||
if(SpellLevel > 65)
|
||||
{
|
||||
if(IsGroupSpell(spell_id) && GetLevel() < 62)
|
||||
// Only check for beneficial buffs
|
||||
if (IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id)) {
|
||||
if (SpellLevel > 65) {
|
||||
if (IsGroupSpell(spell_id) && GetLevel() < 62)
|
||||
return false;
|
||||
else if(GetLevel() < 61)
|
||||
else if (GetLevel() < 61)
|
||||
return false;
|
||||
}
|
||||
else if(SpellLevel > 50) // 51-65
|
||||
{
|
||||
if(GetLevel() < (SpellLevel/2+15))
|
||||
} else if (SpellLevel > 50) { // 51-65
|
||||
if (GetLevel() < (SpellLevel / 2 + 15))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -2911,7 +2979,6 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
||||
SendPetBuffsToClient();
|
||||
}
|
||||
|
||||
|
||||
if((IsClient() && !CastToClient()->GetPVP()) || (IsPet() && GetOwner() && GetOwner()->IsClient() && !GetOwner()->CastToClient()->GetPVP()) ||
|
||||
(IsMerc() && GetOwner() && GetOwner()->IsClient() && !GetOwner()->CastToClient()->GetPVP()))
|
||||
{
|
||||
@ -3103,7 +3170,6 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
// send to people in the area, ignoring caster and target
|
||||
entity_list.QueueCloseClients(spelltar, action_packet, true, 200, this, true, spelltar->IsClient() ? FilterPCSpells : FilterNPCSpells);
|
||||
|
||||
|
||||
/* Send the EVENT_CAST_ON event */
|
||||
if(spelltar->IsNPC())
|
||||
{
|
||||
@ -3234,7 +3300,6 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
|
||||
}
|
||||
|
||||
|
||||
if(!IsBeneficialAllowed(spelltar) ||
|
||||
(IsGroupOnlySpell(spell_id) &&
|
||||
!(
|
||||
@ -3271,7 +3336,6 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob* spelltar, bool reflect, bool use_r
|
||||
// ok at this point the spell is permitted to affect the target,
|
||||
// but we need to check special cases and resists
|
||||
|
||||
|
||||
// check immunities
|
||||
if(spelltar->IsImmuneToSpell(spell_id, this))
|
||||
{
|
||||
@ -4014,7 +4078,6 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!CharismaCheck){
|
||||
|
||||
//Check for Spell Effect specific resistance chances (ie AA Mental Fortitude)
|
||||
@ -4110,60 +4173,60 @@ float Mob::ResistSpell(uint8 resist_type, uint16 spell_id, Mob *caster, bool use
|
||||
resist_chance = 0;
|
||||
}
|
||||
|
||||
//Adjust our resist chance based on level modifiers
|
||||
int temp_level_diff = GetLevel() - caster->GetLevel();
|
||||
if(IsNPC() && GetLevel() >= RuleI(Casting,ResistFalloff))
|
||||
{
|
||||
int a = (RuleI(Casting,ResistFalloff)-1) - caster->GetLevel();
|
||||
if(a > 0)
|
||||
{
|
||||
temp_level_diff = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_level_diff = 0;
|
||||
}
|
||||
}
|
||||
//Adjust our resist chance based on level modifiers
|
||||
int temp_level_diff = GetLevel() - caster->GetLevel();
|
||||
if(IsNPC() && GetLevel() >= RuleI(Casting,ResistFalloff))
|
||||
{
|
||||
int a = (RuleI(Casting,ResistFalloff)-1) - caster->GetLevel();
|
||||
if(a > 0)
|
||||
{
|
||||
temp_level_diff = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_level_diff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(IsClient() && GetLevel() >= 21 && temp_level_diff > 15)
|
||||
{
|
||||
temp_level_diff = 15;
|
||||
}
|
||||
if(IsClient() && GetLevel() >= 21 && temp_level_diff > 15)
|
||||
{
|
||||
temp_level_diff = 15;
|
||||
}
|
||||
|
||||
if(IsNPC() && temp_level_diff < -9)
|
||||
{
|
||||
temp_level_diff = -9;
|
||||
}
|
||||
if(IsNPC() && temp_level_diff < -9)
|
||||
{
|
||||
temp_level_diff = -9;
|
||||
}
|
||||
|
||||
int level_mod = temp_level_diff * temp_level_diff / 2;
|
||||
if(temp_level_diff < 0)
|
||||
{
|
||||
level_mod = -level_mod;
|
||||
}
|
||||
int level_mod = temp_level_diff * temp_level_diff / 2;
|
||||
if(temp_level_diff < 0)
|
||||
{
|
||||
level_mod = -level_mod;
|
||||
}
|
||||
|
||||
if(IsNPC() && (caster->GetLevel() - GetLevel()) < -20)
|
||||
{
|
||||
level_mod = 1000;
|
||||
}
|
||||
if(IsNPC() && (caster->GetLevel() - GetLevel()) < -20)
|
||||
{
|
||||
level_mod = 1000;
|
||||
}
|
||||
|
||||
//Even more level stuff this time dealing with damage spells
|
||||
if(IsNPC() && IsDamageSpell(spell_id) && GetLevel() >= 17)
|
||||
{
|
||||
int level_diff;
|
||||
if(GetLevel() >= RuleI(Casting,ResistFalloff))
|
||||
{
|
||||
level_diff = (RuleI(Casting,ResistFalloff)-1) - caster->GetLevel();
|
||||
if(level_diff < 0)
|
||||
{
|
||||
level_diff = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
level_diff = GetLevel() - caster->GetLevel();
|
||||
}
|
||||
level_mod += (2 * level_diff);
|
||||
}
|
||||
//Even more level stuff this time dealing with damage spells
|
||||
if(IsNPC() && IsDamageSpell(spell_id) && GetLevel() >= 17)
|
||||
{
|
||||
int level_diff;
|
||||
if(GetLevel() >= RuleI(Casting,ResistFalloff))
|
||||
{
|
||||
level_diff = (RuleI(Casting,ResistFalloff)-1) - caster->GetLevel();
|
||||
if(level_diff < 0)
|
||||
{
|
||||
level_diff = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
level_diff = GetLevel() - caster->GetLevel();
|
||||
}
|
||||
level_mod += (2 * level_diff);
|
||||
}
|
||||
|
||||
if (CharismaCheck)
|
||||
{
|
||||
@ -4723,7 +4786,6 @@ uint16 Mob::GetSpellIDFromSlot(uint8 slot)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
bool Mob::FindType(uint16 type, bool bOffensive, uint16 threshold) {
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
for (int i = 0; i < buff_count; i++) {
|
||||
@ -4922,7 +4984,6 @@ int Mob::GetCasterLevel(uint16 spell_id) {
|
||||
return(level);
|
||||
}
|
||||
|
||||
|
||||
//this method does NOT tell the client to stop singing the song.
|
||||
//this is NOT the right way to stop a mob from singing, use InterruptSpell
|
||||
//you should really know what your doing before you call this
|
||||
@ -4965,7 +5026,6 @@ void Mob::SendPetBuffsToClient()
|
||||
|
||||
int PetBuffCount = 0;
|
||||
|
||||
|
||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_PetBuffWindow,sizeof(PetBuff_Struct));
|
||||
PetBuff_Struct* pbs=(PetBuff_Struct*)outapp->pBuffer;
|
||||
memset(outapp->pBuffer,0,outapp->size);
|
||||
@ -5044,8 +5104,6 @@ EQApplicationPacket *Mob::MakeBuffsPacket(bool for_target)
|
||||
return outapp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Mob::BuffModifyDurationBySpellID(uint16 spell_id, int32 newDuration)
|
||||
{
|
||||
uint32 buff_count = GetMaxTotalSlots();
|
||||
|
||||
@ -27,20 +27,20 @@
|
||||
|
||||
Schema:
|
||||
CREATE TABLE traps (
|
||||
id int(11) NOT nullptr auto_increment,
|
||||
zone varchar(16) NOT nullptr default '',
|
||||
x int(11) NOT nullptr default '0',
|
||||
y int(11) NOT nullptr default '0',
|
||||
z int(11) NOT nullptr default '0',
|
||||
chance tinyint NOT nullptr default '0',
|
||||
maxzdiff float NOT nullptr default '0',
|
||||
radius float NOT nullptr default '0',
|
||||
effect int(11) NOT nullptr default '0',
|
||||
effectvalue int(11) NOT nullptr default '0',
|
||||
effectvalue2 int(11) NOT nullptr default '0',
|
||||
message varcahr(200) NOT nullptr;
|
||||
skill int(11) NOT nullptr default '0',
|
||||
spawnchance int(11) NOT nullptr default '0',
|
||||
id int(11) NOT NULL auto_increment,
|
||||
zone varchar(16) NOT NULL default '',
|
||||
x int(11) NOT NULL default '0',
|
||||
y int(11) NOT NULL default '0',
|
||||
z int(11) NOT NULL default '0',
|
||||
chance tinyint NOT NULL default '0',
|
||||
maxzdiff float NOT NULL default '0',
|
||||
radius float NOT NULL default '0',
|
||||
effect int(11) NOT NULL default '0',
|
||||
effectvalue int(11) NOT NULL default '0',
|
||||
effectvalue2 int(11) NOT NULL default '0',
|
||||
message varcahr(200) NOT NULL;
|
||||
skill int(11) NOT NULL default '0',
|
||||
spawnchance int(11) NOT NULL default '0',
|
||||
PRIMARY KEY (id)
|
||||
) TYPE=MyISAM;
|
||||
|
||||
|
||||
@ -1046,6 +1046,7 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
|
||||
"npc_types.hp_regen_rate,"
|
||||
"npc_types.mana_regen_rate,"
|
||||
"npc_types.aggroradius,"
|
||||
"npc_types.assistradius,"
|
||||
"npc_types.bodytype,"
|
||||
"npc_types.npc_faction_id,"
|
||||
"npc_types.face,"
|
||||
@ -1145,6 +1146,9 @@ const NPCType* ZoneDatabase::GetNPCType (uint32 id) {
|
||||
// set defaultvalue for aggroradius
|
||||
if (tmpNPCType->aggroradius <= 0)
|
||||
tmpNPCType->aggroradius = 70;
|
||||
tmpNPCType->assistradius = (int32)atoi(row[r++]);
|
||||
if (tmpNPCType->assistradius <= 0)
|
||||
tmpNPCType->assistradius = tmpNPCType->aggroradius;
|
||||
|
||||
if (row[r] && strlen(row[r]))
|
||||
tmpNPCType->bodytype = (uint8)atoi(row[r]);
|
||||
|
||||
@ -97,6 +97,7 @@ struct NPCType
|
||||
int32 hp_regen;
|
||||
int32 mana_regen;
|
||||
int32 aggroradius; // added for AI improvement - neotokyo
|
||||
int32 assistradius; // assist radius, defaults to aggroradis if not set
|
||||
uint8 see_invis; // See Invis flag added
|
||||
bool see_invis_undead; // See Invis vs. Undead flag added
|
||||
bool see_hide;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user