2016-03-24 18:50:31 -04:00
/* EQEMu: Everquest Server Emulator
Copyright ( C ) 2001 - 2016 EQEMu Development Team ( http : //eqemulator.org)
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; version 2 of the License .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY except by those people which sell it , which
are required to give you total support for your newly bought product ;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE . See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2015-01-19 04:12:09 -06:00
# include "../common/global_define.h"
2014-08-21 19:33:02 -07:00
# include "../common/eq_packet.h"
# include "../common/eq_stream_intf.h"
2013-02-16 16:14:39 -08:00
# include "../common/misc.h"
2013-05-21 00:12:28 -07:00
# include "../common/rulesys.h"
# include "../common/emu_opcodes.h"
# include "../common/eq_packet_structs.h"
# include "../common/packet_dump.h"
2014-08-21 19:33:02 -07:00
# include "../common/eq_stream_intf.h"
2016-10-17 02:41:09 -04:00
# include "../common/inventory_profile.h"
2013-05-21 00:12:28 -07:00
# include "../common/races.h"
# include "../common/classes.h"
# include "../common/languages.h"
# include "../common/skills.h"
# include "../common/extprofile.h"
2014-08-21 19:33:02 -07:00
# include "../common/string_util.h"
2016-05-28 04:44:14 -04:00
# include "../common/emu_versions.h"
2014-12-01 18:13:12 -05:00
# include "../common/random.h"
2015-02-17 13:56:58 -05:00
# include "../common/shareddb.h"
2013-05-21 00:12:28 -07:00
2013-05-22 18:36:07 -07:00
# include "client.h"
# include "worlddb.h"
2014-08-21 23:30:09 -07:00
# include "world_config.h"
# include "login_server.h"
# include "login_server_list.h"
2013-05-22 18:36:07 -07:00
# include "zoneserver.h"
# include "zonelist.h"
# include "clientlist.h"
# include "wguild_mgr.h"
2014-08-21 23:30:09 -07:00
# include "sof_char_create_data.h"
2013-05-22 18:36:07 -07:00
2013-02-16 16:14:39 -08:00
# include <iostream>
# include <iomanip>
2013-05-21 00:12:28 -07:00
2013-02-16 16:14:39 -08:00
# include <string.h>
# include <stdio.h>
# include <stdlib.h>
# include <zlib.h>
# include <limits.h>
//FatherNitwit: uncomment to enable my IP based authentication hack
//#define IPBASED_AUTH_HACK
// Disgrace: for windows compile
# ifdef _WINDOWS
2016-05-25 13:46:47 -04:00
# include <winsock2.h>
2013-02-16 16:14:39 -08:00
# include <windows.h>
# else
2013-05-21 00:12:28 -07:00
# ifdef FREEBSD //Timothy Whitman - January 7, 2003
# include <sys/types.h>
# endif
2013-02-16 16:14:39 -08:00
# include <sys/socket.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <unistd.h>
# endif
std : : vector < RaceClassAllocation > character_create_allocations ;
std : : vector < RaceClassCombos > character_create_race_class_combos ;
extern ZSList zoneserver_list ;
extern LoginServerList loginserverlist ;
extern ClientList client_list ;
2020-05-17 18:36:06 -07:00
extern EQ : : Random emu_random ;
2013-02-16 16:14:39 -08:00
extern uint32 numclients ;
extern volatile bool RunLoops ;
2018-03-04 21:38:17 -05:00
extern volatile bool UCSServerAvailable_ ;
2013-02-16 16:14:39 -08:00
Client : : Client ( EQStreamInterface * ieqs )
2013-05-09 10:44:08 -04:00
: autobootup_timeout ( RuleI ( World , ZoneAutobootTimeoutMS ) ) ,
connect ( 1000 ) ,
eqs ( ieqs )
2013-02-16 16:14:39 -08:00
{
// Live does not send datarate as of 3/11/2005
//eqs->SetDataRate(7);
ip = eqs - > GetRemoteIP ( ) ;
port = ntohs ( eqs - > GetRemotePort ( ) ) ;
autobootup_timeout . Disable ( ) ;
connect . Disable ( ) ;
2016-07-17 20:45:58 -05:00
seen_character_select = false ;
2013-02-16 16:14:39 -08:00
cle = 0 ;
2016-07-17 20:45:58 -05:00
zone_id = 0 ;
2013-02-16 16:14:39 -08:00
char_name [ 0 ] = 0 ;
charid = 0 ;
2016-07-17 20:45:58 -05:00
zone_waiting_for_bootup = 0 ;
2019-07-30 19:12:44 -07:00
enter_world_triggered = false ;
2013-02-16 16:14:39 -08:00
StartInTutorial = false ;
2016-04-22 03:49:17 -04:00
m_ClientVersion = eqs - > ClientVersion ( ) ;
2020-05-17 18:36:06 -07:00
m_ClientVersionBit = EQ : : versions : : ConvertClientVersionToClientVersionBit ( m_ClientVersion ) ;
2015-02-14 21:36:54 -05:00
numclients + + ;
2013-02-16 16:14:39 -08:00
}
Client : : ~ Client ( ) {
2016-07-17 20:45:58 -05:00
if ( RunLoops & & cle & & zone_id = = 0 )
2019-07-24 19:20:09 -07:00
cle - > SetOnline ( CLE_Status : : Offline ) ;
2013-02-16 16:14:39 -08:00
numclients - - ;
//let the stream factory know were done with this stream
eqs - > Close ( ) ;
eqs - > ReleaseFromUse ( ) ;
2015-01-27 21:12:44 -08:00
safe_delete ( eqs ) ;
2013-02-16 16:14:39 -08:00
}
void Client : : SendLogServer ( )
{
2015-01-09 03:05:13 -05:00
auto outapp = new EQApplicationPacket ( OP_LogServer , sizeof ( LogServer_Struct ) ) ;
2013-02-16 16:14:39 -08:00
LogServer_Struct * l = ( LogServer_Struct * ) outapp - > pBuffer ;
const char * wsn = WorldConfig : : get ( ) - > ShortName . c_str ( ) ;
memcpy ( l - > worldshortname , wsn , strlen ( wsn ) ) ;
if ( RuleB ( Mail , EnableMailSystem ) )
l - > enablemail = 1 ;
if ( RuleB ( Chat , EnableVoiceMacros ) )
l - > enablevoicemacros = 1 ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
l - > enable_pvp = ( RuleI ( World , PVPSettings ) ) ;
if ( RuleB ( World , IsGMPetitionWindowEnabled ) )
l - > enable_petition_wnd = 1 ;
2016-08-13 15:14:31 -04:00
if ( ( RuleI ( World , FVNoDropFlag ) = = 1 | | RuleI ( World , FVNoDropFlag ) = = 2 ) & & GetAdmin ( ) > RuleI ( Character , MinStatusForNoDropExemptions ) )
2013-02-16 16:14:39 -08:00
l - > enable_FV = 1 ;
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
2013-05-22 16:17:19 -04:00
void Client : : SendEnterWorld ( std : : string name )
2013-02-16 16:14:39 -08:00
{
2014-09-20 15:55:20 -04:00
char char_name [ 64 ] = { 0 } ;
2016-07-17 20:45:58 -05:00
if ( is_player_zoning & & database . GetLiveChar ( GetAccountID ( ) , char_name ) ) {
2013-02-16 16:14:39 -08:00
if ( database . GetAccountIDByChar ( char_name ) ! = GetAccountID ( ) ) {
eqs - > Close ( ) ;
return ;
} else {
2019-09-01 22:53:23 -05:00
LogInfo ( " Telling client to continue session " ) ;
2013-02-16 16:14:39 -08:00
}
}
2015-01-09 03:05:13 -05:00
auto outapp = new EQApplicationPacket ( OP_EnterWorld , strlen ( char_name ) + 1 ) ;
2013-02-16 16:14:39 -08:00
memcpy ( outapp - > pBuffer , char_name , strlen ( char_name ) + 1 ) ;
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
void Client : : SendExpansionInfo ( ) {
2015-01-09 03:05:13 -05:00
auto outapp = new EQApplicationPacket ( OP_ExpansionInfo , sizeof ( ExpansionInfo_Struct ) ) ;
2013-02-16 16:14:39 -08:00
ExpansionInfo_Struct * eis = ( ExpansionInfo_Struct * ) outapp - > pBuffer ;
2019-01-15 00:50:58 -05:00
if ( RuleB ( World , UseClientBasedExpansionSettings ) ) {
2020-05-17 18:36:06 -07:00
eis - > Expansions = EQ : : expansions : : ConvertClientVersionToExpansionsMask ( eqs - > ClientVersion ( ) ) ;
2019-01-15 00:50:58 -05:00
}
else {
2020-05-17 18:36:06 -07:00
eis - > Expansions = ( RuleI ( World , ExpansionSettings ) & EQ : : expansions : : ConvertClientVersionToExpansionsMask ( eqs - > ClientVersion ( ) ) ) ;
2015-06-20 19:44:00 -07:00
}
2013-02-16 16:14:39 -08:00
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
void Client : : SendCharInfo ( ) {
if ( cle ) {
2019-07-24 19:20:09 -07:00
cle - > SetOnline ( CLE_Status : : CharSelect ) ;
2013-02-16 16:14:39 -08:00
}
2020-05-17 18:36:06 -07:00
if ( m_ClientVersionBit & EQ : : versions : : maskRoFAndLater ) {
2015-02-17 13:56:58 -05:00
SendMaxCharCreate ( ) ;
2013-02-16 16:14:39 -08:00
SendMembership ( ) ;
SendMembershipSettings ( ) ;
}
2016-07-17 20:45:58 -05:00
seen_character_select = true ;
2013-02-16 16:14:39 -08:00
// Send OP_SendCharInfo
2015-02-17 13:56:58 -05:00
EQApplicationPacket * outapp = nullptr ;
database . GetCharSelectInfo ( GetAccountID ( ) , & outapp , m_ClientVersionBit ) ;
2013-02-16 16:14:39 -08:00
2015-02-17 13:56:58 -05:00
if ( outapp ) {
QueuePacket ( outapp ) ;
}
else {
2019-09-01 22:53:23 -05:00
LogInfo ( " [Error] Database did not return an OP_SendCharInfo packet for account [{}] " , GetAccountID ( ) ) ;
2015-02-17 13:56:58 -05:00
}
2013-02-16 16:14:39 -08:00
safe_delete ( outapp ) ;
}
2015-02-17 13:56:58 -05:00
void Client : : SendMaxCharCreate ( ) {
2015-01-09 03:05:13 -05:00
auto outapp = new EQApplicationPacket ( OP_SendMaxCharacters , sizeof ( MaxCharacters_Struct ) ) ;
2013-02-16 16:14:39 -08:00
MaxCharacters_Struct * mc = ( MaxCharacters_Struct * ) outapp - > pBuffer ;
2013-05-06 13:07:41 -04:00
2020-05-17 18:36:06 -07:00
mc - > max_chars = EQ : : constants : : StaticLookup ( m_ClientVersion ) - > CharacterCreationLimit ;
if ( mc - > max_chars > EQ : : constants : : CHARACTER_CREATION_LIMIT )
mc - > max_chars = EQ : : constants : : CHARACTER_CREATION_LIMIT ;
2013-02-16 16:14:39 -08:00
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
void Client : : SendMembership ( ) {
2015-01-09 03:05:13 -05:00
auto outapp = new EQApplicationPacket ( OP_SendMembership , sizeof ( Membership_Struct ) ) ;
2013-02-16 16:14:39 -08:00
Membership_Struct * mc = ( Membership_Struct * ) outapp - > pBuffer ;
/*
The remaining entry fields probably hold more membership restriction data that needs to be identified .
Here is a possible list based on the EQ Website membership comparison list :
1. Spell Ranks Allowed
2. Prestige Items Usable
3. In - Game Mail Service ( send / recieve )
4. Parcel Delivery ( send / recieve )
5. Loyalty Rewards Per - Week ( 30 , 60 , Max )
6. Mercenary Tiers ( Apprentice 1 - 2 , Apprentice All Tiers , All Tiers )
7. Neighborhood House
8. Active Journal Quests ( Tasks ? ) ( 10 , 15 , Max )
9. Guild Function ( join , join and create )
10. Broker System ( restricted , unlimited )
11. Voice Chat
12. Chat Ability
13. Progression Server
14. Customer Support
15. In - Game Popup Advertising
That is 15 possible fields , and there are 15 unknowns in the struct . . . Coincidence ?
*/
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
mc - > membership = 2 ; //Hardcode to gold for now. We don't use anything else.
mc - > races = 0x1ffff ; // Available Races (4110 for silver)
mc - > classes = 0x1ffff ; // Available Classes (4614 for silver) - Was 0x101ffff
mc - > entrysize = 21 ; // Number of membership setting entries below
mc - > entries [ 0 ] = 0xffffffff ; // Max AA Restriction
mc - > entries [ 1 ] = 0xffffffff ; // Max Level Restriction
mc - > entries [ 2 ] = 0xffffffff ; // Max Char Slots per Account (not used by client?)
mc - > entries [ 3 ] = 0xffffffff ; // 1 for Silver
2018-08-13 22:32:36 -04:00
mc - > entries [ 4 ] = 0xffffffff ; // Main Inventory Size (0xffffffff on Live for Gold, but limiting to 8 until 10 is supported)
2013-02-16 16:14:39 -08:00
mc - > entries [ 5 ] = 0xffffffff ; // Max Platinum per level
mc - > entries [ 6 ] = 1 ; // 0 for Silver
mc - > entries [ 7 ] = 1 ; // 0 for Silver
mc - > entries [ 8 ] = 1 ; // 1 for Silver
mc - > entries [ 9 ] = 0xffffffff ; // Unknown - Maybe Loyalty Points every 12 hours? 60 per week for Silver
mc - > entries [ 10 ] = 1 ; // 1 for Silver
mc - > entries [ 11 ] = 0xffffffff ; // Shared Bank Slots
2013-05-06 13:07:41 -04:00
mc - > entries [ 12 ] = 0xffffffff ; // Unknown - Maybe Max Active Tasks?
2013-02-16 16:14:39 -08:00
mc - > entries [ 13 ] = 1 ; // 1 for Silver
mc - > entries [ 14 ] = 1 ; // 0 for Silver
mc - > entries [ 15 ] = 1 ; // 0 for Silver
mc - > entries [ 16 ] = 1 ; // 1 for Silver
mc - > entries [ 17 ] = 1 ; // 0 for Silver
mc - > entries [ 18 ] = 1 ; // 0 for Silver
mc - > entries [ 19 ] = 0xffffffff ; // 0 for Silver
mc - > entries [ 20 ] = 0xffffffff ; // 0 for Silver
mc - > exit_url_length = 0 ;
//mc->exit_url = 0; // Used on Live: "http://www.everquest.com/free-to-play/exit-silver"
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
void Client : : SendMembershipSettings ( ) {
2015-01-09 03:05:13 -05:00
auto outapp = new EQApplicationPacket ( OP_SendMembershipDetails , sizeof ( Membership_Details_Struct ) ) ;
2013-02-16 16:14:39 -08:00
Membership_Details_Struct * mds = ( Membership_Details_Struct * ) outapp - > pBuffer ;
mds - > membership_setting_count = 66 ;
2013-05-23 20:22:42 -04:00
int32 gold_settings [ 22 ] = { - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 1 , 1 , 1 , - 1 , 1 , - 1 , - 1 , 1 , 1 , 1 , 1 , 1 , 1 , - 1 , - 1 , 0 } ;
2013-02-16 16:14:39 -08:00
uint32 entry_count = 0 ;
for ( int setting_id = 0 ; setting_id < 22 ; setting_id + + )
{
for ( int setting_index = 0 ; setting_index < 3 ; setting_index + + )
{
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
mds - > settings [ entry_count ] . setting_index = setting_index ;
mds - > settings [ entry_count ] . setting_id = setting_id ;
mds - > settings [ entry_count ] . setting_value = gold_settings [ setting_id ] ;
entry_count + + ;
}
}
mds - > race_entry_count = 15 ;
mds - > class_entry_count = 15 ;
uint32 cur_purchase_id = 90287 ;
uint32 cur_purchase_id2 = 90301 ;
uint32 cur_bitwise_value = 1 ;
for ( int entry_id = 0 ; entry_id < 15 ; entry_id + + )
{
if ( entry_id = = 0 )
{
mds - > membership_races [ entry_id ] . purchase_id = 1 ;
mds - > membership_races [ entry_id ] . bitwise_entry = 0x1ffff ;
mds - > membership_classes [ entry_id ] . purchase_id = 1 ;
mds - > membership_classes [ entry_id ] . bitwise_entry = 0x1ffff ;
}
else
{
mds - > membership_races [ entry_id ] . purchase_id = cur_purchase_id ;
if ( entry_id < 3 )
{
mds - > membership_classes [ entry_id ] . purchase_id = cur_purchase_id ;
}
else
{
mds - > membership_classes [ entry_id ] . purchase_id = cur_purchase_id2 ;
cur_purchase_id2 + + ;
}
if ( entry_id = = 1 )
{
mds - > membership_races [ entry_id ] . bitwise_entry = 4110 ;
mds - > membership_classes [ entry_id ] . bitwise_entry = 4614 ;
}
else if ( entry_id = = 2 )
{
mds - > membership_races [ entry_id ] . bitwise_entry = 4110 ;
mds - > membership_classes [ entry_id ] . bitwise_entry = 4614 ;
}
else
{
if ( entry_id = = 12 )
{
// Live Skips 4096
cur_bitwise_value * = 2 ;
}
mds - > membership_races [ entry_id ] . bitwise_entry = cur_bitwise_value ;
mds - > membership_classes [ entry_id ] . bitwise_entry = cur_bitwise_value ;
}
cur_purchase_id + + ;
}
cur_bitwise_value * = 2 ;
}
mds - > exit_url_length = 0 ; // Live uses 42
//strcpy(eq->exit_url, "http://www.everquest.com/free-to-play/exit");
mds - > exit_url_length2 = 0 ; // Live uses 49
2013-05-06 13:07:41 -04:00
//strcpy(eq->exit_url2, "http://www.everquest.com/free-to-play/exit-silver");
2013-02-16 16:14:39 -08:00
/*
Account Access Level Settings
ID - Free Silver Gold - Possible Setting
00 - 250 1000 - 1 - Max AA Restriction
01 - - 1 - 1 - 1 - Max Level Restriction
02 - 2 4 - 1 - Max Char Slots per Account
03 - 1 1 - 1 - Max Spell Rank
04 - 4 6 - 1 - Main Inventory Size
05 - 100 500 - 1 - Max Platinum per level
06 - 0 0 1 - Send Mail ?
07 - 0 0 1 - Send Parcels ?
08 - 1 1 1 - Voice Chat Unlimited ?
09 - 2 5 - 1 - Mercenary Tiers
10 - 0 1 1 - Create Guilds ?
11 - 0 0 - 1 - Shared Bank Slots
12 - 9 14 - 1 - Max Journal Quests - 1
13 - 0 1 1 - Neighborhood - House Allowed ?
14 - 0 0 1 - Prestige Enabled ?
15 - 0 0 1 - Broker System Unlimited ?
16 - 0 1 1 - Chat UnRestricted ?
17 - 0 0 1 - Progression Server Access ?
18 - 0 0 1 - Full Customer Support ?
19 - 0 0 - 1 - 0 for Silver
20 - 0 0 - 1 - 0 for Silver
21 - 0 0 0 - Unknown 0
*/
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
void Client : : SendPostEnterWorld ( ) {
2015-01-09 03:05:13 -05:00
auto outapp = new EQApplicationPacket ( OP_PostEnterWorld , 1 ) ;
2013-02-16 16:14:39 -08:00
outapp - > size = 0 ;
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
2019-07-10 00:11:17 -05:00
bool Client : : HandleSendLoginInfoPacket ( const EQApplicationPacket * app )
{
2013-04-22 22:47:19 -07:00
if ( app - > size ! = sizeof ( LoginInfo_Struct ) ) {
return false ;
}
2019-07-10 00:11:17 -05:00
auto * login_info = ( LoginInfo_Struct * ) app - > pBuffer ;
2013-04-22 22:47:19 -07:00
// Quagmire - max len for name is 18, pass 15
2019-07-10 00:11:17 -05:00
char name [ 19 ] = { 0 } ;
2013-04-22 22:47:19 -07:00
char password [ 16 ] = { 0 } ;
2019-07-10 00:11:17 -05:00
strn0cpy ( name , ( char * ) login_info - > login_info , 18 ) ;
strn0cpy ( password , ( char * ) & ( login_info - > login_info [ strlen ( name ) + 1 ] ) , 15 ) ;
LogDebug ( " Receiving Login Info Packet from Client | name [{0}] password [{1}] " , name , password ) ;
2013-04-22 22:47:19 -07:00
if ( strlen ( password ) < = 1 ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Login without a password " ) ;
2013-04-22 22:47:19 -07:00
return false ;
}
2019-07-10 00:11:17 -05:00
is_player_zoning = ( login_info - > zoning = = 1 ) ;
2019-07-10 00:45:40 -05:00
2019-07-10 00:11:17 -05:00
uint32 id = std : : stoi ( name ) ;
2017-11-14 21:42:14 -08:00
if ( id = = 0 ) {
2019-07-06 03:19:50 -05:00
LogWarning ( " Receiving Login Info Packet from Client | account_id is 0 - disconnecting " ) ;
2013-04-22 22:47:19 -07:00
return false ;
}
2019-09-07 23:59:12 -05:00
LogClientLogin ( " [HandleSendLoginInfoPacket] Checking Auth id [{}] " , id ) ;
2019-07-10 00:11:17 -05:00
if ( ( cle = client_list . CheckAuth ( id , password ) ) ) {
2019-09-07 23:59:12 -05:00
LogClientLogin ( " [HandleSendLoginInfoPacket] Checking Auth id [{}] passed " , id ) ;
2017-11-14 21:42:14 -08:00
if ( ! is_player_zoning ) {
2017-07-15 09:36:43 -04:00
// Track who is in and who is out of the game
char * inout = ( char * ) " " ;
2019-07-24 19:20:09 -07:00
if ( cle - > GetOnline ( ) = = CLE_Status : : Never ) {
2017-07-15 09:36:43 -04:00
// Desktop -> Char Select
inout = ( char * ) " In " ;
}
else {
// Game -> Char Select
inout = ( char * ) " Out " ;
2016-07-17 20:45:58 -05:00
}
2017-11-14 21:42:14 -08:00
2017-07-15 09:36:43 -04:00
// Always at Char select at this point.
// Either from a fresh client launch or coming back from the game.
// Exiting the game entirely does not come through here.
// Could use a Logging Out Completely message somewhere.
2019-07-24 19:20:09 -07:00
cle - > SetOnline ( CLE_Status : : CharSelect ) ;
2017-07-15 09:36:43 -04:00
2019-09-07 02:30:33 -05:00
LogInfo ( " Account ({}) Logging({}) to character select :: LSID [{}] " , cle - > AccountName ( ) , inout , cle - > LSID ( ) ) ;
2013-04-22 22:47:19 -07:00
}
2017-07-15 12:09:47 -04:00
else {
cle - > SetOnline ( ) ;
}
2017-11-14 21:42:14 -08:00
2013-04-22 22:47:19 -07:00
const WorldConfig * Config = WorldConfig : : get ( ) ;
2017-11-14 21:42:14 -08:00
if ( Config - > UpdateStats ) {
2015-01-09 03:05:13 -05:00
auto pack = new ServerPacket ;
2013-04-22 22:47:19 -07:00
pack - > opcode = ServerOP_LSPlayerJoinWorld ;
pack - > size = sizeof ( ServerLSPlayerJoinWorld_Struct ) ;
pack - > pBuffer = new uchar [ pack - > size ] ;
memset ( pack - > pBuffer , 0 , pack - > size ) ;
ServerLSPlayerJoinWorld_Struct * join = ( ServerLSPlayerJoinWorld_Struct * ) pack - > pBuffer ;
strcpy ( join - > key , GetLSKey ( ) ) ;
join - > lsaccount_id = GetLSID ( ) ;
loginserverlist . SendPacket ( pack ) ;
safe_delete ( pack ) ;
}
2017-11-14 21:42:14 -08:00
2016-07-17 20:45:58 -05:00
if ( ! is_player_zoning )
2013-04-22 22:47:19 -07:00
SendGuildList ( ) ;
2017-11-14 21:42:14 -08:00
2013-04-22 22:47:19 -07:00
SendLogServer ( ) ;
SendApproveWorld ( ) ;
SendEnterWorld ( cle - > name ( ) ) ;
SendPostEnterWorld ( ) ;
2016-07-17 20:45:58 -05:00
if ( ! is_player_zoning ) {
2013-04-22 22:47:19 -07:00
SendExpansionInfo ( ) ;
SendCharInfo ( ) ;
database . LoginIP ( cle - > AccountID ( ) , long2ip ( GetIP ( ) ) . c_str ( ) ) ;
}
2017-11-14 21:42:14 -08:00
cle - > SetIP ( GetIP ( ) ) ;
return true ;
2013-04-22 22:47:19 -07:00
}
else {
2019-09-01 22:53:23 -05:00
LogInfo ( " Bad/Expired session key [{}] " , name ) ;
2013-04-22 22:47:19 -07:00
return false ;
}
}
2014-09-20 02:46:04 -04:00
bool Client : : HandleNameApprovalPacket ( const EQApplicationPacket * app )
{
2013-04-22 22:44:29 -07:00
if ( GetAccountID ( ) = = 0 ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Name approval request with no logged in account " ) ;
2013-04-22 22:44:29 -07:00
return false ;
}
snprintf ( char_name , 64 , " %s " , ( char * ) app - > pBuffer ) ;
uchar race = app - > pBuffer [ 64 ] ;
uchar clas = app - > pBuffer [ 68 ] ;
2019-09-01 22:53:23 -05:00
LogInfo ( " Name approval request. Name=[{}], race=[{}], class=[{}] " , char_name , GetRaceIDName ( race ) , GetClassIDName ( clas ) ) ;
2013-04-22 22:44:29 -07:00
EQApplicationPacket * outapp ;
outapp = new EQApplicationPacket ;
outapp - > SetOpcode ( OP_ApproveName ) ;
outapp - > pBuffer = new uchar [ 1 ] ;
outapp - > size = 1 ;
2014-09-09 16:03:24 -05:00
bool valid = false ;
2014-09-22 02:52:23 -05:00
if ( ! database . CheckNameFilter ( char_name ) ) {
valid = false ;
}
/* Name must begin with an upper-case letter. */
else if ( islower ( char_name [ 0 ] ) ) {
valid = false ;
}
else if ( database . ReserveName ( GetAccountID ( ) , char_name ) ) {
valid = true ;
}
else {
valid = false ;
}
2013-04-22 22:44:29 -07:00
outapp - > pBuffer [ 0 ] = valid ? 1 : 0 ;
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
2014-09-20 02:46:04 -04:00
if ( ! valid )
2013-05-09 10:44:08 -04:00
memset ( char_name , 0 , sizeof ( char_name ) ) ;
2013-04-22 22:44:29 -07:00
return true ;
}
2020-04-08 16:00:27 -05:00
bool Client : : HandleGenerateRandomNamePacket ( const EQApplicationPacket * app ) {
// creates up to a 10 char name
char vowels [ 18 ] = " aeiouyaeiouaeioe " ;
char cons [ 48 ] = " bcdfghjklmnpqrstvwxzybcdgklmnprstvwbcdgkpstrkd " ;
char rndname [ 17 ] = " \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 " ;
char paircons [ 33 ] = " ngrkndstshthphsktrdrbrgrfrclcr " ;
int rndnum = emu_random . Int ( 0 , 75 ) , n = 1 ;
bool dlc = false ;
bool vwl = false ;
bool dbl = false ;
if ( rndnum > 63 )
{ // rndnum is 0 - 75 where 64-75 is cons pair, 17-63 is cons, 0-16 is vowel
rndnum = ( rndnum - 61 ) * 2 ; // name can't start with "ng" "nd" or "rk"
rndname [ 0 ] = paircons [ rndnum ] ;
rndname [ 1 ] = paircons [ rndnum + 1 ] ;
n = 2 ;
}
else if ( rndnum > 16 )
{
rndnum - = 17 ;
rndname [ 0 ] = cons [ rndnum ] ;
}
else
{
rndname [ 0 ] = vowels [ rndnum ] ;
vwl = true ;
}
int namlen = emu_random . Int ( 5 , 10 ) ;
for ( int i = n ; i < namlen ; i + + )
{
dlc = false ;
if ( vwl ) //last char was a vowel
{ // so pick a cons or cons pair
rndnum = emu_random . Int ( 0 , 62 ) ;
if ( rndnum > 46 )
{ // pick a cons pair
if ( i > namlen - 3 ) // last 2 chars in name?
{ // name can only end in cons pair "rk" "st" "sh" "th" "ph" "sk" "nd" or "ng"
rndnum = emu_random . Int ( 0 , 7 ) * 2 ;
}
else
{ // pick any from the set
rndnum = ( rndnum - 47 ) * 2 ;
}
rndname [ i ] = paircons [ rndnum ] ;
rndname [ i + 1 ] = paircons [ rndnum + 1 ] ;
dlc = true ; // flag keeps second letter from being doubled below
i + = 1 ;
}
else
{ // select a single cons
rndname [ i ] = cons [ rndnum ] ;
}
}
else
{ // select a vowel
rndname [ i ] = vowels [ emu_random . Int ( 0 , 16 ) ] ;
}
vwl = ! vwl ;
if ( ! dbl & & ! dlc )
{ // one chance at double letters in name
if ( ! emu_random . Int ( 0 , i + 9 ) ) // chances decrease towards end of name
{
rndname [ i + 1 ] = rndname [ i ] ;
dbl = true ;
i + = 1 ;
}
}
}
2013-04-22 22:52:29 -07:00
2020-04-08 16:00:27 -05:00
rndname [ 0 ] = toupper ( rndname [ 0 ] ) ;
NameGeneration_Struct * ngs = ( NameGeneration_Struct * ) app - > pBuffer ;
memset ( ngs - > name , 0 , 64 ) ;
strcpy ( ngs - > name , rndname ) ;
2013-04-22 22:52:29 -07:00
QueuePacket ( app ) ;
return true ;
}
2013-04-22 22:47:19 -07:00
2013-04-22 22:56:55 -07:00
bool Client : : HandleCharacterCreateRequestPacket ( const EQApplicationPacket * app ) {
// New OpCode in SoF
2013-05-09 10:44:08 -04:00
uint32 allocs = character_create_allocations . size ( ) ;
uint32 combos = character_create_race_class_combos . size ( ) ;
uint32 len = sizeof ( RaceClassAllocation ) * allocs ;
len + = sizeof ( RaceClassCombos ) * combos ;
len + = sizeof ( uint8 ) ;
len + = sizeof ( uint32 ) ;
len + = sizeof ( uint32 ) ;
2013-04-22 22:56:55 -07:00
2015-01-09 03:05:13 -05:00
auto outapp = new EQApplicationPacket ( OP_CharacterCreateRequest , len ) ;
2013-05-09 10:44:08 -04:00
unsigned char * ptr = outapp - > pBuffer ;
* ( ( uint8 * ) ptr ) = 0 ;
ptr + = sizeof ( uint8 ) ;
* ( ( uint32 * ) ptr ) = allocs ;
ptr + = sizeof ( uint32 ) ;
for ( int i = 0 ; i < allocs ; + + i ) {
RaceClassAllocation * alc = ( RaceClassAllocation * ) ptr ;
alc - > Index = character_create_allocations [ i ] . Index ;
for ( int j = 0 ; j < 7 ; + + j ) {
alc - > BaseStats [ j ] = character_create_allocations [ i ] . BaseStats [ j ] ;
alc - > DefaultPointAllocation [ j ] = character_create_allocations [ i ] . DefaultPointAllocation [ j ] ;
}
ptr + = sizeof ( RaceClassAllocation ) ;
}
* ( ( uint32 * ) ptr ) = combos ;
ptr + = sizeof ( uint32 ) ;
for ( int i = 0 ; i < combos ; + + i ) {
RaceClassCombos * cmb = ( RaceClassCombos * ) ptr ;
cmb - > ExpansionRequired = character_create_race_class_combos [ i ] . ExpansionRequired ;
cmb - > Race = character_create_race_class_combos [ i ] . Race ;
cmb - > Class = character_create_race_class_combos [ i ] . Class ;
cmb - > Deity = character_create_race_class_combos [ i ] . Deity ;
cmb - > AllocationIndex = character_create_race_class_combos [ i ] . AllocationIndex ;
cmb - > Zone = character_create_race_class_combos [ i ] . Zone ;
ptr + = sizeof ( RaceClassCombos ) ;
}
2013-04-22 22:56:55 -07:00
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
return true ;
}
2013-04-22 23:00:44 -07:00
bool Client : : HandleCharacterCreatePacket ( const EQApplicationPacket * app ) {
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
if ( GetAccountID ( ) = = 0 ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Account ID not set; unable to create character " ) ;
2013-04-22 23:00:44 -07:00
return false ;
}
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
else if ( app - > size ! = sizeof ( CharCreate_Struct ) ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Wrong size on OP_CharacterCreate. Got: [{}], Expected: [{}] " , app - > size , sizeof ( CharCreate_Struct ) ) ;
2013-04-22 23:00:44 -07:00
DumpPacket ( app ) ;
// the previous behavior was essentially returning true here
// but that seems a bit odd to me.
2013-05-06 13:07:41 -04:00
return true ;
2013-04-22 23:00:44 -07:00
}
CharCreate_Struct * cc = ( CharCreate_Struct * ) app - > pBuffer ;
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
if ( OPCharCreate ( char_name , cc ) = = false ) {
2013-04-22 23:00:44 -07:00
database . DeleteCharacter ( char_name ) ;
2015-01-09 03:05:13 -05:00
auto outapp = new EQApplicationPacket ( OP_ApproveName , 1 ) ;
2013-04-22 23:00:44 -07:00
outapp - > pBuffer [ 0 ] = 0 ;
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
2013-05-09 10:44:08 -04:00
else
2013-10-12 00:29:44 -04:00
{
2020-05-17 18:36:06 -07:00
if ( m_ClientVersionBit & EQ : : versions : : maskTitaniumAndEarlier )
2013-10-12 00:29:44 -04:00
StartInTutorial = true ;
2013-04-22 23:00:44 -07:00
SendCharInfo ( ) ;
2013-10-12 00:29:44 -04:00
}
2013-05-06 13:07:41 -04:00
2013-04-22 23:00:44 -07:00
return true ;
}
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
bool Client : : HandleEnterWorldPacket ( const EQApplicationPacket * app ) {
2013-04-22 23:10:57 -07:00
if ( GetAccountID ( ) = = 0 ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Enter world with no logged in account " ) ;
2013-04-22 23:10:57 -07:00
eqs - > Close ( ) ;
return true ;
}
if ( GetAdmin ( ) < 0 )
{
2019-09-01 22:53:23 -05:00
LogInfo ( " Account banned or suspended " ) ;
2013-04-22 23:10:57 -07:00
eqs - > Close ( ) ;
return true ;
}
2016-08-27 17:22:56 -04:00
if ( RuleB ( World , EnableIPExemptions ) | | RuleI ( World , MaxClientsPerIP ) > = 0 ) {
2013-05-09 10:44:08 -04:00
client_list . GetCLEIP ( this - > GetIP ( ) ) ; //Check current CLE Entry IPs against incoming connection
}
2013-04-22 23:10:57 -07:00
EnterWorld_Struct * ew = ( EnterWorld_Struct * ) app - > pBuffer ;
strn0cpy ( char_name , ew - > name , 64 ) ;
EQApplicationPacket * outapp ;
uint32 tmpaccid = 0 ;
2016-07-17 20:45:58 -05:00
charid = database . GetCharacterInfo ( char_name , & tmpaccid , & zone_id , & instance_id ) ;
2020-04-17 18:48:43 +03:00
if ( charid = = 0 ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Could not get CharInfo for [{}] " , char_name ) ;
2013-04-22 23:10:57 -07:00
eqs - > Close ( ) ;
return true ;
}
// Make sure this account owns this character
if ( tmpaccid ! = GetAccountID ( ) ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " This account does not own the character named [{}] " , char_name ) ;
2013-04-22 23:10:57 -07:00
eqs - > Close ( ) ;
return true ;
}
2015-02-17 13:56:58 -05:00
// This can probably be moved outside and have another method return requested info (don't forget to remove the #include "../common/shareddb.h" above)
2015-02-23 19:57:47 -05:00
// (This is a literal translation of the original process..I don't see why it can't be changed to a single-target query over account iteration)
2016-07-17 20:45:58 -05:00
if ( ! is_player_zoning ) {
2020-05-17 18:36:06 -07:00
size_t character_limit = EQ : : constants : : StaticLookup ( eqs - > ClientVersion ( ) ) - > CharacterCreationLimit ;
if ( character_limit > EQ : : constants : : CHARACTER_CREATION_LIMIT ) { character_limit = EQ : : constants : : CHARACTER_CREATION_LIMIT ; }
if ( eqs - > ClientVersion ( ) = = EQ : : versions : : ClientVersion : : Titanium ) { character_limit = Titanium : : constants : : CHARACTER_CREATION_LIMIT ; }
2015-02-17 13:56:58 -05:00
std : : string tgh_query = StringFormat (
" SELECT "
" `id`, "
" name, "
" `level`, "
2015-02-18 00:22:05 -05:00
" last_login "
2015-02-17 13:56:58 -05:00
" FROM "
" character_data "
" WHERE `account_id` = %i ORDER BY `name` LIMIT %u " , GetAccountID ( ) , character_limit ) ;
auto tgh_results = database . QueryDatabase ( tgh_query ) ;
/* Check GoHome */
if ( ew - > return_home & & ! ew - > tutorial ) {
bool home_enabled = false ;
for ( auto row = tgh_results . begin ( ) ; row ! = tgh_results . end ( ) ; + + row ) {
if ( strcasecmp ( row [ 1 ] , char_name ) = = 0 ) {
2015-02-22 22:27:58 -05:00
if ( RuleB ( World , EnableReturnHomeButton ) ) {
int now = time ( nullptr ) ;
if ( ( now - atoi ( row [ 3 ] ) ) > = RuleI ( World , MinOfflineTimeToReturnHome ) ) {
home_enabled = true ;
break ;
}
2015-02-17 13:56:58 -05:00
}
2013-04-22 23:10:57 -07:00
}
}
2015-02-17 13:56:58 -05:00
if ( home_enabled ) {
2016-07-17 20:45:58 -05:00
zone_id = database . MoveCharacterToBind ( charid , 4 ) ;
2015-02-17 13:56:58 -05:00
}
else {
2019-09-01 22:53:23 -05:00
LogInfo ( " [{}] is trying to go home before they're able " , char_name ) ;
2015-02-17 13:56:58 -05:00
database . SetHackerFlag ( GetAccountName ( ) , char_name , " MQGoHome: player tried to go home before they were able. " ) ;
eqs - > Close ( ) ;
return true ;
}
2013-04-22 23:10:57 -07:00
}
2015-02-17 13:56:58 -05:00
/* Check Tutorial*/
if ( RuleB ( World , EnableTutorialButton ) & & ( ew - > tutorial | | StartInTutorial ) ) {
bool tutorial_enabled = false ;
for ( auto row = tgh_results . begin ( ) ; row ! = tgh_results . end ( ) ; + + row ) {
if ( strcasecmp ( row [ 1 ] , char_name ) = = 0 ) {
2015-02-22 22:27:58 -05:00
if ( RuleB ( World , EnableTutorialButton ) & & ( ( uint8 ) atoi ( row [ 2 ] ) < = RuleI ( World , MaxLevelForTutorial ) ) ) {
tutorial_enabled = true ;
break ;
2015-02-17 13:56:58 -05:00
}
2013-04-22 23:10:57 -07:00
}
}
2015-02-17 13:56:58 -05:00
if ( tutorial_enabled ) {
2016-07-17 20:45:58 -05:00
zone_id = RuleI ( World , TutorialZoneID ) ;
database . MoveCharacterToZone ( charid , database . GetZoneName ( zone_id ) ) ;
2015-02-17 13:56:58 -05:00
}
else {
2019-09-01 22:53:23 -05:00
LogInfo ( " [{}] is trying to go to tutorial but are not allowed " , char_name ) ;
2015-02-17 13:56:58 -05:00
database . SetHackerFlag ( GetAccountName ( ) , char_name , " MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character. " ) ;
eqs - > Close ( ) ;
return true ;
}
2013-04-22 23:10:57 -07:00
}
}
2016-07-17 20:45:58 -05:00
if ( zone_id = = 0 | | ! database . GetZoneName ( zone_id ) ) {
2013-04-22 23:10:57 -07:00
// This is to save people in an invalid zone, once it's removed from the DB
database . MoveCharacterToZone ( charid , " arena " ) ;
2019-09-01 22:53:23 -05:00
LogInfo ( " Zone not found in database zone_id=[{}], moveing char to arena character:[{}] " , zone_id , char_name ) ;
2013-04-22 23:10:57 -07:00
}
2016-07-17 20:45:58 -05:00
if ( instance_id > 0 )
2013-04-22 23:10:57 -07:00
{
2016-07-17 20:45:58 -05:00
if ( ! database . VerifyInstanceAlive ( instance_id , GetCharID ( ) ) )
2013-04-22 23:10:57 -07:00
{
2016-07-17 20:45:58 -05:00
zone_id = database . MoveCharacterToBind ( charid ) ;
instance_id = 0 ;
2013-04-22 23:10:57 -07:00
}
else
{
2016-07-17 20:45:58 -05:00
if ( ! database . VerifyZoneInstance ( zone_id , instance_id ) )
2013-04-22 23:10:57 -07:00
{
2016-07-17 20:45:58 -05:00
zone_id = database . MoveCharacterToBind ( charid ) ;
instance_id = 0 ;
2013-04-22 23:10:57 -07:00
}
}
}
2016-07-17 20:45:58 -05:00
if ( ! is_player_zoning ) {
2013-04-22 23:10:57 -07:00
database . SetGroupID ( char_name , 0 , charid ) ;
database . SetLoginFlags ( charid , false , false , 1 ) ;
}
else {
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
uint32 groupid = database . GetGroupID ( char_name ) ;
if ( groupid > 0 ) {
char * leader = 0 ;
char leaderbuf [ 64 ] = { 0 } ;
if ( ( leader = database . GetGroupLeaderForLogin ( char_name , leaderbuf ) ) & & strlen ( leader ) > 1 ) {
2015-01-09 03:05:13 -05:00
auto outapp3 = new EQApplicationPacket ( OP_GroupUpdate , sizeof ( GroupJoin_Struct ) ) ;
2013-04-22 23:10:57 -07:00
GroupJoin_Struct * gj = ( GroupJoin_Struct * ) outapp3 - > pBuffer ;
gj - > action = 8 ;
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
strcpy ( gj - > yourname , char_name ) ;
strcpy ( gj - > membername , leader ) ;
2013-04-22 23:10:57 -07:00
QueuePacket ( outapp3 ) ;
safe_delete ( outapp3 ) ;
}
}
}
outapp = new EQApplicationPacket ( OP_MOTD ) ;
2016-05-09 14:23:27 -04:00
std : : string tmp ;
if ( database . GetVariable ( " MOTD " , tmp ) ) {
2016-05-09 21:46:05 -04:00
outapp - > size = tmp . length ( ) + 1 ;
2013-04-22 23:10:57 -07:00
outapp - > pBuffer = new uchar [ outapp - > size ] ;
memset ( outapp - > pBuffer , 0 , outapp - > size ) ;
2016-05-09 14:23:27 -04:00
strcpy ( ( char * ) outapp - > pBuffer , tmp . c_str ( ) ) ;
2013-04-22 23:10:57 -07:00
} else {
// Null Message of the Day. :)
outapp - > size = 1 ;
outapp - > pBuffer = new uchar [ outapp - > size ] ;
outapp - > pBuffer [ 0 ] = 0 ;
}
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
2018-03-04 21:38:17 -05:00
// set mailkey - used for duration of character session
2014-12-01 18:13:12 -05:00
int MailKey = emu_random . Int ( 1 , INT_MAX ) ;
2013-04-22 23:10:57 -07:00
database . SetMailKey ( charid , GetIP ( ) , MailKey ) ;
2018-03-04 21:38:17 -05:00
if ( UCSServerAvailable_ ) {
const WorldConfig * Config = WorldConfig : : get ( ) ;
std : : string buffer ;
2020-05-17 18:36:06 -07:00
EQ : : versions : : UCSVersion ConnectionType = EQ : : versions : : ucsUnknown ;
2018-03-04 21:38:17 -05:00
// chat server packet
switch ( GetClientVersion ( ) ) {
2020-05-17 18:36:06 -07:00
case EQ : : versions : : ClientVersion : : Titanium :
ConnectionType = EQ : : versions : : ucsTitaniumChat ;
2018-03-04 21:38:17 -05:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : versions : : ClientVersion : : SoF :
ConnectionType = EQ : : versions : : ucsSoFCombined ;
2018-03-04 21:38:17 -05:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : versions : : ClientVersion : : SoD :
ConnectionType = EQ : : versions : : ucsSoDCombined ;
2018-03-04 21:38:17 -05:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : versions : : ClientVersion : : UF :
ConnectionType = EQ : : versions : : ucsUFCombined ;
2018-03-04 21:38:17 -05:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : versions : : ClientVersion : : RoF :
ConnectionType = EQ : : versions : : ucsRoFCombined ;
2018-03-04 21:38:17 -05:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : versions : : ClientVersion : : RoF2 :
ConnectionType = EQ : : versions : : ucsRoF2Combined ;
2018-03-04 21:38:17 -05:00
break ;
default :
2020-05-17 18:36:06 -07:00
ConnectionType = EQ : : versions : : ucsUnknown ;
2018-03-04 21:38:17 -05:00
break ;
}
2013-04-22 23:10:57 -07:00
2018-03-04 21:38:17 -05:00
buffer = StringFormat ( " %s,%i,%s.%s,%c%08X " ,
Config - > ChatHost . c_str ( ) ,
Config - > ChatPort ,
Config - > ShortName . c_str ( ) ,
GetCharName ( ) ,
ConnectionType ,
MailKey
) ;
2013-04-22 23:10:57 -07:00
2018-03-04 21:38:17 -05:00
outapp = new EQApplicationPacket ( OP_SetChatServer , ( buffer . length ( ) + 1 ) ) ;
memcpy ( outapp - > pBuffer , buffer . c_str ( ) , buffer . length ( ) ) ;
outapp - > pBuffer [ buffer . length ( ) ] = ' \0 ' ;
2013-04-22 23:10:57 -07:00
2018-03-04 21:38:17 -05:00
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
2013-04-22 23:10:57 -07:00
2018-03-04 21:38:17 -05:00
// mail server packet
switch ( GetClientVersion ( ) ) {
2020-05-17 18:36:06 -07:00
case EQ : : versions : : ClientVersion : : Titanium :
ConnectionType = EQ : : versions : : ucsTitaniumMail ;
2018-03-04 21:38:17 -05:00
break ;
default :
// retain value from previous switch
break ;
}
2013-04-22 23:10:57 -07:00
2018-03-04 21:38:17 -05:00
buffer = StringFormat ( " %s,%i,%s.%s,%c%08X " ,
Config - > MailHost . c_str ( ) ,
Config - > MailPort ,
Config - > ShortName . c_str ( ) ,
GetCharName ( ) ,
ConnectionType ,
MailKey
) ;
2013-04-22 23:10:57 -07:00
2018-03-04 21:38:17 -05:00
outapp = new EQApplicationPacket ( OP_SetChatServer2 , ( buffer . length ( ) + 1 ) ) ;
memcpy ( outapp - > pBuffer , buffer . c_str ( ) , buffer . length ( ) ) ;
outapp - > pBuffer [ buffer . length ( ) ] = ' \0 ' ;
2013-04-22 23:10:57 -07:00
2018-03-04 21:38:17 -05:00
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
2013-04-22 23:10:57 -07:00
EnterWorld ( ) ;
return true ;
}
2013-04-22 23:14:00 -07:00
bool Client : : HandleDeleteCharacterPacket ( const EQApplicationPacket * app ) {
uint32 char_acct_id = database . GetAccountIDByChar ( ( char * ) app - > pBuffer ) ;
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
if ( char_acct_id = = GetAccountID ( ) ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Delete character: [{}] " , app - > pBuffer ) ;
2013-04-22 23:14:00 -07:00
database . DeleteCharacter ( ( char * ) app - > pBuffer ) ;
SendCharInfo ( ) ;
}
return true ;
}
2013-04-22 23:22:13 -07:00
bool Client : : HandleZoneChangePacket ( const EQApplicationPacket * app ) {
// HoT sends this to world while zoning and wants it echoed back.
2020-05-17 18:36:06 -07:00
if ( m_ClientVersionBit & EQ : : versions : : maskRoFAndLater )
2013-04-22 23:22:13 -07:00
{
QueuePacket ( app ) ;
}
return true ;
}
2013-02-16 16:14:39 -08:00
bool Client : : HandlePacket ( const EQApplicationPacket * app ) {
2013-04-22 23:18:40 -07:00
2013-02-16 16:14:39 -08:00
EmuOpcode opcode = app - > GetOpcode ( ) ;
2019-09-01 22:53:23 -05:00
LogNetcode ( " Received EQApplicationPacket [{:#04x}] " , opcode ) ;
2013-02-16 16:14:39 -08:00
if ( ! eqs - > CheckState ( ESTABLISHED ) ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Client disconnected (net inactive on send) " ) ;
2013-02-16 16:14:39 -08:00
return false ;
}
// Voidd: Anti-GM Account hack, Checks source ip against valid GM Account IP Addresses
if ( RuleB ( World , GMAccountIPList ) & & this - > GetAdmin ( ) > = ( RuleI ( World , MinGMAntiHackStatus ) ) ) {
if ( ! database . CheckGMIPs ( long2ip ( this - > GetIP ( ) ) . c_str ( ) , this - > GetAccountID ( ) ) ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " GM Account not permited from source address [{}] and accountid [{}] " , long2ip ( this - > GetIP ( ) ) . c_str ( ) , this - > GetAccountID ( ) ) ;
2013-02-16 16:14:39 -08:00
eqs - > Close ( ) ;
}
}
if ( GetAccountID ( ) = = 0 & & opcode ! = OP_SendLoginInfo ) {
// Got a packet other than OP_SendLoginInfo when not logged in
2019-09-01 22:53:23 -05:00
LogInfo ( " Expecting OP_SendLoginInfo, got [{}] " , OpcodeNames [ opcode ] ) ;
2013-02-16 16:14:39 -08:00
return false ;
}
else if ( opcode = = OP_AckPacket ) {
return true ;
}
switch ( opcode )
{
2013-04-22 23:18:40 -07:00
case OP_World_Client_CRC1 :
2013-05-06 13:07:41 -04:00
case OP_World_Client_CRC2 :
2013-04-22 23:10:57 -07:00
{
2013-04-22 23:18:40 -07:00
// There is no obvious entry in the CC struct to indicate that the 'Start Tutorial button
// is selected when a character is created. I have observed that in this case, OP_EnterWorld is sent
// before OP_World_Client_CRC1. Therefore, if we receive OP_World_Client_CRC1 before OP_EnterWorld,
// then 'Start Tutorial' was not chosen.
StartInTutorial = false ;
2013-04-22 23:10:57 -07:00
return true ;
}
2013-02-16 16:14:39 -08:00
case OP_SendLoginInfo :
{
2013-04-22 22:47:19 -07:00
return HandleSendLoginInfoPacket ( app ) ;
2013-02-16 16:14:39 -08:00
}
case OP_ApproveName : //Name approval
{
2013-04-22 22:44:29 -07:00
return HandleNameApprovalPacket ( app ) ;
2013-02-16 16:14:39 -08:00
}
case OP_RandomNameGenerator :
{
2013-04-22 22:52:29 -07:00
return HandleGenerateRandomNamePacket ( app ) ;
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
case OP_CharacterCreateRequest :
2013-04-22 22:56:55 -07:00
{
2013-02-16 16:14:39 -08:00
// New OpCode in SoF
2013-04-22 22:56:55 -07:00
return HandleCharacterCreateRequestPacket ( app ) ;
2013-02-16 16:14:39 -08:00
}
case OP_CharacterCreate : //Char create
{
2013-04-22 23:00:44 -07:00
return HandleCharacterCreatePacket ( app ) ;
2013-02-16 16:14:39 -08:00
}
case OP_EnterWorld : // Enter world
{
2013-04-22 23:10:57 -07:00
return HandleEnterWorldPacket ( app ) ;
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
case OP_DeleteCharacter :
2013-04-22 23:14:00 -07:00
{
return HandleDeleteCharacterPacket ( app ) ;
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
case OP_WorldComplete :
2013-04-22 23:10:57 -07:00
{
2013-02-16 16:14:39 -08:00
eqs - > Close ( ) ;
2013-04-22 23:10:57 -07:00
return true ;
2013-02-16 16:14:39 -08:00
}
2017-03-12 23:19:24 -04:00
case OP_WorldLogout :
{
2017-07-15 09:54:04 -04:00
// I don't see this getting executed on logout
2017-03-12 23:19:24 -04:00
eqs - > Close ( ) ;
2019-07-24 19:20:09 -07:00
cle - > SetOnline ( CLE_Status : : Offline ) ; //allows this player to log in again without an ip restriction.
2017-03-12 23:19:24 -04:00
return false ;
}
2013-04-22 23:22:13 -07:00
case OP_ZoneChange :
{
// HoT sends this to world while zoning and wants it echoed back.
return HandleZoneChangePacket ( app ) ;
}
2013-02-16 16:14:39 -08:00
case OP_LoginUnknown1 :
case OP_LoginUnknown2 :
2013-04-22 23:18:40 -07:00
case OP_CrashDump :
case OP_WearChange :
case OP_LoginComplete :
case OP_ApproveWorld :
case OP_WorldClientReady :
2013-05-06 13:07:41 -04:00
{
2013-04-22 23:22:13 -07:00
// Essentially we are just 'eating' these packets, indicating
// they are handled.
2013-04-22 23:10:57 -07:00
return true ;
}
2013-05-06 13:07:41 -04:00
default :
2013-04-22 23:10:57 -07:00
{
2019-09-01 22:53:23 -05:00
LogNetcode ( " Received unknown EQApplicationPacket " ) ;
2013-04-22 23:10:57 -07:00
return true ;
2013-02-16 16:14:39 -08:00
}
}
2013-04-22 23:10:57 -07:00
return true ;
2013-02-16 16:14:39 -08:00
}
bool Client : : Process ( ) {
bool ret = true ;
//bool sendguilds = true;
2017-02-28 23:17:30 -08:00
sockaddr_in to = { } ;
2013-02-16 16:14:39 -08:00
memset ( ( char * ) & to , 0 , sizeof ( to ) ) ;
2013-05-09 10:44:08 -04:00
to . sin_family = AF_INET ;
to . sin_port = port ;
to . sin_addr . s_addr = ip ;
2013-02-16 16:14:39 -08:00
if ( autobootup_timeout . Check ( ) ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Zone bootup timer expired, bootup failed or too slow " ) ;
2016-07-17 20:45:58 -05:00
TellClientZoneUnavailable ( ) ;
2013-02-16 16:14:39 -08:00
}
2019-07-27 20:13:04 -07:00
2013-02-16 16:14:39 -08:00
if ( connect . Check ( ) ) {
SendGuildList ( ) ; // Send OPCode: OP_GuildsList
SendApproveWorld ( ) ;
connect . Disable ( ) ;
}
2019-07-25 22:26:56 -07:00
if ( cle )
cle - > KeepAlive ( ) ;
2013-02-16 16:14:39 -08:00
/************ Get all packets from packet manager out queue and process them ************/
EQApplicationPacket * app = 0 ;
while ( ret & & ( app = ( EQApplicationPacket * ) eqs - > PopPacket ( ) ) ) {
ret = HandlePacket ( app ) ;
delete app ;
}
if ( ! eqs - > CheckState ( ESTABLISHED ) ) {
if ( WorldConfig : : get ( ) - > UpdateStats ) {
2015-01-09 03:05:13 -05:00
auto pack = new ServerPacket ;
2013-02-16 16:14:39 -08:00
pack - > opcode = ServerOP_LSPlayerLeftWorld ;
pack - > size = sizeof ( ServerLSPlayerLeftWorld_Struct ) ;
pack - > pBuffer = new uchar [ pack - > size ] ;
memset ( pack - > pBuffer , 0 , pack - > size ) ;
ServerLSPlayerLeftWorld_Struct * logout = ( ServerLSPlayerLeftWorld_Struct * ) pack - > pBuffer ;
strcpy ( logout - > key , GetLSKey ( ) ) ;
logout - > lsaccount_id = GetLSID ( ) ;
loginserverlist . SendPacket ( pack ) ;
safe_delete ( pack ) ;
}
2019-09-01 22:53:23 -05:00
LogInfo ( " Client disconnected (not active in process) " ) ;
2013-02-16 16:14:39 -08:00
return false ;
}
return ret ;
}
void Client : : EnterWorld ( bool TryBootup ) {
2016-07-17 20:45:58 -05:00
if ( zone_id = = 0 )
2013-02-16 16:14:39 -08:00
return ;
2016-07-17 20:45:58 -05:00
ZoneServer * zone_server = nullptr ;
if ( instance_id > 0 )
2013-02-16 16:14:39 -08:00
{
2016-07-17 20:45:58 -05:00
if ( database . VerifyInstanceAlive ( instance_id , GetCharID ( ) ) )
2013-02-16 16:14:39 -08:00
{
2016-07-17 20:45:58 -05:00
if ( database . VerifyZoneInstance ( zone_id , instance_id ) )
2013-02-16 16:14:39 -08:00
{
2016-07-17 20:45:58 -05:00
zone_server = zoneserver_list . FindByInstanceID ( instance_id ) ;
2013-02-16 16:14:39 -08:00
}
else
{
2016-07-17 20:45:58 -05:00
instance_id = 0 ;
zone_server = nullptr ;
2013-02-16 16:14:39 -08:00
database . MoveCharacterToBind ( GetCharID ( ) ) ;
2016-07-17 20:45:58 -05:00
TellClientZoneUnavailable ( ) ;
2013-02-16 16:14:39 -08:00
return ;
}
}
else
{
2016-07-17 20:45:58 -05:00
instance_id = 0 ;
zone_server = nullptr ;
2013-02-16 16:14:39 -08:00
database . MoveCharacterToBind ( GetCharID ( ) ) ;
2016-07-17 20:45:58 -05:00
TellClientZoneUnavailable ( ) ;
2013-02-16 16:14:39 -08:00
return ;
}
}
else
2016-07-17 20:45:58 -05:00
zone_server = zoneserver_list . FindByZoneID ( zone_id ) ;
2013-02-16 16:14:39 -08:00
2016-07-17 20:45:58 -05:00
const char * zone_name = database . GetZoneName ( zone_id , true ) ;
if ( zone_server ) {
2019-07-30 19:12:44 -07:00
if ( false = = enter_world_triggered ) {
//Drop any clients we own in other zones.
zoneserver_list . DropClient ( GetLSID ( ) , zone_server ) ;
// warn the zone we're coming
zone_server - > IncomingClient ( this ) ;
//tell the server not to trigger this multiple times before we get a zone unavailable
enter_world_triggered = true ;
}
2013-02-16 16:14:39 -08:00
}
else {
if ( TryBootup ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Attempting autobootup of [{}] ([{}]:[{}]) " , zone_name , zone_id , instance_id ) ;
2013-02-16 16:14:39 -08:00
autobootup_timeout . Start ( ) ;
2016-07-17 20:45:58 -05:00
zone_waiting_for_bootup = zoneserver_list . TriggerBootup ( zone_id , instance_id ) ;
if ( zone_waiting_for_bootup = = 0 ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " No zoneserver available to boot up " ) ;
2016-07-17 20:45:58 -05:00
TellClientZoneUnavailable ( ) ;
2013-02-16 16:14:39 -08:00
}
return ;
}
else {
2019-09-01 22:53:23 -05:00
LogInfo ( " Requested zone [{}] is not running " , zone_name ) ;
2016-07-17 20:45:58 -05:00
TellClientZoneUnavailable ( ) ;
2013-02-16 16:14:39 -08:00
return ;
}
}
2019-07-30 19:12:44 -07:00
2016-07-17 20:45:58 -05:00
zone_waiting_for_bootup = 0 ;
2013-02-16 16:14:39 -08:00
2019-07-30 19:12:44 -07:00
if ( GetAdmin ( ) < 80 & & zoneserver_list . IsZoneLocked ( zone_id ) ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Enter world failed. Zone is locked " ) ;
2019-07-30 19:12:44 -07:00
TellClientZoneUnavailable ( ) ;
return ;
}
if ( ! cle ) {
TellClientZoneUnavailable ( ) ;
2015-01-30 15:03:02 -08:00
return ;
}
2013-02-16 16:14:39 -08:00
cle - > SetChar ( charid , char_name ) ;
database . UpdateLiveChar ( char_name , GetAccountID ( ) ) ;
2019-09-07 02:30:33 -05:00
LogInfo (
2019-09-07 01:59:50 -05:00
" ({}) [{}] [{}] (Zone ID [{}]: Instance ID: [{}]) " ,
2016-07-17 20:45:58 -05:00
char_name ,
( seen_character_select ? " Zoning from character select " : " Zoning to " ) ,
zone_name ,
zone_id ,
instance_id
) ;
if ( seen_character_select ) {
2015-01-09 03:05:13 -05:00
auto pack = new ServerPacket ;
2013-02-16 16:14:39 -08:00
pack - > opcode = ServerOP_AcceptWorldEntrance ;
pack - > size = sizeof ( WorldToZone_Struct ) ;
pack - > pBuffer = new uchar [ pack - > size ] ;
memset ( pack - > pBuffer , 0 , pack - > size ) ;
WorldToZone_Struct * wtz = ( WorldToZone_Struct * ) pack - > pBuffer ;
wtz - > account_id = GetAccountID ( ) ;
wtz - > response = 0 ;
2016-07-17 20:45:58 -05:00
zone_server - > SendPacket ( pack ) ;
2013-02-16 16:14:39 -08:00
delete pack ;
}
else { // if they havent seen character select screen, we can assume this is a zone
// to zone movement, which should be preauthorized before they leave the previous zone
Clearance ( 1 ) ;
}
}
void Client : : Clearance ( int8 response )
{
2013-05-04 18:06:58 -07:00
ZoneServer * zs = nullptr ;
2016-07-17 20:45:58 -05:00
if ( instance_id > 0 )
2013-02-16 16:14:39 -08:00
{
2016-07-17 20:45:58 -05:00
zs = zoneserver_list . FindByInstanceID ( instance_id ) ;
2013-02-16 16:14:39 -08:00
}
else
{
2016-07-17 20:45:58 -05:00
zs = zoneserver_list . FindByZoneID ( zone_id ) ;
2013-02-16 16:14:39 -08:00
}
2013-05-09 10:44:08 -04:00
if ( zs = = 0 | | response = = - 1 | | response = = 0 )
{
if ( zs = = 0 )
{
2019-09-01 22:53:23 -05:00
LogInfo ( " Unable to find zoneserver in Client::Clearance!! " ) ;
2013-05-09 10:44:08 -04:00
} else {
2019-09-01 22:53:23 -05:00
LogInfo ( " Invalid response [{}] in Client::Clearance " , response ) ;
2013-05-09 10:44:08 -04:00
}
2013-02-16 16:14:39 -08:00
2016-07-17 20:45:58 -05:00
TellClientZoneUnavailable ( ) ;
2013-05-09 10:44:08 -04:00
return ;
}
2013-02-16 16:14:39 -08:00
EQApplicationPacket * outapp ;
2013-05-09 10:44:08 -04:00
if ( zs - > GetCAddress ( ) = = nullptr ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Unable to do zs->GetCAddress() in Client::Clearance!! " ) ;
2016-07-17 20:45:58 -05:00
TellClientZoneUnavailable ( ) ;
2013-05-09 10:44:08 -04:00
return ;
}
2013-02-16 16:14:39 -08:00
2016-07-17 20:45:58 -05:00
if ( zone_id = = 0 ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " zoneID is nullptr in Client::Clearance!! " ) ;
2016-07-17 20:45:58 -05:00
TellClientZoneUnavailable ( ) ;
2013-05-09 10:44:08 -04:00
return ;
}
2013-02-16 16:14:39 -08:00
2016-07-17 20:45:58 -05:00
const char * zonename = database . GetZoneName ( zone_id ) ;
2013-05-09 10:44:08 -04:00
if ( zonename = = 0 ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " zonename is nullptr in Client::Clearance!! " ) ;
2016-07-17 20:45:58 -05:00
TellClientZoneUnavailable ( ) ;
2013-05-09 10:44:08 -04:00
return ;
}
2013-02-16 16:14:39 -08:00
// Send zone server IP data
outapp = new EQApplicationPacket ( OP_ZoneServerInfo , sizeof ( ZoneServerInfo_Struct ) ) ;
ZoneServerInfo_Struct * zsi = ( ZoneServerInfo_Struct * ) outapp - > pBuffer ;
2015-07-16 01:51:10 -07:00
const char * zs_addr = nullptr ;
if ( cle & & cle - > IsLocalClient ( ) ) {
const char * local_addr = zs - > GetCLocalAddress ( ) ;
2015-07-16 14:35:20 -07:00
2015-07-16 01:51:10 -07:00
if ( local_addr [ 0 ] ) {
zs_addr = local_addr ;
} else {
2017-04-16 21:06:05 -07:00
zs_addr = zs - > GetIP ( ) . c_str ( ) ;
2017-07-21 00:46:12 -05:00
if ( ! zs_addr [ 0 ] ) {
zs_addr = WorldConfig : : get ( ) - > LocalAddress . c_str ( ) ;
}
2017-04-16 21:06:05 -07:00
if ( strcmp ( zs_addr , " 127.0.0.1 " ) = = 0 )
2015-07-16 14:35:20 -07:00
{
2019-09-01 22:53:23 -05:00
LogInfo ( " Local zone address was [{}], setting local address to: [{}] " , zs_addr , WorldConfig : : get ( ) - > LocalAddress . c_str ( ) ) ;
2015-07-16 14:35:20 -07:00
zs_addr = WorldConfig : : get ( ) - > LocalAddress . c_str ( ) ;
} else {
2019-09-01 22:53:23 -05:00
LogInfo ( " Local zone address [{}] " , zs_addr ) ;
2015-07-16 14:35:20 -07:00
}
2015-07-16 01:51:10 -07:00
}
2015-07-16 14:35:20 -07:00
2015-07-16 01:51:10 -07:00
} else {
const char * addr = zs - > GetCAddress ( ) ;
if ( addr [ 0 ] ) {
zs_addr = addr ;
2013-02-16 16:14:39 -08:00
} else {
2015-07-16 15:07:59 -07:00
zs_addr = WorldConfig : : get ( ) - > WorldAddress . c_str ( ) ;
2013-02-16 16:14:39 -08:00
}
}
2015-07-16 01:51:10 -07:00
2013-02-16 16:14:39 -08:00
strcpy ( zsi - > ip , zs_addr ) ;
zsi - > port = zs - > GetCPort ( ) ;
2019-09-01 22:53:23 -05:00
LogInfo ( " Sending client to zone [{}] ([{}]:[{}]) at [{}]:[{}] " , zonename , zone_id , instance_id , zsi - > ip , zsi - > port ) ;
2013-02-16 16:14:39 -08:00
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
if ( cle )
2019-07-24 19:20:09 -07:00
cle - > SetOnline ( CLE_Status : : Zoning ) ;
2013-02-16 16:14:39 -08:00
}
2016-07-17 20:45:58 -05:00
void Client : : TellClientZoneUnavailable ( ) {
2015-01-09 03:05:13 -05:00
auto outapp = new EQApplicationPacket ( OP_ZoneUnavail , sizeof ( ZoneUnavail_Struct ) ) ;
2013-02-16 16:14:39 -08:00
ZoneUnavail_Struct * ua = ( ZoneUnavail_Struct * ) outapp - > pBuffer ;
2016-07-17 20:45:58 -05:00
const char * zonename = database . GetZoneName ( zone_id ) ;
2013-02-16 16:14:39 -08:00
if ( zonename )
strcpy ( ua - > zonename , zonename ) ;
QueuePacket ( outapp ) ;
delete outapp ;
2016-07-17 20:45:58 -05:00
zone_id = 0 ;
zone_waiting_for_bootup = 0 ;
2019-07-30 19:12:44 -07:00
enter_world_triggered = false ;
2013-02-16 16:14:39 -08:00
autobootup_timeout . Disable ( ) ;
}
bool Client : : GenPassKey ( char * key ) {
2013-05-04 18:06:58 -07:00
char * passKey = nullptr ;
2014-12-01 18:13:12 -05:00
* passKey + = ( ( char ) ( ' A ' + ( ( int ) emu_random . Int ( 0 , 25 ) ) ) ) ;
* passKey + = ( ( char ) ( ' A ' + ( ( int ) emu_random . Int ( 0 , 25 ) ) ) ) ;
2013-02-16 16:14:39 -08:00
memcpy ( key , passKey , strlen ( passKey ) ) ;
return true ;
}
void Client : : QueuePacket ( const EQApplicationPacket * app , bool ack_req ) {
2019-09-01 23:22:40 -05:00
LogNetcode ( " Sending EQApplicationPacket OpCode {:#04x} " , app - > GetOpcode ( ) ) ;
2013-02-16 16:14:39 -08:00
ack_req = true ; // It's broke right now, dont delete this line till fix it. =P
eqs - > QueuePacket ( app , ack_req ) ;
}
void Client : : SendGuildList ( ) {
EQApplicationPacket * outapp ;
outapp = new EQApplicationPacket ( OP_GuildsList ) ;
//ask the guild manager to build us a nice guild list packet
outapp - > pBuffer = guild_mgr . MakeGuildList ( " " , outapp - > size ) ;
2013-05-04 18:06:58 -07:00
if ( outapp - > pBuffer = = nullptr ) {
2013-02-16 16:14:39 -08:00
return ;
}
eqs - > FastQueuePacket ( ( EQApplicationPacket * * ) & outapp ) ;
}
// @merth: I have no idea what this struct is for, so it's hardcoded for now
void Client : : SendApproveWorld ( )
{
EQApplicationPacket * outapp ;
// Send OPCode: OP_ApproveWorld, size: 544
outapp = new EQApplicationPacket ( OP_ApproveWorld , sizeof ( ApproveWorld_Struct ) ) ;
ApproveWorld_Struct * aw = ( ApproveWorld_Struct * ) outapp - > pBuffer ;
uchar foo [ ] = {
2016-11-15 21:30:43 -08:00
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x37 , 0x87 , 0x13 , 0xbe , 0xc8 , 0xa7 , 0x77 , 0xcb ,
0x27 , 0xed , 0xe1 , 0xe6 , 0x5d , 0x1c , 0xaa , 0xd3 , 0x3c , 0x26 , 0x3b , 0x6d , 0x8c , 0xdb , 0x36 , 0x8d ,
0x91 , 0x72 , 0xf5 , 0xbb , 0xe0 , 0x5c , 0x50 , 0x6f , 0x09 , 0x6d , 0xc9 , 0x1e , 0xe7 , 0x2e , 0xf4 , 0x38 ,
0x1b , 0x5e , 0xa8 , 0xc2 , 0xfe , 0xb4 , 0x18 , 0x4a , 0xf7 , 0x72 , 0x85 , 0x13 , 0xf5 , 0x63 , 0x6c , 0x16 ,
0x69 , 0xf4 , 0xe0 , 0x17 , 0xff , 0x87 , 0x11 , 0xf3 , 0x2b , 0xb7 , 0x73 , 0x04 , 0x37 , 0xca , 0xd5 , 0x77 ,
0xf8 , 0x03 , 0x20 , 0x0a , 0x56 , 0x8b , 0xfb , 0x35 , 0xff , 0x59 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x15 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x53 , 0xC3 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00
} ;
2013-02-16 16:14:39 -08:00
memcpy ( aw - > unknown544 , foo , sizeof ( foo ) ) ;
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
2014-10-08 01:18:38 -04:00
bool Client : : OPCharCreate ( char * name , CharCreate_Struct * cc )
{
2013-02-16 16:14:39 -08:00
PlayerProfile_Struct pp ;
ExtendedProfile_Struct ext ;
2020-05-17 18:36:06 -07:00
EQ : : InventoryProfile inv ;
2019-01-15 00:50:58 -05:00
2020-05-17 18:36:06 -07:00
pp . SetPlayerProfileVersion ( EQ : : versions : : ConvertClientVersionToMobVersion ( EQ : : versions : : ConvertClientVersionBitToClientVersion ( m_ClientVersionBit ) ) ) ;
inv . SetInventoryVersion ( EQ : : versions : : ConvertClientVersionBitToClientVersion ( m_ClientVersionBit ) ) ;
2019-01-15 00:50:58 -05:00
inv . SetGMInventory ( false ) ; // character cannot have gm flag at this point
2013-05-04 18:06:58 -07:00
time_t bday = time ( nullptr ) ;
2013-02-16 16:14:39 -08:00
char startzone [ 50 ] = { 0 } ;
uint32 i ;
2014-10-08 01:18:38 -04:00
struct in_addr in ;
2014-10-07 23:40:13 -04:00
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
int stats_sum = cc - > STR + cc - > STA + cc - > AGI + cc - > DEX + cc - > WIS + cc - > INT + cc - > CHA ;
2013-02-16 16:14:39 -08:00
in . s_addr = GetIP ( ) ;
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
2019-09-01 22:53:23 -05:00
LogInfo ( " Character creation request from [{}] LS#[{}] ([{}]:[{}]) : " , GetCLE ( ) - > LSName ( ) , GetCLE ( ) - > LSID ( ) , inet_ntoa ( in ) , GetPort ( ) ) ;
LogInfo ( " Name: [{}] " , name ) ;
2019-09-01 20:47:26 -05:00
Log ( Logs : : Detail , Logs : : WorldServer , " Race: %d Class: %d Gender: %d Deity: %d Start zone: %d Tutorial: %s " ,
2014-10-08 01:18:38 -04:00
cc - > race , cc - > class_ , cc - > gender , cc - > deity , cc - > start_zone , cc - > tutorial ? " true " : " false " ) ;
2019-09-01 22:53:23 -05:00
LogInfo ( " STR STA AGI DEX WIS INT CHA Total " ) ;
2019-09-01 20:47:26 -05:00
Log ( Logs : : Detail , Logs : : WorldServer , " %3d %3d %3d %3d %3d %3d %3d %3d " ,
2013-02-16 16:14:39 -08:00
cc - > STR , cc - > STA , cc - > AGI , cc - > DEX , cc - > WIS , cc - > INT , cc - > CHA ,
stats_sum ) ;
2019-09-01 22:53:23 -05:00
LogInfo ( " Face: [{}] Eye colors: [{}] [{}] " , cc - > face , cc - > eyecolor1 , cc - > eyecolor2 ) ;
LogInfo ( " Hairstyle: [{}] Haircolor: [{}] " , cc - > hairstyle , cc - > haircolor ) ;
LogInfo ( " Beard: [{}] Beardcolor: [{}] " , cc - > beard , cc - > beardcolor ) ;
2013-02-16 16:14:39 -08:00
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
/* Validate the char creation struct */
2020-05-17 18:36:06 -07:00
if ( m_ClientVersionBit & EQ : : versions : : maskSoFAndLater ) {
2014-10-08 01:18:38 -04:00
if ( ! CheckCharCreateInfoSoF ( cc ) ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " CheckCharCreateInfo did not validate the request (bad race/class/stats) " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
} else {
2014-10-08 01:18:38 -04:00
if ( ! CheckCharCreateInfoTitanium ( cc ) ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " CheckCharCreateInfo did not validate the request (bad race/class/stats) " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
}
2013-02-16 16:14:39 -08:00
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
/* Convert incoming cc_s to the new PlayerProfile_Struct */
2013-02-16 16:14:39 -08:00
memset ( & pp , 0 , sizeof ( PlayerProfile_Struct ) ) ; // start building the profile
strn0cpy ( pp . name , name , 63 ) ;
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 ;
2013-05-09 10:44:08 -04:00
pp . beard = cc - > beard ;
2013-02-16 16:14:39 -08:00
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 ;
2014-10-08 01:18:38 -04:00
pp . cur_hp = 1000 ; // 1k hp during dev only
2013-02-16 16:14:39 -08:00
pp . hunger_level = 6000 ;
pp . thirst_level = 6000 ;
2014-10-08 01:18:38 -04:00
/* Set Racial and Class specific language and skills */
SetRacialLanguages ( & pp ) ;
SetRaceStartingSkills ( & pp ) ;
SetClassStartingSkills ( & pp ) ;
2014-09-13 03:20:43 -04:00
SetClassLanguages ( & pp ) ;
2015-02-23 13:32:10 -05:00
2020-05-17 18:36:06 -07:00
pp . skills [ EQ : : skills : : SkillSwimming ] = RuleI ( Skills , SwimmingStartValue ) ;
pp . skills [ EQ : : skills : : SkillSenseHeading ] = RuleI ( Skills , SenseHeadingStartValue ) ;
2015-02-23 13:32:10 -05:00
2013-02-16 16:14:39 -08:00
// strcpy(pp.servername, WorldConfig::get()->ShortName.c_str());
2020-05-17 18:36:06 -07:00
memset ( pp . spell_book , 0xFF , ( sizeof ( uint32 ) * EQ : : spells : : SPELLBOOK_SIZE ) ) ;
2019-01-24 03:53:41 -05:00
2020-05-17 18:36:06 -07:00
memset ( pp . mem_spells , 0xFF , ( sizeof ( uint32 ) * EQ : : spells : : SPELL_GEM_COUNT ) ) ;
2013-02-16 16:14:39 -08:00
for ( i = 0 ; i < BUFF_COUNT ; i + + )
pp . buffs [ i ] . spellid = 0xFFFF ;
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
/* If server is PVP by default, make all character set to it. */
2013-02-16 16:14:39 -08:00
pp . pvp = database . GetServerType ( ) = = 1 ? 1 : 0 ;
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
/* If it is an SoF Client and the SoF Start Zone rule is set, send new chars there */
2020-05-17 18:36:06 -07:00
if ( m_ClientVersionBit & EQ : : versions : : maskSoFAndLater ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Found 'SoFStartZoneID' rule setting: [{}] " , RuleI ( World , SoFStartZoneID ) ) ;
2015-01-13 21:47:51 +00:00
if ( RuleI ( World , SoFStartZoneID ) > 0 ) {
pp . zone_id = RuleI ( World , SoFStartZoneID ) ;
cc - > start_zone = pp . zone_id ;
2013-02-16 16:14:39 -08:00
}
}
2015-01-13 21:47:51 +00:00
else {
2019-09-01 22:53:23 -05:00
LogInfo ( " Found 'TitaniumStartZoneID' rule setting: [{}] " , RuleI ( World , TitaniumStartZoneID ) ) ;
2015-01-13 21:47:51 +00:00
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.*/
2020-05-17 18:36:06 -07:00
bool ValidStartZone = database . GetStartZone ( & pp , cc , m_ClientVersionBit & EQ : : versions : : maskTitaniumAndEarlier ) ;
2015-01-13 21:47:51 +00:00
if ( ! ValidStartZone ) {
return false ;
}
2013-02-16 16:14:39 -08:00
2014-10-08 01:18:38 -04:00
/* just in case */
if ( ! pp . zone_id ) {
2013-02-16 16:14:39 -08:00
pp . zone_id = 1 ; // qeynos
pp . x = pp . y = pp . z = - 1 ;
}
2016-04-26 16:06:24 -04:00
/* Set Home Binds -- yep, all of them */
pp . binds [ 1 ] . zoneId = pp . zone_id ;
pp . binds [ 1 ] . x = pp . x ;
pp . binds [ 1 ] . y = pp . y ;
pp . binds [ 1 ] . z = pp . z ;
pp . binds [ 1 ] . heading = pp . heading ;
pp . binds [ 2 ] . zoneId = pp . zone_id ;
pp . binds [ 2 ] . x = pp . x ;
pp . binds [ 2 ] . y = pp . y ;
pp . binds [ 2 ] . z = pp . z ;
pp . binds [ 2 ] . heading = pp . heading ;
pp . binds [ 3 ] . zoneId = pp . zone_id ;
pp . binds [ 3 ] . x = pp . x ;
pp . binds [ 3 ] . y = pp . y ;
pp . binds [ 3 ] . z = pp . z ;
pp . binds [ 3 ] . heading = pp . heading ;
2014-10-08 01:18:38 -04:00
pp . binds [ 4 ] . zoneId = pp . zone_id ;
pp . binds [ 4 ] . x = pp . x ;
pp . binds [ 4 ] . y = pp . y ;
pp . binds [ 4 ] . z = pp . z ;
pp . binds [ 4 ] . heading = pp . heading ;
2013-02-16 16:14:39 -08:00
2014-10-07 23:40:13 -04:00
/* Overrides if we have the tutorial flag set! */
if ( cc - > tutorial & & RuleB ( World , EnableTutorialButton ) ) {
pp . zone_id = RuleI ( World , TutorialZoneID ) ;
database . GetSafePoints ( pp . zone_id , 0 , & pp . x , & pp . y , & pp . z ) ;
}
2013-02-16 16:14:39 -08:00
2017-03-12 03:41:21 -04:00
/* Will either be the same as home or tutorial if enabled. */
if ( RuleB ( World , StartZoneSameAsBindOnCreation ) ) {
pp . binds [ 0 ] . zoneId = 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 ;
}
2013-02-16 16:14:39 -08:00
2019-09-01 20:47:26 -05:00
Log ( Logs : : Detail , Logs : : WorldServer , " Current location: %s (%d) %0.2f, %0.2f, %0.2f, %0.2f " ,
2014-10-07 23:40:13 -04:00
database . GetZoneName ( pp . zone_id ) , pp . zone_id , pp . x , pp . y , pp . z , pp . heading ) ;
2019-09-01 20:47:26 -05:00
Log ( Logs : : Detail , Logs : : WorldServer , " Bind location: %s (%d) %0.2f, %0.2f, %0.2f " ,
database . GetZoneName ( pp . binds [ 0 ] . zoneId ) , pp . binds [ 0 ] . zoneId , pp . binds [ 0 ] . x , pp . binds [ 0 ] . y , pp . binds [ 0 ] . z ) ;
Log ( Logs : : Detail , Logs : : WorldServer , " Home location: %s (%d) %0.2f, %0.2f, %0.2f " ,
database . GetZoneName ( pp . binds [ 4 ] . zoneId ) , pp . binds [ 4 ] . zoneId , pp . binds [ 4 ] . x , pp . binds [ 4 ] . y , pp . binds [ 4 ] . z ) ;
2013-02-16 16:14:39 -08:00
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
/* Starting Items inventory */
2013-02-16 16:14:39 -08:00
database . SetStartingItems ( & pp , & inv , pp . race , pp . class_ , pp . deity , pp . zone_id , pp . name , GetAdmin ( ) ) ;
// now we give the pp and the inv we made to StoreCharacter
// to see if we can store it
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
if ( ! database . StoreCharacter ( GetAccountID ( ) , & pp , & inv ) ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Character creation failed: [{}] " , pp . name ) ;
2013-02-16 16:14:39 -08:00
return false ;
}
2019-09-01 22:53:23 -05:00
LogInfo ( " Character creation successful: [{}] " , pp . name ) ;
2014-10-08 01:18:38 -04:00
return true ;
2013-02-16 16:14:39 -08:00
}
// returns true if the request is ok, false if there's an error
2014-10-08 01:28:03 -04:00
bool CheckCharCreateInfoSoF ( CharCreate_Struct * cc )
{
if ( ! cc )
return false ;
2013-02-16 16:14:39 -08:00
2019-09-01 22:53:23 -05:00
LogInfo ( " Validating char creation info " ) ;
2013-02-16 16:14:39 -08:00
2013-05-09 10:44:08 -04:00
RaceClassCombos class_combo ;
bool found = false ;
int combos = character_create_race_class_combos . size ( ) ;
2014-10-08 01:28:03 -04:00
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 ;
2013-05-09 10:44:08 -04:00
}
}
2014-10-08 01:28:03 -04:00
if ( ! found ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Could not find class/race/deity/start_zone combination " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
uint32 max_stats = 0 ;
uint32 allocs = character_create_allocations . size ( ) ;
2013-05-23 20:22:42 -04:00
RaceClassAllocation allocation = { 0 } ;
2013-05-09 10:44:08 -04:00
found = false ;
2014-10-08 01:28:03 -04:00
for ( int i = 0 ; i < allocs ; + + i ) {
if ( character_create_allocations [ i ] . Index = = class_combo . AllocationIndex ) {
2013-05-09 10:44:08 -04:00
allocation = character_create_allocations [ i ] ;
found = true ;
break ;
}
}
2014-10-08 01:28:03 -04:00
if ( ! found ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Could not find starting stats for selected character combo, cannot verify stats " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
max_stats = allocation . DefaultPointAllocation [ 0 ] +
allocation . DefaultPointAllocation [ 1 ] +
allocation . DefaultPointAllocation [ 2 ] +
allocation . DefaultPointAllocation [ 3 ] +
allocation . DefaultPointAllocation [ 4 ] +
allocation . DefaultPointAllocation [ 5 ] +
allocation . DefaultPointAllocation [ 6 ] ;
2014-10-08 01:28:03 -04:00
if ( cc - > STR > allocation . BaseStats [ 0 ] + max_stats | | cc - > STR < allocation . BaseStats [ 0 ] ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Strength out of range " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
2014-10-08 01:28:03 -04:00
if ( cc - > DEX > allocation . BaseStats [ 1 ] + max_stats | | cc - > DEX < allocation . BaseStats [ 1 ] ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Dexterity out of range " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
2014-10-08 01:28:03 -04:00
if ( cc - > AGI > allocation . BaseStats [ 2 ] + max_stats | | cc - > AGI < allocation . BaseStats [ 2 ] ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Agility out of range " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
2014-10-08 01:28:03 -04:00
if ( cc - > STA > allocation . BaseStats [ 3 ] + max_stats | | cc - > STA < allocation . BaseStats [ 3 ] ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Stamina out of range " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
2014-10-08 01:28:03 -04:00
if ( cc - > INT > allocation . BaseStats [ 4 ] + max_stats | | cc - > INT < allocation . BaseStats [ 4 ] ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Intelligence out of range " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
2014-10-08 01:28:03 -04:00
if ( cc - > WIS > allocation . BaseStats [ 5 ] + max_stats | | cc - > WIS < allocation . BaseStats [ 5 ] ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Wisdom out of range " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
2014-10-08 01:28:03 -04:00
if ( cc - > CHA > allocation . BaseStats [ 6 ] + max_stats | | cc - > CHA < allocation . BaseStats [ 6 ] ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Charisma out of range " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
uint32 current_stats = 0 ;
current_stats + = cc - > STR - allocation . BaseStats [ 0 ] ;
current_stats + = cc - > DEX - allocation . BaseStats [ 1 ] ;
current_stats + = cc - > AGI - allocation . BaseStats [ 2 ] ;
current_stats + = cc - > STA - allocation . BaseStats [ 3 ] ;
current_stats + = cc - > INT - allocation . BaseStats [ 4 ] ;
current_stats + = cc - > WIS - allocation . BaseStats [ 5 ] ;
current_stats + = cc - > CHA - allocation . BaseStats [ 6 ] ;
2014-10-08 01:28:03 -04:00
if ( current_stats > max_stats ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " Current Stats > Maximum Stats " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
2013-02-16 16:14:39 -08:00
return true ;
}
bool CheckCharCreateInfoTitanium ( CharCreate_Struct * cc )
{
2013-05-09 10:44:08 -04:00
uint32 bSTR , bSTA , bAGI , bDEX , bWIS , bINT , bCHA , bTOTAL , cTOTAL , stat_points ; //these are all uint32 in CharCreate_Struct, so we'll make them uint32 here to make the compiler shut up
int classtemp , racetemp ;
int Charerrors = 0 ;
2013-02-16 16:14:39 -08:00
2015-01-31 17:03:44 -05:00
// if this is increased you'll have to add a column to the classrace
2013-02-16 16:14:39 -08:00
// table below
2013-05-09 10:44:08 -04:00
# define _TABLE_RACES 16
static const int BaseRace [ _TABLE_RACES ] [ 7 ] =
{ /* STR STA AGI DEX WIS INT CHR */
{ /*Human*/ 75 , 75 , 75 , 75 , 75 , 75 , 75 } ,
{ /*Barbarian*/ 103 , 95 , 82 , 70 , 70 , 60 , 55 } ,
{ /*Erudite*/ 60 , 70 , 70 , 70 , 83 , 107 , 70 } ,
{ /*Wood Elf*/ 65 , 65 , 95 , 80 , 80 , 75 , 75 } ,
{ /*High Elf*/ 55 , 65 , 85 , 70 , 95 , 92 , 80 } ,
{ /*Dark Elf*/ 60 , 65 , 90 , 75 , 83 , 99 , 60 } ,
{ /*Half Elf*/ 70 , 70 , 90 , 85 , 60 , 75 , 75 } ,
{ /*Dwarf*/ 90 , 90 , 70 , 90 , 83 , 60 , 45 } ,
{ /*Troll*/ 108 , 109 , 83 , 75 , 60 , 52 , 40 } ,
{ /*Ogre*/ 130 , 122 , 70 , 70 , 67 , 60 , 37 } ,
{ /*Halfling*/ 70 , 75 , 95 , 90 , 80 , 67 , 50 } ,
{ /*Gnome*/ 60 , 70 , 85 , 85 , 67 , 98 , 60 } ,
{ /*Iksar*/ 70 , 70 , 90 , 85 , 80 , 75 , 55 } ,
{ /*Vah Shir*/ 90 , 75 , 90 , 70 , 70 , 65 , 65 } ,
{ /*Froglok*/ 70 , 80 , 100 , 100 , 75 , 75 , 50 } ,
{ /*Drakkin*/ 70 , 80 , 85 , 75 , 80 , 85 , 75 }
} ;
static const int BaseClass [ PLAYER_CLASS_COUNT ] [ 8 ] =
{ /* STR STA AGI DEX WIS INT CHR ADD*/
{ /*Warrior*/ 10 , 10 , 5 , 0 , 0 , 0 , 0 , 25 } ,
{ /*Cleric*/ 5 , 5 , 0 , 0 , 10 , 0 , 0 , 30 } ,
{ /*Paladin*/ 10 , 5 , 0 , 0 , 5 , 0 , 10 , 20 } ,
{ /*Ranger*/ 5 , 10 , 10 , 0 , 5 , 0 , 0 , 20 } ,
{ /*ShadowKnight*/ 10 , 5 , 0 , 0 , 0 , 10 , 5 , 20 } ,
{ /*Druid*/ 0 , 10 , 0 , 0 , 10 , 0 , 0 , 30 } ,
{ /*Monk*/ 5 , 5 , 10 , 10 , 0 , 0 , 0 , 20 } ,
{ /*Bard*/ 5 , 0 , 0 , 10 , 0 , 0 , 10 , 25 } ,
{ /*Rouge*/ 0 , 0 , 10 , 10 , 0 , 0 , 0 , 30 } ,
{ /*Shaman*/ 0 , 5 , 0 , 0 , 10 , 0 , 5 , 30 } ,
{ /*Necromancer*/ 0 , 0 , 0 , 10 , 0 , 10 , 0 , 30 } ,
{ /*Wizard*/ 0 , 10 , 0 , 0 , 0 , 10 , 0 , 30 } ,
{ /*Magician*/ 0 , 10 , 0 , 0 , 0 , 10 , 0 , 30 } ,
{ /*Enchanter*/ 0 , 0 , 0 , 0 , 0 , 10 , 10 , 30 } ,
{ /*Beastlord*/ 0 , 10 , 5 , 0 , 10 , 0 , 5 , 20 } ,
{ /*Berserker*/ 10 , 5 , 0 , 10 , 0 , 0 , 0 , 25 }
} ;
static const bool ClassRaceLookupTable [ PLAYER_CLASS_COUNT ] [ _TABLE_RACES ] =
{ /*Human Barbarian Erudite Woodelf Highelf Darkelf Halfelf Dwarf Troll Ogre Halfling Gnome Iksar Vahshir Froglok Drakkin*/
{ /*Warrior*/ true , true , false , true , false , true , true , true , true , true , true , true , true , true , true , true } ,
{ /*Cleric*/ true , false , true , false , true , true , true , true , false , false , true , true , false , false , true , true } ,
{ /*Paladin*/ true , false , true , false , true , false , true , true , false , false , true , true , false , false , true , true } ,
{ /*Ranger*/ true , false , false , true , false , false , true , false , false , false , true , false , false , false , false , true } ,
{ /*ShadowKnight*/ true , false , true , false , false , true , false , false , true , true , false , true , true , false , true , true } ,
{ /*Druid*/ true , false , false , true , false , false , true , false , false , false , true , false , false , false , false , true } ,
{ /*Monk*/ true , false , false , false , false , false , false , false , false , false , false , false , true , false , false , true } ,
{ /*Bard*/ true , false , false , true , false , false , true , false , false , false , false , false , false , true , false , true } ,
{ /*Rogue*/ true , true , false , true , false , true , true , true , false , false , true , true , false , true , true , true } ,
{ /*Shaman*/ false , true , false , false , false , false , false , false , true , true , false , false , true , true , true , false } ,
{ /*Necromancer*/ true , false , true , false , false , true , false , false , false , false , false , true , true , false , true , true } ,
{ /*Wizard*/ true , false , true , false , true , true , false , false , false , false , false , true , false , false , true , true } ,
{ /*Magician*/ true , false , true , false , true , true , false , false , false , false , false , true , false , false , false , true } ,
{ /*Enchanter*/ true , false , true , false , true , true , false , false , false , false , false , true , false , false , false , true } ,
{ /*Beastlord*/ false , true , false , false , false , false , false , false , true , true , false , false , true , true , false , false } ,
{ /*Berserker*/ false , true , false , false , false , false , false , true , true , true , false , false , false , true , false , false }
2015-01-31 17:03:44 -05:00
} ;
2013-05-09 10:44:08 -04:00
2014-10-08 01:28:03 -04:00
if ( ! cc )
return false ;
2013-05-09 10:44:08 -04:00
2019-09-01 22:53:23 -05:00
LogInfo ( " Validating char creation info " ) ;
2013-05-09 10:44:08 -04:00
classtemp = cc - > class_ - 1 ;
racetemp = cc - > race - 1 ;
// these have non sequential race numbers so they need to be mapped
if ( cc - > race = = FROGLOK ) racetemp = 14 ;
if ( cc - > race = = VAHSHIR ) racetemp = 13 ;
if ( cc - > race = = IKSAR ) racetemp = 12 ;
if ( cc - > race = = DRAKKIN ) racetemp = 15 ;
// if out of range looking it up in the table would crash stuff
// so we return from these
2014-10-08 01:28:03 -04:00
if ( classtemp > = PLAYER_CLASS_COUNT ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " class is out of range " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
2014-10-08 01:28:03 -04:00
if ( racetemp > = _TABLE_RACES ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " race is out of range " ) ;
2013-05-09 10:44:08 -04:00
return false ;
}
2014-10-08 01:28:03 -04:00
if ( ! ClassRaceLookupTable [ classtemp ] [ racetemp ] ) { //Lookup table better than a bunch of ifs?
2019-09-01 22:53:23 -05:00
LogInfo ( " invalid race/class combination " ) ;
2013-05-09 10:44:08 -04:00
// we return from this one, since if it's an invalid combination our table
// doesn't have meaningful values for the stats
return false ;
}
2015-01-31 17:03:44 -05:00
// add up the base values for this class/race
2013-05-09 10:44:08 -04:00
// this is what they start with, and they have stat_points more
// that can distributed
bSTR = BaseClass [ classtemp ] [ 0 ] + BaseRace [ racetemp ] [ 0 ] ;
bSTA = BaseClass [ classtemp ] [ 1 ] + BaseRace [ racetemp ] [ 1 ] ;
bAGI = BaseClass [ classtemp ] [ 2 ] + BaseRace [ racetemp ] [ 2 ] ;
bDEX = BaseClass [ classtemp ] [ 3 ] + BaseRace [ racetemp ] [ 3 ] ;
bWIS = BaseClass [ classtemp ] [ 4 ] + BaseRace [ racetemp ] [ 4 ] ;
bINT = BaseClass [ classtemp ] [ 5 ] + BaseRace [ racetemp ] [ 5 ] ;
bCHA = BaseClass [ classtemp ] [ 6 ] + BaseRace [ racetemp ] [ 6 ] ;
stat_points = BaseClass [ classtemp ] [ 7 ] ;
bTOTAL = bSTR + bSTA + bAGI + bDEX + bWIS + bINT + bCHA ;
cTOTAL = cc - > STR + cc - > STA + cc - > AGI + cc - > DEX + cc - > WIS + cc - > INT + cc - > CHA ;
2015-01-31 17:03:44 -05:00
// the first check makes sure the total is exactly what was expected.
2013-05-09 10:44:08 -04:00
// this will catch all the stat cheating, but there's still the issue
// of reducing CHA or INT or something, to use for STR, so we check
// that none are lower than the base or higher than base + stat_points
// NOTE: these could just be else if, but i want to see all the stats
// that are messed up not just the first hit
2014-10-08 01:28:03 -04:00
if ( bTOTAL + stat_points ! = cTOTAL ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " stat points total doesn't match expected value: expecting [{}] got [{}] " , bTOTAL + stat_points , cTOTAL ) ;
2013-05-09 10:44:08 -04:00
Charerrors + + ;
}
2014-10-08 01:28:03 -04:00
if ( cc - > STR > bSTR + stat_points | | cc - > STR < bSTR ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " stat STR is out of range " ) ;
2013-05-09 10:44:08 -04:00
Charerrors + + ;
}
2014-10-08 01:28:03 -04:00
if ( cc - > STA > bSTA + stat_points | | cc - > STA < bSTA ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " stat STA is out of range " ) ;
2013-05-09 10:44:08 -04:00
Charerrors + + ;
}
2014-10-08 01:28:03 -04:00
if ( cc - > AGI > bAGI + stat_points | | cc - > AGI < bAGI ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " stat AGI is out of range " ) ;
2013-05-09 10:44:08 -04:00
Charerrors + + ;
}
2014-10-08 01:28:03 -04:00
if ( cc - > DEX > bDEX + stat_points | | cc - > DEX < bDEX ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " stat DEX is out of range " ) ;
2013-05-09 10:44:08 -04:00
Charerrors + + ;
}
2014-10-08 01:28:03 -04:00
if ( cc - > WIS > bWIS + stat_points | | cc - > WIS < bWIS ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " stat WIS is out of range " ) ;
2013-05-09 10:44:08 -04:00
Charerrors + + ;
}
2014-10-08 01:28:03 -04:00
if ( cc - > INT > bINT + stat_points | | cc - > INT < bINT ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " stat INT is out of range " ) ;
2013-05-09 10:44:08 -04:00
Charerrors + + ;
}
2014-10-08 01:28:03 -04:00
if ( cc - > CHA > bCHA + stat_points | | cc - > CHA < bCHA ) {
2019-09-01 22:53:23 -05:00
LogInfo ( " stat CHA is out of range " ) ;
2013-05-09 10:44:08 -04:00
Charerrors + + ;
}
/*TODO: Check for deity/class/race.. it'd be nice, but probably of any real use to hack(faction, deity based items are all I can think of)
I am NOT writing those tables - kathgar */
2019-09-01 22:53:23 -05:00
LogInfo ( " Found [{}] errors in character creation request " , Charerrors ) ;
2013-05-09 10:44:08 -04:00
return Charerrors = = 0 ;
2013-02-16 16:14:39 -08:00
}
2014-09-24 23:35:10 -04:00
void Client : : SetClassStartingSkills ( PlayerProfile_Struct * pp )
2013-02-16 16:14:39 -08:00
{
2020-05-17 18:36:06 -07:00
for ( uint32 i = 0 ; i < = EQ : : skills : : HIGHEST_SKILL ; + + i ) {
2014-09-24 23:35:10 -04:00
if ( pp - > skills [ i ] = = 0 ) {
2014-09-26 00:44:51 -04:00
// Skip specialized, tradeskills (fishing excluded), Alcohol Tolerance, and Bind Wound
2020-05-17 18:36:06 -07:00
if ( EQ : : skills : : IsSpecializedSkill ( ( EQ : : skills : : SkillType ) i ) | |
( EQ : : skills : : IsTradeskill ( ( EQ : : skills : : SkillType ) i ) & & i ! = EQ : : skills : : SkillFishing ) | |
i = = EQ : : skills : : SkillAlcoholTolerance | | i = = EQ : : skills : : SkillBindWound )
2013-05-09 10:44:08 -04:00
continue ;
2020-05-17 18:36:06 -07:00
pp - > skills [ i ] = database . GetSkillCap ( pp - > class_ , ( EQ : : skills : : SkillType ) i , 1 ) ;
2013-05-09 10:44:08 -04:00
}
}
2016-01-26 15:08:41 -05:00
2020-05-17 18:36:06 -07:00
if ( cle - > GetClientVersion ( ) < static_cast < uint8 > ( EQ : : versions : : ClientVersion : : RoF2 ) & & pp - > class_ = = BERSERKER ) {
pp - > skills [ EQ : : skills : : Skill1HPiercing ] = pp - > skills [ EQ : : skills : : Skill2HPiercing ] ;
pp - > skills [ EQ : : skills : : Skill2HPiercing ] = 0 ;
2016-01-26 15:08:41 -05:00
}
2013-02-16 16:14:39 -08:00
}
void Client : : SetRaceStartingSkills ( PlayerProfile_Struct * pp )
{
2013-05-09 10:44:08 -04:00
switch ( pp - > race )
{
case BARBARIAN :
case DWARF :
case ERUDITE :
case HALF_ELF :
case HIGH_ELF :
case HUMAN :
case OGRE :
case TROLL :
case DRAKKIN : //Drakkin are supposed to get a starting AA Skill
{
// No Race Specific Skills
break ;
}
case DARK_ELF :
{
2020-05-17 18:36:06 -07:00
pp - > skills [ EQ : : skills : : SkillHide ] = 50 ;
2013-05-09 10:44:08 -04:00
break ;
}
case FROGLOK :
{
2020-05-17 18:36:06 -07:00
pp - > skills [ EQ : : skills : : SkillSwimming ] = 125 ;
2013-05-09 10:44:08 -04:00
break ;
}
case GNOME :
{
2020-05-17 18:36:06 -07:00
pp - > skills [ EQ : : skills : : SkillTinkering ] = 50 ;
2013-05-09 10:44:08 -04:00
break ;
}
case HALFLING :
{
2020-05-17 18:36:06 -07:00
pp - > skills [ EQ : : skills : : SkillHide ] = 50 ;
pp - > skills [ EQ : : skills : : SkillSneak ] = 50 ;
2013-05-09 10:44:08 -04:00
break ;
}
case IKSAR :
{
2020-05-17 18:36:06 -07:00
pp - > skills [ EQ : : skills : : SkillForage ] = 50 ;
pp - > skills [ EQ : : skills : : SkillSwimming ] = 100 ;
2013-05-09 10:44:08 -04:00
break ;
}
case WOOD_ELF :
{
2020-05-17 18:36:06 -07:00
pp - > skills [ EQ : : skills : : SkillForage ] = 50 ;
pp - > skills [ EQ : : skills : : SkillHide ] = 50 ;
2013-05-09 10:44:08 -04:00
break ;
}
case VAHSHIR :
{
2020-05-17 18:36:06 -07:00
pp - > skills [ EQ : : skills : : SkillSafeFall ] = 50 ;
pp - > skills [ EQ : : skills : : SkillSneak ] = 50 ;
2013-05-09 10:44:08 -04:00
break ;
}
}
2013-02-16 16:14:39 -08:00
}
void Client : : SetRacialLanguages ( PlayerProfile_Struct * pp )
{
2013-05-09 10:44:08 -04:00
switch ( pp - > race )
{
case BARBARIAN :
{
pp - > languages [ LANG_COMMON_TONGUE ] = 100 ;
pp - > languages [ LANG_BARBARIAN ] = 100 ;
break ;
}
case DARK_ELF :
{
pp - > languages [ LANG_COMMON_TONGUE ] = 100 ;
pp - > languages [ LANG_DARK_ELVISH ] = 100 ;
pp - > languages [ LANG_DARK_SPEECH ] = 100 ;
pp - > languages [ LANG_ELDER_ELVISH ] = 100 ;
pp - > languages [ LANG_ELVISH ] = 25 ;
break ;
}
case DWARF :
{
pp - > languages [ LANG_COMMON_TONGUE ] = 100 ;
pp - > languages [ LANG_DWARVISH ] = 100 ;
pp - > languages [ LANG_GNOMISH ] = 25 ;
break ;
}
case ERUDITE :
{
pp - > languages [ LANG_COMMON_TONGUE ] = 100 ;
pp - > languages [ LANG_ERUDIAN ] = 100 ;
break ;
}
case FROGLOK :
{
pp - > languages [ LANG_COMMON_TONGUE ] = 100 ;
pp - > languages [ LANG_FROGLOK ] = 100 ;
pp - > languages [ LANG_TROLL ] = 25 ;
break ;
}
case GNOME :
{
pp - > languages [ LANG_COMMON_TONGUE ] = 100 ;
pp - > languages [ LANG_DWARVISH ] = 25 ;
pp - > languages [ LANG_GNOMISH ] = 100 ;
break ;
}
case HALF_ELF :
{
pp - > languages [ LANG_COMMON_TONGUE ] = 100 ;
pp - > languages [ LANG_ELVISH ] = 100 ;
break ;
}
case HALFLING :
{
pp - > languages [ LANG_COMMON_TONGUE ] = 100 ;
pp - > languages [ LANG_HALFLING ] = 100 ;
break ;
}
case HIGH_ELF :
{
pp - > languages [ LANG_COMMON_TONGUE ] = 100 ;
pp - > languages [ LANG_DARK_ELVISH ] = 25 ;
pp - > languages [ LANG_ELDER_ELVISH ] = 25 ;
pp - > languages [ LANG_ELVISH ] = 100 ;
break ;
}
case HUMAN :
{
pp - > languages [ LANG_COMMON_TONGUE ] = 100 ;
break ;
}
case IKSAR :
{
2015-07-22 09:23:49 -04:00
pp - > languages [ LANG_COMMON_TONGUE ] = RuleI ( Character , IksarCommonTongue ) ;
2013-05-09 10:44:08 -04:00
pp - > languages [ LANG_DARK_SPEECH ] = 100 ;
pp - > languages [ LANG_LIZARDMAN ] = 100 ;
break ;
}
case OGRE :
{
2015-07-22 09:23:49 -04:00
pp - > languages [ LANG_COMMON_TONGUE ] = RuleI ( Character , OgreCommonTongue ) ;
2013-05-09 10:44:08 -04:00
pp - > languages [ LANG_DARK_SPEECH ] = 100 ;
pp - > languages [ LANG_OGRE ] = 100 ;
break ;
}
case TROLL :
{
2015-07-22 09:23:49 -04:00
pp - > languages [ LANG_COMMON_TONGUE ] = RuleI ( Character , TrollCommonTongue ) ;
2013-05-09 10:44:08 -04:00
pp - > languages [ LANG_DARK_SPEECH ] = 100 ;
pp - > languages [ LANG_TROLL ] = 100 ;
break ;
}
case WOOD_ELF :
{
pp - > languages [ LANG_COMMON_TONGUE ] = 100 ;
pp - > languages [ LANG_ELVISH ] = 100 ;
break ;
}
case VAHSHIR :
{
pp - > languages [ LANG_COMMON_TONGUE ] = 100 ;
pp - > languages [ LANG_COMBINE_TONGUE ] = 100 ;
pp - > languages [ LANG_ERUDIAN ] = 25 ;
pp - > languages [ LANG_VAH_SHIR ] = 100 ;
break ;
}
case DRAKKIN :
{
pp - > languages [ LANG_COMMON_TONGUE ] = 100 ;
pp - > languages [ LANG_ELDER_DRAGON ] = 100 ;
pp - > languages [ LANG_DRAGON ] = 100 ;
break ;
}
}
2013-02-16 16:14:39 -08:00
}
2013-05-09 10:44:08 -04:00
2014-09-13 03:20:43 -04:00
void Client : : SetClassLanguages ( PlayerProfile_Struct * pp )
{
// we only need to handle one class, but custom server might want to do more
switch ( pp - > class_ ) {
case ROGUE :
pp - > languages [ LANG_THIEVES_CANT ] = 100 ;
break ;
default :
break ;
}
}