Merge branch 'master' into eqstream

This commit is contained in:
KimLS
2016-12-21 14:26:59 -08:00
41 changed files with 339 additions and 218 deletions
+5 -5
View File
@@ -1072,6 +1072,11 @@ bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, b
//if weapon damage > 0 then we know we can hit the target with this weapon
//otherwise we cannot and we set the damage to -5 later on
if(weapon_damage > 0){
auto shield_inc = spellbonuses.ShieldEquipDmgMod + itembonuses.ShieldEquipDmgMod + aabonuses.ShieldEquipDmgMod;
if (shield_inc > 0 && HasShieldEquiped() && Hand == EQEmu::inventory::slotPrimary) {
weapon_damage = weapon_damage * (100 + shield_inc) / 100;
hate = hate * (100 + shield_inc) / 100;
}
//Berserker Berserk damage bonus
if(IsBerserk() && GetClass() == BERSERKER){
@@ -2291,11 +2296,6 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
// Spell Casting Subtlety etc
int hatemod = 100 + other->spellbonuses.hatemod + other->itembonuses.hatemod + other->aabonuses.hatemod;
int32 shieldhatemod = other->spellbonuses.ShieldEquipHateMod + other->itembonuses.ShieldEquipHateMod + other->aabonuses.ShieldEquipHateMod;
if (shieldhatemod && other->HasShieldEquiped())
hatemod += shieldhatemod;
if(hatemod < 1)
hatemod = 1;
hate = ((hate * (hatemod))/100);
+5 -23
View File
@@ -940,12 +940,8 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
case SE_ShieldBlock:
newbon->ShieldBlock += base1;
break;
case SE_ShieldEquipHateMod:
newbon->ShieldEquipHateMod += base1;
break;
case SE_ShieldEquipDmgMod:
newbon->ShieldEquipDmgMod[0] += base1;
newbon->ShieldEquipDmgMod[1] += base2;
newbon->ShieldEquipDmgMod += base1;
break;
case SE_SecondaryDmgInc:
newbon->SecondaryDmgInc = true;
@@ -2655,13 +2651,8 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *ne
new_bonus->ShieldBlock += effect_value;
break;
case SE_ShieldEquipHateMod:
new_bonus->ShieldEquipHateMod += effect_value;
break;
case SE_ShieldEquipDmgMod:
new_bonus->ShieldEquipDmgMod[0] += effect_value;
new_bonus->ShieldEquipDmgMod[1] += base2;
new_bonus->ShieldEquipDmgMod += effect_value;
break;
case SE_BlockBehind:
@@ -4555,19 +4546,10 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
itembonuses.DoubleRangedAttack = effect_value;
break;
case SE_ShieldEquipHateMod:
spellbonuses.ShieldEquipHateMod = effect_value;
aabonuses.ShieldEquipHateMod = effect_value;
itembonuses.ShieldEquipHateMod = effect_value;
break;
case SE_ShieldEquipDmgMod:
spellbonuses.ShieldEquipDmgMod[0] = effect_value;
spellbonuses.ShieldEquipDmgMod[1] = effect_value;
aabonuses.ShieldEquipDmgMod[0] = effect_value;
aabonuses.ShieldEquipDmgMod[1] = effect_value;
itembonuses.ShieldEquipDmgMod[0] = effect_value;
itembonuses.ShieldEquipDmgMod[1] = effect_value;
spellbonuses.ShieldEquipDmgMod = effect_value;
aabonuses.ShieldEquipDmgMod = effect_value;
itembonuses.ShieldEquipDmgMod = effect_value;
break;
case SE_TriggerMeleeThreshold:
+2 -2
View File
@@ -2391,7 +2391,7 @@ void Bot::AI_Process() {
}
}
atCombatRange = true;
} else if(IsBotCaster() && GetLevel() > 12) {
} else if(IsBotCaster() && GetLevel() >= RuleI(Bots, CasterStopMeleeLevel)) {
if(IsBotCasterCombatRange(GetTarget()))
atCombatRange = true;
}
@@ -2440,7 +2440,7 @@ void Bot::AI_Process() {
if(GetTarget()->GetHPRatio() <= 99.0f)
BotRangedAttack(GetTarget());
}
else if(!IsBotArcher() && (!(IsBotCaster() && GetLevel() > 12)) && GetTarget() && !IsStunned() && !IsMezzed() && (GetAppearance() != eaDead)) {
else if(!IsBotArcher() && (!(IsBotCaster() && GetLevel() >= RuleI(Bots, CasterStopMeleeLevel))) && GetTarget() && !IsStunned() && !IsMezzed() && (GetAppearance() != eaDead)) {
// we can't fight if we don't have a target, are stun/mezzed or dead..
// Stop attacking if the target is enraged
if((IsEngaged() && !BehindMob(GetTarget(), GetX(), GetY()) && GetTarget()->IsEnraged()) || GetBotStance() == BotStancePassive)
+2 -1
View File
@@ -825,7 +825,7 @@ public:
bool SummonItem(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, bool attuned = false, uint16 to_slot = EQEmu::inventory::slotCursor, uint32 ornament_icon = 0, uint32 ornament_idfile = 0, uint32 ornament_hero_model = 0);
void SetStats(uint8 type,int16 set_val);
void IncStats(uint8 type,int16 increase_val);
void DropItem(int16 slot_id);
void DropItem(int16 slot_id, bool recurse = true);
int GetItemLinkHash(const EQEmu::ItemInstance* inst); // move to ItemData..or make use of the pre-calculated database field
@@ -855,6 +855,7 @@ public:
void SetConsumption(int32 in_hunger, int32 in_thirst);
bool CheckTradeLoreConflict(Client* other);
bool CheckTradeNonDroppable();
void LinkDead();
void Insight(uint32 t_id);
bool CheckDoubleAttack();
+27 -1
View File
@@ -5003,6 +5003,9 @@ void Client::Handle_OP_CrashDump(const EQApplicationPacket *app)
void Client::Handle_OP_CreateObject(const EQApplicationPacket *app)
{
if (Log.log_settings[Logs::Inventory].is_category_enabled)
Log.Out(Logs::Detail, Logs::Inventory, "Handle_OP_CreateObject() [psize: %u] %s", app->size, DumpPacketToString(app).c_str());
DropItem(EQEmu::inventory::slotCursor);
return;
}
@@ -13287,7 +13290,6 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app)
other->trade->state = TradeCompleting;
trade->state = TradeCompleting;
// should we do this for NoDrop items as well?
if (CheckTradeLoreConflict(other) || other->CheckTradeLoreConflict(this)) {
Message_StringID(13, TRADE_CANCEL_LORE);
other->Message_StringID(13, TRADE_CANCEL_LORE);
@@ -13296,6 +13298,26 @@ void Client::Handle_OP_TradeAcceptClick(const EQApplicationPacket *app)
other->trade->Reset();
trade->Reset();
}
else if (CheckTradeNonDroppable()) {
Message_StringID(13, TRADE_HAS_BEEN_CANCELLED);
other->Message_StringID(13, TRADE_HAS_BEEN_CANCELLED);
this->FinishTrade(this);
other->FinishTrade(other);
other->trade->Reset();
trade->Reset();
Message(15, "Hacking activity detected in trade transaction.");
// TODO: query (this) as a hacker
}
else if (other->CheckTradeNonDroppable()) {
Message_StringID(13, TRADE_HAS_BEEN_CANCELLED);
other->Message_StringID(13, TRADE_HAS_BEEN_CANCELLED);
this->FinishTrade(this);
other->FinishTrade(other);
other->trade->Reset();
trade->Reset();
other->Message(15, "Hacking activity detected in trade transaction.");
// TODO: query (other) as a hacker
}
else {
// Audit trade to database for both trade streams
other->trade->LogTrade();
@@ -14030,6 +14052,10 @@ void Client::Handle_OP_WearChange(const EQApplicationPacket *app)
if (wc->spawn_id != GetID())
return;
// Hero Forge ID needs to be fixed here as RoF2 appears to send an incorrect value.
if (wc->hero_forge_model != 0 && wc->wear_slot_id >= 0 && wc->wear_slot_id < EQEmu::textures::weaponPrimary)
wc->hero_forge_model = GetHerosForgeModel(wc->wear_slot_id);
// we could maybe ignore this and just send our own from moveitem
entity_list.QueueClients(this, app, true);
return;
+1
View File
@@ -393,6 +393,7 @@ bool Client::Process() {
{
EQEmu::ItemInstance *wpn = GetInv().GetItem(EQEmu::inventory::slotPrimary);
TryWeaponProc(wpn, auto_attack_target, EQEmu::inventory::slotPrimary);
TriggerDefensiveProcs(auto_attack_target, EQEmu::inventory::slotPrimary, false);
DoAttackRounds(auto_attack_target, EQEmu::inventory::slotPrimary);
if (CheckAATimer(aaTimerRampage))
+4 -13
View File
@@ -745,24 +745,15 @@ void command_wc(Client *c, const Seperator *sep)
uint32 hero_forge_model = 0;
uint32 wearslot = atoi(sep->arg[1]);
// Hero Forge
if (sep->argnum > 2)
{
hero_forge_model = atoi(sep->arg[3]);
if (hero_forge_model > 0)
{
// Conversion to simplify the command arguments
// Hero's Forge model is actually model * 1000 + texture * 100 + wearslot
hero_forge_model *= 1000;
hero_forge_model += (atoi(sep->arg[2]) * 100);
hero_forge_model += wearslot;
// For Hero's Forge, slot 7 is actually for Robes, but it still needs to use slot 1 in the packet
if (wearslot == 7)
{
wearslot = 1;
}
if (hero_forge_model != 0 && hero_forge_model < 1000) {
// Shorthand Hero Forge ID. Otherwise use the value the user entered.
hero_forge_model = (hero_forge_model * 100) + wearslot;
}
}
/*
// Leaving here to add color option to the #wc command eventually
+1 -2
View File
@@ -457,8 +457,7 @@ struct StatBonuses {
int32 ItemATKCap; // Raise item attack cap
int32 FinishingBlow[2]; // Chance to do a finishing blow for specified damage amount.
uint32 FinishingBlowLvl[2]; // Sets max level an NPC can be affected by FB. (base1 = lv, base2= ???)
int32 ShieldEquipHateMod; // Hate mod when shield equiped.
int32 ShieldEquipDmgMod[2]; // Damage mod when shield equiped. 0 = damage modifier 1 = Unknown
int32 ShieldEquipDmgMod; // Increases weapon's base damage by base1 % when shield is equipped (indirectly increasing hate)
bool TriggerOnValueAmount; // Triggers off various different conditions, bool to check if client has effect.
int8 StunBashChance; // chance to stun with bash.
int8 IncreaseChanceMemwipe; // increases chance to memory wipe
+85 -61
View File
@@ -36,7 +36,6 @@ Child of the Mob class.
#include "../common/string_util.h"
#include "../common/say_link.h"
#include "client.h"
#include "corpse.h"
#include "entity.h"
#include "groups.h"
@@ -1063,77 +1062,86 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
SendLootReqErrorPacket(client, LootResponse::LootAll);
}
void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
/* This gets sent no matter what as a sort of ACK */
client->QueuePacket(app);
void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
{
auto lootitem = (LootingItem_Struct *)app->pBuffer;
if (!loot_cooldown_timer.Check()) {
client->QueuePacket(app);
SendEndLootErrorPacket(client);
//unlock corpse for others
if (this->being_looted_by = client->GetID()) {
being_looted_by = 0xFFFFFFFF;
}
// unlock corpse for others
if (IsBeingLootedBy(client))
ResetLooter();
return;
}
/* To prevent item loss for a player using 'Loot All' who doesn't have inventory space for all their items. */
if (RuleB(Character, CheckCursorEmptyWhenLooting) && !client->GetInv().CursorEmpty()) {
client->Message(13, "You may not loot an item while you have an item on your cursor.");
client->QueuePacket(app);
SendEndLootErrorPacket(client);
/* Unlock corpse for others */
if (this->being_looted_by = client->GetID()) {
being_looted_by = 0xFFFFFFFF;
}
if (IsBeingLootedBy(client))
ResetLooter();
return;
}
LootingItem_Struct* lootitem = (LootingItem_Struct*)app->pBuffer;
if (this->being_looted_by != client->GetID()) {
if (!IsBeingLootedBy(client)) {
client->Message(13, "Error: Corpse::LootItem: BeingLootedBy != client");
client->QueuePacket(app);
SendEndLootErrorPacket(client);
return;
}
if (IsPlayerCorpse() && !CanPlayerLoot(client->CharacterID()) && !become_npc && (char_id != client->CharacterID() && client->Admin() < 150)) {
if (IsPlayerCorpse() && !CanPlayerLoot(client->CharacterID()) && !become_npc &&
(char_id != client->CharacterID() && client->Admin() < 150)) {
client->Message(13, "Error: This is a player corpse and you dont own it.");
client->QueuePacket(app);
SendEndLootErrorPacket(client);
return;
}
if (is_locked && client->Admin() < 100) {
client->QueuePacket(app);
SendLootReqErrorPacket(client, LootResponse::SomeoneElse);
client->Message(13, "Error: Corpse locked by GM.");
return;
}
if (IsPlayerCorpse() && (char_id != client->CharacterID()) && CanPlayerLoot(client->CharacterID()) && GetPlayerKillItem() == 0){
if (IsPlayerCorpse() && (char_id != client->CharacterID()) && CanPlayerLoot(client->CharacterID()) &&
GetPlayerKillItem() == 0) {
client->Message(13, "Error: You cannot loot any more items from this corpse.");
client->QueuePacket(app);
SendEndLootErrorPacket(client);
being_looted_by = 0xFFFFFFFF;
ResetLooter();
return;
}
const EQEmu::ItemData* item = 0;
const EQEmu::ItemData *item = 0;
EQEmu::ItemInstance *inst = 0;
ServerLootItem_Struct* item_data = nullptr, *bag_item_data[10];
ServerLootItem_Struct *item_data = nullptr, *bag_item_data[10];
memset(bag_item_data, 0, sizeof(bag_item_data));
if (GetPlayerKillItem() > 1){
if (GetPlayerKillItem() > 1) {
item = database.GetItem(GetPlayerKillItem());
}
else if (GetPlayerKillItem() == -1 || GetPlayerKillItem() == 1){
item_data = GetItem(lootitem->slot_id - EQEmu::legacy::CORPSE_BEGIN); //dont allow them to loot entire bags of items as pvp reward
}
else{
} else if (GetPlayerKillItem() == -1 || GetPlayerKillItem() == 1) {
item_data =
GetItem(lootitem->slot_id -
EQEmu::legacy::CORPSE_BEGIN); // dont allow them to loot entire bags of items as pvp reward
} else {
item_data = GetItem(lootitem->slot_id - EQEmu::legacy::CORPSE_BEGIN, bag_item_data);
}
if (GetPlayerKillItem()<=1 && item_data != 0) {
if (GetPlayerKillItem() <= 1 && item_data != 0) {
item = database.GetItem(item_data->item_id);
}
if (item != 0) {
if (item_data){
inst = database.CreateItem(item, item_data ? item_data->charges : 0, item_data->aug_1, item_data->aug_2, item_data->aug_3, item_data->aug_4, item_data->aug_5, item_data->aug_6, item_data->attuned);
}
else {
if (item_data) {
inst = database.CreateItem(item, item_data ? item_data->charges : 0, item_data->aug_1,
item_data->aug_2, item_data->aug_3, item_data->aug_4,
item_data->aug_5, item_data->aug_6, item_data->attuned);
} else {
inst = database.CreateItem(item);
}
}
@@ -1141,8 +1149,9 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
if (client && inst) {
if (client->CheckLoreConflict(item)) {
client->Message_StringID(0, LOOT_LORE_ERROR);
client->QueuePacket(app);
SendEndLootErrorPacket(client);
being_looted_by = 0;
ResetLooter();
delete inst;
return;
}
@@ -1153,8 +1162,9 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
if (itm) {
if (client->CheckLoreConflict(itm->GetItem())) {
client->Message_StringID(0, LOOT_LORE_ERROR);
client->QueuePacket(app);
SendEndLootErrorPacket(client);
being_looted_by = 0;
ResetLooter();
delete inst;
return;
}
@@ -1165,21 +1175,32 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
char buf[88];
char q_corpse_name[64];
strcpy(q_corpse_name, corpse_name);
snprintf(buf, 87, "%d %d %s", inst->GetItem()->ID, inst->GetCharges(), EntityList::RemoveNumbers(q_corpse_name));
snprintf(buf, 87, "%d %d %s", inst->GetItem()->ID, inst->GetCharges(),
EntityList::RemoveNumbers(q_corpse_name));
buf[87] = '\0';
std::vector<EQEmu::Any> args;
args.push_back(inst);
args.push_back(this);
parse->EventPlayer(EVENT_LOOT, client, buf, 0, &args);
if (parse->EventPlayer(EVENT_LOOT, client, buf, 0, &args) != 0) {
lootitem->auto_loot = -1;
client->Message_StringID(CC_Red, LOOT_NOT_ALLOWED, inst->GetItem()->Name);
client->QueuePacket(app);
delete inst;
return;
}
// do we want this to have a fail option too?
parse->EventItem(EVENT_LOOT, client, inst, this, buf, 0);
// safe to ACK now
client->QueuePacket(app);
if (!IsPlayerCorpse() && RuleB(Character, EnableDiscoveredItems)) {
if (client && !client->GetGM() && !client->IsDiscovered(inst->GetItem()->ID))
client->DiscoverItem(inst->GetItem()->ID);
}
if (zone->adv_data) {
ServerZoneAdventureDataReply_Struct *ad = (ServerZoneAdventureDataReply_Struct*)zone->adv_data;
ServerZoneAdventureDataReply_Struct *ad = (ServerZoneAdventureDataReply_Struct *)zone->adv_data;
if (ad->type == Adventure_Collect && !IsPlayerCorpse()) {
if (ad->data_id == inst->GetItem()->ID) {
zone->DoAdventureCountIncrease();
@@ -1188,11 +1209,10 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
}
/* First add it to the looter - this will do the bag contents too */
if (lootitem->auto_loot) {
if (lootitem->auto_loot > 0) {
if (!client->AutoPutLootInInventory(*inst, true, true, bag_item_data))
client->PutLootInInventory(EQEmu::inventory::slotCursor, *inst, bag_item_data);
}
else {
} else {
client->PutLootInInventory(EQEmu::inventory::slotCursor, *inst, bag_item_data);
}
@@ -1201,9 +1221,11 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
client->UpdateTasksForItem(ActivityLoot, item->ID);
/* Remove it from Corpse */
if (item_data){
/* Delete needs to be before RemoveItem because its deletes the pointer for item_data/bag_item_data */
database.DeleteItemOffCharacterCorpse(this->corpse_db_id, item_data->equip_slot, item_data->item_id);
if (item_data) {
/* Delete needs to be before RemoveItem because its deletes the pointer for
* item_data/bag_item_data */
database.DeleteItemOffCharacterCorpse(this->corpse_db_id, item_data->equip_slot,
item_data->item_id);
/* Delete Item Instance */
RemoveItem(item_data->lootslot);
}
@@ -1212,8 +1234,11 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
if (item->IsClassBag() && (GetPlayerKillItem() != -1 || GetPlayerKillItem() != 1)) {
for (int i = EQEmu::inventory::containerBegin; i < EQEmu::inventory::ContainerCount; i++) {
if (bag_item_data[i]) {
/* Delete needs to be before RemoveItem because its deletes the pointer for item_data/bag_item_data */
database.DeleteItemOffCharacterCorpse(this->corpse_db_id, bag_item_data[i]->equip_slot, bag_item_data[i]->item_id);
/* Delete needs to be before RemoveItem because its deletes the pointer for
* item_data/bag_item_data */
database.DeleteItemOffCharacterCorpse(this->corpse_db_id,
bag_item_data[i]->equip_slot,
bag_item_data[i]->item_id);
/* Delete Item Instance */
RemoveItem(bag_item_data[i]);
}
@@ -1224,38 +1249,37 @@ void Corpse::LootItem(Client* client, const EQApplicationPacket* app) {
SetPlayerKillItemID(0);
}
/* Send message with item link to groups and such */
EQEmu::SayLinkEngine linker;
linker.SetLinkType(EQEmu::saylink::SayLinkItemInst);
linker.SetItemInst(inst);
/* Send message with item link to groups and such */
EQEmu::SayLinkEngine linker;
linker.SetLinkType(EQEmu::saylink::SayLinkItemInst);
linker.SetItemInst(inst);
auto item_link = linker.GenerateLink();
auto item_link = linker.GenerateLink();
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str());
client->Message_StringID(MT_LootMessages, LOOTED_MESSAGE, item_link.c_str());
if (!IsPlayerCorpse()) {
if (!IsPlayerCorpse()) {
Group *g = client->GetGroup();
if(g != nullptr) {
g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str());
}
else {
if (g != nullptr) {
g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE,
client->GetName(), item_link.c_str());
} else {
Raid *r = client->GetRaid();
if(r != nullptr) {
r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE, client->GetName(), item_link.c_str());
if (r != nullptr) {
r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE,
client->GetName(), item_link.c_str());
}
}
}
}
else {
} else {
SendEndLootErrorPacket(client);
safe_delete(inst);
return;
}
if (IsPlayerCorpse()){
if (IsPlayerCorpse()) {
client->SendItemLink(inst);
}
else{
} else {
client->SendItemLink(inst, true);
}
+2 -1
View File
@@ -20,8 +20,8 @@
#define CORPSE_H
#include "mob.h"
#include "client.h"
class Client;
class EQApplicationPacket;
class Group;
class NPC;
@@ -118,6 +118,7 @@ class Corpse : public Mob {
inline bool IsLocked() { return is_locked; }
inline void ResetLooter() { being_looted_by = 0xFFFFFFFF; }
inline bool IsBeingLooted() { return (being_looted_by != 0xFFFFFFFF); }
inline bool IsBeingLootedBy(Client *c) { return being_looted_by == c->GetID(); }
/* Mob */
void FillSpawnStruct(NewSpawn_Struct* ns, Mob* ForWho);
+7 -1
View File
@@ -306,7 +306,13 @@ void Client::GoFish()
const EQEmu::ItemData* food_item = database.GetItem(food_id);
Message_StringID(MT_Skills, FISHING_SUCCESS);
if (food_item->ItemType != EQEmu::item::ItemTypeFood) {
Message_StringID(MT_Skills, FISHING_SUCCESS);
}
else {
Message_StringID(MT_Skills, FISHING_SUCCESS_FISH_NAME, food_item->Name);
}
EQEmu::ItemInstance* inst = database.CreateItem(food_item, 1);
if(inst != nullptr) {
if(CheckLoreConflict(inst->GetItem()))
+59 -3
View File
@@ -594,10 +594,37 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2,
}
// Drop item from inventory to ground (generally only dropped from SLOT_CURSOR)
void Client::DropItem(int16 slot_id)
void Client::DropItem(int16 slot_id, bool recurse)
{
if(GetInv().CheckNoDrop(slot_id) && RuleI(World, FVNoDropFlag) == 0 ||
RuleI(Character, MinStatusForNoDropExemptions) < Admin() && RuleI(World, FVNoDropFlag) == 2) {
Log.Out(Logs::General, Logs::Inventory, "'%s' (char_id: %u) Attempting to drop item from slot %i on the ground",
GetCleanName(), CharacterID(), slot_id);
if(GetInv().CheckNoDrop(slot_id, recurse) && RuleI(World, FVNoDropFlag) == 0 ||
RuleI(Character, MinStatusForNoDropExemptions) < Admin() && RuleI(World, FVNoDropFlag) == 2)
{
auto invalid_drop = m_inv.GetItem(slot_id);
if (!invalid_drop) {
Log.Out(Logs::General, Logs::Inventory, "Error in InventoryProfile::CheckNoDrop() - returned 'true' for empty slot");
}
else {
if (Log.log_settings[Logs::Inventory].is_category_enabled) {
Log.Out(Logs::General, Logs::Inventory, "DropItem() Hack detected - full item parse:");
Log.Out(Logs::General, Logs::Inventory, "depth: 0, Item: '%s' (id: %u), IsDroppable: %s",
(invalid_drop->GetItem() ? invalid_drop->GetItem()->Name : "null data"), invalid_drop->GetID(), invalid_drop->IsDroppable(false));
for (auto iter1 : *invalid_drop->GetContents()) { // depth 1
Log.Out(Logs::General, Logs::Inventory, "-depth: 1, Item: '%s' (id: %u), IsDroppable: %s",
(iter1.second->GetItem() ? iter1.second->GetItem()->Name : "null data"), iter1.second->GetID(), iter1.second->IsDroppable(false));
for (auto iter2 : *iter1.second->GetContents()) { // depth 2
Log.Out(Logs::General, Logs::Inventory, "--depth: 2, Item: '%s' (id: %u), IsDroppable: %s",
(iter2.second->GetItem() ? iter2.second->GetItem()->Name : "null data"), iter2.second->GetID(), iter2.second->IsDroppable(false));
}
}
}
}
invalid_drop = nullptr;
database.SetHackerFlag(this->AccountName(), this->GetCleanName(), "Tried to drop an item on the ground that was nodrop!");
GetInv().DeleteItem(slot_id);
return;
@@ -606,12 +633,39 @@ void Client::DropItem(int16 slot_id)
// Take control of item in client inventory
EQEmu::ItemInstance *inst = m_inv.PopItem(slot_id);
if(inst) {
if (Log.log_settings[Logs::Inventory].is_category_enabled) {
Log.Out(Logs::General, Logs::Inventory, "DropItem() Processing - full item parse:");
Log.Out(Logs::General, Logs::Inventory, "depth: 0, Item: '%s' (id: %u), IsDroppable: %s",
(inst->GetItem() ? inst->GetItem()->Name : "null data"), inst->GetID(), inst->IsDroppable(false));
if (!inst->IsDroppable(false))
Log.Out(Logs::General, Logs::Error, "Non-droppable item being processed for drop by '%s'", GetCleanName());
for (auto iter1 : *inst->GetContents()) { // depth 1
Log.Out(Logs::General, Logs::Inventory, "-depth: 1, Item: '%s' (id: %u), IsDroppable: %s",
(iter1.second->GetItem() ? iter1.second->GetItem()->Name : "null data"), iter1.second->GetID(), iter1.second->IsDroppable(false));
if (!iter1.second->IsDroppable(false))
Log.Out(Logs::General, Logs::Error, "Non-droppable item being processed for drop by '%s'", GetCleanName());
for (auto iter2 : *iter1.second->GetContents()) { // depth 2
Log.Out(Logs::General, Logs::Inventory, "--depth: 2, Item: '%s' (id: %u), IsDroppable: %s",
(iter2.second->GetItem() ? iter2.second->GetItem()->Name : "null data"), iter2.second->GetID(), iter2.second->IsDroppable(false));
if (!iter2.second->IsDroppable(false))
Log.Out(Logs::General, Logs::Error, "Non-droppable item being processed for drop by '%s'", GetCleanName());
}
}
}
int i = parse->EventItem(EVENT_DROP_ITEM, this, inst, nullptr, "", slot_id);
if(i != 0) {
Log.Out(Logs::General, Logs::Inventory, "Item drop handled by [EVENT_DROP_ITEM]");
safe_delete(inst);
}
} else {
// Item doesn't exist in inventory!
Log.Out(Logs::General, Logs::Inventory, "DropItem() - No item found in slot %i", slot_id);
Message(13, "Error: Item not found in slot %i", slot_id);
return;
}
@@ -633,6 +687,8 @@ void Client::DropItem(int16 slot_id)
entity_list.AddObject(object, true);
object->StartDecay();
Log.Out(Logs::General, Logs::Inventory, "Item drop handled ut assolet");
safe_delete(inst);
}
-3
View File
@@ -4668,9 +4668,6 @@ int16 Mob::GetMeleeDamageMod_SE(uint16 skill)
dmg_mod += itembonuses.DamageModifier2[EQEmu::skills::HIGHEST_SKILL + 1] + spellbonuses.DamageModifier2[EQEmu::skills::HIGHEST_SKILL + 1] + aabonuses.DamageModifier2[EQEmu::skills::HIGHEST_SKILL + 1] +
itembonuses.DamageModifier2[skill] + spellbonuses.DamageModifier2[skill] + aabonuses.DamageModifier2[skill];
if (HasShieldEquiped() && !IsOffHandAtk())
dmg_mod += itembonuses.ShieldEquipDmgMod[0] + spellbonuses.ShieldEquipDmgMod[0] + aabonuses.ShieldEquipDmgMod[0];
if(dmg_mod < -100)
dmg_mod = -100;
+2 -2
View File
@@ -2038,7 +2038,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
#endif
if(IsNPC()) {
if(GetLevel() <= 52)
CastToNPC()->Depop();
CastToNPC()->Depop(true);
else
Message(13, "Your target is too high level to be affected by this spell.");
}
@@ -2982,8 +2982,8 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
case SE_FcHealAmtIncoming:
case SE_LimitManaMax:
case SE_DoubleRangedAttack:
case SE_ShieldEquipHateMod:
case SE_ShieldEquipDmgMod:
case SE_GroupShielding:
case SE_TriggerOnReqTarget:
case SE_LimitRace:
case SE_FcLimitUse:
+22 -17
View File
@@ -230,23 +230,6 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
}
}
// check for fizzle
// note that CheckFizzle itself doesn't let NPCs fizzle,
// but this code allows for it.
if(slot < CastingSlot::MaxGems && !CheckFizzle(spell_id))
{
int fizzle_msg = IsBardSong(spell_id) ? MISS_NOTE : SPELL_FIZZLE;
InterruptSpell(fizzle_msg, 0x121, spell_id);
uint32 use_mana = ((spells[spell_id].mana) / 4);
Log.Out(Logs::Detail, Logs::Spells, "Spell casting canceled: fizzled. %d mana has been consumed", use_mana);
// fizzle 1/4 the mana away
SetMana(GetMana() - use_mana);
TryTriggerOnValueAmount(false, true);
return(false);
}
if (HasActiveSong() && IsBardSong(spell_id)) {
Log.Out(Logs::Detail, Logs::Spells, "Casting a new song while singing a song. Killing old song %d.", bardsong);
//Note: this does NOT tell the client
@@ -366,6 +349,28 @@ bool Mob::DoCastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
}
casting_spell_aa_id = aa_id;
// check for fizzle
// note that CheckFizzle itself doesn't let NPCs fizzle,
// but this code allows for it.
if (slot < CastingSlot::MaxGems && !CheckFizzle(spell_id)) {
int fizzle_msg = IsBardSong(spell_id) ? MISS_NOTE : SPELL_FIZZLE;
uint32 use_mana = ((spells[spell_id].mana) / 4);
Log.Out(Logs::Detail, Logs::Spells, "Spell casting canceled: fizzled. %d mana has been consumed", use_mana);
// fizzle 1/4 the mana away
Mob::SetMana(GetMana() - use_mana); // We send StopCasting which will update mana
StopCasting();
Message_StringID(MT_SpellFailure, fizzle_msg);
entity_list.FilteredMessageClose_StringID(
this, true, 200, MT_SpellFailure, IsClient() ? FilterPCSpells : FilterNPCSpells,
fizzle_msg == MISS_NOTE ? MISSED_NOTE_OTHER : SPELL_FIZZLE_OTHER, GetName());
TryTriggerOnValueAmount(false, true);
return(false);
}
SaveSpellLoc();
Log.Out(Logs::Detail, Logs::Spells, "Casting %d Started at (%.3f,%.3f,%.3f)", spell_id, m_SpellLocation.x, m_SpellLocation.y, m_SpellLocation.z);
+3
View File
@@ -46,6 +46,7 @@
#define FISHING_FAILED 168 //You didn't catch anything.
#define FISHING_POLE_BROKE 169 //Your fishing pole broke!
#define FISHING_SUCCESS 170 //You caught, something...
#define FISHING_SUCCESS_FISH_NAME 421 //You caught %1!
#define FISHING_SPILL_BEER 171 //You spill your beer while bringing in your line.
#define FISHING_LOST_BAIT 172 //You lost your bait!
#define SPELL_FIZZLE 173 //Your spell fizzles!
@@ -255,6 +256,7 @@
#define MEMBER_OF_YOUR_GUILD 1429
#define OFFICER_OF_YOUR_GUILD 1430
#define LEADER_OF_YOUR_GUILD 1431
#define TRADE_HAS_BEEN_CANCELLED 1449
#define RECEIVED_PLATINUM 1452 //You receive %1 Platinum from %2.
#define RECEIVED_GOLD 1453 //You receive %1 Gold from %2.
#define RECEIVED_SILVER 1454 //You receive %1 Silver from %2.
@@ -277,6 +279,7 @@
#define TRADESKILL_MISSING_COMPONENTS 3456 //Sorry, but you don't have everything you need for this recipe in your general inventory.
#define TRADESKILL_LEARN_RECIPE 3457 //You have learned the recipe %1!
#define EXPEDITION_MIN_REMAIN 3551 //You only have %1 minutes remaining before this expedition comes to an end.
#define LOOT_NOT_ALLOWED 3562 //You are not allowed to loot the item: %1.
#define NO_CAST_ON_PET 4045 //You cannot cast this spell on your pet.
#define REWIND_WAIT 4059 //You must wait a bit longer before using the rewind command again.
#define CORPSEDRAG_LIMIT 4061 //You are already dragging as much as you can!
+27 -13
View File
@@ -967,23 +967,37 @@ bool Client::CheckTradeLoreConflict(Client* other)
{
if (!other)
return true;
// Move each trade slot into free inventory slot
for (int16 i = EQEmu::legacy::TRADE_BEGIN; i <= EQEmu::legacy::TRADE_END; i++){
const EQEmu::ItemInstance* inst = m_inv[i];
if (inst && inst->GetItem()) {
if (other->CheckLoreConflict(inst->GetItem()))
return true;
}
for (int16 index = EQEmu::legacy::TRADE_BEGIN; index <= EQEmu::legacy::TRADE_END; ++index) {
const EQEmu::ItemInstance* inst = m_inv[index];
if (!inst || !inst->GetItem())
continue;
if (other->CheckLoreConflict(inst->GetItem()))
return true;
}
for (int16 i = EQEmu::legacy::TRADE_BAGS_BEGIN; i <= EQEmu::legacy::TRADE_BAGS_END; i++){
const EQEmu::ItemInstance* inst = m_inv[i];
for (int16 index = EQEmu::legacy::TRADE_BAGS_BEGIN; index <= EQEmu::legacy::TRADE_BAGS_END; ++index) {
const EQEmu::ItemInstance* inst = m_inv[index];
if (!inst || !inst->GetItem())
continue;
if (inst && inst->GetItem()) {
if (other->CheckLoreConflict(inst->GetItem()))
return true;
}
if (other->CheckLoreConflict(inst->GetItem()))
return true;
}
return false;
}
bool Client::CheckTradeNonDroppable()
{
for (int16 index = EQEmu::legacy::TRADE_BEGIN; index <= EQEmu::legacy::TRADE_END; ++index){
const EQEmu::ItemInstance* inst = m_inv[index];
if (!inst)
continue;
if (!inst->IsDroppable())
return true;
}
return false;