Index: src/login/login.c
===================================================================
--- src/login/login.c (revision 17365)
+++ src/login/login.c (working copy)
@@ -567,6 +567,7 @@
char birthdate[10+1] = "";
char pincode[PINCODE_LENGTH+1];
int account_id = RFIFOL(fd,2);
+ int cl_version = 0;
memset(pincode,0,PINCODE_LENGTH+1);
@@ -575,15 +576,18 @@
if( !accounts->load_num(accounts, &acc, account_id) )
ShowNotice("Char-server '%s': account %d NOT found (ip: %s).\n", server[id].name, account_id, ip);
else{
+ struct auth_node *node = (struct auth_node*)idb_get(auth_db, account_id);
safestrncpy(email, acc.email, sizeof(email));
expiration_time = acc.expiration_time;
group_id = acc.group_id;
char_slots = acc.char_slots;
safestrncpy(birthdate, acc.birthdate, sizeof(birthdate));
safestrncpy(pincode, acc.pincode, sizeof(pincode));
+ if(node) cl_version = node->version;
+ ShowInfo("login R_0x2716, S_0x2717 version = %d, node=%d\n",cl_version,node);
}
- WFIFOHEAD(fd,72);
+ WFIFOHEAD(fd,73);
WFIFOW(fd,0) = 0x2717;
WFIFOL(fd,2) = account_id;
safestrncpy((char*)WFIFOP(fd,6), email, 40);
@@ -593,13 +597,13 @@
safestrncpy((char*)WFIFOP(fd,52), birthdate, 10+1);
safestrncpy((char*)WFIFOP(fd,63), pincode, 4+1 );
WFIFOL(fd,68) = (uint32)acc.pincode_change;
- WFIFOSET(fd,72);
+ WFIFOB(fd,72) = cl_version;
+ WFIFOSET(fd,73);
}
break;
case 0x2719: // ping request from charserver
RFIFOSKIP(fd,2);
-
WFIFOHEAD(fd,2);
WFIFOW(fd,0) = 0x2718;
WFIFOSET(fd,2);
@@ -1270,10 +1274,8 @@
{
struct online_login_data* data;
-
// mark client as 'online'
data = add_online_user(-1, sd->account_id);
-
// schedule deletion of this node
data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0);
}
Index: src/map/status.c
===================================================================
--- src/map/status.c (revision 17365)
+++ src/map/status.c (working copy)
@@ -49,10 +49,12 @@
};
static int max_weight_base[CLASS_COUNT];
-static int hp_coefficient[CLASS_COUNT];
-static int hp_coefficient2[CLASS_COUNT];
-static int hp_sigma_val[CLASS_COUNT][MAX_LEVEL+1];
-static int sp_coefficient[CLASS_COUNT];
+static struct {
+ int hp_table[MAX_LEVEL];
+ int sp_table[MAX_LEVEL];
+ int max_level;
+} hpsp_info[CLASS_COUNT];
+
#ifdef RENEWAL_ASPD
static int aspd_base[CLASS_COUNT][MAX_WEAPON_TYPE+1];
#else
@@ -2239,39 +2241,11 @@
return 1;
}
-/// Helper function for status_base_pc_maxhp(), used to pre-calculate the hp_sigma_val[] array
-static void status_calc_sigma(void)
-{
- int i,j;
-
- for(i = 0; i < CLASS_COUNT; i++)
- {
- unsigned int k = 0;
- hp_sigma_val[i][0] = hp_sigma_val[i][1] = 0;
- for(j = 2; j <= MAX_LEVEL; j++)
- {
- k += (hp_coefficient[i]*j + 50) / 100;
- hp_sigma_val[i][j] = k;
- if (k >= INT_MAX)
- break; //Overflow protection. [Skotlex]
- }
- for(; j <= MAX_LEVEL; j++)
- hp_sigma_val[i][j] = INT_MAX;
- }
-}
-
-/// Calculates base MaxHP value according to class and base level
-/// The recursive equation used to calculate level bonus is (using integer operations)
-/// f(0) = 35 | f(x+1) = f(x) + A + (x + B)*C/D
-/// which reduces to something close to
-/// f(x) = 35 + x*(A + B*C/D) + sum(i=2..x){ i*C/D }
+//Calculate maxHP from tables
static unsigned int status_base_pc_maxhp(struct map_session_data* sd, struct status_data* status)
{
- uint64 val = pc_class2idx(sd->status.class_);
- val = 35 + sd->status.base_level*(int64)hp_coefficient2[val]/100 + hp_sigma_val[val][sd->status.base_level];
+ uint32 val = hpsp_info[pc_class2idx(sd->status.class_)].hp_table[sd->status.base_level-1];
- if((sd->class_&MAPID_UPPERMASK) == MAPID_NINJA || (sd->class_&MAPID_UPPERMASK) == MAPID_GUNSLINGER)
- val += 100; //Since their HP can't be approximated well enough without this.
if((sd->class_&MAPID_UPPERMASK) == MAPID_TAEKWON && sd->status.base_level >= 90 && pc_famerank(sd->status.char_id, MAPID_TAEKWON))
val *= 3; //Triple max HP for top ranking Taekwons over level 90.
if((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.base_level >= 99)
@@ -2286,11 +2260,11 @@
return (unsigned int)val;
}
+//Calculate maxSP from tables
static unsigned int status_base_pc_maxsp(struct map_session_data* sd, struct status_data *status)
{
- uint64 val;
+ uint32 val = hpsp_info[pc_class2idx(sd->status.class_)].sp_table[sd->status.base_level-1];
- val = 10 + sd->status.base_level*(int64)sp_coefficient[pc_class2idx(sd->status.class_)]/100;
val += val * status->int_/100;
if (sd->class_&JOBL_UPPER)
@@ -3950,8 +3924,8 @@
status->matk_max += sd->bonus.ematk;
status->matk_min += sd->bonus.ematk;
}
- status->matk_min = status_calc_ematk(bl, sc, status->matk_min);
- status->matk_max = status_calc_ematk(bl, sc, status->matk_max);
+ status->matk_min = status_calc_ematk(bl, sc, status->matk_min);
+ status->matk_max = status_calc_ematk(bl, sc, status->matk_max);
//This is the only portion in MATK that varies depending on the weapon level and refinement rate.
if( status->rhw.matk > 0 ){
int wMatk = status->rhw.matk;
@@ -3961,17 +3935,19 @@
}
}
#endif
- if (bl->type&BL_PC && sd->matk_rate != 100) {
+ if (bl->type&BL_PC && sd->matk_rate != 100) {
status->matk_max = status->matk_max * sd->matk_rate/100;
status->matk_min = status->matk_min * sd->matk_rate/100;
}
- status->matk_min = status_calc_matk(bl, sc, status->matk_min);
+
status->matk_max = status_calc_matk(bl, sc, status->matk_max);
- if ((bl->type&BL_HOM && battle_config.hom_setting&0x20) //Hom Min Matk is always the same as Max Matk
- || sc->data[SC_RECOGNIZEDSPELL])
- status->matk_min = status->matk_max;
+ if ((bl->type&BL_HOM && battle_config.hom_setting&0x20) //Hom Min Matk is always the same as Max Matk
+ || (sc && sc->data[SC_RECOGNIZEDSPELL]))
+ status->matk_min = status->matk_max;
+ else
+ status->matk_min = status_calc_matk(bl, sc, status->matk_min);
#ifdef RENEWAL
if( sd && sd->right_weapon.overrefine > 0){
@@ -4741,37 +4717,37 @@
return cap_value(matk,0,USHRT_MAX);
#ifndef RENEWAL
// take note fixed value first before % modifiers
- if (sc->data[SC_MATKPOTION])
- matk += sc->data[SC_MATKPOTION]->val1;
- if (sc->data[SC_MATKFOOD])
- matk += sc->data[SC_MATKFOOD]->val1;
- if (sc->data[SC_MANA_PLUS])
- matk += sc->data[SC_MANA_PLUS]->val1;
- if (sc->data[SC_AQUAPLAY_OPTION])
- matk += sc->data[SC_AQUAPLAY_OPTION]->val2;
- if (sc->data[SC_CHILLY_AIR_OPTION])
- matk += sc->data[SC_CHILLY_AIR_OPTION]->val2;
- if (sc->data[SC_WATER_BARRIER])
- matk -= sc->data[SC_WATER_BARRIER]->val3;
- if (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3)
- matk += 50;
- if (sc->data[SC_ODINS_POWER])
- matk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; //70 lvl1, 100lvl2
- if (sc->data[SC_IZAYOI])
- matk += 50 * sc->data[SC_IZAYOI]->val1;
+ if (sc->data[SC_MATKPOTION])
+ matk += sc->data[SC_MATKPOTION]->val1;
+ if (sc->data[SC_MATKFOOD])
+ matk += sc->data[SC_MATKFOOD]->val1;
+ if (sc->data[SC_MANA_PLUS])
+ matk += sc->data[SC_MANA_PLUS]->val1;
+ if (sc->data[SC_AQUAPLAY_OPTION])
+ matk += sc->data[SC_AQUAPLAY_OPTION]->val2;
+ if (sc->data[SC_CHILLY_AIR_OPTION])
+ matk += sc->data[SC_CHILLY_AIR_OPTION]->val2;
+ if (sc->data[SC_WATER_BARRIER])
+ matk -= sc->data[SC_WATER_BARRIER]->val3;
+ if (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3)
+ matk += 50;
+ if (sc->data[SC_ODINS_POWER])
+ matk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; //70 lvl1, 100lvl2
+ if (sc->data[SC_IZAYOI])
+ matk += 50 * sc->data[SC_IZAYOI]->val1;
#endif
- if (sc->data[SC_MAGICPOWER] && sc->data[SC_MAGICPOWER]->val4)
- matk += matk * sc->data[SC_MAGICPOWER]->val3/100;
- if (sc->data[SC_MINDBREAKER])
- matk += matk * sc->data[SC_MINDBREAKER]->val2/100;
- if (sc->data[SC_INCMATKRATE])
- matk += matk * sc->data[SC_INCMATKRATE]->val1/100;
- if (sc->data[SC_MOONLITSERENADE])
- matk += matk * sc->data[SC_MOONLITSERENADE]->val2/100;
- if (sc->data[SC_MELODYOFSINK])
- matk += matk * sc->data[SC_MELODYOFSINK]->val3/100;
- if (sc->data[SC_BEYONDOFWARCRY])
- matk -= matk * sc->data[SC_BEYONDOFWARCRY]->val3/100;
+ if (sc->data[SC_MAGICPOWER] && sc->data[SC_MAGICPOWER]->val4)
+ matk += matk * sc->data[SC_MAGICPOWER]->val3/100;
+ if (sc->data[SC_MINDBREAKER])
+ matk += matk * sc->data[SC_MINDBREAKER]->val2/100;
+ if (sc->data[SC_INCMATKRATE])
+ matk += matk * sc->data[SC_INCMATKRATE]->val1/100;
+ if (sc->data[SC_MOONLITSERENADE])
+ matk += matk * sc->data[SC_MOONLITSERENADE]->val2/100;
+ if (sc->data[SC_MELODYOFSINK])
+ matk += matk * sc->data[SC_MELODYOFSINK]->val3/100;
+ if (sc->data[SC_BEYONDOFWARCRY])
+ matk -= matk * sc->data[SC_BEYONDOFWARCRY]->val3/100;
if( sc->data[SC_ZANGETSU] )
matk += matk * sc->data[SC_ZANGETSU]->val2 / 100;
@@ -11341,15 +11317,8 @@
}
-/*------------------------------------------
- * DB reading.
- * job_db1.txt - weight, hp, sp, aspd
- * job_db2.txt - job level stat bonuses
- * size_fix.txt - size adjustment table for weapons
- * refine_db.txt - refining data table
- *------------------------------------------*/
-static bool status_readdb_job1(char* fields[], int columns, int current)
-{// Job-specific values (weight, HP, SP, ASPD)
+//Reading job_db1.txt line, (class,weight,aspd)
+static bool status_readdb_job1(char* fields[], int columns, int current){
int idx, class_;
unsigned int i;
@@ -11363,20 +11332,18 @@
idx = pc_class2idx(class_);
max_weight_base[idx] = atoi(fields[1]);
- hp_coefficient[idx] = atoi(fields[2]);
- hp_coefficient2[idx] = atoi(fields[3]);
- sp_coefficient[idx] = atoi(fields[4]);
#ifdef RENEWAL_ASPD
for(i = 0; i <= MAX_WEAPON_TYPE; i++)
#else
for(i = 0; i < MAX_WEAPON_TYPE; i++)
#endif
{
- aspd_base[idx][i] = atoi(fields[i+5]);
+ aspd_base[idx][i] = atoi(fields[i+2]);
}
return true;
}
+//Reading job_db2.txt line (class,JobLv1,JobLv2,JobLv3,...)
static bool status_readdb_job2(char* fields[], int columns, int current)
{
int idx, class_, i;
@@ -11397,6 +11364,78 @@
return true;
}
+//Reading job_maxhp.txt line
+static bool status_readdb_maxhp(char* fields[], int columns, int current)
+{
+ int idx, i, maxlvl;
+ int job_id,job_count,jobs[CLASS_COUNT];
+
+ job_count = pc_split_atoi(fields[1],jobs,':',CLASS_COUNT);
+ if (job_count < 1)
+ return false;
+ for (i = 1; i < job_count; i++) {
+ job_id = jobs[i];
+ if(!pcdb_checkid(job_id))
+ {
+ ShowWarning("status_readdb_maxhp: Invalid job class %d specified.\n", job_id);
+ return false;
+ }
+ idx = pc_class2idx(job_id);
+
+ maxlvl = atoi(fields[0]);
+ if(maxlvl > MAX_LEVEL){
+ ShowWarning("status_readdb_maxhp: Invalid maxlevel %d specified.\n", maxlvl);
+ return false;
+ }
+ if(hpsp_info[idx].max_level && hpsp_info[idx].max_level != maxlvl){
+ ShowWarning("status_readdb_maxhp: maxlevel %d was already specified with different value %d.\n",maxlvl,hpsp_info[idx].max_level);
+ return false;
+ }
+ hpsp_info[idx].max_level = maxlvl;
+ for(i = 2; i < maxlvl; i++)
+ {
+ hpsp_info[idx].hp_table[i-1] = atoi(fields[i]);
+ }
+ }
+ return true;
+}
+
+//Reading job_maxsp.txt line
+static bool status_readdb_maxsp(char* fields[], int columns, int current)
+{
+ int idx, i, maxlvl;
+ int job_id,job_count,jobs[CLASS_COUNT];
+
+ job_count = pc_split_atoi(fields[1],jobs,':',CLASS_COUNT);
+ if (job_count < 1)
+ return false;
+ for (i = 1; i < job_count; i++) {
+ job_id = jobs[i];
+ if(!pcdb_checkid(job_id))
+ {
+ ShowWarning("status_readdb_maxhp: Invalid job class %d specified.\n", job_id);
+ return false;
+ }
+ idx = pc_class2idx(job_id);
+
+ maxlvl = atoi(fields[0]);
+ if(maxlvl > MAX_LEVEL){
+ ShowWarning("status_readdb_maxhp: Invalid maxlevel %d specified.\n", maxlvl);
+ return false;
+ }
+ if(hpsp_info[idx].max_level && hpsp_info[idx].max_level != maxlvl){
+ ShowWarning("status_readdb_maxhp: maxlevel %d was already specified with different value %d.\n",maxlvl,hpsp_info[idx].max_level);
+ return false;
+ }
+ hpsp_info[idx].max_level = maxlvl;
+ for(i = 2; i < maxlvl; i++)
+ {
+ hpsp_info[idx].sp_table[i-1] = atoi(fields[i]);
+ }
+ }
+ return true;
+}
+
static bool status_readdb_sizefix(char* fields[], int columns, int current)
{
unsigned int i;
@@ -11442,34 +11481,33 @@
return true;
}
-/*
-* Read status db
-* job1.txt
-* job2.txt
-* size_fixe.txt
-* refine_db.txt
-*/
+
+/*------------------------------------------
+ * DB reading.
+ * job_db1.txt - job weight, aspd
+ * job_db2.txt - job level stat bonuses
+ * job_maxhp_db.txt - job max hp
+ * job_maxsp_db.txt - job max sp
+ * size_fix.txt - size adjustment table for weapons
+ * refine_db.txt - refining data table
+ *------------------------------------------*/
int status_readdb(void)
{
int i, j;
-
// initialize databases to default
//
-
// reset job_db1.txt data
memset(max_weight_base, 0, sizeof(max_weight_base));
- memset(hp_coefficient, 0, sizeof(hp_coefficient));
- memset(hp_coefficient2, 0, sizeof(hp_coefficient2));
- memset(sp_coefficient, 0, sizeof(sp_coefficient));
memset(aspd_base, 0, sizeof(aspd_base));
// reset job_db2.txt data
memset(job_bonus,0,sizeof(job_bonus)); // Job-specific stats bonus
+ // hp_sptable
+ memset(hpsp_info,0,sizeof(hpsp_info));
// size_fix.txt
for(i=0;i<ARRAYLENGTH(atkmods);i++)
for(j=0;j<MAX_WEAPON_TYPE;j++)
atkmods[i][j]=100;
-
// refine_db.txt
for(i=0;i<ARRAYLENGTH(refine_info);i++)
{
@@ -11482,17 +11520,17 @@
}
// read databases
- //
-
-
+ // path,filename,separator,mincol,maxcol,maxrow,func_parsor
#ifdef RENEWAL_ASPD
- sv_readdb(db_path, "re/job_db1.txt", ',', 6+MAX_WEAPON_TYPE, 6+MAX_WEAPON_TYPE, -1, &status_readdb_job1);
+ sv_readdb(db_path, "re/job_db1.txt",',',6+MAX_WEAPON_TYPE,6+MAX_WEAPON_TYPE,-1,&status_readdb_job1);
#else
- sv_readdb(db_path, "pre-re/job_db1.txt", ',', 5+MAX_WEAPON_TYPE, 5+MAX_WEAPON_TYPE, -1, &status_readdb_job1);
+ sv_readdb(db_path, "pre-re/job_db1.txt",',',5+MAX_WEAPON_TYPE,5+MAX_WEAPON_TYPE,-1,&status_readdb_job1);
#endif
- sv_readdb(db_path, "job_db2.txt", ',', 1, 1+MAX_LEVEL, -1, &status_readdb_job2);
- sv_readdb(db_path, "size_fix.txt", ',', MAX_WEAPON_TYPE, MAX_WEAPON_TYPE, ARRAYLENGTH(atkmods), &status_readdb_sizefix);
+ sv_readdb(db_path, "job_db2.txt",',',1,1+MAX_LEVEL,-1,&status_readdb_job2);
+ sv_readdb(db_path, "size_fix.txt",',',MAX_WEAPON_TYPE,MAX_WEAPON_TYPE,ARRAYLENGTH(atkmods),&status_readdb_sizefix);
sv_readdb(db_path, DBPATH"refine_db.txt", ',', 4+MAX_REFINE, 4+MAX_REFINE, ARRAYLENGTH(refine_info), &status_readdb_refine);
+ sv_readdb(db_path, DBPATH"job_maxhp_db.txt", ',', 3, 1+MAX_LEVEL, -1, &status_readdb_maxhp);
+ sv_readdb(db_path, DBPATH"job_maxsp_db.txt", ',', 3, 1+MAX_LEVEL, -1, &status_readdb_maxsp);
return 0;
}
@@ -11508,7 +11546,6 @@
initChangeTables();
initDummyData();
status_readdb();
- status_calc_sigma();
natural_heal_prev_tick = gettick();
sc_data_ers = ers_new(sizeof(struct status_change_entry),"status.c::sc_data_ers",ERS_OPT_NONE);
add_timer_interval(natural_heal_prev_tick + NATURAL_HEAL_INTERVAL, status_natural_heal_timer, 0, 0, NATURAL_HEAL_INTERVAL);
Index: src/char/char.c
===================================================================
--- src/char/char.c (revision 17365)
+++ src/char/char.c (working copy)
@@ -170,9 +170,9 @@
int pincode_maxtry = 3;
bool pincode_force = true;
-void pincode_check( int fd, struct char_session_data* sd );
-void pincode_change( int fd, struct char_session_data* sd );
-void pincode_setnew( int fd, struct char_session_data* sd );
+int pincode_check( int fd, struct char_session_data* sd );
+int pincode_change( int fd, struct char_session_data* sd );
+int pincode_setnew( int fd, struct char_session_data* sd );
void pincode_sendstate( int fd, struct char_session_data* sd, uint16 state );
void pincode_notifyLoginPinUpdate( int account_id, char* pin );
void pincode_notifyLoginPinError( int account_id );
@@ -184,7 +184,7 @@
bool char_movetoused = true;
bool char_moves_unlimited = false;
-void moveCharSlot( int fd, struct char_session_data* sd, unsigned short from, unsigned short to );
+int moveCharSlot( int fd, struct char_session_data* sd);
void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason );
//Custom limits for the fame lists. [Skotlex]
@@ -222,6 +222,7 @@
time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
int group_id;
unsigned changing_mapservers : 1;
+ int version;
};
static DBMap* auth_db; // int account_id -> struct auth_node*
@@ -2001,13 +2002,12 @@
void mmo_char_send(int fd, struct char_session_data* sd){
ShowInfo("sd->version = %d\n",sd->version);
-#if PACKETVER >= 20130000
+ if(sd->version > 34){
mmo_char_send082d(fd,sd);
char_charlist_notify(fd,sd);
char_block_character(fd,sd);
-#endif
- //@FIXME dump from kro doesn't show 6b transmission
- mmo_char_send006b(fd,sd);
+ }
+ mmo_char_send006b(fd,sd); //@FIXME dump from kro doesn't show 6b transmission
}
int char_married(int pl1, int pl2)
@@ -2280,7 +2280,7 @@
break;
case 0x2717: // account data
- if (RFIFOREST(fd) < 72)
+ if (RFIFOREST(fd) < 73)
return 0;
// find the authenticated session with this account id
@@ -2300,6 +2300,7 @@
safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
sd->pincode_change = (time_t)RFIFOL(fd,68);
+ sd->version = RFIFOB(fd,72);
ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
// continued from char_auth_ok...
if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
@@ -2346,7 +2347,7 @@
#endif
}
}
- RFIFOSKIP(fd,72);
+ RFIFOSKIP(fd,73);
break;
// login-server alive packet
@@ -3620,34 +3621,490 @@
WFIFOSET(fd,10);
}
+//For use in packets that depend on an sd being present [Skotlex]
+#define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }
-static void char_delete2_req(int fd, struct char_session_data* sd)
-{// CH: <0827>.W <char id>.L
+
+// 0065 <account id>.L <login id1>.L <login id2>.L <???>.W <sex>.B
+int char_parse_reqtoconnect(int fd, struct char_session_data* sd,uint32 ipl){
+ if( RFIFOREST(fd) < 17 ) // request to connect
+ return 0;
+ else {
+ struct auth_node* node;
+
+ int account_id = RFIFOL(fd,2);
+ uint32 login_id1 = RFIFOL(fd,6);
+ uint32 login_id2 = RFIFOL(fd,10);
+ int sex = RFIFOB(fd,16);
+ RFIFOSKIP(fd,17);
+
+ ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2);
+
+ if (sd) {
+ //Received again auth packet for already authentified account?? Discard it.
+ //TODO: Perhaps log this as a hack attempt?
+ //TODO: and perhaps send back a reply?
+ ShowInfo("Already registered break\n");
+ return 0;
+ }
+
+ CREATE(session[fd]->session_data, struct char_session_data, 1);
+ sd = (struct char_session_data*)session[fd]->session_data;
+ sd->account_id = account_id;
+ sd->login_id1 = login_id1;
+ sd->login_id2 = login_id2;
+ sd->sex = sex;
+ sd->auth = false; // not authed yet
+
+ // send back account_id
+ WFIFOHEAD(fd,4);
+ WFIFOL(fd,0) = account_id;
+ WFIFOSET(fd,4);
+
+ if( runflag != CHARSERVER_ST_RUNNING )
+ {
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0;// rejected from server
+ WFIFOSET(fd,3);
+ return 0;
+ }
+
+ // search authentification
+ node = (struct auth_node*)idb_get(auth_db, account_id);
+ if( node != NULL &&
+ node->account_id == account_id &&
+ node->login_id1 == login_id1 &&
+ node->login_id2 == login_id2 /*&&
+ node->ip == ipl*/ )
+ {// authentication found (coming from map server)
+ idb_remove(auth_db, account_id);
+ char_auth_ok(fd, sd);
+ }
+ else
+ {// authentication not found (coming from login server)
+ if (login_fd > 0) { // don't send request if no login-server
+ WFIFOHEAD(login_fd,23);
+ WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
+ WFIFOL(login_fd,2) = sd->account_id;
+ WFIFOL(login_fd,6) = sd->login_id1;
+ WFIFOL(login_fd,10) = sd->login_id2;
+ WFIFOB(login_fd,14) = sd->sex;
+ WFIFOL(login_fd,15) = htonl(ipl);
+ WFIFOL(login_fd,19) = fd;
+ WFIFOSET(login_fd,23);
+ } else { // if no login-server, we must refuse connection
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0;
+ WFIFOSET(fd,3);
+ }
+ }
+ }
+ return 1;
+}
+
+int char_parse_charselect(int fd, struct char_session_data* sd,uint32 ipl){
+ FIFOSD_CHECK(3);
+ {
+ struct mmo_charstatus char_dat;
+ struct mmo_charstatus *cd;
+ char* data;
+ int char_id;
+ uint32 subnet_map_ip;
+ struct auth_node* node;
+ int i, map_fd;
+
+ int slot = RFIFOB(fd,2);
+ RFIFOSKIP(fd,3);
+
+ if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot)
+ || SQL_SUCCESS != Sql_NextRow(sql_handle)
+ || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) )
+ { //Not found?? May be forged packet.
+ Sql_ShowDebug(sql_handle);
+ Sql_FreeResult(sql_handle);
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0; // rejected from server
+ WFIFOSET(fd,3);
+ return 0;
+ }
+
+ char_id = atoi(data);
+ Sql_FreeResult(sql_handle);
+
+ /* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
+ set_char_online(-2,char_id,sd->account_id);
+ if( !mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */
+ set_char_offline(char_id, sd->account_id);
+ /* failed to load something. REJECT! */
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0;
+ WFIFOSET(fd,3);
+ return 0;/* jump off this boat */
+ }
+
+ //Have to switch over to the DB instance otherwise data won't propagate [Kevin]
+ cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
+ cd->sex = sd->sex;
+
+ if (log_char) {
+ char esc_name[NAME_LENGTH*2+1];
+
+ Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH));
+ if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
+ charlog_db, sd->account_id, slot, esc_name) )
+ Sql_ShowDebug(sql_handle);
+ }
+ ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
+
+ // searching map server
+ i = search_mapserver(cd->last_point.map, -1, -1);
+
+ // if map is not found, we check major cities
+ if (i < 0 || !cd->last_point.map) {
+ unsigned short j;
+ //First check that there's actually a map server online.
+ ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] );
+ if (j == ARRAYLENGTH(server)) {
+ ShowInfo("Connection Closed. No map servers available.\n");
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x81;
+ WFIFOB(fd,2) = 1; // 01 = Server closed
+ WFIFOSET(fd,3);
+ return 0;
+ }
+ if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
+ cd->last_point.x = 273;
+ cd->last_point.y = 354;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
+ cd->last_point.x = 120;
+ cd->last_point.y = 100;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
+ cd->last_point.x = 160;
+ cd->last_point.y = 94;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
+ cd->last_point.x = 116;
+ cd->last_point.y = 57;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
+ cd->last_point.x = 87;
+ cd->last_point.y = 117;
+ } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
+ cd->last_point.x = 94;
+ cd->last_point.y = 103;
+ } else {
+ ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map));
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x81;
+ WFIFOB(fd,2) = 1; // 01 = Server closed
+ WFIFOSET(fd,3);
+ return 0;
+ }
+ ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
+ cd->last_point.map = j;
+ }
+
+ //Send NEW auth packet [Kevin]
+ //FIXME: is this case even possible? [ultramage]
+ if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL)
+ {
+ ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
+ server[i].fd = -1;
+ memset(&server[i], 0, sizeof(struct mmo_map_server));
+ //Send server closed.
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x81;
+ WFIFOB(fd,2) = 1; // 01 = Server closed
+ WFIFOSET(fd,3);
+ return 0;
+ }
+
+ //Send player to map
+ WFIFOHEAD(fd,28);
+ WFIFOW(fd,0) = 0x71;
+ WFIFOL(fd,2) = cd->char_id;
+ mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
+ subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
+ WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip);
+ WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
+ WFIFOSET(fd,28);
+
+ // create temporary auth entry
+ CREATE(node, struct auth_node, 1);
+ node->account_id = sd->account_id;
+ node->char_id = cd->char_id;
+ node->login_id1 = sd->login_id1;
+ node->login_id2 = sd->login_id2;
+ node->sex = sd->sex;
+ node->expiration_time = sd->expiration_time;
+ node->group_id = sd->group_id;
+ node->ip = ipl;
+ node->version = sd->version;
+ idb_put(auth_db, sd->account_id, node);
+
+ }
+ return 1;
+}
+
+// S 0970 <name>.24B <slot>.B <hair color>.W <hair style>.W
+// S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W
+int char_parse_createnewchar(int fd, struct char_session_data* sd,int cmd){
+ int i=0, ch;
+
+ if (cmd == 0x970) FIFOSD_CHECK(31) //>=20120307
+ else if (cmd == 0x67) FIFOSD_CHECK(37)
+ else return 0;
+
+ if( !char_new ) //turn character creation on/off [Kevin]
+ i = -2;
+ else {
+ if (cmd == 0x970){
+ i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
+ RFIFOSKIP(fd,31);
+ }
+ else if(cmd == 0x67){
+#if PACKETVER < 20120307
+ i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35));
+ RFIFOSKIP(fd,37);
+#endif
+ }
+ }
+
+ //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3)
+ if (i < 0) {
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6e;
+ /* Others I found [Ind] */
+ /* 0x02 = Symbols in Character Names are forbidden */
+ /* 0x03 = You are not elegible to open the Character Slot. */
+ switch (i) {
+ case -1: WFIFOB(fd,2) = 0x00; break;
+ case -2: WFIFOB(fd,2) = 0xFF; break;
+ case -3: WFIFOB(fd,2) = 0x01; break;
+ case -4: WFIFOB(fd,2) = 0x03; break;
+ }
+ WFIFOSET(fd,3);
+ } else {
+ int len;
+ // retrieve data
+ struct mmo_charstatus char_dat;
+ mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed.
+
+ // send to player
+ WFIFOHEAD(fd,2+MAX_CHAR_BUF);
+ WFIFOW(fd,0) = 0x6d;
+ len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat);
+ WFIFOSET(fd,len);
+
+ // add new entry to the chars list
+ ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
+ if( ch < MAX_CHARS )
+ sd->found_char[ch] = i; // the char_id of the new char
+ }
+ return 1;
+}
+
+int char_parse_delchar(int fd,struct char_session_data* sd, int cmd){
+ char email[40];
+ int i, ch;
+
+ if (cmd == 0x68) FIFOSD_CHECK(46)
+ else if (cmd == 0x1fb) FIFOSD_CHECK(56)
+ else return 0;
+
+ {
+ int cid = RFIFOL(fd,2);
+
+ ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
+ memcpy(email, RFIFOP(fd,6), 40);
+ RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56);
+
+ // Check if e-mail is correct
+ if(strcmpi(email, sd->email) && //email does not matches and
+ (
+ strcmp("[email protected]", sd->email) || //it is not default email, or
+ (strcmp("[email protected]", email) && strcmp("", email)) //email sent does not matches default
+ )) { //Fail
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x70;
+ WFIFOB(fd,2) = 0; // 00 = Incorrect Email address
+ WFIFOSET(fd,3);
+ return 0;
+ }
+
+ // check if this char exists
+ ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
+ if( i == MAX_CHARS )
+ { // Such a character does not exist in the account
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x70;
+ WFIFOB(fd,2) = 0;
+ WFIFOSET(fd,3);
+ return 0;
+ }
+
+ // remove char from list and compact it
+ for(ch = i; ch < MAX_CHARS-1; ch++)
+ sd->found_char[ch] = sd->found_char[ch+1];
+ sd->found_char[MAX_CHARS-1] = -1;
+
+ /* Delete character */
+ if(delete_char_sql(cid)<0){
+ //can't delete the char
+ //either SQL error or can't delete by some CONFIG conditions
+ //del fail
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd, 0) = 0x70;
+ WFIFOB(fd, 2) = 0;
+ WFIFOSET(fd, 3);
+ return 0;
+ }
+ /* Char successfully deleted.*/
+ WFIFOHEAD(fd,2);
+ WFIFOW(fd,0) = 0x6f;
+ WFIFOSET(fd,2);
+ }
+ return 1;
+}
+
+// R 0187 <account ID>.l
+int char_parse_keepalive(int fd){
+ if (RFIFOREST(fd) < 6)
+ return 0;
+ //int aid = RFIFOL(fd,2);
+ RFIFOSKIP(fd,6);
+ return 1;
+}
+
+// R 08fc <char ID>.l <new name>.24B
+// R 028d <account ID>.l <char ID>.l <new name>.24B
+int char_parse_reqrename(int fd, struct char_session_data* sd, int cmd){
+ if(cmd == 0x8fc) FIFOSD_CHECK(30)
+ if(cmd == 0x28d) FIFOSD_CHECK(34)
+ else return 0;
+
+ {
+ int i, cid=0;
+ char name[NAME_LENGTH];
+ char esc_name[NAME_LENGTH*2+1];
+ safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH);
+
+ if(cmd == 0x8fc){
+ cid =RFIFOL(fd,2);
+ RFIFOSKIP(fd,30);
+ }
+ else if(cmd == 0x28d) {
+ int aid = RFIFOL(fd,2);
+ cid =RFIFOL(fd,6);
+ if( aid != sd->account_id )
+ return 0;
+ RFIFOSKIP(fd,34);
+ }
+
+ ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
+ if( i == MAX_CHARS )
+ return 0;
+
+ normalize_name(name,TRIM_CHARS);
+ Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
+ if( !check_char_name(name,esc_name) )
+ {
+ i = 1;
+ safestrncpy(sd->new_name, name, NAME_LENGTH);
+ }
+ else
+ i = 0;
+
+ WFIFOHEAD(fd, 4);
+ WFIFOW(fd,0) = 0x28e;
+ WFIFOW(fd,2) = i;
+ WFIFOSET(fd,4);
+ }
+ return 1;
+}
+
+// 0x28f <char_id>.L
+int char_parse_ackrename(int fd, struct char_session_data* sd){
+ // 0: Sucessfull
+ // 1: This character's name has already been changed. You cannot change a character's name more than once.
+ // 2: User information is not correct.
+ // 3: You have failed to change this character's name.
+ // 4: Another user is using this character name, so please select another one.
+ FIFOSD_CHECK(6)
+
+ {
+ int i;
+ int cid = RFIFOL(fd,2);
+ RFIFOSKIP(fd,6);
+
+ ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
+ if( i == MAX_CHARS )
+ return 0;
+ i = rename_char_sql(sd, cid);
+
+ WFIFOHEAD(fd, 4);
+ WFIFOW(fd,0) = 0x290;
+ WFIFOW(fd,2) = i;
+ WFIFOSET(fd,4);
+ }
+ return 1;
+}
+
+// R 07e5 <?>.w <aid>.l
+int char_parse_reqcaptcha(int fd){
+ WFIFOHEAD(fd,5);
+ WFIFOW(fd,0) = 0x7e9;
+ WFIFOW(fd,2) = 5;
+ WFIFOB(fd,4) = 1;
+ WFIFOSET(fd,5);
+ RFIFOSKIP(fd,8);
+ return 1;
+}
+
+// R 07e7 <len>.w <aid>.l <code>.b10 <?>.b14
+int char_parse_chkcaptcha(int fd){
+ WFIFOHEAD(fd,5);
+ WFIFOW(fd,0) = 0x7e9;
+ WFIFOW(fd,2) = 5;
+ WFIFOB(fd,4) = 1;
+ WFIFOSET(fd,5);
+ RFIFOSKIP(fd,32);
+ return 1;
+}
+
+// CH: <0827>.W <char id>.L
+int char_delete2_req(int fd, struct char_session_data* sd)
+{
int char_id, i;
char* data;
time_t delete_date;
+ FIFOSD_CHECK(6)
+
char_id = RFIFOL(fd,2);
+ RFIFOSKIP(fd,6);
ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
if( i == MAX_CHARS )
{// character not found
char_delete2_ack(fd, char_id, 3, 0);
- return;
+ return 0;
}
if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) )
{
Sql_ShowDebug(sql_handle);
char_delete2_ack(fd, char_id, 3, 0);
- return;
+ return 0;
}
Sql_GetData(sql_handle, 0, &data, NULL); delete_date = strtoul(data, NULL, 10);
if( delete_date ) {// character already queued for deletion
char_delete2_ack(fd, char_id, 0, 0);
- return;
+ return 0;
}
/*
@@ -3674,14 +4131,14 @@
{
Sql_ShowDebug(sql_handle);
char_delete2_ack(fd, char_id, 3, 0);
- return;
+ return 0;
}
char_delete2_ack(fd, char_id, 1, delete_date);
+ return 1;
}
-
-static void char_delete2_accept(int fd, struct char_session_data* sd)
+int char_delete2_accept(int fd, struct char_session_data* sd)
{// CH: <0829>.W <char id>.L <birth date:YYMMDD>.6B
char birthdate[8+1];
int char_id, i, k;
@@ -3689,6 +4146,8 @@
char* data;
time_t delete_date;
+ FIFOSD_CHECK(12)
+
char_id = RFIFOL(fd,2);
ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id);
@@ -3703,19 +4162,20 @@
birthdate[6] = RFIFOB(fd,10);
birthdate[7] = RFIFOB(fd,11);
birthdate[8] = 0;
+ RFIFOSKIP(fd,12);
ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
if( i == MAX_CHARS )
{// character not found
char_delete2_accept_ack(fd, char_id, 3);
- return;
+ return 0;
}
if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `base_level`,`delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) )
{// data error
Sql_ShowDebug(sql_handle);
char_delete2_accept_ack(fd, char_id, 3);
- return;
+ return 0;
}
Sql_GetData(sql_handle, 0, &data, NULL); base_level = (unsigned int)strtoul(data, NULL, 10);
@@ -3724,26 +4184,26 @@
if( !delete_date || delete_date>time(NULL) )
{// not queued or delay not yet passed
char_delete2_accept_ack(fd, char_id, 4);
- return;
+ return 0;
}
if( strcmp(sd->birthdate+2, birthdate) ) // +2 to cut off the century
{// birth date is wrong
char_delete2_accept_ack(fd, char_id, 5);
- return;
+ return 0;
}
if( ( char_del_level > 0 && base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && base_level <= (unsigned int)(-char_del_level) ) )
{// character level config restriction
char_delete2_accept_ack(fd, char_id, 2);
- return;
+ return 0;
}
// success
if( delete_char_sql(char_id) < 0 )
{
char_delete2_accept_ack(fd, char_id, 3);
- return;
+ return 0;
}
// refresh character list cache
@@ -3754,20 +4214,24 @@
sd->found_char[MAX_CHARS-1] = -1;
char_delete2_accept_ack(fd, char_id, 1);
+ return 1;
}
-
-static void char_delete2_cancel(int fd, struct char_session_data* sd)
-{// CH: <082b>.W <char id>.L
+// CH: <082b>.W <char id>.L
+int char_delete2_cancel(int fd, struct char_session_data* sd)
+{
int char_id, i;
+ FIFOSD_CHECK(6)
+
char_id = RFIFOL(fd,2);
+ RFIFOSKIP(fd,6);
ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id );
if( i == MAX_CHARS )
{// character not found
char_delete2_cancel_ack(fd, char_id, 2);
- return;
+ return 0;
}
// there is no need to check, whether or not the character was
@@ -3777,24 +4241,61 @@
{
Sql_ShowDebug(sql_handle);
char_delete2_cancel_ack(fd, char_id, 2);
- return;
+ return 0;
}
char_delete2_cancel_ack(fd, char_id, 1);
+ return 1;
}
+int char_parse_maplogin(int fd){
+ int i;
+ if (RFIFOREST(fd) < 60)
+ return 0;
+ else {
+ char* l_user = (char*)RFIFOP(fd,2);
+ char* l_pass = (char*)RFIFOP(fd,26);
+ l_user[23] = '\0';
+ l_pass[23] = '\0';
+ ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 );
+ if( runflag != CHARSERVER_ST_RUNNING ||
+ i == ARRAYLENGTH(server) ||
+ strcmp(l_user, userid) != 0 ||
+ strcmp(l_pass, passwd) != 0 )
+ {
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x2af9;
+ WFIFOB(fd,2) = 3;
+ WFIFOSET(fd,3);
+ } else {
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x2af9;
+ WFIFOB(fd,2) = 0;
+ WFIFOSET(fd,3);
+
+ server[i].fd = fd;
+ server[i].ip = ntohl(RFIFOL(fd,54));
+ server[i].port = ntohs(RFIFOW(fd,58));
+ server[i].users = 0;
+ memset(server[i].map, 0, sizeof(server[i].map));
+ session[fd]->func_parse = parse_frommap;
+ session[fd]->flag.server = 1;
+ realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
+ char_mapif_init(fd);
+ }
+ RFIFOSKIP(fd,60);
+ }
+ return 1;
+}
+
int parse_char(int fd)
{
- int i, ch;
- char email[40];
+ int i;
unsigned short cmd;
- int map_fd;
- struct char_session_data* sd;
+ struct char_session_data* sd = (struct char_session_data*)session[fd]->session_data;
uint32 ipl = session[fd]->client_addr;
- sd = (struct char_session_data*)session[fd]->session_data;
-
// disconnect any player if no login-server.
if(login_fd < 0)
set_eof(fd);
@@ -3815,582 +4316,44 @@
while( RFIFOREST(fd) >= 2 )
{
- //For use in packets that depend on an sd being present [Skotlex]
- #define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }
-
cmd = RFIFOW(fd,0);
switch( cmd )
{
- // request to connect
- // 0065 <account id>.L <login id1>.L <login id2>.L <???>.W <sex>.B
- case 0x65:
- if( RFIFOREST(fd) < 17 )
- return 0;
- {
- struct auth_node* node;
-
- int account_id = RFIFOL(fd,2);
- uint32 login_id1 = RFIFOL(fd,6);
- uint32 login_id2 = RFIFOL(fd,10);
- int sex = RFIFOB(fd,16);
- RFIFOSKIP(fd,17);
-
- ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2);
-
- if (sd) {
- //Received again auth packet for already authentified account?? Discard it.
- //TODO: Perhaps log this as a hack attempt?
- //TODO: and perhaps send back a reply?
- break;
- }
-
- CREATE(session[fd]->session_data, struct char_session_data, 1);
- sd = (struct char_session_data*)session[fd]->session_data;
- sd->account_id = account_id;
- sd->login_id1 = login_id1;
- sd->login_id2 = login_id2;
- sd->sex = sex;
- sd->auth = false; // not authed yet
-
- // send back account_id
- WFIFOHEAD(fd,4);
- WFIFOL(fd,0) = account_id;
- WFIFOSET(fd,4);
-
- if( runflag != CHARSERVER_ST_RUNNING )
- {
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x6c;
- WFIFOB(fd,2) = 0;// rejected from server
- WFIFOSET(fd,3);
- break;
- }
-
- // search authentification
- node = (struct auth_node*)idb_get(auth_db, account_id);
- if( node != NULL &&
- node->account_id == account_id &&
- node->login_id1 == login_id1 &&
- node->login_id2 == login_id2 /*&&
- node->ip == ipl*/ )
- {// authentication found (coming from map server)
- idb_remove(auth_db, account_id);
- char_auth_ok(fd, sd);
- }
- else
- {// authentication not found (coming from login server)
- if (login_fd > 0) { // don't send request if no login-server
- WFIFOHEAD(login_fd,23);
- WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
- WFIFOL(login_fd,2) = sd->account_id;
- WFIFOL(login_fd,6) = sd->login_id1;
- WFIFOL(login_fd,10) = sd->login_id2;
- WFIFOB(login_fd,14) = sd->sex;
- WFIFOL(login_fd,15) = htonl(ipl);
- WFIFOL(login_fd,19) = fd;
- WFIFOSET(login_fd,23);
- } else { // if no login-server, we must refuse connection
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x6c;
- WFIFOB(fd,2) = 0;
- WFIFOSET(fd,3);
- }
- }
- }
- break;
-
+ case 0x65: char_parse_reqtoconnect(fd,sd,ipl); break;
// char select
- case 0x66:
- FIFOSD_CHECK(3);
- {
- struct mmo_charstatus char_dat;
- struct mmo_charstatus *cd;
- char* data;
- int char_id;
- uint32 subnet_map_ip;
- struct auth_node* node;
-
- int slot = RFIFOB(fd,2);
- RFIFOSKIP(fd,3);
-
- if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot)
- || SQL_SUCCESS != Sql_NextRow(sql_handle)
- || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) )
- { //Not found?? May be forged packet.
- Sql_ShowDebug(sql_handle);
- Sql_FreeResult(sql_handle);
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x6c;
- WFIFOB(fd,2) = 0; // rejected from server
- WFIFOSET(fd,3);
- break;
- }
-
- char_id = atoi(data);
- Sql_FreeResult(sql_handle);
-
- /* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
- set_char_online(-2,char_id,sd->account_id);
- if( !mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */
- set_char_offline(char_id, sd->account_id);
- /* failed to load something. REJECT! */
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x6c;
- WFIFOB(fd,2) = 0;
- WFIFOSET(fd,3);
- break;/* jump off this boat */
- }
-
- //Have to switch over to the DB instance otherwise data won't propagate [Kevin]
- cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
- cd->sex = sd->sex;
-
- if (log_char) {
- char esc_name[NAME_LENGTH*2+1];
-
- Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH));
- if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
- charlog_db, sd->account_id, slot, esc_name) )
- Sql_ShowDebug(sql_handle);
- }
- ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
-
- // searching map server
- i = search_mapserver(cd->last_point.map, -1, -1);
-
- // if map is not found, we check major cities
- if (i < 0 || !cd->last_point.map) {
- unsigned short j;
- //First check that there's actually a map server online.
- ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] );
- if (j == ARRAYLENGTH(server)) {
- ShowInfo("Connection Closed. No map servers available.\n");
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x81;
- WFIFOB(fd,2) = 1; // 01 = Server closed
- WFIFOSET(fd,3);
- break;
- }
- if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
- cd->last_point.x = 273;
- cd->last_point.y = 354;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
- cd->last_point.x = 120;
- cd->last_point.y = 100;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
- cd->last_point.x = 160;
- cd->last_point.y = 94;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
- cd->last_point.x = 116;
- cd->last_point.y = 57;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
- cd->last_point.x = 87;
- cd->last_point.y = 117;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
- cd->last_point.x = 94;
- cd->last_point.y = 103;
- } else {
- ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map));
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x81;
- WFIFOB(fd,2) = 1; // 01 = Server closed
- WFIFOSET(fd,3);
- break;
- }
- ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
- cd->last_point.map = j;
- }
-
- //Send NEW auth packet [Kevin]
- //FIXME: is this case even possible? [ultramage]
- if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL)
- {
- ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
- server[i].fd = -1;
- memset(&server[i], 0, sizeof(struct mmo_map_server));
- //Send server closed.
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x81;
- WFIFOB(fd,2) = 1; // 01 = Server closed
- WFIFOSET(fd,3);
- break;
- }
-
- //Send player to map
- WFIFOHEAD(fd,28);
- WFIFOW(fd,0) = 0x71;
- WFIFOL(fd,2) = cd->char_id;
- mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
- subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
- WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip);
- WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
- WFIFOSET(fd,28);
-
- // create temporary auth entry
- CREATE(node, struct auth_node, 1);
- node->account_id = sd->account_id;
- node->char_id = cd->char_id;
- node->login_id1 = sd->login_id1;
- node->login_id2 = sd->login_id2;
- node->sex = sd->sex;
- node->expiration_time = sd->expiration_time;
- node->group_id = sd->group_id;
- node->ip = ipl;
- idb_put(auth_db, sd->account_id, node);
-
- }
- break;
-
- // create new char
-#if PACKETVER >= 20120307
- // S 0970 <name>.24B <slot>.B <hair color>.W <hair style>.W
- case 0x970:
- FIFOSD_CHECK(31);
-#else
- // S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W
- case 0x67:
- FIFOSD_CHECK(37);
-#endif
-
- if( !char_new ) //turn character creation on/off [Kevin]
- i = -2;
- else
-#if PACKETVER >= 20120307
- i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
-#else
- i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35));
-#endif
-
- //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3)
- if (i < 0) {
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x6e;
- /* Others I found [Ind] */
- /* 0x02 = Symbols in Character Names are forbidden */
- /* 0x03 = You are not elegible to open the Character Slot. */
- switch (i) {
- case -1: WFIFOB(fd,2) = 0x00; break;
- case -2: WFIFOB(fd,2) = 0xFF; break;
- case -3: WFIFOB(fd,2) = 0x01; break;
- case -4: WFIFOB(fd,2) = 0x03; break;
- }
- WFIFOSET(fd,3);
- } else {
- int len;
- // retrieve data
- struct mmo_charstatus char_dat;
- mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed.
-
- // send to player
- WFIFOHEAD(fd,2+MAX_CHAR_BUF);
- WFIFOW(fd,0) = 0x6d;
- len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat);
- WFIFOSET(fd,len);
-
- // add new entry to the chars list
- ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
- if( ch < MAX_CHARS )
- sd->found_char[ch] = i; // the char_id of the new char
- }
-#if PACKETVER >= 20120307
- RFIFOSKIP(fd,31);
-#else
- RFIFOSKIP(fd,37);
-#endif
- break;
-
+ case 0x66: char_parse_charselect(fd,sd,ipl); break;
+ // createnewchar
+ case 0x970: char_parse_createnewchar(fd,sd,cmd); break;
+ case 0x67: char_parse_createnewchar(fd,sd,cmd); break;
// delete char
- case 0x68:
- // 2004-04-19aSakexe+ langtype 12 char deletion packet
- case 0x1fb:
- if (cmd == 0x68) FIFOSD_CHECK(46);
- if (cmd == 0x1fb) FIFOSD_CHECK(56);
- {
- int cid = RFIFOL(fd,2);
-
- ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
- memcpy(email, RFIFOP(fd,6), 40);
- RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56);
-
- // Check if e-mail is correct
- if(strcmpi(email, sd->email) && //email does not matches and
- (
- strcmp("[email protected]", sd->email) || //it is not default email, or
- (strcmp("[email protected]", email) && strcmp("", email)) //email sent does not matches default
- )) { //Fail
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x70;
- WFIFOB(fd,2) = 0; // 00 = Incorrect Email address
- WFIFOSET(fd,3);
- break;
- }
-
- // check if this char exists
- ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
- if( i == MAX_CHARS )
- { // Such a character does not exist in the account
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x70;
- WFIFOB(fd,2) = 0;
- WFIFOSET(fd,3);
- break;
- }
-
- // remove char from list and compact it
- for(ch = i; ch < MAX_CHARS-1; ch++)
- sd->found_char[ch] = sd->found_char[ch+1];
- sd->found_char[MAX_CHARS-1] = -1;
-
- /* Delete character */
- if(delete_char_sql(cid)<0){
- //can't delete the char
- //either SQL error or can't delete by some CONFIG conditions
- //del fail
- WFIFOHEAD(fd,3);
- WFIFOW(fd, 0) = 0x70;
- WFIFOB(fd, 2) = 0;
- WFIFOSET(fd, 3);
- break;
- }
- /* Char successfully deleted.*/
- WFIFOHEAD(fd,2);
- WFIFOW(fd,0) = 0x6f;
- WFIFOSET(fd,2);
- }
- break;
-
+ case 0x68: char_parse_delchar(fd,sd,cmd); break; //
+ case 0x1fb: char_parse_delchar(fd,sd,cmd); break; // 2004-04-19aSakexe+ langtype 12 char deletion packet
// client keep-alive packet (every 12 seconds)
- // R 0187 <account ID>.l
- case 0x187:
- if (RFIFOREST(fd) < 6)
- return 0;
- RFIFOSKIP(fd,6);
- break;
- // char rename request
- // R 08fc <char ID>.l <new name>.24B
- case 0x8fc:
- FIFOSD_CHECK(30);
- {
- int i, cid =RFIFOL(fd,2);
- char name[NAME_LENGTH];
- char esc_name[NAME_LENGTH*2+1];
- safestrncpy(name, (char *)RFIFOP(fd,6), NAME_LENGTH);
- RFIFOSKIP(fd,30);
-
- ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
- if( i == MAX_CHARS )
- break;
-
- normalize_name(name,TRIM_CHARS);
- Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
- if( !check_char_name(name,esc_name) ) {
- i = 1;
- safestrncpy(sd->new_name, name, NAME_LENGTH);
- } else
- i = 0;
-
- WFIFOHEAD(fd, 4);
- WFIFOW(fd,0) = 0x28e;
- WFIFOW(fd,2) = i;
- WFIFOSET(fd,4);
- }
- break;
-
- // char rename request
- // R 028d <account ID>.l <char ID>.l <new name>.24B
- case 0x28d:
- FIFOSD_CHECK(34);
- {
- int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6);
- char name[NAME_LENGTH];
- char esc_name[NAME_LENGTH*2+1];
- safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH);
- RFIFOSKIP(fd,34);
-
- if( aid != sd->account_id )
- break;
- ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
- if( i == MAX_CHARS )
- break;
-
- normalize_name(name,TRIM_CHARS);
- Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
- if( !check_char_name(name,esc_name) )
- {
- i = 1;
- safestrncpy(sd->new_name, name, NAME_LENGTH);
- }
- else
- i = 0;
-
- WFIFOHEAD(fd, 4);
- WFIFOW(fd,0) = 0x28e;
- WFIFOW(fd,2) = i;
- WFIFOSET(fd,4);
- }
- break;
- //Confirm change name.
- // 0x28f <char_id>.L
- case 0x28f:
- // 0: Sucessfull
- // 1: This character's name has already been changed. You cannot change a character's name more than once.
- // 2: User information is not correct.
- // 3: You have failed to change this character's name.
- // 4: Another user is using this character name, so please select another one.
- FIFOSD_CHECK(6);
- {
- int i;
- int cid = RFIFOL(fd,2);
- RFIFOSKIP(fd,6);
-
- ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
- if( i == MAX_CHARS )
- break;
- i = rename_char_sql(sd, cid);
-
- WFIFOHEAD(fd, 4);
- WFIFOW(fd,0) = 0x290;
- WFIFOW(fd,2) = i;
- WFIFOSET(fd,4);
- }
- break;
-
- // captcha code request (not implemented)
- // R 07e5 <?>.w <aid>.l
- case 0x7e5:
- WFIFOHEAD(fd,5);
- WFIFOW(fd,0) = 0x7e9;
- WFIFOW(fd,2) = 5;
- WFIFOB(fd,4) = 1;
- WFIFOSET(fd,5);
- RFIFOSKIP(fd,8);
- break;
-
- // captcha code check (not implemented)
- // R 07e7 <len>.w <aid>.l <code>.b10 <?>.b14
- case 0x7e7:
- WFIFOHEAD(fd,5);
- WFIFOW(fd,0) = 0x7e9;
- WFIFOW(fd,2) = 5;
- WFIFOB(fd,4) = 1;
- WFIFOSET(fd,5);
- RFIFOSKIP(fd,32);
- break;
-
+ case 0x187: char_parse_keepalive(fd); break;
+ // char rename
+ case 0x8fc: char_parse_reqrename(fd,sd,cmd); break; //request <date/version?>
+ case 0x28d: char_parse_reqrename(fd,sd,cmd); break; //request <date/version?>
+ case 0x28f: char_parse_ackrename(fd,sd); break; //Confirm change name.
+ // captcha
+ case 0x7e5: char_parse_reqcaptcha(fd); break; // captcha code request (not implemented)
+ case 0x7e7: char_parse_chkcaptcha(fd); break; // captcha code check (not implemented)
// deletion timer request
- case 0x827:
- FIFOSD_CHECK(6);
- char_delete2_req(fd, sd);
- RFIFOSKIP(fd,6);
- break;
-
+ case 0x827: char_delete2_req(fd, sd); break;
// deletion accept request
- case 0x829:
- FIFOSD_CHECK(12);
- char_delete2_accept(fd, sd);
- RFIFOSKIP(fd,12);
- break;
-
+ case 0x829: char_delete2_accept(fd, sd); break;
// deletion cancel request
- case 0x82b:
- FIFOSD_CHECK(6);
- char_delete2_cancel(fd, sd);
- RFIFOSKIP(fd,6);
- break;
-
+ case 0x82b: char_delete2_cancel(fd, sd); break;
// login as map-server
- case 0x2af8:
- if (RFIFOREST(fd) < 60)
- return 0;
- else {
- char* l_user = (char*)RFIFOP(fd,2);
- char* l_pass = (char*)RFIFOP(fd,26);
- l_user[23] = '\0';
- l_pass[23] = '\0';
- ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 );
- if( runflag != CHARSERVER_ST_RUNNING ||
- i == ARRAYLENGTH(server) ||
- strcmp(l_user, userid) != 0 ||
- strcmp(l_pass, passwd) != 0 )
- {
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x2af9;
- WFIFOB(fd,2) = 3;
- WFIFOSET(fd,3);
- } else {
- WFIFOHEAD(fd,3);
- WFIFOW(fd,0) = 0x2af9;
- WFIFOB(fd,2) = 0;
- WFIFOSET(fd,3);
-
- server[i].fd = fd;
- server[i].ip = ntohl(RFIFOL(fd,54));
- server[i].port = ntohs(RFIFOW(fd,58));
- server[i].users = 0;
- memset(server[i].map, 0, sizeof(server[i].map));
- session[fd]->func_parse = parse_frommap;
- session[fd]->flag.server = 1;
- realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
- char_mapif_init(fd);
- }
- RFIFOSKIP(fd,60);
- }
- return 0; // avoid processing of followup packets here
-
- // checks the entered pin
- case 0x8b8:
- if( RFIFOREST(fd) < 10 )
- return 0;
- if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
- pincode_check( fd, sd );
- RFIFOSKIP(fd,10);
- break;
-
- // request for PIN window
- case 0x8c5:
- if( RFIFOREST(fd) < 6 )
- return 0;
- if( pincode_enabled && RFIFOL(fd,2) == sd->account_id ){
- if( strlen( sd->pincode ) <= 0 ){
- pincode_sendstate( fd, sd, PINCODE_NEW );
- }else{
- pincode_sendstate( fd, sd, PINCODE_ASK );
- }
- }
- RFIFOSKIP(fd,6);
- break;
-
- // pincode change request
- case 0x8be:
- if( RFIFOREST(fd) < 14 )
- return 0;
-
- if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
- pincode_change( fd, sd );
-
- RFIFOSKIP(fd,14);
- break;
-
- // activate PIN system and set first PIN
- case 0x8ba:
- if( RFIFOREST(fd) < 10 )
- return 0;
- if( pincode_enabled && RFIFOL(fd,2) == sd->account_id )
- pincode_setnew( fd, sd );
- RFIFOSKIP(fd,10);
- break;
-
+ case 0x2af8: char_parse_maplogin(fd); return 0; // avoid processing of followup packets here
+ //pincode
+ case 0x8b8: pincode_check( fd, sd ); break; // checks the entered pin
+ case 0x8c5: char_parse_reqpincode_window(fd,sd); break; // request for PIN window
+ case 0x8be: pincode_change( fd, sd ); break; // pincode change request
+ case 0x8ba: pincode_setnew( fd, sd ); break; // activate PIN system and set first PIN
// character movement request
- case 0x8d4:
- if( RFIFOREST(fd) < 8 )
- return 0;
+ case 0x8d4: moveCharSlot(fd,sd); break;
- moveCharSlot( fd, sd, RFIFOW(fd, 2), RFIFOW(fd, 4) );
- mmo_char_send(fd, sd);
- RFIFOSKIP(fd,8);
- break;
-
case 0x9a1:
if( RFIFOREST(fd) < 2 )
return 0;
@@ -4598,18 +4561,37 @@
//------------------------------------------------
//Pincode system
//------------------------------------------------
-void pincode_check( int fd, struct char_session_data* sd ){
+int char_parse_reqpincode_window(int fd, struct char_session_data* sd){
+ if( RFIFOREST(fd) < 6 )
+ return 0;
+ if( pincode_enabled && RFIFOL(fd,2) == sd->account_id ){
+ if( strlen( sd->pincode ) <= 0 ){
+ pincode_sendstate( fd, sd, PINCODE_NEW );
+ }else{
+ pincode_sendstate( fd, sd, PINCODE_ASK );
+ }
+ }
+ RFIFOSKIP(fd,6);
+ return 1;
+}
+
+int pincode_check( int fd, struct char_session_data* sd ){
char pin[PINCODE_LENGTH+1];
+ if( RFIFOREST(fd) < 10 )
+ return 0;
+ if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
+ return 0;
+
memset(pin,0,PINCODE_LENGTH+1);
-
strncpy((char*)pin, (char*)RFIFOP(fd, 6), PINCODE_LENGTH);
+ RFIFOSKIP(fd,10);
pincode_decrypt(sd->pincode_seed, pin );
-
if( pincode_compare( fd, sd, pin ) ){
pincode_sendstate( fd, sd, PINCODE_PASSED );
}
+ return 1;
}
int pincode_compare( int fd, struct char_session_data* sd, char* pin ){
@@ -4627,34 +4609,46 @@
}
}
-void pincode_change( int fd, struct char_session_data* sd ){
+int pincode_change( int fd, struct char_session_data* sd ){
char oldpin[PINCODE_LENGTH+1];
char newpin[PINCODE_LENGTH+1];
+ if( RFIFOREST(fd) < 14 )
+ return 0;
+ if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
+ return 0;
+
memset(oldpin,0,PINCODE_LENGTH+1);
memset(newpin,0,PINCODE_LENGTH+1);
+ strncpy(oldpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH);
+ strncpy(newpin, (char*)RFIFOP(fd,10), PINCODE_LENGTH);
+ RFIFOSKIP(fd,14);
- strncpy(oldpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH);
pincode_decrypt(sd->pincode_seed,oldpin);
-
if( !pincode_compare( fd, sd, oldpin ) )
- return;
-
- strncpy(newpin, (char*)RFIFOP(fd,10), PINCODE_LENGTH);
+ return 0;
pincode_decrypt(sd->pincode_seed,newpin);
pincode_notifyLoginPinUpdate( sd->account_id, newpin );
strncpy(sd->pincode, newpin, sizeof(newpin));
pincode_sendstate( fd, sd, PINCODE_PASSED );
+ return 1;
}
-void pincode_setnew( int fd, struct char_session_data* sd ){
+int pincode_setnew( int fd, struct char_session_data* sd ){
char newpin[PINCODE_LENGTH+1];
memset(newpin,0,PINCODE_LENGTH+1);
+ if( RFIFOREST(fd) < 10 )
+ return 0;
+
+ if( pincode_enabled==0 || RFIFOL(fd,2) != sd->account_id )
+ return 0;
strncpy( newpin, (char*)RFIFOP(fd,6), PINCODE_LENGTH );
+ RFIFOSKIP(fd,10);
+
pincode_decrypt( sd->pincode_seed, newpin );
pincode_notifyLoginPinUpdate( sd->account_id, newpin );
@@ -4724,17 +4718,26 @@
//------------------------------------------------
//Add On system
//------------------------------------------------
-void moveCharSlot( int fd, struct char_session_data* sd, unsigned short from, unsigned short to ){
+int moveCharSlot( int fd, struct char_session_data* sd){
+ uint16 from, to;
+
+ if( RFIFOREST(fd) < 8 )
+ return 0;
+ from = RFIFOW(fd,2);
+ to = RFIFOW(fd,4);
+ //Cnt = RFIFOW(fd,6); //how many time we have left to change (client.. lol we don't trust him)
+ RFIFOSKIP(fd,8);
+
// Have we changed to often or is it disabled?
if( !char_move_enabled || ( !char_moves_unlimited && sd->char_moves[from] <= 0 ) ){
moveCharSlotReply( fd, sd, from, 1 );
- return;
+ return 0;
}
// We dont even have a character on the chosen slot?
if( sd->found_char[from] <= 0 ){
moveCharSlotReply( fd, sd, from, 1 );
- return;
+ return 0;
}
if( sd->found_char[to] > 0 ){
@@ -4749,7 +4752,7 @@
moveCharSlotReply( fd, sd, from, 1 );
Sql_ShowDebug(sql_handle);
Sql_QueryStr(sql_handle,"ROLLBACK");
- return;
+ return 0;
}
}else{
// Admin doesnt allow us to
@@ -4759,7 +4762,7 @@
}else if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_num`='%d' WHERE `char_id`='%d'", char_db, to, sd->found_char[from] ) ){
Sql_ShowDebug(sql_handle);
moveCharSlotReply( fd, sd, from, 1 );
- return;
+ return 0;
}
if( !char_moves_unlimited ){
@@ -4770,6 +4773,7 @@
// We successfully moved the char - time to notify the client
moveCharSlotReply( fd, sd, from, 0 );
mmo_char_send(fd, sd);
+ return 1;
}
// reason
Index: src/common/socket.c
===================================================================
--- src/common/socket.c (revision 17365)
+++ src/common/socket.c (working copy)
@@ -637,7 +637,7 @@
/// advance the RFIFO cursor (marking 'len' bytes as processed)
int RFIFOSKIP(int fd, size_t len)
{
- struct socket_data *s;
+ struct socket_data *s;
if ( !session_isActive(fd) )
return 0;
Index: db/packet_db.txt
===================================================================
--- db/packet_db.txt (revision 17365)
+++ db/packet_db.txt (working copy)
@@ -1416,7 +1416,7 @@
//2009-08-18aRagexeRE
0x07e3,6
-0x07e4,-1,itemlistwindowselected,2:4:8
+0x07e4,-1,itemlistwindowselected,2:4:8:12
0x07e6,8
//2009-08-25aRagexeRE
@@ -1612,7 +1612,7 @@
//2010-11-24aRagexeRE
packet_ver: 26
-0x0288,-1,cashshopbuy,2:4:8:10
+0x0288,-1,cashshopbuy,2:4:6:10
0x0436,19,wanttoconnection,2:6:10:14:18
0x035f,5,walktoxy,2
0x0360,6,ticksend,2
@@ -1658,7 +1658,7 @@
0x083c,19,wanttoconnection,2:6:10:14:18
0x08aa,7,actionrequest,2:6
0x02c4,10,useskilltoid,2:4:6
-0x0811,-1,itemlistwindowselected,2:4:8
+0x0811,-1,itemlistwindowselected,2:4:8:12
0x890,8
0x08a5,18,bookingregreq,2:4:6
0x0835,-1,reqopenbuyingstore,2:4:8:9:89
@@ -1689,7 +1689,7 @@
0x0929,26,partyinvite2,2
0x0885,7,actionrequest,2:6
0x0889,10,useskilltoid,2:4:6
-0x0870,-1,itemlistwindowselected,2:4:8
+0x0870,-1,itemlistwindowselected,2:4:8:12
//0x0926,18,bookingregreq,2:4:6
0x0815,-1,reqopenbuyingstore,2:4:8:9:89
0x0817,2,reqclosebuyingstore,0
@@ -1707,13 +1707,13 @@
0x089c,26,friendslistadd,2
0x0885,5,hommenu,2:4
0x0961,36,storagepassword,2:4:20
-0x0288,-1,cashshopbuy,2:4:8:10
+0x0288,-1,cashshopbuy,2:4:6:10
0x091c,26,partyinvite2,2
0x094b,19,wanttoconnection,2:6:10:14:18
0x0369,7,actionrequest,2:6
0x083c,10,useskilltoid,2:4:6
0x0439,8,useitem,2:4
-0x0945,-1,itemlistwindowselected,2:4:8
+0x0945,-1,itemlistwindowselected,2:4:8:12
0x0815,-1,reqopenbuyingstore,2:4:8:9:89
0x0817,2,reqclosebuyingstore,0
0x0360,6,reqclickbuyingstore,2
@@ -1769,7 +1769,7 @@
0x08A8,36,storagepassword,2:4:20
0x0802,26,partyinvite2,2
0x022D,19,wanttoconnection,2:6:10:14:18
-0x0281,-1,itemlistwindowselected,2:4:8
+0x0281,-1,itemlistwindowselected,2:4:8:12
0x035F,6,ticksend,2
0x0202,5,changedir,2:4
0x07E4,6,takeitem,2
@@ -1808,7 +1808,7 @@
packet_ver: 34
0x014f,6,guildrequestinfo,2
0x01fd,15,repairitem,2:4:6:7:9:11:13
-//0x0281,-1,itemlistwindowselected,2:4:8
+//0x0281,-1,itemlistwindowselected,2:4:8:12
0x035f,6,reqclickbuyingstore,2
0x0363,6,ticksend,2
0x0365,12,searchstoreinfolistitemclick,2:6:10
@@ -1821,7 +1821,7 @@
0x084b,19 //fallitem4
0x085a,90,useskilltoposinfo,2:4:6:8:10
0x085d,18,bookingregreq,2:4:6
-0x0868,-1,itemlistwindowselected,2:4:8
+0x0868,-1,itemlistwindowselected,2:4:8:12
0x086d,26,partyinvite2,2
0x086f,26,friendslistadd,2
0x0874,8,movefromkafra,2:4
@@ -1891,7 +1891,7 @@
0x0815,-1,reqopenbuyingstore,2:4:8:9:89
0x092D,18,bookingregreq,2:4:6
//0x08AA,8 CZ_JOIN_BATTLE_FIELD
-0x0963,-1,itemlistwindowselected,2:4:8
+0x0963,-1,itemlistwindowselected,2:4:8:12
0x0943,19,wanttoconnection,2:6:10:14:18
0x0947,26,partyinvite2,2
//0x0862,4 CZ_GANGSI_RANK
@@ -1923,7 +1923,7 @@
0x0874,-1,reqopenbuyingstore,2:4:8:9:89
0x089B,18,bookingregreq,2:4:6
//0x0965,8 CZ_JOIN_BATTLE_FIELD
-0x086A,-1,itemlistwindowselected,2:4:8
+0x086A,-1,itemlistwindowselected,2:4:8:12
0x08A9,19,wanttoconnection,2:6:10:14:18
0x0950,26,partyinvite2,2
//0x08AC,4 CZ_GANGSI_RANK
@@ -1955,7 +1955,7 @@
0x0869,-1,reqopenbuyingstore,2:4:8:9:89
0x0874,41,bookingregreq,2,4:6
// 0x088E,8); // CZ_JOIN_BATTLE_FIELD
-0x0958,-1,itemlistwindowselected,2:4:8
+0x0958,-1,itemlistwindowselected,2:4:8:12
0x0919,19,wanttoconnection,2:6:10:14:18
0x08A8,26,partyinvite2,2
// 0x0888,4); // CZ_GANGSI_RANK
@@ -1987,7 +1987,7 @@
0x0815,-1,reqopenbuyingstore,2:4:8:9:89
0x0365,41,bookingregreq,2:4:6
// 0x0363,8 // CZ_JOIN_BATTLE_FIELD
-0x0281,-1,itemlistwindowselected,2:4:8
+0x0281,-1,itemlistwindowselected,2:4:8:12
0x022D,19,wanttoconnection,2:6:10:14:18
0x0802,26,partyinvite2,2
// 0x0436,4 // CZ_GANGSI_RANK
@@ -2019,7 +2019,7 @@
0x0815,-1,reqopenbuyingstore,2:4:8:9:89
0x0365,18,bookingregreq,2:4:6
// 0x0363,8 CZ_JOIN_BATTLE_FIELD
-0x0281,-1,itemlistwindowselected,2:4:8
+0x0281,-1,itemlistwindowselected,2:4:8:12
0x0919,19,wanttoconnection,2:6:10:14:18
0x0802,26,partyinvite2,2
// 0x0436,4 CZ_GANGSI_RANK