Soul Reaper souls now persist relog (#5142)

* Fixes #5032.
* Soul Reaper souls will now persist relogs.
* Removed the soul_timer as the timer data is stored to the status change.
Thanks to @laziem and @Tokeiburu!
This commit is contained in:
Aleos 2020-06-29 13:49:01 -04:00 committed by GitHub
parent 87da34f28c
commit cef956d352
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 55 additions and 94 deletions

View File

@ -3492,22 +3492,21 @@ ACMD_FUNC(spiritball)
ACMD_FUNC(soulball)
{
uint32 max_soulballs = min(ARRAYLENGTH(sd->soul_timer), 0x7FFF);
int number;
nullpo_retr(-1, sd);
if (!message || !*message || (number = atoi(message)) < 0 || number > max_soulballs) {
if (!message || !*message || (number = atoi(message)) < 0 || number > MAX_SOUL_BALL) {
char msg[CHAT_SIZE_MAX];
safesnprintf(msg, sizeof(msg), "Usage: @soulball <number: 0-%d>", max_soulballs);
safesnprintf(msg, sizeof(msg), "Usage: @soulball <number: 0-%d>", MAX_SOUL_BALL);
clif_displaymessage(fd, msg);
return -1;
}
if (sd->soulball > 0)
pc_delsoulball(sd, sd->soulball, 1);
pc_delsoulball(sd, sd->soulball, true);
sd->soulball = number;
clif_soulball(sd);
// no message, player can see the difference
return 0;
}

View File

@ -1643,7 +1643,7 @@ int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Dam
if (tsd && (sce = tsc->data[SC_SOULREAPER])) {
if (rnd()%100 < sce->val2 && tsd->soulball < MAX_SOUL_BALL) {
clif_specialeffect(src, 1208, AREA);
pc_addsoulball(tsd, 0, 5 + 3 * pc_checkskill(tsd, SP_SOULENERGY));
pc_addsoulball(tsd, 5 + 3 * pc_checkskill(tsd, SP_SOULENERGY));
}
}
}

View File

@ -4635,11 +4635,11 @@ void clif_storageclose(struct map_session_data* sd)
/// Note: Spirit spheres and Soul spheres work on
/// seprate systems officially, but both send out
/// the same packet which leads to confusion on how
/// much soul energy a Soul Reaper acturally has
/// much soul energy a Soul Reaper actually has
/// should the player also have spirit spheres.
/// They will likely create a new packet for this soon
/// to seprate the animations for spirit and soul spheres.
/// For now well use this and replace it later when possible. [Rytech]
/// For now we'll use this and replace it later when possible. [Rytech]
///
/// 01d0 <id>.L <amount>.W (ZC_SPIRITS)
/// 01e1 <id>.L <amount>.W (ZC_SPIRITS2)

View File

@ -553,68 +553,30 @@ void pc_delspiritball(struct map_session_data *sd,int count,int type)
}
}
static TIMER_FUNC(pc_soulball_timer)
{
struct map_session_data *sd;
if ((sd = (struct map_session_data *)map_id2sd(id)) == nullptr || sd->bl.type != BL_PC)
return 1;
if (sd->soulball <= 0) {
ShowError("pc_soulball_timer: %d soulball's available. (aid=%d tid=%d)\n", sd->soulball, sd->status.account_id, tid);
sd->soulball = 0;
return 0;
}
int i;
ARR_FIND(0, sd->soulball, i, sd->soul_timer[i] == tid);
if (i == sd->soulball) {
ShowError("pc_soulball_timer: timer not found (aid=%d tid=%d)\n", sd->status.account_id, tid);
return 0;
}
sd->soulball--;
if (i != sd->soulball)
memmove(sd->soul_timer + i, sd->soul_timer + i + 1, (sd->soulball - i) * sizeof(int));
sd->soul_timer[sd->soulball] = INVALID_TIMER;
clif_soulball(sd);
return 0;
}
/**
* Adds a soulball to player for 'interval' ms
* Adds a soulball to player
* @param sd: Player data
* @param interval: Duration
* @param max: Max amount of soulballs
*/
int pc_addsoulball(struct map_session_data *sd, int interval, int max)
int pc_addsoulball(map_session_data *sd, int max)
{
nullpo_ret(sd);
status_change *sc = status_get_sc(&sd->bl);
if (sc == nullptr || sc->data[SC_SOULENERGY] == nullptr) {
sc_start(&sd->bl, &sd->bl, SC_SOULENERGY, 100, 0, skill_get_time2(SP_SOULCOLLECT, 1));
sd->soulball = 0;
}
max = min(max, MAX_SOUL_BALL);
sd->soulball = cap_value(sd->soulball, 0, MAX_SOUL_BALL);
if (sd->soulball && sd->soulball >= max) {
if (sd->soul_timer[0] != INVALID_TIMER)
delete_timer(sd->soul_timer[0], pc_soulball_timer);
if (sd->soulball && sd->soulball >= max)
sd->soulball--;
if (sd->soulball != 0)
memmove(sd->soul_timer + 0, sd->soul_timer + 1, (sd->soulball) * sizeof(int));
sd->soul_timer[sd->soulball] = INVALID_TIMER;
}
if (interval > 0) {
int tid = add_timer(gettick() + interval, pc_soulball_timer, sd->bl.id, 0), i;
ARR_FIND(0, sd->soulball, i, sd->soul_timer[i] == INVALID_TIMER || DIFF_TICK(get_timer(tid)->tick, get_timer(sd->soul_timer[i])->tick) < 0);
if (i != sd->soulball)
memmove(sd->soul_timer + i + 1, sd->soul_timer + i, (sd->soulball - i) * sizeof(int));
sd->soul_timer[i] = tid;
}
sd->soulball++;
sc_start(&sd->bl, &sd->bl, SC_SOULENERGY, 100, sd->soulball, skill_get_time2(SP_SOULCOLLECT, 1));
clif_soulball(sd);
return 0;
@ -624,37 +586,27 @@ int pc_addsoulball(struct map_session_data *sd, int interval, int max)
* Removes number of soulball from player
* @param sd: Player data
* @param count: Amount to remove
* @param type: 1 = doesn't give client effect
* @param type: true = doesn't give client effect
*/
int pc_delsoulball(struct map_session_data *sd, int count, int type)
int pc_delsoulball(map_session_data *sd, int count, bool type)
{
nullpo_ret(sd);
if (sd->soulball <= 0) {
sd->soulball = 0;
return 0;
}
if (count <= 0)
return 0;
if (count > sd->soulball)
count = sd->soulball;
sd->soulball -= count;
if (count > MAX_SOUL_BALL)
count = MAX_SOUL_BALL;
status_change *sc = status_get_sc(&sd->bl);
for (int i = 0; i < count; i++) {
if (sd->soul_timer[i] != INVALID_TIMER) {
delete_timer(sd->soul_timer[i], pc_soulball_timer);
sd->soul_timer[i] = INVALID_TIMER;
}
if (sd->soulball <= 0 || sc == nullptr || sc->data[SC_SOULENERGY] == nullptr) {
sd->soulball = 0;
return 0;
}
for (int i = count; i < MAX_SOUL_BALL; i++) {
sd->soul_timer[i - count] = sd->soul_timer[i];
sd->soul_timer[i] = INVALID_TIMER;
}
sd->soulball -= cap_value(count, 0, sd->soulball);
if (sd->soulball == 0)
status_change_end(&sd->bl, SC_SOULENERGY, INVALID_TIMER);
else
sc->data[SC_SOULENERGY]->val1 = sd->soulball;
if (!type)
clif_soulball(sd);
@ -1562,8 +1514,6 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_
for(i = 0; i < MAX_SPIRITBALL; i++)
sd->spirit_timer[i] = INVALID_TIMER;
for (i = 0; i < MAX_SOUL_BALL; i++)
sd->soul_timer[i] = INVALID_TIMER;
if (battle_config.item_auto_get)
sd->state.autoloot = 10000;
@ -8333,7 +8283,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
if ( sd->spiritball !=0 )
pc_delspiritball(sd,sd->spiritball,0);
if (sd->soulball != 0)
pc_delsoulball(sd, sd->soulball, 0);
pc_delsoulball(sd, sd->soulball, false);
if (sd->spiritcharm_type != CHARM_TYPE_NONE && sd->spiritcharm > 0)
pc_delspiritcharm(sd,sd->spiritcharm,sd->spiritcharm_type);
@ -12586,6 +12536,9 @@ void pc_scdata_received(struct map_session_data *sd) {
sd->cart_weight_max = 0; // Force a client refesh
status_calc_cart_weight(sd, (e_status_calc_weight_opt)(CALCWT_ITEM|CALCWT_MAXBONUS|CALCWT_CARTSTATE));
}
if (sd->sc.data[SC_SOULENERGY])
sd->soulball = sd->sc.data[SC_SOULENERGY]->val1;
}
/**
@ -13526,7 +13479,6 @@ void do_init_pc(void) {
add_timer_func_list(pc_calc_pvprank_timer, "pc_calc_pvprank_timer");
add_timer_func_list(pc_autosave, "pc_autosave");
add_timer_func_list(pc_spiritball_timer, "pc_spiritball_timer");
add_timer_func_list(pc_soulball_timer, "pc_soulball_timer");
add_timer_func_list(pc_follow_timer, "pc_follow_timer");
add_timer_func_list(pc_endautobonus, "pc_endautobonus");
add_timer_func_list(pc_spiritcharm_timer, "pc_spiritcharm_timer");

View File

@ -541,7 +541,6 @@ struct map_session_data {
int spiritcharm_type; //Spirit type
int spiritcharm_timer[MAX_SPIRITCHARM];
int8 soulball, soulball_old;
int soul_timer[MAX_SOUL_BALL];
unsigned char potion_success_counter; //Potion successes in row counter
unsigned char mission_count; //Stores the bounty kill count for TK_MISSION
@ -1321,8 +1320,8 @@ void pc_delinvincibletimer(struct map_session_data* sd);
void pc_addspiritball(struct map_session_data *sd,int interval,int max);
void pc_delspiritball(struct map_session_data *sd,int count,int type);
int pc_addsoulball(struct map_session_data *sd,int interval,int max);
int pc_delsoulball(struct map_session_data *sd,int count,int type);
int pc_addsoulball(map_session_data *sd, int max);
int pc_delsoulball(map_session_data *sd, int count, bool type);
void pc_addfame(struct map_session_data *sd,int count);
unsigned char pc_famerank(uint32 char_id, int job);

View File

@ -2034,7 +2034,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
case SC_DRESSUP: case SC_HANBOK: case SC_OKTOBERFEST:
case SC_LHZ_DUN_N1: case SC_LHZ_DUN_N2: case SC_LHZ_DUN_N3: case SC_LHZ_DUN_N4:
case SC_ENTRY_QUEUE_APPLY_DELAY: case SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT:
case SC_REUSE_LIMIT_LUXANIMA: case SC_LUXANIMA:
case SC_REUSE_LIMIT_LUXANIMA: case SC_LUXANIMA: case SC_SOULENERGY:
continue;
case SC_WHISTLE: case SC_ASSNCROS: case SC_POEMBRAGI:
case SC_APPLEIDUN: case SC_HUMMING: case SC_DONTFORGETME:
@ -8515,7 +8515,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case SC_WEDDING: case SC_XMAS: case SC_SUMMER:
case SC_DRESSUP: case SC_HANBOK: case SC_OKTOBERFEST:
case SC_LHZ_DUN_N1: case SC_LHZ_DUN_N2: case SC_LHZ_DUN_N3: case SC_LHZ_DUN_N4:
case SC_REUSE_LIMIT_LUXANIMA: case SC_LUXANIMA:
case SC_REUSE_LIMIT_LUXANIMA: case SC_LUXANIMA: case SC_SOULENERGY:
continue;
case SC_WHISTLE:
case SC_ASSNCROS:
@ -10002,7 +10002,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case SC_DRESSUP: case SC_HANBOK: case SC_OKTOBERFEST:
case SC_LHZ_DUN_N1: case SC_LHZ_DUN_N2: case SC_LHZ_DUN_N3: case SC_LHZ_DUN_N4:
case SC_ENTRY_QUEUE_APPLY_DELAY: case SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT:
case SC_REUSE_LIMIT_LUXANIMA: case SC_LUXANIMA:
case SC_REUSE_LIMIT_LUXANIMA: case SC_LUXANIMA: case SC_SOULENERGY:
continue;
case SC_ASSUMPTIO:
if( bl->type == BL_MOB )
@ -16728,7 +16728,7 @@ void skill_consume_requirement(struct map_session_data *sd, uint16 skill_id, uin
case SP_SOULREAPER:
case SP_SOULEXPLOSION:
case SP_KAUTE:
pc_delsoulball(sd, require.spiritball, 0);
pc_delsoulball(sd, require.spiritball, false);
break;
default: // Skills that require spirit/coin spheres.

View File

@ -1390,6 +1390,11 @@ void initChangeTables(void)
StatusIconChangeTable[SC_ENTRY_QUEUE_APPLY_DELAY] = EFST_ENTRY_QUEUE_APPLY_DELAY;
StatusIconChangeTable[SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT] = EFST_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT;
// Soul Reaper
StatusIconChangeTable[SC_SOULENERGY] = EFST_SOULENERGY;
StatusIconChangeTable[SC_USE_SKILL_SP_SPA] = EFST_USE_SKILL_SP_SPA;
StatusIconChangeTable[SC_USE_SKILL_SP_SHA] = EFST_USE_SKILL_SP_SHA;
/* Other SC which are not necessarily associated to skills */
StatusChangeFlagTable[SC_ASPDPOTION0] |= SCB_ASPD;
StatusChangeFlagTable[SC_ASPDPOTION1] |= SCB_ASPD;
@ -1558,8 +1563,9 @@ void initChangeTables(void)
StatusChangeFlagTable[SC_DORAM_BUF_02] |= SCB_REGEN;
// Soul Reaper
StatusIconChangeTable[SC_USE_SKILL_SP_SPA] = EFST_USE_SKILL_SP_SPA;
StatusIconChangeTable[SC_USE_SKILL_SP_SHA] = EFST_USE_SKILL_SP_SHA;
StatusChangeFlagTable[SC_SOULENERGY] |= SCB_NONE;
StatusChangeFlagTable[SC_USE_SKILL_SP_SPA] |= SCB_NONE;
StatusChangeFlagTable[SC_USE_SKILL_SP_SHA] |= SCB_NONE;
StatusChangeFlagTable[SC_ANCILLA] |= SCB_REGEN;
StatusChangeFlagTable[SC_ENSEMBLEFATIGUE] |= SCB_SPEED|SCB_ASPD;
@ -12883,6 +12889,7 @@ int status_change_clear(struct block_list* bl, int type)
case SC_ENTRY_QUEUE_APPLY_DELAY:
case SC_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT:
case SC_REUSE_LIMIT_LUXANIMA:
case SC_SOULENERGY:
// Costumes
case SC_MOONSTAR:
case SC_SUPER_STAR:
@ -13567,6 +13574,10 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
case SC_JUMPINGCLAN:
status_change_end(bl,SC_CLAN_INFO,INVALID_TIMER);
break;
case SC_SOULENERGY:
if (sd)
pc_delsoulball(sd, sd->soulball, false);
break;
}
opt_flag = 1;
@ -14778,8 +14789,8 @@ TIMER_FUNC(status_change_timer){
}
break;
case SC_SOULCOLLECT:
pc_addsoulball(sd, skill_get_time2(SP_SOULCOLLECT, sce->val1), sce->val2);
if( sd->soulball < sce->val2 ){
pc_addsoulball(sd, sce->val2);
if (sd->soulball < sce->val2) {
sc_timer_next(sce->val3 + tick);
return 0;
}
@ -15028,6 +15039,7 @@ void status_change_clear_buffs(struct block_list* bl, uint8 type)
case SC_LHZ_DUN_N4:
case SC_REUSE_LIMIT_LUXANIMA:
case SC_LUXANIMA:
case SC_SOULENERGY:
// Clans
case SC_CLAN_INFO:
case SC_SWORDCLAN:

View File

@ -3364,7 +3364,6 @@ int unit_free(struct block_list *bl, clr_type clrtype)
pc_inventory_rental_clear(sd);
pc_delspiritball(sd, sd->spiritball, 1);
pc_delspiritcharm(sd, sd->spiritcharm, sd->spiritcharm_type);
pc_delsoulball(sd,sd->soulball, 1);
if( sd->st && sd->st->state != RUN ) {// free attached scripts that are waiting
script_free_state(sd->st);