• This is a read only backup of the old Emudevs forum. If you want to have anything removed, please message me on Discord: KittyKaev

TrinityCore-Multi Reforging for trinitycore 2016

jimteck

Emulation Addict
Code:
#include "ScriptPCH.h"
struct accepted_stat_format {uint32 stat_type; char* stat_name; int32 base_stat_change; };

// ########################################################################################
//  Reforging config
// ########################################################################################
static const uint32 tokenEntry      = 65717;    // token entry
static const uint8 maxTokenAmount   = 3;        // max token cost (multiplies the max stat amount also)
static const uint8 maxReforges      = 3;        // maximum reforges for one item
static const bool send_cache_packets = true;    // change player cache?

static const accepted_stat_format accepted_stat_types[] =
{
    // See ItemPrototype.h for ItemModType definitions. You can add more rows for more stats.
    {ITEM_MOD_HEALTH,       "Health",           7500},
    {ITEM_MOD_STRENGTH,     "Strength",         900},
    {ITEM_MOD_INTELLECT,    "Intellect",        900},
    {ITEM_MOD_AGILITY,      "Agility",          300},
    {ITEM_MOD_SPIRIT,       "Spirit",           1250},
    {ITEM_MOD_STAMINA,      "Stamina",          1000},
    {ITEM_MOD_ATTACK_POWER, "Attack power",     1250},
    {ITEM_MOD_SPELL_POWER,  "Spell power",      1000},
};

// ########################################################################################

static const uint32 accepted_stat_types_max = sizeof(accepted_stat_types) / sizeof(accepted_stat_format);
struct playerItems_format {uint32 Entry, lowGUID;};
static UNORDERED_MAP<uint32, std::vector<playerItems_format> > playerItems;

static const void SendReforgePackets(Player* player)
{
    if(!send_cache_packets)
        return;

    uint32 pGUID = player->GetGUIDLow();
    if(playerItems.find(pGUID) == playerItems.end())
        return;

    for (std::vector<playerItems_format>::iterator it = playerItems[pGUID].begin(); it != playerItems[pGUID].end(); it++)
    {
        // See how enchanthing is done
        // Update player cache (self only) pure visual.
        // HandleItemQuerySingleOpcode copy paste:
        const ItemTemplate* proto = sObjectMgr->GetItemTemplate(it->Entry);
        std::string Name        = proto->Name1;
        std::string Description = proto->Description;
        int loc_idx = player->GetSession()->GetSessionDbLocaleIndex();
        if (loc_idx >= 0)
        {
            if (ItemLocale const* il = sObjectMgr->GetItemLocale(proto->ItemId))
            {
                ObjectMgr::GetLocaleString(il->Name, loc_idx, Name);
                ObjectMgr::GetLocaleString(il->Description, loc_idx, Description);
            }
        }
        WorldPacket data(SMSG_ITEM_QUERY_SINGLE_RESPONSE, 600);
        data << proto->ItemId;
        data << proto->Class;
        data << proto->SubClass;
        data << int32(proto->SoundOverrideSubclass);
        data << Name;
        data << uint8(0x00);
        data << uint8(0x00);
        data << uint8(0x00);
        data << proto->DisplayInfoID;
        data << proto->Quality;
        data << proto->Flags;
        data << proto->Flags2;
        data << proto->BuyPrice;
        data << proto->SellPrice;
        data << proto->InventoryType;
        data << proto->AllowableClass;
        data << proto->AllowableRace;
        data << proto->ItemLevel;
        data << proto->RequiredLevel;
        data << proto->RequiredSkill;
        data << proto->RequiredSkillRank;
        data << proto->RequiredSpell;
        data << proto->RequiredHonorRank;
        data << proto->RequiredCityRank;
        data << proto->RequiredReputationFaction;
        data << proto->RequiredReputationRank;
        data << int32(proto->MaxCount);
        data << int32(proto->Stackable);
        data << proto->ContainerSlots;
        data << proto->StatsCount;
        for (uint32 i = 0; i < proto->StatsCount; ++i)
        {
            data << proto->ItemStat[i].ItemStatType;
            if(sObjectMgr->_itemFakeStatStore[it->lowGUID].find(i) != sObjectMgr->_itemFakeStatStore[it->lowGUID].end())
                data << proto->ItemStat[i].ItemStatValue + sObjectMgr->_itemFakeStatStore[it->lowGUID][i];
            else
                data << proto->ItemStat[i].ItemStatValue;
        }
        data << proto->ScalingStatDistribution;
        data << proto->ScalingStatValue;
        for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
        {
            data << proto->Damage[i].DamageMin;
            data << proto->Damage[i].DamageMax;
            data << proto->Damage[i].DamageType;
        }
        data << proto->Armor;
        data << proto->HolyRes;
        data << proto->FireRes;
        data << proto->NatureRes;
        data << proto->FrostRes;
        data << proto->ShadowRes;
        data << proto->ArcaneRes;
        data << proto->Delay;
        data << proto->AmmoType;
        data << proto->RangedModRange;
        for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
        {
            SpellInfo const* spell = sSpellMgr->GetSpellInfo(proto->Spells[s].SpellId);
            if (spell)
            {
                bool db_data = proto->Spells[s].SpellCooldown >= 0 || proto->Spells[s].SpellCategoryCooldown >= 0;
                data << proto->Spells[s].SpellId;
                data << proto->Spells[s].SpellTrigger;
                data << uint32(-abs(proto->Spells[s].SpellCharges));
                if (db_data)
                {
                    data << uint32(proto->Spells[s].SpellCooldown);
                    data << uint32(proto->Spells[s].SpellCategory);
                    data << uint32(proto->Spells[s].SpellCategoryCooldown);
                }
                else
                {
                    data << uint32(spell->RecoveryTime);
                    data << uint32(spell->Category);
                    data << uint32(spell->CategoryRecoveryTime);
                }
            }
            else
            {
                data << uint32(0);
                data << uint32(0);
                data << uint32(0);
                data << uint32(-1);
                data << uint32(0);
                data << uint32(-1);
            }
        }
        data << proto->Bonding;
        data << Description;
        data << proto->PageText;
        data << proto->LanguageID;
        data << proto->PageMaterial;
        data << proto->StartQuest;
        data << proto->LockID;
        data << int32(proto->Material);
        data << proto->Sheath;
        data << proto->RandomProperty;
        data << proto->RandomSuffix;
        data << proto->Block;
        data << proto->ItemSet;
        data << proto->MaxDurability;
        data << proto->Area;
        data << proto->Map;
        data << proto->BagFamily;
        data << proto->TotemCategory;
        for (int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s)
        {
            data << proto->Socket[s].Color;
            data << proto->Socket[s].Content;
        }
        data << proto->socketBonus;
        data << proto->GemProperties;
        data << proto->RequiredDisenchantSkill;
        data << proto->ArmorDamageModifier;
        data << proto->Duration;
        data << proto->ItemLimitCategory;
        data << proto->HolidayId;
        player->GetSession()->SendPacket(&data);
    }
}

