Пример #1
0
void
BNavMenu::SetShowParent(bool show)
{
	fFlags = uint8((fFlags & ~kShowParent) | (show ? kShowParent : 0));
}
Пример #2
0
// Realm List command handler
bool AuthSocket::_HandleRealmList()
{
    TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "Entering _HandleRealmList");
    if (socket().recv_len() < 5)
        return false;

    socket().recv_skip(5);

    // Get the user id (else close the connection)
    // No SQL injection (prepared statement)
    PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME);
    stmt->setString(0, _login);
    PreparedQueryResult result = LoginDatabase.Query(stmt);
    if (!result)
    {
        TC_LOG_ERROR(LOG_FILTER_AUTHSERVER, "'%s:%d' [ERROR] user %s tried to login but we cannot find him in the database.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());
        socket().shutdown();
        return false;
    }

    Field* fields = result->Fetch();
    uint32 id = fields[0].GetUInt32();

    // Update realm list if need
    sRealmList->UpdateIfNeed();

    // Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm)
    ByteBuffer pkt;

    size_t RealmListSize = 0;
    for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i)
    {
        // don't work with realms which not compatible with the client
        bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && i->second.gamebuild == _build) || ((_expversion & PRE_BC_EXP_FLAG) && !AuthHelper::IsPreBCAcceptedClientBuild(i->second.gamebuild));

        // No SQL injection. id of realm is controlled by the database.
        uint32 flag = i->second.flag;
        RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(i->second.gamebuild);
        if (!okBuild)
        {
            if (!buildInfo)
                continue;

            flag |= REALM_FLAG_OFFLINE | REALM_FLAG_SPECIFYBUILD;   // tell the client what build the realm is for
        }

        if (!buildInfo)
            flag &= ~REALM_FLAG_SPECIFYBUILD;

        std::string name = i->first;
        if (_expversion & PRE_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD)
        {
            std::ostringstream ss;
            ss << name << " (" << buildInfo->MajorVersion << '.' << buildInfo->MinorVersion << '.' << buildInfo->BugfixVersion << ')';
            name = ss.str();
        }

        uint8 lock = (i->second.allowedSecurityLevel > _accountSecurityLevel) ? 1 : 0;

        uint8 AmountOfCharacters = 0;
        stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_NUM_CHARS_ON_REALM);
        stmt->setUInt32(0, i->second.m_ID);
        stmt->setUInt32(1, id);
        result = LoginDatabase.Query(stmt);
        if (result)
            AmountOfCharacters = (*result)[0].GetUInt8();

        pkt << i->second.icon;                              // realm type
        if (_expversion & POST_BC_EXP_FLAG)                 // only 2.x and 3.x clients
            pkt << lock;                                    // if 1, then realm locked
        pkt << uint8(flag);                                 // RealmFlags
        pkt << name;
        pkt << i->second.RealmAddress;
        pkt << i->second.populationLevel;
        pkt << AmountOfCharacters;
        pkt << i->second.timezone;                          // realm category
        if (_expversion & POST_BC_EXP_FLAG)                 // 2.x and 3.x clients
            pkt << uint8(0x2C);                             // unk, may be realm number/id?
        else
            pkt << uint8(0x0);                              // 1.12.1 and 1.12.2 clients

        if (_expversion & POST_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD)
        {
            pkt << uint8(buildInfo->MajorVersion);
            pkt << uint8(buildInfo->MinorVersion);
            pkt << uint8(buildInfo->BugfixVersion);
            pkt << uint16(buildInfo->Build);
        }

        ++RealmListSize;
    }

    if (_expversion & POST_BC_EXP_FLAG)                     // 2.x and 3.x clients
    {
        pkt << uint8(0x10);
        pkt << uint8(0x00);
    }
    else                                                    // 1.12.1 and 1.12.2 clients
    {
        pkt << uint8(0x00);
        pkt << uint8(0x02);
    }

    // make a ByteBuffer which stores the RealmList's size
    ByteBuffer RealmListSizeBuffer;
    RealmListSizeBuffer << uint32(0);
    if (_expversion & POST_BC_EXP_FLAG)                     // only 2.x and 3.x clients
        RealmListSizeBuffer << uint16(RealmListSize);
    else
        RealmListSizeBuffer << uint32(RealmListSize);

    ByteBuffer hdr;
    hdr << uint8(REALM_LIST);
    hdr << uint16(pkt.size() + RealmListSizeBuffer.size());
    hdr.append(RealmListSizeBuffer);                        // append RealmList's size buffer
    hdr.append(pkt);                                        // append realms in the realmlist

    socket().send((char const*)hdr.contents(), hdr.size());

    return true;
}
Пример #3
0
bool
BNavMenu::StartBuildingItemList()
{
	BEntry entry;

	if (fNavDir.device < 0 || entry.SetTo(&fNavDir) != B_OK
		|| !entry.Exists())
		return false;

	fItemList = new BObjectList<BMenuItem>(50);

	fIteratingDesktop = false;

	BDirectory parent;
	status_t status = entry.GetParent(&parent);

	// if ref is the root item then build list of volume root dirs
	fFlags = uint8((fFlags & ~kVolumesOnly)
		| (status == B_ENTRY_NOT_FOUND ? kVolumesOnly : 0));
	if (fFlags & kVolumesOnly)
		return true;

	Model startModel(&entry, true);
	if (startModel.InitCheck() != B_OK || !startModel.IsContainer())
		return false;

	if (startModel.IsQuery())
		fContainer = new QueryEntryListCollection(&startModel);
	else if (startModel.IsVirtualDirectory())
		fContainer = new VirtualDirectoryEntryList(&startModel);
	else if (startModel.IsDesktop()) {
		fIteratingDesktop = true;
		fContainer = DesktopPoseView::InitDesktopDirentIterator(
			0, 	startModel.EntryRef());
		AddRootItemsIfNeeded();
		AddTrashItem();
	} else if (startModel.IsTrash()) {
		// the trash window needs to display a union of all the
		// trash folders from all the mounted volumes
		BVolumeRoster volRoster;
		volRoster.Rewind();
		BVolume volume;
		fContainer = new EntryIteratorList();

		while (volRoster.GetNextVolume(&volume) == B_OK) {
			if (volume.IsReadOnly() || !volume.IsPersistent())
				continue;

			BDirectory trashDir;

			if (FSGetTrashDir(&trashDir, volume.Device()) == B_OK)
				dynamic_cast<EntryIteratorList*>(fContainer)->
					AddItem(new DirectoryEntryList(trashDir));
		}
	} else
		fContainer = new DirectoryEntryList(*dynamic_cast<BDirectory*>
			(startModel.Node()));

	if (fContainer == NULL || fContainer->InitCheck() != B_OK)
		return false;

	fContainer->Rewind();

	return true;
}
Пример #4
0
// Logon Challenge command handler
bool AuthSocket::_HandleLogonChallenge()
{
    TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "Entering _HandleLogonChallenge");
    if (socket().recv_len() < sizeof(sAuthLogonChallenge_C))
        return false;

    // Read the first 4 bytes (header) to get the length of the remaining of the packet
    std::vector<uint8> buf;
    buf.resize(4);

    socket().recv((char *)&buf[0], 4);

#if TRINITY_ENDIAN == TRINITY_BIGENDIAN
    EndianConvert(*((uint16*)(buf[0])));
#endif

    uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size;
    TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[AuthChallenge] got header, body is %#04x bytes", remaining);

    if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (socket().recv_len() < remaining))
        return false;

    //No big fear of memory outage (size is int16, i.e. < 65536)
    buf.resize(remaining + buf.size() + 1);
    buf[buf.size() - 1] = 0;
    sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0];

    // Read the remaining of the packet
    socket().recv((char *)&buf[4], remaining);
    TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[AuthChallenge] got full packet, %#04x bytes", ch->size);
    TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[AuthChallenge] name(%d): '%s'", ch->I_len, ch->I);

    // BigEndian code, nop in little endian case
    // size already converted
#if TRINITY_ENDIAN == TRINITY_BIGENDIAN
    EndianConvert(*((uint32*)(&ch->gamename[0])));
    EndianConvert(ch->build);
    EndianConvert(*((uint32*)(&ch->platform[0])));
    EndianConvert(*((uint32*)(&ch->os[0])));
    EndianConvert(*((uint32*)(&ch->country[0])));
    EndianConvert(ch->timezone_bias);
    EndianConvert(ch->ip);
#endif

    ByteBuffer pkt;

    _login = (const char*)ch->I;
    _build = ch->build;
    _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG));
    _os = (const char*)ch->os;

    if (_os.size() > 4)
        return false;

    // Restore string order as its byte order is reversed
    std::reverse(_os.begin(), _os.end());

    pkt << uint8(AUTH_LOGON_CHALLENGE);
    pkt << uint8(0x00);

    // Verify that this IP is not in the ip_banned table
    LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS));

    std::string const& ip_address = socket().getRemoteAddress();
    PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED);
    stmt->setString(0, ip_address);
    PreparedQueryResult result = LoginDatabase.Query(stmt);
    if (result)
    {
        pkt << uint8(WOW_FAIL_BANNED);
        TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "'%s:%d' [AuthChallenge] Banned ip tries to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort());
    }
    else
    {
        // Get the account details from the account table
        // No SQL injection (prepared statement)
        stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE);
        stmt->setString(0, _login);

        PreparedQueryResult res2 = LoginDatabase.Query(stmt);
        if (res2)
        {
            Field* fields = res2->Fetch();

            // If the IP is 'locked', check that the player comes indeed from the correct IP address
            bool locked = false;
            if (fields[2].GetUInt8() == 1)                  // if ip is locked
            {
                TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), fields[3].GetCString());
                TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[AuthChallenge] Player address is '%s'", ip_address.c_str());

                if (strcmp(fields[4].GetCString(), ip_address.c_str()))
                {
                    TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[AuthChallenge] Account IP differs");
                    pkt << (uint8) WOW_FAIL_SUSPENDED;
                    locked = true;
                }
                else
                    TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[AuthChallenge] Account IP matches");
            }
            //else
            //{
            //    TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[AuthChallenge] Account '%s' is not locked to ip", _login.c_str());
            //    std::string accountCountry = fields[3].GetString();
            //    if (accountCountry.empty() || accountCountry == "00")
            //        TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[AuthChallenge] Account '%s' is not locked to country", _login.c_str());
            //    else if (!accountCountry.empty())
            //    {
            //        uint32 ip = inet_addr(ip_address.c_str());
            //        EndianConvertReverse(ip);

            //        stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY);
            //        stmt->setUInt32(0, ip);
            //        if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt))
            //        {
            //            std::string loginCountry = (*sessionCountryQuery)[0].GetString();
            //            TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[AuthChallenge] Account '%s' is locked to country: '%s' Player country is '%s'", _login.c_str(), accountCountry.c_str(), loginCountry.c_str());
            //            if (loginCountry != accountCountry)
            //            {
            //                TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[AuthChallenge] Account country differs.");
            //                pkt << uint8(WOW_FAIL_UNLOCKABLE_LOCK);
            //                locked = true;
            //            }
            //            else
            //                TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[AuthChallenge] Account country matches");
            //        }
            //        else
            //            TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[AuthChallenge] IP2NATION Table empty");
            //    }
            //}

            if (!locked)
            {
                //set expired bans to inactive
                LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPIRED_ACCOUNT_BANS));

                // If the account is banned, reject the logon attempt
                stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED);
                stmt->setUInt32(0, fields[1].GetUInt32());
                PreparedQueryResult banresult = LoginDatabase.Query(stmt);
                if (banresult)
                {
                    if ((*banresult)[0].GetUInt32() == (*banresult)[1].GetUInt32())
                    {
                        pkt << uint8(WOW_FAIL_BANNED);
                        TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "'%s:%d' [AuthChallenge] Banned account %s tried to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ());
                    }
                    else
                    {
                        pkt << uint8(WOW_FAIL_SUSPENDED);
                        TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "'%s:%d' [AuthChallenge] Temporarily banned account %s tried to login!", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str ());
                    }
                }
                else
                {
                    // Get the password from the account table, upper it, and make the SRP6 calculation
                    std::string rI = fields[0].GetString();

                    // Don't calculate (v, s) if there are already some in the database
                    std::string databaseV = fields[6].GetString();
                    std::string databaseS = fields[7].GetString();

                    TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str());

                    // multiply with 2 since bytes are stored as hexstring
                    if (databaseV.size() != s_BYTE_SIZE * 2 || databaseS.size() != s_BYTE_SIZE * 2)
                        _SetVSFields(rI);
                    else
                    {
                        s.SetHexStr(databaseS.c_str());
                        v.SetHexStr(databaseV.c_str());
                    }

                    b.SetRand(19 * 8);
                    BigNumber gmod = g.ModExp(b, N);
                    B = ((v * 3) + gmod) % N;

                    ASSERT(gmod.GetNumBytes() <= 32);

                    BigNumber unk3;
                    unk3.SetRand(16 * 8);

                    // Fill the response packet with the result
                    if (AuthHelper::IsAcceptedClientBuild(_build))
                        pkt << uint8(WOW_SUCCESS);
                    else
                        pkt << uint8(WOW_FAIL_VERSION_INVALID);

                    // B may be calculated < 32B so we force minimal length to 32B
                    pkt.append(B.AsByteArray(32), 32);      // 32 bytes
                    pkt << uint8(1);
                    pkt.append(g.AsByteArray(), 1);
                    pkt << uint8(32);
                    pkt.append(N.AsByteArray(32), 32);
                    pkt.append(s.AsByteArray(), s.GetNumBytes());   // 32 bytes
                    pkt.append(unk3.AsByteArray(16), 16);
                    uint8 securityFlags = 0;
                    pkt << uint8(securityFlags);            // security flags (0x0...0x04)

                    if (securityFlags & 0x01)               // PIN input
                    {
                        pkt << uint32(0);
                        pkt << uint64(0) << uint64(0);      // 16 bytes hash?
                    }

                    if (securityFlags & 0x02)               // Matrix input
                    {
                        pkt << uint8(0);
                        pkt << uint8(0);
                        pkt << uint8(0);
                        pkt << uint8(0);
                        pkt << uint64(0);
                    }

                    if (securityFlags & 0x04)               // Security token input
                        pkt << uint8(1);

                    uint8 secLevel = fields[5].GetUInt8();
                    _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR;

                    _localizationName.resize(4);
                    for (int i = 0; i < 4; ++i)
                        _localizationName[i] = ch->country[4-i-1];

                    TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "'%s:%d' [AuthChallenge] account %s is using '%c%c%c%c' locale (%u)", socket().getRemoteAddress().c_str(), socket().getRemotePort(),
                            _login.c_str (), ch->country[3], ch->country[2], ch->country[1], ch->country[0], GetLocaleByName(_localizationName)
                        );
                }
            }
        }
        else                                                //no account
            pkt << uint8(WOW_FAIL_UNKNOWN_ACCOUNT);
    }

    socket().send((char const*)pkt.contents(), pkt.size());
    return true;
}
Пример #5
0
// Reconnect Challenge command handler
bool AuthSocket::_HandleReconnectChallenge()
{
    TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "Entering _HandleReconnectChallenge");
    if (socket().recv_len() < sizeof(sAuthLogonChallenge_C))
        return false;

    // Read the first 4 bytes (header) to get the length of the remaining of the packet
    std::vector<uint8> buf;
    buf.resize(4);

    socket().recv((char *)&buf[0], 4);

#if TRINITY_ENDIAN == TRINITY_BIGENDIAN
    EndianConvert(*((uint16*)(buf[0])));
