Another char-server related BETA release.

If you happen to find any errors feel free to report them, I tested it for some hours now and it should be working as intended.

"the packets used by this feature are still unknown to us", I guess not. :P

Thanks again Yommy and enjoy it Ind.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@17194 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
lemongrass3110 2013-03-12 23:05:36 +00:00
parent 9e2bf9e2e2
commit cd8d185f8e
10 changed files with 151 additions and 11 deletions

View File

@ -159,9 +159,12 @@ char_del_delay: 86400
// What folder the DB files are in (item_db.txt, etc.)
db_path: db
//===================================
// Pincode system
// A window is opened before you can select your character and you will have to enter a pincode by using only your mouse.
//===================================
// NOTE: Requires client 2011-03-09aragexeRE or newer.
// A window is opened before you can select your character and you will have to enter a pincode by using only your mouse.
// Default: yes
pincode_enabled: yes
// How often does a user have to change his pincode?
@ -177,4 +180,21 @@ pincode_maxtry: 3
// Default: yes
pincode_force: yes
//===================================
// Addon system
//===================================
// Character moving
// NOTE: Requires client 2011-09-28aragexeRE or newer.
// Allows users to move their characters between slots.
// Default: yes
char_move_enabled: yes
// Allow users to move a character to a used slot?
// If enabled the characters are exchanged.
// Default: yes
char_movetoused: no
// Allow users to move characters as often as they like?
char_moves_unlimited: no
import: conf/import/char_conf.txt

View File

@ -417,6 +417,7 @@ BaseClass 120 1
killerrid 121 1
killedrid 122 1
Sitting 123 1
CharMoves 124 1
bMaxHP 6
bMaxSP 8

View File

@ -5825,6 +5825,8 @@
//
12775,Ancient_Spirit_Amulet,Ancient Spirit Amulet,2,20,,600,,,,,0xFFFFFFFF,7,2,,,,,,{},{},{}
//
12786,Change_Slot_Card,Character Position Change Coupon,2,,,,,,,,0xFFFFFFFF,7,2,,,,,,{ set CharMoves, CharMoves + 1; },{},{}
//
12848,Falcon_Flute,Falcon Flute,11,0,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ if(getskilllv("HT_FALCON")) { if(checkoption(Option_Wug)||checkoption(Option_Wugrider)) end; if(checkfalcon()==1) { setfalcon 0; } else { setfalcon 1; } } },{},{}
12900,Battle_Manual_Box,Battle Manual Box,18,20,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ getitem 12208,10; },{},{}
12901,Insurance_Package,Insurance Package,18,20,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ getitem 12209,10; },{},{}

View File

@ -1919,6 +1919,7 @@
2826,65,100 // Dark Knight Belt
2827,65,100 // Dark Knight Glove
2843,507,100 // Gold Trickle
12786,459,100 // Character Position Change Coupon
13049,65,100 // Lacma
13052,499,100 // Tourist Dagger
13111,507,100 // Sharpshooter Revolver

View File

