Merge branch 'master' into eqstream

This commit is contained in:
KimLS 2017-03-12 18:39:15 -07:00
commit 159706efa9
15 changed files with 315 additions and 68 deletions

View File

@ -1,5 +1,21 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 03/12/2017 ==
Akkadius:
- Implemented range rules for packets and other functions
RULE_INT ( Range, Say, 135 )
RULE_INT ( Range, Emote, 135 )
RULE_INT ( Range, BeginCast, 200)
RULE_INT ( Range, Anims, 135)
RULE_INT ( Range, SpellParticles, 135)
RULE_INT ( Range, DamageMessages, 50)
RULE_INT ( Range, SpellMessages, 75)
RULE_INT ( Range, SongMessages, 75)
RULE_INT ( Range, MobPositionUpdates, 600)
RULE_INT ( Range, CriticalDamage, 80)
- (Readability) Also cleaned up some formatting in messaging and packets so it is easier to understand what is going on with the code
== 03/09/2017 ==
Uleat: Fixed a few glitches related to bot trading and other affected code
- Added a temporary fail clause for partial stack transfers to prevent client item overwrites

View File

@ -207,3 +207,21 @@ bool EQEmu::ItemData::IsTypeShield() const
{
return (ItemType == item::ItemTypeShield);
}
bool EQEmu::ItemData::CheckLoreConflict(const ItemData* l_item, const ItemData* r_item)
{
if (!l_item || !r_item)
return false;
if (!l_item->LoreGroup || !r_item->LoreGroup)
return false;
if (l_item->LoreGroup == r_item->LoreGroup) {
if ((l_item->LoreGroup == -1) && (l_item->ID != r_item->ID))
return false;
return true;
}
return false;
}

View File

@ -538,6 +538,9 @@ namespace EQEmu
bool IsType1HWeapon() const;
bool IsType2HWeapon() const;
bool IsTypeShield() const;
static bool CheckLoreConflict(const ItemData* l_item, const ItemData* r_item);
bool CheckLoreConflict(const ItemData* item) const { return CheckLoreConflict(this, item); }
};
} /*EQEmu*/

View File

@ -226,6 +226,7 @@ RULE_BOOL (World, IsGMPetitionWindowEnabled, false)
RULE_INT (World, FVNoDropFlag, 0) // Sets the Firiona Vie settings on the client. If set to 2, the flag will be set for GMs only, allowing trading of no-drop items.
RULE_BOOL (World, IPLimitDisconnectAll, false)
RULE_INT (World, TellQueueSize, 20)
RULE_BOOL(World, StartZoneSameAsBindOnCreation, true) //Should the start zone ALWAYS be the same location as your bind?
RULE_CATEGORY_END()
RULE_CATEGORY(Zone)
@ -543,6 +544,20 @@ RULE_BOOL(TaskSystem, KeepOneRecordPerCompletedTask, true)
RULE_BOOL(TaskSystem, EnableTaskProximity, true)
RULE_CATEGORY_END()
RULE_CATEGORY(Range)
RULE_INT(Range, Say, 135)
RULE_INT(Range, Emote, 135)
RULE_INT(Range, BeginCast, 200)
RULE_INT(Range, Anims, 135)
RULE_INT(Range, SpellParticles, 135)
RULE_INT(Range, DamageMessages, 50)
RULE_INT(Range, SpellMessages, 75)
RULE_INT(Range, SongMessages, 75)
RULE_INT(Range, MobPositionUpdates, 600)
RULE_INT(Range, CriticalDamage, 80)
RULE_CATEGORY_END()
#ifdef BOTS
RULE_CATEGORY(Bots)
RULE_INT(Bots, AAExpansion, 8) // Bots get AAs through this expansion

View File

