gdle/Source/Client.cpp
Morosity b6b7a3565e Character Delete timer & Restore ability
Character delete time via config (default 1 hour)
Cleaned up some text messages to correct error int
New /getemail & /setemail for account security
Use of setemail is once per account only
Login screen will start to highlight last played char
Only if house owner is deleted will house be lost
2019-11-23 20:34:53 +00:00

1971 lines
60 KiB
C++

#include <StdAfx.h>
#include "easylogging++.h"
#include "InferredPortalData.h"
#include "Client.h"
#include "ClientEvents.h"
#include "Config.h"
#include <chrono>
// Network access
#include "Network.h"
#include "PacketController.h"
#include "BinaryReader.h"
#include "BinaryWriter.h"
// Database access
#include "Database.h"
#include "Database2.h"
#include "DatabaseIO.h"
#include "WeenieFactory.h"
// World access
#include "World.h"
// Player access
#include "WeenieObject.h"
#include "Monster.h"
#include "Player.h"
// Command access
#include "ClientCommands.h"
#include "ChatMsgs.h"
#include "AllegianceManager.h"
#include "Util.h"
#include "House.h"
#include "HouseManager.h"
// CClient - for client/server interaction
CClient::CClient(SOCKADDR_IN *peer, WORD slot, AccountInformation_t &accountInfo)
{
memcpy(&m_vars.addr, peer, sizeof(SOCKADDR_IN));
m_AccountInfo = accountInfo;
m_vars.slot = slot;
m_vars.account = accountInfo.username;
m_pPC = new CPacketController(this);
m_pEvents = new CClientEvents(this);
}
CClient::~CClient()
{
SafeDelete(m_pEvents);
SafeDelete(m_pPC);
}
void CClient::IncomingBlob(BlobPacket_s *blob, double recvTime)
{
if (!IsAlive())
return;
m_pPC->IncomingBlob(blob, recvTime);
}
void CClient::Think()
{
if (!IsAlive())
return;
WorldThink();
m_pPC->Think();
// packet control can signal to kill
if (!m_pPC->IsAlive())
Kill(__FILE__, __LINE__);
}
void CClient::ThinkOutbound()
{
if (!IsAlive())
return;
if (m_pPC && m_pPC->IsAlive())
{
m_pPC->ThinkOutbound();
}
}
void CClient::WorldThink()
{
if (!m_vars.bInWorld)
{
if (m_vars.bNeedChars)
{
UpdateLoginScreen();
m_vars.bNeedChars = false;
}
}
m_pEvents->Think();
}
const AccountInformation_t &CClient::GetAccountInfo()
{
return m_AccountInfo;
}
const std::list<CharacterDesc_t> &CClient::GetCharacters()
{
return m_Characters;
}
bool CClient::HasCharacter(uint32_t character_weenie_id)
{
for (auto &character : m_Characters)
{
if (character.weenie_id == character_weenie_id)
return true;
}
return false;
}
uint32_t CClient::IncCharacterInstanceTS(uint32_t character_weenie_id)
{
WORD newInstanceTS = 0;
// just make this work
m_Characters = g_pDBIO->GetCharacterList(m_AccountInfo.id);
for (auto &character : m_Characters)
{
if (character.weenie_id == character_weenie_id)
{
newInstanceTS = character.instance_ts + 1;
g_pDBIO->SetCharacterInstanceTS(character.weenie_id, newInstanceTS);
}
}
// just make this work
m_Characters = g_pDBIO->GetCharacterList(m_AccountInfo.id);
return newInstanceTS;
}
void CClient::UpdateLoginScreen()
{
m_CharactersSent = m_Characters = g_pDBIO->GetCharacterList(m_AccountInfo.id);
BinaryWriter CharacterList;
CharacterList.Write<uint32_t>(0xF658);
CharacterList.Write<uint32_t>(0); // check what this is
CharacterList.Write<uint32_t>(m_Characters.size());
for (auto &character : m_Characters)
{
CharacterList.Write<uint32_t>(character.weenie_id);
CharacterList.WriteString(character.name);
CharacterList.Write<uint32_t>(character.ts_deleted);
}
CharacterList.Write<uint32_t>(0);
CharacterList.Write<uint32_t>(11); // max characters I'm assuming
CharacterList.WriteString(m_AccountInfo.username);
CharacterList.Write<uint32_t>(1); // what are these
CharacterList.Write<uint32_t>(1); // what are these
SendNetMessage(CharacterList.GetData(), CharacterList.GetSize(), PRIVATE_MSG);
BinaryWriter ServerName;
ServerName.Write<uint32_t>(0xF7E1);
ServerName.Write<uint32_t>(g_pWorld->GetNumPlayers()); // num connections
ServerName.Write<uint32_t>(-1); // Max connections
ServerName.WriteString(g_pConfig->WorldName());
SendNetMessage(ServerName.GetData(), ServerName.GetSize(), PRIVATE_MSG);
BinaryWriter DDD_InterrogationMessage;
DDD_InterrogationMessage.Write<uint32_t>(0xF7E5);
DDD_InterrogationMessage.Write<uint32_t>(1); // servers region
DDD_InterrogationMessage.Write<uint32_t>(1); // name rule language
DDD_InterrogationMessage.Write<uint32_t>(1); // product id
DDD_InterrogationMessage.Write<uint32_t>(2); // supports languages (2)
DDD_InterrogationMessage.Write<uint32_t>(0); // language #1
DDD_InterrogationMessage.Write<uint32_t>(1); // language #2
SendNetMessage(DDD_InterrogationMessage.GetData(), DDD_InterrogationMessage.GetSize(), EVENT_MSG);
}
void CClient::EnterWorld()
{
uint32_t EnterWorld = 0xF7DF; // 0xF7C7;
SendNetMessage(&EnterWorld, sizeof(uint32_t), 9);
SERVER_INFO << "Client" << m_vars.slot << "is entering the world.";
m_vars.bInWorld = TRUE;
BinaryWriter setChatChannels;
setChatChannels.Write<uint32_t>(0x295);
setChatChannels.Write<uint32_t>(Allegiance_ChatChannel);
setChatChannels.Write<uint32_t>(General_ChatChannel);
setChatChannels.Write<uint32_t>(Trade_ChatChannel);
setChatChannels.Write<uint32_t>(LFG_ChatChannel);
setChatChannels.Write<uint32_t>(Roleplay_ChatChannel);
setChatChannels.Write<uint32_t>(Olthoi_ChatChannel);
setChatChannels.Write<uint32_t>(Society_ChatChannel);
setChatChannels.Write<uint32_t>(SocietyCelHan_ChatChannel);
setChatChannels.Write<uint32_t>(SocietyEldWeb_ChatChannel);
setChatChannels.Write<uint32_t>(SocietyRadBlo_ChatChannel);
SendNetMessage(&setChatChannels, PRIVATE_MSG, FALSE, FALSE);
}
void CClient::ExitWorld()
{
uint32_t ExitWorld = 0xF653;
SendNetMessage(&ExitWorld, sizeof(uint32_t), PRIVATE_MSG);
SERVER_INFO << "Client" << m_vars.slot << "is exiting the world.";
m_pPC->ResetEvent();
UpdateLoginScreen();
m_vars.bInWorld = FALSE;
}
void CClient::SendNetMessage(BinaryWriter* pMessage, WORD group, BOOL event, BOOL del, bool ephemeral)
{
if (!pMessage)
return;
SendNetMessage(pMessage->GetData(), pMessage->GetSize(), group, event, del, ephemeral);
if (del)
delete pMessage;
}
void CClient::SendNetMessage(void *data, uint32_t length, WORD group, BOOL game_event, BOOL del, bool ephemeral)
{
if (!IsAlive())
return;
if (!data || !length)
return;
m_pPC->QueueNetMessage(data, length, group, game_event ? GetEvents()->GetPlayerID() : 0, ephemeral);
}
BOOL CClient::CheckBadName(const std::string name)
{
string ps = name;
std::transform(ps.begin(), ps.end(), ps.begin(), ::tolower);
ps = ReplaceInString(ps, " ", "");
ps = ReplaceInString(ps, "-", "");
ps = ReplaceInString(ps, "'", "");
ps = ReplaceInString(ps, "\"", "");
for (auto const& value : g_pPortalDataEx->GetBannedwords())
{
if (ps.find(value) != std::string::npos)
return false;
}
return true;
}
BOOL CClient::CheckNameValidity(const char *name, int access, std::string &resultName)
{
resultName = "";
if (!strncmp(name, "Contributor ", strlen("Contributor ")))
{
if (access >= ADVOCATE_ACCESS)
{
resultName = "+Contributor ";
name += strlen("Contributor ");
}
else
return FALSE;
}
int len = (int)strlen(name);
if ((len < 3) || (len > 32))
return FALSE;
int i = 0;
while (i < len)
{
char letter = name[i];
if (!(letter >= 'A' && letter <= 'Z') && !(letter >= 'a' || letter <= 'z') && !(letter == '\'') && !(letter == ' ') && !(letter == '-'))
break;
i++;
}
if (i == len)
{
resultName += name;
return TRUE;
}
return FALSE;
}
void CClient::DeleteCharacter(BinaryReader *pReader)
{
std::string account_name = pReader->ReadString(); // account
if (strcmp(account_name.c_str(), m_vars.account.c_str()))
return;
int slot = pReader->Read<int>();
if (slot < 0 || slot >= m_Characters.size() || slot >= m_CharactersSent.size())
return; // out of range
auto entry = m_CharactersSent.begin();
std::advance(entry, slot);
std::list<CharacterDesc_t> friendsof = g_pDBIO->GetFriendsOf(entry->weenie_id);
for (auto it : friendsof)
{
CPlayerWeenie* myfriend = g_pWorld->FindPlayer(it.weenie_id);
if (myfriend)
{
myfriend->RemoveFriend(entry->weenie_id);
}
}
g_pDBIO->DeleteCharFriends(entry->weenie_id);
g_pAllegianceManager->BreakAllAllegiance(entry->weenie_id);
g_pHouseManager->RemoveHouseFromAccount(entry->weenie_id);
g_pDBIO->DeleteCharacter(entry->weenie_id);
UpdateLoginScreen();
}
void CClient::RestoreCharacter(BinaryReader *pReader)
{
uint32_t character_id = pReader->Read<uint32_t>();
if (!HasCharacter(character_id))
{
m_pPC->EvilClient(NULL, NULL, true);
}
if (!g_pDBIO->IsCharacterDeleting(character_id))
{
m_pPC->EvilClient(NULL, NULL, true);
}
g_pDBIO->RestoreCharacter(character_id);
UpdateLoginScreen();
}
void CClient::CreateCharacter(BinaryReader *pReader)
{
auto badData = [&](uint32_t err = CG_VERIFICATION_RESPONSE_CORRUPT)
{
BinaryWriter response;
response.Write<uint32_t>(0xF643);
response.Write<uint32_t>(err);
SendNetMessage(response.GetData(), response.GetSize(), PRIVATE_MSG);
};
//uint32_t errorCode = CG_VERIFICATION_RESPONSE_CORRUPT;
std::string account_name = pReader->ReadString();
if (strcmp(account_name.c_str(), m_vars.account.c_str()))
return;
ACCharGenResult cg;
cg.UnPack(pReader);
std::string resultName;
if (pReader->GetLastError())
{
badData();
return;
}
cg.strength = max(min(cg.strength, 100), 10);
cg.endurance = max(min(cg.endurance, 100), 10);
cg.coordination = max(min(cg.coordination, 100), 10);
cg.quickness = max(min(cg.quickness, 100), 10);
cg.focus = max(min(cg.focus, 100), 10);
cg.self = max(min(cg.self, 100), 10);
int totalAttribs = cg.strength + cg.endurance + cg.coordination + cg.quickness + cg.focus + cg.self;
if (totalAttribs > 330)
{
badData();
return;
}
//if (cg.heritageGroup <= 0 || cg.heritageGroup >= 14)
if (cg.heritageGroup <= 0 || cg.heritageGroup >= 12 && !g_pConfig->AllowOlthoi())
{
badData();
BinaryWriter popupString;
popupString.Write<uint32_t>(4);
popupString.WriteString("No Olthoi at this time.");
SendNetMessage(&popupString, PRIVATE_MSG, FALSE, FALSE);
return;
}
if (cg.gender < 0 || cg.gender >= 3) // allow invalid gender? not sure
{
badData();
return;
}
SkillTable *pSkillTable = SkillSystem::GetSkillTable();
int numCreditsUsed = 0;
cg.numSkills = max(0, min(100, cg.numSkills));
ACCharGenData *cgd = CachedCharGenData;
assert(cgd != NULL);
HeritageGroup_CG *heritageGroup = cgd->mHeritageGroupList.lookup(cg.heritageGroup);
Sex_CG *scg = NULL;
for (uint32_t i = 0; i < cg.numSkills; i++)
{
switch (cg.skillAdvancementClasses[i])
{
case SKILL_ADVANCEMENT_CLASS::UNDEF_SKILL_ADVANCEMENT_CLASS:
case SKILL_ADVANCEMENT_CLASS::UNTRAINED_SKILL_ADVANCEMENT_CLASS:
case SKILL_ADVANCEMENT_CLASS::TRAINED_SKILL_ADVANCEMENT_CLASS:
case SKILL_ADVANCEMENT_CLASS::SPECIALIZED_SKILL_ADVANCEMENT_CLASS:
break;
default:
badData();
return;
}
const SkillBase *pSkillBase = pSkillTable->GetSkillBaseRaw(SkillTable::OldToNewSkill((STypeSkill)i));
if (pSkillBase != NULL)
{
//first we check our heritage specific skill costs.
bool found = false;
for (uint32_t j = 0; j < heritageGroup->mSkillList.num_used; j++)
{
if (heritageGroup->mSkillList.array_data[j].skillNum == i)
{
if (cg.skillAdvancementClasses[i] == SKILL_ADVANCEMENT_CLASS::TRAINED_SKILL_ADVANCEMENT_CLASS)
numCreditsUsed += heritageGroup->mSkillList.array_data[j].normalCost;
else if (cg.skillAdvancementClasses[i] == SKILL_ADVANCEMENT_CLASS::SPECIALIZED_SKILL_ADVANCEMENT_CLASS)
numCreditsUsed += heritageGroup->mSkillList.array_data[j].primaryCost;
found = true;
break;
}
}
//then if not found check regular skill costs.
if (!found)
{
if (cg.skillAdvancementClasses[i] == SKILL_ADVANCEMENT_CLASS::TRAINED_SKILL_ADVANCEMENT_CLASS)
numCreditsUsed += pSkillBase->_trained_cost;
else if (cg.skillAdvancementClasses[i] == SKILL_ADVANCEMENT_CLASS::SPECIALIZED_SKILL_ADVANCEMENT_CLASS)
numCreditsUsed += pSkillBase->_specialized_cost;
}
}
else
{
if (cg.skillAdvancementClasses[i] == SKILL_ADVANCEMENT_CLASS::TRAINED_SKILL_ADVANCEMENT_CLASS ||
cg.skillAdvancementClasses[i] == SKILL_ADVANCEMENT_CLASS::SPECIALIZED_SKILL_ADVANCEMENT_CLASS)
{
badData();
return;
}
}
}
if (numCreditsUsed > 56)
{
badData();
return;
}
// need to reformat name here...
if (!CheckNameValidity(cg.name.c_str(), GetAccessLevel(), resultName))
{
badData(CG_VERIFICATION_RESPONSE_NAME_BANNED);
return;
}
if (!CheckBadName(cg.name))
{
badData(CG_VERIFICATION_RESPONSE_NAME_BANNED);
return;
}
// should check variables to make sure everythings within restriction
// wHairTextures[m_wGender][m_wHairStyle];
// WORD wHairTextures[2][4] = { { 0x10B8, 0x10B8, 0x10B8, 0x10B7 }, { 0x11FD, 0x11FD, 0x11FD, 0x10B7 } };
// group 4, 0x0000F643, 0x00000001, <guid>, <char name[str]>, 0x00000000
{
// check if name exists
if (g_pDBIO->IsCharacterNameOpen(resultName.c_str()))
{
const int MIN_PLAYER_GUID = 0x50000000;
const int MAX_PLAYER_GUID = 0x5FFFFFFF;
unsigned int newCharacterGUID = g_pDBIO->GetHighestWeenieID(MIN_PLAYER_GUID, MAX_PLAYER_GUID) + 1;
if (g_pDBIO->CreateCharacter(m_AccountInfo.id, newCharacterGUID, resultName.c_str()))
{
m_Characters = g_pDBIO->GetCharacterList(m_AccountInfo.id);
// start pReader Zaikhil
Position startPos;
// startPos = Position(0x7D64001D, Vector(74.748657f, 97.934601f, 12.004999f), Quaternion(0.926898f, 0.000000f, 0.000000f, -0.375314f)); // zaikhil
// startPos = Position(0x9722003A, Vector(168.354004f, 24.618000f, 102.005005f), Quaternion(-0.922790f, 0.000000f, 0.000000f, -0.385302f));
startPos = Position(0xD3380005, Vector(5.500000f, 109.800003f, 168.463333f), Quaternion(1.000000f, 0.000000f, 0.000000f, 0.000000f));
// WCID "1" is always a player weenie
CWeenieObject *weenie = g_pWeenieFactory->CreateWeenieByClassID(1, &startPos, false);
if (!weenie)
{
badData();
return;
}
weenie->SetID(newCharacterGUID);
// alter parameters for character creation here
weenie->SetName(resultName.c_str());
weenie->m_Qualities.SetInt(HERITAGE_GROUP_INT, cg.heritageGroup);
weenie->m_Qualities.SetInt(GENDER_INT, cg.gender);
weenie->m_Qualities.SetAttribute(STRENGTH_ATTRIBUTE, cg.strength);
weenie->m_Qualities.SetAttribute(ENDURANCE_ATTRIBUTE, cg.endurance);
weenie->m_Qualities.SetAttribute(COORDINATION_ATTRIBUTE, cg.coordination);
weenie->m_Qualities.SetAttribute(QUICKNESS_ATTRIBUTE, cg.quickness);
weenie->m_Qualities.SetAttribute(FOCUS_ATTRIBUTE, cg.focus);
weenie->m_Qualities.SetAttribute(SELF_ATTRIBUTE, cg.self);
weenie->m_Qualities.SetInt(CHARACTER_TITLE_ID_INT, 1);
if (heritageGroup)
{
weenie->m_Qualities.SetString(HERITAGE_GROUP_STRING, heritageGroup->name.c_str());
if (cg.templateNum >= 0 && cg.templateNum < heritageGroup->mTemplateList.num_used)
weenie->m_Qualities.SetString(TEMPLATE_STRING, heritageGroup->mTemplateList.array_data[cg.templateNum].name.c_str());
scg = heritageGroup->mGenderList.lookup(cg.gender);
if (scg)
{
weenie->m_Qualities.SetDataID(PALETTE_BASE_DID, scg->basePalette);
weenie->m_Qualities.SetDataID(ICON_DID, scg->iconImage);
weenie->m_Qualities.SetDataID(SOUND_TABLE_DID, scg->soundTable);
weenie->m_Qualities.SetDataID(MOTION_TABLE_DID, scg->motionTable);
weenie->m_Qualities.SetDataID(COMBAT_TABLE_DID, scg->combatTable);
weenie->m_Qualities.SetDataID(PHYSICS_EFFECT_TABLE_DID, scg->physicsTable);
weenie->m_Qualities.SetDataID(SETUP_DID, scg->setup);
weenie->m_Qualities.SetFloat(DEFAULT_SCALE_FLOAT, scg->scaling / 100);
weenie->m_ObjDescOverride = scg->objDesc;
//weenie->m_ObjDesc = scg->objDesc;
//weenie->m_ObjDesc.paletteID = scg->basePalette;
cg.hairStyle = max(0, min((int)scg->mHairStyleList.num_used - 1, cg.hairStyle));
HairStyle_CG *hairStyle = &scg->mHairStyleList.array_data[cg.hairStyle];
weenie->m_ObjDescOverride += hairStyle->objDesc;
//weenie->m_ObjDesc += hairStyle->objDesc;
AnimPartChange *change = hairStyle->objDesc.GetAnimPartChange(CharacterPartIndex::Head);
if (change)
weenie->m_Qualities.SetDataID(HEAD_OBJECT_DID, change->part_id);
//if (hairStyle->objDesc.firstAPChange)
// weenie->m_Qualities.SetDataID(HEAD_OBJECT_DID, hairStyle->objDesc.firstAPChange->part_id);
if (hairStyle->alternateSetup)
weenie->m_Qualities.SetDataID(SETUP_DID, hairStyle->alternateSetup);
// fix Gearknight and olthoi head_object_did
//if (cg.heritageGroup == Gearknight_HeritageGroup)
// weenie->m_Qualities.SetDataID(HEAD_OBJECT_DID, hairStyle->objDesc.lastAPChange->part_id);
//if (cg.heritageGroup == Olthoi_HeritageGroup)
// weenie->m_Qualities.SetDataID(HEAD_OBJECT_DID, 0x010045f0);
//if (cg.heritageGroup == OlthoiAcid_HeritageGroup)
// weenie->m_Qualities.SetDataID(HEAD_OBJECT_DID, 0x01004616);
if (cg.eyesStrip != -1)
{
cg.eyesStrip = max(0, min((int)scg->mEyeStripList.num_used - 1, cg.eyesStrip));
EyesStrip_CG *eyesStrip = &scg->mEyeStripList.array_data[cg.eyesStrip];
if (eyesStrip)
{
if (hairStyle->bald)
{
//weenie->m_ObjDesc += eyesStrip->objDesc_Bald;
weenie->m_Qualities.SetDataID(DEFAULT_EYES_TEXTURE_DID, eyesStrip->objDesc_Bald.firstTMChange->old_tex_id);
weenie->m_Qualities.SetDataID(EYES_TEXTURE_DID, eyesStrip->objDesc_Bald.firstTMChange->new_tex_id);
}
else
{
//weenie->m_ObjDesc += eyesStrip->objDesc;
weenie->m_Qualities.SetDataID(DEFAULT_EYES_TEXTURE_DID, eyesStrip->objDesc.firstTMChange->old_tex_id);
weenie->m_Qualities.SetDataID(EYES_TEXTURE_DID, eyesStrip->objDesc.firstTMChange->new_tex_id);
}
}
}
if (cg.noseStrip != -1)
{
cg.noseStrip = max(0, min((int)scg->mNoseStripList.num_used - 1, cg.noseStrip));
FaceStrip_CG *faceStrip = &scg->mNoseStripList.array_data[cg.noseStrip];
if (faceStrip)
{
//weenie->m_ObjDesc += faceStrip->objDesc;
weenie->m_Qualities.SetDataID(DEFAULT_NOSE_TEXTURE_DID, faceStrip->objDesc.firstTMChange->old_tex_id);
weenie->m_Qualities.SetDataID(NOSE_TEXTURE_DID, faceStrip->objDesc.firstTMChange->new_tex_id);
}
}
if (cg.mouthStrip != -1)
{
cg.mouthStrip = max(0, min((int)scg->mMouthStripList.num_used - 1, cg.mouthStrip));
FaceStrip_CG *faceStrip = &scg->mMouthStripList.array_data[cg.mouthStrip];
if (faceStrip)
{
// weenie->m_ObjDesc += faceStrip->objDesc;
weenie->m_Qualities.SetDataID(DEFAULT_MOUTH_TEXTURE_DID, faceStrip->objDesc.firstTMChange->old_tex_id);
weenie->m_Qualities.SetDataID(MOUTH_TEXTURE_DID, faceStrip->objDesc.firstTMChange->new_tex_id);
}
}
PalSet *ps;
if (ps = PalSet::Get(scg->skinPalSet))
{
uint32_t skinPalette = ps->GetPaletteID(cg.skinShade);
weenie->m_Qualities.SetDataID(SKIN_PALETTE_DID, skinPalette);
//weenie->m_ObjDesc.AddSubpalette(new Subpalette(skinPalette, 0 << 3, 0x18 << 3));
PalSet::Release(ps);
}
cg.hairColor = max(0, min((int)scg->mHairColorList.num_used - 1, cg.hairColor));
if (ps = PalSet::Get(scg->mHairColorList.array_data[cg.hairColor]))
{
uint32_t hairPalette = ps->GetPaletteID(cg.hairShade);
weenie->m_Qualities.SetDataID(HAIR_PALETTE_DID, hairPalette);
//weenie->m_ObjDesc.AddSubpalette(new Subpalette(hairPalette, 0x18 << 3, 0x8 << 3));
PalSet::Release(ps);
}
if (cg.eyeColor != -1)
{
cg.eyeColor = max(0, min((int)scg->mEyeColorList.num_used - 1, cg.eyeColor));
uint32_t eyesPalette = scg->mEyeColorList.array_data[cg.eyeColor];
weenie->m_Qualities.SetDataID(EYES_PALETTE_DID, eyesPalette);
//weenie->m_ObjDesc.AddSubpalette(new Subpalette(eyesPalette, 0x20 << 3, 0x8 << 3));
}
/*
EYES_TEXTURE_DID,
NOSE_TEXTURE_DID,
MOUTH_TEXTURE_DID,
DEFAULT_EYES_TEXTURE_DID,
DEFAULT_NOSE_TEXTURE_DID,
DEFAULT_MOUTH_TEXTURE_DID,
HAIR_PALETTE_DID,
EYES_PALETTE_DID,
SKIN_PALETTE_DID,
HEAD_OBJECT_DID,
*/
}
}
for (uint32_t i = 0; i < cg.numSkills; i++)
{
weenie->m_Qualities.SetSkillAdvancementClass(SkillTable::OldToNewSkill((STypeSkill)i), cg.skillAdvancementClasses[i]);
if (cg.skillAdvancementClasses[i] == SKILL_ADVANCEMENT_CLASS::SPECIALIZED_SKILL_ADVANCEMENT_CLASS)
weenie->m_Qualities.SetSkillLevel((STypeSkill)i, 10);
else if (cg.skillAdvancementClasses[i] == SKILL_ADVANCEMENT_CLASS::TRAINED_SKILL_ADVANCEMENT_CLASS)
{
Skill trained;
weenie->m_Qualities.InqSkill((STypeSkill)i, trained);
trained._init_level = 0;
trained._level_from_pp = 5;
trained._pp = 526;
weenie->m_Qualities.SetSkill((STypeSkill)i, trained);
}
}
time_t t = chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::stringstream ss;
ss << std::put_time(std::localtime(&t), "%m/%d/%y %I:%M:%S %p."); // convert time to a string of format '01/01/18 11:59:59 AM.'
std::string str = ss.str();
weenie->m_Qualities.SetInt(CREATION_TIMESTAMP_INT, t);
weenie->m_Qualities.SetString(DATE_OF_BIRTH_STRING, ss.str());
weenie->m_Qualities.SetInt(AGE_INT, 0);
if (weenie->m_Qualities.GetInt(HERITAGE_GROUP_INT, 0) == Lugian_HeritageGroup)
weenie->m_Qualities.SetDataID(MOTION_TABLE_DID, 0x9000216);
/*
cg.startArea = max(0, min(cgd->mStartAreaList.num_used - 1, cg.startArea));
assert(cgd->mStartAreaList.array_data[cg.startArea].mPositionList.num_used >= 1);
startPos = cgd->mStartAreaList.array_data[cg.startArea].mPositionList.array_data[0];
weenie->SetInitialPosition(startPos);
*/
startPos = Position(0xA9B00006, Vector(24.258204f, 123.777000f, 63.060749f), Quaternion(1, 0, 0, 0)); // holtburg
switch (cg.startArea)
{
default:
case 0:
// Holtburg
startPos = Position(g_pConfig->HoltburgStartPosition());
if (!startPos.objcell_id)
{
startPos = Position(0x870301AD, Vector(12.319900f, -28.482000f, 0.005000f), Quaternion(0.315322f, 0, 0, 0.948985f));
//startPos = Position(0xA9B00006, Vector(24.258204f, 123.777000f, 63.060749f), Quaternion(1, 0, 0, 0));
weenie->m_Qualities.SetBool(RECALLS_DISABLED_BOOL, 1); // Cannot use recalls out of the training academy.
}
break;
case 1:
// Shoushi
startPos = Position(g_pConfig->ShoushiStartPosition());
if (!startPos.objcell_id)
{
startPos = Position(0x800401AD, Vector(12.319900f, -28.482000f, 0.005000f), Quaternion(0.315322f, 0.0, 0.0, 0.948985f));
//startPos = Position(0xDE51000C, Vector(26.712753f, 89.279999f, 17.778936f), Quaternion(0.931082f, 0.0, 0.0, -0.364811f));
weenie->m_Qualities.SetBool(RECALLS_DISABLED_BOOL, 1);
}
break;
case 2:
// Yaraq
startPos = Position(g_pConfig->YaraqStartPosition());
if (!startPos.objcell_id)
{
startPos = Position(0x8C0401AD, Vector(12.319900f, -28.482000f, 0.005000f), Quaternion(0.315322f, 0.0, 0.0, 0.948985f));
//startPos = Position(0x7D680019, Vector(79.102280f, 19.573767f, 12.821287f), Quaternion(-0.656578f, 0.0, 0.0, 0.754258f));
weenie->m_Qualities.SetBool(RECALLS_DISABLED_BOOL, 1);
}
break;
case 3:
// Sanamar
startPos = Position(g_pConfig->SanamarStartPosition());
if (!startPos.objcell_id)
{
startPos = Position(0x7203026C, Vector(11.66688f, -28.831614f, 0.005f), Quaternion(0, 0, 0, 1.0f));
//startPos = Position(0xA9B00006, Vector(24.258204f, 123.777000f, 63.060749f), Quaternion(1, 0, 0, 0));
weenie->m_Qualities.SetBool(RECALLS_DISABLED_BOOL, 1);
}
break;
case 4:
// Olthoi Island
startPos = Position(g_pConfig->OlthoiStartPosition());
if (!startPos.objcell_id)
{
startPos = Position(0xE6D3000E, Vector(40.57f, 138.16f, 218.00f), Quaternion(0, 0, 0, 1));
}
break;
}
weenie->SetInitialPosition(startPos);
weenie->m_Qualities.SetPosition(SANCTUARY_POSITION, startPos);
weenie->m_Qualities.SetInt(AVAILABLE_SKILL_CREDITS_INT, 52 - max(0, min(52, numCreditsUsed)));
weenie->m_Qualities.SetInt(CONTAINERS_CAPACITY_INT, 7);
weenie->SetMaxVitals(false);
weenie->m_Qualities._create_list->clear(); //Clear the create list as we don't want what's in it.
if (!g_pWorld->CreateEntity(weenie))
return;; //Briefly add the weenie to the world so we don't get errors when adding the starting gear.
//add starter gear
GenerateStarterGear(weenie, cg, scg);
// Set Olthoi starting stats/skills
if (cg.heritageGroup == Olthoi_HeritageGroup)
{
weenie->m_Qualities.SetInt(LEVEL_INT, 180);
weenie->m_Qualities.SetAttribute(STRENGTH_ATTRIBUTE, 350);
weenie->m_Qualities.SetAttribute(ENDURANCE_ATTRIBUTE, 350);
weenie->m_Qualities.SetAttribute(COORDINATION_ATTRIBUTE, 300);
weenie->m_Qualities.SetAttribute(QUICKNESS_ATTRIBUTE, 350);
weenie->m_Qualities.SetAttribute(FOCUS_ATTRIBUTE, 200);
weenie->m_Qualities.SetAttribute(SELF_ATTRIBUTE, 200);
weenie->m_Qualities.SetAttribute2nd(HEALTH_ATTRIBUTE_2ND, 325);
weenie->m_Qualities.SetAttribute2nd(STAMINA_ATTRIBUTE_2ND, 325);
weenie->m_Qualities.SetInt(PLAYER_KILLER_STATUS_INT, PK_PKStatus); // Olthoi are always Red
}
if (cg.heritageGroup == OlthoiAcid_HeritageGroup)
{
weenie->m_Qualities.SetInt(LEVEL_INT, 180);
weenie->m_Qualities.SetAttribute(STRENGTH_ATTRIBUTE, 200);
weenie->m_Qualities.SetAttribute(ENDURANCE_ATTRIBUTE, 200);
weenie->m_Qualities.SetAttribute(COORDINATION_ATTRIBUTE, 300);
weenie->m_Qualities.SetAttribute(QUICKNESS_ATTRIBUTE, 250);
weenie->m_Qualities.SetAttribute(FOCUS_ATTRIBUTE, 400);
weenie->m_Qualities.SetAttribute(SELF_ATTRIBUTE, 400);
weenie->m_Qualities.SetAttribute2nd(HEALTH_ATTRIBUTE_2ND, 400);
weenie->m_Qualities.SetAttribute2nd(STAMINA_ATTRIBUTE_2ND, 400);
weenie->m_Qualities.SetAttribute2nd(MANA_ATTRIBUTE_2ND, 400);
weenie->m_Qualities.SetInt(PLAYER_KILLER_STATUS_INT, PK_PKStatus); // Olthoi are always Red
}
// add racial augmentations
switch (cg.heritageGroup)
{
case Shadowbound_HeritageGroup:
case Penumbraen_HeritageGroup:
weenie->m_Qualities.SetInt(AUGMENTATION_CRITICAL_EXPERTISE_INT, 1); break;
case Gearknight_HeritageGroup:
weenie->m_Qualities.SetInt(AUGMENTATION_DAMAGE_REDUCTION_INT, 1); break;
case Tumerok_HeritageGroup:
weenie->m_Qualities.SetInt(AUGMENTATION_CRITICAL_POWER_INT, 1); break;
case Lugian_HeritageGroup:
weenie->m_Qualities.SetInt(AUGMENTATION_INCREASED_CARRYING_CAPACITY_INT, 1); break;
case Empyrean_HeritageGroup:
weenie->m_Qualities.SetInt(AUGMENTATION_INFUSED_LIFE_MAGIC_INT, 1); break;
case Undead_HeritageGroup:
weenie->m_Qualities.SetInt(AUGMENTATION_CRITICAL_DEFENSE_INT, 1); break;
case Olthoi_HeritageGroup:
case OlthoiAcid_HeritageGroup:
break; // none
default: // sho, aluv, gharu, viamont
weenie->m_Qualities.SetInt(AUGMENTATION_JACK_OF_ALL_TRADES_INT, 1); break;
}
weenie->Save();
g_pWorld->RemoveEntity(weenie);
//delete weenie; //RemoveEntity already performs the deletion.
BinaryWriter response;
response.Write<uint32_t>(0xF643);
response.Write<uint32_t>(1);
response.Write<uint32_t>(newCharacterGUID);
response.WriteString(cg.name.c_str());
response.Write<uint32_t>(0);
SendNetMessage(response.GetData(), response.GetSize(), PRIVATE_MSG);
}
else
{
SERVER_ERROR << "Failed to create character.";
badData(CG_VERIFICATION_RESPONSE_DATABASE_DOWN);
}
}
else
{
SERVER_INFO << "Character name already exists.";
badData(CG_VERIFICATION_RESPONSE_NAME_IN_USE);
}
}
return;
}
void CClient::GenerateStarterGear(CWeenieObject *weenieObject, ACCharGenResult &cg, Sex_CG *scg)
{
if (!weenieObject)
return;
CMonsterWeenie *weenie = weenieObject->AsMonster();
if (weenie == NULL)
return;
if (cg.heritageGroup != Gearknight_HeritageGroup && cg.heritageGroup < 12) // Gearknights and olthoi don't get clothes to start.
{
if (cg.headgearStyle != UINT_MAX)
weenie->SpawnWielded(cg.headgearStyle, scg->mHeadgearList, cg.headgearColor, scg->mClothingColorsList, cg.headgearShade);
weenie->SpawnWielded(cg.shirtStyle, scg->mShirtList, cg.shirtColor, scg->mClothingColorsList, cg.shirtShade);
weenie->SpawnWielded(cg.trousersStyle, scg->mPantsList, cg.trousersColor, scg->mClothingColorsList, cg.trousersShade);
weenie->SpawnWielded(cg.footwearStyle, scg->mFootwearList, cg.footwearColor, scg->mClothingColorsList, cg.footwearShade);
}
if (cg.heritageGroup < 12) // Olthoi get their own set of starting items.
{
//weenie->m_Qualities.SetInt(COIN_VALUE_INT, GetAccessLevel() >= ADMIN_ACCESS ? 500000000 : 10000);
weenie->SpawnInContainer(W_COINSTACK_CLASS, 500);
weenie->SpawnInContainer(W_TUTORIALBOOK_CLASS, 1);
weenie->SpawnInContainer(W_TINKERINGTOOL_CLASS, 1);
weenie->SpawnInContainer(W_SACK_CLASS, 1);
weenie->SpawnInContainer(W_CALLINGSTONE_CLASS, 1);
weenie->SpawnInContainer(33613, 1); // Pathwarden Token
}
weenie->SpawnInContainer(31000, 1); // Blackmoor's Favor
CContainerWeenie *sack = weenie;
for (auto pack : weenie->m_Packs)
{
if (pack->AsContainer())
{
sack = pack->AsContainer();
break;
}
}
weenie->RecalculateCoinAmount(W_COINSTACK_CLASS);
// heritage items regardless of skill
switch (cg.heritageGroup)
{
case Invalid_HeritageGroup:
case Aluvian_HeritageGroup:
weenie->SpawnInContainer(W_NOTELETTERGREETINGALU_CLASS);
weenie->SpawnInContainer(W_BREAD_CLASS, 1);
break;
case Gharundim_HeritageGroup:
weenie->SpawnInContainer(W_NOTELETTERGREETINGGHA_CLASS);
weenie->SpawnInContainer(W_CHEESE_CLASS, 1);
break;
case Sho_HeritageGroup:
weenie->SpawnInContainer(W_NOTELETTERGREETINGSHO_CLASS);
break;
case Viamontian_HeritageGroup:
weenie->SpawnInContainer(W_NOTELETTERGREETINGVIA_CLASS);
break;
case Olthoi_HeritageGroup:
weenie->SpawnInContainer(43701, 1); // Olthoi Fibrous Healing Tissue
weenie->SpawnInContainer(43634, 10); // Acidic Infusions
case OlthoiAcid_HeritageGroup:
weenie->SpawnInContainer(43701, 1); // Olthoi Fibrous Healing Tissue
weenie->SpawnInContainer(43634, 10); // Acidic Infusions
weenie->SpawnInContainer(43489, 1); // Salivatory Goo
weenie->SpawnInContainer(43637, 100); // Saliva Invigorator
weenie->SpawnInContainer(W_PACKWARESSENCE_CLASS, 1);
break;
case Penumbraen_HeritageGroup:
weenie->SpawnInContainer(W_NOTELETTERGREETINGSHA_CLASS);
break;
case Shadowbound_HeritageGroup:
weenie->SpawnInContainer(W_NOTELETTERGREETINGSHA_CLASS);
break;
case Gearknight_HeritageGroup:
weenie->SpawnInContainer(W_NOTELETTERGREETINGGEA_CLASS);
weenie->SpawnInContainer(43022, 1); // Core Plating Deintegrator
weenie->SpawnInContainer(42979, 1); // Core Plating Integrator
default:
weenie->SpawnInContainer(W_APPLE_CLASS, 1);
break;
}
if (cg.numSkills <= 0)
return;
if (cg.trained(ALCHEMY_SKILL))
weenie->SpawnInContainer(W_MORTARANDPESTLE_CLASS, 1);
if (cg.specialized(ALCHEMY_SKILL))
weenie->SpawnInContainer(W_GEMAZURITE_CLASS, 3);
if (cg.trained(COOKING_SKILL))
{
weenie->SpawnInContainer(W_FLOUR_CLASS, 6);
weenie->SpawnInContainer(W_WATER_CLASS, 6);
}
if (cg.trained(FLETCHING_SKILL))
{
weenie->SpawnInContainer(W_ARROWHEAD_CLASS, 30);
weenie->SpawnInContainer(W_ARROWSHAFT_CLASS, 30);
}
if (cg.trained(HEALING_SKILL))
weenie->SpawnInContainer(W_HEALINGKITCRUDE_CLASS, 1);
if (cg.specialized(HEALING_SKILL))
weenie->SpawnInContainer(W_HEALINGKITCRUDE_CLASS, 1);
if (cg.trained(LOCKPICK_SKILL))
weenie->SpawnInContainer(W_LOCKPICKCRUDE_CLASS, 1);
if (cg.trained(ITEM_APPRAISAL_SKILL) ||
cg.trained(ARMOR_APPRAISAL_SKILL) ||
cg.trained(WEAPON_APPRAISAL_SKILL) ||
cg.trained(MAGIC_ITEM_APPRAISAL_SKILL))
{
weenie->SpawnInContainer(W_TINKERINGTOOL_CLASS, 1);
}
switch (cg.heritageGroup)
{
case Invalid_HeritageGroup:
case Aluvian_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGDAGGER_CLASS, 1);
if (cg.trained(TWO_HANDED_COMBAT_SKILL))
weenie->SpawnInContainer(W_TRAININGSPADONE_CLASS, 1);
if (cg.trained(MISSILE_WEAPONS_SKILL))
{
weenie->SpawnInContainer(W_BOWTRAINING_CLASS, 1);
weenie->SpawnInContainer(W_ARROW_CLASS, 30);
}
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_DAGGERTRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGKNIFE_CLASS, 1);
if (cg.trained(CREATURE_ENCHANTMENT_SKILL) ||
cg.trained(ITEM_ENCHANTMENT_SKILL) ||
cg.trained(LIFE_MAGIC_SKILL) ||
cg.trained(WAR_MAGIC_SKILL) ||
cg.trained(VOID_MAGIC_SKILL))
weenie->SpawnInContainer(W_WANDTRAINING_CLASS, 1);
break;
case Gharundim_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGSTAFF_CLASS, 1);
if (cg.trained(TWO_HANDED_COMBAT_SKILL))
weenie->SpawnInContainer(W_TRAININGSPADONE_CLASS, 1);
if (cg.trained(MISSILE_WEAPONS_SKILL))
{
weenie->SpawnInContainer(W_BOWTRAINING_CLASS, 1);
weenie->SpawnInContainer(W_ARROW_CLASS, 30);
}
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_STAFFTRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGBASTONE_CLASS, 1);
if (cg.trained(CREATURE_ENCHANTMENT_SKILL) ||
cg.trained(ITEM_ENCHANTMENT_SKILL) ||
cg.trained(LIFE_MAGIC_SKILL) ||
cg.trained(WAR_MAGIC_SKILL) ||
cg.trained(VOID_MAGIC_SKILL))
weenie->SpawnInContainer(W_WANDTRAINING_CLASS, 1);
break;
case Sho_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGKNUCKLES_CLASS, 1);
if (cg.trained(TWO_HANDED_COMBAT_SKILL))
weenie->SpawnInContainer(W_TRAININGSPADONE_CLASS, 1);
if (cg.trained(MISSILE_WEAPONS_SKILL))
{
weenie->SpawnInContainer(W_BOWTRAINING_CLASS, 1);
weenie->SpawnInContainer(W_ARROW_CLASS, 30);
}
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_CESTUSTRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGHANDWRAPS_CLASS, 1);
if (cg.trained(CREATURE_ENCHANTMENT_SKILL) ||
cg.trained(ITEM_ENCHANTMENT_SKILL) ||
cg.trained(LIFE_MAGIC_SKILL) ||
cg.trained(WAR_MAGIC_SKILL) ||
cg.trained(VOID_MAGIC_SKILL))
weenie->SpawnInContainer(W_WANDTRAINING_CLASS, 1);
break;
case Viamontian_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGBROADSWORD_CLASS, 1);
if (cg.trained(TWO_HANDED_COMBAT_SKILL))
weenie->SpawnInContainer(W_TRAININGSPADONE_CLASS, 1);
if (cg.trained(MISSILE_WEAPONS_SKILL))
{
weenie->SpawnInContainer(W_BOWTRAINING_CLASS, 1);
weenie->SpawnInContainer(W_ARROW_CLASS, 30);
}
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_SWORDTRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGSHORTSWORD_CLASS, 1);
if (cg.trained(CREATURE_ENCHANTMENT_SKILL) ||
cg.trained(ITEM_ENCHANTMENT_SKILL) ||
cg.trained(LIFE_MAGIC_SKILL) ||
cg.trained(WAR_MAGIC_SKILL) ||
cg.trained(VOID_MAGIC_SKILL))
weenie->SpawnInContainer(W_WANDTRAINING_CLASS, 1);
break;
case Lugian_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGCLUB_CLASS, 1);
if (cg.trained(TWO_HANDED_COMBAT_SKILL))
weenie->SpawnInContainer(W_TRAININGSPADONE_CLASS, 1);
if (cg.trained(MISSILE_WEAPONS_SKILL))
{
weenie->SpawnInContainer(W_BOWTRAINING_CLASS, 1);
weenie->SpawnInContainer(W_ARROW_CLASS, 30);
}
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_MACETRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGDABUS_CLASS, 1);
if (cg.trained(CREATURE_ENCHANTMENT_SKILL) ||
cg.trained(ITEM_ENCHANTMENT_SKILL) ||
cg.trained(LIFE_MAGIC_SKILL) ||
cg.trained(WAR_MAGIC_SKILL) ||
cg.trained(VOID_MAGIC_SKILL))
weenie->SpawnInContainer(W_WANDTRAINING_CLASS, 1);
break;
case Tumerok_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGSPEAR_CLASS, 1);
if (cg.trained(TWO_HANDED_COMBAT_SKILL))
weenie->SpawnInContainer(W_TRAININGSPADONE_CLASS, 1);
if (cg.trained(MISSILE_WEAPONS_SKILL))
{
weenie->SpawnInContainer(W_BOWTRAINING_CLASS, 1);
weenie->SpawnInContainer(W_ARROW_CLASS, 30);
}
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_SPEARTRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGBUDIAQ_CLASS, 1);
if (cg.trained(CREATURE_ENCHANTMENT_SKILL) ||
cg.trained(ITEM_ENCHANTMENT_SKILL) ||
cg.trained(LIFE_MAGIC_SKILL) ||
cg.trained(WAR_MAGIC_SKILL) ||
cg.trained(VOID_MAGIC_SKILL))
weenie->SpawnInContainer(W_WANDTRAINING_CLASS, 1);
break;
case Empyrean_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGBROADSWORD_CLASS, 1);
if (cg.trained(TWO_HANDED_COMBAT_SKILL))
weenie->SpawnInContainer(W_TRAININGSPADONE_CLASS, 1);
if (cg.trained(MISSILE_WEAPONS_SKILL))
{
weenie->SpawnInContainer(W_BOWTRAINING_CLASS, 1);
weenie->SpawnInContainer(W_ARROW_CLASS, 30);
}
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_SWORDTRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGSHORTSWORD_CLASS, 1);
if (cg.trained(CREATURE_ENCHANTMENT_SKILL) ||
cg.trained(ITEM_ENCHANTMENT_SKILL) ||
cg.trained(LIFE_MAGIC_SKILL) ||
cg.trained(WAR_MAGIC_SKILL) ||
cg.trained(VOID_MAGIC_SKILL))
weenie->SpawnInContainer(W_WANDTRAINING_CLASS, 1);
break;
case Undead_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGHANDAXE_CLASS, 1);
if (cg.trained(TWO_HANDED_COMBAT_SKILL))
weenie->SpawnInContainer(W_TRAININGSPADONE_CLASS, 1);
if (cg.trained(MISSILE_WEAPONS_SKILL))
{
weenie->SpawnInContainer(W_BOWTRAINING_CLASS, 1);
weenie->SpawnInContainer(W_ARROW_CLASS, 30);
}
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_AXETRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGTUNGI_CLASS, 1);
if (cg.trained(CREATURE_ENCHANTMENT_SKILL) ||
cg.trained(ITEM_ENCHANTMENT_SKILL) ||
cg.trained(LIFE_MAGIC_SKILL) ||
cg.trained(WAR_MAGIC_SKILL) ||
cg.trained(VOID_MAGIC_SKILL))
weenie->SpawnInContainer(W_WANDTRAINING_CLASS, 1);
break;
case Gearknight_HeritageGroup:
weenie->SpawnInContainer(W_APPLE_CLASS, 1);
weenie->SpawnInContainer(43022, 1); // Core Plating Deintegrator
weenie->SpawnInContainer(42979, 1); // Core Plating Integrator
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGCLUB_CLASS, 1);
if (cg.trained(TWO_HANDED_COMBAT_SKILL))
weenie->SpawnInContainer(W_TRAININGSPADONE_CLASS, 1);
if (cg.trained(MISSILE_WEAPONS_SKILL))
{
weenie->SpawnInContainer(W_BOWTRAINING_CLASS, 1);
weenie->SpawnInContainer(W_ARROW_CLASS, 30);
}
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_MACETRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGDABUS_CLASS, 1);
if (cg.trained(CREATURE_ENCHANTMENT_SKILL) ||
cg.trained(ITEM_ENCHANTMENT_SKILL) ||
cg.trained(LIFE_MAGIC_SKILL) ||
cg.trained(WAR_MAGIC_SKILL) ||
cg.trained(VOID_MAGIC_SKILL))
weenie->SpawnInContainer(W_WANDTRAINING_CLASS, 1);
break;
case Penumbraen_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGKNUCKLES_CLASS, 1);
if (cg.trained(TWO_HANDED_COMBAT_SKILL))
weenie->SpawnInContainer(W_TRAININGSPADONE_CLASS, 1);
if (cg.trained(MISSILE_WEAPONS_SKILL))
{
weenie->SpawnInContainer(W_BOWTRAINING_CLASS, 1);
weenie->SpawnInContainer(W_ARROW_CLASS, 30);
}
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_CESTUSTRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGHANDWRAPS_CLASS, 1);
if (cg.trained(CREATURE_ENCHANTMENT_SKILL) ||
cg.trained(ITEM_ENCHANTMENT_SKILL) ||
cg.trained(LIFE_MAGIC_SKILL) ||
cg.trained(WAR_MAGIC_SKILL) ||
cg.trained(VOID_MAGIC_SKILL))
weenie->SpawnInContainer(W_WANDTRAINING_CLASS, 1);
break;
case Shadowbound_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGKNUCKLES_CLASS, 1);
if (cg.trained(TWO_HANDED_COMBAT_SKILL))
weenie->SpawnInContainer(W_TRAININGSPADONE_CLASS, 1);
if (cg.trained(MISSILE_WEAPONS_SKILL))
{
weenie->SpawnInContainer(W_BOWTRAINING_CLASS, 1);
weenie->SpawnInContainer(W_ARROW_CLASS, 30);
}
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_CESTUSTRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGHANDWRAPS_CLASS, 1);
if (cg.trained(CREATURE_ENCHANTMENT_SKILL) ||
cg.trained(ITEM_ENCHANTMENT_SKILL) ||
cg.trained(LIFE_MAGIC_SKILL) ||
cg.trained(WAR_MAGIC_SKILL) ||
cg.trained(VOID_MAGIC_SKILL))
weenie->SpawnInContainer(W_WANDTRAINING_CLASS, 1);
break;
}
if (cg.trained(CREATURE_ENCHANTMENT_SKILL) || cg.trained(ITEM_ENCHANTMENT_SKILL) || cg.trained(LIFE_MAGIC_SKILL) || cg.trained(WAR_MAGIC_SKILL) || cg.trained(VOID_MAGIC_SKILL))
{
sack->SpawnInContainer(W_SCARABLEAD_CLASS, 5);
weenie->SpawnInContainer(W_TAPERPRISMATIC_CLASS, 25);
}
if (cg.trained(CREATURE_ENCHANTMENT_SKILL))
{
weenie->m_Qualities.AddSpell(FocusSelf1_SpellID);
weenie->m_Qualities.AddSpell(InvulnerabilityOther1_SpellID);
weenie->m_Qualities.AddSpell(InvulnerabilitySelf1_SpellID);
weenie->SpawnInContainer(W_PACKCREATUREESSENCE_CLASS, 1);
}
if (cg.specialized(CREATURE_ENCHANTMENT_SKILL))
{
weenie->m_Qualities.AddSpell(FocusSelf1_SpellID);
weenie->m_Qualities.AddSpell(ManaMasterySelf1_SpellID);
weenie->m_Qualities.AddSpell(WillpowerSelf1_SpellID);
}
if (cg.trained(ITEM_ENCHANTMENT_SKILL))
{
weenie->m_Qualities.AddSpell(BloodDrinker1_SpellID);
weenie->m_Qualities.AddSpell(BludgeonBane1_SpellID);
weenie->m_Qualities.AddSpell(Impenetrability1_SpellID);
weenie->m_Qualities.AddSpell(SwiftKiller1_SpellID);
weenie->SpawnInContainer(W_PACKITEMESSENCE_CLASS, 1);
}
if (cg.specialized(ITEM_ENCHANTMENT_SKILL))
{
weenie->m_Qualities.AddSpell(Defender1_SpellID);
weenie->m_Qualities.AddSpell(Impenetrability1_SpellID);
}
if (cg.trained(LIFE_MAGIC_SKILL))
{
weenie->m_Qualities.AddSpell(ArmorOther1_SpellID);
weenie->m_Qualities.AddSpell(ArmorSelf1_SpellID);
weenie->m_Qualities.AddSpell(HealOther1_SpellID);
weenie->m_Qualities.AddSpell(HealSelf1_SpellID);
weenie->m_Qualities.AddSpell(ImperilOther1_SpellID);
if (cg.heritageGroup != Empyrean_HeritageGroup) // Empyreans get the Life magic aug on creation
weenie->SpawnInContainer(W_PACKLIFEESSENCE_CLASS, 1);
}
if (cg.specialized(LIFE_MAGIC_SKILL))
{
weenie->m_Qualities.AddSpell(DrainHealth1_SpellID);
weenie->m_Qualities.AddSpell(HarmOther1_SpellID);
}
if (cg.trained(WAR_MAGIC_SKILL))
{
weenie->m_Qualities.AddSpell(FlameBolt1_SpellID);
weenie->m_Qualities.AddSpell(ForceBolt1_SpellID);
weenie->m_Qualities.AddSpell(FrostBolt1_SpellID);
weenie->m_Qualities.AddSpell(ShockWave1_SpellID);
weenie->SpawnInContainer(W_PACKWARESSENCE_CLASS, 1);
}
if (cg.specialized(WAR_MAGIC_SKILL))
{
weenie->m_Qualities.AddSpell(LightningBolt1_SpellID);
weenie->m_Qualities.AddSpell(WhirlingBlade1_SpellID);
weenie->m_Qualities.AddSpell(AcidStream1_SpellID);
}
if (cg.trained(VOID_MAGIC_SKILL))
{
weenie->m_Qualities.AddSpell(netherbolt1_SpellID);
weenie->m_Qualities.AddSpell(CurseDestructionOther1_SpellID);
weenie->m_Qualities.AddSpell(FesterOther1_SpellID);
weenie->SpawnInContainer(43173, 1);
}
if (cg.specialized(VOID_MAGIC_SKILL))
{
weenie->m_Qualities.AddSpell(Corrosion1_SpellID);
weenie->m_Qualities.AddSpell(Corruption1_SpellID);
weenie->m_Qualities.AddSpell(CurseWeakness1_SpellID);
}
if (cg.trained(DUAL_WIELD_SKILL))
{
switch (cg.heritageGroup)
{
case Default:
case Aluvian_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGDAGGER_CLASS, 1);
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_DAGGERTRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGKNIFE_CLASS, 1);
break;
case Gharundim_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGSTAFF_CLASS, 1);
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_STAFFTRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGBASTONE_CLASS, 1);
break;
case Penumbraen_HeritageGroup:
case Shadowbound_HeritageGroup:
case Sho_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGKNUCKLES_CLASS, 1);
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_CESTUSTRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGHANDWRAPS_CLASS, 1);
break;
case Empyrean_HeritageGroup:
case Viamontian_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGBROADSWORD_CLASS, 1);
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_SWORDTRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGSHORTSWORD_CLASS, 1);
break;
case Gearknight_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGCLUB_CLASS, 1);
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_MACETRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGDABUS_CLASS, 1);
break;
case Tumerok_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGSPEAR_CLASS, 1);
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_SPEARTRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGBUDIAQ_CLASS, 1);
break;
case Lugian_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGCLUB_CLASS, 1);
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_MACETRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGDABUS_CLASS, 1);
break;
case Undead_HeritageGroup:
if (cg.trained(LIGHT_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGHANDAXE_CLASS, 1);
if (cg.trained(HEAVY_WEAPONS_SKILL))
weenie->SpawnInContainer(W_AXETRAINING_CLASS, 1);
if (cg.trained(FINESSE_WEAPONS_SKILL))
weenie->SpawnInContainer(W_TRAININGTUNGI_CLASS, 1);
break;
case Olthoi_HeritageGroup:
case OlthoiAcid_HeritageGroup:
break; // none
}
}
}
void CClient::SendLandblock(uint32_t dwFileID)
{
TURBINEFILE* pLandData = g_pCell->GetFile(dwFileID);
if (!pLandData)
{
if (m_pEvents)
{
m_pEvents->SendText(csprintf("Your client is requesting cell data (0x%08X) that this server does not have!", dwFileID), LTT_DEFAULT);
m_pEvents->SendText("If you are stuck in portal mode, type /render radius 5 to escape. The server administrator should reconfigure the server with a FULL cell.dat file!", LTT_DEFAULT);
}
return;
}
if ((dwFileID & 0xFFFF) != 0xFFFF)
{
SERVER_WARN << "Client requested Landblock" << dwFileID << "-should end pReader 0xFFFF";
}
if (pLandData)
{
BinaryWriter BlockPackage;
BlockPackage.Write<uint32_t>(0xF7E2);
uint32_t dwFileSize = pLandData->GetLength();
BYTE* pbFileData = pLandData->GetData();
uLongf dwPackageSize = (uint32_t)((dwFileSize * 1.02f) + 12 + 1);
BYTE* pbPackageData = new BYTE[dwPackageSize];
if (Z_OK != compress2(pbPackageData, &dwPackageSize, pbFileData, dwFileSize, Z_BEST_COMPRESSION))
{
SERVER_ERROR << "Error compressing LandBlock package!";
}
BlockPackage.Write<uint32_t>(1); //the resource type: 1 for 0xFFFF, 2 for 0xFFFE, 3 for 0x100
BlockPackage.Write<uint32_t>(2); //1 = client_portal / 2 = client_cell_1 / 3 = client_local_English
BlockPackage.Write<uint32_t>(1); //?
BlockPackage.Write<uint32_t>(dwFileID); //the resource ID number
BlockPackage.Write<uint32_t>(1); //the file version number
BlockPackage.Write<BYTE>(1); // 0 = uncompressed / 1 = compressed
BlockPackage.Write<uint32_t>(2); //?
BlockPackage.Write<uint32_t>(dwPackageSize + sizeof(uint32_t) * 2); //the number of bytes required for the remainder of this message, including this uint32_t
BlockPackage.Write<uint32_t>(dwFileSize); //the size of the uncompressed file
BlockPackage.Write(pbPackageData, dwPackageSize); //bytes of zlib compressed file data
BlockPackage.Align();
delete[] pbPackageData;
delete pLandData;
SendNetMessage(BlockPackage.GetData(), BlockPackage.GetSize(), EVENT_MSG, FALSE);
}
}
void CClient::SendLandblockInfo(uint32_t dwFileID)
{
if ((dwFileID & 0xFFFF) != 0xFFFE)
{
SERVER_WARN << "Client requested LandblockInfo" << dwFileID << "should end pReader 0xFFFE";
return;
}
TURBINEFILE *pObjData = g_pCell->GetFile(dwFileID);
if (!pObjData)
{
return;
}
if (pObjData)
{
BinaryWriter BlockInfoPackage;
BlockInfoPackage.Write<uint32_t>(0xF7E2);
uint32_t dwFileSize = pObjData->GetLength();
BYTE* pbFileData = pObjData->GetData();
uLongf dwPackageSize = (uint32_t)((dwFileSize * 1.02f) + 12 + 1);
BYTE* pbPackageData = new BYTE[dwPackageSize];
if (Z_OK != compress2(pbPackageData, &dwPackageSize, pbFileData, dwFileSize, Z_BEST_COMPRESSION))
{
SERVER_ERROR << "Error compressing LandBlockInfo package!";
}
BlockInfoPackage.Write<uint32_t>(2); // 1 for 0xFFFF, 2 for 0xFFFE, 3 for 0x100
BlockInfoPackage.Write<uint32_t>(2);
BlockInfoPackage.Write<uint32_t>(1);
BlockInfoPackage.Write<uint32_t>(dwFileID);
BlockInfoPackage.Write<uint32_t>(1);
BlockInfoPackage.Write<BYTE>(1);
BlockInfoPackage.Write<uint32_t>(2);
BlockInfoPackage.Write<uint32_t>(dwPackageSize + sizeof(uint32_t) * 2);
BlockInfoPackage.Write<uint32_t>(dwFileSize);
BlockInfoPackage.Write(pbPackageData, dwPackageSize);
BlockInfoPackage.Align();
delete[] pbPackageData;
delete pObjData;
SendNetMessage(BlockInfoPackage.GetData(), BlockInfoPackage.GetSize(), EVENT_MSG, FALSE);
}
}
void CClient::SendLandcell(uint32_t dwFileID)
{
TURBINEFILE* pCellData = g_pCell->GetFile(dwFileID);
if (!pCellData)
{
if (m_pEvents)
{
m_pEvents->SendText(csprintf("Your client is requesting cell data (#%08X) that this server does not have!", dwFileID), LTT_DEFAULT);
m_pEvents->SendText("If you are stuck in portal mode, type /render radius 5 to escape. The server administrator should reconfigure the server with a FULL cell.dat file!", LTT_DEFAULT);
}
return;
}
if (pCellData)
{
BinaryWriter CellPackage;
CellPackage.Write<uint32_t>(0xF7E2);
uint32_t dwFileSize = pCellData->GetLength();
BYTE* pbFileData = pCellData->GetData();
uLongf dwPackageSize = (uint32_t)((dwFileSize * 1.02f) + 12 + 1);
BYTE* pbPackageData = new BYTE[dwPackageSize];
if (Z_OK != compress2(pbPackageData, &dwPackageSize, pbFileData, dwFileSize, Z_BEST_COMPRESSION))
{
// These are CEnvCell if I recall correctly
SERVER_ERROR << "Error compressing landcell package!";
}
CellPackage.Write<uint32_t>(3); // 1 for 0xFFFF, 2 for 0xFFFE, 3 for 0x100
CellPackage.Write<uint32_t>(2);
CellPackage.Write<uint32_t>(1);
CellPackage.Write<uint32_t>(dwFileID);
CellPackage.Write<uint32_t>(1);
CellPackage.Write<BYTE>(1);
CellPackage.Write<uint32_t>(2);
CellPackage.Write<uint32_t>(dwPackageSize + sizeof(uint32_t) * 2);
CellPackage.Write<uint32_t>(dwFileSize);
CellPackage.Write(pbPackageData, dwPackageSize);
CellPackage.Align();
delete[] pbPackageData;
delete pCellData;
//LOG(Temp, Normal, "Sent cell %08X ..\n", dwFileID);
SendNetMessage(CellPackage.GetData(), CellPackage.GetSize(), EVENT_MSG, FALSE);
}
//if (m_pEvents)
// m_pEvents->SendText(csprintf("The server has sent you cell #%04X!", dwFileID >> 16), LTT_DEFAULT);
}
void CClient::ProcessMessage(BYTE *data, uint32_t length, WORD group)
{
if (g_bDebugToggle)
{
NETWORK_DEBUG << "Received response(group" << group << ")";
NETWORK_DEBUG << data;
}
BinaryReader in(data, length);
uint32_t dwMessageCode = in.ReadUInt32();
#ifdef _DEBUG
// LOG(Client, Normal, "Processing response 0x%X (size %d):\n", dwMessageCode, length);
#endif
if (in.GetLastError())
{
NETWORK_ERROR << "Error processing response." << dwMessageCode;
return;
}
switch (dwMessageCode)
{
case 0xF653:
{
if (m_vars.bInWorld)
{
m_pEvents->ForceLogout();
}
break;
}
case 0xF655: // Delete Character
if (!m_vars.bInWorld)
{
DeleteCharacter(&in);
}
break;
case 0xF656: // Create Character
{
if (!m_vars.bInWorld)
{
CreateCharacter(&in);
}
break;
}
case 0xF7D9: // Restore Character
{
if (!m_vars.bInWorld)
{
RestoreCharacter(&in);
}
break;
}
case 0xF6EA: // Request Object
{
if (m_vars.bInWorld)
{
uint32_t dwEID = in.ReadUInt32();
if (in.GetLastError()) break;
CPlayerWeenie *pPlayer;
if ((m_pEvents) && (pPlayer = m_pEvents->GetPlayer()))
{
CWeenieObject *pTarget = g_pWorld->FindWithinPVS(pPlayer, dwEID);
if (pTarget)
pPlayer->MakeAware(pTarget, true);
else
{
pTarget = g_pWorld->FindObject(dwEID);
if (pTarget)
{
// LOG(Temp, Normal, "Player %s is requesting info on %s it shouldn't know about.\n", pPlayer->GetName().c_str(), pTarget->GetName().c_str());
}
}
}
}
break;
}
case 0xF7E6://DDD_InterrogationResponseMessage
{
uint32_t clientLanguage = in.ReadUInt32();
int32_t fileCount = in.ReadInt32();
bool allMatch = true;
for (int i = 0; i < fileCount; i++)
{
// file info contains
// int int <file 0xffff0001>
// dataset datasubset <file 0xffff0001>
int32_t ds = in.ReadInt32();
int32_t dss = in.ReadInt32();
BYTE *itr = in.GetDataPtr();
int match = 0;
in.SetOffset(in.GetOffset() + sizeof(int32_t) * 3);
switch (ds)
{
case 0:
// portal
if (dss == 1)
match = g_pPortal->CompareIteration(itr);
break;
case 1:
switch (dss)
{
case 2: // cell
match = g_pCell->CompareIteration(itr);
break;
case 3: // local_english
break;
}
break;
}
if (match != 0)
{
allMatch = false;
// NETWORK_DEBUG << "Client DAT Mismatch: " << ds << dss;
}
}
if (!allMatch)
{
// error with wrong version
GetPacketController()->SendCriticalError(ST_SERVER_ERRORS, STR_LOGIN_CLIENT_VERSION);
}
// ends with 0
//PackableList<uint32_t> fileIds;
//fileIds.UnPack(&in);
if (in.GetLastError())
break;
BinaryWriter EndDDD;
EndDDD.Write<int32_t>(0xF7EA);
SendNetMessage(EndDDD.GetData(), EndDDD.GetSize(), EVENT_MSG);
break;
}
case 0xF7EA: //DDD_OnEndDDD
{
//BinaryWriter EndDDD;
//EndDDD.Write<uint32_t>(0xF7EA);
//SendNetMessage(EndDDD.GetData(), EndDDD.GetSize(), EVENT_MSG);
break;
}
case 0xF7E3: //DDD_RequestDataMessage
{
if (m_vars.bInWorld)
{
uint32_t dwFileClass = in.ReadUInt32();
uint32_t dwFileID = in.ReadUInt32();
if (in.GetLastError()) break;
//disabled downloading files.
m_pEvents->SendText("Your client is requesting map data from the server. This feature is disabled to preserve bandwidth", LTT_DEFAULT);
m_pEvents->SendText("If you are stuck in portal mode, type /render radius 5 to escape. Make sure you are using the approppriate cell.dat file!", LTT_DEFAULT);
//switch (dwFileClass)
//{
//default:
// LOG(Client, Warning, "Unknown download request: %08X %d\n", dwFileID, dwFileClass);
// break;
//case 1:
//{
// SendLandblock(dwFileID); // 1 is landblock 0xFFFF
// break;
//}
//case 2:
// SendLandblockInfo(dwFileID); // 2 is landblock environemnt 0xFFFE
// break;
//case 3:
// SendLandcell(dwFileID); // 0x100+
// break;
//}
}
break;
}
case 0xF7B1:
{
//should check the sequence
if (m_vars.bInWorld)
{
m_pEvents->ProcessEvent(&in);
}
break;
}
case 0xF7C8:
{
if (!m_vars.bInWorld)
{
EnterWorld();
}
break;
}
case 0xF657:
{
if (m_vars.bInWorld)
{
uint32_t dwGUID = in.ReadUInt32();
char* szName = in.ReadString();
if (in.GetLastError()) break;
m_pEvents->LoginCharacter(dwGUID, /*szName*/GetAccount());
}
break;
}
// modified cmoski code
case 0xF7DE:
{ //Gets data from /general here to rebroadcast as a world message below \o/
uint32_t size = in.ReadUInt32();
uint32_t TurbineChatType = in.ReadUInt32(); //0x1 Inbound, 0x3 Outbound, 0x5 Outbound Ack
uint32_t unk1 = in.ReadUInt32();
uint32_t unk2 = in.ReadUInt32();
uint32_t unk3 = in.ReadUInt32();
uint32_t unk4 = in.ReadUInt32();
uint32_t unk5 = in.ReadUInt32();
uint32_t unk6 = in.ReadUInt32();
uint32_t payload = in.ReadUInt32();
if (in.GetLastError())
break;
if (TurbineChatType == 0x3) //0x3 Outbound
{
if (!m_pEvents->GetPlayer() || !m_pEvents->CheckForChatSpam())
break;
uint32_t serial = in.ReadUInt32(); // serial of this character's chat
uint32_t channel_unk = in.ReadUInt32();
uint32_t channel_unk2 = in.ReadUInt32();
uint32_t listening_channel = in.ReadUInt32(); // ListeningChannel in SetTurbineChatChannels (0x000BEEF0-9)
//std::string message = in.ReadWStringToString();
std::u16string message = in.ReadString16();
uint32_t payloadSize = in.ReadUInt32();
uint32_t playerGUID = in.ReadUInt32();
uint32_t ob_unknown = in.ReadUInt32(); //Always 0?
uint32_t ob_unknown2 = in.ReadUInt32();
std::u16string filteredText = FilterBadChatCharacters(message);
if (in.GetLastError() || !filteredText.size())
break;
BinaryWriter chatAck;
chatAck.Write<uint32_t>(0xF7DE);
chatAck.Write<uint32_t>(0x30); // Size
chatAck.Write<uint32_t>(0x05); // Type 05 - ACK
chatAck.Write<uint32_t>(0x02); // ??
chatAck.Write<uint32_t>(0x01); // ??
chatAck.Write<uint32_t>(0xB0045); // bitfield?
chatAck.Write<uint32_t>(0x01);
chatAck.Write<uint32_t>(0xB0045); // bitfield?
chatAck.Write<uint32_t>(0x00);
chatAck.Write<uint32_t>(0x10); // Payload size
chatAck.Write<uint32_t>(serial); // serial
chatAck.Write<uint32_t>(0x02);
chatAck.Write<uint32_t>(0x02);
chatAck.Write<uint32_t>(0x00);
SendNetMessage(&chatAck, 0x04, FALSE, FALSE);
if (filteredText.c_str()[0] == '!' || filteredText.c_str()[0] == '@' || filteredText.c_str()[0] == '/')
{
CommandBase::Execute((char*)filteredText.erase(0, 1).c_str(), m_pEvents->GetPlayer()->GetClient());
}
else
{
if (!m_pEvents->GetPlayer()->IsPlayerSquelched(playerGUID))
{
switch (listening_channel)
{
case General_ChatChannel:
case Trade_ChatChannel:
case LFG_ChatChannel:
case Roleplay_ChatChannel:
case Allegiance_ChatChannel:
// case Olthoi_ChatChannel:
// case Society_ChatChannel:
if (listening_channel > 1 && !g_pConfig->AllowGeneralChat())
break;
g_pWorld->BroadcastChatChannel(listening_channel, m_pEvents->GetPlayer(), filteredText);
break;
}
}
}
}
break;
}
default:
SERVER_INFO << "Unhandled response" << dwMessageCode << "from the client.";
break;
}
//if ( dwMessageCode != 0xF7B1 )
// LOG(Temp, Normal, "Received response %04X\n", dwMessageCode);
}
BOOL CClient::CheckAccount(const char* cmp)
{
return !stricmp(m_vars.account.c_str(), cmp);
}
int CClient::GetAccessLevel()
{
return m_AccountInfo.access;
}
void CClient::SetAccessLevel(unsigned int access)
{
m_AccountInfo.access = access;
}
BOOL CClient::CheckAddress(SOCKADDR_IN *peer)
{
return !memcmp(GetHostAddress(), peer, sizeof(SOCKADDR_IN));
}
WORD CClient::GetSlot()
{
return m_vars.slot;
}
const char *CClient::GetAccount()
{
return m_vars.account.c_str();
}
const char *CClient::GetDescription()
{
// Must lead with index or the kick/ban feature won't function.
return csprintf("#%u %s \"%s\"", m_vars.slot, inet_ntoa(m_vars.addr.sin_addr), m_vars.account.c_str());
}
void CClient::SetLoginData(uint32_t dwUnixTime, uint32_t dwPortalStamp, uint32_t dwCellStamp)
{
m_vars.fLoginTime = g_pGlobals->Time();
m_vars.ClientLoginUnixTime = dwUnixTime;
m_vars.PortalStamp = dwPortalStamp;
m_vars.CellStamp = dwCellStamp;
m_vars.bInitDats = FALSE;
}
SOCKADDR_IN *CClient::GetHostAddress()
{
return &m_vars.addr;
}