Compare commits
10 Commits
master
...
hotfix/iss
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1e01f6448f | ||
![]() |
42eccbb1bf | ||
![]() |
50bd9cdfbe | ||
![]() |
5676a45908 | ||
![]() |
1c1bb9892c | ||
![]() |
c951f68250 | ||
![]() |
9440ba8929 | ||
![]() |
9ff252d2b1 | ||
![]() |
7a345b85cb | ||
![]() |
da8d77bfc1 |
@ -940,6 +940,8 @@ CREATE TABLE IF NOT EXISTS `sc_data` (
|
||||
`char_id` int(11) unsigned NOT NULL,
|
||||
`type` smallint(11) unsigned NOT NULL,
|
||||
`tick` bigint(20) NOT NULL,
|
||||
`tick_total` bigint(20) NOT NULL,
|
||||
`tick_time` bigint(20) NOT NULL,
|
||||
`val1` int(11) NOT NULL default '0',
|
||||
`val2` int(11) NOT NULL default '0',
|
||||
`val3` int(11) NOT NULL default '0',
|
||||
|
5
sql-files/upgrades/upgrade_20200803.sql
Normal file
5
sql-files/upgrades/upgrade_20200803.sql
Normal file
@ -0,0 +1,5 @@
|
||||
ALTER TABLE `sc_data` ADD COLUMN `tick_total` BIGINT(20) NOT NULL AFTER `tick`;
|
||||
UPDATE `sc_data` SET `tick_total` = `tick`;
|
||||
|
||||
ALTER TABLE `sc_data` ADD COLUMN `tick_time` BIGINT(20) NOT NULL AFTER `tick_total`;
|
||||
UPDATE `sc_data` SET `tick_time` = `tick`;
|
@ -2385,7 +2385,7 @@ bool char_checkdb(void){
|
||||
return false;
|
||||
}
|
||||
//checking scdata_db
|
||||
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`type`,`tick`,`val1`,`val2`,`val3`,`val4`"
|
||||
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`type`,`tick`,`tick_total`,`tick_time`,`val1`,`val2`,`val3`,`val4`"
|
||||
" FROM `%s` LIMIT 1;", schema_config.scdata_db) ){
|
||||
Sql_ShowDebug(sql_handle);
|
||||
return false;
|
||||
|
@ -284,7 +284,7 @@ int chmapif_parse_askscdata(int fd){
|
||||
int aid, cid;
|
||||
aid = RFIFOL(fd,2);
|
||||
cid = RFIFOL(fd,6);
|
||||
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
|
||||
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4, tick_total, tick_time from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
|
||||
schema_config.scdata_db, aid, cid) )
|
||||
{
|
||||
Sql_ShowDebug(sql_handle);
|
||||
@ -308,6 +308,8 @@ int chmapif_parse_askscdata(int fd){
|
||||
Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data);
|
||||
Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data);
|
||||
Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data);
|
||||
Sql_GetData(sql_handle, 6, &data, NULL); scdata.tick_total = strtoll(data, nullptr, 10);
|
||||
Sql_GetData(sql_handle, 7, &data, NULL); scdata.tick_time = strtoll(data, nullptr, 10);
|
||||
memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data));
|
||||
}
|
||||
if (count >= 50)
|
||||
@ -958,14 +960,14 @@ int chmapif_parse_save_scdata(int fd){
|
||||
int i;
|
||||
|
||||
StringBuf_Init(&buf);
|
||||
StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", schema_config.scdata_db);
|
||||
StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `tick_total`, `tick_time`, `val1`, `val2`, `val3`, `val4`) VALUES ", schema_config.scdata_db);
|
||||
for( i = 0; i < count; ++i )
|
||||
{
|
||||
memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data));
|
||||
if( i > 0 )
|
||||
StringBuf_AppendStr(&buf, ", ");
|
||||
StringBuf_Printf(&buf, "('%d','%d','%hu','%" PRtf "','%ld','%ld','%ld','%ld')", aid, cid,
|
||||
data.type, data.tick, data.val1, data.val2, data.val3, data.val4);
|
||||
StringBuf_Printf(&buf, "('%d','%d','%hu','%" PRtf "','%" PRtf "','%" PRtf "','%ld','%ld','%ld','%ld')", aid, cid,
|
||||
data.type, data.tick, data.tick_total, data.tick_time, data.val1, data.val2, data.val3, data.val4);
|
||||
}
|
||||
if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
|
||||
Sql_ShowDebug(sql_handle);
|
||||
|
@ -408,6 +408,8 @@ struct status_change_data {
|
||||
unsigned short type; //SC_type
|
||||
long val1, val2, val3, val4;
|
||||
t_tick tick; //Remaining duration.
|
||||
t_tick tick_total; // Total duration
|
||||
t_tick tick_time; // Interval duration
|
||||
};
|
||||
|
||||
#define MAX_BONUS_SCRIPT_LENGTH 512
|
||||
|
@ -1318,6 +1318,15 @@ int chrif_save_scdata(map_session_data *sd) { //parses the sc_data of the player
|
||||
data.tick = 0; //Negative tick does not necessarily mean that sc has expired
|
||||
} else
|
||||
data.tick = INFINITE_TICK; //Infinite duration
|
||||
if (sce->tick_timer != INVALID_TIMER) {
|
||||
timer = get_timer(sce->tick_timer);
|
||||
if (timer == nullptr || timer->func != status_change_tick_timer)
|
||||
continue;
|
||||
if (DIFF_TICK(timer->tick, tick) >= 0)
|
||||
data.tick_time = DIFF_TICK(timer->tick, tick);
|
||||
} else
|
||||
data.tick_time = 0;
|
||||
data.tick_total = sce->tick_total;
|
||||
data.type = i;
|
||||
data.val1 = sce->val1;
|
||||
data.val2 = sce->val2;
|
||||
@ -1401,7 +1410,7 @@ int chrif_load_scdata(int fd) {
|
||||
for (i = 0; i < count; i++) {
|
||||
struct status_change_data *data = (struct status_change_data*)RFIFOP(fd,14 + i*sizeof(struct status_change_data));
|
||||
|
||||
status_change_start(NULL,&sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_LOADED|SCSTART_NORATEDEF);
|
||||
status_change_start_sub(NULL,&sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, data->tick_total, data->tick_time, SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_LOADED|SCSTART_NORATEDEF);
|
||||
}
|
||||
|
||||
pc_scdata_received(sd);
|
||||
|
192
src/map/clif.cpp
192
src/map/clif.cpp
@ -6464,87 +6464,26 @@ void clif_cooking_list( map_session_data *sd, int trigger, uint16 skill_id, int
|
||||
/// 0196 <index>.W <id>.L <state>.B (ZC_MSG_STATE_CHANGE) [used for ending status changes and starting them on non-pc units (when needed)]
|
||||
/// 043f <index>.W <id>.L <state>.B <remain msec>.L { <val>.L }*3 (ZC_MSG_STATE_CHANGE2) [used exclusively for starting statuses on pcs]
|
||||
/// 0983 <index>.W <id>.L <state>.B <total msec>.L <remain msec>.L { <val>.L }*3 (ZC_MSG_STATE_CHANGE3) (PACKETVER >= 20120618)
|
||||
/// @param bl Sends packet to clients around this object
|
||||
/// @param id ID of object that has this effect
|
||||
/// @param type Status icon see enum efst_type
|
||||
/// @param flag 1:Active, 0:Deactive
|
||||
/// @param tick Duration in ms
|
||||
/// @param val1
|
||||
/// @param val2
|
||||
/// @param val3
|
||||
void clif_status_change_sub(struct block_list *bl, int id, int type, int flag, t_tick tick, int val1, int val2, int val3, enum send_target target_type)
|
||||
/// @param bl: Sends packet to clients around this object
|
||||
/// @param id: ID of object that has this effect
|
||||
/// @param type: Status icon (see efst_types)
|
||||
/// @param flag: 1:Active, 0:Inactive
|
||||
/// @param tick_total: Total duration in ms
|
||||
/// @param tick: Remaining duration in ms
|
||||
/// @param val1: Value 1
|
||||
/// @param val2: Value 2
|
||||
/// @param val3: Value 3
|
||||
void clif_status_change_sub(struct block_list *bl, int id, int type, int flag, t_tick tick_total, t_tick tick, int val1, int val2, int val3)
|
||||
{
|
||||
unsigned char buf[32];
|
||||
|
||||
if (type == EFST_BLANK) //It shows nothing on the client...
|
||||
return;
|
||||
|
||||
if (type == EFST_POSTDELAY && tick == 0)
|
||||
return;
|
||||
|
||||
nullpo_retv(bl);
|
||||
|
||||
// Statuses with an infinite duration, but still needs a duration sent to display properly.
|
||||
if (type == EFST_LUNARSTANCE || type == EFST_UNIVERSESTANCE || type == EFST_SUNSTANCE || type == EFST_STARSTANCE)
|
||||
tick = 200;
|
||||
|
||||
#if PACKETVER >= 20120618
|
||||
if (flag && battle_config.display_status_timers)
|
||||
WBUFW(buf,0) = 0x983;
|
||||
else
|
||||
#elif PACKETVER >= 20090121
|
||||
if (flag && battle_config.display_status_timers)
|
||||
WBUFW(buf,0) = 0x43f;
|
||||
else
|
||||
#endif
|
||||
WBUFW(buf,0) = 0x196;
|
||||
WBUFW(buf,2) = type;
|
||||
WBUFL(buf,4) = id;
|
||||
WBUFB(buf,8) = flag;
|
||||
#if PACKETVER >= 20120618
|
||||
if (flag && battle_config.display_status_timers) {
|
||||
if (tick <= 0)
|
||||
tick = 9999; // this is indeed what official servers do
|
||||
|
||||
WBUFL(buf,9) = client_tick(tick);/* at this stage remain and total are the same value I believe */
|
||||
WBUFL(buf,13) = client_tick(tick);
|
||||
WBUFL(buf,17) = val1;
|
||||
WBUFL(buf,21) = val2;
|
||||
WBUFL(buf,25) = val3;
|
||||
}
|
||||
#elif PACKETVER >= 20090121
|
||||
if (flag && battle_config.display_status_timers) {
|
||||
if (tick <= 0)
|
||||
tick = 9999; // this is indeed what official servers do
|
||||
|
||||
WBUFL(buf,9) = client_tick(tick);
|
||||
WBUFL(buf,13) = val1;
|
||||
WBUFL(buf,17) = val2;
|
||||
WBUFL(buf,21) = val3;
|
||||
}
|
||||
#endif
|
||||
clif_send(buf, packet_len(WBUFW(buf,0)), bl, target_type);
|
||||
}
|
||||
|
||||
/* Sends status effect to clients around the bl
|
||||
* @param bl Object that has the effect
|
||||
* @param type Status icon see enum efst_type
|
||||
* @param flag 1:Active, 0:Deactive
|
||||
* @param tick Duration in ms
|
||||
* @param val1
|
||||
* @param val2
|
||||
* @param val3
|
||||
*/
|
||||
void clif_status_change(struct block_list *bl, int type, int flag, t_tick tick, int val1, int val2, int val3) {
|
||||
map_session_data *sd = NULL;
|
||||
|
||||
if (type == EFST_BLANK) //It shows nothing on the client...
|
||||
return;
|
||||
|
||||
if (type == EFST_POSTDELAY && tick == 0)
|
||||
return;
|
||||
|
||||
if (type == EFST_ILLUSION && !battle_config.display_hallucination) // Disable Hallucination.
|
||||
if (!(status_efst_get_bl_type((efst_type)type) & bl->type)) // only send status changes that actually matter to the client
|
||||
return;
|
||||
|
||||
#if !( PACKETVER_MAIN_NUM >= 20191120 || PACKETVER_RE_NUM >= 20191106 )
|
||||
@ -6553,14 +6492,56 @@ void clif_status_change(struct block_list *bl, int type, int flag, t_tick tick,
|
||||
type = EFST_RIDING;
|
||||
#endif
|
||||
|
||||
nullpo_retv(bl);
|
||||
packet_status_change p = { 0 };
|
||||
map_session_data *sd = BL_CAST(BL_PC, bl);
|
||||
|
||||
sd = BL_CAST(BL_PC, bl);
|
||||
if (battle_config.display_status_timers > 0) {
|
||||
// Statuses with an infinite duration, but still needs a duration sent to display properly.
|
||||
switch (type) {
|
||||
case EFST_LUNARSTANCE:
|
||||
case EFST_UNIVERSESTANCE:
|
||||
case EFST_SUNSTANCE:
|
||||
case EFST_STARSTANCE:
|
||||
tick = 200;
|
||||
break;
|
||||
default:
|
||||
if (tick < 0)
|
||||
tick = 9999; // this is indeed what official servers do
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(status_efst_get_bl_type((efst_type)type)&bl->type)) // only send status changes that actually matter to the client
|
||||
return;
|
||||
p.PacketType = status_changeType;
|
||||
p.index = type;
|
||||
p.AID = id;
|
||||
p.state = (uint8)flag;
|
||||
|
||||
clif_status_change_sub(bl, bl->id, type, flag, tick, val1, val2, val3, ((sd ? (pc_isinvisible(sd) ? SELF : AREA) : AREA_WOS)));
|
||||
#if PACKETVER >= 20090121
|
||||
if (battle_config.display_status_timers > 0) {
|
||||
#if PACKETVER >= 20120618
|
||||
p.Total = client_tick(tick);
|
||||
#endif
|
||||
p.Left = client_tick(tick_total);
|
||||
p.val1 = val1;
|
||||
p.val2 = val2;
|
||||
p.val3 = val3;
|
||||
}
|
||||
#endif
|
||||
|
||||
clif_send(&p, sizeof(p), bl, pc_isinvisible(sd) ? SELF : AREA);
|
||||
}
|
||||
|
||||
/* Sends status effect to clients around the bl
|
||||
* @param bl: Object that has the effect
|
||||
* @param type: Status icon (see efst_types)
|
||||
* @param flag: 1:Active, 0:Inactive
|
||||
* @param tick_total: Total duration in ms
|
||||
* @param val1: Value 1
|
||||
* @param val2: Value 2
|
||||
* @param val3: Value 3
|
||||
*/
|
||||
void clif_status_change(struct block_list *bl, int type, int flag, t_tick tick_total, int val1, int val2, int val3) {
|
||||
clif_status_change_sub(bl, bl->id, type, flag, tick_total, tick_total, val1, val2, val3);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -6570,13 +6551,12 @@ void clif_status_change(struct block_list *bl, int type, int flag, t_tick tick,
|
||||
* @param target: Client send type
|
||||
*/
|
||||
void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl, enum send_target target) {
|
||||
unsigned char i;
|
||||
nullpo_retv(bl);
|
||||
|
||||
struct sc_display_entry **sc_display;
|
||||
unsigned char sc_display_count;
|
||||
bool spheres_sent;
|
||||
|
||||
nullpo_retv(bl);
|
||||
|
||||
switch( bl->type ){
|
||||
case BL_PC: {
|
||||
map_session_data* sd = (map_session_data*)bl;
|
||||
@ -6598,14 +6578,14 @@ void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl,
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < sc_display_count; i++) {
|
||||
for (unsigned char i = 0; i < sc_display_count; i++) {
|
||||
enum sc_type type = sc_display[i]->type;
|
||||
status_change *sc = status_get_sc(bl);
|
||||
const struct TimerData *td = (sc && sc->getSCE(type) ? get_timer(sc->getSCE(type)->timer) : NULL);
|
||||
t_tick tick = 0;
|
||||
const TimerData *td = (sc && sc->getSCE(type) ? get_timer(sc->getSCE(type)->timer) : nullptr);
|
||||
t_tick tick = 0, cur_tick = gettick();
|
||||
|
||||
if (td)
|
||||
tick = DIFF_TICK(td->tick, gettick());
|
||||
if (td != nullptr)
|
||||
tick = DIFF_TICK(td->tick, cur_tick);
|
||||
|
||||
// Status changes that need special handling
|
||||
switch( type ){
|
||||
@ -6626,9 +6606,9 @@ void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl,
|
||||
}
|
||||
|
||||
#if PACKETVER > 20120418
|
||||
clif_efst_status_change(tbl, bl->id, target, status_db.getIcon(type), tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3);
|
||||
clif_efst_status_change(tbl, bl->id, target, status_db.getIcon(type), sc->getSCE(type)->tick_total, tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3);
|
||||
#else
|
||||
clif_status_change_sub(tbl, bl->id, status_db.getIcon(type), 1, tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3, target);
|
||||
clif_status_change_sub(tbl, bl->id, status_db.getIcon(type), 1, tick, tick sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3, target);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -6636,38 +6616,30 @@ void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl,
|
||||
/// Notifies the client when a player enters the screen with an active EFST.
|
||||
/// 08ff <id>.L <index>.W <remain msec>.L { <val>.L }*3 (ZC_EFST_SET_ENTER) (PACKETVER >= 20111108)
|
||||
/// 0984 <id>.L <index>.W <total msec>.L <remain msec>.L { <val>.L }*3 (ZC_EFST_SET_ENTER2) (PACKETVER >= 20120618)
|
||||
void clif_efst_status_change(struct block_list *bl, int tid, enum send_target target, int type, t_tick tick, int val1, int val2, int val3) {
|
||||
void clif_efst_status_change(struct block_list *bl, int tid, enum send_target target, int type, t_tick tick_total, t_tick tick, int val1, int val2, int val3) {
|
||||
#if PACKETVER >= 20111108
|
||||
unsigned char buf[32];
|
||||
#if PACKETVER >= 20120618
|
||||
const int cmd = 0x984;
|
||||
#elif PACKETVER >= 20111108
|
||||
const int cmd = 0x8ff;
|
||||
#endif
|
||||
int offset = 0;
|
||||
nullpo_retv(bl);
|
||||
|
||||
if (type == EFST_BLANK)
|
||||
return;
|
||||
|
||||
nullpo_retv(bl);
|
||||
|
||||
if (tick <= 0)
|
||||
if (tick < 0)
|
||||
tick = 9999;
|
||||
|
||||
WBUFW(buf,offset + 0) = cmd;
|
||||
WBUFL(buf,offset + 2) = tid;
|
||||
WBUFW(buf,offset + 6) = type;
|
||||
#if PACKETVER >= 20111108
|
||||
WBUFL(buf,offset + 8) = client_tick(tick); // Set remaining status duration [exneval]
|
||||
PACKET_EFST_SET_ENTER p = { 0 };
|
||||
|
||||
p.PacketType = HEADER_ZC_EFST_SET_ENTER;
|
||||
p.GID = tid;
|
||||
p.type = type;
|
||||
p.remaining = client_tick(tick);
|
||||
#if PACKETVER >= 20120618
|
||||
WBUFL(buf,offset + 12) = client_tick(tick);
|
||||
offset += 4;
|
||||
p.total = client_tick(tick_total);
|
||||
#endif
|
||||
WBUFL(buf,offset + 12) = val1;
|
||||
WBUFL(buf,offset + 16) = val2;
|
||||
WBUFL(buf,offset + 20) = val3;
|
||||
#endif
|
||||
clif_send(buf,packet_len(cmd),bl,target);
|
||||
p.val1 = val1;
|
||||
p.val2 = val2;
|
||||
p.val3 = val3;
|
||||
|
||||
clif_send(&p, sizeof(p), bl, target);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -771,8 +771,9 @@ void clif_bladestop(struct block_list *src, int dst_id, int active);
|
||||
void clif_changemapcell(int fd, int16 m, int x, int y, int type, enum send_target target);
|
||||
|
||||
#define clif_status_load(bl, type, flag) clif_status_change((bl), (type), (flag), 0, 0, 0, 0)
|
||||
void clif_status_change(struct block_list *bl, int type, int flag, t_tick tick, int val1, int val2, int val3);
|
||||
void clif_efst_status_change(struct block_list *bl, int tid, enum send_target target, int type, t_tick tick, int val1, int val2, int val3);
|
||||
void clif_status_change(struct block_list *bl, int type, int flag, t_tick tick_total, int val1, int val2, int val3);
|
||||
void clif_status_change_sub(struct block_list *bl, int id, int type, int flag, t_tick tick_total, t_tick tick, int val1, int val2, int val3);
|
||||
void clif_efst_status_change(struct block_list *bl, int tid, enum send_target target, int type, t_tick tick_total, t_tick tick, int val1, int val2, int val3);
|
||||
void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl, enum send_target target);
|
||||
|
||||
void clif_wis_message(map_session_data* sd, const char* nick, const char* mes, int mes_len, int gmlvl);
|
||||
|
@ -475,6 +475,19 @@ struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2{
|
||||
struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2_sub items[];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct PACKET_EFST_SET_ENTER {
|
||||
int16 PacketType;
|
||||
uint32 GID;
|
||||
uint16 type;
|
||||
uint32 remaining;
|
||||
#if PACKETVER >= 20120618
|
||||
uint32 total;
|
||||
#endif
|
||||
int32 val1;
|
||||
int32 val2;
|
||||
int32 val3;
|
||||
};
|
||||
|
||||
// NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
|
||||
#if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 )
|
||||
#pragma pack( pop )
|
||||
@ -515,7 +528,13 @@ DEFINE_PACKET_HEADER(CZ_REQ_SE_CASH_TAB_CODE, 0x846)
|
||||
DEFINE_PACKET_HEADER(ZC_ACK_SE_CASH_ITEM_LIST2, 0x8c0)
|
||||
DEFINE_PACKET_HEADER(ZC_ACK_SCHEDULER_CASHITEM, 0x8ca)
|
||||
DEFINE_PACKET_HEADER(ZC_CLEAR_DIALOG, 0x8d6)
|
||||
#if PACKETVER >= 20111108 && PACKETVER < 20120618
|
||||
DEFINE_PACKET_HEADER(ZC_EFST_SET_ENTER, 0x8ff)
|
||||
#endif
|
||||
DEFINE_PACKET_HEADER(ZC_ENTRY_QUEUE_INIT, 0x90e);
|
||||
#if PACKETVER >= 20120618
|
||||
DEFINE_PACKET_HEADER(ZC_EFST_SET_ENTER, 0x984)
|
||||
#endif
|
||||
DEFINE_PACKET_HEADER(ZC_BANKING_CHECK, 0x9a6)
|
||||
DEFINE_PACKET_HEADER(ZC_ACK_BANKING_DEPOSIT, 0x9a8)
|
||||
DEFINE_PACKET_HEADER(ZC_ACK_BANKING_WITHDRAW, 0x9aa)
|
||||
|
@ -12246,7 +12246,8 @@ BUILDIN_FUNC(sc_start)
|
||||
TBL_NPC * nd = map_id2nd(st->oid);
|
||||
struct block_list* bl;
|
||||
enum sc_type type;
|
||||
int tick, val1, val2, val3, val4=0, rate, flag;
|
||||
int val1, val2, val3, val4=0, rate, flag;
|
||||
t_tick tick;
|
||||
char start_type;
|
||||
const char* command = script_getfuncname(st);
|
||||
|
||||
@ -12258,7 +12259,7 @@ BUILDIN_FUNC(sc_start)
|
||||
start_type = 1;
|
||||
|
||||
type = (sc_type)script_getnum(st,2);
|
||||
tick = script_getnum(st,3);
|
||||
tick = script_getnum64(st,3);
|
||||
val1 = script_getnum(st,4);
|
||||
|
||||
//If from NPC we make default flag 1 to be unavoidable
|
||||
|
@ -9846,19 +9846,22 @@ void status_display_remove(struct block_list *bl, enum sc_type type) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies SC defense to a given status change
|
||||
* This function also determines whether or not the status change will be applied
|
||||
* Applies a Status Change for a given amount of time
|
||||
* @param src: Source of the status change [PC|MOB|HOM|MER|ELEM|NPC]
|
||||
* @param bl: Target of the status change (See: enum sc_type)
|
||||
* @param type: Status change (SC_*)
|
||||
* @param rate: Initial percentage rate of affecting bl (0~10000)
|
||||
* @param val1~4: Depends on type of status change
|
||||
* @param duration: Initial duration that the status change affects bl
|
||||
* @param val1: Depends on type of status change
|
||||
* @param val2: Depends on type of status change
|
||||
* @param val3: Depends on type of status change
|
||||
* @param val4: Depends on type of status change
|
||||
* @param duration: Remaining duration
|
||||
* @param duration_total: Initial duration
|
||||
* @param flag: Value which determines what parts to calculate. See e_status_change_start_flags
|
||||
* @param delay: Delay in milliseconds before the SC is applied
|
||||
* @return adjusted duration based on flag values
|
||||
*/
|
||||
int status_change_start(struct block_list* src, struct block_list* bl,enum sc_type type,int rate,int val1,int val2,int val3,int val4,t_tick duration,unsigned char flag, int32 delay) {
|
||||
int status_change_start_sub(struct block_list* src, struct block_list* bl,enum sc_type type,int rate,int val1,int val2,int val3,int val4,t_tick duration,t_tick duration_total,t_tick duration_tick,unsigned char flag, int32 delay) {
|
||||
map_session_data *sd = NULL;
|
||||
status_change* sc;
|
||||
struct status_change_entry* sce;
|
||||
@ -9932,14 +9935,14 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust tick according to status resistances
|
||||
// Adjust duration_total according to status resistances
|
||||
if( !(flag&(SCSTART_NOAVOID|SCSTART_LOADED)) ) {
|
||||
duration = status_get_sc_def(src, bl, type, rate, duration, flag);
|
||||
if( !duration )
|
||||
duration_total = status_get_sc_def(src, bl, type, rate, duration_total, flag);
|
||||
if( duration_total == 0 )
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tick = (int)duration;
|
||||
int tick = static_cast<int>(duration_total);
|
||||
|
||||
sd = BL_CAST(BL_PC, bl);
|
||||
vd = status_get_viewdata(bl);
|
||||
@ -12758,6 +12761,33 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
||||
calc_flag.reset(SCB_BODY);
|
||||
}*/
|
||||
|
||||
t_tick totaltick, subtick, subticktime = (intptr_t)nullptr;
|
||||
bool has_tick_interval = false;
|
||||
|
||||
//if (tick_time)
|
||||
// tick += 1;
|
||||
|
||||
if (duration_total > INT_MAX)
|
||||
totaltick = duration_total;
|
||||
else
|
||||
totaltick = tick;
|
||||
|
||||
if (!(flag & SCSTART_LOADED)) {
|
||||
subtick = totaltick; // When starting a new SC (not loading), its remaining duration is the same as the total
|
||||
|
||||
if (tick_time) {
|
||||
subticktime = tick_time;
|
||||
has_tick_interval = true;
|
||||
}
|
||||
} else {
|
||||
subtick = duration;
|
||||
|
||||
if (duration_tick > 0) {
|
||||
subticktime = duration_tick;
|
||||
has_tick_interval = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flag&SCSTART_NOICON) && !(flag&SCSTART_LOADED && scdb->flag[SCF_DISPLAYPC] || scdb->flag[SCF_DISPLAYNPC])) {
|
||||
int status_icon = scdb->icon;
|
||||
|
||||
@ -12766,15 +12796,15 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
||||
status_icon = EFST_ATTACK_PROPERTY_NOTHING + val1; // Assign status icon for older clients
|
||||
#endif
|
||||
|
||||
clif_status_change(bl, status_icon, 1, tick, scdb->flag[SCF_SENDVAL1] ? val1 : 1, scdb->flag[SCF_SENDVAL2] ? val2 : 0, scdb->flag[SCF_SENDVAL3] ? val3 : 0);
|
||||
if (sc->getSCE(type))
|
||||
clif_status_change(bl, status_icon, 0, 0, 0, 0, 0);
|
||||
clif_status_change_sub(bl, bl->id, status_icon, 1, totaltick, subtick, scdb->flag[SCF_SENDVAL1] ? val1 : 1, scdb->flag[SCF_SENDVAL2] ? val2 : 0, scdb->flag[SCF_SENDVAL3] ? val3 : 0);
|
||||
}
|
||||
|
||||
// Used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first.
|
||||
if( tick_time )
|
||||
tick = tick_time;
|
||||
|
||||
// Don't trust the previous sce assignment, in case the SC ended somewhere between there and here.
|
||||
if((sce=sc->getSCE(type))) { // reuse old sc
|
||||
if (has_tick_interval && sce->tick_timer != INVALID_TIMER)
|
||||
delete_timer(sce->tick_timer, status_change_tick_timer);
|
||||
if( sce->timer != INVALID_TIMER )
|
||||
delete_timer(sce->timer, status_change_timer);
|
||||
sc_isnew = false;
|
||||
@ -12786,10 +12816,15 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
||||
sce->val2 = val2;
|
||||
sce->val3 = val3;
|
||||
sce->val4 = val4;
|
||||
if (tick >= 0)
|
||||
sce->timer = add_timer(gettick() + tick, status_change_timer, bl->id, type);
|
||||
if (subtick >= 0)
|
||||
sce->timer = add_timer(gettick() + subtick, status_change_timer, bl->id, type);
|
||||
else
|
||||
sce->timer = INVALID_TIMER; // Infinite duration
|
||||
if (has_tick_interval && subticktime >= 0)
|
||||
sce->tick_timer = add_timer(gettick() + subticktime, status_change_tick_timer, bl->id, type);
|
||||
else
|
||||
sce->tick_timer = INVALID_TIMER; // Infinite duration
|
||||
sce->tick_total = totaltick;
|
||||
|
||||
if (calc_flag.any()) {
|
||||
if (sd != nullptr) {
|
||||
@ -12905,6 +12940,24 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a Status Change for its full time
|
||||
* @param src: Source of the status change [PC|MOB|HOM|MER|ELEM|NPC]
|
||||
* @param bl: Target of the status change (See: enum sc_type)
|
||||
* @param type: Status change (SC_*)
|
||||
* @param rate: Initial percentage rate of affecting bl (0~10000)
|
||||
* @param val1: Depends on type of status change
|
||||
* @param val2: Depends on type of status change
|
||||
* @param val3: Depends on type of status change
|
||||
* @param val4: Depends on type of status change
|
||||
* @param tick: Remaining duration
|
||||
* @param flag: Value which determines what parts to calculate. See e_status_change_start_flags
|
||||
* @return adjusted duration based on flag values
|
||||
*/
|
||||
int status_change_start(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int val1, int val2, int val3, int val4, t_tick tick, unsigned char flag, int32 delay) {
|
||||
return status_change_start_sub(src, bl, type, rate, val1, val2, val3, val4, 0, tick, flag, delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* End all statuses except those listed
|
||||
* TODO: May be useful for dispel instead resetting a list there
|
||||
@ -12958,6 +13011,8 @@ int status_change_clear(struct block_list* bl, int type)
|
||||
status_change_end(bl, status);
|
||||
if( type == 1 && sc->getSCE(status) ) { // If for some reason status_change_end decides to still keep the status when quitting. [Skotlex]
|
||||
(sc->count)--;
|
||||
if (sc->getSCE(status)->tick_timer != INVALID_TIMER)
|
||||
delete_timer(sc->getSCE(status)->tick_timer, status_change_tick_timer);
|
||||
if (sc->getSCE(status)->timer != INVALID_TIMER)
|
||||
delete_timer(sc->getSCE(status)->timer, status_change_timer);
|
||||
sc->deleteSCE(status);
|
||||
@ -13044,6 +13099,8 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
|
||||
if (!status_isdead(bl) && (sce->val2 || sce->val3 || sce->val4))
|
||||
return 0; //Don't end the status change yet as there are still unit groups associated with it
|
||||
}
|
||||
if (sce->tick_timer != INVALID_TIMER)
|
||||
delete_timer(sce->tick_timer, status_change_tick_timer);
|
||||
if (sce->timer != INVALID_TIMER) // Could be a SC with infinite duration
|
||||
delete_timer(sce->timer,status_change_timer);
|
||||
}
|
||||
@ -13690,7 +13747,68 @@ TIMER_FUNC(status_change_timer){
|
||||
std::function<void (t_tick)> sc_timer_next = [&sce, &bl, &data](t_tick t) {
|
||||
sce->timer = add_timer(t, status_change_timer, bl->id, data);
|
||||
};
|
||||
|
||||
|
||||
// If status has an interval and there is at least 100ms remaining time, wait for next interval
|
||||
if (interval > 0 && sc->getSCE(type) && sce->val4 >= 100) {
|
||||
sc_timer_next(min(sce->val4, interval) + tick);
|
||||
sce->val4 -= interval;
|
||||
if (dounlock)
|
||||
map_freeblock_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dounlock)
|
||||
map_freeblock_unlock();
|
||||
|
||||
// Default for all non-handled control paths is to end the status
|
||||
return status_change_end(bl, type, tid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets timers for statuses that have an interval
|
||||
* Used with reoccurring status effects, such as dropping SP every 5 seconds
|
||||
* @param tid: Timer ID
|
||||
* @param tick: How long before next call
|
||||
* @param id: ID of character
|
||||
* @param data: Information passed through the timer call
|
||||
* @return 1: Success 0: Fail
|
||||
*/
|
||||
TIMER_FUNC(status_change_tick_timer) {
|
||||
block_list *bl = map_id2bl(id);
|
||||
|
||||
if (!bl) {
|
||||
ShowDebug("status_change_tick_timer: Null pointer id: %d data: %" PRIdPTR "\n", id, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
status_change *const sc = status_get_sc(bl);
|
||||
status_data *const status = status_get_status_data(bl);
|
||||
|
||||
if (!sc) {
|
||||
ShowDebug("status_change_tick_timer: Null pointer id: %d data: %" PRIdPTR " bl-type: %d\n", id, data, bl->type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sc_type type = (sc_type)data;
|
||||
status_change_entry *const sce = sc->getSCE(type);
|
||||
|
||||
if (!sce) {
|
||||
ShowDebug("status_change_tick_timer: Null pointer id: %d data: %" PRIdPTR " bl-type: %d\n", id, data, bl->type);
|
||||
return 0;
|
||||
}
|
||||
if (sce->tick_timer != tid) {
|
||||
ShowError("status_change_tick_timer: Mismatch for type %d: %d != %d (bl id %d)\n", type, tid, sce->tick_timer, bl->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int interval = status_get_sc_interval(type);
|
||||
bool dounlock = false;
|
||||
map_session_data *sd = BL_CAST(BL_PC, bl);
|
||||
|
||||
std::function<void(t_tick)> sc_timer_next = [&sce, &bl, &data](t_tick t) {
|
||||
sce->tick_timer = add_timer(t, status_change_tick_timer, bl->id, data);
|
||||
};
|
||||
|
||||
switch(type) {
|
||||
case SC_MAXIMIZEPOWER:
|
||||
case SC_CLOAKING:
|
||||
@ -13887,7 +14005,7 @@ TIMER_FUNC(status_change_timer){
|
||||
bl->m == sd->feel_map[1].m ||
|
||||
bl->m == sd->feel_map[2].m)
|
||||
{ // Timeout will be handled by pc_setpos
|
||||
sce->timer = INVALID_TIMER;
|
||||
sce->tick_timer = INVALID_TIMER;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
@ -14698,8 +14816,7 @@ TIMER_FUNC(status_change_timer){
|
||||
if (dounlock)
|
||||
map_freeblock_unlock();
|
||||
|
||||
// Default for all non-handled control paths is to end the status
|
||||
return status_change_end( bl,type,tid );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -15869,6 +15986,7 @@ void do_init_status(void) {
|
||||
memset(SCDisabled, 0, sizeof(SCDisabled));
|
||||
|
||||
add_timer_func_list(status_change_timer,"status_change_timer");
|
||||
add_timer_func_list(status_change_tick_timer, "status_change_tick_timer");
|
||||
add_timer_func_list(status_natural_heal_timer,"status_natural_heal_timer");
|
||||
add_timer_func_list(status_clear_lastEffect_timer, "status_clear_lastEffect_timer");
|
||||
initDummyData();
|
||||
|
@ -3200,6 +3200,8 @@ struct sc_display_entry {
|
||||
struct status_change_entry {
|
||||
int timer;
|
||||
int val1,val2,val3,val4;
|
||||
int tick_timer; // Timer for the next interval based timer execution
|
||||
t_tick tick_total; // Total amount of time the status is active for
|
||||
};
|
||||
|
||||
///Status change
|
||||
@ -3383,6 +3385,7 @@ int status_isimmune(struct block_list *bl);
|
||||
|
||||
t_tick status_get_sc_def(struct block_list *src,struct block_list *bl, enum sc_type type, int rate, t_tick tick, unsigned char flag);
|
||||
int status_change_start(struct block_list* src, struct block_list* bl,enum sc_type type,int rate,int val1,int val2,int val3,int val4,t_tick duration,unsigned char flag, int32 delay = 0);
|
||||
int status_change_start_sub(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int val1, int val2, int val3, int val4, t_tick duration, t_tick duration_total, t_tick duration_tick, unsigned char flag, int32 delay = 0);
|
||||
//Short version, receives rate in 1->100 range, and does not uses a flag setting.
|
||||
static int sc_start(block_list *src, block_list *bl, sc_type type, int32 rate, int32 val1, t_tick duration, int32 delay = 0) {
|
||||
return status_change_start(src, bl, type, 100 * rate, val1, 0, 0, 0, duration, SCSTART_NONE, delay);
|
||||
@ -3395,6 +3398,7 @@ static int sc_start4(block_list *src, block_list *bl, sc_type type, int32 rate,
|
||||
}
|
||||
int status_change_end(struct block_list* bl, enum sc_type type, int tid = INVALID_TIMER);
|
||||
TIMER_FUNC(status_change_timer);
|
||||
TIMER_FUNC(status_change_tick_timer);
|
||||
int status_change_timer_sub(struct block_list* bl, va_list ap);
|
||||
int status_change_clear(struct block_list* bl, int type);
|
||||
void status_change_clear_buffs(struct block_list* bl, uint8 type);
|
||||
|
Loading…
x
Reference in New Issue
Block a user