From 9e5bfabf9195771d20d8ee5943a80d68fd3a8eab Mon Sep 17 00:00:00 2001 From: Shendare Date: Mon, 9 Nov 2015 22:43:25 -0800 Subject: [PATCH 01/50] 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/50] 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/50] 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 bc77439d117a20bc587aafc33aab69f58d1b16e2 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Wed, 16 Dec 2015 09:05:27 -0500 Subject: [PATCH 04/50] When binding someone else's wounds, the code tried to send a bind would response to client with a type of 2. The intent (based on comments was to get the client to display a "stand still" message on the receiving client. That reply message was not generating that message, but if the client you were binding was also binding his own wounds, it would cause your target to stand up, interrupting his bind. I replaced this client reply with a simple, directed client message. It all seems to work fine now. --- zone/client.cpp | 9 ++------- zone/string_ids.h | 1 + 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index f65a30350..4b81cf250 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -2577,12 +2577,7 @@ bool Client::BindWound(Mob* bindmob, bool start, bool fail){ else { // send bindmob "stand still" if(!bindmob->IsAIControlled() && bindmob != this ) { - bind_out->type = 2; // ? - //bind_out->type = 3; // ? - bind_out->to = GetID(); // ? - bindmob->CastToClient()->QueuePacket(outapp); - bind_out->type = 0; - bind_out->to = 0; + bindmob->CastToClient()->Message_StringID(clientMessageYellow, YOU_ARE_BEING_BANDAGED); } else if (bindmob->IsAIControlled() && bindmob != this ){ ; // Tell IPC to stand still? @@ -2668,7 +2663,7 @@ bool Client::BindWound(Mob* bindmob, bool start, bool fail){ else { //I dont have the real, live Message(15, "You cannot bind wounds above %d%% hitpoints.", max_percent); - if(bindmob->IsClient()) + if(bindmob != this && bindmob->IsClient()) bindmob->CastToClient()->Message(15, "You cannot have your wounds bound above %d%% hitpoints.", max_percent); // Too many hp message goes here. } diff --git a/zone/string_ids.h b/zone/string_ids.h index e3b943744..be05b1eb2 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -27,6 +27,7 @@ #define GAIN_XP 138 //You gain experience!! #define GAIN_GROUPXP 139 //You gain party experience!! #define BOW_DOUBLE_DAMAGE 143 //Your bow shot did double dmg. +#define YOU_ARE_BEING_BANDAGED 147 //Someone is bandaging you. #define FORAGE_GRUBS 150 //You have scrounged up some fishing grubs. #define FORAGE_WATER 151 //You have scrounged up some water. #define FORAGE_FOOD 152 //You have scrounged up some food. From 07ab58483dbaabd7728236e9b7975a660706567f Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Wed, 16 Dec 2015 09:16:27 -0500 Subject: [PATCH 05/50] Updated changelog --- changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.txt b/changelog.txt index adc272817..f708219e8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 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. + == 12/14/2015 == Kinglykrab: Added IsBlind() and IsFeared() functionality to Perl and Lua. - Note: Both methods are Mob methods and may be used on NPCs or PCs. 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] 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/50] * 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/50] * 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/50] 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/50] 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/50] 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/50] 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 From 11f3e3024509389eddea247337c9ba9632d0c7f2 Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Sat, 2 Jan 2016 09:16:13 -0500 Subject: [PATCH 41/50] Fixed a ton of buffs when using an EE item (SendBuffDurationPacket). --- zone/spells.cpp | 54 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/zone/spells.cpp b/zone/spells.cpp index 18de9a444..4224e9ac3 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -5310,6 +5310,7 @@ void Client::SendBuffDurationPacket(Buffs_Struct &buff) EQApplicationPacket* outapp; outapp = new EQApplicationPacket(OP_Buff, sizeof(SpellBuffFade_Struct)); SpellBuffFade_Struct* sbf = (SpellBuffFade_Struct*) outapp->pBuffer; + int index; sbf->entityid = GetID(); sbf->slot = 2; @@ -5317,6 +5318,19 @@ void Client::SendBuffDurationPacket(Buffs_Struct &buff) sbf->slotid = 0; sbf->level = buff.casterlevel > 0 ? buff.casterlevel : GetLevel(); + // We really don't know what to send as sbf->effect. + // The code used to send level (and still does for cases we don't know) + // + // The fixes below address known issues with sending level in this field. + // Typically, when the packet is sent, or when the user + // next does something on the UI that causes an update (like opening a + // pack), the stats updated by the spell in question get corrupted. + // + // The values were determined by trial and error. I could not find a + // pattern or find a field in spells_new that would work. + + sbf->effect=sbf->level; + if (IsEffectInSpell(buff.spellid, SE_TotalHP)) { // If any of the lower 6 bits are set, the GUI changes MAX_HP AGAIN. @@ -5327,25 +5341,45 @@ void Client::SendBuffDurationPacket(Buffs_Struct &buff) else if (IsEffectInSpell(buff.spellid, SE_CurrentHP)) { // This is mostly a problem when we try and update duration on a - // dot or a hp->mana conversion. Zero cancels the effect, any - // other value has the GUI doing that value at the same time server - // is doing theirs. This makes the two match. - int index = GetSpellEffectIndex(buff.spellid, SE_CurrentHP); + // dot or a hp->mana conversion. Zero cancels the effect + // Sending teh actual change again seems to work. + index = GetSpellEffectIndex(buff.spellid, SE_CurrentHP); sbf->effect = abs(spells[buff.spellid].base[index]); } else if (IsEffectInSpell(buff.spellid, SE_SeeInvis)) { - // Wish I knew what this sbf->effect field was trying to tell - // the client. 10 seems to not break SeeInvis spells. Level, + // 10 seems to not break SeeInvis spells. Level, // which is what the old client sends breaks the client at at // least level 9, maybe more. sbf->effect = 10; } - else + else if (IsEffectInSpell(buff.spellid, SE_ArmorClass) || + IsEffectInSpell(buff.spellid, SE_ResistFire) || + IsEffectInSpell(buff.spellid, SE_ResistCold) || + IsEffectInSpell(buff.spellid, SE_ResistPoison) || + IsEffectInSpell(buff.spellid, SE_ResistDisease) || + IsEffectInSpell(buff.spellid, SE_ResistMagic) || + IsEffectInSpell(buff.spellid, SE_STR) || + IsEffectInSpell(buff.spellid, SE_STA) || + IsEffectInSpell(buff.spellid, SE_DEX) || + IsEffectInSpell(buff.spellid, SE_WIS) || + IsEffectInSpell(buff.spellid, SE_INT) || + IsEffectInSpell(buff.spellid, SE_AGI)) { - // Default to what old code did until we find a better fix for - // other spell lines. - sbf->effect=sbf->level; + // This seems to work. Previosly stats got corrupted when sending + // level. + sbf->effect = 46; + } + else if (IsEffectInSpell(buff.spellid, SE_CHA)) + { + index = GetSpellEffectIndex(buff.spellid, SE_CHA); + sbf->effect = abs(spells[buff.spellid].base[index]); + // Only use this valie if its not a spacer. + if (sbf->effect != 0) + { + // Same as other stats, need this to prevent a double update. + sbf->effect = 46; + } } sbf->bufffade = 0; From f754f06bec96e1710f85141c2deeb13e5214b8ae Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Sat, 2 Jan 2016 17:26:59 -0500 Subject: [PATCH 42/50] Added runspeed to mystats window. --- zone/client.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zone/client.cpp b/zone/client.cpp index 4b81cf250..ccf561306 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -6803,7 +6803,8 @@ void Client::SendStatsWindow(Client* client, bool use_window) /* AC */ indP << "AC: " << CalcAC() << "
" << /* AC2 */ indP << "- Mit: " << GetACMit() << " | Avoid: " << GetACAvoid() << " | Spell: " << spellbonuses.AC << " | Shield: " << shield_ac << "
" << /* Haste */ indP << "Haste: " << GetHaste() << "
" << - /* Haste2 */ indP << " - Item: " << itembonuses.haste << " + Spell: " << (spellbonuses.haste + spellbonuses.hastetype2) << " (Cap: " << RuleI(Character, HasteCap) << ") | Over: " << (spellbonuses.hastetype3 + ExtraHaste) << "