@ -0,0 +1,10 @@
INSERT INTO `rule_values` VALUES (1, 'Range:SongMessages', '75', 'The packet range in which song messages are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:Emote', '135', 'The packet range in which emote messages are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:BeginCast', '200', 'The packet range in which begin cast messages are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:Anims', '135', 'The packet range in which animations are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:DamageMessages', '50', 'The packet range in which damage messages are sent (non-crit)');
INSERT INTO `rule_values` VALUES (1, 'Range:SpellMessages', '75', 'The packet range in which spell damage messages are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:Say', '135', 'The range that is required before /say or hail messages will work to an NPC');
INSERT INTO `rule_values` VALUES (1, 'Range:SpellParticles', '135', 'The packet range in which spell particles are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:MobPositionUpdates', '600', 'The packet range in which mob position updates are sent');
INSERT INTO `rule_values` VALUES (1, 'Range:CriticalDamage', '80', 'The packet range in which critical hit messages are sent');

View File

@ -1528,12 +1528,14 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
database.GetSafePoints(pp.zone_id, 0, &pp.x, &pp.y, &pp.z);
}
/* Will either be the same as home or tutorial */
pp.binds[0].zoneId = pp.zone_id;
pp.binds[0].x = pp.x;
pp.binds[0].y = pp.y;
pp.binds[0].z = pp.z;
pp.binds[0].heading = pp.heading;
/* Will either be the same as home or tutorial if enabled. */
if(RuleB(World, StartZoneSameAsBindOnCreation)) {
pp.binds[0].zoneId = pp.zone_id;
pp.binds[0].x = pp.x;
pp.binds[0].y = pp.y;
pp.binds[0].z = pp.z;
pp.binds[0].heading = pp.heading;
}
Log.Out(Logs::Detail, Logs::World_Server,"Current location: %s (%d) %0.2f, %0.2f, %0.2f, %0.2f",
database.GetZoneName(pp.zone_id), pp.zone_id, pp.x, pp.y, pp.z, pp.heading);

View File

@ -353,7 +353,7 @@ bool WorldDatabase::GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct*
in_pp->x = in_pp->y = in_pp->z = in_pp->heading = in_pp->zone_id = 0;
in_pp->binds[0].x = in_pp->binds[0].y = in_pp->binds[0].z = in_pp->binds[0].zoneId = in_pp->binds[0].instance_id = 0;
// see if we have an entry for start_zone. We can support both titanium & SOF+ by having two entries per class/race/deity combo with different zone_ids
std::string query = StringFormat("SELECT x, y, z, heading, start_zone, bind_id FROM start_zones WHERE zone_id = %i "
std::string query = StringFormat("SELECT x, y, z, heading, start_zone, bind_id, bind_x, bind_y, bind_z FROM start_zones WHERE zone_id = %i "
"AND player_class = %i AND player_deity = %i AND player_race = %i",
in_cc->start_zone, in_cc->class_, in_cc->deity, in_cc->race);
auto results = QueryDatabase(query);
@ -376,6 +376,9 @@ bool WorldDatabase::GetStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct*
in_pp->heading = atof(row[3]);
in_pp->zone_id = atoi(row[4]);
in_pp->binds[0].zoneId = atoi(row[5]);
in_pp->binds[0].x = atof(row[6]);
in_pp->binds[0].y = atof(row[7]);
in_pp->binds[0].z = atof(row[8]);
}
if(in_pp->x == 0 && in_pp->y == 0 && in_pp->z == 0)

View File

