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:
parent
9e2bf9e2e2
commit
cd8d185f8e
@ -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
|
||||
|
@ -417,6 +417,7 @@ BaseClass 120 1
|
||||
killerrid 121 1
|
||||
killedrid 122 1
|
||||
Sitting 123 1
|
||||
CharMoves 124 1
|
||||
|
||||
bMaxHP 6
|
||||
bMaxSP 8
|
||||
|
@ -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; },{},{}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
1
sql-files/upgrades/upgrade_svn17194.sql
Normal file
1
sql-files/upgrades/upgrade_svn17194.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE `char` ADD COLUMN `moves` int(11) unsigned NOT NULL DEFAULT '0';
|
125
src/char/char.c
125
src/char/char.c
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user