diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index c518459e57..a278576c83 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -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 ", max_soulballs); + + safesnprintf(msg, sizeof(msg), "Usage: @soulball ", 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; } diff --git a/src/map/battle.cpp b/src/map/battle.cpp index df20fc8177..b60955e6c2 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -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)); } } } diff --git a/src/map/clif.cpp b/src/map/clif.cpp index f968926c22..84cf82671d 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -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 .L .W (ZC_SPIRITS) /// 01e1 .L .W (ZC_SPIRITS2) diff --git a/src/map/pc.cpp b/src/map/pc.cpp index eb4eff443b..423242ea44 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -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"); diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 61c5288705..261141c0f9 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -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); diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 8000ab7eb8..62953736bb 100755 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -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. diff --git a/src/map/status.cpp b/src/map/status.cpp index fbdbc3bab1..c15cc6f919 100644 --- a/src/map/status.cpp +++ b/src/map/status.cpp @@ -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: diff --git a/src/map/unit.cpp b/src/map/unit.cpp index 2a08bef2de..eba9de6b31 100644 --- a/src/map/unit.cpp +++ b/src/map/unit.cpp @@ -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);