diff --git a/changelog.txt b/changelog.txt index 073827861..9514c812c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -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 diff --git a/common/item_data.cpp b/common/item_data.cpp index e23f962d2..c0e70d72a 100644 --- a/common/item_data.cpp +++ b/common/item_data.cpp @@ -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; +} diff --git a/common/item_data.h b/common/item_data.h index 14aa368c2..e5d1a24f2 100644 --- a/common/item_data.h +++ b/common/item_data.h @@ -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*/ diff --git a/common/ruletypes.h b/common/ruletypes.h index 1b2688f53..4faa9b5ec 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -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 diff --git a/utils/sql/git/optional/2017_03_12_rule_values_range_update.sql b/utils/sql/git/optional/2017_03_12_rule_values_range_update.sql new file mode 100644 index 000000000..2dad8e8e5 --- /dev/null +++ b/utils/sql/git/optional/2017_03_12_rule_values_range_update.sql @@ -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'); diff --git a/world/client.cpp b/world/client.cpp index f17e90942..1c1dacd46 100644 --- a/world/client.cpp +++ b/world/client.cpp @@ -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); diff --git a/world/worlddb.cpp b/world/worlddb.cpp index 2955daf50..cd6733770 100644 --- a/world/worlddb.cpp +++ b/world/worlddb.cpp @@ -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) diff --git a/zone/attack.cpp b/zone/attack.cpp index 0c8a9ac30..01e1a13e4 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -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; } diff --git a/zone/client.cpp b/zone/client.cpp index 784fa1536..2146337bc 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -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; } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 17d08696e..46c5b932b 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -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; diff --git a/zone/corpse.cpp b/zone/corpse.cpp index 24c4b8220..a1cc8c69d 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -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; diff --git a/zone/mob.cpp b/zone/mob.cpp index 5f524a539..cc76519fa 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -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); diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 3844a9d6d..fee557108 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -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(ca_atk->m_skill))) + if (!MaxSkill(static_cast(ca_atk->m_skill)) && !CanBypassSkillCheck) return; if (GetTarget()->GetID() != ca_atk->m_target) diff --git a/zone/spells.cpp b/zone/spells.cpp index e592f0eae..22b0281ec 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -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) diff --git a/zone/zoning.cpp b/zone/zoning.cpp index 16130f8e2..30dc4d81f 100644 --- a/zone/zoning.cpp +++ b/zone/zoning.cpp @@ -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); }