Files
ThomasandClaude Sonnet 5 f59158a95c Fix quest array off-by-ones and add QuestID bounds checks
Several quest-loading loops used <=N over arrays sized N (Variables,
Switches, Items, EpisodeVar, JobVar, PlanetVar, UnionVar), writing one
element past the end on every character load. Also guard STB_QUEST
table lookups with a rowcount bounds check before indexing by
QuestID, which could otherwise read out of bounds for stale/invalid
quest ids.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-09 06:35:11 +02:00

1381 lines
57 KiB
C++

/*
Rose Online Server Emulator
Copyright (C) 2006,2007 OSRose Team http://www.osrose.net
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; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
depeloped with Main erose/hrose source server + some change from the original eich source
*/
#include "player.h"
#include "worldserver.h"
unsigned char GetCharVal( char mychar )
{
switch( mychar )
{
case '0': return 0;
case '1': return 1;
case '2': return 2;
case '3': return 3;
case '4': return 4;
case '5': return 5;
case '6': return 6;
case '7': return 7;
case '8': return 8;
case '9': return 9;
case 'a': return 10;
case 'b': return 11;
case 'c': return 12;
case 'd': return 13;
case 'e': return 14;
case 'f': return 15;
case 'A': return 10;
case 'B': return 11;
case 'C': return 12;
case 'D': return 13;
case 'E': return 14;
case 'F': return 15;
default:
break;
}
return 0;
}
void EncodeBinary( char* encoded, unsigned char* data, unsigned datalen )
{
for( unsigned short i = 0, j = 0; i < datalen; i++ )
{
encoded[ j++ ] = "0123456789ABCDEF"[ data[ i ] >> 4 ];
encoded[ j++ ] = "0123456789ABCDEF"[ data[ i ] & 0xf ];
}
encoded[ datalen * 2 ] = 0;
}
void DecodeBinary( char* encoded, unsigned char* data )
{
unsigned curbit = 0;
for( unsigned i = 0; i < (unsigned)strlen(encoded); i+=2 )
{
data[curbit] = GetCharVal( encoded[i] ) << 4;
data[curbit] += GetCharVal( encoded[i+1] );
curbit++;
}
}
// Load this characters userdata from the database
bool CPlayer::loaddata( )
{
//Log(MSG_INFO,"Loading character data");
memset( &quest, 0, sizeof(quest) ); // quest slots without a saved row must default to zero, not stack/heap garbage
MYSQL_ROW row;
MYSQL_RES *result = GServer->DB->QStore("SELECT level,face,hairStyle,sex,classid,zuly,str,dex,_int,con,cha,sen,curHp,curMp,id,statp,skillp,exp,stamina,quickbar,basic_skills,askill,askilllvl,pskill,pskilllvl,respawnid,clanid,clan_rank,townid,isgm,isdev FROM characters WHERE char_name='%s'", CharInfo->charname);
if(result==NULL) return false;
if(mysql_num_rows(result)!=1)
{
Log( MSG_WARNING, "Number of user with charname '%s' is %i", CharInfo->charname,mysql_num_rows(result));
return false;
}
row = mysql_fetch_row(result);
Stats->Level = atoi(row[0]);
CharInfo->Face = atoi(row[1]);
CharInfo->Hair = atoi(row[2]);
CharInfo->Sex = atoi(row[3]);
CharInfo->Job = atoi(row[4]);
CharInfo->Zulies = atol(row[5]);
Attr->Str = atoi(row[6]);
Attr->Dex = atoi(row[7]);
Attr->Int = atoi(row[8]);
Attr->Con = atoi(row[9]);
Attr->Cha = atoi(row[10]);
Attr->Sen = atoi(row[11]);
Stats->HP = atoi(row[12]);
Stats->MP = atoi(row[13]);
CharInfo->charid = atoi(row[14]);
CharInfo->StatPoints = atoi(row[15]);
CharInfo->SkillPoints = atoi(row[16]);
CharInfo->Exp = atoi(row[17]);
CharInfo->stamina = atoi(row[18]);
Position->respawn = atoi(row[25]);
Clan->clanid = atoi(row[26]);
Clan->clanrank = atoi(row[27]);
Position->saved = atoi(row[28]);
Stats->xprate = GetXPRate();
CharInfo->IsGM = atoi(row[29]);
CharInfo->IsDev = atoi(row[30]);
Log(MSG_DEBUG,"Selected Character %s Class %i GM status: %i DEV status %i", CharInfo->charname, CharInfo->Job, CharInfo->IsGM, CharInfo->IsDev);
p_skills = 0;
for(char i=0;i<32;i++)
{
char* tmp=strtok((i==0?row[19]:NULL), ",");
if (tmp!=NULL) quickbar[i]=atoi(tmp);
else
quickbar[i]=0;
}
for(char i=0;i<30;i++)
{
char* tmp=strtok((i==0?row[20]:NULL), ",");
if (tmp!=NULL) bskills[i]=atoi(tmp);
else
bskills[i]=0;
}
for(char i=0;i<30;i++)
{
char* tmp=strtok((i==0?row[21]:NULL), ",");
if (tmp!=NULL) askill[i]=atoi(tmp);
else
askill[i]=0;
}
for(char i=0;i<30;i++)
{
char* tmp=strtok((i==0?row[22]:NULL), ",");
if (tmp!=NULL) askilllvl[i]=atoi(tmp);
else
askilllvl[i]=0;
}
for(char i=0;i<30;i++)
{
char* tmp=strtok((i==0?row[23]:NULL), ",");
if (tmp!=NULL) pskill[i]=atoi(tmp);
else
pskill[i]=0;
}
for(char i=0;i<30;i++)
{
char* tmp=strtok((i==0?row[24]:NULL), ",");
if (tmp!=NULL) pskilllvl[i]=atoi(tmp);
else
pskilllvl[i]=0;
}
GServer->DB->QFree( );
CharInfo->Pending_Exp = 0;
Log(MSG_INFO,"Loading union data");
result = GServer->DB->QStore("SELECT unionid,union1points,union2points,union3points,union4points,union5points,union6points,union7points,union8points,union9points,union10points FROM characters WHERE char_name='%s'", CharInfo->charname);
if(result == NULL) return false;
if(mysql_num_rows(result)!=1)
{
Log( MSG_WARNING, "Number of user with charname '%s' is %i", CharInfo->charname,mysql_num_rows(result));
return false;
}
row = mysql_fetch_row(result);
for (char points=0; points<11;points++)
{
if(points == 9)
{
Union_s->unionvar[points] = Session->KTPoints;
}
else
{
Union_s->unionvar[points] = atoi(row[points]);
}
}
GServer->DB->QFree( );
// code to reset players back to the correct faction after using the KTRose shop
if(Union_s->unionvar[0] == 9)
{
//Log(MSG_DEBUG, "UnionVar 7 used to reset player Union from %i to %i",Union_s->unionvar[0],Union_s->unionvar[7] );
Union_s->unionvar[0] = Union_s->unionvar[7];
Union_s->unionvar[7] = 0;
}
// PY loadup code
//Log(MSG_INFO,"Loading inventory data");
result = GServer->DB->QStore("SELECT itemid,itemtype,refine,durability,lifespan,count,stats,socketed,appraised,trans_action FROM charitems WHERE owner=%i", CharInfo->charid);
if(result == NULL)
{
Log(MSG_WARNING, "Something a bit wrong with this query");
return false;
}
const char *tmpid;
const char *itmp;
int itemid;
while( row = mysql_fetch_row(result) )
{
tmpid = strtok( row[0] , "|");
for(unsigned int i=1;i<=MAX_INVENTORY; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
items[i].itemnum = atoi(itmp);
}
tmpid = strtok( row[1] , "|");
for(unsigned int i=1;i<=MAX_INVENTORY; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
items[i].itemtype = atoi(itmp);
}
tmpid = strtok( row[2] , "|");
for(unsigned int i=1;i<=MAX_INVENTORY; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
items[i].refine = atoi(itmp);
}
tmpid = strtok( row[3] , "|");
for(unsigned int i=1;i<=MAX_INVENTORY; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
items[i].durability = atoi(itmp);
}
tmpid = strtok( row[4] , "|");
for(unsigned int i=1;i<=MAX_INVENTORY; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
items[i].lifespan = atoi(itmp);
}
tmpid = strtok( row[5] , "|");
for(unsigned int i=1;i<=MAX_INVENTORY; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
{
items[i].count = atoi(itmp);
//Log(MSG_INFO,"slot: %i itemid: %i type: %i count: %i",i, items[i].itemnum,items[i].itemtype,items[i].count); //PAT items seem to load ok here
}
}
tmpid = strtok( row[6] , "|");
for(unsigned int i=1;i<=MAX_INVENTORY; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
{
items[i].stats = atoi(itmp);
if(items[i].stats >300)
{
items[i].gem = items[i].stats;
}
else
items[i].gem = 0;
}
}
tmpid = strtok( row[7] , "|");
for(unsigned int i=1;i<=MAX_INVENTORY; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
items[i].socketed = (atoi(itmp)==1)?true:false;
//just in case there is a discrepency in the database this will fix sockets.
if(items[i].gem != 0)
items[i].socketed = true;
}
tmpid = strtok( row[8] , "|");
for(unsigned int i=1;i<=MAX_INVENTORY; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
items[i].appraised = (atoi(itmp)==1)?true:false;
}
for(unsigned int i=1;i<=MAX_INVENTORY; i++)
{
// first delete bad items
if(items[i].itemnum > GServer->EquipList[items[i].itemtype].STBMax)
{
Log(MSG_INFO,"deleting item in slot: %i itemid: %i type: %i count: %i",i, items[i].itemnum,items[i].itemtype,items[i].count);
//Item number too high
items[i].itemnum = 0;
items[i].itemtype = 0;
items[i].count = 0;
items[i].durability = 0;
}
// find item type for crafting
if(items[i].itemtype > 0 && items[i].itemtype < 10)
items[i].type = GServer->EquipList[items[i].itemtype].Index[items[i].itemnum]->type;
if(items[i].itemtype == 10)
items[i].type = GServer->UseList.Index[items[i].itemnum]->type;
if(items[i].itemtype == 11)
items[i].type = GServer->JemList.Index[items[i].itemnum]->type;
if(items[i].itemtype == 12)
items[i].type = GServer->NaturalList.Index[items[i].itemnum]->type;
if(items[i].itemtype == 14)
items[i].type = GServer->PatList.Index[items[i].itemnum]->type;
//Log(MSG_INFO,"slot: %i itemid: %i type: %i count: %i",i, items[i].itemnum,items[i].itemtype,items[i].count);
}
}
//PY end
/*
result = GServer->DB->QStore("SELECT itemnum,itemtype,refine,durability,lifespan,slotnum,count,stats,socketed,appraised,gem FROM items WHERE owner=%i", CharInfo->charid);
if(result==NULL) return false;
while(row = mysql_fetch_row(result))
{
if(!GServer->IsValidItem( atoi(row[1]), atoi(row[0]) ) || atoi(row[6])==0)
{
Log(MSG_WARNING, "char %s have a invalid or empty item in inventory: %i-%i [%i], this item will be deleted", CharInfo->charname, atoi(row[1]), atoi(row[0]), atoi(row[6]) );
continue;
}
UINT itemnum = atoi(row[5]);
items[itemnum].itemnum = atoi(row[0]);
items[itemnum].itemtype = atoi(row[1]);
items[itemnum].refine = atoi(row[2]);
items[itemnum].durability = atoi(row[3]);
items[itemnum].lifespan = atoi(row[4]);
items[itemnum].count = atoi(row[6]);
items[itemnum].stats = atoi(row[7]);
items[itemnum].socketed = (atoi(row[8])==1)?true:false;
items[itemnum].appraised = (atoi(row[9])==1)?true:false;
items[itemnum].gem = atoi(row[10])>3999?0:atoi(row[10]);
//extra code to fix bugged gem items
if(items[itemnum].gem > 0)
{
items[itemnum].stats = items[itemnum].gem;
}
// find item type for crafting
if(items[itemnum].itemtype < 10)
items[itemnum].type = GServer->EquipList[items[itemnum].itemtype].Index[items[itemnum].itemnum]->type;
if(items[itemnum].itemtype == 10)
items[itemnum].type = GServer->UseList.Index[items[itemnum].itemnum]->type;
if(items[itemnum].itemtype == 11)
items[itemnum].type = GServer->JemList.Index[items[itemnum].itemnum]->type;
if(items[itemnum].itemtype == 12)
items[itemnum].type = GServer->NaturalList.Index[items[itemnum].itemnum]->type;
if(items[itemnum].itemtype == 14)
items[itemnum].type = GServer->PatList.Index[items[itemnum].itemnum]->type;
}*/
//Log( MSG_DEBUG, "loaded inventory info");
GServer->DB->QFree( );
// PY loadup code for storage
//Log(MSG_INFO,"Loading storage data");
result = GServer->DB->QStore("SELECT itemid,itemtype,refine,durability,lifespan,count,stats,socketed,appraised,trans_action FROM charstorage WHERE owner=%i", Session->userid);
if(result == NULL)
{
Log(MSG_WARNING, "Something a bit wrong with this query");
return false;
}
tmpid = "";
itmp = 0;
while( row = mysql_fetch_row(result) )
{
tmpid = strtok( row[0] , "|");
for(unsigned int i=0;i<=MAX_STORAGE; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
storageitems[i].itemnum = atoi(itmp);
//if (Session->userid == 8) //test code delete later
//{
// if(i < 4)
// Log(MSG_DEBUG,"Storage item %i loaded. Value = %i",i,atoi(itmp));
//}
}
tmpid = strtok( row[1] , "|");
for(unsigned int i=0;i<=MAX_STORAGE; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
storageitems[i].itemtype = atoi(itmp);
}
tmpid = strtok( row[2] , "|");
for(unsigned int i=0;i<=MAX_STORAGE; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
storageitems[i].refine = atoi(itmp);
}
tmpid = strtok( row[3] , "|");
for(unsigned int i=0;i<=MAX_STORAGE; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
storageitems[i].durability = atoi(itmp);
}
tmpid = strtok( row[4] , "|");
for(unsigned int i=0;i<=MAX_STORAGE; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
storageitems[i].lifespan = atoi(itmp);
}
tmpid = strtok( row[5] , "|");
for(unsigned int i=0;i<=MAX_STORAGE; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
storageitems[i].count = atoi(itmp);
}
tmpid = strtok( row[6] , "|");
for(unsigned int i=0;i<=MAX_STORAGE; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
{
storageitems[i].stats = atoi(itmp);
if(storageitems[i].stats > 300)
{
storageitems[i].gem = items[i].stats;
}
else
storageitems[i].gem = 0;
}
}
tmpid = strtok( row[7] , "|");
for(unsigned int i=0;i<=MAX_STORAGE; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
storageitems[i].socketed = (atoi(itmp)==1)?true:false;
//just in case there is a discrepency in the database this will fix sockets.
if(storageitems[i].gem != 0)
storageitems[i].socketed = true;
}
tmpid = strtok( row[8] , "|");
for(unsigned int i=0;i<=MAX_STORAGE; i++)
{
if((itmp = strtok( NULL , "|"))!= NULL)
storageitems[i].appraised = (atoi(itmp)==1)?true:false;
}
for(unsigned int i=0;i<=MAX_STORAGE; i++)
{
// find item type for crafting
if(storageitems[i].itemtype > 0 && storageitems[i].itemtype < 10)
storageitems[i].type = GServer->EquipList[storageitems[i].itemtype].Index[storageitems[i].itemnum]->type;
if(storageitems[i].itemtype == 10)
storageitems[i].type = GServer->UseList.Index[storageitems[i].itemnum]->type;
if(storageitems[i].itemtype == 11)
storageitems[i].type = GServer->JemList.Index[storageitems[i].itemnum]->type;
if(storageitems[i].itemtype == 12)
storageitems[i].type = GServer->NaturalList.Index[storageitems[i].itemnum]->type;
if(storageitems[i].itemtype == 14)
storageitems[i].type = GServer->PatList.Index[storageitems[i].itemnum]->type;
}
}
//PY end
/*
//original storage load code
GServer->DB->QFree( );
Log(MSG_INFO,"Loading storage data");
result = GServer->DB->QStore("SELECT itemnum,itemtype,refine,durability,lifespan,slotnum,count,stats,socketed,appraised,gem FROM storage WHERE owner=%i", Session->userid);
if(result == NULL) return false;
nstorageitems = mysql_num_rows(result);
while(row = mysql_fetch_row(result))
{
if(!GServer->IsValidItem( atoi(row[1]), atoi(row[0]) ) || atoi(row[6])==0)
{
Log(MSG_WARNING, "char %s have a invalid or empty item in storage: %i%i [%i], this item will be deleted", CharInfo->charname, atoi(row[1]), atoi(row[0]), atoi(row[6]) );
continue;
}
UINT itemnum = atoi(row[5]);
storageitems[itemnum].itemnum = atoi(row[0]);
storageitems[itemnum].itemtype = atoi(row[1]);
storageitems[itemnum].refine = atoi(row[2]);
storageitems[itemnum].durability = atoi(row[3]);
storageitems[itemnum].lifespan = atoi(row[4]);
storageitems[itemnum].count = atoi(row[6]);
storageitems[itemnum].stats = atoi(row[7]);
storageitems[itemnum].socketed = (atoi(row[8])==1)?true:false;
storageitems[itemnum].appraised = (atoi(row[9])==1)?true:false;
storageitems[itemnum].gem = atoi(row[10]);
//extra code to fix bugged gem items
if(storageitems[itemnum].gem > 0)
{
storageitems[itemnum].stats = storageitems[itemnum].gem;
}
// find item type for crafting
if(storageitems[itemnum].itemtype < 10)
storageitems[itemnum].type = GServer->EquipList[items[itemnum].itemtype].Index[items[itemnum].itemnum]->type;
if(storageitems[itemnum].itemtype == 10)
storageitems[itemnum].type = GServer->UseList.Index[items[itemnum].itemnum]->type;
if(storageitems[itemnum].itemtype == 11)
storageitems[itemnum].type = GServer->JemList.Index[items[itemnum].itemnum]->type;
if(storageitems[itemnum].itemtype == 12)
storageitems[itemnum].type = GServer->NaturalList.Index[items[itemnum].itemnum]->type;
if(storageitems[itemnum].itemtype == 14)
storageitems[itemnum].type = GServer->PatList.Index[items[itemnum].itemnum]->type;
}
*/
//End of original storage load code.
GServer->DB->QFree( );
//Log(MSG_INFO,"saving backup storage data.");
SaveBackupStorage(1); // makes a copy of the account's storage at the moment of login
//Log( MSG_DEBUG, "Saved backup storage data");
if(Clan->clanid!=0)
{
result = GServer->DB->QStore("SELECT logo,back,name,cp,grade FROM list_clan where id=%i", Clan->clanid);
if(result==NULL) return false;
if(mysql_num_rows(result)!=1)
{
Log(MSG_WARNING, "There are %i clan(s) with id %i", mysql_num_rows(result), Clan->clanid );
Clan->clanid=0;
}
else
{
row = mysql_fetch_row(result);
Clan->logo = atoi(row[0]);
Clan->back = atoi(row[1]);
strcpy(Clan->clanname,row[2]);
Clan->CP = atoi(row[3]);
Clan->grade = atoi(row[4]);
}
GServer->DB->QFree( );
}
memset(&quest, 0, sizeof(SQuestData));
//Log( MSG_DEBUG, "loaded clan info");
UINT QuestToggle = 0;
UINT rowcount = 0;
/*
result = GServer->DB->QStore("SELECT quests from list_quest where owner=%i",CharInfo->charid );
if(result!=NULL)
{
while(row = mysql_fetch_row(result))
{
if( row[0] != NULL )
{
memcpy(&quest, row[0], sizeof(SQuestData));
rowcount++;
}
}
if(rowcount == 0) //no data detected
{
//Log( MSG_DEBUG, "No quest data detected with Exjam method. using PY method instead");
QuestToggle = 1; // set toggle to use PY method
GServer->DB->QFree( );
}
if(QuestToggle == 0)
{
//delete the old quest entry after loading it.
//GServer->DB->QExecute( "DELETE FROM list_quest WHERE owner=%i",thisclient->CharInfo->charid );
//now convert quest flags to new system
for(int flagid=0;flagid<512;flagid++)
{
dword byteid = flagid / 8;
dword bitid = flagid % 8;
if (((quest.flags[byteid] >> bitid) & 1) == 1)
quest.Qflags[byteid][bitid] = 1;
else
quest.Qflags[byteid][bitid] = 0;
}
GServer->DB->QFree( );
Log( MSG_DEBUG, "loaded quests via Exjam method");
savequests(this);
Log( MSG_DEBUG, "Converted flags and re-saved quests info");
}
}
else
{
GServer->DB->QFree( );
}
if(QuestToggle = 1)
*/
{ // PY quest loading. Only performed if no old quests are found. Won't be any since there are no old characters
Log( MSG_DEBUG, "starting PY quest load");
result = GServer->DB->QStore("SELECT questid,starttime,vbl,switches,items,count,episodevar,jobvar,planetvar,unionvar from player_quests where owner=%i",CharInfo->charid );
//Log( MSG_DEBUG, "ran the query");
tmpid = "";
itmp = "";
if(result != NULL)
{
UINT Index = 0;
while(row = mysql_fetch_row(result))
{
quest.quests[Index].QuestID = atoi(row[0]);
quest.quests[Index].StartTime = atoi(row[1]);
tmpid = strtok( row[2] , "|");
for(unsigned int j=0;j<10;j++) //quest variables
{
if(tmpid != NULL)
quest.quests[Index].Variables[j] = atoi(tmpid);
else
quest.quests[Index].Variables[j] = 0;
tmpid = strtok(NULL, ",|");
//Log( MSG_DEBUG, "Quest Var[%i][%i] = %i",Index ,j ,quest.quests[Index].Variables[j]);
}
tmpid = strtok( row[3] , "|"); //quest switches
for(unsigned int j=0;j<4;j++)
{
if(tmpid != NULL)
quest.quests[Index].Switches[j] = atoi(tmpid);
else
quest.quests[Index].Switches[j] = 0;
tmpid = strtok(NULL, ",|");
//Log( MSG_DEBUG, "Quest Switch[%i][%i] = %i",Index ,j ,quest.quests[Index].Switches[j]);
}
tmpid = strtok( row[4] , "|"); //quest items
for(unsigned int j=0;j<5;j++)
{
if(tmpid != NULL)
{
itemid = atoi(tmpid);
quest.quests[Index].Items[j].itemnum = itemid % 1000;
quest.quests[Index].Items[j].itemtype = itemid / 1000;
}
else
{
quest.quests[Index].Items[j].itemnum = 0;
quest.quests[Index].Items[j].itemtype = 0;
}
tmpid = strtok(NULL, ",|");
//Log( MSG_DEBUG, "Quest Item[%i][%i] = %i",Index , j ,quest.quests[Index].Items[j].itemnum);
}
tmpid = strtok( row[5] , "|"); //quest item count
for(unsigned int j=0;j<5;j++)
{
if(tmpid != NULL)
quest.quests[Index].Items[j].count = atoi(tmpid);
else
quest.quests[Index].Items[j].count = 0;
tmpid = strtok(NULL, ",|");
//Log( MSG_DEBUG, "Quest Item Count[%i][%i] = %i",Index ,j ,quest.quests[Index].Items[j].count);
}
tmpid = strtok( row[6] , "|");
for(unsigned int j=0;j<5;j++) //episode variables
{
if(tmpid != NULL)
quest.EpisodeVar[j] = atoi(tmpid);
else
quest.EpisodeVar[j] = 0;
tmpid = strtok(NULL, ",|");
//Log( MSG_DEBUG, "Quest EpisodeVar[%i][%i] = %i",Index ,j ,quest.EpisodeVar[j]);
}
tmpid = strtok( row[7] , "|"); //job variables
for(unsigned int j=0;j<3;j++)
{
if(tmpid != NULL)
quest.JobVar[j] = atoi(tmpid);
else
quest.JobVar[j] = 0;
tmpid = strtok(NULL, ",|");
//Log( MSG_DEBUG, "Quest JobVar[%i][%i] = %i",Index ,j ,quest.JobVar[j]);
}
tmpid = strtok( row[8] , "|"); //Planet variables
for(unsigned int j=0;j<7;j++)
{
if(tmpid != NULL)
quest.PlanetVar[j] = atoi(tmpid);
else
quest.PlanetVar[j] = 0;
tmpid = strtok(NULL, ",|");
}
tmpid = strtok( row[9] , "|"); //Planet variables
for(unsigned int j=0;j<10;j++)
{
if(tmpid != NULL)
quest.UnionVar[j] = atoi(tmpid);
else
quest.UnionVar[j] = 0;
tmpid = strtok(NULL, ",|");
}
Index ++;
}
}
//Log( MSG_DEBUG, "loaded the regular quest variables");
GServer->DB->QFree( );
// PY method load quest flags
//Log( MSG_DEBUG, "starting PY flag load");
result = GServer->DB->QStore("SELECT flags from questflags where owner=%i",CharInfo->charid );
//Log( MSG_DEBUG, "ran the query");
if(result != NULL)
{
tmpid = "";
itmp = 0;
UINT Index = 0;
UINT flagCount = 0;
//first set all quest flags to zero
for(int i=0;i<64;i++)
{
for(int j=0;j<8;j++)
quest.Qflags[i][j] = 0;
}
while(row = mysql_fetch_row(result))
{
int flagid = atoi(row[0]);
dword byteid = flagid / 8;
dword bitid = flagid % 8;
quest.Qflags[byteid][bitid] = 1;
flagCount++;
}
//Log( MSG_DEBUG, "Flag count = %i",flagCount);
}
GServer->DB->QFree( );
//Log( MSG_DEBUG, "loaded quests info via PY method");
}
Session->isLoggedIn = true;
// Timestamp for last login
time_t rtime;
time(&rtime);
char *timestamp = ctime(&rtime);
timestamp[ strlen(timestamp)-1 ] = ' ';
//Log(MSG_DEBUG,"setting time stamp fo login: %s for userid: %u",timestamp,Session->userid );
GServer->DB->QExecute("UPDATE accounts SET online=1, lastlogin='%s' where id=%u", timestamp,Session->userid );
Session->LogTime = clock();
//Log(MSG_INFO,"set datestamp");
// Calculate how many fairies are available online, according to amount of players
int oldFairyMax = GServer->Config.FairyMax;
GServer->Config.FairyMax = (int)ceil((float)GServer->ClientList.size() / 50.0) + GServer->Config.ScrollFairy; //1 fairy for every 50 player + the number of fairies summoned by scrolls
if( oldFairyMax < GServer->Config.FairyMax ){
CFairy* thisfairy = new (nothrow) CFairy;
thisfairy->LastTime = clock();
thisfairy->assigned = 0;
thisfairy->ListIndex = 0;
thisfairy->WaitTime = GServer->Config.FairyWait;
GServer->FairyList.push_back( thisfairy );
}
//die_quest = 0;
return true;
}
// Trying a new save method PY (nothing changed yet. just made a copy of savedata for safety
void CPlayer::savedata( )
{
lastSaveTime = clock();
if(Session->userid!=0)
{
CMap* map = GServer->MapList.Index[Position->Map];
CRespawnPoint* thisrespawn = map->GetNearRespawn( this );
CPlayer* thisclient = GServer->GetClientByID( clientid );
if(thisrespawn == NULL)
Position->respawn = 4;
else
Position->respawn = thisrespawn->id;
char quick[1024];
char basic[1024];
//char sclass[1024];
//char slevel[1024];
char active[1024];
char activelvl[1024];
char pasive[1024];
char pasivelvl[1024];
for(UINT i=0;i<30;i++)
{
if(i==0)
sprintf(&basic[i], "%i",bskills[i]);
else
sprintf(&basic[strlen(basic)], ",%i",bskills[i]);
}
for(UINT i=0;i<30;i++)
{
if(i==0)
sprintf(&active[i], "%i",askill[i]);
else
sprintf(&active[strlen(active)], ",%i",askill[i]);
}
for(UINT i=0;i<30;i++)
{
if(i==0)
sprintf(&activelvl[i], "%i",askilllvl[i]);
else
sprintf(&activelvl[strlen(activelvl)], ",%i",askilllvl[i]);
}
for(UINT i=0;i<30;i++)
{
if(i==0)
sprintf(&pasive[i], "%i",pskill[i]);
else
sprintf(&pasive[strlen(pasive)], ",%i",pskill[i]);
}
for(UINT i=0;i<30;i++)
{
if(i==0)
sprintf(&pasivelvl[i], "%i",pskilllvl[i]);
else
sprintf(&pasivelvl[strlen(pasivelvl)], ",%i",pskilllvl[i]);
}
for(UINT i=0;i<32;i++)
{
if(i==0)
sprintf(&quick[i], "%i",quickbar[i]);
else
sprintf(&quick[strlen(quick)], ",%i",quickbar[i]);
}
long int hp = Stats->HP;
if(hp<=0)
hp=Stats->MaxHP * 10 / 100;
if(Stats->MP<0)
Stats->MP=0;
GServer->DB->QExecute("UPDATE characters SET level=%i,face=%i,hairStyle=%i,sex=%i,classid=%i,zuly=%i,str=%i,dex=%i,_int=%i, con=%i,cha=%i,sen=%i,curHp=%i,curMp=%i,id=%i,statp=%i,skillp=%i,exp=%i,stamina=%i,quickbar='%s',basic_skills='%s',askill='%s',askilllvl='%s',pskill='%s',pskilllvl='%s',respawnid=%i,clanid=%i,clan_rank=%i,townid=%i WHERE char_name='%s'",
Stats->Level, CharInfo->Face, CharInfo->Hair, CharInfo->Sex, CharInfo->Job, CharInfo->Zulies, Attr->Str, Attr->Dex, Attr->Int, Attr->Con, Attr->Cha, Attr->Sen, hp, Stats->MP, CharInfo->charid, CharInfo->StatPoints, CharInfo->SkillPoints,
CharInfo->Exp, CharInfo->stamina, quick, basic, active, activelvl, pasive, pasivelvl, Position->respawn, Clan->clanid, Clan->clanrank, Position->saved, CharInfo->charname );
GServer->DB->QExecute("UPDATE characters SET unionid=%i,union1points=%i,union2points=%i,union3points=%i,union4points=%i,union5points=%i,union6points=%i,union7points=%i,union8points=%i,union9points=%i,union10points=%i WHERE char_name='%s'",
Union_s->unionvar[0], Union_s->unionvar[1],Union_s->unionvar[2], Union_s->unionvar[3], Union_s->unionvar[4], Union_s->unionvar[5], Union_s->unionvar[6], Union_s->unionvar[7], Union_s->unionvar[8], Union_s->unionvar[9], Union_s->unionvar[10], CharInfo->charname );
//save the inventory
saveinventory();
//save the storage items
savestorage();
//this lot to be removed later
//if(!GServer->DB->QExecute("DELETE FROM items WHERE owner=%i", CharInfo->charid)) return;
//for(UINT i=0;i<MAX_INVENTORY;i++)
//{
// if (items[i].count > 0)
// {
// GServer->DB->QExecute("INSERT INTO items (owner,itemnum,itemtype,refine,durability,lifespan,slotnum,count,stats,socketed,appraised,gem) VALUES(%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i)",
// CharInfo->charid, items[i].itemnum, items[i].itemtype,items[i].refine, items[i].durability,
// items[i].lifespan, i, items[i].count, items[i].stats, (items[i].socketed?1:0),
// (items[i].appraised?1:0),items[i].gem );
// }
//}
//Why is this still here and active?
//if savestorage is live and functional then this antiquated crap needs to be removed
if(!GServer->DB->QExecute("DELETE FROM storage WHERE owner=%i", Session->userid)) return;
for(UINT i=0;i<160;i++)
{
if (storageitems[i].count > 0)
{
GServer->DB->QExecute("INSERT INTO storage (owner,itemnum,itemtype,refine,durability,lifespan,slotnum,count,stats,socketed,appraised,gem) VALUES(%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i)",
Session->userid, storageitems[i].itemnum, storageitems[i].itemtype,storageitems[i].refine, storageitems[i].durability,
storageitems[i].lifespan, i, storageitems[i].count, storageitems[i].stats, (storageitems[i].socketed?1:0),
(storageitems[i].appraised?1:0), storageitems[i].gem );
}
}
savequests( this );
GServer->DB->QExecute("UPDATE accounts SET zulystorage = %i, logtime = %i,ktpoints=%i WHERE id = %i", CharInfo->Storage_Zulies, Session->logtime,Session->KTPoints, Session->userid);
Log(MSG_INFO, "Data Saved for char '%s' ", CharInfo->charname );
}
}
//PY Character save
void CPlayer::quicksave( )
{
GServer->DB->QExecute("UPDATE characters SET level=%i,face=%i,hairStyle=%i,sex=%i,classid=%i,zuly=%i,str=%i,dex=%i,_int=%i, con=%i,cha=%i,sen=%i,curHp=%i,curMp=%i,id=%i,statp=%i,skillp=%i,exp=%i,stamina=%i,respawnid=%i,clanid=%i,clan_rank=%i,townid=%i WHERE char_name='%s'",
Stats->Level, CharInfo->Face, CharInfo->Hair, CharInfo->Sex, CharInfo->Job, CharInfo->Zulies, Attr->Str, Attr->Dex, Attr->Int, Attr->Con, Attr->Cha, Attr->Sen, Stats->HP, Stats->MP, CharInfo->charid, CharInfo->StatPoints, CharInfo->SkillPoints,
CharInfo->Exp, CharInfo->stamina, Position->respawn, Clan->clanid, Clan->clanrank, Position->saved, CharInfo->charname );
Log(MSG_INFO, "Data Quick Saved for char '%s' ", CharInfo->charname );
}
//PY Inventory save
void CPlayer::saveinventory( )
{
//build the strings
char tmp1[1024] = "";
char tmp2[1024] = "";
char tmp3[1024] = "";
char tmp4[1024] = "";
char tmp5[1024] = "";
char tmp6[1024] = "";
char tmp7[1024] = "";
char tmp8[1024] = "";
char tmp9[1024] = "";
char slot[1024] = "";
long tran = 0;
for(unsigned int i=0;i<=MAX_INVENTORY; i++) //inventory holds 140
{
int socketed = 0;
int appraised = 0;
tran += items[i].itemnum + items[i].itemtype + items[i].refine;
//tran += items[i].durability + items[i].lifespan + items[i].count + items[i].stats;
//Log(MSG_INFO,"slot: %i itemid: %i type: %i count: %i",i, items[i].itemnum,items[i].itemtype,items[i].count);
if(i == 0)
{
if(items[i].count == 0)
{
sprintf(&tmp1[strlen(tmp1)], "0");
sprintf(&tmp2[strlen(tmp2)], "0");
sprintf(&tmp3[strlen(tmp3)], "0");
sprintf(&tmp4[strlen(tmp4)], "0");
sprintf(&tmp5[strlen(tmp5)], "0");
sprintf(&tmp6[strlen(tmp6)], "0");
sprintf(&tmp7[strlen(tmp7)], "0");
sprintf(&tmp8[strlen(tmp8)], "0");
sprintf(&tmp9[strlen(tmp9)], "0");
sprintf(&slot[strlen(slot)], "%i",i);
}
else
{
if(items[i].socketed == true)
socketed = 1;
if(items[i].appraised == true)
appraised = 1;
sprintf(&tmp1[strlen(tmp1)], "%i",items[i].itemnum);
sprintf(&tmp2[strlen(tmp2)], "%i",items[i].itemtype);
sprintf(&tmp3[strlen(tmp3)], "%i",items[i].refine);
sprintf(&tmp4[strlen(tmp4)], "%i",items[i].durability);
sprintf(&tmp5[strlen(tmp5)], "%i",items[i].lifespan);
sprintf(&tmp6[strlen(tmp6)], "%i",items[i].count);
sprintf(&tmp7[strlen(tmp7)], "%i",items[i].stats);
sprintf(&tmp8[strlen(tmp8)], "%i",socketed);
sprintf(&tmp9[strlen(tmp9)], "%i",appraised);
sprintf(&slot[strlen(slot)], "%i",i);
}
}
else
{
if(items[i].count == 0)
{
sprintf(&tmp1[strlen(tmp1)], "|0");
sprintf(&tmp2[strlen(tmp2)], "|0");
sprintf(&tmp3[strlen(tmp3)], "|0");
sprintf(&tmp4[strlen(tmp4)], "|0");
sprintf(&tmp5[strlen(tmp5)], "|0");
sprintf(&tmp6[strlen(tmp6)], "|0");
sprintf(&tmp7[strlen(tmp7)], "|0");
sprintf(&tmp8[strlen(tmp8)], "|0");
sprintf(&tmp9[strlen(tmp9)], "|0");
sprintf(&slot[strlen(slot)], "|%i",i);
}
else
{
if(items[i].socketed == true)
socketed = 1;
if(items[i].appraised == true)
appraised = 1;
if(items[i].gem != 0 && items[i].gem != items[i].stats)
items[i].stats = items[i].gem;
sprintf(&tmp1[strlen(tmp1)], "|%i",items[i].itemnum);
sprintf(&tmp2[strlen(tmp2)], "|%i",items[i].itemtype);
sprintf(&tmp3[strlen(tmp3)], "|%i",items[i].refine);
sprintf(&tmp4[strlen(tmp4)], "|%i",items[i].durability);
sprintf(&tmp5[strlen(tmp5)], "|%i",items[i].lifespan);
sprintf(&tmp6[strlen(tmp6)], "|%i",items[i].count);
sprintf(&tmp7[strlen(tmp7)], "|%i",items[i].stats);
sprintf(&tmp8[strlen(tmp8)], "|%i",socketed);
sprintf(&tmp9[strlen(tmp9)], "|%i",appraised);
sprintf(&slot[strlen(slot)], "|%i",i);
}
}
}
//Log(MSG_INFO,"Save string1 = %s ", tmp1);
//Log(MSG_INFO,"Save string2 = %s ", tmp2);
//Log(MSG_INFO,"Save string3 = %s ", tmp3);
//Log(MSG_INFO,"Save string4 = %s ", tmp4);
//Log(MSG_INFO,"Save string5 = %s ", tmp5);
//Log(MSG_INFO,"Save string6 = %s ", tmp6);
//Log(MSG_INFO,"Save string7 = %s ", tmp7);
//Log(MSG_INFO,"Save string8 = %s ", tmp8);
//Log(MSG_INFO,"Save string9 = %s ", tmp9);
//check if a record exists for this player
MYSQL_RES *result = GServer->DB->QStore("SELECT itemid,itemtype,refine,durability,lifespan,count,stats,socketed,appraised,slot,trans_action FROM charitems WHERE owner=%i", CharInfo->charid);
MYSQL_ROW row;
bool doesexist = false;
while(row = mysql_fetch_row(result))
{
doesexist = true;
}
GServer->DB->QFree( );
if(doesexist == true)
{
//record exists so update it
//Log(MSG_INFO,"record exists.... updating");
GServer->DB->QExecute("UPDATE charitems SET itemid='%s',itemtype='%s',refine='%s',durability='%s',lifespan='%s',count='%s',stats='%s',socketed='%s',appraised='%s',slot='%s',trans_action=%i WHERE owner='%i'",
tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8,tmp9,slot,tran,CharInfo->charid);
}
else
{
//record does not exist so make a new one
//Log(MSG_INFO,"record does not exist.... creating new record");
//GServer->DB->QExecute("INSERT INTO charitems (owner,trans_action) VALUES ('%i','%i')",CharInfo->charid,tran);
GServer->DB->QExecute("INSERT INTO charitems (owner,itemid,itemtype,refine,durability,lifespan,count,stats,socketed,appraised,trans_action) VALUES('%i','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%i')",
CharInfo->charid,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8,tmp9,slot,tran);
}
//save zuly
GServer->DB->QExecute("UPDATE characters SET zuly=%i WHERE char_name='%s'",
CharInfo->Zulies, CharInfo->charname );
//Log(MSG_INFO,"Inventory saved");
return;
}
//PY Storage save
void CPlayer::savestorage( )
{
//build the strings. As we need a slot zero for storage we are going to have to add a buffer entry first
//for some bizarre reason when we load teh storage it ignores the leading zero so stuff gets shifted left without this
char tmp1[1024] = "0";
char tmp2[1024] = "0";
char tmp3[1024] = "0";
char tmp4[1024] = "0";
char tmp5[1024] = "0";
char tmp6[1024] = "0";
char tmp7[1024] = "0";
char tmp8[1024] = "0";
char tmp9[1024] = "0";
char slot[1024] = "0";
long tran = 0;
for(unsigned int i=0;i<=MAX_STORAGE; i++) //Storage holds 160
{
int socketed = 0;
int appraised = 0;
tran += storageitems[i].itemnum + storageitems[i].itemtype + storageitems[i].refine;
tran += storageitems[i].durability + storageitems[i].lifespan + storageitems[i].count + storageitems[i].stats;
if(storageitems[i].count == 0)
{
sprintf(&tmp1[strlen(tmp1)], "|0");
sprintf(&tmp2[strlen(tmp2)], "|0");
sprintf(&tmp3[strlen(tmp3)], "|0");
sprintf(&tmp4[strlen(tmp4)], "|0");
sprintf(&tmp5[strlen(tmp5)], "|0");
sprintf(&tmp6[strlen(tmp6)], "|0");
sprintf(&tmp7[strlen(tmp7)], "|0");
sprintf(&tmp8[strlen(tmp8)], "|0");
sprintf(&tmp9[strlen(tmp9)], "|0");
if(i != 0) //don't write the zero value for slot since we already started the string with a leading zero
sprintf(&slot[strlen(slot)], "|%i",i);
}
else
{
if(storageitems[i].socketed == true)
socketed = 1;
if(storageitems[i].appraised == true)
appraised = 1;
sprintf(&tmp1[strlen(tmp1)], "|%i",storageitems[i].itemnum);
sprintf(&tmp2[strlen(tmp2)], "|%i",storageitems[i].itemtype);
sprintf(&tmp3[strlen(tmp3)], "|%i",storageitems[i].refine);
sprintf(&tmp4[strlen(tmp4)], "|%i",storageitems[i].durability);
sprintf(&tmp5[strlen(tmp5)], "|%i",storageitems[i].lifespan);
sprintf(&tmp6[strlen(tmp6)], "|%i",storageitems[i].count);
sprintf(&tmp7[strlen(tmp7)], "|%i",storageitems[i].stats);
sprintf(&tmp8[strlen(tmp8)], "|%i",socketed);
sprintf(&tmp9[strlen(tmp9)], "|%i",appraised);
if(i != 0) //don't write the zero value for slot since we already started the string with a leading zero
sprintf(&slot[strlen(slot)], "|%i",i);
}
}
//check if a record exists for this player
MYSQL_RES *result = GServer->DB->QStore("SELECT itemid,itemtype,refine,durability,lifespan,count,stats,socketed,appraised,slot,trans_action FROM charstorage WHERE owner=%i", Session->userid);
MYSQL_ROW row;
bool doesexist = false;
while(row = mysql_fetch_row(result))
{
doesexist = true;
}
GServer->DB->QFree( );
if(doesexist == true)
{
//record exists so update it
//Log(MSG_INFO,"record exists.... updating");
GServer->DB->QExecute("UPDATE charstorage SET itemid='%s',itemtype='%s',refine='%s',durability='%s',lifespan='%s',count='%s',stats='%s',socketed='%s',appraised='%s',slot='%s',trans_action=%i WHERE owner='%i'",
tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8,tmp9,slot,tran,Session->userid);
}
else
{
//record does not exist so make a new one
//Log(MSG_INFO,"record does not exist.... creating new record");
//GServer->DB->QExecute("INSERT INTO charitems (owner,trans_action) VALUES ('%i','%i')",CharInfo->charid,tran);
GServer->DB->QExecute("INSERT INTO charstorage (owner,itemid,itemtype,refine,durability,lifespan,count,stats,socketed,appraised,slot,trans_action) VALUES('%i','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%i')",
Session->userid,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8,tmp9,slot,tran);
}
//save zuly storage
GServer->DB->QExecute("UPDATE accounts SET zulystorage = %i WHERE id = %i", CharInfo->Storage_Zulies, Session->userid);
//Log(MSG_INFO,"Storage saved");
return;
}
//PY Storage save
void CPlayer::SaveBackupStorage( int logstate )
{
//build the strings. As we need a slot zero for storage we are going to have to add a buffer entry first
//for some bizarre reason when we load the storage it ignores the leading zero so stuff gets shifted left without this
char tmp1[1024] = "0";
char tmp2[1024] = "0";
char tmp3[1024] = "0";
char tmp4[1024] = "0";
char tmp5[1024] = "0";
char tmp6[1024] = "0";
char tmp7[1024] = "0";
char tmp8[1024] = "0";
char tmp9[1024] = "0";
char slot[1034] = "0";
long tran = 0;
for(unsigned int i=0;i<=MAX_STORAGE; i++) //Storage holds 160
{
int socketed = 0;
int appraised = 0;
if(storageitems[i].count == 0)
{
sprintf(&tmp1[strlen(tmp1)], "|0");
sprintf(&tmp2[strlen(tmp2)], "|0");
sprintf(&tmp3[strlen(tmp3)], "|0");
sprintf(&tmp4[strlen(tmp4)], "|0");
sprintf(&tmp5[strlen(tmp5)], "|0");
sprintf(&tmp6[strlen(tmp6)], "|0");
sprintf(&tmp7[strlen(tmp7)], "|0");
sprintf(&tmp8[strlen(tmp8)], "|0");
sprintf(&tmp9[strlen(tmp9)], "|0");
if(i != 0) //don't write the zero value for slot since we already started the string with a leading zero
sprintf(&slot[strlen(slot)], "|%i",i);
}
else
{
if(storageitems[i].socketed == true)
socketed = 1;
if(storageitems[i].appraised == true)
appraised = 1;
sprintf(&tmp1[strlen(tmp1)], "|%i",storageitems[i].itemnum);
sprintf(&tmp2[strlen(tmp2)], "|%i",storageitems[i].itemtype);
sprintf(&tmp3[strlen(tmp3)], "|%i",storageitems[i].refine);
sprintf(&tmp4[strlen(tmp4)], "|%i",storageitems[i].durability);
sprintf(&tmp5[strlen(tmp5)], "|%i",storageitems[i].lifespan);
sprintf(&tmp6[strlen(tmp6)], "|%i",storageitems[i].count);
sprintf(&tmp7[strlen(tmp7)], "|%i",storageitems[i].stats);
sprintf(&tmp8[strlen(tmp8)], "|%i",socketed);
sprintf(&tmp9[strlen(tmp9)], "|%i",appraised);
if(i != 0) //don't write the zero value for slot since we already started the string with a leading zero
sprintf(&slot[strlen(slot)], "|%i",i);
}
}
MYSQL_RES *result = GServer->DB->QStore("SELECT thisrev FROM backupstorage WHERE owner=%i", Session->userid);
MYSQL_ROW row;
int thisrev = 0;
int tmprev = 0;
while(row = mysql_fetch_row(result))
{
tmprev = atoi(row[0]);
if(tmprev > thisrev)thisrev = tmprev;
}
thisrev ++; // add 1 to the highest existing rev number for this user
GServer->DB->QFree( );
// Timestamp
time_t rtime;
time(&rtime);
char *timestamp = ctime(&rtime);
timestamp[ strlen(timestamp)-1 ] = ' ';
GServer->DB->QExecute("INSERT INTO backupstorage (owner,itemid,itemtype,refine,durability,lifespan,count,stats,socketed,appraised,slot,trans_action,datestamp,thisrev) VALUES('%i','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%i','%s','%i')",
Session->userid,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7,tmp8,tmp9,slot,logstate,timestamp,thisrev);
//Log(MSG_INFO,"backup Storage saved for User %i revision number %i logstate %i",Session->userid, thisrev, logstate);
return;
}
// This is a REALLY bad way of saving the character data, but it works ^^
/*void CPlayer::savedata( )
{
lastSaveTime = clock();
if(Session->userid!=0)
{
CMap* map = GServer->MapList.Index[Position->Map];
CRespawnPoint* thisrespawn = map->GetNearRespawn( this );
CPlayer* thisclient = GServer->GetClientByID( clientid );
if(thisrespawn == NULL)
Position->respawn = 4;
else
Position->respawn = thisrespawn->id;
char quick[1024];
char basic[1024];
//char sclass[1024];
//char slevel[1024];
char active[1024];
char activelvl[1024];
char pasive[1024];
char pasivelvl[1024];
for(UINT i=0;i<30;i++)
{
if(i==0)
sprintf(&basic[i], "%i",bskills[i]);
else
sprintf(&basic[strlen(basic)], ",%i",bskills[i]);
}
for(UINT i=0;i<30;i++)
{
if(i==0)
sprintf(&active[i], "%i",askill[i]);
else
sprintf(&active[strlen(active)], ",%i",askill[i]);
}
for(UINT i=0;i<30;i++)
{
if(i==0)
sprintf(&activelvl[i], "%i",askilllvl[i]);
else
sprintf(&activelvl[strlen(activelvl)], ",%i",askilllvl[i]);
}
for(UINT i=0;i<30;i++)
{
if(i==0)
sprintf(&pasive[i], "%i",pskill[i]);
else
sprintf(&pasive[strlen(pasive)], ",%i",pskill[i]);
}
for(UINT i=0;i<30;i++)
{
if(i==0)
sprintf(&pasivelvl[i], "%i",pskilllvl[i]);
else
sprintf(&pasivelvl[strlen(pasivelvl)], ",%i",pskilllvl[i]);
}
for(UINT i=0;i<32;i++)
{
if(i==0)
sprintf(&quick[i], "%i",quickbar[i]);
else
sprintf(&quick[strlen(quick)], ",%i",quickbar[i]);
}
long int hp = Stats->HP;
if(hp<=0)
hp=Stats->MaxHP * 10 / 100;
if(Stats->MP<0)
Stats->MP=0;
//Save data complete now?? (Pepu)
GServer->DB->QExecute("UPDATE characters SET level=%i,face=%i,hairStyle=%i,sex=%i,classid=%i,zuly=%i,str=%i,dex=%i,_int=%i, con=%i,cha=%i,sen=%i,curHp=%i,curMp=%i,id=%i,statp=%i,skillp=%i,exp=%i,stamina=%i,quickbar='%s',basic_skills='%s',askill='%s',askilllvl='%s',pskill='%s',pskilllvl='%s',respawnid=%i,clanid=%i,clan_rank=%i,townid=%i WHERE char_name='%s'",
Stats->Level, CharInfo->Face, CharInfo->Hair, CharInfo->Sex, CharInfo->Job, CharInfo->Zulies, Attr->Str, Attr->Dex, Attr->Int, Attr->Con, Attr->Cha, Attr->Sen, hp, Stats->MP, CharInfo->charid, CharInfo->StatPoints, CharInfo->SkillPoints,
CharInfo->Exp, CharInfo->stamina, quick, basic, active, activelvl, pasive, pasivelvl, Position->respawn, Clan->clanid, Clan->clanrank, Position->saved, CharInfo->charname );
GServer->DB->QExecute("UPDATE characters SET unionid=%i,union1points=%i,union2points=%i,union3points=%i,union4points=%i,union5points=%i,union6points=%i,union7points=%i,union8points=%i,union9points=%i,union10points=%i WHERE char_name='%s'",
Union_s->unionvar[0], Union_s->unionvar[1],Union_s->unionvar[2], Union_s->unionvar[3], Union_s->unionvar[4], Union_s->unionvar[5], Union_s->unionvar[6], Union_s->unionvar[7], Union_s->unionvar[8], Union_s->unionvar[9], Union_s->unionvar[10], CharInfo->charname );
if(!GServer->DB->QExecute("DELETE FROM items WHERE owner=%i", CharInfo->charid)) return;
for(UINT i=0;i<MAX_INVENTORY;i++)
{
if (items[i].count > 0)
{
GServer->DB->QExecute("INSERT INTO items (owner,itemnum,itemtype,refine,durability,lifespan,slotnum,count,stats,socketed,appraised,gem) VALUES(%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i)",
CharInfo->charid, items[i].itemnum, items[i].itemtype,items[i].refine, items[i].durability,
items[i].lifespan, i, items[i].count, items[i].stats, (items[i].socketed?1:0),
(items[i].appraised?1:0),items[i].gem );
}
}
if(!GServer->DB->QExecute("DELETE FROM storage WHERE owner=%i", Session->userid)) return;
for(UINT i=0;i<160;i++)
{
if (storageitems[i].count > 0)
{
GServer->DB->QExecute("INSERT INTO storage (owner,itemnum,itemtype,refine,durability,lifespan,slotnum,count,stats,socketed,appraised,gem) VALUES(%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i)",
Session->userid, storageitems[i].itemnum, storageitems[i].itemtype,storageitems[i].refine, storageitems[i].durability,
storageitems[i].lifespan, i, storageitems[i].count, storageitems[i].stats, (storageitems[i].socketed?1:0),
(storageitems[i].appraised?1:0), storageitems[i].gem );
}
}
savequests( this );
GServer->DB->QExecute("UPDATE accounts SET zulystorage = %i WHERE id = %i", CharInfo->Storage_Zulies, Session->userid);
Log(MSG_INFO, "Data Saved for char '%s' ", CharInfo->charname );
}
}*/
void CPlayer::savequests( CPlayer* thisclient )
{
//char* questBuffer = new char[sizeof(SQuestData)*3 +1];
//mysql_real_escape_string(GServer->DB->Mysql, questBuffer, (const char*)&quest, sizeof(SQuestData));
//GServer->DB->QExecute( "DELETE FROM list_quest WHERE owner=%i",thisclient->CharInfo->charid );
//GServer->DB->QExecute("INSERT INTO list_quest (owner, quests) VALUES(%i,'%s')",
// thisclient->CharInfo->charid, questBuffer);
//delete questBuffer;
//PY retro method
//GServer->DB->QFree( );
//Log(MSG_DEBUG,"Started SaveQuests");
GServer->DB->QExecute( "DELETE FROM player_quests WHERE owner=%i",thisclient->CharInfo->charid );
//Log(MSG_DEBUG,"Ran the player_quests deletion query");
for(int i=0;i<10;i++)
{
if (thisclient->quest.quests[i].QuestID == 0) continue;
char vbl[100] = ""; //make the variables list
for(int j=0;j<10;j++)
{
sprintf(&vbl[strlen(vbl)], "%u",thisclient->quest.quests[i].Variables[j]);
if(j < 9)
sprintf(&vbl[strlen(vbl)],"|");
}
char switches[10] = ""; //make the switches list
for(int j=0;j<4;j++)
{
sprintf(&switches[strlen(switches)], "%u",thisclient->quest.quests[i].Switches[j]);
if(j < 3)
sprintf(&switches[strlen(switches)],"|");
}
char itemslist[100] = ""; //make the items list. Changed items to itemslist due to warning.
char itemcount[100] = ""; //item counts
for(int j=0;j<5;j++)
{
int ItemID = thisclient->quest.quests[i].Items[j].itemtype * 1000 + thisclient->quest.quests[i].Items[j].itemnum;
//sprintf(&items[strlen(items)], "%i",thisclient->quest.quests[i].Items[j].itemnum);
sprintf(&itemslist[strlen(itemslist)], "%i",ItemID);
sprintf(&itemcount[strlen(itemcount)], "%i",thisclient->quest.quests[i].Items[j].count);
if(j < 4)
{
sprintf(&itemslist[strlen(itemslist)],"|");
sprintf(&itemcount[strlen(itemcount)],"|");
}
}
char episode[50] = ""; //make the episode variable list
for(int j=0;j<5;j++)
{
sprintf(&episode[strlen(episode)], "%u",thisclient->quest.EpisodeVar[j]);
if(j < 4)
sprintf(&episode[strlen(episode)],"|");
}
char jobvar[30] = ""; //make the job variable list
for(int j=0;j<3;j++)
{
sprintf(&jobvar[strlen(jobvar)], "%u",thisclient->quest.JobVar[j]);
if(j < 2)
sprintf(&jobvar[strlen(jobvar)],"|");
}
char planetvar[70] = ""; //make the planet variable list
for(int j=0;j<7;j++)
{
sprintf(&planetvar[strlen(planetvar)], "%u",thisclient->quest.PlanetVar[j]);
if(j < 6)
sprintf(&planetvar[strlen(planetvar)],"|");
}
char unionvar[100] = ""; //make the union variable list
for(int j=0;j<10;j++)
{
sprintf(&unionvar[strlen(unionvar)], "%u",thisclient->quest.UnionVar[j]);
if(j < 9)
sprintf(&unionvar[strlen(unionvar)],"|");
}
GServer->DB->QExecute("INSERT INTO player_quests (owner, questid, starttime, vbl, switches, items, count, episodevar, jobvar, planetvar, unionvar) VALUES(%i,%i,%i,'%s','%s','%s','%s','%s','%s','%s','%s')",
thisclient->CharInfo->charid, thisclient->quest.quests[i].QuestID, thisclient->quest.quests[i].StartTime,
vbl, switches, itemslist, itemcount, episode, jobvar, planetvar, unionvar);
//Log(MSG_DEBUG,"Ran the player_quests insertion query");
}
//GServer->DB->QFree( );
//now the quest flags
GServer->DB->QExecute( "DELETE FROM questflags WHERE owner=%i",thisclient->CharInfo->charid );
//Log(MSG_DEBUG,"Ran the questflag deletion query");
char qflags[10000] = "";
int flagCount = 0;
/*
for(int i=0;i<1000;i++)
{
if(thisclient->quest.Qflags[i] == 1)
{
if(sizeof(&qflags) > 995)
{
Log(MSG_WARNING,"Quest flag list too big for player %s",thisclient->CharInfo->charname);
i = 999;
continue;
}
if(flagCount == 0)
{
sprintf(&qflags[strlen(qflags)], "%i",i);
flagCount++;
}
else
{
sprintf(&qflags[strlen(qflags)],"|");
sprintf(&qflags[strlen(qflags)], "%i",i);
flagCount++;
}
}
}
*/
for(int i=0;i<0x40;i++)
{
for(int j=0;j<8;j++)
{
if(thisclient->quest.Qflags[i][j] != 0)
{
int flagid = (i*8)+j;
GServer->DB->QExecute("INSERT INTO questflags (owner, flags) VALUES(%i,%i)",
thisclient->CharInfo->charid, flagid);
//Log(MSG_DEBUG,"Ran the questflag deletion query");
flagCount++;
}
}
}
//Log(MSG_DEBUG,"%i Quest flags detected during save process",flagCount);
}