@ -1481,9 +1481,18 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk
}
if(killerMob && killerMob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) {
char val1[20]={0};
entity_list.MessageClose_StringID(this, false, 100, MT_NonMelee, HIT_NON_MELEE,
killerMob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1));
char val1[20] = { 0 };
entity_list.MessageClose_StringID(
this, /* Sender */
false, /* Skip Sender */
RuleI(Range, DamageMessages),
MT_NonMelee, /* 283 */
HIT_NON_MELEE, /* %1 hit %2 for %3 points of non-melee damage. */
killerMob->GetCleanName(), /* Message1 */
GetCleanName(), /* Message2 */
ConvertArray(damage, val1)/* Message3 */
);
}
int exploss = 0;
@ -2010,8 +2019,17 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQEmu::skills::Skil
if (killer_mob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) {
char val1[20] = { 0 };
entity_list.MessageClose_StringID(this, false, 100, MT_NonMelee, HIT_NON_MELEE,
killer_mob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1));
entity_list.MessageClose_StringID(
this, /* Sender */
false, /* Skip Sender */
RuleI(Range, DamageMessages),
MT_NonMelee, /* 283 */
HIT_NON_MELEE, /* %1 hit %2 for %3 points of non-melee damage. */
killer_mob->GetCleanName(), /* Message1 */
GetCleanName(), /* Message2 */
ConvertArray(damage, val1) /* Message3 */
);
}
}
else {
@ -3226,7 +3244,7 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
//we used to do a message to the client, but its gone now.
// emote goes with every one ... even npcs
entity_list.MessageClose(this, true, 300, MT_Emote, "%s beams a smile at %s", attacker->GetCleanName(), this->GetCleanName() );
entity_list.MessageClose(this, true, RuleI(Range, SpellMessages), MT_Emote, "%s beams a smile at %s", attacker->GetCleanName(), this->GetCleanName() );
}
} //end `if there is some damage being done and theres anattacker person involved`
@ -3306,8 +3324,15 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
//fade mez if we are mezzed
if (IsMezzed() && attacker) {
Log.Out(Logs::Detail, Logs::Combat, "Breaking mez due to attack.");
entity_list.MessageClose_StringID(this, true, 100, MT_WornOff,
HAS_BEEN_AWAKENED, GetCleanName(), attacker->GetCleanName());
entity_list.MessageClose_StringID(
this, /* Sender */
true, /* Skip Sender */
RuleI(Range, SpellMessages),
MT_WornOff, /* 284 */
HAS_BEEN_AWAKENED, // %1 has been awakened by %2.
GetCleanName(), /* Message1 */
attacker->GetCleanName() /* Message2 */
);
BuffFadeByEffect(SE_Mez);
}
@ -3451,8 +3476,8 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
else
filter = FilterPetMisses;
if(!FromDamageShield)
owner->CastToClient()->QueuePacket(outapp,true,CLIENT_CONNECTED,filter);
if (!FromDamageShield)
owner->CastToClient()->QueuePacket(outapp, true, CLIENT_CONNECTED, filter);
}
}
skip = owner;
@ -3466,9 +3491,18 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
char val1[20] = {0};
if (FromDamageShield) {
if (attacker->CastToClient()->GetFilter(FilterDamageShields) != FilterHide)
attacker->Message_StringID(MT_DS,OTHER_HIT_NONMELEE, GetCleanName(), ConvertArray(damage, val1));
attacker->Message_StringID(MT_DS, OTHER_HIT_NONMELEE, GetCleanName(), ConvertArray(damage, val1));
} else {
entity_list.MessageClose_StringID(this, true, 100, MT_NonMelee, HIT_NON_MELEE, attacker->GetCleanName(), GetCleanName(), ConvertArray(damage, val1));
entity_list.MessageClose_StringID(
this, /* Sender */
true, /* Skip Sender */
RuleI(Range, SpellMessages),
MT_NonMelee, /* 283 */
HIT_NON_MELEE, /* %1 hit %2 for %3 points of non-melee damage. */
attacker->GetCleanName(), /* Message1 */
GetCleanName(), /* Message2 */
ConvertArray(damage, val1) /* Message3 */
);
}
} else {
if(damage > 0) {
@ -3502,7 +3536,17 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
// If this is Damage Shield damage, the correct OP_Damage packets will be sent from Mob::DamageShield, so
// we don't send them here.
if(!FromDamageShield) {
entity_list.QueueCloseClients(this, outapp, true, 200, skip, true, filter);
entity_list.QueueCloseClients(
this, /* Sender */
outapp, /* packet */
true, /* Skip Sender */
RuleI(Range, SpellMessages),
skip, /* Skip this mob */
true, /* Packet ACK */
filter /* eqFilterType filter */
);
//send the damage to ourself if we are a client
if(IsClient()) {
//I dont think any filters apply to damage affecting us
@ -3518,10 +3562,20 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
//might filter on (attack_skill>200 && attack_skill<250), but I dont think we need it
attacker->FilteredMessage_StringID(attacker, MT_DoTDamage, FilterDOT,
YOUR_HIT_DOT, GetCleanName(), itoa(damage), spells[spell_id].name);
// older clients don't have the below String ID, but it will be filtered
entity_list.FilteredMessageClose_StringID(attacker, true, 200,
MT_DoTDamage, FilterDOT, OTHER_HIT_DOT, GetCleanName(),
itoa(damage), attacker->GetCleanName(), spells[spell_id].name);
/* older clients don't have the below String ID, but it will be filtered */
entity_list.FilteredMessageClose_StringID(
attacker, /* Sender */
true, /* Skip Sender */
RuleI(Range, SpellMessages),
MT_DoTDamage, /* Type: 325 */
FilterDOT, /* FilterType: 19 */
OTHER_HIT_DOT, /* MessageFormat: %1 has taken %2 damage from %3 by %4. */
GetCleanName(), /* Message1 */
itoa(damage), /* Message2 */
attacker->GetCleanName(), /* Message3 */
spells[spell_id].name /* Message4 */
);
}
} //end packet sending
@ -3850,7 +3904,7 @@ void Mob::TrySpellProc(const EQEmu::ItemInstance *inst, const EQEmu::ItemData *w
begincast->spell_id = SpellProcs[i].spellID;
begincast->cast_time = 0;
outapp->priority = 3;
entity_list.QueueCloseClients(this, outapp, false, 200, 0, true);
entity_list.QueueCloseClients(this, outapp, false, RuleI(Range, SpellMessages), 0, true);
safe_delete(outapp);
ExecWeaponProc(nullptr, SpellProcs[i].spellID, on, SpellProcs[i].level_override);
CheckNumHitsRemaining(NumHit::OffensiveSpellProcs, 0,
@ -3929,8 +3983,18 @@ void Mob::TryPetCriticalHit(Mob *defender, DamageHitInfo &hit)
critMod += GetCritDmgMob(hit.skill);
hit.damage_done += 5;
hit.damage_done = (hit.damage_done * critMod) / 100;
entity_list.FilteredMessageClose_StringID(this, false, 200, MT_CritMelee, FilterMeleeCrits,
CRITICAL_HIT, GetCleanName(), itoa(hit.damage_done + hit.min_damage));
entity_list.FilteredMessageClose_StringID(
this, /* Sender */
false, /* Skip Sender */
RuleI(Range, CriticalDamage),
MT_CritMelee, /* Type: 301 */
FilterMeleeCrits, /* FilterType: 12 */
CRITICAL_HIT, /* MessageFormat: %1 scores a critical hit! (%2) */
GetCleanName(), /* Message1 */
itoa(hit.damage_done + hit.min_damage) /* Message2 */
);
}
}
}
@ -3968,14 +4032,33 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
{aabonuses.SlayUndead[1], itembonuses.SlayUndead[1], spellbonuses.SlayUndead[1]});
hit.damage_done = std::max(hit.damage_done, hit.base_damage) + 5;
hit.damage_done = (hit.damage_done * SlayDmgBonus) / 100;
if (GetGender() == 1) // female
/* Female */
if (GetGender() == 1) {
entity_list.FilteredMessageClose_StringID(
this, false, 200, MT_CritMelee, FilterMeleeCrits, FEMALE_SLAYUNDEAD,
GetCleanName(), itoa(hit.damage_done + hit.min_damage));
else // males and neuter I guess
this, /* Sender */
false, /* Skip Sender */
RuleI(Range, CriticalDamage),
MT_CritMelee, /* Type: 301 */
FilterMeleeCrits, /* FilterType: 12 */
FEMALE_SLAYUNDEAD, /* MessageFormat: %1's holy blade cleanses her target!(%2) */
GetCleanName(), /* Message1 */
itoa(hit.damage_done + hit.min_damage) /* Message2 */
);
}
/* Males and Neuter */
else {
entity_list.FilteredMessageClose_StringID(
this, false, 200, MT_CritMelee, FilterMeleeCrits, MALE_SLAYUNDEAD,
GetCleanName(), itoa(hit.damage_done + hit.min_damage));
this, /* Sender */
false, /* Skip Sender */
RuleI(Range, CriticalDamage),
MT_CritMelee, /* Type: 301 */
FilterMeleeCrits, /* FilterType: 12 */
MALE_SLAYUNDEAD, /* MessageFormat: %1's holy blade cleanses his target!(%2) */
GetCleanName(), /* Message1 */
itoa(hit.damage_done + hit.min_damage) /* Message2 */
);
}
return;
}
}
@ -4044,9 +4127,17 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
return;
}
hit.damage_done = hit.damage_done * 200 / 100;
entity_list.FilteredMessageClose_StringID(
this, false, 200, MT_CritMelee, FilterMeleeCrits, DEADLY_STRIKE,
GetCleanName(), itoa(hit.damage_done + hit.min_damage));
this, /* Sender */
false, /* Skip Sender */
RuleI(Range, CriticalDamage),
MT_CritMelee, /* Type: 301 */
FilterMeleeCrits, /* FilterType: 12 */
DEADLY_STRIKE, /* MessageFormat: %1 scores a Deadly Strike!(%2) */
GetCleanName(), /* Message1 */
itoa(hit.damage_done + hit.min_damage) /* Message2 */
);
return;
}
}
@ -4064,9 +4155,18 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
if (IsBerserk() || berserk) {
hit.damage_done += og_damage * 119 / 100;
Log.Out(Logs::Detail, Logs::Combat, "Crip damage %d", hit.damage_done);
entity_list.FilteredMessageClose_StringID(
this, false, 200, MT_CritMelee, FilterMeleeCrits, CRIPPLING_BLOW, GetCleanName(),
itoa(hit.damage_done + hit.min_damage));
this, /* Sender */
false, /* Skip Sender */
RuleI(Range, CriticalDamage),
MT_CritMelee, /* Type: 301 */
FilterMeleeCrits, /* FilterType: 12 */
CRIPPLING_BLOW, /* MessageFormat: %1 lands a Crippling Blow!(%2) */
GetCleanName(), /* Message1 */
itoa(hit.damage_done + hit.min_damage) /* Message2 */
);
// Crippling blows also have a chance to stun
// Kayen: Crippling Blow would cause a chance to interrupt for npcs < 55, with a
// staggers message.
@ -4076,10 +4176,18 @@ void Mob::TryCriticalHit(Mob *defender, DamageHitInfo &hit, ExtraAttackOptions *
}
return;
}
// okay, critted but didn't do anything else, just normal message now
entity_list.FilteredMessageClose_StringID(this, false, 200, MT_CritMelee, FilterMeleeCrits,
CRITICAL_HIT, GetCleanName(),
itoa(hit.damage_done + hit.min_damage));
/* Normal Critical hit message */
entity_list.FilteredMessageClose_StringID(
this, /* Sender */
false, /* Skip Sender */
RuleI(Range, CriticalDamage),
MT_CritMelee, /* Type: 301 */
FilterMeleeCrits, /* FilterType: 12 */
CRITICAL_HIT, /* MessageFormat: %1 scores a critical hit! (%2) */
GetCleanName(), /* Message1 */
itoa(hit.damage_done + hit.min_damage) /* Message2 */
);
}
}
}
@ -4105,7 +4213,18 @@ bool Mob::TryFinishingBlow(Mob *defender, int &damage)
if (FB_Level && FB_Dmg && (defender->GetLevel() <= FB_Level) &&
(ProcChance >= zone->random.Int(1, 1000))) {
entity_list.MessageClose_StringID(this, false, 200, MT_CritMelee, FINISHING_BLOW, GetName());
/* Finishing Blow Critical Message */
entity_list.FilteredMessageClose_StringID(
this, /* Sender */
false, /* Skip Sender */
RuleI(Range, CriticalDamage),
MT_CritMelee, /* Type: 301 */
FilterMeleeCrits, /* FilterType: 12 */
FINISHING_BLOW, /* MessageFormat: %1 scores a Finishing Blow!!) */
GetCleanName() /* Message1 */
);
damage = FB_Dmg;
return true;
}

