From 9e5bfabf9195771d20d8ee5943a80d68fd3a8eab Mon Sep 17 00:00:00 2001 From: Shendare Date: Mon, 9 Nov 2015 22:43:25 -0800 Subject: [PATCH 01/40] Augmentation Feature Patch RoF+ clients now support the built-in adding, swapping, destroying, and removing of augments in equipment, updating an equipped item's look in case of ornamentation changes. All clients will now verify that the proper distiller (or a perfected distiller for RoF+) is being sent for consumption for safely removing augments. Hard-coded item IDs for distillers have been replaced with checks on item types. --- zone/client_packet.cpp | 323 ++++++++++++++++++++++++++++------------- zone/tradeskills.cpp | 27 ++-- 2 files changed, 240 insertions(+), 110 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 2ee01fe25..7d392ec37 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -2931,139 +2931,260 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) { ItemInst *itemOneToPush = nullptr, *itemTwoToPush = nullptr; - //Message(15, "%i %i %i %i %i %i", in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id); + //Log.Out(Logs::DebugLevel::Moderate, Logs::Debug, "cslot: %i aslot: %i cidx: %i aidx: %i act: %i dest: %i", + // in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id); - // Adding augment - if (in_augment->augment_action == 0) + ItemInst *tobe_auged = nullptr, *new_aug = nullptr, *old_aug = nullptr, *aug = nullptr, *solvent = nullptr; + Inventory& user_inv = GetInv(); + + uint16 item_slot = in_augment->container_slot; + uint16 solvent_slot = in_augment->augment_slot; + uint8 mat = Inventory::CalcMaterialFromSlot(item_slot); // for when player is augging a piece of equipment while they're wearing it + + if (item_slot == INVALID_INDEX || solvent_slot == INVALID_INDEX) { - ItemInst *tobe_auged = nullptr, *auged_with = nullptr; - int8 slot = -1; - Inventory& user_inv = GetInv(); + Message(13, "Error: Invalid Aug Index."); + return; + } - uint16 slot_id = in_augment->container_slot; - uint16 aug_slot_id = in_augment->augment_slot; - if (slot_id == INVALID_INDEX || aug_slot_id == INVALID_INDEX) + tobe_auged = user_inv.GetItem(item_slot); + solvent = user_inv.GetItem(solvent_slot); + new_aug = user_inv.GetItem(MainCursor); + + if (!tobe_auged) + { + Message(13, "Error: Invalid item passed for augmenting."); + return; + } + + if ((in_augment->augment_action == 1) || (in_augment->augment_action == 2)) + { + // Check for valid distiller if safely removing / swapping an augmentation + + if (!solvent) { - Message(13, "Error: Invalid Aug Index."); + Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment without a distiller."); + Message(13, "Error: Missing an augmentation distiller for safely removing this augment."); return; } - - tobe_auged = user_inv.GetItem(slot_id); - auged_with = user_inv.GetItem(MainCursor); - - if (tobe_auged && auged_with) + else if (solvent->GetItem()->ItemType == ItemUseTypes::ItemTypeAugmentationDistiller) { - if (((tobe_auged->IsAugmentSlotAvailable(auged_with->GetAugmentType(), in_augment->augment_index)) != -1) && - (tobe_auged->AvailableWearSlot(auged_with->GetItem()->Slots))) + old_aug = tobe_auged->GetAugment(in_augment->augment_index); + + if (!old_aug) { - tobe_auged->PutAugment(in_augment->augment_index, *auged_with); - tobe_auged->UpdateOrnamentationInfo(); + Log.Out(Logs::General, Logs::Error, "Player tried to safely remove a nonexistent augment."); + Message(13, "Error: No augment found in slot %i for safely removing.", in_augment->augment_index); + return; + } + else if (solvent->GetItem()->ID != old_aug->GetItem()->AugDistiller) + { + Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment with the wrong distiller (item %u vs expected %u).", solvent->GetItem()->ID, old_aug->GetItem()->AugDistiller); + Message(13, "Error: Wrong augmentation distiller for safely removing this augment."); + return; + } + } + else if (solvent->GetItem()->ItemType != ItemUseTypes::ItemTypePerfectedAugmentationDistiller) + { + Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment with a non-distiller item."); + Message(13, "Error: Invalid augmentation distiller for safely removing this augment."); + return; + } + } - ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_index); - if (aug) { - std::vector args; - args.push_back(aug); - parse->EventItem(EVENT_AUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); - - args.assign(1, tobe_auged); - parse->EventItem(EVENT_AUGMENT_INSERT, this, aug, nullptr, "", in_augment->augment_index, &args); - } - else + switch (in_augment->augment_action) + { + case 0: // Adding an augment + case 2: // Swapping augment + if (new_aug) + { + if (((tobe_auged->IsAugmentSlotAvailable(new_aug->GetAugmentType(), in_augment->augment_index)) != -1) && + (tobe_auged->AvailableWearSlot(new_aug->GetItem()->Slots))) { - Message(13, "Error: Could not find augmentation at index %i. Aborting.", in_augment->augment_index); - return; - } - - itemOneToPush = tobe_auged->Clone(); - // Must push items after the items in inventory are deleted - necessary due to lore items... - if (itemOneToPush) - { - DeleteItemInInventory(slot_id, 0, true); - DeleteItemInInventory(MainCursor, 0, true); - - if (PutItemInInventory(slot_id, *itemOneToPush, true)) + old_aug = tobe_auged->RemoveAugment(in_augment->augment_index); + if (old_aug) { + // An old augment was removed in order to be replaced with the new one (augment_action 2) + CalcBonuses(); - // Successfully added an augment to the item + + std::vector args; + args.push_back(old_aug); + parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); + + args.assign(1, tobe_auged); + args.push_back(false); + + parse->EventItem(EVENT_AUGMENT_REMOVE, this, old_aug, nullptr, "", in_augment->augment_index, &args); + } + + tobe_auged->PutAugment(in_augment->augment_index, *new_aug); + tobe_auged->UpdateOrnamentationInfo(); + + aug = tobe_auged->GetAugment(in_augment->augment_index); + if (aug) + { + std::vector args; + args.push_back(aug); + parse->EventItem(EVENT_AUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); + + args.assign(1, tobe_auged); + parse->EventItem(EVENT_AUGMENT_INSERT, this, aug, nullptr, "", in_augment->augment_index, &args); + } + else + { + Message(13, "Error: Could not properly insert augmentation into augment slot %i. Aborting.", in_augment->augment_index); + return; + } + + itemOneToPush = tobe_auged->Clone(); + if (old_aug) + { + itemTwoToPush = old_aug->Clone(); + } + + // Must push items after the items in inventory are deleted - necessary due to lore items... + if (itemOneToPush) + { + DeleteItemInInventory(item_slot, 0, true); + DeleteItemInInventory(MainCursor, new_aug->IsStackable() ? 1 : 0, true); + + if (solvent) + { + // Consume the augment distiller + DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true); + } + + if (itemTwoToPush) + { + // Return the old aug to the player's cursor + + PutItemInInventory(MainCursor, *itemTwoToPush, true); + } + + if (PutItemInInventory(item_slot, *itemOneToPush, true)) + { + CalcBonuses(); + // Successfully added an augment to the item + if (mat != _MaterialInvalid) + { + SendWearChange(mat); // Visible item augged while equipped. Send WC in case ornamentation changed. + } + return; + } + else + { + Message(13, "Error: No available slot for end result. Please free up the augment slot."); + } + return; } else { - Message(13, "Error: No available slot for end result. Please free up the augment slot."); + Message(13, "Error in cloning item for augment. Aborted."); } } else { - Message(13, "Error in cloning item for augment. Aborted."); + Message(13, "Error: No available slot for augment in that item."); } + } + break; + case 1: // Removing augment safely (distiller) + aug = tobe_auged->GetAugment(in_augment->augment_index); + if (aug) + { + std::vector args; + args.push_back(aug); + parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); + args.assign(1, tobe_auged); + + args.push_back(false); + + parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args); } else { - Message(13, "Error: No available slot for augment in that item."); + Message(13, "Error: Could not find augmentation to remove at index %i. Aborting.", in_augment->augment_index); + return; } - } - } - else if (in_augment->augment_action == 1) - { - ItemInst *tobe_auged = nullptr, *auged_with = nullptr; - int8 slot = -1; - Inventory& user_inv = GetInv(); + old_aug = tobe_auged->RemoveAugment(in_augment->augment_index); + tobe_auged->UpdateOrnamentationInfo(); - uint16 slot_id = in_augment->container_slot; - uint16 aug_slot_id = in_augment->augment_slot; //it's actually solvent slot - if (slot_id == INVALID_INDEX || aug_slot_id == INVALID_INDEX) - { - Message(13, "Error: Invalid Aug Index."); - return; - } - - tobe_auged = user_inv.GetItem(slot_id); - auged_with = user_inv.GetItem(aug_slot_id); - - ItemInst *old_aug = nullptr; - if (!auged_with) - return; - const uint32 id = auged_with->GetID(); - ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_index); - if (aug) { - std::vector args; - args.push_back(aug); - parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); - - args.assign(1, tobe_auged); - - args.push_back(false); - - parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args); - } - else - { - Message(13, "Error: Could not find augmentation at index %i. Aborting."); - return; - } - old_aug = tobe_auged->RemoveAugment(in_augment->augment_index); - tobe_auged->UpdateOrnamentationInfo(); - - itemOneToPush = tobe_auged->Clone(); - if (old_aug) - itemTwoToPush = old_aug->Clone(); - if (itemOneToPush && itemTwoToPush && auged_with) - { - DeleteItemInInventory(slot_id, 0, true); - DeleteItemInInventory(aug_slot_id, auged_with->IsStackable() ? 1 : 0, true); - - if (!PutItemInInventory(slot_id, *itemOneToPush, true)) + itemOneToPush = tobe_auged->Clone(); + if (old_aug) + itemTwoToPush = old_aug->Clone(); + if (itemOneToPush && itemTwoToPush) { - Message(15, "Failed to remove augment properly!"); + DeleteItemInInventory(item_slot, 0, true); + DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true); + + if (!PutItemInInventory(item_slot, *itemOneToPush, true)) + { + Message(15, "Failed to remove augment properly!"); + } + + if (PutItemInInventory(MainCursor, *itemTwoToPush, true)) + { + CalcBonuses(); + //Message(15, "Successfully removed an augmentation!"); + if (mat != _MaterialInvalid) + { + SendWearChange(mat); // Visible item augged while equipped. Send WC in case ornamentation changed. + } + } + } + break; + case 3: // Destroying augment (formerly done in birdbath/sealer with a solvent) + + // RoF client does not require an augmentation solvent for destroying an augmentation in an item. + // Augments can be destroyed with a right click -> Destroy at any time. + + aug = tobe_auged->GetAugment(in_augment->augment_index); + if (aug) + { + std::vector args; + args.push_back(aug); + parse->EventItem(EVENT_UNAUGMENT_ITEM, this, tobe_auged, nullptr, "", in_augment->augment_index, &args); + + args.assign(1, tobe_auged); + + args.push_back(true); + + parse->EventItem(EVENT_AUGMENT_REMOVE, this, aug, nullptr, "", in_augment->augment_index, &args); + } + else + { + Message(13, "Error: Could not find augmentation to remove at index %i. Aborting."); + return; } - if (PutItemInInventory(MainCursor, *itemTwoToPush, true)) + tobe_auged->DeleteAugment(in_augment->augment_index); + tobe_auged->UpdateOrnamentationInfo(); + + itemOneToPush = tobe_auged->Clone(); + if (itemOneToPush) { - CalcBonuses(); - //Message(15, "Successfully removed an augmentation!"); + DeleteItemInInventory(item_slot, 0, true); + + if (!PutItemInInventory(item_slot, *itemOneToPush, true)) + { + Message(15, "Failed to destroy augment properly!"); + } } - } + + CalcBonuses(); + //Message(15, "Successfully removed an augmentation!"); + if (mat != _MaterialInvalid) + { + SendWearChange(mat); + } + break; + default: // Unknown + Log.Out(Logs::General, Logs::Inventory, "Unrecognized augmentation action - cslot: %i aslot: %i cidx: %i aidx: %i act: %i dest: %i", + in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id); + break; } } else diff --git a/zone/tradeskills.cpp b/zone/tradeskills.cpp index 903c7c34c..2efed1e93 100644 --- a/zone/tradeskills.cpp +++ b/zone/tradeskills.cpp @@ -166,25 +166,34 @@ void Object::HandleAugmentation(Client* user, const AugmentItem_Struct* in_augme else { ItemInst *old_aug = nullptr; - const uint32 id = auged_with->GetID(); + bool isSolvent = auged_with->GetItem()->ItemType == ItemUseTypes::ItemTypeAugmentationSolvent; + if (!isSolvent && auged_with->GetItem()->ItemType != ItemUseTypes::ItemTypeAugmentationDistiller) + { + Log.Out(Logs::General, Logs::Error, "Player tried to remove an augment without a solvent or distiller."); + user->Message(13, "Error: Missing an augmentation solvent or distiller for removing this augment."); + + return; + } + ItemInst *aug = tobe_auged->GetAugment(in_augment->augment_slot); - if(aug) { + if (aug) { + if (!isSolvent && auged_with->GetItem()->ID != aug->GetItem()->AugDistiller) + { + Log.Out(Logs::General, Logs::Error, "Player tried to safely remove an augment with the wrong distiller (item %u vs expected %u).", auged_with->GetItem()->ID, aug->GetItem()->AugDistiller); + user->Message(13, "Error: Wrong augmentation distiller for safely removing this augment."); + return; + } std::vector args; args.push_back(aug); parse->EventItem(EVENT_UNAUGMENT_ITEM, user, tobe_auged, nullptr, "", slot, &args); args.assign(1, tobe_auged); - bool destroyed = false; - if(id == 40408 || id == 40409 || id == 40410) { - destroyed = true; - } - - args.push_back(&destroyed); + args.push_back(&isSolvent); parse->EventItem(EVENT_AUGMENT_REMOVE, user, aug, nullptr, "", slot, &args); } - if(id == 40408 || id == 40409 || id == 40410) + if (isSolvent) tobe_auged->DeleteAugment(in_augment->augment_slot); else old_aug = tobe_auged->RemoveAugment(in_augment->augment_slot); From f6c2c07a941ce75dbccf0ca9e82e1df0d89d239b Mon Sep 17 00:00:00 2001 From: Shendare Date: Tue, 10 Nov 2015 18:14:47 -0800 Subject: [PATCH 02/40] Augmentation Feature Patch Code Cleanup Avoided an extraneous GetItem() call when performing an action that doesn't return an augment to the player. Added additional error checking and logging. Improved error messages and code comments. --- zone/client_packet.cpp | 71 +++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 7d392ec37..36c4e1da8 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -2924,7 +2924,6 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) return; } - // Delegate to tradeskill object to perform combine AugmentItem_Struct* in_augment = (AugmentItem_Struct*)app->pBuffer; bool deleteItems = false; if (GetClientVersion() >= ClientVersion::RoF) @@ -2934,7 +2933,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) //Log.Out(Logs::DebugLevel::Moderate, Logs::Debug, "cslot: %i aslot: %i cidx: %i aidx: %i act: %i dest: %i", // in_augment->container_slot, in_augment->augment_slot, in_augment->container_index, in_augment->augment_index, in_augment->augment_action, in_augment->dest_inst_id); - ItemInst *tobe_auged = nullptr, *new_aug = nullptr, *old_aug = nullptr, *aug = nullptr, *solvent = nullptr; + ItemInst *tobe_auged = nullptr, *old_aug = nullptr, *new_aug = nullptr, *aug = nullptr, *solvent = nullptr; Inventory& user_inv = GetInv(); uint16 item_slot = in_augment->container_slot; @@ -2949,7 +2948,6 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) tobe_auged = user_inv.GetItem(item_slot); solvent = user_inv.GetItem(solvent_slot); - new_aug = user_inv.GetItem(MainCursor); if (!tobe_auged) { @@ -2996,7 +2994,15 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) { case 0: // Adding an augment case 2: // Swapping augment - if (new_aug) + new_aug = user_inv.GetItem(MainCursor); + + if (!new_aug) // Shouldn't get the OP code without the augment on the user's cursor, but maybe it's h4x. + { + Log.Out(Logs::General, Logs::Error, "AugmentItem OpCode with 'Insert' or 'Swap' action received, but no augment on client's cursor."); + Message(13, "Error: No augment found on cursor for inserting."); + return; + } + else { if (((tobe_auged->IsAugmentSlotAvailable(new_aug->GetAugmentType(), in_augment->augment_index)) != -1) && (tobe_auged->AvailableWearSlot(new_aug->GetItem()->Slots))) @@ -3014,7 +3020,6 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) args.assign(1, tobe_auged); args.push_back(false); - parse->EventItem(EVENT_AUGMENT_REMOVE, this, old_aug, nullptr, "", in_augment->augment_index, &args); } @@ -3057,27 +3062,29 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) if (itemTwoToPush) { - // Return the old aug to the player's cursor - - PutItemInInventory(MainCursor, *itemTwoToPush, true); + // This is a swap. Return the old aug to the player's cursor. + if (PutItemInInventory(MainCursor, *itemTwoToPush, true)) + { + Log.Out(Logs::General, Logs::Error, "Problem returning old augment to player's cursor after augmentation swap."); + Message(15, "Error: Failed to retrieve old augment after augmentation swap!"); + } } if (PutItemInInventory(item_slot, *itemOneToPush, true)) { - CalcBonuses(); // Successfully added an augment to the item + + CalcBonuses(); + if (mat != _MaterialInvalid) { SendWearChange(mat); // Visible item augged while equipped. Send WC in case ornamentation changed. } - return; } else { Message(13, "Error: No available slot for end result. Please free up the augment slot."); } - - return; } else { @@ -3109,37 +3116,49 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) Message(13, "Error: Could not find augmentation to remove at index %i. Aborting.", in_augment->augment_index); return; } + old_aug = tobe_auged->RemoveAugment(in_augment->augment_index); tobe_auged->UpdateOrnamentationInfo(); itemOneToPush = tobe_auged->Clone(); if (old_aug) itemTwoToPush = old_aug->Clone(); + if (itemOneToPush && itemTwoToPush) { - DeleteItemInInventory(item_slot, 0, true); + // Consume the augment distiller DeleteItemInInventory(solvent_slot, solvent->IsStackable() ? 1 : 0, true); + // Remove the augmented item + DeleteItemInInventory(item_slot, 0, true); + + // Replace it with the unaugmented item if (!PutItemInInventory(item_slot, *itemOneToPush, true)) { - Message(15, "Failed to remove augment properly!"); + Log.Out(Logs::General, Logs::Error, "Problem returning equipment item to player's inventory after safe augment removal."); + Message(15, "Error: Failed to return item after de-augmentation!"); } - if (PutItemInInventory(MainCursor, *itemTwoToPush, true)) + CalcBonuses(); + + if (mat != _MaterialInvalid) { - CalcBonuses(); - //Message(15, "Successfully removed an augmentation!"); - if (mat != _MaterialInvalid) - { - SendWearChange(mat); // Visible item augged while equipped. Send WC in case ornamentation changed. - } + SendWearChange(mat); // Visible item augged while equipped. Send WC in case ornamentation changed. + } + + // Drop the removed augment on the player's cursor + if (!PutItemInInventory(MainCursor, *itemTwoToPush, true)) + { + Log.Out(Logs::General, Logs::Error, "Problem returning augment to player's cursor after safe removal."); + Message(15, "Error: Failed to return augment after removal from item!"); + return; } } break; case 3: // Destroying augment (formerly done in birdbath/sealer with a solvent) - // RoF client does not require an augmentation solvent for destroying an augmentation in an item. - // Augments can be destroyed with a right click -> Destroy at any time. + // RoF client does not require an augmentation solvent for destroying an augmentation in an item. + // Augments can be destroyed with a right click -> Destroy at any time. aug = tobe_auged->GetAugment(in_augment->augment_index); if (aug) @@ -3170,12 +3189,13 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) if (!PutItemInInventory(item_slot, *itemOneToPush, true)) { - Message(15, "Failed to destroy augment properly!"); + Log.Out(Logs::General, Logs::Error, "Problem returning equipment item to player's inventory after augment deletion."); + Message(15, "Error: Failed to return item after destroying augment!"); } } CalcBonuses(); - //Message(15, "Successfully removed an augmentation!"); + if (mat != _MaterialInvalid) { SendWearChange(mat); @@ -3189,6 +3209,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) } else { + // Delegate to tradeskill object to perform combine Object::HandleAugmentation(this, in_augment, m_tradeskill_object); } return; From 7c414728773f3a756bd9ad6960eb7f1ffb8b5865 Mon Sep 17 00:00:00 2001 From: Shendare Date: Sat, 14 Nov 2015 11:40:28 -0800 Subject: [PATCH 03/40] Fixed swapping error message You now get the error message if the augment swap doesn't work, instead of when it works. One little bang. --- zone/client_packet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 36c4e1da8..b42b53e04 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -3063,7 +3063,7 @@ void Client::Handle_OP_AugmentItem(const EQApplicationPacket *app) if (itemTwoToPush) { // This is a swap. Return the old aug to the player's cursor. - if (PutItemInInventory(MainCursor, *itemTwoToPush, true)) + if (!PutItemInInventory(MainCursor, *itemTwoToPush, true)) { Log.Out(Logs::General, Logs::Error, "Problem returning old augment to player's cursor after augmentation swap."); Message(15, "Error: Failed to retrieve old augment after augmentation swap!"); From 17bbd8dfbec00ac21c148e14df778a59dbb78975 Mon Sep 17 00:00:00 2001 From: regneq Date: Thu, 17 Dec 2015 14:14:04 -0800 Subject: [PATCH 04/40] eqtime is now stored in the DB. required/2015_12_17_eqtime.sql --- common/database.cpp | 39 ++++++++++++ common/database.h | 2 + common/eqemu_config.cpp | 8 --- common/eqemu_config.h | 2 - common/eqtime.cpp | 66 -------------------- common/eqtime.h | 6 -- utils/sql/git/required/2015_12_17_eqtime.sql | 11 ++++ world/net.cpp | 13 ++-- world/zoneserver.cpp | 4 +- 9 files changed, 63 insertions(+), 88 deletions(-) create mode 100644 utils/sql/git/required/2015_12_17_eqtime.sql diff --git a/common/database.cpp b/common/database.cpp index 475b48258..b8ea025ae 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -2182,3 +2182,42 @@ void Database::ClearInvSnapshots(bool use_rule) std::string query = StringFormat("DELETE FROM inventory_snapshots WHERE time_index <= %lu", (unsigned long)del_time); QueryDatabase(query); } + +struct TimeOfDay_Struct Database::LoadTime(time_t &realtime) +{ + + TimeOfDay_Struct eqTime; + std::string query = StringFormat("SELECT minute,hour,day,month,year,realtime FROM eqtime limit 1"); + auto results = QueryDatabase(query); + + if (!results.Success() || results.RowCount() == 0) + { + Log.Out(Logs::Detail, Logs::World_Server, "Loading EQ time of day failed. Using defaults."); + eqTime.minute = 0; + eqTime.hour = 9; + eqTime.day = 1; + eqTime.month = 1; + eqTime.year = 3100; + realtime = time(0); + } + + auto row = results.begin(); + + eqTime.minute = atoi(row[0]); + eqTime.hour = atoi(row[1]); + eqTime.day = atoi(row[2]); + eqTime.month = atoi(row[3]); + eqTime.year = atoi(row[4]); + realtime = atoi(row[5]); + + return eqTime; +} + +bool Database::SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year) +{ + std::string query = StringFormat("UPDATE eqtime set minute = %d, hour = %d, day = %d, month = %d, year = %d, realtime = %d limit 1", minute, hour, day, month, year, time(0)); + auto results = QueryDatabase(query); + + return results.Success(); + +} \ No newline at end of file diff --git a/common/database.h b/common/database.h index f066cb417..02110b9a6 100644 --- a/common/database.h +++ b/common/database.h @@ -241,6 +241,8 @@ public: uint8 GetSkillCap(uint8 skillid, uint8 in_race, uint8 in_class, uint16 in_level); void AddReport(std::string who, std::string against, std::string lines); + struct TimeOfDay_Struct LoadTime(time_t &realtime); + bool SaveTime(int8 minute, int8 hour, int8 day, int8 month, int16 year); void ClearMerchantTemp(); void ClearPTimers(uint32 charid); void SetFirstLogon(uint32 CharID, uint8 firstlogon); diff --git a/common/eqemu_config.cpp b/common/eqemu_config.cpp index 6e1400904..fb295cec1 100644 --- a/common/eqemu_config.cpp +++ b/common/eqemu_config.cpp @@ -254,10 +254,6 @@ void EQEmuConfig::do_files(TiXmlElement *ele) if (text) { OpCodesFile = text; } - text = ParseTextBlock(ele, "eqtime", true); - if (text) { - EQTimeFile = text; - } } void EQEmuConfig::do_directories(TiXmlElement *ele) @@ -408,9 +404,6 @@ std::string EQEmuConfig::GetByName(const std::string &var_name) const if (var_name == "OpCodesFile") { return (OpCodesFile); } - if (var_name == "EQTimeFile") { - return (EQTimeFile); - } if (var_name == "MapDir") { return (MapDir); } @@ -475,7 +468,6 @@ void EQEmuConfig::Dump() const std::cout << "QSDatabasePort = " << QSDatabasePort << std::endl; std::cout << "SpellsFile = " << SpellsFile << std::endl; std::cout << "OpCodesFile = " << OpCodesFile << std::endl; - std::cout << "EQTimeFile = " << EQTimeFile << std::endl; std::cout << "MapDir = " << MapDir << std::endl; std::cout << "QuestDir = " << QuestDir << std::endl; std::cout << "PluginDir = " << PluginDir << std::endl; diff --git a/common/eqemu_config.h b/common/eqemu_config.h index 1ad2174dc..039b6c327 100644 --- a/common/eqemu_config.h +++ b/common/eqemu_config.h @@ -79,7 +79,6 @@ class EQEmuConfig : public XMLParser // From std::string SpellsFile; std::string OpCodesFile; - std::string EQTimeFile; // From std::string MapDir; @@ -154,7 +153,6 @@ class EQEmuConfig : public XMLParser // Files SpellsFile = "spells_us.txt"; OpCodesFile = "opcodes.conf"; - EQTimeFile = "eqtime.cfg"; // Dirs MapDir = "Maps"; QuestDir = "quests"; diff --git a/common/eqtime.cpp b/common/eqtime.cpp index e504964b8..8ece4ad69 100644 --- a/common/eqtime.cpp +++ b/common/eqtime.cpp @@ -133,72 +133,6 @@ int EQTime::SetCurrentEQTimeOfDay(TimeOfDay_Struct start_eq, time_t start_real) return 1; } -//saveFile and loadFile need to use long for the save datatype... -//For some reason, ifstream/ofstream have problems with EQEmu datatypes in files. -bool EQTime::saveFile(const char *filename) -{ - std::ofstream of; - of.open(filename); - if (!of) - { - Log.Out(Logs::General, Logs::Error, "EQTime::saveFile failed: Unable to open file '%s'", filename); - return false; - } - //Enable for debugging - of << EQT_VERSION << std::endl; - of << (long)eqTime.start_eqtime.day << std::endl; - of << (long)eqTime.start_eqtime.hour << std::endl; - of << (long)eqTime.start_eqtime.minute << std::endl; - of << (long)eqTime.start_eqtime.month << std::endl; - of << eqTime.start_eqtime.year << std::endl; - of << eqTime.start_realtime << std::endl; - of.close(); - return true; -} - -bool EQTime::loadFile(const char *filename) -{ - int version=0; - long in_data=0; - std::ifstream in; - in.open(filename); - if(!in) - { - Log.Out(Logs::General, Logs::Error, "Could not load EQTime file %s", filename); - return false; - } - in >> version; - in.ignore(80, '\n'); - if(version != EQT_VERSION) - { - Log.Out(Logs::General, Logs::Error, "'%s' is NOT a valid EQTime file. File version is %i, EQTime version is %i", filename, version, EQT_VERSION); - return false; - } - //in >> eqTime.start_eqtime.day; - in >> in_data; - in.ignore(80, '\n'); - eqTime.start_eqtime.day = in_data; - //in >> eqTime.start_eqtime.hour; - in >> in_data; - eqTime.start_eqtime.hour = in_data; - in.ignore(80, '\n'); - //in >> eqTime.start_eqtime.minute; - in >> in_data; - in.ignore(80, '\n'); - eqTime.start_eqtime.minute = in_data; - //in >> eqTime.start_eqtime.month; - in >> in_data; - in.ignore(80, '\n'); - eqTime.start_eqtime.month = in_data; - in >> eqTime.start_eqtime.year; - in.ignore(80, '\n'); - in >> eqTime.start_realtime; - //Enable for debugging... - in.close(); - return true; -} - - bool EQTime::IsTimeBefore(TimeOfDay_Struct *base, TimeOfDay_Struct *test) { if (base->year > test->year) return(true); diff --git a/common/eqtime.h b/common/eqtime.h index aeda9f0f6..f40b855f6 100644 --- a/common/eqtime.h +++ b/common/eqtime.h @@ -39,12 +39,6 @@ public: static void ToString(TimeOfDay_Struct *t, std::string &str); - //Database functions - //bool loadDB(Database q); - //bool setDB(Database q); - bool loadFile(const char *filename); - bool saveFile(const char *filename); - private: //This is our reference clock. eqTimeOfDay eqTime; diff --git a/utils/sql/git/required/2015_12_17_eqtime.sql b/utils/sql/git/required/2015_12_17_eqtime.sql new file mode 100644 index 000000000..c264edf27 --- /dev/null +++ b/utils/sql/git/required/2015_12_17_eqtime.sql @@ -0,0 +1,11 @@ +DROP TABLE IF EXISTS `eqtime`; +CREATE TABLE `eqtime` ( + `minute` tinyint(4) not null default 0, + `hour` tinyint(4) not null default 0, + `day` tinyint(4) not null default 0, + `month` tinyint(4) not null default 0, + `year` int(4) not null default 0, + `realtime` int(11) not null default 0 +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +INSERT INTO eqtime values (0,1,28,12,3766,1444035661); \ No newline at end of file diff --git a/world/net.cpp b/world/net.cpp index d7669ce12..b5c29fecb 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -345,8 +345,11 @@ int main(int argc, char** argv) { database.ClearMerchantTemp(); } Log.Out(Logs::General, Logs::World_Server, "Loading EQ time of day.."); - if (!zoneserver_list.worldclock.loadFile(Config->EQTimeFile.c_str())) - Log.Out(Logs::General, Logs::World_Server, "Unable to load %s", Config->EQTimeFile.c_str()); + TimeOfDay_Struct eqTime; + time_t realtime; + eqTime = database.LoadTime(realtime); + zoneserver_list.worldclock.SetCurrentEQTimeOfDay(eqTime, realtime); + Log.Out(Logs::General, Logs::World_Server, "Loading launcher list.."); launcher_list.LoadList(); @@ -519,8 +522,10 @@ int main(int argc, char** argv) { void CatchSignal(int sig_num) { Log.Out(Logs::General, Logs::World_Server,"Caught signal %d",sig_num); - if(zoneserver_list.worldclock.saveFile(WorldConfig::get()->EQTimeFile.c_str())==false) - Log.Out(Logs::General, Logs::World_Server,"Failed to save time file."); + TimeOfDay_Struct eqTime; + zoneserver_list.worldclock.GetCurrentEQTimeOfDay(time(0), &eqTime); + if (!database.SaveTime(eqTime.minute, eqTime.hour, eqTime.day, eqTime.month, eqTime.year)) + Log.Out(Logs::General, Logs::World_Server, "Failed to save eqtime."); RunLoops = false; } diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index f6447f3f4..580053a3b 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -989,8 +989,8 @@ bool ZoneServer::Process() { Log.Out(Logs::Detail, Logs::World_Server,"Received SetWorldTime"); eqTimeOfDay* newtime = (eqTimeOfDay*) pack->pBuffer; zoneserver_list.worldclock.SetCurrentEQTimeOfDay(newtime->start_eqtime, newtime->start_realtime); - Log.Out(Logs::Detail, Logs::World_Server,"New time = %d-%d-%d %d:%d (%d)\n", newtime->start_eqtime.year, newtime->start_eqtime.month, (int)newtime->start_eqtime.day, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.minute, (int)newtime->start_realtime); - zoneserver_list.worldclock.saveFile(WorldConfig::get()->EQTimeFile.c_str()); + Log.Out(Logs::Detail, Logs::World_Server, "New time = %d-%d-%d %d:%d (%d)\n", newtime->start_eqtime.year, newtime->start_eqtime.month, (int)newtime->start_eqtime.day, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.minute, (int)newtime->start_realtime); + database.SaveTime((int)newtime->start_eqtime.minute, (int)newtime->start_eqtime.hour, (int)newtime->start_eqtime.day, newtime->start_eqtime.month, newtime->start_eqtime.year); zoneserver_list.SendTimeSync(); break; } From d449d4f54c7d1eb03eb91dfef27031663871414d Mon Sep 17 00:00:00 2001 From: regneq Date: Thu, 17 Dec 2015 15:49:37 -0800 Subject: [PATCH 05/40] EQTime will now save to the DB once every 10 real world minutes. --- world/net.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/world/net.cpp b/world/net.cpp index b5c29fecb..86f794af0 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -349,6 +349,8 @@ int main(int argc, char** argv) { time_t realtime; eqTime = database.LoadTime(realtime); zoneserver_list.worldclock.SetCurrentEQTimeOfDay(eqTime, realtime); + Timer EQTimeTimer(600000); + EQTimeTimer.Start(600000); Log.Out(Logs::General, Logs::World_Server, "Loading launcher list.."); launcher_list.LoadList(); @@ -473,6 +475,16 @@ int main(int argc, char** argv) { database.PurgeExpiredInstances(); } + if (EQTimeTimer.Check()) + { + TimeOfDay_Struct tod; + zoneserver_list.worldclock.GetCurrentEQTimeOfDay(time(0), &tod); + if (!database.SaveTime(tod.minute, tod.hour, tod.day, tod.month, tod.year)) + Log.Out(Logs::General, Logs::World_Server, "Failed to save eqtime."); + else + Log.Out(Logs::General, Logs::World_Server, "EQTime successfully saved."); + } + //check for timeouts in other threads timeout_manager.CheckTimeouts(); loginserverlist.Process(); @@ -522,10 +534,6 @@ int main(int argc, char** argv) { void CatchSignal(int sig_num) { Log.Out(Logs::General, Logs::World_Server,"Caught signal %d",sig_num); - TimeOfDay_Struct eqTime; - zoneserver_list.worldclock.GetCurrentEQTimeOfDay(time(0), &eqTime); - if (!database.SaveTime(eqTime.minute, eqTime.hour, eqTime.day, eqTime.month, eqTime.year)) - Log.Out(Logs::General, Logs::World_Server, "Failed to save eqtime."); RunLoops = false; } From 488be05e0e68ce30d8da001d252c1d3a764d1d8c Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 17 Dec 2015 19:50:33 -0500 Subject: [PATCH 06/40] Add DB manifest for eqtime change --- common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/common/version.h b/common/version.h index 2e5af617c..c3dfa1c26 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9091 +#define CURRENT_BINARY_DATABASE_VERSION 9092 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9000 #else diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 2f37dfe84..adc9009c2 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -345,6 +345,7 @@ 9089|2015_11_02_ai_idle_no_spell_recast_default_changes.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Spells:AI_IdleNoSpellMinRecast%' AND `rule_value` = '500'|not_empty| 9090|2015_12_01_spell_scribe_restriction_rule.sql|SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Character:RestrictSpellScribing'|empty| 9091|2015_12_07_command_settings.sql|SHOW TABLES LIKE 'command_settings'|empty| +9092|2015_12_17_eqtime.sql|SHOW TABLES LIKE 'eqtime'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not From f8867ea73d81b9e2f1a35b2aa52f7fd63d5a5173 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 18 Dec 2015 13:46:05 -0500 Subject: [PATCH 07/40] Bump up initial aggro from Yell for Help to match initial aggro I guess I forgot this one --- zone/aggro.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/aggro.cpp b/zone/aggro.cpp index a1903c8ca..5febe5767 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -476,7 +476,7 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) { attacker->GetName(), DistanceSquared(mob->GetPosition(), sender->GetPosition()), fabs(sender->GetZ()+mob->GetZ())); #endif - mob->AddToHateList(attacker, 1, 0, false); + mob->AddToHateList(attacker, 25, 0, false); } } } From 03592e58f903d2a5066c3710c46c90fe485e3061 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Fri, 18 Dec 2015 17:41:57 -0500 Subject: [PATCH 08/40] Port EQMacEmu's Assist Aggro code This code also allows you to toggle on Tick Pulling (Aggro:AllowTickPulling) which was a pulling technique (exploit) fixed sometime in 2006 This code also implements assist caps to cut down on trains (5 by default) Unsure if live what this number is (it exists) or if it's a per NPC basis An NPC with Assist Aggro will not call for help, only NPCs with Primary Aggro will --- common/ruletypes.h | 3 +++ zone/aggro.cpp | 10 ++++++++++ zone/attack.cpp | 5 +++++ zone/mob.cpp | 5 +++++ zone/mob.h | 14 ++++++++++++++ zone/mob_ai.cpp | 6 +++++- zone/npc.cpp | 12 +++++++++++- 7 files changed, 53 insertions(+), 2 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 91d3479be..83ef9aff3 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -459,6 +459,8 @@ RULE_BOOL(Combat, ProjectileDmgOnImpact, true) //If enabled, projectiles (ie arr RULE_BOOL(Combat, MeleePush, true) // enable melee push RULE_INT(Combat, MeleePushChance, 50) // (NPCs) chance the target will be pushed. Made up, 100 actually isn't that bad RULE_BOOL(Combat, UseLiveCombatRounds, true) // turn this false if you don't want to worry about fixing up combat rounds for NPCs +RULE_INT(Combat, NPCAssistCap, 5) // Maxiumium number of NPCs that will assist another NPC at once +RULE_INT(Combat, NPCAssistCapTimer, 6000) // Time in milliseconds a NPC will take to clear assist aggro cap space RULE_CATEGORY_END() RULE_CATEGORY(NPC) @@ -494,6 +496,7 @@ RULE_INT(Aggro, PetSpellAggroMod, 10) RULE_REAL(Aggro, TunnelVisionAggroMod, 0.75) //people not currently the top hate generate this much hate on a Tunnel Vision mob 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_CATEGORY_END() RULE_CATEGORY(TaskSystem) diff --git a/zone/aggro.cpp b/zone/aggro.cpp index 5febe5767..a2ee52357 100644 --- a/zone/aggro.cpp +++ b/zone/aggro.cpp @@ -431,11 +431,20 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) { if (sender->GetPrimaryFaction() == 0 ) return; // well, if we dont have a faction set, we're gonna be indiff to everybody + if (sender->HasAssistAggro()) + return; + for (auto it = npc_list.begin(); it != npc_list.end(); ++it) { NPC *mob = it->second; if (!mob) continue; + if (mob->CheckAggro(attacker)) + continue; + + if (sender->NPCAssistCap() >= RuleI(Combat, NPCAssistCap)) + break; + float r = mob->GetAssistRange(); r = r * r; @@ -477,6 +486,7 @@ void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) { sender->GetPosition()), fabs(sender->GetZ()+mob->GetZ())); #endif mob->AddToHateList(attacker, 25, 0, false); + sender->AddAssistCap(); } } } diff --git a/zone/attack.cpp b/zone/attack.cpp index 2752752aa..6b2534a43 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -2422,6 +2422,11 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b hate = 1; } + if (iYellForHelp) + SetPrimaryAggro(true); + else + SetAssistAggro(true); + bool wasengaged = IsEngaged(); Mob* owner = other->GetOwner(); Mob* mypet = this->GetPet(); diff --git a/zone/mob.cpp b/zone/mob.cpp index eccf04a76..6e778f004 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -433,6 +433,9 @@ Mob::Mob(const char* in_name, emoteid = 0; endur_upkeep = false; + PrimaryAggro = false; + AssistAggro = false; + npc_assist_cap = 0; } Mob::~Mob() @@ -2693,6 +2696,8 @@ bool Mob::RemoveFromHateList(Mob* mob) { AI_Event_NoLongerEngaged(); zone->DelAggroMob(); + if (IsNPC() && !RuleB(Aggro, AllowTickPulling)) + ResetAssistCap(); } } if(GetTarget() == mob) diff --git a/zone/mob.h b/zone/mob.h index 2ca027023..d02e0f089 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -504,6 +504,10 @@ public: Mob* GetHateRandom() { return hate_list.GetRandomEntOnHateList();} Mob* GetHateMost() { return hate_list.GetEntWithMostHateOnList();} bool IsEngaged() { return(!hate_list.IsHateListEmpty()); } + bool HasPrimaryAggro() { return PrimaryAggro; } + bool HasAssistAggro() { return AssistAggro; } + void SetPrimaryAggro(bool value) { PrimaryAggro = value; if (value) AssistAggro = false; } + void SetAssistAggro(bool value) { AssistAggro = value; if (PrimaryAggro) AssistAggro = false; } bool HateSummon(); void FaceTarget(Mob* MobToFace = 0); void SetHeading(float iHeading) { if(m_Position.w != iHeading) { pLastChange = Timer::GetCurrentTime(); @@ -993,6 +997,11 @@ public: void ApplyAABonuses(const AA::Rank &rank, StatBonuses* newbon); bool CheckAATimer(int timer); + int NPCAssistCap() { return npc_assist_cap; } + void AddAssistCap() { ++npc_assist_cap; } + void DelAssistCap() { --npc_assist_cap; } + void ResetAssistCap() { npc_assist_cap = 0; } + protected: void CommonDamage(Mob* other, int32 &damage, const uint16 spell_id, const SkillUseTypes attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, int special = 0); static uint16 GetProcID(uint16 spell_id, uint8 effect_index); @@ -1293,6 +1302,11 @@ protected: glm::vec4 m_CurrentWayPoint; int cur_wp_pause; + bool PrimaryAggro; + bool AssistAggro; + int npc_assist_cap; + Timer assist_cap_timer; // clear assist cap so more nearby mobs can be called for help + int patrol; glm::vec3 m_FearWalkTarget; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index 25ed72441..79c4493ea 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1735,8 +1735,10 @@ void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) { if (iYellForHelp) { if(IsPet()) { GetOwner()->AI_Event_Engaged(attacker, iYellForHelp); - } else { + } else if (!HasAssistAggro() && NPCAssistCap() < RuleI(Combat, NPCAssistCap)) { entity_list.AIYellForHelp(this, attacker); + if (NPCAssistCap() > 0 && !assist_cap_timer.Enabled()) + assist_cap_timer.Start(RuleI(Combat, NPCAssistCapTimer)); } } @@ -1787,6 +1789,8 @@ void Mob::AI_Event_NoLongerEngaged() { if(IsNPC()) { + SetPrimaryAggro(false); + SetAssistAggro(false); if(CastToNPC()->GetCombatEvent() && GetHP() > 0) { if(entity_list.GetNPCByID(this->GetID())) diff --git a/zone/npc.cpp b/zone/npc.cpp index ebdd8a79d..fd7f6880c 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -712,8 +712,18 @@ bool NPC::Process() } //Handle assists... - if(assist_timer.Check() && IsEngaged() && !Charmed()) { + if (assist_cap_timer.Check()) { + if (NPCAssistCap() > 0) + DelAssistCap(); + else + assist_cap_timer.Disable(); + } + + if (assist_timer.Check() && IsEngaged() && !Charmed() && !HasAssistAggro() && + NPCAssistCap() < RuleI(Combat, NPCAssistCap)) { entity_list.AIYellForHelp(this, GetTarget()); + if (NPCAssistCap() > 0 && !assist_cap_timer.Enabled()) + assist_cap_timer.Start(RuleI(Combat, NPCAssistCapTimer)); } if(qGlobals) From b4b1324aceb942b537c687fec64888ec6a8e3487 Mon Sep 17 00:00:00 2001 From: Uleat Date: Sat, 19 Dec 2015 12:42:55 -0500 Subject: [PATCH 09/40] Updated client version bitmasks --- common/clientversions.h | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/common/clientversions.h b/common/clientversions.h index 4e575f8f4..308a5f091 100644 --- a/common/clientversions.h +++ b/common/clientversions.h @@ -24,20 +24,27 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "types.h" -static const uint32 BIT_Client62 = 1; -static const uint32 BIT_Titanium = 2; -static const uint32 BIT_SoF = 4; -static const uint32 BIT_SoD = 8; -static const uint32 BIT_UF = 16; -static const uint32 BIT_RoF = 32; -static const uint32 BIT_RoF2 = 64; +static const uint32 BIT_Client62 = 0x00000001; // 1 (unsupported - placeholder for scripts) + +static const uint32 BIT_Titanium = 0x00000002; // 2 +static const uint32 BIT_SoF = 0x00000004; // 4 +static const uint32 BIT_SoD = 0x00000008; // 8 +static const uint32 BIT_UF = 0x00000010; // 16 +static const uint32 BIT_RoF = 0x00000020; // 32 +static const uint32 BIT_RoF2 = 0x00000040; // 64 + +static const uint32 BIT_TitaniumAndEarlier = 0x00000003; // 3 +static const uint32 BIT_SoFAndEarlier = 0x00000007; // 7 +static const uint32 BIT_SoDAndEarlier = 0x0000000F; // 15 +static const uint32 BIT_UFAndEarlier = 0x0000001F; // 31 +static const uint32 BIT_RoFAndEarlier = 0x0000003F; // 63 + +static const uint32 BIT_SoFAndLater = 0xFFFFFFFC; // 4294967292 +static const uint32 BIT_SoDAndLater = 0xFFFFFFF8; // 4294967288 +static const uint32 BIT_UFAndLater = 0xFFFFFFF0; // 4294967280 +static const uint32 BIT_RoFAndLater = 0xFFFFFFE0; // 4294967264 +static const uint32 BIT_RoF2AndLater = 0xFFFFFFC0; // 4294967232 -static const uint32 BIT_TitaniumAndEarlier = 0x00000003; -static const uint32 BIT_SoFAndLater = 0xFFFFFFFC; -static const uint32 BIT_SoDAndLater = 0xFFFFFFF8; -static const uint32 BIT_UFAndLater = 0xFFFFFFF0; -static const uint32 BIT_RoFAndLater = 0xFFFFFFE0; -static const uint32 BIT_RoF2AndLater = 0xFFFFFFC0; static const uint32 BIT_AllClients = 0xFFFFFFFF; enum class ClientVersion From 0177c8d7d9238be93beb241bec6d48ce0ef9e26f Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Sat, 19 Dec 2015 15:23:04 -0500 Subject: [PATCH 10/40] Exported several Mob-based methods to Perl and Lua. --- changelog.txt | 22 ++ zone/lua_mob.cpp | 116 ++++++++++- zone/lua_mob.h | 19 ++ zone/perl_mob.cpp | 510 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 666 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index f708219e8..c64baec6c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,27 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 12/19/2015 == +Kinglykrab: Added many methods to Perl and Lua, list below: + - SeeInvisible() + - SeeInvisibleUndead() + - SeeHide() + - SeeImprovedHide() + - GetNimbusEffect1() - returns first nimbus effect + - GetNimbusEffect2() - returns second nimbus effect + - GetNimbusEffect3() - returns third nimbus effect + - IsTargetable() + - HasShieldEquiped() + - HasTwoHandBluntEquiped() + - HasTwoHanderEquiped() + - GetHerosForgeModel() - returns int32 Hero's Forge model + - IsEliteMaterialItem() - returns uint32 Hero's Forge Model + - GetBaseSize() - returns Mob's base size + - HasOwner() + - IsPet() + - HasPet() + - IsSilenced() + - IsAmnesiad() + == 12/16/2015 == Noudess: Repaired issue with Bind Wounds on someone else. Message was not coming out on client (hold still) and a bind wounds on someone already binding their wounds would interrupt their bind and make them stand. Also removed some duplicate messaging. diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 3963ec64c..469e8cb2f 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -1881,6 +1881,101 @@ bool Lua_Mob::IsBlind() { return self->IsBlind(); } +uint8 Lua_Mob::SeeInvisible() { + Lua_Safe_Call_Int(); + return self->SeeInvisible(); +} + +bool Lua_Mob::SeeInvisibleUndead() { + Lua_Safe_Call_Bool(); + return self->SeeInvisibleUndead(); +} + +bool Lua_Mob::SeeHide() { + Lua_Safe_Call_Bool(); + return self->SeeHide(); +} + +bool Lua_Mob::SeeImprovedHide() { + Lua_Safe_Call_Bool(); + return self->SeeImprovedHide(); +} + +uint8 Lua_Mob::GetNimbusEffect1() { + Lua_Safe_Call_Int(); + return self->GetNimbusEffect1(); +} + +uint8 Lua_Mob::GetNimbusEffect2() { + Lua_Safe_Call_Int(); + return self->GetNimbusEffect2(); +} + +uint8 Lua_Mob::GetNimbusEffect3() { + Lua_Safe_Call_Int(); + return self->GetNimbusEffect3(); +} + +bool Lua_Mob::IsTargetable() { + Lua_Safe_Call_Bool(); + return self->IsTargetable(); +} + +bool Lua_Mob::HasShieldEquiped() { + Lua_Safe_Call_Bool(); + return self->HasShieldEquiped(); +} + +bool Lua_Mob::HasTwoHandBluntEquiped() { + Lua_Safe_Call_Bool(); + return self->HasTwoHandBluntEquiped(); +} + +bool Lua_Mob::HasTwoHanderEquipped() { + Lua_Safe_Call_Bool(); + return self->HasTwoHanderEquipped(); +} + +uint32 Lua_Mob::GetHerosForgeModel(uint8 material_slot) { + Lua_Safe_Call_Int(); + return self->GetHerosForgeModel(material_slot); +} + +uint32 Lua_Mob::IsEliteMaterialItem(uint8 material_slot) { + Lua_Safe_Call_Int(); + return self->IsEliteMaterialItem(material_slot); +} + +float Lua_Mob::GetBaseSize() { + Lua_Safe_Call_Real(); + return self->GetBaseSize(); +} + +bool Lua_Mob::HasOwner() { + Lua_Safe_Call_Bool(); + return self->HasOwner(); +} + +bool Lua_Mob::IsPet() { + Lua_Safe_Call_Bool(); + return self->IsPet(); +} + +bool Lua_Mob::HasPet() { + Lua_Safe_Call_Bool(); + return self->HasPet(); +} + +bool Lua_Mob::IsSilenced() { + Lua_Safe_Call_Bool(); + return self->IsSilenced(); +} + +bool Lua_Mob::IsAmnesiad() { + Lua_Safe_Call_Bool(); + return self->IsAmnesiad(); +} + luabind::scope lua_register_mob() { return luabind::class_("Mob") .def(luabind::constructor<>()) @@ -2203,7 +2298,26 @@ luabind::scope lua_register_mob() { .def("BuffFadeBySlot", (void(Lua_Mob::*)(int,bool))&Lua_Mob::BuffFadeBySlot) .def("CanBuffStack", (int(Lua_Mob::*)(int,int))&Lua_Mob::CanBuffStack) .def("CanBuffStack", (int(Lua_Mob::*)(int,int,bool))&Lua_Mob::CanBuffStack) - .def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot); + .def("SetPseudoRoot", (void(Lua_Mob::*)(void))&Lua_Mob::SetPseudoRoot) + .def("SeeInvisible", (uint8(Lua_Mob::*)(void))&Lua_Mob::SeeInvisible) + .def("SeeInvisibleUndead", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeInvisibleUndead) + .def("SeeHide", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeHide) + .def("SeeImprovedHide", (bool(Lua_Mob::*)(bool))&Lua_Mob::SeeImprovedHide) + .def("GetNimbusEffect1", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect1) + .def("GetNimbusEffect2", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect2) + .def("GetNimbusEffect3", (uint8(Lua_Mob::*)(void))&Lua_Mob::GetNimbusEffect3) + .def("IsTargetable", (bool(Lua_Mob::*)(void))&Lua_Mob::IsTargetable) + .def("HasShieldEquiped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasShieldEquiped) + .def("HasTwoHandBluntEquiped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasTwoHandBluntEquiped) + .def("HasTwoHanderEquipped", (bool(Lua_Mob::*)(void))&Lua_Mob::HasTwoHanderEquipped) + .def("GetHerosForgeModel", (int32(Lua_Mob::*)(uint8))&Lua_Mob::GetHerosForgeModel) + .def("IsEliteMaterialItem", (uint32(Lua_Mob::*)(uint8))&Lua_Mob::IsEliteMaterialItem) + .def("GetBaseSize", (double(Lua_Mob::*)(void))&Lua_Mob::GetBaseSize) + .def("HasOwner", (bool(Lua_Mob::*)(void))&Lua_Mob::HasOwner) + .def("IsPet", (bool(Lua_Mob::*)(void))&Lua_Mob::IsPet) + .def("HasPet", (bool(Lua_Mob::*)(void))&Lua_Mob::HasPet) + .def("IsSilenced", (bool(Lua_Mob::*)(void))&Lua_Mob::IsSilenced) + .def("IsAmnesiad", (bool(Lua_Mob::*)(void))&Lua_Mob::IsAmnesiad); } luabind::scope lua_register_special_abilities() { diff --git a/zone/lua_mob.h b/zone/lua_mob.h index 3b98b4af3..c7530e391 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -358,6 +358,25 @@ public: int CanBuffStack(int spell_id, int caster_level); int CanBuffStack(int spell_id, int caster_level, bool fail_if_overwrite); void SetPseudoRoot(bool in); + uint8 SeeInvisible(); + bool SeeInvisibleUndead(); + bool SeeHide(); + bool SeeImprovedHide(); + uint8 GetNimbusEffect1(); + uint8 GetNimbusEffect2(); + uint8 GetNimbusEffect3(); + bool IsTargetable(); + bool HasShieldEquiped(); + bool HasTwoHandBluntEquiped(); + bool HasTwoHanderEquipped(); + uint32 GetHerosForgeModel(uint8 material_slot); + uint32 IsEliteMaterialItem(uint8 material_slot); + float GetBaseSize(); + bool HasOwner(); + bool IsPet(); + bool HasPet(); + bool IsSilenced(); + bool IsAmnesiad(); }; #endif diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index adbdd0301..2b2442fe6 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -8490,6 +8490,497 @@ XS(XS_Mob_IsBlind) { XSRETURN(1); } +XS(XS_Mob_SeeInvisible); +XS(XS_Mob_SeeInvisible) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::SeeInvisible(THIS)"); + { + Mob* THIS; + uint8 RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->SeeInvisible(); + XSprePUSH; + PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_SeeInvisibleUndead); +XS(XS_Mob_SeeInvisibleUndead) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::SeeInvisibleUndead(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->SeeInvisibleUndead(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_SeeHide); +XS(XS_Mob_SeeHide) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::SeeHide(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->SeeHide(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_SeeImprovedHide); +XS(XS_Mob_SeeImprovedHide) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::SeeImprovedHide(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->SeeImprovedHide(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_GetNimbusEffect1); +XS(XS_Mob_GetNimbusEffect1) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::GetNimbusEffect1(THIS)"); + { + Mob* THIS; + uint8 RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetNimbusEffect1(); + XSprePUSH; + PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_GetNimbusEffect2); +XS(XS_Mob_GetNimbusEffect2) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::GetNimbusEffect2(THIS)"); + { + Mob* THIS; + uint8 RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetNimbusEffect2(); + XSprePUSH; + PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_GetNimbusEffect3); +XS(XS_Mob_GetNimbusEffect3) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::GetNimbusEffect3(THIS)"); + { + Mob* THIS; + uint8 RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetNimbusEffect3(); + XSprePUSH; + PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_IsTargetable); +XS(XS_Mob_IsTargetable) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::IsTargetable(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->IsTargetable(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_HasShieldEquiped); +XS(XS_Mob_HasShieldEquiped) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::HasShieldEquiped(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->HasShieldEquiped(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_HasTwoHandBluntEquiped); +XS(XS_Mob_HasTwoHandBluntEquiped) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::HasTwoHandBluntEquiped(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->HasTwoHandBluntEquiped(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_HasTwoHanderEquipped); +XS(XS_Mob_HasTwoHanderEquipped) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::HasTwoHanderEquipped(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->HasTwoHanderEquipped(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_GetHerosForgeModel); +XS(XS_Mob_GetHerosForgeModel) { + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: Mob::GetHerosForgeModel(THIS, material_slot)"); + { + Mob* THIS; + int32 RETVAL; + uint8 material_slot = (uint8)SvUV(ST(1)); + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetHerosForgeModel(material_slot); + XSprePUSH; + PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_IsEliteMaterialItem); +XS(XS_Mob_IsEliteMaterialItem) { + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: Mob::IsEliteMaterialItem(THIS, material_slot)"); + { + Mob* THIS; + uint32 RETVAL; + uint8 material_slot = (uint8)SvUV(ST(1)); + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->IsEliteMaterialItem(material_slot); + XSprePUSH; + PUSHu((UV)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_GetBaseSize); +XS(XS_Mob_GetBaseSize) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::GetBaseSize(THIS)"); + { + Mob* THIS; + float RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetBaseSize(); + XSprePUSH; + PUSHn((double)RETVAL); + } + XSRETURN(1); +} + +XS(XS_Mob_HasOwner); +XS(XS_Mob_HasOwner) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::HasOwner(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->HasOwner(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_IsPet); +XS(XS_Mob_IsPet) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::IsPet(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->IsPet(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_HasPet); +XS(XS_Mob_HasPet) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::HasPet(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->HasPet(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_IsSilenced); +XS(XS_Mob_IsSilenced) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::IsSilenced(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->IsSilenced(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + +XS(XS_Mob_IsAmnesiad); +XS(XS_Mob_IsAmnesiad) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::IsAmnesiad(THIS)"); + { + Mob* THIS; + bool RETVAL; + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->IsAmnesiad(); + ST(0) = boolSV(RETVAL); + sv_2mortal(ST(0)); + } + XSRETURN(1); +} + #ifdef __cplusplus extern "C" #endif @@ -8803,6 +9294,25 @@ XS(boot_Mob) newXSproto(strcpy(buf, "CanClassEquipItem"), XS_Mob_CanClassEquipItem, file, "$$"); newXSproto(strcpy(buf, "IsFeared"), XS_Mob_IsFeared, file, "$"); newXSproto(strcpy(buf, "IsBlind"), XS_Mob_IsBlind, file, "$"); + newXSproto(strcpy(buf, "SeeInvisible"), XS_Mob_SeeInvisible, file, "$"); + newXSproto(strcpy(buf, "SeeInvisibleUndead"), XS_Mob_SeeInvisibleUndead, file, "$"); + newXSproto(strcpy(buf, "SeeHide"), XS_Mob_SeeHide, file, "$"); + newXSproto(strcpy(buf, "SeeImprovedHide"), XS_Mob_SeeImprovedHide, file, "$"); + newXSproto(strcpy(buf, "GetNimbusEffect1"), XS_Mob_GetNimbusEffect1, file, "$"); + newXSproto(strcpy(buf, "GetNimbusEffect2"), XS_Mob_GetNimbusEffect2, file, "$"); + newXSproto(strcpy(buf, "GetNimbusEffect3"), XS_Mob_GetNimbusEffect3, file, "$"); + newXSproto(strcpy(buf, "IsTargetable"), XS_Mob_IsTargetable, file, "$"); + newXSproto(strcpy(buf, "HasShieldEquiped"), XS_Mob_HasShieldEquiped, file, "$"); + newXSproto(strcpy(buf, "HasTwoHandBluntEquiped"), XS_Mob_HasTwoHandBluntEquiped, file, "$"); + newXSproto(strcpy(buf, "HasTwoHanderEquipped"), XS_Mob_HasTwoHanderEquipped, file, "$"); + newXSproto(strcpy(buf, "GetHerosForgeModel"), XS_Mob_GetHerosForgeModel, file, "$$"); + newXSproto(strcpy(buf, "IsEliteMaterialItem"), XS_Mob_IsEliteMaterialItem, file, "$$"); + newXSproto(strcpy(buf, "GetBaseSize"), XS_Mob_GetBaseSize, file, "$"); + newXSproto(strcpy(buf, "HasOwner"), XS_Mob_HasOwner, file, "$"); + newXSproto(strcpy(buf, "IsPet"), XS_Mob_IsPet, file, "$"); + newXSproto(strcpy(buf, "HasPet"), XS_Mob_HasPet, file, "$"); + newXSproto(strcpy(buf, "IsSilenced"), XS_Mob_IsSilenced, file, "$"); + newXSproto(strcpy(buf, "IsAmnesiad"), XS_Mob_IsAmnesiad, file, "$"); XSRETURN_YES; } From 8133f5312f9ef8980ca33b8f12a6beb602338f86 Mon Sep 17 00:00:00 2001 From: Natedog2012 Date: Mon, 21 Dec 2015 05:27:20 -0800 Subject: [PATCH 11/40] First step into implementing evolving items, added fields to database that were missing. --- changelog.txt | 7 +++++++ common/item_fieldlist.h | 4 ++++ common/item_struct.h | 4 ++++ common/patches/rof.cpp | 10 +++++----- common/patches/rof2.cpp | 10 +++++----- common/patches/uf.cpp | 10 +++++----- common/patches/uf_structs.h | 2 +- common/shareddb.cpp | 5 ++++- common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + .../git/required/2015_12_21_items_updates_evoitem.sql | 8 ++++++++ 11 files changed, 45 insertions(+), 18 deletions(-) create mode 100644 utils/sql/git/required/2015_12_21_items_updates_evoitem.sql diff --git a/changelog.txt b/changelog.txt index c64baec6c..2ce2a68ad 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,12 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 12/21/2015 == +Natedog: Updated item table fields and added a few missing fields for evolving items + -DO NOT implement Heirloom items till the inventory code is fixed to allow placing NO DROP + items in your shared bank. (but item field located on items table) + -NYI - SkillModMax: Max skill point modification from the percent mods. EX: + 100% 2HSlashing (Max 50) - can only increase 2hslash by 50 MAX! (item field located though) + == 12/19/2015 == Kinglykrab: Added many methods to Perl and Lua, list below: - SeeInvisible() diff --git a/common/item_fieldlist.h b/common/item_fieldlist.h index 1b3fe0cb0..665783498 100644 --- a/common/item_fieldlist.h +++ b/common/item_fieldlist.h @@ -41,6 +41,7 @@ F(ac) F(deity) F(skillmodvalue) F(UNK033) +F(skillmodmax) F(skillmodtype) F(banedmgrace) F(banedmgamt) @@ -172,7 +173,10 @@ F(bardlevel) F(questitemflag) F(svcorruption) F(purity) +F(evoitem) +F(evoid) F(evolvinglevel) +F(evomax) F(backstabdmg) F(dsmitigation) F(heroic_str) diff --git a/common/item_struct.h b/common/item_struct.h index 64292f490..ba8afcd14 100644 --- a/common/item_struct.h +++ b/common/item_struct.h @@ -130,6 +130,7 @@ struct Item_Struct { uint32 Deity; // Bitmask of Deities that can equip this item //uint32 Unk033 int32 SkillModValue; // % Mod to skill specified in SkillModType + int32 SkillModMax; // Max skill point modification uint32 SkillModType; // Type of skill for SkillModValue to apply to uint32 BaneDmgRace; // Bane Damage Race int8 BaneDmgAmt; // Bane Damage Body Amount @@ -218,7 +219,10 @@ struct Item_Struct { // Begin SoF Fields int32 SVCorruption; uint32 Purity; + uint8 EvolvingItem; + uint32 EvolvingID; uint8 EvolvingLevel; + uint8 EvolvingMax; uint32 BackstabDmg; uint32 DSMitigation; int32 HeroicStr; diff --git a/common/patches/rof.cpp b/common/patches/rof.cpp index 79c7271fd..76d62e3a4 100644 --- a/common/patches/rof.cpp +++ b/common/patches/rof.cpp @@ -5231,19 +5231,19 @@ namespace RoF hdr.unknown044 = 0; hdr.unknown048 = 0; hdr.unknown052 = 0; - hdr.isEvolving = item->EvolvingLevel > 0 ? 1 : 0; + hdr.isEvolving = item->EvolvingItem; ss.write((const char*)&hdr, sizeof(RoF::structs::ItemSerializationHeader)); - if (item->EvolvingLevel > 0) { + if (item->EvolvingItem > 0) { RoF::structs::EvolvingItem evotop; evotop.unknown001 = 0; evotop.unknown002 = 0; evotop.unknown003 = 0; evotop.unknown004 = 0; evotop.evoLevel = item->EvolvingLevel; - evotop.progress = 95.512; + evotop.progress = 0; evotop.Activated = 1; - evotop.evomaxlevel = 7; + evotop.evomaxlevel = item->EvolvingMax; ss.write((const char*)&evotop, sizeof(RoF::structs::EvolvingItem)); } //ORNAMENT IDFILE / ICON @@ -5353,7 +5353,7 @@ namespace RoF ibs.Races = item->Races; ibs.Deity = item->Deity; ibs.SkillModValue = item->SkillModValue; - ibs.SkillModMax = 0xffffffff; + ibs.SkillModMax = item->SkillModMax; ibs.SkillModType = (int8)(item->SkillModType); ibs.SkillModExtra = 0; ibs.BaneDmgRace = item->BaneDmgRace; diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index e5cc77791..a8b231300 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -5432,19 +5432,19 @@ namespace RoF2 hdr.unknown044 = 0; hdr.unknown048 = 0; hdr.unknown052 = 0; - hdr.isEvolving = item->EvolvingLevel > 0 ? 1 : 0; + hdr.isEvolving = item->EvolvingItem; ss.write((const char*)&hdr, sizeof(RoF2::structs::ItemSerializationHeader)); - if (item->EvolvingLevel > 0) { + if (item->EvolvingItem > 0) { RoF2::structs::EvolvingItem evotop; evotop.unknown001 = 0; evotop.unknown002 = 0; evotop.unknown003 = 0; evotop.unknown004 = 0; evotop.evoLevel = item->EvolvingLevel; - evotop.progress = 95.512; + evotop.progress = 0; evotop.Activated = 1; - evotop.evomaxlevel = 7; + evotop.evomaxlevel = item->EvolvingMax; ss.write((const char*)&evotop, sizeof(RoF2::structs::EvolvingItem)); } //ORNAMENT IDFILE / ICON @@ -5554,7 +5554,7 @@ namespace RoF2 ibs.Races = item->Races; ibs.Deity = item->Deity; ibs.SkillModValue = item->SkillModValue; - ibs.SkillModMax = 0xffffffff; + ibs.SkillModMax = item->SkillModMax; ibs.SkillModType = (int8)(item->SkillModType); ibs.SkillModExtra = 0; ibs.BaneDmgRace = item->BaneDmgRace; diff --git a/common/patches/uf.cpp b/common/patches/uf.cpp index 0e88a2a09..3535503a0 100644 --- a/common/patches/uf.cpp +++ b/common/patches/uf.cpp @@ -3835,19 +3835,19 @@ namespace UF hdr.unknown044 = 0; hdr.unknown048 = 0; hdr.unknown052 = 0; - hdr.isEvolving = item->EvolvingLevel > 0 ? 1 : 0; + hdr.isEvolving = item->EvolvingItem; ss.write((const char*)&hdr, sizeof(UF::structs::ItemSerializationHeader)); - if (item->EvolvingLevel > 0) { + if (item->EvolvingItem > 0) { UF::structs::EvolvingItem evotop; evotop.unknown001 = 0; evotop.unknown002 = 0; evotop.unknown003 = 0; evotop.unknown004 = 0; evotop.evoLevel = item->EvolvingLevel; - evotop.progress = 95.512; + evotop.progress = 0; evotop.Activated = 1; - evotop.evomaxlevel = 7; + evotop.evomaxlevel = item->EvolvingMax; ss.write((const char*)&evotop, sizeof(UF::structs::EvolvingItem)); } //ORNAMENT IDFILE / ICON - @@ -3947,7 +3947,7 @@ namespace UF ibs.Races = item->Races; ibs.Deity = item->Deity; ibs.SkillModValue = item->SkillModValue; - ibs.unknown5 = 0; + ibs.SkillModMax = item->SkillModMax; ibs.SkillModType = item->SkillModType; ibs.BaneDmgRace = item->BaneDmgRace; ibs.BaneDmgBody = item->BaneDmgBody; diff --git a/common/patches/uf_structs.h b/common/patches/uf_structs.h index 3631edea3..7f3a7dcc0 100644 --- a/common/patches/uf_structs.h +++ b/common/patches/uf_structs.h @@ -4103,7 +4103,7 @@ struct ItemBodyStruct uint32 Races; uint32 Deity; int32 SkillModValue; - uint32 unknown5; + uint32 SkillModMax; uint32 SkillModType; uint32 BaneDmgRace; uint32 BaneDmgBody; diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 59a2a118b..751093eaf 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -878,7 +878,7 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_ item.AC = (int32)atoul(row[ItemField::ac]); item.Deity = (uint32)atoul(row[ItemField::deity]); item.SkillModValue = (int32)atoul(row[ItemField::skillmodvalue]); - + item.SkillModMax = (int32)atoul(row[ItemField::skillmodmax]); item.SkillModType = (uint32)atoul(row[ItemField::skillmodtype]); item.BaneDmgRace = (uint32)atoul(row[ItemField::banedmgrace]); item.BaneDmgAmt = (int8)atoi(row[ItemField::banedmgamt]); @@ -1020,7 +1020,10 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_ item.QuestItemFlag = (atoi(row[ItemField::questitemflag])==0) ? false : true; item.SVCorruption = (int32)atoi(row[ItemField::svcorruption]); item.Purity = (uint32)atoul(row[ItemField::purity]); + item.EvolvingItem = (uint8)atoul(row[ItemField::evoitem]); + item.EvolvingID = (uint8)atoul(row[ItemField::evoid]); item.EvolvingLevel = (uint8)atoul(row[ItemField::evolvinglevel]); + item.EvolvingMax = (uint8)atoul(row[ItemField::evomax]); item.BackstabDmg = (uint32)atoul(row[ItemField::backstabdmg]); item.DSMitigation = (uint32)atoul(row[ItemField::dsmitigation]); item.HeroicStr = (int32)atoi(row[ItemField::heroic_str]); diff --git a/common/version.h b/common/version.h index c3dfa1c26..b2dd26212 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9092 +#define CURRENT_BINARY_DATABASE_VERSION 9093 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9000 #else diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index adc9009c2..db4078eb5 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -346,6 +346,7 @@ 9090|2015_12_01_spell_scribe_restriction_rule.sql|SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Character:RestrictSpellScribing'|empty| 9091|2015_12_07_command_settings.sql|SHOW TABLES LIKE 'command_settings'|empty| 9092|2015_12_17_eqtime.sql|SHOW TABLES LIKE 'eqtime'|empty| +9093|2015_12_21_items_updates_evoitem.sql|SHOW COLUMNS FROM `items` LIKE 'evoitem'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2015_12_21_items_updates_evoitem.sql b/utils/sql/git/required/2015_12_21_items_updates_evoitem.sql new file mode 100644 index 000000000..195df8a87 --- /dev/null +++ b/utils/sql/git/required/2015_12_21_items_updates_evoitem.sql @@ -0,0 +1,8 @@ +ALTER TABLE `items` + ADD COLUMN `evoitem` INT(11) NOT NULL DEFAULT '0' AFTER `purity`, + ADD COLUMN `evoid` INT(11) NOT NULL DEFAULT '0' AFTER `evoitem`, + ADD COLUMN `evomax` INT(11) NOT NULL DEFAULT '0' AFTER `evolvinglevel`, + CHANGE `UNK038` `skillmodmax` INT(11) NOT NULL DEFAULT '0', + CHANGE `UNK222` `heirloom` INT(11) NOT NULL DEFAULT '0', + CHANGE `UNK235` `placeable` INT(11) NOT NULL DEFAULT '0', + CHANGE `UNK242` `epicitem` INT(11) NOT NULL DEFAULT '0'; \ No newline at end of file From fc33a10ec07e5db61aa366e54c0d5ec2a6526e73 Mon Sep 17 00:00:00 2001 From: Natedog2012 Date: Mon, 21 Dec 2015 07:36:14 -0800 Subject: [PATCH 12/40] Change GetSkill to use SkillModMax for clients --- zone/bonuses.cpp | 1 + zone/client.h | 2 +- zone/common.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/zone/bonuses.cpp b/zone/bonuses.cpp index 3aa9cc4a1..f8edee26d 100644 --- a/zone/bonuses.cpp +++ b/zone/bonuses.cpp @@ -490,6 +490,7 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu (item->SkillModValue < 0 && newbon->skillmod[item->SkillModType] > item->SkillModValue)) { newbon->skillmod[item->SkillModType] = item->SkillModValue; + newbon->skillmodmax[item->SkillModType] = item->SkillModMax; } } diff --git a/zone/client.h b/zone/client.h index b5d3728e1..6db22c5b0 100644 --- a/zone/client.h +++ b/zone/client.h @@ -679,7 +679,7 @@ public: void IncreaseSkill(int skill_id, int value = 1) { if (skill_id <= HIGHEST_SKILL) { m_pp.skills[skill_id] += value; } } void IncreaseLanguageSkill(int skill_id, int value = 1); - virtual uint16 GetSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return((itembonuses.skillmod[skill_id] > 0) ? m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100 : m_pp.skills[skill_id]); } return 0; } + virtual uint16 GetSkill(SkillUseTypes skill_id) const {if (skill_id <= HIGHEST_SKILL) {return(itembonuses.skillmod[skill_id] > 0 ? (itembonuses.skillmodmax[skill_id] > 0 ? std::min(m_pp.skills[skill_id] + itembonuses.skillmodmax[skill_id], m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100) : m_pp.skills[skill_id] * (100 + itembonuses.skillmod[skill_id]) / 100) : m_pp.skills[skill_id]);} return 0;} uint32 GetRawSkill(SkillUseTypes skill_id) const { if (skill_id <= HIGHEST_SKILL) { return(m_pp.skills[skill_id]); } return 0; } bool HasSkill(SkillUseTypes skill_id) const; bool CanHaveSkill(SkillUseTypes skill_id) const; diff --git a/zone/common.h b/zone/common.h index a637e94bd..48749dbc3 100644 --- a/zone/common.h +++ b/zone/common.h @@ -278,6 +278,7 @@ struct StatBonuses { float AggroRange; // when calculate just replace original value with this float AssistRange; int32 skillmod[HIGHEST_SKILL+1]; + int32 skillmodmax[HIGHEST_SKILL+1]; int effective_casting_level; int reflect_chance; // chance to reflect incoming spell uint32 singingMod; From 7ad33f2445faa8cab9c08b8a4b9c52b3e7015e5c Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Mon, 21 Dec 2015 12:33:32 -0500 Subject: [PATCH 13/40] Fix formatting --- common/shareddb.cpp | 422 ++++++++++++++++++++++---------------------- 1 file changed, 211 insertions(+), 211 deletions(-) diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 751093eaf..129584159 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -802,264 +802,264 @@ bool SharedDatabase::LoadItems(const std::string &prefix) { return true; } -void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_item_id) { - EQEmu::FixedMemoryHashSet hash(reinterpret_cast(data), size, items, max_item_id); +void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_item_id) +{ + EQEmu::FixedMemoryHashSet hash(reinterpret_cast(data), size, items, max_item_id); char ndbuffer[4]; bool disableNoRent = false; - if(GetVariable("disablenorent", ndbuffer, 4)) { - if(ndbuffer[0] == '1' && ndbuffer[1] == '\0') { + if (GetVariable("disablenorent", ndbuffer, 4)) { + if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') { disableNoRent = true; } } bool disableNoDrop = false; - if(GetVariable("disablenodrop", ndbuffer, 4)) { - if(ndbuffer[0] == '1' && ndbuffer[1] == '\0') { + if (GetVariable("disablenodrop", ndbuffer, 4)) { + if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') { disableNoDrop = true; } } bool disableLoreGroup = false; - if(GetVariable("disablelore", ndbuffer, 4)) { - if(ndbuffer[0] == '1' && ndbuffer[1] == '\0') { + if (GetVariable("disablelore", ndbuffer, 4)) { + if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') { disableLoreGroup = true; } } bool disableNoTransfer = false; - if(GetVariable("disablenotransfer", ndbuffer, 4)) { - if(ndbuffer[0] == '1' && ndbuffer[1] == '\0') { + if (GetVariable("disablenotransfer", ndbuffer, 4)) { + if (ndbuffer[0] == '1' && ndbuffer[1] == '\0') { disableNoTransfer = true; } } - Item_Struct item; + Item_Struct item; const std::string query = "SELECT source," -#define F(x) "`"#x"`," +#define F(x) "`" #x "`," #include "item_fieldlist.h" #undef F "updated FROM items ORDER BY id"; auto results = QueryDatabase(query); - if (!results.Success()) { - return; - } + if (!results.Success()) { + return; + } - for(auto row = results.begin(); row != results.end(); ++row) { - memset(&item, 0, sizeof(Item_Struct)); + for (auto row = results.begin(); row != results.end(); ++row) { + memset(&item, 0, sizeof(Item_Struct)); - item.ItemClass = (uint8)atoi(row[ItemField::itemclass]); - strcpy(item.Name,row[ItemField::name]); - strcpy(item.Lore,row[ItemField::lore]); - strcpy(item.IDFile,row[ItemField::idfile]); + item.ItemClass = (uint8)atoi(row[ItemField::itemclass]); + strcpy(item.Name, row[ItemField::name]); + strcpy(item.Lore, row[ItemField::lore]); + strcpy(item.IDFile, row[ItemField::idfile]); - item.ID = (uint32)atoul(row[ItemField::id]); - item.Weight = (uint8)atoi(row[ItemField::weight]); - item.NoRent = disableNoRent ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::norent]); - item.NoDrop = disableNoDrop ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::nodrop]); - item.Size = (uint8)atoi(row[ItemField::size]); - item.Slots = (uint32)atoul(row[ItemField::slots]); - item.Price = (uint32)atoul(row[ItemField::price]); - item.Icon = (uint32)atoul(row[ItemField::icon]); - item.BenefitFlag = (atoul(row[ItemField::benefitflag]) != 0); - item.Tradeskills = (atoi(row[ItemField::tradeskills])==0) ? false : true; - item.CR = (int8)atoi(row[ItemField::cr]); - item.DR = (int8)atoi(row[ItemField::dr]); - item.PR = (int8)atoi(row[ItemField::pr]); - item.MR = (int8)atoi(row[ItemField::mr]); - item.FR = (int8)atoi(row[ItemField::fr]); - item.AStr = (int8)atoi(row[ItemField::astr]); - item.ASta = (int8)atoi(row[ItemField::asta]); - item.AAgi = (int8)atoi(row[ItemField::aagi]); - item.ADex = (int8)atoi(row[ItemField::adex]); - item.ACha = (int8)atoi(row[ItemField::acha]); - item.AInt = (int8)atoi(row[ItemField::aint]); - item.AWis = (int8)atoi(row[ItemField::awis]); - item.HP = (int32)atoul(row[ItemField::hp]); - item.Mana = (int32)atoul(row[ItemField::mana]); - item.AC = (int32)atoul(row[ItemField::ac]); - item.Deity = (uint32)atoul(row[ItemField::deity]); - item.SkillModValue = (int32)atoul(row[ItemField::skillmodvalue]); + item.ID = (uint32)atoul(row[ItemField::id]); + item.Weight = (uint8)atoi(row[ItemField::weight]); + item.NoRent = disableNoRent ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::norent]); + item.NoDrop = disableNoDrop ? (uint8)atoi("255") : (uint8)atoi(row[ItemField::nodrop]); + item.Size = (uint8)atoi(row[ItemField::size]); + item.Slots = (uint32)atoul(row[ItemField::slots]); + item.Price = (uint32)atoul(row[ItemField::price]); + item.Icon = (uint32)atoul(row[ItemField::icon]); + item.BenefitFlag = (atoul(row[ItemField::benefitflag]) != 0); + item.Tradeskills = (atoi(row[ItemField::tradeskills]) == 0) ? false : true; + item.CR = (int8)atoi(row[ItemField::cr]); + item.DR = (int8)atoi(row[ItemField::dr]); + item.PR = (int8)atoi(row[ItemField::pr]); + item.MR = (int8)atoi(row[ItemField::mr]); + item.FR = (int8)atoi(row[ItemField::fr]); + item.AStr = (int8)atoi(row[ItemField::astr]); + item.ASta = (int8)atoi(row[ItemField::asta]); + item.AAgi = (int8)atoi(row[ItemField::aagi]); + item.ADex = (int8)atoi(row[ItemField::adex]); + item.ACha = (int8)atoi(row[ItemField::acha]); + item.AInt = (int8)atoi(row[ItemField::aint]); + item.AWis = (int8)atoi(row[ItemField::awis]); + item.HP = (int32)atoul(row[ItemField::hp]); + item.Mana = (int32)atoul(row[ItemField::mana]); + item.AC = (int32)atoul(row[ItemField::ac]); + item.Deity = (uint32)atoul(row[ItemField::deity]); + item.SkillModValue = (int32)atoul(row[ItemField::skillmodvalue]); item.SkillModMax = (int32)atoul(row[ItemField::skillmodmax]); - item.SkillModType = (uint32)atoul(row[ItemField::skillmodtype]); - item.BaneDmgRace = (uint32)atoul(row[ItemField::banedmgrace]); - item.BaneDmgAmt = (int8)atoi(row[ItemField::banedmgamt]); - item.BaneDmgBody = (uint32)atoul(row[ItemField::banedmgbody]); - item.Magic = (atoi(row[ItemField::magic])==0) ? false : true; - item.CastTime_ = (int32)atoul(row[ItemField::casttime_]); - item.ReqLevel = (uint8)atoi(row[ItemField::reqlevel]); - item.BardType = (uint32)atoul(row[ItemField::bardtype]); - item.BardValue = (int32)atoul(row[ItemField::bardvalue]); - item.Light = (int8)atoi(row[ItemField::light]); - item.Delay = (uint8)atoi(row[ItemField::delay]); - item.RecLevel = (uint8)atoi(row[ItemField::reclevel]); - item.RecSkill = (uint8)atoi(row[ItemField::recskill]); - item.ElemDmgType = (uint8)atoi(row[ItemField::elemdmgtype]); - item.ElemDmgAmt = (uint8)atoi(row[ItemField::elemdmgamt]); - item.Range = (uint8)atoi(row[ItemField::range]); - item.Damage = (uint32)atoi(row[ItemField::damage]); - item.Color = (uint32)atoul(row[ItemField::color]); - item.Classes = (uint32)atoul(row[ItemField::classes]); - item.Races = (uint32)atoul(row[ItemField::races]); + item.SkillModType = (uint32)atoul(row[ItemField::skillmodtype]); + item.BaneDmgRace = (uint32)atoul(row[ItemField::banedmgrace]); + item.BaneDmgAmt = (int8)atoi(row[ItemField::banedmgamt]); + item.BaneDmgBody = (uint32)atoul(row[ItemField::banedmgbody]); + item.Magic = (atoi(row[ItemField::magic]) == 0) ? false : true; + item.CastTime_ = (int32)atoul(row[ItemField::casttime_]); + item.ReqLevel = (uint8)atoi(row[ItemField::reqlevel]); + item.BardType = (uint32)atoul(row[ItemField::bardtype]); + item.BardValue = (int32)atoul(row[ItemField::bardvalue]); + item.Light = (int8)atoi(row[ItemField::light]); + item.Delay = (uint8)atoi(row[ItemField::delay]); + item.RecLevel = (uint8)atoi(row[ItemField::reclevel]); + item.RecSkill = (uint8)atoi(row[ItemField::recskill]); + item.ElemDmgType = (uint8)atoi(row[ItemField::elemdmgtype]); + item.ElemDmgAmt = (uint8)atoi(row[ItemField::elemdmgamt]); + item.Range = (uint8)atoi(row[ItemField::range]); + item.Damage = (uint32)atoi(row[ItemField::damage]); + item.Color = (uint32)atoul(row[ItemField::color]); + item.Classes = (uint32)atoul(row[ItemField::classes]); + item.Races = (uint32)atoul(row[ItemField::races]); - item.MaxCharges = (int16)atoi(row[ItemField::maxcharges]); - item.ItemType = (uint8)atoi(row[ItemField::itemtype]); + item.MaxCharges = (int16)atoi(row[ItemField::maxcharges]); + item.ItemType = (uint8)atoi(row[ItemField::itemtype]); item.Material = (uint8)atoi(row[ItemField::material]); item.HerosForgeModel = (uint32)atoi(row[ItemField::herosforgemodel]); - item.SellRate = (float)atof(row[ItemField::sellrate]); - item.CastTime = (uint32)atoul(row[ItemField::casttime]); - item.EliteMaterial = (uint32)atoul(row[ItemField::elitematerial]); - item.ProcRate = (int32)atoi(row[ItemField::procrate]); - item.CombatEffects = (int8)atoi(row[ItemField::combateffects]); - item.Shielding = (int8)atoi(row[ItemField::shielding]); - item.StunResist = (int8)atoi(row[ItemField::stunresist]); - item.StrikeThrough = (int8)atoi(row[ItemField::strikethrough]); - item.ExtraDmgSkill = (uint32)atoul(row[ItemField::extradmgskill]); - item.ExtraDmgAmt = (uint32)atoul(row[ItemField::extradmgamt]); - item.SpellShield = (int8)atoi(row[ItemField::spellshield]); - item.Avoidance = (int8)atoi(row[ItemField::avoidance]); - item.Accuracy = (int8)atoi(row[ItemField::accuracy]); - item.CharmFileID = (uint32)atoul(row[ItemField::charmfileid]); - item.FactionMod1 = (int32)atoul(row[ItemField::factionmod1]); - item.FactionMod2 = (int32)atoul(row[ItemField::factionmod2]); - item.FactionMod3 = (int32)atoul(row[ItemField::factionmod3]); - item.FactionMod4 = (int32)atoul(row[ItemField::factionmod4]); - item.FactionAmt1 = (int32)atoul(row[ItemField::factionamt1]); - item.FactionAmt2 = (int32)atoul(row[ItemField::factionamt2]); - item.FactionAmt3 = (int32)atoul(row[ItemField::factionamt3]); - item.FactionAmt4 = (int32)atoul(row[ItemField::factionamt4]); + item.SellRate = (float)atof(row[ItemField::sellrate]); + item.CastTime = (uint32)atoul(row[ItemField::casttime]); + item.EliteMaterial = (uint32)atoul(row[ItemField::elitematerial]); + item.ProcRate = (int32)atoi(row[ItemField::procrate]); + item.CombatEffects = (int8)atoi(row[ItemField::combateffects]); + item.Shielding = (int8)atoi(row[ItemField::shielding]); + item.StunResist = (int8)atoi(row[ItemField::stunresist]); + item.StrikeThrough = (int8)atoi(row[ItemField::strikethrough]); + item.ExtraDmgSkill = (uint32)atoul(row[ItemField::extradmgskill]); + item.ExtraDmgAmt = (uint32)atoul(row[ItemField::extradmgamt]); + item.SpellShield = (int8)atoi(row[ItemField::spellshield]); + item.Avoidance = (int8)atoi(row[ItemField::avoidance]); + item.Accuracy = (int8)atoi(row[ItemField::accuracy]); + item.CharmFileID = (uint32)atoul(row[ItemField::charmfileid]); + item.FactionMod1 = (int32)atoul(row[ItemField::factionmod1]); + item.FactionMod2 = (int32)atoul(row[ItemField::factionmod2]); + item.FactionMod3 = (int32)atoul(row[ItemField::factionmod3]); + item.FactionMod4 = (int32)atoul(row[ItemField::factionmod4]); + item.FactionAmt1 = (int32)atoul(row[ItemField::factionamt1]); + item.FactionAmt2 = (int32)atoul(row[ItemField::factionamt2]); + item.FactionAmt3 = (int32)atoul(row[ItemField::factionamt3]); + item.FactionAmt4 = (int32)atoul(row[ItemField::factionamt4]); - strcpy(item.CharmFile,row[ItemField::charmfile]); + strcpy(item.CharmFile, row[ItemField::charmfile]); - item.AugType = (uint32)atoul(row[ItemField::augtype]); - item.AugSlotType[0] = (uint8)atoi(row[ItemField::augslot1type]); - item.AugSlotVisible[0] = (uint8)atoi(row[ItemField::augslot1visible]); - item.AugSlotUnk2[0] = 0; - item.AugSlotType[1] = (uint8)atoi(row[ItemField::augslot2type]); - item.AugSlotVisible[1] = (uint8)atoi(row[ItemField::augslot2visible]); - item.AugSlotUnk2[1] = 0; - item.AugSlotType[2] = (uint8)atoi(row[ItemField::augslot3type]); - item.AugSlotVisible[2] = (uint8)atoi(row[ItemField::augslot3visible]); - item.AugSlotUnk2[2] = 0; - item.AugSlotType[3] = (uint8)atoi(row[ItemField::augslot4type]); - item.AugSlotVisible[3] = (uint8)atoi(row[ItemField::augslot4visible]); - item.AugSlotUnk2[3] = 0; - item.AugSlotType[4] = (uint8)atoi(row[ItemField::augslot5type]); - item.AugSlotVisible[4] = (uint8)atoi(row[ItemField::augslot5visible]); - item.AugSlotUnk2[4] = 0; + item.AugType = (uint32)atoul(row[ItemField::augtype]); + item.AugSlotType[0] = (uint8)atoi(row[ItemField::augslot1type]); + item.AugSlotVisible[0] = (uint8)atoi(row[ItemField::augslot1visible]); + item.AugSlotUnk2[0] = 0; + item.AugSlotType[1] = (uint8)atoi(row[ItemField::augslot2type]); + item.AugSlotVisible[1] = (uint8)atoi(row[ItemField::augslot2visible]); + item.AugSlotUnk2[1] = 0; + item.AugSlotType[2] = (uint8)atoi(row[ItemField::augslot3type]); + item.AugSlotVisible[2] = (uint8)atoi(row[ItemField::augslot3visible]); + item.AugSlotUnk2[2] = 0; + item.AugSlotType[3] = (uint8)atoi(row[ItemField::augslot4type]); + item.AugSlotVisible[3] = (uint8)atoi(row[ItemField::augslot4visible]); + item.AugSlotUnk2[3] = 0; + item.AugSlotType[4] = (uint8)atoi(row[ItemField::augslot5type]); + item.AugSlotVisible[4] = (uint8)atoi(row[ItemField::augslot5visible]); + item.AugSlotUnk2[4] = 0; item.AugSlotType[5] = (uint8)atoi(row[ItemField::augslot6type]); item.AugSlotVisible[5] = (uint8)atoi(row[ItemField::augslot6visible]); item.AugSlotUnk2[5] = 0; - item.LDoNTheme = (uint32)atoul(row[ItemField::ldontheme]); - item.LDoNPrice = (uint32)atoul(row[ItemField::ldonprice]); - item.LDoNSold = (uint32)atoul(row[ItemField::ldonsold]); - item.BagType = (uint8)atoi(row[ItemField::bagtype]); - item.BagSlots = (uint8)atoi(row[ItemField::bagslots]); - item.BagSize = (uint8)atoi(row[ItemField::bagsize]); - item.BagWR = (uint8)atoi(row[ItemField::bagwr]); - item.Book = (uint8)atoi(row[ItemField::book]); - item.BookType = (uint32)atoul(row[ItemField::booktype]); + item.LDoNTheme = (uint32)atoul(row[ItemField::ldontheme]); + item.LDoNPrice = (uint32)atoul(row[ItemField::ldonprice]); + item.LDoNSold = (uint32)atoul(row[ItemField::ldonsold]); + item.BagType = (uint8)atoi(row[ItemField::bagtype]); + item.BagSlots = (uint8)atoi(row[ItemField::bagslots]); + item.BagSize = (uint8)atoi(row[ItemField::bagsize]); + item.BagWR = (uint8)atoi(row[ItemField::bagwr]); + item.Book = (uint8)atoi(row[ItemField::book]); + item.BookType = (uint32)atoul(row[ItemField::booktype]); - strcpy(item.Filename,row[ItemField::filename]); + strcpy(item.Filename, row[ItemField::filename]); - item.BaneDmgRaceAmt = (uint32)atoul(row[ItemField::banedmgraceamt]); - item.AugRestrict = (uint32)atoul(row[ItemField::augrestrict]); - item.LoreGroup = disableLoreGroup ? (uint8)atoi("0") : atoi(row[ItemField::loregroup]); - item.LoreFlag = item.LoreGroup!=0; - item.PendingLoreFlag = (atoi(row[ItemField::pendingloreflag])==0) ? false : true; - item.ArtifactFlag = (atoi(row[ItemField::artifactflag])==0) ? false : true; - item.SummonedFlag = (atoi(row[ItemField::summonedflag])==0) ? false : true; - item.Favor = (uint32)atoul(row[ItemField::favor]); - item.FVNoDrop = (atoi(row[ItemField::fvnodrop])==0) ? false : true; - item.Endur = (uint32)atoul(row[ItemField::endur]); - item.DotShielding = (uint32)atoul(row[ItemField::dotshielding]); - item.Attack = (uint32)atoul(row[ItemField::attack]); - item.Regen = (uint32)atoul(row[ItemField::regen]); - item.ManaRegen = (uint32)atoul(row[ItemField::manaregen]); - item.EnduranceRegen = (uint32)atoul(row[ItemField::enduranceregen]); - item.Haste = (uint32)atoul(row[ItemField::haste]); - item.DamageShield = (uint32)atoul(row[ItemField::damageshield]); - item.RecastDelay = (uint32)atoul(row[ItemField::recastdelay]); - item.RecastType = (uint32)atoul(row[ItemField::recasttype]); - item.GuildFavor = (uint32)atoul(row[ItemField::guildfavor]); - item.AugDistiller = (uint32)atoul(row[ItemField::augdistiller]); - item.Attuneable = (atoi(row[ItemField::attuneable])==0) ? false : true; - item.NoPet = (atoi(row[ItemField::nopet])==0) ? false : true; - item.PointType = (uint32)atoul(row[ItemField::pointtype]); - item.PotionBelt = (atoi(row[ItemField::potionbelt])==0) ? false : true; - item.PotionBeltSlots = (atoi(row[ItemField::potionbeltslots])==0) ? false : true; - item.StackSize = (uint16)atoi(row[ItemField::stacksize]); - item.NoTransfer = disableNoTransfer ? false : (atoi(row[ItemField::notransfer])==0) ? false : true; - item.Stackable = (atoi(row[ItemField::stackable])==0) ? false : true; - item.Click.Effect = (uint32)atoul(row[ItemField::clickeffect]); - item.Click.Type = (uint8)atoul(row[ItemField::clicktype]); - item.Click.Level = (uint8)atoul(row[ItemField::clicklevel]); - item.Click.Level2 = (uint8)atoul(row[ItemField::clicklevel2]); + item.BaneDmgRaceAmt = (uint32)atoul(row[ItemField::banedmgraceamt]); + item.AugRestrict = (uint32)atoul(row[ItemField::augrestrict]); + item.LoreGroup = disableLoreGroup ? (uint8)atoi("0") : atoi(row[ItemField::loregroup]); + item.LoreFlag = item.LoreGroup != 0; + item.PendingLoreFlag = (atoi(row[ItemField::pendingloreflag]) == 0) ? false : true; + item.ArtifactFlag = (atoi(row[ItemField::artifactflag]) == 0) ? false : true; + item.SummonedFlag = (atoi(row[ItemField::summonedflag]) == 0) ? false : true; + item.Favor = (uint32)atoul(row[ItemField::favor]); + item.FVNoDrop = (atoi(row[ItemField::fvnodrop]) == 0) ? false : true; + item.Endur = (uint32)atoul(row[ItemField::endur]); + item.DotShielding = (uint32)atoul(row[ItemField::dotshielding]); + item.Attack = (uint32)atoul(row[ItemField::attack]); + item.Regen = (uint32)atoul(row[ItemField::regen]); + item.ManaRegen = (uint32)atoul(row[ItemField::manaregen]); + item.EnduranceRegen = (uint32)atoul(row[ItemField::enduranceregen]); + item.Haste = (uint32)atoul(row[ItemField::haste]); + item.DamageShield = (uint32)atoul(row[ItemField::damageshield]); + item.RecastDelay = (uint32)atoul(row[ItemField::recastdelay]); + item.RecastType = (uint32)atoul(row[ItemField::recasttype]); + item.GuildFavor = (uint32)atoul(row[ItemField::guildfavor]); + item.AugDistiller = (uint32)atoul(row[ItemField::augdistiller]); + item.Attuneable = (atoi(row[ItemField::attuneable]) == 0) ? false : true; + item.NoPet = (atoi(row[ItemField::nopet]) == 0) ? false : true; + item.PointType = (uint32)atoul(row[ItemField::pointtype]); + item.PotionBelt = (atoi(row[ItemField::potionbelt]) == 0) ? false : true; + item.PotionBeltSlots = (atoi(row[ItemField::potionbeltslots]) == 0) ? false : true; + item.StackSize = (uint16)atoi(row[ItemField::stacksize]); + item.NoTransfer = disableNoTransfer ? false : (atoi(row[ItemField::notransfer]) == 0) ? false : true; + item.Stackable = (atoi(row[ItemField::stackable]) == 0) ? false : true; + item.Click.Effect = (uint32)atoul(row[ItemField::clickeffect]); + item.Click.Type = (uint8)atoul(row[ItemField::clicktype]); + item.Click.Level = (uint8)atoul(row[ItemField::clicklevel]); + item.Click.Level2 = (uint8)atoul(row[ItemField::clicklevel2]); - strcpy(item.CharmFile,row[ItemField::charmfile]); + strcpy(item.CharmFile, row[ItemField::charmfile]); - item.Proc.Effect = (int32)atoul(row[ItemField::proceffect]); - item.Proc.Type = (uint8)atoul(row[ItemField::proctype]); - item.Proc.Level = (uint8)atoul(row[ItemField::proclevel]); - item.Proc.Level2 = (uint8)atoul(row[ItemField::proclevel2]); - item.Worn.Effect = (int32)atoul(row[ItemField::worneffect]); - item.Worn.Type = (uint8)atoul(row[ItemField::worntype]); - item.Worn.Level = (uint8)atoul(row[ItemField::wornlevel]); - item.Worn.Level2 = (uint8)atoul(row[ItemField::wornlevel2]); - item.Focus.Effect = (int32)atoul(row[ItemField::focuseffect]); - item.Focus.Type = (uint8)atoul(row[ItemField::focustype]); - item.Focus.Level = (uint8)atoul(row[ItemField::focuslevel]); - item.Focus.Level2 = (uint8)atoul(row[ItemField::focuslevel2]); - item.Scroll.Effect = (int32)atoul(row[ItemField::scrolleffect]); - item.Scroll.Type = (uint8)atoul(row[ItemField::scrolltype]); - item.Scroll.Level = (uint8)atoul(row[ItemField::scrolllevel]); - item.Scroll.Level2 = (uint8)atoul(row[ItemField::scrolllevel2]); - item.Bard.Effect = (int32)atoul(row[ItemField::bardeffect]); - item.Bard.Type = (uint8)atoul(row[ItemField::bardtype]); - item.Bard.Level = (uint8)atoul(row[ItemField::bardlevel]); - item.Bard.Level2 = (uint8)atoul(row[ItemField::bardlevel2]); - item.QuestItemFlag = (atoi(row[ItemField::questitemflag])==0) ? false : true; - item.SVCorruption = (int32)atoi(row[ItemField::svcorruption]); - item.Purity = (uint32)atoul(row[ItemField::purity]); + item.Proc.Effect = (int32)atoul(row[ItemField::proceffect]); + item.Proc.Type = (uint8)atoul(row[ItemField::proctype]); + item.Proc.Level = (uint8)atoul(row[ItemField::proclevel]); + item.Proc.Level2 = (uint8)atoul(row[ItemField::proclevel2]); + item.Worn.Effect = (int32)atoul(row[ItemField::worneffect]); + item.Worn.Type = (uint8)atoul(row[ItemField::worntype]); + item.Worn.Level = (uint8)atoul(row[ItemField::wornlevel]); + item.Worn.Level2 = (uint8)atoul(row[ItemField::wornlevel2]); + item.Focus.Effect = (int32)atoul(row[ItemField::focuseffect]); + item.Focus.Type = (uint8)atoul(row[ItemField::focustype]); + item.Focus.Level = (uint8)atoul(row[ItemField::focuslevel]); + item.Focus.Level2 = (uint8)atoul(row[ItemField::focuslevel2]); + item.Scroll.Effect = (int32)atoul(row[ItemField::scrolleffect]); + item.Scroll.Type = (uint8)atoul(row[ItemField::scrolltype]); + item.Scroll.Level = (uint8)atoul(row[ItemField::scrolllevel]); + item.Scroll.Level2 = (uint8)atoul(row[ItemField::scrolllevel2]); + item.Bard.Effect = (int32)atoul(row[ItemField::bardeffect]); + item.Bard.Type = (uint8)atoul(row[ItemField::bardtype]); + item.Bard.Level = (uint8)atoul(row[ItemField::bardlevel]); + item.Bard.Level2 = (uint8)atoul(row[ItemField::bardlevel2]); + item.QuestItemFlag = (atoi(row[ItemField::questitemflag]) == 0) ? false : true; + item.SVCorruption = (int32)atoi(row[ItemField::svcorruption]); + item.Purity = (uint32)atoul(row[ItemField::purity]); item.EvolvingItem = (uint8)atoul(row[ItemField::evoitem]); item.EvolvingID = (uint8)atoul(row[ItemField::evoid]); - item.EvolvingLevel = (uint8)atoul(row[ItemField::evolvinglevel]); + item.EvolvingLevel = (uint8)atoul(row[ItemField::evolvinglevel]); item.EvolvingMax = (uint8)atoul(row[ItemField::evomax]); - item.BackstabDmg = (uint32)atoul(row[ItemField::backstabdmg]); - item.DSMitigation = (uint32)atoul(row[ItemField::dsmitigation]); - item.HeroicStr = (int32)atoi(row[ItemField::heroic_str]); - item.HeroicInt = (int32)atoi(row[ItemField::heroic_int]); - item.HeroicWis = (int32)atoi(row[ItemField::heroic_wis]); - item.HeroicAgi = (int32)atoi(row[ItemField::heroic_agi]); - item.HeroicDex = (int32)atoi(row[ItemField::heroic_dex]); - item.HeroicSta = (int32)atoi(row[ItemField::heroic_sta]); - item.HeroicCha = (int32)atoi(row[ItemField::heroic_cha]); - item.HeroicMR = (int32)atoi(row[ItemField::heroic_mr]); - item.HeroicFR = (int32)atoi(row[ItemField::heroic_fr]); - item.HeroicCR = (int32)atoi(row[ItemField::heroic_cr]); - item.HeroicDR = (int32)atoi(row[ItemField::heroic_dr]); - item.HeroicPR = (int32)atoi(row[ItemField::heroic_pr]); - item.HeroicSVCorrup = (int32)atoi(row[ItemField::heroic_svcorrup]); - item.HealAmt = (int32)atoi(row[ItemField::healamt]); - item.SpellDmg = (int32)atoi(row[ItemField::spelldmg]); - item.LDoNSellBackRate = (uint32)atoul(row[ItemField::ldonsellbackrate]); - item.ScriptFileID = (uint32)atoul(row[ItemField::scriptfileid]); - item.ExpendableArrow = (uint16)atoul(row[ItemField::expendablearrow]); - item.Clairvoyance = (uint32)atoul(row[ItemField::clairvoyance]); + item.BackstabDmg = (uint32)atoul(row[ItemField::backstabdmg]); + item.DSMitigation = (uint32)atoul(row[ItemField::dsmitigation]); + item.HeroicStr = (int32)atoi(row[ItemField::heroic_str]); + item.HeroicInt = (int32)atoi(row[ItemField::heroic_int]); + item.HeroicWis = (int32)atoi(row[ItemField::heroic_wis]); + item.HeroicAgi = (int32)atoi(row[ItemField::heroic_agi]); + item.HeroicDex = (int32)atoi(row[ItemField::heroic_dex]); + item.HeroicSta = (int32)atoi(row[ItemField::heroic_sta]); + item.HeroicCha = (int32)atoi(row[ItemField::heroic_cha]); + item.HeroicMR = (int32)atoi(row[ItemField::heroic_mr]); + item.HeroicFR = (int32)atoi(row[ItemField::heroic_fr]); + item.HeroicCR = (int32)atoi(row[ItemField::heroic_cr]); + item.HeroicDR = (int32)atoi(row[ItemField::heroic_dr]); + item.HeroicPR = (int32)atoi(row[ItemField::heroic_pr]); + item.HeroicSVCorrup = (int32)atoi(row[ItemField::heroic_svcorrup]); + item.HealAmt = (int32)atoi(row[ItemField::healamt]); + item.SpellDmg = (int32)atoi(row[ItemField::spelldmg]); + item.LDoNSellBackRate = (uint32)atoul(row[ItemField::ldonsellbackrate]); + item.ScriptFileID = (uint32)atoul(row[ItemField::scriptfileid]); + item.ExpendableArrow = (uint16)atoul(row[ItemField::expendablearrow]); + item.Clairvoyance = (uint32)atoul(row[ItemField::clairvoyance]); - strcpy(item.ClickName,row[ItemField::clickname]); - strcpy(item.ProcName,row[ItemField::procname]); - strcpy(item.WornName,row[ItemField::wornname]); - strcpy(item.FocusName,row[ItemField::focusname]); - strcpy(item.ScrollName,row[ItemField::scrollname]); - - try { - hash.insert(item.ID, item); - } catch(std::exception &ex) { - Log.Out(Logs::General, Logs::Error, "Database::LoadItems: %s", ex.what()); - break; - } - } + strcpy(item.ClickName, row[ItemField::clickname]); + strcpy(item.ProcName, row[ItemField::procname]); + strcpy(item.WornName, row[ItemField::wornname]); + strcpy(item.FocusName, row[ItemField::focusname]); + strcpy(item.ScrollName, row[ItemField::scrollname]); + try { + hash.insert(item.ID, item); + } catch (std::exception &ex) { + Log.Out(Logs::General, Logs::Error, "Database::LoadItems: %s", ex.what()); + break; + } + } } const Item_Struct* SharedDatabase::GetItem(uint32 id) { From c168d7b7b6f87d5c942fe1acfa69429d85836f43 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Mon, 21 Dec 2015 12:41:49 -0500 Subject: [PATCH 14/40] Fix macro hack? [skip ci] --- common/shareddb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 129584159..fe4ad1b5d 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -835,7 +835,7 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_ Item_Struct item; const std::string query = "SELECT source," -#define F(x) "`" #x "`," +#define F(x) "`"#x"`," #include "item_fieldlist.h" #undef F "updated FROM items ORDER BY id"; From 9a1271805a3c41850fa8759ed5079c667900cf22 Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Mon, 21 Dec 2015 15:43:56 -0500 Subject: [PATCH 15/40] Added GetMeleeMitigation() to Perl and Lua for Mobs (Clients/NPCs). --- changelog.txt | 2 ++ zone/lua_mob.cpp | 8 +++++++- zone/lua_mob.h | 1 + zone/mob.cpp | 8 ++++++++ zone/mob.h | 1 + zone/perl_mob.cpp | 28 ++++++++++++++++++++++++++++ 6 files changed, 47 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 2ce2a68ad..74b6ab113 100644 --- a/changelog.txt +++ b/changelog.txt @@ -6,6 +6,8 @@ Natedog: Updated item table fields and added a few missing fields for evolving i items in your shared bank. (but item field located on items table) -NYI - SkillModMax: Max skill point modification from the percent mods. EX: 100% 2HSlashing (Max 50) - can only increase 2hslash by 50 MAX! (item field located though) +Kinglykrab: Added GetMeleeMitigation() for NPCs and Clients in Perl and Lua. + - This allows you to check total item, spell, and AA melee mitigation contribution. == 12/19/2015 == Kinglykrab: Added many methods to Perl and Lua, list below: diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 469e8cb2f..46b6b4a9b 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -1976,6 +1976,11 @@ bool Lua_Mob::IsAmnesiad() { return self->IsAmnesiad(); } +int32 Lua_Mob::GetMeleeMitigation() { + Lua_Safe_Call_Int(); + return self->GetMeleeMitigation(); +} + luabind::scope lua_register_mob() { return luabind::class_("Mob") .def(luabind::constructor<>()) @@ -2317,7 +2322,8 @@ luabind::scope lua_register_mob() { .def("IsPet", (bool(Lua_Mob::*)(void))&Lua_Mob::IsPet) .def("HasPet", (bool(Lua_Mob::*)(void))&Lua_Mob::HasPet) .def("IsSilenced", (bool(Lua_Mob::*)(void))&Lua_Mob::IsSilenced) - .def("IsAmnesiad", (bool(Lua_Mob::*)(void))&Lua_Mob::IsAmnesiad); + .def("IsAmnesiad", (bool(Lua_Mob::*)(void))&Lua_Mob::IsAmnesiad) + .def("GetMeleeMitigation", (int32(Lua_Mob::*)(void))&Lua_Mob::GetMeleeMitigation); } luabind::scope lua_register_special_abilities() { diff --git a/zone/lua_mob.h b/zone/lua_mob.h index c7530e391..4009ae2fa 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -377,6 +377,7 @@ public: bool HasPet(); bool IsSilenced(); bool IsAmnesiad(); + int32 GetMeleeMitigation(); }; #endif diff --git a/zone/mob.cpp b/zone/mob.cpp index 6e778f004..e28ccefcc 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -5682,3 +5682,11 @@ void Mob::SetCurrentSpeed(int in){ } } } + +int32 Mob::GetMeleeMitigation() { + int32 mitigation = 0; + mitigation += spellbonuses.MeleeMitigationEffect; + mitigation += itembonuses.MeleeMitigationEffect; + mitigation += aabonuses.MeleeMitigationEffect; + return mitigation; +} \ No newline at end of file diff --git a/zone/mob.h b/zone/mob.h index d02e0f089..8fc7e7f08 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -752,6 +752,7 @@ public: inline bool GetInvul(void) { return invulnerable; } inline void SetExtraHaste(int Haste) { ExtraHaste = Haste; } virtual int GetHaste(); + int32 GetMeleeMitigation(); uint8 GetWeaponDamageBonus(const Item_Struct* weapon, bool offhand = false); uint16 GetDamageTable(SkillUseTypes skillinuse); diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index 2b2442fe6..40077c2c5 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -8981,6 +8981,33 @@ XS(XS_Mob_IsAmnesiad) { XSRETURN(1); } +XS(XS_Mob_GetMeleeMitigation); +XS(XS_Mob_GetMeleeMitigation) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: Mob::GetMeleeMitigation(THIS)"); + { + Mob* THIS; + int32 RETVAL; + dXSTARG; + + if (sv_derived_from(ST(0), "Mob")) { + IV tmp = SvIV((SV*)SvRV(ST(0))); + THIS = INT2PTR(Mob*, tmp); + } + else + Perl_croak(aTHX_ "THIS is not of type Mob"); + + if (THIS == nullptr) + Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); + + RETVAL = THIS->GetMeleeMitigation(); + XSprePUSH; + PUSHi((IV)RETVAL); + } + XSRETURN(1); +} + #ifdef __cplusplus extern "C" #endif @@ -9313,6 +9340,7 @@ XS(boot_Mob) newXSproto(strcpy(buf, "HasPet"), XS_Mob_HasPet, file, "$"); newXSproto(strcpy(buf, "IsSilenced"), XS_Mob_IsSilenced, file, "$"); newXSproto(strcpy(buf, "IsAmnesiad"), XS_Mob_IsAmnesiad, file, "$"); + newXSproto(strcpy(buf, "GetMeleeMitigation"), XS_Mob_GetMeleeMitigation, file, "$"); XSRETURN_YES; } From 7223f2da067dc4fc6ed1e248e25c0b847431ec37 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 21 Dec 2015 15:31:38 -0600 Subject: [PATCH 16/40] Add 13th floor item import script (Natedog/Akkadius) [skip ci] --- utils/scripts/import_13th_floor.pl | 245 +++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 utils/scripts/import_13th_floor.pl diff --git a/utils/scripts/import_13th_floor.pl b/utils/scripts/import_13th_floor.pl new file mode 100644 index 000000000..1478de4c2 --- /dev/null +++ b/utils/scripts/import_13th_floor.pl @@ -0,0 +1,245 @@ +######################################################################## +#::: 13th floor import script +#::: Current Source: http://items.sodeq.org/download.php +#::: Authors: (Natedog, Akkadius) +######################################################################## + +use DBI; +use DBD::mysql; + +my $database_name = ""; +my $total_items = 0; +my $read_items_file = "items.txt"; #default +my $dbh = LoadMysql(); + +read_items_file_from_13th_floor_text(); +update_items_table(); + +sub LoadMysql{ + #::: Config Variables + my $confile = "eqemu_config.xml"; + open(F, "<$confile") or die "Unable to open config: $confile\n"; + my $indb = 0; + while() { + s/\r//g; + if(//i) { $indb = 1; } + next unless($indb == 1); + if(/<\/database>/i) { $indb = 0; last; } + if(/(.*)<\/host>/i) { $host = $1; } + elsif(/(.*)<\/username>/i) { $user = $1; } + elsif(/(.*)<\/password>/i) { $pass = $1; } + elsif(/(.*)<\/db>/i) { $db = $1; } + } + $database_name = $db; + #::: DATA SOURCE NAME + $dsn = "dbi:mysql:$db:localhost:3306"; + #::: PERL DBI CONNECT + $connect = DBI->connect($dsn, $user, $pass); + return $connect; +} + +sub read_items_file_from_13th_floor_text { + + #::: Read from file and place into array + open(F, "<" . $read_items_file) or die "Unable to open itemfile: " . $read_items_file . "\n"; + my @item_file_lines = ; + close(F); + + #::: Chomp this array... + my @newitem_file_lines; + chomp($item_file_lines[0]); + @fields = split("(?prepare("SHOW TABLES LIKE 'items_floor'"); + $sth->execute(); + my $has_items_floor = $sth->fetchrow_array(); + + #::: If we have items_floor + if ($has_items_floor eq '') { + $dbh->do("CREATE TABLE `items_floor` (`" . join("` VARCHAR(64) NOT NULL DEFAULT '', `", @fields). "` VARCHAR(64) NOT NULL DEFAULT '', UNIQUE INDEX `ID` (`id`)) COLLATE='latin1_swedish_ci' ENGINE=MyISAM"); + $dbh->do("ALTER TABLE `items_floor` CHANGE `id` `id` INT(11) NOT NULL DEFAULT '0'"); + printf "Database items_floor created\n"; + } + + #::: Create REPLACE INTO header and define worker variables... + $master_insert = "REPLACE INTO `items_floor` (" . join(",", @fields) . ") VALUES "; + $query_insert_ph = ""; #::: Used for building placeholder values in query Ex: (?, ?, ?) + @field_values = (); #::: Used for stuffing mysql field values + $query_count = 0; #::: Used for chunking query updates + $print_cycle = 0; #::: Counter for console updates + $start_time = time(); #::: Start time for import + $total_items_file = scalar(grep $_, @item_file_lines) - 1; #::: Total items in text file + + #::: Iterate through each item in items.txt + for (1 .. $#item_file_lines) { + @f = split("(? 500){ + $query_insert_ph = substr($query_insert_ph, 0, -2); + $dbh->prepare($master_insert . " " . $query_insert_ph)->execute(@field_values); + $query_count = 0; + $query_insert_ph = ""; + @field_values = (); + } + + #::: Print updates to console + if($print_cycle > 25){ + print "Processing (" . $read_items_file . ") :: (Items: " . $total_items . "/" . $total_items_file . ") \r"; + $print_cycle = 0; + } + + #::: Counters + $total_items++; + $query_count++; + $print_cycle++; + } + + #::: One last processing print + print "Processing (" . $read_items_file . ") :: (Items: " . $total_items . "/" . $total_items_file . ") \r"; + + printf "\n" . $total_items . " items added to database... Took " . (time() - $start_time) . " second(s)... \n"; +} + +sub update_items_table { + + #::: Keep Items table sane + $query_handle = $dbh->prepare(" + ALTER TABLE `items` + MODIFY COLUMN `UNK132` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL; + "); + $query_handle->execute(); + + my @matching_table; + my @missing_items_table; + my @missing_items_floor_table; + + #::: Get columns from `items` + my $sth = $dbh->prepare("SHOW COLUMNS FROM `items`;"); + $sth->execute(); + my @items_table; + while (my @row = $sth->fetchrow_array()) { + push(@items_table, $row[0]); + } + + #::: Get columns from `items_floor` + $sth2 = $dbh->prepare("SHOW COLUMNS FROM `items_floor`"); + $sth2->execute(); + my @items_floor_table; + while (my @row = $sth2->fetchrow_array()) { + push(@items_floor_table, $row[0]); + } + + #::: Go through the original items table columns and line them up with what columns match on 13th floor + #::: This is so we can use the matching columns to update and insert item data into `items` table + foreach $value (@items_table) { + if ( grep( /^$value$/i, @items_floor_table ) ) { + push(@matching_table, $value); + } else { + #::: What values are we missing from EMU items table.. + push(@missing_items_table, $value); + } + } + + #::: What values are we missing from.. 13thFloor + foreach $value (@items_floor_table) { + if ( grep( /^$value$/i, @items_table ) ) { + #DO NOTHING... + } else { + push(@missing_items_floor_table, $value); + } + } + + #::: Go through the matched columns and build our query strings... + + my $items_field_list = ""; #::: Build the field list for the INSERT (field1, field2) + my $items_floor_field_list = ""; #::: What fields we will select from items_floor table to insert into items (matched columns) + my $update_fields = ""; #::: To update an existing item entry if it exists... + + foreach $match (@matching_table) { + $match = lc($match); + $update_fields .= "`" . $match . "` = fi.`" . $match . "`, "; + $items_field_list .= "`" . $match . "`, "; + $items_floor_field_list .= "fi.`" . $match . "`, "; + } + #::: Trim ', ' off the ends + $update_fields = substr($update_fields, 0, -2); + $items_field_list = substr($items_field_list, 0, -2); + $items_floor_field_list = substr($items_floor_field_list, 0, -2); + + #::: Mixed up fields... + $items_floor_field_list =~ s/booktype/booklang/g; #our booktype is mixed with theirs... + $update_fields =~ s/`booktype` = fi.`booktype`/`booktype` = fi.`booklang`/g; + + #::: FIELDS THAT DO NOT MATCH GO HERE + my @items_add = ( + "casttime_", "endur", "range", "attuneable", "evolvinglevel", "herosforgemodel", "scrolltype", + "scriptfileid", "powersourcecapacity", "augslot1unk2", "augslot2unk2", "augslot3unk2", "augslot4unk2", + "augslot5unk2", "augslot6unk2", "recskill", "book" + ); + my @items_floor_add = ( + "foodduration", "endurance", "therange", "attunable", "evolvl", "heroforge1", "scrolleffecttype", + "rightclickscriptid", "powersourcecap", "augslot1unk", "augslot2unk", "augslot3unk", "augslot4unk", + "augslot5unk", "augslot6unk", "reqskill", "booktype" + ); + + #::: Match the mis-matched fields... + my $spot = 0; + foreach $value (@items_add) { + $items_field_list .= ", `" . $value . "`"; + $update_fields .= ", `" . $value . "` = fi.`" . $items_floor_add[$spot] . "`"; + $spot++; + @missing_items_table = grep {$_ ne $value} @missing_items_table; + } + foreach $value (@items_floor_add) { + $items_floor_field_list .= ", fi.`" . $value . "`"; + @missing_items_floor_table = grep {$_ ne $value} @missing_items_floor_table; + } + + my $update_query = " + INSERT INTO items (" . $items_field_list . ") + SELECT " . $items_floor_field_list . " + FROM items_floor fi + ON DUPLICATE KEY UPDATE " . $update_fields; + + #::: Print missing fields to file + my $write_file = "missing_item_fields.txt"; + + open(F, ">$write_file") or die "Unable to open questfile: $write_file\n"; + print F "$update_query \n\n"; + print F "EQEMU items Table missing fields\n"; + foreach $value (@missing_items_table) { + print F "$value\n"; + } + print F "\n\n13thFloor items Table missing fields\n"; + foreach $value (@missing_items_floor_table) { + print F "$value\n"; + } + close(F); + + #::: Number of rows affected by query + $rows = $dbh->do($update_query); + + #::: Update stackables + $dbh->do("UPDATE items i SET i.stackable = 1 WHERE i.stacksize > 1"); + + print "Added all new items to Items table (" . $rows . ")!\n"; + +} + +sub trim($) { + my $string = shift; + $string =~ s/^\s+//; + $string =~ s/\s+$//; + return $string; +} \ No newline at end of file From 4b2f12cd67b547f58f9f6d0849f1dce63e204f75 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 21 Dec 2015 15:32:59 -0600 Subject: [PATCH 17/40] Linux-ify 13th floor script [skip ci] --- utils/scripts/import_13th_floor.pl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/scripts/import_13th_floor.pl b/utils/scripts/import_13th_floor.pl index 1478de4c2..4c50eca7f 100644 --- a/utils/scripts/import_13th_floor.pl +++ b/utils/scripts/import_13th_floor.pl @@ -1,3 +1,5 @@ +#! /usr/bin/perl + ######################################################################## #::: 13th floor import script #::: Current Source: http://items.sodeq.org/download.php From dc58173f158f83e70e40e500ce657e1b5ce7b3c7 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 22 Dec 2015 01:04:27 -0600 Subject: [PATCH 18/40] Remove unused script since we have a newer one now [skip ci] --- utils/scripts/load_13thfloor_items.pl | 77 --------------------------- 1 file changed, 77 deletions(-) delete mode 100644 utils/scripts/load_13thfloor_items.pl diff --git a/utils/scripts/load_13thfloor_items.pl b/utils/scripts/load_13thfloor_items.pl deleted file mode 100644 index 03fbfe5fb..000000000 --- a/utils/scripts/load_13thfloor_items.pl +++ /dev/null @@ -1,77 +0,0 @@ -#! /usr/bin/perl - -use DBI; -use Getopt::Std; - -getopts('d:h'); -$conf = "eqemu_config.xml"; -if($opt_h) { - die "Usage: load_13thfloor_items.pl [-d path/to/eqemu_config.xml]\n"; -} -if($opt_d) { - $conf = $opt_d; -} - -$db = "eq"; -$user = "eq"; -$pass = "eq"; -$host = "localhost"; -open(F, "<$conf") or die "Unable to open config $conf\n"; -$indb = 0; -while() { - s/\r//g; - if(//i) { - $indb = 1; - } - next unless($indb == 1); - if(/<\/database>/i) { - $indb = 0; - last; - } - if(/(.*)<\/host>/i) { - $host = $1; - } elsif(/(.*)<\/username>/i) { - $user = $1; - } elsif(/(.*)<\/password>/i) { - $pass = $1; - } elsif(/(.*)<\/db>/i) { - $db = $1; - } -} -if(!$db || !$user || !$pass || !$host) { - die "Invalid db.ini, missing one of: host, user, password, database\n"; -} - -$source="DBI:mysql:database=$db;host=$host"; - -my $dbh = DBI->connect($source, $user, $pass) || die "Could not create db handle\n"; - -$_=; -chomp(); -s/'/\\'/g; -@fields=split("(? "itemuse" -); - -$insert="replace into items (".join(",",@fields).",source,updated) values ('"; -$insert=~s/UNK130/potionbeltslots/; -$insert=~s/UNK133/stackable/; - -#select(STDOUT); $|=1; -while() { - chomp(); - s/'/\\'/g; - @f=split("(?do($statement); - printf("Processing: %d %s \r",$f[4],$f[1]); - ++$count; -} -printf("Processed: %d items(s) \n",$count); - From 3a7d7c727f323733d5f1dda8b1c3a709c68ff9ed Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 26 Dec 2015 13:29:34 -0500 Subject: [PATCH 19/40] AA updates [skip ci] --- utils/sql/git/optional/2015_12_26_oow_aa_missing.sql | 3 +++ utils/sql/peq_aa_tables_post_rework.sql | 6 ++++++ 2 files changed, 9 insertions(+) create mode 100644 utils/sql/git/optional/2015_12_26_oow_aa_missing.sql diff --git a/utils/sql/git/optional/2015_12_26_oow_aa_missing.sql b/utils/sql/git/optional/2015_12_26_oow_aa_missing.sql new file mode 100644 index 000000000..50e3aade3 --- /dev/null +++ b/utils/sql/git/optional/2015_12_26_oow_aa_missing.sql @@ -0,0 +1,3 @@ +INSERT INTO `aa_ranks` (`id`, `upper_hotkey_sid`, `lower_hotkey_sid`, `title_sid`, `desc_sid`, `cost`, `level_req`, `spell`, `spell_type`, `recast_time`, `expansion`, `prev_id`, `next_id`) VALUES (1015, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1014, 1016); + +INSERT INTO `aa_rank_effects` (`rank_id`, `slot`, `effect_id`, `base1`, `base2`) VALUES (1015, 1, 262, 40, 7), (1015, 2, 262, 40, 8), (1015, 3, 262, 40, 9), (1015, 4, 262, 40, 10), (1015, 5, 262, 40, 11); diff --git a/utils/sql/peq_aa_tables_post_rework.sql b/utils/sql/peq_aa_tables_post_rework.sql index 53d465778..9d3b05eaf 100644 --- a/utils/sql/peq_aa_tables_post_rework.sql +++ b/utils/sql/peq_aa_tables_post_rework.sql @@ -2532,6 +2532,7 @@ INSERT INTO `aa_ranks` (`id`, `upper_hotkey_sid`, `lower_hotkey_sid`, `title_sid (1012, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1011, 1013), (1013, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1012, 1014), (1014, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1013, 1015), + (1015, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1014, 1016), (1016, -1, -1, 1011, 1011, 0, 51, -1, 0, 0, 8, 1015, -1), (1017, 1017, 1017, 1017, 1017, 6, 59, 16531, 75, 15, 15, -1, 13726), (1018, 1018, 1018, 1018, 1018, 2, 63, 16455, 69, 1, 15, -1, -1), @@ -9526,6 +9527,11 @@ INSERT INTO `aa_rank_effects` (`rank_id`, `slot`, `effect_id`, `base1`, `base2`) (1014, 3, 262, 32, 9), (1014, 4, 262, 32, 10), (1014, 5, 262, 32, 11), + (1015, 1, 262, 40, 7), + (1015, 2, 262, 40, 8), + (1015, 3, 262, 40, 9), + (1015, 4, 262, 40, 10), + (1015, 5, 262, 40, 11), (1016, 1, 262, 50, 7), (1016, 2, 262, 50, 8), (1016, 3, 262, 50, 9), From 1b4dbd1ce7003c031c6804ebf8f2dc534b2f39ea Mon Sep 17 00:00:00 2001 From: Akkadius Date: Sun, 27 Dec 2015 17:26:39 -0600 Subject: [PATCH 20/40] Adjust import_13th_floor.pl to flip slots 21 and 22 [skip ci] --- utils/scripts/import_13th_floor.pl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/utils/scripts/import_13th_floor.pl b/utils/scripts/import_13th_floor.pl index 4c50eca7f..6a66892f9 100644 --- a/utils/scripts/import_13th_floor.pl +++ b/utils/scripts/import_13th_floor.pl @@ -111,6 +111,14 @@ sub read_items_file_from_13th_floor_text { print "Processing (" . $read_items_file . ") :: (Items: " . $total_items . "/" . $total_items_file . ") \r"; printf "\n" . $total_items . " items added to database... Took " . (time() - $start_time) . " second(s)... \n"; + + print "Flipping slots 21 and 22..."; + $rows_affected = $dbh->prepare(" + UPDATE `items_floor` + SET `slots` = (`slots` ^ 6291456) + WHERE (`slots` & 6291456) + IN (2097152, 4194304)")->execute(); + print " Rows affected (" . $rows_affected . ")\n"; } sub update_items_table { From e423165bcb6fdb023e2c210f2bba34c4dfb447d2 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 28 Dec 2015 02:25:01 -0600 Subject: [PATCH 21/40] DB Update System :: Implement SVN updates into the manifest (To support older databases) [skip ci] --- utils/sql/db_update_manifest.txt | 356 +++++++++++++++---------------- 1 file changed, 178 insertions(+), 178 deletions(-) diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index db4078eb5..f62c89fbb 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -1,261 +1,261 @@ -5001|1_task_system.sql +5001|1_task_system.sql|SHOW TABLES LIKE 'tasks'|empty| # 5002|2_optional_maxclients.sql # 5003|14_optional_merchantlist.sql -5004|35_task_stepped.sql -5005|42_task_min_maxlevel.sql -5006|55_zone_shutdowndeleay.sql +5004|35_task_stepped.sql|SHOW COLUMNS FROM `tasks` LIKE 'stepped'|not_empty| +5005|42_task_min_maxlevel.sql|SHOW COLUMNS FROM `tasks` LIKE 'minlevel'|empty| +5006|55_zone_shutdowndeleay.sql|SHOW COLUMNS FROM `zone` LIKE 'shutdowndelay'|empty| # 5007|68_optional_character_maxexplevel.sql # 5008|103_optional_chat_rules.sql -5009|104_traps.sql +5009|104_traps.sql|SHOW COLUMNS FROM `traps` LIKE 'respawn_time'|empty| # 5010|106_optional_proc_rules.sql -5011|120_damageshieldtypes.sql -5012|125_aggrozone.sql +5011|120_damageshieldtypes.sql|SHOW TABLES LIKE 'damageshieldtypes'|empty| +# 5012|125_aggrozone.sql # 5013|127_optional_spell_rules.sql # 5014|129_optional_shared_plat_rule.sql # 5015|131_optional_combat_rules.sql -5016|133_task_repeatable.sql -5017|142_deathpeace_and_lifetap_aas.sql +5016|133_task_repeatable.sql|SHOW COLUMNS FROM `tasks` LIKE 'repeatable'|empty| +5017|142_deathpeace_and_lifetap_aas.sql|SELECT * FROM db_version WHERE version > 5016|empty| # 5018|158_optional_death_exp_loss.sql -5019|176_melody.sql -5020|189_character_.sql -5021|196_trader.sql -5022|210_undyeme.sql -5023|222_buyer.sql -5024|226_account_limiting.sql -5025|230_spells_table.sql -5026|235_horses_table.sql -5027|243_spawn_timers.sql -5028|247_mail.sql -5029|249_chatchannels.sql -5030|250_bot_spell_update.sql +# 5019|176_melody.sql +5020|189_character_.sql|SELECT * FROM db_version WHERE version >= 5020|empty| +5021|196_trader.sql|SHOW TABLES LIKE 'trader'|empty| +# 5022|210_undyeme.sql +5023|222_buyer.sql|SHOW TABLES LIKE 'buyer'|empty| +# 5024|226_account_limiting.sql +5025|230_spells_table.sql|SHOW TABLES LIKE 'spells_new'|empty| +5026|235_horses_table.sql|SHOW TABLES LIKE 'horses'|empty| +5027|243_spawn_timers.sql|SHOW TABLES LIKE 'respawn_times'|empty| +5028|247_mail.sql|SHOW TABLES LIKE 'mail'|empty| +5029|249_chatchannels.sql|SHOW TABLES LIKE 'chatchannels'|empty| +# 5030|250_bot_spell_update.sql # 5031|250_optional_bot_spell_update.sql # 5032|285_optional_bot_spell_update.sql -5033|292_augslots.sql -5034|294_merchant_logging.sql -5035|304_faction_list.sql -5036|326_aas.sql -5037|328_bot_management.sql +# 5033|292_augslots.sql|SELECT * FROM db_version WHERE version >= 5033|empty| +5034|294_merchant_logging.sql|SHOW COLUMNS FROM `eventlog` LIKE 'event_nid'|empty| +5035|304_faction_list.sql|SHOW COLUMNS FROM `faction_list` LIKE 'mod_c16'|empty| +5036|326_aas.sql|SELECT * FROM db_version WHERE version > 5035|empty| +# 5037|328_bot_management.sql # 5038|328_optional_bot_management.sql -5039|340_gm_ips.sql -5040|356_combat.sql -5041|360_peqzone.sql -5042|364_ranged_dist_rule.sql -5043|386_bot_save_raid.sql +5039|340_gm_ips.sql|SHOW TABLES LIKE 'gm_ips'|empty| +# 5040|356_combat.sql +# 5041|360_peqzone.sql +# 5042|364_ranged_dist_rule.sql +# 5043|386_bot_save_raid.sql # 5044|434_optional_rest_state_rules.sql -5045|447_sof_startzone_rule.sql -5046|463_altadv_vars.sql -5047|475_aa_actions.sql -5048|500_spawn2_optimization.sql -5049|503_bugs.sql -5050|518_drakkin_npc_type_features.sql -5051|524_rule_values_notes.sql -5052|527_npc_armor_tint.sql -5053|553_saylink_table.sql -5054|564_nokeyring.sql -5055|600_group_leadership.sql -5056|612_instance_changes.sql -5057|615_adventure_assassination.sql -5058|619_Adventure_Recruiter_Flavor.sql -5059|621_LDoNTraps.sql -5060|633_ucs.sql -5061|634_TrapTemplateDefaultValue.sql -5062|643_BotsTable.sql -5063|646_archery_penalty_rule.sql -5064|665_heroic_resists.sql -5065|667_titles.sql -5066|687_aa_table_changes.sql -5067|699_peqzone_rule.sql -5068|702_aashieldblock_tint_table.sql -5069|703_peqzone_rule.sql -5070|704_rules.sql -5071|710_tint_set_naming.sql -5072|721_pathing_rules.sql -5073|730_smart_delay_moving.sql -5074|731_rule_assist_notarget_self.sql -5075|732_sacrifice_rules.sql -5076|745_slow_mitigation.sql -5077|754_archery_base_damage_rule.sql -5078|755_sof_altadv_vars_updates.sql -5079|773_monk_rules.sql +# 5045|447_sof_startzone_rule.sql +# 5046|463_altadv_vars.sql +# 5047|475_aa_actions.sql +5048|500_spawn2_optimization.sql|SELECT * FROM db_version WHERE version >= 5048|empty| +5049|503_bugs.sql|SHOW TABLES LIKE 'bugs'|empty| +5050|518_drakkin_npc_type_features.sql|SHOW TABLES LIKE 'bugs'|empty| +5051|524_rule_values_notes.sql|SELECT * FROM db_version WHERE version >= 5051|empty| +5052|527_npc_armor_tint.sql|SELECT * FROM db_version WHERE version >= 5052|empty| +5053|553_saylink_table.sql|SHOW TABLES LIKE 'saylink'|empty| +5054|564_nokeyring.sql|SHOW COLUMNS FROM `doors` LIKE 'nokeyring'|empty| +5055|600_group_leadership.sql|SELECT * FROM db_version WHERE version >= 5055|empty| +5056|612_instance_changes.sql|SELECT * FROM db_version WHERE version >= 5056|empty| +5057|615_adventure_assassination.sql|SELECT * FROM db_version WHERE version >= 5057|empty| +5058|619_Adventure_Recruiter_Flavor.sql|SELECT * FROM db_version WHERE version >= 5058|empty| +5059|621_LDoNTraps.sql|SHOW TABLES LIKE 'ldon_trap_templates'|empty| +5060|633_ucs.sql|SHOW TABLES LIKE 'friends'|empty| +5061|634_TrapTemplateDefaultValue.sql|SHOW COLUMNS FROM `npc_types` LIKE 'trap_template'|empty| +# 5062|643_BotsTable.sql +# 5063|646_archery_penalty_rule.sql +5064|665_heroic_resists.sql|SELECT * FROM db_version WHERE version >= 5064|empty| +5065|667_titles.sql|SHOW TABLES LIKE 'titles'|empty| +5066|687_aa_table_changes.sql|SELECT * FROM db_version WHERE version >= 5066|empty| +# 5067|699_peqzone_rule.sql +5068|702_aashieldblock_tint_table.sql|SHOW TABLES LIKE 'npc_types_tint'|empty| +# 5069|703_peqzone_rule.sql +# 5070|704_rules.sql +5071|710_tint_set_naming.sql|SELECT * FROM db_version WHERE version >= 5071|empty| +5072|721_pathing_rules.sql|SELECT * FROM db_version WHERE version >= 5072|empty| +# 5073|730_smart_delay_moving.sql +# 5074|731_rule_assist_notarget_self.sql +# 5075|732_sacrifice_rules.sql +5076|745_slow_mitigation.sql|SELECT * FROM db_version WHERE version >= 5076|empty| +# 5077|754_archery_base_damage_rule.sql +5078|755_sof_altadv_vars_updates.sql|SELECT * FROM db_version WHERE version >= 5078|empty| +# 5079|773_monk_rules.sql # 5080|853_optional_rule_aaexp.sql # 5081|858_optional_rule_ip_limit_by_status.sql # 5082|892_optional_bots_table_mod.sql # 5083|893_optional_bots_table_mod.sql -5084|898_npc_maxlevel_scalerate.sql +5084|898_npc_maxlevel_scalerate.sql|SHOW COLUMNS FROM `npc_types` LIKE 'maxlevel'|empty| # 5085|902_optional_rule_snareflee.sql -5086|923_spawn2_enabled.sql -5087|962_hot_zone.sql -5088|964_reports.sql -5089|971_veteran_rewards.sql -5090|977_raid_npc_private_corpses.sql -5091|979_unique_spawn_by_name.sql -5092|980_account_ip.sql -5093|1022_botadventuring.sql -5094|1027_botactives.sql -5095|1030_botzoningsupport.sql -5096|1036_botbuffs.sql -5097|1038_botpetstatepersists.sql -5098|1038_grouptablesuniquecolumndefinitions.sql -5099|1039_botguilds.sql -5100|1040_DeprecatedBotRaidsSystems.sql -5101|1057_titles.sql -5102|1077_botgroups.sql -5103|1136_spell_globals.sql +5086|923_spawn2_enabled.sql|SHOW COLUMNS FROM `spawn2` LIKE 'enabled'|empty| +5087|962_hot_zone.sql|SHOW COLUMNS FROM `zone` LIKE 'hotzone'|empty| +5088|964_reports.sql|SHOW TABLES LIKE 'reports'|empty| +5089|971_veteran_rewards.sql|SHOW TABLES LIKE 'veteran_reward_templates'|empty| +5090|977_raid_npc_private_corpses.sql|SELECT * FROM db_version WHERE version >= 5090|empty| +5091|979_unique_spawn_by_name.sql|SHOW COLUMNS FROM `npc_types` LIKE 'unique_spawn_by_name'|empty| +5092|980_account_ip.sql|SHOW TABLES LIKE 'account_ip'|empty| +# 5093|1022_botadventuring.sql +# 5094|1027_botactives.sql +# 5095|1030_botzoningsupport.sql +# 5096|1036_botbuffs.sql +# 5097|1038_botpetstatepersists.sql +5098|1038_grouptablesuniquecolumndefinitions.sql|SELECT * FROM db_version WHERE version >= 5098|empty| +# 5099|1039_botguilds.sql +# 5100|1040_DeprecatedBotRaidsSystems.sql +5101|1057_titles.sql|SHOW TABLES LIKE 'player_titlesets'|empty| +# 5102|1077_botgroups.sql +5103|1136_spell_globals.sql|SHOW TABLES LIKE 'spell_globals'|empty| # 5104|1144_optional_rule_return_nodrop.sql -5105|1195_account_suspendeduntil.sql -5106|1259_npc_skill_types.sql -5107|1280_bot_augs.sql +5105|1195_account_suspendeduntil.sql|SELECT * FROM db_version WHERE version >= 5105|empty| +5106|1259_npc_skill_types.sql|SHOW COLUMNS FROM `npc_types` LIKE 'prim_melee_type'|empty| +# 5107|1280_bot_augs.sql # 5108|1290_optional_exp_loss_rule.sql -5109|1293_guild_bank.sql -5110|1379_loginserver_trusted_server.sql -5111|1392_recipe_learning.sql +5109|1293_guild_bank.sql|SHOW TABLES LIKE 'guild_bank'|empty| +# 5110|1379_loginserver_trusted_server.sql +5111|1392_recipe_learning.sql|SELECT * FROM db_version WHERE version >= 5111|empty| # 5112|1394_optional_rule_sod_hp_mana_end.sql -5113|1404_faction_list.sql +5113|1404_faction_list.sql|SELECT * FROM db_version WHERE version >= 5113|empty| # 5114|1410_optional_sod_aas_ht_and_loh.sql -5115|1436_login_server_table_fix.sql -5116|1446_allowrest_optional.sql -5117|1446_allowrest_required.sql -5118|1450_cvs.sql -5119|1451_guilds.sql -5120|1498_instance_adventure.sql -5121|1510_global_instances.sql -5122|1511_map_path_loading.sql -5123|1513_zone_points.sql -5124|1519_zone_primary_key_id.sql -5125|1542_items_table_cleanup.sql -5126|1548_nimbuseffect_required.sql -5127|1562_instanced_spawnconditions.sql -5128|1586_waypoints_optional.sql -5129|1610_tradeskill_required.sql -5130|1618_zone.sql +# 5115|1436_login_server_table_fix.sql +# 5116|1446_allowrest_optional.sql +5117|1446_allowrest_required.sql|SELECT * FROM db_version WHERE version >= 5117|empty| +# 5118|1450_cvs.sql +5119|1451_guilds.sql|SELECT * FROM db_version WHERE version >= 5119|empty| +5120|1498_instance_adventure.sql|SELECT * FROM db_version WHERE version >= 5120|empty| +5121|1510_global_instances.sql|SELECT * FROM db_version WHERE version >= 5121|empty| +5122|1511_map_path_loading.sql|SHOW COLUMNS FROM `zone` LIKE 'map_file_name'|empty| +5123|1513_zone_points.sql|SELECT * FROM db_version WHERE version >= 5123|empty| +5124|1519_zone_primary_key_id.sql|SELECT * FROM db_version WHERE version >= 5124|empty| +5125|1542_items_table_cleanup.sql|SELECT * FROM db_version WHERE version >= 5125|empty| +5126|1548_nimbuseffect_required.sql|SELECT * FROM db_version WHERE version >= 5126|empty| +5127|1562_instanced_spawnconditions.sql|SHOW TABLES LIKE 'spawn_condition_values'|empty| +# 5128|1586_waypoints_optional.sql +5129|1610_tradeskill_required.sql|SELECT * FROM db_version WHERE version >= 5129|empty| +5130|1618_zone.sql|SELECT * FROM db_version WHERE version >= 5130|empty| # 5131|1625_optional_rule_class_race_exp_bonus.sql # 5132|1672_optional_rules_respawn_window.sql # 5133|1679_optional_rules_blocked_buffs.sql -5134|1696_modify_zone_and_object_tables.sql -5135|1711_account_restricted_aa.sql +5134|1696_modify_zone_and_object_tables.sql|SELECT * FROM db_version WHERE version >= 5134|empty| +5135|1711_account_restricted_aa.sql|SHOW COLUMNS FROM `account` LIKE 'time_creation'|empty| # 5136|1717_optional_rule_bash_stun_chance.sql # 5137|1718_optional_rules_mod3s.sql # 5138|1719_optional_triggerOnCastAAs.sql # 5139|1720_optional_sql_AAs.sql -5140|1720_required_sql_AA_effects_update.sql +# 5140|1720_required_sql_AA_effects_update.sql # 5141|1721_optional_sql_drakkin_breath_update.sql -5142|1721_required_sql_altadv_vars_update.sql +# 5142|1721_required_sql_altadv_vars_update.sql # 5143|1723_optional_sql_new_stats_window_rule.sql -5144|1723_required_sql_corruption.sql +5144|1723_required_sql_corruption.sql|SELECT * FROM db_version WHERE version >= 5144|empty| # 5145|1736_optional_sql_feral_swipe.sql -5146|1737_required_sql_rule_and_aa_update.sql +# 5146|1737_required_sql_rule_and_aa_update.sql # 5147|1746_optional_sql_bot_manaregen.sql # 5148|1747_optional_HoT_zone_and_zonepoints.sql # 5149|1750_optional_sql_reflect_rule.sql # 5150|1753_optional_haste_cap_rule.sql -5151|1753_required_sql_healing_adept_aa.sql -5152|1754_required_sql_healing_adept_aa_fix.sql -5153|1755_required_sql_fear_resist_aas.sql +# 5151|1753_required_sql_healing_adept_aa.sql +# 5152|1754_required_sql_healing_adept_aa_fix.sql +# 5153|1755_required_sql_fear_resist_aas.sql # 5154|1784_optional_corpsedrag_rules.sql -5155|1786_required_update_to_aas.sql -5156|1790_required_aa_required_level_cost.sql -5157|1793_resist_adjust.sql +# 5155|1786_required_update_to_aas.sql +# 5156|1790_required_aa_required_level_cost.sql +5157|1793_resist_adjust.sql|SHOW COLUMNS FROM `npc_spells_entries` LIKE 'resist_adjust'|empty| # 5158|1799_optional_rest_regen_endurance_rule.sql -5159|1802_required_doppelganger.sql -5160|1803_required_tasks_xpreward_signed.sql -5161|1804_required_ae_melee_updates.sql +5159|1802_required_doppelganger.sql|SELECT * FROM db_version WHERE version >= 5159|empty| +5160|1803_required_tasks_xpreward_signed.sql|SELECT * FROM db_version WHERE version >= 5160|empty| +5161|1804_required_ae_melee_updates.sql|SELECT * FROM db_version WHERE version >= 5161|empty| # 5162|1809_optional_rules.sql -5163|1813_required_doppelganger_npcid_change.sql +5163|1813_required_doppelganger_npcid_change.sql|SELECT * FROM db_version WHERE version >= 5163|empty| # 5164|1817_optional_npc_archery_bonus_rule.sql # 5165|1823_optional_delay_death.sql -5166|1847_required_doors_dest_zone_size_32.sql +5166|1847_required_doors_dest_zone_size_32.sql|SELECT * FROM db_version WHERE version >= 5166|empty| # 5167|1859_optional_item_casts_use_focus_rule.sql # 5168|1884_optional_bot_spells_update.sql # 5169|1885_optional_rules_fv_pvp_expansions.sql # 5170|1889_optional_skill_cap_rule.sql -5171|1908_required_npc_types_definitions.sql +5171|1908_required_npc_types_definitions.sql|SHOW COLUMNS FROM `npc_types` LIKE 'attack_count'|empty| # 5172|1926_optional_stat_cap.sql -5173|1944_spawn2.sql -5174|1946_doors.sql +5173|1944_spawn2.sql|SHOW COLUMNS FROM `spawn2` LIKE 'animation'|empty| +5174|1946_doors.sql|SELECT * FROM db_version WHERE version >= 5166|empty| # 5175|1960_optional_console_timeout_rule.sql # 5176|1962_optional_guild_creation_window_rules.sql # 5177|1963_optional_rule_live_like_focuses.sql # 5178|1968_optional_enrage_rules.sql # 5179|1972_optional_extradmg_item_cap.sql -5180|1974_required_bot_spells_update.sql -5181|1977_underwater.sql +# 5180|1974_required_bot_spells_update.sql +5181|1977_underwater.sql|SHOW COLUMNS FROM `npc_types` LIKE 'underwater'|empty| # 5182|1998_optional_intoxication_and_looting_rules.sql -5183|2004_charges_alt_currency.sql +5183|2004_charges_alt_currency.sql|SHOW TABLES LIKE 'alternate_currency'|empty| # 5184|2015_optional_specialization_training_rule.sql # 5185|2016_optional_rule_bot_aa_expansion.sql # 5186|2023_optional_mysqlcli.sql # 5187|2024_optional_update_crystals.sql -5188|2024_required_update.sql -5189|2057_required_discovered_items.sql +5188|2024_required_update.sql|SHOW TABLES LIKE 'char_create_combinations'|empty| +5189|2057_required_discovered_items.sql|SHOW TABLES LIKE 'discovered_items'|empty| # 5190|2058_optional_rule_discovered_items.sql -5191|2062_required_version_changes.sql -5192|2069_required_pets.sql -5193|2079_player_speech.sql -5194|2087_required_bots_hp_and_mana_and_spell_updates.sql -5195|2098_required_zonepoint_version_changes.sql -5196|2099_required_discovered_items_account_status.sql -5197|2104_required_group_roles.sql -5198|2107_required_bot_stances.sql -5199|2129_required_lfguild.sql -5200|2133_required_faction_loot_despawn.sql -5201|2136_extended_targets.sql -5202|2142_emotes.sql +5191|2062_required_version_changes.sql|SELECT * FROM db_version WHERE version >= 5191|empty| +5192|2069_required_pets.sql|SHOW TABLES LIKE 'pets_equipmentset'|empty| +# 5193|2079_player_speech.sql +# 5194|2087_required_bots_hp_and_mana_and_spell_updates.sql +5195|2098_required_zonepoint_version_changes.sql|SELECT * FROM db_version WHERE version >= 5195|empty| +5196|2099_required_discovered_items_account_status.sql|SELECT * FROM db_version WHERE version >= 5196|empty| +5197|2104_required_group_roles.sql|SELECT * FROM db_version WHERE version >= 5197|empty| +# 5198|2107_required_bot_stances.sql +5199|2129_required_lfguild.sql|SHOW TABLES LIKE 'lfguild'|empty| +5200|2133_required_faction_loot_despawn.sql|SELECT * FROM db_version WHERE version >= 5200|empty| +5201|2136_extended_targets.sql|SELECT * FROM db_version WHERE version >= 5201|empty| +5202|2142_emotes.sql|SELECT * FROM db_version WHERE version >= 5202|empty| # 5203|2154_optional_rule_spell_procs_resists_falloff.sql # 5204|2156_optional_charm_break_rule.sql # 5205|2159_optional_defensiveproc_rules.sql -5206|2164_require_bots_bottimers.sql +# 5206|2164_require_bots_bottimers.sql # 5207|2171_optional_SpecialAttackACBonus_rule.sql # 5208|2176_optional_aa_expansion_SOF_fix.sql # 5209|2176_optional_FrenzyBonus_rule.sql -5210|2176_required_aa_updates.sql -5211|2178_required_aa_updates.sql +5210|2176_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5210|empty| +5211|2178_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5211|empty| # 5212|2183_optional_bot_xp_rule.sql # 5213|2185_optional_NPCFlurryChacne_rule # 5214|2185_optional_NPCFlurryChacne_rule.sql # 5215|2185_optional_NPCFlurryChance_rule.sql -5216|2185_required_aa_updates -5217|2185_required_aa_updates.sql +5216|2185_required_aa_updates|SELECT * FROM db_version WHERE version >= 5216|empty| +5217|2185_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5217|empty| # 5218|2188_optional_miscspelleffect_rules # 5219|2188_optional_miscspelleffect_rules.sql -5220|2188_required_aa_updates -5221|2188_required_aa_updates.sql +# 5220|2188_required_aa_updates +5221|2188_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5221|empty| # 5222|2189_optional_taunt_rules # 5223|2189_optional_taunt_rules.sql -5224|2195_required_sharedplatupdates.sql +5224|2195_required_sharedplatupdates.sql|SELECT * FROM db_version WHERE version >= 5224|empty| # 5225|2208_optional_aa_stacking_rule.sql # 5226|2208_optional_EnableSoulAbrasionAA.sql -5227|2208_required_aa_updates.sql +5227|2208_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5227|empty| # 5228|2209_optional_additive_bonus_rule.sql -5229|2213_loot_changes.sql -5230|2214_faction_list_mod.sql -5231|2215_required_aa_updates.sql +5229|2213_loot_changes.sql|SELECT * FROM db_version WHERE version >= 5229|empty| +5230|2214_faction_list_mod.sql|SHOW TABLES LIKE 'faction_list_mod'|empty| +5231|2215_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5231|empty| # 5232|2243_optional_char_max_level_rule.sql -5233|2260_probability.sql -5234|2262_required_pet_discipline_update.sql -5235|2264_required_aa_updates.sql -5236|2268_QueryServ.sql -5237|2268_required_updates.sql +# 5233|2260_probability.sql +5234|2262_required_pet_discipline_update.sql|SELECT * FROM db_version WHERE version >= 5234|empty| +5235|2264_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5235|empty| +# 5236|2268_QueryServ.sql +5237|2268_required_updates.sql|SELECT * FROM db_version WHERE version >= 5237|empty| # 5238|2274_optional_rule_iplimitdisconnectall.sql # 5239|2278_optional_rule_targetableswarmpet.sql # 5240|2280_optional_rule_targetableswarmpet-rename.sql -5241|2283_required_npc_changes.sql -5242|2299_required_inspectmessage_fields.sql +5241|2283_required_npc_changes.sql|SHOW COLUMNS FROM `npc_types` LIKE 'spellscale'|empty| +5242|2299_required_inspectmessage_fields.sql|SELECT * FROM db_version WHERE version >= 5242|empty| # 5243|2300_optional_loot_changes.sql -5244|2304_QueryServ.sql -5245|2340_required_maxbuffslotspet.sql -5246|2361_QueryServ.sql -5247|2361_required_qs_rule_values.sql -5248|2370_required_aa_updates.sql -5249|2376_required_aa_updates.sql -# 5250|2380_optional_merc_data.sql -# 5251|2380_optional_merc_merchant_npctypes_update.sql -# 5252|2380_optional_merc_rules.sql -5253|2383_required_group_ismerc.sql +# 5244|2304_QueryServ.sql +# 5245|2340_required_maxbuffslotspet.sql +# 5246|2361_QueryServ.sql +# 5247|2361_required_qs_rule_values.sql +5248|2370_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5248|empty| +5249|2376_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5249|empty| +5250|2380_optional_merc_data.sql|SELECT * FROM db_version WHERE version >= 5250|empty| +5251|2380_optional_merc_merchant_npctypes_update.sql|SELECT * FROM db_version WHERE version >= 5251|empty| +5252|2380_optional_merc_rules.sql|SELECT * FROM db_version WHERE version >= 5252|empty| +5253|2383_required_group_ismerc.sql|SELECT * FROM db_version WHERE version >= 5253|empty| # 5254|2428_optional_levelbasedexpmods.sql # 5255|2448_optional_stun_proc_aggro_rule.sql -5256|2471_required_aa_updates.sql -5257|2482_required_start_zones.sql -5258|2504_required_aa_updates.sql +5256|2471_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5256|empty| +5257|2482_required_start_zones.sql|SELECT * FROM db_version WHERE version >= 5257|empty| +5258|2504_required_aa_updates.sql|SELECT * FROM db_version WHERE version >= 5258|empty| 8000|mercs.sql|SHOW TABLES LIKE 'merc_stats'|empty| 9000|2013_02_18_Merc_Rules_and_Tables.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Mercs:ResurrectRadius%'|empty| 9001|2013_02_25_Impr_HT_LT.sql|SHOW TABLES LIKE 'merc_inventory'|empty| @@ -340,7 +340,7 @@ 9084|2015_06_30_runspeed_adjustments.sql|SELECT `runspeed` FROM `npc_types` WHERE `runspeed` > 3|not_empty| 9085|2015_07_01_Marquee_Rule.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Character:MarqueeHPUpdates%'|empty| 9086|2015_07_02_aa_rework.sql|SHOW TABLES LIKE 'aa_ranks'|empty| -9087|2015_09_25_inventory_snapshots.sql|SHOW TABLES LIKE 'inventory_snapshots'|empty| +9087|2015_09_25_inventory_snapshots.sql|SHOW COLUMNS FROM `character_data` LIKE 'e_last_invsnapshot'|empty| 9088|2015_11_01_perl_event_export_settings.sql|SHOW TABLES LIKE 'perl_event_export_settings'|empty| 9089|2015_11_02_ai_idle_no_spell_recast_default_changes.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Spells:AI_IdleNoSpellMinRecast%' AND `rule_value` = '500'|not_empty| 9090|2015_12_01_spell_scribe_restriction_rule.sql|SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Character:RestrictSpellScribing'|empty| From bda39c4f77352fcabff91e55c3b277179cb23ab3 Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Mon, 28 Dec 2015 20:07:59 -0500 Subject: [PATCH 22/40] Revert accidental change to SetPseudoRoot in lua_mob.cpp. --- zone/lua_mob.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 46b6b4a9b..0d45c6c36 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -2303,7 +2303,7 @@ luabind::scope lua_register_mob() { .def("BuffFadeBySlot", (void(Lua_Mob::*)(int,bool))&Lua_Mob::BuffFadeBySlot) .def("CanBuffStack", (int(Lua_Mob::*)(int,int))&Lua_Mob::CanBuffStack) .def("CanBuffStack", (int(Lua_Mob::*)(int,int,bool))&Lua_Mob::CanBuffStack) - .def("SetPseudoRoot", (void(Lua_Mob::*)(void))&Lua_Mob::SetPseudoRoot) + .def("SetPseudoRoot", (void(Lua_Mob::*)(bool))&Lua_Mob::SetPseudoRoot) .def("SeeInvisible", (uint8(Lua_Mob::*)(void))&Lua_Mob::SeeInvisible) .def("SeeInvisibleUndead", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeInvisibleUndead) .def("SeeHide", (bool(Lua_Mob::*)(void))&Lua_Mob::SeeHide) From ce71b6d9f07ac1ee0f4e3a86156389c8617a01e5 Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Mon, 28 Dec 2015 22:04:19 -0500 Subject: [PATCH 23/40] Added GetInstanceTimer() to Perl and Lua. --- changelog.txt | 3 +++ zone/embparser_api.cpp | 12 ++++++++++++ zone/lua_general.cpp | 4 ++++ zone/questmgr.cpp | 8 ++++++++ zone/questmgr.h | 1 + 5 files changed, 28 insertions(+) diff --git a/changelog.txt b/changelog.txt index 74b6ab113..abb096988 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 12/28/2015 == +Kinglykrab: Added GetInstanceTimer() to Perl and Lua. + == 12/21/2015 == Natedog: Updated item table fields and added a few missing fields for evolving items -DO NOT implement Heirloom items till the inventory code is fixed to allow placing NO DROP diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 126e8169d..8ac6d61bf 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -2919,6 +2919,17 @@ XS(XS__UpdateInstanceTimer) { XSRETURN_EMPTY; } +XS(XS__GetInstanceTimer); +XS(XS__GetInstanceTimer) { + dXSARGS; + if (items != 0) + Perl_croak(aTHX_ "Usage: GetInstanceTimer()"); + + uint32 timer = quest_manager.GetInstanceTimer(); + + XSRETURN_UV(timer); +} + XS(XS__GetInstanceID); XS(XS__GetInstanceID) { dXSARGS; @@ -3650,6 +3661,7 @@ EXTERN_C XS(boot_quest) newXS(strcpy(buf, "CreateInstance"), XS__CreateInstance, file); newXS(strcpy(buf, "DestroyInstance"), XS__DestroyInstance, file); newXS(strcpy(buf, "UpdateInstanceTimer"), XS__UpdateInstanceTimer, file); + newXS(strcpy(buf, "GetInstanceTimer"), XS__GetInstanceTimer, file); newXS(strcpy(buf, "FlagInstanceByGroupLeader"), XS__FlagInstanceByGroupLeader, file); newXS(strcpy(buf, "FlagInstanceByRaidLeader"), XS__FlagInstanceByRaidLeader, file); newXS(strcpy(buf, "FlyMode"), XS__FlyMode, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index bed0fd7bc..0af3ed365 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -808,6 +808,10 @@ void lua_update_instance_timer(uint16 instance_id, uint32 new_duration) { quest_manager.UpdateInstanceTimer(instance_id, new_duration); } +uint32 lua_get_instance_timer() { + return quest_manager.GetInstanceTimer(); +} + int lua_get_instance_id(const char *zone, uint32 version) { return quest_manager.GetInstanceID(zone, version); } diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index cb70f93d3..d1cf87dad 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2598,6 +2598,14 @@ void QuestManager::UpdateInstanceTimer(uint16 instance_id, uint32 new_duration) } } +uint32 QuestManager::GetInstanceTimer() { + if (zone && zone->GetInstanceID() > 0 && zone->GetInstanceTimer()) { + uint32 ttime = zone->GetInstanceTimer()->GetRemainingTime(); + return ttime; + } + return 0; +} + uint16 QuestManager::GetInstanceID(const char *zone, int16 version) { QuestManagerCurrentQuestVars(); diff --git a/zone/questmgr.h b/zone/questmgr.h index cd1c4a303..276fcfeca 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -218,6 +218,7 @@ public: uint32 MerchantCountItem(uint32 NPCid, uint32 itemid); uint16 CreateInstance(const char *zone, int16 version, uint32 duration); void UpdateInstanceTimer(uint16 instance_id, uint32 new_duration); + uint32 GetInstanceTimer(); void DestroyInstance(uint16 instance_id); uint16 GetInstanceID(const char *zone, int16 version); void AssignToInstance(uint16 instance_id); From ff876bd558519b44e4cd46858ef9e848b5832044 Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Tue, 29 Dec 2015 00:55:17 -0500 Subject: [PATCH 24/40] Added GetInstanceTimerByID(instance_id) to Perl and Lua. --- changelog.txt | 2 ++ zone/embparser_api.cpp | 13 +++++++++++++ zone/lua_general.cpp | 4 ++++ zone/questmgr.cpp | 15 +++++++++++++++ zone/questmgr.h | 1 + 5 files changed, 35 insertions(+) diff --git a/changelog.txt b/changelog.txt index abb096988..77ccc5f49 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- == 12/28/2015 == Kinglykrab: Added GetInstanceTimer() to Perl and Lua. + - Added GetInstanceTimerByID(instance_id) to Perl and Lua. + - Note: If you do not provide an instance id in the method it defaults to instance id 0 and returns 0 for time remaining. == 12/21/2015 == Natedog: Updated item table fields and added a few missing fields for evolving items diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 8ac6d61bf..c7d4b1a1f 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -2930,6 +2930,18 @@ XS(XS__GetInstanceTimer) { XSRETURN_UV(timer); } +XS(XS__GetInstanceTimerByID); +XS(XS__GetInstanceTimerByID) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: GetInstanceTimerByID(instance_id)"); + + uint16 instance_id = (uint16)SvUV(ST(0)); + uint32 timer = quest_manager.GetInstanceTimerByID(instance_id); + + XSRETURN_UV(timer); +} + XS(XS__GetInstanceID); XS(XS__GetInstanceID) { dXSARGS; @@ -3662,6 +3674,7 @@ EXTERN_C XS(boot_quest) newXS(strcpy(buf, "DestroyInstance"), XS__DestroyInstance, file); newXS(strcpy(buf, "UpdateInstanceTimer"), XS__UpdateInstanceTimer, file); newXS(strcpy(buf, "GetInstanceTimer"), XS__GetInstanceTimer, file); + newXS(strcpy(buf, "GetInstanceTimerByID"), XS__GetInstanceTimerByID, file); newXS(strcpy(buf, "FlagInstanceByGroupLeader"), XS__FlagInstanceByGroupLeader, file); newXS(strcpy(buf, "FlagInstanceByRaidLeader"), XS__FlagInstanceByRaidLeader, file); newXS(strcpy(buf, "FlyMode"), XS__FlyMode, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 0af3ed365..f731263a1 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -812,6 +812,10 @@ uint32 lua_get_instance_timer() { return quest_manager.GetInstanceTimer(); } +uint32 lua_get_instance_timer_by_id(uint16 instance_id) { + return quest_manager.GetInstanceTimerByID(instance_id); +} + int lua_get_instance_id(const char *zone, uint32 version) { return quest_manager.GetInstanceID(zone, version); } diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index d1cf87dad..690d70bf0 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -2606,6 +2606,21 @@ uint32 QuestManager::GetInstanceTimer() { return 0; } +uint32 QuestManager::GetInstanceTimerByID(uint16 instance_id) { + if (instance_id == 0) + return 0; + + std::string query = StringFormat("SELECT ((start_time + duration) - UNIX_TIMESTAMP()) AS `remaining` FROM `instance_list` WHERE `id` = %lu", (unsigned long)instance_id); + auto results = database.QueryDatabase(query); + + if (results.Success()) { + auto row = results.begin(); + uint32 timer = atoi(row[0]); + return timer; + } + return 0; +} + uint16 QuestManager::GetInstanceID(const char *zone, int16 version) { QuestManagerCurrentQuestVars(); diff --git a/zone/questmgr.h b/zone/questmgr.h index 276fcfeca..2b8963b70 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -219,6 +219,7 @@ public: uint16 CreateInstance(const char *zone, int16 version, uint32 duration); void UpdateInstanceTimer(uint16 instance_id, uint32 new_duration); uint32 GetInstanceTimer(); + uint32 GetInstanceTimerByID(uint16 instance_id = 0); void DestroyInstance(uint16 instance_id); uint16 GetInstanceID(const char *zone, int16 version); void AssignToInstance(uint16 instance_id); From 34e1dc9829e652a4eab973aaf651587ea911c5bb Mon Sep 17 00:00:00 2001 From: Kinglykrab Date: Tue, 29 Dec 2015 02:28:31 -0500 Subject: [PATCH 25/40] Added UpdateZoneHeader(type, value) to Perl and Lua. --- changelog.txt | 2 ++ zone/embparser_api.cpp | 14 ++++++++ zone/lua_general.cpp | 4 +++ zone/questmgr.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++ zone/questmgr.h | 1 + 5 files changed, 93 insertions(+) diff --git a/changelog.txt b/changelog.txt index 77ccc5f49..e31f3598a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) Kinglykrab: Added GetInstanceTimer() to Perl and Lua. - Added GetInstanceTimerByID(instance_id) to Perl and Lua. - Note: If you do not provide an instance id in the method it defaults to instance id 0 and returns 0 for time remaining. + - Added UpdateZoneHeader(type, value) to Perl and Lua. + - Note: UpdateZoneHeader allows you to manipulate fog color, fog density, and many other zone header settings on the fly in Perl and Lua. == 12/21/2015 == Natedog: Updated item table fields and added a few missing fields for evolving items diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index c7d4b1a1f..bf43e43a1 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3637,6 +3637,19 @@ XS(XS__debug) XSRETURN_EMPTY; } +XS(XS__UpdateZoneHeader); +XS(XS__UpdateZoneHeader) { + dXSARGS; + if (items != 2) + Perl_croak(aTHX_ "Usage: UpdateZoneHeader(type, value)"); + + std::string type = (std::string)SvPV_nolen(ST(0)); + std::string value = (std::string)SvPV_nolen(ST(1)); + quest_manager.UpdateZoneHeader(type, value); + + XSRETURN_EMPTY; +} + /* This is the callback perl will look for to setup the @@ -3866,6 +3879,7 @@ EXTERN_C XS(boot_quest) newXS(strcpy(buf, "untraindiscs"), XS__untraindiscs, file); newXS(strcpy(buf, "updatespawntimer"), XS__UpdateSpawnTimer, file); newXS(strcpy(buf, "updatetaskactivity"), XS__updatetaskactivity, file); + newXS(strcpy(buf, "UpdateZoneHeader"), XS__UpdateZoneHeader, file); newXS(strcpy(buf, "varlink"), XS__varlink, file); newXS(strcpy(buf, "voicetell"), XS__voicetell, file); newXS(strcpy(buf, "we"), XS__we, file); diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index f731263a1..ff0e357fb 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -1304,6 +1304,10 @@ void lua_debug(std::string message, int level) { Log.Out(static_cast(level), Logs::QuestDebug, message); } +void lua_update_zone_header(std::string type, std::string value) { + quest_manager.UpdateZoneHeader(type, value); +} + #define LuaCreateNPCParse(name, c_type, default_value) do { \ cur = table[#name]; \ if(luabind::type(cur) != LUA_TNIL) { \ diff --git a/zone/questmgr.cpp b/zone/questmgr.cpp index 690d70bf0..86b8cb7d9 100644 --- a/zone/questmgr.cpp +++ b/zone/questmgr.cpp @@ -3093,3 +3093,75 @@ std::string QuestManager::GetEncounter() const { return ""; } + +void QuestManager::UpdateZoneHeader(std::string type, std::string value) { + if (strcasecmp(type.c_str(), "ztype") == 0) + zone->newzone_data.ztype = atoi(value.c_str()); + else if (strcasecmp(type.c_str(), "fog_red") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.fog_red[i] = atoi(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "fog_green") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.fog_green[i] = atoi(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "fog_blue") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.fog_blue[i] = atoi(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "fog_minclip") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.fog_minclip[i] = atof(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "fog_maxclip") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.fog_maxclip[i] = atof(value.c_str()); + } + } + else if (strcasecmp(type.c_str(), "gravity") == 0) + zone->newzone_data.gravity = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "time_type") == 0) + zone->newzone_data.time_type = atoi(value.c_str()); + else if (strcasecmp(type.c_str(), "rain_chance") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.rain_chance[i] = atoi(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "rain_duration") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.rain_duration[i] = atoi(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "snow_chance") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.snow_chance[i] = atoi(value.c_str()); + } + } else if (strcasecmp(type.c_str(), "snow_duration") == 0) { + for (int i = 0; i < 4; i++) { + zone->newzone_data.snow_duration[i] = atoi(value.c_str()); + } + } + else if (strcasecmp(type.c_str(), "sky") == 0) + zone->newzone_data.sky = atoi(value.c_str()); + else if (strcasecmp(type.c_str(), "safe_x") == 0) + zone->newzone_data.safe_x = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "safe_y") == 0) + zone->newzone_data.safe_y = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "safe_z") == 0) + zone->newzone_data.safe_z = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "max_z") == 0) + zone->newzone_data.max_z = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "underworld") == 0) + zone->newzone_data.underworld = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "minclip") == 0) + zone->newzone_data.minclip = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "maxclip") == 0) + zone->newzone_data.maxclip = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "fog_density") == 0) + zone->newzone_data.fog_density = atof(value.c_str()); + else if (strcasecmp(type.c_str(), "suspendbuffs") == 0) + zone->newzone_data.SuspendBuffs = atoi(value.c_str()); + + EQApplicationPacket* outapp = new EQApplicationPacket(OP_NewZone, sizeof(NewZone_Struct)); + memcpy(outapp->pBuffer, &zone->newzone_data, outapp->size); + entity_list.QueueClients(0, outapp); + safe_delete(outapp); +} \ No newline at end of file diff --git a/zone/questmgr.h b/zone/questmgr.h index 2b8963b70..a4cc2a38b 100644 --- a/zone/questmgr.h +++ b/zone/questmgr.h @@ -218,6 +218,7 @@ public: uint32 MerchantCountItem(uint32 NPCid, uint32 itemid); uint16 CreateInstance(const char *zone, int16 version, uint32 duration); void UpdateInstanceTimer(uint16 instance_id, uint32 new_duration); + void UpdateZoneHeader(std::string type, std::string value); uint32 GetInstanceTimer(); uint32 GetInstanceTimerByID(uint16 instance_id = 0); void DestroyInstance(uint16 instance_id); From 9757c380177cfcc9b52c88d8b9924c9bb35729fb Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 29 Dec 2015 01:30:20 -0600 Subject: [PATCH 26/40] Adjust manifest [skip ci] --- utils/sql/db_update_manifest.txt | 2 +- zone/npc.cpp | 40 ++++++++++++++++++++++++++++++++ zone/npc.h | 1 + zone/spawn2.cpp | 2 ++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index f62c89fbb..0a73d4560 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -32,7 +32,7 @@ # 5032|285_optional_bot_spell_update.sql # 5033|292_augslots.sql|SELECT * FROM db_version WHERE version >= 5033|empty| 5034|294_merchant_logging.sql|SHOW COLUMNS FROM `eventlog` LIKE 'event_nid'|empty| -5035|304_faction_list.sql|SHOW COLUMNS FROM `faction_list` LIKE 'mod_c16'|empty| +5035|304_faction_list.sql|SELECT * FROM db_version WHERE version >= 5035|empty| 5036|326_aas.sql|SELECT * FROM db_version WHERE version > 5035|empty| # 5037|328_bot_management.sql # 5038|328_optional_bot_management.sql diff --git a/zone/npc.cpp b/zone/npc.cpp index fd7f6880c..9d39f4ad3 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -843,6 +843,46 @@ bool NPC::DatabaseCastAccepted(int spell_id) { return false; } +bool NPC::SpawnZoneController(){ + + NPCType* npc_type = new NPCType; + memset(npc_type, 0, sizeof(NPCType)); + + strncpy(npc_type->name, "zone_controller", 60); + npc_type->cur_hp = 2000000000; + npc_type->max_hp = 2000000000; + npc_type->race = 240; + npc_type->gender = 0; + npc_type->class_ = 1; + npc_type->deity = 1; + npc_type->level = 200; + npc_type->npc_id = 0; + npc_type->loottable_id = 0; + npc_type->texture = 3; + npc_type->runspeed = 0; + npc_type->d_melee_texture1 = 0; + npc_type->d_melee_texture2 = 0; + npc_type->merchanttype = 0; + npc_type->bodytype = 11; + + npc_type->prim_melee_type = 28; + npc_type->sec_melee_type = 28; + + strcpy(npc_type->special_abilities, "12,1^13,1^14,1^15,1^16,1^17,1^19,1^22,1^24,1^25,1^28,1^31,1^35,1^39,1^42,1"); + + glm::vec4 point; + point.x = 5000; + point.y = 5000; + point.z = -5000; + + NPC* npc = new NPC(npc_type, nullptr, point, FlyMode3); + npc->GiveNPCTypeData(npc_type); + + entity_list.AddNPC(npc); + + return true; +} + NPC* NPC::SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client) { if(spawncommand == 0 || spawncommand[0] == 0) { return 0; diff --git a/zone/npc.h b/zone/npc.h index 32afd0afd..327918c19 100644 --- a/zone/npc.h +++ b/zone/npc.h @@ -96,6 +96,7 @@ class NPC : public Mob { public: static NPC* SpawnNPC(const char* spawncommand, const glm::vec4& position, Client* client = nullptr); + static bool SpawnZoneController(); static int8 GetAILevel(bool iForceReRead = false); NPC(const NPCType* data, Spawn2* respawn, const glm::vec4& position, int iflymode, bool IsCorpse = false); diff --git a/zone/spawn2.cpp b/zone/spawn2.cpp index f2461ed4b..7cb3b1f3c 100644 --- a/zone/spawn2.cpp +++ b/zone/spawn2.cpp @@ -549,6 +549,8 @@ bool ZoneDatabase::PopulateZoneSpawnList(uint32 zoneid, LinkedList &spa spawn2_list.Insert(new_spawn); } + NPC::SpawnZoneController(); + return true; } From 3af9aeeeafadc332185bc97fce105def14e06ba0 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 29 Dec 2015 01:45:53 -0600 Subject: [PATCH 27/40] Adjust manifest [skip ci] --- utils/sql/db_update_manifest.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 0a73d4560..84ac931a7 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -340,7 +340,7 @@ 9084|2015_06_30_runspeed_adjustments.sql|SELECT `runspeed` FROM `npc_types` WHERE `runspeed` > 3|not_empty| 9085|2015_07_01_Marquee_Rule.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Character:MarqueeHPUpdates%'|empty| 9086|2015_07_02_aa_rework.sql|SHOW TABLES LIKE 'aa_ranks'|empty| -9087|2015_09_25_inventory_snapshots.sql|SHOW COLUMNS FROM `character_data` LIKE 'e_last_invsnapshot'|empty| +9087|2015_09_25_inventory_snapshots.sql|SHOW TABLES LIKE 'inventory_snapshots'|empty| 9088|2015_11_01_perl_event_export_settings.sql|SHOW TABLES LIKE 'perl_event_export_settings'|empty| 9089|2015_11_02_ai_idle_no_spell_recast_default_changes.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Spells:AI_IdleNoSpellMinRecast%' AND `rule_value` = '500'|not_empty| 9090|2015_12_01_spell_scribe_restriction_rule.sql|SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Character:RestrictSpellScribing'|empty| From f25246e1a02069f5a2e8674950fb540d2231da89 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 29 Dec 2015 01:47:21 -0600 Subject: [PATCH 28/40] Adjust eqemu_update.pl [skip ci] --- utils/scripts/eqemu_update.pl | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/utils/scripts/eqemu_update.pl b/utils/scripts/eqemu_update.pl index 8fd3af540..fa05c3f54 100644 --- a/utils/scripts/eqemu_update.pl +++ b/utils/scripts/eqemu_update.pl @@ -107,6 +107,33 @@ if($path eq ""){ exit; } +if($ARGV[0] eq "install_peq_db"){ + + $db_name = "peq"; + if($ARGV[1]){ + $db_name = $ARGV[1]; + } + + $db = $db_name; + + #::: Database Routines + print "MariaDB :: Creating Database '" . $db_name . "'\n"; + print `"$path" --host $host --user $user --password="$pass" -N -B -e "DROP DATABASE IF EXISTS $db_name;"`; + print `"$path" --host $host --user $user --password="$pass" -N -B -e "CREATE DATABASE $db_name"`; + if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); } + if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); } + $bin_db_ver = trim($db_version[1]); + check_db_version_table(); + $local_db_ver = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1")); + fetch_peq_db_full(); + print "\nFetching Latest Database Updates...\n"; + main_db_management(); + print "\nApplying Latest Database Updates...\n"; + main_db_management(); + + print get_mysql_result("UPDATE `launcher` SET `dynamics` = 30 WHERE `name` = 'zone'"); +} + if($ARGV[0] eq "installer"){ print "Running EQEmu Server installer routines...\n"; mkdir('logs'); @@ -1316,8 +1343,14 @@ sub run_database_check{ @total_updates = (); + #::: This is where we set checkpoints for where a database might be so we don't check so far back in the manifest... + $revision_check = 1000; + if(get_mysql_result("SHOW TABLES LIKE 'character_data'") ne ""){ + $revision_check = 9000; + } + #::: Iterate through Manifest backwards from binary version down to local version... - for($i = $bin_db_ver; $i > 1000; $i--){ + for($i = $bin_db_ver; $i > $revision_check; $i--){ if(!defined($m_d{$i}[0])){ next; } $file_name = trim($m_d{$i}[1]); From 8425607460da820f7727267c6a94f75c5774a60b Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 29 Dec 2015 04:08:10 -0600 Subject: [PATCH 29/40] Implemented standardized zone controller scripts (Rule Zone, UseZoneController) Defaulted to true - When a zone boots, it will spawn an invisible npc by the name of zone_controller - Lua and Perl scripts can be represented with this npc as zone_controller.pl/lua - This NPC's ID is ruled be define ZONE_CONTROLLER_NPC_ID 10 - Two EVENT's uniquely are handled with this NPC/controller (They only work with the zone_controller NPC) - EVENT_SPAWN_ZONE :: All NPC spawns in the zone trigger the controller and pass the following variables: $spawned_entity_id $spawned_npc_id - EVENT_DEATH_ZONE :: All NPC deaths in the zone trigger the controller event and pass the following variables: $killer_id $killer_damage $killer_spell $killer_skill $killed_npc_id --- changelog.txt | 16 ++++++ common/features.h | 2 + common/ruletypes.h | 1 + common/version.h | 2 +- utils/sql/db_update_manifest.txt | 1 + .../required/2015_12_29_quest_zone_events.sql | 4 ++ zone/attack.cpp | 54 +++++++++++-------- zone/embparser.cpp | 19 ++++++- zone/entity.cpp | 10 ++++ zone/event_codes.h | 3 +- zone/lua_general.cpp | 4 +- zone/lua_parser.cpp | 4 +- zone/npc.cpp | 11 +++- zone/quest_parser_collection.cpp | 11 +++- 14 files changed, 111 insertions(+), 31 deletions(-) create mode 100644 utils/sql/git/required/2015_12_29_quest_zone_events.sql diff --git a/changelog.txt b/changelog.txt index e31f3598a..f8ca4c917 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,21 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 12/29/2015 == +Akkadius: Implemented standardized zone controller scripts (Rule Zone, UseZoneController) Defaulted to true + - When a zone boots, it will spawn an invisible npc by the name of zone_controller + - Lua and Perl scripts can be represented with this npc as zone_controller.pl/lua + - This NPC's ID is ruled be define ZONE_CONTROLLER_NPC_ID 10 + - Two EVENT's uniquely are handled with this NPC/controller (They only work with the zone_controller NPC) + - EVENT_SPAWN_ZONE :: All NPC spawns in the zone trigger the controller and pass the following variables: + $spawned_entity_id + $spawned_npc_id + - EVENT_DEATH_ZONE :: All NPC deaths in the zone trigger the controller event and pass the following variables: + $killer_id + $killer_damage + $killer_spell + $killer_skill + $killed_npc_id + == 12/28/2015 == Kinglykrab: Added GetInstanceTimer() to Perl and Lua. - Added GetInstanceTimerByID(instance_id) to Perl and Lua. diff --git a/common/features.h b/common/features.h index 2ede4b4be..8115efd82 100644 --- a/common/features.h +++ b/common/features.h @@ -233,6 +233,8 @@ enum { //some random constants #define GROUP_EXP_PER_POINT 1000 #define RAID_EXP_PER_POINT 2000 +#define ZONE_CONTROLLER_NPC_ID 10 + //Some hard coded statuses from commands and other places: enum { minStatusToBeGM = 40, diff --git a/common/ruletypes.h b/common/ruletypes.h index 83ef9aff3..41e4e22a4 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -233,6 +233,7 @@ RULE_BOOL(Zone, LevelBasedEXPMods, false) // Allows you to use the level_exp_mod RULE_INT(Zone, WeatherTimer, 600) // Weather timer when no duration is available RULE_BOOL(Zone, EnableLoggedOffReplenishments, true) RULE_INT(Zone, MinOfflineTimeToReplenishments, 21600) // 21600 seconds is 6 Hours +RULE_BOOL(Zone, UseZoneController, true) // Enables the ability to use persistent quest based zone controllers (zone_controller.pl/lua) RULE_CATEGORY_END() RULE_CATEGORY(Map) diff --git a/common/version.h b/common/version.h index b2dd26212..00a999add 100644 --- a/common/version.h +++ b/common/version.h @@ -30,7 +30,7 @@ Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt */ -#define CURRENT_BINARY_DATABASE_VERSION 9093 +#define CURRENT_BINARY_DATABASE_VERSION 9094 #ifdef BOTS #define CURRENT_BINARY_BOTS_DATABASE_VERSION 9000 #else diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index 84ac931a7..86f7ebe7c 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -347,6 +347,7 @@ 9091|2015_12_07_command_settings.sql|SHOW TABLES LIKE 'command_settings'|empty| 9092|2015_12_17_eqtime.sql|SHOW TABLES LIKE 'eqtime'|empty| 9093|2015_12_21_items_updates_evoitem.sql|SHOW COLUMNS FROM `items` LIKE 'evoitem'|empty| +9094|2015_12_29_quest_zone_events.sql|SELECT * FROM perl_event_export_settings WHERE event_description = 'EVENT_SPAWN_ZONE'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2015_12_29_quest_zone_events.sql b/utils/sql/git/required/2015_12_29_quest_zone_events.sql new file mode 100644 index 000000000..783cb477e --- /dev/null +++ b/utils/sql/git/required/2015_12_29_quest_zone_events.sql @@ -0,0 +1,4 @@ +INSERT INTO `perl_event_export_settings` (`event_id`, `event_description`, `export_qglobals`, `export_mob`, `export_zone`, `export_item`, `export_event`) VALUES (81, 'EVENT_SPAWN_ZONE', 0, 0, 0, 0, 1); +INSERT INTO `perl_event_export_settings` (`event_id`, `event_description`, `export_qglobals`, `export_mob`, `export_zone`, `export_item`, `export_event`) VALUES (82, 'EVENT_DEATH_ZONE', 0, 0, 0, 0, 1); +ALTER TABLE `rule_values` +MODIFY COLUMN `notes` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL AFTER `rule_value`; \ No newline at end of file diff --git a/zone/attack.cpp b/zone/attack.cpp index 6b2534a43..5f7b19e80 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -2009,15 +2009,15 @@ void NPC::Damage(Mob* other, int32 damage, uint16 spell_id, SkillUseTypes attack } } -bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack_skill) { - Log.Out(Logs::Detail, Logs::Combat, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", killerMob->GetName(), damage, spell, attack_skill); +bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, SkillUseTypes attack_skill) { + Log.Out(Logs::Detail, Logs::Combat, "Fatal blow dealt by %s with %d damage, spell %d, skill %d", killer_mob->GetName(), damage, spell, attack_skill); Mob *oos = nullptr; - if(killerMob) { - oos = killerMob->GetOwnerOrSelf(); + if(killer_mob) { + oos = killer_mob->GetOwnerOrSelf(); char buffer[48] = { 0 }; - snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast(attack_skill)); + snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast(attack_skill)); if(parse->EventNPC(EVENT_DEATH, this, oos, buffer, 0) != 0) { if(GetHP() < 0) { @@ -2026,15 +2026,15 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack return false; } - if(killerMob && killerMob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) { + if(killer_mob && killer_mob->IsClient() && (spell != SPELL_UNKNOWN) && damage > 0) { char val1[20]={0}; entity_list.MessageClose_StringID(this, false, 100, MT_NonMelee, HIT_NON_MELEE, - killerMob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1)); + killer_mob->GetCleanName(), GetCleanName(), ConvertArray(damage, val1)); } } else { char buffer[48] = { 0 }; - snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast(attack_skill)); + snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast(attack_skill)); if(parse->EventNPC(EVENT_DEATH, this, nullptr, buffer, 0) != 0) { if(GetHP() < 0) { @@ -2072,21 +2072,21 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack EQApplicationPacket* app= new EQApplicationPacket(OP_Death,sizeof(Death_Struct)); Death_Struct* d = (Death_Struct*)app->pBuffer; d->spawn_id = GetID(); - d->killer_id = killerMob ? killerMob->GetID() : 0; + d->killer_id = killer_mob ? killer_mob->GetID() : 0; d->bindzoneid = 0; d->spell_id = spell == SPELL_UNKNOWN ? 0xffffffff : spell; d->attack_skill = SkillDamageTypes[attack_skill]; d->damage = damage; app->priority = 6; - entity_list.QueueClients(killerMob, app, false); + entity_list.QueueClients(killer_mob, app, false); if(respawn2) { respawn2->DeathReset(1); } - if (killerMob) { + if (killer_mob) { if(GetClass() != LDON_TREASURE) - hate_list.AddEntToHateList(killerMob, damage); + hate_list.AddEntToHateList(killer_mob, damage); } safe_delete(app); @@ -2148,8 +2148,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack { if(!IsLdonTreasure && MerchantType == 0) { kr->SplitExp((finalxp), this); - if(killerMob && (kr->IsRaidMember(killerMob->GetName()) || kr->IsRaidMember(killerMob->GetUltimateOwner()->GetName()))) - killerMob->TrySpellOnKill(killed_level,spell); + if(killer_mob && (kr->IsRaidMember(killer_mob->GetName()) || kr->IsRaidMember(killer_mob->GetUltimateOwner()->GetName()))) + killer_mob->TrySpellOnKill(killed_level,spell); } /* Send the EVENT_KILLED_MERIT event for all raid members */ for (int i = 0; i < MAX_RAID_MEMBERS; i++) { @@ -2193,8 +2193,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack { if(!IsLdonTreasure && MerchantType == 0) { kg->SplitExp((finalxp), this); - if(killerMob && (kg->IsGroupMember(killerMob->GetName()) || kg->IsGroupMember(killerMob->GetUltimateOwner()->GetName()))) - killerMob->TrySpellOnKill(killed_level,spell); + if(killer_mob && (kg->IsGroupMember(killer_mob->GetName()) || kg->IsGroupMember(killer_mob->GetUltimateOwner()->GetName()))) + killer_mob->TrySpellOnKill(killed_level,spell); } /* Send the EVENT_KILLED_MERIT event and update kill tasks * for all group members */ @@ -2244,8 +2244,8 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack if(!GetOwner() || (GetOwner() && !GetOwner()->IsClient())) { give_exp_client->AddEXP((finalxp), conlevel); - if(killerMob && (killerMob->GetID() == give_exp_client->GetID() || killerMob->GetUltimateOwner()->GetID() == give_exp_client->GetID())) - killerMob->TrySpellOnKill(killed_level,spell); + if(killer_mob && (killer_mob->GetID() == give_exp_client->GetID() || killer_mob->GetUltimateOwner()->GetID() == give_exp_client->GetID())) + killer_mob->TrySpellOnKill(killed_level,spell); } } } @@ -2393,20 +2393,30 @@ bool NPC::Death(Mob* killerMob, int32 damage, uint16 spell, SkillUseTypes attack uint16 emoteid = oos->GetEmoteID(); if(emoteid != 0) oos->CastToNPC()->DoNPCEmote(KILLEDNPC, emoteid); - killerMob->TrySpellOnKill(killed_level, spell); + killer_mob->TrySpellOnKill(killed_level, spell); } } WipeHateList(); p_depop = true; - if(killerMob && killerMob->GetTarget() == this) //we can kill things without having them targeted - killerMob->SetTarget(nullptr); //via AE effects and such.. + if(killer_mob && killer_mob->GetTarget() == this) //we can kill things without having them targeted + killer_mob->SetTarget(nullptr); //via AE effects and such.. entity_list.UpdateFindableNPCState(this, true); char buffer[48] = { 0 }; - snprintf(buffer, 47, "%d %d %d %d", killerMob ? killerMob->GetID() : 0, damage, spell, static_cast(attack_skill)); + snprintf(buffer, 47, "%d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast(attack_skill)); parse->EventNPC(EVENT_DEATH_COMPLETE, this, oos, buffer, 0); + + /* Zone controller process EVENT_DEATH_ZONE (Death events) */ + if (RuleB(Zone, UseZoneController)) { + if (entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID) && this->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID){ + char data_pass[100] = { 0 }; + snprintf(data_pass, 99, "%d %d %d %d %d", killer_mob ? killer_mob->GetID() : 0, damage, spell, static_cast(attack_skill), this->GetNPCTypeID()); + parse->EventNPC(EVENT_DEATH_ZONE, entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID)->CastToNPC(), nullptr, data_pass, 0); + } + } + return true; } diff --git a/zone/embparser.cpp b/zone/embparser.cpp index 617d17d2e..12501b089 100644 --- a/zone/embparser.cpp +++ b/zone/embparser.cpp @@ -114,7 +114,9 @@ const char *QuestEventSubroutines[_LargestEventID] = { "EVENT_RESPAWN", "EVENT_DEATH_COMPLETE", "EVENT_UNHANDLED_OPCODE", - "EVENT_TICK" + "EVENT_TICK", + "EVENT_SPAWN_ZONE", + "EVENT_DEATH_ZONE", }; PerlembParser::PerlembParser() : perl(nullptr) { @@ -1424,6 +1426,21 @@ void PerlembParser::ExportEventVariables(std::string &package_name, QuestEventID ExportVar(package_name.c_str(), "slotid", extradata); break; } + case EVENT_SPAWN_ZONE: { + Seperator sep(data); + ExportVar(package_name.c_str(), "spawned_entity_id", sep.arg[0]); + ExportVar(package_name.c_str(), "spawned_npc_id", sep.arg[1]); + break; + } + case EVENT_DEATH_ZONE: { + Seperator sep(data); + ExportVar(package_name.c_str(), "killer_id", sep.arg[0]); + ExportVar(package_name.c_str(), "killer_damage", sep.arg[1]); + ExportVar(package_name.c_str(), "killer_spell", sep.arg[2]); + ExportVar(package_name.c_str(), "killer_skill", sep.arg[3]); + ExportVar(package_name.c_str(), "killed_npc_id", sep.arg[4]); + break; + } default: { break; diff --git a/zone/entity.cpp b/zone/entity.cpp index 23848f73e..92fefb2ec 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -641,8 +641,18 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue) { npc->SetID(GetFreeID()); npc->SetMerchantProbability((uint8) zone->random.Int(0, 99)); + parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0); + /* Zone controller process EVENT_SPAWN_ZONE */ + if (RuleB(Zone, UseZoneController)) { + if (entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID) && npc->GetNPCTypeID() != ZONE_CONTROLLER_NPC_ID){ + char data_pass[100] = { 0 }; + snprintf(data_pass, 99, "%d %d", npc->GetID(), npc->GetNPCTypeID()); + parse->EventNPC(EVENT_SPAWN_ZONE, entity_list.GetNPCByNPCTypeID(ZONE_CONTROLLER_NPC_ID)->CastToNPC(), nullptr, data_pass, 0); + } + } + uint16 emoteid = npc->GetEmoteID(); if (emoteid != 0) npc->DoNPCEmote(ONSPAWN, emoteid); diff --git a/zone/event_codes.h b/zone/event_codes.h index 7850b0eb3..1b0e18505 100644 --- a/zone/event_codes.h +++ b/zone/event_codes.h @@ -83,7 +83,8 @@ typedef enum { EVENT_DEATH_COMPLETE, EVENT_UNHANDLED_OPCODE, EVENT_TICK, - + EVENT_SPAWN_ZONE, + EVENT_DEATH_ZONE, _LargestEventID } QuestEventID; diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index ff0e357fb..a42efd592 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -1731,7 +1731,9 @@ luabind::scope lua_register_events() { luabind::value("leave_area", static_cast(EVENT_LEAVE_AREA)), luabind::value("death_complete", static_cast(EVENT_DEATH_COMPLETE)), luabind::value("unhandled_opcode", static_cast(EVENT_UNHANDLED_OPCODE)), - luabind::value("tick", static_cast(EVENT_TICK)) + luabind::value("tick", static_cast(EVENT_TICK)), + luabind::value("spawn_zone", static_cast(EVENT_SPAWN_ZONE)), + luabind::value("death_zone", static_cast(EVENT_DEATH_ZONE)) ]; } diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index 462752705..aeb1e3228 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -117,7 +117,9 @@ const char *LuaEvents[_LargestEventID] = { "event_respawn", "event_death_complete", "event_unhandled_opcode", - "event_tick" + "event_tick", + "event_spawn_zone", + "event_death_zone" }; extern Zone *zone; diff --git a/zone/npc.cpp b/zone/npc.cpp index 9d39f4ad3..8f09d3f40 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -845,18 +845,22 @@ bool NPC::DatabaseCastAccepted(int spell_id) { bool NPC::SpawnZoneController(){ + if (!RuleB(Zone, UseZoneController)) + return false; + NPCType* npc_type = new NPCType; memset(npc_type, 0, sizeof(NPCType)); strncpy(npc_type->name, "zone_controller", 60); npc_type->cur_hp = 2000000000; npc_type->max_hp = 2000000000; + npc_type->hp_regen = 100000000; npc_type->race = 240; - npc_type->gender = 0; + npc_type->gender = 2; npc_type->class_ = 1; npc_type->deity = 1; npc_type->level = 200; - npc_type->npc_id = 0; + npc_type->npc_id = ZONE_CONTROLLER_NPC_ID; npc_type->loottable_id = 0; npc_type->texture = 3; npc_type->runspeed = 0; @@ -868,6 +872,9 @@ bool NPC::SpawnZoneController(){ npc_type->prim_melee_type = 28; npc_type->sec_melee_type = 28; + npc_type->findable = 0; + npc_type->trackable = 0; + strcpy(npc_type->special_abilities, "12,1^13,1^14,1^15,1^16,1^17,1^19,1^22,1^24,1^25,1^28,1^31,1^35,1^39,1^42,1"); glm::vec4 point; diff --git a/zone/quest_parser_collection.cpp b/zone/quest_parser_collection.cpp index 1f4f99c0e..4d2a2960a 100644 --- a/zone/quest_parser_collection.cpp +++ b/zone/quest_parser_collection.cpp @@ -484,10 +484,17 @@ QuestInterface *QuestParserCollection::GetQIByNPCQuest(uint32 npcid, std::string //second look for /quests/zone/npcname.ext (precedence) const NPCType *npc_type = database.LoadNPCTypesData(npcid); - if(!npc_type) { + if (!npc_type && npcid != ZONE_CONTROLLER_NPC_ID) { return nullptr; } - std::string npc_name = npc_type->name; + + std::string npc_name; + if (npcid == ZONE_CONTROLLER_NPC_ID){ + npc_name = "zone_controller"; + } + else{ + npc_name = npc_type->name; + } int sz = static_cast(npc_name.length()); for(int i = 0; i < sz; ++i) { if(npc_name[i] == '`') { From 8b35ae9921de54de5c0567d4e30d5710b6de7b00 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 29 Dec 2015 05:21:27 -0600 Subject: [PATCH 30/40] Change how rules are loaded and inherit values - When a custom ruleset is loaded, it will always first look for a value present in the ruleset id for that zone, when it is not present, it will load from the default ruleset instead of immediately falling back to the source value. This is to eliminate the excessive amount of duplicate entries in the rule_values tables --- common/rulesys.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/common/rulesys.cpp b/common/rulesys.cpp index 13e342fe5..670c090b5 100644 --- a/common/rulesys.cpp +++ b/common/rulesys.cpp @@ -236,7 +236,7 @@ void RuleManager::SaveRules(Database *database, const char *ruleset_name) { } bool RuleManager::LoadRules(Database *database, const char *ruleset_name) { - + int ruleset_id = GetRulesetID(database, ruleset_name); if (ruleset_id < 0) { Log.Out(Logs::Detail, Logs::Rules, "Failed to find ruleset '%s' for load operation. Canceling.", ruleset_name); @@ -248,6 +248,26 @@ bool RuleManager::LoadRules(Database *database, const char *ruleset_name) { m_activeRuleset = ruleset_id; m_activeName = ruleset_name; + /* Load default ruleset values first if we're loading something other than default */ + if (strcasecmp(ruleset_name, "default") != 0){ + std::string default_ruleset_name = "default"; + int default_ruleset_id = GetRulesetID(database, default_ruleset_name.c_str()); + if (default_ruleset_id < 0) { + Log.Out(Logs::Detail, Logs::Rules, "Failed to find default ruleset '%s' for load operation. Canceling.", default_ruleset_name.c_str()); + return(false); + } + Log.Out(Logs::Detail, Logs::Rules, "Loading rule set '%s' (%d)", default_ruleset_name, default_ruleset_id); + + std::string query = StringFormat("SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id = %d", default_ruleset_id); + auto results = database->QueryDatabase(query); + if (!results.Success()) + return false; + + for (auto row = results.begin(); row != results.end(); ++row) + if (!SetRule(row[0], row[1], nullptr, false)) + Log.Out(Logs::Detail, Logs::Rules, "Unable to interpret rule record for %s", row[0]); + } + std::string query = StringFormat("SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id=%d", ruleset_id); auto results = database->QueryDatabase(query); if (!results.Success()) From 2bf6c2788ee79a59b1cd5e180493c28c6d15e25c Mon Sep 17 00:00:00 2001 From: Akkadius Date: Tue, 29 Dec 2015 05:40:34 -0600 Subject: [PATCH 31/40] eqemu_update.pl - Implement 14) [Remove Duplicate Rule Values] :: Looks for redundant rule_values entries and removes them --- common/database_conversions.cpp | 2 +- utils/scripts/eqemu_update.pl | 36 ++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/common/database_conversions.cpp b/common/database_conversions.cpp index fa7c57a12..c7428c07e 100644 --- a/common/database_conversions.cpp +++ b/common/database_conversions.cpp @@ -493,7 +493,7 @@ bool Database::CheckDatabaseConversions() { /* Check for a new version of this script, the arg passed would have to be higher than the copy they have downloaded locally and they will re fetch */ - system("perl eqemu_update.pl V 13"); + system("perl eqemu_update.pl V 14"); /* Run Automatic Database Upgrade Script */ system("perl eqemu_update.pl ran_from_world"); diff --git a/utils/scripts/eqemu_update.pl b/utils/scripts/eqemu_update.pl index fa05c3f54..c2fc92818 100644 --- a/utils/scripts/eqemu_update.pl +++ b/utils/scripts/eqemu_update.pl @@ -23,7 +23,7 @@ if($Config{osname}=~/linux/i){ $OS = "Linux"; } if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; } #::: If current version is less than what world is reporting, then download a new one... -$current_version = 13; +$current_version = 14; if($ARGV[0] eq "V"){ if($ARGV[1] > $current_version){ @@ -134,6 +134,11 @@ if($ARGV[0] eq "install_peq_db"){ print get_mysql_result("UPDATE `launcher` SET `dynamics` = 30 WHERE `name` = 'zone'"); } +if($ARGV[0] eq "remove_duplicate_rules"){ + remove_duplicate_rule_values(); + exit; +} + if($ARGV[0] eq "installer"){ print "Running EQEmu Server installer routines...\n"; mkdir('logs'); @@ -278,6 +283,7 @@ sub show_menu_prompt { 11 => \&fetch_latest_windows_binaries, 12 => \&fetch_server_dlls, 13 => \&do_windows_login_server_setup, + 14 => \&remove_duplicate_rule_values, 19 => \&do_bots_db_schema_drop, 20 => \&do_update_self, 0 => \&script_exit, @@ -355,6 +361,7 @@ return < Date: Tue, 29 Dec 2015 06:06:12 -0600 Subject: [PATCH 32/40] Fix Travis --- common/rulesys.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/rulesys.cpp b/common/rulesys.cpp index 670c090b5..56289b09a 100644 --- a/common/rulesys.cpp +++ b/common/rulesys.cpp @@ -256,7 +256,7 @@ bool RuleManager::LoadRules(Database *database, const char *ruleset_name) { Log.Out(Logs::Detail, Logs::Rules, "Failed to find default ruleset '%s' for load operation. Canceling.", default_ruleset_name.c_str()); return(false); } - Log.Out(Logs::Detail, Logs::Rules, "Loading rule set '%s' (%d)", default_ruleset_name, default_ruleset_id); + Log.Out(Logs::Detail, Logs::Rules, "Loading rule set '%s' (%d)", default_ruleset_name.c_str(), default_ruleset_id); std::string query = StringFormat("SELECT rule_name, rule_value FROM rule_values WHERE ruleset_id = %d", default_ruleset_id); auto results = database->QueryDatabase(query); From 7045581fdca8de2c7852682d19a09fc8f86e4eff Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 29 Dec 2015 15:22:09 -0500 Subject: [PATCH 33/40] Cap big bags to 10 slots for now --- common/shareddb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/shareddb.cpp b/common/shareddb.cpp index fe4ad1b5d..402d77e76 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -954,7 +954,7 @@ void SharedDatabase::LoadItems(void *data, uint32 size, int32 items, uint32 max_ item.LDoNPrice = (uint32)atoul(row[ItemField::ldonprice]); item.LDoNSold = (uint32)atoul(row[ItemField::ldonsold]); item.BagType = (uint8)atoi(row[ItemField::bagtype]); - item.BagSlots = (uint8)atoi(row[ItemField::bagslots]); + item.BagSlots = (uint8)std::min(atoi(row[ItemField::bagslots]), 10); // FIXME: remove when big bags supported item.BagSize = (uint8)atoi(row[ItemField::bagsize]); item.BagWR = (uint8)atoi(row[ItemField::bagwr]); item.Book = (uint8)atoi(row[ItemField::book]); From 2d375eb5659f6f12d34ddce97e612060ded54a2a Mon Sep 17 00:00:00 2001 From: af4t Date: Wed, 30 Dec 2015 02:17:09 -0500 Subject: [PATCH 34/40] MSVC 2015 wants #included for std::min. If any other compilers require the same, feel free to alter the #if test. --- common/shareddb.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 402d77e76..0890f3fcf 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -1,6 +1,10 @@ #include #include +#if defined(_MSC_VER) && _MSC_VER >= 1900 + #include +#endif + #include "classes.h" #include "eq_packet_structs.h" #include "eqemu_exception.h" From fe61abc3cdfc011945598dd17932aecb335bbe1a Mon Sep 17 00:00:00 2001 From: Tim DeLong Date: Wed, 30 Dec 2015 11:42:49 -0500 Subject: [PATCH 35/40] * AddReport's who and against strings were not being escaped properly. --- common/database.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/database.cpp b/common/database.cpp index b8ea025ae..dcc3fbe77 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -1564,7 +1564,7 @@ void Database::AddReport(std::string who, std::string against, std::string lines char *escape_str = new char[lines.size()*2+1]; DoEscapeString(escape_str, lines.c_str(), lines.size()); - std::string query = StringFormat("INSERT INTO reports (name, reported, reported_text) VALUES('%s', '%s', '%s')", who.c_str(), against.c_str(), escape_str); + std::string query = StringFormat("INSERT INTO reports (name, reported, reported_text) VALUES('%s', '%s', '%s')", EscapeString(who).c_str(), EscapeString(against).c_str(), escape_str); QueryDatabase(query); safe_delete_array(escape_str); } From aad1396c73be1e9dddb93dda9742e89ecf6219ea Mon Sep 17 00:00:00 2001 From: Tim DeLong Date: Wed, 30 Dec 2015 23:30:52 -0500 Subject: [PATCH 36/40] * CheckNameFilter was enforcing minimum surname length of 3 instead of 4. * Minor refactoring of CheckNameFilter to eliminate redundant code. --- common/database.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/common/database.cpp b/common/database.cpp index dcc3fbe77..932aa4229 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -1183,21 +1183,16 @@ bool Database::CheckNameFilter(const char* name, bool surname) { std::string str_name = name; - if(surname) + // the minimum 4 is enforced by the client too + if (!name || strlen(name) < 4) { - // the minimum 4 is enforced by the client too - if(!name || strlen(name) < 3) - { - return false; - } + return false; } - else + + // Given name length is enforced by the client too + if (!surname && strlen(name) > 15) { - // the minimum 4 is enforced by the client too - if(!name || strlen(name) < 4 || strlen(name) > 15) - { - return false; - } + return false; } for (size_t i = 0; i < str_name.size(); i++) From 3996a70037a7bfd2c7818af16f95a8442d056d7f Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Thu, 31 Dec 2015 01:08:04 -0500 Subject: [PATCH 37/40] 2h DB should match client closer I think the dev missed something when making it pretty for the forums This should match it better. --- zone/attack.cpp | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/zone/attack.cpp b/zone/attack.cpp index 5f7b19e80..ad5be845a 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -2703,16 +2703,38 @@ uint8 Mob::GetWeaponDamageBonus(const Item_Struct *weapon, bool offhand) } } else { // 2h damage bonus + int damage_bonus = 1 + (level - 28) / 3; if (delay <= 27) - return 1 + ((level - 28) / 3); - else if (delay < 40) - return 1 + ((level - 28) / 3) + ((level - 30) / 5); - else if (delay < 43) - return 2 + ((level - 28) / 3) + ((level - 30) / 5) + ((delay - 40) / 3); - else if (delay < 45) - return 3 + ((level - 28) / 3) + ((level - 30) / 5) + ((delay - 40) / 3); - else if (delay >= 45) - return 4 + ((level - 28) / 3) + ((level - 30) / 5) + ((delay - 40) / 3); + return damage_bonus + 1; + // Client isn't reflecting what the dev quoted, this matches better + if (level > 29) { + int level_bonus = (level - 30) / 5 + 1; + if (level > 50) { + level_bonus++; + int level_bonus2 = level - 50; + if (level > 67) + level_bonus2 += 5; + else if (level > 59) + level_bonus2 += 4; + else if (level > 58) + level_bonus2 += 3; + else if (level > 56) + level_bonus2 += 2; + else if (level > 54) + level_bonus2++; + level_bonus += level_bonus2 * delay / 40; + } + damage_bonus += level_bonus; + } + if (delay >= 40) { + int delay_bonus = (delay - 40) / 3 + 1; + if (delay >= 45) + delay_bonus += 2; + else if (delay >= 43) + delay_bonus++; + damage_bonus += delay_bonus; + } + return damage_bonus; } } From 9ea9ed259077abbdab528fab4ab1ed6e07a43d4d Mon Sep 17 00:00:00 2001 From: Akkadius Date: Thu, 31 Dec 2015 21:45:42 -0600 Subject: [PATCH 38/40] Update eqemu_update.pl to include loginserver setup in normal installer routine [skip ci] --- utils/scripts/eqemu_update.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/utils/scripts/eqemu_update.pl b/utils/scripts/eqemu_update.pl index c2fc92818..6d9be10a2 100644 --- a/utils/scripts/eqemu_update.pl +++ b/utils/scripts/eqemu_update.pl @@ -184,6 +184,7 @@ if($ARGV[0] eq "installer"){ if($OS eq "Windows"){ check_windows_firewall_rules(); + do_windows_login_server_setup(); } exit; } From 647fbcd6b64a60cb80f77fada1b5d1f12defc61d Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 1 Jan 2016 01:11:32 -0600 Subject: [PATCH 39/40] Adjust an incredibly spammy log message --- world/net.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/world/net.cpp b/world/net.cpp index 86f794af0..cd84c530a 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -482,7 +482,7 @@ int main(int argc, char** argv) { if (!database.SaveTime(tod.minute, tod.hour, tod.day, tod.month, tod.year)) Log.Out(Logs::General, Logs::World_Server, "Failed to save eqtime."); else - Log.Out(Logs::General, Logs::World_Server, "EQTime successfully saved."); + Log.Out(Logs::Detail, Logs::World_Server, "EQTime successfully saved."); } //check for timeouts in other threads From dfdfb18a7ecfed952d3a21a564063b1d22b3536d Mon Sep 17 00:00:00 2001 From: Akkadius Date: Fri, 1 Jan 2016 01:12:49 -0600 Subject: [PATCH 40/40] VS2012 fix --- common/shareddb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 0890f3fcf..f82d54fad 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -1,7 +1,7 @@ #include #include -#if defined(_MSC_VER) && _MSC_VER >= 1900 +#if defined(_MSC_VER) && _MSC_VER >= 1800 #include #endif