" << + /* Haste2 */ indP << " - Item: " << itembonuses.haste << " + Spell: " << (spellbonuses.haste + spellbonuses.hastetype2) << " (Cap: " << RuleI(Character, HasteCap) << ") | Over: " << (spellbonuses.hastetype3 + ExtraHaste) << "
" << + /* RunSpeed*/ indP << "Runspeed: " << GetRunspeed() << "
" << /* RegenLbl */ indL << indS << "Regen
" << indS << indP << indP << " Base | Items (Cap) " << indP << " | Spell | A.A.s | Total
" << /* Regen */ regen_string << "
" << /* Stats */ stat_field << "

" << From 05de206aceb51ebbbf9a9b2232bd7ac74e0747c0 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 3 Jan 2016 01:58:37 -0500 Subject: [PATCH 43/50] Rework quiver haste --- common/ruletypes.h | 2 +- zone/attack.cpp | 29 ++++++++++++++++------------- zone/client.cpp | 22 ++++++++++------------ zone/client.h | 2 +- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 41e4e22a4..493bb8ca6 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -450,7 +450,7 @@ RULE_REAL (Combat,TauntSkillFalloff, 0.33)//For every taunt skill point that's n RULE_BOOL (Combat,EXPFromDmgShield, false) //Determine if damage from a damage shield counts for EXP gain. RULE_INT(Combat, MonkACBonusWeight, 15) RULE_INT(Combat, ClientStunLevel, 55) //This is the level where client kicks and bashes can stun the target -RULE_INT(Combat, QuiverWRHasteDiv, 3) //Weight Reduction is divided by this to get haste contribution for quivers +RULE_INT(Combat, QuiverHasteCap, 1000) //Quiver haste cap 1000 on live for a while, currently 700 on live RULE_BOOL(Combat, UseArcheryBonusRoll, false) //Make the 51+ archery bonus require an actual roll RULE_INT(Combat, ArcheryBonusChance, 50) RULE_INT(Combat, BerserkerFrenzyStart, 35) diff --git a/zone/attack.cpp b/zone/attack.cpp index ad5be845a..accb7beff 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -4649,28 +4649,31 @@ void Client::SetAttackTimer() int hhe = itembonuses.HundredHands + spellbonuses.HundredHands; int speed = 0; - int delay = 36; - float quiver_haste = 0.0f; + int delay = 3600; //if we have no weapon.. if (ItemToUse == nullptr) { //above checks ensure ranged weapons do not fall into here // Work out if we're a monk if (GetClass() == MONK || GetClass() == BEASTLORD) - delay = GetMonkHandToHandDelay(); + delay = 100 * GetMonkHandToHandDelay(); } else { //we have a weapon, use its delay - delay = ItemToUse->Delay; - if (ItemToUse->ItemType == ItemTypeBow || ItemToUse->ItemType == ItemTypeLargeThrowing) - quiver_haste = GetQuiverHaste(); + delay = 100 * ItemToUse->Delay; + } + + speed = delay / haste_mod; + + if (ItemToUse && ItemToUse->ItemType == ItemTypeBow) { + // Live actually had a bug here where they would return the non-modified attack speed + // rather than the cap ... + speed = std::max(speed - GetQuiverHaste(speed), RuleI(Combat, QuiverHasteCap)); + } else { + if (RuleB(Spells, Jun182014HundredHandsRevamp)) + speed = static_cast(speed + ((hhe / 1000.0f) * speed)); + else + speed = static_cast(speed + ((hhe / 100.0f) * delay)); } - if (RuleB(Spells, Jun182014HundredHandsRevamp)) - speed = static_cast(((delay / haste_mod) + ((hhe / 1000.0f) * (delay / haste_mod))) * 100); - else - speed = static_cast(((delay / haste_mod) + ((hhe / 100.0f) * delay)) * 100); - // this is probably wrong - if (quiver_haste > 0) - speed *= quiver_haste; TimerToUse->SetAtTrigger(std::max(RuleI(Combat, MinHastedDelay), speed), true, true); } } diff --git a/zone/client.cpp b/zone/client.cpp index ccf561306..ceedf19d7 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8356,21 +8356,19 @@ void Client::ShowNumHits() return; } -float Client::GetQuiverHaste() +int Client::GetQuiverHaste(int delay) { - float quiver_haste = 0; + const ItemInst *pi = nullptr; for (int r = EmuConstants::GENERAL_BEGIN; r <= EmuConstants::GENERAL_END; r++) { - const ItemInst *pi = GetInv().GetItem(r); - if (!pi) - continue; - if (pi->IsType(ItemClassContainer) && pi->GetItem()->BagType == BagTypeQuiver) { - float temp_wr = (pi->GetItem()->BagWR / RuleI(Combat, QuiverWRHasteDiv)); - quiver_haste = std::max(temp_wr, quiver_haste); - } + pi = GetInv().GetItem(r); + if (pi && pi->IsType(ItemClassContainer) && pi->GetItem()->BagType == BagTypeQuiver && + pi->GetItem()->BagWR > 0) + break; + if (r == EmuConstants::GENERAL_END) + // we will get here if we don't find a valid quiver + return 0; } - if (quiver_haste > 0) - quiver_haste = 1.0f / (1.0f + static_cast(quiver_haste) / 100.0f); - return quiver_haste; + return (pi->GetItem()->BagWR * 0.0025f * delay) + 1; } void Client::SendColoredText(uint32 color, std::string message) diff --git a/zone/client.h b/zone/client.h index 6db22c5b0..bc2f89b87 100644 --- a/zone/client.h +++ b/zone/client.h @@ -226,7 +226,7 @@ public: virtual inline bool IsBerserk() { return berserk; } virtual int32 GetMeleeMitDmg(Mob *attacker, int32 damage, int32 minhit, float mit_rating, float atk_rating); virtual void SetAttackTimer(); - float GetQuiverHaste(); + int GetQuiverHaste(int delay); void DoAttackRounds(Mob *target, int hand, bool IsFromSpell = false); void AI_Init(); From 5bcb9f0b35750a06e41fef32a46398bb7f7f7400 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 3 Jan 2016 14:38:50 -0500 Subject: [PATCH 44/50] Fix classic h2h dmg/delay also support for revamp The revamp was implemented during SoF Set Combat:UseRevampHandToHand to true to enable --- common/ruletypes.h | 1 + zone/attack.cpp | 182 +++++++++++++++++++++++++-------------------- zone/bot.cpp | 62 ++++++++------- zone/bot.h | 2 +- zone/lua_mob.cpp | 12 +-- zone/lua_mob.h | 4 +- zone/mob.h | 4 +- zone/perl_mob.cpp | 20 ++--- 8 files changed, 161 insertions(+), 126 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index 493bb8ca6..f83ea0266 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -462,6 +462,7 @@ RULE_INT(Combat, MeleePushChance, 50) // (NPCs) chance the target will be pushed 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_BOOL(Combat, UseRevampHandToHand, false) // use h2h revamped dmg/delays I believe this was implemented during SoF RULE_CATEGORY_END() RULE_CATEGORY(NPC) diff --git a/zone/attack.cpp b/zone/attack.cpp index accb7beff..532a53686 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -846,7 +846,7 @@ int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) { } else{ if((GetClass() == MONK || GetClass() == BEASTLORD) && GetLevel() >= 30){ - dmg = GetMonkHandToHandDamage(); + dmg = GetHandToHandDamage(); } else if(GetOwner() && GetLevel() >= RuleI(Combat, PetAttackMagicLevel)){ //pets wouldn't actually use this but... @@ -868,12 +868,7 @@ int Mob::GetWeaponDamage(Mob *against, const Item_Struct *weapon_item) { dmg = dmg <= 0 ? 1 : dmg; } else{ - if(GetClass() == MONK || GetClass() == BEASTLORD){ - dmg = GetMonkHandToHandDamage(); - } - else{ - dmg = 1; - } + dmg = GetHandToHandDamage(); } } @@ -1006,7 +1001,7 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate if((GetClass() == MONK || GetClass() == BEASTLORD)) { if(MagicGloves || GetLevel() >= 30){ - dmg = GetMonkHandToHandDamage(); + dmg = GetHandToHandDamage(); if (hate) *hate += dmg; } } @@ -1041,13 +1036,8 @@ int Mob::GetWeaponDamage(Mob *against, const ItemInst *weapon_item, uint32 *hate } } else{ - if(GetClass() == MONK || GetClass() == BEASTLORD){ - dmg = GetMonkHandToHandDamage(); - if (hate) *hate += dmg; - } - else{ - dmg = 1; - } + dmg = GetHandToHandDamage(); + if (hate) *hate += dmg; } } @@ -2738,69 +2728,105 @@ uint8 Mob::GetWeaponDamageBonus(const Item_Struct *weapon, bool offhand) } } -int Mob::GetMonkHandToHandDamage(void) +int Mob::GetHandToHandDamage(void) { - // Kaiyodo - Determine a monk's fist damage. Table data from www.monkly-business.com - // saved as static array - this should speed this function up considerably - static int damage[66] = { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - 99, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11, - 12,12,12,12,12,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14, - 14,14,15,15,15,15 }; - - // Have a look to see if we have epic fists on - - if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652) - return(9); - else - { - int Level = GetLevel(); - if (Level > 65) - return(19); - else - return damage[Level]; + if (RuleB(Combat, UseRevampHandToHand)) { + // everyone uses this in the revamp! + int skill = GetSkill(SkillHandtoHand); + int epic = 0; + if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 46) + epic = 280; + if (epic > skill) + skill = epic; + return skill / 15 + 3; } + + static uint8 mnk_dmg[] = {99, + 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, // 1-10 + 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, // 11-20 + 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, // 21-30 + 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, // 31-40 + 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, // 41-50 + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, // 51-60 + 14, 14}; // 61-62 + static uint8 bst_dmg[] = {99, + 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, // 1-10 + 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, // 11-20 + 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, // 21-30 + 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, // 31-40 + 10, 11, 11, 11, 11, 11, 11, 12, 12}; // 41-49 + if (GetClass() == MONK) { + if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 50) + return 9; + if (level > 62) + return 15; + return mnk_dmg[level]; + } else if (GetClass() == BEASTLORD) { + if (level > 49) + return 13; + return bst_dmg[level]; + } + return 2; } -int Mob::GetMonkHandToHandDelay(void) +int Mob::GetHandToHandDelay(void) { - // Kaiyodo - Determine a monk's fist delay. Table data from www.monkly-business.com - // saved as static array - this should speed this function up considerably - static int delayshuman[66] = { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - 99,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, - 36,36,36,36,36,35,35,35,35,35,34,34,34,34,34,33,33,33,33,33, - 32,32,32,32,32,31,31,31,31,31,30,30,30,29,29,29,28,28,28,27, - 26,24,22,20,20,20 }; - static int delaysiksar[66] = { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - 99,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, - 36,36,36,36,36,36,36,36,36,36,35,35,35,35,35,34,34,34,34,34, - 33,33,33,33,33,32,32,32,32,32,31,31,31,30,30,30,29,29,29,28, - 27,24,22,20,20,20 }; - - // Have a look to see if we have epic fists on - if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652) - return(16); - else - { - int Level = GetLevel(); - if (GetRace() == HUMAN) - { - if (Level > 65) - return(24); - else - return delayshuman[Level]; - } - else //heko: iksar table - { - if (Level > 65) - return(25); - else - return delaysiksar[Level]; - } + if (RuleB(Combat, UseRevampHandToHand)) { + // everyone uses this in the revamp! + int skill = GetSkill(SkillHandtoHand); + int epic = 0; + int iksar = 0; + if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 46) + epic = 280; + else if (GetRace() == IKSAR) + iksar = 1; + if (epic > skill) + skill = epic; + return iksar - skill / 21 + 38; } + + int delay = 35; + static uint8 mnk_hum_delay[] = {99, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 1-10 + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 11-20 + 35, 35, 35, 35, 35, 35, 35, 34, 34, 34, // 21-30 + 34, 33, 33, 33, 33, 32, 32, 32, 32, 31, // 31-40 + 31, 31, 31, 30, 30, 30, 30, 29, 29, 29, // 41-50 + 29, 28, 28, 28, 28, 27, 27, 27, 27, 26, // 51-60 + 24, 22}; // 61-62 + static uint8 mnk_iks_delay[] = {99, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 1-10 + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 11-20 + 35, 35, 35, 35, 35, 35, 35, 35, 35, 34, // 21-30 + 34, 34, 34, 34, 34, 33, 33, 33, 33, 33, // 31-40 + 33, 32, 32, 32, 32, 32, 32, 31, 31, 31, // 41-50 + 31, 31, 31, 30, 30, 30, 30, 30, 30, 29, // 51-60 + 25, 23}; // 61-62 + static uint8 bst_delay[] = {99, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 1-10 + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, // 11-20 + 35, 35, 35, 35, 35, 35, 35, 35, 34, 34, // 21-30 + 34, 34, 34, 33, 33, 33, 33, 33, 32, 32, // 31-40 + 32, 32, 32, 31, 31, 31, 31, 31, 30, 30, // 41-50 + 30, 30, 30, 29, 29, 29, 29, 29, 28, 28, // 51-60 + 28, 28, 28, 27, 27, 27, 27, 27, 26, 26, // 61-70 + 26, 26, 26}; // 71-73 + + if (GetClass() == MONK) { + // Have a look to see if we have epic fists on + if (IsClient() && CastToClient()->GetItemIDAt(12) == 10652 && GetLevel() > 50) + return 16; + int level = GetLevel(); + if (level > 62) + return GetRace() == IKSAR ? 21 : 20; + return GetRace() == IKSAR ? mnk_iks_delay[level] : mnk_hum_delay[level]; + } else if (GetClass() == BEASTLORD) { + int level = GetLevel(); + if (level > 73) + return 25; + return bst_delay[level]; + } + return 35; } int32 Mob::ReduceDamage(int32 damage) @@ -4649,18 +4675,14 @@ void Client::SetAttackTimer() int hhe = itembonuses.HundredHands + spellbonuses.HundredHands; int speed = 0; - int delay = 3600; + int delay = 3500; //if we have no weapon.. - if (ItemToUse == nullptr) { - //above checks ensure ranged weapons do not fall into here - // Work out if we're a monk - if (GetClass() == MONK || GetClass() == BEASTLORD) - delay = 100 * GetMonkHandToHandDelay(); - } else { + if (ItemToUse == nullptr) + delay = 100 * GetHandToHandDelay(); + else //we have a weapon, use its delay delay = 100 * ItemToUse->Delay; - } speed = delay / haste_mod; diff --git a/zone/bot.cpp b/zone/bot.cpp index 9909c6d5d..01f2da41d 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -6236,31 +6236,44 @@ float Bot::GetProcChances(float ProcBonus, uint16 hand) { return ProcChance; } -int Bot::GetMonkHandToHandDamage(void) { - static int damage[66] = { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - 99, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 9, 9, 9, 9, 9,10,10,10,10,10,11,11,11,11,11, - 12,12,12,12,12,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14, - 14,14,15,15,15,15 }; +int Bot::GetHandToHandDamage(void) { + if (RuleB(Combat, UseRevampHandToHand)) { + // everyone uses this in the revamp! + int skill = GetSkill(SkillHandtoHand); + int epic = 0; + if (CastToNPC()->GetEquipment(MaterialHands) == 10652 && GetLevel() > 46) + epic = 280; + if (epic > skill) + skill = epic; + return skill / 15 + 3; + } - uint32 botWeaponId = INVALID_ID; - botWeaponId = CastToNPC()->GetEquipment(MaterialHands); - if(botWeaponId == 10652) + static uint8 mnk_dmg[] = {99, + 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, // 1-10 + 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, // 11-20 + 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, // 21-30 + 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, // 31-40 + 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, // 41-50 + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, // 51-60 + 14, 14}; // 61-62 + static uint8 bst_dmg[] = {99, + 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, // 1-10 + 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, // 11-20 + 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, // 21-30 + 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, // 31-40 + 10, 11, 11, 11, 11, 11, 11, 12, 12}; // 41-49 + if (GetClass() == MONK) { + if (CastToNPC()->GetEquipment(MaterialHands) == 10652 && GetLevel() > 50) return 9; - else { - int Level = GetLevel(); - if(Level > 65) - return 19; - else - return damage[Level]; - } - - int Level = GetLevel(); - if (Level > 65) - return 19; - else - return damage[Level]; + if (level > 62) + return 15; + return mnk_dmg[level]; + } else if (GetClass() == BEASTLORD) { + if (level > 49) + return 13; + return bst_dmg[level]; + } + return 2; } bool Bot::TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse) { @@ -7012,8 +7025,7 @@ void Bot::SetAttackTimer() { int speed = 0; int delay = 36; if (ItemToUse == nullptr) { - if ((GetClass() == MONK) || (GetClass() == BEASTLORD)) - delay = GetMonkHandToHandDelay(); + delay = GetHandToHandDelay(); } else { delay = ItemToUse->Delay; } diff --git a/zone/bot.h b/zone/bot.h index 701f96dd4..a280a2a58 100644 --- a/zone/bot.h +++ b/zone/bot.h @@ -171,7 +171,7 @@ public: uint16 BotGetSpellType(int spellslot) { return AIspells[spellslot].type; } uint16 BotGetSpellPriority(int spellslot) { return AIspells[spellslot].priority; } virtual float GetProcChances(float ProcBonus, uint16 hand); - virtual int GetMonkHandToHandDamage(void); + virtual int GetHandToHandDamage(void); virtual bool TryFinishingBlow(Mob *defender, SkillUseTypes skillinuse); virtual void DoRiposte(Mob* defender); inline virtual int32 GetATK() const { return ATK + itembonuses.ATK + spellbonuses.ATK + ((GetSTR() + GetSkill(SkillOffense)) * 9 / 10); } diff --git a/zone/lua_mob.cpp b/zone/lua_mob.cpp index 0d45c6c36..38fd80cc7 100644 --- a/zone/lua_mob.cpp +++ b/zone/lua_mob.cpp @@ -1023,14 +1023,14 @@ int Lua_Mob::GetHaste() { return self->GetHaste(); } -int Lua_Mob::GetMonkHandToHandDamage() { +int Lua_Mob::GetHandToHandDamage() { Lua_Safe_Call_Int(); - return self->GetMonkHandToHandDamage(); + return self->GetHandToHandDamage(); } -int Lua_Mob::GetMonkHandToHandDelay() { +int Lua_Mob::GetHandToHandDelay() { Lua_Safe_Call_Int(); - return self->GetMonkHandToHandDelay(); + return self->GetHandToHandDelay(); } void Lua_Mob::Mesmerize() { @@ -2165,8 +2165,8 @@ luabind::scope lua_register_mob() { .def("GetInvul", (bool(Lua_Mob::*)(void))&Lua_Mob::GetInvul) .def("SetExtraHaste", (void(Lua_Mob::*)(int))&Lua_Mob::SetExtraHaste) .def("GetHaste", (int(Lua_Mob::*)(void))&Lua_Mob::GetHaste) - .def("GetMonkHandToHandDamage", (int(Lua_Mob::*)(void))&Lua_Mob::GetMonkHandToHandDamage) - .def("GetMonkHandToHandDelay", (int(Lua_Mob::*)(void))&Lua_Mob::GetMonkHandToHandDelay) + .def("GetHandToHandDamage", (int(Lua_Mob::*)(void))&Lua_Mob::GetHandToHandDamage) + .def("GetHandToHandDelay", (int(Lua_Mob::*)(void))&Lua_Mob::GetHandToHandDelay) .def("Mesmerize", (void(Lua_Mob::*)(void))&Lua_Mob::Mesmerize) .def("IsMezzed", (bool(Lua_Mob::*)(void))&Lua_Mob::IsMezzed) .def("IsEnraged", (bool(Lua_Mob::*)(void))&Lua_Mob::IsEnraged) diff --git a/zone/lua_mob.h b/zone/lua_mob.h index 4009ae2fa..cbc34dc7d 100644 --- a/zone/lua_mob.h +++ b/zone/lua_mob.h @@ -217,8 +217,8 @@ public: bool GetInvul(); void SetExtraHaste(int haste); int GetHaste(); - int GetMonkHandToHandDamage(); - int GetMonkHandToHandDelay(); + int GetHandToHandDamage(); + int GetHandToHandDelay(); void Mesmerize(); bool IsMezzed(); bool IsEnraged(); diff --git a/zone/mob.h b/zone/mob.h index 8fc7e7f08..334c81e51 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -756,7 +756,7 @@ public: uint8 GetWeaponDamageBonus(const Item_Struct* weapon, bool offhand = false); uint16 GetDamageTable(SkillUseTypes skillinuse); - virtual int GetMonkHandToHandDamage(void); + virtual int GetHandToHandDamage(void); bool CanThisClassDoubleAttack(void) const; bool CanThisClassTripleAttack() const; @@ -766,7 +766,7 @@ public: bool CanThisClassParry(void) const; bool CanThisClassBlock(void) const; - int GetMonkHandToHandDelay(void); + int GetHandToHandDelay(void); uint32 GetClassLevelFactor(); void Mesmerize(); inline bool IsMezzed() const { return mezzed; } diff --git a/zone/perl_mob.cpp b/zone/perl_mob.cpp index 40077c2c5..8f96849df 100644 --- a/zone/perl_mob.cpp +++ b/zone/perl_mob.cpp @@ -4721,12 +4721,12 @@ XS(XS_Mob_GetHaste) XSRETURN(1); } -XS(XS_Mob_GetMonkHandToHandDamage); /* prototype to pass -Wmissing-prototypes */ -XS(XS_Mob_GetMonkHandToHandDamage) +XS(XS_Mob_GetHandToHandDamage); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_GetHandToHandDamage) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: Mob::GetMonkHandToHandDamage(THIS)"); + Perl_croak(aTHX_ "Usage: Mob::GetHandToHandDamage(THIS)"); { Mob * THIS; int RETVAL; @@ -4741,7 +4741,7 @@ XS(XS_Mob_GetMonkHandToHandDamage) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = THIS->GetMonkHandToHandDamage(); + RETVAL = THIS->GetHandToHandDamage(); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); @@ -4877,12 +4877,12 @@ XS(XS_Mob_CanThisClassParry) XSRETURN(1); } -XS(XS_Mob_GetMonkHandToHandDelay); /* prototype to pass -Wmissing-prototypes */ -XS(XS_Mob_GetMonkHandToHandDelay) +XS(XS_Mob_GetHandToHandDelay); /* prototype to pass -Wmissing-prototypes */ +XS(XS_Mob_GetHandToHandDelay) { dXSARGS; if (items != 1) - Perl_croak(aTHX_ "Usage: Mob::GetMonkHandToHandDelay(THIS)"); + Perl_croak(aTHX_ "Usage: Mob::GetHandToHandDelay(THIS)"); { Mob * THIS; int RETVAL; @@ -4897,7 +4897,7 @@ XS(XS_Mob_GetMonkHandToHandDelay) if(THIS == nullptr) Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); - RETVAL = THIS->GetMonkHandToHandDelay(); + RETVAL = THIS->GetHandToHandDelay(); XSprePUSH; PUSHi((IV)RETVAL); } XSRETURN(1); @@ -9192,13 +9192,13 @@ XS(boot_Mob) newXSproto(strcpy(buf, "GetInvul"), XS_Mob_GetInvul, file, "$"); newXSproto(strcpy(buf, "SetExtraHaste"), XS_Mob_SetExtraHaste, file, "$$"); newXSproto(strcpy(buf, "GetHaste"), XS_Mob_GetHaste, file, "$"); - newXSproto(strcpy(buf, "GetMonkHandToHandDamage"), XS_Mob_GetMonkHandToHandDamage, file, "$"); + newXSproto(strcpy(buf, "GetHandToHandDamage"), XS_Mob_GetHandToHandDamage, file, "$"); newXSproto(strcpy(buf, "CanThisClassDoubleAttack"), XS_Mob_CanThisClassDoubleAttack, file, "$"); newXSproto(strcpy(buf, "CanThisClassDualWield"), XS_Mob_CanThisClassDualWield, file, "$"); newXSproto(strcpy(buf, "CanThisClassRiposte"), XS_Mob_CanThisClassRiposte, file, "$"); newXSproto(strcpy(buf, "CanThisClassDodge"), XS_Mob_CanThisClassDodge, file, "$"); newXSproto(strcpy(buf, "CanThisClassParry"), XS_Mob_CanThisClassParry, file, "$"); - newXSproto(strcpy(buf, "GetMonkHandToHandDelay"), XS_Mob_GetMonkHandToHandDelay, file, "$"); + newXSproto(strcpy(buf, "GetHandToHandDelay"), XS_Mob_GetHandToHandDelay, file, "$"); newXSproto(strcpy(buf, "GetClassLevelFactor"), XS_Mob_GetClassLevelFactor, file, "$"); newXSproto(strcpy(buf, "Mesmerize"), XS_Mob_Mesmerize, file, "$"); newXSproto(strcpy(buf, "IsMezzed"), XS_Mob_IsMezzed, file, "$"); From 6a404a5a26686dd868e0d8c888a4607aacbd70d5 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 4 Jan 2016 11:04:56 -0600 Subject: [PATCH 45/50] Put the zone controller somewhere where people can't see it even with a terrible GlobalLoad.txt [skip ci] --- zone/npc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zone/npc.cpp b/zone/npc.cpp index 8f09d3f40..bad907936 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -878,9 +878,9 @@ bool NPC::SpawnZoneController(){ 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; + point.x = 3000; + point.y = 1000; + point.z = -500; NPC* npc = new NPC(npc_type, nullptr, point, FlyMode3); npc->GiveNPCTypeData(npc_type); From 2155a53a0d40542f5be3fc25d5cb8046bbd4b8f3 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 4 Jan 2016 11:16:26 -0600 Subject: [PATCH 46/50] Another slight adjustment [skip ci] --- zone/npc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zone/npc.cpp b/zone/npc.cpp index bad907936..11440e6e1 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -856,6 +856,7 @@ bool NPC::SpawnZoneController(){ npc_type->max_hp = 2000000000; npc_type->hp_regen = 100000000; npc_type->race = 240; + npc_type->size = 1; npc_type->gender = 2; npc_type->class_ = 1; npc_type->deity = 1; @@ -880,7 +881,7 @@ bool NPC::SpawnZoneController(){ glm::vec4 point; point.x = 3000; point.y = 1000; - point.z = -500; + point.z = 500; NPC* npc = new NPC(npc_type, nullptr, point, FlyMode3); npc->GiveNPCTypeData(npc_type); From 9174ccd6356b6b27eb81e7ea45e9c02a1f7db829 Mon Sep 17 00:00:00 2001 From: Akkadius Date: Mon, 4 Jan 2016 17:11:59 -0600 Subject: [PATCH 47/50] Another slight adjustment [skip ci] --- zone/npc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/npc.cpp b/zone/npc.cpp index 11440e6e1..22e4b4b0d 100644 --- a/zone/npc.cpp +++ b/zone/npc.cpp @@ -856,7 +856,7 @@ bool NPC::SpawnZoneController(){ npc_type->max_hp = 2000000000; npc_type->hp_regen = 100000000; npc_type->race = 240; - npc_type->size = 1; + npc_type->size = .1; npc_type->gender = 2; npc_type->class_ = 1; npc_type->deity = 1; From 20f5c42c3ec6f0f7b47ac5518ef126e830e89b76 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Tue, 5 Jan 2016 02:54:09 -0500 Subject: [PATCH 48/50] Fix 60+ resist caps --- zone/client_mods.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zone/client_mods.cpp b/zone/client_mods.cpp index 13a8130bd..06c267fd4 100644 --- a/zone/client_mods.cpp +++ b/zone/client_mods.cpp @@ -58,8 +58,8 @@ int32 Client::GetMaxResist() const { int level = GetLevel(); int32 base = 500; - if (level > 60) { - base += ((level - 60) * 5); + if (level > 65) { + base += ((level - 65) * 5); } return base; } From 17c45c8d36fcc75c7eeac210437dcd3864d0b74a Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 6 Jan 2016 13:30:50 -0500 Subject: [PATCH 49/50] Move triggered on cast things to after the spell This appears how live does it --- zone/spells.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/zone/spells.cpp b/zone/spells.cpp index 4224e9ac3..b8c3023b8 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -1268,6 +1268,14 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, } } + // we're done casting, now try to apply the spell + if( !SpellFinished(spell_id, spell_target, slot, mana_used, inventory_slot, resist_adjust) ) + { + Log.Out(Logs::Detail, Logs::Spells, "Casting of %d canceled: SpellFinished returned false.", spell_id); + InterruptSpell(); + return; + } + if(IsClient()) { CheckNumHitsRemaining(NumHit::MatchingSpells); TrySympatheticProc(target, spell_id); @@ -1277,14 +1285,6 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot, TryTriggerOnCast(spell_id, 0); - // we're done casting, now try to apply the spell - if( !SpellFinished(spell_id, spell_target, slot, mana_used, inventory_slot, resist_adjust) ) - { - Log.Out(Logs::Detail, Logs::Spells, "Casting of %d canceled: SpellFinished returned false.", spell_id); - InterruptSpell(); - return; - } - if(DeleteChargeFromSlot >= 0) CastToClient()->DeleteItemInInventory(DeleteChargeFromSlot, 1, true); From 2f129da08adde7f9e30096e6ee90439efa4632a3 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Wed, 6 Jan 2016 15:48:10 -0500 Subject: [PATCH 50/50] Add GetAttackDelay to lua's NPC API --- zone/lua_npc.cpp | 6 ++++++ zone/lua_npc.h | 1 + 2 files changed, 7 insertions(+) diff --git a/zone/lua_npc.cpp b/zone/lua_npc.cpp index f7a8ad99c..6d6c69a62 100644 --- a/zone/lua_npc.cpp +++ b/zone/lua_npc.cpp @@ -428,6 +428,11 @@ float Lua_NPC::GetAttackSpeed() { return self->GetAttackSpeed(); } +int Lua_NPC::GetAttackDelay() { + Lua_Safe_Call_Int(); + return self->GetAttackDelay(); +} + int Lua_NPC::GetAccuracyRating() { Lua_Safe_Call_Int(); return self->GetAccuracyRating(); @@ -550,6 +555,7 @@ luabind::scope lua_register_npc() { .def("GetSpellFocusHeal", (void(Lua_NPC::*)(int))&Lua_NPC::GetSpellFocusHeal) .def("GetSlowMitigation", (int(Lua_NPC::*)(void))&Lua_NPC::GetSlowMitigation) .def("GetAttackSpeed", (float(Lua_NPC::*)(void))&Lua_NPC::GetAttackSpeed) + .def("GetAttackDelay", (int(Lua_NPC::*)(void))&Lua_NPC::GetAttackDelay) .def("GetAccuracyRating", (int(Lua_NPC::*)(void))&Lua_NPC::GetAccuracyRating) .def("GetSpawnKillCount", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnKillCount) .def("GetScore", (int(Lua_NPC::*)(void))&Lua_NPC::GetScore) diff --git a/zone/lua_npc.h b/zone/lua_npc.h index 2b201f323..f5bb4719d 100644 --- a/zone/lua_npc.h +++ b/zone/lua_npc.h @@ -111,6 +111,7 @@ public: int GetSpellFocusHeal(); float GetSlowMitigation(); float GetAttackSpeed(); + int GetAttackDelay(); int GetAccuracyRating(); int GetSpawnKillCount(); int GetScore();