class REFORGING_DATA_HANDLER : public PlayerScript
{
public:
    REFORGING_DATA_HANDLER() : PlayerScript("REFORGING_DATA_HANDLER")
    {
        // DB cleanup on startup
        CharacterDatabase.Execute("DELETE FROM custom_reforges WHERE NOT EXISTS (SELECT 1 FROM item_instance WHERE item_instance.guid = custom_reforges.iGUID)");
    }

    // Called when a player logs out.
    void OnLogout(Player* player)
    {
        DeleteSavedReforges(player->GetGUIDLow()); // delete stored reforges from the player (not DB)
    }

    void OnLogin(Player* player)
    {
        uint32 pGUID = player->GetGUIDLow();

        DeleteSavedReforges(pGUID); // delete saved reforges from the player before loading them
        QueryResult result = CharacterDatabase.PQuery("SELECT `iGUID`, `stat_count_id`, `stat_diff`, `Entry` FROM `custom_reforges` WHERE pGUID = %u and EXISTS (SELECT 1 FROM item_instance WHERE item_instance.guid = custom_reforges.iGUID)", pGUID);
        if (result)
        {
            UNORDERED_MAP<uint32, std::map<uint32, int32> > stat_temp_container; // iGUID <stat_count, stat_diff>
            std::set<uint32> sent_error_message;
            do
            {
                uint32 lowGUID = (*result)[0].GetUInt32();
                if(sObjectMgr->_itemFakeStatStore.find(lowGUID) != sObjectMgr->_itemFakeStatStore.end() && sObjectMgr->_itemFakeStatStore[lowGUID].size() >= maxReforges)
                {
                    if(sent_error_message.find(lowGUID) != sent_error_message.end())
                        continue;
                    sLog->outErrorDb("Too many reforges for item lowGUID %u, ignoring extra reforges.", lowGUID);
                    sent_error_message.insert(lowGUID);
                }
                else
                {
                    stat_temp_container[lowGUID][(*result)[1].GetUInt32()] = (*result)[2].GetInt32();
                    playerItems_format temp = {(*result)[3].GetUInt32(), lowGUID}; // temp var so we can insert our stuff
                    playerItems[pGUID].push_back(temp);
                }
            } while (result->NextRow());

            // apply stat changes for all reforged items equipped and save them to container
            for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++)
            {
                if(Item* invItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
                {
                    uint32 invGUID = invItem->GetGUIDLow();
                    if(stat_temp_container.find(invGUID) != stat_temp_container.end())
                    {
                        player->_ApplyItemMods(invItem, slot, false);
                        for(std::map<uint32, int32>::iterator stat_count_id = stat_temp_container[invGUID].begin(); stat_count_id != stat_temp_container[invGUID].end(); stat_count_id++)
                        {
                            sObjectMgr->_itemFakeStatStore[invGUID][stat_count_id->first] = stat_count_id->second;
                        }
                        player->_ApplyItemMods(invItem, slot, true);
                        stat_temp_container.erase(invGUID); // saved reforges for this item, delete from temp
                    }
                }
            }

            // save the rest of the player's reforges to the container if more exist
            if(!stat_temp_container.empty())
            {
                for(UNORDERED_MAP<uint32, std::map<uint32, int32> >::iterator iGUID = stat_temp_container.begin(); iGUID != stat_temp_container.end(); iGUID++)
                {
                    for(std::map<uint32, int32>::iterator stat_count_id = iGUID->second.begin(); stat_count_id != iGUID->second.end(); stat_count_id++)
                    {
                        sObjectMgr->_itemFakeStatStore[iGUID->first][stat_count_id->first] = stat_count_id->second;
                    }
                }
            }
        }

        SendReforgePackets(player);
    }

private:

