mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 16:51:29 +00:00
Merge master to movement_manager, fix for merge failure
This commit is contained in:
commit
cd6fd2d2dc
100
changelog.txt
100
changelog.txt
@ -1,5 +1,105 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 10/09/2018 ==
|
||||
Uleat: Added bot owner options
|
||||
- usage: ^owneroption [option] (or aliased as: ^oo [option])
|
||||
- options are saved in the database and therefore, persistent
|
||||
- Implemented option 'deathmarquee'
|
||||
-- toggles client owner flag to show marquee message when a bot dies (default: disabled)
|
||||
|
||||
== 10/07/2018 ==
|
||||
Uleat: Fixed a few bot issues..
|
||||
- Fix for bot item trades not attuning
|
||||
- Fix for bot mana, endurance not updating properly
|
||||
|
||||
== 10/06/2018 ==
|
||||
Uleat: Fixed a few bot issues..
|
||||
- Fix for bot 'stop melee level' not honoring setting level over rule level
|
||||
- Fix for missing bot combat spell casting when within melee range
|
||||
- Fix (in-work) for bots 'forgetting' current target when it flees
|
||||
|
||||
== 09/18/2018 ==
|
||||
Uleat: Notes for manual conversion of quest script inventory slot values
|
||||
- You should use reference/lookup values provided by the lua and perl apis to avoid skirting safety checks
|
||||
and to ensure that the values used are the correct ones for your needs
|
||||
|
||||
[perl api examples]
|
||||
old:
|
||||
1) my $charmitem = $client->GetItemIDAt(0);
|
||||
2) for($for_x = 22; $for_x < 30; $for_x++) {...}
|
||||
3) for($slot1 = 0; $slot1 <= 30; $slot1++) {...}
|
||||
|
||||
new:
|
||||
1) my $charmitem = $client->GetItemIDAt(quest::getinventoryslotid("charm"));
|
||||
2) for($for_x = quest::getinventoryslotid("general.begin"); $for_x <= quest::getinventoryslotid("general.end"); $for_x++) {...} ** notice change of conditional
|
||||
3) for($slot1 = quest::getinventoryslotid("possessions.begin"); $slot1 <= quest::getinventoryslotid("possessions.end"); $slot1++) {...}
|
||||
|
||||
[lua api examples]
|
||||
old:
|
||||
1) if(e.self:GetItemIDAt(30) == 31599) then ...
|
||||
2) for i = 0, 30, 1 do ...
|
||||
|
||||
new:
|
||||
1) if(e.self:GetItemIDAt(Slot.Cursor) == 31599) then ...
|
||||
2) for i = Slot.PossessionsBegin, Slot.PossessionsEnd, 1 do ...
|
||||
|
||||
- If you need to manually assign bag slot ranges to individual 'general' slots, use this assignment for now:
|
||||
-- General1 (23) = 251 .. 260
|
||||
-- General2 (24) = 261 .. 270
|
||||
-- General3 (25) = 271 .. 280
|
||||
-- General4 (26) = 281 .. 290
|
||||
-- General5 (27) = 291 .. 300
|
||||
-- General6 (28) = 301 .. 310
|
||||
-- General7 (29) = 311 .. 320
|
||||
-- General8 (30) = 321 .. 330
|
||||
-- General9 (31) = 331 .. 340
|
||||
-- General10 (32) = 341 .. 350
|
||||
-- Cursor (33) = 351 .. 360
|
||||
|
||||
- If you need to manually assign ammo or powersource slots, use these values:
|
||||
-- PowerSource = 21
|
||||
-- Ammo = 22
|
||||
|
||||
- All slot values not addressed above remain the same
|
||||
|
||||
- Additional information can be found at:
|
||||
-- https://github.com/EQEmu/Server/wiki/Inventory-Slots
|
||||
-- https://github.com/EQEmu/Server/wiki/Perl-API
|
||||
-- https://github.com/EQEmu/Server/wiki/Lua-API
|
||||
|
||||
== 09/03/2018 ==
|
||||
Uleat: Rework of 'invsnapshot' command and implementation of automatic inventory snapshots.
|
||||
- Inventory snapshots are now taken automatically using the interval rule values - if snapshots are enabled
|
||||
- Command 'invsnapshot' now has more options available to include a restore feature
|
||||
-- A pop-up help menu is available
|
||||
-- argument 'capture' is available to anyone with status high enough to register the command
|
||||
-- Advanced options are only available to players with 150 status or greater
|
||||
-- argument 'list' provides a list of "timestamp : item count" entries
|
||||
-- argument 'parse' displays a "slot : item id : item name" listing of valid snapshots by timestamp
|
||||
-- argument 'compare' shows a 'difference' comparison of "snapshot-to-inventory" changes
|
||||
-- argument 'restore' applies a saved snapshot to the player's inventory (with a pre-clearing call)
|
||||
|
||||
== 08/13/2018 ==
|
||||
Uleat: Activation of RoF+ clients' two additional general slots and integration of SoF+ clients' PowerSource slot
|
||||
- Inventory 'Possessions' main slots are now contiguous and implemented to RoF2 standards
|
||||
-- 'slotGeneral9'(31) and 'slotGeneral10'(32) are now active
|
||||
-- Possessions slot enumerations are now defined as between 'slotCharm'(0) and 'slotCursor'(33)
|
||||
-- 'slotPowerSource'(21) is no longer a special case slot(9999)
|
||||
- Special code has been added to exclude 'slotPowerSource,' 'slotGeneral9' and 'slotGeneral10' from server
|
||||
actions in clients that do not support them.
|
||||
- The lua api has been updated to use the new slot enumeration as well as having some slot range definitions added
|
||||
- The perl api now has a look-up function to provide token-to-value translations .. definitions are similar to lua
|
||||
- In both lua and perl, it is HIGHLY recommended that any custom scripts using hard-coded inventory slot values be
|
||||
updated to use the constants/lookup methods as any old values are no longer guaranteed to be accurate
|
||||
- Database will have existing inventory slot values modified to the new standard and table `items` entries will
|
||||
also be updated to the 'correct' equipable slot bitmask
|
||||
- Script (quest) updates are required with this change
|
||||
|
||||
Note: The proper way to reference inventory slots is to use either instrinsic lookups (c/c++ & perl) or to use valid
|
||||
const ref declarations (c/c++ & lua). Any other method is not guaranteed to be accurate and may result in item loss
|
||||
and/or unexpected/undefined behavior.
|
||||
|
||||
|
||||
== 07/10/2018 ==
|
||||
Akkadius: Adjusted DataBuckets to use other acceptable time formats
|
||||
Example: quest::set_data('key', 'value', '1d');
|
||||
|
||||
@ -2111,10 +2111,27 @@ void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings)
|
||||
}
|
||||
}
|
||||
|
||||
void Database::ClearInvSnapshots(bool use_rule)
|
||||
{
|
||||
int Database::CountInvSnapshots() {
|
||||
std::string query = StringFormat("SELECT COUNT(*) FROM (SELECT * FROM `inventory_snapshots` a GROUP BY `charid`, `time_index`) b");
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return -1;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
int64 count = atoll(row[0]);
|
||||
if (count > 2147483647)
|
||||
return -2;
|
||||
if (count < 0)
|
||||
return -3;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void Database::ClearInvSnapshots(bool from_now) {
|
||||
uint32 del_time = time(nullptr);
|
||||
if (use_rule) { del_time -= RuleI(Character, InvSnapshotHistoryD) * 86400; }
|
||||
if (!from_now) { del_time -= RuleI(Character, InvSnapshotHistoryD) * 86400; }
|
||||
|
||||
std::string query = StringFormat("DELETE FROM inventory_snapshots WHERE time_index <= %lu", (unsigned long)del_time);
|
||||
QueryDatabase(query);
|
||||
|
||||
@ -264,7 +264,8 @@ public:
|
||||
void SetLFP(uint32 CharID, bool LFP);
|
||||
void SetLoginFlags(uint32 CharID, bool LFP, bool LFG, uint8 firstlogon);
|
||||
|
||||
void ClearInvSnapshots(bool use_rule = true);
|
||||
int CountInvSnapshots();
|
||||
void ClearInvSnapshots(bool from_now = false);
|
||||
|
||||
/* EQEmuLogSys */
|
||||
void LoadLogSettings(EQEmuLogSys::LogSettings* log_settings);
|
||||
|
||||
@ -78,28 +78,30 @@ namespace EQEmu
|
||||
} // namespace invtype
|
||||
|
||||
namespace invslot {
|
||||
using namespace Titanium::invslot::enum_;
|
||||
|
||||
const int16 SLOT_POWER_SOURCE = 9999;
|
||||
using namespace RoF2::invslot::enum_;
|
||||
|
||||
using RoF2::invslot::SLOT_INVALID;
|
||||
using RoF2::invslot::SLOT_BEGIN;
|
||||
|
||||
using Titanium::invslot::POSSESSIONS_BEGIN;
|
||||
using Titanium::invslot::POSSESSIONS_END;
|
||||
using SoF::invslot::POSSESSIONS_COUNT;
|
||||
using Titanium::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE;
|
||||
|
||||
using Titanium::invslot::EQUIPMENT_BEGIN;
|
||||
using Titanium::invslot::EQUIPMENT_END;
|
||||
using Titanium::invslot::EQUIPMENT_COUNT;
|
||||
const int16 SLOT_AUGMENT_GENERIC_RETURN = 1001; // clients don't appear to use this method... (internal inventory return value)
|
||||
|
||||
using Titanium::invslot::GENERAL_BEGIN;
|
||||
using Titanium::invslot::GENERAL_END;
|
||||
using Titanium::invslot::GENERAL_COUNT;
|
||||
using RoF2::invslot::POSSESSIONS_BEGIN;
|
||||
using RoF2::invslot::POSSESSIONS_END;
|
||||
using RoF2::invslot::POSSESSIONS_COUNT;
|
||||
|
||||
using Titanium::invslot::BONUS_BEGIN;
|
||||
using Titanium::invslot::BONUS_STAT_END;
|
||||
using Titanium::invslot::BONUS_SKILL_END;
|
||||
using RoF2::invslot::EQUIPMENT_BEGIN;
|
||||
using RoF2::invslot::EQUIPMENT_END;
|
||||
using RoF2::invslot::EQUIPMENT_COUNT;
|
||||
|
||||
using RoF2::invslot::GENERAL_BEGIN;
|
||||
using RoF2::invslot::GENERAL_END;
|
||||
using RoF2::invslot::GENERAL_COUNT;
|
||||
|
||||
using RoF2::invslot::BONUS_BEGIN;
|
||||
using RoF2::invslot::BONUS_STAT_END;
|
||||
using RoF2::invslot::BONUS_SKILL_END;
|
||||
|
||||
using Titanium::invslot::BANK_BEGIN;
|
||||
using SoF::invslot::BANK_END;
|
||||
@ -145,7 +147,7 @@ namespace EQEmu
|
||||
const int16 GENERAL_BAGS_8_COUNT = 8 * SLOT_COUNT;
|
||||
const int16 GENERAL_BAGS_8_END = (GENERAL_BAGS_BEGIN + GENERAL_BAGS_8_COUNT) - 1;
|
||||
|
||||
const int16 CURSOR_BAG_BEGIN = 331;
|
||||
const int16 CURSOR_BAG_BEGIN = 351;
|
||||
const int16 CURSOR_BAG_COUNT = SLOT_COUNT;
|
||||
const int16 CURSOR_BAG_END = (CURSOR_BAG_BEGIN + CURSOR_BAG_COUNT) - 1;
|
||||
|
||||
|
||||
@ -523,18 +523,4 @@ static const uint8 SkillDamageTypes[EQEmu::skills::HIGHEST_SKILL + 1] = // chang
|
||||
|
||||
static const uint32 MAX_SPELL_DB_ID_VAL = 65535;
|
||||
|
||||
namespace EQEmu
|
||||
{
|
||||
namespace legacy {
|
||||
enum InventorySlot {
|
||||
SLOT_CURSOR_END = (int16)0xFFFE, // I hope no one is using this...
|
||||
SLOT_TRADESKILL = 1000,
|
||||
SLOT_AUGMENT = 1001,
|
||||
//SLOT_INVALID = (int16)0xFFFF,
|
||||
};
|
||||
|
||||
} // namespace legacy
|
||||
|
||||
}
|
||||
|
||||
#endif /*COMMON_EQ_CONSTANTS_H*/
|
||||
|
||||
@ -268,7 +268,8 @@ enum {
|
||||
commandBanPlayers = 100, //can set bans on players
|
||||
commandChangeDatarate = 201, //edit client's data rate
|
||||
commandZoneToCoords = 0, //can #zone with coords
|
||||
commandInterrogateInv = 100 //below this == only log on error state and self-only target dump
|
||||
commandInterrogateInv = 100, //below this == only log on error state and self-only target dump
|
||||
commandInvSnapshot = 150 //ability to clear/restore snapshots
|
||||
};
|
||||
|
||||
//default states for logging flag on NPCs and clients (having NPCs on by default is prolly a bad idea)
|
||||
|
||||
@ -177,7 +177,7 @@ EQEmu::ItemInstance* EQEmu::InventoryProfile::GetItem(int16 slot_id) const
|
||||
result = _GetItem(m_inv, slot_id);
|
||||
}
|
||||
else if ((slot_id >= invslot::EQUIPMENT_BEGIN && slot_id <= invslot::EQUIPMENT_END) ||
|
||||
(slot_id >= invslot::TRIBUTE_BEGIN && slot_id <= invslot::TRIBUTE_END) || (slot_id == invslot::SLOT_POWER_SOURCE)) {
|
||||
(slot_id >= invslot::TRIBUTE_BEGIN && slot_id <= invslot::TRIBUTE_END)) {
|
||||
// Equippable slots (on body)
|
||||
result = _GetItem(m_worn, slot_id);
|
||||
}
|
||||
@ -231,6 +231,25 @@ EQEmu::ItemInstance* EQEmu::InventoryProfile::GetItem(int16 slot_id, uint8 bagid
|
||||
// Put an item snto specified slot
|
||||
int16 EQEmu::InventoryProfile::PutItem(int16 slot_id, const ItemInstance& inst)
|
||||
{
|
||||
if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) {
|
||||
if ((((uint64)1 << slot_id) & m_lookup->PossessionsBitmask) == 0)
|
||||
return EQEmu::invslot::SLOT_INVALID;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invbag::GENERAL_BAGS_END && slot_id >= EQEmu::invbag::GENERAL_BAGS_BEGIN) {
|
||||
auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot_id - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT);
|
||||
if ((((uint64)1 << temp_slot) & m_lookup->PossessionsBitmask) == 0)
|
||||
return EQEmu::invslot::SLOT_INVALID;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) {
|
||||
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= m_lookup->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
return EQEmu::invslot::SLOT_INVALID;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) {
|
||||
auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
|
||||
if (temp_slot >= m_lookup->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
return EQEmu::invslot::SLOT_INVALID;
|
||||
}
|
||||
|
||||
// Clean up item already in slot (if exists)
|
||||
DeleteItem(slot_id);
|
||||
|
||||
@ -244,80 +263,139 @@ int16 EQEmu::InventoryProfile::PutItem(int16 slot_id, const ItemInstance& inst)
|
||||
return _PutItem(slot_id, inst.Clone());
|
||||
}
|
||||
|
||||
int16 EQEmu::InventoryProfile::PushCursor(const ItemInstance& inst)
|
||||
{
|
||||
int16 EQEmu::InventoryProfile::PushCursor(const ItemInstance &inst) {
|
||||
m_cursor.push(inst.Clone());
|
||||
return invslot::slotCursor;
|
||||
}
|
||||
|
||||
EQEmu::ItemInstance* EQEmu::InventoryProfile::GetCursorItem()
|
||||
{
|
||||
EQEmu::ItemInstance* EQEmu::InventoryProfile::GetCursorItem() {
|
||||
return m_cursor.peek_front();
|
||||
}
|
||||
|
||||
// Swap items in inventory
|
||||
bool EQEmu::InventoryProfile::SwapItem(int16 slot_a, int16 slot_b, SwapItemFailState& fail_state, uint16 race_id, uint8 class_id, uint16 deity_id, uint8 level)
|
||||
{
|
||||
bool EQEmu::InventoryProfile::SwapItem(
|
||||
int16 source_slot,
|
||||
int16 destination_slot,
|
||||
SwapItemFailState &fail_state,
|
||||
uint16 race_id,
|
||||
uint8 class_id,
|
||||
uint16 deity_id,
|
||||
uint8 level
|
||||
) {
|
||||
fail_state = swapInvalid;
|
||||
|
||||
// Temp holding areas for a and b
|
||||
ItemInstance* inst_a = GetItem(slot_a);
|
||||
ItemInstance* inst_b = GetItem(slot_b);
|
||||
|
||||
if (inst_a) {
|
||||
if (!inst_a->IsSlotAllowed(slot_b)) {
|
||||
if (source_slot <= EQEmu::invslot::POSSESSIONS_END && source_slot >= EQEmu::invslot::POSSESSIONS_BEGIN) {
|
||||
if ((((uint64) 1 << source_slot) & m_lookup->PossessionsBitmask) == 0) {
|
||||
fail_state = swapNotAllowed;
|
||||
return false;
|
||||
}
|
||||
if ((slot_b >= invslot::EQUIPMENT_BEGIN && slot_b <= invslot::EQUIPMENT_END) || slot_b == invslot::SLOT_POWER_SOURCE) {
|
||||
auto item_a = inst_a->GetItem();
|
||||
if (!item_a) {
|
||||
}
|
||||
else if (source_slot <= EQEmu::invbag::GENERAL_BAGS_END && source_slot >= EQEmu::invbag::GENERAL_BAGS_BEGIN) {
|
||||
auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((source_slot - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT);
|
||||
if ((((uint64)1 << temp_slot) & m_lookup->PossessionsBitmask) == 0) {
|
||||
fail_state = swapNotAllowed;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (source_slot <= EQEmu::invslot::BANK_END && source_slot >= EQEmu::invslot::BANK_BEGIN) {
|
||||
if ((source_slot - EQEmu::invslot::BANK_BEGIN) >= m_lookup->InventoryTypeSize[EQEmu::invtype::typeBank]) {
|
||||
fail_state = swapNotAllowed;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (source_slot <= EQEmu::invbag::BANK_BAGS_END && source_slot >= EQEmu::invbag::BANK_BAGS_BEGIN) {
|
||||
auto temp_slot = (source_slot - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
|
||||
if (temp_slot >= m_lookup->InventoryTypeSize[EQEmu::invtype::typeBank]) {
|
||||
fail_state = swapNotAllowed;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (destination_slot <= EQEmu::invslot::POSSESSIONS_END && destination_slot >= EQEmu::invslot::POSSESSIONS_BEGIN) {
|
||||
if ((((uint64)1 << destination_slot) & m_lookup->PossessionsBitmask) == 0) {
|
||||
fail_state = swapNotAllowed;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (destination_slot <= EQEmu::invbag::GENERAL_BAGS_END && destination_slot >= EQEmu::invbag::GENERAL_BAGS_BEGIN) {
|
||||
auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((destination_slot - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT);
|
||||
if ((((uint64)1 << temp_slot) & m_lookup->PossessionsBitmask) == 0) {
|
||||
fail_state = swapNotAllowed;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (destination_slot <= EQEmu::invslot::BANK_END && destination_slot >= EQEmu::invslot::BANK_BEGIN) {
|
||||
if ((destination_slot - EQEmu::invslot::BANK_BEGIN) >= m_lookup->InventoryTypeSize[EQEmu::invtype::typeBank]) {
|
||||
fail_state = swapNotAllowed;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (destination_slot <= EQEmu::invbag::BANK_BAGS_END && destination_slot >= EQEmu::invbag::BANK_BAGS_BEGIN) {
|
||||
auto temp_slot = (destination_slot - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
|
||||
if (temp_slot >= m_lookup->InventoryTypeSize[EQEmu::invtype::typeBank]) {
|
||||
fail_state = swapNotAllowed;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Temp holding areas for source and destination
|
||||
ItemInstance *source_item_instance = GetItem(source_slot);
|
||||
ItemInstance *destination_item_instance = GetItem(destination_slot);
|
||||
|
||||
if (source_item_instance) {
|
||||
if (!source_item_instance->IsSlotAllowed(destination_slot)) {
|
||||
fail_state = swapNotAllowed;
|
||||
return false;
|
||||
}
|
||||
if ((destination_slot >= invslot::EQUIPMENT_BEGIN && destination_slot <= invslot::EQUIPMENT_END)) {
|
||||
auto source_item = source_item_instance->GetItem();
|
||||
if (!source_item) {
|
||||
fail_state = swapNullData;
|
||||
return false;
|
||||
}
|
||||
if (race_id && class_id && !item_a->IsEquipable(race_id, class_id)) {
|
||||
if (race_id && class_id && !source_item->IsEquipable(race_id, class_id)) {
|
||||
fail_state = swapRaceClass;
|
||||
return false;
|
||||
}
|
||||
if (deity_id && item_a->Deity && !(deity::ConvertDeityTypeToDeityTypeBit((deity::DeityType)deity_id) & item_a->Deity)) {
|
||||
if (deity_id && source_item->Deity && !(deity::ConvertDeityTypeToDeityTypeBit((deity::DeityType)deity_id) & source_item->Deity)) {
|
||||
fail_state = swapDeity;
|
||||
return false;
|
||||
}
|
||||
if (level && item_a->ReqLevel && level < item_a->ReqLevel) {
|
||||
if (level && source_item->ReqLevel && level < source_item->ReqLevel) {
|
||||
fail_state = swapLevel;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inst_b) {
|
||||
if (!inst_b->IsSlotAllowed(slot_a)) {
|
||||
if (destination_item_instance) {
|
||||
if (!destination_item_instance->IsSlotAllowed(source_slot)) {
|
||||
fail_state = swapNotAllowed;
|
||||
return false;
|
||||
}
|
||||
if ((slot_a >= invslot::EQUIPMENT_BEGIN && slot_a <= invslot::EQUIPMENT_END) || slot_a == invslot::SLOT_POWER_SOURCE) {
|
||||
auto item_b = inst_b->GetItem();
|
||||
if (!item_b) {
|
||||
if ((source_slot >= invslot::EQUIPMENT_BEGIN && source_slot <= invslot::EQUIPMENT_END)) {
|
||||
auto destination_item = destination_item_instance->GetItem();
|
||||
if (!destination_item) {
|
||||
fail_state = swapNullData;
|
||||
return false;
|
||||
}
|
||||
if (race_id && class_id && !item_b->IsEquipable(race_id, class_id)) {
|
||||
if (race_id && class_id && !destination_item->IsEquipable(race_id, class_id)) {
|
||||
fail_state = swapRaceClass;
|
||||
return false;
|
||||
}
|
||||
if (deity_id && item_b->Deity && !(deity::ConvertDeityTypeToDeityTypeBit((deity::DeityType)deity_id) & item_b->Deity)) {
|
||||
if (deity_id && destination_item->Deity && !(deity::ConvertDeityTypeToDeityTypeBit((deity::DeityType)deity_id) & destination_item->Deity)) {
|
||||
fail_state = swapDeity;
|
||||
return false;
|
||||
}
|
||||
if (level && item_b->ReqLevel && level < item_b->ReqLevel) {
|
||||
if (level && destination_item->ReqLevel && level < destination_item->ReqLevel) {
|
||||
fail_state = swapLevel;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_PutItem(slot_a, inst_b); // Assign b->a
|
||||
_PutItem(slot_b, inst_a); // Assign a->b
|
||||
_PutItem(source_slot, destination_item_instance); // Assign destination -> source
|
||||
_PutItem(destination_slot, source_item_instance); // Assign source -> destination
|
||||
|
||||
fail_state = swapPass;
|
||||
|
||||
@ -325,10 +403,9 @@ bool EQEmu::InventoryProfile::SwapItem(int16 slot_a, int16 slot_b, SwapItemFailS
|
||||
}
|
||||
|
||||
// Remove item from inventory (with memory delete)
|
||||
bool EQEmu::InventoryProfile::DeleteItem(int16 slot_id, uint8 quantity)
|
||||
{
|
||||
bool EQEmu::InventoryProfile::DeleteItem(int16 slot_id, uint8 quantity) {
|
||||
// Pop item out of inventory map (or queue)
|
||||
ItemInstance* item_to_delete = PopItem(slot_id);
|
||||
ItemInstance *item_to_delete = PopItem(slot_id);
|
||||
|
||||
// Determine if object should be fully deleted, or
|
||||
// just a quantity of charges of the item can be deleted
|
||||
@ -342,7 +419,7 @@ bool EQEmu::InventoryProfile::DeleteItem(int16 slot_id, uint8 quantity)
|
||||
// the item is not stackable, and is not a charged item, or is expendable, delete it
|
||||
if (item_to_delete->IsStackable() ||
|
||||
(!item_to_delete->IsStackable() &&
|
||||
((item_to_delete->GetItem()->MaxCharges == 0) || item_to_delete->IsExpendable()))
|
||||
((item_to_delete->GetItem()->MaxCharges == 0) || item_to_delete->IsExpendable()))
|
||||
) {
|
||||
// Item can now be destroyed
|
||||
InventoryProfile::MarkDirty(item_to_delete);
|
||||
@ -379,11 +456,11 @@ EQEmu::ItemInstance* EQEmu::InventoryProfile::PopItem(int16 slot_id)
|
||||
if (slot_id == invslot::slotCursor) {
|
||||
p = m_cursor.pop();
|
||||
}
|
||||
else if ((slot_id >= invslot::EQUIPMENT_BEGIN && slot_id <= invslot::EQUIPMENT_END) || (slot_id == invslot::SLOT_POWER_SOURCE)) {
|
||||
else if (slot_id >= invslot::EQUIPMENT_BEGIN && slot_id <= invslot::EQUIPMENT_END) {
|
||||
p = m_worn[slot_id];
|
||||
m_worn.erase(slot_id);
|
||||
}
|
||||
else if ((slot_id >= invslot::GENERAL_BEGIN && slot_id <= invslot::GENERAL_END)) {
|
||||
else if (slot_id >= invslot::GENERAL_BEGIN && slot_id <= invslot::GENERAL_END) {
|
||||
p = m_inv[slot_id];
|
||||
m_inv.erase(slot_id);
|
||||
}
|
||||
@ -420,6 +497,8 @@ bool EQEmu::InventoryProfile::HasSpaceForItem(const ItemData *ItemToTry, int16 Q
|
||||
if (ItemToTry->Stackable) {
|
||||
|
||||
for (int16 i = invslot::GENERAL_BEGIN; i <= invslot::GENERAL_END; i++) {
|
||||
if ((((uint64)1 << i) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
ItemInstance* InvItem = GetItem(i);
|
||||
|
||||
@ -457,6 +536,8 @@ bool EQEmu::InventoryProfile::HasSpaceForItem(const ItemData *ItemToTry, int16 Q
|
||||
}
|
||||
|
||||
for (int16 i = invslot::GENERAL_BEGIN; i <= invslot::GENERAL_END; i++) {
|
||||
if ((((uint64)1 << i) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
ItemInstance* InvItem = GetItem(i);
|
||||
|
||||
@ -483,7 +564,7 @@ bool EQEmu::InventoryProfile::HasSpaceForItem(const ItemData *ItemToTry, int16 Q
|
||||
|
||||
uint8 BagSize = InvItem->GetItem()->BagSlots;
|
||||
|
||||
for (uint8 BagSlot = invbag::SLOT_BEGIN; BagSlot<BagSize; BagSlot++) {
|
||||
for (uint8 BagSlot = invbag::SLOT_BEGIN; BagSlot < BagSize; BagSlot++) {
|
||||
|
||||
InvItem = GetItem(BaseSlotID + BagSlot);
|
||||
|
||||
@ -663,6 +744,9 @@ int16 EQEmu::InventoryProfile::FindFreeSlot(bool for_bag, bool try_cursor, uint8
|
||||
{
|
||||
// Check basic inventory
|
||||
for (int16 i = invslot::GENERAL_BEGIN; i <= invslot::GENERAL_END; i++) {
|
||||
if ((((uint64)1 << i) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
if (!GetItem(i))
|
||||
// Found available slot in personal inventory
|
||||
return i;
|
||||
@ -670,6 +754,9 @@ int16 EQEmu::InventoryProfile::FindFreeSlot(bool for_bag, bool try_cursor, uint8
|
||||
|
||||
if (!for_bag) {
|
||||
for (int16 i = invslot::GENERAL_BEGIN; i <= invslot::GENERAL_END; i++) {
|
||||
if ((((uint64)1 << i) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
const ItemInstance* inst = GetItem(i);
|
||||
if (inst && inst->IsClassBag() && inst->GetItem()->BagSize >= min_size)
|
||||
{
|
||||
@ -720,6 +807,9 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
|
||||
// step 1: find room for bags (caller should really ask for slots for bags first to avoid sending them to cursor..and bag item loss)
|
||||
if (inst->IsClassBag()) {
|
||||
for (int16 free_slot = general_start; free_slot <= invslot::GENERAL_END; ++free_slot) {
|
||||
if ((((uint64)1 << free_slot) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
if (!m_inv[free_slot])
|
||||
return free_slot;
|
||||
}
|
||||
@ -730,6 +820,9 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
|
||||
// step 2: find partial room for stackables
|
||||
if (inst->IsStackable()) {
|
||||
for (int16 free_slot = general_start; free_slot <= invslot::GENERAL_END; ++free_slot) {
|
||||
if ((((uint64)1 << free_slot) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
const ItemInstance* main_inst = m_inv[free_slot];
|
||||
|
||||
if (!main_inst)
|
||||
@ -740,6 +833,9 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
|
||||
}
|
||||
|
||||
for (int16 free_slot = general_start; free_slot <= invslot::GENERAL_END; ++free_slot) {
|
||||
if ((((uint64)1 << free_slot) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
const ItemInstance* main_inst = m_inv[free_slot];
|
||||
|
||||
if (!main_inst)
|
||||
@ -763,6 +859,9 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
|
||||
// step 3a: find room for container-specific items (ItemClassArrow)
|
||||
if (inst->GetItem()->ItemType == item::ItemTypeArrow) {
|
||||
for (int16 free_slot = general_start; free_slot <= invslot::GENERAL_END; ++free_slot) {
|
||||
if ((((uint64)1 << free_slot) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
const ItemInstance* main_inst = m_inv[free_slot];
|
||||
|
||||
if (!main_inst || (main_inst->GetItem()->BagType != item::BagTypeQuiver) || !main_inst->IsClassBag())
|
||||
@ -779,6 +878,9 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
|
||||
// step 3b: find room for container-specific items (ItemClassSmallThrowing)
|
||||
if (inst->GetItem()->ItemType == item::ItemTypeSmallThrowing) {
|
||||
for (int16 free_slot = general_start; free_slot <= invslot::GENERAL_END; ++free_slot) {
|
||||
if ((((uint64)1 << free_slot) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
const ItemInstance* main_inst = m_inv[free_slot];
|
||||
|
||||
if (!main_inst || (main_inst->GetItem()->BagType != item::BagTypeBandolier) || !main_inst->IsClassBag())
|
||||
@ -794,6 +896,9 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
|
||||
|
||||
// step 4: just find an empty slot
|
||||
for (int16 free_slot = general_start; free_slot <= invslot::GENERAL_END; ++free_slot) {
|
||||
if ((((uint64)1 << free_slot) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
const ItemInstance* main_inst = m_inv[free_slot];
|
||||
|
||||
if (!main_inst)
|
||||
@ -801,6 +906,9 @@ int16 EQEmu::InventoryProfile::FindFreeSlotForTradeItem(const ItemInstance* inst
|
||||
}
|
||||
|
||||
for (int16 free_slot = general_start; free_slot <= invslot::GENERAL_END; ++free_slot) {
|
||||
if ((((uint64)1 << free_slot) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
const ItemInstance* main_inst = m_inv[free_slot];
|
||||
|
||||
if (main_inst && main_inst->IsClassBag()) {
|
||||
@ -977,12 +1085,13 @@ bool EQEmu::InventoryProfile::CanItemFitInContainer(const ItemData *ItemToTry, c
|
||||
bool EQEmu::InventoryProfile::SupportsClickCasting(int16 slot_id)
|
||||
{
|
||||
// there are a few non-potion items that identify as ItemTypePotion..so, we still need to ubiquitously include the equipment range
|
||||
if ((uint16)slot_id <= invslot::GENERAL_END || slot_id == invslot::SLOT_POWER_SOURCE)
|
||||
{
|
||||
if (slot_id >= invslot::EQUIPMENT_BEGIN && slot_id <= invslot::EQUIPMENT_END) {
|
||||
return true;
|
||||
}
|
||||
else if (slot_id >= invbag::GENERAL_BAGS_BEGIN && slot_id <= invbag::GENERAL_BAGS_END)
|
||||
{
|
||||
else if (slot_id >= invslot::GENERAL_BEGIN && slot_id <= invslot::GENERAL_END) {
|
||||
return true;
|
||||
}
|
||||
else if (slot_id >= invbag::GENERAL_BAGS_BEGIN && slot_id <= invbag::GENERAL_BAGS_END) {
|
||||
if (inventory::Lookup(m_mob_version)->AllowClickCastFromBag)
|
||||
return true;
|
||||
}
|
||||
@ -992,8 +1101,16 @@ bool EQEmu::InventoryProfile::SupportsClickCasting(int16 slot_id)
|
||||
|
||||
bool EQEmu::InventoryProfile::SupportsPotionBeltCasting(int16 slot_id)
|
||||
{
|
||||
if ((uint16)slot_id <= invslot::GENERAL_END || slot_id == invslot::SLOT_POWER_SOURCE || (slot_id >= invbag::GENERAL_BAGS_BEGIN && slot_id <= invbag::GENERAL_BAGS_END))
|
||||
// does this have the same criteria as 'SupportsClickCasting' above? (bag clicking per client)
|
||||
if (slot_id >= invslot::EQUIPMENT_BEGIN && slot_id <= invslot::EQUIPMENT_END) {
|
||||
return true;
|
||||
}
|
||||
else if (slot_id >= invslot::GENERAL_BEGIN && slot_id <= invslot::GENERAL_END) {
|
||||
return true;
|
||||
}
|
||||
else if (slot_id >= invbag::GENERAL_BAGS_BEGIN && slot_id <= invbag::GENERAL_BAGS_END) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -1006,7 +1123,7 @@ bool EQEmu::InventoryProfile::SupportsContainers(int16 slot_id)
|
||||
(slot_id >= invslot::BANK_BEGIN && slot_id <= invslot::BANK_END) ||
|
||||
(slot_id >= invslot::SHARED_BANK_BEGIN && slot_id <= invslot::SHARED_BANK_END) ||
|
||||
(slot_id >= invslot::TRADE_BEGIN && slot_id <= invslot::TRADE_END)
|
||||
) {
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1054,13 +1171,19 @@ uint8 EQEmu::InventoryProfile::FindBrightestLightType()
|
||||
uint8 brightest_light_type = 0;
|
||||
|
||||
for (auto iter = m_worn.begin(); iter != m_worn.end(); ++iter) {
|
||||
if ((iter->first < invslot::EQUIPMENT_BEGIN || iter->first > invslot::EQUIPMENT_END) && iter->first != invslot::SLOT_POWER_SOURCE) { continue; }
|
||||
if (iter->first == invslot::slotAmmo) { continue; }
|
||||
if ((iter->first < invslot::EQUIPMENT_BEGIN || iter->first > invslot::EQUIPMENT_END))
|
||||
continue;
|
||||
|
||||
if (iter->first == invslot::slotAmmo)
|
||||
continue;
|
||||
|
||||
auto inst = iter->second;
|
||||
if (inst == nullptr) { continue; }
|
||||
if (inst == nullptr)
|
||||
continue;
|
||||
|
||||
auto item = inst->GetItem();
|
||||
if (item == nullptr) { continue; }
|
||||
if (item == nullptr)
|
||||
continue;
|
||||
|
||||
if (lightsource::IsLevelGreater(item->Light, brightest_light_type))
|
||||
brightest_light_type = item->Light;
|
||||
@ -1068,15 +1191,21 @@ uint8 EQEmu::InventoryProfile::FindBrightestLightType()
|
||||
|
||||
uint8 general_light_type = 0;
|
||||
for (auto iter = m_inv.begin(); iter != m_inv.end(); ++iter) {
|
||||
if (iter->first < invslot::GENERAL_BEGIN || iter->first > invslot::GENERAL_END) { continue; }
|
||||
if (iter->first < invslot::GENERAL_BEGIN || iter->first > invslot::GENERAL_END)
|
||||
continue;
|
||||
|
||||
auto inst = iter->second;
|
||||
if (inst == nullptr) { continue; }
|
||||
auto item = inst->GetItem();
|
||||
if (item == nullptr) { continue; }
|
||||
if (inst == nullptr)
|
||||
continue;
|
||||
|
||||
if (!item->IsClassCommon()) { continue; }
|
||||
if (item->Light < 9 || item->Light > 13) { continue; }
|
||||
auto item = inst->GetItem();
|
||||
if (item == nullptr)
|
||||
continue;
|
||||
|
||||
if (!item->IsClassCommon())
|
||||
continue;
|
||||
if (item->Light < 9 || item->Light > 13)
|
||||
continue;
|
||||
|
||||
if (lightsource::TypeToLevel(item->Light))
|
||||
general_light_type = item->Light;
|
||||
@ -1136,7 +1265,7 @@ int EQEmu::InventoryProfile::GetSlotByItemInstCollection(const std::map<int16, I
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return EQEmu::invslot::SLOT_INVALID;
|
||||
}
|
||||
|
||||
void EQEmu::InventoryProfile::dumpItemCollection(const std::map<int16, ItemInstance*> &collection)
|
||||
@ -1174,6 +1303,15 @@ void EQEmu::InventoryProfile::dumpBagContents(ItemInstance *inst, std::map<int16
|
||||
// Internal Method: Retrieves item within an inventory bucket
|
||||
EQEmu::ItemInstance* EQEmu::InventoryProfile::_GetItem(const std::map<int16, ItemInstance*>& bucket, int16 slot_id) const
|
||||
{
|
||||
if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) {
|
||||
if ((((uint64)1 << slot_id) & m_lookup->PossessionsBitmask) == 0)
|
||||
return nullptr;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) {
|
||||
if (slot_id - EQEmu::invslot::BANK_BEGIN >= m_lookup->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto it = bucket.find(slot_id);
|
||||
if (it != bucket.end()) {
|
||||
return it->second;
|
||||
@ -1205,21 +1343,27 @@ int16 EQEmu::InventoryProfile::_PutItem(int16 slot_id, ItemInstance* inst)
|
||||
m_cursor.push_front(inst);
|
||||
result = slot_id;
|
||||
}
|
||||
else if ((slot_id >= invslot::EQUIPMENT_BEGIN && slot_id <= invslot::EQUIPMENT_END) || (slot_id == invslot::SLOT_POWER_SOURCE)) {
|
||||
m_worn[slot_id] = inst;
|
||||
result = slot_id;
|
||||
else if (slot_id >= invslot::EQUIPMENT_BEGIN && slot_id <= invslot::EQUIPMENT_END) {
|
||||
if ((((uint64)1 << slot_id) & m_lookup->PossessionsBitmask) != 0) {
|
||||
m_worn[slot_id] = inst;
|
||||
result = slot_id;
|
||||
}
|
||||
}
|
||||
else if ((slot_id >= invslot::GENERAL_BEGIN && slot_id <= invslot::GENERAL_END)) {
|
||||
m_inv[slot_id] = inst;
|
||||
result = slot_id;
|
||||
if ((((uint64)1 << slot_id) & m_lookup->PossessionsBitmask) != 0) {
|
||||
m_inv[slot_id] = inst;
|
||||
result = slot_id;
|
||||
}
|
||||
}
|
||||
else if (slot_id >= invslot::TRIBUTE_BEGIN && slot_id <= invslot::TRIBUTE_END) {
|
||||
m_worn[slot_id] = inst;
|
||||
result = slot_id;
|
||||
}
|
||||
else if (slot_id >= invslot::BANK_BEGIN && slot_id <= invslot::BANK_END) {
|
||||
m_bank[slot_id] = inst;
|
||||
result = slot_id;
|
||||
if (slot_id - EQEmu::invslot::BANK_BEGIN < m_lookup->InventoryTypeSize[EQEmu::invtype::typeBank]) {
|
||||
m_bank[slot_id] = inst;
|
||||
result = slot_id;
|
||||
}
|
||||
}
|
||||
else if (slot_id >= invslot::SHARED_BANK_BEGIN && slot_id <= invslot::SHARED_BANK_END) {
|
||||
m_shbank[slot_id] = inst;
|
||||
@ -1254,6 +1398,15 @@ int16 EQEmu::InventoryProfile::_HasItem(std::map<int16, ItemInstance*>& bucket,
|
||||
uint32 quantity_found = 0;
|
||||
|
||||
for (auto iter = bucket.begin(); iter != bucket.end(); ++iter) {
|
||||
if (iter->first <= EQEmu::invslot::POSSESSIONS_END && iter->first >= EQEmu::invslot::POSSESSIONS_BEGIN) {
|
||||
if ((((uint64)1 << iter->first) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
}
|
||||
else if (iter->first <= EQEmu::invslot::BANK_END && iter->first >= EQEmu::invslot::BANK_BEGIN) {
|
||||
if (iter->first - EQEmu::invslot::BANK_BEGIN >= m_lookup->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
continue;
|
||||
}
|
||||
|
||||
auto inst = iter->second;
|
||||
if (inst == nullptr) { continue; }
|
||||
|
||||
@ -1265,7 +1418,7 @@ int16 EQEmu::InventoryProfile::_HasItem(std::map<int16, ItemInstance*>& bucket,
|
||||
|
||||
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
|
||||
if (inst->GetAugmentItemID(index) == item_id && quantity <= 1)
|
||||
return legacy::SLOT_AUGMENT;
|
||||
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
|
||||
}
|
||||
|
||||
if (!inst->IsClassBag()) { continue; }
|
||||
@ -1282,7 +1435,7 @@ int16 EQEmu::InventoryProfile::_HasItem(std::map<int16, ItemInstance*>& bucket,
|
||||
|
||||
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
|
||||
if (bag_inst->GetAugmentItemID(index) == item_id && quantity <= 1)
|
||||
return legacy::SLOT_AUGMENT;
|
||||
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1313,7 +1466,7 @@ int16 EQEmu::InventoryProfile::_HasItem(ItemInstQueue& iqueue, uint32 item_id, u
|
||||
|
||||
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
|
||||
if (inst->GetAugmentItemID(index) == item_id && quantity <= 1)
|
||||
return legacy::SLOT_AUGMENT;
|
||||
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
|
||||
}
|
||||
|
||||
if (!inst->IsClassBag()) { continue; }
|
||||
@ -1330,7 +1483,7 @@ int16 EQEmu::InventoryProfile::_HasItem(ItemInstQueue& iqueue, uint32 item_id, u
|
||||
|
||||
for (int index = invaug::SOCKET_BEGIN; index <= invaug::SOCKET_END; ++index) {
|
||||
if (bag_inst->GetAugmentItemID(index) == item_id && quantity <= 1)
|
||||
return legacy::SLOT_AUGMENT;
|
||||
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1347,6 +1500,15 @@ int16 EQEmu::InventoryProfile::_HasItemByUse(std::map<int16, ItemInstance*>& buc
|
||||
uint32 quantity_found = 0;
|
||||
|
||||
for (auto iter = bucket.begin(); iter != bucket.end(); ++iter) {
|
||||
if (iter->first <= EQEmu::invslot::POSSESSIONS_END && iter->first >= EQEmu::invslot::POSSESSIONS_BEGIN) {
|
||||
if ((((uint64)1 << iter->first) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
}
|
||||
else if (iter->first <= EQEmu::invslot::BANK_END && iter->first >= EQEmu::invslot::BANK_BEGIN) {
|
||||
if (iter->first - EQEmu::invslot::BANK_BEGIN >= m_lookup->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
continue;
|
||||
}
|
||||
|
||||
auto inst = iter->second;
|
||||
if (inst == nullptr) { continue; }
|
||||
|
||||
@ -1411,6 +1573,15 @@ int16 EQEmu::InventoryProfile::_HasItemByUse(ItemInstQueue& iqueue, uint8 use, u
|
||||
int16 EQEmu::InventoryProfile::_HasItemByLoreGroup(std::map<int16, ItemInstance*>& bucket, uint32 loregroup)
|
||||
{
|
||||
for (auto iter = bucket.begin(); iter != bucket.end(); ++iter) {
|
||||
if (iter->first <= EQEmu::invslot::POSSESSIONS_END && iter->first >= EQEmu::invslot::POSSESSIONS_BEGIN) {
|
||||
if ((((uint64)1 << iter->first) & m_lookup->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
}
|
||||
else if (iter->first <= EQEmu::invslot::BANK_END && iter->first >= EQEmu::invslot::BANK_BEGIN) {
|
||||
if (iter->first - EQEmu::invslot::BANK_BEGIN >= m_lookup->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
continue;
|
||||
}
|
||||
|
||||
auto inst = iter->second;
|
||||
if (inst == nullptr) { continue; }
|
||||
|
||||
@ -1422,7 +1593,7 @@ int16 EQEmu::InventoryProfile::_HasItemByLoreGroup(std::map<int16, ItemInstance*
|
||||
if (aug_inst == nullptr) { continue; }
|
||||
|
||||
if (aug_inst->GetItem()->LoreGroup == loregroup)
|
||||
return legacy::SLOT_AUGMENT;
|
||||
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
|
||||
}
|
||||
|
||||
if (!inst->IsClassBag()) { continue; }
|
||||
@ -1439,12 +1610,12 @@ int16 EQEmu::InventoryProfile::_HasItemByLoreGroup(std::map<int16, ItemInstance*
|
||||
if (aug_inst == nullptr) { continue; }
|
||||
|
||||
if (aug_inst->GetItem()->LoreGroup == loregroup)
|
||||
return legacy::SLOT_AUGMENT;
|
||||
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return INVALID_INDEX;
|
||||
return EQEmu::invslot::SLOT_INVALID;
|
||||
}
|
||||
|
||||
// Internal Method: Checks an inventory queue type bucket for a particular item
|
||||
@ -1462,7 +1633,7 @@ int16 EQEmu::InventoryProfile::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32
|
||||
if (aug_inst == nullptr) { continue; }
|
||||
|
||||
if (aug_inst->GetItem()->LoreGroup == loregroup)
|
||||
return legacy::SLOT_AUGMENT;
|
||||
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
|
||||
}
|
||||
|
||||
if (!inst->IsClassBag()) { continue; }
|
||||
@ -1479,7 +1650,7 @@ int16 EQEmu::InventoryProfile::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32
|
||||
if (aug_inst == nullptr) { continue; }
|
||||
|
||||
if (aug_inst->GetItem()->LoreGroup == loregroup)
|
||||
return legacy::SLOT_AUGMENT;
|
||||
return invslot::SLOT_AUGMENT_GENERIC_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1487,5 +1658,5 @@ int16 EQEmu::InventoryProfile::_HasItemByLoreGroup(ItemInstQueue& iqueue, uint32
|
||||
break;
|
||||
}
|
||||
|
||||
return INVALID_INDEX;
|
||||
return EQEmu::invslot::SLOT_INVALID;
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ namespace EQEmu
|
||||
|
||||
// Swap items in inventory
|
||||
enum SwapItemFailState : int8 { swapInvalid = -1, swapPass = 0, swapNotAllowed, swapNullData, swapRaceClass, swapDeity, swapLevel };
|
||||
bool SwapItem(int16 slot_a, int16 slot_b, SwapItemFailState& fail_state, uint16 race_id = 0, uint8 class_id = 0, uint16 deity_id = 0, uint8 level = 0);
|
||||
bool SwapItem(int16 source_slot, int16 destination_slot, SwapItemFailState& fail_state, uint16 race_id = 0, uint8 class_id = 0, uint16 deity_id = 0, uint8 level = 0);
|
||||
|
||||
// Remove item from inventory
|
||||
bool DeleteItem(int16 slot_id, uint8 quantity = 0);
|
||||
|
||||
@ -110,9 +110,7 @@ bool EQEmu::InventorySlot::IsDeleteSlot() const
|
||||
|
||||
bool EQEmu::InventorySlot::IsEquipmentIndex(int16 slot_index)
|
||||
{
|
||||
/*if (slot_index < inventory::EquipmentBegin || slot_index > inventory::EquipmentEnd)
|
||||
return false;*/
|
||||
if ((slot_index < invslot::EQUIPMENT_BEGIN || slot_index > invslot::EQUIPMENT_END) && slot_index != invslot::SLOT_POWER_SOURCE)
|
||||
if (slot_index < invslot::EQUIPMENT_BEGIN || slot_index > invslot::EQUIPMENT_END)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -120,8 +118,6 @@ bool EQEmu::InventorySlot::IsEquipmentIndex(int16 slot_index)
|
||||
|
||||
bool EQEmu::InventorySlot::IsGeneralIndex(int16 slot_index)
|
||||
{
|
||||
/*if (slot_index < inventory::GeneralBegin || slot_index > inventory::GeneralEnd)
|
||||
return false;*/
|
||||
if (slot_index < invslot::GENERAL_BEGIN || slot_index > invslot::GENERAL_END)
|
||||
return false;
|
||||
|
||||
@ -130,22 +126,18 @@ bool EQEmu::InventorySlot::IsGeneralIndex(int16 slot_index)
|
||||
|
||||
bool EQEmu::InventorySlot::IsCursorIndex(int16 slot_index)
|
||||
{
|
||||
/*if (slot_index != inventory::slotCursor)
|
||||
return false;*/
|
||||
if (slot_index != invslot::slotCursor)
|
||||
return false;
|
||||
if (slot_index == invslot::slotCursor)
|
||||
return true;
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EQEmu::InventorySlot::IsWeaponIndex(int16 slot_index)
|
||||
{
|
||||
/*if ((slot_index != inventory::slotRange) && (slot_index != inventory::slotPrimary) && (slot_index != inventory::slotSecondary))
|
||||
return false;*/
|
||||
if ((slot_index != invslot::slotRange) && (slot_index != invslot::slotPrimary) && (slot_index != invslot::slotSecondary))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
if (slot_index == invslot::slotPrimary || slot_index == invslot::slotSecondary || slot_index == invslot::slotRange)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EQEmu::InventorySlot::IsTextureIndex(int16 slot_index)
|
||||
|
||||
@ -271,17 +271,10 @@ bool EQEmu::ItemInstance::IsEquipable(int16 slot_id) const
|
||||
if (!m_item)
|
||||
return false;
|
||||
|
||||
// another "shouldn't do" fix..will be fixed in future updates (requires code and database work)
|
||||
int16 use_slot = INVALID_INDEX;
|
||||
if (slot_id == invslot::SLOT_POWER_SOURCE) { use_slot = invslot::slotGeneral1; }
|
||||
if ((uint16)slot_id <= invslot::EQUIPMENT_END) { use_slot = slot_id; }
|
||||
if (slot_id < EQEmu::invslot::EQUIPMENT_BEGIN || slot_id > EQEmu::invslot::EQUIPMENT_END)
|
||||
return false;
|
||||
|
||||
if (use_slot != INVALID_INDEX) {
|
||||
if (m_item->Slots & (1 << use_slot))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return ((m_item->Slots & (1 << slot_id)) != 0);
|
||||
}
|
||||
|
||||
bool EQEmu::ItemInstance::IsAugmentable() const
|
||||
@ -298,20 +291,18 @@ bool EQEmu::ItemInstance::IsAugmentable() const
|
||||
}
|
||||
|
||||
bool EQEmu::ItemInstance::AvailableWearSlot(uint32 aug_wear_slots) const {
|
||||
// TODO: check to see if incoming 'aug_wear_slots' "switches" bit assignments like above...
|
||||
// (if wrong, would only affect MainAmmo and MainPowerSource augments)
|
||||
if (!m_item || !m_item->IsClassCommon())
|
||||
return false;
|
||||
|
||||
int index = invslot::EQUIPMENT_BEGIN;
|
||||
for (; index <= invslot::slotGeneral1; ++index) { // MainGeneral1 should be legacy::EQUIPMENT_END
|
||||
for (; index <= invslot::EQUIPMENT_END; ++index) {
|
||||
if (m_item->Slots & (1 << index)) {
|
||||
if (aug_wear_slots & (1 << index))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (index < 23) ? true : false;
|
||||
return (index <= EQEmu::invslot::EQUIPMENT_END);
|
||||
}
|
||||
|
||||
int8 EQEmu::ItemInstance::AvailableAugmentSlot(int32 augtype) const
|
||||
@ -810,12 +801,10 @@ EQEmu::ItemInstance* EQEmu::ItemInstance::Clone() const
|
||||
}
|
||||
|
||||
bool EQEmu::ItemInstance::IsSlotAllowed(int16 slot_id) const {
|
||||
// 'SupportsContainers' and 'slot_id > 21' previously saw the reassigned PowerSource slot (9999 to 22) as valid
|
||||
if (!m_item) { return false; }
|
||||
else if (InventoryProfile::SupportsContainers(slot_id)) { return true; }
|
||||
else if (m_item->Slots & (1 << slot_id)) { return true; }
|
||||
else if (slot_id == invslot::SLOT_POWER_SOURCE && (m_item->Slots & (1 << 22))) { return true; } // got lazy... <watch>
|
||||
else if (slot_id != invslot::SLOT_POWER_SOURCE && slot_id > invslot::EQUIPMENT_END) { return true; }
|
||||
else if (slot_id > invslot::EQUIPMENT_END) { return true; } // why do we call 'InventoryProfile::SupportsContainers' with this here?
|
||||
else { return false; }
|
||||
}
|
||||
|
||||
|
||||
@ -124,7 +124,7 @@ namespace EQEmu
|
||||
|
||||
class OutBuffer : public std::stringstream {
|
||||
public:
|
||||
inline size_t size() { return tellp(); }
|
||||
inline size_t size() { return static_cast<size_t>(tellp()); }
|
||||
void overwrite(OutBuffer::pos_type position, const char *_Str, std::streamsize _Count);
|
||||
uchar* detach();
|
||||
};
|
||||
|
||||
@ -73,7 +73,7 @@ uint32 SwapBits21And22(uint32 mask);
|
||||
uint32 Catch22(uint32 mask);
|
||||
|
||||
// macro to catch fp errors (provided by noudness)
|
||||
#define FCMP(a,b) (fabs(a-b) < FLT_EPSILON)
|
||||
#define FCMP(a,b) (std::abs(a-b) < FLT_EPSILON)
|
||||
|
||||
#define _ITOA_BUFLEN 25
|
||||
const char *itoa(int num); //not thread safe
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -46,18 +46,18 @@ namespace SoD
|
||||
void SerializeItem(EQEmu::OutBuffer& ob, const EQEmu::ItemInstance *inst, int16 slot_id, uint8 depth);
|
||||
|
||||
// server to client inventory location converters
|
||||
static inline uint32 ServerToSoDSlot(uint32 ServerSlot);
|
||||
static inline uint32 ServerToSoDCorpseSlot(uint32 serverCorpseSlot);
|
||||
static inline uint32 ServerToSoDSlot(uint32 server_slot);
|
||||
static inline uint32 ServerToSoDCorpseSlot(uint32 server_corpse_slot);
|
||||
|
||||
// client to server inventory location converters
|
||||
static inline uint32 SoDToServerSlot(uint32 sodSlot);
|
||||
static inline uint32 SoDToServerCorpseSlot(uint32 sodCorpseSlot);
|
||||
static inline uint32 SoDToServerSlot(uint32 sod_slot);
|
||||
static inline uint32 SoDToServerCorpseSlot(uint32 sod_corpse_slot);
|
||||
|
||||
// server to client say link converter
|
||||
static inline void ServerToSoDSayLink(std::string& sodSayLink, const std::string& serverSayLink);
|
||||
static inline void ServerToSoDSayLink(std::string &sod_saylink, const std::string &server_saylink);
|
||||
|
||||
// client to server say link converter
|
||||
static inline void SoDToServerSayLink(std::string& serverSayLink, const std::string& sodSayLink);
|
||||
static inline void SoDToServerSayLink(std::string &server_saylink, const std::string &sod_saylink);
|
||||
|
||||
static inline CastingSlot ServerToSoDCastingSlot(EQEmu::CastingSlot slot);
|
||||
static inline EQEmu::CastingSlot SoDToServerCastingSlot(CastingSlot slot);
|
||||
@ -400,7 +400,7 @@ namespace SoD
|
||||
for (int index = 0; index < item_count; ++index, ++eq) {
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)eq->inst, eq->slot_id, 0);
|
||||
if (ob.tellp() == last_pos)
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
Log(Logs::General, Logs::Netcode, "SoD::ENCODE(OP_CharInventory) Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
@ -464,7 +464,12 @@ namespace SoD
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DeleteCharge) { ENCODE_FORWARD(OP_MoveItem); }
|
||||
ENCODE(OP_DeleteCharge)
|
||||
{
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoD::ENCODE(OP_DeleteCharge)");
|
||||
|
||||
ENCODE_FORWARD(OP_MoveItem);
|
||||
}
|
||||
|
||||
ENCODE(OP_DeleteItem)
|
||||
{
|
||||
@ -1064,7 +1069,7 @@ namespace SoD
|
||||
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)int_struct->inst, int_struct->slot_id, 0);
|
||||
if (ob.tellp() == last_pos) {
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
Log(Logs::General, Logs::Netcode, "SoD::ENCODE(OP_ItemPacket) Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -1125,6 +1130,8 @@ namespace SoD
|
||||
ENCODE_LENGTH_EXACT(LootingItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoD::ENCODE(OP_LootItem)");
|
||||
|
||||
OUT(lootee);
|
||||
OUT(looter);
|
||||
eq->slot_id = ServerToSoDCorpseSlot(emu->slot_id);
|
||||
@ -1286,6 +1293,8 @@ namespace SoD
|
||||
ENCODE_LENGTH_EXACT(MoveItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoD::ENCODE(OP_MoveItem)");
|
||||
|
||||
eq->from_slot = ServerToSoDSlot(emu->from_slot);
|
||||
eq->to_slot = ServerToSoDSlot(emu->to_slot);
|
||||
OUT(number_in_stack);
|
||||
@ -1524,7 +1533,7 @@ namespace SoD
|
||||
|
||||
// OUT(unknown06160[4]);
|
||||
|
||||
// Copy bandoliers where server and client indexes converge
|
||||
// Copy bandoliers where server and client indices converge
|
||||
for (r = 0; r < EQEmu::profile::BANDOLIERS_SIZE && r < profile::BANDOLIERS_SIZE; ++r) {
|
||||
OUT_str(bandoliers[r].Name);
|
||||
for (uint32 k = 0; k < profile::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||
@ -1533,7 +1542,7 @@ namespace SoD
|
||||
OUT_str(bandoliers[r].Items[k].Name);
|
||||
}
|
||||
}
|
||||
// Nullify bandoliers where server and client indexes diverge, with a client bias
|
||||
// Nullify bandoliers where server and client indices diverge, with a client bias
|
||||
for (r = EQEmu::profile::BANDOLIERS_SIZE; r < profile::BANDOLIERS_SIZE; ++r) {
|
||||
eq->bandoliers[r].Name[0] = '\0';
|
||||
for (uint32 k = 0; k < profile::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||
@ -1545,13 +1554,13 @@ namespace SoD
|
||||
|
||||
// OUT(unknown07444[5120]);
|
||||
|
||||
// Copy potion belt where server and client indexes converge
|
||||
// Copy potion belt where server and client indices converge
|
||||
for (r = 0; r < EQEmu::profile::POTION_BELT_SIZE && r < profile::POTION_BELT_SIZE; ++r) {
|
||||
OUT(potionbelt.Items[r].ID);
|
||||
OUT(potionbelt.Items[r].Icon);
|
||||
OUT_str(potionbelt.Items[r].Name);
|
||||
}
|
||||
// Nullify potion belt where server and client indexes diverge, with a client bias
|
||||
// Nullify potion belt where server and client indices diverge, with a client bias
|
||||
for (r = EQEmu::profile::POTION_BELT_SIZE; r < profile::POTION_BELT_SIZE; ++r) {
|
||||
eq->potionbelt.Items[r].ID = 0;
|
||||
eq->potionbelt.Items[r].Icon = 0;
|
||||
@ -3140,6 +3149,8 @@ namespace SoD
|
||||
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
|
||||
SETUP_DIRECT_DECODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoD::DECODE(OP_LootItem)");
|
||||
|
||||
IN(lootee);
|
||||
IN(looter);
|
||||
emu->slot_id = SoDToServerCorpseSlot(eq->slot_id);
|
||||
@ -3153,7 +3164,7 @@ namespace SoD
|
||||
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
|
||||
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[SoD] Moved item from %u to %u", eq->from_slot, eq->to_slot);
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoD::DECODE(OP_MoveItem)");
|
||||
|
||||
emu->from_slot = SoDToServerSlot(eq->from_slot);
|
||||
emu->to_slot = SoDToServerSlot(eq->to_slot);
|
||||
@ -3474,7 +3485,7 @@ namespace SoD
|
||||
ibs.nodrop = item->NoDrop;
|
||||
ibs.attune = item->Attuneable;
|
||||
ibs.size = item->Size;
|
||||
ibs.slots = SwapBits21And22(item->Slots);
|
||||
ibs.slots = item->Slots;
|
||||
ibs.price = item->Price;
|
||||
ibs.icon = item->Icon;
|
||||
ibs.unknown1 = 1;
|
||||
@ -3737,94 +3748,216 @@ namespace SoD
|
||||
|
||||
ob.write((const char*)&subitem_count, sizeof(uint32));
|
||||
|
||||
for (uint32 index = EQEmu::invbag::SLOT_BEGIN; index <= EQEmu::invbag::SLOT_END; ++index) {
|
||||
EQEmu::ItemInstance* sub = inst->GetItem(index);
|
||||
if (!sub)
|
||||
continue;
|
||||
// moved outside of loop since it is not modified within that scope
|
||||
int16 SubSlotNumber = EQEmu::invbag::SLOT_INVALID;
|
||||
|
||||
int SubSlotNumber = INVALID_INDEX;
|
||||
if (slot_id_in >= EQEmu::invslot::GENERAL_BEGIN && slot_id_in <= EQEmu::invslot::GENERAL_END)
|
||||
SubSlotNumber = (((slot_id_in + 3) * EQEmu::invbag::SLOT_COUNT) + index + 1);
|
||||
else if (slot_id_in >= EQEmu::invslot::BANK_BEGIN && slot_id_in <= EQEmu::invslot::BANK_END)
|
||||
SubSlotNumber = (((slot_id_in - EQEmu::invslot::BANK_BEGIN) * EQEmu::invbag::SLOT_COUNT) + EQEmu::invbag::BANK_BAGS_BEGIN + index);
|
||||
else if (slot_id_in >= EQEmu::invslot::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::invslot::SHARED_BANK_END)
|
||||
SubSlotNumber = (((slot_id_in - EQEmu::invslot::SHARED_BANK_BEGIN) * EQEmu::invbag::SLOT_COUNT) + EQEmu::invbag::SHARED_BANK_BAGS_BEGIN + index);
|
||||
else
|
||||
SubSlotNumber = slot_id_in;
|
||||
if (slot_id_in <= EQEmu::invslot::slotGeneral8 && slot_id_in >= EQEmu::invslot::GENERAL_BEGIN)
|
||||
SubSlotNumber = EQEmu::invbag::GENERAL_BAGS_BEGIN + ((slot_id_in - EQEmu::invslot::GENERAL_BEGIN) * EQEmu::invbag::SLOT_COUNT);
|
||||
else if (slot_id_in <= EQEmu::invslot::GENERAL_END && slot_id_in >= EQEmu::invslot::slotGeneral9)
|
||||
SubSlotNumber = EQEmu::invbag::SLOT_INVALID;
|
||||
else if (slot_id_in == EQEmu::invslot::slotCursor)
|
||||
SubSlotNumber = EQEmu::invbag::CURSOR_BAG_BEGIN;
|
||||
else if (slot_id_in <= EQEmu::invslot::BANK_END && slot_id_in >= EQEmu::invslot::BANK_BEGIN)
|
||||
SubSlotNumber = EQEmu::invbag::BANK_BAGS_BEGIN + ((slot_id_in - EQEmu::invslot::BANK_BEGIN) * EQEmu::invbag::SLOT_COUNT);
|
||||
else if (slot_id_in <= EQEmu::invslot::SHARED_BANK_END && slot_id_in >= EQEmu::invslot::SHARED_BANK_BEGIN)
|
||||
SubSlotNumber = EQEmu::invbag::SHARED_BANK_BAGS_BEGIN + ((slot_id_in - EQEmu::invslot::SHARED_BANK_BEGIN) * EQEmu::invbag::SLOT_COUNT);
|
||||
else
|
||||
SubSlotNumber = slot_id_in; // not sure if this is the best way to handle this..leaving for now
|
||||
|
||||
ob.write((const char*)&index, sizeof(uint32));
|
||||
if (SubSlotNumber != EQEmu::invbag::SLOT_INVALID) {
|
||||
for (uint32 index = EQEmu::invbag::SLOT_BEGIN; index <= EQEmu::invbag::SLOT_END; ++index) {
|
||||
EQEmu::ItemInstance* sub = inst->GetItem(index);
|
||||
if (!sub)
|
||||
continue;
|
||||
|
||||
SerializeItem(ob, sub, SubSlotNumber, (depth + 1));
|
||||
++subitem_count;
|
||||
ob.write((const char*)&index, sizeof(uint32));
|
||||
|
||||
SerializeItem(ob, sub, SubSlotNumber, (depth + 1));
|
||||
++subitem_count;
|
||||
}
|
||||
|
||||
if (subitem_count)
|
||||
ob.overwrite(count_pos, (const char*)&subitem_count, sizeof(uint32));
|
||||
}
|
||||
|
||||
if (subitem_count)
|
||||
ob.overwrite(count_pos, (const char*)&subitem_count, sizeof(uint32));
|
||||
}
|
||||
|
||||
static inline uint32 ServerToSoDSlot(uint32 serverSlot)
|
||||
{
|
||||
uint32 SoDSlot = 0;
|
||||
uint32 SoDSlot = invslot::SLOT_INVALID;
|
||||
|
||||
if (serverSlot >= EQEmu::invslot::slotAmmo && serverSlot <= 53) // Cursor/Ammo/Power Source and Normal Inventory Slots
|
||||
SoDSlot = serverSlot + 1;
|
||||
else if (serverSlot >= EQEmu::invbag::GENERAL_BAGS_BEGIN && serverSlot <= EQEmu::invbag::CURSOR_BAG_END)
|
||||
SoDSlot = serverSlot + 11;
|
||||
else if (serverSlot >= EQEmu::invbag::BANK_BAGS_BEGIN && serverSlot <= EQEmu::invbag::BANK_BAGS_END)
|
||||
SoDSlot = serverSlot + 1;
|
||||
else if (serverSlot >= EQEmu::invbag::SHARED_BANK_BAGS_BEGIN && serverSlot <= EQEmu::invbag::SHARED_BANK_BAGS_END)
|
||||
SoDSlot = serverSlot + 1;
|
||||
else if (serverSlot == EQEmu::invslot::SLOT_POWER_SOURCE)
|
||||
SoDSlot = invslot::slotPowerSource;
|
||||
else
|
||||
if (serverSlot <= EQEmu::invslot::slotGeneral8) {
|
||||
SoDSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invslot::CORPSE_END && serverSlot >= EQEmu::invslot::slotCursor) {
|
||||
SoDSlot = serverSlot - 2;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invbag::GENERAL_BAGS_8_END && serverSlot >= EQEmu::invbag::GENERAL_BAGS_BEGIN) {
|
||||
SoDSlot = serverSlot + 11;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invbag::CURSOR_BAG_END && serverSlot >= EQEmu::invbag::CURSOR_BAG_BEGIN) {
|
||||
SoDSlot = serverSlot - 9;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invslot::TRIBUTE_END && serverSlot >= EQEmu::invslot::TRIBUTE_BEGIN) {
|
||||
SoDSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invslot::GUILD_TRIBUTE_END && serverSlot >= EQEmu::invslot::GUILD_TRIBUTE_BEGIN) {
|
||||
SoDSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot == EQEmu::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE) {
|
||||
SoDSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invslot::BANK_END && serverSlot >= EQEmu::invslot::BANK_BEGIN) {
|
||||
SoDSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invbag::BANK_BAGS_END && serverSlot >= EQEmu::invbag::BANK_BAGS_BEGIN) {
|
||||
SoDSlot = serverSlot + 1;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invslot::SHARED_BANK_END && serverSlot >= EQEmu::invslot::SHARED_BANK_BEGIN) {
|
||||
SoDSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invbag::SHARED_BANK_BAGS_END && serverSlot >= EQEmu::invbag::SHARED_BANK_BAGS_BEGIN) {
|
||||
SoDSlot = serverSlot + 1;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invslot::TRADE_END && serverSlot >= EQEmu::invslot::TRADE_BEGIN) {
|
||||
SoDSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invbag::TRADE_BAGS_END && serverSlot >= EQEmu::invbag::TRADE_BAGS_BEGIN) {
|
||||
SoDSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invslot::WORLD_END && serverSlot >= EQEmu::invslot::WORLD_BEGIN) {
|
||||
SoDSlot = serverSlot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Slot %i to SoD Slot %i", serverSlot, SoDSlot);
|
||||
|
||||
return SoDSlot;
|
||||
}
|
||||
|
||||
static inline uint32 ServerToSoDCorpseSlot(uint32 serverCorpseSlot)
|
||||
static inline uint32 ServerToSoDCorpseSlot(uint32 server_corpse_slot)
|
||||
{
|
||||
//uint32 SoDCorpse;
|
||||
return (serverCorpseSlot + 1);
|
||||
uint32 SoDSlot = invslot::SLOT_INVALID;
|
||||
|
||||
if (server_corpse_slot <= EQEmu::invslot::slotGeneral8 && server_corpse_slot >= EQEmu::invslot::slotGeneral1) {
|
||||
SoDSlot = server_corpse_slot;
|
||||
}
|
||||
|
||||
else if (server_corpse_slot <= EQEmu::invslot::CORPSE_END && server_corpse_slot >= EQEmu::invslot::slotCursor) {
|
||||
SoDSlot = server_corpse_slot - 2;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Corpse Slot %i to SoD Corpse Slot %i", server_corpse_slot, SoDSlot);
|
||||
|
||||
return SoDSlot;
|
||||
}
|
||||
|
||||
static inline uint32 SoDToServerSlot(uint32 sodSlot)
|
||||
static inline uint32 SoDToServerSlot(uint32 sod_slot)
|
||||
{
|
||||
uint32 ServerSlot = 0;
|
||||
uint32 server_slot = EQEmu::invslot::SLOT_INVALID;
|
||||
|
||||
if (sodSlot >= invslot::slotAmmo && sodSlot <= invslot::CORPSE_END) // Cursor/Ammo/Power Source and Normal Inventory Slots
|
||||
ServerSlot = sodSlot - 1;
|
||||
else if (sodSlot >= invbag::GENERAL_BAGS_BEGIN && sodSlot <= invbag::CURSOR_BAG_END)
|
||||
ServerSlot = sodSlot - 11;
|
||||
else if (sodSlot >= invbag::BANK_BAGS_BEGIN && sodSlot <= invbag::BANK_BAGS_END)
|
||||
ServerSlot = sodSlot - 1;
|
||||
else if (sodSlot >= invbag::SHARED_BANK_BAGS_BEGIN && sodSlot <= invbag::SHARED_BANK_BAGS_END)
|
||||
ServerSlot = sodSlot - 1;
|
||||
else if (sodSlot == invslot::slotPowerSource)
|
||||
ServerSlot = EQEmu::invslot::SLOT_POWER_SOURCE;
|
||||
else
|
||||
ServerSlot = sodSlot;
|
||||
return ServerSlot;
|
||||
if (sod_slot <= invslot::slotGeneral8) {
|
||||
server_slot = sod_slot;
|
||||
}
|
||||
|
||||
else if (sod_slot <= invslot::CORPSE_END && sod_slot >= invslot::slotCursor) {
|
||||
server_slot = sod_slot + 2;
|
||||
}
|
||||
|
||||
else if (sod_slot <= invbag::GENERAL_BAGS_END && sod_slot >= invbag::GENERAL_BAGS_BEGIN) {
|
||||
server_slot = sod_slot - 11;
|
||||
}
|
||||
|
||||
else if (sod_slot <= invbag::CURSOR_BAG_END && sod_slot >= invbag::CURSOR_BAG_BEGIN) {
|
||||
server_slot = sod_slot + 9;
|
||||
}
|
||||
|
||||
else if (sod_slot <= invslot::TRIBUTE_END && sod_slot >= invslot::TRIBUTE_BEGIN) {
|
||||
server_slot = sod_slot;
|
||||
}
|
||||
|
||||
else if (sod_slot <= invslot::GUILD_TRIBUTE_END && sod_slot >= invslot::GUILD_TRIBUTE_BEGIN) {
|
||||
server_slot = sod_slot;
|
||||
}
|
||||
|
||||
else if (sod_slot == invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE) {
|
||||
server_slot = sod_slot;
|
||||
}
|
||||
|
||||
else if (sod_slot <= invslot::BANK_END && sod_slot >= invslot::BANK_BEGIN) {
|
||||
server_slot = sod_slot;
|
||||
}
|
||||
|
||||
else if (sod_slot <= invbag::BANK_BAGS_END && sod_slot >= invbag::BANK_BAGS_BEGIN) {
|
||||
server_slot = sod_slot - 1;
|
||||
}
|
||||
|
||||
else if (sod_slot <= invslot::SHARED_BANK_END && sod_slot >= invslot::SHARED_BANK_BEGIN) {
|
||||
server_slot = sod_slot;
|
||||
}
|
||||
|
||||
else if (sod_slot <= invbag::SHARED_BANK_BAGS_END && sod_slot >= invbag::SHARED_BANK_BAGS_BEGIN) {
|
||||
server_slot = sod_slot - 1;
|
||||
}
|
||||
|
||||
else if (sod_slot <= invslot::TRADE_END && sod_slot >= invslot::TRADE_BEGIN) {
|
||||
server_slot = sod_slot;
|
||||
}
|
||||
|
||||
else if (sod_slot <= invbag::TRADE_BAGS_END && sod_slot >= invbag::TRADE_BAGS_BEGIN) {
|
||||
server_slot = sod_slot;
|
||||
}
|
||||
|
||||
else if (sod_slot <= invslot::WORLD_END && sod_slot >= invslot::WORLD_BEGIN) {
|
||||
server_slot = sod_slot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert SoD Slot %i to Server Slot %i", sod_slot, server_slot);
|
||||
|
||||
return server_slot;
|
||||
}
|
||||
|
||||
static inline uint32 SoDToServerCorpseSlot(uint32 sodCorpseSlot)
|
||||
static inline uint32 SoDToServerCorpseSlot(uint32 sod_corpse_slot)
|
||||
{
|
||||
//uint32 ServerCorpse;
|
||||
return (sodCorpseSlot - 1);
|
||||
uint32 server_slot = EQEmu::invslot::SLOT_INVALID;
|
||||
|
||||
if (sod_corpse_slot <= invslot::slotGeneral8 && sod_corpse_slot >= invslot::slotGeneral1) {
|
||||
server_slot = sod_corpse_slot;
|
||||
}
|
||||
|
||||
else if (sod_corpse_slot <= invslot::CORPSE_END && sod_corpse_slot >= invslot::slotCursor) {
|
||||
server_slot = sod_corpse_slot + 2;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert SoD Corpse Slot %i to Server Corpse Slot %i", sod_corpse_slot, server_slot);
|
||||
|
||||
return server_slot;
|
||||
}
|
||||
|
||||
static inline void ServerToSoDSayLink(std::string& sodSayLink, const std::string& serverSayLink)
|
||||
static inline void ServerToSoDSayLink(std::string &sod_saylink, const std::string &server_saylink)
|
||||
{
|
||||
if ((constants::SAY_LINK_BODY_SIZE == EQEmu::constants::SAY_LINK_BODY_SIZE) || (serverSayLink.find('\x12') == std::string::npos)) {
|
||||
sodSayLink = serverSayLink;
|
||||
if ((constants::SAY_LINK_BODY_SIZE == EQEmu::constants::SAY_LINK_BODY_SIZE) || (server_saylink.find('\x12') == std::string::npos)) {
|
||||
sod_saylink = server_saylink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(serverSayLink, '\x12');
|
||||
auto segments = SplitString(server_saylink, '\x12');
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
if (segments[segment_iter].length() <= EQEmu::constants::SAY_LINK_BODY_SIZE) {
|
||||
sodSayLink.append(segments[segment_iter]);
|
||||
sod_saylink.append(segments[segment_iter]);
|
||||
// TODO: log size mismatch error
|
||||
continue;
|
||||
}
|
||||
@ -3834,37 +3967,37 @@ namespace SoD
|
||||
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
|
||||
// Diff: ^^^^^ ^
|
||||
|
||||
sodSayLink.push_back('\x12');
|
||||
sodSayLink.append(segments[segment_iter].substr(0, 31));
|
||||
sodSayLink.append(segments[segment_iter].substr(36, 5));
|
||||
sod_saylink.push_back('\x12');
|
||||
sod_saylink.append(segments[segment_iter].substr(0, 31));
|
||||
sod_saylink.append(segments[segment_iter].substr(36, 5));
|
||||
|
||||
if (segments[segment_iter][41] == '0')
|
||||
sodSayLink.push_back(segments[segment_iter][42]);
|
||||
sod_saylink.push_back(segments[segment_iter][42]);
|
||||
else
|
||||
sodSayLink.push_back('F');
|
||||
sod_saylink.push_back('F');
|
||||
|
||||
sodSayLink.append(segments[segment_iter].substr(43));
|
||||
sodSayLink.push_back('\x12');
|
||||
sod_saylink.append(segments[segment_iter].substr(43));
|
||||
sod_saylink.push_back('\x12');
|
||||
}
|
||||
else {
|
||||
sodSayLink.append(segments[segment_iter]);
|
||||
sod_saylink.append(segments[segment_iter]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void SoDToServerSayLink(std::string& serverSayLink, const std::string& sodSayLink)
|
||||
static inline void SoDToServerSayLink(std::string &server_saylink, const std::string &sod_saylink)
|
||||
{
|
||||
if ((EQEmu::constants::SAY_LINK_BODY_SIZE == constants::SAY_LINK_BODY_SIZE) || (sodSayLink.find('\x12') == std::string::npos)) {
|
||||
serverSayLink = sodSayLink;
|
||||
if ((EQEmu::constants::SAY_LINK_BODY_SIZE == constants::SAY_LINK_BODY_SIZE) || (sod_saylink.find('\x12') == std::string::npos)) {
|
||||
server_saylink = sod_saylink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(sodSayLink, '\x12');
|
||||
auto segments = SplitString(sod_saylink, '\x12');
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
if (segments[segment_iter].length() <= constants::SAY_LINK_BODY_SIZE) {
|
||||
serverSayLink.append(segments[segment_iter]);
|
||||
server_saylink.append(segments[segment_iter]);
|
||||
// TODO: log size mismatch error
|
||||
continue;
|
||||
}
|
||||
@ -3874,16 +4007,16 @@ namespace SoD
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// Diff: ^^^^^ ^
|
||||
|
||||
serverSayLink.push_back('\x12');
|
||||
serverSayLink.append(segments[segment_iter].substr(0, 31));
|
||||
serverSayLink.append("00000");
|
||||
serverSayLink.append(segments[segment_iter].substr(31, 5));
|
||||
serverSayLink.push_back('0');
|
||||
serverSayLink.append(segments[segment_iter].substr(36));
|
||||
serverSayLink.push_back('\x12');
|
||||
server_saylink.push_back('\x12');
|
||||
server_saylink.append(segments[segment_iter].substr(0, 31));
|
||||
server_saylink.append("00000");
|
||||
server_saylink.append(segments[segment_iter].substr(31, 5));
|
||||
server_saylink.push_back('0');
|
||||
server_saylink.append(segments[segment_iter].substr(36));
|
||||
server_saylink.push_back('\x12');
|
||||
}
|
||||
else {
|
||||
serverSayLink.append(segments[segment_iter]);
|
||||
server_saylink.append(segments[segment_iter]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,6 +150,8 @@ namespace SoD
|
||||
const int16 SLOT_INVALID = IINVALID;
|
||||
const int16 SLOT_BEGIN = INULL;
|
||||
|
||||
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
|
||||
|
||||
const int16 POSSESSIONS_BEGIN = slotCharm;
|
||||
const int16 POSSESSIONS_END = slotCursor;
|
||||
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
|
||||
|
||||
@ -46,21 +46,21 @@ namespace SoF
|
||||
void SerializeItem(EQEmu::OutBuffer& ob, const EQEmu::ItemInstance *inst, int16 slot_id, uint8 depth);
|
||||
|
||||
// server to client inventory location converters
|
||||
static inline uint32 ServerToSoFSlot(uint32 serverSlot);
|
||||
static inline uint32 ServerToSoFCorpseSlot(uint32 serverCorpseSlot);
|
||||
static inline uint32 ServerToSoFSlot(uint32 server_slot);
|
||||
static inline uint32 ServerToSoFCorpseSlot(uint32 server_corpse_slot);
|
||||
|
||||
// client to server inventory location converters
|
||||
static inline uint32 SoFToServerSlot(uint32 sofSlot);
|
||||
static inline uint32 SoFToServerCorpseSlot(uint32 sofCorpseSlot);
|
||||
static inline uint32 SoFToServerSlot(uint32 sof_slot);
|
||||
static inline uint32 SoFToServerCorpseSlot(uint32 sof_corpse_slot);
|
||||
|
||||
// server to client say link converter
|
||||
static inline void ServerToSoFSayLink(std::string& sofSayLink, const std::string& serverSayLink);
|
||||
static inline void ServerToSoFSayLink(std::string &sof_saylink, const std::string &server_saylink);
|
||||
|
||||
// client to server say link converter
|
||||
static inline void SoFToServerSayLink(std::string& serverSayLink, const std::string& sofSayLink);
|
||||
static inline void SoFToServerSayLink(std::string &server_saylink, const std::string &sof_saylink);
|
||||
|
||||
static inline CastingSlot ServerToSoFCastingSlot(EQEmu::CastingSlot slot);
|
||||
static inline EQEmu::CastingSlot SoFToServerCastingSlot(CastingSlot slot, uint32 itemlocation);
|
||||
static inline EQEmu::CastingSlot SoFToServerCastingSlot(CastingSlot slot, uint32 item_location);
|
||||
|
||||
static inline int ServerToSoFBuffSlot(int index);
|
||||
static inline int SoFToServerBuffSlot(int index);
|
||||
@ -103,8 +103,6 @@ namespace SoF
|
||||
signature.first_eq_opcode = opcodes->EmuToEQ(OP_ZoneEntry);
|
||||
into.RegisterPatch(signature, pname.c_str(), &opcodes, &struct_strategy);
|
||||
|
||||
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[IDENTIFY] Registered patch %s", name);
|
||||
}
|
||||
|
||||
@ -382,7 +380,7 @@ namespace SoF
|
||||
for (int index = 0; index < item_count; ++index, ++eq) {
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)eq->inst, eq->slot_id, 0);
|
||||
if (ob.tellp() == last_pos)
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
Log(Logs::General, Logs::Netcode, "SoF::ENCODE(OP_CharInventory) Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
@ -445,7 +443,12 @@ namespace SoF
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DeleteCharge) { ENCODE_FORWARD(OP_MoveItem); }
|
||||
ENCODE(OP_DeleteCharge)
|
||||
{
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoF::ENCODE(OP_DeleteCharge)");
|
||||
|
||||
ENCODE_FORWARD(OP_MoveItem);
|
||||
}
|
||||
|
||||
ENCODE(OP_DeleteItem)
|
||||
{
|
||||
@ -861,7 +864,7 @@ namespace SoF
|
||||
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)int_struct->inst, int_struct->slot_id, 0);
|
||||
if (ob.tellp() == last_pos) {
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
Log(Logs::General, Logs::Netcode, "SoF::ENCODE(OP_ItemPacket) Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -922,6 +925,8 @@ namespace SoF
|
||||
ENCODE_LENGTH_EXACT(LootingItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoF::ENCODE(OP_LootItem)");
|
||||
|
||||
OUT(lootee);
|
||||
OUT(looter);
|
||||
eq->slot_id = ServerToSoFCorpseSlot(emu->slot_id);
|
||||
@ -965,6 +970,8 @@ namespace SoF
|
||||
ENCODE_LENGTH_EXACT(MoveItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoF::ENCODE(OP_MoveItem)");
|
||||
|
||||
eq->from_slot = ServerToSoFSlot(emu->from_slot);
|
||||
eq->to_slot = ServerToSoFSlot(emu->to_slot);
|
||||
OUT(number_in_stack);
|
||||
@ -1190,7 +1197,7 @@ namespace SoF
|
||||
|
||||
// OUT(unknown06160[4]);
|
||||
|
||||
// Copy bandoliers where server and client indexes converge
|
||||
// Copy bandoliers where server and client indices converge
|
||||
for (r = 0; r < EQEmu::profile::BANDOLIERS_SIZE && r < profile::BANDOLIERS_SIZE; ++r) {
|
||||
OUT_str(bandoliers[r].Name);
|
||||
for (uint32 k = 0; k < profile::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||
@ -1199,7 +1206,7 @@ namespace SoF
|
||||
OUT_str(bandoliers[r].Items[k].Name);
|
||||
}
|
||||
}
|
||||
// Nullify bandoliers where server and client indexes diverge, with a client bias
|
||||
// Nullify bandoliers where server and client indices diverge, with a client bias
|
||||
for (r = EQEmu::profile::BANDOLIERS_SIZE; r < profile::BANDOLIERS_SIZE; ++r) {
|
||||
eq->bandoliers[r].Name[0] = '\0';
|
||||
for (uint32 k = 0; k < profile::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||
@ -1211,13 +1218,13 @@ namespace SoF
|
||||
|
||||
// OUT(unknown07444[5120]);
|
||||
|
||||
// Copy potion belt where server and client indexes converge
|
||||
// Copy potion belt where server and client indices converge
|
||||
for (r = 0; r < EQEmu::profile::POTION_BELT_SIZE && r < profile::POTION_BELT_SIZE; ++r) {
|
||||
OUT(potionbelt.Items[r].ID);
|
||||
OUT(potionbelt.Items[r].Icon);
|
||||
OUT_str(potionbelt.Items[r].Name);
|
||||
}
|
||||
// Nullify potion belt where server and client indexes diverge, with a client bias
|
||||
// Nullify potion belt where server and client indices diverge, with a client bias
|
||||
for (r = EQEmu::profile::POTION_BELT_SIZE; r < profile::POTION_BELT_SIZE; ++r) {
|
||||
eq->potionbelt.Items[r].ID = 0;
|
||||
eq->potionbelt.Items[r].Icon = 0;
|
||||
@ -2548,6 +2555,8 @@ namespace SoF
|
||||
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
|
||||
SETUP_DIRECT_DECODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoF::DECODE(OP_LootItem)");
|
||||
|
||||
IN(lootee);
|
||||
IN(looter);
|
||||
emu->slot_id = SoFToServerCorpseSlot(eq->slot_id);
|
||||
@ -2561,7 +2570,7 @@ namespace SoF
|
||||
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
|
||||
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[SoF] Moved item from %u to %u", eq->from_slot, eq->to_slot);
|
||||
Log(Logs::Moderate, Logs::Netcode, "SoF::DECODE(OP_MoveItem)");
|
||||
|
||||
emu->from_slot = SoFToServerSlot(eq->from_slot);
|
||||
emu->to_slot = SoFToServerSlot(eq->to_slot);
|
||||
@ -2867,7 +2876,7 @@ namespace SoF
|
||||
ibs.nodrop = item->NoDrop;
|
||||
ibs.attune = item->Attuneable;
|
||||
ibs.size = item->Size;
|
||||
ibs.slots = SwapBits21And22(item->Slots);
|
||||
ibs.slots = item->Slots;
|
||||
ibs.price = item->Price;
|
||||
ibs.icon = item->Icon;
|
||||
ibs.unknown1 = 1;
|
||||
@ -3129,96 +3138,224 @@ namespace SoF
|
||||
|
||||
ob.write((const char*)&subitem_count, sizeof(uint32));
|
||||
|
||||
for (uint32 index = EQEmu::invbag::SLOT_BEGIN; index <= EQEmu::invbag::SLOT_END; ++index) {
|
||||
EQEmu::ItemInstance* sub = inst->GetItem(index);
|
||||
if (!sub)
|
||||
continue;
|
||||
// moved outside of loop since it is not modified within that scope
|
||||
int16 SubSlotNumber = EQEmu::invbag::SLOT_INVALID;
|
||||
|
||||
int SubSlotNumber = INVALID_INDEX;
|
||||
if (slot_id_in >= EQEmu::invslot::GENERAL_BEGIN && slot_id_in <= EQEmu::invslot::GENERAL_END)
|
||||
SubSlotNumber = (((slot_id_in + 3) * EQEmu::invbag::SLOT_COUNT) + index + 1);
|
||||
else if (slot_id_in >= EQEmu::invslot::BANK_BEGIN && slot_id_in <= EQEmu::invslot::BANK_END)
|
||||
SubSlotNumber = (((slot_id_in - EQEmu::invslot::BANK_BEGIN) * EQEmu::invbag::SLOT_COUNT) + EQEmu::invbag::BANK_BAGS_BEGIN + index);
|
||||
else if (slot_id_in >= EQEmu::invslot::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::invslot::SHARED_BANK_END)
|
||||
SubSlotNumber = (((slot_id_in - EQEmu::invslot::SHARED_BANK_BEGIN) * EQEmu::invbag::SLOT_COUNT) + EQEmu::invbag::SHARED_BANK_BAGS_BEGIN + index);
|
||||
else
|
||||
SubSlotNumber = slot_id_in;
|
||||
if (slot_id_in <= EQEmu::invslot::slotGeneral8 && slot_id_in >= EQEmu::invslot::GENERAL_BEGIN)
|
||||
SubSlotNumber = EQEmu::invbag::GENERAL_BAGS_BEGIN + ((slot_id_in - EQEmu::invslot::GENERAL_BEGIN) * EQEmu::invbag::SLOT_COUNT);
|
||||
else if (slot_id_in <= EQEmu::invslot::GENERAL_END && slot_id_in >= EQEmu::invslot::slotGeneral9)
|
||||
SubSlotNumber = EQEmu::invbag::SLOT_INVALID;
|
||||
else if (slot_id_in == EQEmu::invslot::slotCursor)
|
||||
SubSlotNumber = EQEmu::invbag::CURSOR_BAG_BEGIN;
|
||||
else if (slot_id_in <= EQEmu::invslot::BANK_END && slot_id_in >= EQEmu::invslot::BANK_BEGIN)
|
||||
SubSlotNumber = EQEmu::invbag::BANK_BAGS_BEGIN + ((slot_id_in - EQEmu::invslot::BANK_BEGIN) * EQEmu::invbag::SLOT_COUNT);
|
||||
else if (slot_id_in <= EQEmu::invslot::SHARED_BANK_END && slot_id_in >= EQEmu::invslot::SHARED_BANK_BEGIN)
|
||||
SubSlotNumber = EQEmu::invbag::SHARED_BANK_BAGS_BEGIN + ((slot_id_in - EQEmu::invslot::SHARED_BANK_BEGIN) * EQEmu::invbag::SLOT_COUNT);
|
||||
else
|
||||
SubSlotNumber = slot_id_in; // not sure if this is the best way to handle this..leaving for now
|
||||
|
||||
ob.write((const char*)&index, sizeof(uint32));
|
||||
if (SubSlotNumber != EQEmu::invbag::SLOT_INVALID) {
|
||||
for (uint32 index = EQEmu::invbag::SLOT_BEGIN; index <= EQEmu::invbag::SLOT_END; ++index) {
|
||||
EQEmu::ItemInstance* sub = inst->GetItem(index);
|
||||
if (!sub)
|
||||
continue;
|
||||
|
||||
SerializeItem(ob, sub, SubSlotNumber, (depth + 1));
|
||||
++subitem_count;
|
||||
ob.write((const char*)&index, sizeof(uint32));
|
||||
|
||||
SerializeItem(ob, sub, SubSlotNumber, (depth + 1));
|
||||
++subitem_count;
|
||||
}
|
||||
|
||||
if (subitem_count)
|
||||
ob.overwrite(count_pos, (const char*)&subitem_count, sizeof(uint32));
|
||||
}
|
||||
|
||||
if (subitem_count)
|
||||
ob.overwrite(count_pos, (const char*)&subitem_count, sizeof(uint32));
|
||||
}
|
||||
|
||||
static inline uint32 ServerToSoFSlot(uint32 serverSlot)
|
||||
static inline uint32 ServerToSoFSlot(uint32 server_slot)
|
||||
{
|
||||
uint32 SoFSlot = 0;
|
||||
uint32 sof_slot = invslot::SLOT_INVALID;
|
||||
|
||||
if (serverSlot >= EQEmu::invslot::slotAmmo && serverSlot <= 53) // Cursor/Ammo/Power Source and Normal Inventory Slots
|
||||
SoFSlot = serverSlot + 1;
|
||||
else if (serverSlot >= EQEmu::invbag::GENERAL_BAGS_BEGIN && serverSlot <= EQEmu::invbag::CURSOR_BAG_END)
|
||||
SoFSlot = serverSlot + 11;
|
||||
else if (serverSlot >= EQEmu::invbag::BANK_BAGS_BEGIN && serverSlot <= EQEmu::invbag::BANK_BAGS_END)
|
||||
SoFSlot = serverSlot + 1;
|
||||
else if (serverSlot >= EQEmu::invbag::SHARED_BANK_BAGS_BEGIN && serverSlot <= EQEmu::invbag::SHARED_BANK_BAGS_END)
|
||||
SoFSlot = serverSlot + 1;
|
||||
else if (serverSlot == EQEmu::invslot::SLOT_POWER_SOURCE)
|
||||
SoFSlot = invslot::slotPowerSource;
|
||||
else
|
||||
SoFSlot = serverSlot;
|
||||
if (server_slot <= EQEmu::invslot::slotGeneral8) {
|
||||
sof_slot = server_slot;
|
||||
}
|
||||
|
||||
else if (server_slot <= EQEmu::invslot::CORPSE_END && server_slot >= EQEmu::invslot::slotCursor) {
|
||||
sof_slot = server_slot - 2;
|
||||
}
|
||||
|
||||
else if (server_slot <= EQEmu::invbag::GENERAL_BAGS_8_END && server_slot >= EQEmu::invbag::GENERAL_BAGS_BEGIN) {
|
||||
sof_slot = server_slot + 11;
|
||||
}
|
||||
|
||||
else if (server_slot <= EQEmu::invbag::CURSOR_BAG_END && server_slot >= EQEmu::invbag::CURSOR_BAG_BEGIN) {
|
||||
sof_slot = server_slot - 9;
|
||||
}
|
||||
|
||||
else if (server_slot <= EQEmu::invslot::TRIBUTE_END && server_slot >= EQEmu::invslot::TRIBUTE_BEGIN) {
|
||||
sof_slot = server_slot;
|
||||
}
|
||||
|
||||
else if (server_slot <= EQEmu::invslot::GUILD_TRIBUTE_END && server_slot >= EQEmu::invslot::GUILD_TRIBUTE_BEGIN) {
|
||||
sof_slot = server_slot;
|
||||
}
|
||||
|
||||
else if (server_slot == EQEmu::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE) {
|
||||
sof_slot = server_slot;
|
||||
}
|
||||
|
||||
else if (server_slot <= EQEmu::invslot::BANK_END && server_slot >= EQEmu::invslot::BANK_BEGIN) {
|
||||
sof_slot = server_slot;
|
||||
}
|
||||
|
||||
else if (server_slot <= EQEmu::invbag::BANK_BAGS_END && server_slot >= EQEmu::invbag::BANK_BAGS_BEGIN) {
|
||||
sof_slot = server_slot + 1;
|
||||
}
|
||||
|
||||
else if (server_slot <= EQEmu::invslot::SHARED_BANK_END && server_slot >= EQEmu::invslot::SHARED_BANK_BEGIN) {
|
||||
sof_slot = server_slot;
|
||||
}
|
||||
|
||||
else if (server_slot <= EQEmu::invbag::SHARED_BANK_BAGS_END && server_slot >= EQEmu::invbag::SHARED_BANK_BAGS_BEGIN) {
|
||||
sof_slot = server_slot + 1;
|
||||
}
|
||||
|
||||
else if (server_slot <= EQEmu::invslot::TRADE_END && server_slot >= EQEmu::invslot::TRADE_BEGIN) {
|
||||
sof_slot = server_slot;
|
||||
}
|
||||
|
||||
else if (server_slot <= EQEmu::invbag::TRADE_BAGS_END && server_slot >= EQEmu::invbag::TRADE_BAGS_BEGIN) {
|
||||
sof_slot = server_slot;
|
||||
}
|
||||
|
||||
else if (server_slot <= EQEmu::invslot::WORLD_END && server_slot >= EQEmu::invslot::WORLD_BEGIN) {
|
||||
sof_slot = server_slot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Slot %i to SoF Slot %i", server_slot, sof_slot);
|
||||
|
||||
return sof_slot;
|
||||
}
|
||||
|
||||
static inline uint32 ServerToSoFCorpseSlot(uint32 server_corpse_slot)
|
||||
{
|
||||
uint32 SoFSlot = invslot::SLOT_INVALID;
|
||||
|
||||
if (server_corpse_slot <= EQEmu::invslot::slotGeneral8 && server_corpse_slot >= EQEmu::invslot::slotGeneral1) {
|
||||
SoFSlot = server_corpse_slot;
|
||||
}
|
||||
|
||||
else if (server_corpse_slot <= EQEmu::invslot::CORPSE_END && server_corpse_slot >= EQEmu::invslot::slotCursor) {
|
||||
SoFSlot = server_corpse_slot - 2;
|
||||
}
|
||||
|
||||
Log(Logs::Detail,
|
||||
Logs::Netcode,
|
||||
"Convert Server Corpse Slot %i to SoF Corpse Slot %i",
|
||||
server_corpse_slot,
|
||||
SoFSlot);
|
||||
|
||||
return SoFSlot;
|
||||
}
|
||||
|
||||
static inline uint32 ServerToSoFCorpseSlot(uint32 serverCorpseSlot)
|
||||
static inline uint32 SoFToServerSlot(uint32 sof_slot)
|
||||
{
|
||||
//uint32 SoFCorpse;
|
||||
return (serverCorpseSlot + 1);
|
||||
uint32 server_slot = EQEmu::invslot::SLOT_INVALID;
|
||||
|
||||
if (sof_slot <= invslot::slotGeneral8) {
|
||||
server_slot = sof_slot;
|
||||
}
|
||||
|
||||
else if (sof_slot <= invslot::CORPSE_END && sof_slot >= invslot::slotCursor) {
|
||||
server_slot = sof_slot + 2;
|
||||
}
|
||||
|
||||
else if (sof_slot <= invbag::GENERAL_BAGS_END && sof_slot >= invbag::GENERAL_BAGS_BEGIN) {
|
||||
server_slot = sof_slot - 11;
|
||||
}
|
||||
|
||||
else if (sof_slot <= invbag::CURSOR_BAG_END && sof_slot >= invbag::CURSOR_BAG_BEGIN) {
|
||||
server_slot = sof_slot + 9;
|
||||
}
|
||||
|
||||
else if (sof_slot <= invslot::TRIBUTE_END && sof_slot >= invslot::TRIBUTE_BEGIN) {
|
||||
server_slot = sof_slot;
|
||||
}
|
||||
|
||||
else if (sof_slot <= invslot::GUILD_TRIBUTE_END && sof_slot >= invslot::GUILD_TRIBUTE_BEGIN) {
|
||||
server_slot = sof_slot;
|
||||
}
|
||||
|
||||
else if (sof_slot == invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE) {
|
||||
server_slot = sof_slot;
|
||||
}
|
||||
|
||||
else if (sof_slot <= invslot::BANK_END && sof_slot >= invslot::BANK_BEGIN) {
|
||||
server_slot = sof_slot;
|
||||
}
|
||||
|
||||
else if (sof_slot <= invbag::BANK_BAGS_END && sof_slot >= invbag::BANK_BAGS_BEGIN) {
|
||||
server_slot = sof_slot - 1;
|
||||
}
|
||||
|
||||
else if (sof_slot <= invslot::SHARED_BANK_END && sof_slot >= invslot::SHARED_BANK_BEGIN) {
|
||||
server_slot = sof_slot;
|
||||
}
|
||||
|
||||
else if (sof_slot <= invbag::SHARED_BANK_BAGS_END && sof_slot >= invbag::SHARED_BANK_BAGS_BEGIN) {
|
||||
server_slot = sof_slot - 1;
|
||||
}
|
||||
|
||||
else if (sof_slot <= invslot::TRADE_END && sof_slot >= invslot::TRADE_BEGIN) {
|
||||
server_slot = sof_slot;
|
||||
}
|
||||
|
||||
else if (sof_slot <= invbag::TRADE_BAGS_END && sof_slot >= invbag::TRADE_BAGS_BEGIN) {
|
||||
server_slot = sof_slot;
|
||||
}
|
||||
|
||||
else if (sof_slot <= invslot::WORLD_END && sof_slot >= invslot::WORLD_BEGIN) {
|
||||
server_slot = sof_slot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert SoF Slot %i to Server Slot %i", sof_slot, server_slot);
|
||||
|
||||
return server_slot;
|
||||
}
|
||||
|
||||
static inline uint32 SoFToServerSlot(uint32 sofSlot)
|
||||
static inline uint32 SoFToServerCorpseSlot(uint32 sof_corpse_slot)
|
||||
{
|
||||
uint32 ServerSlot = 0;
|
||||
uint32 server_slot = EQEmu::invslot::SLOT_INVALID;
|
||||
|
||||
if (sofSlot >= invslot::slotAmmo && sofSlot <= invslot::CORPSE_END) // Cursor/Ammo/Power Source and Normal Inventory Slots
|
||||
ServerSlot = sofSlot - 1;
|
||||
else if (sofSlot >= invbag::GENERAL_BAGS_BEGIN && sofSlot <= invbag::CURSOR_BAG_END)
|
||||
ServerSlot = sofSlot - 11;
|
||||
else if (sofSlot >= invbag::BANK_BAGS_BEGIN && sofSlot <= invbag::BANK_BAGS_END)
|
||||
ServerSlot = sofSlot - 1;
|
||||
else if (sofSlot >= invbag::SHARED_BANK_BAGS_BEGIN && sofSlot <= invbag::SHARED_BANK_BAGS_END)
|
||||
ServerSlot = sofSlot - 1;
|
||||
else if (sofSlot == invslot::slotPowerSource)
|
||||
ServerSlot = EQEmu::invslot::SLOT_POWER_SOURCE;
|
||||
else
|
||||
ServerSlot = sofSlot;
|
||||
if (sof_corpse_slot <= invslot::slotGeneral8 && sof_corpse_slot >= invslot::slotGeneral1) {
|
||||
server_slot = sof_corpse_slot;
|
||||
}
|
||||
|
||||
return ServerSlot;
|
||||
else if (sof_corpse_slot <= invslot::CORPSE_END && sof_corpse_slot >= invslot::slotCursor) {
|
||||
server_slot = sof_corpse_slot + 2;
|
||||
}
|
||||
|
||||
Log(Logs::Detail,
|
||||
Logs::Netcode,
|
||||
"Convert SoF Corpse Slot %i to Server Corpse Slot %i",
|
||||
sof_corpse_slot,
|
||||
server_slot);
|
||||
|
||||
return server_slot;
|
||||
}
|
||||
|
||||
static inline uint32 SoFToServerCorpseSlot(uint32 sofCorpseSlot)
|
||||
static inline void ServerToSoFSayLink(std::string &sof_saylink, const std::string &server_saylink)
|
||||
{
|
||||
//uint32 ServerCorpse;
|
||||
return (sofCorpseSlot - 1);
|
||||
}
|
||||
|
||||
static inline void ServerToSoFSayLink(std::string& sofSayLink, const std::string& serverSayLink)
|
||||
{
|
||||
if ((constants::SAY_LINK_BODY_SIZE == EQEmu::constants::SAY_LINK_BODY_SIZE) || (serverSayLink.find('\x12') == std::string::npos)) {
|
||||
sofSayLink = serverSayLink;
|
||||
if ((constants::SAY_LINK_BODY_SIZE == EQEmu::constants::SAY_LINK_BODY_SIZE) || (server_saylink.find('\x12') == std::string::npos)) {
|
||||
sof_saylink = server_saylink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(serverSayLink, '\x12');
|
||||
auto segments = SplitString(server_saylink, '\x12');
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
if (segments[segment_iter].length() <= EQEmu::constants::SAY_LINK_BODY_SIZE) {
|
||||
sofSayLink.append(segments[segment_iter]);
|
||||
sof_saylink.append(segments[segment_iter]);
|
||||
// TODO: log size mismatch error
|
||||
continue;
|
||||
}
|
||||
@ -3228,37 +3365,37 @@ namespace SoF
|
||||
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
|
||||
// Diff: ^^^^^ ^
|
||||
|
||||
sofSayLink.push_back('\x12');
|
||||
sofSayLink.append(segments[segment_iter].substr(0, 31));
|
||||
sofSayLink.append(segments[segment_iter].substr(36, 5));
|
||||
sof_saylink.push_back('\x12');
|
||||
sof_saylink.append(segments[segment_iter].substr(0, 31));
|
||||
sof_saylink.append(segments[segment_iter].substr(36, 5));
|
||||
|
||||
if (segments[segment_iter][41] == '0')
|
||||
sofSayLink.push_back(segments[segment_iter][42]);
|
||||
sof_saylink.push_back(segments[segment_iter][42]);
|
||||
else
|
||||
sofSayLink.push_back('F');
|
||||
sof_saylink.push_back('F');
|
||||
|
||||
sofSayLink.append(segments[segment_iter].substr(43));
|
||||
sofSayLink.push_back('\x12');
|
||||
sof_saylink.append(segments[segment_iter].substr(43));
|
||||
sof_saylink.push_back('\x12');
|
||||
}
|
||||
else {
|
||||
sofSayLink.append(segments[segment_iter]);
|
||||
sof_saylink.append(segments[segment_iter]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void SoFToServerSayLink(std::string& serverSayLink, const std::string& sofSayLink)
|
||||
static inline void SoFToServerSayLink(std::string &server_saylink, const std::string &sof_saylink)
|
||||
{
|
||||
if ((EQEmu::constants::SAY_LINK_BODY_SIZE == constants::SAY_LINK_BODY_SIZE) || (sofSayLink.find('\x12') == std::string::npos)) {
|
||||
serverSayLink = sofSayLink;
|
||||
if ((EQEmu::constants::SAY_LINK_BODY_SIZE == constants::SAY_LINK_BODY_SIZE) || (sof_saylink.find('\x12') == std::string::npos)) {
|
||||
server_saylink = sof_saylink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(sofSayLink, '\x12');
|
||||
auto segments = SplitString(sof_saylink, '\x12');
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
if (segments[segment_iter].length() <= constants::SAY_LINK_BODY_SIZE) {
|
||||
serverSayLink.append(segments[segment_iter]);
|
||||
server_saylink.append(segments[segment_iter]);
|
||||
// TODO: log size mismatch error
|
||||
continue;
|
||||
}
|
||||
@ -3268,98 +3405,95 @@ namespace SoF
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// Diff: ^^^^^ ^
|
||||
|
||||
serverSayLink.push_back('\x12');
|
||||
serverSayLink.append(segments[segment_iter].substr(0, 31));
|
||||
serverSayLink.append("00000");
|
||||
serverSayLink.append(segments[segment_iter].substr(31, 5));
|
||||
serverSayLink.push_back('0');
|
||||
serverSayLink.append(segments[segment_iter].substr(36));
|
||||
serverSayLink.push_back('\x12');
|
||||
server_saylink.push_back('\x12');
|
||||
server_saylink.append(segments[segment_iter].substr(0, 31));
|
||||
server_saylink.append("00000");
|
||||
server_saylink.append(segments[segment_iter].substr(31, 5));
|
||||
server_saylink.push_back('0');
|
||||
server_saylink.append(segments[segment_iter].substr(36));
|
||||
server_saylink.push_back('\x12');
|
||||
}
|
||||
else {
|
||||
serverSayLink.append(segments[segment_iter]);
|
||||
server_saylink.append(segments[segment_iter]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline CastingSlot ServerToSoFCastingSlot(EQEmu::CastingSlot slot)
|
||||
{
|
||||
static inline CastingSlot ServerToSoFCastingSlot(EQEmu::CastingSlot slot) {
|
||||
switch (slot) {
|
||||
case EQEmu::CastingSlot::Gem1:
|
||||
return CastingSlot::Gem1;
|
||||
case EQEmu::CastingSlot::Gem2:
|
||||
return CastingSlot::Gem2;
|
||||
case EQEmu::CastingSlot::Gem3:
|
||||
return CastingSlot::Gem3;
|
||||
case EQEmu::CastingSlot::Gem4:
|
||||
return CastingSlot::Gem4;
|
||||
case EQEmu::CastingSlot::Gem5:
|
||||
return CastingSlot::Gem5;
|
||||
case EQEmu::CastingSlot::Gem6:
|
||||
return CastingSlot::Gem6;
|
||||
case EQEmu::CastingSlot::Gem7:
|
||||
return CastingSlot::Gem7;
|
||||
case EQEmu::CastingSlot::Gem8:
|
||||
return CastingSlot::Gem8;
|
||||
case EQEmu::CastingSlot::Gem9:
|
||||
return CastingSlot::Gem9;
|
||||
case EQEmu::CastingSlot::Item:
|
||||
return CastingSlot::Item;
|
||||
case EQEmu::CastingSlot::PotionBelt:
|
||||
return CastingSlot::PotionBelt;
|
||||
case EQEmu::CastingSlot::Discipline:
|
||||
return CastingSlot::Discipline;
|
||||
case EQEmu::CastingSlot::AltAbility:
|
||||
return CastingSlot::AltAbility;
|
||||
default: // we shouldn't have any issues with other slots ... just return something
|
||||
return CastingSlot::Discipline;
|
||||
case EQEmu::CastingSlot::Gem1:
|
||||
return CastingSlot::Gem1;
|
||||
case EQEmu::CastingSlot::Gem2:
|
||||
return CastingSlot::Gem2;
|
||||
case EQEmu::CastingSlot::Gem3:
|
||||
return CastingSlot::Gem3;
|
||||
case EQEmu::CastingSlot::Gem4:
|
||||
return CastingSlot::Gem4;
|
||||
case EQEmu::CastingSlot::Gem5:
|
||||
return CastingSlot::Gem5;
|
||||
case EQEmu::CastingSlot::Gem6:
|
||||
return CastingSlot::Gem6;
|
||||
case EQEmu::CastingSlot::Gem7:
|
||||
return CastingSlot::Gem7;
|
||||
case EQEmu::CastingSlot::Gem8:
|
||||
return CastingSlot::Gem8;
|
||||
case EQEmu::CastingSlot::Gem9:
|
||||
return CastingSlot::Gem9;
|
||||
case EQEmu::CastingSlot::Item:
|
||||
return CastingSlot::Item;
|
||||
case EQEmu::CastingSlot::PotionBelt:
|
||||
return CastingSlot::PotionBelt;
|
||||
case EQEmu::CastingSlot::Discipline:
|
||||
return CastingSlot::Discipline;
|
||||
case EQEmu::CastingSlot::AltAbility:
|
||||
return CastingSlot::AltAbility;
|
||||
default: // we shouldn't have any issues with other slots ... just return something
|
||||
return CastingSlot::Discipline;
|
||||
}
|
||||
}
|
||||
|
||||
static inline EQEmu::CastingSlot SoFToServerCastingSlot(CastingSlot slot, uint32 itemlocation)
|
||||
{
|
||||
static inline EQEmu::CastingSlot SoFToServerCastingSlot(CastingSlot slot, uint32 item_location) {
|
||||
switch (slot) {
|
||||
case CastingSlot::Gem1:
|
||||
return EQEmu::CastingSlot::Gem1;
|
||||
case CastingSlot::Gem2:
|
||||
return EQEmu::CastingSlot::Gem2;
|
||||
case CastingSlot::Gem3:
|
||||
return EQEmu::CastingSlot::Gem3;
|
||||
case CastingSlot::Gem4:
|
||||
return EQEmu::CastingSlot::Gem4;
|
||||
case CastingSlot::Gem5:
|
||||
return EQEmu::CastingSlot::Gem5;
|
||||
case CastingSlot::Gem6:
|
||||
return EQEmu::CastingSlot::Gem6;
|
||||
case CastingSlot::Gem7:
|
||||
return EQEmu::CastingSlot::Gem7;
|
||||
case CastingSlot::Gem8:
|
||||
return EQEmu::CastingSlot::Gem8;
|
||||
case CastingSlot::Gem9:
|
||||
return EQEmu::CastingSlot::Gem9;
|
||||
case CastingSlot::Ability:
|
||||
return EQEmu::CastingSlot::Ability;
|
||||
// Tit uses 10 for item and discipline casting, but items have a valid location
|
||||
case CastingSlot::Item:
|
||||
if (itemlocation == INVALID_INDEX)
|
||||
case CastingSlot::Gem1:
|
||||
return EQEmu::CastingSlot::Gem1;
|
||||
case CastingSlot::Gem2:
|
||||
return EQEmu::CastingSlot::Gem2;
|
||||
case CastingSlot::Gem3:
|
||||
return EQEmu::CastingSlot::Gem3;
|
||||
case CastingSlot::Gem4:
|
||||
return EQEmu::CastingSlot::Gem4;
|
||||
case CastingSlot::Gem5:
|
||||
return EQEmu::CastingSlot::Gem5;
|
||||
case CastingSlot::Gem6:
|
||||
return EQEmu::CastingSlot::Gem6;
|
||||
case CastingSlot::Gem7:
|
||||
return EQEmu::CastingSlot::Gem7;
|
||||
case CastingSlot::Gem8:
|
||||
return EQEmu::CastingSlot::Gem8;
|
||||
case CastingSlot::Gem9:
|
||||
return EQEmu::CastingSlot::Gem9;
|
||||
case CastingSlot::Ability:
|
||||
return EQEmu::CastingSlot::Ability;
|
||||
// Tit uses 10 for item and discipline casting, but items have a valid location
|
||||
case CastingSlot::Item:
|
||||
if (item_location == INVALID_INDEX)
|
||||
return EQEmu::CastingSlot::Discipline;
|
||||
else
|
||||
return EQEmu::CastingSlot::Item;
|
||||
case CastingSlot::PotionBelt:
|
||||
return EQEmu::CastingSlot::PotionBelt;
|
||||
case CastingSlot::AltAbility:
|
||||
return EQEmu::CastingSlot::AltAbility;
|
||||
default: // we shouldn't have any issues with other slots ... just return something
|
||||
return EQEmu::CastingSlot::Discipline;
|
||||
else
|
||||
return EQEmu::CastingSlot::Item;
|
||||
case CastingSlot::PotionBelt:
|
||||
return EQEmu::CastingSlot::PotionBelt;
|
||||
case CastingSlot::AltAbility:
|
||||
return EQEmu::CastingSlot::AltAbility;
|
||||
default: // we shouldn't have any issues with other slots ... just return something
|
||||
return EQEmu::CastingSlot::Discipline;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int ServerToSoFBuffSlot(int index)
|
||||
{
|
||||
static inline int ServerToSoFBuffSlot(int index) {
|
||||
// we're a disc
|
||||
if (index >= EQEmu::constants::LongBuffs + EQEmu::constants::ShortBuffs)
|
||||
return index - EQEmu::constants::LongBuffs - EQEmu::constants::ShortBuffs +
|
||||
constants::LongBuffs + constants::ShortBuffs;
|
||||
constants::LongBuffs + constants::ShortBuffs;
|
||||
// we're a song
|
||||
if (index >= EQEmu::constants::LongBuffs)
|
||||
return index - EQEmu::constants::LongBuffs + constants::LongBuffs;
|
||||
@ -3379,4 +3513,4 @@ namespace SoF
|
||||
// we're a normal buff
|
||||
return index; // as long as we guard against bad slots server side, we should be fine
|
||||
}
|
||||
} /*SoF*/
|
||||
}
|
||||
|
||||
@ -150,6 +150,8 @@ namespace SoF
|
||||
const int16 SLOT_INVALID = IINVALID;
|
||||
const int16 SLOT_BEGIN = INULL;
|
||||
|
||||
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
|
||||
|
||||
const int16 POSSESSIONS_BEGIN = slotCharm;
|
||||
const int16 POSSESSIONS_END = slotCursor;
|
||||
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
|
||||
|
||||
@ -45,21 +45,21 @@ namespace Titanium
|
||||
void SerializeItem(EQEmu::OutBuffer& ob, const EQEmu::ItemInstance *inst, int16 slot_id_in, uint8 depth);
|
||||
|
||||
// server to client inventory location converters
|
||||
static inline int16 ServerToTitaniumSlot(uint32 serverSlot);
|
||||
static inline int16 ServerToTitaniumCorpseSlot(uint32 serverCorpseSlot);
|
||||
static inline int16 ServerToTitaniumSlot(uint32 server_slot);
|
||||
static inline int16 ServerToTitaniumCorpseSlot(uint32 server_corpse_slot);
|
||||
|
||||
// client to server inventory location converters
|
||||
static inline uint32 TitaniumToServerSlot(int16 titaniumSlot);
|
||||
static inline uint32 TitaniumToServerCorpseSlot(int16 titaniumCorpseSlot);
|
||||
static inline uint32 TitaniumToServerSlot(int16 titanium_slot);
|
||||
static inline uint32 TitaniumToServerCorpseSlot(int16 titanium_corpse_slot);
|
||||
|
||||
// server to client say link converter
|
||||
static inline void ServerToTitaniumSayLink(std::string& titaniumSayLink, const std::string& serverSayLink);
|
||||
static inline void ServerToTitaniumSayLink(std::string &titanium_saylink, const std::string &server_saylink);
|
||||
|
||||
// client to server say link converter
|
||||
static inline void TitaniumToServerSayLink(std::string& serverSayLink, const std::string& titaniumSayLink);
|
||||
static inline void TitaniumToServerSayLink(std::string &server_saylink, const std::string &titanium_saylink);
|
||||
|
||||
static inline CastingSlot ServerToTitaniumCastingSlot(EQEmu::CastingSlot slot);
|
||||
static inline EQEmu::CastingSlot TitaniumToServerCastingSlot(CastingSlot slot, uint32 itemlocation);
|
||||
static inline EQEmu::CastingSlot TitaniumToServerCastingSlot(CastingSlot slot, uint32 item_location);
|
||||
|
||||
static inline int ServerToTitaniumBuffSlot(int index);
|
||||
static inline int TitaniumToServerBuffSlot(int index);
|
||||
@ -335,9 +335,9 @@ namespace Titanium
|
||||
EQEmu::OutBuffer::pos_type last_pos = ob.tellp();
|
||||
|
||||
for (int r = 0; r < itemcount; r++, eq++) {
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)eq->inst, eq->slot_id, 0);
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)eq->inst, ServerToTitaniumSlot(eq->slot_id), 0);
|
||||
if (ob.tellp() == last_pos)
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
Log(Logs::General, Logs::Netcode, "Titanium::ENCODE(OP_CharInventory) Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
@ -367,7 +367,12 @@ namespace Titanium
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DeleteCharge) { ENCODE_FORWARD(OP_MoveItem); }
|
||||
ENCODE(OP_DeleteCharge)
|
||||
{
|
||||
Log(Logs::Moderate, Logs::Netcode, "Titanium::ENCODE(OP_DeleteCharge)");
|
||||
|
||||
ENCODE_FORWARD(OP_MoveItem);
|
||||
}
|
||||
|
||||
ENCODE(OP_DeleteItem)
|
||||
{
|
||||
@ -772,21 +777,15 @@ namespace Titanium
|
||||
OUT(TargetID);
|
||||
OUT(playerid);
|
||||
|
||||
int r;
|
||||
for (r = 0; r <= 20; r++) {
|
||||
strn0cpy(eq->itemnames[r], emu->itemnames[r], sizeof(eq->itemnames[r]));
|
||||
for (int i = EQEmu::invslot::slotCharm; i <= EQEmu::invslot::slotWaist; ++i) {
|
||||
strn0cpy(eq->itemnames[i], emu->itemnames[i], sizeof(eq->itemnames[i]));
|
||||
OUT(itemicons[i]);
|
||||
}
|
||||
|
||||
// move arrow item down to last element in titanium array
|
||||
strn0cpy(eq->itemnames[21], emu->itemnames[22], sizeof(eq->itemnames[21]));
|
||||
// move ammo down to last element in titanium array
|
||||
strn0cpy(eq->itemnames[invslot::slotAmmo], emu->itemnames[EQEmu::invslot::slotAmmo], sizeof(eq->itemnames[invslot::slotAmmo]));
|
||||
eq->itemicons[invslot::slotAmmo] = emu->itemicons[EQEmu::invslot::slotAmmo];
|
||||
|
||||
int k;
|
||||
for (k = 0; k <= 20; k++) {
|
||||
OUT(itemicons[k]);
|
||||
}
|
||||
|
||||
// move arrow icon down to last element in titanium array
|
||||
eq->itemicons[21] = emu->itemicons[22];
|
||||
strn0cpy(eq->text, emu->text, sizeof(eq->text));
|
||||
|
||||
FINISH_ENCODE();
|
||||
@ -821,9 +820,9 @@ namespace Titanium
|
||||
|
||||
ob.write((const char*)__emu_buffer, 4);
|
||||
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)int_struct->inst, int_struct->slot_id, 0);
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)int_struct->inst, ServerToTitaniumSlot(int_struct->slot_id), 0);
|
||||
if (ob.tellp() == last_pos) {
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
Log(Logs::General, Logs::Netcode, "Titanium::ENCODE(OP_ItemPacket) Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -874,6 +873,8 @@ namespace Titanium
|
||||
ENCODE_LENGTH_EXACT(LootingItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "Titanium::ENCODE(OP_LootItem)");
|
||||
|
||||
OUT(lootee);
|
||||
OUT(looter);
|
||||
eq->slot_id = ServerToTitaniumCorpseSlot(emu->slot_id);
|
||||
@ -903,6 +904,8 @@ namespace Titanium
|
||||
ENCODE_LENGTH_EXACT(MoveItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "Titanium::ENCODE(OP_MoveItem)");
|
||||
|
||||
eq->from_slot = ServerToTitaniumSlot(emu->from_slot);
|
||||
eq->to_slot = ServerToTitaniumSlot(emu->to_slot);
|
||||
OUT(number_in_stack);
|
||||
@ -1050,7 +1053,7 @@ namespace Titanium
|
||||
|
||||
// OUT(unknown06160[4]);
|
||||
|
||||
// Copy bandoliers where server and client indexes converge
|
||||
// Copy bandoliers where server and client indices converge
|
||||
for (r = 0; r < EQEmu::profile::BANDOLIERS_SIZE && r < profile::BANDOLIERS_SIZE; ++r) {
|
||||
OUT_str(bandoliers[r].Name);
|
||||
for (uint32 k = 0; k < profile::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||
@ -1059,7 +1062,7 @@ namespace Titanium
|
||||
OUT_str(bandoliers[r].Items[k].Name);
|
||||
}
|
||||
}
|
||||
// Nullify bandoliers where server and client indexes diverge, with a client bias
|
||||
// Nullify bandoliers where server and client indices diverge, with a client bias
|
||||
for (r = EQEmu::profile::BANDOLIERS_SIZE; r < profile::BANDOLIERS_SIZE; ++r) {
|
||||
eq->bandoliers[r].Name[0] = '\0';
|
||||
for (uint32 k = 0; k < profile::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||
@ -1071,13 +1074,13 @@ namespace Titanium
|
||||
|
||||
// OUT(unknown07444[5120]);
|
||||
|
||||
// Copy potion belt where server and client indexes converge
|
||||
// Copy potion belt where server and client indices converge
|
||||
for (r = 0; r < EQEmu::profile::POTION_BELT_SIZE && r < profile::POTION_BELT_SIZE; ++r) {
|
||||
OUT(potionbelt.Items[r].ID);
|
||||
OUT(potionbelt.Items[r].Icon);
|
||||
OUT_str(potionbelt.Items[r].Name);
|
||||
}
|
||||
// Nullify potion belt where server and client indexes diverge, with a client bias
|
||||
// Nullify potion belt where server and client indices diverge, with a client bias
|
||||
for (r = EQEmu::profile::POTION_BELT_SIZE; r < profile::POTION_BELT_SIZE; ++r) {
|
||||
eq->potionbelt.Items[r].ID = 0;
|
||||
eq->potionbelt.Items[r].Icon = 0;
|
||||
@ -1936,23 +1939,18 @@ namespace Titanium
|
||||
IN(TargetID);
|
||||
IN(playerid);
|
||||
|
||||
int r;
|
||||
for (r = 0; r <= 20; r++) {
|
||||
strn0cpy(emu->itemnames[r], eq->itemnames[r], sizeof(emu->itemnames[r]));
|
||||
for (int i = invslot::slotCharm; i <= invslot::slotWaist; ++i) {
|
||||
strn0cpy(emu->itemnames[i], eq->itemnames[i], sizeof(emu->itemnames[i]));
|
||||
IN(itemicons[i]);
|
||||
}
|
||||
|
||||
// move arrow item up to last element in server array
|
||||
strn0cpy(emu->itemnames[21], "", sizeof(emu->itemnames[21]));
|
||||
strn0cpy(emu->itemnames[22], eq->itemnames[21], sizeof(emu->itemnames[22]));
|
||||
// move ammo up to last element in server array
|
||||
strn0cpy(emu->itemnames[EQEmu::invslot::slotAmmo], eq->itemnames[invslot::slotAmmo], sizeof(emu->itemnames[EQEmu::invslot::slotAmmo]));
|
||||
emu->itemicons[EQEmu::invslot::slotAmmo] = eq->itemicons[invslot::slotAmmo];
|
||||
|
||||
int k;
|
||||
for (k = 0; k <= 20; k++) {
|
||||
IN(itemicons[k]);
|
||||
}
|
||||
|
||||
// move arrow icon up to last element in server array
|
||||
emu->itemicons[21] = 0xFFFFFFFF;
|
||||
emu->itemicons[22] = eq->itemicons[21];
|
||||
// nullify power source element in server array
|
||||
strn0cpy(emu->itemnames[EQEmu::invslot::slotPowerSource], "", sizeof(emu->itemnames[EQEmu::invslot::slotPowerSource]));
|
||||
emu->itemicons[EQEmu::invslot::slotPowerSource] = 0xFFFFFFFF;
|
||||
|
||||
strn0cpy(emu->text, eq->text, sizeof(emu->text));
|
||||
|
||||
@ -2020,6 +2018,8 @@ namespace Titanium
|
||||
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
|
||||
SETUP_DIRECT_DECODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "Titanium::DECODE(OP_LootItem)");
|
||||
|
||||
IN(lootee);
|
||||
IN(looter);
|
||||
emu->slot_id = TitaniumToServerCorpseSlot(eq->slot_id);
|
||||
@ -2033,7 +2033,7 @@ namespace Titanium
|
||||
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
|
||||
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[Titanium] Moved item from %u to %u", eq->from_slot, eq->to_slot);
|
||||
Log(Logs::Moderate, Logs::Netcode, "Titanium::DECODE(OP_MoveItem)");
|
||||
|
||||
emu->from_slot = TitaniumToServerSlot(eq->from_slot);
|
||||
emu->to_slot = TitaniumToServerSlot(eq->to_slot);
|
||||
@ -2225,13 +2225,16 @@ namespace Titanium
|
||||
}
|
||||
|
||||
// file scope helper methods
|
||||
void SerializeItem(EQEmu::OutBuffer& ob, const EQEmu::ItemInstance *inst, int16 slot_id_in, uint8 depth)
|
||||
{
|
||||
const char* protection = "\\\\\\\\\\";
|
||||
const EQEmu::ItemData* item = inst->GetUnscaledItem();
|
||||
void SerializeItem(EQEmu::OutBuffer& ob, const EQEmu::ItemInstance *inst, int16 slot_id_in, uint8 depth) {
|
||||
const char *protection = "\\\\\\\\\\";
|
||||
const EQEmu::ItemData *item = inst->GetUnscaledItem();
|
||||
|
||||
ob << StringFormat(
|
||||
"%.*s%s",
|
||||
(depth ? (depth - 1) : 0),
|
||||
protection,
|
||||
(depth ? "\"" : "")); // For leading quotes (and protection) if a subitem;
|
||||
|
||||
ob << StringFormat("%.*s%s", (depth ? (depth - 1) : 0), protection, (depth ? "\"" : "")); // For leading quotes (and protection) if a subitem;
|
||||
|
||||
// Instance data
|
||||
ob << itoa((inst->IsStackable() ? inst->GetCharges() : 0)); // stack count
|
||||
ob << '|' << itoa(0); // unknown
|
||||
@ -2239,9 +2242,11 @@ namespace Titanium
|
||||
ob << '|' << itoa(inst->GetPrice()); // merchant price
|
||||
ob << '|' << itoa((!inst->GetMerchantSlot() ? 1 : inst->GetMerchantCount())); // inst count/merchant count
|
||||
ob << '|' << itoa((inst->IsScaling() ? (inst->GetExp() / 100) : 0)); // inst experience
|
||||
ob << '|' << itoa((!inst->GetMerchantSlot() ? inst->GetSerialNumber() : inst->GetMerchantSlot())); // merchant serial number
|
||||
ob << '|' << itoa((!inst->GetMerchantSlot() ? inst->GetSerialNumber()
|
||||
: inst->GetMerchantSlot())); // merchant serial number
|
||||
ob << '|' << itoa(inst->GetRecastTimestamp()); // recast timestamp
|
||||
ob << '|' << itoa(((inst->IsStackable() ? ((inst->GetItem()->ItemType == EQEmu::item::ItemTypePotion) ? 1 : 0) : inst->GetCharges()))); // charge count
|
||||
ob << '|' << itoa(((inst->IsStackable() ? ((inst->GetItem()->ItemType == EQEmu::item::ItemTypePotion) ? 1 : 0)
|
||||
: inst->GetCharges()))); // charge count
|
||||
ob << '|' << itoa((inst->IsAttuned() ? 1 : 0)); // inst attuned
|
||||
ob << '|' << itoa(0); // unknown
|
||||
ob << '|';
|
||||
@ -2259,7 +2264,7 @@ namespace Titanium
|
||||
ob << '|' << itoa(item->NoRent);
|
||||
ob << '|' << itoa(item->NoDrop);
|
||||
ob << '|' << itoa(item->Size);
|
||||
ob << '|' << itoa(item->Slots);
|
||||
ob << '|' << itoa(Catch22(SwapBits21And22(item->Slots)));
|
||||
ob << '|' << itoa(item->Price);
|
||||
ob << '|' << itoa(item->Icon);
|
||||
ob << '|' << "0";
|
||||
@ -2449,62 +2454,208 @@ namespace Titanium
|
||||
for (int index = EQEmu::invbag::SLOT_BEGIN; index <= invbag::SLOT_END; ++index) {
|
||||
ob << '|';
|
||||
|
||||
EQEmu::ItemInstance* sub = inst->GetItem(index);
|
||||
EQEmu::ItemInstance *sub = inst->GetItem(index);
|
||||
if (!sub)
|
||||
continue;
|
||||
|
||||
|
||||
SerializeItem(ob, sub, 0, (depth + 1));
|
||||
}
|
||||
|
||||
ob << StringFormat("%.*s%s", (depth ? (depth - 1) : 0), protection, (depth ? "\"" : "")); // For trailing quotes (and protection) if a subitem;
|
||||
ob << StringFormat(
|
||||
"%.*s%s",
|
||||
(depth ? (depth - 1) : 0),
|
||||
protection,
|
||||
(depth ? "\"" : "")); // For trailing quotes (and protection) if a subitem;
|
||||
|
||||
if (!depth)
|
||||
ob.write("\0", 1);
|
||||
}
|
||||
|
||||
static inline int16 ServerToTitaniumSlot(uint32 serverSlot)
|
||||
{
|
||||
//int16 TitaniumSlot;
|
||||
if (serverSlot == INVALID_INDEX)
|
||||
return INVALID_INDEX;
|
||||
static inline int16 ServerToTitaniumSlot(uint32 server_slot) {
|
||||
int16 titanium_slot = invslot::SLOT_INVALID;
|
||||
|
||||
return serverSlot; // deprecated
|
||||
if (server_slot <= EQEmu::invslot::slotWaist) {
|
||||
titanium_slot = server_slot;
|
||||
}
|
||||
else if (server_slot == EQEmu::invslot::slotAmmo) {
|
||||
titanium_slot = server_slot - 1;
|
||||
}
|
||||
else if (server_slot <= EQEmu::invslot::slotGeneral8 && server_slot >= EQEmu::invslot::slotGeneral1) {
|
||||
titanium_slot = server_slot - 1;
|
||||
}
|
||||
else if (server_slot <= (EQEmu::invslot::POSSESSIONS_COUNT + EQEmu::invslot::slotWaist) &&
|
||||
server_slot >= EQEmu::invslot::slotCursor) {
|
||||
titanium_slot = server_slot - 3;
|
||||
}
|
||||
else if (server_slot == (EQEmu::invslot::POSSESSIONS_COUNT + EQEmu::invslot::slotAmmo)) {
|
||||
titanium_slot = server_slot - 4;
|
||||
}
|
||||
else if (server_slot <= EQEmu::invbag::GENERAL_BAGS_8_END &&
|
||||
server_slot >= EQEmu::invbag::GENERAL_BAGS_BEGIN) {
|
||||
titanium_slot = server_slot;
|
||||
}
|
||||
else if (server_slot <= EQEmu::invbag::CURSOR_BAG_END && server_slot >= EQEmu::invbag::CURSOR_BAG_BEGIN) {
|
||||
titanium_slot = server_slot - 20;
|
||||
}
|
||||
else if (server_slot <= EQEmu::invslot::TRIBUTE_END && server_slot >= EQEmu::invslot::TRIBUTE_BEGIN) {
|
||||
titanium_slot = server_slot;
|
||||
}
|
||||
else if (server_slot <= EQEmu::invslot::GUILD_TRIBUTE_END &&
|
||||
server_slot >= EQEmu::invslot::GUILD_TRIBUTE_BEGIN) {
|
||||
titanium_slot = server_slot;
|
||||
}
|
||||
else if (server_slot == EQEmu::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE) {
|
||||
titanium_slot = server_slot;
|
||||
}
|
||||
else if (server_slot <= EQEmu::invslot::BANK_END && server_slot >= EQEmu::invslot::BANK_BEGIN) {
|
||||
titanium_slot = server_slot;
|
||||
}
|
||||
else if (server_slot <= EQEmu::invbag::BANK_BAGS_16_END && server_slot >= EQEmu::invbag::BANK_BAGS_BEGIN) {
|
||||
titanium_slot = server_slot;
|
||||
}
|
||||
else if (server_slot <= EQEmu::invslot::SHARED_BANK_END && server_slot >= EQEmu::invslot::SHARED_BANK_BEGIN) {
|
||||
titanium_slot = server_slot;
|
||||
}
|
||||
else if (server_slot <= EQEmu::invbag::SHARED_BANK_BAGS_END &&
|
||||
server_slot >= EQEmu::invbag::SHARED_BANK_BAGS_BEGIN) {
|
||||
titanium_slot = server_slot;
|
||||
}
|
||||
else if (server_slot <= EQEmu::invslot::TRADE_END && server_slot >= EQEmu::invslot::TRADE_BEGIN) {
|
||||
titanium_slot = server_slot;
|
||||
}
|
||||
else if (server_slot <= EQEmu::invbag::TRADE_BAGS_END && server_slot >= EQEmu::invbag::TRADE_BAGS_BEGIN) {
|
||||
titanium_slot = server_slot;
|
||||
}
|
||||
else if (server_slot <= EQEmu::invslot::WORLD_END && server_slot >= EQEmu::invslot::WORLD_BEGIN) {
|
||||
titanium_slot = server_slot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Slot %i to Titanium Slot %i", server_slot, titanium_slot);
|
||||
|
||||
return titanium_slot;
|
||||
}
|
||||
|
||||
static inline int16 ServerToTitaniumCorpseSlot(uint32 serverCorpseSlot)
|
||||
{
|
||||
//int16 TitaniumCorpse;
|
||||
return serverCorpseSlot;
|
||||
|
||||
static inline int16 ServerToTitaniumCorpseSlot(uint32 server_corpse_slot) {
|
||||
int16 titanium_slot = invslot::SLOT_INVALID;
|
||||
|
||||
if (server_corpse_slot <= EQEmu::invslot::slotGeneral8 && server_corpse_slot >= EQEmu::invslot::slotGeneral1) {
|
||||
titanium_slot = server_corpse_slot - 1;
|
||||
}
|
||||
|
||||
else if (server_corpse_slot <= (EQEmu::invslot::POSSESSIONS_COUNT + EQEmu::invslot::slotWaist) &&
|
||||
server_corpse_slot >= EQEmu::invslot::slotCursor) {
|
||||
titanium_slot = server_corpse_slot - 3;
|
||||
}
|
||||
|
||||
else if (server_corpse_slot == (EQEmu::invslot::POSSESSIONS_COUNT + EQEmu::invslot::slotAmmo)) {
|
||||
titanium_slot = server_corpse_slot - 4;
|
||||
}
|
||||
|
||||
Log(Logs::Detail,
|
||||
Logs::Netcode,
|
||||
"Convert Server Corpse Slot %i to Titanium Corpse Slot %i",
|
||||
server_corpse_slot,
|
||||
titanium_slot);
|
||||
|
||||
return titanium_slot;
|
||||
}
|
||||
|
||||
static inline uint32 TitaniumToServerSlot(int16 titaniumSlot)
|
||||
{
|
||||
//uint32 ServerSlot;
|
||||
if (titaniumSlot == INVALID_INDEX)
|
||||
return INVALID_INDEX;
|
||||
static inline uint32 TitaniumToServerSlot(int16 titanium_slot) {
|
||||
uint32 server_slot = EQEmu::invslot::SLOT_INVALID;
|
||||
|
||||
return titaniumSlot; // deprecated
|
||||
if (titanium_slot <= invslot::slotWaist) {
|
||||
server_slot = titanium_slot;
|
||||
}
|
||||
else if (titanium_slot == invslot::slotAmmo) {
|
||||
server_slot = titanium_slot + 1;
|
||||
}
|
||||
else if (titanium_slot <= invslot::slotGeneral8 && titanium_slot >= invslot::slotGeneral1) {
|
||||
server_slot = titanium_slot + 1;
|
||||
}
|
||||
else if (titanium_slot <= (invslot::POSSESSIONS_COUNT + invslot::slotWaist) &&
|
||||
titanium_slot >= invslot::slotCursor) {
|
||||
server_slot = titanium_slot + 3;
|
||||
}
|
||||
else if (titanium_slot == (invslot::POSSESSIONS_COUNT + invslot::slotAmmo)) {
|
||||
server_slot = titanium_slot + 4;
|
||||
}
|
||||
else if (titanium_slot <= invbag::GENERAL_BAGS_END && titanium_slot >= invbag::GENERAL_BAGS_BEGIN) {
|
||||
server_slot = titanium_slot;
|
||||
}
|
||||
else if (titanium_slot <= invbag::CURSOR_BAG_END && titanium_slot >= invbag::CURSOR_BAG_BEGIN) {
|
||||
server_slot = titanium_slot + 20;
|
||||
}
|
||||
else if (titanium_slot <= invslot::TRIBUTE_END && titanium_slot >= invslot::TRIBUTE_BEGIN) {
|
||||
server_slot = titanium_slot;
|
||||
}
|
||||
else if (titanium_slot == invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE) {
|
||||
server_slot = titanium_slot;
|
||||
}
|
||||
else if (titanium_slot <= invslot::GUILD_TRIBUTE_END && titanium_slot >= invslot::GUILD_TRIBUTE_BEGIN) {
|
||||
server_slot = titanium_slot;
|
||||
}
|
||||
else if (titanium_slot <= invslot::BANK_END && titanium_slot >= invslot::BANK_BEGIN) {
|
||||
server_slot = titanium_slot;
|
||||
}
|
||||
else if (titanium_slot <= invbag::BANK_BAGS_END && titanium_slot >= invbag::BANK_BAGS_BEGIN) {
|
||||
server_slot = titanium_slot;
|
||||
}
|
||||
else if (titanium_slot <= invslot::SHARED_BANK_END && titanium_slot >= invslot::SHARED_BANK_BEGIN) {
|
||||
server_slot = titanium_slot;
|
||||
}
|
||||
else if (titanium_slot <= invbag::SHARED_BANK_BAGS_END && titanium_slot >= invbag::SHARED_BANK_BAGS_BEGIN) {
|
||||
server_slot = titanium_slot;
|
||||
}
|
||||
else if (titanium_slot <= invslot::TRADE_END && titanium_slot >= invslot::TRADE_BEGIN) {
|
||||
server_slot = titanium_slot;
|
||||
}
|
||||
else if (titanium_slot <= invbag::TRADE_BAGS_END && titanium_slot >= invbag::TRADE_BAGS_BEGIN) {
|
||||
server_slot = titanium_slot;
|
||||
}
|
||||
else if (titanium_slot <= invslot::WORLD_END && titanium_slot >= invslot::WORLD_BEGIN) {
|
||||
server_slot = titanium_slot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Titanium Slot %i to Server Slot %i", titanium_slot, server_slot);
|
||||
|
||||
return server_slot;
|
||||
}
|
||||
|
||||
static inline uint32 TitaniumToServerCorpseSlot(int16 titaniumCorpseSlot)
|
||||
static inline uint32 TitaniumToServerCorpseSlot(int16 titanium_corpse_slot)
|
||||
{
|
||||
//uint32 ServerCorpse;
|
||||
return titaniumCorpseSlot;
|
||||
uint32 server_slot = EQEmu::invslot::SLOT_INVALID;
|
||||
|
||||
if (titanium_corpse_slot <= invslot::slotGeneral8 && titanium_corpse_slot >= invslot::slotGeneral1) {
|
||||
server_slot = titanium_corpse_slot + 1;
|
||||
}
|
||||
|
||||
else if (titanium_corpse_slot <= (invslot::POSSESSIONS_COUNT + invslot::slotWaist) && titanium_corpse_slot >= invslot::slotCursor) {
|
||||
server_slot = titanium_corpse_slot + 3;
|
||||
}
|
||||
|
||||
else if (titanium_corpse_slot == (invslot::POSSESSIONS_COUNT + invslot::slotAmmo)) {
|
||||
server_slot = titanium_corpse_slot + 4;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Titanium Corpse Slot %i to Server Corpse Slot %i", titanium_corpse_slot, server_slot);
|
||||
|
||||
return server_slot;
|
||||
}
|
||||
|
||||
static inline void ServerToTitaniumSayLink(std::string& titaniumSayLink, const std::string& serverSayLink)
|
||||
static inline void ServerToTitaniumSayLink(std::string &titanium_saylink, const std::string &server_saylink)
|
||||
{
|
||||
if ((constants::SAY_LINK_BODY_SIZE == EQEmu::constants::SAY_LINK_BODY_SIZE) || (serverSayLink.find('\x12') == std::string::npos)) {
|
||||
titaniumSayLink = serverSayLink;
|
||||
if ((constants::SAY_LINK_BODY_SIZE == EQEmu::constants::SAY_LINK_BODY_SIZE) || (server_saylink.find('\x12') == std::string::npos)) {
|
||||
titanium_saylink = server_saylink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(serverSayLink, '\x12');
|
||||
auto segments = SplitString(server_saylink, '\x12');
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
if (segments[segment_iter].length() <= EQEmu::constants::SAY_LINK_BODY_SIZE) {
|
||||
titaniumSayLink.append(segments[segment_iter]);
|
||||
titanium_saylink.append(segments[segment_iter]);
|
||||
// TODO: log size mismatch error
|
||||
continue;
|
||||
}
|
||||
@ -2514,37 +2665,37 @@ namespace Titanium
|
||||
// 6.2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXXXXX (45)
|
||||
// Diff: ^^^^^ ^ ^^^^^
|
||||
|
||||
titaniumSayLink.push_back('\x12');
|
||||
titaniumSayLink.append(segments[segment_iter].substr(0, 31));
|
||||
titaniumSayLink.append(segments[segment_iter].substr(36, 5));
|
||||
titanium_saylink.push_back('\x12');
|
||||
titanium_saylink.append(segments[segment_iter].substr(0, 31));
|
||||
titanium_saylink.append(segments[segment_iter].substr(36, 5));
|
||||
|
||||
if (segments[segment_iter][41] == '0')
|
||||
titaniumSayLink.push_back(segments[segment_iter][42]);
|
||||
titanium_saylink.push_back(segments[segment_iter][42]);
|
||||
else
|
||||
titaniumSayLink.push_back('F');
|
||||
titanium_saylink.push_back('F');
|
||||
|
||||
titaniumSayLink.append(segments[segment_iter].substr(48));
|
||||
titaniumSayLink.push_back('\x12');
|
||||
titanium_saylink.append(segments[segment_iter].substr(48));
|
||||
titanium_saylink.push_back('\x12');
|
||||
}
|
||||
else {
|
||||
titaniumSayLink.append(segments[segment_iter]);
|
||||
titanium_saylink.append(segments[segment_iter]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void TitaniumToServerSayLink(std::string& serverSayLink, const std::string& titaniumSayLink)
|
||||
static inline void TitaniumToServerSayLink(std::string &server_saylink, const std::string &titanium_saylink)
|
||||
{
|
||||
if ((EQEmu::constants::SAY_LINK_BODY_SIZE == constants::SAY_LINK_BODY_SIZE) || (titaniumSayLink.find('\x12') == std::string::npos)) {
|
||||
serverSayLink = titaniumSayLink;
|
||||
if ((EQEmu::constants::SAY_LINK_BODY_SIZE == constants::SAY_LINK_BODY_SIZE) || (titanium_saylink.find('\x12') == std::string::npos)) {
|
||||
server_saylink = titanium_saylink;
|
||||
return;
|
||||
}
|
||||
|
||||
auto segments = SplitString(titaniumSayLink, '\x12');
|
||||
auto segments = SplitString(titanium_saylink, '\x12');
|
||||
|
||||
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
||||
if (segment_iter & 1) {
|
||||
if (segments[segment_iter].length() <= constants::SAY_LINK_BODY_SIZE) {
|
||||
serverSayLink.append(segments[segment_iter]);
|
||||
server_saylink.append(segments[segment_iter]);
|
||||
// TODO: log size mismatch error
|
||||
continue;
|
||||
}
|
||||
@ -2554,91 +2705,89 @@ namespace Titanium
|
||||
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
||||
// Diff: ^^^^^ ^ ^^^^^
|
||||
|
||||
serverSayLink.push_back('\x12');
|
||||
serverSayLink.append(segments[segment_iter].substr(0, 31));
|
||||
serverSayLink.append("00000");
|
||||
serverSayLink.append(segments[segment_iter].substr(31, 5));
|
||||
serverSayLink.push_back('0');
|
||||
serverSayLink.push_back(segments[segment_iter][36]);
|
||||
serverSayLink.append("00000");
|
||||
serverSayLink.append(segments[segment_iter].substr(37));
|
||||
serverSayLink.push_back('\x12');
|
||||
server_saylink.push_back('\x12');
|
||||
server_saylink.append(segments[segment_iter].substr(0, 31));
|
||||
server_saylink.append("00000");
|
||||
server_saylink.append(segments[segment_iter].substr(31, 5));
|
||||
server_saylink.push_back('0');
|
||||
server_saylink.push_back(segments[segment_iter][36]);
|
||||
server_saylink.append("00000");
|
||||
server_saylink.append(segments[segment_iter].substr(37));
|
||||
server_saylink.push_back('\x12');
|
||||
}
|
||||
else {
|
||||
serverSayLink.append(segments[segment_iter]);
|
||||
server_saylink.append(segments[segment_iter]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline CastingSlot ServerToTitaniumCastingSlot(EQEmu::CastingSlot slot)
|
||||
{
|
||||
static inline CastingSlot ServerToTitaniumCastingSlot(EQEmu::CastingSlot slot) {
|
||||
switch (slot) {
|
||||
case EQEmu::CastingSlot::Gem1:
|
||||
return CastingSlot::Gem1;
|
||||
case EQEmu::CastingSlot::Gem2:
|
||||
return CastingSlot::Gem2;
|
||||
case EQEmu::CastingSlot::Gem3:
|
||||
return CastingSlot::Gem3;
|
||||
case EQEmu::CastingSlot::Gem4:
|
||||
return CastingSlot::Gem4;
|
||||
case EQEmu::CastingSlot::Gem5:
|
||||
return CastingSlot::Gem5;
|
||||
case EQEmu::CastingSlot::Gem6:
|
||||
return CastingSlot::Gem6;
|
||||
case EQEmu::CastingSlot::Gem7:
|
||||
return CastingSlot::Gem7;
|
||||
case EQEmu::CastingSlot::Gem8:
|
||||
return CastingSlot::Gem8;
|
||||
case EQEmu::CastingSlot::Gem9:
|
||||
return CastingSlot::Gem9;
|
||||
case EQEmu::CastingSlot::Item:
|
||||
return CastingSlot::Item;
|
||||
case EQEmu::CastingSlot::PotionBelt:
|
||||
return CastingSlot::PotionBelt;
|
||||
case EQEmu::CastingSlot::Discipline:
|
||||
return CastingSlot::Discipline;
|
||||
case EQEmu::CastingSlot::AltAbility:
|
||||
return CastingSlot::AltAbility;
|
||||
default: // we shouldn't have any issues with other slots ... just return something
|
||||
return CastingSlot::Discipline;
|
||||
case EQEmu::CastingSlot::Gem1:
|
||||
return CastingSlot::Gem1;
|
||||
case EQEmu::CastingSlot::Gem2:
|
||||
return CastingSlot::Gem2;
|
||||
case EQEmu::CastingSlot::Gem3:
|
||||
return CastingSlot::Gem3;
|
||||
case EQEmu::CastingSlot::Gem4:
|
||||
return CastingSlot::Gem4;
|
||||
case EQEmu::CastingSlot::Gem5:
|
||||
return CastingSlot::Gem5;
|
||||
case EQEmu::CastingSlot::Gem6:
|
||||
return CastingSlot::Gem6;
|
||||
case EQEmu::CastingSlot::Gem7:
|
||||
return CastingSlot::Gem7;
|
||||
case EQEmu::CastingSlot::Gem8:
|
||||
return CastingSlot::Gem8;
|
||||
case EQEmu::CastingSlot::Gem9:
|
||||
return CastingSlot::Gem9;
|
||||
case EQEmu::CastingSlot::Item:
|
||||
return CastingSlot::Item;
|
||||
case EQEmu::CastingSlot::PotionBelt:
|
||||
return CastingSlot::PotionBelt;
|
||||
case EQEmu::CastingSlot::Discipline:
|
||||
return CastingSlot::Discipline;
|
||||
case EQEmu::CastingSlot::AltAbility:
|
||||
return CastingSlot::AltAbility;
|
||||
default: // we shouldn't have any issues with other slots ... just return something
|
||||
return CastingSlot::Discipline;
|
||||
}
|
||||
}
|
||||
|
||||
static inline EQEmu::CastingSlot TitaniumToServerCastingSlot(CastingSlot slot, uint32 itemlocation)
|
||||
{
|
||||
static inline EQEmu::CastingSlot TitaniumToServerCastingSlot(CastingSlot slot, uint32 item_location) {
|
||||
switch (slot) {
|
||||
case CastingSlot::Gem1:
|
||||
return EQEmu::CastingSlot::Gem1;
|
||||
case CastingSlot::Gem2:
|
||||
return EQEmu::CastingSlot::Gem2;
|
||||
case CastingSlot::Gem3:
|
||||
return EQEmu::CastingSlot::Gem3;
|
||||
case CastingSlot::Gem4:
|
||||
return EQEmu::CastingSlot::Gem4;
|
||||
case CastingSlot::Gem5:
|
||||
return EQEmu::CastingSlot::Gem5;
|
||||
case CastingSlot::Gem6:
|
||||
return EQEmu::CastingSlot::Gem6;
|
||||
case CastingSlot::Gem7:
|
||||
return EQEmu::CastingSlot::Gem7;
|
||||
case CastingSlot::Gem8:
|
||||
return EQEmu::CastingSlot::Gem8;
|
||||
case CastingSlot::Gem9:
|
||||
return EQEmu::CastingSlot::Gem9;
|
||||
case CastingSlot::Ability:
|
||||
return EQEmu::CastingSlot::Ability;
|
||||
// Tit uses 10 for item and discipline casting, but items have a valid location
|
||||
case CastingSlot::Item:
|
||||
if (itemlocation == INVALID_INDEX)
|
||||
case CastingSlot::Gem1:
|
||||
return EQEmu::CastingSlot::Gem1;
|
||||
case CastingSlot::Gem2:
|
||||
return EQEmu::CastingSlot::Gem2;
|
||||
case CastingSlot::Gem3:
|
||||
return EQEmu::CastingSlot::Gem3;
|
||||
case CastingSlot::Gem4:
|
||||
return EQEmu::CastingSlot::Gem4;
|
||||
case CastingSlot::Gem5:
|
||||
return EQEmu::CastingSlot::Gem5;
|
||||
case CastingSlot::Gem6:
|
||||
return EQEmu::CastingSlot::Gem6;
|
||||
case CastingSlot::Gem7:
|
||||
return EQEmu::CastingSlot::Gem7;
|
||||
case CastingSlot::Gem8:
|
||||
return EQEmu::CastingSlot::Gem8;
|
||||
case CastingSlot::Gem9:
|
||||
return EQEmu::CastingSlot::Gem9;
|
||||
case CastingSlot::Ability:
|
||||
return EQEmu::CastingSlot::Ability;
|
||||
// Tit uses 10 for item and discipline casting, but items have a valid location
|
||||
case CastingSlot::Item:
|
||||
if (item_location == INVALID_INDEX)
|
||||
return EQEmu::CastingSlot::Discipline;
|
||||
else
|
||||
return EQEmu::CastingSlot::Item;
|
||||
case CastingSlot::PotionBelt:
|
||||
return EQEmu::CastingSlot::PotionBelt;
|
||||
case CastingSlot::AltAbility:
|
||||
return EQEmu::CastingSlot::AltAbility;
|
||||
default: // we shouldn't have any issues with other slots ... just return something
|
||||
return EQEmu::CastingSlot::Discipline;
|
||||
else
|
||||
return EQEmu::CastingSlot::Item;
|
||||
case CastingSlot::PotionBelt:
|
||||
return EQEmu::CastingSlot::PotionBelt;
|
||||
case CastingSlot::AltAbility:
|
||||
return EQEmu::CastingSlot::AltAbility;
|
||||
default: // we shouldn't have any issues with other slots ... just return something
|
||||
return EQEmu::CastingSlot::Discipline;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -149,6 +149,8 @@ namespace Titanium
|
||||
const int16 SLOT_INVALID = IINVALID;
|
||||
const int16 SLOT_BEGIN = INULL;
|
||||
|
||||
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
|
||||
|
||||
const int16 POSSESSIONS_BEGIN = slotCharm;
|
||||
const int16 POSSESSIONS_END = slotCursor;
|
||||
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
|
||||
|
||||
@ -520,7 +520,7 @@ namespace UF
|
||||
for (int index = 0; index < item_count; ++index, ++eq) {
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)eq->inst, eq->slot_id, 0);
|
||||
if (ob.tellp() == last_pos)
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
Log(Logs::General, Logs::Netcode, "UF::ENCODE(OP_CharInventory) Serialization failed on item slot %d during OP_CharInventory. Item skipped.", eq->slot_id);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
@ -584,7 +584,12 @@ namespace UF
|
||||
FINISH_ENCODE();
|
||||
}
|
||||
|
||||
ENCODE(OP_DeleteCharge) { ENCODE_FORWARD(OP_MoveItem); }
|
||||
ENCODE(OP_DeleteCharge)
|
||||
{
|
||||
Log(Logs::Moderate, Logs::Netcode, "UF::ENCODE(OP_DeleteCharge)");
|
||||
|
||||
ENCODE_FORWARD(OP_MoveItem);
|
||||
}
|
||||
|
||||
ENCODE(OP_DeleteItem)
|
||||
{
|
||||
@ -1272,7 +1277,7 @@ namespace UF
|
||||
|
||||
SerializeItem(ob, (const EQEmu::ItemInstance*)int_struct->inst, int_struct->slot_id, 0);
|
||||
if (ob.tellp() == last_pos) {
|
||||
Log(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
Log(Logs::General, Logs::Netcode, "UF::ENCODE(OP_ItemPacket) Serialization failed on item slot %d.", int_struct->slot_id);
|
||||
delete in;
|
||||
return;
|
||||
}
|
||||
@ -1345,6 +1350,8 @@ namespace UF
|
||||
ENCODE_LENGTH_EXACT(LootingItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "UF::ENCODE(OP_LootItem)");
|
||||
|
||||
OUT(lootee);
|
||||
OUT(looter);
|
||||
eq->slot_id = ServerToUFCorpseSlot(emu->slot_id);
|
||||
@ -1510,6 +1517,8 @@ namespace UF
|
||||
ENCODE_LENGTH_EXACT(MoveItem_Struct);
|
||||
SETUP_DIRECT_ENCODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "UF::ENCODE(OP_MoveItem)");
|
||||
|
||||
eq->from_slot = ServerToUFSlot(emu->from_slot);
|
||||
eq->to_slot = ServerToUFSlot(emu->to_slot);
|
||||
OUT(number_in_stack);
|
||||
@ -1769,7 +1778,7 @@ namespace UF
|
||||
|
||||
// OUT(unknown06160[4]);
|
||||
|
||||
// Copy bandoliers where server and client indexes converge
|
||||
// Copy bandoliers where server and client indices converge
|
||||
for (r = 0; r < EQEmu::profile::BANDOLIERS_SIZE && r < profile::BANDOLIERS_SIZE; ++r) {
|
||||
OUT_str(bandoliers[r].Name);
|
||||
for (uint32 k = 0; k < profile::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||
@ -1778,7 +1787,7 @@ namespace UF
|
||||
OUT_str(bandoliers[r].Items[k].Name);
|
||||
}
|
||||
}
|
||||
// Nullify bandoliers where server and client indexes diverge, with a client bias
|
||||
// Nullify bandoliers where server and client indices diverge, with a client bias
|
||||
for (r = EQEmu::profile::BANDOLIERS_SIZE; r < profile::BANDOLIERS_SIZE; ++r) {
|
||||
eq->bandoliers[r].Name[0] = '\0';
|
||||
for (uint32 k = 0; k < profile::BANDOLIER_ITEM_COUNT; ++k) { // Will need adjusting if 'server != client' is ever true
|
||||
@ -1790,13 +1799,13 @@ namespace UF
|
||||
|
||||
// OUT(unknown07444[5120]);
|
||||
|
||||
// Copy potion belt where server and client indexes converge
|
||||
// Copy potion belt where server and client indices converge
|
||||
for (r = 0; r < EQEmu::profile::POTION_BELT_SIZE && r < profile::POTION_BELT_SIZE; ++r) {
|
||||
OUT(potionbelt.Items[r].ID);
|
||||
OUT(potionbelt.Items[r].Icon);
|
||||
OUT_str(potionbelt.Items[r].Name);
|
||||
}
|
||||
// Nullify potion belt where server and client indexes diverge, with a client bias
|
||||
// Nullify potion belt where server and client indices diverge, with a client bias
|
||||
for (r = EQEmu::profile::POTION_BELT_SIZE; r < profile::POTION_BELT_SIZE; ++r) {
|
||||
eq->potionbelt.Items[r].ID = 0;
|
||||
eq->potionbelt.Items[r].Icon = 0;
|
||||
@ -3496,6 +3505,8 @@ namespace UF
|
||||
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
|
||||
SETUP_DIRECT_DECODE(LootingItem_Struct, structs::LootingItem_Struct);
|
||||
|
||||
Log(Logs::Moderate, Logs::Netcode, "UF::DECODE(OP_LootItem)");
|
||||
|
||||
IN(lootee);
|
||||
IN(looter);
|
||||
emu->slot_id = UFToServerCorpseSlot(eq->slot_id);
|
||||
@ -3509,7 +3520,7 @@ namespace UF
|
||||
DECODE_LENGTH_EXACT(structs::MoveItem_Struct);
|
||||
SETUP_DIRECT_DECODE(MoveItem_Struct, structs::MoveItem_Struct);
|
||||
|
||||
Log(Logs::General, Logs::Netcode, "[UF] Moved item from %u to %u", eq->from_slot, eq->to_slot);
|
||||
Log(Logs::Moderate, Logs::Netcode, "UF::DECODE(OP_MoveItem)");
|
||||
|
||||
emu->from_slot = UFToServerSlot(eq->from_slot);
|
||||
emu->to_slot = UFToServerSlot(eq->to_slot);
|
||||
@ -3810,7 +3821,7 @@ namespace UF
|
||||
ibs.nodrop = item->NoDrop;
|
||||
ibs.attune = item->Attuneable;
|
||||
ibs.size = item->Size;
|
||||
ibs.slots = SwapBits21And22(item->Slots);
|
||||
ibs.slots = item->Slots;
|
||||
ibs.price = item->Price;
|
||||
ibs.icon = item->Icon;
|
||||
ibs.unknown1 = 1;
|
||||
@ -4096,81 +4107,201 @@ namespace UF
|
||||
|
||||
ob.write((const char*)&subitem_count, sizeof(uint32));
|
||||
|
||||
for (uint32 index = EQEmu::invbag::SLOT_BEGIN; index <= EQEmu::invbag::SLOT_END; ++index) {
|
||||
EQEmu::ItemInstance* sub = inst->GetItem(index);
|
||||
if (!sub)
|
||||
continue;
|
||||
// moved outside of loop since it is not modified within that scope
|
||||
int16 SubSlotNumber = EQEmu::invbag::SLOT_INVALID;
|
||||
|
||||
int SubSlotNumber = INVALID_INDEX;
|
||||
if (slot_id_in >= EQEmu::invslot::GENERAL_BEGIN && slot_id_in <= EQEmu::invslot::GENERAL_END)
|
||||
SubSlotNumber = (((slot_id_in + 3) * EQEmu::invbag::SLOT_COUNT) + index + 1);
|
||||
else if (slot_id_in >= EQEmu::invslot::BANK_BEGIN && slot_id_in <= EQEmu::invslot::BANK_END)
|
||||
SubSlotNumber = (((slot_id_in - EQEmu::invslot::BANK_BEGIN) * EQEmu::invbag::SLOT_COUNT) + EQEmu::invbag::BANK_BAGS_BEGIN + index);
|
||||
else if (slot_id_in >= EQEmu::invslot::SHARED_BANK_BEGIN && slot_id_in <= EQEmu::invslot::SHARED_BANK_END)
|
||||
SubSlotNumber = (((slot_id_in - EQEmu::invslot::SHARED_BANK_BEGIN) * EQEmu::invbag::SLOT_COUNT) + EQEmu::invbag::SHARED_BANK_BAGS_BEGIN + index);
|
||||
else
|
||||
SubSlotNumber = slot_id_in;
|
||||
if (slot_id_in <= EQEmu::invslot::slotGeneral8 && slot_id_in >= EQEmu::invslot::GENERAL_BEGIN)
|
||||
SubSlotNumber = EQEmu::invbag::GENERAL_BAGS_BEGIN + ((slot_id_in - EQEmu::invslot::GENERAL_BEGIN) * EQEmu::invbag::SLOT_COUNT);
|
||||
else if (slot_id_in <= EQEmu::invslot::GENERAL_END && slot_id_in >= EQEmu::invslot::slotGeneral9)
|
||||
SubSlotNumber = EQEmu::invbag::SLOT_INVALID;
|
||||
else if (slot_id_in == EQEmu::invslot::slotCursor)
|
||||
SubSlotNumber = EQEmu::invbag::CURSOR_BAG_BEGIN;
|
||||
else if (slot_id_in <= EQEmu::invslot::BANK_END && slot_id_in >= EQEmu::invslot::BANK_BEGIN)
|
||||
SubSlotNumber = EQEmu::invbag::BANK_BAGS_BEGIN + ((slot_id_in - EQEmu::invslot::BANK_BEGIN) * EQEmu::invbag::SLOT_COUNT);
|
||||
else if (slot_id_in <= EQEmu::invslot::SHARED_BANK_END && slot_id_in >= EQEmu::invslot::SHARED_BANK_BEGIN)
|
||||
SubSlotNumber = EQEmu::invbag::SHARED_BANK_BAGS_BEGIN + ((slot_id_in - EQEmu::invslot::SHARED_BANK_BEGIN) * EQEmu::invbag::SLOT_COUNT);
|
||||
else
|
||||
SubSlotNumber = slot_id_in; // not sure if this is the best way to handle this..leaving for now
|
||||
|
||||
ob.write((const char*)&index, sizeof(uint32));
|
||||
if (SubSlotNumber != EQEmu::invbag::SLOT_INVALID) {
|
||||
for (uint32 index = EQEmu::invbag::SLOT_BEGIN; index <= EQEmu::invbag::SLOT_END; ++index) {
|
||||
EQEmu::ItemInstance* sub = inst->GetItem(index);
|
||||
if (!sub)
|
||||
continue;
|
||||
|
||||
SerializeItem(ob, sub, SubSlotNumber, (depth + 1));
|
||||
++subitem_count;
|
||||
ob.write((const char*)&index, sizeof(uint32));
|
||||
|
||||
SerializeItem(ob, sub, SubSlotNumber, (depth + 1));
|
||||
++subitem_count;
|
||||
}
|
||||
|
||||
if (subitem_count)
|
||||
ob.overwrite(count_pos, (const char*)&subitem_count, sizeof(uint32));
|
||||
}
|
||||
|
||||
if (subitem_count)
|
||||
ob.overwrite(count_pos, (const char*)&subitem_count, sizeof(uint32));
|
||||
}
|
||||
|
||||
static inline uint32 ServerToUFSlot(uint32 serverSlot)
|
||||
{
|
||||
uint32 UnderfootSlot = 0;
|
||||
uint32 UFSlot = invslot::SLOT_INVALID;
|
||||
|
||||
if (serverSlot >= EQEmu::invslot::slotAmmo && serverSlot <= 53) // Cursor/Ammo/Power Source and Normal Inventory Slots
|
||||
UnderfootSlot = serverSlot + 1;
|
||||
else if (serverSlot >= EQEmu::invbag::GENERAL_BAGS_BEGIN && serverSlot <= EQEmu::invbag::CURSOR_BAG_END)
|
||||
UnderfootSlot = serverSlot + 11;
|
||||
else if (serverSlot >= EQEmu::invbag::BANK_BAGS_BEGIN && serverSlot <= EQEmu::invbag::BANK_BAGS_END)
|
||||
UnderfootSlot = serverSlot + 1;
|
||||
else if (serverSlot >= EQEmu::invbag::SHARED_BANK_BAGS_BEGIN && serverSlot <= EQEmu::invbag::SHARED_BANK_BAGS_END)
|
||||
UnderfootSlot = serverSlot + 1;
|
||||
else if (serverSlot == EQEmu::invslot::SLOT_POWER_SOURCE)
|
||||
UnderfootSlot = invslot::slotPowerSource;
|
||||
else
|
||||
UnderfootSlot = serverSlot;
|
||||
if (serverSlot <= EQEmu::invslot::slotGeneral8) {
|
||||
UFSlot = serverSlot;
|
||||
}
|
||||
|
||||
return UnderfootSlot;
|
||||
else if (serverSlot <= EQEmu::invslot::CORPSE_END && serverSlot >= EQEmu::invslot::slotCursor) {
|
||||
UFSlot = serverSlot - 2;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invbag::GENERAL_BAGS_8_END && serverSlot >= EQEmu::invbag::GENERAL_BAGS_BEGIN) {
|
||||
UFSlot = serverSlot + 11;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invbag::CURSOR_BAG_END && serverSlot >= EQEmu::invbag::CURSOR_BAG_BEGIN) {
|
||||
UFSlot = serverSlot - 9;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invslot::TRIBUTE_END && serverSlot >= EQEmu::invslot::TRIBUTE_BEGIN) {
|
||||
UFSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invslot::GUILD_TRIBUTE_END && serverSlot >= EQEmu::invslot::GUILD_TRIBUTE_BEGIN) {
|
||||
UFSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot == EQEmu::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE) {
|
||||
UFSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invslot::BANK_END && serverSlot >= EQEmu::invslot::BANK_BEGIN) {
|
||||
UFSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invbag::BANK_BAGS_END && serverSlot >= EQEmu::invbag::BANK_BAGS_BEGIN) {
|
||||
UFSlot = serverSlot + 1;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invslot::SHARED_BANK_END && serverSlot >= EQEmu::invslot::SHARED_BANK_BEGIN) {
|
||||
UFSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invbag::SHARED_BANK_BAGS_END && serverSlot >= EQEmu::invbag::SHARED_BANK_BAGS_BEGIN) {
|
||||
UFSlot = serverSlot + 1;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invslot::TRADE_END && serverSlot >= EQEmu::invslot::TRADE_BEGIN) {
|
||||
UFSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invbag::TRADE_BAGS_END && serverSlot >= EQEmu::invbag::TRADE_BAGS_BEGIN) {
|
||||
UFSlot = serverSlot;
|
||||
}
|
||||
|
||||
else if (serverSlot <= EQEmu::invslot::WORLD_END && serverSlot >= EQEmu::invslot::WORLD_BEGIN) {
|
||||
UFSlot = serverSlot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Slot %i to UF Slot %i", serverSlot, UFSlot);
|
||||
|
||||
return UFSlot;
|
||||
}
|
||||
|
||||
static inline uint32 ServerToUFCorpseSlot(uint32 serverCorpseSlot)
|
||||
{
|
||||
//uint32 UnderfootCorpse;
|
||||
return (serverCorpseSlot + 1);
|
||||
uint32 UFSlot = invslot::SLOT_INVALID;
|
||||
|
||||
if (serverCorpseSlot <= EQEmu::invslot::slotGeneral8 && serverCorpseSlot >= EQEmu::invslot::slotGeneral1) {
|
||||
UFSlot = serverCorpseSlot;
|
||||
}
|
||||
|
||||
else if (serverCorpseSlot <= EQEmu::invslot::CORPSE_END && serverCorpseSlot >= EQEmu::invslot::slotCursor) {
|
||||
UFSlot = serverCorpseSlot - 2;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert Server Corpse Slot %i to UF Corpse Slot %i", serverCorpseSlot, UFSlot);
|
||||
|
||||
return UFSlot;
|
||||
}
|
||||
|
||||
static inline uint32 UFToServerSlot(uint32 ufSlot)
|
||||
{
|
||||
uint32 ServerSlot = 0;
|
||||
uint32 ServerSlot = EQEmu::invslot::SLOT_INVALID;
|
||||
|
||||
if (ufSlot >= invslot::slotAmmo && ufSlot <= invslot::CORPSE_END) // Cursor/Ammo/Power Source and Normal Inventory Slots
|
||||
ServerSlot = ufSlot - 1;
|
||||
else if (ufSlot >= invbag::GENERAL_BAGS_BEGIN && ufSlot <= invbag::CURSOR_BAG_END)
|
||||
ServerSlot = ufSlot - 11;
|
||||
else if (ufSlot >= invbag::BANK_BAGS_BEGIN && ufSlot <= invbag::BANK_BAGS_END)
|
||||
ServerSlot = ufSlot - 1;
|
||||
else if (ufSlot >= invbag::SHARED_BANK_BAGS_BEGIN && ufSlot <= invbag::SHARED_BANK_BAGS_END)
|
||||
ServerSlot = ufSlot - 1;
|
||||
else if (ufSlot == invslot::slotPowerSource)
|
||||
ServerSlot = EQEmu::invslot::SLOT_POWER_SOURCE;
|
||||
else
|
||||
if (ufSlot <= invslot::slotGeneral8) {
|
||||
ServerSlot = ufSlot;
|
||||
}
|
||||
|
||||
else if (ufSlot <= invslot::CORPSE_END && ufSlot >= invslot::slotCursor) {
|
||||
ServerSlot = ufSlot + 2;
|
||||
}
|
||||
|
||||
else if (ufSlot <= invbag::GENERAL_BAGS_END && ufSlot >= invbag::GENERAL_BAGS_BEGIN) {
|
||||
ServerSlot = ufSlot - 11;
|
||||
}
|
||||
|
||||
else if (ufSlot <= invbag::CURSOR_BAG_END && ufSlot >= invbag::CURSOR_BAG_BEGIN) {
|
||||
ServerSlot = ufSlot + 9;
|
||||
}
|
||||
|
||||
else if (ufSlot <= invslot::TRIBUTE_END && ufSlot >= invslot::TRIBUTE_BEGIN) {
|
||||
ServerSlot = ufSlot;
|
||||
}
|
||||
|
||||
else if (ufSlot <= invslot::GUILD_TRIBUTE_END && ufSlot >= invslot::GUILD_TRIBUTE_BEGIN) {
|
||||
ServerSlot = ufSlot;
|
||||
}
|
||||
|
||||
else if (ufSlot == invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE) {
|
||||
ServerSlot = ufSlot;
|
||||
}
|
||||
|
||||
else if (ufSlot <= invslot::BANK_END && ufSlot >= invslot::BANK_BEGIN) {
|
||||
ServerSlot = ufSlot;
|
||||
}
|
||||
|
||||
else if (ufSlot <= invbag::BANK_BAGS_END && ufSlot >= invbag::BANK_BAGS_BEGIN) {
|
||||
ServerSlot = ufSlot - 1;
|
||||
}
|
||||
|
||||
else if (ufSlot <= invslot::SHARED_BANK_END && ufSlot >= invslot::SHARED_BANK_BEGIN) {
|
||||
ServerSlot = ufSlot;
|
||||
}
|
||||
|
||||
else if (ufSlot <= invbag::SHARED_BANK_BAGS_END && ufSlot >= invbag::SHARED_BANK_BAGS_BEGIN) {
|
||||
ServerSlot = ufSlot - 1;
|
||||
}
|
||||
|
||||
else if (ufSlot <= invslot::TRADE_END && ufSlot >= invslot::TRADE_BEGIN) {
|
||||
ServerSlot = ufSlot;
|
||||
}
|
||||
|
||||
else if (ufSlot <= invbag::TRADE_BAGS_END && ufSlot >= invbag::TRADE_BAGS_BEGIN) {
|
||||
ServerSlot = ufSlot;
|
||||
}
|
||||
|
||||
else if (ufSlot <= invslot::WORLD_END && ufSlot >= invslot::WORLD_BEGIN) {
|
||||
ServerSlot = ufSlot;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert UF Slot %i to Server Slot %i", ufSlot, ServerSlot);
|
||||
|
||||
return ServerSlot;
|
||||
}
|
||||
|
||||
static inline uint32 UFToServerCorpseSlot(uint32 ufCorpseSlot)
|
||||
{
|
||||
//uint32 ServerCorpse;
|
||||
return (ufCorpseSlot - 1);
|
||||
uint32 ServerSlot = EQEmu::invslot::SLOT_INVALID;
|
||||
|
||||
if (ufCorpseSlot <= invslot::slotGeneral8 && ufCorpseSlot >= invslot::slotGeneral1) {
|
||||
ServerSlot = ufCorpseSlot;
|
||||
}
|
||||
|
||||
else if (ufCorpseSlot <= invslot::CORPSE_END && ufCorpseSlot >= invslot::slotCursor) {
|
||||
ServerSlot = ufCorpseSlot + 2;
|
||||
}
|
||||
|
||||
Log(Logs::Detail, Logs::Netcode, "Convert UF Corpse Slot %i to Server Corpse Slot %i", ufCorpseSlot, ServerSlot);
|
||||
|
||||
return ServerSlot;
|
||||
}
|
||||
|
||||
static inline void ServerToUFSayLink(std::string& ufSayLink, const std::string& serverSayLink)
|
||||
|
||||
@ -150,6 +150,8 @@ namespace UF
|
||||
const int16 SLOT_INVALID = IINVALID;
|
||||
const int16 SLOT_BEGIN = INULL;
|
||||
|
||||
const int16 SLOT_TRADESKILL_EXPERIMENT_COMBINE = 1000;
|
||||
|
||||
const int16 POSSESSIONS_BEGIN = slotCharm;
|
||||
const int16 POSSESSIONS_END = slotCursor;
|
||||
const int16 POSSESSIONS_COUNT = (POSSESSIONS_END - POSSESSIONS_BEGIN) + 1;
|
||||
|
||||
@ -389,6 +389,7 @@ RULE_INT(Spells, AI_PursueDetrimentalChance, 90) // Chance while chasing target
|
||||
RULE_INT(Spells, AI_IdleNoSpellMinRecast, 6000) // AI spell recast time(MS) check when no spell is cast while idle. (min time in random)
|
||||
RULE_INT(Spells, AI_IdleNoSpellMaxRecast, 60000) // AI spell recast time(MS) check when no spell is cast while chasing target. (max time in random)
|
||||
RULE_INT(Spells, AI_IdleBeneficialChance, 100) // Chance while idle to do a beneficial spell on self or others.
|
||||
RULE_INT(Spells, AI_HealHPPct, 50) // HP Pct NPCs will start heals at (in and out of combat) if spell's max_hp is not set
|
||||
RULE_BOOL(Spells, SHDProcIDOffByOne, true) // pre June 2009 SHD spell procs were off by 1, they stopped doing this in June 2009 (so UF+ spell files need this false)
|
||||
RULE_BOOL(Spells, Jun182014HundredHandsRevamp, false) // this should be true for if you import a spell file newer than June 18, 2014
|
||||
RULE_BOOL(Spells, SwarmPetTargetLock, false) // Use old method of swarm pets target locking till target dies then despawning.
|
||||
@ -551,7 +552,8 @@ RULE_REAL(Aggro, TunnelVisionAggroMod, 0.75) //people not currently the top hate
|
||||
RULE_INT(Aggro, MaxScalingProcAggro, 400) // Set to -1 for no limit. Maxmimum amount of aggro that HP scaling SPA effect in a proc will add.
|
||||
RULE_INT(Aggro, IntAggroThreshold, 75) // Int <= this will aggro regardless of level difference.
|
||||
RULE_BOOL(Aggro, AllowTickPulling, false) // tick pulling is an exploit in an NPC's call for help fixed sometime in 2006 on live
|
||||
RULE_BOOL(Aggro, UseLevelAggro, true) // Level 18+ and Undead will aggro regardless of level difference. (this will disabled Rule:IntAggroThreshold if set to true)
|
||||
RULE_INT(Aggro, MinAggroLevel, 18) // For use with UseLevelAggro
|
||||
RULE_BOOL(Aggro, UseLevelAggro, true) // MinAggroLevel rule value+ and Undead will aggro regardless of level difference. (this will disabled Rule:IntAggroThreshold if set to true)
|
||||
RULE_INT(Aggro, ClientAggroCheckInterval, 6) // Interval in which clients actually check for aggro - in seconds
|
||||
RULE_REAL(Aggro, PetAttackRange, 40000.0) // max squared range /pet attack works at default is 200
|
||||
RULE_BOOL(Aggro, NPCAggroMaxDistanceEnabled, true) /* If enabled, NPC's will drop aggro beyond 600 units or what is defined at the zone level */
|
||||
|
||||
@ -547,9 +547,12 @@ bool SharedDatabase::GetSharedBank(uint32 id, EQEmu::InventoryProfile *inv, bool
|
||||
return true;
|
||||
}
|
||||
|
||||
// Overloaded: Retrieve character inventory based on character id
|
||||
// Overloaded: Retrieve character inventory based on character id (zone entry)
|
||||
bool SharedDatabase::GetInventory(uint32 char_id, EQEmu::InventoryProfile *inv)
|
||||
{
|
||||
if (!char_id || !inv)
|
||||
return false;
|
||||
|
||||
// Retrieve character inventory
|
||||
std::string query =
|
||||
StringFormat("SELECT slotid, itemid, charges, color, augslot1, augslot2, augslot3, augslot4, augslot5, "
|
||||
@ -566,8 +569,40 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQEmu::InventoryProfile *inv)
|
||||
|
||||
auto timestamps = GetItemRecastTimestamps(char_id);
|
||||
|
||||
auto cv_conflict = false;
|
||||
auto pmask = inv->GetLookup()->PossessionsBitmask;
|
||||
auto bank_size = inv->GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank];
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
int16 slot_id = atoi(row[0]);
|
||||
|
||||
if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) { // Titanium thru UF check
|
||||
if ((((uint64)1 << slot_id) & pmask) == 0) {
|
||||
cv_conflict = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (slot_id <= EQEmu::invbag::GENERAL_BAGS_END && slot_id >= EQEmu::invbag::GENERAL_BAGS_BEGIN) { // Titanium thru UF check
|
||||
auto parent_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot_id - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT);
|
||||
if ((((uint64)1 << parent_slot) & pmask) == 0) {
|
||||
cv_conflict = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) { // Titanium check
|
||||
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= bank_size) {
|
||||
cv_conflict = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) { // Titanium check
|
||||
auto parent_index = ((slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT);
|
||||
if (parent_index < EQEmu::invslot::SLOT_BEGIN || parent_index >= bank_size) {
|
||||
cv_conflict = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 item_id = atoi(row[1]);
|
||||
uint16 charges = atoi(row[2]);
|
||||
uint32 color = atoul(row[3]);
|
||||
@ -633,10 +668,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQEmu::InventoryProfile *inv)
|
||||
inst->SetOrnamentationIDFile(ornament_idfile);
|
||||
inst->SetOrnamentHeroModel(item->HerosForgeModel);
|
||||
|
||||
if (instnodrop ||
|
||||
(((slot_id >= EQEmu::invslot::EQUIPMENT_BEGIN && slot_id <= EQEmu::invslot::EQUIPMENT_END) ||
|
||||
slot_id == EQEmu::invslot::SLOT_POWER_SOURCE) &&
|
||||
inst->GetItem()->Attuneable))
|
||||
if (instnodrop || (inst->GetItem()->Attuneable && slot_id >= EQEmu::invslot::EQUIPMENT_BEGIN && slot_id <= EQEmu::invslot::EQUIPMENT_END))
|
||||
inst->SetAttuned(true);
|
||||
|
||||
if (color > 0)
|
||||
@ -684,13 +716,22 @@ bool SharedDatabase::GetInventory(uint32 char_id, EQEmu::InventoryProfile *inv)
|
||||
char_id, item_id, slot_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (cv_conflict) {
|
||||
char char_name[64] = "";
|
||||
GetCharName(char_id, char_name);
|
||||
Log(Logs::Moderate, Logs::Client_Login,
|
||||
"ClientVersion conflict during inventory load at zone entry for '%s' (charid: %u, inver: %s)",
|
||||
char_name, char_id, EQEmu::versions::MobVersionName(inv->InventoryVersion())
|
||||
);
|
||||
}
|
||||
|
||||
// Retrieve shared inventory
|
||||
return GetSharedBank(char_id, inv, true);
|
||||
}
|
||||
|
||||
// Overloaded: Retrieve character inventory based on account_id and character name
|
||||
bool SharedDatabase::GetInventory(uint32 account_id, char *name, EQEmu::InventoryProfile *inv)
|
||||
// Overloaded: Retrieve character inventory based on account_id and character name (char select)
|
||||
bool SharedDatabase::GetInventory(uint32 account_id, char *name, EQEmu::InventoryProfile *inv) // deprecated
|
||||
{
|
||||
// Retrieve character inventory
|
||||
std::string query =
|
||||
|
||||
@ -89,7 +89,7 @@ class SharedDatabase : public Database
|
||||
int32 GetSharedPlatinum(uint32 account_id);
|
||||
bool SetSharedPlatinum(uint32 account_id, int32 amount_to_add);
|
||||
bool GetInventory(uint32 char_id, EQEmu::InventoryProfile* inv);
|
||||
bool GetInventory(uint32 account_id, char* name, EQEmu::InventoryProfile* inv);
|
||||
bool GetInventory(uint32 account_id, char* name, EQEmu::InventoryProfile* inv); // deprecated
|
||||
std::map<uint32, uint32> GetItemRecastTimestamps(uint32 char_id);
|
||||
uint32 GetItemRecastTimestamp(uint32 char_id, uint32 recast_type);
|
||||
void ClearOldRecastTimestamps(uint32 char_id);
|
||||
|
||||
@ -30,9 +30,9 @@
|
||||
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9127
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9129
|
||||
#ifdef BOTS
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9019
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9021
|
||||
#else
|
||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 0 // must be 0
|
||||
#endif
|
||||
|
||||
@ -31,6 +31,7 @@ friends
|
||||
guild_members
|
||||
instance_list_player
|
||||
inventory
|
||||
inventory_snapshots
|
||||
keyring
|
||||
mail
|
||||
player_titlesets
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
command_settings
|
||||
inventory_versions
|
||||
launcher
|
||||
rule_sets
|
||||
rule_values
|
||||
|
||||
@ -381,6 +381,8 @@
|
||||
9125|2018_07_20_task_emote.sql|SHOW COLUMNS FROM `tasks` LIKE 'completion_emote'|empty|
|
||||
9126|2018_09_07_FastRegen.sql|SHOW COLUMNS FROM `zone` LIKE 'fast_regen_hp'|empty|
|
||||
9127|2018_09_07_NPCMaxAggroDist.sql|SHOW COLUMNS FROM `zone` LIKE 'npc_max_aggro_dist'|empty|
|
||||
9128|2018_08_13_inventory_version_update.sql|SHOW TABLES LIKE 'inventory_versions'|empty|
|
||||
9129|2018_08_13_inventory_update.sql|SELECT * FROM `inventory_versions` WHERE `version` = 2 and `step` = 0|not_empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@ -18,6 +18,8 @@
|
||||
9017|2017_03_26_bots_spells_id_fix_for_saved_shadowknight_bots.sql|SELECT * FROM `bot_data` WHERE `class` = '5' AND `spells_id` = '3004'|not_empty|
|
||||
9018|2018_02_02_Bot_Spells_Min_Max_HP.sql|SHOW COLUMNS FROM `bot_spells_entries` LIKE 'min_hp'|empty|
|
||||
9019|2018_04_12_bots_stop_melee_level.sql|SHOW COLUMNS FROM `bot_data` LIKE 'stop_melee_level'|empty|
|
||||
9020|2018_08_13_bots_inventory_update.sql|SELECT * FROM `inventory_versions` WHERE `version` = 2 and `bot_step` = 0|not_empty|
|
||||
9021|2018_10_09_bots_owner_options.sql|SHOW TABLES LIKE 'bot_owner_options'|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
-- update `bot_inventories` slots
|
||||
UPDATE `bot_inventories` SET `slot_id` = 22 WHERE `slot_id` = 21; -- adjust ammo slot
|
||||
UPDATE `bot_inventories` SET `slot_id` = 21 WHERE `slot_id` = 9999; -- adjust powersource slot
|
||||
|
||||
UPDATE `inventory_versions` SET `bot_step` = 1 WHERE `version` = 2;
|
||||
@ -0,0 +1,11 @@
|
||||
DROP TABLE IF EXISTS `bot_owner_options`;
|
||||
|
||||
CREATE TABLE `bot_owner_options` (
|
||||
`owner_id` INT(11) UNSIGNED NOT NULL,
|
||||
`death_marquee` SMALLINT(3) UNSIGNED NULL DEFAULT '0',
|
||||
PRIMARY KEY (`owner_id`)
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=MyISAM;
|
||||
|
||||
INSERT INTO `bot_command_settings`(`bot_command`, `access`, `aliases`) VALUES ('owneroption', '0', 'oo');
|
||||
72
utils/sql/git/required/2018_08_13_inventory_update.sql
Normal file
72
utils/sql/git/required/2018_08_13_inventory_update.sql
Normal file
@ -0,0 +1,72 @@
|
||||
-- create inventory v1 backup
|
||||
SELECT @pre_timestamp := UNIX_TIMESTAMP(NOW());
|
||||
INSERT INTO `inventory_snapshots_v1_bak`
|
||||
(`time_index`,`charid`,`slotid`,`itemid`,`charges`,`color`,`augslot1`,`augslot2`,`augslot3`,`augslot4`,
|
||||
`augslot5`,`augslot6`,`instnodrop`,`custom_data`,`ornamenticon`,`ornamentidfile`,`ornament_hero_model`)
|
||||
SELECT
|
||||
@pre_timestamp, `charid`, `slotid`, `itemid`, `charges`, `color`, `augslot1`, `augslot2`, `augslot3`, `augslot4`,
|
||||
`augslot5`,`augslot6`,`instnodrop`,`custom_data`,`ornamenticon`,`ornamentidfile`,`ornament_hero_model`
|
||||
FROM `inventory`;
|
||||
|
||||
|
||||
-- update equipable slots in `items` table
|
||||
SELECT 'pre-transform count..',
|
||||
(SELECT COUNT(id) FROM `items` WHERE `slots` & (3 << 21)) total,
|
||||
(SELECT COUNT(id) FROM `items` WHERE `slots` & (1 << 21)) bit21,
|
||||
(SELECT COUNT(id) FROM `items` WHERE `slots` & (1 << 22)) bit22;
|
||||
|
||||
UPDATE `items` SET `slots` = (`slots` ^ (3 << 21)) WHERE (`slots` & (3 << 21)) IN ((1 << 21), (1 << 22)); -- transform
|
||||
|
||||
SELECT 'post-transform count..',
|
||||
(SELECT COUNT(id) FROM `items` WHERE `slots` & (3 << 21)) total,
|
||||
(SELECT COUNT(id) FROM `items` WHERE `slots` & (1 << 21)) bit21,
|
||||
(SELECT COUNT(id) FROM `items` WHERE `slots` & (1 << 22)) bit22;
|
||||
|
||||
|
||||
-- update `inventory` slots
|
||||
UPDATE `inventory` SET `slotid` = 33 WHERE `slotid` = 30; -- adjust cursor
|
||||
UPDATE `inventory` SET `slotid` = (`slotid` + 20) WHERE `slotid` >= 331 AND `slotid` <= 340; -- adjust cursor bags
|
||||
UPDATE `inventory` SET `slotid` = 30 WHERE `slotid` = 29; -- adjust general8 slot
|
||||
UPDATE `inventory` SET `slotid` = 29 WHERE `slotid` = 28; -- adjust general7 slot
|
||||
UPDATE `inventory` SET `slotid` = 28 WHERE `slotid` = 27; -- adjust general6 slot
|
||||
UPDATE `inventory` SET `slotid` = 27 WHERE `slotid` = 26; -- adjust general5 slot
|
||||
UPDATE `inventory` SET `slotid` = 26 WHERE `slotid` = 25; -- adjust general4 slot
|
||||
UPDATE `inventory` SET `slotid` = 25 WHERE `slotid` = 24; -- adjust general3 slot
|
||||
UPDATE `inventory` SET `slotid` = 24 WHERE `slotid` = 23; -- adjust general2 slot
|
||||
UPDATE `inventory` SET `slotid` = 23 WHERE `slotid` = 22; -- adjust general1 slot
|
||||
-- current general bags remain the same
|
||||
UPDATE `inventory` SET `slotid` = 22 WHERE `slotid` = 21; -- adjust ammo slot
|
||||
UPDATE `inventory` SET `slotid` = 21 WHERE `slotid` = 9999; -- adjust powersource slot
|
||||
|
||||
|
||||
-- update `character_corpse_items` slots
|
||||
UPDATE `character_corpse_items` SET `equip_slot` = 33 WHERE `equip_slot` = 30; -- adjust cursor
|
||||
UPDATE `character_corpse_items` SET `equip_slot` = (`equip_slot` + 20) WHERE `equip_slot` >= 331 AND `equip_slot` <= 340; -- adjust cursor bags
|
||||
UPDATE `character_corpse_items` SET `equip_slot` = 30 WHERE `equip_slot` = 29; -- adjust general8 slot
|
||||
UPDATE `character_corpse_items` SET `equip_slot` = 29 WHERE `equip_slot` = 28; -- adjust general7 slot
|
||||
UPDATE `character_corpse_items` SET `equip_slot` = 28 WHERE `equip_slot` = 27; -- adjust general6 slot
|
||||
UPDATE `character_corpse_items` SET `equip_slot` = 27 WHERE `equip_slot` = 26; -- adjust general5 slot
|
||||
UPDATE `character_corpse_items` SET `equip_slot` = 26 WHERE `equip_slot` = 25; -- adjust general4 slot
|
||||
UPDATE `character_corpse_items` SET `equip_slot` = 25 WHERE `equip_slot` = 24; -- adjust general3 slot
|
||||
UPDATE `character_corpse_items` SET `equip_slot` = 24 WHERE `equip_slot` = 23; -- adjust general2 slot
|
||||
UPDATE `character_corpse_items` SET `equip_slot` = 23 WHERE `equip_slot` = 22; -- adjust general1 slot
|
||||
-- current general bags remain the same
|
||||
UPDATE `character_corpse_items` SET `equip_slot` = 22 WHERE `equip_slot` = 21; -- adjust ammo slot
|
||||
UPDATE `character_corpse_items` SET `equip_slot` = 21 WHERE `equip_slot` = 9999; -- adjust powersource slot
|
||||
|
||||
|
||||
-- update `character_pet_inventory` slots
|
||||
UPDATE `character_pet_inventory` SET `slot` = 22 WHERE `slot` = 21; -- adjust ammo slot
|
||||
|
||||
UPDATE `inventory_versions` SET `step` = 1 WHERE `version` = 2;
|
||||
|
||||
|
||||
-- create initial inventory v2 snapshots
|
||||
SELECT @post_timestamp := UNIX_TIMESTAMP(NOW());
|
||||
INSERT INTO `inventory_snapshots`
|
||||
(`time_index`,`charid`,`slotid`,`itemid`,`charges`,`color`,`augslot1`,`augslot2`,`augslot3`,`augslot4`,
|
||||
`augslot5`,`augslot6`,`instnodrop`,`custom_data`,`ornamenticon`,`ornamentidfile`,`ornament_hero_model`)
|
||||
SELECT
|
||||
@post_timestamp, `charid`, `slotid`, `itemid`, `charges`, `color`, `augslot1`, `augslot2`, `augslot3`, `augslot4`,
|
||||
`augslot5`,`augslot6`,`instnodrop`,`custom_data`,`ornamenticon`,`ornamentidfile`,`ornament_hero_model`
|
||||
FROM `inventory`;
|
||||
@ -0,0 +1,61 @@
|
||||
DROP TABLE IF EXISTS `inventory_version`;
|
||||
DROP TABLE IF EXISTS `inventory_snapshots`;
|
||||
|
||||
|
||||
CREATE TABLE `inventory_versions` (
|
||||
`version` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`step` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`bot_step` INT(11) UNSIGNED NOT NULL DEFAULT '0'
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=MyISAM;
|
||||
|
||||
INSERT INTO `inventory_versions` VALUES (2, 0, 0);
|
||||
|
||||
|
||||
CREATE TABLE `inventory_snapshots` (
|
||||
`time_index` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`charid` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`slotid` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`itemid` INT(11) UNSIGNED NULL DEFAULT '0',
|
||||
`charges` SMALLINT(3) UNSIGNED NULL DEFAULT '0',
|
||||
`color` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot5` MEDIUMINT(7) UNSIGNED NULL DEFAULT '0',
|
||||
`augslot6` MEDIUMINT(7) NOT NULL DEFAULT '0',
|
||||
`instnodrop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`custom_data` TEXT NULL,
|
||||
`ornamenticon` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`ornamentidfile` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`ornament_hero_model` INT(11) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`time_index`, `charid`, `slotid`)
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB;
|
||||
|
||||
|
||||
CREATE TABLE `inventory_snapshots_v1_bak` (
|
||||
`time_index` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`charid` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`slotid` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`itemid` INT(11) UNSIGNED NULL DEFAULT '0',
|
||||
`charges` SMALLINT(3) UNSIGNED NULL DEFAULT '0',
|
||||
`color` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`augslot5` MEDIUMINT(7) UNSIGNED NULL DEFAULT '0',
|
||||
`augslot6` MEDIUMINT(7) NOT NULL DEFAULT '0',
|
||||
`instnodrop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`custom_data` TEXT NULL,
|
||||
`ornamenticon` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`ornamentidfile` INT(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||
`ornament_hero_model` INT(11) NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`time_index`, `charid`, `slotid`)
|
||||
)
|
||||
COLLATE='latin1_swedish_ci'
|
||||
ENGINE=InnoDB;
|
||||
@ -52,6 +52,7 @@ guild_members
|
||||
hackers
|
||||
instance_list_player
|
||||
inventory
|
||||
inventory_snapshots
|
||||
item_tick
|
||||
keyring
|
||||
launcher_zones
|
||||
|
||||
@ -254,7 +254,7 @@ void Client::SendMembership() {
|
||||
mc->entries[1] = 0xffffffff; // Max Level Restriction
|
||||
mc->entries[2] = 0xffffffff; // Max Char Slots per Account (not used by client?)
|
||||
mc->entries[3] = 0xffffffff; // 1 for Silver
|
||||
mc->entries[4] = 8; // Main Inventory Size (0xffffffff on Live for Gold, but limiting to 8 until 10 is supported)
|
||||
mc->entries[4] = 0xffffffff; // Main Inventory Size (0xffffffff on Live for Gold, but limiting to 8 until 10 is supported)
|
||||
mc->entries[5] = 0xffffffff; // Max Platinum per level
|
||||
mc->entries[6] = 1; // 0 for Silver
|
||||
mc->entries[7] = 1; // 0 for Silver
|
||||
@ -1444,6 +1444,7 @@ bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||
PlayerProfile_Struct pp;
|
||||
ExtendedProfile_Struct ext;
|
||||
EQEmu::InventoryProfile inv;
|
||||
inv.SetInventoryVersion(EQEmu::versions::ConvertClientVersionBitToClientVersion(m_ClientVersionBit));
|
||||
time_t bday = time(nullptr);
|
||||
char startzone[50]={0};
|
||||
uint32 i;
|
||||
|
||||
@ -97,6 +97,7 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou
|
||||
CharacterSelectEntry_Struct *cse = (CharacterSelectEntry_Struct *)buff_ptr;
|
||||
PlayerProfile_Struct pp;
|
||||
EQEmu::InventoryProfile inv;
|
||||
inv.SetInventoryVersion(client_version);
|
||||
uint32 character_id = (uint32)atoi(row[0]);
|
||||
uint8 has_home = 0;
|
||||
uint8 has_bind = 0;
|
||||
@ -243,7 +244,7 @@ void WorldDatabase::GetCharSelectInfo(uint32 accountID, EQApplicationPacket **ou
|
||||
|
||||
/* Load Inventory */
|
||||
// If we ensure that the material data is updated appropriately, we can do away with inventory loads
|
||||
if (GetInventory(accountID, cse->Name, &inv)) {
|
||||
if (GetCharSelInventory(accountID, cse->Name, &inv)) {
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
const EQEmu::ItemInstance* inst = nullptr;
|
||||
int16 invslot = 0;
|
||||
@ -590,3 +591,143 @@ bool WorldDatabase::LoadCharacterCreateCombos()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// this is a slightly modified version of SharedDatabase::GetInventory(...) for character select use-only
|
||||
bool WorldDatabase::GetCharSelInventory(uint32 account_id, char *name, EQEmu::InventoryProfile *inv)
|
||||
{
|
||||
if (!account_id || !name || !inv)
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT"
|
||||
" slotid,"
|
||||
" itemid,"
|
||||
" charges,"
|
||||
" color,"
|
||||
" augslot1,"
|
||||
" augslot2,"
|
||||
" augslot3,"
|
||||
" augslot4,"
|
||||
" augslot5,"
|
||||
" augslot6,"
|
||||
" instnodrop,"
|
||||
" custom_data,"
|
||||
" ornamenticon,"
|
||||
" ornamentidfile,"
|
||||
" ornament_hero_model "
|
||||
"FROM"
|
||||
" inventory "
|
||||
"INNER JOIN"
|
||||
" character_data ch "
|
||||
"ON"
|
||||
" ch.id = charid "
|
||||
"WHERE"
|
||||
" ch.name = '%s' "
|
||||
"AND"
|
||||
" ch.account_id = %i "
|
||||
"AND"
|
||||
" slotid >= %i "
|
||||
"AND"
|
||||
" slotid <= %i",
|
||||
name,
|
||||
account_id,
|
||||
EQEmu::invslot::slotHead,
|
||||
EQEmu::invslot::slotFeet
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
int16 slot_id = atoi(row[0]);
|
||||
|
||||
switch (slot_id) {
|
||||
case EQEmu::invslot::slotFace:
|
||||
case EQEmu::invslot::slotEar2:
|
||||
case EQEmu::invslot::slotNeck:
|
||||
case EQEmu::invslot::slotShoulders:
|
||||
case EQEmu::invslot::slotBack:
|
||||
case EQEmu::invslot::slotFinger1:
|
||||
case EQEmu::invslot::slotFinger2:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
uint32 item_id = atoi(row[1]);
|
||||
int8 charges = atoi(row[2]);
|
||||
uint32 color = atoul(row[3]);
|
||||
|
||||
uint32 aug[EQEmu::invaug::SOCKET_COUNT];
|
||||
aug[0] = (uint32)atoi(row[4]);
|
||||
aug[1] = (uint32)atoi(row[5]);
|
||||
aug[2] = (uint32)atoi(row[6]);
|
||||
aug[3] = (uint32)atoi(row[7]);
|
||||
aug[4] = (uint32)atoi(row[8]);
|
||||
aug[5] = (uint32)atoi(row[9]);
|
||||
|
||||
bool instnodrop = ((row[10] && (uint16)atoi(row[10])) ? true : false);
|
||||
uint32 ornament_icon = (uint32)atoul(row[12]);
|
||||
uint32 ornament_idfile = (uint32)atoul(row[13]);
|
||||
uint32 ornament_hero_model = (uint32)atoul(row[14]);
|
||||
|
||||
const EQEmu::ItemData *item = GetItem(item_id);
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
EQEmu::ItemInstance *inst = CreateBaseItem(item, charges);
|
||||
|
||||
if (inst == nullptr)
|
||||
continue;
|
||||
|
||||
inst->SetAttuned(instnodrop);
|
||||
|
||||
if (row[11]) {
|
||||
std::string data_str(row[11]);
|
||||
std::string idAsString;
|
||||
std::string value;
|
||||
bool use_id = true;
|
||||
|
||||
for (int i = 0; i < data_str.length(); ++i) {
|
||||
if (data_str[i] == '^') {
|
||||
if (!use_id) {
|
||||
inst->SetCustomData(idAsString, value);
|
||||
idAsString.clear();
|
||||
value.clear();
|
||||
}
|
||||
|
||||
use_id = !use_id;
|
||||
continue;
|
||||
}
|
||||
|
||||
char v = data_str[i];
|
||||
if (use_id)
|
||||
idAsString.push_back(v);
|
||||
else
|
||||
value.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
inst->SetOrnamentIcon(ornament_icon);
|
||||
inst->SetOrnamentationIDFile(ornament_idfile);
|
||||
inst->SetOrnamentHeroModel(item->HerosForgeModel);
|
||||
|
||||
if (color > 0)
|
||||
inst->SetColor(color);
|
||||
|
||||
inst->SetCharges(charges);
|
||||
|
||||
if (item->IsClassCommon()) {
|
||||
for (int i = EQEmu::invaug::SOCKET_BEGIN; i <= EQEmu::invaug::SOCKET_END; i++) {
|
||||
if (aug[i])
|
||||
inst->PutAugment(this, i, aug[i]);
|
||||
}
|
||||
}
|
||||
|
||||
inv->PutItem(slot_id, *inst);
|
||||
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -41,6 +41,8 @@ public:
|
||||
private:
|
||||
void SetTitaniumDefaultStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc);
|
||||
void SetSoFDefaultStartZone(PlayerProfile_Struct* in_pp, CharCreate_Struct* in_cc);
|
||||
|
||||
bool GetCharSelInventory(uint32 account_id, char* name, EQEmu::InventoryProfile* inv);
|
||||
};
|
||||
|
||||
extern WorldDatabase database;
|
||||
|
||||
@ -107,16 +107,10 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
|
||||
float iAggroRange = GetAggroRange();
|
||||
|
||||
float t1, t2, t3;
|
||||
t1 = mob->GetX() - GetX();
|
||||
t2 = mob->GetY() - GetY();
|
||||
t3 = mob->GetZ() - GetZ();
|
||||
//Cheap ABS()
|
||||
if(t1 < 0)
|
||||
t1 = 0 - t1;
|
||||
if(t2 < 0)
|
||||
t2 = 0 - t2;
|
||||
if(t3 < 0)
|
||||
t3 = 0 - t3;
|
||||
t1 = std::abs(mob->GetX() - GetX());
|
||||
t2 = std::abs(mob->GetY() - GetY());
|
||||
t3 = std::abs(mob->GetZ() - GetZ());
|
||||
|
||||
if(( t1 > iAggroRange)
|
||||
|| ( t2 > iAggroRange)
|
||||
|| ( t3 > iAggroRange) ) {
|
||||
@ -158,7 +152,7 @@ void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
|
||||
|
||||
if (RuleB(Aggro, UseLevelAggro))
|
||||
{
|
||||
if (GetLevel() < 18 && mob->GetLevelCon(GetLevel()) == CON_GRAY && GetBodyType() != 3)
|
||||
if (GetLevel() < RuleI(Aggro, MinAggroLevel) && mob->GetLevelCon(GetLevel()) == CON_GRAY && GetBodyType() != 3)
|
||||
{
|
||||
towho->Message(0, "...%s is red to me (basically)", mob->GetName(), dist2, iAggroRange2);
|
||||
return;
|
||||
@ -271,16 +265,10 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
// Image: I moved this up by itself above faction and distance checks because if one of these return true, theres no reason to go through the other information
|
||||
|
||||
float t1, t2, t3;
|
||||
t1 = mob->GetX() - GetX();
|
||||
t2 = mob->GetY() - GetY();
|
||||
t3 = mob->GetZ() - GetZ();
|
||||
//Cheap ABS()
|
||||
if(t1 < 0)
|
||||
t1 = 0 - t1;
|
||||
if(t2 < 0)
|
||||
t2 = 0 - t2;
|
||||
if(t3 < 0)
|
||||
t3 = 0 - t3;
|
||||
t1 = std::abs(mob->GetX() - GetX());
|
||||
t2 = std::abs(mob->GetY() - GetY());
|
||||
t3 = std::abs(mob->GetZ() - GetZ());
|
||||
|
||||
if(( t1 > iAggroRange)
|
||||
|| ( t2 > iAggroRange)
|
||||
|| ( t3 > iAggroRange)
|
||||
@ -336,7 +324,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
||||
(
|
||||
//old InZone check taken care of above by !mob->CastToClient()->Connected()
|
||||
(
|
||||
( GetLevel() >= 18 )
|
||||
( GetLevel() >= RuleI(Aggro, MinAggroLevel))
|
||||
||(GetBodyType() == 3)
|
||||
||( mob->IsClient() && mob->CastToClient()->IsSitting() )
|
||||
||( mob->GetLevelCon(GetLevel()) != CON_GRAY)
|
||||
@ -526,7 +514,7 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) {
|
||||
Log(Logs::General, Logs::None, "AIYellForHelp(\"%s\",\"%s\") %s attacking %s Dist %f Z %f",
|
||||
sender->GetName(), attacker->GetName(), mob->GetName(),
|
||||
attacker->GetName(), DistanceSquared(mob->GetPosition(),
|
||||
sender->GetPosition()), fabs(sender->GetZ()+mob->GetZ()));
|
||||
sender->GetPosition()), std::abs(sender->GetZ()+mob->GetZ()));
|
||||
#endif
|
||||
mob->AddToHateList(attacker, 25, 0, false);
|
||||
sender->AddAssistCap();
|
||||
|
||||
@ -179,14 +179,6 @@ void Client::CalcItemBonuses(StatBonuses* newbon) {
|
||||
SetTwoHanderEquipped(true);
|
||||
}
|
||||
|
||||
//Power Source Slot
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF)
|
||||
{
|
||||
const EQEmu::ItemInstance* inst = m_inv[EQEmu::invslot::SLOT_POWER_SOURCE];
|
||||
if(inst)
|
||||
AddItemBonuses(inst, newbon);
|
||||
}
|
||||
|
||||
//tribute items
|
||||
for (i = EQEmu::invslot::TRIBUTE_BEGIN; i <= EQEmu::invslot::TRIBUTE_END; i++) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[i];
|
||||
@ -3261,7 +3253,7 @@ void NPC::CalcItemBonuses(StatBonuses *newbon)
|
||||
{
|
||||
if(newbon){
|
||||
|
||||
for (int i = EQEmu::invslot::EQUIPMENT_BEGIN; i <= EQEmu::invslot::EQUIPMENT_END; i++){
|
||||
for (int i = EQEmu::invslot::BONUS_BEGIN; i <= EQEmu::invslot::BONUS_STAT_END; i++){
|
||||
const EQEmu::ItemData *cur = database.GetItem(equipment[i]);
|
||||
if(cur){
|
||||
//basic stats
|
||||
@ -3353,13 +3345,6 @@ void Client::CalcItemScale() {
|
||||
if (CalcItemScale(EQEmu::invslot::TRIBUTE_BEGIN, EQEmu::invslot::TRIBUTE_END)) // (< 405)
|
||||
changed = true;
|
||||
|
||||
//Power Source Slot
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF)
|
||||
{
|
||||
if (CalcItemScale(EQEmu::invslot::SLOT_POWER_SOURCE, EQEmu::invslot::SLOT_POWER_SOURCE))
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if(changed)
|
||||
{
|
||||
CalcBonuses();
|
||||
@ -3447,13 +3432,6 @@ void Client::DoItemEnterZone() {
|
||||
if (DoItemEnterZone(EQEmu::invslot::TRIBUTE_BEGIN, EQEmu::invslot::TRIBUTE_END)) // (< 405)
|
||||
changed = true;
|
||||
|
||||
//Power Source Slot
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF)
|
||||
{
|
||||
if (DoItemEnterZone(EQEmu::invslot::SLOT_POWER_SOURCE, EQEmu::invslot::SLOT_POWER_SOURCE))
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if(changed)
|
||||
{
|
||||
CalcBonuses();
|
||||
@ -3486,7 +3464,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) {
|
||||
uint16 oldexp = inst->GetExp();
|
||||
|
||||
parse->EventItem(EVENT_ITEM_ENTER_ZONE, this, inst, nullptr, "", 0);
|
||||
if (i <= EQEmu::invslot::slotAmmo || i == EQEmu::invslot::SLOT_POWER_SOURCE) {
|
||||
if (i <= EQEmu::invslot::EQUIPMENT_END) {
|
||||
parse->EventItem(EVENT_EQUIP_ITEM, this, inst, nullptr, "", i);
|
||||
}
|
||||
|
||||
@ -3496,7 +3474,7 @@ bool Client::DoItemEnterZone(uint32 slot_x, uint32 slot_y) {
|
||||
update_slot = true;
|
||||
}
|
||||
} else {
|
||||
if (i <= EQEmu::invslot::slotAmmo || i == EQEmu::invslot::SLOT_POWER_SOURCE) {
|
||||
if (i <= EQEmu::invslot::EQUIPMENT_END) {
|
||||
parse->EventItem(EVENT_EQUIP_ITEM, this, inst, nullptr, "", i);
|
||||
}
|
||||
|
||||
|
||||
116
zone/bot.cpp
116
zone/bot.cpp
@ -38,6 +38,8 @@ Bot::Bot(NPCType npcTypeData, Client* botOwner) : NPC(&npcTypeData, nullptr, glm
|
||||
this->_botOwnerCharacterID = 0;
|
||||
}
|
||||
|
||||
m_inv.SetInventoryVersion(EQEmu::versions::MobVersion::Bot);
|
||||
|
||||
_guildRank = 0;
|
||||
_guildId = 0;
|
||||
_lastTotalPlayTime = 0;
|
||||
@ -110,6 +112,8 @@ Bot::Bot(uint32 botID, uint32 botOwnerCharacterID, uint32 botSpellsID, double to
|
||||
|
||||
auto bot_owner = GetBotOwner();
|
||||
|
||||
m_inv.SetInventoryVersion(EQEmu::versions::MobVersion::Bot);
|
||||
|
||||
_guildRank = 0;
|
||||
_guildId = 0;
|
||||
_lastTotalPlayTime = totalPlayTime;
|
||||
@ -1850,6 +1854,13 @@ bool Bot::Process() {
|
||||
SendHPUpdate();
|
||||
if(HasPet())
|
||||
GetPet()->SendHPUpdate();
|
||||
|
||||
// hack fix until percentage changes can be implemented
|
||||
auto g = GetGroup();
|
||||
if (g) {
|
||||
g->SendManaPacketFrom(this);
|
||||
g->SendEndurancePacketFrom(this);
|
||||
}
|
||||
}
|
||||
|
||||
if(GetAppearance() == eaDead && GetHP() > 0)
|
||||
@ -2261,10 +2272,15 @@ void Bot::AI_Process() {
|
||||
}
|
||||
|
||||
if (find_target) {
|
||||
if (IsRooted())
|
||||
if (IsRooted()) {
|
||||
SetTarget(hate_list.GetClosestEntOnHateList(this));
|
||||
else
|
||||
SetTarget(hate_list.GetEntWithMostHateOnList(this));
|
||||
}
|
||||
else {
|
||||
// This will keep bots on target for now..but, future updates will allow for rooting/stunning
|
||||
SetTarget(hate_list.GetEscapingEntOnHateList(leash_owner, BOT_LEASH_DISTANCE));
|
||||
if (!GetTarget())
|
||||
SetTarget(hate_list.GetEntWithMostHateOnList(this));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_TARGET();
|
||||
@ -2471,6 +2487,8 @@ void Bot::AI_Process() {
|
||||
ChangeBotArcherWeapons(IsBotArcher());
|
||||
}
|
||||
|
||||
// all of this needs review...
|
||||
|
||||
if (IsBotArcher() && atArcheryRange)
|
||||
atCombatRange = true;
|
||||
else if (caster_distance_max && tar_distance <= caster_distance_max)
|
||||
@ -2567,6 +2585,10 @@ void Bot::AI_Process() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsBotNonSpellFighter() && AI_EngagedCastCheck()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Up to this point, GetTarget() has been safe to dereference since the initial
|
||||
// TEST_TARGET() call. Due to the chance of the target dying and our pointer
|
||||
// being nullified, we need to test it before dereferencing to avoid crashes
|
||||
@ -2576,7 +2598,7 @@ void Bot::AI_Process() {
|
||||
if (GetTarget()->GetHPRatio() <= 99.0f)
|
||||
BotRangedAttack(tar);
|
||||
}
|
||||
else if (!IsBotArcher() && (!(IsBotCaster() && GetLevel() >= RuleI(Bots, CasterStopMeleeLevel)))) {
|
||||
else if (!IsBotArcher() && (IsBotNonSpellFighter() || GetLevel() < GetStopMeleeLevel())) {
|
||||
// we can't fight if we don't have a target, are stun/mezzed or dead..
|
||||
// Stop attacking if the target is enraged
|
||||
TEST_TARGET();
|
||||
@ -3643,15 +3665,13 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
||||
ClientReturn(const ItemInstance* item, int16 from, const char* name = "") : returnItemInstance(item), fromBotSlot(from), toClientSlot(invslot::SLOT_INVALID), adjustStackSize(0), failedItemName(name) { }
|
||||
};
|
||||
|
||||
static const int16 proxyPowerSource = 22;
|
||||
|
||||
static const int16 bot_equip_order[(invslot::CORPSE_BEGIN + 1)] = {
|
||||
static const int16 bot_equip_order[invslot::EQUIPMENT_COUNT] = {
|
||||
invslot::slotCharm, invslot::slotEar1, invslot::slotHead, invslot::slotFace,
|
||||
invslot::slotEar2, invslot::slotNeck, invslot::slotShoulders, invslot::slotArms,
|
||||
invslot::slotBack, invslot::slotWrist1, invslot::slotWrist2, invslot::slotRange,
|
||||
invslot::slotHands, invslot::slotPrimary, invslot::slotSecondary, invslot::slotFinger1,
|
||||
invslot::slotFinger2, invslot::slotChest, invslot::slotLegs, invslot::slotFeet,
|
||||
invslot::slotWaist, invslot::slotAmmo, proxyPowerSource // invslot::SLOT_POWER_SOURCE
|
||||
invslot::slotWaist, invslot::slotPowerSource, invslot::slotAmmo
|
||||
};
|
||||
|
||||
enum { stageStackable = 0, stageEmpty, stageReplaceable };
|
||||
@ -3787,9 +3807,7 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
||||
//}
|
||||
|
||||
if (stage_loop != stageReplaceable) {
|
||||
if ((index == proxyPowerSource) && m_inv[invslot::SLOT_POWER_SOURCE])
|
||||
continue;
|
||||
else if (m_inv[index])
|
||||
if (m_inv[index])
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3838,18 +3856,10 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
||||
}
|
||||
}
|
||||
|
||||
if (index == proxyPowerSource) {
|
||||
trade_iterator.toBotSlot = invslot::SLOT_POWER_SOURCE;
|
||||
trade_iterator.toBotSlot = index;
|
||||
|
||||
if (m_inv[invslot::SLOT_POWER_SOURCE])
|
||||
client_return.push_back(ClientReturn(m_inv[invslot::SLOT_POWER_SOURCE], invslot::SLOT_POWER_SOURCE));
|
||||
}
|
||||
else {
|
||||
trade_iterator.toBotSlot = index;
|
||||
|
||||
if (m_inv[index])
|
||||
client_return.push_back(ClientReturn(m_inv[index], index));
|
||||
}
|
||||
if (m_inv[index])
|
||||
client_return.push_back(ClientReturn(m_inv[index], index));
|
||||
|
||||
break;
|
||||
}
|
||||
@ -3878,6 +3888,8 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
||||
client->ResetTrade();
|
||||
return;
|
||||
}
|
||||
// non-failing checks above are causing this to trigger (i.e., !ItemClassCommon and !IsEquipable{race, class, min_level})
|
||||
// this process is hindered by not having bots use the inventory trade method (TODO: implement bot inventory use)
|
||||
if (client->CheckLoreConflict(return_instance->GetItem())) {
|
||||
client->Message(CC_Yellow, "You already have lore equipment matching the item '%s' - Trade Canceled!", return_instance->GetItem()->Name);
|
||||
client->ResetTrade();
|
||||
@ -3981,8 +3993,17 @@ void Bot::PerformTradeWithClient(int16 beginSlotID, int16 endSlotID, Client* cli
|
||||
|
||||
m_inv.PutItem(trade_iterator.toBotSlot, *trade_iterator.tradeItemInstance);
|
||||
this->BotAddEquipItem(trade_iterator.toBotSlot, (trade_iterator.tradeItemInstance ? trade_iterator.tradeItemInstance->GetID() : 0));
|
||||
trade_iterator.tradeItemInstance = nullptr; // actual deletion occurs in client delete below
|
||||
|
||||
client->DeleteItemInInventory(trade_iterator.fromClientSlot, 0, (trade_iterator.fromClientSlot == EQEmu::invslot::slotCursor));
|
||||
trade_iterator.tradeItemInstance = nullptr;
|
||||
|
||||
// database currently has unattuned item saved in inventory..it will be attuned on next bot load
|
||||
// this prevents unattuned item returns in the mean time (TODO: re-work process)
|
||||
if (trade_iterator.toBotSlot >= invslot::EQUIPMENT_BEGIN && trade_iterator.toBotSlot <= invslot::EQUIPMENT_END) {
|
||||
auto attune_item = m_inv.GetItem(trade_iterator.toBotSlot);
|
||||
if (attune_item && attune_item->GetItem()->Attuneable)
|
||||
attune_item->SetAttuned(true);
|
||||
}
|
||||
}
|
||||
|
||||
// trade messages
|
||||
@ -4006,6 +4027,15 @@ bool Bot::Death(Mob *killerMob, int32 damage, uint16 spell_id, EQEmu::skills::Sk
|
||||
return false;
|
||||
|
||||
Save();
|
||||
|
||||
Mob *my_owner = GetBotOwner();
|
||||
if (my_owner && my_owner->IsClient() && my_owner->CastToClient()->GetBotOptionDeathMarquee()) {
|
||||
if (killerMob)
|
||||
my_owner->CastToClient()->SendMarqueeMessage(CC_Yellow, 510, 0, 1000, 3000, StringFormat("%s has been slain by %s", GetCleanName(), killerMob->GetCleanName()));
|
||||
else
|
||||
my_owner->CastToClient()->SendMarqueeMessage(CC_Yellow, 510, 0, 1000, 3000, StringFormat("%s has been slain", GetCleanName()));
|
||||
}
|
||||
|
||||
Mob *give_exp = hate_list.GetDamageTopOnHateList(this);
|
||||
Client *give_exp_client = nullptr;
|
||||
if(give_exp && give_exp->IsClient())
|
||||
@ -4634,6 +4664,7 @@ int32 Bot::GetBotFocusEffect(BotfocusType bottype, uint16 spell_id) {
|
||||
int32 focus_max = 0;
|
||||
int32 focus_max_real = 0;
|
||||
//item focus
|
||||
// are focus effects the same as bonus? (slotAmmo-excluded)
|
||||
for (int x = EQEmu::invslot::EQUIPMENT_BEGIN; x <= EQEmu::invslot::EQUIPMENT_END; x++) {
|
||||
TempItem = nullptr;
|
||||
EQEmu::ItemInstance* ins = GetBotItem(x);
|
||||
@ -7589,10 +7620,7 @@ void Bot::ProcessBotInspectionRequest(Bot* inspectedBot, Client* client) {
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
const EQEmu::ItemInstance* inst = nullptr;
|
||||
|
||||
// Modded to display power source items (will only show up on SoF+ client inspect windows though.)
|
||||
// I don't think bots are currently coded to use them..but, you'll have to use '#bot inventory list'
|
||||
// to see them on a Titanium client when/if they are activated.
|
||||
for (int16 L = EQEmu::invslot::EQUIPMENT_BEGIN; L <= EQEmu::invslot::slotWaist; L++) {
|
||||
for (int16 L = EQEmu::invslot::EQUIPMENT_BEGIN; L <= EQEmu::invslot::EQUIPMENT_END; L++) {
|
||||
inst = inspectedBot->GetBotItem(L);
|
||||
|
||||
if(inst) {
|
||||
@ -7601,33 +7629,15 @@ void Bot::ProcessBotInspectionRequest(Bot* inspectedBot, Client* client) {
|
||||
strcpy(insr->itemnames[L], item->Name);
|
||||
insr->itemicons[L] = item->Icon;
|
||||
}
|
||||
else
|
||||
else {
|
||||
insr->itemnames[L][0] = '\0';
|
||||
insr->itemicons[L] = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inst = inspectedBot->GetBotItem(EQEmu::invslot::SLOT_POWER_SOURCE);
|
||||
|
||||
if(inst) {
|
||||
item = inst->GetItem();
|
||||
if(item) {
|
||||
strcpy(insr->itemnames[SoF::invslot::slotPowerSource], item->Name);
|
||||
insr->itemicons[SoF::invslot::slotPowerSource] = item->Icon;
|
||||
else {
|
||||
insr->itemnames[L][0] = '\0';
|
||||
insr->itemicons[L] = 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
insr->itemicons[SoF::invslot::slotPowerSource] = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
inst = inspectedBot->GetBotItem(EQEmu::invslot::slotAmmo);
|
||||
|
||||
if(inst) {
|
||||
item = inst->GetItem();
|
||||
if(item) {
|
||||
strcpy(insr->itemnames[SoF::invslot::slotAmmo], item->Name);
|
||||
insr->itemicons[SoF::invslot::slotAmmo] = item->Icon;
|
||||
}
|
||||
else
|
||||
insr->itemicons[SoF::invslot::slotAmmo] = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
strcpy(insr->text, inspectedBot->GetInspectMessage().text);
|
||||
@ -7640,8 +7650,8 @@ void Bot::CalcItemBonuses(StatBonuses* newbon)
|
||||
{
|
||||
const EQEmu::ItemData* itemtmp = nullptr;
|
||||
|
||||
for (int i = EQEmu::invslot::EQUIPMENT_BEGIN; i <= (EQEmu::invslot::EQUIPMENT_END + 1); ++i) {
|
||||
const EQEmu::ItemInstance* item = GetBotItem((i == 22 ? 9999 : i));
|
||||
for (int i = EQEmu::invslot::BONUS_BEGIN; i <= EQEmu::invslot::BONUS_STAT_END; ++i) {
|
||||
const EQEmu::ItemInstance* item = GetBotItem(i);
|
||||
if(item) {
|
||||
AddItemBonuses(item, newbon);
|
||||
}
|
||||
|
||||
53
zone/bot.h
53
zone/bot.h
@ -80,33 +80,33 @@ static const std::string bot_stance_name[BOT_STANCE_COUNT] = {
|
||||
|
||||
static const char* GetBotStanceName(int stance_id) { return bot_stance_name[VALIDBOTSTANCE(stance_id)].c_str(); }
|
||||
|
||||
#define VALIDBOTEQUIPSLOT(x) ((x >= EQEmu::invslot::EQUIPMENT_BEGIN && x <= EQEmu::invslot::EQUIPMENT_END) ? (x) : ((x == EQEmu::invslot::SLOT_POWER_SOURCE) ? (22) : (23)))
|
||||
#define VALIDBOTEQUIPSLOT(x) ((x >= EQEmu::invslot::EQUIPMENT_BEGIN && x <= EQEmu::invslot::EQUIPMENT_END) ? (x) : (EQEmu::invslot::EQUIPMENT_COUNT))
|
||||
|
||||
static std::string bot_equip_slot_name[EQEmu::invslot::EQUIPMENT_COUNT + 2] =
|
||||
static const std::string bot_equip_slot_name[EQEmu::invslot::EQUIPMENT_COUNT + 1] =
|
||||
{
|
||||
"Charm", // MainCharm
|
||||
"Left Ear", // MainEar1
|
||||
"Head", // MainHead
|
||||
"Face", // MainFace
|
||||
"Right Ear", // MainEar2
|
||||
"Neck", // MainNeck
|
||||
"Shoulders", // MainShoulders
|
||||
"Arms", // MainArms
|
||||
"Back", // MainBack
|
||||
"Left Wrist", // MainWrist1
|
||||
"Right Wrist", // MainWrist2
|
||||
"Range", // MainRange
|
||||
"Hands", // MainHands
|
||||
"Primary Hand", // MainPrimary
|
||||
"Secondary Hand", // MainSecondary
|
||||
"Left Finger", // MainFinger1
|
||||
"Right Finger", // MainFinger2
|
||||
"Chest", // MainChest
|
||||
"Legs", // MainLegs
|
||||
"Feet", // MainFeet
|
||||
"Waist", // MainWaist
|
||||
"Ammo", // MainAmmo
|
||||
"Power Source", // 22 (MainPowerSource = 9999)
|
||||
"Charm", // slotCharm
|
||||
"Ear 1", // slotEar1
|
||||
"Head", // slotHead
|
||||
"Face", // slotFace
|
||||
"Ear 2", // slotEar2
|
||||
"Neck", // slotNeck
|
||||
"Shoulders", // slotShoulders
|
||||
"Arms", // slotArms
|
||||
"Back", // slotBack
|
||||
"Wrist 1", // slotWrist1
|
||||
"Wrist 2", // slotWrist2
|
||||
"Range", // slotRange
|
||||
"Hands", // slotHands
|
||||
"Primary", // slotPrimary
|
||||
"Secondary", // slotSecondary
|
||||
"Finger 1", // slotFinger1
|
||||
"Finger 2", // slotFinger2
|
||||
"Chest", // slotChest
|
||||
"Legs", // slotLegs
|
||||
"Feet", // slotFeet
|
||||
"Waist", // slotWaist
|
||||
"Power Source", // slotPowerSource
|
||||
"Ammo", // slotAmmo
|
||||
"Unknown"
|
||||
};
|
||||
|
||||
@ -534,6 +534,9 @@ public:
|
||||
bool IsBotCaster() { return IsCasterClass(GetClass()); }
|
||||
bool IsBotINTCaster() { return IsINTCasterClass(GetClass()); }
|
||||
bool IsBotWISCaster() { return IsWISCasterClass(GetClass()); }
|
||||
bool IsBotSpellFighter() { return IsSpellFighterClass(GetClass()); }
|
||||
bool IsBotFighter() { return IsFighterClass(GetClass()); }
|
||||
bool IsBotNonSpellFighter() { return IsNonSpellFighterClass(GetClass()); }
|
||||
bool CanHeal();
|
||||
int GetRawACNoShield(int &shield_ac);
|
||||
|
||||
|
||||
@ -1399,6 +1399,7 @@ int bot_command_init(void)
|
||||
bot_command_add("lull", "Orders a bot to cast a pacification spell", 0, bot_command_lull) ||
|
||||
bot_command_add("mesmerize", "Orders a bot to cast a mesmerization spell", 0, bot_command_mesmerize) ||
|
||||
bot_command_add("movementspeed", "Orders a bot to cast a movement speed enhancement spell", 0, bot_command_movement_speed) ||
|
||||
bot_command_add("owneroption", "Sets options available to bot owners", 0, bot_command_owner_option) ||
|
||||
bot_command_add("pet", "Lists the available bot pet [subcommands]", 0, bot_command_pet) ||
|
||||
bot_command_add("petremove", "Orders a bot to remove its pet", 0, bot_subcommand_pet_remove) ||
|
||||
bot_command_add("petsettype", "Orders a Magician bot to use a specified pet type", 0, bot_subcommand_pet_set_type) ||
|
||||
@ -3437,6 +3438,25 @@ void bot_command_movement_speed(Client *c, const Seperator *sep)
|
||||
helper_no_available_bots(c, my_bot);
|
||||
}
|
||||
|
||||
void bot_command_owner_option(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (helper_is_help_or_usage(sep->arg[1])) {
|
||||
c->Message(m_usage, "usage: %s [deathmarquee]", sep->arg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string owner_option = sep->arg[1];
|
||||
|
||||
if (!owner_option.compare("deathmarquee")) {
|
||||
c->SetBotOptionDeathMarquee(!c->GetBotOptionDeathMarquee());
|
||||
c->Message(m_action, "Bot death marquee is now %s.", (c->GetBotOptionDeathMarquee() == true ? "enabled" : "disabled"));
|
||||
botdb.SaveOwnerOptionDeathMarquee(c->CharacterID(), c->GetBotOptionDeathMarquee());
|
||||
}
|
||||
else {
|
||||
c->Message(m_fail, "Owner option '%s' is not recognized.", owner_option.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void bot_command_pet(Client *c, const Seperator *sep)
|
||||
{
|
||||
/* VS2012 code - begin */
|
||||
@ -7194,13 +7214,13 @@ void bot_subcommand_inventory_list(Client *c, const Seperator *sep)
|
||||
linker.SetLinkType(EQEmu::saylink::SayLinkItemInst);
|
||||
|
||||
uint32 inventory_count = 0;
|
||||
for (int i = EQEmu::invslot::EQUIPMENT_BEGIN; i <= (EQEmu::invslot::EQUIPMENT_END + 1); ++i) {
|
||||
for (int i = EQEmu::invslot::EQUIPMENT_BEGIN; i <= EQEmu::invslot::EQUIPMENT_END; ++i) {
|
||||
if ((i == EQEmu::invslot::slotSecondary) && is2Hweapon)
|
||||
continue;
|
||||
|
||||
inst = my_bot->CastToBot()->GetBotItem(i == 22 ? EQEmu::invslot::SLOT_POWER_SOURCE : i);
|
||||
inst = my_bot->CastToBot()->GetBotItem(i);
|
||||
if (!inst || !inst->GetItem()) {
|
||||
c->Message(m_message, "I need something for my %s (slot %i)", GetBotEquipSlotName(i), (i == 22 ? EQEmu::invslot::SLOT_POWER_SOURCE : i));
|
||||
c->Message(m_message, "I need something for my %s (slot %i)", GetBotEquipSlotName(i), i);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -7210,7 +7230,7 @@ void bot_subcommand_inventory_list(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
linker.SetItemInst(inst);
|
||||
c->Message(m_message, "Using %s in my %s (slot %i)", linker.GenerateLink().c_str(), GetBotEquipSlotName(i), (i == 22 ? EQEmu::invslot::SLOT_POWER_SOURCE : i));
|
||||
c->Message(m_message, "Using %s in my %s (slot %i)", linker.GenerateLink().c_str(), GetBotEquipSlotName(i), i);
|
||||
|
||||
++inventory_count;
|
||||
}
|
||||
@ -7249,8 +7269,8 @@ void bot_subcommand_inventory_remove(Client *c, const Seperator *sep)
|
||||
}
|
||||
|
||||
int slotId = atoi(sep->arg[1]);
|
||||
if (!sep->IsNumber(1) || ((slotId > EQEmu::invslot::EQUIPMENT_END || slotId < EQEmu::invslot::EQUIPMENT_BEGIN) && slotId != EQEmu::invslot::SLOT_POWER_SOURCE)) {
|
||||
c->Message(m_fail, "Valid slots are 0-21 or 9999");
|
||||
if (!sep->IsNumber(1) || (slotId > EQEmu::invslot::EQUIPMENT_END || slotId < EQEmu::invslot::EQUIPMENT_BEGIN)) {
|
||||
c->Message(m_fail, "Valid slots are 0-22");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -7311,7 +7331,7 @@ void bot_subcommand_inventory_remove(Client *c, const Seperator *sep)
|
||||
case EQEmu::invslot::slotFinger2:
|
||||
case EQEmu::invslot::slotChest:
|
||||
case EQEmu::invslot::slotWaist:
|
||||
case EQEmu::invslot::SLOT_POWER_SOURCE:
|
||||
case EQEmu::invslot::slotPowerSource:
|
||||
case EQEmu::invslot::slotAmmo:
|
||||
c->Message(m_message, "My %s is %s unequipped", GetBotEquipSlotName(slotId), ((itm) ? ("now") : ("already")));
|
||||
break;
|
||||
@ -7356,14 +7376,14 @@ void bot_subcommand_inventory_window(Client *c, const Seperator *sep)
|
||||
//EQEmu::SayLinkEngine linker;
|
||||
//linker.SetLinkType(EQEmu::saylink::SayLinkItemInst);
|
||||
|
||||
for (int i = EQEmu::invslot::EQUIPMENT_BEGIN; i <= (EQEmu::invslot::EQUIPMENT_END + 1); ++i) {
|
||||
for (int i = EQEmu::invslot::EQUIPMENT_BEGIN; i <= EQEmu::invslot::EQUIPMENT_END; ++i) {
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
const EQEmu::ItemInstance* inst = my_bot->CastToBot()->GetBotItem(i == 22 ? EQEmu::invslot::SLOT_POWER_SOURCE : i);
|
||||
const EQEmu::ItemInstance* inst = my_bot->CastToBot()->GetBotItem(i);
|
||||
if (inst)
|
||||
item = inst->GetItem();
|
||||
|
||||
window_text.append("<c \"#FFFFFF\">");
|
||||
window_text.append(GetBotEquipSlotName(i == 22 ? EQEmu::invslot::SLOT_POWER_SOURCE : i));
|
||||
window_text.append(GetBotEquipSlotName(i));
|
||||
window_text.append(": ");
|
||||
if (item) {
|
||||
//window_text.append("</c>");
|
||||
|
||||
@ -575,6 +575,7 @@ void bot_command_levitation(Client *c, const Seperator *sep);
|
||||
void bot_command_lull(Client *c, const Seperator *sep);
|
||||
void bot_command_mesmerize(Client *c, const Seperator *sep);
|
||||
void bot_command_movement_speed(Client *c, const Seperator *sep);
|
||||
void bot_command_owner_option(Client *c, const Seperator *sep);
|
||||
void bot_command_pet(Client *c, const Seperator *sep);
|
||||
void bot_command_pick_lock(Client *c, const Seperator *sep);
|
||||
void bot_command_pull(Client *c, const Seperator *sep);
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
#include "bot_database.h"
|
||||
#include "bot.h"
|
||||
#include "client.h"
|
||||
|
||||
|
||||
BotDatabase botdb;
|
||||
@ -1138,7 +1139,7 @@ bool BotDatabase::LoadItems(const uint32 bot_id, EQEmu::InventoryProfile& invent
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
int16 slot_id = atoi(row[0]);
|
||||
if ((slot_id < EQEmu::invslot::EQUIPMENT_BEGIN || slot_id > EQEmu::invslot::EQUIPMENT_END) && slot_id != EQEmu::invslot::SLOT_POWER_SOURCE)
|
||||
if (slot_id < EQEmu::invslot::EQUIPMENT_BEGIN || slot_id > EQEmu::invslot::EQUIPMENT_END)
|
||||
continue;
|
||||
|
||||
uint32 item_id = atoi(row[1]);
|
||||
@ -1173,7 +1174,7 @@ bool BotDatabase::LoadItems(const uint32 bot_id, EQEmu::InventoryProfile& invent
|
||||
if (item_inst->GetItem()->Attuneable) {
|
||||
if (atoi(row[4]))
|
||||
item_inst->SetAttuned(true);
|
||||
else if (((slot_id >= EQEmu::invslot::EQUIPMENT_BEGIN) && (slot_id <= EQEmu::invslot::EQUIPMENT_END) || slot_id == EQEmu::invslot::SLOT_POWER_SOURCE))
|
||||
else if (slot_id >= EQEmu::invslot::EQUIPMENT_BEGIN && slot_id <= EQEmu::invslot::EQUIPMENT_END)
|
||||
item_inst->SetAttuned(true);
|
||||
}
|
||||
|
||||
@ -1241,7 +1242,7 @@ bool BotDatabase::LoadItemBySlot(Bot* bot_inst)
|
||||
|
||||
bool BotDatabase::LoadItemBySlot(const uint32 bot_id, const uint32 slot_id, uint32& item_id)
|
||||
{
|
||||
if (!bot_id || (slot_id > EQEmu::invslot::EQUIPMENT_END && slot_id != EQEmu::invslot::SLOT_POWER_SOURCE))
|
||||
if (!bot_id || slot_id > EQEmu::invslot::EQUIPMENT_END)
|
||||
return false;
|
||||
|
||||
query = StringFormat("SELECT `item_id` FROM `bot_inventories` WHERE `bot_id` = '%i' AND `slot_id` = '%i' LIMIT 1", bot_id, slot_id);
|
||||
@ -1259,7 +1260,7 @@ bool BotDatabase::LoadItemBySlot(const uint32 bot_id, const uint32 slot_id, uint
|
||||
|
||||
bool BotDatabase::SaveItemBySlot(Bot* bot_inst, const uint32 slot_id, const EQEmu::ItemInstance* item_inst)
|
||||
{
|
||||
if (!bot_inst || !bot_inst->GetBotID() || (slot_id > EQEmu::invslot::EQUIPMENT_END && slot_id != EQEmu::invslot::SLOT_POWER_SOURCE))
|
||||
if (!bot_inst || !bot_inst->GetBotID() || slot_id > EQEmu::invslot::EQUIPMENT_END)
|
||||
return false;
|
||||
|
||||
if (!DeleteItemBySlot(bot_inst->GetBotID(), slot_id))
|
||||
@ -1343,7 +1344,7 @@ bool BotDatabase::SaveItemBySlot(Bot* bot_inst, const uint32 slot_id, const EQEm
|
||||
|
||||
bool BotDatabase::DeleteItemBySlot(const uint32 bot_id, const uint32 slot_id)
|
||||
{
|
||||
if (!bot_id || (slot_id > EQEmu::invslot::EQUIPMENT_END && slot_id != EQEmu::invslot::SLOT_POWER_SOURCE))
|
||||
if (!bot_id || slot_id > EQEmu::invslot::EQUIPMENT_END)
|
||||
return false;
|
||||
|
||||
query = StringFormat("DELETE FROM `bot_inventories` WHERE `bot_id` = '%u' AND `slot_id` = '%u'", bot_id, slot_id);
|
||||
@ -1382,7 +1383,7 @@ bool BotDatabase::SaveEquipmentColor(const uint32 bot_id, const int16 slot_id, c
|
||||
return false;
|
||||
|
||||
bool all_flag = (slot_id == -2);
|
||||
if ((slot_id < EQEmu::invslot::EQUIPMENT_BEGIN || slot_id > EQEmu::invslot::EQUIPMENT_END) && slot_id != EQEmu::invslot::SLOT_POWER_SOURCE && !all_flag)
|
||||
if ((slot_id < EQEmu::invslot::EQUIPMENT_BEGIN || slot_id > EQEmu::invslot::EQUIPMENT_END) && !all_flag)
|
||||
return false;
|
||||
|
||||
std::string where_clause;
|
||||
@ -1659,7 +1660,7 @@ bool BotDatabase::LoadPetItems(const uint32 bot_id, uint32* pet_items)
|
||||
return true;
|
||||
|
||||
int item_index = EQEmu::invslot::EQUIPMENT_BEGIN;
|
||||
for (auto row = results.begin(); row != results.end() && item_index <= EQEmu::invslot::EQUIPMENT_END; ++row) {
|
||||
for (auto row = results.begin(); row != results.end() && (item_index >= EQEmu::invslot::EQUIPMENT_BEGIN && item_index <= EQEmu::invslot::EQUIPMENT_END); ++row) {
|
||||
pet_items[item_index] = atoi(row[0]);
|
||||
++item_index;
|
||||
}
|
||||
@ -1683,7 +1684,7 @@ bool BotDatabase::SavePetItems(const uint32 bot_id, const uint32* pet_items, boo
|
||||
if (!saved_pet_index)
|
||||
return true;
|
||||
|
||||
for (int item_index = EQEmu::invslot::SLOT_BEGIN; item_index <= EQEmu::invslot::EQUIPMENT_END; ++item_index) {
|
||||
for (int item_index = EQEmu::invslot::EQUIPMENT_BEGIN; item_index <= EQEmu::invslot::EQUIPMENT_END; ++item_index) {
|
||||
if (!pet_items[item_index])
|
||||
continue;
|
||||
|
||||
@ -2185,6 +2186,51 @@ bool BotDatabase::SaveStopMeleeLevel(const uint32 owner_id, const uint32 bot_id,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::LoadOwnerOptions(Client *owner)
|
||||
{
|
||||
if (!owner || !owner->CharacterID())
|
||||
return false;
|
||||
|
||||
query = StringFormat(
|
||||
"SELECT `death_marquee` FROM `bot_owner_options`"
|
||||
" WHERE `owner_id` = '%u'",
|
||||
owner->CharacterID()
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
if (!results.RowCount()) {
|
||||
query = StringFormat("REPLACE INTO `bot_owner_options` (`owner_id`) VALUES ('%u')", owner->CharacterID());
|
||||
results = QueryDatabase(query);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto row = results.begin();
|
||||
owner->SetBotOptionDeathMarquee((atoi(row[0]) != 0));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BotDatabase::SaveOwnerOptionDeathMarquee(const uint32 owner_id, const bool flag)
|
||||
{
|
||||
if (!owner_id)
|
||||
return false;
|
||||
|
||||
query = StringFormat(
|
||||
"UPDATE `bot_owner_options`"
|
||||
" SET `death_marquee` = '%u'"
|
||||
" WHERE `owner_id` = '%u'",
|
||||
(flag == true ? 1 : 0),
|
||||
owner_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Bot bot-group functions */
|
||||
bool BotDatabase::QueryBotGroupExistence(const std::string& group_name, bool& extant_flag)
|
||||
|
||||
@ -32,6 +32,7 @@
|
||||
|
||||
class Bot;
|
||||
struct BotsAvailableList;
|
||||
class Client;
|
||||
|
||||
namespace EQEmu
|
||||
{
|
||||
@ -145,6 +146,8 @@ public:
|
||||
|
||||
bool SaveStopMeleeLevel(const uint32 owner_id, const uint32 bot_id, const uint8 sml_value);
|
||||
|
||||
bool LoadOwnerOptions(Client *owner);
|
||||
bool SaveOwnerOptionDeathMarquee(const uint32 owner_id, const bool flag);
|
||||
|
||||
/* Bot bot-group functions */
|
||||
bool QueryBotGroupExistence(const std::string& botgroup_name, bool& extant_flag);
|
||||
|
||||
@ -326,6 +326,10 @@ Client::Client(EQStreamInterface* ieqs)
|
||||
temp_pvp = false;
|
||||
is_client_moving = false;
|
||||
|
||||
#ifdef BOTS
|
||||
bot_owner_options = DefaultBotOwnerOptions;
|
||||
#endif
|
||||
|
||||
AI_Init();
|
||||
}
|
||||
|
||||
@ -672,7 +676,7 @@ bool Client::Save(uint8 iCommitNow) {
|
||||
|
||||
// perform snapshot before SaveCharacterData() so that m_epp will contain the updated time
|
||||
if (RuleB(Character, ActiveInvSnapshots) && time(nullptr) >= GetNextInvSnapshotTime()) {
|
||||
if (database.SaveCharacterInventorySnapshot(CharacterID())) {
|
||||
if (database.SaveCharacterInvSnapshot(CharacterID())) {
|
||||
SetNextInvSnapshot(RuleI(Character, InvSnapshotMinIntervalM));
|
||||
}
|
||||
else {
|
||||
@ -1898,7 +1902,7 @@ void Client::CheckManaEndUpdate() {
|
||||
else if (group) {
|
||||
group->SendEndurancePacketFrom(this);
|
||||
}
|
||||
|
||||
|
||||
auto endurance_packet = new EQApplicationPacket(OP_EnduranceUpdate, sizeof(EnduranceUpdate_Struct));
|
||||
EnduranceUpdate_Struct* endurance_update = (EnduranceUpdate_Struct*)endurance_packet->pBuffer;
|
||||
endurance_update->cur_end = GetEndurance();
|
||||
@ -5674,56 +5678,34 @@ void Client::ProcessInspectRequest(Client* requestee, Client* requester) {
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
const EQEmu::ItemInstance* inst = nullptr;
|
||||
int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType);
|
||||
for(int16 L = 0; L <= 20; L++) {
|
||||
for(int16 L = EQEmu::invslot::EQUIPMENT_BEGIN; L <= EQEmu::invslot::EQUIPMENT_END; L++) {
|
||||
inst = requestee->GetInv().GetItem(L);
|
||||
|
||||
if(inst) {
|
||||
item = inst->GetItem();
|
||||
if(item) {
|
||||
strcpy(insr->itemnames[L], item->Name);
|
||||
if (inst && inst->GetOrnamentationAug(ornamentationAugtype))
|
||||
{
|
||||
const EQEmu::ItemData *aug_item = inst->GetOrnamentationAug(ornamentationAugtype)->GetItem();
|
||||
|
||||
const EQEmu::ItemData *aug_item = nullptr;
|
||||
if (inst->GetOrnamentationAug(ornamentationAugtype))
|
||||
inst->GetOrnamentationAug(ornamentationAugtype)->GetItem();
|
||||
|
||||
if (aug_item)
|
||||
insr->itemicons[L] = aug_item->Icon;
|
||||
}
|
||||
else if (inst && inst->GetOrnamentationIcon())
|
||||
{
|
||||
else if (inst->GetOrnamentationIcon())
|
||||
insr->itemicons[L] = inst->GetOrnamentationIcon();
|
||||
}
|
||||
else
|
||||
{
|
||||
insr->itemicons[L] = item->Icon;
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
insr->itemnames[L][0] = '\0';
|
||||
insr->itemicons[L] = 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inst = requestee->GetInv().GetItem(EQEmu::invslot::SLOT_POWER_SOURCE);
|
||||
|
||||
if(inst) {
|
||||
item = inst->GetItem();
|
||||
if(item) {
|
||||
// we shouldn't do this..but, that's the way it's coded atm...
|
||||
// (this type of action should be handled exclusively in the client translator)
|
||||
strcpy(insr->itemnames[SoF::invslot::slotPowerSource], item->Name);
|
||||
insr->itemicons[SoF::invslot::slotPowerSource] = item->Icon;
|
||||
else {
|
||||
insr->itemnames[L][0] = '\0';
|
||||
insr->itemicons[L] = 0xFFFFFFFF;
|
||||
}
|
||||
else
|
||||
insr->itemicons[SoF::invslot::slotPowerSource] = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
inst = requestee->GetInv().GetItem(EQEmu::invslot::slotAmmo);
|
||||
|
||||
if(inst) {
|
||||
item = inst->GetItem();
|
||||
if(item) {
|
||||
strcpy(insr->itemnames[SoF::invslot::slotAmmo], item->Name);
|
||||
insr->itemicons[SoF::invslot::slotAmmo] = item->Icon;
|
||||
}
|
||||
else
|
||||
insr->itemicons[SoF::invslot::slotAmmo] = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
strcpy(insr->text, requestee->GetInspectMessage().text);
|
||||
@ -7773,9 +7755,9 @@ void Client::SetFactionLevel(uint32 char_id, uint32 npc_id, uint8 char_class, ui
|
||||
{
|
||||
//The ole switcheroo
|
||||
if (npc_value[i] > 0)
|
||||
npc_value[i] = -abs(npc_value[i]);
|
||||
npc_value[i] = -std::abs(npc_value[i]);
|
||||
else if (npc_value[i] < 0)
|
||||
npc_value[i] = abs(npc_value[i]);
|
||||
npc_value[i] = std::abs(npc_value[i]);
|
||||
}
|
||||
|
||||
// Adjust the amount you can go up or down so the resulting range
|
||||
@ -8076,13 +8058,8 @@ void Client::TickItemCheck()
|
||||
|
||||
if(zone->tick_items.empty()) { return; }
|
||||
|
||||
//Scan equip slots for items
|
||||
for (i = EQEmu::invslot::EQUIPMENT_BEGIN; i <= EQEmu::invslot::EQUIPMENT_END; i++)
|
||||
{
|
||||
TryItemTick(i);
|
||||
}
|
||||
//Scan main inventory + cursor
|
||||
for (i = EQEmu::invslot::GENERAL_BEGIN; i <= EQEmu::invslot::slotCursor; i++)
|
||||
//Scan equip, general, cursor slots for items
|
||||
for (i = EQEmu::invslot::POSSESSIONS_BEGIN; i <= EQEmu::invslot::POSSESSIONS_END; i++)
|
||||
{
|
||||
TryItemTick(i);
|
||||
}
|
||||
@ -8134,16 +8111,10 @@ void Client::TryItemTick(int slot)
|
||||
void Client::ItemTimerCheck()
|
||||
{
|
||||
int i;
|
||||
for (i = EQEmu::invslot::EQUIPMENT_BEGIN; i <= EQEmu::invslot::EQUIPMENT_END; i++)
|
||||
for (i = EQEmu::invslot::POSSESSIONS_BEGIN; i <= EQEmu::invslot::POSSESSIONS_END; i++)
|
||||
{
|
||||
TryItemTimer(i);
|
||||
}
|
||||
|
||||
for (i = EQEmu::invslot::GENERAL_BEGIN; i <= EQEmu::invslot::slotCursor; i++)
|
||||
{
|
||||
TryItemTimer(i);
|
||||
}
|
||||
|
||||
for (i = EQEmu::invbag::GENERAL_BAGS_BEGIN; i <= EQEmu::invbag::CURSOR_BAG_END; i++)
|
||||
{
|
||||
TryItemTimer(i);
|
||||
|
||||
@ -1614,6 +1614,25 @@ private:
|
||||
|
||||
void InterrogateInventory_(bool errorcheck, Client* requester, int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, bool log, bool silent, bool &error, int depth);
|
||||
bool InterrogateInventory_error(int16 head, int16 index, const EQEmu::ItemInstance* inst, const EQEmu::ItemInstance* parent, int depth);
|
||||
|
||||
#ifdef BOTS
|
||||
struct BotOwnerOptions {
|
||||
bool death_marquee;
|
||||
};
|
||||
|
||||
BotOwnerOptions bot_owner_options;
|
||||
|
||||
const BotOwnerOptions DefaultBotOwnerOptions = {
|
||||
false // death_marquee
|
||||
};
|
||||
|
||||
public:
|
||||
void SetBotOptionDeathMarquee(bool flag) { bot_owner_options.death_marquee = flag; }
|
||||
|
||||
bool GetBotOptionDeathMarquee() const { return bot_owner_options.death_marquee; }
|
||||
|
||||
private:
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -1496,6 +1496,8 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
#ifdef BOTS
|
||||
botdb.LoadOwnerOptions(this);
|
||||
// TODO: mod below function for loading spawned botgroups
|
||||
Bot::LoadAndSpawnAllZonedBots(this);
|
||||
#endif
|
||||
|
||||
@ -2902,8 +2904,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app)
|
||||
bool deleteItems = false;
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF)
|
||||
{
|
||||
if ((in_augment->container_slot < 0 || in_augment->container_slot >= EQEmu::invslot::slotCursor) &&
|
||||
in_augment->container_slot != EQEmu::invslot::SLOT_POWER_SOURCE &&
|
||||
if ((in_augment->container_slot < EQEmu::invslot::EQUIPMENT_BEGIN || in_augment->container_slot > EQEmu::invslot::GENERAL_END) &&
|
||||
(in_augment->container_slot < EQEmu::invbag::GENERAL_BAGS_BEGIN || in_augment->container_slot > EQEmu::invbag::GENERAL_BAGS_END))
|
||||
{
|
||||
Message(13, "The server does not allow augmentation actions from this slot.");
|
||||
@ -8036,7 +8037,7 @@ void Client::Handle_OP_InspectAnswer(const EQApplicationPacket *app)
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
|
||||
int ornamentationAugtype = RuleI(Character, OrnamentationAugmentType);
|
||||
for (int16 L = EQEmu::invslot::EQUIPMENT_BEGIN; L <= EQEmu::invslot::slotWaist; L++) {
|
||||
for (int16 L = EQEmu::invslot::EQUIPMENT_BEGIN; L <= EQEmu::invslot::EQUIPMENT_END; L++) {
|
||||
const EQEmu::ItemInstance* inst = GetInv().GetItem(L);
|
||||
item = inst ? inst->GetItem() : nullptr;
|
||||
|
||||
@ -8056,16 +8057,6 @@ void Client::Handle_OP_InspectAnswer(const EQApplicationPacket *app)
|
||||
else { insr->itemicons[L] = 0xFFFFFFFF; }
|
||||
}
|
||||
|
||||
const EQEmu::ItemInstance* inst = GetInv().GetItem(EQEmu::invslot::slotAmmo);
|
||||
item = inst ? inst->GetItem() : nullptr;
|
||||
|
||||
if (item) {
|
||||
// another one..I did these, didn't I!!?
|
||||
strcpy(insr->itemnames[SoF::invslot::slotAmmo], item->Name);
|
||||
insr->itemicons[SoF::invslot::slotAmmo] = item->Icon;
|
||||
}
|
||||
else { insr->itemicons[SoF::invslot::slotAmmo] = 0xFFFFFFFF; }
|
||||
|
||||
InspectMessage_Struct* newmessage = (InspectMessage_Struct*)insr->text;
|
||||
InspectMessage_Struct& playermessage = this->GetInspectMessage();
|
||||
memcpy(&playermessage, newmessage, sizeof(InspectMessage_Struct));
|
||||
|
||||
@ -238,6 +238,19 @@ bool Client::Process() {
|
||||
}
|
||||
}
|
||||
|
||||
if (RuleB(Character, ActiveInvSnapshots) && time(nullptr) >= GetNextInvSnapshotTime()) {
|
||||
if (database.SaveCharacterInvSnapshot(CharacterID())) {
|
||||
SetNextInvSnapshot(RuleI(Character, InvSnapshotMinIntervalM));
|
||||
Log(Logs::Moderate, Logs::Inventory, "Successful inventory snapshot taken of %s - setting next interval for %i minute%s.",
|
||||
GetName(), RuleI(Character, InvSnapshotMinIntervalM), (RuleI(Character, InvSnapshotMinIntervalM) == 1 ? "" : "s"));
|
||||
}
|
||||
else {
|
||||
SetNextInvSnapshot(RuleI(Character, InvSnapshotMinRetryM));
|
||||
Log(Logs::Moderate, Logs::Inventory, "Failed to take inventory snapshot of %s - retrying in %i minute%s.",
|
||||
GetName(), RuleI(Character, InvSnapshotMinRetryM), (RuleI(Character, InvSnapshotMinRetryM) == 1 ? "" : "s"));
|
||||
}
|
||||
}
|
||||
|
||||
bool may_use_attacks = false;
|
||||
/*
|
||||
Things which prevent us from attacking:
|
||||
@ -745,19 +758,6 @@ void Client::BulkSendInventoryItems()
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
|
||||
// PowerSource item
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[EQEmu::invslot::SLOT_POWER_SOURCE];
|
||||
if (inst) {
|
||||
inst->Serialize(ob, EQEmu::invslot::SLOT_POWER_SOURCE);
|
||||
|
||||
if (ob.tellp() == last_pos)
|
||||
Log(Logs::General, Logs::Inventory, "Serialization failed on item slot %d during BulkSendInventoryItems. Item skipped.", EQEmu::invslot::SLOT_POWER_SOURCE);
|
||||
|
||||
last_pos = ob.tellp();
|
||||
}
|
||||
}
|
||||
|
||||
// Bank items
|
||||
for (int16 slot_id = EQEmu::invslot::BANK_BEGIN; slot_id <= EQEmu::invslot::BANK_END; slot_id++) {
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
|
||||
404
zone/command.cpp
404
zone/command.cpp
@ -173,7 +173,6 @@ int command_init(void)
|
||||
command_add("castspell", "[spellid] - Cast a spell", 50, command_castspell) ||
|
||||
command_add("chat", "[channel num] [message] - Send a channel message to all zones", 200, command_chat) ||
|
||||
command_add("checklos", "- Check for line of sight to your target", 50, command_checklos) ||
|
||||
command_add("clearinvsnapshots", "[use rule] - Clear inventory snapshot history (true - elapsed entries, false - all entries)", 200, command_clearinvsnapshots) ||
|
||||
command_add("corpse", "- Manipulate corpses, use with no arguments for help", 50, command_corpse) ||
|
||||
command_add("corpsefix", "Attempts to bring corpses from underneath the ground within close proximity of the player", 0, command_corpsefix) ||
|
||||
command_add("crashtest", "- Crash the zoneserver", 255, command_crashtest) ||
|
||||
@ -240,7 +239,7 @@ int command_init(void)
|
||||
command_add("instance", "- Modify Instances", 200, command_instance) ||
|
||||
command_add("interrogateinv", "- use [help] argument for available options", 0, command_interrogateinv) ||
|
||||
command_add("interrupt", "[message id] [color] - Interrupt your casting. Arguments are optional.", 50, command_interrupt) ||
|
||||
command_add("invsnapshot", "- Takes an inventory snapshot of your current target", 80, command_invsnapshot) ||
|
||||
command_add("invsnapshot", "- Manipulates inventory snapshots for your current target", 80, command_invsnapshot) ||
|
||||
command_add("invul", "[on/off] - Turn player target's or your invulnerable flag on or off", 80, command_invul) ||
|
||||
command_add("ipban", "[IP address] - Ban IP by character name", 200, command_ipban) ||
|
||||
command_add("iplookup", "[charname] - Look up IP address of charname", 200, command_iplookup) ||
|
||||
@ -2809,52 +2808,6 @@ void command_peekinv(Client *c, const Seperator *sep)
|
||||
}
|
||||
}
|
||||
|
||||
if ((scopeBit & peekEquip) && (targetClient->ClientVersion() >= EQEmu::versions::ClientVersion::SoF)) {
|
||||
inst_main = targetClient->GetInv().GetItem(EQEmu::invslot::SLOT_POWER_SOURCE);
|
||||
if (inst_main) {
|
||||
itemsFound = true;
|
||||
item_data = inst_main->GetItem();
|
||||
}
|
||||
else {
|
||||
item_data = nullptr;
|
||||
}
|
||||
|
||||
linker.SetItemInst(inst_main);
|
||||
|
||||
c->Message(
|
||||
(item_data == nullptr),
|
||||
"%sSlot: %i, Item: %i (%s), Charges: %i",
|
||||
scope_prefix[scopeIndex],
|
||||
EQEmu::invslot::SLOT_POWER_SOURCE,
|
||||
((item_data == nullptr) ? 0 : item_data->ID),
|
||||
linker.GenerateLink().c_str(),
|
||||
((inst_main == nullptr) ? 0 : inst_main->GetCharges())
|
||||
);
|
||||
|
||||
if (inst_main && inst_main->IsClassCommon()) {
|
||||
for (uint8 indexAug = EQEmu::invaug::SOCKET_BEGIN; indexAug <= EQEmu::invaug::SOCKET_END; ++indexAug) {
|
||||
inst_aug = inst_main->GetItem(indexAug);
|
||||
if (!inst_aug) // extant only
|
||||
continue;
|
||||
|
||||
item_data = inst_aug->GetItem();
|
||||
linker.SetItemInst(inst_aug);
|
||||
|
||||
c->Message(
|
||||
(item_data == nullptr),
|
||||
".%sAugSlot: %i (Slot #%i, Aug idx #%i), Item: %i (%s), Charges: %i",
|
||||
scope_prefix[scopeIndex],
|
||||
INVALID_INDEX,
|
||||
EQEmu::invslot::SLOT_POWER_SOURCE,
|
||||
indexAug,
|
||||
((item_data == nullptr) ? 0 : item_data->ID),
|
||||
linker.GenerateLink().c_str(),
|
||||
((inst_sub == nullptr) ? 0 : inst_sub->GetCharges())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scopeBit & peekLimbo) {
|
||||
int limboIndex = 0;
|
||||
for (auto it = targetClient->GetInv().cursor_cbegin(); (it != targetClient->GetInv().cursor_cend()); ++it, ++limboIndex) {
|
||||
@ -3031,31 +2984,344 @@ void command_interrogateinv(Client *c, const Seperator *sep)
|
||||
|
||||
void command_invsnapshot(Client *c, const Seperator *sep)
|
||||
{
|
||||
auto t = c->GetTarget();
|
||||
if (!t || !t->IsClient()) {
|
||||
c->Message(0, "Target must be a client");
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
if (sep->argnum == 0 || strcmp(sep->arg[1], "help") == 0) {
|
||||
std::string window_title = "Inventory Snapshot Argument Help Menu";
|
||||
|
||||
std::string window_text =
|
||||
"<table>"
|
||||
"<tr>"
|
||||
"<td><c \"#FFFFFF\">Usage:</td>"
|
||||
"<td></td>"
|
||||
"<td>#invsnapshot arguments<br>(<c \"#00FF00\">required <c \"#FFFF00\">optional<c \"#FFFFFF\">)</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#FFFF00\">help</td>"
|
||||
"<td></td>"
|
||||
"<td><c \"#AAAAAA\">this menu</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#00FF00\">capture</td>"
|
||||
"<td></td>"
|
||||
"<td><c \"#AAAAAA\">takes snapshot of character inventory</td>"
|
||||
"</tr>";
|
||||
|
||||
if (c->Admin() >= commandInvSnapshot)
|
||||
window_text.append(
|
||||
"<tr>"
|
||||
"<td><c \"#00FF00\">gcount</td>"
|
||||
"<td></td>"
|
||||
"<td><c \"#AAAAAA\">returns global snapshot count</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#00FF00\">gclear</td>"
|
||||
"<td><c \"#FFFF00\"><br>now</td>"
|
||||
"<td><c \"#AAAAAA\">delete all snapshots - rule<br>delete all snapshots - now</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#00FF00\">count</td>"
|
||||
"<td></td>"
|
||||
"<td><c \"#AAAAAA\">returns character snapshot count</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#00FF00\">clear</td>"
|
||||
"<td><c \"#FFFF00\"><br>now</td>"
|
||||
"<td><c \"#AAAAAA\">delete character snapshots - rule<br>delete character snapshots - now</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#00FF00\">list</td>"
|
||||
"<td><br><c \"#FFFF00\">count</td>"
|
||||
"<td><c \"#AAAAAA\">lists entry ids for current character<br>limits to count</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#00FF00\">parse</td>"
|
||||
"<td><c \"#00FF00\">tstmp</td>"
|
||||
"<td><c \"#AAAAAA\">displays slots and items in snapshot</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#00FF00\">compare</td>"
|
||||
"<td><c \"#00FF00\">tstmp</td>"
|
||||
"<td><c \"#AAAAAA\">compares inventory against snapshot</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<td><c \"#00FF00\">restore</td>"
|
||||
"<td><c \"#00FF00\">tstmp</td>"
|
||||
"<td><c \"#AAAAAA\">restores slots and items in snapshot</td>"
|
||||
"</tr>"
|
||||
);
|
||||
|
||||
window_text.append(
|
||||
"</table>"
|
||||
);
|
||||
|
||||
c->SendPopupToClient(window_title.c_str(), window_text.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (database.SaveCharacterInventorySnapshot(((Client*)t)->CharacterID())) {
|
||||
c->SetNextInvSnapshot(RuleI(Character, InvSnapshotMinIntervalM));
|
||||
c->Message(0, "Successful inventory snapshot taken of %s", t->GetName());
|
||||
}
|
||||
else {
|
||||
c->SetNextInvSnapshot(RuleI(Character, InvSnapshotMinRetryM));
|
||||
c->Message(0, "Failed to take inventory snapshot of %s", t->GetName());
|
||||
}
|
||||
}
|
||||
if (c->Admin() >= commandInvSnapshot) { // global arguments
|
||||
|
||||
void command_clearinvsnapshots(Client *c, const Seperator *sep)
|
||||
{
|
||||
if (strcmp(sep->arg[1], "false") == 0) {
|
||||
database.ClearInvSnapshots(false);
|
||||
c->Message(0, "Inventory snapshots cleared using current time");
|
||||
if (strcmp(sep->arg[1], "gcount") == 0) {
|
||||
auto is_count = database.CountInvSnapshots();
|
||||
c->Message(0, "There %s %i inventory snapshot%s.", (is_count == 1 ? "is" : "are"), is_count, (is_count == 1 ? "" : "s"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(sep->arg[1], "gclear") == 0) {
|
||||
if (strcmp(sep->arg[2], "now") == 0) {
|
||||
database.ClearInvSnapshots(true);
|
||||
c->Message(0, "Inventory snapshots cleared using current time.");
|
||||
}
|
||||
else {
|
||||
database.ClearInvSnapshots();
|
||||
c->Message(0, "Inventory snapshots cleared using RuleI(Character, InvSnapshotHistoryD) (%i day%s).",
|
||||
RuleI(Character, InvSnapshotHistoryD), (RuleI(Character, InvSnapshotHistoryD) == 1 ? "" : "s"));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
database.ClearInvSnapshots();
|
||||
c->Message(0, "Inventory snapshots cleared using RuleI(Character, InvSnapshotHistoryD) (%i days)", RuleI(Character, InvSnapshotHistoryD));
|
||||
|
||||
if (!c->GetTarget() || !c->GetTarget()->IsClient()) {
|
||||
c->Message(0, "Target must be a client.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto tc = (Client*)c->GetTarget();
|
||||
|
||||
if (strcmp(sep->arg[1], "capture") == 0) {
|
||||
if (database.SaveCharacterInvSnapshot(tc->CharacterID())) {
|
||||
tc->SetNextInvSnapshot(RuleI(Character, InvSnapshotMinIntervalM));
|
||||
c->Message(0, "Successful inventory snapshot taken of %s - setting next interval for %i minute%s.",
|
||||
tc->GetName(), RuleI(Character, InvSnapshotMinIntervalM), (RuleI(Character, InvSnapshotMinIntervalM) == 1 ? "" : "s"));
|
||||
}
|
||||
else {
|
||||
tc->SetNextInvSnapshot(RuleI(Character, InvSnapshotMinRetryM));
|
||||
c->Message(0, "Failed to take inventory snapshot of %s - retrying in %i minute%s.",
|
||||
tc->GetName(), RuleI(Character, InvSnapshotMinRetryM), (RuleI(Character, InvSnapshotMinRetryM) == 1 ? "" : "s"));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->Admin() >= commandInvSnapshot) {
|
||||
if (strcmp(sep->arg[1], "count") == 0) {
|
||||
auto is_count = database.CountCharacterInvSnapshots(tc->CharacterID());
|
||||
c->Message(0, "%s (id: %u) has %i inventory snapshot%s.", tc->GetName(), tc->CharacterID(), is_count, (is_count == 1 ? "" : "s"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(sep->arg[1], "clear") == 0) {
|
||||
if (strcmp(sep->arg[2], "now") == 0) {
|
||||
database.ClearCharacterInvSnapshots(tc->CharacterID(), true);
|
||||
c->Message(0, "%s\'s (id: %u) inventory snapshots cleared using current time.", tc->GetName(), tc->CharacterID());
|
||||
}
|
||||
else {
|
||||
database.ClearCharacterInvSnapshots(tc->CharacterID());
|
||||
c->Message(0, "%s\'s (id: %u) inventory snapshots cleared using RuleI(Character, InvSnapshotHistoryD) (%i day%s).",
|
||||
tc->GetName(), tc->CharacterID(), RuleI(Character, InvSnapshotHistoryD), (RuleI(Character, InvSnapshotHistoryD) == 1 ? "" : "s"));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(sep->arg[1], "list") == 0) {
|
||||
std::list<std::pair<uint32, int>> is_list;
|
||||
database.ListCharacterInvSnapshots(tc->CharacterID(), is_list);
|
||||
|
||||
if (is_list.empty()) {
|
||||
c->Message(0, "No inventory snapshots for %s (id: %u)", tc->GetName(), tc->CharacterID());
|
||||
return;
|
||||
}
|
||||
|
||||
auto list_count = 0;
|
||||
if (sep->IsNumber(2))
|
||||
list_count = atoi(sep->arg[2]);
|
||||
if (list_count < 1 || list_count > is_list.size())
|
||||
list_count = is_list.size();
|
||||
|
||||
std::string window_title = StringFormat("Snapshots for %s", tc->GetName());
|
||||
|
||||
std::string window_text =
|
||||
"<table>"
|
||||
"<tr>"
|
||||
"<td>Timestamp</td>"
|
||||
"<td>Entry Count</td>"
|
||||
"</tr>";
|
||||
|
||||
for (auto iter : is_list) {
|
||||
if (!list_count)
|
||||
break;
|
||||
|
||||
window_text.append(StringFormat(
|
||||
"<tr>"
|
||||
"<td>%u</td>"
|
||||
"<td>%i</td>"
|
||||
"</tr>",
|
||||
iter.first,
|
||||
iter.second
|
||||
));
|
||||
|
||||
--list_count;
|
||||
}
|
||||
|
||||
window_text.append(
|
||||
"</table>"
|
||||
);
|
||||
|
||||
c->SendPopupToClient(window_title.c_str(), window_text.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(sep->arg[1], "parse") == 0) {
|
||||
if (!sep->IsNumber(2)) {
|
||||
c->Message(0, "A timestamp is required to use this option.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 timestamp = atoul(sep->arg[2]);
|
||||
|
||||
if (!database.ValidateCharacterInvSnapshotTimestamp(tc->CharacterID(), timestamp)) {
|
||||
c->Message(0, "No inventory snapshots for %s (id: %u) exist at %u.", tc->GetName(), tc->CharacterID(), timestamp);
|
||||
return;
|
||||
}
|
||||
|
||||
std::list<std::pair<int16, uint32>> parse_list;
|
||||
database.ParseCharacterInvSnapshot(tc->CharacterID(), timestamp, parse_list);
|
||||
|
||||
std::string window_title = StringFormat("Snapshot Parse for %s @ %u", tc->GetName(), timestamp);
|
||||
|
||||
std::string window_text = "Slot: ItemID - Description<br>";
|
||||
|
||||
for (auto iter : parse_list) {
|
||||
auto item_data = database.GetItem(iter.second);
|
||||
std::string window_line = StringFormat("%i: %u - %s<br>", iter.first, iter.second, (item_data ? item_data->Name : "[error]"));
|
||||
|
||||
if (window_text.length() + window_line.length() < 4095) {
|
||||
window_text.append(window_line);
|
||||
}
|
||||
else {
|
||||
c->Message(0, "Too many snapshot entries to list...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
c->SendPopupToClient(window_title.c_str(), window_text.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(sep->arg[1], "compare") == 0) {
|
||||
if (!sep->IsNumber(2)) {
|
||||
c->Message(0, "A timestamp is required to use this option.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 timestamp = atoul(sep->arg[2]);
|
||||
|
||||
if (!database.ValidateCharacterInvSnapshotTimestamp(tc->CharacterID(), timestamp)) {
|
||||
c->Message(0, "No inventory snapshots for %s (id: %u) exist at %u.", tc->GetName(), tc->CharacterID(), timestamp);
|
||||
return;
|
||||
}
|
||||
|
||||
std::list<std::pair<int16, uint32>> inv_compare_list;
|
||||
database.DivergeCharacterInventoryFromInvSnapshot(tc->CharacterID(), timestamp, inv_compare_list);
|
||||
|
||||
std::list<std::pair<int16, uint32>> iss_compare_list;
|
||||
database.DivergeCharacterInvSnapshotFromInventory(tc->CharacterID(), timestamp, iss_compare_list);
|
||||
|
||||
std::string window_title = StringFormat("Snapshot Comparison for %s @ %u", tc->GetName(), timestamp);
|
||||
|
||||
std::string window_text = "Slot: (action) Snapshot -> Inventory<br>";
|
||||
|
||||
auto inv_iter = inv_compare_list.begin();
|
||||
auto iss_iter = iss_compare_list.begin();
|
||||
|
||||
while (true) {
|
||||
std::string window_line;
|
||||
|
||||
if (inv_iter == inv_compare_list.end() && iss_iter == iss_compare_list.end()) {
|
||||
break;
|
||||
}
|
||||
else if (inv_iter != inv_compare_list.end() && iss_iter == iss_compare_list.end()) {
|
||||
window_line = StringFormat("%i: (delete) [empty] -> %u<br>", inv_iter->first, inv_iter->second);
|
||||
++inv_iter;
|
||||
}
|
||||
else if (inv_iter == inv_compare_list.end() && iss_iter != iss_compare_list.end()) {
|
||||
window_line = StringFormat("%i: (insert) %u -> [empty]<br>", iss_iter->first, iss_iter->second);
|
||||
++iss_iter;
|
||||
}
|
||||
else {
|
||||
if (inv_iter->first < iss_iter->first) {
|
||||
window_line = StringFormat("%i: (delete) [empty] -> %u<br>", inv_iter->first, inv_iter->second);
|
||||
++inv_iter;
|
||||
}
|
||||
else if (inv_iter->first > iss_iter->first) {
|
||||
window_line = StringFormat("%i: (insert) %u -> [empty]<br>", iss_iter->first, iss_iter->second);
|
||||
++iss_iter;
|
||||
}
|
||||
else {
|
||||
window_line = StringFormat("%i: (replace) %u -> %u<br>", iss_iter->first, iss_iter->second, inv_iter->second);
|
||||
++inv_iter;
|
||||
++iss_iter;
|
||||
}
|
||||
}
|
||||
|
||||
if (window_text.length() + window_line.length() < 4095) {
|
||||
window_text.append(window_line);
|
||||
}
|
||||
else {
|
||||
c->Message(0, "Too many comparison entries to list...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
c->SendPopupToClient(window_title.c_str(), window_text.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(sep->arg[1], "restore") == 0) {
|
||||
if (!sep->IsNumber(2)) {
|
||||
c->Message(0, "A timestamp is required to use this option.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 timestamp = atoul(sep->arg[2]);
|
||||
|
||||
if (!database.ValidateCharacterInvSnapshotTimestamp(tc->CharacterID(), timestamp)) {
|
||||
c->Message(0, "No inventory snapshots for %s (id: %u) exist at %u.", tc->GetName(), tc->CharacterID(), timestamp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (database.SaveCharacterInvSnapshot(tc->CharacterID())) {
|
||||
tc->SetNextInvSnapshot(RuleI(Character, InvSnapshotMinIntervalM));
|
||||
}
|
||||
else {
|
||||
c->Message(13, "Failed to take pre-restore inventory snapshot of %s (id: %u).",
|
||||
tc->GetName(), tc->CharacterID());
|
||||
return;
|
||||
}
|
||||
|
||||
if (database.RestoreCharacterInvSnapshot(tc->CharacterID(), timestamp)) {
|
||||
// cannot delete all valid item slots from client..so, we worldkick
|
||||
tc->WorldKick(); // self restores update before the 'kick' is processed
|
||||
|
||||
c->Message(0, "Successfully applied snapshot %u to %s's (id: %u) inventory.",
|
||||
timestamp, tc->GetName(), tc->CharacterID());
|
||||
}
|
||||
else {
|
||||
c->Message(13, "Failed to apply snapshot %u to %s's (id: %u) inventory.",
|
||||
timestamp, tc->GetName(), tc->CharacterID());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3365,7 +3631,7 @@ void command_listpetition(Client *c, const Seperator *sep)
|
||||
void command_equipitem(Client *c, const Seperator *sep)
|
||||
{
|
||||
uint32 slot_id = atoi(sep->arg[1]);
|
||||
if (sep->IsNumber(1) && ((slot_id >= EQEmu::invslot::EQUIPMENT_BEGIN) && (slot_id <= EQEmu::invslot::EQUIPMENT_END) || (slot_id == EQEmu::invslot::SLOT_POWER_SOURCE))) {
|
||||
if (sep->IsNumber(1) && (slot_id >= EQEmu::invslot::EQUIPMENT_BEGIN && slot_id <= EQEmu::invslot::EQUIPMENT_END)) {
|
||||
const EQEmu::ItemInstance* from_inst = c->GetInv().GetItem(EQEmu::invslot::slotCursor);
|
||||
const EQEmu::ItemInstance* to_inst = c->GetInv().GetItem(slot_id); // added (desync issue when forcing stack to stack)
|
||||
bool partialmove = false;
|
||||
|
||||
@ -261,6 +261,17 @@ enum class LootResponse : uint8 {
|
||||
LootAll = 6 // SoD+
|
||||
};
|
||||
|
||||
enum class LootRequestType : uint8 {
|
||||
Forbidden = 0,
|
||||
GMPeek,
|
||||
GMAllowed,
|
||||
Self,
|
||||
AllowedPVE,
|
||||
AllowedPVPAll,
|
||||
AllowedPVPSingle, // can make this 'AllowedPVPVariable' and allow values between 1 and EQEmu::invtype::POSSESSIONS_SIZE
|
||||
AllowedPVPDefined,
|
||||
};
|
||||
|
||||
//this is our internal representation of the BUFF struct, can put whatever we want in it
|
||||
struct Buffs_Struct {
|
||||
uint16 spellid;
|
||||
|
||||
403
zone/corpse.cpp
403
zone/corpse.cpp
@ -202,6 +202,8 @@ Corpse::Corpse(NPC* in_npc, ItemList* in_itemlist, uint32 in_npctypeid, const NP
|
||||
|
||||
UpdateEquipmentLight();
|
||||
UpdateActiveLight();
|
||||
|
||||
loot_request_type = LootRequestType::Forbidden;
|
||||
}
|
||||
|
||||
Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
@ -322,15 +324,11 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
// to go into the regular slots on the player, out of bags
|
||||
std::list<uint32> removed_list;
|
||||
|
||||
// ideally, we would start at invslot::slotGeneral1 and progress to invslot::slotCursor..
|
||||
// ..then regress and process invslot::EQUIPMENT_BEGIN through invslot::EQUIPMENT_END...
|
||||
// without additional work to database loading of player corpses, this order is not
|
||||
// currently preserved and a re-work of this processing loop is not warranted.
|
||||
for (i = EQEmu::invslot::POSSESSIONS_BEGIN; i <= EQEmu::invslot::POSSESSIONS_END; ++i) {
|
||||
if (i == EQEmu::invslot::slotAmmo && client->ClientVersion() >= EQEmu::versions::ClientVersion::SoF) {
|
||||
item = client->GetInv().GetItem(EQEmu::invslot::SLOT_POWER_SOURCE);
|
||||
if (item != nullptr) {
|
||||
if (!client->IsBecomeNPC() || (client->IsBecomeNPC() && !item->GetItem()->NoRent))
|
||||
MoveItemToCorpse(client, item, EQEmu::invslot::SLOT_POWER_SOURCE, removed_list);
|
||||
}
|
||||
}
|
||||
|
||||
item = client->GetInv().GetItem(i);
|
||||
if (item == nullptr) { continue; }
|
||||
|
||||
@ -340,25 +338,25 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
|
||||
database.TransactionBegin();
|
||||
|
||||
// I have an untested process that avoids this snarl up when all possessions inventory is removed..but this isn't broke
|
||||
// this should not be modified to include the entire range of invtype::TYPE_POSSESSIONS slots by default..
|
||||
// ..due to the possibility of 'hidden' items from client version bias..or, possibly, soul-bound items (WoW?)
|
||||
if (!removed_list.empty()) {
|
||||
std::stringstream ss("");
|
||||
ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID();
|
||||
ss << " AND (";
|
||||
std::list<uint32>::const_iterator iter = removed_list.begin();
|
||||
bool first = true;
|
||||
while (iter != removed_list.end()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
ss << " OR ";
|
||||
}
|
||||
ss << "slotid=" << (*iter);
|
||||
|
||||
if (iter != removed_list.end()) {
|
||||
std::stringstream ss("");
|
||||
ss << "DELETE FROM `inventory` WHERE `charid` = " << client->CharacterID();
|
||||
ss << " AND `slotid` IN (" << (*iter);
|
||||
++iter;
|
||||
|
||||
while (iter != removed_list.end()) {
|
||||
ss << ", " << (*iter);
|
||||
++iter;
|
||||
}
|
||||
ss << ")";
|
||||
|
||||
database.QueryDatabase(ss.str().c_str());
|
||||
}
|
||||
ss << ")";
|
||||
database.QueryDatabase(ss.str().c_str());
|
||||
}
|
||||
|
||||
auto start = client->GetInv().cursor_cbegin();
|
||||
@ -382,6 +380,8 @@ Corpse::Corpse(Client* client, int32 in_rezexp) : Mob (
|
||||
UpdateEquipmentLight();
|
||||
UpdateActiveLight();
|
||||
|
||||
loot_request_type = LootRequestType::Forbidden;
|
||||
|
||||
IsRezzed(false);
|
||||
Save();
|
||||
}
|
||||
@ -524,6 +524,8 @@ EQEmu::TintProfile(),
|
||||
|
||||
UpdateEquipmentLight();
|
||||
UpdateActiveLight();
|
||||
|
||||
loot_request_type = LootRequestType::Forbidden;
|
||||
}
|
||||
|
||||
Corpse::~Corpse() {
|
||||
@ -873,13 +875,16 @@ void Corpse::AllowPlayerLoot(Mob *them, uint8 slot) {
|
||||
}
|
||||
|
||||
void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* app) {
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
// Added 12/08. Started compressing loot struct on live.
|
||||
if(player_corpse_depop) {
|
||||
SendLootReqErrorPacket(client, LootResponse::SomeoneElse);
|
||||
return;
|
||||
}
|
||||
|
||||
if(IsPlayerCorpse() && corpse_db_id == 0) {
|
||||
if(IsPlayerCorpse() && !corpse_db_id) { // really should try to resave in this case
|
||||
// SendLootReqErrorPacket(client, 0);
|
||||
client->Message(13, "Warning: Corpse's dbid = 0! Corpse will not survive zone shutdown!");
|
||||
std::cout << "Error: PlayerCorpse::MakeLootRequestPackets: dbid = 0!" << std::endl;
|
||||
@ -892,165 +897,195 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
|
||||
return;
|
||||
}
|
||||
|
||||
if(being_looted_by == 0)
|
||||
if(!being_looted_by || (being_looted_by != 0xFFFFFFFF && !entity_list.GetID(being_looted_by)))
|
||||
being_looted_by = 0xFFFFFFFF;
|
||||
|
||||
if(this->being_looted_by != 0xFFFFFFFF) {
|
||||
// lets double check....
|
||||
Entity* looter = entity_list.GetID(this->being_looted_by);
|
||||
if(looter == nullptr)
|
||||
this->being_looted_by = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
uint8 Loot_Request_Type = 1;
|
||||
bool loot_coin = false;
|
||||
std::string tmp;
|
||||
if(database.GetVariable("LootCoin", tmp))
|
||||
loot_coin = tmp[0] == 1 && tmp[1] == '\0';
|
||||
|
||||
if (DistanceSquaredNoZ(client->GetPosition(), m_Position) > 625) {
|
||||
SendLootReqErrorPacket(client, LootResponse::TooFar);
|
||||
// not sure if we need to send the packet back in this case? Didn't before!
|
||||
// Will just return for now
|
||||
return;
|
||||
}
|
||||
else if (this->being_looted_by != 0xFFFFFFFF && this->being_looted_by != client->GetID()) {
|
||||
|
||||
if (being_looted_by != 0xFFFFFFFF && being_looted_by != client->GetID()) {
|
||||
SendLootReqErrorPacket(client, LootResponse::SomeoneElse);
|
||||
Loot_Request_Type = 0;
|
||||
}
|
||||
else if (IsPlayerCorpse() && char_id == client->CharacterID()) {
|
||||
Loot_Request_Type = 2;
|
||||
}
|
||||
else if ((IsNPCCorpse() || become_npc) && CanPlayerLoot(client->CharacterID())) {
|
||||
Loot_Request_Type = 2;
|
||||
}
|
||||
else if (GetPlayerKillItem() == -1 && CanPlayerLoot(client->CharacterID())) { /* PVP loot all items, variable cash */
|
||||
Loot_Request_Type = 3;
|
||||
}
|
||||
else if (GetPlayerKillItem() == 1 && CanPlayerLoot(client->CharacterID())) { /* PVP loot 1 item, variable cash */
|
||||
Loot_Request_Type = 4;
|
||||
}
|
||||
else if (GetPlayerKillItem() > 1 && CanPlayerLoot(client->CharacterID())) { /* PVP loot 1 set item, variable cash */
|
||||
Loot_Request_Type = 5;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Loot_Request_Type == 1) {
|
||||
if (client->Admin() < 100 || !client->GetGM()) {
|
||||
SendLootReqErrorPacket(client, LootResponse::NotAtThisTime);
|
||||
// all loot session disqualifiers should occur before this point as not to interfere with any current looter
|
||||
loot_request_type = LootRequestType::Forbidden;
|
||||
|
||||
// loot_request_type is scoped to class Corpse and reset on a per-loot session basis
|
||||
if (client->GetGM()) {
|
||||
if (client->Admin() >= 100)
|
||||
loot_request_type = LootRequestType::GMAllowed;
|
||||
else
|
||||
loot_request_type = LootRequestType::GMPeek;
|
||||
}
|
||||
else {
|
||||
if (IsPlayerCorpse()) {
|
||||
if (char_id == client->CharacterID()) {
|
||||
loot_request_type = LootRequestType::Self;
|
||||
}
|
||||
else if (CanPlayerLoot(client->CharacterID())) {
|
||||
if (GetPlayerKillItem() == -1)
|
||||
loot_request_type = LootRequestType::AllowedPVPAll;
|
||||
else if (GetPlayerKillItem() == 1)
|
||||
loot_request_type = LootRequestType::AllowedPVPSingle;
|
||||
else if (GetPlayerKillItem() > 1)
|
||||
loot_request_type = LootRequestType::AllowedPVPDefined;
|
||||
}
|
||||
}
|
||||
else if ((IsNPCCorpse() || become_npc) && CanPlayerLoot(client->CharacterID())) {
|
||||
loot_request_type = LootRequestType::AllowedPVE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(Loot_Request_Type >= 2 || (Loot_Request_Type == 1 && client->Admin() >= 100 && client->GetGM())) {
|
||||
client->CommonBreakInvisible(); // we should be "all good" so lets break invis now instead of earlier before all error checking is done
|
||||
this->being_looted_by = client->GetID();
|
||||
Log(Logs::Moderate, Logs::Inventory, "MakeLootRequestPackets() LootRequestType %u for %s", loot_request_type, client->GetName());
|
||||
|
||||
if (loot_request_type == LootRequestType::Forbidden) {
|
||||
SendLootReqErrorPacket(client, LootResponse::NotAtThisTime);
|
||||
return;
|
||||
}
|
||||
|
||||
being_looted_by = client->GetID();
|
||||
client->CommonBreakInvisible(); // we should be "all good" so lets break invis now instead of earlier before all error checking is done
|
||||
|
||||
// process coin
|
||||
bool loot_coin = false;
|
||||
std::string tmp;
|
||||
if (database.GetVariable("LootCoin", tmp))
|
||||
loot_coin = (tmp[0] == 1 && tmp[1] == '\0');
|
||||
|
||||
if (loot_request_type == LootRequestType::GMPeek || loot_request_type == LootRequestType::GMAllowed) {
|
||||
client->Message(15, "This corpse contains %u platinum, %u gold, %u silver and %u copper.",
|
||||
GetPlatinum(), GetGold(), GetSilver(), GetCopper());
|
||||
|
||||
auto outapp = new EQApplicationPacket(OP_MoneyOnCorpse, sizeof(moneyOnCorpseStruct));
|
||||
moneyOnCorpseStruct* d = (moneyOnCorpseStruct*) outapp->pBuffer;
|
||||
moneyOnCorpseStruct* d = (moneyOnCorpseStruct*)outapp->pBuffer;
|
||||
|
||||
d->response = static_cast<uint8>(LootResponse::Normal);
|
||||
d->unknown1 = 0x42;
|
||||
d->unknown2 = 0xef;
|
||||
d->response = static_cast<uint8>(LootResponse::Normal);
|
||||
d->unknown1 = 0x42;
|
||||
d->unknown2 = 0xef;
|
||||
|
||||
/* Dont take the coin off if it's a gm peeking at the corpse */
|
||||
if(Loot_Request_Type == 2 || (Loot_Request_Type >= 3 && loot_coin)) {
|
||||
if(!IsPlayerCorpse() && client->IsGrouped() && client->AutoSplitEnabled() && client->GetGroup()) {
|
||||
d->copper = 0;
|
||||
d->silver = 0;
|
||||
d->gold = 0;
|
||||
d->platinum = 0;
|
||||
Group *cgroup = client->GetGroup();
|
||||
cgroup->SplitMoney(GetCopper(), GetSilver(), GetGold(), GetPlatinum(), client);
|
||||
}
|
||||
else {
|
||||
d->copper = this->GetCopper();
|
||||
d->silver = this->GetSilver();
|
||||
d->gold = this->GetGold();
|
||||
d->platinum = this->GetPlatinum();
|
||||
client->AddMoneyToPP(GetCopper(), GetSilver(), GetGold(), GetPlatinum(), false);
|
||||
}
|
||||
d->copper = 0;
|
||||
d->silver = 0;
|
||||
d->gold = 0;
|
||||
d->platinum = 0;
|
||||
|
||||
RemoveCash();
|
||||
Save();
|
||||
}
|
||||
|
||||
auto timestamps = database.GetItemRecastTimestamps(client->CharacterID());
|
||||
outapp->priority = 6;
|
||||
client->QueuePacket(outapp);
|
||||
|
||||
safe_delete(outapp);
|
||||
if(Loot_Request_Type == 5) {
|
||||
int pkitem = GetPlayerKillItem();
|
||||
const EQEmu::ItemData* item = database.GetItem(pkitem);
|
||||
EQEmu::ItemInstance* inst = database.CreateItem(item, item->MaxCharges);
|
||||
if(inst) {
|
||||
if (item->RecastDelay)
|
||||
inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0);
|
||||
client->SendItemPacket(EQEmu::invslot::CORPSE_BEGIN, inst, ItemPacketLoot);
|
||||
safe_delete(inst);
|
||||
}
|
||||
else { client->Message(13, "Could not find item number %i to send!!", GetPlayerKillItem()); }
|
||||
}
|
||||
else {
|
||||
auto outapp = new EQApplicationPacket(OP_MoneyOnCorpse, sizeof(moneyOnCorpseStruct));
|
||||
moneyOnCorpseStruct* d = (moneyOnCorpseStruct*)outapp->pBuffer;
|
||||
|
||||
client->QueuePacket(app);
|
||||
return;
|
||||
d->response = static_cast<uint8>(LootResponse::Normal);
|
||||
d->unknown1 = 0x42;
|
||||
d->unknown2 = 0xef;
|
||||
|
||||
Group* cgroup = client->GetGroup();
|
||||
|
||||
// this can be reworked into a switch and/or massaged to include specialized pve loot rules based on 'LootRequestType'
|
||||
if (!IsPlayerCorpse() && client->IsGrouped() && client->AutoSplitEnabled() && cgroup) {
|
||||
d->copper = 0;
|
||||
d->silver = 0;
|
||||
d->gold = 0;
|
||||
d->platinum = 0;
|
||||
cgroup->SplitMoney(GetCopper(), GetSilver(), GetGold(), GetPlatinum(), client);
|
||||
}
|
||||
else {
|
||||
d->copper = GetCopper();
|
||||
d->silver = GetSilver();
|
||||
d->gold = GetGold();
|
||||
d->platinum = GetPlatinum();
|
||||
client->AddMoneyToPP(GetCopper(), GetSilver(), GetGold(), GetPlatinum(), false);
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
const EQEmu::ItemData* item = nullptr;
|
||||
ItemList::iterator cur,end;
|
||||
cur = itemlist.begin();
|
||||
end = itemlist.end();
|
||||
RemoveCash();
|
||||
Save();
|
||||
|
||||
int corpselootlimit = EQEmu::inventory::Lookup(EQEmu::versions::ConvertClientVersionToMobVersion(client->ClientVersion()))->InventoryTypeSize[EQEmu::invtype::typeCorpse];
|
||||
outapp->priority = 6;
|
||||
client->QueuePacket(outapp);
|
||||
|
||||
for(; cur != end; ++cur) {
|
||||
ServerLootItem_Struct* item_data = *cur;
|
||||
item_data->lootslot = 0xFFFF;
|
||||
safe_delete(outapp);
|
||||
}
|
||||
|
||||
// Dont display the item if it's in a bag
|
||||
// process items
|
||||
auto timestamps = database.GetItemRecastTimestamps(client->CharacterID());
|
||||
|
||||
// Added cursor queue slots to corpse item visibility list. Nothing else should be making it to corpse.
|
||||
if (!IsPlayerCorpse() || item_data->equip_slot <= EQEmu::invslot::slotCursor || item_data->equip_slot == EQEmu::invslot::SLOT_POWER_SOURCE || Loot_Request_Type >= 3 ||
|
||||
(item_data->equip_slot >= 8000 && item_data->equip_slot <= 8999)) {
|
||||
if(i < corpselootlimit) {
|
||||
item = database.GetItem(item_data->item_id);
|
||||
if(client && item) {
|
||||
EQEmu::ItemInstance* inst = database.CreateItem(item, item_data->charges, 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);
|
||||
if(inst) {
|
||||
if (item->RecastDelay)
|
||||
inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0);
|
||||
// SlotGeneral1 is the corpse inventory start offset for Ti(EMu) - CORPSE_END = SlotGeneral1 + SlotCursor
|
||||
client->SendItemPacket(i + EQEmu::invslot::CORPSE_BEGIN, inst, ItemPacketLoot);
|
||||
safe_delete(inst);
|
||||
}
|
||||
if (loot_request_type == LootRequestType::AllowedPVPDefined) {
|
||||
auto pkitemid = GetPlayerKillItem();
|
||||
auto pkitem = database.GetItem(pkitemid);
|
||||
auto pkinst = database.CreateItem(pkitem, pkitem->MaxCharges);
|
||||
|
||||
item_data->lootslot = i;
|
||||
}
|
||||
}
|
||||
if (pkinst) {
|
||||
if (pkitem->RecastDelay)
|
||||
pkinst->SetRecastTimestamp(timestamps.count(pkitem->RecastType) ? timestamps.at(pkitem->RecastType) : 0);
|
||||
|
||||
i++;
|
||||
}
|
||||
Log(Logs::Detail, Logs::Inventory, "MakeLootRequestPackets() Slot %u, Item '%s'", EQEmu::invslot::CORPSE_BEGIN, pkitem->Name);
|
||||
|
||||
client->SendItemPacket(EQEmu::invslot::CORPSE_BEGIN, pkinst, ItemPacketLoot);
|
||||
safe_delete(pkinst);
|
||||
}
|
||||
else {
|
||||
Log(Logs::General, Logs::Inventory, "MakeLootRequestPackets() PlayerKillItem %i not found", pkitemid);
|
||||
|
||||
client->Message(CC_Red, "PlayerKillItem (id: %i) could not be found!", pkitemid);
|
||||
}
|
||||
|
||||
if(IsPlayerCorpse() && (char_id == client->CharacterID() || client->GetGM())) {
|
||||
if(i > corpselootlimit) {
|
||||
client->Message(15, "*** This corpse contains more items than can be displayed! ***");
|
||||
client->Message(0, "Remove items and re-loot corpse to access remaining inventory.");
|
||||
client->Message(0, "(%s contains %i additional %s.)", GetName(), (i - corpselootlimit), (i - corpselootlimit) == 1 ? "item" : "items");
|
||||
}
|
||||
client->QueuePacket(app);
|
||||
return;
|
||||
}
|
||||
|
||||
if(IsPlayerCorpse() && i == 0 && itemlist.size() > 0) { // somehow, player corpse contains items, but client doesn't see them...
|
||||
client->Message(13, "This corpse contains items that are inaccessable!");
|
||||
client->Message(15, "Contact a GM for item replacement, if necessary.");
|
||||
client->Message(15, "BUGGED CORPSE [DBID: %i, Name: %s, Item Count: %i]", GetCorpseDBID(), GetName(), itemlist.size());
|
||||
auto loot_slot = EQEmu::invslot::CORPSE_BEGIN;
|
||||
auto corpse_mask = client->GetInv().GetLookup()->CorpseBitmask;
|
||||
|
||||
for (auto item_data : itemlist) {
|
||||
// every loot session must either set all items' lootslots to 'invslot::SLOT_INVALID'
|
||||
// or to a valid enumerated client-versioned corpse slot (lootslot is not equip_slot)
|
||||
item_data->lootslot = 0xFFFF;
|
||||
|
||||
// align server and client corpse slot mappings so translators can function properly
|
||||
while (loot_slot <= EQEmu::invslot::CORPSE_END && (((uint64)1 << loot_slot) & corpse_mask) == 0)
|
||||
++loot_slot;
|
||||
|
||||
if (loot_slot > EQEmu::invslot::CORPSE_END)
|
||||
continue;
|
||||
|
||||
cur = itemlist.begin();
|
||||
end = itemlist.end();
|
||||
for(; cur != end; ++cur) {
|
||||
ServerLootItem_Struct* item_data = *cur;
|
||||
item = database.GetItem(item_data->item_id);
|
||||
Log(Logs::General, Logs::None, "Corpse Looting: %s was not sent to client loot window (corpse_dbid: %i, charname: %s(%s))", item->Name, GetCorpseDBID(), client->GetName(), client->GetGM() ? "GM" : "Owner");
|
||||
client->Message(0, "Inaccessable Corpse Item: %s", item->Name);
|
||||
}
|
||||
}
|
||||
if (IsPlayerCorpse()) {
|
||||
if (loot_request_type == LootRequestType::AllowedPVPSingle && loot_slot != EQEmu::invslot::CORPSE_BEGIN)
|
||||
continue;
|
||||
|
||||
if (item_data->equip_slot < EQEmu::invslot::POSSESSIONS_BEGIN || item_data->equip_slot > EQEmu::invslot::POSSESSIONS_END)
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto *item = database.GetItem(item_data->item_id);
|
||||
auto inst = database.CreateItem(
|
||||
item,
|
||||
item_data->charges,
|
||||
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
|
||||
);
|
||||
if (!inst)
|
||||
continue;
|
||||
|
||||
if (item->RecastDelay)
|
||||
inst->SetRecastTimestamp(timestamps.count(item->RecastType) ? timestamps.at(item->RecastType) : 0);
|
||||
|
||||
Log(Logs::Moderate, Logs::Inventory, "MakeLootRequestPackets() Slot %i, Item '%s'", loot_slot, item->Name);
|
||||
|
||||
client->SendItemPacket(loot_slot, inst, ItemPacketLoot);
|
||||
safe_delete(inst);
|
||||
|
||||
item_data->lootslot = loot_slot++;
|
||||
}
|
||||
|
||||
// Disgrace: Client seems to require that we send the packet back...
|
||||
@ -1064,8 +1099,22 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a
|
||||
|
||||
void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
{
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
auto lootitem = (LootingItem_Struct *)app->pBuffer;
|
||||
|
||||
Log(Logs::Moderate, Logs::Inventory, "LootItem() LootRequestType %u, Slot %u for %s", loot_request_type, lootitem->slot_id, client->GetName());
|
||||
|
||||
if (loot_request_type < LootRequestType::GMAllowed) { // LootRequestType::Forbidden and LootRequestType::GMPeek
|
||||
client->QueuePacket(app);
|
||||
SendEndLootErrorPacket(client);
|
||||
// unlock corpse for others
|
||||
if (IsBeingLootedBy(client))
|
||||
ResetLooter();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!loot_cooldown_timer.Check()) {
|
||||
client->QueuePacket(app);
|
||||
SendEndLootErrorPacket(client);
|
||||
@ -1093,7 +1142,7 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
if (IsPlayerCorpse() && !CanPlayerLoot(client->CharacterID()) && !become_npc &&
|
||||
(char_id != client->CharacterID() && client->Admin() < 150)) {
|
||||
(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);
|
||||
@ -1108,7 +1157,7 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
if (IsPlayerCorpse() && (char_id != client->CharacterID()) && CanPlayerLoot(client->CharacterID()) &&
|
||||
GetPlayerKillItem() == 0) {
|
||||
GetPlayerKillItem() == 0) {
|
||||
client->Message(13, "Error: You cannot loot any more items from this corpse.");
|
||||
client->QueuePacket(app);
|
||||
SendEndLootErrorPacket(client);
|
||||
@ -1123,12 +1172,13 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
memset(bag_item_data, 0, sizeof(bag_item_data));
|
||||
if (GetPlayerKillItem() > 1) {
|
||||
item = database.GetItem(GetPlayerKillItem());
|
||||
} else if (GetPlayerKillItem() == -1 || GetPlayerKillItem() == 1) {
|
||||
}
|
||||
else if (GetPlayerKillItem() == -1 || GetPlayerKillItem() == 1) {
|
||||
item_data =
|
||||
GetItem(lootitem->slot_id -
|
||||
EQEmu::invslot::CORPSE_BEGIN); // dont allow them to loot entire bags of items as pvp reward
|
||||
} else {
|
||||
item_data = GetItem(lootitem->slot_id - EQEmu::invslot::CORPSE_BEGIN, bag_item_data);
|
||||
GetItem(lootitem->slot_id); // dont allow them to loot entire bags of items as pvp reward
|
||||
}
|
||||
else {
|
||||
item_data = GetItem(lootitem->slot_id, bag_item_data);
|
||||
}
|
||||
|
||||
if (GetPlayerKillItem() <= 1 && item_data != 0) {
|
||||
@ -1138,9 +1188,10 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -1175,7 +1226,7 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
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));
|
||||
EntityList::RemoveNumbers(q_corpse_name));
|
||||
buf[87] = '\0';
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(inst);
|
||||
@ -1187,6 +1238,8 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
delete inst;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// do we want this to have a fail option too?
|
||||
parse->EventItem(EVENT_LOOT, client, inst, this, buf, 0);
|
||||
|
||||
@ -1211,7 +1264,8 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
if (lootitem->auto_loot > 0) {
|
||||
if (!client->AutoPutLootInInventory(*inst, true, true, bag_item_data))
|
||||
client->PutLootInInventory(EQEmu::invslot::slotCursor, *inst, bag_item_data);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
client->PutLootInInventory(EQEmu::invslot::slotCursor, *inst, bag_item_data);
|
||||
}
|
||||
|
||||
@ -1222,9 +1276,9 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
/* Remove it from Corpse */
|
||||
if (item_data) {
|
||||
/* Delete needs to be before RemoveItem because its deletes the pointer for
|
||||
* item_data/bag_item_data */
|
||||
* item_data/bag_item_data */
|
||||
database.DeleteItemOffCharacterCorpse(this->corpse_db_id, item_data->equip_slot,
|
||||
item_data->item_id);
|
||||
item_data->item_id);
|
||||
/* Delete Item Instance */
|
||||
RemoveItem(item_data->lootslot);
|
||||
}
|
||||
@ -1234,10 +1288,10 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
for (int i = EQEmu::invbag::SLOT_BEGIN; i <= EQEmu::invbag::SLOT_END; i++) {
|
||||
if (bag_item_data[i]) {
|
||||
/* Delete needs to be before RemoveItem because its deletes the pointer for
|
||||
* item_data/bag_item_data */
|
||||
* item_data/bag_item_data */
|
||||
database.DeleteItemOffCharacterCorpse(this->corpse_db_id,
|
||||
bag_item_data[i]->equip_slot,
|
||||
bag_item_data[i]->item_id);
|
||||
bag_item_data[i]->equip_slot,
|
||||
bag_item_data[i]->item_id);
|
||||
/* Delete Item Instance */
|
||||
RemoveItem(bag_item_data[i]);
|
||||
}
|
||||
@ -1261,16 +1315,18 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
Group *g = client->GetGroup();
|
||||
if (g != nullptr) {
|
||||
g->GroupMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE,
|
||||
client->GetName(), linker.Link().c_str());
|
||||
} else {
|
||||
client->GetName(), linker.Link().c_str());
|
||||
}
|
||||
else {
|
||||
Raid *r = client->GetRaid();
|
||||
if (r != nullptr) {
|
||||
r->RaidMessage_StringID(client, MT_LootMessages, OTHER_LOOTED_MESSAGE,
|
||||
client->GetName(), linker.Link().c_str());
|
||||
client->GetName(), linker.Link().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
SendEndLootErrorPacket(client);
|
||||
safe_delete(inst);
|
||||
return;
|
||||
@ -1278,7 +1334,8 @@ void Corpse::LootItem(Client *client, const EQApplicationPacket *app)
|
||||
|
||||
if (IsPlayerCorpse()) {
|
||||
client->SendItemLink(inst);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
client->SendItemLink(inst, true);
|
||||
}
|
||||
|
||||
@ -1457,7 +1514,7 @@ void Corpse::UpdateEquipmentLight()
|
||||
m_Light.Level[EQEmu::lightsource::LightEquipment] = 0;
|
||||
|
||||
for (auto iter = itemlist.begin(); iter != itemlist.end(); ++iter) {
|
||||
if (((*iter)->equip_slot < EQEmu::invslot::EQUIPMENT_BEGIN || (*iter)->equip_slot > EQEmu::invslot::EQUIPMENT_END) && (*iter)->equip_slot != EQEmu::invslot::SLOT_POWER_SOURCE) { continue; }
|
||||
if ((*iter)->equip_slot < EQEmu::invslot::EQUIPMENT_BEGIN || (*iter)->equip_slot > EQEmu::invslot::EQUIPMENT_END) { continue; }
|
||||
if ((*iter)->equip_slot == EQEmu::invslot::slotAmmo) { continue; }
|
||||
|
||||
auto item = database.GetItem((*iter)->item_id);
|
||||
|
||||
@ -116,7 +116,7 @@ class Corpse : public Mob {
|
||||
inline void Lock() { is_locked = true; }
|
||||
inline void UnLock() { is_locked = false; }
|
||||
inline bool IsLocked() { return is_locked; }
|
||||
inline void ResetLooter() { being_looted_by = 0xFFFFFFFF; }
|
||||
inline void ResetLooter() { being_looted_by = 0xFFFFFFFF; loot_request_type = LootRequestType::Forbidden; }
|
||||
inline bool IsBeingLooted() { return (being_looted_by != 0xFFFFFFFF); }
|
||||
inline bool IsBeingLootedBy(Client *c) { return being_looted_by == c->GetID(); }
|
||||
|
||||
@ -161,6 +161,7 @@ private:
|
||||
Timer loot_cooldown_timer; /* Delay between loot actions on the corpse entity */
|
||||
EQEmu::TintProfile item_tint;
|
||||
|
||||
LootRequestType loot_request_type;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -1128,9 +1128,9 @@ void PerlembParser::ExportItemVariables(std::string &package_name, Mob *mob) {
|
||||
std::string hashname = package_name + std::string("::oncursor");
|
||||
perl->eval(std::string("%").append(hashname).append(" = ();").c_str());
|
||||
char *hi_decl = nullptr;
|
||||
int itemid = mob->CastToClient()->GetItemIDAt(30);
|
||||
int itemid = mob->CastToClient()->GetItemIDAt(EQEmu::invslot::slotCursor);
|
||||
if(!HASITEM_ISNULLITEM(itemid)) {
|
||||
MakeAnyLenString(&hi_decl, "push (@{$%s{%d}},%d);",hashname.c_str(), itemid, 30);
|
||||
MakeAnyLenString(&hi_decl, "push (@{$%s{%d}},%d);",hashname.c_str(), itemid, EQEmu::invslot::slotCursor);
|
||||
perl->eval(hi_decl);
|
||||
safe_delete_array(hi_decl);
|
||||
}
|
||||
|
||||
@ -33,6 +33,8 @@
|
||||
#include "zone.h"
|
||||
#include "data_bucket.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
extern Zone *zone;
|
||||
extern QueryServ *QServ;
|
||||
|
||||
@ -348,6 +350,83 @@ XS(XS__incstat) {
|
||||
XSRETURN_EMPTY;
|
||||
}
|
||||
|
||||
XS(XS__getinventoryslotid);
|
||||
XS(XS__getinventoryslotid) {
|
||||
dXSARGS;
|
||||
if (items != 1)
|
||||
Perl_croak(aTHX_ "Usage: quest::getinventoryslotid(string identifier)");
|
||||
|
||||
int16 RETVAL;
|
||||
dXSTARG;
|
||||
|
||||
std::string identifier = (Const_char *)SvPV_nolen(ST(0));
|
||||
for (std::string::size_type i = 0; i < identifier.length(); ++i)
|
||||
identifier[i] = std::tolower(identifier[i]);
|
||||
|
||||
if (identifier == "invalid") RETVAL = EQEmu::invslot::SLOT_INVALID;
|
||||
else if (identifier == "cursor") RETVAL = EQEmu::invslot::slotCursor;
|
||||
else if (identifier == "possessions.begin") RETVAL = EQEmu::invslot::POSSESSIONS_BEGIN;
|
||||
else if (identifier == "possessions.end") RETVAL = EQEmu::invslot::POSSESSIONS_END;
|
||||
else if (identifier == "bank.begin") RETVAL = EQEmu::invslot::BANK_BEGIN;
|
||||
else if (identifier == "bank.end") RETVAL = EQEmu::invslot::BANK_END;
|
||||
else if (identifier == "sharedbank.begin") RETVAL = EQEmu::invslot::SHARED_BANK_BEGIN;
|
||||
else if (identifier == "sharedbank.end") RETVAL = EQEmu::invslot::SHARED_BANK_END;
|
||||
else if (identifier == "generalbags.begin") RETVAL = EQEmu::invbag::GENERAL_BAGS_BEGIN;
|
||||
else if (identifier == "generalbags.end") RETVAL = EQEmu::invbag::GENERAL_BAGS_END;
|
||||
else if (identifier == "cursorbag.begin") RETVAL = EQEmu::invbag::CURSOR_BAG_BEGIN;
|
||||
else if (identifier == "cursorbag.end") RETVAL = EQEmu::invbag::CURSOR_BAG_END;
|
||||
else if (identifier == "bankbags.begin") RETVAL = EQEmu::invbag::BANK_BAGS_BEGIN;
|
||||
else if (identifier == "bankbags.end") RETVAL = EQEmu::invbag::BANK_BAGS_END;
|
||||
else if (identifier == "sharedbankbags.begin") RETVAL = EQEmu::invbag::SHARED_BANK_BAGS_BEGIN;
|
||||
else if (identifier == "sharedbankbags.end") RETVAL = EQEmu::invbag::SHARED_BANK_BAGS_END;
|
||||
else if (identifier == "bagslot.begin") RETVAL = EQEmu::invbag::SLOT_BEGIN;
|
||||
else if (identifier == "bagslot.end") RETVAL = EQEmu::invbag::SLOT_END;
|
||||
else if (identifier == "augsocket.begin") RETVAL = EQEmu::invaug::SOCKET_BEGIN;
|
||||
else if (identifier == "augsocket.end") RETVAL = EQEmu::invaug::SOCKET_END;
|
||||
else if (identifier == "equipment.begin") RETVAL = EQEmu::invslot::EQUIPMENT_BEGIN;
|
||||
else if (identifier == "equipment.end") RETVAL = EQEmu::invslot::EQUIPMENT_END;
|
||||
else if (identifier == "general.begin") RETVAL = EQEmu::invslot::GENERAL_BEGIN;
|
||||
else if (identifier == "general.end") RETVAL = EQEmu::invslot::GENERAL_END;
|
||||
else if (identifier == "charm") RETVAL = EQEmu::invslot::slotCharm;
|
||||
else if (identifier == "ear1") RETVAL = EQEmu::invslot::slotEar1;
|
||||
else if (identifier == "head") RETVAL = EQEmu::invslot::slotHead;
|
||||
else if (identifier == "face") RETVAL = EQEmu::invslot::slotFace;
|
||||
else if (identifier == "ear2") RETVAL = EQEmu::invslot::slotEar2;
|
||||
else if (identifier == "neck") RETVAL = EQEmu::invslot::slotNeck;
|
||||
else if (identifier == "shoulders") RETVAL = EQEmu::invslot::slotShoulders;
|
||||
else if (identifier == "arms") RETVAL = EQEmu::invslot::slotArms;
|
||||
else if (identifier == "back") RETVAL = EQEmu::invslot::slotBack;
|
||||
else if (identifier == "wrist1") RETVAL = EQEmu::invslot::slotWrist1;
|
||||
else if (identifier == "wrist2") RETVAL = EQEmu::invslot::slotWrist2;
|
||||
else if (identifier == "range") RETVAL = EQEmu::invslot::slotRange;
|
||||
else if (identifier == "hands") RETVAL = EQEmu::invslot::slotHands;
|
||||
else if (identifier == "primary") RETVAL = EQEmu::invslot::slotPrimary;
|
||||
else if (identifier == "secondary") RETVAL = EQEmu::invslot::slotSecondary;
|
||||
else if (identifier == "finger1") RETVAL = EQEmu::invslot::slotFinger1;
|
||||
else if (identifier == "finger2") RETVAL = EQEmu::invslot::slotFinger2;
|
||||
else if (identifier == "chest") RETVAL = EQEmu::invslot::slotChest;
|
||||
else if (identifier == "legs") RETVAL = EQEmu::invslot::slotLegs;
|
||||
else if (identifier == "feet") RETVAL = EQEmu::invslot::slotFeet;
|
||||
else if (identifier == "waist") RETVAL = EQEmu::invslot::slotWaist;
|
||||
else if (identifier == "powersource") RETVAL = EQEmu::invslot::slotPowerSource;
|
||||
else if (identifier == "ammo") RETVAL = EQEmu::invslot::slotAmmo;
|
||||
else if (identifier == "general1") RETVAL = EQEmu::invslot::slotGeneral1;
|
||||
else if (identifier == "general2") RETVAL = EQEmu::invslot::slotGeneral2;
|
||||
else if (identifier == "general3") RETVAL = EQEmu::invslot::slotGeneral3;
|
||||
else if (identifier == "general4") RETVAL = EQEmu::invslot::slotGeneral4;
|
||||
else if (identifier == "general5") RETVAL = EQEmu::invslot::slotGeneral5;
|
||||
else if (identifier == "general6") RETVAL = EQEmu::invslot::slotGeneral6;
|
||||
else if (identifier == "general7") RETVAL = EQEmu::invslot::slotGeneral7;
|
||||
else if (identifier == "general8") RETVAL = EQEmu::invslot::slotGeneral8;
|
||||
else if (identifier == "general9") RETVAL = EQEmu::invslot::slotGeneral9;
|
||||
else if (identifier == "general10") RETVAL = EQEmu::invslot::slotGeneral10;
|
||||
else RETVAL = EQEmu::invslot::SLOT_INVALID;
|
||||
|
||||
XSprePUSH; PUSHu((IV)RETVAL);
|
||||
|
||||
XSRETURN(1);
|
||||
}
|
||||
|
||||
XS(XS__castspell);
|
||||
XS(XS__castspell) {
|
||||
dXSARGS;
|
||||
@ -3672,6 +3751,7 @@ EXTERN_C XS(boot_quest) {
|
||||
newXS(strcpy(buf, "follow"), XS__follow, file);
|
||||
newXS(strcpy(buf, "forcedoorclose"), XS__forcedoorclose, file);
|
||||
newXS(strcpy(buf, "forcedooropen"), XS__forcedooropen, file);
|
||||
newXS(strcpy(buf, "getinventoryslotid"), XS__getinventoryslotid, file);
|
||||
newXS(strcpy(buf, "getItemName"), XS_qc_getItemName, file);
|
||||
newXS(strcpy(buf, "get_spawn_condition"), XS__get_spawn_condition, file);
|
||||
newXS(strcpy(buf, "getguildnamebyid"), XS__getguildnamebyid, file);
|
||||
|
||||
@ -538,6 +538,69 @@ Mob *HateList::GetRandomEntOnHateList()
|
||||
return (*iterator)->entity_on_hatelist;
|
||||
}
|
||||
|
||||
Mob *HateList::GetEscapingEntOnHateList() {
|
||||
// function is still in design stage
|
||||
|
||||
for (auto iter : list) {
|
||||
if (!iter->entity_on_hatelist)
|
||||
continue;
|
||||
|
||||
if (!iter->entity_on_hatelist->IsFeared())
|
||||
continue;
|
||||
|
||||
if (iter->entity_on_hatelist->IsRooted())
|
||||
continue;
|
||||
if (iter->entity_on_hatelist->IsMezzed())
|
||||
continue;
|
||||
if (iter->entity_on_hatelist->IsStunned())
|
||||
continue;
|
||||
|
||||
return iter->entity_on_hatelist;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Mob *HateList::GetEscapingEntOnHateList(Mob *center, float range, bool first) {
|
||||
// function is still in design stage
|
||||
|
||||
if (!center)
|
||||
return nullptr;
|
||||
|
||||
Mob *escaping_mob = nullptr;
|
||||
float mob_distance = 0.0f;
|
||||
|
||||
for (auto iter : list) {
|
||||
if (!iter->entity_on_hatelist)
|
||||
continue;
|
||||
|
||||
if (!iter->entity_on_hatelist->IsFeared())
|
||||
continue;
|
||||
|
||||
if (iter->entity_on_hatelist->IsRooted())
|
||||
continue;
|
||||
if (iter->entity_on_hatelist->IsMezzed())
|
||||
continue;
|
||||
if (iter->entity_on_hatelist->IsStunned())
|
||||
continue;
|
||||
|
||||
float distance_test = DistanceSquared(center->GetPosition(), iter->entity_on_hatelist->GetPosition());
|
||||
|
||||
if (range > 0.0f && distance_test > range)
|
||||
continue;
|
||||
|
||||
if (first)
|
||||
return iter->entity_on_hatelist;
|
||||
|
||||
if (distance_test > mob_distance) {
|
||||
escaping_mob = iter->entity_on_hatelist;
|
||||
mob_distance = distance_test;
|
||||
}
|
||||
}
|
||||
|
||||
return escaping_mob;
|
||||
}
|
||||
|
||||
int32 HateList::GetEntHateAmount(Mob *in_entity, bool damage)
|
||||
{
|
||||
struct_HateList *entity;
|
||||
|
||||
@ -46,6 +46,8 @@ public:
|
||||
Mob *GetEntWithMostHateOnList(Mob *center, Mob *skip = nullptr);
|
||||
Mob *GetRandomEntOnHateList();
|
||||
Mob *GetEntWithMostHateOnList();
|
||||
Mob *GetEscapingEntOnHateList(); // returns first eligble entity
|
||||
Mob *GetEscapingEntOnHateList(Mob *center, float range = 0.0f, bool first = false);
|
||||
|
||||
bool IsEntOnHateList(Mob *mob);
|
||||
bool IsHateListEmpty();
|
||||
|
||||
@ -44,23 +44,9 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) {
|
||||
x++;
|
||||
}
|
||||
|
||||
DeleteItemInInventory(i, 0, true);
|
||||
DeleteItemInInventory(i, 0, ((((uint64)1 << i) & GetInv().GetLookup()->PossessionsBitmask) != 0));
|
||||
}
|
||||
}
|
||||
|
||||
if (GetItemIDAt(EQEmu::invslot::SLOT_POWER_SOURCE) == itemnum || (itemnum == 0xFFFE && GetItemIDAt(EQEmu::invslot::SLOT_POWER_SOURCE) != INVALID_ID)) {
|
||||
cur = m_inv.GetItem(EQEmu::invslot::SLOT_POWER_SOURCE);
|
||||
if(cur && cur->GetItem()->Stackable) {
|
||||
x += cur->GetCharges();
|
||||
} else {
|
||||
x++;
|
||||
}
|
||||
|
||||
if (ClientVersion() >= EQEmu::versions::ClientVersion::SoF)
|
||||
DeleteItemInInventory(EQEmu::invslot::SLOT_POWER_SOURCE, 0, true);
|
||||
else
|
||||
DeleteItemInInventory(EQEmu::invslot::SLOT_POWER_SOURCE, 0, false); // Prevents Titanium crash
|
||||
}
|
||||
}
|
||||
|
||||
if(where_to_check & invWhereCursor) {
|
||||
@ -99,7 +85,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) {
|
||||
x++;
|
||||
}
|
||||
|
||||
DeleteItemInInventory(i, 0, true);
|
||||
DeleteItemInInventory(i, 0, ((((uint64)1 << i) & GetInv().GetLookup()->PossessionsBitmask) != 0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,7 +98,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) {
|
||||
x++;
|
||||
}
|
||||
|
||||
DeleteItemInInventory(i, 0, true);
|
||||
DeleteItemInInventory(i, 0, ((((uint64)1 << (EQEmu::invslot::GENERAL_BEGIN + ((i - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT))) & GetInv().GetLookup()->PossessionsBitmask) == 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,7 +113,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) {
|
||||
x++;
|
||||
}
|
||||
|
||||
DeleteItemInInventory(i, 0, true);
|
||||
DeleteItemInInventory(i, 0, ((i - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank]));
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,7 +126,7 @@ uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) {
|
||||
x++;
|
||||
}
|
||||
|
||||
DeleteItemInInventory(i, 0, true);
|
||||
DeleteItemInInventory(i, 0, (((i - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -554,8 +540,8 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2,
|
||||
inst->SetOrnamentHeroModel(ornament_hero_model);
|
||||
|
||||
// check to see if item is usable in requested slot
|
||||
if (enforceusable && (((to_slot >= EQEmu::invslot::slotCharm) && (to_slot <= EQEmu::invslot::slotAmmo)) || (to_slot == EQEmu::invslot::SLOT_POWER_SOURCE))) {
|
||||
uint32 slottest = (to_slot == EQEmu::invslot::SLOT_POWER_SOURCE) ? 22 : to_slot; // can't change '22' just yet...
|
||||
if (enforceusable && (to_slot >= EQEmu::invslot::EQUIPMENT_BEGIN && to_slot <= EQEmu::invslot::EQUIPMENT_END)) {
|
||||
uint32 slottest = to_slot;
|
||||
|
||||
if(!(slots & ((uint32)1 << slottest))) {
|
||||
Message(0, "This item is not equipable at slot %u - moving to cursor.", to_slot);
|
||||
@ -785,6 +771,25 @@ void Client::DropInst(const EQEmu::ItemInstance* inst)
|
||||
|
||||
// Returns a slot's item ID (returns INVALID_ID if not found)
|
||||
int32 Client::GetItemIDAt(int16 slot_id) {
|
||||
if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) {
|
||||
if ((((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
return INVALID_ID;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invbag::GENERAL_BAGS_END && slot_id >= EQEmu::invbag::GENERAL_BAGS_BEGIN) {
|
||||
auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot_id - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT);
|
||||
if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
return INVALID_ID;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) {
|
||||
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
return INVALID_ID;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) {
|
||||
auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
|
||||
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
return INVALID_ID;
|
||||
}
|
||||
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (inst)
|
||||
return inst->GetItem()->ID;
|
||||
@ -796,6 +801,25 @@ int32 Client::GetItemIDAt(int16 slot_id) {
|
||||
// Returns an augment's ID that's in an item (returns INVALID_ID if not found)
|
||||
// Pass in the slot ID of the item and which augslot you want to check (0-5)
|
||||
int32 Client::GetAugmentIDAt(int16 slot_id, uint8 augslot) {
|
||||
if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) {
|
||||
if ((((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
return INVALID_ID;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invbag::GENERAL_BAGS_END && slot_id >= EQEmu::invbag::GENERAL_BAGS_BEGIN) {
|
||||
auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot_id - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT);
|
||||
if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
return INVALID_ID;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) {
|
||||
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
return INVALID_ID;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) {
|
||||
auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
|
||||
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
return INVALID_ID;
|
||||
}
|
||||
|
||||
const EQEmu::ItemInstance* inst = m_inv[slot_id];
|
||||
if (inst && inst->GetAugmentItemID(augslot)) {
|
||||
return inst->GetAugmentItemID(augslot);
|
||||
@ -1032,7 +1056,7 @@ void Client::PutLootInInventory(int16 slot_id, const EQEmu::ItemInstance &inst,
|
||||
}
|
||||
|
||||
if (bag_item_data) {
|
||||
for (int index = 0; index < EQEmu::invbag::SLOT_COUNT; ++index) {
|
||||
for (int index = EQEmu::invbag::SLOT_BEGIN; index <= EQEmu::invbag::SLOT_END; ++index) {
|
||||
if (bag_item_data[index] == nullptr)
|
||||
continue;
|
||||
|
||||
@ -1072,12 +1096,15 @@ void Client::PutLootInInventory(int16 slot_id, const EQEmu::ItemInstance &inst,
|
||||
|
||||
CalcBonuses();
|
||||
}
|
||||
bool Client::TryStacking(EQEmu::ItemInstance* item, uint8 type, bool try_worn, bool try_cursor){
|
||||
bool Client::TryStacking(EQEmu::ItemInstance* item, uint8 type, bool try_worn, bool try_cursor) {
|
||||
if(!item || !item->IsStackable() || item->GetCharges()>=item->GetItem()->StackSize)
|
||||
return false;
|
||||
int16 i;
|
||||
uint32 item_id = item->GetItem()->ID;
|
||||
for (i = EQEmu::invslot::GENERAL_BEGIN; i <= EQEmu::invslot::GENERAL_END; i++) {
|
||||
if (((uint64)1 << i) & GetInv().GetLookup()->PossessionsBitmask == 0)
|
||||
continue;
|
||||
|
||||
EQEmu::ItemInstance* tmp_inst = m_inv.GetItem(i);
|
||||
if(tmp_inst && tmp_inst->GetItem()->ID == item_id && tmp_inst->GetCharges() < tmp_inst->GetItem()->StackSize){
|
||||
MoveItemCharges(*item, i, type);
|
||||
@ -1089,6 +1116,9 @@ bool Client::TryStacking(EQEmu::ItemInstance* item, uint8 type, bool try_worn, b
|
||||
}
|
||||
}
|
||||
for (i = EQEmu::invslot::GENERAL_BEGIN; i <= EQEmu::invslot::GENERAL_END; i++) {
|
||||
if (((uint64)1 << i) & GetInv().GetLookup()->PossessionsBitmask == 0)
|
||||
continue;
|
||||
|
||||
for (uint8 j = EQEmu::invbag::SLOT_BEGIN; j <= EQEmu::invbag::SLOT_END; j++) {
|
||||
uint16 slotid = EQEmu::InventoryProfile::CalcSlotId(i, j);
|
||||
EQEmu::ItemInstance* tmp_inst = m_inv.GetItem(slotid);
|
||||
@ -1113,15 +1143,9 @@ bool Client::AutoPutLootInInventory(EQEmu::ItemInstance& inst, bool try_worn, bo
|
||||
{
|
||||
// #1: Try to auto equip
|
||||
if (try_worn && inst.IsEquipable(GetBaseRace(), GetClass()) && inst.GetItem()->ReqLevel <= level && (!inst.GetItem()->Attuneable || inst.IsAttuned()) && inst.GetItem()->ItemType != EQEmu::item::ItemTypeAugmentation) {
|
||||
// too messy as-is... <watch>
|
||||
for (int16 i = EQEmu::invslot::EQUIPMENT_BEGIN; i < EQEmu::invslot::SLOT_POWER_SOURCE; i++) { // originally (i < 22)
|
||||
if (i == EQEmu::invslot::GENERAL_BEGIN) {
|
||||
// added power source check for SoF+ clients
|
||||
if (this->ClientVersion() >= EQEmu::versions::ClientVersion::SoF)
|
||||
i = EQEmu::invslot::SLOT_POWER_SOURCE;
|
||||
else
|
||||
break;
|
||||
}
|
||||
for (int16 i = EQEmu::invslot::EQUIPMENT_BEGIN; i <= EQEmu::invslot::EQUIPMENT_END; i++) {
|
||||
if (((uint64)1 << i) & GetInv().GetLookup()->PossessionsBitmask == 0)
|
||||
continue;
|
||||
|
||||
if (!m_inv[i]) {
|
||||
if (i == EQEmu::invslot::slotPrimary && inst.IsWeapon()) { // If item is primary slot weapon
|
||||
@ -1442,23 +1466,34 @@ void Client::SendLootItemInPacket(const EQEmu::ItemInstance* inst, int16 slot_id
|
||||
}
|
||||
|
||||
bool Client::IsValidSlot(uint32 slot) {
|
||||
if ((slot == (uint32)INVALID_INDEX) ||
|
||||
(slot >= EQEmu::invslot::POSSESSIONS_BEGIN && slot <= EQEmu::invslot::POSSESSIONS_END) ||
|
||||
(slot >= EQEmu::invbag::GENERAL_BAGS_BEGIN && slot <= EQEmu::invbag::CURSOR_BAG_END) ||
|
||||
(slot >= EQEmu::invslot::TRIBUTE_BEGIN && slot <= EQEmu::invslot::TRIBUTE_END) ||
|
||||
(slot >= EQEmu::invslot::BANK_BEGIN && slot <= EQEmu::invslot::BANK_END) ||
|
||||
(slot >= EQEmu::invbag::BANK_BAGS_BEGIN && slot <= EQEmu::invbag::BANK_BAGS_END) ||
|
||||
(slot >= EQEmu::invslot::SHARED_BANK_BEGIN && slot <= EQEmu::invslot::SHARED_BANK_END) ||
|
||||
(slot >= EQEmu::invbag::SHARED_BANK_BAGS_BEGIN && slot <= EQEmu::invbag::SHARED_BANK_BAGS_END) ||
|
||||
(slot >= EQEmu::invslot::TRADE_BEGIN && slot <= EQEmu::invslot::TRADE_END) ||
|
||||
(slot >= EQEmu::invslot::WORLD_BEGIN && slot <= EQEmu::invslot::WORLD_END) ||
|
||||
(slot == EQEmu::invslot::SLOT_POWER_SOURCE)
|
||||
) {
|
||||
if (slot <= EQEmu::invslot::POSSESSIONS_END && slot >= EQEmu::invslot::POSSESSIONS_BEGIN) {
|
||||
return ((((uint64)1 << slot) & GetInv().GetLookup()->PossessionsBitmask) != 0);
|
||||
}
|
||||
else if (slot <= EQEmu::invbag::GENERAL_BAGS_END && slot >= EQEmu::invbag::GENERAL_BAGS_BEGIN) {
|
||||
auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT);
|
||||
return ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) != 0);
|
||||
}
|
||||
else if (slot <= EQEmu::invslot::BANK_END && slot >= EQEmu::invslot::BANK_BEGIN) {
|
||||
return ((slot - EQEmu::invslot::BANK_BEGIN) < GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank]);
|
||||
}
|
||||
else if (slot <= EQEmu::invbag::BANK_BAGS_END && slot >= EQEmu::invbag::BANK_BAGS_BEGIN) {
|
||||
auto temp_slot = (slot - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
|
||||
return (temp_slot < GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank]);
|
||||
}
|
||||
else if (
|
||||
(slot == (uint32)INVALID_INDEX) ||
|
||||
(slot == (uint32)EQEmu::invslot::slotCursor) ||
|
||||
(slot <= EQEmu::invbag::CURSOR_BAG_END && slot >= EQEmu::invbag::CURSOR_BAG_BEGIN) ||
|
||||
(slot <= EQEmu::invslot::TRIBUTE_END && slot >= EQEmu::invslot::TRIBUTE_BEGIN) ||
|
||||
(slot <= EQEmu::invslot::SHARED_BANK_END && slot >= EQEmu::invslot::SHARED_BANK_BEGIN) ||
|
||||
(slot <= EQEmu::invbag::SHARED_BANK_BAGS_END && slot >= EQEmu::invbag::SHARED_BANK_BAGS_BEGIN) ||
|
||||
(slot <= EQEmu::invslot::TRADE_END && slot >= EQEmu::invslot::TRADE_BEGIN) ||
|
||||
(slot <= EQEmu::invslot::WORLD_END && slot >= EQEmu::invslot::WORLD_BEGIN)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Client::IsBankSlot(uint32 slot)
|
||||
@ -1550,10 +1585,14 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
return true; // Item deletion
|
||||
}
|
||||
}
|
||||
if (auto_attack && (move_in->from_slot == EQEmu::invslot::slotPrimary || move_in->from_slot == EQEmu::invslot::slotSecondary || move_in->from_slot == EQEmu::invslot::slotRange))
|
||||
SetAttackTimer();
|
||||
else if (auto_attack && (move_in->to_slot == EQEmu::invslot::slotPrimary || move_in->to_slot == EQEmu::invslot::slotSecondary || move_in->to_slot == EQEmu::invslot::slotRange))
|
||||
SetAttackTimer();
|
||||
|
||||
if (auto_attack) {
|
||||
if (move_in->from_slot == EQEmu::invslot::slotPrimary || move_in->from_slot == EQEmu::invslot::slotSecondary || move_in->from_slot == EQEmu::invslot::slotRange)
|
||||
SetAttackTimer();
|
||||
else if (move_in->to_slot == EQEmu::invslot::slotPrimary || move_in->to_slot == EQEmu::invslot::slotSecondary || move_in->to_slot == EQEmu::invslot::slotRange)
|
||||
SetAttackTimer();
|
||||
}
|
||||
|
||||
// Step 1: Variables
|
||||
int16 src_slot_id = (int16)move_in->from_slot;
|
||||
int16 dst_slot_id = (int16)move_in->to_slot;
|
||||
@ -1599,13 +1638,11 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
uint32 srcbagid =0;
|
||||
uint32 dstbagid = 0;
|
||||
|
||||
//if (src_slot_id >= 250 && src_slot_id < 330) {
|
||||
if (src_slot_id >= EQEmu::invbag::GENERAL_BAGS_BEGIN && src_slot_id <= EQEmu::invbag::GENERAL_BAGS_END) {
|
||||
srcbag = m_inv.GetItem(((int)(src_slot_id / 10)) - 3);
|
||||
if (srcbag)
|
||||
srcbagid = srcbag->GetItem()->ID;
|
||||
}
|
||||
//if (dst_slot_id >= 250 && dst_slot_id < 330) {
|
||||
if (dst_slot_id >= EQEmu::invbag::GENERAL_BAGS_BEGIN && dst_slot_id <= EQEmu::invbag::GENERAL_BAGS_END) {
|
||||
dstbag = m_inv.GetItem(((int)(dst_slot_id / 10)) - 3);
|
||||
if (dstbag)
|
||||
@ -1877,7 +1914,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
}
|
||||
else {
|
||||
// Not dealing with charges - just do direct swap
|
||||
if (src_inst && (dst_slot_id <= EQEmu::invslot::EQUIPMENT_END || dst_slot_id == EQEmu::invslot::SLOT_POWER_SOURCE) && dst_slot_id >= EQEmu::invslot::EQUIPMENT_BEGIN) {
|
||||
if (src_inst && (dst_slot_id <= EQEmu::invslot::EQUIPMENT_END) && dst_slot_id >= EQEmu::invslot::EQUIPMENT_BEGIN) {
|
||||
if (src_inst->GetItem()->Attuneable) {
|
||||
src_inst->SetAttuned(true);
|
||||
}
|
||||
@ -1909,7 +1946,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
|
||||
Log(Logs::Detail, Logs::Inventory, "Moving entire item from slot %d to slot %d", src_slot_id, dst_slot_id);
|
||||
|
||||
if (src_slot_id <= EQEmu::invslot::EQUIPMENT_END || src_slot_id == EQEmu::invslot::SLOT_POWER_SOURCE) {
|
||||
if (src_slot_id <= EQEmu::invslot::EQUIPMENT_END) {
|
||||
if(src_inst) {
|
||||
parse->EventItem(EVENT_UNEQUIP_ITEM, this, src_inst, nullptr, "", src_slot_id);
|
||||
}
|
||||
@ -1919,7 +1956,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
|
||||
}
|
||||
}
|
||||
|
||||
if (dst_slot_id <= EQEmu::invslot::EQUIPMENT_END || dst_slot_id == EQEmu::invslot::SLOT_POWER_SOURCE) {
|
||||
if (dst_slot_id <= EQEmu::invslot::EQUIPMENT_END) {
|
||||
if(dst_inst) {
|
||||
parse->EventItem(EVENT_UNEQUIP_ITEM, this, dst_inst, nullptr, "", dst_slot_id);
|
||||
}
|
||||
@ -1973,7 +2010,7 @@ void Client::SwapItemResync(MoveItem_Struct* move_slots) {
|
||||
Log(Logs::Detail, Logs::Inventory, "Inventory desyncronization. (charname: %s, source: %i, destination: %i)", GetName(), move_slots->from_slot, move_slots->to_slot);
|
||||
Message(15, "Inventory Desyncronization detected: Resending slot data...");
|
||||
|
||||
if ((move_slots->from_slot >= EQEmu::invslot::EQUIPMENT_BEGIN && move_slots->from_slot <= EQEmu::invbag::CURSOR_BAG_END) || move_slots->from_slot == EQEmu::invslot::SLOT_POWER_SOURCE) {
|
||||
if (move_slots->from_slot >= EQEmu::invslot::EQUIPMENT_BEGIN && move_slots->from_slot <= EQEmu::invbag::CURSOR_BAG_END) {
|
||||
int16 resync_slot = (EQEmu::InventoryProfile::CalcSlotId(move_slots->from_slot) == INVALID_INDEX) ? move_slots->from_slot : EQEmu::InventoryProfile::CalcSlotId(move_slots->from_slot);
|
||||
if (IsValidSlot(resync_slot) && resync_slot != INVALID_INDEX) {
|
||||
// This prevents the client from crashing when closing any 'phantom' bags
|
||||
@ -2016,7 +2053,7 @@ void Client::SwapItemResync(MoveItem_Struct* move_slots) {
|
||||
else { Message(13, "Could not resyncronize source slot %i.", move_slots->from_slot); }
|
||||
}
|
||||
|
||||
if ((move_slots->to_slot >= EQEmu::invslot::EQUIPMENT_BEGIN && move_slots->to_slot <= EQEmu::invbag::CURSOR_BAG_END) || move_slots->to_slot == EQEmu::invslot::SLOT_POWER_SOURCE) {
|
||||
if (move_slots->to_slot >= EQEmu::invslot::EQUIPMENT_BEGIN && move_slots->to_slot <= EQEmu::invbag::CURSOR_BAG_END) {
|
||||
int16 resync_slot = (EQEmu::InventoryProfile::CalcSlotId(move_slots->to_slot) == INVALID_INDEX) ? move_slots->to_slot : EQEmu::InventoryProfile::CalcSlotId(move_slots->to_slot);
|
||||
if (IsValidSlot(resync_slot) && resync_slot != INVALID_INDEX) {
|
||||
const EQEmu::ItemData* token_struct = database.GetItem(22292); // 'Copper Coin'
|
||||
@ -2251,47 +2288,118 @@ bool Client::DecreaseByID(uint32 type, uint8 amt) {
|
||||
EQEmu::ItemInstance* ins = nullptr;
|
||||
int x;
|
||||
int num = 0;
|
||||
for(x = EQEmu::invslot::EQUIPMENT_BEGIN; x <= EQEmu::invbag::GENERAL_BAGS_END; x++)
|
||||
{
|
||||
if (x == EQEmu::invslot::slotCursor + 1)
|
||||
x = EQEmu::invbag::GENERAL_BAGS_BEGIN;
|
||||
|
||||
for (x = EQEmu::invslot::POSSESSIONS_BEGIN; x <= EQEmu::invslot::POSSESSIONS_END; ++x) {
|
||||
if (num >= amt)
|
||||
break;
|
||||
if (((uint64)1 << x) & GetInv().GetLookup()->PossessionsBitmask == 0)
|
||||
continue;
|
||||
|
||||
TempItem = nullptr;
|
||||
ins = GetInv().GetItem(x);
|
||||
if (ins)
|
||||
TempItem = ins->GetItem();
|
||||
if (TempItem && TempItem->ID == type)
|
||||
{
|
||||
num += ins->GetCharges();
|
||||
if (num >= amt)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (x = EQEmu::invbag::GENERAL_BAGS_BEGIN; x <= EQEmu::invbag::GENERAL_BAGS_END; ++x) {
|
||||
if (num >= amt)
|
||||
break;
|
||||
if ((((uint64)1 << (EQEmu::invslot::GENERAL_BEGIN + ((x - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT))) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
TempItem = nullptr;
|
||||
ins = GetInv().GetItem(x);
|
||||
if (ins)
|
||||
TempItem = ins->GetItem();
|
||||
if (TempItem && TempItem->ID == type)
|
||||
num += ins->GetCharges();
|
||||
}
|
||||
|
||||
for (x = EQEmu::invbag::CURSOR_BAG_BEGIN; x <= EQEmu::invbag::CURSOR_BAG_END; ++x) {
|
||||
if (num >= amt)
|
||||
break;
|
||||
|
||||
TempItem = nullptr;
|
||||
ins = GetInv().GetItem(x);
|
||||
if (ins)
|
||||
TempItem = ins->GetItem();
|
||||
if (TempItem && TempItem->ID == type)
|
||||
num += ins->GetCharges();
|
||||
}
|
||||
|
||||
if (num < amt)
|
||||
return false;
|
||||
for(x = EQEmu::invslot::EQUIPMENT_BEGIN; x <= EQEmu::invbag::GENERAL_BAGS_END; x++) // should this be CURSOR_BAG_END?
|
||||
{
|
||||
if (x == EQEmu::invslot::slotCursor + 1)
|
||||
x = EQEmu::invbag::GENERAL_BAGS_BEGIN;
|
||||
|
||||
|
||||
for (x = EQEmu::invslot::POSSESSIONS_BEGIN; x <= EQEmu::invslot::POSSESSIONS_END; ++x) {
|
||||
if (amt < 1)
|
||||
break;
|
||||
if (((uint64)1 << x) & GetInv().GetLookup()->PossessionsBitmask == 0)
|
||||
continue;
|
||||
|
||||
TempItem = nullptr;
|
||||
ins = GetInv().GetItem(x);
|
||||
if (ins)
|
||||
TempItem = ins->GetItem();
|
||||
if (TempItem && TempItem->ID == type)
|
||||
{
|
||||
if (ins->GetCharges() < amt)
|
||||
{
|
||||
amt -= ins->GetCharges();
|
||||
DeleteItemInInventory(x,amt,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteItemInInventory(x,amt,true);
|
||||
amt = 0;
|
||||
}
|
||||
if (amt < 1)
|
||||
break;
|
||||
if (TempItem && TempItem->ID != type)
|
||||
continue;
|
||||
|
||||
if (ins->GetCharges() < amt) {
|
||||
amt -= ins->GetCharges();
|
||||
DeleteItemInInventory(x, amt, true);
|
||||
}
|
||||
else {
|
||||
DeleteItemInInventory(x, amt, true);
|
||||
amt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (x = EQEmu::invbag::GENERAL_BAGS_BEGIN; x <= EQEmu::invbag::GENERAL_BAGS_END; ++x) {
|
||||
if (amt < 1)
|
||||
break;
|
||||
if ((((uint64)1 << (EQEmu::invslot::GENERAL_BEGIN + ((x - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT))) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
TempItem = nullptr;
|
||||
ins = GetInv().GetItem(x);
|
||||
if (ins)
|
||||
TempItem = ins->GetItem();
|
||||
if (TempItem && TempItem->ID != type)
|
||||
continue;
|
||||
|
||||
if (ins->GetCharges() < amt) {
|
||||
amt -= ins->GetCharges();
|
||||
DeleteItemInInventory(x, amt, true);
|
||||
}
|
||||
else {
|
||||
DeleteItemInInventory(x, amt, true);
|
||||
amt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (x = EQEmu::invbag::CURSOR_BAG_BEGIN; x <= EQEmu::invbag::CURSOR_BAG_END; ++x) {
|
||||
if (amt < 1)
|
||||
break;
|
||||
|
||||
TempItem = nullptr;
|
||||
ins = GetInv().GetItem(x);
|
||||
if (ins)
|
||||
TempItem = ins->GetItem();
|
||||
if (TempItem && TempItem->ID != type)
|
||||
continue;
|
||||
|
||||
if (ins->GetCharges() < amt) {
|
||||
amt -= ins->GetCharges();
|
||||
DeleteItemInInventory(x, amt, true);
|
||||
}
|
||||
else {
|
||||
DeleteItemInInventory(x, amt, true);
|
||||
amt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2368,6 +2476,9 @@ static bool CopyBagContents(EQEmu::ItemInstance* new_bag, const EQEmu::ItemInsta
|
||||
void Client::DisenchantSummonedBags(bool client_update)
|
||||
{
|
||||
for (auto slot_id = EQEmu::invslot::GENERAL_BEGIN; slot_id <= EQEmu::invslot::GENERAL_END; ++slot_id) {
|
||||
if (((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask == 0)
|
||||
continue; // not useable this session - will be disenchanted once player logs in on client that doesn't exclude affected slots
|
||||
|
||||
auto inst = m_inv[slot_id];
|
||||
if (!inst) { continue; }
|
||||
if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; }
|
||||
@ -2389,6 +2500,9 @@ void Client::DisenchantSummonedBags(bool client_update)
|
||||
}
|
||||
|
||||
for (auto slot_id = EQEmu::invslot::BANK_BEGIN; slot_id <= EQEmu::invslot::BANK_END; ++slot_id) {
|
||||
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
continue;
|
||||
|
||||
auto inst = m_inv[slot_id];
|
||||
if (!inst) { continue; }
|
||||
if (!IsSummonedBagID(inst->GetItem()->ID)) { continue; }
|
||||
@ -2479,6 +2593,9 @@ void Client::DisenchantSummonedBags(bool client_update)
|
||||
void Client::RemoveNoRent(bool client_update)
|
||||
{
|
||||
for (auto slot_id = EQEmu::invslot::EQUIPMENT_BEGIN; slot_id <= EQEmu::invslot::EQUIPMENT_END; ++slot_id) {
|
||||
if (((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask == 0)
|
||||
continue;
|
||||
|
||||
auto inst = m_inv[slot_id];
|
||||
if(inst && !inst->GetItem()->NoRent) {
|
||||
Log(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id);
|
||||
@ -2487,6 +2604,9 @@ void Client::RemoveNoRent(bool client_update)
|
||||
}
|
||||
|
||||
for (auto slot_id = EQEmu::invslot::GENERAL_BEGIN; slot_id <= EQEmu::invslot::GENERAL_END; ++slot_id) {
|
||||
if (((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask == 0)
|
||||
continue;
|
||||
|
||||
auto inst = m_inv[slot_id];
|
||||
if (inst && !inst->GetItem()->NoRent) {
|
||||
Log(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id);
|
||||
@ -2494,15 +2614,11 @@ void Client::RemoveNoRent(bool client_update)
|
||||
}
|
||||
}
|
||||
|
||||
if (m_inv[EQEmu::invslot::SLOT_POWER_SOURCE]) {
|
||||
auto inst = m_inv[EQEmu::invslot::SLOT_POWER_SOURCE];
|
||||
if (inst && !inst->GetItem()->NoRent) {
|
||||
Log(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, EQEmu::invslot::SLOT_POWER_SOURCE);
|
||||
DeleteItemInInventory(EQEmu::invslot::SLOT_POWER_SOURCE, 0, (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) ? client_update : false); // Ti slot non-existent
|
||||
}
|
||||
}
|
||||
|
||||
for (auto slot_id = EQEmu::invbag::GENERAL_BAGS_BEGIN; slot_id <= EQEmu::invbag::CURSOR_BAG_END; ++slot_id) {
|
||||
auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot_id - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT);
|
||||
if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
auto inst = m_inv[slot_id];
|
||||
if(inst && !inst->GetItem()->NoRent) {
|
||||
Log(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id);
|
||||
@ -2511,6 +2627,9 @@ void Client::RemoveNoRent(bool client_update)
|
||||
}
|
||||
|
||||
for (auto slot_id = EQEmu::invslot::BANK_BEGIN; slot_id <= EQEmu::invslot::BANK_END; ++slot_id) {
|
||||
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
continue;
|
||||
|
||||
auto inst = m_inv[slot_id];
|
||||
if(inst && !inst->GetItem()->NoRent) {
|
||||
Log(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id);
|
||||
@ -2519,6 +2638,10 @@ void Client::RemoveNoRent(bool client_update)
|
||||
}
|
||||
|
||||
for (auto slot_id = EQEmu::invbag::BANK_BAGS_BEGIN; slot_id <= EQEmu::invbag::BANK_BAGS_END; ++slot_id) {
|
||||
auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
|
||||
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
continue;
|
||||
|
||||
auto inst = m_inv[slot_id];
|
||||
if(inst && !inst->GetItem()->NoRent) {
|
||||
Log(Logs::Detail, Logs::Inventory, "NoRent Timer Lapse: Deleting %s from slot %i", inst->GetItem()->Name, slot_id);
|
||||
@ -2573,6 +2696,9 @@ void Client::RemoveNoRent(bool client_update)
|
||||
void Client::RemoveDuplicateLore(bool client_update)
|
||||
{
|
||||
for (auto slot_id = EQEmu::invslot::EQUIPMENT_BEGIN; slot_id <= EQEmu::invslot::EQUIPMENT_END; ++slot_id) {
|
||||
if (((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask == 0)
|
||||
continue;
|
||||
|
||||
auto inst = m_inv.PopItem(slot_id);
|
||||
if (inst == nullptr) { continue; }
|
||||
if(CheckLoreConflict(inst->GetItem())) {
|
||||
@ -2586,6 +2712,9 @@ void Client::RemoveDuplicateLore(bool client_update)
|
||||
}
|
||||
|
||||
for (auto slot_id = EQEmu::invslot::GENERAL_BEGIN; slot_id <= EQEmu::invslot::GENERAL_END; ++slot_id) {
|
||||
if (((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask == 0)
|
||||
continue;
|
||||
|
||||
auto inst = m_inv.PopItem(slot_id);
|
||||
if (inst == nullptr) { continue; }
|
||||
if (CheckLoreConflict(inst->GetItem())) {
|
||||
@ -2598,21 +2727,11 @@ void Client::RemoveDuplicateLore(bool client_update)
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
if (m_inv[EQEmu::invslot::SLOT_POWER_SOURCE]) {
|
||||
auto inst = m_inv.PopItem(EQEmu::invslot::SLOT_POWER_SOURCE);
|
||||
if (inst) {
|
||||
if (CheckLoreConflict(inst->GetItem())) {
|
||||
Log(Logs::Detail, Logs::Inventory, "Lore Duplication Error: Deleting %s from slot %i", inst->GetItem()->Name, EQEmu::invslot::SLOT_POWER_SOURCE);
|
||||
database.SaveInventory(character_id, nullptr, EQEmu::invslot::SLOT_POWER_SOURCE);
|
||||
}
|
||||
else {
|
||||
m_inv.PutItem(EQEmu::invslot::SLOT_POWER_SOURCE, *inst);
|
||||
}
|
||||
safe_delete(inst);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto slot_id = EQEmu::invbag::GENERAL_BAGS_BEGIN; slot_id <= EQEmu::invbag::CURSOR_BAG_END; ++slot_id) {
|
||||
auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot_id - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT);
|
||||
if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
continue;
|
||||
|
||||
auto inst = m_inv.PopItem(slot_id);
|
||||
if (inst == nullptr) { continue; }
|
||||
if(CheckLoreConflict(inst->GetItem())) {
|
||||
@ -2626,6 +2745,9 @@ void Client::RemoveDuplicateLore(bool client_update)
|
||||
}
|
||||
|
||||
for (auto slot_id = EQEmu::invslot::BANK_BEGIN; slot_id <= EQEmu::invslot::BANK_END; ++slot_id) {
|
||||
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
continue;
|
||||
|
||||
auto inst = m_inv.PopItem(slot_id);
|
||||
if (inst == nullptr) { continue; }
|
||||
if(CheckLoreConflict(inst->GetItem())) {
|
||||
@ -2639,6 +2761,10 @@ void Client::RemoveDuplicateLore(bool client_update)
|
||||
}
|
||||
|
||||
for (auto slot_id = EQEmu::invbag::BANK_BAGS_BEGIN; slot_id <= EQEmu::invbag::BANK_BAGS_END; ++slot_id) {
|
||||
auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
|
||||
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
continue;
|
||||
|
||||
auto inst = m_inv.PopItem(slot_id);
|
||||
if (inst == nullptr) { continue; }
|
||||
if(CheckLoreConflict(inst->GetItem())) {
|
||||
@ -2711,15 +2837,21 @@ void Client::MoveSlotNotAllowed(bool client_update)
|
||||
}
|
||||
}
|
||||
|
||||
if (m_inv[EQEmu::invslot::SLOT_POWER_SOURCE] && !m_inv[EQEmu::invslot::SLOT_POWER_SOURCE]->IsSlotAllowed(EQEmu::invslot::SLOT_POWER_SOURCE)) {
|
||||
auto inst = m_inv.PopItem(EQEmu::invslot::SLOT_POWER_SOURCE);
|
||||
bool is_arrow = (inst->GetItem()->ItemType == EQEmu::item::ItemTypeArrow) ? true : false;
|
||||
int16 free_slot_id = m_inv.FindFreeSlot(inst->IsClassBag(), true, inst->GetItem()->Size, is_arrow);
|
||||
Log(Logs::Detail, Logs::Inventory, "Slot Assignment Error: Moving %s from slot %i to %i", inst->GetItem()->Name, EQEmu::invslot::SLOT_POWER_SOURCE, free_slot_id);
|
||||
PutItemInInventory(free_slot_id, *inst, (ClientVersion() >= EQEmu::versions::ClientVersion::SoF) ? client_update : false);
|
||||
database.SaveInventory(character_id, nullptr, EQEmu::invslot::SLOT_POWER_SOURCE);
|
||||
safe_delete(inst);
|
||||
}
|
||||
// added this check to move any client-based excluded slots
|
||||
//for (auto slot_id = EQEmu::invslot::POSSESSIONS_BEGIN; slot_id <= EQEmu::invslot::POSSESSIONS_END; ++slot_id) {
|
||||
// if (((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask != 0)
|
||||
// continue;
|
||||
|
||||
// if (m_inv[slot_id]) { // this is currently dangerous for bag-based movements since limbo does not save bag slots
|
||||
// auto inst = m_inv.PopItem(slot_id);
|
||||
// bool is_arrow = (inst->GetItem()->ItemType == EQEmu::item::ItemTypeArrow) ? true : false;
|
||||
// int16 free_slot_id = m_inv.FindFreeSlot(inst->IsClassBag(), true, inst->GetItem()->Size, is_arrow);
|
||||
// Log(Logs::Detail, Logs::Inventory, "Slot Assignment Error: Moving %s from slot %i to %i", inst->GetItem()->Name, slot_id, free_slot_id);
|
||||
// PutItemInInventory(free_slot_id, *inst, client_update);
|
||||
// database.SaveInventory(character_id, nullptr, slot_id);
|
||||
// safe_delete(inst);
|
||||
// }
|
||||
//}
|
||||
|
||||
// No need to check inventory, cursor, bank or shared bank since they allow max item size and containers
|
||||
// Code can be added to check item size vs. container size, but it is left to attrition for now.
|
||||
@ -2785,7 +2917,26 @@ void Client::SendItemPacket(int16 slot_id, const EQEmu::ItemInstance* inst, Item
|
||||
if (!inst)
|
||||
return;
|
||||
|
||||
// Serialize item into |-delimited string
|
||||
if (slot_id <= EQEmu::invslot::POSSESSIONS_END && slot_id >= EQEmu::invslot::POSSESSIONS_BEGIN) {
|
||||
if ((((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
return;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invbag::GENERAL_BAGS_END && slot_id >= EQEmu::invbag::GENERAL_BAGS_BEGIN) {
|
||||
auto temp_slot = EQEmu::invslot::GENERAL_BEGIN + ((slot_id - EQEmu::invbag::GENERAL_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT);
|
||||
if ((((uint64)1 << temp_slot) & GetInv().GetLookup()->PossessionsBitmask) == 0)
|
||||
return;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invslot::BANK_END && slot_id >= EQEmu::invslot::BANK_BEGIN) {
|
||||
if ((slot_id - EQEmu::invslot::BANK_BEGIN) >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
return;
|
||||
}
|
||||
else if (slot_id <= EQEmu::invbag::BANK_BAGS_END && slot_id >= EQEmu::invbag::BANK_BAGS_BEGIN) {
|
||||
auto temp_slot = (slot_id - EQEmu::invbag::BANK_BAGS_BEGIN) / EQEmu::invbag::SLOT_COUNT;
|
||||
if (temp_slot >= GetInv().GetLookup()->InventoryTypeSize[EQEmu::invtype::typeBank])
|
||||
return;
|
||||
}
|
||||
|
||||
// Serialize item into |-delimited string (Titanium- uses '|' delimiter .. newer clients use pure data serialization)
|
||||
std::string packet = inst->Serialize(slot_id);
|
||||
|
||||
EmuOpcode opcode = OP_Unknown;
|
||||
@ -3069,6 +3220,8 @@ bool Client::MoveItemToInventory(EQEmu::ItemInstance *ItemToReturn, bool UpdateC
|
||||
if(ItemToReturn->IsStackable()) {
|
||||
|
||||
for (int16 i = EQEmu::invslot::GENERAL_BEGIN; i <= EQEmu::invslot::slotCursor; i++) { // changed slot max to 30 from 29. client will stack into slot 30 (bags too) before moving.
|
||||
if (((uint64)1 << i) & GetInv().GetLookup()->PossessionsBitmask == 0)
|
||||
continue;
|
||||
|
||||
EQEmu::ItemInstance* InvItem = m_inv.GetItem(i);
|
||||
|
||||
@ -3128,6 +3281,8 @@ bool Client::MoveItemToInventory(EQEmu::ItemInstance *ItemToReturn, bool UpdateC
|
||||
// We have tried stacking items, now just try and find an empty slot.
|
||||
|
||||
for (int16 i = EQEmu::invslot::GENERAL_BEGIN; i <= EQEmu::invslot::slotCursor; i++) { // changed slot max to 30 from 29. client will move into slot 30 (bags too) before pushing onto cursor.
|
||||
if (((uint64)1 << i) & GetInv().GetLookup()->PossessionsBitmask == 0)
|
||||
continue;
|
||||
|
||||
EQEmu::ItemInstance* InvItem = m_inv.GetItem(i);
|
||||
|
||||
@ -3188,7 +3343,7 @@ bool Client::InterrogateInventory(Client* requester, bool log, bool silent, bool
|
||||
std::map<int16, const EQEmu::ItemInstance*> instmap;
|
||||
|
||||
// build reference map
|
||||
for (int16 index = EQEmu::invslot::EQUIPMENT_BEGIN; index <= EQEmu::invslot::POSSESSIONS_END; ++index) {
|
||||
for (int16 index = EQEmu::invslot::POSSESSIONS_BEGIN; index <= EQEmu::invslot::POSSESSIONS_END; ++index) {
|
||||
auto inst = m_inv[index];
|
||||
if (inst == nullptr) { continue; }
|
||||
instmap[index] = inst;
|
||||
@ -3232,9 +3387,6 @@ bool Client::InterrogateInventory(Client* requester, bool log, bool silent, bool
|
||||
instmap[8000 + limbo] = *cursor_itr;
|
||||
}
|
||||
|
||||
if (m_inv[EQEmu::invslot::SLOT_POWER_SOURCE])
|
||||
instmap[EQEmu::invslot::SLOT_POWER_SOURCE] = m_inv[EQEmu::invslot::SLOT_POWER_SOURCE];
|
||||
|
||||
// call InterrogateInventory_ for error check
|
||||
for (auto instmap_itr = instmap.begin(); (instmap_itr != instmap.end()) && (!error); ++instmap_itr) {
|
||||
InterrogateInventory_(true, requester, instmap_itr->first, INVALID_INDEX, instmap_itr->second, nullptr, log, silent, error, 0);
|
||||
@ -3339,8 +3491,7 @@ bool Client::InterrogateInventory_error(int16 head, int16 index, const EQEmu::It
|
||||
(head >= EQEmu::invslot::EQUIPMENT_BEGIN && head <= EQEmu::invslot::EQUIPMENT_END) ||
|
||||
(head >= EQEmu::invslot::TRIBUTE_BEGIN && head <= EQEmu::invslot::TRIBUTE_END) ||
|
||||
(head >= EQEmu::invslot::WORLD_BEGIN && head <= EQEmu::invslot::WORLD_END) ||
|
||||
(head >= 8000 && head <= 8101) ||
|
||||
(head == EQEmu::invslot::SLOT_POWER_SOURCE)) {
|
||||
(head >= 8000 && head <= 8101)) {
|
||||
switch (depth)
|
||||
{
|
||||
case 0: // requirement: inst is extant
|
||||
|
||||
@ -323,7 +323,7 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
|
||||
// @merth: IDFile size has been increased, this needs to change
|
||||
uint16 emat;
|
||||
if(item2->Material <= 0
|
||||
|| item2->Slots & (1 << EQEmu::invslot::slotPrimary | 1 << EQEmu::invslot::slotSecondary)) {
|
||||
|| (item2->Slots & ((1 << EQEmu::invslot::slotPrimary) | (1 << EQEmu::invslot::slotSecondary)))) {
|
||||
memset(newid, 0, sizeof(newid));
|
||||
for(int i=0;i<7;i++){
|
||||
if (!isalpha(item2->IDFile[i])){
|
||||
|
||||
@ -1870,27 +1870,22 @@ luabind::scope lua_register_slot() {
|
||||
luabind::value("Face", static_cast<int>(EQEmu::invslot::slotFace)),
|
||||
luabind::value("Ear2", static_cast<int>(EQEmu::invslot::slotEar2)),
|
||||
luabind::value("Neck", static_cast<int>(EQEmu::invslot::slotNeck)),
|
||||
luabind::value("Shoulder", static_cast<int>(EQEmu::invslot::slotShoulders)), // deprecated
|
||||
luabind::value("Shoulders", static_cast<int>(EQEmu::invslot::slotShoulders)),
|
||||
luabind::value("Arms", static_cast<int>(EQEmu::invslot::slotArms)),
|
||||
luabind::value("Back", static_cast<int>(EQEmu::invslot::slotBack)),
|
||||
luabind::value("Bracer1", static_cast<int>(EQEmu::invslot::slotWrist1)), // deprecated
|
||||
luabind::value("Wrist1", static_cast<int>(EQEmu::invslot::slotWrist1)),
|
||||
luabind::value("Bracer2", static_cast<int>(EQEmu::invslot::slotWrist2)), // deprecated
|
||||
luabind::value("Wrist2", static_cast<int>(EQEmu::invslot::slotWrist2)),
|
||||
luabind::value("Range", static_cast<int>(EQEmu::invslot::slotRange)),
|
||||
luabind::value("Hands", static_cast<int>(EQEmu::invslot::slotHands)),
|
||||
luabind::value("Primary", static_cast<int>(EQEmu::invslot::slotPrimary)),
|
||||
luabind::value("Secondary", static_cast<int>(EQEmu::invslot::slotSecondary)),
|
||||
luabind::value("Ring1", static_cast<int>(EQEmu::invslot::slotFinger1)), // deprecated
|
||||
luabind::value("Finger1", static_cast<int>(EQEmu::invslot::slotFinger1)),
|
||||
luabind::value("Ring2", static_cast<int>(EQEmu::invslot::slotFinger2)), // deprecated
|
||||
luabind::value("Finger2", static_cast<int>(EQEmu::invslot::slotFinger2)),
|
||||
luabind::value("Chest", static_cast<int>(EQEmu::invslot::slotChest)),
|
||||
luabind::value("Legs", static_cast<int>(EQEmu::invslot::slotLegs)),
|
||||
luabind::value("Feet", static_cast<int>(EQEmu::invslot::slotFeet)),
|
||||
luabind::value("Waist", static_cast<int>(EQEmu::invslot::slotWaist)),
|
||||
luabind::value("PowerSource", static_cast<int>(EQEmu::invslot::SLOT_POWER_SOURCE)),
|
||||
luabind::value("PowerSource", static_cast<int>(EQEmu::invslot::slotPowerSource)),
|
||||
luabind::value("Ammo", static_cast<int>(EQEmu::invslot::slotAmmo)),
|
||||
luabind::value("General1", static_cast<int>(EQEmu::invslot::slotGeneral1)),
|
||||
luabind::value("General2", static_cast<int>(EQEmu::invslot::slotGeneral2)),
|
||||
@ -1900,15 +1895,43 @@ luabind::scope lua_register_slot() {
|
||||
luabind::value("General6", static_cast<int>(EQEmu::invslot::slotGeneral6)),
|
||||
luabind::value("General7", static_cast<int>(EQEmu::invslot::slotGeneral7)),
|
||||
luabind::value("General8", static_cast<int>(EQEmu::invslot::slotGeneral8)),
|
||||
luabind::value("General9", static_cast<int>(EQEmu::invslot::slotGeneral9)),
|
||||
luabind::value("General10", static_cast<int>(EQEmu::invslot::slotGeneral10)),
|
||||
luabind::value("Cursor", static_cast<int>(EQEmu::invslot::slotCursor)),
|
||||
luabind::value("PersonalBegin", static_cast<int>(EQEmu::invslot::GENERAL_BEGIN)), // deprecated
|
||||
luabind::value("PossessionsBegin", static_cast<int>(EQEmu::invslot::POSSESSIONS_BEGIN)),
|
||||
luabind::value("PossessionsEnd", static_cast<int>(EQEmu::invslot::POSSESSIONS_END)),
|
||||
luabind::value("EquipmentBegin", static_cast<int>(EQEmu::invslot::EQUIPMENT_BEGIN)),
|
||||
luabind::value("EquipmentEnd", static_cast<int>(EQEmu::invslot::EQUIPMENT_END)),
|
||||
luabind::value("GeneralBegin", static_cast<int>(EQEmu::invslot::GENERAL_BEGIN)),
|
||||
luabind::value("PersonalEnd", static_cast<int>(EQEmu::invslot::GENERAL_END)), // deprecated
|
||||
luabind::value("GeneralEnd", static_cast<int>(EQEmu::invslot::GENERAL_END)),
|
||||
luabind::value("CursorEnd", 0xFFFE), // deprecated
|
||||
luabind::value("Tradeskill", static_cast<int>(EQEmu::legacy::SLOT_TRADESKILL)), // deprecated
|
||||
luabind::value("Augment", static_cast<int>(EQEmu::legacy::SLOT_AUGMENT)), // deprecated
|
||||
luabind::value("Invalid", INVALID_INDEX)
|
||||
luabind::value("GeneralBagsBegin", static_cast<int>(EQEmu::invbag::GENERAL_BAGS_BEGIN)),
|
||||
luabind::value("GeneralBagsEnd", static_cast<int>(EQEmu::invbag::GENERAL_BAGS_END)),
|
||||
luabind::value("CursorBagBegin", static_cast<int>(EQEmu::invbag::CURSOR_BAG_BEGIN)),
|
||||
luabind::value("CursorBagEnd", static_cast<int>(EQEmu::invbag::CURSOR_BAG_END)),
|
||||
luabind::value("Tradeskill", static_cast<int>(EQEmu::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE)),
|
||||
luabind::value("Augment", static_cast<int>(EQEmu::invslot::SLOT_AUGMENT_GENERIC_RETURN)), // will be revised out
|
||||
luabind::value("BankBegin", static_cast<int>(EQEmu::invslot::BANK_BEGIN)),
|
||||
luabind::value("BankEnd", static_cast<int>(EQEmu::invslot::BANK_END)),
|
||||
luabind::value("BankBagsBegin", static_cast<int>(EQEmu::invbag::BANK_BAGS_BEGIN)),
|
||||
luabind::value("BankBagsEnd", static_cast<int>(EQEmu::invbag::BANK_BAGS_END)),
|
||||
luabind::value("SharedBankBegin", static_cast<int>(EQEmu::invslot::SHARED_BANK_BEGIN)),
|
||||
luabind::value("SharedBankEnd", static_cast<int>(EQEmu::invslot::SHARED_BANK_END)),
|
||||
luabind::value("SharedBankBagsBegin", static_cast<int>(EQEmu::invbag::SHARED_BANK_BAGS_BEGIN)),
|
||||
luabind::value("SharedBankBagsEnd", static_cast<int>(EQEmu::invbag::SHARED_BANK_BAGS_END)),
|
||||
luabind::value("BagSlotBegin", static_cast<int>(EQEmu::invbag::SLOT_BEGIN)),
|
||||
luabind::value("BagSlotEnd", static_cast<int>(EQEmu::invbag::SLOT_END)),
|
||||
luabind::value("AugSocketBegin", static_cast<int>(EQEmu::invaug::SOCKET_BEGIN)),
|
||||
luabind::value("AugSocketEnd", static_cast<int>(EQEmu::invaug::SOCKET_END)),
|
||||
luabind::value("Invalid", static_cast<int>(EQEmu::invslot::SLOT_INVALID)),
|
||||
|
||||
luabind::value("Shoulder", static_cast<int>(EQEmu::invslot::slotShoulders)), // deprecated
|
||||
luabind::value("Bracer1", static_cast<int>(EQEmu::invslot::slotWrist1)), // deprecated
|
||||
luabind::value("Bracer2", static_cast<int>(EQEmu::invslot::slotWrist2)), // deprecated
|
||||
luabind::value("Ring1", static_cast<int>(EQEmu::invslot::slotFinger1)), // deprecated
|
||||
luabind::value("Ring2", static_cast<int>(EQEmu::invslot::slotFinger2)), // deprecated
|
||||
luabind::value("PersonalBegin", static_cast<int>(EQEmu::invslot::GENERAL_BEGIN)), // deprecated
|
||||
luabind::value("PersonalEnd", static_cast<int>(EQEmu::invslot::GENERAL_END)), // deprecated
|
||||
luabind::value("CursorEnd", 0xFFFE) // deprecated (not in use..and never valid vis-a-vis client behavior)
|
||||
];
|
||||
}
|
||||
|
||||
@ -1919,16 +1942,17 @@ luabind::scope lua_register_material() {
|
||||
luabind::value("Head", static_cast<int>(EQEmu::textures::armorHead)),
|
||||
luabind::value("Chest", static_cast<int>(EQEmu::textures::armorChest)),
|
||||
luabind::value("Arms", static_cast<int>(EQEmu::textures::armorArms)),
|
||||
luabind::value("Bracer", static_cast<int>(EQEmu::textures::armorWrist)), // deprecated
|
||||
luabind::value("Wrist", static_cast<int>(EQEmu::textures::armorWrist)),
|
||||
luabind::value("Hands", static_cast<int>(EQEmu::textures::armorHands)),
|
||||
luabind::value("Legs", static_cast<int>(EQEmu::textures::armorLegs)),
|
||||
luabind::value("Feet", static_cast<int>(EQEmu::textures::armorFeet)),
|
||||
luabind::value("Primary", static_cast<int>(EQEmu::textures::weaponPrimary)),
|
||||
luabind::value("Secondary", static_cast<int>(EQEmu::textures::weaponSecondary)),
|
||||
luabind::value("Max", static_cast<int>(EQEmu::textures::materialCount)), // deprecated
|
||||
luabind::value("Count", static_cast<int>(EQEmu::textures::materialCount)),
|
||||
luabind::value("Invalid", static_cast<int>(EQEmu::textures::materialInvalid))
|
||||
luabind::value("Invalid", static_cast<int>(EQEmu::textures::materialInvalid)),
|
||||
|
||||
luabind::value("Bracer", static_cast<int>(EQEmu::textures::armorWrist)), // deprecated
|
||||
luabind::value("Max", static_cast<int>(EQEmu::textures::materialCount)) // deprecated
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -38,10 +38,10 @@ int Lua_Inventory::PushCursor(Lua_ItemInst item) {
|
||||
return self->PushCursor(*inst);
|
||||
}
|
||||
|
||||
bool Lua_Inventory::SwapItem(int slot_a, int slot_b) {
|
||||
bool Lua_Inventory::SwapItem(int source_slot, int destination_slot) {
|
||||
Lua_Safe_Call_Bool();
|
||||
EQEmu::InventoryProfile::SwapItemFailState fail_state = EQEmu::InventoryProfile::swapInvalid;
|
||||
return self->SwapItem(slot_a, slot_b, fail_state);
|
||||
return self->SwapItem(source_slot, destination_slot, fail_state);
|
||||
}
|
||||
|
||||
bool Lua_Inventory::DeleteItem(int slot_id) {
|
||||
|
||||
@ -39,7 +39,7 @@ public:
|
||||
Lua_ItemInst GetItem(int slot_id, int bag_slot);
|
||||
int PutItem(int slot_id, Lua_ItemInst item);
|
||||
int PushCursor(Lua_ItemInst item);
|
||||
bool SwapItem(int slot_a, int slot_b);
|
||||
bool SwapItem(int source_slot, int destination_slot);
|
||||
bool DeleteItem(int slot_id);
|
||||
bool DeleteItem(int slot_id, int quantity);
|
||||
bool CheckNoDrop(int slot_id);
|
||||
|
||||
@ -217,22 +217,16 @@ void Merc::CalcItemBonuses(StatBonuses* newbon) {
|
||||
|
||||
unsigned int i;
|
||||
//should not include 21 (SLOT_AMMO)
|
||||
for (i = 0; i < EQEmu::invslot::slotAmmo; i++) {
|
||||
if(equipment[i] == 0)
|
||||
for (i = EQEmu::invslot::BONUS_BEGIN; i <= EQEmu::invslot::BONUS_STAT_END; i++) {
|
||||
if (i == EQEmu::invslot::slotAmmo)
|
||||
continue;
|
||||
if (equipment[i] == 0)
|
||||
continue;
|
||||
const EQEmu::ItemData * itm = database.GetItem(equipment[i]);
|
||||
if(itm)
|
||||
if (itm)
|
||||
AddItemBonuses(itm, newbon);
|
||||
}
|
||||
|
||||
//Power Source Slot
|
||||
/*if (GetClientVersion() >= EQClientSoF)
|
||||
{
|
||||
const EQEmu::ItemInstance* inst = m_inv[MainPowerSource];
|
||||
if(inst)
|
||||
AddItemBonuses(inst, newbon);
|
||||
}*/
|
||||
|
||||
// Caps
|
||||
if(newbon->HPRegen > CalcHPRegenCap())
|
||||
newbon->HPRegen = CalcHPRegenCap();
|
||||
|
||||
89
zone/mob.cpp
89
zone/mob.cpp
@ -249,7 +249,7 @@ Mob::Mob(const char* in_name,
|
||||
max_mana = 0;
|
||||
hp_regen = in_hp_regen;
|
||||
mana_regen = in_mana_regen;
|
||||
oocregen = RuleI(NPC, OOCRegen); //default Out of Combat Regen
|
||||
ooc_regen = RuleI(NPC, OOCRegen); //default Out of Combat Regen
|
||||
maxlevel = in_maxlevel;
|
||||
scalerate = in_scalerate;
|
||||
invisible = false;
|
||||
@ -1297,14 +1297,17 @@ void Mob::CreateHPPacket(EQApplicationPacket* app)
|
||||
}
|
||||
}
|
||||
|
||||
// sends hp update of this mob to people who might care
|
||||
void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= false*/)
|
||||
{
|
||||
|
||||
/* If our HP is different from last HP update call - let's update ourself */
|
||||
void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= false*/) {
|
||||
|
||||
/**
|
||||
* If our HP is different from last HP update call - let's update selves
|
||||
*/
|
||||
if (IsClient()) {
|
||||
if (cur_hp != last_hp || force_update_all) {
|
||||
/* This is to prevent excessive packet sending under trains/fast combat */
|
||||
|
||||
/**
|
||||
* This is to prevent excessive packet sending under trains/fast combat
|
||||
*/
|
||||
if (this->CastToClient()->hp_self_update_throttle_timer.Check() || force_update_all) {
|
||||
Log(Logs::General, Logs::HP_Update,
|
||||
"Mob::SendHPUpdate :: Update HP of self (%s) HP: %i last: %i skip_self: %s",
|
||||
@ -1316,11 +1319,12 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
|
||||
|
||||
if (!skip_self || this->CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::SoD) {
|
||||
auto client_packet = new EQApplicationPacket(OP_HPUpdate, sizeof(SpawnHPUpdate_Struct));
|
||||
SpawnHPUpdate_Struct* hp_packet_client = (SpawnHPUpdate_Struct*)client_packet->pBuffer;
|
||||
|
||||
hp_packet_client->cur_hp = CastToClient()->GetHP() - itembonuses.HP;
|
||||
SpawnHPUpdate_Struct *hp_packet_client = (SpawnHPUpdate_Struct *) client_packet->pBuffer;
|
||||
|
||||
hp_packet_client->cur_hp = CastToClient()->GetHP() - itembonuses.HP;
|
||||
hp_packet_client->spawn_id = GetID();
|
||||
hp_packet_client->max_hp = CastToClient()->GetMaxHP() - itembonuses.HP;
|
||||
hp_packet_client->max_hp = CastToClient()->GetMaxHP() - itembonuses.HP;
|
||||
|
||||
CastToClient()->QueuePacket(client_packet);
|
||||
|
||||
@ -1329,7 +1333,9 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
|
||||
ResetHPUpdateTimer();
|
||||
}
|
||||
|
||||
/* Used to check if HP has changed to update self next round */
|
||||
/**
|
||||
* Used to check if HP has changed to update self next round
|
||||
*/
|
||||
last_hp = cur_hp;
|
||||
}
|
||||
}
|
||||
@ -1337,7 +1343,12 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
|
||||
|
||||
int8 current_hp_percent = (max_hp == 0 ? 0 : static_cast<int>(cur_hp * 100 / max_hp));
|
||||
|
||||
Log(Logs::General, Logs::HP_Update, "Mob::SendHPUpdate :: SendHPUpdate %s HP is %i last %i", this->GetCleanName(), current_hp_percent, last_hp_percent);
|
||||
Log(Logs::General,
|
||||
Logs::HP_Update,
|
||||
"Mob::SendHPUpdate :: SendHPUpdate %s HP is %i last %i",
|
||||
this->GetCleanName(),
|
||||
current_hp_percent,
|
||||
last_hp_percent);
|
||||
|
||||
if (current_hp_percent == last_hp_percent && !force_update_all) {
|
||||
Log(Logs::General, Logs::HP_Update, "Mob::SendHPUpdate :: Same HP - skipping update");
|
||||
@ -1346,8 +1357,9 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
|
||||
}
|
||||
else {
|
||||
|
||||
if (IsClient() && RuleB(Character, MarqueeHPUpdates))
|
||||
if (IsClient() && RuleB(Character, MarqueeHPUpdates)) {
|
||||
this->CastToClient()->SendHPUpdateMarquee();
|
||||
}
|
||||
|
||||
Log(Logs::General, Logs::HP_Update, "Mob::SendHPUpdate :: HP Changed - Send update");
|
||||
|
||||
@ -1355,52 +1367,69 @@ void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= fal
|
||||
}
|
||||
|
||||
EQApplicationPacket hp_packet;
|
||||
Group *group = nullptr;
|
||||
Group *group = nullptr;
|
||||
|
||||
CreateHPPacket(&hp_packet);
|
||||
|
||||
/* Update those who have us targeted */
|
||||
/**
|
||||
* Update those who have us targeted
|
||||
*/
|
||||
entity_list.QueueClientsByTarget(this, &hp_packet, false, 0, false, true, EQEmu::versions::bit_AllClients);
|
||||
|
||||
/* Update those who have us on x-target */
|
||||
/**
|
||||
* Update those who have us on x-target
|
||||
*/
|
||||
entity_list.QueueClientsByXTarget(this, &hp_packet, false);
|
||||
|
||||
/* Update groups using Group LAA health name tag counter */
|
||||
/**
|
||||
* Update groups using Group LAA health name tag counter
|
||||
*/
|
||||
entity_list.QueueToGroupsForNPCHealthAA(this, &hp_packet);
|
||||
|
||||
/* Update group */
|
||||
if(IsGrouped()) {
|
||||
/**
|
||||
* Group
|
||||
*/
|
||||
if (IsGrouped()) {
|
||||
group = entity_list.GetGroupByMob(this);
|
||||
if(group)
|
||||
if (group) {
|
||||
group->SendHPPacketsFrom(this);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update Raid */
|
||||
if(IsClient()){
|
||||
/**
|
||||
* Raid
|
||||
*/
|
||||
if (IsClient()) {
|
||||
Raid *raid = entity_list.GetRaidByClient(CastToClient());
|
||||
if (raid)
|
||||
if (raid) {
|
||||
raid->SendHPManaEndPacketsFrom(this);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pet - Update master - group and raid if exists */
|
||||
if(GetOwner() && GetOwner()->IsClient()) {
|
||||
/**
|
||||
* Pet
|
||||
*/
|
||||
if (GetOwner() && GetOwner()->IsClient()) {
|
||||
GetOwner()->CastToClient()->QueuePacket(&hp_packet, false);
|
||||
group = entity_list.GetGroupByClient(GetOwner()->CastToClient());
|
||||
|
||||
if(group)
|
||||
if (group) {
|
||||
group->SendHPPacketsFrom(this);
|
||||
}
|
||||
|
||||
Raid *raid = entity_list.GetRaidByClient(GetOwner()->CastToClient());
|
||||
if(raid)
|
||||
if (raid) {
|
||||
raid->SendHPManaEndPacketsFrom(this);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send to pet */
|
||||
if(GetPet() && GetPet()->IsClient()) {
|
||||
if (GetPet() && GetPet()->IsClient()) {
|
||||
GetPet()->CastToClient()->QueuePacket(&hp_packet, false);
|
||||
}
|
||||
|
||||
/* Destructible objects */
|
||||
/**
|
||||
* Destructible objects
|
||||
*/
|
||||
if (IsNPC() && IsDestructibleObject()) {
|
||||
if (GetHPRatio() > 74) {
|
||||
if (GetAppearance() != eaStanding) {
|
||||
|
||||
@ -420,7 +420,7 @@ public:
|
||||
bool avoidable = true, int8 buffslot = -1, bool iBuffTic = false, eSpecialAttacks special = eSpecialAttacks::None) = 0;
|
||||
inline virtual void SetHP(int32 hp) { if (hp >= max_hp) cur_hp = max_hp; else cur_hp = hp;}
|
||||
bool ChangeHP(Mob* other, int32 amount, uint16 spell_id = 0, int8 buffslot = -1, bool iBuffTic = false);
|
||||
inline void SetOOCRegen(int32 newoocregen) {oocregen = newoocregen;}
|
||||
inline void SetOOCRegen(int32 newoocregen) {ooc_regen = newoocregen;}
|
||||
virtual void Heal();
|
||||
virtual void HealDamage(uint32 ammount, Mob* caster = nullptr, uint16 spell_id = SPELL_UNKNOWN);
|
||||
virtual void SetMaxHP() { cur_hp = max_hp; }
|
||||
@ -1216,7 +1216,7 @@ protected:
|
||||
int32 max_mana;
|
||||
int32 hp_regen;
|
||||
int32 mana_regen;
|
||||
int32 oocregen;
|
||||
int32 ooc_regen;
|
||||
uint8 maxlevel;
|
||||
uint32 scalerate;
|
||||
Buffs_Struct *buffs;
|
||||
|
||||
@ -97,10 +97,11 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates
|
||||
continue;
|
||||
}
|
||||
|
||||
if (AIspells[i].min_hp != 0 && GetIntHPRatio() < AIspells[i].min_hp)
|
||||
// we reuse these fields for heal overrides
|
||||
if (AIspells[i].type != SpellType_Heal && AIspells[i].min_hp != 0 && GetIntHPRatio() < AIspells[i].min_hp)
|
||||
continue;
|
||||
|
||||
if (AIspells[i].max_hp != 0 && GetIntHPRatio() > AIspells[i].max_hp)
|
||||
if (AIspells[i].type != SpellType_Heal && AIspells[i].max_hp != 0 && GetIntHPRatio() > AIspells[i].max_hp)
|
||||
continue;
|
||||
|
||||
if (iSpellTypes & AIspells[i].type) {
|
||||
@ -137,9 +138,13 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes, bool bInnates
|
||||
&& tar->DontHealMeBefore() < Timer::GetCurrentTime()
|
||||
&& !(tar->IsPet() && tar->GetOwner()->IsClient()) //no buffing PC's pets
|
||||
) {
|
||||
uint8 hpr = (uint8)tar->GetHPRatio();
|
||||
|
||||
if(hpr <= 35 || (!IsEngaged() && hpr <= 50) || (tar->IsClient() && hpr <= 99)) {
|
||||
auto hp_ratio = tar->GetIntHPRatio();
|
||||
|
||||
int min_hp = AIspells[i].min_hp; // well 0 is default, so no special case here
|
||||
int max_hp = AIspells[i].max_hp ? AIspells[i].max_hp : RuleI(Spells, AI_HealHPPct);
|
||||
|
||||
if (EQEmu::ValueWithin(hp_ratio, min_hp, max_hp) || (tar->IsClient() && hp_ratio <= 99)) { // not sure about client bit, leaving it
|
||||
uint32 tempTime = 0;
|
||||
AIDoSpellCast(i, tar, mana_cost, &tempTime);
|
||||
tar->SetDontHealMeBefore(tempTime);
|
||||
|
||||
93
zone/npc.cpp
93
zone/npc.cpp
@ -667,77 +667,78 @@ bool NPC::Process()
|
||||
parse->EventNPC(EVENT_TICK, this, nullptr, "", 0);
|
||||
BuffProcess();
|
||||
|
||||
if (currently_fleeing)
|
||||
if (currently_fleeing) {
|
||||
ProcessFlee();
|
||||
|
||||
uint32 sitting_bonus = 0;
|
||||
uint32 petbonus = 0;
|
||||
uint32 bestregen = 0;
|
||||
int32 dbregen = GetNPCHPRegen();
|
||||
|
||||
if (GetAppearance() == eaSitting)
|
||||
sitting_bonus += 3;
|
||||
|
||||
int32 OOCRegen = 0;
|
||||
if (oocregen > 0) { //should pull from Mob class
|
||||
OOCRegen += GetMaxHP() * oocregen / 100;
|
||||
}
|
||||
|
||||
// Fixing NPC regen.NPCs should regen to full during
|
||||
// a set duration, not based on their HPs.Increase NPC's HPs by
|
||||
// % of total HPs / tick.
|
||||
//
|
||||
// If oocregen set in db, apply to pets as well.
|
||||
// This allows the obscene #s for pets in the db to be tweaked
|
||||
// while maintaining a decent ooc regen.
|
||||
uint32 npc_sitting_regen_bonus = 0;
|
||||
uint32 pet_regen_bonus = 0;
|
||||
uint32 npc_regen = 0;
|
||||
int32 npc_hp_regen = GetNPCHPRegen();
|
||||
|
||||
bestregen = std::max(dbregen,OOCRegen);
|
||||
if (GetAppearance() == eaSitting) {
|
||||
npc_sitting_regen_bonus += 3;
|
||||
}
|
||||
|
||||
int32 ooc_regen_calc = 0;
|
||||
if (ooc_regen > 0) { //should pull from Mob class
|
||||
ooc_regen_calc += GetMaxHP() * ooc_regen / 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use max value between two values
|
||||
*/
|
||||
npc_regen = std::max(npc_hp_regen, ooc_regen_calc);
|
||||
|
||||
if ((GetHP() < GetMaxHP()) && !IsPet()) {
|
||||
if (!IsEngaged())
|
||||
SetHP(GetHP() + bestregen + sitting_bonus);
|
||||
else
|
||||
SetHP(GetHP() + dbregen);
|
||||
if (!IsEngaged()) {
|
||||
SetHP(GetHP() + npc_regen + npc_sitting_regen_bonus);
|
||||
}
|
||||
else {
|
||||
SetHP(GetHP() + npc_hp_regen);
|
||||
}
|
||||
}
|
||||
else if (GetHP() < GetMaxHP() && GetOwnerID() != 0) {
|
||||
if (!IsEngaged()) {
|
||||
if (oocregen > 0) {
|
||||
petbonus = std::max(OOCRegen,dbregen);
|
||||
if (ooc_regen > 0) {
|
||||
pet_regen_bonus = std::max(ooc_regen_calc, npc_hp_regen);
|
||||
}
|
||||
else {
|
||||
petbonus = dbregen + (GetLevel() / 5);
|
||||
pet_regen_bonus = npc_hp_regen + (GetLevel() / 5);
|
||||
}
|
||||
|
||||
SetHP(GetHP() + sitting_bonus + petbonus);
|
||||
SetHP(GetHP() + npc_sitting_regen_bonus + pet_regen_bonus);
|
||||
}
|
||||
else
|
||||
SetHP(GetHP() + dbregen);
|
||||
else {
|
||||
SetHP(GetHP() + npc_hp_regen);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
SetHP(GetHP() + npc_hp_regen + npc_sitting_regen_bonus);
|
||||
}
|
||||
else
|
||||
SetHP(GetHP() + dbregen + sitting_bonus);
|
||||
|
||||
if (GetMana() < GetMaxMana()) {
|
||||
SetMana(GetMana() + mana_regen + sitting_bonus);
|
||||
SetMana(GetMana() + mana_regen + npc_sitting_regen_bonus);
|
||||
}
|
||||
|
||||
SendHPUpdate();
|
||||
|
||||
if (zone->adv_data && !p_depop)
|
||||
{
|
||||
ServerZoneAdventureDataReply_Struct* ds = (ServerZoneAdventureDataReply_Struct*)zone->adv_data;
|
||||
if (ds->type == Adventure_Rescue && ds->data_id == GetNPCTypeID())
|
||||
{
|
||||
if (zone->adv_data && !p_depop) {
|
||||
ServerZoneAdventureDataReply_Struct *ds = (ServerZoneAdventureDataReply_Struct *) zone->adv_data;
|
||||
if (ds->type == Adventure_Rescue && ds->data_id == GetNPCTypeID()) {
|
||||
Mob *o = GetOwner();
|
||||
if (o && o->IsClient())
|
||||
{
|
||||
if (o && o->IsClient()) {
|
||||
float x_diff = ds->dest_x - GetX();
|
||||
float y_diff = ds->dest_y - GetY();
|
||||
float z_diff = ds->dest_z - GetZ();
|
||||
float dist = ((x_diff * x_diff) + (y_diff * y_diff) + (z_diff * z_diff));
|
||||
if (dist < RuleR(Adventure, DistanceForRescueComplete))
|
||||
{
|
||||
float dist = ((x_diff * x_diff) + (y_diff * y_diff) + (z_diff * z_diff));
|
||||
if (dist < RuleR(Adventure, DistanceForRescueComplete)) {
|
||||
zone->DoAdventureCountIncrease();
|
||||
Say("You don't know what this means to me. Thank you so much for finding and saving me from"
|
||||
" this wretched place. I'll find my way from here.");
|
||||
Say(
|
||||
"You don't know what this means to me. Thank you so much for finding and saving me from"
|
||||
" this wretched place. I'll find my way from here."
|
||||
);
|
||||
Depop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3026,7 +3026,7 @@ XS(XS_Client_SummonItem) {
|
||||
dXSARGS;
|
||||
if (items < 2 || items > 10)
|
||||
Perl_croak(aTHX_
|
||||
"Usage: Client::SummonItem(THIS, uint32 item_id, [int16 charges = -1], [bool attune = false], [uint32 aug1 = 0], [uint32 aug2 = 0], [uint32 aug3 = 0], [uint32 aug4 = 0], [uint32 aug5 = 0], [uint16 slot_id = 30])");
|
||||
"Usage: Client::SummonItem(THIS, uint32 item_id, [int16 charges = -1], [bool attune = false], [uint32 aug1 = 0], [uint32 aug2 = 0], [uint32 aug3 = 0], [uint32 aug4 = 0], [uint32 aug5 = 0], [uint16 slot_id = cursor])");
|
||||
{
|
||||
Client *THIS;
|
||||
uint32 item_id = (uint32) SvUV(ST(1));
|
||||
@ -3037,7 +3037,7 @@ XS(XS_Client_SummonItem) {
|
||||
uint32 aug3 = 0;
|
||||
uint32 aug4 = 0;
|
||||
uint32 aug5 = 0;
|
||||
uint16 slot_id = 30;
|
||||
uint16 slot_id = EQEmu::invslot::slotCursor;
|
||||
|
||||
if (sv_derived_from(ST(0), "Client")) {
|
||||
IV tmp = SvIV((SV *) SvRV(ST(0)));
|
||||
|
||||
@ -527,7 +527,7 @@ void NPC::GetPetState(SpellBuff_Struct *pet_buffs, uint32 *items, char *name) {
|
||||
memcpy(items, equipment, sizeof(uint32) * EQEmu::invslot::EQUIPMENT_COUNT);
|
||||
|
||||
//save their buffs.
|
||||
for (int i=0; i < GetPetMaxTotalSlots(); i++) {
|
||||
for (int i=EQEmu::invslot::EQUIPMENT_BEGIN; i < GetPetMaxTotalSlots(); i++) {
|
||||
if (buffs[i].spellid != SPELL_UNKNOWN) {
|
||||
pet_buffs[i].spellid = buffs[i].spellid;
|
||||
pet_buffs[i].effect_type = i+1;
|
||||
|
||||
@ -281,7 +281,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
if (itm && (itm->GetItem()->Click.Type == EQEmu::item::ItemEffectEquipClick) && !(item_slot <= EQEmu::invslot::slotAmmo || item_slot == EQEmu::invslot::SLOT_POWER_SOURCE)){
|
||||
if (itm && (itm->GetItem()->Click.Type == EQEmu::item::ItemEffectEquipClick) && item_slot > EQEmu::invslot::EQUIPMENT_END){
|
||||
if (CastToClient()->ClientVersion() < EQEmu::versions::ClientVersion::SoF) {
|
||||
// They are attempting to cast a must equip clicky without having it equipped
|
||||
Log(Logs::General, Logs::Error, "HACKER: %s (account: %s) attempted to click an equip-only effect on item %s (id: %d) without equiping it!", CastToClient()->GetCleanName(), CastToClient()->AccountName(), itm->GetItem()->Name, itm->GetItem()->ID);
|
||||
|
||||
@ -264,7 +264,7 @@ void Object::HandleCombine(Client* user, const NewCombine_Struct* in_combine, Ob
|
||||
uint32 some_id = 0;
|
||||
bool worldcontainer=false;
|
||||
|
||||
if (in_combine->container_slot == EQEmu::legacy::SLOT_TRADESKILL) {
|
||||
if (in_combine->container_slot == EQEmu::invslot::SLOT_TRADESKILL_EXPERIMENT_COMBINE) {
|
||||
if(!worldo) {
|
||||
user->Message(13, "Error: Server is not aware of the tradeskill container you are attempting to use");
|
||||
return;
|
||||
|
||||
@ -1202,7 +1202,7 @@ void Client::SendSingleTraderItem(uint32 CharID, int SerialNumber) {
|
||||
|
||||
EQEmu::ItemInstance* inst= database.LoadSingleTraderItem(CharID, SerialNumber);
|
||||
if(inst) {
|
||||
SendItemPacket(30, inst, ItemPacketMerchant); // MainCursor?
|
||||
SendItemPacket(EQEmu::invslot::slotCursor, inst, ItemPacketMerchant); // MainCursor?
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
@ -1233,7 +1233,7 @@ void Client::BulkSendTraderInventory(uint32 char_id) {
|
||||
}
|
||||
|
||||
inst->SetPrice(TraderItems->ItemCost[i]);
|
||||
SendItemPacket(30, inst, ItemPacketMerchant); // MainCursor?
|
||||
SendItemPacket(EQEmu::invslot::slotCursor, inst, ItemPacketMerchant); // MainCursor?
|
||||
safe_delete(inst);
|
||||
}
|
||||
else
|
||||
@ -2072,7 +2072,7 @@ static void UpdateTraderCustomerItemsAdded(uint32 CustomerID, TraderCharges_Stru
|
||||
Log(Logs::Detail, Logs::Trading, "Sending price update for %s, Serial No. %i with %i charges",
|
||||
item->Name, gis->SerialNumber[i], gis->Charges[i]);
|
||||
|
||||
Customer->SendItemPacket(30, inst, ItemPacketMerchant); // MainCursor?
|
||||
Customer->SendItemPacket(EQEmu::invslot::slotCursor, inst, ItemPacketMerchant); // MainCursor?
|
||||
}
|
||||
}
|
||||
|
||||
@ -2156,7 +2156,7 @@ static void UpdateTraderCustomerPriceChanged(uint32 CustomerID, TraderCharges_St
|
||||
Log(Logs::Detail, Logs::Trading, "Sending price update for %s, Serial No. %i with %i charges",
|
||||
item->Name, gis->SerialNumber[i], gis->Charges[i]);
|
||||
|
||||
Customer->SendItemPacket(30, inst, ItemPacketMerchant); // MainCursor??
|
||||
Customer->SendItemPacket(EQEmu::invslot::slotCursor, inst, ItemPacketMerchant); // MainCursor??
|
||||
}
|
||||
safe_delete(inst);
|
||||
}
|
||||
|
||||
390
zone/zonedb.cpp
390
zone/zonedb.cpp
@ -1180,7 +1180,7 @@ bool ZoneDatabase::LoadCharacterData(uint32 character_id, PlayerProfile_Struct*
|
||||
m_epp->aa_effects = atoi(row[r]); r++; // "`e_aa_effects`, "
|
||||
m_epp->perAA = atoi(row[r]); r++; // "`e_percent_to_aa`, "
|
||||
m_epp->expended_aa = atoi(row[r]); r++; // "`e_expended_aa_spent`, "
|
||||
m_epp->last_invsnapshot_time = atoi(row[r]); r++; // "`e_last_invsnapshot` "
|
||||
m_epp->last_invsnapshot_time = atoul(row[r]); r++; // "`e_last_invsnapshot` "
|
||||
m_epp->next_invsnapshot_time = m_epp->last_invsnapshot_time + (RuleI(Character, InvSnapshotMinIntervalM) * 60);
|
||||
}
|
||||
return true;
|
||||
@ -1576,56 +1576,6 @@ bool ZoneDatabase::SaveCharacterLeadershipAA(uint32 character_id, PlayerProfile_
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterInventorySnapshot(uint32 character_id){
|
||||
uint32 time_index = time(nullptr);
|
||||
std::string query = StringFormat(
|
||||
"INSERT INTO inventory_snapshots ("
|
||||
" time_index,"
|
||||
" charid,"
|
||||
" slotid,"
|
||||
" itemid,"
|
||||
" charges,"
|
||||
" color,"
|
||||
" augslot1,"
|
||||
" augslot2,"
|
||||
" augslot3,"
|
||||
" augslot4,"
|
||||
" augslot5,"
|
||||
" augslot6,"
|
||||
" instnodrop,"
|
||||
" custom_data,"
|
||||
" ornamenticon,"
|
||||
" ornamentidfile,"
|
||||
" ornament_hero_model"
|
||||
")"
|
||||
" SELECT"
|
||||
" %u,"
|
||||
" charid,"
|
||||
" slotid,"
|
||||
" itemid,"
|
||||
" charges,"
|
||||
" color,"
|
||||
" augslot1,"
|
||||
" augslot2,"
|
||||
" augslot3,"
|
||||
" augslot4,"
|
||||
" augslot5,"
|
||||
" augslot6,"
|
||||
" instnodrop,"
|
||||
" custom_data,"
|
||||
" ornamenticon,"
|
||||
" ornamentidfile,"
|
||||
" ornament_hero_model"
|
||||
" FROM inventory"
|
||||
" WHERE charid = %u",
|
||||
time_index,
|
||||
character_id
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
Log(Logs::General, Logs::None, "ZoneDatabase::SaveCharacterInventorySnapshot %i (%s)", character_id, (results.Success() ? "pass" : "fail"));
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp, ExtendedProfile_Struct* m_epp){
|
||||
|
||||
/* If this is ever zero - the client hasn't fully loaded and potentially crashed during zone */
|
||||
@ -2052,6 +2002,344 @@ bool ZoneDatabase::NoRentExpired(const char* name){
|
||||
return (seconds>1800);
|
||||
}
|
||||
|
||||
bool ZoneDatabase::SaveCharacterInvSnapshot(uint32 character_id) {
|
||||
uint32 time_index = time(nullptr);
|
||||
std::string query = StringFormat(
|
||||
"INSERT "
|
||||
"INTO"
|
||||
" `inventory_snapshots` "
|
||||
"(`time_index`,"
|
||||
" `charid`,"
|
||||
" `slotid`,"
|
||||
" `itemid`,"
|
||||
" `charges`,"
|
||||
" `color`,"
|
||||
" `augslot1`,"
|
||||
" `augslot2`,"
|
||||
" `augslot3`,"
|
||||
" `augslot4`,"
|
||||
" `augslot5`,"
|
||||
" `augslot6`,"
|
||||
" `instnodrop`,"
|
||||
" `custom_data`,"
|
||||
" `ornamenticon`,"
|
||||
" `ornamentidfile`,"
|
||||
" `ornament_hero_model`"
|
||||
") "
|
||||
"SELECT"
|
||||
" %u,"
|
||||
" `charid`,"
|
||||
" `slotid`,"
|
||||
" `itemid`,"
|
||||
" `charges`,"
|
||||
" `color`,"
|
||||
" `augslot1`,"
|
||||
" `augslot2`,"
|
||||
" `augslot3`,"
|
||||
" `augslot4`,"
|
||||
" `augslot5`,"
|
||||
" `augslot6`,"
|
||||
" `instnodrop`,"
|
||||
" `custom_data`,"
|
||||
" `ornamenticon`,"
|
||||
" `ornamentidfile`,"
|
||||
" `ornament_hero_model` "
|
||||
"FROM"
|
||||
" `inventory` "
|
||||
"WHERE"
|
||||
" `charid` = %u",
|
||||
time_index,
|
||||
character_id
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
Log(Logs::Moderate, Logs::Inventory, "ZoneDatabase::SaveCharacterInventorySnapshot %i (%s)", character_id, (results.Success() ? "pass" : "fail"));
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
int ZoneDatabase::CountCharacterInvSnapshots(uint32 character_id) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT"
|
||||
" COUNT(*) "
|
||||
"FROM "
|
||||
"("
|
||||
"SELECT * FROM"
|
||||
" `inventory_snapshots` a "
|
||||
"WHERE"
|
||||
" `charid` = %u "
|
||||
"GROUP BY"
|
||||
" `time_index`"
|
||||
") b",
|
||||
character_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return -1;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
int64 count = atoll(row[0]);
|
||||
if (count > 2147483647)
|
||||
return -2;
|
||||
if (count < 0)
|
||||
return -3;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void ZoneDatabase::ClearCharacterInvSnapshots(uint32 character_id, bool from_now) {
|
||||
uint32 del_time = time(nullptr);
|
||||
if (!from_now) { del_time -= RuleI(Character, InvSnapshotHistoryD) * 86400; }
|
||||
|
||||
std::string query = StringFormat(
|
||||
"DELETE "
|
||||
"FROM"
|
||||
" `inventory_snapshots` "
|
||||
"WHERE"
|
||||
" `charid` = %u "
|
||||
"AND"
|
||||
" `time_index` <= %lu",
|
||||
character_id,
|
||||
(unsigned long)del_time
|
||||
);
|
||||
QueryDatabase(query);
|
||||
}
|
||||
|
||||
void ZoneDatabase::ListCharacterInvSnapshots(uint32 character_id, std::list<std::pair<uint32, int>> &is_list) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT"
|
||||
" `time_index`,"
|
||||
" COUNT(*) "
|
||||
"FROM"
|
||||
" `inventory_snapshots` "
|
||||
"WHERE"
|
||||
" `charid` = %u "
|
||||
"GROUP BY"
|
||||
" `time_index` "
|
||||
"ORDER BY"
|
||||
" `time_index` "
|
||||
"DESC",
|
||||
character_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return;
|
||||
|
||||
for (auto row : results)
|
||||
is_list.push_back(std::pair<uint32, int>(atoul(row[0]), atoi(row[1])));
|
||||
}
|
||||
|
||||
bool ZoneDatabase::ValidateCharacterInvSnapshotTimestamp(uint32 character_id, uint32 timestamp) {
|
||||
if (!character_id || !timestamp)
|
||||
return false;
|
||||
|
||||
std::string query = StringFormat(
|
||||
"SELECT"
|
||||
" * "
|
||||
"FROM"
|
||||
" `inventory_snapshots` "
|
||||
"WHERE"
|
||||
" `charid` = %u "
|
||||
"AND"
|
||||
" `time_index` = %u "
|
||||
"LIMIT 1",
|
||||
character_id,
|
||||
timestamp
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success() || results.RowCount() == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZoneDatabase::ParseCharacterInvSnapshot(uint32 character_id, uint32 timestamp, std::list<std::pair<int16, uint32>> &parse_list) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT"
|
||||
" `slotid`,"
|
||||
" `itemid` "
|
||||
"FROM"
|
||||
" `inventory_snapshots` "
|
||||
"WHERE"
|
||||
" `charid` = %u "
|
||||
"AND"
|
||||
" `time_index` = %u "
|
||||
"ORDER BY"
|
||||
" `slotid`",
|
||||
character_id,
|
||||
timestamp
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return;
|
||||
|
||||
for (auto row : results)
|
||||
parse_list.push_back(std::pair<int16, uint32>(atoi(row[0]), atoul(row[1])));
|
||||
}
|
||||
|
||||
void ZoneDatabase::DivergeCharacterInvSnapshotFromInventory(uint32 character_id, uint32 timestamp, std::list<std::pair<int16, uint32>> &compare_list) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT"
|
||||
" slotid,"
|
||||
" itemid "
|
||||
"FROM"
|
||||
" `inventory_snapshots` "
|
||||
"WHERE"
|
||||
" `time_index` = %u "
|
||||
"AND"
|
||||
" `charid` = %u "
|
||||
"AND"
|
||||
" `slotid` NOT IN "
|
||||
"("
|
||||
"SELECT"
|
||||
" a.`slotid` "
|
||||
"FROM"
|
||||
" `inventory_snapshots` a "
|
||||
"JOIN"
|
||||
" `inventory` b "
|
||||
"USING"
|
||||
" (`slotid`, `itemid`) "
|
||||
"WHERE"
|
||||
" a.`time_index` = %u "
|
||||
"AND"
|
||||
" a.`charid` = %u "
|
||||
"AND"
|
||||
" b.`charid` = %u"
|
||||
")",
|
||||
timestamp,
|
||||
character_id,
|
||||
timestamp,
|
||||
character_id,
|
||||
character_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return;
|
||||
|
||||
for (auto row : results)
|
||||
compare_list.push_back(std::pair<int16, uint32>(atoi(row[0]), atoul(row[1])));
|
||||
}
|
||||
|
||||
void ZoneDatabase::DivergeCharacterInventoryFromInvSnapshot(uint32 character_id, uint32 timestamp, std::list<std::pair<int16, uint32>> &compare_list) {
|
||||
std::string query = StringFormat(
|
||||
"SELECT"
|
||||
" `slotid`,"
|
||||
" `itemid` "
|
||||
"FROM"
|
||||
" `inventory` "
|
||||
"WHERE"
|
||||
" `charid` = %u "
|
||||
"AND"
|
||||
" `slotid` NOT IN "
|
||||
"("
|
||||
"SELECT"
|
||||
" a.`slotid` "
|
||||
"FROM"
|
||||
" `inventory` a "
|
||||
"JOIN"
|
||||
" `inventory_snapshots` b "
|
||||
"USING"
|
||||
" (`slotid`, `itemid`) "
|
||||
"WHERE"
|
||||
" b.`time_index` = %u "
|
||||
"AND"
|
||||
" b.`charid` = %u "
|
||||
"AND"
|
||||
" a.`charid` = %u"
|
||||
")",
|
||||
character_id,
|
||||
timestamp,
|
||||
character_id,
|
||||
character_id
|
||||
);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
if (!results.Success())
|
||||
return;
|
||||
|
||||
for (auto row : results)
|
||||
compare_list.push_back(std::pair<int16, uint32>(atoi(row[0]), atoul(row[1])));
|
||||
}
|
||||
|
||||
bool ZoneDatabase::RestoreCharacterInvSnapshot(uint32 character_id, uint32 timestamp) {
|
||||
// we should know what we're doing by the time we call this function..but,
|
||||
// this is to prevent inventory deletions where no timestamp entries exists
|
||||
if (!ValidateCharacterInvSnapshotTimestamp(character_id, timestamp)) {
|
||||
Log(Logs::General, Logs::Error, "ZoneDatabase::RestoreCharacterInvSnapshot() called for id: %u without valid snapshot entries @ %u", character_id, timestamp);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string query = StringFormat(
|
||||
"DELETE "
|
||||
"FROM"
|
||||
" `inventory` "
|
||||
"WHERE"
|
||||
" `charid` = %u",
|
||||
character_id
|
||||
);
|
||||
auto results = database.QueryDatabase(query);
|
||||
if (!results.Success())
|
||||
return false;
|
||||
|
||||
query = StringFormat(
|
||||
"INSERT "
|
||||
"INTO"
|
||||
" `inventory` "
|
||||
"(`charid`,"
|
||||
" `slotid`,"
|
||||
" `itemid`,"
|
||||
" `charges`,"
|
||||
" `color`,"
|
||||
" `augslot1`,"
|
||||
" `augslot2`,"
|
||||
" `augslot3`,"
|
||||
" `augslot4`,"
|
||||
" `augslot5`,"
|
||||
" `augslot6`,"
|
||||
" `instnodrop`,"
|
||||
" `custom_data`,"
|
||||
" `ornamenticon`,"
|
||||
" `ornamentidfile`,"
|
||||
" `ornament_hero_model`"
|
||||
") "
|
||||
"SELECT"
|
||||
" `charid`,"
|
||||
" `slotid`,"
|
||||
" `itemid`,"
|
||||
" `charges`,"
|
||||
" `color`,"
|
||||
" `augslot1`,"
|
||||
" `augslot2`,"
|
||||
" `augslot3`,"
|
||||
" `augslot4`,"
|
||||
" `augslot5`,"
|
||||
" `augslot6`,"
|
||||
" `instnodrop`,"
|
||||
" `custom_data`,"
|
||||
" `ornamenticon`,"
|
||||
" `ornamentidfile`,"
|
||||
" `ornament_hero_model` "
|
||||
"FROM"
|
||||
" `inventory_snapshots` "
|
||||
"WHERE"
|
||||
" `charid` = %u "
|
||||
"AND"
|
||||
" `time_index` = %u",
|
||||
character_id,
|
||||
timestamp
|
||||
);
|
||||
results = database.QueryDatabase(query);
|
||||
|
||||
Log(Logs::General, Logs::Inventory, "ZoneDatabase::RestoreCharacterInvSnapshot() %s snapshot for %u @ %u",
|
||||
(results.Success() ? "restored" : "failed to restore"), character_id, timestamp);
|
||||
|
||||
return results.Success();
|
||||
}
|
||||
|
||||
const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load /*= false*/)
|
||||
{
|
||||
const NPCType *npc = nullptr;
|
||||
|
||||
@ -315,7 +315,6 @@ public:
|
||||
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
|
||||
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
|
||||
bool SaveCharacterLeadershipAA(uint32 character_id, PlayerProfile_Struct* pp);
|
||||
bool SaveCharacterInventorySnapshot(uint32 character_id);
|
||||
|
||||
/* Character Data Deletes */
|
||||
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
|
||||
@ -328,7 +327,16 @@ public:
|
||||
|
||||
/* Character Inventory */
|
||||
bool NoRentExpired(const char* name);
|
||||
|
||||
bool SaveCharacterInvSnapshot(uint32 character_id);
|
||||
int CountCharacterInvSnapshots(uint32 character_id);
|
||||
void ClearCharacterInvSnapshots(uint32 character_id, bool from_now = false);
|
||||
void ListCharacterInvSnapshots(uint32 character_id, std::list<std::pair<uint32, int>> &is_list);
|
||||
bool ValidateCharacterInvSnapshotTimestamp(uint32 character_id, uint32 timestamp);
|
||||
void ParseCharacterInvSnapshot(uint32 character_id, uint32 timestamp, std::list<std::pair<int16, uint32>> &parse_list);
|
||||
void DivergeCharacterInvSnapshotFromInventory(uint32 character_id, uint32 timestamp, std::list<std::pair<int16, uint32>> &compare_list);
|
||||
void DivergeCharacterInventoryFromInvSnapshot(uint32 character_id, uint32 timestamp, std::list<std::pair<int16, uint32>> &compare_list);
|
||||
bool RestoreCharacterInvSnapshot(uint32 character_id, uint32 timestamp);
|
||||
|
||||
/* Corpses */
|
||||
bool DeleteItemOffCharacterCorpse(uint32 db_id, uint32 equip_slot, uint32 item_id);
|
||||
uint32 GetCharacterCorpseItemCount(uint32 corpse_id);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user