#endif

    uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size;
    TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[ReconnectChallenge] got header, body is %#04x bytes", remaining);

    if ((remaining < sizeof(sAuthLogonChallenge_C) - buf.size()) || (socket().recv_len() < remaining))
        return false;

    // No big fear of memory outage (size is int16, i.e. < 65536)
    buf.resize(remaining + buf.size() + 1);
    buf[buf.size() - 1] = 0;
    sAuthLogonChallenge_C *ch = (sAuthLogonChallenge_C*)&buf[0];

    // Read the remaining of the packet
    socket().recv((char *)&buf[4], remaining);
    TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[ReconnectChallenge] got full packet, %#04x bytes", ch->size);
    TC_LOG_DEBUG(LOG_FILTER_AUTHSERVER, "[ReconnectChallenge] name(%d): '%s'", ch->I_len, ch->I);

    _login = (const char*)ch->I;

    PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_SESSIONKEY);
    stmt->setString(0, _login);
    PreparedQueryResult result = LoginDatabase.Query(stmt);

    // Stop if the account is not found
    if (!result)
    {
        TC_LOG_ERROR(LOG_FILTER_AUTHSERVER, "'%s:%d' [ERROR] user %s tried to login and we cannot find his session key in the database.", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());
        socket().shutdown();
        return false;
    }

    // Reinitialize build, expansion and the account securitylevel
    _build = ch->build;
    _expversion = uint8(AuthHelper::IsPostBCAcceptedClientBuild(_build) ? POST_BC_EXP_FLAG : (AuthHelper::IsPreBCAcceptedClientBuild(_build) ? PRE_BC_EXP_FLAG : NO_VALID_EXP_FLAG));
    _os = (const char*)ch->os;

    if (_os.size() > 4)
        return false;

    // Restore string order as its byte order is reversed
    std::reverse(_os.begin(), _os.end());

    Field* fields = result->Fetch();
    uint8 secLevel = fields[2].GetUInt8();
    _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR;

    K.SetHexStr ((*result)[0].GetCString());

    // Sending response
    ByteBuffer pkt;
    pkt << uint8(AUTH_RECONNECT_CHALLENGE);
    pkt << uint8(0x00);
    _reconnectProof.SetRand(16 * 8);
    pkt.append(_reconnectProof.AsByteArray(16), 16);        // 16 bytes random
    pkt << uint64(0x00) << uint64(0x00);                    // 16 bytes zeros
    socket().send((char const*)pkt.contents(), pkt.size());
    return true;
}
Пример #6
0
void CUser::MerchantItemBuy(Packet & pkt)
{
	uint32 itemid, req_gold;
	uint16 item_count, leftover_count;
	uint8 item_slot, dest_slot;

	CUser *pMerchant = g_pMain->GetUserPtr(m_sMerchantsSocketID);
	if (pMerchant == NULL)
		return;

	pkt >> itemid >> item_count >> item_slot >> dest_slot;

	// Make sure the slots are correct and that we're actually buying at least 1 item.
	if (item_slot >= MAX_MERCH_ITEMS
		|| dest_slot >= HAVE_MAX
		|| item_count == 0)
		return;

	// Grab pointers to the items.
	_MERCH_DATA *pMerch = &pMerchant->m_arMerchantItems[item_slot];
	_ITEM_DATA *pItem = GetItem(SLOT_MAX + dest_slot);

	// Make sure the merchant actually has that item in that slot
	// and that they have enough
	if (pMerch->nNum != itemid
		|| pMerch->sCount < item_count)
		return;

	// If it's not stackable, and we're specifying something other than 1
	// we really don't care to handle this request...
	_ITEM_TABLE *proto = g_pMain->GetItemPtr(itemid);
	if (proto == NULL
		|| !proto->m_bCountable && item_count != 1)
		return;

	// Do we have enough coins?
	req_gold = pMerch->nPrice * item_count;
	if (m_iGold < req_gold)
		return;

	// If the slot's not empty
	if (pItem->nNum != 0 
		// and we already have an item that isn't the same item
		// or it's the same item but the item's not stackable...
		&& (pItem->nNum != itemid || !proto->m_bCountable))
		return;

	leftover_count = pMerch->sCount - item_count;
	pMerchant->GoldChange(GetSocketID(), req_gold);
	pItem->nNum = itemid;
	pItem->sCount += item_count;
	pItem->sDuration = pMerch->sDuration;
	pItem->nSerialNum = pMerch->nSerialNum;

	pMerch->sCount -= item_count;

	// TO-DO : Proper checks for the removal of the items in the array, we're now assuming everything gets bought
	if (pMerch->sCount == 0)
		memset(pMerch, 0, sizeof(_MERCH_DATA));

	SetSlotItemValue();
	pMerchant->SetSlotItemValue();

	SetUserAbility();
	pMerchant->SetUserAbility();

	SendStackChange(itemid, pItem->sCount, pItem->sDuration, dest_slot, 
		(pItem->sCount == item_count)); // is it a new item?

	pMerchant->SendStackChange(itemid, leftover_count, pMerch->sDuration, 
		pMerch->bOriginalSlot - SLOT_MAX);

	Packet result(WIZ_MERCHANT, uint8(MERCHANT_ITEM_PURCHASED));
	result << itemid << GetName();
	pMerchant->Send(&result);

	result.clear();

	result	<< uint8(MERCHANT_ITEM_BUY) << uint16(1)
			<< itemid << leftover_count
			<< item_slot << dest_slot;
	Send(&result);

	if (item_slot < 4 && leftover_count == 0)
	{
		result.Initialize(WIZ_MERCHANT_INOUT);
		result << uint8(2) << m_sMerchantsSocketID << uint16(item_slot);
		pMerchant->SendToRegion(&result);
	}

	int nItemsRemaining = 0;
	for (int i = 0; i < MAX_MERCH_ITEMS; i++)
	{
		if (pMerchant->m_arMerchantItems[i].nNum != 0)
			nItemsRemaining++;
	}

	if (nItemsRemaining == 0)
		MerchantClose();
}			
Пример #7
0
void CUser::BuyingMerchantBuy(Packet & pkt)
{
	uint32 nPrice;
	uint16 sStackSize, sRemainingStackSize;
	uint8 bSellerSrcSlot, bMerchantListSlot;

	CUser *pMerchant = g_pMain->GetUserPtr(m_sMerchantsSocketID);
	if (pMerchant == NULL)
		return;

	pkt >> bSellerSrcSlot >> bMerchantListSlot >> sStackSize;

	_MERCH_DATA *pWantedItem = &pMerchant->m_arMerchantItems[bMerchantListSlot];
	_ITEM_DATA *pSellerItem = GetItem(SLOT_MAX + bSellerSrcSlot);

	// Make sure the merchant actually has that item in that slot
	// and that they want enough, and the selling user has enough
	if (pWantedItem->nNum != pSellerItem->nNum
		|| pWantedItem->sCount < sStackSize
		|| pSellerItem->sCount < sStackSize)
		return;

	// If it's not stackable, and we're specifying something other than 1
	// we really don't care to handle this request...
	_ITEM_TABLE *proto = g_pMain->GetItemPtr(pWantedItem->nNum);
	if (proto == NULL
		|| !proto->m_bCountable && sStackSize != 1)
		return;

	// Do they have enough coins?
	nPrice = pWantedItem->nPrice * sStackSize;
	if (nPrice > pMerchant->m_iGold)
		return;

	// Now find the buyer a home for their item
	int8 bDstPos = pMerchant->FindSlotForItem(pWantedItem->nNum, sStackSize);
	if (bDstPos < 0)
		return;

	_ITEM_DATA *pMerchantItem = pMerchant->GetItem(bDstPos);
	// Take coins off the buying merchant
	if (!pMerchant->GoldLose(nPrice))
		return;

	// and give them all to me, me, me!
	GoldGain(nPrice);

	// Get the remaining stack size after purchase.
	sRemainingStackSize = pSellerItem->sCount - sStackSize;

	// Now we give the buying merchant their wares.
	pMerchantItem->nNum = pSellerItem->nNum;
	pMerchantItem->sDuration = pSellerItem->sDuration;
	pSellerItem->sCount -= sStackSize;
	pMerchantItem->sCount += sStackSize;

	// If the seller's all out, remove their item.
	if (pSellerItem->sCount == 0)
		memset(pSellerItem, 0, sizeof(_ITEM_DATA));

	// TO-DO : Proper checks for the removal of the items in the array, we're now assuming everything gets bought

	// Update players
	SendStackChange(pSellerItem->nNum, pSellerItem->sCount, pSellerItem->sDuration, bSellerSrcSlot);
	pMerchant->SendStackChange(pMerchantItem->nNum, pMerchantItem->sCount, pMerchantItem->sDuration, bDstPos,
		pMerchantItem->sCount == sStackSize); 	// if the buying merchant only has what they wanted, it's a new item.
												// (otherwise it was a stackable item that was merged into an existing slot)

	Packet result(WIZ_MERCHANT, uint8(MERCHANT_BUY_BOUGHT));
	result << bMerchantListSlot << uint16(0) << GetName();
	pMerchant->Send(&result);

	result.clear();
	result	<< uint8(MERCHANT_BUY_SOLD) << uint16(1)
			<< pMerchantItem->nNum << sRemainingStackSize
			<< bMerchantListSlot;
	Send(&result);

	if (bMerchantListSlot < 4 && sRemainingStackSize == 0)
	{
		result.Initialize(WIZ_MERCHANT_INOUT);
		result << uint8(2) << m_sMerchantsSocketID << uint16(bMerchantListSlot);
		pMerchant->SendToRegion(&result);
	}

	int nItemsRemaining = 0;
	for (int i = 0; i < MAX_MERCH_ITEMS; i++)
	{
		if (pMerchant->m_arMerchantItems[i].nNum != 0)
			nItemsRemaining++;
	}

	if (nItemsRemaining == 0)
		pMerchant->BuyingMerchantClose();
		
}
Пример #8
0
void CMagicProcess::AreaAttackDamage(int magictype, int rx, int rz, int magicid, int moral, int data1, int data2, int data3, int dexpoint, int righthand_damage)
{
	MAP* pMap = m_pSrcUser->GetMap();
	if (pMap == NULL) return;
	// 자신의 region에 있는 UserArray을 먼저 검색하여,, 가까운 거리에 유저가 있는지를 판단..
	if(rx < 0 || rz < 0 || rx > pMap->GetXRegionMax() || rz > pMap->GetZRegionMax())	{
		TRACE("#### CMagicProcess-AreaAttackDamage() Fail : [nid=%d, name=%s], nRX=%d, nRZ=%d #####\n", m_pSrcUser->m_iUserId, m_pSrcUser->m_strUserID, rx, rz);
		return;
	}

	_MAGIC_TYPE3* pType3 = NULL;
	_MAGIC_TYPE4* pType4 = NULL;
	_MAGIC_TABLE* pMagic = NULL;

	int damage = 0, tid = 0, target_damage = 0, attribute = 0;
	float fRadius = 0; 

	pMagic = g_pMain.m_MagictableArray.GetData( magicid );   // Get main magic table.
	if( !pMagic )	{
		TRACE("#### CMagicProcess-AreaAttackDamage Fail : magic maintable error ,, magicid=%d\n", magicid);
		return;
	}

	if(magictype == 3)	{
		pType3 = g_pMain.m_Magictype3Array.GetData( magicid );      // Get magic skill table type 3.
		if( !pType3 )	{
			TRACE("#### CMagicProcess-AreaAttackDamage Fail : magic table3 error ,, magicid=%d\n", magicid);
			return;
		}
		target_damage = pType3->sFirstDamage;
		attribute = pType3->bAttribute;
		fRadius = (float)pType3->bRadius;
	}
	else if(magictype == 4)	{
		pType4 = g_pMain.m_Magictype4Array.GetData( magicid );      // Get magic skill table type 3.
		if( !pType4 )	{
			TRACE("#### CMagicProcess-AreaAttackDamage Fail : magic table4 error ,, magicid=%d\n", magicid);
			return;
		}
		fRadius = (float)pType4->bRadius;
	}

	if( fRadius <= 0 )	{
		TRACE("#### CMagicProcess-AreaAttackDamage Fail : magicid=%d, radius = %d\n", magicid, fRadius);
		return;
	}


	__Vector3 vStart, vEnd;
	CNpc* pNpc = NULL ;      // Pointer initialization!
	float fDis = 0.0f;
	vStart.Set((float)data1, (float)0, (float)data3);
	int count = 0, total_mon = 0, attack_type=0;
	int* pNpcIDList = NULL;
	BOOL bResult = TRUE;

	EnterCriticalSection( &g_region_critical );

	CRegion *pRegion = &pMap->m_ppRegion[rx][rz];
	total_mon = pRegion->m_RegionNpcArray.GetSize();
	pNpcIDList = new int[total_mon];

	foreach_stlmap (itr, pRegion->m_RegionNpcArray)
		pNpcIDList[count++] = *itr->second;

	LeaveCriticalSection(&g_region_critical);

	for(int i = 0; i < total_mon; i++)
	{
		int nid = pNpcIDList[i];
		if( nid < NPC_BAND ) continue;
		pNpc = (CNpc*)g_pMain.m_arNpc.GetData(nid - NPC_BAND);

		if (pNpc == NULL || pNpc->m_NpcState == NPC_DEAD)
			continue;

		if( m_pSrcUser->m_bNation == pNpc->m_byGroup ) continue;
		vEnd.Set(pNpc->m_fCurX, pNpc->m_fCurY, pNpc->m_fCurZ); 
		fDis = pNpc->GetDistance(vStart, vEnd);

		if(fDis > fRadius)
			continue;

		if(magictype == 3)	{	// 타잎 3일 경우...
			damage = GetMagicDamage(pNpc->m_sNid+NPC_BAND, target_damage, attribute, dexpoint, righthand_damage);
			TRACE("Area magictype3 ,, magicid=%d, damage=%d\n", magicid, damage);
			if(damage >= 0)	{
				bResult = pNpc->SetHMagicDamage(damage);
			}
			else	{
				damage = abs(damage);
				if(pType3->bAttribute == 3)   attack_type = 3; // 기절시키는 마법이라면.....
				else attack_type = magicid;

				if(pNpc->SetDamage(attack_type, damage, m_pSrcUser->m_strUserID, m_pSrcUser->m_iUserId + USER_BAND) == FALSE)	{
					// Npc가 죽은 경우,,
					pNpc->SendExpToUserList(); // 경험치 분배!!
					pNpc->SendDead();
					m_pSrcUser->SendAttackSuccess(pNpc->m_sNid+NPC_BAND, MAGIC_ATTACK_TARGET_DEAD, damage, pNpc->m_iHP);
				}
				else	{
					m_pSrcUser->SendAttackSuccess(pNpc->m_sNid+NPC_BAND, ATTACK_SUCCESS, damage, pNpc->m_iHP);
				}
			}

			// 패킷 전송.....
			//if ( pMagic->bType[1] == 0 || pMagic->bType[1] == 3 ) 
			{
				Packet result(AG_MAGIC_ATTACK_RESULT, uint8(MAGIC_EFFECTING));
				result	<< magicid << m_pSrcUser->m_iUserId << uint16(pNpc->m_sNid+NPC_BAND)
						<< uint16(data1) << uint16(bResult) << uint16(data3)
						<< uint16(moral) << uint16(0) << uint16(0);
				g_pMain.Send(&result);
			}
		}
		else if(magictype == 4)	{	// 타잎 4일 경우...
			bResult = TRUE;
			switch (pType4->bBuffType) {	// Depending on which buff-type it is.....
				case 1 :				// HP 올리기..
					break;

				case 2 :				// 방어력 올리기..
					break;

				case 4 :				// 공격력 올리기..
					break;

				case 5 :				// 공격 속도 올리기..
					break;

				case 6 :				// 이동 속도 올리기..
					//if (pNpc->m_MagicType4[pType4->bBuffType-1].sDurationTime > 0) {
					//	result = 0 ;
					//}
					//else {
						pNpc->m_MagicType4[pType4->bBuffType-1].byAmount = pType4->bSpeed;
						pNpc->m_MagicType4[pType4->bBuffType-1].sDurationTime = pType4->sDuration;
						pNpc->m_MagicType4[pType4->bBuffType-1].tStartTime = UNIXTIME;
						pNpc->m_fSpeed_1 = (float)(pNpc->m_fOldSpeed_1 * ((double)pType4->bSpeed / 100));
						pNpc->m_fSpeed_2 = (float)(pNpc->m_fOldSpeed_2 * ((double)pType4->bSpeed / 100));
					//}
					break;

				case 7 :				// 능력치 올리기...
					break;

				case 8 :				// 저항력 올리기...
					break;

				case 9 :				// 공격 성공율 및 회피 성공율 올리기..
					break;	

				default :
					bResult = FALSE;
					break;
			}

			TRACE("Area magictype4 ,, magicid=%d\n", magicid);

			Packet result(AG_MAGIC_ATTACK_RESULT, uint8(MAGIC_EFFECTING));
			result	<< magicid << m_pSrcUser->m_iUserId << uint16(pNpc->m_sNid+NPC_BAND)
					<< uint16(data1) << uint16(bResult) << uint16(data3)
					<< uint16(0) << uint16(0) << uint16(0);
			g_pMain.Send(&result);
		}
	}

	if(pNpcIDList)	{
		delete [] pNpcIDList;
		pNpcIDList = NULL;
	}
}
Пример #9
0
//////////////////////////////////////////////////////////////
/// This function handles CMSG_CREATURE_QUERY:
//////////////////////////////////////////////////////////////
void WorldSession::HandleCreatureQueryOpcode( WorldPacket & recv_data )
{
	CHECK_PACKET_SIZE(recv_data, 12);
	WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 150);
	uint32 entry;
	uint64 guid;
	CreatureInfo *ci;

	recv_data >> entry;
	recv_data >> guid;

	if(entry == 300000)
	{
		data << (uint32)entry;
		data << "WayPoint";
		data << uint8(0) << uint8(0) << uint8(0);
		data << "Level is WayPoint ID";
		for(uint32 i = 0; i < 8;i++)
		{
			data << uint32(0);
		}
		data << uint8(0);  
	}
	else
	{
		ci = CreatureNameStorage.LookupEntry(entry);
		if(ci == NULL)
			return;

		LocalizedCreatureName * lcn = (language>0) ? sLocalizationMgr.GetLocalizedCreatureName(entry, language) : NULL;

		if(lcn == NULL)
		{
			sLog.outDetail("WORLD: CMSG_CREATURE_QUERY '%s'", ci->Name);
			data << (uint32)entry;
			data << ci->Name;
			data << uint8(0) << uint8(0) << uint8(0);
			data << ci->SubName;
		}
		else
		{
			sLog.outDetail("WORLD: CMSG_CREATURE_QUERY '%s' (localized to %s)", ci->Name, lcn->Name);
			data << (uint32)entry;
			data << lcn->Name;
			data << uint8(0) << uint8(0) << uint8(0);
			data << lcn->SubName;
		}
		data << ci->info_str; //!!! this is a string in 2.3.0 Example: stormwind guard has : "Direction"
		data << ci->Flags1;  
		data << ci->Type;
		data << ci->Family;
		data << ci->Rank;
		data << ci->Unknown1;
		data << ci->SpellDataID;
		data << ci->Male_DisplayID;
		data << ci->Female_DisplayID;
		data << ci->Male_DisplayID2;
		data << ci->Female_DisplayID2;
		data << ci->unkfloat1;
		data << ci->unkfloat2;
		data << ci->Leader;
	}

	SendPacket( &data );
}
Пример #10
0
void CMagicProcess::ExecuteType4(int magicid, int sid, int tid, int data1, int data2, int data3, int moral )
{
	Packet result(AG_MAGIC_ATTACK_RESULT);
	int damage = 0;
	BOOL bResult = TRUE;

	_MAGIC_TYPE4* pType = NULL;
	CNpc* pNpc = NULL ;      // Pointer initialization!

	if(tid == -1)	{	// 지역 공격
		bResult = AreaAttack(4, magicid, moral, data1, data2, data3, 0, 0);
		if (bResult)
			return;

		goto fail_return;
	}

	pNpc = g_pMain.m_arNpc.GetData(tid-NPC_BAND);
	if(pNpc == NULL || pNpc->m_NpcState == NPC_DEAD || pNpc->m_iHP == 0)	{
		bResult = FALSE;
		goto fail_return;
	}

	pType = g_pMain.m_Magictype4Array.GetData( magicid );     // Get magic skill table type 4.
	if( !pType ) return;

	//TRACE("magictype4 ,, magicid=%d\n", magicid);

	switch (pType->bBuffType) {	// Depending on which buff-type it is.....
		case 1 :				// HP 올리기..
			break;

		case 2 :				// 방어력 올리기..
			break;

		case 4 :				// 공격력 올리기..
			break;

		case 5 :				// 공격 속도 올리기..
			break;

		case 6 :				// 이동 속도 올리기..
//			if (pNpc->m_MagicType4[pType->bBuffType-1].sDurationTime > 0) {
//				result = 0 ;
//				goto fail_return ;					
//			}
//			else {
				pNpc->m_MagicType4[pType->bBuffType-1].byAmount = pType->bSpeed;
				pNpc->m_MagicType4[pType->bBuffType-1].sDurationTime = pType->sDuration;
				pNpc->m_MagicType4[pType->bBuffType-1].tStartTime = UNIXTIME;
				pNpc->m_fSpeed_1 = (float)(pNpc->m_fOldSpeed_1 * ((double)pType->bSpeed / 100));
				pNpc->m_fSpeed_2 = (float)(pNpc->m_fOldSpeed_2 * ((double)pType->bSpeed / 100));
				//TRACE("executeType4 ,, speed1=%.2f, %.2f,, type=%d, cur=%.2f, %.2f\n", pNpc->m_fOldSpeed_1, pNpc->m_fOldSpeed_2, pType->bSpeed, pNpc->m_fSpeed_1, pNpc->m_fSpeed_2);
//			}
			break;

		case 7 :				// 능력치 올리기...
			break;

		case 8 :				// 저항력 올리기...
			break;

		case 9 :				// 공격 성공율 및 회피 성공율 올리기..
			break;	

		default :
			bResult = FALSE;
			goto fail_return;
	}

	result	<< uint8(MAGIC_EFFECTING) << magicid << uint16(sid) << uint16(tid)
			<< uint16(data1) << uint16(bResult) << uint16(data3)
			<< uint16(0) << uint16(0) << uint16(0);
	g_pMain.Send(&result);
	return;

fail_return:
	result	<< uint8(MAGIC_FAIL) << magicid << uint16(sid) << uint16(tid)
			<< uint16(0) << uint16(0) << uint16(0)
			<< uint16(0) << uint16(0) << uint16(0);
	g_pMain.Send(&result);
}
Пример #11
0
void CMagicProcess::ExecuteType3(int magicid, int tid, int data1, int data2, int data3, int moral, int dexpoint, int righthand_damage )   // Applied when a magical attack, healing, and mana restoration is done.
{	
	int damage = 0, attack_type = 0; 
	BOOL bResult = TRUE;
	_MAGIC_TYPE3* pType = NULL;
	CNpc* pNpc = NULL ;      // Pointer initialization!

	_MAGIC_TABLE* pMagic = NULL;
	pMagic = g_pMain.m_MagictableArray.GetData( magicid );   // Get main magic table.
	if( !pMagic ) return; 

	if(tid == -1)	{	// 지역 공격
		bResult = AreaAttack(3, magicid, moral, data1, data2, data3, dexpoint, righthand_damage);
		//if(result == 0)		goto packet_send;
		//else 
			return;
	}

	pNpc = g_pMain.m_arNpc.GetData(tid-NPC_BAND);
	if(pNpc == NULL || pNpc->m_NpcState == NPC_DEAD || pNpc->m_iHP == 0)	{
		bResult = FALSE;
		goto packet_send;
	}
	
	pType = g_pMain.m_Magictype3Array.GetData( magicid );      // Get magic skill table type 3.
	if( !pType ) return;
	
//	if (pType->sFirstDamage < 0) {
	if ((pType->sFirstDamage < 0) && (pType->bDirectType == 1) && (magicid < 400000)) {
		damage = GetMagicDamage(tid, pType->sFirstDamage, pType->bAttribute, dexpoint, righthand_damage) ;
	}
	else {
		damage = pType->sFirstDamage ;
	}

	//TRACE("magictype3 ,, magicid=%d, damage=%d\n", magicid, damage);
	
	if (pType->bDuration == 0)    { // Non-Durational Spells.
		if (pType->bDirectType == 1) {    // Health Point related !
			//damage = pType->sFirstDamage;     // Reduce target health point
//			if(damage >= 0)	{
			if(damage > 0)	{
				bResult = pNpc->SetHMagicDamage(damage);
			}
			else	{
				damage = abs(damage);
				if(pType->bAttribute == 3)   attack_type = 3; // 기절시키는 마법이라면.....
				else attack_type = magicid;

				if (!pNpc->SetDamage(attack_type, damage, m_pSrcUser->m_strUserID, m_pSrcUser->m_iUserId + USER_BAND))
				{
					// Npc가 죽은 경우,,
					pNpc->SendExpToUserList(); // 경험치 분배!!
					pNpc->SendDead();
					m_pSrcUser->SendAttackSuccess(tid, MAGIC_ATTACK_TARGET_DEAD, damage, pNpc->m_iHP, MAGIC_ATTACK);
				}
				else	{
					// 공격 결과 전송
					m_pSrcUser->SendAttackSuccess(tid, ATTACK_SUCCESS, damage, pNpc->m_iHP, MAGIC_ATTACK);
				}
			}
		}
		else if ( pType->bDirectType == 2 || pType->bDirectType == 3 )    // Magic or Skill Point related !
			pNpc->MSpChange(pType->bDirectType, pType->sFirstDamage);     // Change the SP or the MP of the target.
		else if( pType->bDirectType == 4 )     // Armor Durability related.
			pNpc->ItemWoreOut( DEFENCE, pType->sFirstDamage);     // Reduce Slot Item Durability
	}
	else if (pType->bDuration != 0)   {  // Durational Spells! Remember, durational spells only involve HPs.
		if(damage >= 0)	{
		}
		else	{
			damage = abs(damage);
			if(pType->bAttribute == 3)   attack_type = 3; // 기절시키는 마법이라면.....
			else attack_type = magicid;
				
			if(pNpc->SetDamage(attack_type, damage, m_pSrcUser->m_strUserID, m_pSrcUser->m_iUserId + USER_BAND) == FALSE)	{
				// Npc가 죽은 경우,,
				pNpc->SendExpToUserList(); // 경험치 분배!!
				pNpc->SendDead();
				m_pSrcUser->SendAttackSuccess(tid, MAGIC_ATTACK_TARGET_DEAD, damage, pNpc->m_iHP);
			}
			else	{
				// 공격 결과 전송
				m_pSrcUser->SendAttackSuccess(tid, ATTACK_SUCCESS, damage, pNpc->m_iHP);
			}
		}

		damage = GetMagicDamage(tid, pType->sTimeDamage, pType->bAttribute, dexpoint, righthand_damage);
		// The duration magic routine.
		for(int i=0; i<MAX_MAGIC_TYPE3; i++)	{
			if(pNpc->m_MagicType3[i].sHPAttackUserID == -1 && pNpc->m_MagicType3[i].byHPDuration == 0)	{
				pNpc->m_MagicType3[i].sHPAttackUserID = m_pSrcUser->m_iUserId;
				pNpc->m_MagicType3[i].tStartTime = UNIXTIME;
				pNpc->m_MagicType3[i].byHPDuration = pType->bDuration;
				pNpc->m_MagicType3[i].byHPInterval = 2;
				pNpc->m_MagicType3[i].sHPAmount = damage / (pType->bDuration / 2);
				break;
			}
		}	
	} 

packet_send:
	//if ( pMagic->bType[1] == 0 || pMagic->bType[1] == 3 ) 
	{
		Packet result(AG_MAGIC_ATTACK_RESULT, uint8(MAGIC_EFFECTING));
		result	<< magicid << m_pSrcUser->m_iUserId << uint16(tid)
				<< uint16(data1) << uint16(bResult) << uint16(data3)
				<< uint16(moral) << uint16(0) << uint16(0);
		g_pMain.Send(&result);
	}
	
}
Пример #12
0
void WorldSession::HandlePlayerLogin(LoginQueryHolder *holder)
{
    uint64 playerGuid = holder->GetGuid();

    Player *pCurrChar = new Player(this);
    pCurrChar->GetMotionMaster()->Initialize();

    // "GetAccountId()==db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools)
    if(!pCurrChar->LoadFromDB(GUID_LOPART(playerGuid), holder))
    {
        KickPlayer();                                       // disconnect client, player no set to session and it will not deleted or saved at kick
        delete pCurrChar;                                   // delete it manually
        delete holder;                                      // delete all unprocessed queries
        m_playerLoading = false;
        return;
    }

    SetPlayer(pCurrChar);

    pCurrChar->SendDungeonDifficulty(false);

    WorldPacket data( SMSG_LOGIN_VERIFY_WORLD, 20 );
    data << pCurrChar->GetMapId();
    data << pCurrChar->GetPositionX();
    data << pCurrChar->GetPositionY();
    data << pCurrChar->GetPositionZ();
    data << pCurrChar->GetOrientation();
    SendPacket(&data);

    // load player specific part before send times
    LoadAccountData(holder->GetResult(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA),PER_CHARACTER_CACHE_MASK);
    SendAccountDataTimes(PER_CHARACTER_CACHE_MASK);

    data.Initialize(SMSG_FEATURE_SYSTEM_STATUS, 2);         // added in 2.2.0
    data << uint8(2);                                       // unknown value
    data << uint8(0);                                       // enable(1)/disable(0) voice chat interface in client
    SendPacket(&data);

    // Send MOTD
    {
        data.Initialize(SMSG_MOTD, 50);                     // new in 2.0.1
        data << (uint32)0;

        uint32 linecount=0;
        std::string str_motd = sWorld.GetMotd();
        std::string::size_type pos, nextpos;

        pos = 0;
        while ( (nextpos= str_motd.find('@',pos)) != std::string::npos )
        {
            if (nextpos != pos)
            {
                data << str_motd.substr(pos, nextpos-pos);
                ++linecount;
            }
            pos = nextpos + 1;
        }

        if (pos < str_motd.length())
        {
            data << str_motd.substr(pos);
            ++linecount;
        }

        data.put(0, linecount);

        SendPacket( &data );
        DEBUG_LOG( "WORLD: Sent motd (SMSG_MOTD)" );
    }

    //QueryResult *result = CharacterDatabase.PQuery("SELECT guildid,rank FROM guild_member WHERE guid = '%u'",pCurrChar->GetGUIDLow());
    QueryResult *resultGuild = holder->GetResult(PLAYER_LOGIN_QUERY_LOADGUILD);

    if(resultGuild)
    {
        Field *fields = resultGuild->Fetch();
        pCurrChar->SetInGuild(fields[0].GetUInt32());
        pCurrChar->SetRank(fields[1].GetUInt32());
        delete resultGuild;
    }
    else if(pCurrChar->GetGuildId())                        // clear guild related fields in case wrong data about non existed membership
    {
        pCurrChar->SetInGuild(0);
        pCurrChar->SetRank(0);
    }

    if(pCurrChar->GetGuildId() != 0)
    {
        Guild* guild = sObjectMgr.GetGuildById(pCurrChar->GetGuildId());
        if(guild)
        {
            data.Initialize(SMSG_GUILD_EVENT, (1+1+guild->GetMOTD().size()+1));
            data << uint8(GE_MOTD);
            data << uint8(1);
            data << guild->GetMOTD();
            SendPacket(&data);
            DEBUG_LOG( "WORLD: Sent guild-motd (SMSG_GUILD_EVENT)" );

            guild->DisplayGuildBankTabsInfo(this);

            guild->BroadcastEvent(GE_SIGNED_ON, pCurrChar->GetGUID(), 1, pCurrChar->GetName(), "", "");
        }
        else
        {
            // remove wrong guild data
            sLog.outError("Player %s (GUID: %u) marked as member not existed guild (id: %u), removing guild membership for player.",pCurrChar->GetName(),pCurrChar->GetGUIDLow(),pCurrChar->GetGuildId());
            pCurrChar->SetInGuild(0);
        }
    }

    data.Initialize(SMSG_LEARNED_DANCE_MOVES, 4+4);
    data << uint32(0);
    data << uint32(0);
    SendPacket(&data);

    pCurrChar->SendInitialPacketsBeforeAddToMap();

    //Show cinematic at the first time that player login
    if( !pCurrChar->getCinematic() )
    {
        pCurrChar->setCinematic(1);

        if(ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(pCurrChar->getClass()))
        {
            if (cEntry->CinematicSequence)
                pCurrChar->SendCinematicStart(cEntry->CinematicSequence);
            else if (ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(pCurrChar->getRace()))
                pCurrChar->SendCinematicStart(rEntry->CinematicSequence);
        }
    }

    if (!pCurrChar->GetMap()->Add(pCurrChar))
    {
        // normal delayed teleport protection not applied (and this correct) for this case (Player object just created)
        AreaTrigger const* at = sObjectMgr.GetGoBackTrigger(pCurrChar->GetMapId());
        if(at)
            pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation());
        else
            pCurrChar->TeleportToHomebind();
    }

    sObjectAccessor.AddObject(pCurrChar);
    //DEBUG_LOG("Player %s added to Map.",pCurrChar->GetName());

    pCurrChar->SendInitialPacketsAfterAddToMap();

    CharacterDatabase.PExecute("UPDATE characters SET online = 1 WHERE guid = '%u'", pCurrChar->GetGUIDLow());
    LoginDatabase.PExecute("UPDATE account SET active_realm_id = %d WHERE id = '%u'", realmID, GetAccountId());
    pCurrChar->SetInGameTime( getMSTime() );

    // announce group about member online (must be after add to player list to receive announce to self)
    if (Group *group = pCurrChar->GetGroup())
        group->SendUpdate();

    // friend status
    sSocialMgr.SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetGUIDLow(), true);

    // Place character in world (and load zone) before some object loading
    pCurrChar->LoadCorpse();

    // setting Ghost+speed if dead
    if (pCurrChar->m_deathState != ALIVE)
    {
        // not blizz like, we must correctly save and load player instead...
        if(pCurrChar->getRace() == RACE_NIGHTELF)
            pCurrChar->CastSpell(pCurrChar, 20584, true);   // auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form)
        pCurrChar->CastSpell(pCurrChar, 8326, true);        // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?)

        pCurrChar->SetMovement(MOVE_WATER_WALK);
    }

    pCurrChar->ContinueTaxiFlight();

    // reset for all pets before pet loading
    if(pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS))
        Pet::resetTalentsForAllPetsOf(pCurrChar);

    // Load pet if any (if player not alive and in taxi flight or another then pet will remember as temporary unsummoned)
    pCurrChar->LoadPet();

    // Set FFA PvP for non GM in non-rest mode
    if(sWorld.IsFFAPvPRealm() && !pCurrChar->isGameMaster() && !pCurrChar->HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_RESTING) )
        pCurrChar->SetFFAPvP(true);

    if(pCurrChar->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP))
        pCurrChar->SetContestedPvP();

    // Apply at_login requests
    if(pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_SPELLS))
    {
        pCurrChar->resetSpells();
        SendNotification(LANG_RESET_SPELLS);
    }

    if(pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
    {
        pCurrChar->resetTalents(true,true);
        pCurrChar->SendTalentsInfoData(false);              // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state
        SendNotification(LANG_RESET_TALENTS);               // we can use SMSG_TALENTS_INVOLUNTARILY_RESET here
    }

    if (pCurrChar->HasAtLoginFlag(AT_LOGIN_FIRST))
        pCurrChar->RemoveAtLoginFlag(AT_LOGIN_FIRST);

    // show time before shutdown if shutdown planned.
    if(sWorld.IsShutdowning())
        sWorld.ShutdownMsg(true,pCurrChar);

    if(sWorld.getConfig(CONFIG_BOOL_ALL_TAXI_PATHS))
        pCurrChar->SetTaxiCheater(true);

    if(pCurrChar->isGameMaster())
        SendNotification(LANG_GM_ON);

    std::string IP_str = GetRemoteAddress();
    sLog.outChar("Account: %d (IP: %s) Login Character:[%s] (guid: %u)",
        GetAccountId(), IP_str.c_str(), pCurrChar->GetName(), pCurrChar->GetGUIDLow());

    if(!pCurrChar->IsStandState() && !pCurrChar->hasUnitState(UNIT_STAT_STUNNED))
        pCurrChar->SetStandState(UNIT_STAND_STATE_STAND);

    m_playerLoading = false;
    delete holder;
}
Пример #13
0
RASocket::RASocket()
{
    _minLevel = uint8(sConfigMgr->GetIntDefault("RA.MinLevel", 3));
    _commandExecuting = false;
}
Пример #14
0
uint8 Item::GetBagSlot() const
{
    return m_container ? m_container->GetSlot() : uint8(INVENTORY_SLOT_BAG_0);
}
Пример #15
0
/// Only _static_ data is sent in this packet !!!
void WorldSession::HandleCreatureQueryOpcode(WorldPacket& recvData)
{
    uint32 entry;
    recvData >> entry;
    uint64 guid;
    recvData >> guid;

    CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(entry);
    if (ci)
    {

        std::string Name, SubName;
        Name = ci->Name;
        SubName = ci->SubName;

        int loc_idx = GetSessionDbLocaleIndex();
        if (loc_idx >= 0)
        {
            if (CreatureLocale const* cl = sObjectMgr->GetCreatureLocale(entry))
            {
                ObjectMgr::GetLocaleString(cl->Name, loc_idx, Name);
                ObjectMgr::GetLocaleString(cl->SubName, loc_idx, SubName);
            }
        }
        TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CREATURE_QUERY '%s' - Entry: %u.", ci->Name.c_str(), entry);
                                                            // guess size
        WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 100);
        data << uint32(entry);                              // creature entry
        data << Name;
        data << uint8(0) << uint8(0) << uint8(0);           // name2, name3, name4, always empty
        data << SubName;
        data << ci->IconName;                               // "Directions" for guard, string for Icons 2.3.0
        data << uint32(ci->type_flags);                     // flags
        data << uint32(ci->type);                           // CreatureType.dbc
        data << uint32(ci->family);                         // CreatureFamily.dbc
        data << uint32(ci->rank);                           // Creature Rank (elite, boss, etc)
        data << uint32(ci->KillCredit[0]);                  // new in 3.1, kill credit
        data << uint32(ci->KillCredit[1]);                  // new in 3.1, kill credit
        data << uint32(ci->Modelid1);                       // Modelid1
        data << uint32(ci->Modelid2);                       // Modelid2
        data << uint32(ci->Modelid3);                       // Modelid3
        data << uint32(ci->Modelid4);                       // Modelid4
        data << float(ci->ModHealth);                       // dmg/hp modifier
        data << float(ci->ModMana);                         // dmg/mana modifier
        data << uint8(ci->RacialLeader);
        for (uint32 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i)
            data << uint32(ci->questItems[i]);              // itemId[6], quest drop
        data << uint32(ci->movementId);                     // CreatureMovementInfo.dbc
        SendPacket(&data);
        TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE");
    }
    else
    {
        TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: CMSG_CREATURE_QUERY - NO CREATURE INFO! (GUID: %u, ENTRY: %u)",
            GUID_LOPART(guid), entry);
        WorldPacket data(SMSG_CREATURE_QUERY_RESPONSE, 4);
        data << uint32(entry | 0x80000000);
        SendPacket(&data);
        TC_LOG_DEBUG(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_CREATURE_QUERY_RESPONSE");
    }
}
Пример #16
0
void WorldSession::SendListInventory( uint64 vendorguid )
{
    sLog.outDebug(  "WORLD: Sent SMSG_LIST_INVENTORY" );

    Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorguid,UNIT_NPC_FLAG_VENDOR);
    if (!pCreature)
    {
        sLog.outDebug( "WORLD: SendListInventory - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(vendorguid)) );
        _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0);
        return;
    }

    // remove fake death
    if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
        GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);

    // Stop the npc if moving
    pCreature->StopMoving();

    VendorItemData const* vItems = pCreature->GetVendorItems();
    if(!vItems)
    {
        _player->SendSellError( SELL_ERR_CANT_FIND_VENDOR, NULL, 0, 0);
        return;
    }

    uint8 numitems = vItems->GetItemCount();
    uint8 count = 0;

    WorldPacket data( SMSG_LIST_INVENTORY, (8+1+numitems*8*4) );
    data << uint64(vendorguid);
    data << uint8(numitems);

    float discountMod = _player->GetReputationPriceDiscount(pCreature);

    for (int i = 0; i < numitems; ++i )
    {
        if(VendorItem const* crItem = vItems->GetItem(i))
        {
            if(ItemPrototype const *pProto = objmgr.GetItemPrototype(crItem->item))
            {
                if((pProto->AllowableClass & _player->getClassMask()) == 0 && pProto->Bonding == BIND_WHEN_PICKED_UP && !_player->isGameMaster())
                    continue;

                ++count;

                // reputation discount
                int32 price = uint32(floor(pProto->BuyPrice * discountMod));

                data << uint32(count);
                data << uint32(crItem->item);
                data << uint32(pProto->DisplayInfoID);
                data << int32(crItem->maxcount <= 0 ? 0xFFFFFFFF : pCreature->GetVendorItemCurrentCount(crItem));
                data << uint32(price);
                data << uint32(pProto->MaxDurability);
                data << uint32(pProto->BuyCount);
                data << uint32(crItem->ExtendedCost);
            }
        }
    }

    if ( count == 0 || data.size() != 8 + 1 + size_t(count) * 8 * 4 )
        return;

    data.put<uint8>(8, count);
    SendPacket( &data );
}
Пример #17
0
void WorldSession::HandleCharCustomize(WorldPacket& recv_data)
{
    uint64 guid;
    std::string newname;

    recv_data >> guid;
    recv_data >> newname;

    uint8 gender, skin, face, hairStyle, hairColor, facialHair;
    recv_data >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face;

    QueryResult *result = CharacterDatabase.PQuery("SELECT at_login FROM characters WHERE guid ='%u'", GUID_LOPART(guid));
    if (!result)
    {
        WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
        data << uint8(CHAR_CREATE_ERROR);
        SendPacket( &data );
        return;
    }

    Field *fields = result->Fetch();
    uint32 at_loginFlags = fields[0].GetUInt32();
    delete result;

    if (!(at_loginFlags & AT_LOGIN_CUSTOMIZE))
    {
        WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
        data << uint8(CHAR_CREATE_ERROR);
        SendPacket( &data );
        return;
    }

    // prevent character rename to invalid name
    if (!normalizePlayerName(newname))
    {
        WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
        data << uint8(CHAR_NAME_NO_NAME);
        SendPacket( &data );
        return;
    }

    uint8 res = ObjectMgr::CheckPlayerName(newname,true);
    if (res != CHAR_NAME_SUCCESS)
    {
        WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
        data << uint8(res);
        SendPacket( &data );
        return;
    }

    // check name limitations
    if (GetSecurity() == SEC_PLAYER && sObjectMgr.IsReservedName(newname))
    {
        WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
        data << uint8(CHAR_NAME_RESERVED);
        SendPacket( &data );
        return;
    }

    // character with this name already exist
    if (uint64 newguid = sObjectMgr.GetPlayerGUIDByName(newname))
    {
        if (newguid != guid)
        {
            WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1);
            data << uint8(CHAR_CREATE_NAME_IN_USE);
            SendPacket( &data );
            return;
        }
    }

    CharacterDatabase.escape_string(newname);
    Player::Customize(guid, gender, skin, face, hairStyle, hairColor, facialHair);
    CharacterDatabase.PExecute("UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), uint32(AT_LOGIN_CUSTOMIZE), GUID_LOPART(guid));
    CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid ='%u'", GUID_LOPART(guid));

    std::string IP_str = GetRemoteAddress();
    sLog.outChar("Account: %d (IP: %s), Character guid: %u Customized to: %s", GetAccountId(), IP_str.c_str(), GUID_LOPART(guid), newname.c_str());

    WorldPacket data(SMSG_CHAR_CUSTOMIZE, 1+8+(newname.size()+1)+6);
    data << uint8(RESPONSE_SUCCESS);
    data << uint64(guid);
    data << newname;
    data << uint8(gender);
    data << uint8(skin);
    data << uint8(face);
    data << uint8(hairStyle);
    data << uint8(hairColor);
    data << uint8(facialHair);
    SendPacket(&data);
}
Пример #18
0
void WorldSession::HandleSocketOpcode(WorldPacket& recv_data)
{
    sLog.outDebug("WORLD: CMSG_SOCKET_GEMS");

    uint64 item_guid;
    uint64 gem_guids[MAX_GEM_SOCKETS];

    recv_data >> item_guid;
    if(!item_guid)
        return;

    for (int i = 0; i < MAX_GEM_SOCKETS; ++i)
        recv_data >> gem_guids[i];

    //cheat -> tried to socket same gem multiple times
    if ((gem_guids[0] && (gem_guids[0] == gem_guids[1] || gem_guids[0] == gem_guids[2])) ||
        (gem_guids[1] && (gem_guids[1] == gem_guids[2])))
        return;

    Item *itemTarget = _player->GetItemByGuid(item_guid);
    if(!itemTarget)                                         //missing item to socket
        return;

    ItemPrototype const* itemProto = itemTarget->GetProto();
    if(!itemProto)
        return;

    //this slot is excepted when applying / removing meta gem bonus
    uint8 slot = itemTarget->IsEquipped() ? itemTarget->GetSlot() : uint8(NULL_SLOT);

    Item *Gems[MAX_GEM_SOCKETS];
    for (int i = 0; i < MAX_GEM_SOCKETS; ++i)
        Gems[i] = gem_guids[i] ? _player->GetItemByGuid(gem_guids[i]) : NULL;

    GemPropertiesEntry const *GemProps[MAX_GEM_SOCKETS];
    for (int i = 0; i < MAX_GEM_SOCKETS; ++i)                //get geminfo from dbc storage
        GemProps[i] = (Gems[i]) ? sGemPropertiesStore.LookupEntry(Gems[i]->GetProto()->GemProperties) : NULL;

    for (int i = 0; i < MAX_GEM_SOCKETS; ++i)                //check for hack maybe
    {
        if (!GemProps[i])
            continue;

        // tried to put gem in socket where no socket exists (take care about prismatic sockets)
        if (!itemProto->Socket[i].Color)
        {
            // no prismatic socket
            if(!itemTarget->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
                return;

            // not first not-colored (not normaly used) socket
            if(i!=0 && !itemProto->Socket[i-1].Color && (i+1 >= MAX_GEM_SOCKETS || itemProto->Socket[i+1].Color))
                return;

            // ok, this is first not colored socket for item with prismatic socket
        }

        // tried to put normal gem in meta socket
        if (itemProto->Socket[i].Color == SOCKET_COLOR_META && GemProps[i]->color != SOCKET_COLOR_META)
            return;

        // tried to put meta gem in normal socket
        if (itemProto->Socket[i].Color != SOCKET_COLOR_META && GemProps[i]->color == SOCKET_COLOR_META)
            return;
    }

    uint32 GemEnchants[MAX_GEM_SOCKETS];
    uint32 OldEnchants[MAX_GEM_SOCKETS];
    for (int i = 0; i < MAX_GEM_SOCKETS; ++i)                //get new and old enchantments
    {
        GemEnchants[i] = (GemProps[i]) ? GemProps[i]->spellitemenchantement : 0;
        OldEnchants[i] = itemTarget->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i));
    }

    // check unique-equipped conditions
    for (int i = 0; i < MAX_GEM_SOCKETS; ++i)
    {
        if(!Gems[i])
            continue;

        // continue check for case when attempt add 2 similar unique equipped gems in one item.
        ItemPrototype const* iGemProto = Gems[i]->GetProto();

        // unique item (for new and already placed bit removed enchantments
        if (iGemProto->Flags & ITEM_FLAGS_UNIQUE_EQUIPPED)
        {
            for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
            {
                if(i==j)                                    // skip self
                    continue;

                if (Gems[j])
                {
                    if (iGemProto->ItemId == Gems[j]->GetEntry())
                    {
                        _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
                        return;
                    }
                }
                else if(OldEnchants[j])
                {
                    if(SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
                    {
                        if (iGemProto->ItemId == enchantEntry->GemID)
                        {
                            _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
                            return;
                        }
                    }
                }

            }
        }

        // unique limit type item
        int32 limit_newcount = 0;
        if (iGemProto->ItemLimitCategory)
        {
            if(ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(iGemProto->ItemLimitCategory))
            {
                for (int j = 0; j < MAX_GEM_SOCKETS; ++j)
                {
                    if (Gems[j])
                    {
                        // destroyed gem
                        if (OldEnchants[j])
                        {
                            if(SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
                                if(ItemPrototype const* jProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID))
                                    if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory)
                                        --limit_newcount;
                        }

                        // new gem
                        if (iGemProto->ItemLimitCategory == Gems[j]->GetProto()->ItemLimitCategory)
                            ++limit_newcount;
                    }
                    // existed gem
                    else if(OldEnchants[j])
                    {
                        if(SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(OldEnchants[j]))
                            if(ItemPrototype const* jProto = ObjectMgr::GetItemPrototype(enchantEntry->GemID))
                                if (iGemProto->ItemLimitCategory == jProto->ItemLimitCategory)
                                    ++limit_newcount;
                    }
                }

                if(limit_newcount > 0 && uint32(limit_newcount) > limitEntry->maxCount)
                {
                    _player->SendEquipError( EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED, itemTarget, NULL );
                    return;
                }
            }
        }

        // for equipped item check all equipment for duplicate equipped gems
        if(itemTarget->IsEquipped())
        {
            if(uint8 res = _player->CanEquipUniqueItem(Gems[i],slot,limit_newcount >= 0 ? limit_newcount : 0))
            {
                _player->SendEquipError( res, itemTarget, NULL );
                return;
            }
        }
    }

    bool SocketBonusActivated = itemTarget->GemsFitSockets();    //save state of socketbonus
    _player->ToggleMetaGemsActive(slot, false);             //turn off all metagems (except for the target item)

    //if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met

    //remove ALL enchants
    for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
        _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),false);

    for (int i = 0; i < MAX_GEM_SOCKETS; ++i)
    {
        if(GemEnchants[i])
        {
            itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), GemEnchants[i],0,0);
            if(Item* guidItem = _player->GetItemByGuid(gem_guids[i]))
                _player->DestroyItem(guidItem->GetBagSlot(), guidItem->GetSlot(), true );
        }
    }

    for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
        _player->ApplyEnchantment(itemTarget,EnchantmentSlot(enchant_slot),true);

    bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state
    if(SocketBonusActivated ^ SocketBonusToBeActivated)     //if there was a change...
    {
        _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,false);
        itemTarget->SetEnchantment(BONUS_ENCHANTMENT_SLOT, (SocketBonusToBeActivated ? itemTarget->GetProto()->socketBonus : 0), 0, 0);
        _player->ApplyEnchantment(itemTarget,BONUS_ENCHANTMENT_SLOT,true);
        //it is not displayed, client has an inbuilt system to determine if the bonus is activated
    }

    _player->ToggleMetaGemsActive(slot, true);              //turn on all metagems (except for target item)
}
Пример #19
0
// Only _static_ data send in this packet !!!
void WorldSession::HandleItemQuerySingleOpcode( WorldPacket & recv_data )
{
    //sLog.outDebug("WORLD: CMSG_ITEM_QUERY_SINGLE");
    uint32 item;
    recv_data >> item;

    sLog.outDetail("STORAGE: Item Query = %u", item);

    ItemPrototype const *pProto = objmgr.GetItemPrototype( item );
    if( pProto )
    {
        std::string Name        = pProto->Name1;
        std::string Description = pProto->Description;

        int loc_idx = GetSessionDbLocaleIndex();
        if ( loc_idx >= 0 )
        {
            ItemLocale const *il = objmgr.GetItemLocale(pProto->ItemId);
            if (il)
            {
                if (il->Name.size() > size_t(loc_idx) && !il->Name[loc_idx].empty())
                    Name = il->Name[loc_idx];
                if (il->Description.size() > size_t(loc_idx) && !il->Description[loc_idx].empty())
                    Description = il->Description[loc_idx];
            }
        }
                                                            // guess size
        WorldPacket data( SMSG_ITEM_QUERY_SINGLE_RESPONSE, 600);
        data << pProto->ItemId;
        data << pProto->Class;
        data << pProto->SubClass;
        data << int32(pProto->Unk0);                        // new 2.0.3, not exist in wdb cache?
        data << Name;
        data << uint8(0x00);                                //pProto->Name2; // blizz not send name there, just uint8(0x00); <-- \0 = empty string = empty name...
        data << uint8(0x00);                                //pProto->Name3; // blizz not send name there, just uint8(0x00);
        data << uint8(0x00);                                //pProto->Name4; // blizz not send name there, just uint8(0x00);
        data << pProto->DisplayInfoID;
        data << pProto->Quality;
        data << pProto->Flags;
        data << pProto->Faction;                            // 3.2 faction?
        data << pProto->BuyPrice;
        data << pProto->SellPrice;
        data << pProto->InventoryType;
        data << pProto->AllowableClass;
        data << pProto->AllowableRace;
        data << pProto->ItemLevel;
        data << pProto->RequiredLevel;
        data << pProto->RequiredSkill;
        data << pProto->RequiredSkillRank;
        data << pProto->RequiredSpell;
        data << pProto->RequiredHonorRank;
        data << pProto->RequiredCityRank;
        data << pProto->RequiredReputationFaction;
        data << pProto->RequiredReputationRank;
        data << int32(pProto->MaxCount);
        data << int32(pProto->Stackable);
        data << pProto->ContainerSlots;
        data << pProto->StatsCount;                         // item stats count
        for (uint32 i = 0; i < pProto->StatsCount; ++i)
        {
            data << pProto->ItemStat[i].ItemStatType;
            data << pProto->ItemStat[i].ItemStatValue;
        }
        data << pProto->ScalingStatDistribution;            // scaling stats distribution
        data << pProto->ScalingStatValue;                   // some kind of flags used to determine stat values column
        for (int i = 0; i < MAX_ITEM_PROTO_DAMAGES; ++i)
        {
            data << pProto->Damage[i].DamageMin;
            data << pProto->Damage[i].DamageMax;
            data << pProto->Damage[i].DamageType;
        }

        // resistances (7)
        data << pProto->Armor;
        data << pProto->HolyRes;
        data << pProto->FireRes;
        data << pProto->NatureRes;
        data << pProto->FrostRes;
        data << pProto->ShadowRes;
        data << pProto->ArcaneRes;

        data << pProto->Delay;
        data << pProto->AmmoType;
        data << pProto->RangedModRange;

        for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
        {
            // send DBC data for cooldowns in same way as it used in Spell::SendSpellCooldown
            // use `item_template` or if not set then only use spell cooldowns
            SpellEntry const* spell = sSpellStore.LookupEntry(pProto->Spells[s].SpellId);
            if(spell)
            {
                bool db_data = pProto->Spells[s].SpellCooldown >= 0 || pProto->Spells[s].SpellCategoryCooldown >= 0;

                data << pProto->Spells[s].SpellId;
                data << pProto->Spells[s].SpellTrigger;
                data << uint32(-abs(pProto->Spells[s].SpellCharges));

                if(db_data)
                {
                    data << uint32(pProto->Spells[s].SpellCooldown);
                    data << uint32(pProto->Spells[s].SpellCategory);
                    data << uint32(pProto->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 << pProto->Bonding;
        data << Description;
        data << pProto->PageText;
        data << pProto->LanguageID;
        data << pProto->PageMaterial;
        data << pProto->StartQuest;
        data << pProto->LockID;
        data << int32(pProto->Material);
        data << pProto->Sheath;
        data << pProto->RandomProperty;
        data << pProto->RandomSuffix;
        data << pProto->Block;
        data << pProto->ItemSet;
        data << pProto->MaxDurability;
        data << pProto->Area;
        data << pProto->Map;                                // Added in 1.12.x & 2.0.1 client branch
        data << pProto->BagFamily;
        data << pProto->TotemCategory;
        for (int s = 0; s < MAX_ITEM_PROTO_SOCKETS; ++s)
        {
            data << pProto->Socket[s].Color;
            data << pProto->Socket[s].Content;
        }
        data << pProto->socketBonus;
        data << pProto->GemProperties;
        data << pProto->RequiredDisenchantSkill;
        data << pProto->ArmorDamageModifier;
        data << abs(pProto->Duration);                      // added in 2.4.2.8209, duration (seconds)
        data << pProto->ItemLimitCategory;                  // WotLK, ItemLimitCategory
        data << pProto->HolidayId;                          // Holiday.dbc?
        SendPacket( &data );
    }
    else
    {
        sLog.outDebug(  "WORLD: CMSG_ITEM_QUERY_SINGLE - NO item INFO! (ENTRY: %u)", item );
        WorldPacket data( SMSG_ITEM_QUERY_SINGLE_RESPONSE, 4);
        data << uint32(item | 0x80000000);
        SendPacket( &data );
    }
}
Пример #20
0
void Weather::SendWeatherUpdateToPlayer(Player* player)
{
    WorldPacket data(SMSG_WEATHER, (4+4+4));
    data << uint32(GetWeatherState()) << (float)m_grade << uint8(0);
    player->GetSession()->SendPacket(&data);
}
Пример #21
0
/// Send the new weather to all players in the zone
bool Weather::UpdateWeather()
{
    ///- Send the weather packet to all players in this zone
    if (m_grade >= 1)
        m_grade = 0.9999f;
    else if (m_grade < 0)
        m_grade = 0.0001f;

    WeatherState state = GetWeatherState();

    WorldPacket data(SMSG_WEATHER, (4+4+4));
    data << uint32(state);
    data << (float)m_grade;
    data << uint8(0);

    //- Returns false if there were no players found to update
    if (!sWorld->SendZoneMessage(m_zone, &data))
        return false;

    ///- Log the event
    char const* wthstr;
    switch (state)
    {
        case WEATHER_STATE_FOG:
            wthstr = "fog";
            break;
        case WEATHER_STATE_LIGHT_RAIN:
            wthstr = "light rain";
            break;
        case WEATHER_STATE_MEDIUM_RAIN:
            wthstr = "medium rain";
            break;
        case WEATHER_STATE_HEAVY_RAIN:
            wthstr = "heavy rain";
            break;
        case WEATHER_STATE_LIGHT_SNOW:
            wthstr = "light snow";
            break;
        case WEATHER_STATE_MEDIUM_SNOW:
            wthstr = "medium snow";
            break;
        case WEATHER_STATE_HEAVY_SNOW:
            wthstr = "heavy snow";
            break;
        case WEATHER_STATE_LIGHT_SANDSTORM:
            wthstr = "light sandstorm";
            break;
        case WEATHER_STATE_MEDIUM_SANDSTORM:
            wthstr = "medium sandstorm";
            break;
        case WEATHER_STATE_HEAVY_SANDSTORM:
            wthstr = "heavy sandstorm";
            break;
        case WEATHER_STATE_THUNDERS:
            wthstr = "thunders";
            break;
        case WEATHER_STATE_BLACKRAIN:
            wthstr = "blackrain";
            break;
        case WEATHER_STATE_FINE:
        default:
            wthstr = "fine";
            break;
    }

    TC_LOG_INFO("misc", "Change the weather of zone %u to %s.", m_zone, wthstr);
    sScriptMgr->OnWeatherChange(this, state, m_grade);
    return true;
}
Пример #22
0
void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2)
{
    CharmInfo* charmInfo = pet->GetCharmInfo();
    if (!charmInfo)
    {
        sLog->outError("WorldSession::HandlePetAction(petGuid: " UI64FMTD ", tagGuid: " UI64FMTD ", spellId: %u, flag: %u): object (entry: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!",
            guid1, guid2, spellid, flag, pet->GetGUIDLow(), pet->GetTypeId());
        return;
    }

    switch (flag)
    {
        case ACT_COMMAND:                                   //0x07
            switch (spellid)
            {
                case COMMAND_STAY:                          //flat=1792  //STAY
				{
					bool controlledMotion = pet->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_CONTROLLED) != NULL_MOTION_TYPE;
					if (!controlledMotion)
					{
						pet->StopMovingOnCurrentPos();
						pet->GetMotionMaster()->Clear(false);
						pet->GetMotionMaster()->MoveIdle();
					}

                    charmInfo->SetCommandState(COMMAND_STAY);
                    charmInfo->SetIsCommandAttack(false);
                    charmInfo->SetIsCommandFollow(false);
                    charmInfo->SetIsFollowing(false);
                    charmInfo->SetIsReturning(false);
					charmInfo->SetIsAtStay(!controlledMotion);
                    charmInfo->SaveStayPosition(controlledMotion);

					charmInfo->SetForcedSpell(0);
					charmInfo->SetForcedTargetGUID(0);
                    break;
				}
                case COMMAND_FOLLOW:                        //spellid=1792  //FOLLOW
				{
                    pet->AttackStop();
                    pet->InterruptNonMeleeSpells(false);
					pet->ClearInPetCombat();
                    pet->GetMotionMaster()->MoveFollow(_player, PET_FOLLOW_DIST, pet->GetFollowAngle());
                    charmInfo->SetCommandState(COMMAND_FOLLOW);

                    charmInfo->SetIsCommandAttack(false);
                    charmInfo->SetIsAtStay(false);
                    charmInfo->SetIsReturning(true);
                    charmInfo->SetIsCommandFollow(true);
                    charmInfo->SetIsFollowing(false);

					charmInfo->SetForcedSpell(0);
					charmInfo->SetForcedTargetGUID(0);
                    break;
				}
                case COMMAND_ATTACK:                        //spellid=1792  //ATTACK
                {
                    // Can't attack if owner is pacified
                    if (_player->HasAuraType(SPELL_AURA_MOD_PACIFY))
                    {
                        //pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED);
                        //TODO: Send proper error message to client
                        return;
                    }

                    // only place where pet can be player
                    Unit* TargetUnit = ObjectAccessor::GetUnit(*_player, guid2);
                    if (!TargetUnit)
                        return;

                    if (Unit* owner = pet->GetOwner())
                        if (!owner->IsValidAttackTarget(TargetUnit))
                            return;

					// pussywizard:
					if (Creature* creaturePet = pet->ToCreature())
						if (!creaturePet->_CanDetectFeignDeathOf(TargetUnit) || !creaturePet->CanCreatureAttack(TargetUnit) || creaturePet->isTargetNotAcceptableByMMaps(TargetUnit->GetGUID(), sWorld->GetGameTime(), TargetUnit))
							return;

                    // Not let attack through obstructions
                    bool checkLos = !MMAP::MMapFactory::IsPathfindingEnabled(pet->GetMap()) || 
									(TargetUnit->GetTypeId() == TYPEID_UNIT && (TargetUnit->ToCreature()->isWorldBoss() || TargetUnit->ToCreature()->IsDungeonBoss()));

					if (checkLos && !pet->IsWithinLOSInMap(TargetUnit))
					{
						WorldPacket data(SMSG_CAST_FAILED, 1+4+1);
						data << uint8(0);
						data << uint32(7389);
						data << uint8(SPELL_FAILED_LINE_OF_SIGHT);
						SendPacket(&data);
						return;
                    }

                    pet->ClearUnitState(UNIT_STATE_FOLLOW);
                    // This is true if pet has no target or has target but targets differs.
                    if (pet->GetVictim() != TargetUnit || (pet->GetVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack()))
                    {
                        pet->AttackStop();

                        if (pet->GetTypeId() != TYPEID_PLAYER && pet->ToCreature()->IsAIEnabled)
                        {
                            charmInfo->SetIsCommandAttack(true);
                            charmInfo->SetIsAtStay(false);
                            charmInfo->SetIsFollowing(false);
                            charmInfo->SetIsCommandFollow(false);
                            charmInfo->SetIsReturning(false);

                            pet->ToCreature()->AI()->AttackStart(TargetUnit);

                            //10% chance to play special pet attack talk, else growl
                            if (pet->IsPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10)
                                pet->SendPetTalk((uint32)PET_TALK_ATTACK);
                            else
                            {
                                // 90% chance for pet and 100% chance for charmed creature
                                pet->SendPetAIReaction(guid1);
                            }
                        }
                        else                                // charmed player
                        {
                            charmInfo->SetIsCommandAttack(true);
                            charmInfo->SetIsAtStay(false);
                            charmInfo->SetIsFollowing(false);
                            charmInfo->SetIsCommandFollow(false);
                            charmInfo->SetIsReturning(false);

							pet->Attack(TargetUnit, true);
                            pet->SendPetAIReaction(guid1);
                        }
                    }
                    break;
                }
                case COMMAND_ABANDON:                       // abandon (hunter pet) or dismiss (summoned pet)
                    if (pet->GetCharmerGUID() == GetPlayer()->GetGUID())
					{
						if (pet->IsSummon())
							pet->ToTempSummon()->UnSummon();
						else
							_player->StopCastingCharm();
					}
                    else if (pet->GetOwnerGUID() == GetPlayer()->GetGUID())
                    {
                        ASSERT(pet->GetTypeId() == TYPEID_UNIT);
                        if (pet->IsPet())
                        {
                            if (pet->ToPet()->getPetType() == HUNTER_PET)
                                GetPlayer()->RemovePet(pet->ToPet(), PET_SAVE_AS_DELETED);
                            else
                                //dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
                                pet->setDeathState(CORPSE);
                        }
                        else if (pet->HasUnitTypeMask(UNIT_MASK_MINION|UNIT_MASK_SUMMON|UNIT_MASK_GUARDIAN|UNIT_MASK_CONTROLABLE_GUARDIAN))
                        {
                            pet->ToTempSummon()->UnSummon();
                        }
                    }
                    break;
                default:
                    sLog->outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid);
            }
            break;
        case ACT_REACTION:                                  // 0x6
            switch (spellid)
            {
                case REACT_PASSIVE:                         //passive
                    pet->AttackStop();
					pet->ClearInPetCombat();

                case REACT_DEFENSIVE:                       //recovery
                case REACT_AGGRESSIVE:                      //activete
                    if (pet->GetTypeId() == TYPEID_UNIT)
                        pet->ToCreature()->SetReactState(ReactStates(spellid));
					else
						charmInfo->SetPlayerReactState(ReactStates(spellid));
                    break;
            }
            break;
        case ACT_DISABLED:                                  // 0x81    spell (disabled), ignore
        case ACT_PASSIVE:                                   // 0x01
        case ACT_ENABLED:                                   // 0xC1    spell
        {
            Unit* unit_target = NULL;

            if (guid2)
                unit_target = ObjectAccessor::GetUnit(*_player, guid2);

            // do not cast unknown spells
            SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid);
            if (!spellInfo)
            {
                sLog->outError("WORLD: unknown PET spell id %i", spellid);
                return;
            }

            for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
            {
                if (spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_SRC_AREA_ENEMY || spellInfo->Effects[i].TargetA.GetTarget() == TARGET_UNIT_DEST_AREA_ENEMY || spellInfo->Effects[i].TargetA.GetTarget() == TARGET_DEST_DYNOBJ_ENEMY)
                    return;
            }

            // do not cast not learned spells
            if (!pet->HasSpell(spellid) || spellInfo->IsPassive())
                return;

            //  Clear the flags as if owner clicked 'attack'. AI will reset them
            //  after AttackStart, even if spell failed
            charmInfo->SetIsAtStay(false);
            charmInfo->SetIsCommandAttack(!pet->ToCreature()->HasReactState(REACT_PASSIVE));
            charmInfo->SetIsReturning(false);
            charmInfo->SetIsFollowing(false);

            Spell* spell = new Spell(pet, spellInfo, TRIGGERED_NONE);
			spell->LoadScripts(); // xinef: load for CheckPetCast

            SpellCastResult result = spell->CheckPetCast(unit_target);

            //auto turn to target unless possessed
            if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->isPossessed() && !pet->IsVehicle())
            {
                if (unit_target)
                {
                    pet->SetInFront(unit_target);
                    if (unit_target->GetTypeId() == TYPEID_PLAYER)
                        pet->SendUpdateToPlayer(unit_target->ToPlayer());
                }
                else if (Unit* unit_target2 = spell->m_targets.GetUnitTarget())
                {
                    pet->SetInFront(unit_target2);
                    if (unit_target2->GetTypeId() == TYPEID_PLAYER)
                        pet->SendUpdateToPlayer(unit_target2->ToPlayer());
                }
                if (Unit* powner = pet->GetCharmerOrOwner())
                    if (powner->GetTypeId() == TYPEID_PLAYER)
                        pet->SendUpdateToPlayer(powner->ToPlayer());

                result = SPELL_CAST_OK;
            }

            if (result == SPELL_CAST_OK)
            {
                pet->ToCreature()->AddSpellCooldown(spellid, 0, 0);

                unit_target = spell->m_targets.GetUnitTarget();

                //10% chance to play special pet attack talk, else growl
                //actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
                if (pet->IsPet() && (((Pet*)pet)->getPetType() == SUMMON_PET) && (pet != unit_target) && (urand(0, 100) < 10))
                    pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
                else
                {
                    pet->SendPetAIReaction(guid1);
                }

                if (unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->isPossessed() && !pet->IsVehicle())
                {
                    // This is true if pet has no target or has target but targets differs.
                    if (pet->GetVictim() != unit_target)
                    {
                        if (pet->ToCreature()->IsAIEnabled)
                            pet->ToCreature()->AI()->AttackStart(unit_target);
                    }
                }

                spell->prepare(&(spell->m_targets));

				charmInfo->SetForcedSpell(0);
				charmInfo->SetForcedTargetGUID(0);
            }
            else
            {
				// dont spam alerts
				if (!charmInfo->GetForcedSpell())
				{
					if (pet->isPossessed() || pet->IsVehicle())
						Spell::SendCastResult(GetPlayer(), spellInfo, 0, result);
					else
						spell->SendPetCastResult(result);
				}

                if (!pet->ToCreature()->HasSpellCooldown(spellid))
                    GetPlayer()->SendClearCooldown(spellid, pet);

                spell->finish(false);
                delete spell;

				// reset specific flags in case of spell fail. AI will reset other flags
				pet->PetSpellFail(spellInfo, unit_target, result);
            }
            break;
        }
        default:
            sLog->outError("WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid);
    }
}
Пример #23
0
uint8 WorldSession::HandleLoadPetFromDBFirstCallback(PreparedQueryResult result, uint8 asynchLoadType)
{
    if (!GetPlayer() || GetPlayer()->GetPet() || GetPlayer()->GetVehicle() || GetPlayer()->IsSpectator())
        return PET_LOAD_ERROR;

    if (!result)
        return PET_LOAD_NO_RESULT;

    Field* fields = result->Fetch();

	// Xinef: this can happen if fetch is called twice, impossibru.
	if (!fields)
		return PET_LOAD_ERROR;

	Player* owner = GetPlayer();

    // update for case of current pet "slot = 0"
    uint32 petentry = fields[1].GetUInt32();
    if (!petentry)
        return PET_LOAD_NO_RESULT;

	uint8 petSlot = fields[7].GetUInt8();
	bool current = petSlot == PET_SAVE_AS_CURRENT;
    uint32 summon_spell_id = fields[15].GetUInt32();
    SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(summon_spell_id); // CANT BE NULL
    bool is_temporary_summoned = spellInfo && spellInfo->GetDuration() > 0;
    uint32 pet_number = fields[0].GetUInt32();
	uint32 savedhealth = fields[10].GetUInt32();
    uint32 savedmana = fields[11].GetUInt32();
	PetType pet_type = PetType(fields[16].GetUInt8());

	// xinef: BG resurrect, overwrite saved value
	if (asynchLoadType == PET_LOAD_BG_RESURRECT)
		savedhealth = 1;

	if (pet_type == HUNTER_PET && savedhealth == 0 && asynchLoadType != PET_LOAD_SUMMON_DEAD_PET)
	{
		WorldPacket data(SMSG_CAST_FAILED, 1+4+1+4);
        data << uint8(0);
        data << uint32(883);
        data << uint8(SPELL_FAILED_TARGETS_DEAD);
        SendPacket(&data);
		owner->RemoveSpellCooldown(883, false);
		return PET_LOAD_ERROR;
	}

    // check temporary summoned pets like mage water elemental
    if (current && is_temporary_summoned)
        return PET_LOAD_ERROR;

    if (pet_type == HUNTER_PET)
    {
        CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petentry);
        if (!creatureInfo || !creatureInfo->IsTameable(owner->CanTameExoticPets()))
            return PET_LOAD_ERROR;
    }

    Map* map = owner->GetMap();
    uint32 guid = sObjectMgr->GenerateLowGuid(HIGHGUID_PET);
	Pet* pet = new Pet(owner, pet_type);
	LoadPetFromDBQueryHolder* holder = new LoadPetFromDBQueryHolder(pet_number, current, uint32(time(NULL) - fields[14].GetUInt32()), fields[13].GetString(), savedhealth, savedmana);
    if (!pet->Create(guid, map, owner->GetPhaseMask(), petentry, pet_number) || !holder->Initialize())
	{
		delete pet;
		delete holder;
        return PET_LOAD_ERROR;
	}

    float px, py, pz;
    owner->GetClosePoint(px, py, pz, pet->GetObjectSize(), PET_FOLLOW_DIST, pet->GetFollowAngle());
    if (!pet->IsPositionValid())
    {
        sLog->outError("Pet (guidlow %d, entry %d) not loaded. Suggested coordinates isn't valid (X: %f Y: %f)", pet->GetGUIDLow(), pet->GetEntry(), pet->GetPositionX(), pet->GetPositionY());
		delete pet;
		delete holder;
        return PET_LOAD_ERROR;
    }

	pet->SetLoading(true);
    pet->Relocate(px, py, pz, owner->GetOrientation());
    pet->setPetType(pet_type);
    pet->setFaction(owner->getFaction());
    pet->SetUInt32Value(UNIT_CREATED_BY_SPELL, summon_spell_id);

    if (pet->IsCritter())
    {
        map->AddToMap(pet->ToCreature(), true);
		pet->SetLoading(false); // xinef, mine
		delete holder;
        return PET_LOAD_OK;
    }

    pet->GetCharmInfo()->SetPetNumber(pet_number, pet->IsPermanentPetFor(owner));

    pet->SetDisplayId(fields[3].GetUInt32());
    pet->SetNativeDisplayId(fields[3].GetUInt32());
    uint32 petlevel = fields[4].GetUInt8();
    pet->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
    pet->SetName(fields[8].GetString());

    switch (pet->getPetType())
    {
        case SUMMON_PET:
            petlevel = owner->getLevel();

			if (pet->IsPetGhoul())
				pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 0x400); // class = rogue
			else
				pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 0x800); // class = mage

            pet->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
                                                            // this enables popup window (pet dismiss, cancel)
            break;
        case HUNTER_PET:
            pet->SetUInt32Value(UNIT_FIELD_BYTES_0, 0x02020100); // class = warrior, gender = none, power = focus
            pet->SetSheath(SHEATH_STATE_MELEE);
            pet->SetByteFlag(UNIT_FIELD_BYTES_2, 2, fields[9].GetBool() ? UNIT_CAN_BE_ABANDONED : UNIT_CAN_BE_RENAMED | UNIT_CAN_BE_ABANDONED);

            pet->SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE);
                                                            // this enables popup window (pet abandon, cancel)
            pet->SetMaxPower(POWER_HAPPINESS, pet->GetCreatePowers(POWER_HAPPINESS));
            pet->SetPower(POWER_HAPPINESS, fields[12].GetUInt32());
            pet->setPowerType(POWER_FOCUS);
            break;
        default:
            if (!pet->IsPetGhoul())
                sLog->outError("Pet have incorrect type (%u) for pet loading.", pet->getPetType());
            break;
    }

    pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL))); // cast can't be helped here
    pet->SetCreatorGUID(owner->GetGUID());
	owner->SetMinion(pet, true);

    pet->InitStatsForLevel(petlevel);
    pet->SetUInt32Value(UNIT_FIELD_PETEXPERIENCE, fields[5].GetUInt32());

    pet->SynchronizeLevelWithOwner();

    pet->SetReactState(ReactStates(fields[6].GetUInt8()));
    pet->SetCanModifyStats(true);

    // set current pet as current
    // 0=current
    // 1..MAX_PET_STABLES in stable slot
    // PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning))
    if (petSlot)
    {
        SQLTransaction trans = CharacterDatabase.BeginTransaction();

        PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID);
        stmt->setUInt8(0, uint8(PET_SAVE_NOT_IN_SLOT));
        stmt->setUInt32(1, owner->GetGUIDLow());
        stmt->setUInt8(2, uint8(PET_SAVE_AS_CURRENT));
        stmt->setUInt32(3, pet_number);
        trans->Append(stmt);

        stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
        stmt->setUInt8(0, uint8(PET_SAVE_AS_CURRENT));
        stmt->setUInt32(1, owner->GetGUIDLow());
        stmt->setUInt32(2, pet_number);
        trans->Append(stmt);

        CharacterDatabase.CommitTransaction(trans);
    }

    // Send fake summon spell cast - this is needed for correct cooldown application for spells
    // Example: 46584 - without this cooldown (which should be set always when pet is loaded) isn't set clientside
    // TODO: pets should be summoned from real cast instead of just faking it?
    if (summon_spell_id)
    {
        WorldPacket data(SMSG_SPELL_GO, (8+8+4+4+2));
        data.append(owner->GetPackGUID());
        data.append(owner->GetPackGUID());
        data << uint8(0);
        data << uint32(summon_spell_id);
        data << uint32(256); // CAST_FLAG_UNKNOWN3
        data << uint32(0);
        owner->SendMessageToSet(&data, true);
    }

	// do it as early as possible!
	pet->InitTalentForLevel();                                   // set original talents points before spell loading
	if (!is_temporary_summoned)
		pet->GetCharmInfo()->InitPetActionBar();

    map->AddToMap(pet->ToCreature(), true);
    if (pet->getPetType() == SUMMON_PET && !current)              //all (?) summon pets come with full health when called, but not when they are current
        pet->SetPower(POWER_MANA, pet->GetMaxPower(POWER_MANA));
    else
    {
        pet->SetHealth(savedhealth > pet->GetMaxHealth() ? pet->GetMaxHealth() : savedhealth);
        pet->SetPower(POWER_MANA, savedmana > pet->GetMaxPower(POWER_MANA) ? pet->GetMaxPower(POWER_MANA) : savedmana);
    }

	pet->SetAsynchLoadType(asynchLoadType);

	// xinef: clear any old result
	if (_loadPetFromDBSecondCallback.ready())
	{
		SQLQueryHolder* param;
		_loadPetFromDBSecondCallback.get(param);
		delete param;
	}
	_loadPetFromDBSecondCallback.cancel();

    _loadPetFromDBSecondCallback = CharacterDatabase.DelayQueryHolder((SQLQueryHolder*)holder);
	return PET_LOAD_OK;
}
Пример #24
0
void WorldSession::SendTrainerList(uint64 guid, const std::string &strTitle)
{
    sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendTrainerList");

    Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_TRAINER);
    if (!unit)
    {
        sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendTrainerList - Unit (GUID: %u) not found or you can not interact with him.", uint32(GUID_LOPART(guid)));
        return;
    }

    // remove fake death
    if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
        GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);

    // trainer list loaded at check;
    if (!unit->isCanTrainingOf(_player, true))
        return;

    CreatureTemplate const *creatureInfo = unit->GetCreatureTemplate();

    if (!creatureInfo)
    {
        sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendTrainerList - (GUID: %u) NO CREATUREINFO!", GUID_LOPART(guid));
        return;
    }

    TrainerSpellData const* trainer_spells = unit->GetTrainerSpells();
    if (!trainer_spells)
    {
        sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: SendTrainerList - Training spells not found for creature (GUID: %u Entry: %u)",
            GUID_LOPART(guid), unit->GetEntry());
        return;
    }

    WorldPacket data(SMSG_TRAINER_LIST, 8 + 4 + 4 + trainer_spells->spellList.size() * 38 + strTitle.size() + 1);
    data << guid;
    data << uint32(trainer_spells->trainerType);
    data << uint32(1);

    size_t count_pos = data.wpos();
    data << uint32(trainer_spells->spellList.size());

    // reputation discount
    float fDiscountMod = _player->GetReputationPriceDiscount(unit);

    uint32 count = 0;
    for (TrainerSpellMap::const_iterator itr = trainer_spells->spellList.begin(); itr != trainer_spells->spellList.end(); ++itr)
    {
        TrainerSpell const* tSpell = &itr->second;
        TrainerSpellState state = _player->GetTrainerSpellState(tSpell);

        data << uint32(tSpell->spell);                      // learned spell (or cast-spell in profession case)
        data << uint8(state);
        data << uint32(floor(tSpell->spellCost * fDiscountMod));

        data << uint8(tSpell->reqLevel);
        data << uint32(tSpell->reqSkill);
        data << uint32(tSpell->reqSkillValue);
        data << uint32(0);
        data << uint32(0);
        data << uint32(0);
        data << uint32(0);

        ++count;
    }

    data << strTitle;

    data.put<uint32>(count_pos, count);
    SendPacket(&data);
}
Пример #25
0
void WorldSession::SendStableResult(uint8 res)
{
    WorldPacket data(SMSG_STABLE_RESULT, 1);
    data << uint8(res);
    SendPacket(&data);
}
Пример #26
0
DumpReturn PlayerDumpReader::LoadDump(const std::string& file, uint32 account, std::string name, uint32 guid)
{
    uint32 charcount = AccountMgr::GetCharactersCount(account);
    if (charcount >= 10)
        return DUMP_TOO_MANY_CHARS;

    FILE* fin = fopen(file.c_str(), "r");
    if (!fin)
        return DUMP_FILE_OPEN_ERROR;

    QueryResult result = QueryResult(NULL);
    char newguid[20], chraccount[20], newpetid[20], currpetid[20], lastpetid[20];

    // make sure the same guid doesn't already exist and is safe to use
    bool incHighest = true;
    if (guid != 0 && guid < sObjectMgr->_hiCharGuid)
    {
        PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_GUID);
        stmt->setUInt32(0, guid);
        PreparedQueryResult result = CharacterDatabase.Query(stmt);

        if (result)
            guid = sObjectMgr->_hiCharGuid;                     // use first free if exists
        else incHighest = false;
    }
    else
        guid = sObjectMgr->_hiCharGuid;

    // normalize the name if specified and check if it exists
    if (!normalizePlayerName(name))
        name = "";

    if (ObjectMgr::CheckPlayerName(name, true) == CHAR_NAME_SUCCESS)
    {
        PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME);
        stmt->setString(0, name);
        PreparedQueryResult result = CharacterDatabase.Query(stmt);

        if (result)
            name = "";                                      // use the one from the dump
    }
    else
        name = "";

    // name encoded or empty

    snprintf(newguid, 20, "%u", guid);
    snprintf(chraccount, 20, "%u", account);
    snprintf(newpetid, 20, "%u", sObjectMgr->GeneratePetNumber());
    snprintf(lastpetid, 20, "%s", "");

    std::map<uint32, uint32> items;
    std::map<uint32, uint32> mails;
    char buf[32000] = "";

    typedef std::map<uint32, uint32> PetIds;                // old->new petid relation
    typedef PetIds::value_type PetIdsPair;
    PetIds petids;

    uint8 gender = GENDER_NONE;
    uint8 race = RACE_NONE;
    uint8 playerClass = 0;
    uint8 level = 1;

    SQLTransaction trans = CharacterDatabase.BeginTransaction();
    while (!feof(fin))
    {
        if (!fgets(buf, 32000, fin))
        {
            if (feof(fin))
                break;
            ROLLBACK(DUMP_FILE_BROKEN);
        }

        std::string line;
        line.assign(buf);

        // skip empty strings
        size_t nw_pos = line.find_first_not_of(" \t\n\r\7");
        if (nw_pos == std::string::npos)
            continue;

        // skip logfile-side dump start notice, the important notes and dump end notices
        if ((line.substr(nw_pos, 16) == "== START DUMP ==") ||
                (line.substr(nw_pos, 15) == "IMPORTANT NOTE:") ||
                (line.substr(nw_pos, 14) == "== END DUMP =="))
            continue;

        // add required_ check
        /*
        if (line.substr(nw_pos, 41) == "UPDATE character_db_version SET required_")
        {
            if (!CharacterDatabase.Execute(line.c_str()))
                ROLLBACK(DUMP_FILE_BROKEN);

            continue;
        }
        */

        // determine table name and load type
        std::string tn = gettablename(line);
        if (tn.empty())
        {
            sLog->outError(LOG_FILTER_GENERAL, "LoadPlayerDump: Can't extract table name from line: '%s'!", line.c_str());
            ROLLBACK(DUMP_FILE_BROKEN);
        }

        DumpTableType type = DumpTableType(0);
        uint8 i;
        for (i = 0; i < DUMP_TABLE_COUNT; ++i)
        {
            if (tn == dumpTables[i].name)
            {
                type = dumpTables[i].type;
                break;
            }
        }

        if (i == DUMP_TABLE_COUNT)
        {
            sLog->outError(LOG_FILTER_GENERAL, "LoadPlayerDump: Unknown table: '%s'!", tn.c_str());
            ROLLBACK(DUMP_FILE_BROKEN);
        }

        // change the data to server values
        switch (type)
        {
        case DTT_CHARACTER:
        {
            if (!changenth(line, 1, newguid))           // characters.guid update
                ROLLBACK(DUMP_FILE_BROKEN);

            if (!changenth(line, 2, chraccount))        // characters.account update
                ROLLBACK(DUMP_FILE_BROKEN);

            race = uint8(atol(getnth(line, 4).c_str()));
            playerClass = uint8(atol(getnth(line, 5).c_str()));
            gender = uint8(atol(getnth(line, 6).c_str()));
            level = uint8(atol(getnth(line, 7).c_str()));
            if (name == "")
            {
                // check if the original name already exists
                name = getnth(line, 3);

                PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME);
                stmt->setString(0, name);
                PreparedQueryResult result = CharacterDatabase.Query(stmt);

                if (result)
                    if (!changenth(line, 38, "1"))       // characters.at_login set to "rename on login"
                        ROLLBACK(DUMP_FILE_BROKEN);
            }
            else if (!changenth(line, 3, name.c_str())) // characters.name
                ROLLBACK(DUMP_FILE_BROKEN);

            const char null[5] = "NULL";
            if (!changenth(line, 63, null))             // characters.deleteInfos_Account
                ROLLBACK(DUMP_FILE_BROKEN);
            if (!changenth(line, 64, null))             // characters.deleteInfos_Name
                ROLLBACK(DUMP_FILE_BROKEN);
            if (!changenth(line, 65, null))             // characters.deleteDate
                ROLLBACK(DUMP_FILE_BROKEN);
            break;
        }
        case DTT_CHAR_TABLE:
        {
            if (!changenth(line, 1, newguid))           // character_*.guid update
                ROLLBACK(DUMP_FILE_BROKEN);
            break;
        }
        case DTT_EQSET_TABLE:
        {
            if (!changenth(line, 1, newguid))
                ROLLBACK(DUMP_FILE_BROKEN);             // character_equipmentsets.guid

            char newSetGuid[24];
            snprintf(newSetGuid, 24, UI64FMTD, sObjectMgr->GenerateEquipmentSetGuid());
            if (!changenth(line, 2, newSetGuid))
                ROLLBACK(DUMP_FILE_BROKEN);             // character_equipmentsets.setguid
            break;
        }
        case DTT_INVENTORY:
        {
            if (!changenth(line, 1, newguid))           // character_inventory.guid update
                ROLLBACK(DUMP_FILE_BROKEN);

            if (!changeGuid(line, 2, items, sObjectMgr->_hiItemGuid, true))
                ROLLBACK(DUMP_FILE_BROKEN);             // character_inventory.bag update
            if (!changeGuid(line, 4, items, sObjectMgr->_hiItemGuid))
                ROLLBACK(DUMP_FILE_BROKEN);             // character_inventory.item update
            break;
        }
        case DTT_MAIL:                                  // mail
        {
            if (!changeGuid(line, 1, mails, sObjectMgr->_mailId))
                ROLLBACK(DUMP_FILE_BROKEN);             // mail.id update
            if (!changenth(line, 6, newguid))           // mail.receiver update
                ROLLBACK(DUMP_FILE_BROKEN);
            break;
        }
        case DTT_MAIL_ITEM:                             // mail_items
        {
            if (!changeGuid(line, 1, mails, sObjectMgr->_mailId))
                ROLLBACK(DUMP_FILE_BROKEN);             // mail_items.id
            if (!changeGuid(line, 2, items, sObjectMgr->_hiItemGuid))
                ROLLBACK(DUMP_FILE_BROKEN);             // mail_items.item_guid
            if (!changenth(line, 3, newguid))           // mail_items.receiver
                ROLLBACK(DUMP_FILE_BROKEN);
            break;
        }
        case DTT_ITEM:
        {
            // item, owner, data field:item, owner guid
            if (!changeGuid(line, 1, items, sObjectMgr->_hiItemGuid))
                ROLLBACK(DUMP_FILE_BROKEN);              // item_instance.guid update
            if (!changenth(line, 3, newguid))           // item_instance.owner_guid update
                ROLLBACK(DUMP_FILE_BROKEN);
            break;
        }
        case DTT_ITEM_GIFT:
        {
            if (!changenth(line, 1, newguid))           // character_gifts.guid update
                ROLLBACK(DUMP_FILE_BROKEN);
            if (!changeGuid(line, 2, items, sObjectMgr->_hiItemGuid))
                ROLLBACK(DUMP_FILE_BROKEN);             // character_gifts.item_guid update
            break;
        }
        case DTT_PET:
        {
            //store a map of old pet id to new inserted pet id for use by type 5 tables
            snprintf(currpetid, 20, "%s", getnth(line, 1).c_str());
            if (*lastpetid == '\0')
                snprintf(lastpetid, 20, "%s", currpetid);
            if (strcmp(lastpetid, currpetid) != 0)
            {
                snprintf(newpetid, 20, "%d", sObjectMgr->GeneratePetNumber());
                snprintf(lastpetid, 20, "%s", currpetid);
            }

            std::map<uint32, uint32> :: const_iterator petids_iter = petids.find(atoi(currpetid));

            if (petids_iter == petids.end())
            {
                petids.insert(PetIdsPair(atoi(currpetid), atoi(newpetid)));
            }

            if (!changenth(line, 1, newpetid))          // character_pet.id update
                ROLLBACK(DUMP_FILE_BROKEN);
            if (!changenth(line, 3, newguid))           // character_pet.owner update
                ROLLBACK(DUMP_FILE_BROKEN);

            break;
        }
        case DTT_PET_TABLE:                             // pet_aura, pet_spell, pet_spell_cooldown
        {
            snprintf(currpetid, 20, "%s", getnth(line, 1).c_str());

            // lookup currpetid and match to new inserted pet id
            std::map<uint32, uint32> :: const_iterator petids_iter = petids.find(atoi(currpetid));
            if (petids_iter == petids.end())             // couldn't find new inserted id
                ROLLBACK(DUMP_FILE_BROKEN);

            snprintf(newpetid, 20, "%d", petids_iter->second);

            if (!changenth(line, 1, newpetid))
                ROLLBACK(DUMP_FILE_BROKEN);

            break;
        }
        default:
            sLog->outError(LOG_FILTER_GENERAL, "Unknown dump table type: %u", type);
            break;
        }

        fixNULLfields(line);

        trans->Append(line.c_str());
    }

    CharacterDatabase.CommitTransaction(trans);

    // in case of name conflict player has to rename at login anyway
    sWorld->AddCharacterNameData(guid, name, gender, race, playerClass, level);

    sObjectMgr->_hiItemGuid += items.size();
    sObjectMgr->_mailId     += mails.size();

    if (incHighest)
        ++sObjectMgr->_hiCharGuid;

    fclose(fin);

    return DUMP_SUCCESS;
}
Пример #27
0
// Read AMS or AMS2 (newVersion = true) pattern. At least this part of the format is more or less identical between the two trackers...
static void ReadAMSPattern(CPattern &pattern, bool newVersion, FileReader &patternChunk, CSoundFile &sndFile)
//-----------------------------------------------------------------------------------------------------------
{
	enum
	{
		emptyRow		= 0xFF,	// No commands on row
		endOfRowMask	= 0x80,	// If set, no more commands on this row
		noteMask		= 0x40,	// If set, no note+instr in this command
		channelMask		= 0x1F,	// Mask for extracting channel

		// Note flags
		readNextCmd		= 0x80,	// One more command follows
		noteDataMask	= 0x7F,	// Extract note

		// Command flags
		volCommand		= 0x40,	// Effect is compressed volume command
		commandMask		= 0x3F,	// Command or volume mask
	};

	// Effect translation table for extended (non-Protracker) effects
	static const ModCommand::COMMAND effTrans[] =
	{
		CMD_S3MCMDEX,		// Forward / Backward
		CMD_PORTAMENTOUP,	// Extra fine slide up
		CMD_PORTAMENTODOWN,	// Extra fine slide up
		CMD_RETRIG,			// Retrigger
		CMD_NONE,
		CMD_TONEPORTAVOL,	// Toneporta with fine volume slide
		CMD_VIBRATOVOL,		// Vibrato with fine volume slide
		CMD_NONE,
		CMD_PANNINGSLIDE,
		CMD_NONE,
		CMD_VOLUMESLIDE,	// Two times finder volume slide than Axx
		CMD_NONE,
		CMD_CHANNELVOLUME,	// Channel volume (0...127)
		CMD_PATTERNBREAK,	// Long pattern break (in hex)
		CMD_S3MCMDEX,		// Fine slide commands
		CMD_NONE,			// Fractional BPM
		CMD_KEYOFF,			// Key off at tick xx
		CMD_PORTAMENTOUP,	// Porta up, but uses all octaves (?)
		CMD_PORTAMENTODOWN,	// Porta down, but uses all octaves (?)
		CMD_NONE,
		CMD_NONE,
		CMD_NONE,
		CMD_NONE,
		CMD_NONE,
		CMD_NONE,
		CMD_NONE,
		CMD_GLOBALVOLSLIDE,	// Global volume slide
		CMD_NONE,
		CMD_GLOBALVOLUME,	// Global volume (0... 127)
	};

	ModCommand dummy;

	for(ROWINDEX row = 0; row < pattern.GetNumRows(); row++)
	{
		PatternRow baseRow = pattern.GetRow(row);
		while(patternChunk.AreBytesLeft())
		{
			const uint8 flags = patternChunk.ReadUint8();
			if(flags == emptyRow)
			{
				break;
			}

			const CHANNELINDEX chn = (flags & channelMask);
			ModCommand &m = chn < pattern.GetNumChannels() ? baseRow[chn] : dummy;
			bool moreCommands = true;
			if(!(flags & noteMask))
			{
				// Read note + instr
				uint8 note = patternChunk.ReadUint8();
				moreCommands = (note & readNextCmd) != 0;
				note &= noteDataMask;

				if(note == 1)
				{
					m.note = NOTE_KEYOFF;
				} else if(note >= 2 && note <= 121 && newVersion)
				{
					m.note = note - 2 + NOTE_MIN;
				} else if(note >= 12 && note <= 108 && !newVersion)
				{
					m.note = note + 12 + NOTE_MIN;
				}
				m.instr = patternChunk.ReadUint8();
			}

			while(moreCommands)
			{
				// Read one more effect command
				ModCommand origCmd = m;
				const uint8 command = patternChunk.ReadUint8(), effect = (command & commandMask);
				moreCommands = (command & readNextCmd) != 0;

				if(command & volCommand)
				{
					m.volcmd = VOLCMD_VOLUME;
					m.vol = effect;
				} else
				{
					m.param = patternChunk.ReadUint8();

					if(effect < 0x10)
					{
						// PT commands
						m.command = effect;
						sndFile.ConvertModCommand(m);

						// Post-fix some commands
						switch(m.command)
						{
						case CMD_PANNING8:
							// 4-Bit panning
							m.command = CMD_PANNING8;
							m.param = (m.param & 0x0F) * 0x11;
							break;

						case CMD_VOLUME:
							m.command = CMD_NONE;
							m.volcmd = VOLCMD_VOLUME;
							m.vol = static_cast<ModCommand::VOL>(std::min((m.param + 1) / 2, 64));
							break;

						case CMD_MODCMDEX:
							if(m.param == 0x80)
							{
								// Break sample loop (cut after loop)
								m.command = CMD_NONE;
							} else
							{
								m.ExtendedMODtoS3MEffect();
							}
							break;
						}
					} else if(effect - 0x10 < (int)CountOf(effTrans))
					{
						// Extended commands
						m.command = effTrans[effect - 0x10];

						// Post-fix some commands
						switch(effect)
						{
						case 0x10:
							// Play sample forwards / backwards
							if(m.param <= 0x01)
							{
								m.param |= 0x9E;
							} else
							{
								m.command = CMD_NONE;
							}
							break;

						case 0x11:
						case 0x12:
							// Extra fine slides
							m.param = static_cast<ModCommand::PARAM>(std::min(uint8(0x0F), m.param) | 0xE0);
							break;

						case 0x15:
						case 0x16:
							// Fine slides
							m.param = static_cast<ModCommand::PARAM>((std::min(0x10, m.param + 1) / 2) | 0xF0);
							break;

						case 0x1E:
							// More fine slides
							switch(m.param >> 4)
							{
							case 0x1:
								// Fine porta up
								m.command = CMD_PORTAMENTOUP;
								m.param |= 0xF0;
								break;
							case 0x2:
								// Fine porta down
								m.command = CMD_PORTAMENTODOWN;
								m.param |= 0xF0;
								break;
							case 0xA:
								// Extra fine volume slide up
								m.command = CMD_VOLUMESLIDE;
								m.param = ((((m.param & 0x0F) + 1) / 2) << 4) | 0x0F;
								break;
							case 0xB:
								// Extra fine volume slide down
								m.command = CMD_VOLUMESLIDE;
								m.param = (((m.param & 0x0F) + 1) / 2) | 0xF0;
								break;
							default:
								m.command = CMD_NONE;
								break;
							}
							break;

						case 0x1C:
							// Adjust channel volume range
							m.param = static_cast<ModCommand::PARAM>(std::min((m.param + 1) / 2, 64));
							break;
						}
					}

					// Try merging commands first
					ModCommand::CombineEffects(m.command, m.param, origCmd.command, origCmd.param);

					if(ModCommand::GetEffectWeight(origCmd.command) > ModCommand::GetEffectWeight(m.command))
					{
						if(m.volcmd == VOLCMD_NONE && ModCommand::ConvertVolEffect(m.command, m.param, true))
						{
							// Volume column to the rescue!
							m.volcmd = m.command;
							m.vol = m.param;
						}

						m.command = origCmd.command;
						m.param = origCmd.param;
					}
				}
			}

			if(flags & endOfRowMask)
			{
				// End of row
				break;
			}
		}
	}
Пример #28
0
void WardenWin::RequestData()
{
    SF_LOG_DEBUG("warden", "Request data");

    // If all checks were done, fill the todo list again
    if (_memChecksTodo.empty())
        _memChecksTodo.assign(sWardenCheckMgr->MemChecksIdPool.begin(), sWardenCheckMgr->MemChecksIdPool.end());

    if (_otherChecksTodo.empty())
        _otherChecksTodo.assign(sWardenCheckMgr->OtherChecksIdPool.begin(), sWardenCheckMgr->OtherChecksIdPool.end());

    _serverTicks = getMSTime();

    uint16 id;
    uint8 type;
    WardenCheck* wd;
    _currentChecks.clear();

    // Build check request
    for (uint32 i = 0; i < sWorld->getIntConfig(CONFIG_WARDEN_NUM_MEM_CHECKS); ++i)
    {
        // If todo list is done break loop (will be filled on next Update() run)
        if (_memChecksTodo.empty())
            break;

        // Get check id from the end and remove it from todo
        id = _memChecksTodo.back();
        _memChecksTodo.pop_back();

        // Add the id to the list sent in this cycle
        _currentChecks.push_back(id);
    }

    ByteBuffer buff;
    buff << uint8(WARDEN_SMSG_CHEAT_CHECKS_REQUEST);

    ACE_READ_GUARD(ACE_RW_Mutex, g, sWardenCheckMgr->_checkStoreLock);

    for (uint32 i = 0; i < sWorld->getIntConfig(CONFIG_WARDEN_NUM_OTHER_CHECKS); ++i)
    {
        // If todo list is done break loop (will be filled on next Update() run)
        if (_otherChecksTodo.empty())
            break;

        // Get check id from the end and remove it from todo
        id = _otherChecksTodo.back();
        _otherChecksTodo.pop_back();

        // Add the id to the list sent in this cycle
        _currentChecks.push_back(id);

        wd = sWardenCheckMgr->GetWardenDataById(id);

        switch (wd->Type)
        {
            case MPQ_CHECK:
            case LUA_STR_CHECK:
            case DRIVER_CHECK:
                buff << uint8(wd->Str.size());
                buff.append(wd->Str.c_str(), wd->Str.size());
                break;
            default:
                break;
        }
    }

    uint8 xorByte = _inputKey[0];

    // Add TIMING_CHECK
    buff << uint8(0x00);
    buff << uint8(TIMING_CHECK ^ xorByte);

    uint8 index = 1;

    for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr)
    {
        wd = sWardenCheckMgr->GetWardenDataById(*itr);

        type = wd->Type;
        buff << uint8(type ^ xorByte);
        switch (type)
        {
            case MEM_CHECK:
            {
                buff << uint8(0x00);
                buff << uint32(wd->Address);
                buff << uint8(wd->Length);
                break;
            }
            case PAGE_CHECK_A:
            case PAGE_CHECK_B:
            {
                buff.append(wd->Data.AsByteArray(0, false).get(), wd->Data.GetNumBytes());
                buff << uint32(wd->Address);
                buff << uint8(wd->Length);
                break;
            }
            case MPQ_CHECK:
            case LUA_STR_CHECK:
            {
                buff << uint8(index++);
                break;
            }
            case DRIVER_CHECK:
            {
                buff.append(wd->Data.AsByteArray(0, false).get(), wd->Data.GetNumBytes());
                buff << uint8(index++);
                break;
            }
            case MODULE_CHECK:
            {
                uint32 seed = static_cast<uint32>(rand32());
                buff << uint32(seed);
                HmacHash hmac(4, (uint8*)&seed);
                hmac.UpdateData(wd->Str);
                hmac.Finalize();
                buff.append(hmac.GetDigest(), hmac.GetLength());
                break;
            }
            /*case PROC_CHECK:
            {
                buff.append(wd->i.AsByteArray(0, false).get(), wd->i.GetNumBytes());
                buff << uint8(index++);
                buff << uint8(index++);
                buff << uint32(wd->Address);
                buff << uint8(wd->Length);
                break;
            }*/
            default:
                break;                                      // Should never happen
        }
    }
    buff << uint8(xorByte);
    buff.hexlike();

    // Encrypt with warden RC4 key
    EncryptData(buff.contents(), buff.size());

    WorldPacket pkt(SMSG_WARDEN_DATA, buff.size());
    pkt.append(buff);
    _session->SendPacket(&pkt);

    _dataSent = true;

    std::stringstream stream;
    stream << "Sent check id's: ";
    for (std::list<uint16>::iterator itr = _currentChecks.begin(); itr != _currentChecks.end(); ++itr)
        stream << *itr << " ";

    SF_LOG_DEBUG("warden", "%s", stream.str().c_str());
}
Пример #29
0
void WorldSession::HandlePlayerLoginOpcode( WorldPacket & recv_data )
{
    CHECK_PACKET_SIZE(recv_data,8);

    m_playerLoading = true;
    uint64 playerGuid = 0;

    DEBUG_LOG( "WORLD: Recvd Player Logon Message" );

    recv_data >> playerGuid;

    Player* plr = new Player(this);

    // "GetAccountId()==db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools)
    if(!plr->LoadFromDB(GUID_LOPART(playerGuid)))
    {
        KickPlayer();                                       // disconnect client, player no set to session and it will not deleted or saved at kick
        delete plr;                                         // delete it manually
        m_playerLoading = false;
        return;
    }
    //plr->_RemoveAllItemMods();

    //set a count of unread mails
    time_t cTime = time(NULL);
    QueryResult *resultMails = sDatabase.PQuery("SELECT COUNT(id) FROM `mail` WHERE `receiver` = '%u' AND `checked` = 0 AND `deliver_time` <= '" I64FMTD "'", GUID_LOPART(playerGuid),(uint64)cTime);
    if (resultMails)
    {
        Field *fieldMail = resultMails->Fetch();
        plr->unReadMails = fieldMail[0].GetUInt8();
        delete resultMails;
    }

    // store nearest delivery time (it > 0 and if it < current then at next player update SendNewMaill will be called)
    resultMails = sDatabase.PQuery("SELECT MIN(`deliver_time`) FROM `mail` WHERE `receiver` = '%u' AND `checked` = 0", GUID_LOPART(playerGuid));
    if (resultMails)
    {
        Field *fieldMail = resultMails->Fetch();
        plr->m_nextMailDelivereTime = (time_t)fieldMail[0].GetUInt64();
        delete resultMails;
    }

    SetPlayer(plr);

    Player *pCurrChar = GetPlayer();

    pCurrChar->SendDungeonDifficulty();

    WorldPacket data( SMSG_LOGIN_VERIFY_WORLD, 20 );
    data << plr->GetMapId();
    data << plr->GetPositionX();
    data << plr->GetPositionY();
    data << plr->GetPositionZ();
    data << plr->GetOrientation();
    SendPacket(&data);

    data.Initialize( SMSG_ACCOUNT_DATA_MD5, 128 );
    for(int i = 0; i < 32; i++)
        data << uint32(0);
    SendPacket(&data);

    pCurrChar->LoadIgnoreList();
    pCurrChar->SendFriendlist();
    pCurrChar->SendIgnorelist();

    // Send MOTD
    {
        data.Initialize(SMSG_MOTD, 50);                     // new in 2.0.1
        data << (uint32)0;

        uint32 linecount=0;
        string str_motd = sWorld.GetMotd();
        string::size_type pos, nextpos;

        pos = 0;
        while ( (nextpos= str_motd.find('@',pos)) != string::npos )
        {
            if (nextpos != pos)
            {
                data << str_motd.substr(pos,nextpos-pos);
                linecount++;
            }
            pos = nextpos+1;
        }

        if (pos<str_motd.length())
        {
            data << str_motd.substr(pos);
            linecount++;
        }

        data.put(0, linecount);

        SendPacket( &data );
        DEBUG_LOG( "WORLD: Sent motd (SMSG_MOTD)" );
    }

    if(pCurrChar->GetGuildId() != 0)
    {
        Guild* guild = objmgr.GetGuildById(pCurrChar->GetGuildId());
        if(guild)
        {
            data.Initialize(SMSG_GUILD_EVENT, (2+guild->GetMOTD().size()+1));
            data << (uint8)GE_MOTD;
            data << (uint8)1;
            data << guild->GetMOTD();
            SendPacket(&data);
            DEBUG_LOG( "WORLD: Sent guild-motd (SMSG_GUILD_EVENT)" );

            data.Initialize(SMSG_GUILD_EVENT, (5+10));      // we guess size
            data<<(uint8)GE_SIGNED_ON;
            data<<(uint8)1;
            data<<pCurrChar->GetName();
            data<<pCurrChar->GetGUID();
            guild->BroadcastPacket(&data);
            DEBUG_LOG( "WORLD: Sent guild-signed-on (SMSG_GUILD_EVENT)" );
        }
        else
        {
            // remove wrong guild data
            sLog.outError("Player %s (GUID: %u) marked as member not existed guild (id: %u), removing guild membership for player.",pCurrChar->GetName(),pCurrChar->GetGUIDLow(),pCurrChar->GetGuildId());
            pCurrChar->SetUInt32Value(PLAYER_GUILDID,0);
            pCurrChar->SetUInt32ValueInDB(PLAYER_GUILDID,0,pCurrChar->GetGUID());
        }
    }

    // rest_start

    // home bind stuff
    {
        QueryResult *result4 = sDatabase.PQuery("SELECT `map`,`zone`,`position_x`,`position_y`,`position_z` FROM `character_homebind` WHERE `guid` = '%u'", GUID_LOPART(playerGuid));
        if (result4)
        {
            Field *fields = result4->Fetch();
            _player->m_homebindMapId = fields[0].GetUInt32();
            _player->m_homebindZoneId = fields[1].GetUInt16();
            _player->m_homebindX = fields[2].GetFloat();
            _player->m_homebindY = fields[3].GetFloat();
            _player->m_homebindZ = fields[4].GetFloat();
            delete result4;
        }
        else
        {
            int plrace = GetPlayer()->getRace();
            int plclass = GetPlayer()->getClass();
            QueryResult *result5 = sDatabase.PQuery("SELECT `map`,`zone`,`position_x`,`position_y`,`position_z` FROM `playercreateinfo` WHERE `race` = '%u' AND `class` = '%u'", plrace, plclass);

            if(!result5)
            {
                sLog.outErrorDb("Table `playercreateinfo` not have data for race %u class %u , character can't be loaded.",plrace, plclass);
                LogoutPlayer(false);                        // without save
                return;
            }

            Field *fields = result5->Fetch();
            // store and send homebind for player
            _player->m_homebindMapId = fields[0].GetUInt32();
            _player->m_homebindZoneId = fields[1].GetUInt16();
            _player->m_homebindX = fields[2].GetFloat();
            _player->m_homebindY = fields[3].GetFloat();
            _player->m_homebindZ = fields[4].GetFloat();
            sDatabase.PExecute("INSERT INTO `character_homebind` (`guid`,`map`,`zone`,`position_x`,`position_y`,`position_z`) VALUES ('%u', '%u', '%u', '%f', '%f', '%f')", GUID_LOPART(playerGuid), _player->m_homebindMapId, (uint32)_player->m_homebindZoneId, _player->m_homebindX, _player->m_homebindY, _player->m_homebindZ);
            delete result5;
        }

        data.Initialize (SMSG_BINDPOINTUPDATE, 5*4);
        data << _player->m_homebindX << _player->m_homebindY << _player->m_homebindZ;
        data << (uint32) _player->m_homebindMapId;
        data << (uint32) _player->m_homebindZoneId;
        SendPacket (&data);

        DEBUG_LOG("Setting player home position: mapid is: %u, zoneid is %u, X is %f, Y is %f, Z is %f\n",
            _player->m_homebindMapId,_player->m_homebindZoneId,_player->m_homebindX,_player->m_homebindY, _player->m_homebindZ);
    }

    data.Initialize( SMSG_TUTORIAL_FLAGS, 8*32 );
    for (int i = 0; i < 8; i++)
        data << uint32( GetPlayer()->GetTutorialInt(i) );
    SendPacket(&data);
    //sLog.outDebug( "WORLD: Sent tutorial flags." );

    pCurrChar->_LoadSpellCooldowns();
    GetPlayer()->SendInitialSpells();
    GetPlayer()->SendInitialActionButtons();
    GetPlayer()->SendInitialReputations();

    /*if(GetPlayer()->getClass() == CLASS_HUNTER || GetPlayer()->getClass() == CLASS_ROGUE)
    {
        uint32 shiftdata=0x01;
        for(uint8 i=0;i<32;i++)
        {
            if ( 522753 & shiftdata )
            {
                data.Initialize(SMSG_SET_FLAT_SPELL_MODIFIER);
                data << uint8(i);
                data << uint8(5);
                data << uint16(1);
                data << uint16(0);
                SendPacket(&data);
            }
            shiftdata=shiftdata<<1;
        }
    }*/

    //Show cinematic at the first time that player login
    if( !GetPlayer()->getCinematic() )
    {
        GetPlayer()->setCinematic(1);

        ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(GetPlayer()->getRace());
        if(rEntry)
        {
            data.Initialize( SMSG_TRIGGER_CINEMATIC,4 );
            data << uint32(rEntry->startmovie);
            SendPacket( &data );
        }
    }

    pCurrChar->SendInitWorldStates();

    pCurrChar->CastSpell(pCurrChar, 836, true);             // LOGINEFFECT

    data.Initialize(SMSG_LOGIN_SETTIMESPEED, 8);
    time_t gameTime = sWorld.GetGameTime();
    struct tm *lt = localtime(&gameTime);
    uint32 xmitTime = (lt->tm_year - 100) << 24 | lt->tm_mon  << 20 |
        (lt->tm_mday - 1) << 14 | lt->tm_wday << 11 |
        lt->tm_hour << 6 | lt->tm_min;
    data << xmitTime;
    data << (float)0.017f;                                  // game speed
    SendPacket( &data );

    GetPlayer()->UpdateHonorFields();

    QueryResult *result = sDatabase.PQuery("SELECT `guildid`,`rank` FROM `guild_member` WHERE `guid` = '%u'",pCurrChar->GetGUIDLow());

    if(result)
    {
        Field *fields = result->Fetch();
        pCurrChar->SetInGuild(fields[0].GetUInt32());
        pCurrChar->SetRank(fields[1].GetUInt32());
        delete result;
    }
    else if(pCurrChar->GetGuildId())                        // clear guild related fields in case wrong data about non existed membership
    {
        pCurrChar->SetInGuild(0);
        pCurrChar->SetRank(0);
    }

    if (!MapManager::Instance().GetMap(pCurrChar->GetMapId(), pCurrChar)->AddInstanced(pCurrChar))
    {
        // TODO : Teleport to zone-in area
    }

    MapManager::Instance().GetMap(pCurrChar->GetMapId(), pCurrChar)->Add(pCurrChar);
    ObjectAccessor::Instance().InsertPlayer(pCurrChar);
    //sLog.outDebug("Player %s added to Map.",pCurrChar->GetName());

    if (pCurrChar->m_transport)
    {
        Transport* curTrans = pCurrChar->m_transport;
        pCurrChar->TeleportTo(curTrans->GetMapId(), curTrans->GetPositionX(), curTrans->GetPositionY(), curTrans->GetPositionZ(), curTrans->GetOrientation(), true, false);
    }

    sDatabase.PExecute("UPDATE `character` SET `online` = 1 WHERE `guid` = '%u'", pCurrChar->GetGUIDLow());
    loginDatabase.PExecute("UPDATE `account` SET `online` = 1 WHERE `id` = '%u'", GetAccountId());
    plr->SetInGameTime( getMSTime() );

    // set some aura effects after add player to map
    if(pCurrChar->HasAuraType(SPELL_AURA_MOD_STUN))
        pCurrChar->SetMovement(MOVE_ROOT);

    if(pCurrChar->HasAuraType(SPELL_AURA_MOD_ROOT))
    {
        WorldPacket data(SMSG_FORCE_MOVE_ROOT, 10);
        data.append(pCurrChar->GetPackGUID());
        data << (uint32)2;
        pCurrChar->SendMessageToSet(&data,true);
    }

    // announce group about member online (must be after add to player list to receive announce to self)
    if(pCurrChar->groupInfo.group)
    {
        //pCurrChar->groupInfo.group->SendInit(this); // useless
        pCurrChar->groupInfo.group->SendUpdate();
    }

    // friend status
    data.Initialize(SMSG_FRIEND_STATUS, 19);
    data<<uint8(FRIEND_ONLINE);
    data<<pCurrChar->GetGUID();
    data<<uint8(1);
    data<<pCurrChar->GetAreaId();
    data<<pCurrChar->getLevel();
    data<<pCurrChar->getClass();
    pCurrChar->BroadcastPacketToFriendListers(&data);

    pCurrChar->SendEnchantmentDurations();                  // must be after add to map

    // Place character in world (and load zone) before some object loading
    pCurrChar->LoadCorpse();

    // setting Ghost+speed if dead
    //if ( pCurrChar->m_deathState == DEAD )
    if ( pCurrChar->m_deathState != ALIVE )
    {
        // not blizz like, we must correctly save and load player instead...
        if(pCurrChar->getRace() == RACE_NIGHTELF)
            pCurrChar->CastSpell(pCurrChar, 20584, true, 0);// auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form)
        pCurrChar->CastSpell(pCurrChar, 8326, true, 0);     // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?)

        //pCurrChar->SetUInt32Value(UNIT_FIELD_AURA+41, 8326);
        //pCurrChar->SetUInt32Value(UNIT_FIELD_AURA+42, 20584);
        //pCurrChar->SetUInt32Value(UNIT_FIELD_AURAFLAGS+6, 238);
        //pCurrChar->SetUInt32Value(UNIT_FIELD_AURALEVELS+11, 514);
        //pCurrChar->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS+11, 65535);
        //pCurrChar->SetUInt32Value(UNIT_FIELD_DISPLAYID, 1825);
        //if (pCurrChar->getRace() == RACE_NIGHTELF)
        //{
        //    pCurrChar->SetSpeed(MOVE_RUN,  1.5f*1.2f, true);
        //    pCurrChar->SetSpeed(MOVE_SWIM, 1.5f*1.2f, true);
        //}
        //else
        //{
        //    pCurrChar->SetSpeed(MOVE_RUN,  1.5f, true);
        //    pCurrChar->SetSpeed(MOVE_SWIM, 1.5f, true);
        //}
        pCurrChar->SetMovement(MOVE_WATER_WALK);
    }

    // Load pet if any and player is alive
    if(pCurrChar->isAlive())
        pCurrChar->LoadPet();

    // show time before shutdown if shutdown planned.
    if(sWorld.IsShutdowning())
        sWorld.ShutdownMsg(true,pCurrChar);

    if(pCurrChar->isGameMaster())
        SendNotification("GM mode is ON");
    m_playerLoading = false;
    pCurrChar->SendAllowMove();

    data.Initialize(SMSG_UNKNOWN_811, 4);
    data << uint32(0);
    SendPacket(&data);
}
Пример #30
-5
void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
{
    std::string name;
    uint8 race_, class_;

    recv_data >> name;

    recv_data >> race_;
    recv_data >> class_;

    WorldPacket data(SMSG_CHAR_CREATE, 1);                  // returned with diff.values in all cases

    if(GetSecurity() == SEC_PLAYER)
    {
        if(uint32 mask = sWorld.getConfig(CONFIG_UINT32_CHARACTERS_CREATING_DISABLED))
        {
            bool disabled = false;

            uint32 team = Player::TeamForRace(race_);
            switch(team)
            {
                case ALLIANCE: disabled = mask & (1 << 0); break;
                case HORDE:    disabled = mask & (1 << 1); break;
            }

            if(disabled)
            {
                data << (uint8)CHAR_CREATE_DISABLED;
                SendPacket( &data );
                return;
            }
        }
    }

    ChrClassesEntry const* classEntry = sChrClassesStore.LookupEntry(class_);
    ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race_);

    if( !classEntry || !raceEntry )
    {
        data << (uint8)CHAR_CREATE_FAILED;
        SendPacket( &data );
        sLog.outError("Class: %u or Race %u not found in DBC (Wrong DBC files?) or Cheater?", class_, race_);
        return;
    }

    // prevent character creating Expansion race without Expansion account
    if (raceEntry->expansion > Expansion())
    {
        data << (uint8)CHAR_CREATE_EXPANSION;
        sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u race (%u)", Expansion(), GetAccountId(), raceEntry->expansion, race_);
        SendPacket( &data );
        return;
    }

    // prevent character creating Expansion class without Expansion account
    if (classEntry->expansion > Expansion())
    {
        data << (uint8)CHAR_CREATE_EXPANSION_CLASS;
        sLog.outError("Expansion %u account:[%d] tried to Create character with expansion %u class (%u)", Expansion(), GetAccountId(), classEntry->expansion, class_);
        SendPacket( &data );
        return;
    }

    // prevent character creating with invalid name
    if (!normalizePlayerName(name))
    {
        data << (uint8)CHAR_NAME_NO_NAME;
        SendPacket( &data );
        sLog.outError("Account:[%d] but tried to Create character with empty [name]", GetAccountId());
        return;
    }

    // check name limitations
    uint8 res = ObjectMgr::CheckPlayerName(name, true);
    if (res != CHAR_NAME_SUCCESS)
    {
        data << uint8(res);
        SendPacket( &data );
        return;
    }

    if (GetSecurity() == SEC_PLAYER && sObjectMgr.IsReservedName(name))
    {
        data << (uint8)CHAR_NAME_RESERVED;
        SendPacket( &data );
        return;
    }

    if (sObjectMgr.GetPlayerGUIDByName(name))
    {
        data << (uint8)CHAR_CREATE_NAME_IN_USE;
        SendPacket( &data );
        return;
    }

    QueryResult *resultacct = LoginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId());
    if (resultacct)
    {
        Field *fields=resultacct->Fetch();
        uint32 acctcharcount = fields[0].GetUInt32();
        delete resultacct;

        if (acctcharcount >= sWorld.getConfig(CONFIG_UINT32_CHARACTERS_PER_ACCOUNT))
        {
            data << (uint8)CHAR_CREATE_ACCOUNT_LIMIT;
            SendPacket( &data );
            return;
        }
    }

    QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%d'", GetAccountId());
    uint8 charcount = 0;
    if ( result )
    {
        Field *fields = result->Fetch();
        charcount = fields[0].GetUInt8();
        delete result;

        if (charcount >= sWorld.getConfig(CONFIG_UINT32_CHARACTERS_PER_REALM))
        {
            data << (uint8)CHAR_CREATE_SERVER_LIMIT;
            SendPacket( &data );
            return;
        }
    }

    // speedup check for heroic class disabled case
    uint32 heroic_free_slots = sWorld.getConfig(CONFIG_UINT32_HEROIC_CHARACTERS_PER_REALM);
    if(heroic_free_slots == 0 && GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT)
    {
        data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT;
        SendPacket( &data );
        return;
    }

    // speedup check for heroic class disabled case
    uint32 req_level_for_heroic = sWorld.getConfig(CONFIG_UINT32_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING);
    if(GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && req_level_for_heroic > sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL))
    {
        data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT;
        SendPacket( &data );
        return;
    }

    bool AllowTwoSideAccounts = sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ACCOUNTS) || GetSecurity() > SEC_PLAYER;
    CinematicsSkipMode skipCinematics = CinematicsSkipMode(sWorld.getConfig(CONFIG_UINT32_SKIP_CINEMATICS));

    bool have_same_race = false;

    // if 0 then allowed creating without any characters
    bool have_req_level_for_heroic = (req_level_for_heroic==0);

    if(!AllowTwoSideAccounts || skipCinematics == CINEMATICS_SKIP_SAME_RACE || class_ == CLASS_DEATH_KNIGHT)
    {
        QueryResult *result2 = CharacterDatabase.PQuery("SELECT level,race,class FROM characters WHERE account = '%u' %s",
            GetAccountId(), (skipCinematics == CINEMATICS_SKIP_SAME_RACE || class_ == CLASS_DEATH_KNIGHT) ? "" : "LIMIT 1");
        if(result2)
        {
            uint32 team_= Player::TeamForRace(race_);

            Field* field = result2->Fetch();
            uint8 acc_race  = field[1].GetUInt32();

            if(GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT)
            {
                uint8 acc_class = field[2].GetUInt32();
                if(acc_class == CLASS_DEATH_KNIGHT)
                {
                    if(heroic_free_slots > 0)
                        --heroic_free_slots;

                    if(heroic_free_slots == 0)
                    {
                        data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT;
                        SendPacket( &data );
                        delete result2;
                        return;
                    }
                }

                if(!have_req_level_for_heroic)
                {
                    uint32 acc_level = field[0].GetUInt32();
                    if(acc_level >= req_level_for_heroic)
                        have_req_level_for_heroic = true;
                }
            }

            // need to check team only for first character
            // TODO: what to if account already has characters of both races?
            if (!AllowTwoSideAccounts)
            {
                uint32 acc_team = 0;
                if(acc_race > 0)
                    acc_team = Player::TeamForRace(acc_race);

                if(acc_team != team_)
                {
                    data << (uint8)CHAR_CREATE_PVP_TEAMS_VIOLATION;
                    SendPacket( &data );
                    delete result2;
                    return;
                }
            }

            // search same race for cinematic or same class if need
            // TODO: check if cinematic already shown? (already logged in?; cinematic field)
            while ((skipCinematics == CINEMATICS_SKIP_SAME_RACE && !have_same_race) || class_ == CLASS_DEATH_KNIGHT)
            {
                if(!result2->NextRow())
                    break;

                field = result2->Fetch();
                acc_race = field[1].GetUInt32();

                if(!have_same_race)
                    have_same_race = race_ == acc_race;

                if(GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT)
                {
                    uint8 acc_class = field[2].GetUInt32();
                    if(acc_class == CLASS_DEATH_KNIGHT)
                    {
                        if(heroic_free_slots > 0)
                            --heroic_free_slots;

                        if(heroic_free_slots == 0)
                        {
                            data << (uint8)CHAR_CREATE_UNIQUE_CLASS_LIMIT;
                            SendPacket( &data );
                            delete result2;
                            return;
                        }
                    }

                    if(!have_req_level_for_heroic)
                    {
                        uint32 acc_level = field[0].GetUInt32();
                        if(acc_level >= req_level_for_heroic)
                            have_req_level_for_heroic = true;
                    }
                }
            }
            delete result2;
        }
    }

    if(GetSecurity() == SEC_PLAYER && class_ == CLASS_DEATH_KNIGHT && !have_req_level_for_heroic)
    {
        data << (uint8)CHAR_CREATE_LEVEL_REQUIREMENT;
        SendPacket( &data );
        return;
    }

    // extract other data required for player creating
    uint8 gender, skin, face, hairStyle, hairColor, facialHair, outfitId;
    recv_data >> gender >> skin >> face;
    recv_data >> hairStyle >> hairColor >> facialHair >> outfitId;

    Player *pNewChar = new Player(this);
    if(!pNewChar->Create( sObjectMgr.GenerateLowGuid(HIGHGUID_PLAYER), name, race_, class_, gender, skin, face, hairStyle, hairColor, facialHair, outfitId ))
    {
        // Player not create (race/class problem?)
        delete pNewChar;

        data << (uint8)CHAR_CREATE_ERROR;
        SendPacket( &data );

        return;
    }

    if ((have_same_race && skipCinematics == CINEMATICS_SKIP_SAME_RACE) || skipCinematics == CINEMATICS_SKIP_ALL)
        pNewChar->setCinematic(1);                          // not show intro

    pNewChar->SetAtLoginFlag(AT_LOGIN_FIRST);               // First login

    // Player created, save it now
    pNewChar->SaveToDB();
    charcount += 1;

    LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", GetAccountId(), realmID);
    LoginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)",  charcount, GetAccountId(), realmID);

    data << (uint8)CHAR_CREATE_SUCCESS;
    SendPacket( &data );

    std::string IP_str = GetRemoteAddress();
    BASIC_LOG("Account: %d (IP: %s) Create Character:[%s] (guid: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), pNewChar->GetGUIDLow());
    sLog.outChar("Account: %d (IP: %s) Create Character:[%s] (guid: %u)", GetAccountId(), IP_str.c_str(), name.c_str(), pNewChar->GetGUIDLow());

    delete pNewChar;                                        // created only to call SaveToDB()
}