mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-21 18:31:30 +00:00
working on loading resists from character create.
This commit is contained in:
parent
c873fe5a22
commit
62bb426847
@ -1121,6 +1121,12 @@ struct PlayerProfile_Struct
|
|||||||
/*19559*/ uint8 unknown19595[5]; // ***Placeholder (6/29/2005)
|
/*19559*/ uint8 unknown19595[5]; // ***Placeholder (6/29/2005)
|
||||||
/*19564*/ uint32 RestTimer;
|
/*19564*/ uint32 RestTimer;
|
||||||
/*19568*/ uint32 char_id; // Found as part of bazaar revamp (5/15/2024)
|
/*19568*/ uint32 char_id; // Found as part of bazaar revamp (5/15/2024)
|
||||||
|
/*19572*/ uint32 cold_resist;
|
||||||
|
/*19576*/ uint32 fire_resist;
|
||||||
|
/*19580*/ uint32 magic_resist;
|
||||||
|
/*19584*/ uint32 disease_resist;
|
||||||
|
/*19588*/ uint32 poison_resist;
|
||||||
|
/*19592*/ uint32 corruption_resist;
|
||||||
|
|
||||||
// All player profile packets are translated and this overhead is ignored in out-bound packets
|
// All player profile packets are translated and this overhead is ignored in out-bound packets
|
||||||
PlayerProfile_Struct() : m_player_profile_version(EQ::versions::MobVersion::Unknown) { }
|
PlayerProfile_Struct() : m_player_profile_version(EQ::versions::MobVersion::Unknown) { }
|
||||||
|
|||||||
@ -56,6 +56,7 @@ SET(world_headers
|
|||||||
login_server.h
|
login_server.h
|
||||||
login_server_list.h
|
login_server_list.h
|
||||||
queryserv.h
|
queryserv.h
|
||||||
|
race_combos.h
|
||||||
shared_task_manager.h
|
shared_task_manager.h
|
||||||
shared_task_world_messaging.h
|
shared_task_world_messaging.h
|
||||||
sof_char_create_data.h
|
sof_char_create_data.h
|
||||||
|
|||||||
537
world/client.cpp
537
world/client.cpp
@ -47,6 +47,7 @@
|
|||||||
#include "clientlist.h"
|
#include "clientlist.h"
|
||||||
#include "wguild_mgr.h"
|
#include "wguild_mgr.h"
|
||||||
#include "sof_char_create_data.h"
|
#include "sof_char_create_data.h"
|
||||||
|
#include "race_combos.h"
|
||||||
#include "../common/zone_store.h"
|
#include "../common/zone_store.h"
|
||||||
#include "../common/repositories/account_repository.h"
|
#include "../common/repositories/account_repository.h"
|
||||||
#include "../common/repositories/player_event_logs_repository.h"
|
#include "../common/repositories/player_event_logs_repository.h"
|
||||||
@ -85,8 +86,8 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<RaceClassAllocation> character_create_allocations;
|
std::vector<CharCreatePointAllocation> character_create_allocations;
|
||||||
std::vector<RaceClassCombos> character_create_race_class_combos;
|
std::vector<CharCreateCombination> character_create_race_class_combos;
|
||||||
|
|
||||||
extern ZSList zoneserver_list;
|
extern ZSList zoneserver_list;
|
||||||
extern LoginServerList loginserverlist;
|
extern LoginServerList loginserverlist;
|
||||||
@ -1642,229 +1643,6 @@ void Client::SendApproveWorld()
|
|||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
|
||||||
{
|
|
||||||
PlayerProfile_Struct pp;
|
|
||||||
EQ::InventoryProfile inv;
|
|
||||||
|
|
||||||
pp.SetPlayerProfileVersion(EQ::versions::ConvertClientVersionToMobVersion(EQ::versions::ConvertClientVersionBitToClientVersion(m_ClientVersionBit)));
|
|
||||||
inv.SetInventoryVersion(EQ::versions::ConvertClientVersionBitToClientVersion(m_ClientVersionBit));
|
|
||||||
inv.SetGMInventory(false); // character cannot have gm flag at this point
|
|
||||||
|
|
||||||
time_t bday = time(nullptr);
|
|
||||||
in_addr in;
|
|
||||||
|
|
||||||
const uint32 stats_sum = (
|
|
||||||
cc->AGI +
|
|
||||||
cc->CHA +
|
|
||||||
cc->DEX +
|
|
||||||
cc->INT +
|
|
||||||
cc->STA +
|
|
||||||
cc->STR +
|
|
||||||
cc->WIS
|
|
||||||
);
|
|
||||||
|
|
||||||
in.s_addr = GetIP();
|
|
||||||
|
|
||||||
LogInfo(
|
|
||||||
"Character creation request from [{}] LS [{}] [{}] [{}]",
|
|
||||||
GetCLE()->LSName(),
|
|
||||||
GetCLE()->LSID(),
|
|
||||||
inet_ntoa(in),
|
|
||||||
GetPort()
|
|
||||||
);
|
|
||||||
LogInfo("Name [{}]", name);
|
|
||||||
LogInfo(
|
|
||||||
"race [{}] class [{}] gender [{}] deity [{}] start_zone [{}] tutorial [{}]",
|
|
||||||
cc->race,
|
|
||||||
cc->class_,
|
|
||||||
cc->gender,
|
|
||||||
cc->deity,
|
|
||||||
cc->start_zone,
|
|
||||||
cc->tutorial ? "true" : "false"
|
|
||||||
);
|
|
||||||
LogInfo(
|
|
||||||
"AGI [{}] CHA [{}] DEX [{}] INT [{}] STA [{}] STR [{}] WIS [{}] Total [{}]",
|
|
||||||
cc->AGI,
|
|
||||||
cc->CHA,
|
|
||||||
cc->DEX,
|
|
||||||
cc->INT,
|
|
||||||
cc->STA,
|
|
||||||
cc->STR,
|
|
||||||
cc->WIS,
|
|
||||||
stats_sum
|
|
||||||
);
|
|
||||||
LogInfo("Face [{}] Eye Colors [{}] [{}]", cc->face, cc->eyecolor1, cc->eyecolor2);
|
|
||||||
LogInfo("Hair [{}] Hair Color [{}]", cc->hairstyle, cc->haircolor);
|
|
||||||
LogInfo("Beard [{}] Beard Color [{}]", cc->beard, cc->beardcolor);
|
|
||||||
|
|
||||||
/* Validate the char creation struct */
|
|
||||||
if (m_ClientVersionBit & EQ::versions::maskSoFAndLater) {
|
|
||||||
if (!CheckCharCreateInfoSoF(cc)) {
|
|
||||||
LogInfo("CheckCharCreateInfo did not validate the request (bad race/class/stats)");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!CheckCharCreateInfoTitanium(cc)) {
|
|
||||||
LogInfo("CheckCharCreateInfo did not validate the request (bad race/class/stats)");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert incoming cc_s to the new PlayerProfile_Struct */
|
|
||||||
memset(&pp, 0, sizeof(PlayerProfile_Struct)); // start building the profile
|
|
||||||
|
|
||||||
strn0cpy(pp.name, name, sizeof(pp.name));
|
|
||||||
|
|
||||||
pp.race = cc->race;
|
|
||||||
pp.class_ = cc->class_;
|
|
||||||
pp.gender = cc->gender;
|
|
||||||
pp.deity = cc->deity;
|
|
||||||
pp.STR = cc->STR;
|
|
||||||
pp.STA = cc->STA;
|
|
||||||
pp.AGI = cc->AGI;
|
|
||||||
pp.DEX = cc->DEX;
|
|
||||||
pp.WIS = cc->WIS;
|
|
||||||
pp.INT = cc->INT;
|
|
||||||
pp.CHA = cc->CHA;
|
|
||||||
pp.face = cc->face;
|
|
||||||
pp.eyecolor1 = cc->eyecolor1;
|
|
||||||
pp.eyecolor2 = cc->eyecolor2;
|
|
||||||
pp.hairstyle = cc->hairstyle;
|
|
||||||
pp.haircolor = cc->haircolor;
|
|
||||||
pp.beard = cc->beard;
|
|
||||||
pp.beardcolor = cc->beardcolor;
|
|
||||||
pp.drakkin_heritage = cc->drakkin_heritage;
|
|
||||||
pp.drakkin_tattoo = cc->drakkin_tattoo;
|
|
||||||
pp.drakkin_details = cc->drakkin_details;
|
|
||||||
pp.birthday = bday;
|
|
||||||
pp.lastlogin = bday;
|
|
||||||
pp.level = 1;
|
|
||||||
pp.points = 5;
|
|
||||||
pp.cur_hp = 1000;
|
|
||||||
pp.hunger_level = 6000;
|
|
||||||
pp.thirst_level = 6000;
|
|
||||||
|
|
||||||
/* Set default skills for everybody */
|
|
||||||
pp.skills[EQ::skills::SkillSwimming] = RuleI(Skills, SwimmingStartValue);
|
|
||||||
pp.skills[EQ::skills::SkillSenseHeading] = RuleI(Skills, SenseHeadingStartValue);
|
|
||||||
|
|
||||||
/* Set Racial and Class specific language and skills */
|
|
||||||
SetRacialLanguages(&pp);
|
|
||||||
SetRaceStartingSkills(&pp);
|
|
||||||
SetClassStartingSkills(&pp);
|
|
||||||
SetClassLanguages(&pp);
|
|
||||||
|
|
||||||
memset(pp.spell_book, std::numeric_limits<uint8>::max(), (sizeof(uint32) * EQ::spells::SPELLBOOK_SIZE));
|
|
||||||
memset(pp.mem_spells, std::numeric_limits<uint8>::max(), (sizeof(uint32) * EQ::spells::SPELL_GEM_COUNT));
|
|
||||||
|
|
||||||
for (auto& b : pp.buffs) {
|
|
||||||
b.spellid = std::numeric_limits<uint16>::max();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If server is PVP by default, make all character set to it. */
|
|
||||||
pp.pvp = database.GetServerType() == 1 ? 1 : 0;
|
|
||||||
|
|
||||||
/* If it is an SoF Client and the SoF Start Zone rule is set, send new chars there */
|
|
||||||
if (m_ClientVersionBit & EQ::versions::maskSoFAndLater) {
|
|
||||||
LogInfo("Found [SoFStartZoneID] rule setting [{}]", RuleI(World, SoFStartZoneID));
|
|
||||||
if (RuleI(World, SoFStartZoneID) > 0) {
|
|
||||||
pp.zone_id = RuleI(World, SoFStartZoneID);
|
|
||||||
cc->start_zone = pp.zone_id;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LogInfo("Found [TitaniumStartZoneID] rule setting [{}]", RuleI(World, TitaniumStartZoneID));
|
|
||||||
if (RuleI(World, TitaniumStartZoneID) > 0) { /* if there's a startzone variable put them in there */
|
|
||||||
pp.zone_id = RuleI(World, TitaniumStartZoneID);
|
|
||||||
cc->start_zone = pp.zone_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* use normal starting zone logic to either get defaults, or if startzone was set, load that from the db table.*/
|
|
||||||
const bool is_valid_start_zone = content_db.GetStartZone(&pp, cc, m_ClientVersionBit & EQ::versions::maskTitaniumAndEarlier);
|
|
||||||
if (!is_valid_start_zone){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pp.zone_id) {
|
|
||||||
pp.zone_id = Zones::QEYNOS;
|
|
||||||
|
|
||||||
pp.x = pp.y = pp.z = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint8 slot_id = 1; slot_id < 5; slot_id++) {
|
|
||||||
pp.binds[slot_id].zone_id = pp.zone_id;
|
|
||||||
pp.binds[slot_id].x = pp.x;
|
|
||||||
pp.binds[slot_id].y = pp.y;
|
|
||||||
pp.binds[slot_id].z = pp.z;
|
|
||||||
pp.binds[slot_id].heading = pp.heading;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Overrides if we have the tutorial flag set! */
|
|
||||||
if (cc->tutorial && RuleB(World, EnableTutorialButton)) {
|
|
||||||
pp.zone_id = RuleI(World, TutorialZoneID);
|
|
||||||
|
|
||||||
auto z = GetZone(pp.zone_id);
|
|
||||||
if (z) {
|
|
||||||
pp.x = z->safe_x;
|
|
||||||
pp.y = z->safe_y;
|
|
||||||
pp.z = z->safe_z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Will either be the same as home or tutorial if enabled. */
|
|
||||||
if (RuleB(World, StartZoneSameAsBindOnCreation)) {
|
|
||||||
pp.binds[0].zone_id = pp.zone_id;
|
|
||||||
pp.binds[0].x = pp.x;
|
|
||||||
pp.binds[0].y = pp.y;
|
|
||||||
pp.binds[0].z = pp.z;
|
|
||||||
pp.binds[0].heading = pp.heading;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetZone(pp.zone_id)) {
|
|
||||||
LogInfo(
|
|
||||||
"Current location zone_short_name [{}] zone_id [{}] x [{:.2f}] y [{:.2f}] z [{:.2f}] heading [{:.2f}]",
|
|
||||||
ZoneName(pp.zone_id),
|
|
||||||
pp.zone_id,
|
|
||||||
pp.x,
|
|
||||||
pp.y,
|
|
||||||
pp.z,
|
|
||||||
pp.heading
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetZone(pp.binds[0].zone_id)) {
|
|
||||||
LogInfo(
|
|
||||||
"Bind location zone_short_name [{}] zone_id [{}] x [{:.2f}] y [{:.2f}] z [{:.2f}] heading [{:.2f}]",
|
|
||||||
ZoneName(pp.binds[0].zone_id),
|
|
||||||
pp.binds[0].zone_id,
|
|
||||||
pp.binds[0].x,
|
|
||||||
pp.binds[0].y,
|
|
||||||
pp.binds[0].z,
|
|
||||||
pp.binds[4].heading
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetZone(pp.binds[4].zone_id)) {
|
|
||||||
LogInfo(
|
|
||||||
"Home location zone_short_name [{}] zone_id [{}] x [{:.2f}] y [{:.2f}] z [{:.2f}] heading [{:.2f}]",
|
|
||||||
ZoneName(pp.binds[4].zone_id),
|
|
||||||
pp.binds[4].zone_id,
|
|
||||||
pp.binds[4].x,
|
|
||||||
pp.binds[4].y,
|
|
||||||
pp.binds[4].z,
|
|
||||||
pp.binds[4].heading
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
content_db.SetStartingItems(&pp, &inv, pp.race, pp.class_, pp.deity, pp.zone_id, pp.name, GetAdmin());
|
|
||||||
|
|
||||||
const bool success = StoreCharacter(GetAccountID(), &pp, &inv);
|
|
||||||
|
|
||||||
LogInfo("Character creation {} for [{}]", success ? "succeeded" : "failed", pp.name);
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns true if the request is ok, false if there's an error
|
// returns true if the request is ok, false if there's an error
|
||||||
bool CheckCharCreateInfoSoF(CharCreate_Struct* cc)
|
bool CheckCharCreateInfoSoF(CharCreate_Struct* cc)
|
||||||
{
|
{
|
||||||
@ -1873,7 +1651,7 @@ bool CheckCharCreateInfoSoF(CharCreate_Struct *cc)
|
|||||||
|
|
||||||
LogInfo("Validating char creation info");
|
LogInfo("Validating char creation info");
|
||||||
|
|
||||||
RaceClassCombos class_combo;
|
CharCreateCombination class_combo;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
int combos = character_create_race_class_combos.size();
|
int combos = character_create_race_class_combos.size();
|
||||||
for (int i = 0; i < combos; ++i) {
|
for (int i = 0; i < combos; ++i) {
|
||||||
@ -1893,7 +1671,7 @@ bool CheckCharCreateInfoSoF(CharCreate_Struct *cc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32 allocs = character_create_allocations.size();
|
uint32 allocs = character_create_allocations.size();
|
||||||
RaceClassAllocation allocation = {0};
|
CharCreatePointAllocation allocation = { 0 };
|
||||||
found = false;
|
found = false;
|
||||||
for (int i = 0; i < allocs; ++i) {
|
for (int i = 0; i < allocs; ++i) {
|
||||||
if (character_create_allocations[i].Index == class_combo.AllocationIndex) {
|
if (character_create_allocations[i].Index == class_combo.AllocationIndex) {
|
||||||
@ -2132,6 +1910,311 @@ bool CheckCharCreateInfoTitanium(CharCreate_Struct *cc)
|
|||||||
return Charerrors == 0;
|
return Charerrors == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: these hard coded values should be settable somewhere somehow.
|
||||||
|
void GetResistsForCharacterCreate(CharCreate_Struct* cc,
|
||||||
|
bool sofAndLater,
|
||||||
|
uint32 &cold_resist,
|
||||||
|
uint32& fire_resist,
|
||||||
|
uint32& magic_resist,
|
||||||
|
uint32& disease_resist,
|
||||||
|
uint32& poison_resist,
|
||||||
|
uint32& corruption_resist)
|
||||||
|
{
|
||||||
|
if (!sofAndLater) {
|
||||||
|
cold_resist = 25;
|
||||||
|
fire_resist = 25;
|
||||||
|
magic_resist = 25;
|
||||||
|
disease_resist = 15;
|
||||||
|
poison_resist = 15;
|
||||||
|
corruption_resist = 15;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharCreateCombination class_combo;
|
||||||
|
bool found = false;
|
||||||
|
int combos = character_create_race_class_combos.size();
|
||||||
|
for (int i = 0; i < combos; ++i) {
|
||||||
|
if (character_create_race_class_combos[i].Class == cc->class_ &&
|
||||||
|
character_create_race_class_combos[i].Race == cc->race &&
|
||||||
|
character_create_race_class_combos[i].Deity == cc->deity &&
|
||||||
|
character_create_race_class_combos[i].Zone == cc->start_zone) {
|
||||||
|
class_combo = character_create_race_class_combos[i];
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
cold_resist = 25;
|
||||||
|
fire_resist = 25;
|
||||||
|
magic_resist = 25;
|
||||||
|
disease_resist = 15;
|
||||||
|
poison_resist = 15;
|
||||||
|
corruption_resist = 15;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharCreatePointAllocation allocation;
|
||||||
|
found = false;
|
||||||
|
combos = character_create_allocations.size();
|
||||||
|
for (int i = 0; i < combos; ++i) {
|
||||||
|
if (character_create_allocations[i].Index == class_combo.AllocationIndex) {
|
||||||
|
allocation = character_create_allocations[i];
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
cold_resist = 25;
|
||||||
|
fire_resist = 25;
|
||||||
|
magic_resist = 25;
|
||||||
|
disease_resist = 15;
|
||||||
|
poison_resist = 15;
|
||||||
|
corruption_resist = 15;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cold_resist = allocation.BaseResists[0];
|
||||||
|
fire_resist = allocation.BaseResists[1];
|
||||||
|
magic_resist = allocation.BaseResists[2];
|
||||||
|
disease_resist = allocation.BaseResists[3];
|
||||||
|
poison_resist = allocation.BaseResists[4];
|
||||||
|
corruption_resist = allocation.BaseResists[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Client::OPCharCreate(char *name, CharCreate_Struct *cc)
|
||||||
|
{
|
||||||
|
PlayerProfile_Struct pp;
|
||||||
|
EQ::InventoryProfile inv;
|
||||||
|
|
||||||
|
pp.SetPlayerProfileVersion(EQ::versions::ConvertClientVersionToMobVersion(EQ::versions::ConvertClientVersionBitToClientVersion(m_ClientVersionBit)));
|
||||||
|
inv.SetInventoryVersion(EQ::versions::ConvertClientVersionBitToClientVersion(m_ClientVersionBit));
|
||||||
|
inv.SetGMInventory(false); // character cannot have gm flag at this point
|
||||||
|
|
||||||
|
time_t bday = time(nullptr);
|
||||||
|
in_addr in;
|
||||||
|
|
||||||
|
const uint32 stats_sum = (
|
||||||
|
cc->AGI +
|
||||||
|
cc->CHA +
|
||||||
|
cc->DEX +
|
||||||
|
cc->INT +
|
||||||
|
cc->STA +
|
||||||
|
cc->STR +
|
||||||
|
cc->WIS
|
||||||
|
);
|
||||||
|
|
||||||
|
in.s_addr = GetIP();
|
||||||
|
|
||||||
|
LogInfo(
|
||||||
|
"Character creation request from [{}] LS [{}] [{}] [{}]",
|
||||||
|
GetCLE()->LSName(),
|
||||||
|
GetCLE()->LSID(),
|
||||||
|
inet_ntoa(in),
|
||||||
|
GetPort()
|
||||||
|
);
|
||||||
|
LogInfo("Name [{}]", name);
|
||||||
|
LogInfo(
|
||||||
|
"race [{}] class [{}] gender [{}] deity [{}] start_zone [{}] tutorial [{}]",
|
||||||
|
cc->race,
|
||||||
|
cc->class_,
|
||||||
|
cc->gender,
|
||||||
|
cc->deity,
|
||||||
|
cc->start_zone,
|
||||||
|
cc->tutorial ? "true" : "false"
|
||||||
|
);
|
||||||
|
LogInfo(
|
||||||
|
"AGI [{}] CHA [{}] DEX [{}] INT [{}] STA [{}] STR [{}] WIS [{}] Total [{}]",
|
||||||
|
cc->AGI,
|
||||||
|
cc->CHA,
|
||||||
|
cc->DEX,
|
||||||
|
cc->INT,
|
||||||
|
cc->STA,
|
||||||
|
cc->STR,
|
||||||
|
cc->WIS,
|
||||||
|
stats_sum
|
||||||
|
);
|
||||||
|
LogInfo("Face [{}] Eye Colors [{}] [{}]", cc->face, cc->eyecolor1, cc->eyecolor2);
|
||||||
|
LogInfo("Hair [{}] Hair Color [{}]", cc->hairstyle, cc->haircolor);
|
||||||
|
LogInfo("Beard [{}] Beard Color [{}]", cc->beard, cc->beardcolor);
|
||||||
|
|
||||||
|
/* Validate the char creation struct */
|
||||||
|
if (m_ClientVersionBit & EQ::versions::maskSoFAndLater) {
|
||||||
|
if (!CheckCharCreateInfoSoF(cc)) {
|
||||||
|
LogInfo("CheckCharCreateInfo did not validate the request (bad race/class/stats)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!CheckCharCreateInfoTitanium(cc)) {
|
||||||
|
LogInfo("CheckCharCreateInfo did not validate the request (bad race/class/stats)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert incoming cc_s to the new PlayerProfile_Struct */
|
||||||
|
memset(&pp, 0, sizeof(PlayerProfile_Struct)); // start building the profile
|
||||||
|
|
||||||
|
strn0cpy(pp.name, name, sizeof(pp.name));
|
||||||
|
|
||||||
|
pp.race = cc->race;
|
||||||
|
pp.class_ = cc->class_;
|
||||||
|
pp.gender = cc->gender;
|
||||||
|
pp.deity = cc->deity;
|
||||||
|
pp.STR = cc->STR;
|
||||||
|
pp.STA = cc->STA;
|
||||||
|
pp.AGI = cc->AGI;
|
||||||
|
pp.DEX = cc->DEX;
|
||||||
|
pp.WIS = cc->WIS;
|
||||||
|
pp.INT = cc->INT;
|
||||||
|
pp.CHA = cc->CHA;
|
||||||
|
pp.face = cc->face;
|
||||||
|
pp.eyecolor1 = cc->eyecolor1;
|
||||||
|
pp.eyecolor2 = cc->eyecolor2;
|
||||||
|
pp.hairstyle = cc->hairstyle;
|
||||||
|
pp.haircolor = cc->haircolor;
|
||||||
|
pp.beard = cc->beard;
|
||||||
|
pp.beardcolor = cc->beardcolor;
|
||||||
|
pp.drakkin_heritage = cc->drakkin_heritage;
|
||||||
|
pp.drakkin_tattoo = cc->drakkin_tattoo;
|
||||||
|
pp.drakkin_details = cc->drakkin_details;
|
||||||
|
pp.birthday = bday;
|
||||||
|
pp.lastlogin = bday;
|
||||||
|
pp.level = 1;
|
||||||
|
pp.points = 5;
|
||||||
|
pp.cur_hp = 1000;
|
||||||
|
pp.hunger_level = 6000;
|
||||||
|
pp.thirst_level = 6000;
|
||||||
|
|
||||||
|
GetResistsForCharacterCreate(cc,
|
||||||
|
m_ClientVersionBit & EQ::versions::maskSoFAndLater,
|
||||||
|
pp.cold_resist,
|
||||||
|
pp.fire_resist,
|
||||||
|
pp.magic_resist,
|
||||||
|
pp.disease_resist,
|
||||||
|
pp.poison_resist,
|
||||||
|
pp.corruption_resist);
|
||||||
|
|
||||||
|
/* Set default skills for everybody */
|
||||||
|
pp.skills[EQ::skills::SkillSwimming] = RuleI(Skills, SwimmingStartValue);
|
||||||
|
pp.skills[EQ::skills::SkillSenseHeading] = RuleI(Skills, SenseHeadingStartValue);
|
||||||
|
|
||||||
|
/* Set Racial and Class specific language and skills */
|
||||||
|
SetRacialLanguages(&pp);
|
||||||
|
SetRaceStartingSkills(&pp);
|
||||||
|
SetClassStartingSkills(&pp);
|
||||||
|
SetClassLanguages(&pp);
|
||||||
|
|
||||||
|
memset(pp.spell_book, std::numeric_limits<uint8>::max(), (sizeof(uint32) * EQ::spells::SPELLBOOK_SIZE));
|
||||||
|
memset(pp.mem_spells, std::numeric_limits<uint8>::max(), (sizeof(uint32) * EQ::spells::SPELL_GEM_COUNT));
|
||||||
|
|
||||||
|
for (auto& b : pp.buffs) {
|
||||||
|
b.spellid = std::numeric_limits<uint16>::max();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If server is PVP by default, make all character set to it. */
|
||||||
|
pp.pvp = database.GetServerType() == 1 ? 1 : 0;
|
||||||
|
|
||||||
|
/* If it is an SoF Client and the SoF Start Zone rule is set, send new chars there */
|
||||||
|
if (m_ClientVersionBit & EQ::versions::maskSoFAndLater) {
|
||||||
|
LogInfo("Found [SoFStartZoneID] rule setting [{}]", RuleI(World, SoFStartZoneID));
|
||||||
|
if (RuleI(World, SoFStartZoneID) > 0) {
|
||||||
|
pp.zone_id = RuleI(World, SoFStartZoneID);
|
||||||
|
cc->start_zone = pp.zone_id;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LogInfo("Found [TitaniumStartZoneID] rule setting [{}]", RuleI(World, TitaniumStartZoneID));
|
||||||
|
if (RuleI(World, TitaniumStartZoneID) > 0) { /* if there's a startzone variable put them in there */
|
||||||
|
pp.zone_id = RuleI(World, TitaniumStartZoneID);
|
||||||
|
cc->start_zone = pp.zone_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* use normal starting zone logic to either get defaults, or if startzone was set, load that from the db table.*/
|
||||||
|
const bool is_valid_start_zone = content_db.GetStartZone(&pp, cc, m_ClientVersionBit & EQ::versions::maskTitaniumAndEarlier);
|
||||||
|
if (!is_valid_start_zone){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pp.zone_id) {
|
||||||
|
pp.zone_id = Zones::QEYNOS;
|
||||||
|
|
||||||
|
pp.x = pp.y = pp.z = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8 slot_id = 1; slot_id < 5; slot_id++) {
|
||||||
|
pp.binds[slot_id].zone_id = pp.zone_id;
|
||||||
|
pp.binds[slot_id].x = pp.x;
|
||||||
|
pp.binds[slot_id].y = pp.y;
|
||||||
|
pp.binds[slot_id].z = pp.z;
|
||||||
|
pp.binds[slot_id].heading = pp.heading;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Overrides if we have the tutorial flag set! */
|
||||||
|
if (cc->tutorial && RuleB(World, EnableTutorialButton)) {
|
||||||
|
pp.zone_id = RuleI(World, TutorialZoneID);
|
||||||
|
|
||||||
|
auto z = GetZone(pp.zone_id);
|
||||||
|
if (z) {
|
||||||
|
pp.x = z->safe_x;
|
||||||
|
pp.y = z->safe_y;
|
||||||
|
pp.z = z->safe_z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Will either be the same as home or tutorial if enabled. */
|
||||||
|
if (RuleB(World, StartZoneSameAsBindOnCreation)) {
|
||||||
|
pp.binds[0].zone_id = pp.zone_id;
|
||||||
|
pp.binds[0].x = pp.x;
|
||||||
|
pp.binds[0].y = pp.y;
|
||||||
|
pp.binds[0].z = pp.z;
|
||||||
|
pp.binds[0].heading = pp.heading;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetZone(pp.zone_id)) {
|
||||||
|
LogInfo(
|
||||||
|
"Current location zone_short_name [{}] zone_id [{}] x [{:.2f}] y [{:.2f}] z [{:.2f}] heading [{:.2f}]",
|
||||||
|
ZoneName(pp.zone_id),
|
||||||
|
pp.zone_id,
|
||||||
|
pp.x,
|
||||||
|
pp.y,
|
||||||
|
pp.z,
|
||||||
|
pp.heading
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetZone(pp.binds[0].zone_id)) {
|
||||||
|
LogInfo(
|
||||||
|
"Bind location zone_short_name [{}] zone_id [{}] x [{:.2f}] y [{:.2f}] z [{:.2f}] heading [{:.2f}]",
|
||||||
|
ZoneName(pp.binds[0].zone_id),
|
||||||
|
pp.binds[0].zone_id,
|
||||||
|
pp.binds[0].x,
|
||||||
|
pp.binds[0].y,
|
||||||
|
pp.binds[0].z,
|
||||||
|
pp.binds[4].heading
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetZone(pp.binds[4].zone_id)) {
|
||||||
|
LogInfo(
|
||||||
|
"Home location zone_short_name [{}] zone_id [{}] x [{:.2f}] y [{:.2f}] z [{:.2f}] heading [{:.2f}]",
|
||||||
|
ZoneName(pp.binds[4].zone_id),
|
||||||
|
pp.binds[4].zone_id,
|
||||||
|
pp.binds[4].x,
|
||||||
|
pp.binds[4].y,
|
||||||
|
pp.binds[4].z,
|
||||||
|
pp.binds[4].heading
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
content_db.SetStartingItems(&pp, &inv, pp.race, pp.class_, pp.deity, pp.zone_id, pp.name, GetAdmin());
|
||||||
|
|
||||||
|
const bool success = StoreCharacter(GetAccountID(), &pp, &inv);
|
||||||
|
|
||||||
|
LogInfo("Character creation {} for [{}]", success ? "succeeded" : "failed", pp.name);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
void Client::SetClassStartingSkills(PlayerProfile_Struct *pp)
|
void Client::SetClassStartingSkills(PlayerProfile_Struct *pp)
|
||||||
{
|
{
|
||||||
for (uint32 i = 0; i <= EQ::skills::HIGHEST_SKILL; ++i) {
|
for (uint32 i = 0; i <= EQ::skills::HIGHEST_SKILL; ++i) {
|
||||||
|
|||||||
@ -122,7 +122,4 @@ private:
|
|||||||
void RecordPossibleHack(const std::string& message);
|
void RecordPossibleHack(const std::string& message);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CheckCharCreateInfoSoF(CharCreate_Struct *cc);
|
|
||||||
bool CheckCharCreateInfoTitanium(CharCreate_Struct *cc);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
18
world/race_combos.h
Normal file
18
world/race_combos.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct CharCreatePointAllocation
|
||||||
|
{
|
||||||
|
unsigned int Index;
|
||||||
|
unsigned int BaseStats[7];
|
||||||
|
unsigned int DefaultPointAllocation[7];
|
||||||
|
unsigned int BaseResists[7];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CharCreateCombination {
|
||||||
|
unsigned int ExpansionRequired;
|
||||||
|
unsigned int Race;
|
||||||
|
unsigned int Class;
|
||||||
|
unsigned int Deity;
|
||||||
|
unsigned int AllocationIndex;
|
||||||
|
unsigned int Zone;
|
||||||
|
};
|
||||||
@ -25,14 +25,15 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "sof_char_create_data.h"
|
#include "sof_char_create_data.h"
|
||||||
|
#include "race_combos.h"
|
||||||
#include "../common/repositories/character_instance_safereturns_repository.h"
|
#include "../common/repositories/character_instance_safereturns_repository.h"
|
||||||
#include "../common/repositories/criteria/content_filter_criteria.h"
|
#include "../common/repositories/criteria/content_filter_criteria.h"
|
||||||
#include "../common/zone_store.h"
|
#include "../common/zone_store.h"
|
||||||
|
|
||||||
WorldDatabase database;
|
WorldDatabase database;
|
||||||
WorldDatabase content_db;
|
WorldDatabase content_db;
|
||||||
extern std::vector<RaceClassAllocation> character_create_allocations;
|
extern std::vector<CharCreatePointAllocation> character_create_allocations;
|
||||||
extern std::vector<RaceClassCombos> character_create_race_class_combos;
|
extern std::vector<CharCreateCombination> character_create_race_class_combos;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -807,7 +808,7 @@ bool WorldDatabase::LoadCharacterCreateAllocations()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
RaceClassAllocation allocate;
|
CharCreatePointAllocation allocate;
|
||||||
allocate.Index = Strings::ToInt(row[0]);
|
allocate.Index = Strings::ToInt(row[0]);
|
||||||
allocate.BaseStats[0] = Strings::ToInt(row[1]);
|
allocate.BaseStats[0] = Strings::ToInt(row[1]);
|
||||||
allocate.BaseStats[3] = Strings::ToInt(row[2]);
|
allocate.BaseStats[3] = Strings::ToInt(row[2]);
|
||||||
@ -823,6 +824,12 @@ bool WorldDatabase::LoadCharacterCreateAllocations()
|
|||||||
allocate.DefaultPointAllocation[4] = Strings::ToInt(row[12]);
|
allocate.DefaultPointAllocation[4] = Strings::ToInt(row[12]);
|
||||||
allocate.DefaultPointAllocation[5] = Strings::ToInt(row[13]);
|
allocate.DefaultPointAllocation[5] = Strings::ToInt(row[13]);
|
||||||
allocate.DefaultPointAllocation[6] = Strings::ToInt(row[14]);
|
allocate.DefaultPointAllocation[6] = Strings::ToInt(row[14]);
|
||||||
|
allocate.BaseResists[0] = Strings::ToInt(row[15]);
|
||||||
|
allocate.BaseResists[1] = Strings::ToInt(row[16]);
|
||||||
|
allocate.BaseResists[2] = Strings::ToInt(row[17]);
|
||||||
|
allocate.BaseResists[3] = Strings::ToInt(row[18]);
|
||||||
|
allocate.BaseResists[4] = Strings::ToInt(row[19]);
|
||||||
|
allocate.BaseResists[5] = Strings::ToInt(row[20]);
|
||||||
|
|
||||||
character_create_allocations.push_back(allocate);
|
character_create_allocations.push_back(allocate);
|
||||||
}
|
}
|
||||||
@ -840,7 +847,7 @@ bool WorldDatabase::LoadCharacterCreateCombos()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
RaceClassCombos combo;
|
CharCreateCombination combo;
|
||||||
combo.AllocationIndex = Strings::ToInt(row[0]);
|
combo.AllocationIndex = Strings::ToInt(row[0]);
|
||||||
combo.Race = Strings::ToInt(row[1]);
|
combo.Race = Strings::ToInt(row[1]);
|
||||||
combo.Class = Strings::ToInt(row[2]);
|
combo.Class = Strings::ToInt(row[2]);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user