    void DeleteSavedReforges(uint32 pGUID)
    {
        if(playerItems.find(pGUID) == playerItems.end())
            return; // Already empty!
        for (std::vector<playerItems_format>::iterator it = playerItems[pGUID].begin(); it != playerItems[pGUID].end(); it++)
        {
            if(sObjectMgr->_itemFakeStatStore.find(it->lowGUID) != sObjectMgr->_itemFakeStatStore.end())
                sObjectMgr->_itemFakeStatStore.erase(it->lowGUID);
        }
        playerItems.erase(pGUID);
    }
};

class REFORGER_NPC : public CreatureScript
{
public:
    REFORGER_NPC() : CreatureScript("REFORGER_NPC")
    {
        for(uint32 i = 0; i < accepted_stat_types_max; i++)
        {
            stat_format temp = {accepted_stat_types[i].stat_name, accepted_stat_types[i].base_stat_change};
            stat_types[accepted_stat_types[i].stat_type] = temp;
        }
    }

    bool OnGossipHello(Player* player, Creature* creature)
    {
        if(selectedItem.find(player->GetGUIDLow()) != selectedItem.end())
            selectedItem.erase(player->GetGUIDLow());

        player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Buy Reforge Tokens.", VENDOR, 0);
        player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, "Select equipped item in slot:", MAIN_MENU, 0);
        for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++)
        {
            if(Item* invItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
                if(IsReforgable(invItem, player))
                    if(char* slotname = GetSlotName(slot, player->GetSession()))
                        player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, slotname, SELECT_STAT_INCREASE, slot);
        }
        player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, "Update menu", MAIN_MENU, 0);
        player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
        return true;
    }

    bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action)
    {
        player->PlayerTalkClass->ClearMenus();
        switch(sender)
        {
        case VENDOR: 
            player->GetSession()->SendListInventory(creature->GetGUID());
            break;
        case MAIN_MENU: OnGossipHello(player, creature); break;
        case SELECT_STAT_INCREASE:
            // action = slot
            if (Item* invItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, action))
            {
                if(IsReforgable(invItem, player))
                {
                    selectedItem[player->GetGUIDLow()] = invItem;
                    const ItemTemplate* proto = invItem->GetTemplate();
                    char label[250];

                    snprintf(label, 250, "Selected item:\n%s", invItem->GetTemplate()->Name1.c_str());
                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, label, sender, action);
                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, "Select stat to increase:", sender, action);
                    bool hasfakestats = ((sObjectMgr->_itemFakeStatStore.find(invItem->GetGUIDLow()) != sObjectMgr->_itemFakeStatStore.end()) ? true : false);
                    for (uint32 i = 0; i < proto->StatsCount; ++i)
                    {
                        if(hasfakestats && sObjectMgr->_itemFakeStatStore[invItem->GetGUIDLow()].find(i) != sObjectMgr->_itemFakeStatStore[invItem->GetGUIDLow()].end())
                            continue; // already modded this stat, skip.
                        if(char* stat_name = GetStatName(proto->ItemStat[i].ItemStatType))
                            player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, stat_name, SELECT_TOKEN_COST, i);
                    }
                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TALK, "Back..", MAIN_MENU, 0);
                    player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
                }
                else
                {
                    player->GetSession()->SendNotification("Item not reforgable");
                    OnGossipHello(player, creature);
                }
            }
            else
            {
                player->GetSession()->SendNotification("No item selected");
                OnGossipHello(player, creature);
            }
            break;
        case SELECT_TOKEN_COST:
            // action = stat_count_id
            {
                Item* invItem = selectedItem[player->GetGUIDLow()];
                if (invItem && invItem->IsInWorld() && IsReforgable(invItem, player))
                {
                    const ItemTemplate* proto = invItem->GetTemplate();
                    char label[250];
                    char popup[250];

                    snprintf(label, 250, "Selected item:\n%s", invItem->GetTemplate()->Name1.c_str());
                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, label, sender, action);
                    snprintf(label, 250, "Selected stat: %s", stat_types[proto->ItemStat[action].ItemStatType].stat_name);
                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, label, sender, action);
                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, "Select amount to increase:", sender, action);
                    for (uint32 i = 1; i <= maxTokenAmount; ++i)
                    {
                        snprintf(label, 250, "Increase by %i for %u x %s", stat_types[proto->ItemStat[action].ItemStatType].stat_base_value*i, i, GetItemName(tokenEntry, player->GetSession()).c_str());
                        snprintf(popup, 250, "Are you sure?\nThe item is set untradeable and non-refundable\n\nCosts %u x %s", i, GetItemName(tokenEntry, player->GetSession()).c_str());
                        player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_TRAINER, label, i, action, popup, 0, false); // sender = token_count, action = stat_count_id
                    }
                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TALK, "Back..", SELECT_STAT_INCREASE, invItem->GetSlot());
                    player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
                }
                else
                {
                    player->GetSession()->SendNotification("Invalid item selected");
                    OnGossipHello(player, creature);
                }
            }
            break;
        default: // Reforge
            // sender = token_count, action = stat_count_id
            {
                Item* invItem = selectedItem[player->GetGUIDLow()];
                if (invItem && invItem->IsInWorld() && IsReforgable(invItem, player))
                {
                    if(sender && sender <= maxTokenAmount)
                    {
                        if(player->HasItemCount(tokenEntry, sender))
                        {
                            player->DestroyItemCount(tokenEntry, sender, true);
                            UpdatePlayerReforgeStats(invItem, player, action, sender);
                        }
                        else
                        {
                            player->GetSession()->SendNotification("Not enough tokens");
                            OnGossipSelect(player, creature, SELECT_TOKEN_COST, action);
                            return true;
                        }
                    }
                    else
                        player->GetSession()->SendNotification("Invalid token count");
                }
                else
                    player->GetSession()->SendNotification("Invalid item selected");
                OnGossipHello(player, creature);
            }
        }
        return true;
    }

