Skip to content
Permalink
Browse files
* Follow up to: 99098c1
-- 'bonus_script' is now by default will be store on 'bonus_script' table. CAUTION: Please import 'upgrade_20131111.sql' file or execute the query inside to make `bonus_script` table.
-- Updated bonus_script documentation following flag &8 (BONUS_FLAG_REM_ON_LOGOUT) behavior. By default, bonus_script will be stored when player logs out and will be continued when player logs in.

* And small changes.
  • Loading branch information
cydh committed Nov 11, 2013
1 parent 4d61cc0 commit 9e8e3cfaccf05b0714619ac9739c3e616a86c980
Showing with 282 additions and 46 deletions.
  1. +1 −0 conf/inter_athena.conf
  2. +10 −9 doc/script_commands.txt
  3. +12 −0 sql-files/main.sql
  4. +11 −0 sql-files/upgrades/upgrade_20131111.sql
  5. +103 −1 src/char/char.c
  6. +2 −0 src/char/char.h
  7. +7 −0 src/common/mmo.h
  8. +113 −2 src/map/chrif.c
  9. +4 −0 src/map/chrif.h
  10. +0 −2 src/map/clif.c
  11. +6 −18 src/map/pc.c
  12. +2 −3 src/map/pc.h
  13. +1 −1 src/map/script.c
  14. +2 −2 src/map/skill.c
  15. +8 −8 src/map/status.h
@@ -104,6 +104,7 @@ mercenary_owner_db: mercenary_owner
elemental_db: elemental
ragsrvinfo_db: ragsrvinfo
skillcooldown_db: skillcooldown
bonus_script_db: bonus_script

// Map Database Tables
item_db_db: item_db
@@ -5063,24 +5063,25 @@ autobonus and autobonus3).

This command will attach a script to a player for a given duration, in seconds.
After that time, the script will automatically expire. The same bonus cannot be
stacked.
stacked. By default, this bonus will be stored on `bonus_script` table when player
logs out.

Note that the maximum number of 'bonus_script' commands that can run simultaneously
for a player is 10 (MAX_PC_BONUS_SCRIPT in 'src/map/pc.h').

Flags:
&1: Remove when dead.
&2: Removable by Dispell.
&4: Removable by Clearance.
&8: Save script when player logs out and resume next login. [TODO]
&1: Remove when dead.
&2: Removable by Dispell.
&4: Removable by Clearance.
&8: Remove when player logs out.

Types:
0: Buff
1: Debuff
0: Buff
1: Debuff

Example:
// Apple gives you +5 Str bonus for 1 minute when it's consumed.
512,Apple,Apple,0,15,,20,,,,,0xFFFFFFFF,63,2,,,,,,{ bonus_script "{ bonus bStr,5; }",60; },{},{}
// Apple gives you +5 Str bonus for 1 minute when it's consumed.
512,Apple,Apple,0,15,,20,,,,,0xFFFFFFFF,63,2,,,,,,{ bonus_script "{ bonus bStr,5; }",60; },{},{}

---------------------------------------

@@ -696,3 +696,15 @@ CREATE TABLE IF NOT EXISTS `interreg` (
) ENGINE=InnoDB;
INSERT INTO `interreg` (`varname`, `value`) VALUES
('unique_id', '0');

--
-- Table structure for table `bonus_script`
--

CREATE TABLE IF NOT EXISTS `bonus_script` (
`char_id` int(11) NOT NULL,
`script` varchar(1024) NOT NULL,
`tick` int(11) NOT NULL,
`flag` tinyint(3) unsigned NOT NULL DEFAULT '0',
`type` tinyint(1) unsigned NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
@@ -0,0 +1,11 @@
--
-- Table structure for table `bonus_script`
--

CREATE TABLE IF NOT EXISTS `bonus_script` (
`char_id` int(11) NOT NULL,
`script` varchar(1024) NOT NULL,
`tick` int(11) NOT NULL,
`flag` tinyint(3) unsigned NOT NULL DEFAULT '0',
`type` tinyint(1) unsigned NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
@@ -69,6 +69,7 @@ char mercenary_db[256] = "mercenary";
char mercenary_owner_db[256] = "mercenary_owner";
char elemental_db[256] = "elemental";
char ragsrvinfo_db[256] = "ragsrvinfo";
char bonus_script_db[256] = "bonus_script";

// show loading/saving messages
int save_log = 1;
@@ -206,6 +207,10 @@ struct fame_list smith_fame_list[MAX_FAME_LIST];
struct fame_list chemist_fame_list[MAX_FAME_LIST];
struct fame_list taekwon_fame_list[MAX_FAME_LIST];

//Bonus Script
void bonus_script_get(int fd);///Get bonus_script data
void bonus_script_save(int fd); ///Save bonus_script data

// check for exit signal
// 0 is saving complete
// other is char_id
@@ -1807,6 +1812,10 @@ int delete_char_sql(int char_id)
Sql_ShowDebug(sql_handle);
#endif

/* bonus_scripts */
if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", bonus_script_db, char_id) )
Sql_ShowDebug(sql_handle);

if (log_char) {
if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`char_msg`,`name`) VALUES (NOW(), '%d', '%d', 'Deleted char (CID %d)', '%s')",
charlog_db, account_id, 0, char_id, esc_name) )
@@ -3671,7 +3680,19 @@ int parse_frommap(int fd)
break;

