knightonline/server/GameServer/Bot.cpp

272 lines
6.3 KiB
C++

#include "stdafx.h"
#include "Map.h"
#include "../shared/DateTime.h"
CBot::CBot()
{
Initialize();
}
void CBot::Initialize()
{
MerchantChat.clear();
LastWarpTime = 0;
m_tLastKillTime = 0;
m_sChallangeAchieveID = 0;
m_pktcount = 0;
m_strUserID.clear();
m_strMemo.clear();
m_strAccountID.clear();
for (int i = 0; i < STAT_COUNT; i++)
m_bRebStats[i] = 0;
m_sAchieveCoverTitle = 0;
memset(&m_arSellMerchantItems, 0, sizeof(m_arSellMerchantItems));
memset(&m_arBuyMerchantItems, 0, sizeof(m_arBuyMerchantItems));
m_bMerchantState = MERCHANT_STATE_NONE;
m_bAuthority = 1;
m_sBind = -1;
m_state = GAME_STATE_CONNECTED;
m_bPartyLeader = false;
m_bIsChicken = false;
m_bIsHidingHelmet = false;
m_bIsHidingCospre = false;
m_bPremiumMerchant = false;
m_bInParty = false;
m_bInvisibilityType = INVIS_NONE;
m_sDirection = 0;
memset(&m_bStats, 0, sizeof(m_bStats));
m_bAuthority = AUTHORITY_PLAYER;
m_bLevel = 1;
m_iExp = 0;
m_iBank = m_iGold = 0;
m_iLoyalty = 100;
m_iLoyaltyMonthly = 0;
m_iMannerPoint = 0;
m_sHp = m_sMp = m_sSp = 0;
m_iMaxHp = 0;
m_iMaxMp = 1;
m_iMaxSp = 120;
m_sMerchantsSocketID = -1;
m_bResHpType = USER_STANDING;
m_bBlockPrivateChat = false;
m_sPrivateChatUser = -1;
m_bNeedParty = 0x01;
m_bAbnormalType = ABNORMAL_NORMAL; // User starts out in normal size.
m_nOldAbnormalType = m_bAbnormalType;
m_teamColour = TeamColourNone;
}
bool CBot::RegisterRegion()
{
uint16
new_region_x = GetNewRegionX(), new_region_z = GetNewRegionZ(),
old_region_x = GetRegionX(), old_region_z = GetRegionZ();
if (GetRegion() == nullptr || (old_region_x == new_region_x && old_region_z == new_region_z))
return false;
AddToRegion(new_region_x, new_region_z);
RemoveRegion(old_region_x - new_region_x, old_region_z - new_region_z);
InsertRegion(new_region_x - old_region_x, new_region_z - old_region_z);
return true;
}
void CBot::AddToRegion(int16 new_region_x, int16 new_region_z)
{
GetRegion()->Remove(this);
SetRegion(new_region_x, new_region_z);
GetRegion()->Add(this);
}
void CBot::RemoveRegion(int16 del_x, int16 del_z)
{
ASSERT(GetMap() != nullptr);
Packet result;
GetInOut(result, INOUT_OUT);
g_pMain->Send_OldRegions(&result, del_x, del_z, GetMap(), GetRegionX(), GetRegionZ(),nullptr,0);
}
void CBot::InsertRegion(int16 insert_x, int16 insert_z)
{
ASSERT(GetMap() != nullptr);
Packet result;
GetInOut(result, INOUT_IN);
g_pMain->Send_NewRegions(&result, insert_x, insert_z, GetMap(), GetRegionX(), GetRegionZ(),nullptr,0);
}
void CBot::SetRegion(uint16 x /*= -1*/, uint16 z /*= -1*/)
{
m_sRegionX = x; m_sRegionZ = z;
m_pRegion = m_pMap->GetRegion(x, z); // TODO: Clean this up
}
void CBot::StateChangeServerDirect(uint8 bType, uint32 nBuff)
{
uint8 buff = *(uint8 *)&nBuff; // don't ask
switch (bType)
{
case 1:
m_bResHpType = buff;
break;
case 2:
m_bNeedParty = buff;
break;
case 3:
m_nOldAbnormalType = m_bAbnormalType;
m_bAbnormalType = nBuff;
break;
case 5:
m_bAbnormalType = nBuff;
break;
case 6:
nBuff = m_bPartyLeader; // we don't set this here.
break;
case 7:
break;
case 8: // beginner quest
break;
case 14:
break;
}
Packet result(WIZ_STATE_CHANGE);
result << GetID() << bType << nBuff;
SendToRegion(&result);
}
void CBot::GetInOut(Packet & result, uint8 bType)
{
result.Initialize(WIZ_USER_INOUT);
result << uint16(bType) << GetID();
if (bType != INOUT_OUT)
GetUserInfo(result);
}
void CBot::UserInOut(uint8 bType)
{
Packet result;
GetInOut(result, bType);
Guard lock(g_pMain->m_BotcharacterNameLock);
if (bType == INOUT_OUT)
{
GetRegion()->Remove(this);
m_state = GAME_STATE_CONNECTED;
std::string upperName = GetName();
STRTOUPPER(upperName);
g_pMain->m_BotcharacterNameMap.erase(upperName);
}
else
{
GetRegion()->Add(this);
m_state = GAME_STATE_INGAME;
std::string upperName = GetName();
STRTOUPPER(upperName);
g_pMain->m_BotcharacterNameMap[upperName] = this;
}
SendToRegion(&result);
}
void CBot::SendToRegion(Packet *pkt)
{
g_pMain->Send_Region(pkt, GetMap(), GetRegionX(), GetRegionZ(), nullptr, 0);
}
void CBot::GetUserInfo(Packet & pkt)
{
pkt.SByte();
pkt << GetName()
<< uint16(m_bNation) << GetClanID() << m_bFame;
CKnights * pKnights = g_pMain->GetClanPtr(GetClanID());
if (pKnights == nullptr)
{
pkt << uint32(0) << uint16(0) << uint8(0) << uint16(-1) << uint32(0) << uint8(0);
}
else
{
CKnights *aKnights = g_pMain->GetClanPtr(pKnights->GetAllianceID());
pkt << pKnights->GetAllianceID()
<< pKnights->m_strName
<< pKnights->m_byGrade << pKnights->m_byRanking
<< uint16(pKnights->m_sMarkVersion) // symbol/mark version
<< pKnights->GetCapeID(aKnights) // cape ID
<< pKnights->m_bCapeR << pKnights->m_bCapeG << pKnights->m_bCapeB << uint8(0) // this is stored in 4 bytes after all.
// not sure what this is, but it (just?) enables the clan symbol on the cape
// value in dump was 9, but everything tested seems to behave as equally well...
// we'll probably have to implement logic to respect requirements.
<< uint8(1);
}
uint8 bInvisibilityType = m_bInvisibilityType;
if (bInvisibilityType != INVIS_NONE)
bInvisibilityType = INVIS_DISPEL_ON_MOVE;
pkt << m_bLevel << m_bRace << m_sClass
<< GetSPosX() << GetSPosZ() << GetSPosY()
<< m_bFace << m_nHair
<< m_bResHpType << uint32(m_bAbnormalType)
<< m_bNeedParty
<< m_bAuthority
<< m_bPartyLeader // is party leader (bool)
<< bInvisibilityType // visibility state
<< uint8(m_teamColour) // team colour (i.e. in soccer, 0=none, 1=blue, 2=red)
<< m_bIsHidingHelmet << m_bIsHidingCospre // either this is correct and items are super buggy, or it causes baldness. You choose.
<< m_sDirection // direction
<< m_bIsChicken // chicken/beginner flag
<< m_bRank // king flag
<< uint16(0)
<< int8(-1) << int8(-1); // NP ranks (total, monthly)
uint8 equippedItems[] =
{
BREAST, LEG, HEAD, GLOVE, FOOT, SHOULDER, RIGHTHAND, LEFTHAND, CWING, CHELMET, CLEFT, CRIGHT, CTOP, FAIRY
};
foreach_array (i, equippedItems)
{
_ITEM_DATA * pItem = &m_sItemArray[equippedItems[i]];
if(pItem == nullptr)
continue;
pkt << pItem->nNum << pItem->sDuration << pItem->bFlag;
}
pkt << m_bZone << uint8(-1) << uint8(-1) << uint16(0) << uint16(0) << uint16(0) << m_bIsHidingCospre << uint8(0) << uint8(GetRebLevel()) << uint16(m_sAchieveCoverTitle) << uint16(0) << uint8(0) << uint8(0);
}