diff --git a/common/database.cpp b/common/database.cpp index a5bce5a52..429da0e42 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -1092,7 +1092,7 @@ bool Database::CheckDatabaseConversions() { // querylen = MakeAnyLenString(&query, "SELECT `id` FROM `character_` WHERE `id` = 61238"); int char_iter_count = 0; - querylen = MakeAnyLenString(&query, "SELECT `id` FROM `character_` WHERE `id` >= 61238 LIMIT 100"); + querylen = MakeAnyLenString(&query, "SELECT `id` FROM `character_` WHERE `id` >= 61238 LIMIT 1"); if (RunQuery(query, querylen, errbuf, &result)) { safe_delete_array(query); while (row = mysql_fetch_row(result)) { diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index da5e62dc5..9b2af6c45 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -538,29 +538,511 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) client->Disconnect(); } - char* query = 0; - uint32_breakdown workpt; - workpt.b4() = DBA_b4_Entity; - workpt.w2_3() = GetID(); - workpt.b1() = DBA_b1_Entity_Client_InfoForLogin; - DBAsyncWork* dbaw = new DBAsyncWork(&database, &MTdbafq, workpt, DBAsync::Read); - dbaw->AddQuery(1, &query, MakeAnyLenString(&query, - "SELECT status,name,lsaccount_id,gmspeed,revoked,hideme,time_creation FROM account WHERE id=%i", - account_id)); - //DO NOT FORGET TO EDIT ZoneDatabase::GetCharacterInfoForLogin if you change this - dbaw->AddQuery(2, &query, MakeAnyLenString(&query, - "SELECT id,profile,zonename,x,y,z,guild_id,rank,extprofile,class,level,lfp,lfg,instanceid,xtargets,firstlogon" - " FROM character_ LEFT JOIN guild_members ON id=char_id WHERE id=%i", - character_id)); - dbaw->AddQuery(3, &query, MakeAnyLenString(&query, - "SELECT faction_id,current_value FROM faction_values WHERE temp = 0 AND char_id = %i", - character_id)); - if (!(pDBAsyncWorkID = dbasync->AddWork(&dbaw))) { - safe_delete(dbaw); - LogFile->write(EQEMuLog::Error,"dbasync->AddWork() returned false, client crash"); - client_state = CLIENT_KICKED; - return; + uint32 pplen = 0; + EQApplicationPacket* outapp = 0; + MYSQL_RES* result = 0; + bool loaditems = 0; + uint32 i; + std::string query; + unsigned long* lengths; + + /* Set item materials */ + for (int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++) + if (m_pp.item_tint[i].rgb.use_tint == 1) + m_pp.item_tint[i].rgb.use_tint = 0xFF; + + uint32 cid = CharacterID(); + character_id = cid; + + database.RemoveTempFactions(this); + database.LoadCharacterFactionValues(cid, factionvalues); + /* Load Character Account Data: Temp until I move */ + query = StringFormat("SELECT `status`, `name`, `lsaccount_id`, `gmspeed`, `revoked`, `hideme` FROM `account` WHERE `id` = %i", this->AccountID()); + auto results = database.QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { + if (admin){ admin = atoi(row[0]); } + if (account_name){ strcpy(account_name, row[1]); } + if (lsaccountid && atoi(row[2]) > 0){ lsaccountid = atoi(row[2]); } + else{ lsaccountid = 0; } + if (gmspeed){ gmspeed = atoi(row[3]); } + if (revoked){ revoked = atoi(row[4]); } + if (gmhideme){ gmhideme = atoi(row[5]); } + if (account_creation){ account_creation = atoul(row[6]); } } + /* Load Character Legacy Data: Temp until I move */ + query = StringFormat("id,profile,zonename,x,y,z,guild_id,rank,extprofile,class,level,lfp,lfg,instanceid,xtargets,firstlogon FROM character_ LEFT JOIN guild_members ON id=char_id WHERE id=%i", cid); + results = database.QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { + m_pp.lastlogin = time(nullptr); + + if (RuleB(Character, SharedBankPlat)) + m_pp.platinum_shared = database.GetSharedPlatinum(database.GetAccountIDByChar(cid)); + + if (guildrank) { + if (row[7] != nullptr) + guildrank = atoi(row[7]); + else + guildrank = GUILD_RANK_NONE; + } + // if (ext) { SetExtendedProfile(ext, row[8], lengths[8]); } + if (level){ level = atoi(row[10]); } + if (LFP){ LFP = atoi(row[11]); } + if (LFG){ LFG = atoi(row[12]); } + if (firstlogon){ firstlogon = atoi(row[15]); } + } + /* Load Character Inventory */ + loaditems = database.GetInventory(cid, &m_inv); + /* Load Character Currency into PP */ + database.LoadCharacterCurrency(cid, &m_pp); + /* Load Character Data from DB into PP */ + database.LoadCharacterData(cid, &m_pp); + /* Move to another method when can, this is pointless... */ + database.GetPlayerInspectMessage(m_pp.name, &m_inspect_message); + /* Load Character Currency */ + database.LoadCharacterCurrency(cid, &m_pp); + /* Load Character Skills */ + database.LoadCharacterSkills(cid, &m_pp); + /* Load Character Disciplines */ + database.LoadCharacterDisciplines(cid, &m_pp); + + if (gmhideme) { trackable = false; } + + conn_state = PlayerProfileLoaded; + + /* Set Current zone */ + // m_pp.zone_id = zone->GetZoneID(); + // m_pp.zoneInstance = zone->GetInstanceID(); + + TotalSecondsPlayed = m_pp.timePlayedMin * 60; + + max_AAXP = RuleI(AA, ExpPerPoint); + + if (!RuleB(Character, MaintainIntoxicationAcrossZones)) + m_pp.intoxication = 0; + + if ((m_pp.x == -1 && m_pp.y == -1 && m_pp.z == -1) || (m_pp.x == -2 && m_pp.y == -2 && m_pp.z == -2)) { + m_pp.x = zone->safe_x(); + m_pp.y = zone->safe_y(); + m_pp.z = zone->safe_z(); + } + + /* If too far below ground, then fix */ + float ground_z = GetGroundZ(m_pp.x, m_pp.y, m_pp.z); + if (m_pp.z < (ground_z - 500)) + m_pp.z = ground_z; + + class_ = m_pp.class_; + + level = m_pp.level; + x_pos = m_pp.x; + y_pos = m_pp.y; + z_pos = m_pp.z; + heading = m_pp.heading; + race = m_pp.race; + base_race = m_pp.race; + gender = m_pp.gender; + base_gender = m_pp.gender; + deity = m_pp.deity; //FYI: DEITY_AGNOSTIC = 396; still valid? + haircolor = m_pp.haircolor; + beardcolor = m_pp.beardcolor; + eyecolor1 = m_pp.eyecolor1; + eyecolor2 = m_pp.eyecolor2; + hairstyle = m_pp.hairstyle; + luclinface = m_pp.face; + beard = m_pp.beard; + drakkin_heritage = m_pp.drakkin_heritage; + drakkin_tattoo = m_pp.drakkin_tattoo; + drakkin_details = m_pp.drakkin_details; + + if (m_pp.gm && admin < minStatusToBeGM) + m_pp.gm = 0; + + /* Load Guild */ + if (!IsInAGuild()) { m_pp.guild_id = GUILD_NONE; } + else { + m_pp.guild_id = GuildID(); + + if (zone->GetZoneID() == RuleI(World, GuildBankZoneID)) + GuildBanker = (guild_mgr.IsGuildLeader(GuildID(), CharacterID()) || guild_mgr.GetBankerFlag(CharacterID())); + } + + m_pp.guildbanker = GuildBanker; + + switch (race) + { + case OGRE: + size = 9; break; + case TROLL: + size = 8; break; + case VAHSHIR: case BARBARIAN: + size = 7; break; + case HUMAN: case HIGH_ELF: case ERUDITE: case IKSAR: case DRAKKIN: + size = 6; break; + case HALF_ELF: + size = 5.5; break; + case WOOD_ELF: case DARK_ELF: case FROGLOK: + size = 5; break; + case DWARF: + size = 4; break; + case HALFLING: + size = 3.5; break; + case GNOME: + size = 3; break; + default: + size = 0; + } + + /* Check for Invalid points */ + if (m_pp.ldon_points_guk < 0 || m_pp.ldon_points_guk > 2000000000){ m_pp.ldon_points_guk = 0; } + if (m_pp.ldon_points_mir < 0 || m_pp.ldon_points_mir > 2000000000){ m_pp.ldon_points_mir = 0; } + if (m_pp.ldon_points_mmc < 0 || m_pp.ldon_points_mmc > 2000000000){ m_pp.ldon_points_mmc = 0; } + if (m_pp.ldon_points_ruj < 0 || m_pp.ldon_points_ruj > 2000000000){ m_pp.ldon_points_ruj = 0; } + if (m_pp.ldon_points_tak < 0 || m_pp.ldon_points_tak > 2000000000){ m_pp.ldon_points_tak = 0; } + if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; } + + if (GetSkill(SkillSwimming) < 100) + SetSkill(SkillSwimming, 100); + + /* Initialize AA's : Move to function eventually */ + for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ aa[a] = &m_pp.aa_array[a]; } + query = StringFormat( + "SELECT " + "slot, " + "aa_id, " + "aa_value " + "FROM " + "`character_alternate_abilities` " + "WHERE `id` = %u ORDER BY `slot`", this->CharacterID()); + results = database.QueryDatabase(query); i = 0; + for (auto row = results.begin(); row != results.end(); ++row) { + i = atoi(row[0]); + m_pp.aa_array[i].AA = atoi(row[1]); + m_pp.aa_array[i].value = atoi(row[1]); + aa[i]->AA = atoi(row[1]); + aa[i]->value = atoi(row[2]); + } + for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ + uint32 id = aa[a]->AA; + //watch for invalid AA IDs + if (id == aaNone) + continue; + if (id >= aaHighestID) { + aa[a]->AA = aaNone; + aa[a]->value = 0; + continue; + } + if (aa[a]->value == 0) { + aa[a]->AA = aaNone; + continue; + } + if (aa[a]->value > HIGHEST_AA_VALUE) { + aa[a]->AA = aaNone; + aa[a]->value = 0; + continue; + } + + if (aa[a]->value > 1) /* hack in some stuff for sony's new AA method (where each level of each aa.has a seperate ID) */ + aa_points[(id - aa[a]->value + 1)] = aa[a]->value; + else + aa_points[id] = aa[a]->value; + } + + if (SPDAT_RECORDS > 0) + { + for (uint32 z = 0; z= (uint32)SPDAT_RECORDS) + UnmemSpell(z, false); + } + + database.LoadBuffs(this); + uint32 max_slots = GetMaxBuffSlots(); + for (int i = 0; i < max_slots; i++) { + if (buffs[i].spellid != SPELL_UNKNOWN) { + m_pp.buffs[i].spellid = buffs[i].spellid; + m_pp.buffs[i].bard_modifier = 10; + m_pp.buffs[i].slotid = 2; + m_pp.buffs[i].player_id = 0x2211; + m_pp.buffs[i].level = buffs[i].casterlevel; + m_pp.buffs[i].effect = 0; + m_pp.buffs[i].duration = buffs[i].ticsremaining; + m_pp.buffs[i].counters = buffs[i].counters; + } + else { + m_pp.buffs[i].spellid = SPELLBOOK_UNKNOWN; + m_pp.buffs[i].bard_modifier = 10; + m_pp.buffs[i].slotid = 0; + m_pp.buffs[i].player_id = 0; + m_pp.buffs[i].level = 0; + m_pp.buffs[i].effect = 0; + m_pp.buffs[i].duration = 0; + m_pp.buffs[i].counters = 0; + } + } + } + + /* Load Character Key Ring */ + KeyRingLoad(); + + /* Send Group Members via PP */ + uint32 groupid = database.GetGroupID(GetName()); + Group* group = nullptr; + if (groupid > 0){ + group = entity_list.GetGroupByID(groupid); + if (!group) { //nobody from our is here... start a new group + group = new Group(groupid); + if (group->GetID() != 0) + entity_list.AddGroup(group, groupid); + else //error loading group members... + { + delete group; + group = nullptr; + } + } //else, somebody from our group is already here... + + if (group) + group->UpdatePlayer(this); + else + database.SetGroupID(GetName(), 0, CharacterID()); //cannot re-establish group, kill it + + } + else { //no group id + //clear out the group junk in our PP + uint32 xy = 0; + for (xy = 0; xy < MAX_GROUP_MEMBERS; xy++) + memset(m_pp.groupMembers[xy], 0, 64); + } + + if (group){ + // If the group leader is not set, pull the group leader infomrmation from the database. + if (!group->GetLeader()){ + char ln[64]; + char MainTankName[64]; + char AssistName[64]; + char PullerName[64]; + char NPCMarkerName[64]; + GroupLeadershipAA_Struct GLAA; + memset(ln, 0, 64); + strcpy(ln, database.GetGroupLeadershipInfo(group->GetID(), ln, MainTankName, AssistName, PullerName, NPCMarkerName, &GLAA)); + Client *c = entity_list.GetClientByName(ln); + if (c) + group->SetLeader(c); + + group->SetMainTank(MainTankName); + group->SetMainAssist(AssistName); + group->SetPuller(PullerName); + group->SetNPCMarker(NPCMarkerName); + group->SetGroupAAs(&GLAA); + + //group->NotifyMainTank(this, 1); + //group->NotifyMainAssist(this, 1); + //group->NotifyPuller(this, 1); + + // If we are the leader, force an update of our group AAs to other members in the zone, in case + // we purchased a new one while out-of-zone. + if (group->IsLeader(this)) + group->SendLeadershipAAUpdate(); + + } + LFG = false; + } + +#ifdef BOTS + Bot::LoadAndSpawnAllZonedBots(this); +#endif + + CalcBonuses(); + if (m_pp.cur_hp <= 0) + m_pp.cur_hp = GetMaxHP(); + + SetHP(m_pp.cur_hp); + Mob::SetMana(m_pp.mana); + SetEndurance(m_pp.endurance); + + if (IsLFP()) { + // Update LFP in case any (or all) of our group disbanded while we were zoning. + UpdateLFP(); + } + + if (m_pp.z <= zone->newzone_data.underworld) { + m_pp.x = zone->newzone_data.safe_x; + m_pp.y = zone->newzone_data.safe_y; + m_pp.z = zone->newzone_data.safe_z; + } + + /* Get Expansions from variables table and ship via PP */ + char val[20] = { 0 }; + if (database.GetVariable("Expansions", val, 20)) + m_pp.expansions = atoi(val); + else + m_pp.expansions = 0x3FF; + + p_timers.SetCharID(CharacterID()); + if (!p_timers.Load(&database)) { + LogFile->write(EQEMuLog::Error, "Unable to load ability timers from the database for %s (%i)!", GetCleanName(), CharacterID()); + } + + for (unsigned int i = 0; i < MAX_PP_MEMSPELL; ++i) + if (IsValidSpell(m_pp.mem_spells[i])) + m_pp.spellSlotRefresh[i] = p_timers.GetRemainingTime(pTimerSpellStart + m_pp.mem_spells[i]) * 1000; + + /* Ability slot refresh send SK/PAL */ + if (m_pp.class_ == SHADOWKNIGHT || m_pp.class_ == PALADIN) { + uint32 abilitynum = 0; + if (m_pp.class_ == SHADOWKNIGHT){ abilitynum = pTimerHarmTouch; } + else{ abilitynum = pTimerLayHands; } + + uint32 remaining = p_timers.GetRemainingTime(abilitynum); + if (remaining > 0 && remaining < 15300) + m_pp.abilitySlotRefresh = remaining * 1000; + else + m_pp.abilitySlotRefresh = 0; + } + +#ifdef _EQDEBUG + printf("Dumping inventory on load:\n"); + m_inv.dumpEntireInventory(); +#endif + + //lost in current PP + // strcpy(m_pp.servername,"eqemulator"); + + m_pp.air_remaining = 60; //Reset to max so they dont drown on zone in if its underwater + + if (zone->IsPVPZone()) + m_pp.pvp = 1; + + m_pp.timeentitledonaccount = database.GetTotalTimeEntitledOnAccount(AccountID()) / 1440; + + /* Reset rest timer if the durations have been lowered in the database */ + if ((m_pp.RestTimer > RuleI(Character, RestRegenTimeToActivate)) && (m_pp.RestTimer > RuleI(Character, RestRegenRaidTimeToActivate))) + m_pp.RestTimer = 0; + + /* This checksum should disappear once dynamic structs are in... each struct strategy will do it */ + CRC32::SetEQChecksum((unsigned char*)&m_pp, sizeof(PlayerProfile_Struct)-4); + + outapp = new EQApplicationPacket(OP_PlayerProfile, sizeof(PlayerProfile_Struct)); + + /* The entityid field in the Player Profile is used by the Client in relation to Group Leadership AA */ + m_pp.entityid = GetID(); + memcpy(outapp->pBuffer, &m_pp, outapp->size); + outapp->priority = 6; + FastQueuePacket(&outapp); + + if (m_pp.RestTimer) + rest_timer.Start(m_pp.RestTimer * 1000); + + database.LoadPetInfo(this); + /* + This was moved before the spawn packets are sent + in hopes that it adds more consistency... + Remake pet + */ + if (m_petinfo.SpellID > 1 && !GetPet() && m_petinfo.SpellID <= SPDAT_RECORDS) + { + MakePoweredPet(m_petinfo.SpellID, spells[m_petinfo.SpellID].teleport_zone, m_petinfo.petpower, m_petinfo.Name, m_petinfo.size); + if (GetPet() && GetPet()->IsNPC()) { + NPC *pet = GetPet()->CastToNPC(); + pet->SetPetState(m_petinfo.Buffs, m_petinfo.Items); + pet->CalcBonuses(); + pet->SetHP(m_petinfo.HP); + pet->SetMana(m_petinfo.Mana); + } + m_petinfo.SpellID = 0; + } + /* Moved here so it's after where we load the pet data. */ + if (!GetAA(aaPersistentMinion)) + memset(&m_suspendedminion, 0, sizeof(PetInfo)); + + /* Server Zone Entry Packet */ + outapp = new EQApplicationPacket(OP_ZoneEntry, sizeof(ServerZoneEntry_Struct)); + ServerZoneEntry_Struct* sze = (ServerZoneEntry_Struct*)outapp->pBuffer; + + FillSpawnStruct(&sze->player, CastToMob()); + sze->player.spawn.curHp = 1; + sze->player.spawn.NPC = 0; + sze->player.spawn.z += 6; //arbitrary lift, seems to help spawning under zone. + outapp->priority = 6; + FastQueuePacket(&outapp); + + /* Zone Spawns Packet */ + entity_list.SendZoneSpawnsBulk(this); + entity_list.SendZoneCorpsesBulk(this); + entity_list.SendZonePVPUpdates(this); //hack until spawn struct is fixed. + + /* Time of Day packet */ + outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct)); + TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer; + zone->zone_time.getEQTimeOfDay(time(0), tod); + outapp->priority = 6; + FastQueuePacket(&outapp); + + /* Tribute Packets */ + DoTributeUpdate(); + if (m_pp.tribute_active) { + //restart the tribute timer where we left off + tribute_timer.Start(m_pp.tribute_time_remaining); + } + + /* + Character Inventory Packet + this is not quite where live sends inventory, they do it after tribute + */ + if (loaditems) { //dont load if a length error occurs + BulkSendInventoryItems(); + + // Send stuff on the cursor which isnt sent in bulk + iter_queue it; + for (it = m_inv.cursor_begin(); it != m_inv.cursor_end(); ++it) { + // First item cursor is sent in bulk inventory packet + if (it == m_inv.cursor_begin()) + continue; + const ItemInst *inst = *it; + SendItemPacket(MainCursor, inst, ItemPacketSummonItem); + } + } + + /* Task Packets */ + LoadClientTaskState(); + + if (GetClientVersion() >= EQClientRoF) + { + outapp = new EQApplicationPacket(OP_ReqNewZone, 0); + Handle_Connect_OP_ReqNewZone(outapp); + safe_delete(outapp); + } + + if (ClientVersionBit & BIT_UnderfootAndLater) + { + outapp = new EQApplicationPacket(OP_XTargetResponse, 8); + outapp->WriteUInt32(GetMaxXTargets()); + outapp->WriteUInt32(0); + FastQueuePacket(&outapp); + } + + /* + Weather Packet + This shouldent be moved, this seems to be what the client + uses to advance to the next state (sending ReqNewZone) + */ + outapp = new EQApplicationPacket(OP_Weather, 12); + Weather_Struct *ws = (Weather_Struct *)outapp->pBuffer; + ws->val1 = 0x000000FF; + if (zone->zone_weather == 1) + ws->type = 0x31; // Rain + if (zone->zone_weather == 2) + { + outapp->pBuffer[8] = 0x01; + ws->type = 0x02; + } + outapp->priority = 6; + QueuePacket(outapp); + safe_delete(outapp); + + SetAttackTimer(); + + conn_state = ZoneInfoSent; + return; } @@ -8692,11 +9174,6 @@ void Client::Handle_OP_FindPersonRequest(const EQApplicationPacket *app) void Client::DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw) { Entity::DBAWComplete(workpt_b1, dbaw); switch (workpt_b1) { - case DBA_b1_Entity_Client_InfoForLogin: { - if (!FinishConnState2(dbaw)) - client_state = CLIENT_ERROR; - break; - } case DBA_b1_Entity_Client_Save: { clock_t t = std::clock(); /* Function timer start */ @@ -8726,539 +9203,6 @@ void Client::DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw) { } } -bool Client::FinishConnState2(DBAsyncWork* dbaw) { - uint32 pplen = 0; - DBAsyncQuery* dbaq = 0; - EQApplicationPacket* outapp = 0; - MYSQL_RES* result = 0; - bool loaditems = 0; - char errbuf[MYSQL_ERRMSG_SIZE]; - uint32 i; - - for (i=1; i<=3; i++) { - dbaq = dbaw->PopAnswer(); - if (!dbaq) { - std::cout << "Error in FinishConnState2(): dbaq==0" << std::endl; - return false; - } - if (!dbaq->GetAnswer(errbuf, &result)) { - std::cout << "Error in FinishConnState2(): !dbaq[" << dbaq->QPT() << "]->GetAnswer(): " << errbuf << std::endl; - return false; - } - if (dbaq->QPT() == 1) { - database.GetAccountInfoForLogin_result(result, 0, account_name, &lsaccountid, &gmspeed, &revoked, &gmhideme, &account_creation); - if(gmhideme) - { - trackable = false; - } - } - else if (dbaq->QPT() == 2) { - loaditems = database.GetCharacterInfoForLogin_result(result, 0, 0, &m_pp, &m_inv, &m_epp, &pplen, &guild_id, &guildrank, &class_, &level, &LFP, &LFG, &MaxXTargets, &firstlogon); - } - else if (dbaq->QPT() == 3) { - database.RemoveTempFactions(this); - database.LoadFactionValues_result(result, factionvalues); - } - else { - std::cout << "Error in FinishConnState2(): dbaq->PQT() unknown" << std::endl; - return false; - } - } - - /* Load Character Currency into PP */ - database.LoadCharacterCurrency(CharacterID(), &m_pp); - /* Load Character Data from DB into PP */ - database.LoadCharacterData(CharacterID(), &m_pp); - /* Move to another method when can, this is pointless... */ - database.GetPlayerInspectMessage(m_pp.name, &m_inspect_message); - /* Load Character Currency*/ - database.LoadCharacterCurrency(CharacterID(), &m_pp); - - conn_state = PlayerProfileLoaded; - /* Set Current zone */ - m_pp.zone_id = zone->GetZoneID(); - m_pp.zoneInstance = zone->GetInstanceID(); - - TotalSecondsPlayed = m_pp.timePlayedMin * 60; - - max_AAXP = RuleI(AA, ExpPerPoint); - - if(!RuleB(Character, MaintainIntoxicationAcrossZones)) - m_pp.intoxication = 0; - - if((m_pp.x == -1 && m_pp.y == -1 && m_pp.z == -1)||(m_pp.x == -2 && m_pp.y == -2 && m_pp.z == -2)) { - m_pp.x = zone->safe_x(); - m_pp.y = zone->safe_y(); - m_pp.z = zone->safe_z(); - } - - - class_ = m_pp.class_; - - if(level > 0) { - if(m_pp.level != level) { - //they changed their level in the database... not ideal, but oh well.. - m_pp.exp = GetEXPForLevel(level); - m_pp.level = level; - } - } else { - level = m_pp.level; - } - - x_pos = m_pp.x; - y_pos = m_pp.y; - z_pos = m_pp.z; - heading = m_pp.heading; - race = m_pp.race; - base_race = m_pp.race; - gender = m_pp.gender; - base_gender = m_pp.gender; - deity = m_pp.deity; //FYI: DEITY_AGNOSTIC = 396; still valid? - haircolor = m_pp.haircolor; - beardcolor = m_pp.beardcolor; - eyecolor1 = m_pp.eyecolor1; - eyecolor2 = m_pp.eyecolor2; - hairstyle = m_pp.hairstyle; - luclinface = m_pp.face; - beard = m_pp.beard; - drakkin_heritage = m_pp.drakkin_heritage; - drakkin_tattoo = m_pp.drakkin_tattoo; - drakkin_details = m_pp.drakkin_details; - - //if we zone in with invalid Z, fix it. - if (zone->zonemap != nullptr) { - Map::Vertex me; - me.x = GetX(); - me.y = GetY(); - me.z = GetZ() + (GetSize() == 0.0 ? 6 : GetSize()); - - Map::Vertex hit; - - if (zone->zonemap->FindBestZ(me, &hit) == BEST_Z_INVALID) - { -#if EQDEBUG >= 5 - LogFile->write(EQEMuLog::Debug, "Player %s started below the zone trying to fix! (%.3f, %.3f, %.3f)", GetName(), me.x, me.y, me.z); -#endif - me.z += 200; //arbitrary # - if (zone->zonemap->FindBestZ(me, &hit) != BEST_Z_INVALID) - { - //+10 so they dont stick in the ground - SendTo(me.x, me.y, hit.z + 10); - m_pp.z = hit.z + 10; - } - else - { - //one more, desperate try - me.z += 2000; - if (zone->zonemap->FindBestZ(me, &hit) != BEST_Z_INVALID) - { - //+10 so they dont stick in the ground - SendTo(me.x, me.y, hit.z + 10); - m_pp.z = hit.z + 10; - } - } - } - } - - if (m_pp.gm && admin < minStatusToBeGM) - m_pp.gm = 0; - - - - /* Load Guild */ - if (!IsInAGuild()) { m_pp.guild_id = GUILD_NONE; } - else { - m_pp.guild_id = GuildID(); - - if(zone->GetZoneID() == RuleI(World, GuildBankZoneID)) - GuildBanker = (guild_mgr.IsGuildLeader(GuildID(), CharacterID()) || guild_mgr.GetBankerFlag(CharacterID())); - } - - m_pp.guildbanker = GuildBanker; - - switch (race) - { - case OGRE: - size = 9; break; - case TROLL: - size = 8; break; - case VAHSHIR: case BARBARIAN: - size = 7; break; - case HUMAN: case HIGH_ELF: case ERUDITE: case IKSAR: case DRAKKIN: - size = 6; break; - case HALF_ELF: - size = 5.5; break; - case WOOD_ELF: case DARK_ELF: case FROGLOK: - size = 5; break; - case DWARF: - size = 4; break; - case HALFLING: - size = 3.5; break; - case GNOME: - size = 3; break; - default: - size = 0; - } - - /* Check for Invalid points */ - if (m_pp.ldon_points_guk < 0 || m_pp.ldon_points_guk > 2000000000){ m_pp.ldon_points_guk = 0; } - if (m_pp.ldon_points_mir < 0 || m_pp.ldon_points_mir > 2000000000){ m_pp.ldon_points_mir = 0; } - if (m_pp.ldon_points_mmc < 0 || m_pp.ldon_points_mmc > 2000000000){ m_pp.ldon_points_mmc = 0; } - if (m_pp.ldon_points_ruj < 0 || m_pp.ldon_points_ruj > 2000000000){ m_pp.ldon_points_ruj = 0; } - if (m_pp.ldon_points_tak < 0 || m_pp.ldon_points_tak > 2000000000){ m_pp.ldon_points_tak = 0; } - if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; } - - if(GetSkill(SkillSwimming) < 100) - SetSkill(SkillSwimming, 100); - - - - /* Load Character AA's */ - //database.LoadCharacterAA(this->CharacterID(), &m_pp, &aa, &aa_points); - - /* Initialize AA's */ - for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ - aa[a] = &m_pp.aa_array[a]; - } - std::string query = StringFormat( - "SELECT " - "slot, " - "aa_id, " - "aa_value " - "FROM " - "`character_alternate_abilities` " - "WHERE `id` = %i ORDER BY `slot`", this->CharacterID()); - auto results = database.QueryDatabase(query); int si = 0; - for (auto row = results.begin(); row != results.end(); ++row) { - si = atoi(row[0]); - m_pp.aa_array[si].AA = atoi(row[1]); - m_pp.aa_array[si].value = atoi(row[1]); - aa[si]->AA = atoi(row[1]); - aa[si]->value = atoi(row[2]); - } - for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ - uint32 id = aa[a]->AA; - //watch for invalid AA IDs - if (id == aaNone) - continue; - if (id >= aaHighestID) { - aa[a]->AA = aaNone; - aa[a]->value = 0; - continue; - } - if (aa[a]->value == 0) { - aa[a]->AA = aaNone; - continue; - } - if (aa[a]->value > HIGHEST_AA_VALUE) { - aa[a]->AA = aaNone; - aa[a]->value = 0; - continue; - } - - if (aa[a]->value > 1) /* hack in some stuff for sony's new AA method (where each level of each aa.has a seperate ID) */ - aa_points[(id - aa[a]->value + 1)] = aa[a]->value; - else - aa_points[id] = aa[a]->value; - } - - if(SPDAT_RECORDS > 0) - { - for(uint32 z=0;z= (uint32)SPDAT_RECORDS) - UnmemSpell(z, false); - } - - database.LoadBuffs(this); - uint32 max_slots = GetMaxBuffSlots(); - for(int i = 0; i < max_slots; i++) { - if(buffs[i].spellid != SPELL_UNKNOWN) { - m_pp.buffs[i].spellid = buffs[i].spellid; - m_pp.buffs[i].bard_modifier = 10; - m_pp.buffs[i].slotid = 2; - m_pp.buffs[i].player_id = 0x2211; - m_pp.buffs[i].level = buffs[i].casterlevel; - m_pp.buffs[i].effect = 0; - m_pp.buffs[i].duration = buffs[i].ticsremaining; - m_pp.buffs[i].counters = buffs[i].counters; - } else { - m_pp.buffs[i].spellid = SPELLBOOK_UNKNOWN; - m_pp.buffs[i].bard_modifier = 10; - m_pp.buffs[i].slotid = 0; - m_pp.buffs[i].player_id = 0; - m_pp.buffs[i].level = 0; - m_pp.buffs[i].effect = 0; - m_pp.buffs[i].duration = 0; - m_pp.buffs[i].counters = 0; - } - } - } - - /* Load Character Key Ring */ - KeyRingLoad(); - - /* Send Group Members via PP */ - uint32 groupid = database.GetGroupID(GetName()); - Group* group = nullptr; - if(groupid > 0){ - group = entity_list.GetGroupByID(groupid); - if(!group) { //nobody from our is here... start a new group - group = new Group(groupid); - if(group->GetID() != 0) - entity_list.AddGroup(group, groupid); - else //error loading group members... - { - delete group; - group = nullptr; - } - } //else, somebody from our group is already here... - - if(group) - group->UpdatePlayer(this); - else - database.SetGroupID(GetName(), 0, CharacterID()); //cannot re-establish group, kill it - - } else { //no group id - //clear out the group junk in our PP - uint32 xy=0; - for(xy=0;xy < MAX_GROUP_MEMBERS;xy++) - memset(m_pp.groupMembers[xy], 0, 64); - } - - if(group){ - // If the group leader is not set, pull the group leader infomrmation from the database. - if(!group->GetLeader()){ - char ln[64]; - char MainTankName[64]; - char AssistName[64]; - char PullerName[64]; - char NPCMarkerName[64]; - GroupLeadershipAA_Struct GLAA; - memset(ln, 0, 64); - strcpy(ln, database.GetGroupLeadershipInfo(group->GetID(), ln, MainTankName, AssistName, PullerName, NPCMarkerName, &GLAA)); - Client *c = entity_list.GetClientByName(ln); - if(c) - group->SetLeader(c); - - group->SetMainTank(MainTankName); - group->SetMainAssist(AssistName); - group->SetPuller(PullerName); - group->SetNPCMarker(NPCMarkerName); - group->SetGroupAAs(&GLAA); - - //group->NotifyMainTank(this, 1); - //group->NotifyMainAssist(this, 1); - //group->NotifyPuller(this, 1); - - // If we are the leader, force an update of our group AAs to other members in the zone, in case - // we purchased a new one while out-of-zone. - if(group->IsLeader(this)) - group->SendLeadershipAAUpdate(); - - } - LFG = false; - } - -#ifdef BOTS - Bot::LoadAndSpawnAllZonedBots(this); -#endif - - CalcBonuses(); - if (m_pp.cur_hp <= 0) - m_pp.cur_hp = GetMaxHP(); - - SetHP(m_pp.cur_hp); - Mob::SetMana(m_pp.mana); - SetEndurance(m_pp.endurance); - - if(IsLFP()) { - // Update LFP in case any (or all) of our group disbanded while we were zoning. - UpdateLFP(); - } - - if(m_pp.z <= zone->newzone_data.underworld) { - m_pp.x = zone->newzone_data.safe_x; - m_pp.y = zone->newzone_data.safe_y; - m_pp.z = zone->newzone_data.safe_z; - } - - /* Get Expansions from variables table and ship via PP */ - char val[20] = {0}; - if (database.GetVariable("Expansions", val, 20)) - m_pp.expansions = atoi(val); - else - m_pp.expansions = 0x3FF; - - p_timers.SetCharID(CharacterID()); - if(!p_timers.Load(&database)) { - LogFile->write(EQEMuLog::Error, "Unable to load ability timers from the database for %s (%i)!", GetCleanName(), CharacterID()); - } - - for(unsigned int i =0 ; i < MAX_PP_MEMSPELL; ++i) - if(IsValidSpell(m_pp.mem_spells[i])) - m_pp.spellSlotRefresh[i] = p_timers.GetRemainingTime(pTimerSpellStart + m_pp.mem_spells[i]) * 1000; - - /* Ability slot refresh send SK/PAL */ - if(m_pp.class_==SHADOWKNIGHT || m_pp.class_==PALADIN) { - uint32 abilitynum=0; - if (m_pp.class_ == SHADOWKNIGHT){ abilitynum = pTimerHarmTouch; } - else{ abilitynum = pTimerLayHands; } - - uint32 remaining = p_timers.GetRemainingTime(abilitynum); - if(remaining > 0 && remaining < 15300) - m_pp.abilitySlotRefresh = remaining * 1000; - else - m_pp.abilitySlotRefresh = 0; - } - -#ifdef _EQDEBUG - printf("Dumping inventory on load:\n"); - m_inv.dumpEntireInventory(); -#endif - -//lost in current PP -// strcpy(m_pp.servername,"eqemulator"); - - m_pp.air_remaining = 60; //Reset to max so they dont drown on zone in if its underwater - - if(zone->IsPVPZone()) - m_pp.pvp=1; - - m_pp.timeentitledonaccount = database.GetTotalTimeEntitledOnAccount(AccountID()) / 1440; - - /* Reset rest timer if the durations have been lowered in the database */ - if ((m_pp.RestTimer > RuleI(Character, RestRegenTimeToActivate)) && (m_pp.RestTimer > RuleI(Character, RestRegenRaidTimeToActivate))) - m_pp.RestTimer = 0; - - /* This checksum should disappear once dynamic structs are in... each struct strategy will do it */ - CRC32::SetEQChecksum((unsigned char*)&m_pp, sizeof(PlayerProfile_Struct)-4); - - outapp = new EQApplicationPacket(OP_PlayerProfile,sizeof(PlayerProfile_Struct)); - - /* The entityid field in the Player Profile is used by the Client in relation to Group Leadership AA */ - m_pp.entityid = GetID(); - memcpy(outapp->pBuffer,&m_pp,outapp->size); - outapp->priority = 6; - FastQueuePacket(&outapp); - - if(m_pp.RestTimer) - rest_timer.Start(m_pp.RestTimer * 1000); - - database.LoadPetInfo(this); - /* - This was moved before the spawn packets are sent - in hopes that it adds more consistency... - Remake pet - */ - if (m_petinfo.SpellID > 1 && !GetPet() && m_petinfo.SpellID <= SPDAT_RECORDS) - { - MakePoweredPet(m_petinfo.SpellID, spells[m_petinfo.SpellID].teleport_zone, m_petinfo.petpower, m_petinfo.Name, m_petinfo.size); - if (GetPet() && GetPet()->IsNPC()) { - NPC *pet = GetPet()->CastToNPC(); - pet->SetPetState(m_petinfo.Buffs, m_petinfo.Items); - pet->CalcBonuses(); - pet->SetHP(m_petinfo.HP); - pet->SetMana(m_petinfo.Mana); - } - m_petinfo.SpellID = 0; - } - /* Moved here so it's after where we load the pet data. */ - if(!GetAA(aaPersistentMinion)) - memset(&m_suspendedminion, 0, sizeof(PetInfo)); - - /* Server Zone Entry Packet */ - outapp = new EQApplicationPacket(OP_ZoneEntry, sizeof(ServerZoneEntry_Struct)); - ServerZoneEntry_Struct* sze = (ServerZoneEntry_Struct*)outapp->pBuffer; - - FillSpawnStruct(&sze->player,CastToMob()); - sze->player.spawn.curHp=1; - sze->player.spawn.NPC=0; - sze->player.spawn.z += 6; //arbitrary lift, seems to help spawning under zone. - outapp->priority = 6; - FastQueuePacket(&outapp); - - /* Zone Spawns Packet */ - entity_list.SendZoneSpawnsBulk(this); - entity_list.SendZoneCorpsesBulk(this); - entity_list.SendZonePVPUpdates(this); //hack until spawn struct is fixed. - - /* Time of Day packet */ - outapp = new EQApplicationPacket(OP_TimeOfDay, sizeof(TimeOfDay_Struct)); - TimeOfDay_Struct* tod = (TimeOfDay_Struct*)outapp->pBuffer; - zone->zone_time.getEQTimeOfDay(time(0), tod); - outapp->priority = 6; - FastQueuePacket(&outapp); - - /* Tribute Packets */ - DoTributeUpdate(); - if(m_pp.tribute_active) { - //restart the tribute timer where we left off - tribute_timer.Start(m_pp.tribute_time_remaining); - } - - /* - Character Inventory Packet - this is not quite where live sends inventory, they do it after tribute - */ - if (loaditems) { //dont load if a length error occurs - BulkSendInventoryItems(); - - // Send stuff on the cursor which isnt sent in bulk - iter_queue it; - for (it=m_inv.cursor_begin();it!=m_inv.cursor_end();++it) { - // First item cursor is sent in bulk inventory packet - if (it==m_inv.cursor_begin()) - continue; - const ItemInst *inst=*it; - SendItemPacket(MainCursor, inst, ItemPacketSummonItem); - } - } - - /* Task Packets */ - LoadClientTaskState(); - - if (GetClientVersion() >= EQClientRoF) - { - outapp = new EQApplicationPacket(OP_ReqNewZone, 0); - Handle_Connect_OP_ReqNewZone(outapp); - safe_delete(outapp); - } - - if(ClientVersionBit & BIT_UnderfootAndLater) - { - outapp = new EQApplicationPacket(OP_XTargetResponse, 8); - outapp->WriteUInt32(GetMaxXTargets()); - outapp->WriteUInt32(0); - FastQueuePacket(&outapp); - } - - /* - Weather Packet - This shouldent be moved, this seems to be what the client - uses to advance to the next state (sending ReqNewZone) - */ - outapp = new EQApplicationPacket(OP_Weather, 12); - Weather_Struct *ws = (Weather_Struct *) outapp->pBuffer; - ws->val1 = 0x000000FF; - if (zone->zone_weather == 1) - ws->type = 0x31; // Rain - if (zone->zone_weather == 2) - { - outapp->pBuffer[8] = 0x01; - ws->type = 0x02; - } - outapp->priority = 6; - QueuePacket(outapp); - safe_delete(outapp); - - SetAttackTimer(); - - conn_state = ZoneInfoSent; - - return true; -} - /* Finish client connecting state */ void Client::CompleteConnect() { UpdateWho(); diff --git a/zone/effects.cpp b/zone/effects.cpp index a24a6b39b..5e07d5f9a 100644 --- a/zone/effects.cpp +++ b/zone/effects.cpp @@ -616,13 +616,9 @@ bool Client::TrainDiscipline(uint32 itemid) { } void Client::SendDisciplineUpdate() { - //this dosent seem to work right now - EQApplicationPacket app(OP_DisciplineUpdate, sizeof(Disciplines_Struct)); Disciplines_Struct *d = (Disciplines_Struct*)app.pBuffer; - //dunno why I dont just send the one from m_pp memcpy(d, &m_pp.disciplines, sizeof(m_pp.disciplines)); - QueuePacket(&app); } diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index e7bad016c..4eb0e64ab 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -370,41 +370,6 @@ void ZoneDatabase::UpdateBug(PetitionBug_Struct* bug){ safe_delete_array(bugtext); } - -bool ZoneDatabase::GetAccountInfoForLogin_result(MYSQL_RES* result, int16* admin, char* account_name, uint32* lsaccountid, uint8* gmspeed, bool* revoked,bool* gmhideme, uint32* account_creation) { - MYSQL_ROW row; - if (mysql_num_rows(result) == 1) { - row = mysql_fetch_row(result); - if (admin) - *admin = atoi(row[0]); - if (account_name) - strcpy(account_name, row[1]); - if (lsaccountid) { - - if (row[2]) - *lsaccountid = atoi(row[2]); - else - *lsaccountid = 0; - - - } - if (gmspeed) - *gmspeed = atoi(row[3]); - if (revoked) - *revoked = atoi(row[4]); - if(gmhideme) - *gmhideme = atoi(row[5]); - if(account_creation) - *account_creation = atoul(row[6]); - - return true; - } - else { - return false; - } -} - - bool ZoneDatabase::SetSpecialAttkFlag(uint8 id, const char* flag) { char errbuf[MYSQL_ERRMSG_SIZE]; char *query = 0; @@ -859,43 +824,8 @@ void ZoneDatabase::UpdateBuyLine(uint32 CharID, uint32 BuySlot, uint32 Quantity) } -bool ZoneDatabase::GetCharacterInfoForLogin(const char* name, uint32* character_id, - char* current_zone, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext, - uint32* pplen, uint32* guilddbid, uint8* guildrank, - uint8 *class_, uint8 *level, bool *LFP, bool *LFG, uint8 *NumXTargets, uint8 *firstlogon) { - - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - uint32 querylen; - MYSQL_RES *result; - - bool ret = false; - - //DO NOT FORGET TO EDIT Client::Handle_Connect_OP_ZoneEntry if you change this. - - if (character_id && *character_id) { - // searching by ID should be a lil bit faster - querylen = MakeAnyLenString(&query, "SELECT id,profile,zonename,x,y,z,guild_id,rank,extprofile,class,level,lfp,lfg,instanceid,xtargets,firstlogon FROM character_ LEFT JOIN guild_members ON id=char_id WHERE id=%i", *character_id); - } - else { - querylen = MakeAnyLenString(&query, "SELECT id,profile,zonename,x,y,z,guild_id,rank,extprofile,class,level,lfp,lfg,instanceid,xtargets,firstlogon FROM character_ LEFT JOIN guild_members ON id=char_id WHERE name='%s'", name); - } - - if (RunQuery(query, querylen, errbuf, &result)) { - ret = GetCharacterInfoForLogin_result(result, character_id, current_zone, pp, inv, ext, pplen, guilddbid, guildrank, class_, level, LFP, LFG, NumXTargets, firstlogon); - mysql_free_result(result); - } - else { - LogFile->write(EQEMuLog::Error, "GetCharacterInfoForLogin query '%s' %s", query, errbuf); - } - - safe_delete_array(query); - return ret; -} - #define StructDist(in, f1, f2) (uint32(&in->f2)-uint32(&in->f1)) - bool ZoneDatabase::LoadCharacterData(uint32 character_id, PlayerProfile_Struct* pp){ std::string query = StringFormat( "SELECT " @@ -1085,6 +1015,38 @@ bool ZoneDatabase::LoadCharacterData(uint32 character_id, PlayerProfile_Struct* return true; } +bool ZoneDatabase::LoadCharacterFactionValues(uint32 character_id, faction_map & val_list) { + std::string query = StringFormat("SELECT faction_id,current_value FROM faction_values WHERE char_id = %i", character_id); + auto results = database.QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { val_list[atoi(row[0])] = atoi(row[1]); } + return true; +} + +bool ZoneDatabase::LoadCharacterDisciplines(uint32 character_id, PlayerProfile_Struct* pp){ + std::string query = StringFormat( + "SELECT " + "disc_id " + "FROM " + "`character_disciplines`" + "WHERE `id` = %u ORDER BY `disc_id`", character_id); + auto results = database.QueryDatabase(query); int i = 0; + for (auto row = results.begin(); row != results.end(); ++row) { pp->disciplines.values[i] = atoi(row[0]); i++; } + return true; +} + +bool ZoneDatabase::LoadCharacterSkills(uint32 character_id, PlayerProfile_Struct* pp){ + std::string query = StringFormat( + "SELECT " + "skill_id, " + "`value` " + "FROM " + "`character_skills` " + "WHERE `id` = %u ORDER BY `skill_id`", character_id); + auto results = database.QueryDatabase(query); int i = 0; + for (auto row = results.begin(); row != results.end(); ++row) { i = atoi(row[0]); pp->skills[i] = atoi(row[1]); } + return true; +} + bool ZoneDatabase::LoadCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp){ std::string query = StringFormat( "SELECT " @@ -1458,103 +1420,6 @@ bool ZoneDatabase::SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 cur return true; } -// Process results of GetCharacterInfoForLogin() -// Query this processes: SELECT id,profile,zonename,x,y,z,guild,guildrank,extprofile,class,level FROM character_ WHERE id=%i -bool ZoneDatabase::GetCharacterInfoForLogin_result(MYSQL_RES* result, - uint32* character_id, char* current_zone, PlayerProfile_Struct* pp, Inventory* inv, - ExtendedProfile_Struct *ext, uint32* pplen, uint32* guilddbid, uint8* guildrank, - uint8 *class_, uint8 *level, bool *LFP, bool *LFG, uint8 *NumXTargets, uint8* firstlogon) { - - MYSQL_ROW row; - unsigned long* lengths; - - if (mysql_num_rows(result) == 1) { - row = mysql_fetch_row(result); - lengths = mysql_fetch_lengths(result); - if (pp && pplen) { - if (lengths[1] == sizeof(PlayerProfile_Struct)) { - // memcpy(pp, row[1], sizeof(PlayerProfile_Struct)); - } else { - LogFile->write(EQEMuLog::Error, "Player profile length mismatch in GetCharacterInfo Expected: %i, Got: %i", - sizeof(PlayerProfile_Struct), lengths[1]); - return false; - } - - *pplen = lengths[1]; - pp->zone_id = GetZoneID(row[2]); - pp->zoneInstance = atoi(row[13]); - - pp->x = atof(row[3]); - pp->y = atof(row[4]); - pp->z = atof(row[5]); - - pp->lastlogin = time(nullptr); - - if (pp->x == -1 && pp->y == -1 && pp->z == -1) - GetSafePoints(pp->zone_id, database.GetInstanceVersion(pp->zoneInstance), &pp->x, &pp->y, &pp->z); - } - - uint32 char_id = atoi(row[0]); - if (RuleB(Character, SharedBankPlat)) - pp->platinum_shared = database.GetSharedPlatinum(GetAccountIDByChar(char_id)); - if (character_id) - *character_id = char_id; - if (current_zone) - strcpy(current_zone, row[2]); - - if (guilddbid) { - if(row[6] != nullptr) - *guilddbid = atoi(row[6]); - else - *guilddbid = GUILD_NONE; - } - if (guildrank) { - if(row[7] != nullptr) - *guildrank = atoi(row[7]); - else - *guildrank = GUILD_RANK_NONE; - } - - if(ext) { - //SetExtendedProfile handles any conversion - SetExtendedProfile(ext, row[8], lengths[8]); - } - - if(class_) - *class_ = atoi(row[9]); - - if(level) - *level = atoi(row[10]); - - if(LFP) - *LFP = atoi(row[11]); - - if(LFG) - *LFG = atoi(row[12]); - - if(NumXTargets) - { - *NumXTargets = atoi(row[14]); - } - - - if(firstlogon) - { - *firstlogon = atoi(row[15]); - } - - // Fix use_tint, previously it was set to 1 for a dyed slot, client wants it set to 0xFF - for(int i = EmuConstants::MATERIAL_BEGIN; i <= EmuConstants::MATERIAL_END; i++) - if(pp->item_tint[i].rgb.use_tint == 1) - pp->item_tint[i].rgb.use_tint = 0xFF; - - // Retrieve character inventory - return GetInventory(char_id, inv); - } - - return false; -} - bool ZoneDatabase::NoRentExpired(const char* name){ char errbuf[MYSQL_ERRMSG_SIZE]; char *query = 0; @@ -2812,31 +2677,6 @@ bool ZoneDatabase::SetZoneTZ(uint32 zoneid, uint32 version, uint32 tz) { } //End new timezone functions. -/* - solar: this is never actually called, client_process starts an async query - instead and uses GetAccountInfoForLogin_result to process it.. - */ -bool ZoneDatabase::GetAccountInfoForLogin(uint32 account_id, int16* admin, char* account_name, uint32* lsaccountid, uint8* gmspeed, bool* revoked,bool* gmhideme) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - MYSQL_RES *result; - - if (RunQuery(query, MakeAnyLenString(&query, "SELECT status, name, lsaccount_id, gmspeed, revoked, hideme FROM account WHERE id=%i", account_id), errbuf, &result)) { - safe_delete_array(query); - bool ret = GetAccountInfoForLogin_result(result, admin, account_name, lsaccountid, gmspeed, revoked,gmhideme); - mysql_free_result(result); - return ret; - } - else - { - std::cerr << "Error in GetAccountInfoForLogin query '" << query << "' " << errbuf << std::endl; - safe_delete_array(query); - return false; - } - - return false; -} - void ZoneDatabase::RefreshGroupFromDB(Client *c){ if(!c){ return; @@ -3568,31 +3408,6 @@ bool ZoneDatabase::GetFactionData(FactionMods* fm, uint32 class_mod, uint32 race return true; } -bool ZoneDatabase::LoadFactionValues(uint32 char_id, faction_map & val_list) { - char errbuf[MYSQL_ERRMSG_SIZE]; - char *query = 0; - MYSQL_RES *result; - if (RunQuery(query, MakeAnyLenString(&query, "SELECT faction_id,current_value FROM faction_values WHERE char_id = %i",char_id), errbuf, &result)) { - safe_delete_array(query); - bool ret = LoadFactionValues_result(result, val_list); - mysql_free_result(result); - return ret; - } - else { - std::cerr << "Error in LoadFactionValues query '" << query << "' " << errbuf << std::endl; - safe_delete_array(query); - } - return false; -} - -bool ZoneDatabase::LoadFactionValues_result(MYSQL_RES* result, faction_map & val_list) { - MYSQL_ROW row; - while((row = mysql_fetch_row(result))) { - val_list[atoi(row[0])] = atoi(row[1]); - } - return true; -} - //o-------------------------------------------------------------- //| Name: GetFactionName; rembrant, Dec. 16 //o-------------------------------------------------------------- diff --git a/zone/zonedb.h b/zone/zonedb.h index d0e70b995..ce32e919f 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -249,20 +249,7 @@ public: void StoreCharacterLookup(uint32 char_id); bool SetServerFilters(char* name, ServerSideFilters_Struct *ssfs); uint32 GetServerFilters(char* name, ServerSideFilters_Struct *ssfs); - bool GetAccountInfoForLogin(uint32 account_id, int16* admin = 0, char* account_name = 0, - uint32* lsaccountid = 0, uint8* gmspeed = 0, bool* revoked = 0, bool* gmhideme = 0); - bool GetAccountInfoForLogin_result(MYSQL_RES* result, int16* admin = 0, char* account_name = 0, - uint32* lsaccountid = 0, uint8* gmspeed = 0, bool* revoked = 0, bool* gmhideme = nullptr, - uint32* account_creation = 0); - bool GetCharacterInfoForLogin_result(MYSQL_RES* result, uint32* character_id = 0, char* current_zone = 0, - PlayerProfile_Struct* pp = 0, Inventory* inv = 0, ExtendedProfile_Struct *ext = 0, uint32* pplen = 0, - uint32* guilddbid = 0, uint8* guildrank = 0, uint8 *class_= 0, uint8 *level = 0, bool *LFP = 0, - bool *LFG = 0, uint8 *NumXTargets = 0, uint8* firstlogon = 0); - bool GetCharacterInfoForLogin(const char* name, uint32* character_id = 0, char* current_zone = 0, - PlayerProfile_Struct* pp = 0, Inventory* inv = 0, ExtendedProfile_Struct *ext = 0, uint32* pplen = 0, - uint32* guilddbid = 0, uint8* guildrank = 0, uint8 *class_ = 0, uint8 *level = 0, bool *LFP = 0, - bool *LFG = 0, uint8 *NumXTargets = 0, uint8* firstlogon = 0); void SaveBuffs(Client *c); void LoadBuffs(Client *c); void LoadPetInfo(Client *c); @@ -270,6 +257,9 @@ public: void RemoveTempFactions(Client *c); /* Player Profile Loaders */ + bool LoadCharacterFactionValues(uint32 character_id, faction_map & val_list); + bool LoadCharacterDisciplines(uint32 character_id, PlayerProfile_Struct* pp); + bool LoadCharacterSkills(uint32 character_id, PlayerProfile_Struct* pp); bool LoadCharacterData(uint32 character_id, PlayerProfile_Struct* pp); bool LoadCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp); @@ -321,8 +311,6 @@ public: bool GetFactionIdsForNPC(uint32 nfl_id, std::list *faction_list, int32* primary_faction = 0); // neotokyo: improve faction handling bool SetCharacterFactionLevel(uint32 char_id, int32 faction_id, int32 value, uint8 temp, faction_map &val_list); // rembrant, needed for factions Dec, 16 2001 bool LoadFactionData(); - bool LoadFactionValues(uint32 char_id, faction_map & val_list); - bool LoadFactionValues_result(MYSQL_RES* result, faction_map & val_list); /* * AAs