Thanks! I found the problem.
char.c
int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
{
unsigned short offset = 0;
uint8* buf;
if( buffer == NULL || p == NULL )
return 0;
buf = WBUFP(buffer,0);
WBUFL(buf,0) = p->char_id;
WBUFL(buf,4) = min(p->base_exp, INT32_MAX);
WBUFL(buf,8) = p->zeny;
WBUFL(buf,12) = min(p->job_exp, INT32_MAX);
WBUFL(buf,16) = p->job_level;
WBUFL(buf,20) = 0; // probably opt1
WBUFL(buf,24) = 0; // probably opt2
WBUFL(buf,28) = p->option;
WBUFL(buf,32) = p->karma;
WBUFL(buf,36) = p->manner;
WBUFW(buf,40) = min(p->status_point, INT16_MAX);
WBUFL(buf,42) = p->hp;
WBUFL(buf,46) = p->max_hp;
offset+=4;
buf = WBUFP(buffer,offset);
WBUFW(buf,46) = min(p->sp, INT16_MAX);
WBUFW(buf,48) = min(p->max_sp, INT16_MAX);
WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed;
WBUFW(buf,52) = p->class_;
WBUFW(buf,54) = p->hair;
//When the weapon is sent and your option is riding, the client crashes on login!?
WBUFW(buf,56) = p->option&(0x20|0x80000|0x100000|0x200000|0x400000|0x800000|0x1000000|0x2000000|0x4000000|0x8000000) ? 0 : p->weapon;
WBUFW(buf,58) = p->base_level;
WBUFW(buf,60) = min(p->skill_point, INT16_MAX);
WBUFW(buf,62) = p->head_bottom;
WBUFW(buf,64) = p->shield;
WBUFW(buf,66) = p->head_top;
WBUFW(buf,68) = p->head_mid;
WBUFW(buf,70) = p->hair_color;
WBUFW(buf,72) = p->clothes_color;
memcpy(WBUFP(buf,74), p->name, NAME_LENGTH);
WBUFB(buf,98) = min(p->str, UINT8_MAX);
WBUFB(buf,99) = min(p->agi, UINT8_MAX);
WBUFB(buf,100) = min(p->vit, UINT8_MAX);
WBUFB(buf,101) = min(p->int_, UINT8_MAX);
WBUFB(buf,102) = min(p->dex, UINT8_MAX);
WBUFB(buf,103) = min(p->luk, UINT8_MAX);
WBUFW(buf,104) = p->slot;
WBUFW(buf,106) = ( p->rename > 0 ) ? 0 : 1;
// Commenting out that one line of code allows the character to show up on the character select screen.
// offset += 2;
#if (PACKETVER >= 20100720 && PACKETVER <= 20100727) || PACKETVER >= 20100803
mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char*)WBUFP(buf,108));
offset += MAP_NAME_LENGTH_EXT;
#endif
#if PACKETVER >= 20100803
WBUFL(buf,124) = TOL(p->delete_date);
offset += 4;
#endif
#if PACKETVER >= 20110111
WBUFL(buf,128) = p->robe;
offset += 4;
#endif
#if PACKETVER != 20111116 //2011-11-16 wants 136, ask gravity.
#if PACKETVER >= 20110928
// change slot feature (0 = disabled, otherwise enabled)
if( !char_move_enabled )
WBUFL(buf,132) = 0;
else if( char_moves_unlimited )
WBUFL(buf,132) = 1;
else
WBUFL(buf,132) = max( 0, (int)p->character_moves );
offset += 4;
#endif
#if PACKETVER >= 20111025
WBUFL(buf,136) = ( p->rename > 0 ) ? 1 : 0; // (0 = disabled, otherwise displays "Add-Ons" sidebar)
offset += 4;
#endif
#endif
return 106+offset;
}
Meanwhile, I ran into a new issue.
When I try to select a character to enter the game, I immediately get the message: "This character has been frozen", and I can't get in.
Later on, I found the function int parse_char(int fd) in char.c, which handles incoming packets from the client.
When logging in, it receives packet 0x65
When creating a character, it gets 0x67
When selecting a character, it’s supposed to receive 0x66
But in my case, that packet (0x66) never gets triggered—parse_char doesn’t even fire at all.
Also, I searched through the server code and couldn’t find the message "This character has been frozen" anywhere, which makes me think the client itself might be blocking the login on its own. But why?
As far as I can tell, the character data looks totally normal. The character’s location is set to prontera,150,150, and data.grf definitely includes the required files: prontera.gat, prontera.gnd, and prontera.rsw.
So now I’m wondering—what else could be going wrong here?