Corrects status icon timer after relog

* Fixes #4984.
* Resolves status icon timers not properly showing the difference of remaining/total time when a player relogs.
* Fixes status icon timers going into negative values.
Thanks to @attackjom!
This commit is contained in:
aleos 2020-08-03 10:20:07 -04:00
parent 9991b09837
commit da8d77bfc1
10 changed files with 248 additions and 231 deletions

View File

@ -910,6 +910,7 @@ CREATE TABLE IF NOT EXISTS `sc_data` (
`account_id` int(11) unsigned NOT NULL, `account_id` int(11) unsigned NOT NULL,
`char_id` int(11) unsigned NOT NULL, `char_id` int(11) unsigned NOT NULL,
`type` smallint(11) unsigned NOT NULL, `type` smallint(11) unsigned NOT NULL,
`tick_total` bigint(20) NOT NULL,
`tick` bigint(20) NOT NULL, `tick` bigint(20) NOT NULL,
`val1` int(11) NOT NULL default '0', `val1` int(11) NOT NULL default '0',
`val2` int(11) NOT NULL default '0', `val2` int(11) NOT NULL default '0',

View File

@ -0,0 +1,2 @@
ALTER TABLE `sc_data` ADD COLUMN `tick_total` BIGINT(20) NOT NULL AFTER `tick`;
UPDATE `sc_data` SET `tick_total` = `tick`;

View File

@ -2338,7 +2338,7 @@ bool char_checkdb(void){
return false; return false;
} }
//checking scdata_db //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`,`val1`,`val2`,`val3`,`val4`"
" FROM `%s` LIMIT 1;", schema_config.scdata_db) ){ " FROM `%s` LIMIT 1;", schema_config.scdata_db) ){
Sql_ShowDebug(sql_handle); Sql_ShowDebug(sql_handle);
return false; return false;

View File

@ -279,7 +279,7 @@ int chmapif_parse_askscdata(int fd){
int aid, cid; int aid, cid;
aid = RFIFOL(fd,2); aid = RFIFOL(fd,2);
cid = RFIFOL(fd,6); 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, tick_total, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
schema_config.scdata_db, aid, cid) ) schema_config.scdata_db, aid, cid) )
{ {
Sql_ShowDebug(sql_handle); Sql_ShowDebug(sql_handle);
@ -299,10 +299,11 @@ int chmapif_parse_askscdata(int fd){
{ {
Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data); Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data);
Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = strtoll( data, nullptr, 10 ); Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = strtoll( data, nullptr, 10 );
Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data); Sql_GetData(sql_handle, 2, &data, NULL); scdata.tick_total = strtoll(data, nullptr, 10);
Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data); Sql_GetData(sql_handle, 3, &data, NULL); scdata.val1 = atoi(data);
Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data); Sql_GetData(sql_handle, 4, &data, NULL); scdata.val2 = atoi(data);
Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data); Sql_GetData(sql_handle, 5, &data, NULL); scdata.val3 = atoi(data);
Sql_GetData(sql_handle, 6, &data, NULL); scdata.val4 = atoi(data);
memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data)); memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data));
} }
if (count >= 50) if (count >= 50)
@ -942,14 +943,14 @@ int chmapif_parse_save_scdata(int fd){
int i; int i;
StringBuf_Init(&buf); 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`, `val1`, `val2`, `val3`, `val4`) VALUES ", schema_config.scdata_db);
for( i = 0; i < count; ++i ) for( i = 0; i < count; ++i )
{ {
memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data)); memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data));
if( i > 0 ) if( i > 0 )
StringBuf_AppendStr(&buf, ", "); StringBuf_AppendStr(&buf, ", ");
StringBuf_Printf(&buf, "('%d','%d','%hu','%" PRtf "','%ld','%ld','%ld','%ld')", aid, cid, StringBuf_Printf(&buf, "('%d','%d','%hu','%" PRtf "','%" PRtf "','%ld','%ld','%ld','%ld')", aid, cid,
data.type, data.tick, data.val1, data.val2, data.val3, data.val4); data.type, data.tick, data.tick_total, data.val1, data.val2, data.val3, data.val4);
} }
if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
Sql_ShowDebug(sql_handle); Sql_ShowDebug(sql_handle);

View File

@ -340,6 +340,7 @@ struct status_change_data {
unsigned short type; //SC_type unsigned short type; //SC_type
long val1, val2, val3, val4; long val1, val2, val3, val4;
t_tick tick; //Remaining duration. t_tick tick; //Remaining duration.
t_tick tick_total; // Total duration
}; };
#define MAX_BONUS_SCRIPT_LENGTH 512 #define MAX_BONUS_SCRIPT_LENGTH 512

View File

@ -1330,6 +1330,7 @@ int chrif_save_scdata(struct map_session_data *sd) { //parses the sc_data of the
data.tick = 0; //Negative tick does not necessarily mean that sc has expired data.tick = 0; //Negative tick does not necessarily mean that sc has expired
} else } else
data.tick = INFINITE_TICK; //Infinite duration data.tick = INFINITE_TICK; //Infinite duration
data.tick_total = sc->data[i]->tick_total;
data.type = i; data.type = i;
data.val1 = sc->data[i]->val1; data.val1 = sc->data[i]->val1;
data.val2 = sc->data[i]->val2; data.val2 = sc->data[i]->val2;
@ -1413,7 +1414,7 @@ int chrif_load_scdata(int fd) {
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
struct status_change_data *data = (struct status_change_data*)RFIFOP(fd,14 + i*sizeof(struct status_change_data)); 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, SCSTART_NOAVOID|SCSTART_NOTICKDEF|SCSTART_LOADED|SCSTART_NORATEDEF);
} }
pc_scdata_received(sd); pc_scdata_received(sd);

View File

@ -6126,17 +6126,17 @@ void clif_cooking_list( struct map_session_data *sd, int trigger, uint16 skill_i
/// 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)] /// 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] /// 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) /// 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 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 type Status icon see enum efst_types /// @param flag: 1:Active, 0:Inactive
/// @param flag 1:Active, 0:Deactive /// @param tick_total: Total duration in ms
/// @param tick Duration in ms /// @param tick: Remaining duration in ms
/// @param val1 /// @param val1: Value 1
/// @param val2 /// @param val2: Value 2
/// @param val3 /// @param val3: Value 3
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) void clif_status_change_sub(struct block_list *bl, int type, int flag, t_tick tick_total, t_tick tick, int val1, int val2, int val3)
{ {
unsigned char buf[32]; nullpo_retv(bl);
if (type == EFST_BLANK) //It shows nothing on the client... if (type == EFST_BLANK) //It shows nothing on the client...
return; return;
@ -6144,79 +6144,61 @@ void clif_status_change_sub(struct block_list *bl, int id, int type, int flag, t
if (type == EFST_POSTDELAY && tick == 0) if (type == EFST_POSTDELAY && tick == 0)
return; return;
nullpo_retv(bl); if (!(status_type2relevant_bl_types(type) & bl->type)) // only send status changes that actually matter to the client
return;
packet_status_change p = { 0 };
map_session_data *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. // 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) switch (type) {
case EFST_LUNARSTANCE:
case EFST_UNIVERSESTANCE:
case EFST_SUNSTANCE:
case EFST_STARSTANCE:
tick = 200; tick = 200;
break;
default:
if (tick < 0)
tick = 9999; // this is indeed what official servers do
break;
}
p.PacketType = status_changeType;
} else
p.PacketType = sc_notickType;
p.index = type;
p.AID = bl->id;
p.state = (uint8)flag;
#if PACKETVER >= 20120618 #if PACKETVER >= 20120618
if (flag && battle_config.display_status_timers) if (battle_config.display_status_timers > 0)
WBUFW(buf,0) = 0x983; p.Total = client_tick(tick_total);
else
#elif PACKETVER >= 20090121
if (flag && battle_config.display_status_timers)
WBUFW(buf,0) = 0x43f;
else
#endif #endif
WBUFW(buf,0) = 0x196; #if PACKETVER >= 20090121
WBUFW(buf,2) = type; if (battle_config.display_status_timers > 0) {
WBUFL(buf,4) = id; p.Left = client_tick(tick);
WBUFB(buf,8) = flag; p.val1 = val1;
#if PACKETVER >= 20120618 p.val2 = val2;
if (flag && battle_config.display_status_timers) { p.val3 = val3;
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 #endif
clif_send(buf, packet_len(WBUFW(buf,0)), bl, target_type);
clif_send(&p, sizeof(p), bl, (sd && sd->status.option & OPTION_INVISIBLE) ? SELF : AREA);
} }
/* Sends status effect to clients around the bl /* Sends status effect to clients around the bl
* @param bl Object that has the effect * @param bl: Object that has the effect
* @param type Status icon see enum efst_types * @param type: Status icon (see efst_types)
* @param flag 1:Active, 0:Deactive * @param flag: 1:Active, 0:Inactive
* @param tick Duration in ms * @param tick_total: Total duration in ms
* @param val1 * @param val1: Value 1
* @param val2 * @param val2: Value 2
* @param val3 * @param val3: Value 3
*/ */
void clif_status_change(struct block_list *bl, int type, int flag, 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) {
struct map_session_data *sd = NULL; clif_status_change_sub(bl, type, flag, tick_total, tick_total, val1, val2, val3);
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.
return;
nullpo_retv(bl);
sd = BL_CAST(BL_PC, bl);
if (!(status_type2relevant_bl_types(type)&bl->type)) // only send status changes that actually matter to the client
return;
clif_status_change_sub(bl, bl->id, type, flag, tick, val1, val2, val3, ((sd ? (pc_isinvisible(sd) ? SELF : AREA) : AREA_WOS)));
} }
/** /**
@ -6267,13 +6249,13 @@ void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl,
#if PACKETVER > 20120418 #if PACKETVER > 20120418
clif_efst_status_change(tbl, bl->id, AREA_WOS, StatusIconChangeTable[type], tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3); clif_efst_status_change(tbl, bl->id, AREA_WOS, StatusIconChangeTable[type], tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3);
#else #else
clif_status_change_sub(tbl, bl->id, StatusIconChangeTable[type], 1, tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3, AREA_WOS); clif_status_change_sub(tbl, StatusIconChangeTable[type], 1, tick, tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3, AREA_WOS);
#endif #endif
}else{ }else{
#if PACKETVER > 20120418 #if PACKETVER > 20120418
clif_efst_status_change(tbl, bl->id, target, StatusIconChangeTable[type], tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3); clif_efst_status_change(tbl, bl->id, target, StatusIconChangeTable[type], tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3);
#else #else
clif_status_change_sub(tbl, bl->id, StatusIconChangeTable[type], 1, tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3, target); clif_status_change_sub(tbl, StatusIconChangeTable[type], 1, tick, tick, sc_display[i]->val1, sc_display[i]->val2, sc_display[i]->val3, target);
#endif #endif
} }
} }

View File

@ -728,7 +728,8 @@ 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); 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) #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_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 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, 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_efst_status_change_sub(struct block_list *tbl, struct block_list *bl, enum send_target target); void clif_efst_status_change_sub(struct block_list *tbl, struct block_list *bl, enum send_target target);

View File

@ -9099,18 +9099,21 @@ void status_display_remove(struct block_list *bl, enum sc_type type) {
} }
/** /**
* Applies SC defense to a given status change * Applies a Status Change for a given amount of time
* This function also determines whether or not the status change will be applied
* @param src: Source of the status change [PC|MOB|HOM|MER|ELEM|NPC] * @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 bl: Target of the status change (See: enum sc_type)
* @param type: Status change (SC_*) * @param type: Status change (SC_*)
* @param rate: Initial percentage rate of affecting bl (0~10000) * @param rate: Initial percentage rate of affecting bl (0~10000)
* @param val1~4: Depends on type of status change * @param val1: Depends on type of status change
* @param tick: Initial duration that the status change affects bl * @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 flag: Value which determines what parts to calculate. See e_status_change_start_flags
* @return adjusted duration based on flag values * @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) { 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,unsigned char flag) {
struct map_session_data *sd = NULL; struct map_session_data *sd = NULL;
struct status_change* sc; struct status_change* sc;
struct status_change_entry* sce; struct status_change_entry* sce;
@ -9207,14 +9210,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)) ) { if( !(flag&(SCSTART_NOAVOID|SCSTART_LOADED)) ) {
duration = status_get_sc_def(src, bl, type, rate, duration, flag); duration_total = status_get_sc_def(src, bl, type, rate, duration_total, flag);
if( !duration ) if( duration_total == 0 )
return 0; return 0;
} }
int tick = (int)duration; int tick_total = static_cast<int>(duration_total);
sd = BL_CAST(BL_PC, bl); sd = BL_CAST(BL_PC, bl);
vd = status_get_viewdata(bl); vd = status_get_viewdata(bl);
@ -9417,7 +9420,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
} }
if (!opt_flag) return 0; if (!opt_flag) return 0;
} }
if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC if (tick_total == 1) return 1; // Minimal duration: Only strip without causing the SC
break; break;
case SC_STRIPSHIELD: case SC_STRIPSHIELD:
if( val2 == 1 ) val2 = 0; // GX effect. Do not take shield off.. if( val2 == 1 ) val2 = 0; // GX effect. Do not take shield off..
@ -9431,7 +9434,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
return 0; return 0;
pc_unequipitem(sd,i,3); pc_unequipitem(sd,i,3);
} }
if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC if (tick_total == 1) return 1; // Minimal duration: Only strip without causing the SC
break; break;
case SC_STRIPARMOR: case SC_STRIPARMOR:
if (sd && !(flag&SCSTART_LOADED)) { if (sd && !(flag&SCSTART_LOADED)) {
@ -9443,7 +9446,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
return 0; return 0;
pc_unequipitem(sd,i,3); pc_unequipitem(sd,i,3);
} }
if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC if (tick_total == 1) return 1; // Minimal duration: Only strip without causing the SC
break; break;
case SC_STRIPHELM: case SC_STRIPHELM:
if (sd && !(flag&SCSTART_LOADED)) { if (sd && !(flag&SCSTART_LOADED)) {
@ -9455,7 +9458,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
return 0; return 0;
pc_unequipitem(sd,i,3); pc_unequipitem(sd,i,3);
} }
if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC if (tick_total == 1) return 1; // Minimal duration: Only strip without causing the SC
break; break;
case SC_MERC_FLEEUP: case SC_MERC_FLEEUP:
case SC_MERC_ATKUP: case SC_MERC_ATKUP:
@ -9533,7 +9536,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
if( i < 0 ) if( i < 0 )
return 0; return 0;
} }
if (tick == 1) return 1; // Minimal duration: Only strip without causing the SC if (tick_total == 1) return 1; // Minimal duration: Only strip without causing the SC
break; break;
case SC_TOXIN: case SC_TOXIN:
case SC_PARALYSE: case SC_PARALYSE:
@ -10237,7 +10240,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_SPRITEMABLE: case SC_SPRITEMABLE:
case SC_CLAN_INFO: case SC_CLAN_INFO:
case SC_DAILYSENDMAILCNT: case SC_DAILYSENDMAILCNT:
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
case SC_KEEPING: case SC_KEEPING:
@ -10245,7 +10248,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
unit_data *ud = unit_bl2ud(bl); unit_data *ud = unit_bl2ud(bl);
if (ud) if (ud)
ud->attackabletime = ud->canact_tick = ud->canmove_tick = gettick() + tick; ud->attackabletime = ud->canact_tick = ud->canmove_tick = gettick() + tick_total;
} }
break; break;
case SC_DECREASEAGI: case SC_DECREASEAGI:
@ -10267,29 +10270,29 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
int i; int i;
for( i = 0; i < MAX_DEVOTION; i++ ) { for( i = 0; i < MAX_DEVOTION; i++ ) {
if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) ) if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, SCSTART_NOAVOID|SCSTART_NOICON); status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick_total, SCSTART_NOAVOID|SCSTART_NOICON);
} }
} }
else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick, SCSTART_NOAVOID|SCSTART_NOICON); status_change_start(src,&tsd->bl, type, 10000, val1, val2, val3, val4, tick_total, SCSTART_NOAVOID|SCSTART_NOICON);
} }
if( val4 ) if( val4 )
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
case SC_AUTOBERSERK: case SC_AUTOBERSERK:
if (status->hp < status->max_hp>>2 && if (status->hp < status->max_hp>>2 &&
(!sc->data[SC_PROVOKE] || sc->data[SC_PROVOKE]->val2==0)) (!sc->data[SC_PROVOKE] || sc->data[SC_PROVOKE]->val2==0))
sc_start4(src,bl,SC_PROVOKE,100,10,1,0,0,60000); sc_start4(src,bl,SC_PROVOKE,100,10,1,0,0,60000);
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
case SC_SIGNUMCRUCIS: case SC_SIGNUMCRUCIS:
val2 = 10 + 4*val1; // Def reduction val2 = 10 + 4*val1; // Def reduction
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
clif_emotion(bl, ET_SWEAT); clif_emotion(bl, ET_SWEAT);
break; break;
case SC_MAXIMIZEPOWER: case SC_MAXIMIZEPOWER:
tick_time = val2 = tick>0?tick:60000; tick_time = val2 = tick_total>0?tick_total:60000;
tick = INFINITE_TICK; // Duration sent to the client should be infinite tick_total = INFINITE_TICK; // Duration sent to the client should be infinite
break; break;
case SC_EDP: case SC_EDP:
val2 = val1 + 2; // Chance to Poison enemies. val2 = val1 + 2; // Chance to Poison enemies.
@ -10300,8 +10303,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
uint16 poison_level = pc_checkskill(sd, GC_RESEARCHNEWPOISON); uint16 poison_level = pc_checkskill(sd, GC_RESEARCHNEWPOISON);
if (poison_level > 0) { if (poison_level > 0) {
tick += 30000; // Base of 30 seconds tick_total += 30000; // Base of 30 seconds
tick += poison_level * 15 * 1000; // Additional 15 seconds per level tick_total += poison_level * 15 * 1000; // Additional 15 seconds per level
} }
} }
break; break;
@ -10329,7 +10332,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC_SACRIFICE: case SC_SACRIFICE:
val2 = 5; // Lasts 5 hits val2 = 5; // Lasts 5 hits
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
case SC_ENCPOISON: case SC_ENCPOISON:
val2= 250+50*val1; // Poisoning Chance (2.5+0.5%) in 1/10000 rate val2= 250+50*val1; // Poisoning Chance (2.5+0.5%) in 1/10000 rate
@ -10366,11 +10369,11 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
int i; int i;
for( i = 0; i < MAX_DEVOTION; i++ ) { for( i = 0; i < MAX_DEVOTION; i++ ) {
if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) ) if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, SCSTART_NOAVOID|SCSTART_NOICON); status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick_total, SCSTART_NOAVOID|SCSTART_NOICON);
} }
} }
else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick, SCSTART_NOAVOID|SCSTART_NOICON); status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 1, tick_total, SCSTART_NOAVOID|SCSTART_NOICON);
} }
break; break;
case SC_STRIPWEAPON: case SC_STRIPWEAPON:
@ -10475,9 +10478,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
// val3 : Brings the skill_lv (merged into val1 here) // val3 : Brings the skill_lv (merged into val1 here)
// val4 : Partner // val4 : Partner
if (val1 == CG_MOONLIT) if (val1 == CG_MOONLIT)
clif_status_change(bl,EFST_MOON,1,tick,0, 0, 0); clif_status_change(bl,EFST_MOON,1,tick_total,0, 0, 0);
val1|= (val3<<16); val1|= (val3<<16);
val3 = tick/1000; // Tick duration val3 = tick_total/1000; // Tick duration
tick_time = 1000; // [GodLesZ] tick time tick_time = 1000; // [GodLesZ] tick time
break; break;
#ifndef RENEWAL #ifndef RENEWAL
@ -10552,7 +10555,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
// mmocharstatus.manner, each negative point results in 1 minute with this status activated. // mmocharstatus.manner, each negative point results in 1 minute with this status activated.
// This is done this way because the message that the client displays is hardcoded, and only // This is done this way because the message that the client displays is hardcoded, and only
// shows how many minutes are remaining. [Panikon] // shows how many minutes are remaining. [Panikon]
tick = 60000; tick_total = 60000;
val1 = battle_config.manner_system; // Mute filters. val1 = battle_config.manner_system; // Mute filters.
if (sd) { if (sd) {
clif_changestatus(sd,SP_MANNER,sd->status.manner); clif_changestatus(sd,SP_MANNER,sd->status.manner);
@ -10562,8 +10565,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_STONE: case SC_STONE:
val3 = max(val3, 100); // Incubation time val3 = max(val3, 100); // Incubation time
val4 = max(tick-val3, 100); // Petrify time val4 = max(tick_total-val3, 100); // Petrify time
tick = val3; tick_total = val3;
calc_flag = 0; // Actual status changes take effect on petrified state. calc_flag = 0; // Actual status changes take effect on petrified state.
break; break;
@ -10580,32 +10583,32 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_BLEEDING: case SC_BLEEDING:
case SC_BURNING: case SC_BURNING:
tick_time = status_get_sc_interval(type); tick_time = status_get_sc_interval(type);
val4 = tick - tick_time; // Remaining time val4 = tick_total - tick_time; // Remaining time
break; break;
case SC_TOXIN: case SC_TOXIN:
if (val3 == 1) // Target if (val3 == 1) // Target
tick_time = status_get_sc_interval(type); tick_time = status_get_sc_interval(type);
else // Caster else // Caster
tick_time = 1000; tick_time = 1000;
val4 = tick - tick_time; // Remaining time val4 = tick_total - tick_time; // Remaining time
break; break;
case SC_DEATHHURT: case SC_DEATHHURT:
if (val3 == 1) if (val3 == 1)
break; break;
tick_time = status_get_sc_interval(type); tick_time = status_get_sc_interval(type);
val4 = tick - tick_time; // Remaining time val4 = tick_total - tick_time; // Remaining time
case SC_LEECHESEND: case SC_LEECHESEND:
if (val3 == 0) if (val3 == 0)
break; break;
tick_time = status_get_sc_interval(type); tick_time = status_get_sc_interval(type);
val4 = tick - tick_time; // Remaining time val4 = tick_total - tick_time; // Remaining time
break; break;
case SC_PYREXIA: case SC_PYREXIA:
if (val3 == 1) { // Target if (val3 == 1) { // Target
// Causes blind for duration of pyrexia, unreducable and unavoidable, but can be healed with e.g. green potion // Causes blind for duration of pyrexia, unreducable and unavoidable, but can be healed with e.g. green potion
status_change_start(src, bl, SC_BLIND, 10000, val1, 0, 0, 0, tick, SCSTART_NOAVOID | SCSTART_NOTICKDEF | SCSTART_NORATEDEF); status_change_start(src, bl, SC_BLIND, 10000, val1, 0, 0, 0, tick_total, SCSTART_NOAVOID | SCSTART_NOTICKDEF | SCSTART_NORATEDEF);
tick_time = status_get_sc_interval(type); tick_time = status_get_sc_interval(type);
val4 = tick - tick_time; // Remaining time val4 = tick_total - tick_time; // Remaining time
} else // Caster } else // Caster
val2 = 15; // CRIT % and ATK % increase val2 = 15; // CRIT % and ATK % increase
break; break;
@ -10616,7 +10619,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_MAGICMUSHROOM: case SC_MAGICMUSHROOM:
if (val3 == 1) { // Target if (val3 == 1) { // Target
tick_time = status_get_sc_interval(type); tick_time = status_get_sc_interval(type);
val4 = tick - tick_time; // Remaining time val4 = tick_total - tick_time; // Remaining time
} else // Caster } else // Caster
val2 = 10; // After-cast delay % reduction val2 = 10; // After-cast delay % reduction
break; break;
@ -10632,7 +10635,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
// val2 = seconds between heals // val2 = seconds between heals
// val4 = total of heals // val4 = total of heals
if( val2 < 1 ) val2 = 1; if( val2 < 1 ) val2 = 1;
if( (val4 = tick/(val2 * 1000)) < 1 ) if( (val4 = tick_total/(val2 * 1000)) < 1 )
val4 = 1; val4 = 1;
tick_time = val2 * 1000; // [GodLesZ] tick time tick_time = val2 * 1000; // [GodLesZ] tick time
break; break;
@ -10646,17 +10649,17 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
} }
val1 = boss_md->bl.id; val1 = boss_md->bl.id;
tick_time = 1000; // [GodLesZ] tick time tick_time = 1000; // [GodLesZ] tick time
val4 = tick / tick_time; val4 = tick_total / tick_time;
} }
break; break;
case SC_HIDING: case SC_HIDING:
val2 = tick/1000; val2 = tick_total/1000;
tick_time = 1000; // [GodLesZ] tick time tick_time = 1000; // [GodLesZ] tick time
val3 = 0; // Unused, previously speed adjustment val3 = 0; // Unused, previously speed adjustment
val4 = val1+3; // Seconds before SP substraction happen. val4 = val1+3; // Seconds before SP substraction happen.
break; break;
case SC_CHASEWALK: case SC_CHASEWALK:
val2 = tick>0?tick:10000; // Interval at which SP is drained. val2 = tick_total>0?tick_total:10000; // Interval at which SP is drained.
val3 = 35 - 5 * val1; // Speed adjustment. val3 = 35 - 5 * val1; // Speed adjustment.
if (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_ROGUE) if (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_ROGUE)
val3 -= 40; val3 -= 40;
@ -10666,8 +10669,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_CLOAKING: case SC_CLOAKING:
if (!sd) // Monsters should be able to walk with no penalties. [Skotlex] if (!sd) // Monsters should be able to walk with no penalties. [Skotlex]
val1 = 10; val1 = 10;
tick_time = val2 = tick>0?tick:60000; // SP consumption rate. tick_time = val2 = tick_total>0?tick_total:60000; // SP consumption rate.
tick = INFINITE_TICK; // Duration sent to the client should be infinite tick_total = INFINITE_TICK; // Duration sent to the client should be infinite
val3 = 0; // Unused, previously walk speed adjustment val3 = 0; // Unused, previously walk speed adjustment
// val4&1 signals the presence of a wall. // val4&1 signals the presence of a wall.
// val4&2 makes cloak not end on normal attacks [Skotlex] // val4&2 makes cloak not end on normal attacks [Skotlex]
@ -10681,7 +10684,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_RUWACH: case SC_RUWACH:
case SC_SIGHTBLASTER: case SC_SIGHTBLASTER:
val3 = skill_get_splash(val2, val1); // Val2 should bring the skill-id. val3 = skill_get_splash(val2, val1); // Val2 should bring the skill-id.
val2 = tick/20; val2 = tick_total/20;
tick_time = 20; // [GodLesZ] tick time tick_time = 20; // [GodLesZ] tick time
break; break;
@ -10698,11 +10701,11 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
if( sd ) { if( sd ) {
for( i = 0; i < MAX_DEVOTION; i++ ) { for( i = 0; i < MAX_DEVOTION; i++ ) {
if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) ) if( sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])) )
status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, SCSTART_NOAVOID|SCSTART_NOICON); status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick_total, SCSTART_NOAVOID|SCSTART_NOICON);
} }
} }
else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) )
status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick, SCSTART_NOAVOID|SCSTART_NOICON); status_change_start(src,&tsd->bl, type, 10000, val1, val2, 0, 0, tick_total, SCSTART_NOAVOID|SCSTART_NOICON);
} }
} }
break; break;
@ -10718,7 +10721,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
int i; int i;
for (i = 0; i < MAX_DEVOTION; i++) { // See if there are devoted characters, and pass the status to them. [Skotlex] for (i = 0; i < MAX_DEVOTION; i++) { // See if there are devoted characters, and pass the status to them. [Skotlex]
if (sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i]))) if (sd->devotion[i] && (tsd = map_id2sd(sd->devotion[i])))
status_change_start(src,&tsd->bl,type,10000,val1,val2,val3,val4,tick,SCSTART_NOAVOID); status_change_start(src,&tsd->bl,type,10000,val1,val2,val3,val4,tick_total,SCSTART_NOAVOID);
} }
} }
} }
@ -10732,8 +10735,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
} }
val2 = 12; // SP cost val2 = 12; // SP cost
tick_time = 10000; // Decrease at 10secs intervals. tick_time = 10000; // Decrease at 10secs intervals.
val3 = tick / tick_time; val3 = tick_total / tick_time;
tick = INFINITE_TICK; // Duration sent to the client should be infinite tick_total = INFINITE_TICK; // Duration sent to the client should be infinite
break; break;
case SC_PARRYING: case SC_PARRYING:
val2 = 20 + val1*3; // Block Chance val2 = 20 + val1*3; // Block Chance
@ -10750,20 +10753,20 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_BERSERK: case SC_BERSERK:
if( val3 == SC__BLOODYLUST ) if( val3 == SC__BLOODYLUST )
sc_start(src,bl,(sc_type)val3,100,val1,tick); sc_start(src,bl,(sc_type)val3,100,val1,tick_total);
else else
sc_start4(src,bl, SC_ENDURE, 100,10,0,0,1, tick); sc_start4(src,bl, SC_ENDURE, 100,10,0,0,1, tick_total);
// HP healing is performing after the calc_status call. // HP healing is performing after the calc_status call.
// Val2 holds HP penalty // Val2 holds HP penalty
if (!val4) val4 = skill_get_time2(status_sc2skill(type),val1); if (!val4) val4 = skill_get_time2(status_sc2skill(type),val1);
if (!val4) val4 = 10000; // Val4 holds damage interval if (!val4) val4 = 10000; // Val4 holds damage interval
val3 = tick/val4; // val3 holds skill duration val3 = tick_total/val4; // val3 holds skill duration
tick_time = val4; // [GodLesZ] tick time tick_time = val4; // [GodLesZ] tick time
break; break;
case SC_GOSPEL: case SC_GOSPEL:
if(val4 == BCT_SELF) { // Self effect if(val4 == BCT_SELF) { // Self effect
val2 = tick/10000; val2 = tick_total/10000;
tick_time = 10000; // [GodLesZ] tick time tick_time = 10000; // [GodLesZ] tick time
status_change_clear_buffs(bl, SCCB_BUFFS|SCCB_DEBUFFS|SCCB_CHEM_PROTECT); // Remove buffs/debuffs status_change_clear_buffs(bl, SCCB_BUFFS|SCCB_DEBUFFS|SCCB_CHEM_PROTECT); // Remove buffs/debuffs
} }
@ -10828,12 +10831,12 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_REJECTSWORD: case SC_REJECTSWORD:
val2 = 15*val1; // Reflect chance val2 = 15*val1; // Reflect chance
val3 = 3; // Reflections val3 = 3; // Reflections
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
case SC_MEMORIZE: case SC_MEMORIZE:
val2 = 5; // Memorized casts. val2 = 5; // Memorized casts.
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
#ifndef RENEWAL #ifndef RENEWAL
@ -10881,11 +10884,11 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
if (src2 && sc2) { if (src2 && sc2) {
if (!sce2) // Start lock on caster. if (!sce2) // Start lock on caster.
sc_start4(src2,src2,SC_CLOSECONFINE,100,val1,1,0,0,tick+1000); sc_start4(src2,src2,SC_CLOSECONFINE,100,val1,1,0,0,tick_total+1000);
else { // Increase count of locked enemies and refresh time. else { // Increase count of locked enemies and refresh time.
(sce2->val2)++; (sce2->val2)++;
delete_timer(sce2->timer, status_change_timer); delete_timer(sce2->timer, status_change_timer);
sce2->timer = add_timer(gettick()+tick+1000, status_change_timer, src2->id, SC_CLOSECONFINE); sce2->timer = add_timer(gettick()+tick_total+1000, status_change_timer, src2->id, SC_CLOSECONFINE);
} }
} else // Status failed. } else // Status failed.
return 0; return 0;
@ -10920,13 +10923,13 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
// val4: TK: Combo time // val4: TK: Combo time
struct unit_data *ud = unit_bl2ud(bl); struct unit_data *ud = unit_bl2ud(bl);
if ( ud && (!val3 || val3 == 2) ) { if ( ud && (!val3 || val3 == 2) ) {
tick += 300 * battle_config.combo_delay_rate/100; tick_total += 300 * battle_config.combo_delay_rate/100;
ud->attackabletime = gettick()+tick; ud->attackabletime = gettick()+tick_total;
if( !val3 ) if( !val3 )
unit_set_walkdelay(bl, gettick(), tick, 1); unit_set_walkdelay(bl, gettick(), tick_total, 1);
} }
val3 = 0; val3 = 0;
val4 = tick; val4 = tick_total;
break; break;
} }
case SC_EARTHSCROLL: case SC_EARTHSCROLL:
@ -10939,7 +10942,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
// Note: this int64 value is stored in two separate int32 variables (FIXME) // Note: this int64 value is stored in two separate int32 variables (FIXME)
val3 = (int)(currenttick & 0x00000000ffffffffLL); val3 = (int)(currenttick & 0x00000000ffffffffLL);
val4 = (int)((currenttick & 0xffffffff00000000LL) >> 32); val4 = (int)((currenttick & 0xffffffff00000000LL) >> 32);
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
} }
case SC_KAAHI: case SC_KAAHI:
@ -10954,7 +10957,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC_TRICKDEAD: case SC_TRICKDEAD:
if (vd) vd->dead_sit = 1; if (vd) vd->dead_sit = 1;
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
case SC_CONCENTRATE: case SC_CONCENTRATE:
val2 = 2 + val1; val2 = 2 + val1;
@ -10985,7 +10988,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
val3 = (val2) ? 300 : 200; // Aspd increase val3 = (val2) ? 300 : 200; // Aspd increase
} }
if (s_sd && pc_checkskill(s_sd, BS_HILTBINDING) > 0) if (s_sd && pc_checkskill(s_sd, BS_HILTBINDING) > 0)
tick += tick / 10; //If caster has Hilt Binding, duration increases by 10% tick_total += tick_total / 10; //If caster has Hilt Binding, duration increases by 10%
} }
break; break;
case SC_CONCENTRATION: case SC_CONCENTRATION:
@ -10997,7 +11000,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
val4 = 5*val1; // Def reduction val4 = 5*val1; // Def reduction
#endif #endif
val3 = 10*val1; // Hit Increase val3 = 10*val1; // Hit Increase
sc_start(src, bl, SC_ENDURE, 100, 1, tick); // Level 1 Endure effect sc_start(src, bl, SC_ENDURE, 100, 1, tick_total); // Level 1 Endure effect
break; break;
case SC_ANGELUS: case SC_ANGELUS:
val2 = 5*val1; // def increase val2 = 5*val1; // def increase
@ -11070,7 +11073,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC_JAILED: case SC_JAILED:
// Val1 is duration in minutes. Use INT_MAX to specify 'unlimited' time. // Val1 is duration in minutes. Use INT_MAX to specify 'unlimited' time.
tick = val1>0?1000:250; tick_total = val1>0?1000:250;
if (sd) { if (sd) {
if (sd->mapindex != val2) { if (sd->mapindex != val2) {
int pos = (bl->x&0xFFFF)|(bl->y<<16), // Current Coordinates int pos = (bl->x&0xFFFF)|(bl->y<<16), // Current Coordinates
@ -11100,7 +11103,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC_SWOO: case SC_SWOO:
if(status_has_mode(status,MD_STATUS_IMMUNE)) if(status_has_mode(status,MD_STATUS_IMMUNE))
tick /= 5; // !TODO: Reduce skill's duration. But for how long? tick_total /= 5; // !TODO: Reduce skill's duration. But for how long?
break; break;
case SC_ARMOR: case SC_ARMOR:
// NPC_DEFENDER: // NPC_DEFENDER:
@ -11236,7 +11239,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
} }
break; break;
case SC_ABUNDANCE: case SC_ABUNDANCE:
val4 = tick / 10000; val4 = tick_total / 10000;
tick_time = 10000; // [GodLesZ] tick time tick_time = 10000; // [GodLesZ] tick time
break; break;
case SC_GIANTGROWTH: case SC_GIANTGROWTH:
@ -11249,7 +11252,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
/* Arch Bishop */ /* Arch Bishop */
case SC_RENOVATIO: case SC_RENOVATIO:
val4 = tick / 5000; val4 = tick_total / 5000;
tick_time = 5000; tick_time = 5000;
break; break;
case SC_SECRAMENT: case SC_SECRAMENT:
@ -11260,13 +11263,13 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC_WEAPONBLOCKING: case SC_WEAPONBLOCKING:
val2 = 10 + 2 * val1; // Chance val2 = 10 + 2 * val1; // Chance
val4 = tick / 5000; val4 = tick_total / 5000;
tick_time = 5000; // [GodLesZ] tick time tick_time = 5000; // [GodLesZ] tick time
break; break;
case SC_OBLIVIONCURSE: case SC_OBLIVIONCURSE:
if (val3 == 0) if (val3 == 0)
break; break;
val4 = tick / 3000; val4 = tick_total / 3000;
tick_time = 3000; // [GodLesZ] tick time tick_time = 3000; // [GodLesZ] tick time
break; break;
case SC_CLOAKINGEXCEED: case SC_CLOAKINGEXCEED:
@ -11300,7 +11303,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_SPHERE_5: case SC_SPHERE_5:
if( !sd ) if( !sd )
return 0; // Should only work on players. return 0; // Should only work on players.
val4 = tick / 1000; val4 = tick_total / 1000;
if( val4 < 1 ) if( val4 < 1 )
val4 = 1; val4 = 1;
tick_time = 1000; // [GodLesZ] tick time tick_time = 1000; // [GodLesZ] tick time
@ -11315,7 +11318,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC_ELECTRICSHOCKER: case SC_ELECTRICSHOCKER:
case SC_CRYSTALIZE: case SC_CRYSTALIZE:
val4 = tick / 1000; val4 = tick_total / 1000;
if( val4 < 1 ) if( val4 < 1 )
val4 = 1; val4 = 1;
tick_time = 1000; // [GodLesZ] tick time tick_time = 1000; // [GodLesZ] tick time
@ -11323,13 +11326,13 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_MEIKYOUSISUI: case SC_MEIKYOUSISUI:
val2 = val1 * 2; // % HP each sec val2 = val1 * 2; // % HP each sec
val3 = val1; // % SP each sec val3 = val1; // % SP each sec
val4 = tick / 1000; val4 = tick_total / 1000;
if( val4 < 1 ) if( val4 < 1 )
val4 = 1; val4 = 1;
tick_time = 1000; tick_time = 1000;
break; break;
case SC_CAMOUFLAGE: case SC_CAMOUFLAGE:
val4 = tick/1000; val4 = tick_total/1000;
tick_time = 1000; // [GodLesZ] tick time tick_time = 1000; // [GodLesZ] tick time
break; break;
case SC_WUGDASH: case SC_WUGDASH:
@ -11339,7 +11342,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
// Note: this int64 value is stored in two separate int32 variables (FIXME) // Note: this int64 value is stored in two separate int32 variables (FIXME)
val3 = (int)(currenttick&0x00000000ffffffffLL); val3 = (int)(currenttick&0x00000000ffffffffLL);
val4 = (int)((currenttick&0xffffffff00000000LL)>>32); val4 = (int)((currenttick&0xffffffff00000000LL)>>32);
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
} }
case SC__SHADOWFORM: case SC__SHADOWFORM:
@ -11347,7 +11350,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
struct map_session_data * s_sd = map_id2sd(val2); struct map_session_data * s_sd = map_id2sd(val2);
if( s_sd ) if( s_sd )
s_sd->shadowform_id = bl->id; s_sd->shadowform_id = bl->id;
val4 = tick / 1000; val4 = tick_total / 1000;
tick_time = 1000; // [GodLesZ] tick time tick_time = 1000; // [GodLesZ] tick time
} }
break; break;
@ -11358,8 +11361,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC__INVISIBILITY: case SC__INVISIBILITY:
val2 = 50 - 10 * val1; // ASPD val2 = 50 - 10 * val1; // ASPD
val3 = 20 * val1; // CRITICAL val3 = 20 * val1; // CRITICAL
val4 = tick / 1000; val4 = tick_total / 1000;
tick = INFINITE_TICK; // Duration sent to the client should be infinite tick_total = INFINITE_TICK; // Duration sent to the client should be infinite
tick_time = 1000; // [GodLesZ] tick time tick_time = 1000; // [GodLesZ] tick time
break; break;
case SC__ENERVATION: case SC__ENERVATION:
@ -11396,14 +11399,14 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
default: rand_eff = SC_POISON; break; default: rand_eff = SC_POISON; break;
} }
val2 = 10 * val1; // Crit and Flee2 Reduction val2 = 10 * val1; // Crit and Flee2 Reduction
status_change_start(src,bl,rand_eff,10000,val1,0,(rand_eff == SC_POISON ? src->id : 0),0,tick,SCSTART_NOTICKDEF|SCSTART_NORATEDEF); status_change_start(src,bl,rand_eff,10000,val1,0,(rand_eff == SC_POISON ? src->id : 0),0,tick_total,SCSTART_NOTICKDEF|SCSTART_NORATEDEF);
break; break;
} }
case SC__WEAKNESS: case SC__WEAKNESS:
val2 = 10 * val1; val2 = 10 * val1;
// Bypasses coating protection and MADO // Bypasses coating protection and MADO
sc_start(src,bl,SC_STRIPWEAPON,100,val1,tick); sc_start(src,bl,SC_STRIPWEAPON,100,val1,tick_total);
sc_start(src,bl,SC_STRIPSHIELD,100,val1,tick); sc_start(src,bl,SC_STRIPSHIELD,100,val1,tick_total);
break; break;
case SC_GN_CARTBOOST: case SC_GN_CARTBOOST:
if( val1 < 3 ) if( val1 < 3 )
@ -11419,21 +11422,21 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_STRIKING: case SC_STRIKING:
// val2 = watk bonus already calc // val2 = watk bonus already calc
val3 = 6 - val1;// spcost = 6 - level (lvl1:5 ... lvl 5: 1) val3 = 6 - val1;// spcost = 6 - level (lvl1:5 ... lvl 5: 1)
val4 = tick / 1000; val4 = tick_total / 1000;
tick_time = 1000; // [GodLesZ] tick time tick_time = 1000; // [GodLesZ] tick time
break; break;
case SC_WARMER: case SC_WARMER:
val4 = tick / 3000; val4 = tick_total / 3000;
tick = INFINITE_TICK; // Duration sent to the client should be infinite tick_total = INFINITE_TICK; // Duration sent to the client should be infinite
tick_time = 3000; tick_time = 3000;
break; break;
case SC_BLOODSUCKER: case SC_BLOODSUCKER:
val4 = tick / 1000; val4 = tick_total / 1000;
tick_time = 1000; // [GodLesZ] tick time tick_time = 1000; // [GodLesZ] tick time
break; break;
case SC_HELLS_PLANT: case SC_HELLS_PLANT:
tick_time = 333; tick_time = 333;
val4 = tick / tick_time; val4 = tick_total / tick_time;
break; break;
case SC_SWINGDANCE: case SC_SWINGDANCE:
val3 = 3 * val1 + val2; // Walk speed and aspd reduction. val3 = 3 * val1 + val2; // Walk speed and aspd reduction.
@ -11452,11 +11455,11 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
val2 = 5 + 5 * val1; val2 = 5 + 5 * val1;
break; break;
case SC_VOICEOFSIREN: case SC_VOICEOFSIREN:
val4 = tick / 2000; val4 = tick_total / 2000;
tick_time = 2000; // [GodLesZ] tick time tick_time = 2000; // [GodLesZ] tick time
break; break;
case SC_DEEPSLEEP: case SC_DEEPSLEEP:
val4 = tick / 2000; val4 = tick_total / 2000;
tick_time = 2000; // [GodLesZ] tick time tick_time = 2000; // [GodLesZ] tick time
break; break;
case SC_SIRCLEOFNATURE: case SC_SIRCLEOFNATURE:
@ -11469,7 +11472,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_SATURDAYNIGHTFEVER: case SC_SATURDAYNIGHTFEVER:
if (!val4) val4 = skill_get_time2(status_sc2skill(type),val1); if (!val4) val4 = skill_get_time2(status_sc2skill(type),val1);
if (!val4) val4 = 3000; if (!val4) val4 = 3000;
val3 = tick/val4; val3 = tick_total/val4;
tick_time = val4; // [GodLesZ] tick time tick_time = val4; // [GodLesZ] tick time
break; break;
case SC_GLOOMYDAY: case SC_GLOOMYDAY:
@ -11514,13 +11517,13 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_REFLECTDAMAGE: case SC_REFLECTDAMAGE:
val2 = 15 + 5 * val1; // Reflect amount val2 = 15 + 5 * val1; // Reflect amount
val3 = val1*5 + 25; // Number of reflects val3 = val1*5 + 25; // Number of reflects
val4 = tick/1000; // Number of SP cycles (duration) val4 = tick_total/1000; // Number of SP cycles (duration)
tick_time = 1000; // [GodLesZ] tick time tick_time = 1000; // [GodLesZ] tick time
break; break;
case SC_FORCEOFVANGUARD: case SC_FORCEOFVANGUARD:
val2 = 8 + 12 * val1; // Chance val2 = 8 + 12 * val1; // Chance
val3 = 5 + 2 * val1; // Max rage counters val3 = 5 + 2 * val1; // Max rage counters
tick = INFINITE_TICK; // Endless duration in the client tick_total = INFINITE_TICK; // Endless duration in the client
tick_time = 10000; // [GodLesZ] tick time tick_time = 10000; // [GodLesZ] tick time
break; break;
case SC_EXEEDBREAK: case SC_EXEEDBREAK:
@ -11542,13 +11545,13 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
tick_time = 5000; // [GodLesZ] tick time tick_time = 5000; // [GodLesZ] tick time
break; break;
case SC_MAGNETICFIELD: case SC_MAGNETICFIELD:
val3 = tick / 1000; val3 = tick_total / 1000;
tick_time = 1000; // [GodLesZ] tick time tick_time = 1000; // [GodLesZ] tick time
break; break;
case SC_INSPIRATION: case SC_INSPIRATION:
val2 = (sd?sd->status.job_level:50); val2 = (sd?sd->status.job_level:50);
val3 = status_get_lv(bl) / 10 + val2 / 5; //All stat bonus val3 = status_get_lv(bl) / 10 + val2 / 5; //All stat bonus
val4 = tick / 5000; val4 = tick_total / 5000;
tick_time = 5000; // [GodLesZ] tick time tick_time = 5000; // [GodLesZ] tick time
status_change_clear_buffs(bl, SCCB_BUFFS|SCCB_DEBUFFS); // Remove buffs/debuffs status_change_clear_buffs(bl, SCCB_BUFFS|SCCB_DEBUFFS); // Remove buffs/debuffs
break; break;
@ -11559,7 +11562,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
val1 = (sd?sd->status.job_level:2)/2 + 40 + 5 * val1; val1 = (sd?sd->status.job_level:2)/2 + 40 + 5 * val1;
break; break;
case SC_RAISINGDRAGON: case SC_RAISINGDRAGON:
val3 = tick / 5000; val3 = tick_total / 5000;
tick_time = 5000; // [GodLesZ] tick time tick_time = 5000; // [GodLesZ] tick time
break; break;
case SC_GT_ENERGYGAIN: case SC_GT_ENERGYGAIN:
@ -11681,16 +11684,16 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC_TEARGAS: case SC_TEARGAS:
val2 = status_get_max_hp(bl) * 5 / 100; // Drain 5% HP val2 = status_get_max_hp(bl) * 5 / 100; // Drain 5% HP
val4 = tick / 2000; val4 = tick_total / 2000;
tick_time = 2000; tick_time = 2000;
break; break;
case SC_TEARGAS_SOB: case SC_TEARGAS_SOB:
val4 = tick / 3000; val4 = tick_total / 3000;
tick_time = 3000; tick_time = 3000;
break; break;
case SC_STOMACHACHE: case SC_STOMACHACHE:
val2 = 8; // SP consume. val2 = 8; // SP consume.
val4 = tick / 10000; val4 = tick_total / 10000;
tick_time = 10000; // [GodLesZ] tick time tick_time = 10000; // [GodLesZ] tick time
break; break;
case SC_PROMOTE_HEALTH_RESERCH: case SC_PROMOTE_HEALTH_RESERCH:
@ -11723,7 +11726,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
val2 = 20; // Damage increase bonus val2 = 20; // Damage increase bonus
val3 = val1 * 2; val3 = val1 * 2;
tick_time = 1000; tick_time = 1000;
val4 = tick / tick_time; val4 = tick_total / tick_time;
break; break;
case SC_ZANGETSU: case SC_ZANGETSU:
if( status_get_hp(bl) % 2 == 0 ) if( status_get_hp(bl) % 2 == 0 )
@ -11758,7 +11761,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_ANGRIFFS_MODUS: case SC_ANGRIFFS_MODUS:
val2 = 50 + 20 * val1; // atk bonus val2 = 50 + 20 * val1; // atk bonus
val3 = 25 + 10 * val1; // Flee reduction. val3 = 25 + 10 * val1; // Flee reduction.
val4 = tick/1000; // hp/sp reduction timer val4 = tick_total/1000; // hp/sp reduction timer
tick_time = 1000; tick_time = 1000;
break; break;
case SC_GOLDENE_FERSE: case SC_GOLDENE_FERSE:
@ -11794,15 +11797,15 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
val2 = 10 * val1; // aspd reduction % val2 = 10 * val1; // aspd reduction %
val3 = min((( 200 * val1 ) * status_get_lv(src)) / 150, 1000); // dmg reduction linear. upto a maximum of 1000 [iRO Wiki] val3 = min((( 200 * val1 ) * status_get_lv(src)) / 150, 1000); // dmg reduction linear. upto a maximum of 1000 [iRO Wiki]
if(sc->data[SC_PARALYSIS]) if(sc->data[SC_PARALYSIS])
sc_start(src,bl, SC_ENDURE, 100, val1, tick); // Start endure for same duration sc_start(src,bl, SC_ENDURE, 100, val1, tick_total); // Start endure for same duration
break; break;
case SC_STYLE_CHANGE: case SC_STYLE_CHANGE:
tick = INFINITE_TICK; // Infinite duration tick_total = INFINITE_TICK; // Infinite duration
break; break;
case SC_CBC: case SC_CBC:
val3 = 10; // Drain sp % dmg val3 = 10; // Drain sp % dmg
val4 = tick/1000; // dmg each sec val4 = tick_total/1000; // dmg each sec
tick = 1000; tick_total = 1000;
break; break;
case SC_EQC: case SC_EQC:
val2 = 5 * val1; // def % reduc val2 = 5 * val1; // def % reduc
@ -11824,17 +11827,17 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
val2 = ( val1 == 1 ? 6 : 6 - val1 ); val2 = ( val1 == 1 ? 6 : 6 - val1 );
val3 = 20; //+% AllStats val3 = 20; //+% AllStats
tick_time = 1000; tick_time = 1000;
val4 = tick / tick_time; val4 = tick_total / tick_time;
break; break;
case SC_REBOUND: case SC_REBOUND:
tick_time = 2000; tick_time = 2000;
val4 = tick / tick_time; val4 = tick_total / tick_time;
clif_emotion(bl, ET_SWEAT); clif_emotion(bl, ET_SWEAT);
break; break;
case SC_KINGS_GRACE: case SC_KINGS_GRACE:
val2 = 3 + val1; //HP Recover rate val2 = 3 + val1; //HP Recover rate
tick_time = 1000; tick_time = 1000;
val4 = tick / tick_time; val4 = tick_total / tick_time;
break; break;
case SC_TELEKINESIS_INTENSE: case SC_TELEKINESIS_INTENSE:
val2 = 10 * val1; // sp consum / casttime reduc % val2 = 10 * val1; // sp consum / casttime reduc %
@ -11848,7 +11851,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
val2 = 5 * val1; // maxhp bonus val2 = 5 * val1; // maxhp bonus
val3 = 80 + 20 * val1; // healing val3 = 80 + 20 * val1; // healing
tick_time = 1000; tick_time = 1000;
val4 = tick / tick_time; val4 = tick_total / tick_time;
break; break;
case SC_FLASHCOMBO: case SC_FLASHCOMBO:
val2 = 20 * val1 + 20; // atk bonus val2 = 20 * val1 + 20; // atk bonus
@ -11858,8 +11861,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC_UNLIMIT: case SC_UNLIMIT:
val2 = 50 * val1; val2 = 50 * val1;
status_change_start(bl, bl, SC_DEFSET, 10000, 1, 0, 0, 0, tick, SCSTART_NOTICKDEF); status_change_start(bl, bl, SC_DEFSET, 10000, 1, 0, 0, 0, tick_total, SCSTART_NOTICKDEF);
status_change_start(bl, bl, SC_MDEFSET, 10000, 1, 0, 0, 0, tick, SCSTART_NOTICKDEF); status_change_start(bl, bl, SC_MDEFSET, 10000, 1, 0, 0, 0, tick_total, SCSTART_NOTICKDEF);
break; break;
case SC_MONSTER_TRANSFORM: case SC_MONSTER_TRANSFORM:
case SC_ACTIVE_MONSTER_TRANSFORM: case SC_ACTIVE_MONSTER_TRANSFORM:
@ -11887,19 +11890,19 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_OVERHEAT: case SC_OVERHEAT:
case SC_OVERHEAT_LIMITPOINT: case SC_OVERHEAT_LIMITPOINT:
case SC_STEALTHFIELD: case SC_STEALTHFIELD:
tick_time = tick; tick_time = tick_total;
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
case SC_STEALTHFIELD_MASTER: case SC_STEALTHFIELD_MASTER:
tick_time = val3 = 2000 + 1000 * val1; tick_time = val3 = 2000 + 1000 * val1;
val4 = tick / tick_time; val4 = tick_total / tick_time;
break; break;
case SC_VACUUM_EXTREME: case SC_VACUUM_EXTREME:
// Suck target at n second, only if the n second is lower than the duration // Suck target at n second, only if the n second is lower than the duration
// Does not suck targets on no-knockback maps // Does not suck targets on no-knockback maps
if (val4 < tick && unit_blown_immune(bl, 0x9) == UB_KNOCKABLE) { if (val4 < tick_total && unit_blown_immune(bl, 0x9) == UB_KNOCKABLE) {
tick_time = val4; tick_time = val4;
val4 = tick - tick_time; val4 = tick_total - tick_time;
} else } else
val4 = 0; val4 = 0;
break; break;
@ -11908,11 +11911,11 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_WIND_INSIGNIA: case SC_WIND_INSIGNIA:
case SC_EARTH_INSIGNIA: case SC_EARTH_INSIGNIA:
tick_time = 5000; tick_time = 5000;
val4 = tick / tick_time; val4 = tick_total / tick_time;
break; break;
case SC_NEUTRALBARRIER: case SC_NEUTRALBARRIER:
val2 = 10 + val1 * 5; // Def/Mdef val2 = 10 + val1 * 5; // Def/Mdef
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
/* Rebellion */ /* Rebellion */
@ -11925,7 +11928,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
// val2 = src_id // val2 = src_id
val3 = 10; // -10 flee val3 = 10; // -10 flee
//Start timer to send mark on mini map //Start timer to send mark on mini map
val4 = tick/1000; val4 = tick_total/1000;
tick_time = 1000; // Sends every 1 seconds tick_time = 1000; // Sends every 1 seconds
break; break;
case SC_H_MINE: case SC_H_MINE:
@ -11971,7 +11974,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
val2 = (status_get_max_hp(bl) * (val1 + (b_status->dex / 25))) / status_get_max_hp(bl); // MHP% damage val2 = (status_get_max_hp(bl) * (val1 + (b_status->dex / 25))) / status_get_max_hp(bl); // MHP% damage
tick_time = 1000; tick_time = 1000;
val4 = tick / tick_time; val4 = tick_total / tick_time;
} }
break; break;
case SC_ARCLOUSEDASH: case SC_ARCLOUSEDASH:
@ -12018,7 +12021,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
val2 *= 2; // Doubles HP val2 *= 2; // Doubles HP
} }
tick_time = 10000 - ((val1 - 1) * 1000); tick_time = 10000 - ((val1 - 1) * 1000);
val4 = tick / tick_time; val4 = tick_total / tick_time;
} }
break; break;
case SC_TUNAPARTY: case SC_TUNAPARTY:
@ -12042,13 +12045,13 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_GOLDENMACECLAN: case SC_GOLDENMACECLAN:
case SC_CROSSBOWCLAN: case SC_CROSSBOWCLAN:
case SC_JUMPINGCLAN: case SC_JUMPINGCLAN:
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
status_change_start(src,bl,SC_CLAN_INFO,10000,0,val2,0,0,INFINITE_TICK,flag); status_change_start(src,bl,SC_CLAN_INFO,10000,0,val2,0,0,INFINITE_TICK,flag);
break; break;
case SC_DORAM_BUF_01: case SC_DORAM_BUF_01:
case SC_DORAM_BUF_02: case SC_DORAM_BUF_02:
tick_time = 10000; // every 10 seconds tick_time = 10000; // every 10 seconds
if( (val4 = tick/tick_time) < 1 ) if( (val4 = tick_total/tick_time) < 1 )
val4 = 1; val4 = 1;
break; break;
@ -12079,29 +12082,29 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC_HELPANGEL: case SC_HELPANGEL:
tick_time = 1000; tick_time = 1000;
val4 = tick / tick_time; val4 = tick_total / tick_time;
break; break;
case SC_SUNSTANCE: case SC_SUNSTANCE:
val2 = 2 + val1; // ATK Increase val2 = 2 + val1; // ATK Increase
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
case SC_LUNARSTANCE: case SC_LUNARSTANCE:
val2 = 2 + val1; // MaxHP Increase val2 = 2 + val1; // MaxHP Increase
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
case SC_STARSTANCE: case SC_STARSTANCE:
val2 = 4 + 2 * val1; // ASPD Increase val2 = 4 + 2 * val1; // ASPD Increase
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
case SC_UNIVERSESTANCE: case SC_UNIVERSESTANCE:
val2 = 2 + val1; // All Stats Increase val2 = 2 + val1; // All Stats Increase
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
case SC_NEWMOON: case SC_NEWMOON:
val2 = 7; // Number of Regular Attacks Until Reveal val2 = 7; // Number of Regular Attacks Until Reveal
tick_time = 1000; tick_time = 1000;
val4 = tick / tick_time; val4 = tick_total / tick_time;
break; break;
case SC_FALLINGSTAR: case SC_FALLINGSTAR:
val2 = 8 + 2 * (1 + val1) / 2; // Autocast Chance val2 = 8 + 2 * (1 + val1) / 2; // Autocast Chance
@ -12110,7 +12113,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC_CREATINGSTAR: case SC_CREATINGSTAR:
tick_time = 500; tick_time = 500;
val4 = tick / tick_time; val4 = tick_total / tick_time;
break; break;
case SC_LIGHTOFSUN: case SC_LIGHTOFSUN:
case SC_LIGHTOFMOON: case SC_LIGHTOFMOON:
@ -12143,7 +12146,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC_SOULUNITY: case SC_SOULUNITY:
tick_time = 3000; tick_time = 3000;
val4 = tick / tick_time; val4 = tick_total / tick_time;
break; break;
case SC_SOULDIVISION: case SC_SOULDIVISION:
val2 = 10 * val1; // Skill Aftercast Increase val2 = 10 * val1; // Skill Aftercast Increase
@ -12153,9 +12156,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC_SOULCOLLECT: case SC_SOULCOLLECT:
val2 = 5 + 3 * val2; // Max Soul Sphere's. val2 = 5 + 3 * val2; // Max Soul Sphere's.
val3 = tick > 0 ? tick : 60000; val3 = tick_total > 0 ? tick_total : 60000;
tick_time = tick; tick_time = tick_total;
tick = INFINITE_TICK; tick_total = INFINITE_TICK;
break; break;
case SC_SP_SHA: case SC_SP_SHA:
val2 = 50; // Move speed reduction val2 = 50; // Move speed reduction
@ -12192,21 +12195,21 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
case SC_BLEEDING: case SC_BLEEDING:
case SC_BURNING: case SC_BURNING:
case SC_TOXIN: case SC_TOXIN:
tick_time = tick; tick_time = tick_total;
tick = tick_time + max(val4, 0); tick_total = tick_time + max(val4, 0);
break; break;
case SC_DEATHHURT: case SC_DEATHHURT:
if (val3 == 1) if (val3 == 1)
break; break;
tick_time = tick; tick_time = tick_total;
tick = tick_time + max(val4, 0); tick_total = tick_time + max(val4, 0);
case SC_MAGICMUSHROOM: case SC_MAGICMUSHROOM:
case SC_PYREXIA: case SC_PYREXIA:
case SC_LEECHESEND: case SC_LEECHESEND:
if (val3 == 0) if (val3 == 0)
break; break;
tick_time = tick; tick_time = tick_total;
tick = tick_time + max(val4, 0); tick_total = tick_time + max(val4, 0);
break; break;
case SC_SWORDCLAN: case SC_SWORDCLAN:
case SC_ARCWANDCLAN: case SC_ARCWANDCLAN:
@ -12294,7 +12297,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
} }
if (current_equip_combo_pos && tick == INFINITE_TICK) { if (current_equip_combo_pos && tick_total == INFINITE_TICK) {
ShowWarning("sc_start: Item combo contains an INFINITE_TICK duration. Skipping bonus.\n"); ShowWarning("sc_start: Item combo contains an INFINITE_TICK duration. Skipping bonus.\n");
return 0; return 0;
} }
@ -12406,7 +12409,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
break; break;
case SC_ITEMSCRIPT: // Shows Buff Icons case SC_ITEMSCRIPT: // Shows Buff Icons
if (sd && val2 != EFST_BLANK) if (sd && val2 != EFST_BLANK)
clif_status_change(bl, (enum efst_types)val2, 1, tick, 0, 0, 0); clif_status_change(bl, (enum efst_types)val2, 1, tick_total, 0, 0, 0);
break; break;
} }
@ -12614,6 +12617,10 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
calc_flag&=~SCB_BODY; calc_flag&=~SCB_BODY;
}*/ }*/
t_tick tick = duration;
if (!(flag & SCSTART_LOADED))
tick = tick_total; // When starting a new SC (not loading), its remaining duration is the same as the total
if (!(flag&SCSTART_NOICON) && !(flag&SCSTART_LOADED && StatusDisplayType[type])) { if (!(flag&SCSTART_NOICON) && !(flag&SCSTART_LOADED && StatusDisplayType[type])) {
int status_icon = StatusIconChangeTable[type]; int status_icon = StatusIconChangeTable[type];
@ -12622,7 +12629,7 @@ 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 status_icon = EFST_ATTACK_PROPERTY_NOTHING + val1; // Assign status icon for older clients
#endif #endif
clif_status_change(bl, status_icon, 1, tick, (val_flag & 1) ? val1 : 1, (val_flag & 2) ? val2 : 0, (val_flag & 4) ? val3 : 0); clif_status_change_sub(bl, status_icon, 1, tick_total, tick, (val_flag & 1) ? val1 : 1, (val_flag & 2) ? val2 : 0, (val_flag & 4) ? val3 : 0);
} }
// Used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first. // Used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first.
@ -12646,6 +12653,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
sce->timer = add_timer(gettick() + tick, status_change_timer, bl->id, type); sce->timer = add_timer(gettick() + tick, status_change_timer, bl->id, type);
else else
sce->timer = INVALID_TIMER; // Infinite duration sce->timer = INVALID_TIMER; // Infinite duration
sce->tick_total = tick_total;
if (calc_flag) { if (calc_flag) {
if (sd) { if (sd) {
@ -12757,6 +12765,24 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
return 1; 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) {
return status_change_start_sub(src, bl, type, rate, val1, val2, val3, val4, 0, tick, flag);
}
/** /**
* End all statuses except those listed * End all statuses except those listed
* TODO: May be useful for dispel instead resetting a list there * TODO: May be useful for dispel instead resetting a list there

View File

@ -2571,6 +2571,7 @@ struct sc_display_entry {
struct status_change_entry { struct status_change_entry {
int timer; int timer;
int val1,val2,val3,val4; int val1,val2,val3,val4;
t_tick tick_total;
}; };
///Status change ///Status change
@ -2706,6 +2707,7 @@ t_tick status_get_sc_def(struct block_list *src,struct block_list *bl, enum sc_t
#define sc_start4(src, bl, type, rate, val1, val2, val3, val4, tick) status_change_start(src,bl,type,100*(rate),val1,val2,val3,val4,tick,SCSTART_NONE) #define sc_start4(src, bl, type, rate, val1, val2, val3, val4, tick) status_change_start(src,bl,type,100*(rate),val1,val2,val3,val4,tick,SCSTART_NONE)
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); 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);
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, unsigned char flag);
int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const char* file, int line); int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const char* file, int line);
#define status_change_end(bl,type,tid) status_change_end_(bl,type,tid,__FILE__,__LINE__) #define status_change_end(bl,type,tid) status_change_end_(bl,type,tid,__FILE__,__LINE__)
TIMER_FUNC(status_change_timer); TIMER_FUNC(status_change_timer);