View File

@ -1098,7 +1098,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
CheckLDoNHail(GetTarget());
CheckEmoteHail(GetTarget(), message);
if(DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= 200) {
if(DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= RuleI(Range, Say)) {
NPC *tar = GetTarget()->CastToNPC();
parse->EventNPC(EVENT_SAY, tar->CastToNPC(), this, message, language);
@ -1110,7 +1110,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
}
}
else {
if (DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= 200) {
if (DistanceSquaredNoZ(m_Position, GetTarget()->GetPosition()) <= RuleI(Range, Say)) {
parse->EventNPC(EVENT_AGGRO_SAY, GetTarget()->CastToNPC(), this, message, language);
}
}
@ -1139,7 +1139,7 @@ void Client::ChannelMessageReceived(uint8 chan_num, uint8 language, uint8 lang_s
char *Buffer = (char *)es;
Buffer += 4;
snprintf(Buffer, sizeof(Emote_Struct) - 4, "%s %s", GetName(), message);
entity_list.QueueCloseClients(this, outapp, true, 100, 0, true, FilterSocials);
entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, Emote), 0, true, FilterSocials);
safe_delete(outapp);
break;
}

View File

@ -4371,7 +4371,7 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
new EQApplicationPacket(OP_ClientUpdate, sizeof(PlayerPositionUpdateServer_Struct));
PlayerPositionUpdateServer_Struct* ppus = (PlayerPositionUpdateServer_Struct*)outapp->pBuffer;
boat->MakeSpawnUpdate(ppus);
entity_list.QueueCloseClients(boat,outapp,true,300,this,false);
entity_list.QueueCloseClients(boat, outapp, true, 300, this, false);
safe_delete(outapp);
// update the boat's position on the server, without sending an update
boat->GMMove(ppu->x_pos, ppu->y_pos, ppu->z_pos, EQ19toFloat(ppu->heading), false);
@ -4605,9 +4605,9 @@ void Client::Handle_OP_ClientUpdate(const EQApplicationPacket *app)
PlayerPositionUpdateServer_Struct* ppu = (PlayerPositionUpdateServer_Struct*)outapp->pBuffer;
MakeSpawnUpdate(ppu);
if (gmhideme)
entity_list.QueueClientsStatus(this,outapp,true,Admin(),250);
entity_list.QueueClientsStatus(this, outapp, true, Admin(), 250);
else
entity_list.QueueCloseClients(this,outapp,true,300,nullptr,false);
entity_list.QueueCloseClients(this, outapp, true, 300, nullptr, false);
safe_delete(outapp);
}
@ -5487,7 +5487,7 @@ void Client::Handle_OP_Emote(const EQApplicationPacket *app)
}
else
*/
entity_list.QueueCloseClients(this, outapp, true, 100, 0, true, FilterSocials);
entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, Emote), 0, true, FilterSocials);
safe_delete(outapp);
return;

