#include #include "easylogging++.h" #include "InferredPortalData.h" #include "Client.h" #include "ClientEvents.h" #include "Config.h" #include // 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 &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; } bool CClient::RemoveCharacterGag(unsigned int character_id) { for (auto &character : m_Characters) { if (character.weenie_id == character_id) { character.gag_timer = 0; } } for (auto &character : m_CharactersSent) { if (character.weenie_id == character_id) { character.gag_timer = 0; } } return false; } bool CClient::IsCharacterGagged(unsigned int character_id) { for (auto &character : m_Characters) { if (character.weenie_id == character_id && character.gag_timer != 0) { return true; } } return false; } void CClient::UpdateLoginScreen() { m_CharactersSent = m_Characters = g_pDBIO->GetCharacterList(m_AccountInfo.id); BinaryWriter CharacterList; CharacterList.Write(0xF658); CharacterList.Write(0); // check what this is CharacterList.Write(m_Characters.size()); for (auto &character : m_Characters) { CharacterList.Write(character.weenie_id); CharacterList.WriteString(character.name); CharacterList.Write(character.ts_deleted); } CharacterList.Write(0); CharacterList.Write(11); // max characters I'm assuming CharacterList.WriteString(m_AccountInfo.username); CharacterList.Write(1); // what are these CharacterList.Write(1); // what are these SendNetMessage(CharacterList.GetData(), CharacterList.GetSize(), PRIVATE_MSG); BinaryWriter ServerName; ServerName.Write(0xF7E1); ServerName.Write(g_pWorld->GetNumPlayers()); // num connections ServerName.Write(-1); // Max connections ServerName.WriteString(g_pConfig->WorldName()); SendNetMessage(ServerName.GetData(), ServerName.GetSize(), PRIVATE_MSG); BinaryWriter DDD_InterrogationMessage; DDD_InterrogationMessage.Write(0xF7E5); DDD_InterrogationMessage.Write(1); // servers region DDD_InterrogationMessage.Write(1); // name rule language DDD_InterrogationMessage.Write(1); // product id DDD_InterrogationMessage.Write(2); // supports languages (2) DDD_InterrogationMessage.Write(0); // language #1 DDD_InterrogationMessage.Write(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(0x295); setChatChannels.Write(Allegiance_ChatChannel); setChatChannels.Write(General_ChatChannel); setChatChannels.Write(Trade_ChatChannel); setChatChannels.Write(LFG_ChatChannel); setChatChannels.Write(Roleplay_ChatChannel); setChatChannels.Write(Olthoi_ChatChannel); setChatChannels.Write(Society_ChatChannel); setChatChannels.Write(SocietyCelHan_ChatChannel); setChatChannels.Write(SocietyEldWeb_ChatChannel); setChatChannels.Write(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(); 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 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(); 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(0xF643); response.Write(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(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, , , 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(0xF643); response.Write(1); response.Write(newCharacterGUID); response.WriteString(cg.name.c_str()); response.Write(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(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(1); //the resource type: 1 for 0xFFFF, 2 for 0xFFFE, 3 for 0x100 BlockPackage.Write(2); //1 = client_portal / 2 = client_cell_1 / 3 = client_local_English BlockPackage.Write(1); //? BlockPackage.Write(dwFileID); //the resource ID number BlockPackage.Write(1); //the file version number BlockPackage.Write(1); // 0 = uncompressed / 1 = compressed BlockPackage.Write(2); //? BlockPackage.Write(dwPackageSize + sizeof(uint32_t) * 2); //the number of bytes required for the remainder of this message, including this uint32_t BlockPackage.Write(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(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(2); // 1 for 0xFFFF, 2 for 0xFFFE, 3 for 0x100 BlockInfoPackage.Write(2); BlockInfoPackage.Write(1); BlockInfoPackage.Write(dwFileID); BlockInfoPackage.Write(1); BlockInfoPackage.Write(1); BlockInfoPackage.Write(2); BlockInfoPackage.Write(dwPackageSize + sizeof(uint32_t) * 2); BlockInfoPackage.Write(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(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(3); // 1 for 0xFFFF, 2 for 0xFFFE, 3 for 0x100 CellPackage.Write(2); CellPackage.Write(1); CellPackage.Write(dwFileID); CellPackage.Write(1); CellPackage.Write(1); CellPackage.Write(2); CellPackage.Write(dwPackageSize + sizeof(uint32_t) * 2); CellPackage.Write(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 // dataset datasubset 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 fileIds; //fileIds.UnPack(&in); if (in.GetLastError()) break; BinaryWriter EndDDD; EndDDD.Write(0xF7EA); SendNetMessage(EndDDD.GetData(), EndDDD.GetSize(), EVENT_MSG); break; } case 0xF7EA: //DDD_OnEndDDD { //BinaryWriter EndDDD; //EndDDD.Write(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(0xF7DE); chatAck.Write(0x30); // Size chatAck.Write(0x05); // Type 05 - ACK chatAck.Write(0x02); // ?? chatAck.Write(0x01); // ?? chatAck.Write(0xB0045); // bitfield? chatAck.Write(0x01); chatAck.Write(0xB0045); // bitfield? chatAck.Write(0x00); chatAck.Write(0x10); // Payload size chatAck.Write(serial); // serial chatAck.Write(0x02); chatAck.Write(0x02); chatAck.Write(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; if (m_pEvents->IsServerGagged() && listening_channel != Allegiance_ChatChannel) break; if (m_pEvents->IsAllegGagged() && listening_channel == Allegiance_ChatChannel) 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()->sin_addr, &peer->sin_addr, sizeof(in_addr)); } 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; }