private:

    enum Senders
    {
        MAIN_MENU = GOSSIP_ACTION_INFO_DEF+1,
        SELECT_ITEM,
        SELECT_STAT_INCREASE,
        SELECT_TOKEN_COST,
	 VENDOR = GOSSIP_ACTION_INFO_DEF+2,
        REFORGE,
    };

    struct stat_format {char* stat_name; int32 stat_base_value; };
    UNORDERED_MAP<uint32, struct stat_format> stat_types;
    UNORDERED_MAP<uint32, Item*> selectedItem;

    char* GetStatName(uint32 stat_type)
    {
        if(stat_types.find(stat_type) != stat_types.end())
            return stat_types[stat_type].stat_name;
        return NULL;
    }

    char * GetSlotName(uint8 slot, WorldSession* session)
    {
        switch (slot)
        {
        case EQUIPMENT_SLOT_HEAD      : return "Head";
        case EQUIPMENT_SLOT_NECK      : return "Neck";
        case EQUIPMENT_SLOT_SHOULDERS : return "Shoulders";
        case EQUIPMENT_SLOT_BODY      : return "Shirt";
        case EQUIPMENT_SLOT_CHEST     : return "Chest";
        case EQUIPMENT_SLOT_WAIST     : return "Waist";
        case EQUIPMENT_SLOT_LEGS      : return "Legs";
        case EQUIPMENT_SLOT_FEET      : return "Feet";
        case EQUIPMENT_SLOT_WRISTS    : return "Wrists";
        case EQUIPMENT_SLOT_HANDS     : return "Hands";
        case EQUIPMENT_SLOT_FINGER1   : return "Right finger";
        case EQUIPMENT_SLOT_FINGER2   : return "left finger";
        case EQUIPMENT_SLOT_TRINKET1  : return "Right trinket";
        case EQUIPMENT_SLOT_TRINKET2  : return "Left trinket";
        case EQUIPMENT_SLOT_BACK      : return "Back";
        case EQUIPMENT_SLOT_MAINHAND  : return "Main hand";
        case EQUIPMENT_SLOT_OFFHAND   : return "Off hand";
        case EQUIPMENT_SLOT_RANGED    : return "Ranged";
        case EQUIPMENT_SLOT_TABARD    : return "Tabard";
        default: return NULL;
        }
    }

    std::string GetItemName(uint32 entry, WorldSession* session)
    {
        const ItemTemplate* itemTemplate = sObjectMgr->GetItemTemplate(entry);
        std::string name = itemTemplate->Name1;
        int loc_idx = session->GetSessionDbLocaleIndex();
        if (loc_idx >= 0)
            if (ItemLocale const* il = sObjectMgr->GetItemLocale(itemTemplate->ItemId))
                sObjectMgr->GetLocaleString(il->Name, loc_idx, name);
        return name;
    }

    bool IsReforgable(Item* invItem, Player* player)
    {
        if(invItem->IsEquipped() && invItem->GetOwnerGUID() == player->GetGUID())
        {
            if(sObjectMgr->_itemFakeStatStore.find(invItem->GetGUIDLow()) != sObjectMgr->_itemFakeStatStore.end())
                if(sObjectMgr->_itemFakeStatStore[invItem->GetGUIDLow()].size() >= maxReforges)
                    return false;
            const ItemTemplate* proto = invItem->GetTemplate();
            // block heirlooms necessary? probably. (their stats are handled differently)
            if(proto->Quality != ITEM_QUALITY_HEIRLOOM && proto->StatsCount > 0)
            {
                for (uint32 i = 0; i < proto->StatsCount; ++i)
                {
                    if(stat_types.find(proto->ItemStat[i].ItemStatType) == stat_types.end())
                        continue;
                    if(proto->ItemStat[i].ItemStatValue == 0)
                        continue;
                    if(sObjectMgr->_itemFakeStatStore.find(invItem->GetGUIDLow()) != sObjectMgr->_itemFakeStatStore.end())
                    {
                        if(sObjectMgr->_itemFakeStatStore[invItem->GetGUIDLow()].find(i) == sObjectMgr->_itemFakeStatStore[invItem->GetGUIDLow()].end())
                            return true; // found a stat that is not increased yet and is accepted by the script
                    }
                    else
                        return true; // the item is not reforged yet and a good stat was found
                }
            }
        }
        return false;
    }

    void UpdatePlayerReforgeStats(Item* invItem, Player* player, uint32 stat_count_id, uint32 token_count)
    {
        const ItemTemplate* proto = invItem->GetTemplate();
        uint32 stat_diff = stat_types[proto->ItemStat[stat_count_id].ItemStatType].stat_base_value * token_count;
        uint32 guidlow = invItem->GetGUIDLow();

        // non tradeable and refundable
        invItem->SetNotRefundable(player);
        invItem->SetBinding(true);

        // Update player stats
        player->_ApplyItemMods(invItem, invItem->GetSlot(), false);
        sObjectMgr->_itemFakeStatStore[guidlow][stat_count_id] = stat_diff; // save to container for item stats applying (used a lot)
        playerItems_format temp = {invItem->GetEntry(), guidlow};           // temp var so we can insert our stuff to playerItems_format
        playerItems[player->GetGUIDLow()].push_back(temp);                  // save entry and guid of the item so we can delete the item data on logout
        player->_ApplyItemMods(invItem, invItem->GetSlot(), true);

        // save to DB
        player->SaveToDB(); // save player to DB too, since if a crash comes by, he will get a free reforge and no token removing is saved.
        CharacterDatabase.PExecute("REPLACE INTO `custom_reforges` (`pGUID`, `Entry`, `iGUID`, `stat_count_id`, `stat_diff`) VALUES (%u, %u, %u, %u, %i)", player->GetGUIDLow(), invItem->GetEntry(), guidlow, stat_count_id, stat_diff);

        SendReforgePackets(player);
    }
};