View File

@ -1087,7 +1087,6 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
}
if (!IsBeingLootedBy(client)) {
client->Message(13, "Error: Corpse::LootItem: BeingLootedBy != client");
client->QueuePacket(app);
SendEndLootErrorPacket(client);
return;

View File

@ -1427,7 +1427,7 @@ void Mob::SendPosUpdate(uint8 iSendToSelf) {
}
else if(move_tic_count % 2 == 0)
{
entity_list.QueueCloseClients(this, app, (iSendToSelf == 0), 700, nullptr, false);
entity_list.QueueCloseClients(this, app, (iSendToSelf == 0), RuleI(Range, MobPositionUpdates), nullptr, false);
move_tic_count++;
}
else {
@ -1530,15 +1530,26 @@ void Mob::DoAnim(const int animnum, int type, bool ackreq, eqFilterType filter)
auto outapp = new EQApplicationPacket(OP_Animation, sizeof(Animation_Struct));
Animation_Struct* anim = (Animation_Struct*)outapp->pBuffer;
anim->spawnid = GetID();
if(type == 0){
anim->action = animnum;
anim->speed = 10;
}
else{
else {
anim->action = animnum;
anim->speed = type;
}
entity_list.QueueCloseClients(this, outapp, false, 200, 0, ackreq, filter);
entity_list.QueueCloseClients(
this, /* Sender */
outapp, /* Packet */
false, /* Ignore Sender */
RuleI(Range, Anims),
0, /* Skip this mob */
ackreq, /* Packet ACK */
filter /* eqFilterType filter */
);
safe_delete(outapp);
}
@ -1582,7 +1593,7 @@ void Mob::ShowBuffList(Client* client) {
client->Message(0, "Buffs on: %s", this->GetCleanName());
uint32 i;
uint32 buff_count = GetMaxTotalSlots();
for (i=0; i < buff_count; i++) {
for (i = 0; i < buff_count; i++) {
if (buffs[i].spellid != SPELL_UNKNOWN) {
if (spells[buffs[i].spellid].buffdurationformula == DF_Permanent)
client->Message(0, " %i: %s: Permanent", i, spells[buffs[i].spellid].name);

View File

@ -227,8 +227,23 @@ void Client::OPCombatAbility(const CombatAbility_Struct *ca_atk)
if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF2 && ca_atk->m_skill == EQEmu::skills::SkillTigerClaw)
timer = pTimerCombatAbility2;
bool CanBypassSkillCheck = false;
if (ca_atk->m_skill == EQEmu::skills::SkillBash) { // SLAM - Bash without a shield equipped
switch (GetRace())
{
case OGRE:
case TROLL:
case BARBARIAN:
CanBypassSkillCheck = true;
default:
break;
}
}
/* Check to see if actually have skill */
if (!MaxSkill(static_cast<EQEmu::skills::SkillType>(ca_atk->m_skill)))
if (!MaxSkill(static_cast<EQEmu::skills::SkillType>(ca_atk->m_skill)) && !CanBypassSkillCheck)
return;
if (GetTarget()->GetID() != ca_atk->m_target)

View File

@ -364,9 +364,22 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
StopCasting();
Message_StringID(MT_SpellFailure, fizzle_msg);
/* Song Failure Messages */
entity_list.FilteredMessageClose_StringID(
this, true, 200, MT_SpellFailure, IsClient() ? FilterPCSpells : FilterNPCSpells,
fizzle_msg == MISS_NOTE ? MISSED_NOTE_OTHER : SPELL_FIZZLE_OTHER, GetName());
this, /* Sender */
true, /* Skip Sender */
RuleI(Range, SpellMessages),
MT_SpellFailure, /* Type: 289 */
(IsClient() ? FilterPCSpells : FilterNPCSpells), /* FilterType: 8 or 9 depending on client/npc */
(fizzle_msg == MISS_NOTE ? MISSED_NOTE_OTHER : SPELL_FIZZLE_OTHER),
/*
MessageFormat: You miss a note, bringing your song to a close! (if missed note)
MessageFormat: A missed note brings %1's song to a close!
MessageFormat: %1's spell fizzles!
*/
GetName() /* Message1 */
);
TryTriggerOnValueAmount(false, true);
return(false);
@ -470,7 +483,14 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
begincast->spell_id = spell_id;
begincast->cast_time = orgcasttime; // client calculates reduced time by itself
outapp->priority = 3;
entity_list.QueueCloseClients(this, outapp, false, 200, 0, true); //IsClient() ? FILTER_PCSPELLS : FILTER_NPCSPELLS);
entity_list.QueueCloseClients(
this, /* Sender */
outapp, /* Packet */
false, /* Ignore Sender */
RuleI(Range, BeginCast),
0, /* Skip this Mob */
true /* Packet ACK */
); //IsClient() ? FILTER_PCSPELLS : FILTER_NPCSPELLS);
safe_delete(outapp);
}
@ -887,7 +907,7 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid)
ic->messageid = message_other;
ic->spawnid = GetID();
strcpy(ic->message, GetCleanName());
entity_list.QueueCloseClients(this, outapp, true, 200, 0, true, IsClient() ? FilterPCSpells : FilterNPCSpells);
entity_list.QueueCloseClients(this, outapp, true, RuleI(Range, SongMessages), 0, true, IsClient() ? FilterPCSpells : FilterNPCSpells);
safe_delete(outapp);
}
@ -1097,7 +1117,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, CastingSlot slo
// if we got here, we regained concentration
regain_conc = true;
Message_StringID(MT_Spells,REGAIN_AND_CONTINUE);
entity_list.MessageClose_StringID(this, true, 200, MT_Spells, OTHER_REGAIN_CAST, this->GetCleanName());
entity_list.MessageClose_StringID(this, true, RuleI(Range, SpellMessages), MT_Spells, OTHER_REGAIN_CAST, this->GetCleanName());
}
}
@ -2610,7 +2630,7 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) {
action->buff_unknown = 0;
action->level = buffs[buffs_i].casterlevel;
action->type = DamageTypeSpell;
entity_list.QueueCloseClients(this, packet, false, 200, 0, true, IsClient() ? FilterPCSpells : FilterNPCSpells);
entity_list.QueueCloseClients(this, packet, false, RuleI(Range, SongMessages), 0, true, IsClient() ? FilterPCSpells : FilterNPCSpells);
action->buff_unknown = 4;
@ -2682,7 +2702,7 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) {
cd->damage = 0;
if(!IsEffectInSpell(spell_id, SE_BindAffinity))
{
entity_list.QueueCloseClients(this, message_packet, false, 200, 0, true, IsClient() ? FilterPCSpells : FilterNPCSpells);
entity_list.QueueCloseClients(this, message_packet, false, RuleI(Range, SongMessages), 0, true, IsClient() ? FilterPCSpells : FilterNPCSpells);
}
safe_delete(message_packet);
safe_delete(packet);
@ -3485,8 +3505,17 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
spelltar->CastToClient()->QueuePacket(action_packet);
if(IsClient()) // send to caster
CastToClient()->QueuePacket(action_packet);
// send to people in the area, ignoring caster and target
entity_list.QueueCloseClients(spelltar, action_packet, true, 200, this, true, spelltar->IsClient() ? FilterPCSpells : FilterNPCSpells);
entity_list.QueueCloseClients(
spelltar, /* Sender */
action_packet, /* Packet */
true, /* Ignore Sender */
RuleI(Range, SpellMessages),
this, /* Skip this Mob */
true, /* Packet ACK */
(spelltar->IsClient() ? FilterPCSpells : FilterNPCSpells) /* EQ Filter Type: (8 or 9) */
);
/* Send the EVENT_CAST_ON event */
if(spelltar->IsNPC())
@ -3955,9 +3984,16 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
cd->spellid = action->spell;
cd->meleepush_xy = action->sequence;
cd->damage = 0;
if(!IsEffectInSpell(spell_id, SE_BindAffinity))
{
entity_list.QueueCloseClients(spelltar, message_packet, false, 200, 0, true, spelltar->IsClient() ? FilterPCSpells : FilterNPCSpells);
if(!IsEffectInSpell(spell_id, SE_BindAffinity)){
entity_list.QueueCloseClients(
spelltar, /* Sender */
message_packet, /* Packet */
false, /* Ignore Sender */
RuleI(Range, SpellMessages),
0, /* Skip this mob */
true, /* Packet ACK */
(spelltar->IsClient() ? FilterPCSpells : FilterNPCSpells) /* Message Filter Type: (8 or 9) */
);
}
safe_delete(action_packet);
safe_delete(message_packet);
@ -5611,7 +5647,7 @@ void Client::SendSpellAnim(uint16 targetid, uint16 spell_id)
a->sequence = 231;
app.priority = 1;
entity_list.QueueCloseClients(this, &app);
entity_list.QueueCloseClients(this, &app, false, RuleI(Range, SpellParticles));
}
void Mob::CalcDestFromHeading(float heading, float distance, float MaxZDiff, float StartX, float StartY, float &dX, float &dY, float &dZ)

View File

@ -720,7 +720,7 @@ void Client::Gate(uint8 bindnum) {
}
void NPC::Gate(uint8 bindnum) {
entity_list.MessageClose_StringID(this, true, 200, MT_Spells, GATES, GetCleanName());
entity_list.MessageClose_StringID(this, true, RuleI(Range, SpellMessages), MT_Spells, GATES, GetCleanName());
Mob::Gate(bindnum);
}