case 0x2b28: mapif_parse_UpdBankInfo(fd); break;
case 0x2b2a: mapif_parse_ReqBankInfo(fd); break;
case 0x2b2a: mapif_parse_ReqBankInfo(fd); break;

case 0x2b2d: //Load data
if (RFIFOREST(fd) < 6)
return 0;
bonus_script_get(fd);
break;

case 0x2b2e: //Save data
if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
return 0;
bonus_script_save(fd);
break;

default:
{
@@ -4975,6 +4996,83 @@ void moveCharSlotReply( int fd, struct char_session_data* sd, unsigned short ind
WFIFOSET(fd,8);
}

/** [Cydh]
* Get bonus_script data(s) from table to load
* @param fd
*/
void bonus_script_get(int fd) {
int cid;
cid = RFIFOL(fd,2);

if (SQL_ERROR == Sql_Query(sql_handle,"SELECT `script`, `tick`, `flag`, `type` FROM `%s` WHERE `char_id`='%d'",
bonus_script_db,cid))
{
Sql_ShowDebug(sql_handle);
return;
}
if (Sql_NumRows(sql_handle) > 0) {
struct bonus_script_data bsdata;
int count;
char *data;

WFIFOHEAD(fd,10+50*sizeof(struct bonus_script_data));
WFIFOW(fd,0) = 0x2b2f;
WFIFOL(fd,4) = cid;
for (count = 0; count < 20 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count) {
Sql_GetData(sql_handle,0,&data,NULL); memcpy(bsdata.script,data,strlen(data)+1);
Sql_GetData(sql_handle,1,&data,NULL); bsdata.tick = atoi(data);
Sql_GetData(sql_handle,2,&data,NULL); bsdata.flag = atoi(data);
Sql_GetData(sql_handle,3,&data,NULL); bsdata.type = atoi(data);
memcpy(WFIFOP(fd,10+count*sizeof(struct bonus_script_data)),&bsdata,sizeof(struct bonus_script_data));
}
if (count >= 50)
ShowWarning("Too many bonus_script for %d, some of them were not loaded.\n",cid);
if (count > 0) {
WFIFOW(fd,2) = 10 + count*sizeof(struct bonus_script_data);
WFIFOW(fd,8) = count;
WFIFOSET(fd,WFIFOW(fd,2));

//Clear the data once loaded.
if (SQL_ERROR == Sql_Query(sql_handle,"DELETE FROM `%s` WHERE `char_id`='%d'",bonus_script_db,cid))
Sql_ShowDebug(sql_handle);
}
}
Sql_FreeResult(sql_handle);
RFIFOSKIP(fd,6);
}

/** [Cydh]
* Svae bonus_script data(s) to the table

This comment has been minimized.

Copy link
@imblad3

imblad3 Nov 12, 2013

Typo here. "Save"

This comment has been minimized.

Copy link
@cydh

cydh Nov 12, 2013

Author Contributor

lol. u got me. thx. :D

* @param fd
*/
void bonus_script_save(int fd) {
int count, cid;

cid = RFIFOL(fd,4);
count = RFIFOW(fd,8);

if (count > 0) {
struct bonus_script_data bs;
StringBuf buf;
int i;
char esc_script[MAX_BONUS_SCRIPT_LENGTH] = "";

StringBuf_Init(&buf);
StringBuf_Printf(&buf,"INSERT INTO `%s` (`char_id`, `script`, `tick`, `flag`, `type`) VALUES ",bonus_script_db);
for (i = 0; i < count; ++i) {
memcpy(&bs,RFIFOP(fd,10+i*sizeof(struct bonus_script_data)),sizeof(struct bonus_script_data));
Sql_EscapeString(sql_handle,esc_script,bs.script);
if (i > 0)
StringBuf_AppendStr(&buf,", ");
StringBuf_Printf(&buf,"(%d,'%s',%d,%d,%d)",cid,esc_script,bs.tick,bs.flag,bs.type);
}
if (SQL_ERROR == Sql_QueryStr(sql_handle,StringBuf_Value(&buf)))
Sql_ShowDebug(sql_handle);
StringBuf_Destroy(&buf);
}
RFIFOSKIP(fd,RFIFOW(fd,2));
}

//------------------------------------------------
//Invoked 15 seconds after mapif_disconnectplayer in case the map server doesn't
//replies/disconnect the player we tried to kick. [Skotlex]
@@ -5143,6 +5241,10 @@ void sql_config_read(const char* cfgName)
safestrncpy(mercenary_owner_db,w2,sizeof(mercenary_owner_db));
else if(!strcmpi(w1,"elemental_db"))
safestrncpy(elemental_db,w2,sizeof(elemental_db));
else if(!strcmpi(w1,"skillcooldown_db"))
safestrncpy(skillcooldown_db, w2, sizeof(skillcooldown_db));
else if(!strcmpi(w1,"bonus_script_db"))
safestrncpy(bonus_script_db, w2, sizeof(bonus_script_db));
//support the import command, just like any other config
else if(!strcmpi(w1,"import"))
sql_config_read(w2);
@@ -83,6 +83,8 @@ extern char mercenary_db[256];
extern char mercenary_owner_db[256];
extern char elemental_db[256];
extern char ragsrvinfo_db[256];
extern char bonus_script_db[256];
extern char skillcooldown_db[256];

extern int db_use_sqldbs; // added for sql item_db read for char server [Valaris]

@@ -249,6 +249,13 @@ struct status_change_data {
long val1, val2, val3, val4, tick; //Remaining duration.
};

#define MAX_BONUS_SCRIPT_LENGTH 1024
struct bonus_script_data {
char script[MAX_BONUS_SCRIPT_LENGTH];
long tick;
short type, flag;
};

struct skill_cooldown_data {
unsigned short skill_id;
long tick;
@@ -46,7 +46,7 @@ static const int packet_len_table[0x3d] = { // U - used, F - free
11,10,10, 0,11, -1,266,10, // 2b10-2b17: U->2b10, U->2b11, U->2b12, F->2b13, U->2b14, U->2b15, U->2b16, U->2b17
2,10, 2,-1,-1,-1, 2, 7, // 2b18-2b1f: U->2b18, U->2b19, U->2b1a, U->2b1b, U->2b1c, U->2b1d, U->2b1e, U->2b1f
-1,10, 8, 2, 2,14,19,19, // 2b20-2b27: U->2b20, U->2b21, U->2b22, U->2b23, U->2b24, U->2b25, U->2b26, U->2b27
10,10, 6, 0, 0, 0, 0, 0, // 2b28-2b2f: U->2b28, U->2b29, U->2b2a, F->2b2b, F->2b2c, F->2b2d, F->2b2e, F->2b2f
10,10, 6, 0, 0, 6, -1, -1, // 2b28-2b2f: U->2b28, U->2b29, U->2b2a, F->2b2b, F->2b2c, U->2b2d, U->2b2e, U->2b2f
};

//Used Packets:
@@ -101,6 +101,11 @@ static const int packet_len_table[0x3d] = { // U - used, F - free
//2b28: Outgoing, chrif_save_bankdata -> 'send bank data to be saved'
//2b29: Incoming, chrif_load_bankdata -> 'received bank data for playeer to be loaded'
//2b2a: Outgoing, chrif_bankdata_request -> 'request bank data for charid'
//2b2b: FREE
//2b2c: FREE
//2b2d: Outgoing, chrif_bsdata_request -> request bonus_script for pc_authok'ed char.
//2b2e: Outgoing, chrif_save_bsdata -> Send bonus_script of player for saving.
//2b2f: Incoming, chrif_load_bsdata -> received bonus_script of player for loading.

int chrif_connected = 0;
int char_fd = -1;
@@ -284,6 +289,7 @@ int chrif_save(struct map_session_data *sd, int flag) {
chrif_save_scdata(sd);
chrif_skillcooldown_save(sd);
chrif_save_bankdata(sd);
chrif_save_bsdata(sd);
}
if ( !chrif_auth_logout(sd,flag == 1 ? ST_LOGOUT : ST_MAPCHANGE) )
ShowError("chrif_save: Failed to set up player %d:%d for proper quitting!\n", sd->status.account_id, sd->status.char_id);
@@ -1568,7 +1574,7 @@ int chrif_parse(int fd) {
case 0x2b04: chrif_recvmap(fd); break;
case 0x2b06: chrif_changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break;
case 0x2b09: map_addnickdb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break;
case 0x2b0b: chrif_skillcooldown_load(fd); break;
case 0x2b0b: chrif_skillcooldown_load(fd); break;
case 0x2b0d: chrif_changedsex(fd); break;
case 0x2b0f: chrif_char_ask_name_answer(RFIFOL(fd,2), (char*)RFIFOP(fd,6), RFIFOW(fd,30), RFIFOW(fd,32)); break;
case 0x2b12: chrif_divorceack(RFIFOL(fd,2), RFIFOL(fd,6)); break;
@@ -1584,6 +1590,7 @@ int chrif_parse(int fd) {
case 0x2b25: chrif_deadopt(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
case 0x2b27: chrif_authfail(fd); break;
case 0x2b29: chrif_load_bankdata(fd); break;
case 0x2b2f: chrif_load_bsdata(fd); break;
default:
ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd);
set_eof(fd);
@@ -1705,6 +1712,110 @@ int chrif_send_report(char* buf, int len) {
return 0;
}

/** [Cydh]
* Requets bonus_script datas
* @param char_id
*/
int chrif_bsdata_request(int char_id) {
chrif_check(-1);
WFIFOHEAD(char_fd,6);
WFIFOW(char_fd,0) = 0x2b2d;
WFIFOL(char_fd,2) = char_id;
WFIFOSET(char_fd,6);
return 0;
}

/** [Cydh]
* Stores bonus_script data(s) to the table
* @param sd
*/
int chrif_save_bsdata(struct map_session_data *sd) {
int i, count=0;
unsigned int tick;
struct bonus_script_data bs;
const struct TimerData *timer;

chrif_check(-1);
tick = gettick();

WFIFOHEAD(char_fd,10+MAX_PC_BONUS_SCRIPT*sizeof(struct bonus_script_data));
WFIFOW(char_fd,0) = 0x2b2e;
WFIFOL(char_fd,4) = sd->status.char_id;

//Clear un-saved data
pc_bonus_script_check(sd,BONUS_FLAG_REM_ON_LOGOUT);

for (i = 0; i < MAX_PC_BONUS_SCRIPT; i++) {
if (!(&sd->bonus_script[i]) || !sd->bonus_script[i].script || strlen(sd->bonus_script[i].script_str) == 0)
continue;

timer = get_timer(sd->bonus_script[i].tid);
if (timer == NULL || DIFF_TICK(timer->tick,tick) < 0)
continue;

memcpy(bs.script,sd->bonus_script[i].script_str,strlen(sd->bonus_script[i].script_str)+1);
bs.tick = DIFF_TICK(timer->tick,tick);
bs.flag = sd->bonus_script[i].flag;
bs.type = (sd->bonus_script[i].isBuff) ? 1 : 0;

memcpy(WFIFOP(char_fd,10+count*sizeof(struct bonus_script_data)),&bs,sizeof(struct bonus_script_data));
delete_timer(sd->bonus_script[i].tid,pc_bonus_script_timer);
count++;
}

if (count == 0)
return 0;

WFIFOW(char_fd,8) = count;
WFIFOW(char_fd,2) = 10+count*sizeof(struct bonus_script_data);
WFIFOSET(char_fd,WFIFOW(char_fd,2));
return 0;
}

/** [Cydh]
* Loads bonus_script datas
* @param fd
*/
int chrif_load_bsdata(int fd) {
struct map_session_data *sd;
struct bonus_script_data *bs;
int cid, count;
uint8 i, count_ = 0;

cid = RFIFOL(fd,4);
sd = map_charid2sd(cid);

if (!sd) {
ShowError("chrif_load_bsdata: Player with CID %d not found!\n",cid);
return -1;
}

if (sd->status.char_id != cid) {
ShowError("chrif_load_bsdata: Receiving data for char id does not matches (%d != %d)!\n",sd->status.char_id,cid);
return -1;
}

count = RFIFOW(fd,8);

for (i = 0; i < count; i++) {
struct script_code *script;
bs = (struct bonus_script_data*)RFIFOP(fd,10 + i*sizeof(struct bonus_script_data));

if (!(script = parse_script(bs->script,"chrif_load_bsdata",1,1)))
continue;

memcpy(sd->bonus_script[i].script_str,bs->script,strlen(bs->script));
sd->bonus_script[i].script = script;
sd->bonus_script[i].tick = gettick() + bs->tick;
sd->bonus_script[i].flag = (uint8)bs->flag;
sd->bonus_script[i].isBuff = (bs->type) ? true : false;
count_++;
}
if (count_)
status_calc_pc(sd,false);
return 0;
}

/**
* @see DBApply
*/

1 comment on commit 9e8e3cf

@euphyy
Copy link
Contributor

@euphyy euphyy commented on 9e8e3cf Nov 11, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! :3

Please sign in to comment.