@ -5856,6 +5856,8 @@ REPLACE INTO `item_db_re` VALUES (12773,'Victory_Hat_Box2','Victory Hat Box2',2,
#
REPLACE INTO `item_db_re` VALUES (12775,'Ancient_Spirit_Amulet','Ancient Spirit Amulet',2,20,NULL,600,NULL,NULL,NULL,NULL,0xFFFFFFFF,7,2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
#
REPLACE INTO `item_db_re` VALUES (12786,'Change_Slot_Card','Character Position Change Coupon',2,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0xFFFFFFFF,7,2,NULL,NULL,NULL,NULL,NULL,'set CharMoves, CharMoves + 1;',NULL,NULL);
#
REPLACE INTO `item_db_re` VALUES (12848,'Falcon_Flute','Falcon Flute',11,NULL,NULL,10,NULL,NULL,NULL,NULL,0xFFFFFFFF,7,2,NULL,NULL,NULL,NULL,NULL,'if(getskilllv("HT_FALCON")) { if(checkoption(Option_Wug)||checkoption(Option_Wugrider)) end; if(checkfalcon()==1) { setfalcon 0; } else { setfalcon 1; } }',NULL,NULL);
REPLACE INTO `item_db_re` VALUES (12900,'Battle_Manual_Box','Battle Manual Box',18,20,NULL,10,NULL,NULL,NULL,NULL,0xFFFFFFFF,7,2,NULL,NULL,NULL,NULL,NULL,'getitem 12208,10;',NULL,NULL);
REPLACE INTO `item_db_re` VALUES (12901,'Insurance_Package','Insurance Package',18,20,NULL,10,NULL,NULL,NULL,NULL,0xFFFFFFFF,7,2,NULL,NULL,NULL,NULL,NULL,'getitem 12209,10;',NULL,NULL);

View File

@ -0,0 +1 @@
ALTER TABLE `char` ADD COLUMN `moves` int(11) unsigned NOT NULL DEFAULT '0';

View File

@ -131,10 +131,13 @@ struct char_session_data {
uint8 clienttype;
char new_name[NAME_LENGTH];
char birthdate[10+1]; // YYYY-MM-DD
// Pincode system
char pincode[4+1];
uint16 pincode_seed;
time_t pincode_change;
uint16 pincode_try;
// Addon system
unsigned int char_moves[MAX_CHARS]; // character moves left
};
int max_connect_user = -1;
@ -168,6 +171,14 @@ void pincode_notifyLoginPinError( int account_id );
void pincode_decrypt( unsigned long userSeed, char* pin );
int pincode_compare( int fd, struct char_session_data* sd, char* pin );
// Addon system
bool char_move_enabled = true;
bool char_movetoused = true;
bool char_moves_unlimited = false;
void moveCharSlot( int fd, struct char_session_data* sd, unsigned short from, unsigned short to );
void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason );
//Custom limits for the fame lists. [Skotlex]
int fame_list_size_chemist = MAX_FAME_LIST;
int fame_list_size_smith = MAX_FAME_LIST;
@ -502,7 +513,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
(p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) ||
(p->ele_id != cp->ele_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) ||
(p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) ||
(p->rename != cp->rename) || (p->robe != cp->robe)
(p->rename != cp->rename) || (p->robe != cp->robe) || (p->character_moves != cp->character_moves)
)
{ //Save status
if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d',"
@ -512,7 +523,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
"`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%d',"
"`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d',"
"`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d',"
"`delete_date`='%lu',`robe`='%d'"
"`delete_date`='%lu',`robe`='%d',`moves`='%d'"
" WHERE `account_id`='%d' AND `char_id` = '%d'",
char_db, p->base_level, p->job_level,
p->base_exp, p->job_exp, p->zeny,
@ -523,7 +534,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y,
mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename,
(unsigned long)p->delete_date, // FIXME: platform-dependent size
p->robe,
p->robe,p->character_moves,
p->account_id, p->char_id) )
{
Sql_ShowDebug(sql_handle);
@ -1046,7 +1057,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf)
"`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`,"
"`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`,"
"`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`,"
"`robe`"
"`robe`,`moves`"
" FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS)
|| SQL_ERROR == SqlStmt_Execute(stmt)
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL)
@ -1085,20 +1096,29 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf)
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p.rename, 0, NULL, NULL)
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL)
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL)
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_UINT, &p.character_moves, 0, NULL, NULL)
)
{
SqlStmt_ShowDebug(stmt);
SqlStmt_Free(stmt);
return 0;
}
for( i = 0; i < MAX_CHARS; i++ ){
sd->found_char[i] = -1;
sd->char_moves[i] = 0;
}
for( i = 0; i < MAX_CHARS && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++ )
{
p.last_point.map = mapindex_name2id(last_map);
sd->found_char[i] = p.char_id;
sd->found_char[p.slot] = p.char_id;
j += mmo_char_tobuf(WBUFP(buf, j), &p);
// Addon System
// store the required info into the session
sd->char_moves[p.slot] = p.character_moves;
}
for( ; i < MAX_CHARS; i++ )
sd->found_char[i] = -1;
memset(sd->new_name,0,sizeof(sd->new_name));
@ -1143,7 +1163,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
"`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`,"
"`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`,"
"`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`,"
"`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`"
"`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`, `moves`"
" FROM `%s` WHERE `char_id`=? LIMIT 1", char_db)
|| SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
|| SQL_ERROR == SqlStmt_Execute(stmt)
@ -1199,6 +1219,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_SHORT, &p->rename, 0, NULL, NULL)
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL)
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 51, SQLDT_SHORT, &p->robe, 0, NULL, NULL)
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 52, SQLDT_UINT32, &p->character_moves, 0, NULL, NULL)
)
{
SqlStmt_ShowDebug(stmt);
@ -1866,7 +1887,13 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
#endif
#if PACKETVER != 20111116 //2011-11-16 wants 136, ask gravity.
#if PACKETVER >= 20110928
WBUFL(buf,132) = 0; // change slot feature (0 = disabled, otherwise enabled)
// 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
@ -3401,7 +3428,6 @@ int parse_frommap(int fd)
}
break;
default:
{
// inter server - packet
@ -4302,6 +4328,16 @@ int parse_char(int fd)
RFIFOSKIP(fd,10);
break;
// character movement request
case 0x8d4:
if( RFIFOREST(fd) < 8 )
return 0;
moveCharSlot( fd, sd, RFIFOW(fd, 2), RFIFOW(fd, 4) );
RFIFOSKIP(fd,8);
break;
// unknown packet received
default:
ShowError("parse_char: Received unknown packet "CL_WHITE"0x%x"CL_RESET" from ip '"CL_WHITE"%s"CL_RESET"'! Disconnecting!\n", RFIFOW(fd,0), ip2str(ipl, NULL));
@ -4596,6 +4632,69 @@ void pincode_decrypt( unsigned long userSeed, char* pin ){
sprintf(pin, "%d%d%d%d", pin[0], pin[1], pin[2], pin[3]);
}
//------------------------------------------------
//Add On system
//------------------------------------------------
void moveCharSlot( int fd, struct char_session_data* sd, unsigned short from, unsigned short to ){
// 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;
}
// We dont even have a character on the chosen slot?
if( sd->found_char[from] <= 0 ){
moveCharSlotReply( fd, sd, from, 1 );
return;
}
if( sd->found_char[to] > 0 ){
// We want to move to a used position
if( char_movetoused ){ // TODO: check if the target is in deletion process
// Admin is friendly and uses triangle exchange
if( SQL_ERROR == Sql_QueryStr(sql_handle, "START TRANSACTION")
|| SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_num`='%d' WHERE `char_id` = '%d'", char_db, to, sd->found_char[from] )
|| SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `char_num`='%d' WHERE `char_id` = '%d'", char_db, from, sd->found_char[to] )
|| SQL_ERROR == Sql_QueryStr(sql_handle, "COMMIT")
){
moveCharSlotReply( fd, sd, from, 1 );
Sql_ShowDebug(sql_handle);
Sql_QueryStr(sql_handle,"ROLLBACK");
return;
}
}else{
// Admin doesnt allow us to
moveCharSlotReply( fd, sd, from, 1 );
return;
}
}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;
}
if( !char_moves_unlimited ){
sd->char_moves[from]--;
Sql_Query(sql_handle, "UPDATE `%s` SET `moves`='%d' WHERE `char_id`='%d'", char_db, sd->char_moves[from], sd->found_char[from] );
}
// We successfully moved the char - time to notify the client
moveCharSlotReply( fd, sd, from, 0 );
mmo_char_send006b( fd, sd );
}
// reason
// 0: success
// 1: failed
void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short index, short reason ){
WFIFOHEAD(fd,8);
WFIFOW(fd,0) = 0x8d5;
WFIFOW(fd,2) = 8;
WFIFOW(fd,4) = reason;
WFIFOW(fd,6) = sd->char_moves[index];
WFIFOSET(fd,8);
}
//------------------------------------------------
//Invoked 15 seconds after mapif_disconnectplayer in case the map server doesn't
//replies/disconnect the player we tried to kick. [Skotlex]
@ -4927,6 +5026,12 @@ int char_config_read(const char* cfgName)
pincode_maxtry = atoi(w2);
} else if (strcmpi(w1, "pincode_force") == 0) {
pincode_force = config_switch(w2);
} else if (strcmpi(w1, "char_move_enabled") == 0) {
char_move_enabled = config_switch(w2);
} else if (strcmpi(w1, "char_movetoused") == 0) {
char_movetoused = config_switch(w2);
} else if (strcmpi(w1, "char_moves_unlimited") == 0) {
char_moves_unlimited = config_switch(w2);
} else if (strcmpi(w1, "import") == 0) {
char_config_read(w2);
}

View File

@ -382,6 +382,9 @@ struct mmo_charstatus {
short rename;
time_t delete_date;
// Char server addon system
unsigned int character_moves;
};
typedef enum mail_status {

View File

@ -369,6 +369,7 @@ enum _sp {
SP_KILLERRID=121,
SP_KILLEDRID=122,
SP_SITTING=123,
SP_CHARMOVE=124,
// Mercenaries
SP_MERCFLEE=165, SP_MERCKILLS=189, SP_MERCFAITH=190,

View File

@ -6916,6 +6916,7 @@ int pc_readparam(struct map_session_data* sd,int type)
case SP_KILLERRID: val = sd->killerrid; break;
case SP_KILLEDRID: val = sd->killedrid; break;
case SP_SITTING: val = pc_issit(sd)?1:0; break;
case SP_CHARMOVE: val = sd->status.character_moves; break;
case SP_CRITICAL: val = sd->battle_status.cri/10; break;
case SP_ASPD: val = (2000-sd->battle_status.amotion)/10; break;
case SP_BASE_ATK: val = sd->battle_status.batk; break;
@ -7156,6 +7157,9 @@ int pc_setparam(struct map_session_data *sd,int type,int val)
case SP_KILLEDRID:
sd->killedrid = val;
return 1;
case SP_CHARMOVE:
sd->status.character_moves = val;
return 1;
default:
ShowError("pc_setparam: Attempted to set unknown parameter '%d'.\n", type);
return 0;