void AddSC_REFORGER_NPC()
{
    new REFORGER_NPC;
    new REFORGING_DATA_HANDLER;
}
But this code very old,who have custom reforge with tokens or how i can change mod stats new reforge 2016 (no 200 stats ,i need more

Code:
#include "Reforging.h"
#include <sstream>
#include <string>
#include <vector>
#include "Creature.h"
#include "Define.h"
#include "EventProcessor.h"
#include "GossipDef.h"
#include "Item.h"
#include "ItemTemplate.h"
#include "ObjectGuid.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "ScriptedGossip.h"
#include "ScriptMgr.h"
#include "SharedDefines.h"
#include "Spell.h"
#include "Transaction.h"
#include "WorldPacket.h"
#include "WorldSession.h"

/*
Reforging by Rochet2
http://rochet2.github.io/

Rules of thumb:
Item can be reforged once.
Item reforge wont show to anyone but you in tooltips. Stats will be there nevertheless.
You will see the increased stats on all tooltips of the same item you reforged.
You can disable the stat changes to tooltips by setting send_cache_packets to false in Reforging.cpp.
Reforges are stripped when you mail, ah, guildbank the item etc. Only YOU can have the reforge.
Only item base stats are reforgable. Enchants and random stats are not.

This script is made blizzlike. This means that the reforgable stats etc are from CATACLYSM!
I have been informed that some stats were removed etc that would be important to be reforgable.
However I do not know what those stats are currently. Do look through the statTypes to add whatever you want.
Edit IsReforgable is you want to tweak requirements

*/

// Remember to add to GetStatName too
static const ItemModType statTypes[] = { ITEM_MOD_SPIRIT, ITEM_MOD_DODGE_RATING, ITEM_MOD_PARRY_RATING, ITEM_MOD_HIT_RATING, ITEM_MOD_CRIT_RATING, ITEM_MOD_HASTE_RATING, ITEM_MOD_EXPERTISE_RATING };
static const uint8 stat_type_max = sizeof(statTypes) / sizeof(*statTypes);

static const char* GetStatName(uint32 ItemStatType)
{
    switch(ItemStatType)
    {
    case ITEM_MOD_SPIRIT                   	: return "Spirit"; break;
    case ITEM_MOD_DODGE_RATING             	: return "Dodge rating"; break;
    case ITEM_MOD_PARRY_RATING             	: return "Parry rating"; break;
    case ITEM_MOD_HIT_RATING               	: return "Hit rating"; break;
    case ITEM_MOD_CRIT_RATING              	: return "Crit rating"; break;
    case ITEM_MOD_HASTE_RATING             	: return "Haste rating"; break;
    case ITEM_MOD_EXPERTISE_RATING         	: return "Expertise rating"; break;
    default: return NULL;
    }
}

static const char* GetSlotName(uint8 slot, WorldSession* /*session*/)
{
    switch (slot)
    {
    case EQUIPMENT_SLOT_HEAD      : return "Head";
    case EQUIPMENT_SLOT_NECK      : return "Neck";
    case EQUIPMENT_SLOT_SHOULDERS : return "Shoulders";
    case EQUIPMENT_SLOT_BODY      : return "Shirt";
    case EQUIPMENT_SLOT_CHEST     : return "Chest";
    case EQUIPMENT_SLOT_WAIST     : return "Waist";
    case EQUIPMENT_SLOT_LEGS      : return "Legs";
    case EQUIPMENT_SLOT_FEET      : return "Feet";
    case EQUIPMENT_SLOT_WRISTS    : return "Wrists";
    case EQUIPMENT_SLOT_HANDS     : return "Hands";
    case EQUIPMENT_SLOT_FINGER1   : return "Right finger";
    case EQUIPMENT_SLOT_FINGER2   : return "Left finger";
    case EQUIPMENT_SLOT_TRINKET1  : return "Right trinket";
    case EQUIPMENT_SLOT_TRINKET2  : return "Left trinket";
    case EQUIPMENT_SLOT_BACK      : return "Back";
    case EQUIPMENT_SLOT_MAINHAND  : return "Main hand";
    case EQUIPMENT_SLOT_OFFHAND   : return "Off hand";
    case EQUIPMENT_SLOT_TABARD    : return "Tabard";
    case EQUIPMENT_SLOT_RANGED    : return "Ranged";
    default: return NULL;
    }
}

static uint32 Melt(uint8 i, uint8 j)
{
    return (i << 8) + j;
}

static void Unmelt(uint32 melt, uint8& i, uint8& j)
{
    i = melt >> 8;
    j = melt & 0xFF;
}

static Item* GetEquippedItem(Player* player, uint32 guidlow)
{
    for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
        if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
            if (pItem->GetGUID().GetCounter() == guidlow)
                return pItem;
    return NULL;
}

static bool IsReforgable(Item* invItem, Player* player)
{
    //if (!invItem->IsEquipped())
    //    return false;
    if (invItem->GetOwnerGUID() != player->GetGUID())
        return false;
    const ItemTemplate* pProto = invItem->GetTemplate();
    //if (pProto->ItemLevel < 200)
    //    return false;
    //if (pProto->Quality == ITEM_QUALITY_HEIRLOOM) // block heirlooms necessary?
    //    return false;
    if (!pProto->StatsCount || pProto->StatsCount >= MAX_ITEM_PROTO_STATS) // Mandatory! Do NOT remove or edit
        return false;
    if (!player->reforgeMap.empty() && player->reforgeMap.find(invItem->GetGUID().GetCounter()) != player->reforgeMap.end()) // Mandatory! Do NOT remove or edit
        return false;
    for (uint32 i = 0; i < pProto->StatsCount; ++i)
    {
        if (!GetStatName(pProto->ItemStat[i].ItemStatType))
            continue;
        if (((int32)floorf((float)pProto->ItemStat[i].ItemStatValue * 0.4f)) > 1)
            return true;
    }
    return false;
}

static void UpdatePlayerReforgeStats(Item* invItem, Player* player, uint32 decrease, uint32 increase) // stat types
{
    const ItemTemplate* pProto = invItem->GetTemplate();

    int32 stat_diff = 0;
    for (uint32 i = 0; i < pProto->StatsCount; ++i)
    {
        if (pProto->ItemStat[i].ItemStatType == increase)
            return; // Should not have the increased stat already
        if (pProto->ItemStat[i].ItemStatType == decrease)
            stat_diff = (int32)floorf((float)pProto->ItemStat[i].ItemStatValue * 0.4f);
    }
    if (stat_diff <= 0)
        return; // Should have some kind of diff

    // Update player stats
    player->_ApplyItemMods(invItem, invItem->GetSlot(), false);
    uint32 guidlow = invItem->GetGUID().GetCounter();
    ReforgeData& data = player->reforgeMap[guidlow];
    data.increase = increase;
    data.decrease = decrease;
    data.stat_value = stat_diff;
    player->_ApplyItemMods(invItem, invItem->GetSlot(), true);
    // CharacterDatabase.PExecute("REPLACE INTO `custom_reforging` (`GUID`, `increase`, `decrease`, `stat_value`) VALUES (%u, %u, %u, %i)", guidlow, increase, decrease, stat_diff);
    player->ModifyMoney(pProto->SellPrice < (10*GOLD) ? (-10*GOLD) : -(int32)pProto->SellPrice);
    SendReforgePacket(player, invItem->GetEntry(), 0, &data);
    // player->SaveToDB();
}

class REFORGE_PLAYER : public PlayerScript
{
public:
    REFORGE_PLAYER() : PlayerScript("REFORGE_PLAYER")
    {
        CharacterDatabase.DirectExecute("DELETE FROM `custom_reforging` WHERE NOT EXISTS (SELECT 1 FROM `item_instance` WHERE `item_instance`.`guid` = `custom_reforging`.`GUID`)");
    }

    class SendRefPackLogin : public BasicEvent
    {
    public:
        SendRefPackLogin(Player* _player) : player(_player)
        {
            _player->m_Events.AddEvent(this, _player->m_Events.CalculateTime(1000));
        }

        bool Execute(uint64, uint32) override
        {
            SendReforgePackets(player);
            return true;
        }
        Player* player;
    };

    void OnLogin(Player* player, bool /*firstLogin*/) override
    {
        uint32 playerGUID = player->GetGUID().GetCounter();
        QueryResult result = CharacterDatabase.PQuery("SELECT `GUID`, `increase`, `decrease`, `stat_value` FROM `custom_reforging` WHERE `Owner` = %u", playerGUID);
        if (result)
        {
            do
            {
                uint32 lowGUID = (*result)[0].GetUInt32();
                Item* invItem = player->GetItemByGuid(ObjectGuid(HighGuid::Item, 0, lowGUID));
                if (invItem)
                    player->_ApplyItemMods(invItem, invItem->GetSlot(), false);
                ReforgeData& data = player->reforgeMap[lowGUID];
                data.increase = (*result)[1].GetUInt32();
                data.decrease = (*result)[2].GetUInt32();
                data.stat_value = (*result)[3].GetInt32();
                if (invItem)
                    player->_ApplyItemMods(invItem, invItem->GetSlot(), true);
                // SendReforgePacket(player, entry, lowGUID);
            } while (result->NextRow());

            // SendReforgePackets(player);
            new SendRefPackLogin(player);
        }
    }

    //void OnLogout(Player* player) override
    //{
    //    if (player->reforgeMap.empty())
    //        return;
    //    for (ReforgeMapType::const_iterator it = player->reforgeMap.begin(); it != player->reforgeMap.end();)
    //    {
    //        ReforgeMapType::const_iterator old_it = it++;
    //        RemoveReforge(player, old_it->first, false);
    //    }
    //}

    void OnSave(Player* player) override
    {
        uint32 lowguid = player->GetGUID().GetCounter();
        SQLTransaction trans = CharacterDatabase.BeginTransaction();
        trans->PAppend("DELETE FROM `custom_reforging` WHERE `Owner` = %u", lowguid);
        if (!player->reforgeMap.empty())
        {
            // Only save items that are in inventory / bank / etc
            std::vector<Item*> items = GetItemList(player);
            for (std::vector<Item*>::const_iterator it = items.begin(); it != items.end(); ++it)
            {
                ReforgeMapType::const_iterator it2 = player->reforgeMap.find((*it)->GetGUID().GetCounter());
                if (it2 == player->reforgeMap.end())
                    continue;

                const ReforgeData& data = it2->second;
                trans->PAppend("REPLACE INTO `custom_reforging` (`GUID`, `increase`, `decrease`, `stat_value`, `Owner`) VALUES (%u, %u, %u, %i, %u)", it2->first, data.increase, data.decrease, data.stat_value, lowguid);
            }
        }

        if (trans->GetSize()) // basically never false
            CharacterDatabase.CommitTransaction(trans);
    }
};

class REFORGER_NPC : public CreatureScript
{
public:
    REFORGER_NPC() : CreatureScript("REFORGER_NPC") { }

    bool OnGossipHello(Player* player, Creature* creature) override
    {
        AddGossipItemFor(player, GOSSIP_ICON_BATTLE, "Select slot of the item to reforge:", 0, Melt(MAIN_MENU, 0));
        for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
        {
            if (Item* invItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
                if (IsReforgable(invItem, player))
                    if (const char* slotname = GetSlotName(slot, player->GetSession()))
                        AddGossipItemFor(player, GOSSIP_ICON_TRAINER, slotname, 0, Melt(SELECT_STAT_REDUCE, slot));
        }
        AddGossipItemFor(player, GOSSIP_ICON_TRAINER, "Remove reforges", 0, Melt(SELECT_RESTORE, 0));
        AddGossipItemFor(player, GOSSIP_ICON_CHAT, "Update menu", 0, Melt(MAIN_MENU, 0));
        SendGossipMenuFor(player, DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
        return true;
    }

    bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 melt) override
    {
        ClearGossipMenuFor(player);

        uint8 menu, action;
        Unmelt(melt, menu, action);

        switch (menu)
        {
        case MAIN_MENU: OnGossipHello(player, creature); break;
        case SELECT_STAT_REDUCE:
            // action = slot
            if (Item* invItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, action))
            {
                if (IsReforgable(invItem, player))
                {
                    uint32 guidlow = invItem->GetGUID().GetCounter();
                    const ItemTemplate* pProto = invItem->GetTemplate();
                    AddGossipItemFor(player, GOSSIP_ICON_BATTLE, "Stat to decrease:", sender, melt);
                    for (uint32 i = 0; i < pProto->StatsCount; ++i)
                    {
                        int32 stat_diff = ((int32)floorf((float)pProto->ItemStat[i].ItemStatValue * 0.4f));
                        if (stat_diff > 1)
                            if (const char* stat_name = GetStatName(pProto->ItemStat[i].ItemStatType))
                            {
                                std::ostringstream oss;
                                oss << stat_name << " (" << pProto->ItemStat[i].ItemStatValue << " |cFFDB2222-" << stat_diff << "|r)";
                                AddGossipItemFor(player, GOSSIP_ICON_TRAINER, oss.str(), guidlow, Melt(SELECT_STAT_INCREASE, i));
                            }
                    }
                    AddGossipItemFor(player, GOSSIP_ICON_TALK, "Back..", 0, Melt(MAIN_MENU, 0));
                    SendGossipMenuFor(player, DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
                }
                else
                {
                    player->GetSession()->SendNotification("Invalid item selected");
                    OnGossipHello(player, creature);
                }
            }
            else
            {
                player->GetSession()->SendNotification("Invalid item selected");
                OnGossipHello(player, creature);
            }
            break;
        case SELECT_STAT_INCREASE:
            // sender = item guidlow
            // action = StatsCount id
            {
                Item* invItem = GetEquippedItem(player, sender);
                if (invItem)
                {
                    const ItemTemplate* pProto = invItem->GetTemplate();
                    int32 stat_diff = ((int32)floorf((float)pProto->ItemStat[action].ItemStatValue * 0.4f));

                    AddGossipItemFor(player, GOSSIP_ICON_BATTLE, "Stat to increase:", sender, melt);
                    for (uint8 i = 0; i < stat_type_max; ++i)
                    {
                        bool cont = false;
                        for (uint32 j = 0; j < pProto->StatsCount; ++j)
                        {
                            if (statTypes[i] == pProto->ItemStat[j].ItemStatType) // skip existing stats on item
                            {
                                cont = true;
                                break;
                            }
                        }
                        if (cont)
                            continue;
                        if (const char* stat_name = GetStatName(statTypes[i]))
                        {
                            std::ostringstream oss;
                            oss << stat_name << " |cFF3ECB3C+" << stat_diff << "|r";
                            AddGossipItemFor(player, GOSSIP_ICON_INTERACT_1, oss.str(), sender, Melt(i, (uint8)pProto->ItemStat[action].ItemStatType), "Are you sure you want to reforge\n\n" + pProto->Name1, (pProto->SellPrice < (10 * GOLD) ? (10 * GOLD) : pProto->SellPrice), false);
                        }
                    }
                    AddGossipItemFor(player, GOSSIP_ICON_TALK, "Back..", 0, Melt(SELECT_STAT_REDUCE, invItem->GetSlot()));
                    SendGossipMenuFor(player, DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
                }
                else
                {
                    player->GetSession()->SendNotification("Invalid item selected");
                    OnGossipHello(player, creature);
                }
            }
            break;
        case SELECT_RESTORE:
            {
                AddGossipItemFor(player, GOSSIP_ICON_BATTLE, "Select slot to remove reforge from:", sender, melt);
                if (!player->reforgeMap.empty())
                {
                    for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
                    {
                        if (Item* invItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
                            if (player->reforgeMap.find(invItem->GetGUID().GetCounter()) != player->reforgeMap.end())
                                if (const char* slotname = GetSlotName(slot, player->GetSession()))
                                    AddGossipItemFor(player, GOSSIP_ICON_INTERACT_1, slotname, invItem->GetGUID().GetCounter(), Melt(RESTORE, 0), "Remove reforge from\n\n" + invItem->GetTemplate()->Name1, 0, false);
                    }
                }
                AddGossipItemFor(player, GOSSIP_ICON_CHAT, "Update menu", sender, melt);
                AddGossipItemFor(player, GOSSIP_ICON_TALK, "Back..", 0, Melt(MAIN_MENU, 0));
                SendGossipMenuFor(player, DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
            }
            break;
        case RESTORE:
            // sender = item guidlow
            {
                if (player->GetItemByGuid(ObjectGuid(HighGuid::Item, 0, sender)))
                {
                    if (!player->reforgeMap.empty() && player->reforgeMap.find(sender) != player->reforgeMap.end())
                        RemoveReforge(player, sender, true);
                }
                OnGossipHello(player, creature);
            }
            break;
        default: // Reforge
            // sender = item guidlow
            // menu = stat type to increase index to statTypes[]
            // action = stat type to decrease
            {
                if (menu < stat_type_max)
                {
                    Item* invItem = GetEquippedItem(player, sender);
                    if (invItem && IsReforgable(invItem, player))
                    {
                        if (player->HasEnoughMoney(invItem->GetTemplate()->SellPrice < (10 * GOLD) ? (10 * GOLD) : invItem->GetTemplate()->SellPrice))
                        {
                            // int32 stat_diff = ((int32)floorf((float)invItem->GetTemplate()->ItemStat[action].ItemStatValue * 0.4f));
                            UpdatePlayerReforgeStats(invItem, player, action, statTypes[menu]); // rewrite this function
                        }
                        else
                        {
                            player->GetSession()->SendNotification("Not enough money");
                        }
                    }
                    else
                    {
                        player->GetSession()->SendNotification("Invalid item selected");
                    }
                }
                OnGossipHello(player, creature);
            }
        }
        return true;
    }

    enum Menus
    {
        MAIN_MENU = 200, // stat_type_max
        SELECT_ITEM,
        SELECT_STAT_REDUCE,
        SELECT_STAT_INCREASE,
        SELECT_RESTORE,
        RESTORE,
        REFORGE,
    };
};

void AddSC_REFORGER_NPC()
{
    new REFORGER_NPC;
    new REFORGE_PLAYER;
}
 
Last edited:

Rochet2

Moderator / Eluna Dev
or how i can change mod stats new reforge 2016 (no 200 stats ,i need more

What does this mean?
I dont understand what you want and what "no 200 stats" means.
 

jimteck

Emulation Addict
i mean in old reforging can reforg 3000 - 5000 -10000 - 15000 strength or stamina, but in new reforging only 200 strength or stamina
 

Rochet2

Moderator / Eluna Dev
There is a code like this that repeats in the code:
(int32)floorf((float)pProto->ItemStat.ItemStatValue * 0.4f)

Should probably have made a function, but it is now how it is.
You can change that part to change the amount to change the item's stats.
 
Top