diff options
Diffstat (limited to 'src/map')
-rw-r--r-- | src/map/atcommand.c | 6 | ||||
-rw-r--r-- | src/map/battle.c | 72 | ||||
-rw-r--r-- | src/map/battle.h | 2 | ||||
-rw-r--r-- | src/map/clif.c | 7 | ||||
-rw-r--r-- | src/map/map.c | 24 | ||||
-rw-r--r-- | src/map/map.h | 1 | ||||
-rw-r--r-- | src/map/npc.c | 2 | ||||
-rw-r--r-- | src/map/pc.c | 11 | ||||
-rw-r--r-- | src/map/script.c | 28 | ||||
-rw-r--r-- | src/map/skill.c | 105 | ||||
-rw-r--r-- | src/map/status.c | 178 | ||||
-rw-r--r-- | src/map/status.h | 20 | ||||
-rw-r--r-- | src/map/unit.c | 2 |
13 files changed, 280 insertions, 178 deletions
diff --git a/src/map/atcommand.c b/src/map/atcommand.c index e6f022a10..179b96c32 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -1135,7 +1135,7 @@ ACMD(heal) } if ( hp > 0 && sp >= 0 ) { - if(!status->heal(&sd->bl, hp, sp, 0)) + if (status->heal(&sd->bl, hp, sp, STATUS_HEAL_DEFAULT) == 0) clif->message(fd, msg_fd(fd,157)); // HP and SP are already with the good value. else clif->message(fd, msg_fd(fd,17)); // HP, SP recovered. @@ -1152,7 +1152,7 @@ ACMD(heal) //Opposing signs. if ( hp ) { if (hp > 0) - status->heal(&sd->bl, hp, 0, 0); + status->heal(&sd->bl, hp, 0, STATUS_HEAL_DEFAULT); else { status->damage(NULL, &sd->bl, -hp, 0, 0, 0); clif->damage(&sd->bl,&sd->bl, 0, 0, -hp, 0, BDT_ENDURE, 0); @@ -1161,7 +1161,7 @@ ACMD(heal) if ( sp ) { if (sp > 0) - status->heal(&sd->bl, 0, sp, 0); + status->heal(&sd->bl, 0, sp, STATUS_HEAL_DEFAULT); else status->damage(NULL, &sd->bl, 0, -sp, 0, 0); } diff --git a/src/map/battle.c b/src/map/battle.c index 44241bf23..f51240810 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -1365,24 +1365,28 @@ static int64 battle_calc_defense(int attack_type, struct block_list *src, struct #endif } - if( battle_config.vit_penalty_type && battle_config.vit_penalty_target&target->type ) { - unsigned char target_count; //256 max targets should be a sane max - target_count = unit->counttargeted(target); - if(target_count >= battle_config.vit_penalty_count) { - if(battle_config.vit_penalty_type == 1) { - if( !tsc || !tsc->data[SC_STEELBODY] ) - def1 = (def1 * (100 - (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num))/100; - def2 = (def2 * (100 - (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num))/100; - } else { //Assume type 2 - if( !tsc || !tsc->data[SC_STEELBODY] ) - def1 -= (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num; - def2 -= (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num; + if (battle_config.vit_penalty_type != 0 && (battle_config.vit_penalty_target & target->type) != 0) { + int target_count = unit->counttargeted(target); + if (target_count >= battle_config.vit_penalty_count) { + int penalty = (target_count - (battle_config.vit_penalty_count - 1)) * battle_config.vit_penalty_num; + if (battle_config.vit_penalty_type == 1) { + if (tsc == NULL || tsc->data[SC_STEELBODY] == NULL) + def1 = def1 * (100 - penalty) / 100; + def2 = def2 * (100 - penalty) / 100; + } else { // Assume type 2 + if (tsc == NULL || tsc->data[SC_STEELBODY] == NULL) + def1 -= penalty; + def2 -= penalty; } } #ifndef RENEWAL - if(skill_id == AM_ACIDTERROR) def1 = 0; //Acid Terror ignores only armor defense. [Skotlex] + if (skill_id == AM_ACIDTERROR) + def1 = 0; // Acid Terror ignores only armor defense. [Skotlex] #endif - if(def2 < 1) def2 = 1; + if (def1 < 0) + def1 = 0; + if (def2 < 1) + def2 = 1; } //Vitality reduction from rodatazone: http://rodatazone.simgaming.net/mechanics/substats.php#def if (tsd) { @@ -2872,7 +2876,7 @@ static int64 battle_calc_damage(struct block_list *src, struct block_list *bl, s if( sc->data[SC__MAELSTROM] && (flag&BF_MAGIC) && skill_id && (skill->get_inf(skill_id)&INF_GROUND_SKILL) ) { // {(Maelstrom Skill LevelxAbsorbed Skill Level)+(Caster's Job/5)}/2 int sp = (sc->data[SC__MAELSTROM]->val1 * skill_lv + (t_sd ? t_sd->status.job_level / 5 : 0)) / 2; - status->heal(bl, 0, sp, 3); + status->heal(bl, 0, sp, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT); d->dmg_lv = ATK_BLOCK; return 0; } @@ -3243,7 +3247,7 @@ static int64 battle_calc_damage(struct block_list *src, struct block_list *bl, s //(since battle_drain is strictly for players currently) if ((sce=sc->data[SC_HAMI_BLOODLUST]) && flag&BF_WEAPON && damage > 0 && rnd()%100 < sce->val3) - status->heal(src, damage*sce->val4/100, 0, 3); + status->heal(src, damage*sce->val4/100, 0, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT); if( (sce = sc->data[SC_FORCEOFVANGUARD]) && flag&BF_WEAPON && rnd()%100 < sce->val2 && sc->fv_counter <= sce->val3 ) @@ -4224,16 +4228,16 @@ static struct Damage battle_calc_misc_attack(struct block_list *src, struct bloc hitrate = 80; //Default hitrate #endif - if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) { - unsigned char attacker_count; //256 max targets should be a sane max - attacker_count = unit->counttargeted(target); - if(attacker_count >= battle_config.agi_penalty_count) - { + if (battle_config.agi_penalty_type != 0 && (battle_config.agi_penalty_target & target->type) != 0) { + int attacker_count = unit->counttargeted(target); + if (attacker_count >= battle_config.agi_penalty_count) { + int penalty = (attacker_count - (battle_config.agi_penalty_count - 1)) * battle_config.agi_penalty_num; if (battle_config.agi_penalty_type == 1) - flee = (flee * (100 - (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num))/100; + flee = flee * (100 - penalty) / 100; else // assume type 2: absolute reduction - flee -= (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num; - if(flee < 1) flee = 1; + flee -= penalty; + if (flee < 1) + flee = 1; } } @@ -4751,15 +4755,16 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl short hitrate = 80; //Default hitrate #endif - if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) { - unsigned char attacker_count; //256 max targets should be a sane max - attacker_count = unit->counttargeted(target); - if(attacker_count >= battle_config.agi_penalty_count) { + if (battle_config.agi_penalty_type != 0 && (battle_config.agi_penalty_target & target->type) != 0) { + int attacker_count = unit->counttargeted(target); + if (attacker_count >= battle_config.agi_penalty_count) { + int penalty = (attacker_count - (battle_config.agi_penalty_count - 1)) * battle_config.agi_penalty_num; if (battle_config.agi_penalty_type == 1) - flee = (flee * (100 - (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num))/100; - else //asume type 2: absolute reduction - flee -= (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num; - if(flee < 1) flee = 1; + flee = flee * (100 - penalty) / 100; + else // asume type 2: absolute reduction + flee -= penalty; + if (flee < 1) + flee = 1; } } @@ -6094,7 +6099,7 @@ static void battle_drain(struct map_session_data *sd, struct block_list *tbl, in if (!thp && !tsp) return; - status->heal(&sd->bl, thp, tsp, battle_config.show_hp_sp_drain ? 3 : 1); + status->heal(&sd->bl, thp, tsp, STATUS_HEAL_FORCED | (battle_config.show_hp_sp_drain ? STATUS_HEAL_SHOWEFFECT : STATUS_HEAL_DEFAULT)); if (rhp || rsp) status_zap(tbl, rhp, rsp); @@ -7407,6 +7412,7 @@ static const struct battle_data { { "features/feature_attendance_endtime",&battle_config.feature_attendance_endtime, 1, 0, 99999999, }, { "min_item_buy_price", &battle_config.min_item_buy_price, 1, 0, INT_MAX, }, { "min_item_sell_price", &battle_config.min_item_sell_price, 0, 0, INT_MAX, }, + { "display_fake_hp_when_dead", &battle_config.display_fake_hp_when_dead, 1, 0, 1, }, }; static bool battle_set_value_sub(int index, int value) diff --git a/src/map/battle.h b/src/map/battle.h index 02536e4a1..750753c08 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -574,6 +574,8 @@ struct Battle_Config { int min_item_buy_price; int min_item_sell_price; + + int display_fake_hp_when_dead; }; /* criteria for battle_config.idletime_critera */ diff --git a/src/map/clif.c b/src/map/clif.c index 19e90237f..ebf667af0 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -3245,7 +3245,12 @@ static void clif_updatestatus(struct map_session_data *sd, int type) WFIFOL(fd,4)=sd->battle_status.max_sp; break; case SP_HP: - WFIFOL(fd,4)=sd->battle_status.hp; + if (sd->battle_status.hp == 0 && battle_config.display_fake_hp_when_dead) { + // On official servers, the HP displayed when dead is the HP that the character will have at respawn. + WFIFOL(fd, 4) = status->get_restart_hp(sd, &sd->battle_status); + } else { + WFIFOL(fd, 4) = sd->battle_status.hp; + } break; case SP_SP: WFIFOL(fd,4)=sd->battle_status.sp; diff --git a/src/map/map.c b/src/map/map.c index a352d34b0..d4d6e3323 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -3707,7 +3707,7 @@ static void map_zonedb_reload(void) { // first, reset maps to their initial zones: for (int i = 0; i < map->count; i++) { - map->zone_remove(i); + map->zone_remove_all(i); if (battle_config.pk_mode) { map->list[i].flag.pvp = 1; @@ -4688,6 +4688,27 @@ static void map_zone_remove(int m) map->list[m].zone_mf = NULL; map->list[m].zone_mf_count = 0; } +// this one removes every flag, even if they were previously turned on before +// the current zone was applied +static void map_zone_remove_all(int m) +{ + Assert_retv(m >= 0 && m < map->count); + + for (unsigned short k = 0; k < map->list[m].zone_mf_count; k++) { + char flag[MAP_ZONE_MAPFLAG_LENGTH]; + + memcpy(flag, map->list[m].zone_mf[k], MAP_ZONE_MAPFLAG_LENGTH); + strtok(flag, "\t"); + + npc->parse_mapflag(map->list[m].name, "", flag, "off", "", "", "", NULL); + aFree(map->list[m].zone_mf[k]); + map->list[m].zone_mf[k] = NULL; + } + + aFree(map->list[m].zone_mf); + map->list[m].zone_mf = NULL; + map->list[m].zone_mf_count = 0; +} static inline void map_zone_mf_cache_add(int m, char *rflag) { Assert_retv(m >= 0 && m < map->count); @@ -6840,6 +6861,7 @@ void map_defaults(void) /* funcs */ map->zone_init = map_zone_init; map->zone_remove = map_zone_remove; + map->zone_remove_all = map_zone_remove_all; map->zone_apply = map_zone_apply; map->zone_change = map_zone_change; map->zone_change2 = map_zone_change2; diff --git a/src/map/map.h b/src/map/map.h index 0e38bdb13..4267c2c88 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -1220,6 +1220,7 @@ END_ZEROED_BLOCK; /* funcs */ void (*zone_init) (void); void (*zone_remove) (int m); + void (*zone_remove_all) (int m); void (*zone_apply) (int m, struct map_zone_data *zone, const char* start, const char* buffer, const char* filepath); void (*zone_change) (int m, struct map_zone_data *zone, const char* start, const char* buffer, const char* filepath); void (*zone_change2) (int m, struct map_zone_data *zone); diff --git a/src/map/npc.c b/src/map/npc.c index a8bf7d371..7f57a9c50 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -4971,6 +4971,7 @@ static int npc_reload(void) npc->npc_mob = npc->npc_cache_mob = npc->npc_delay_mob = 0; // reset mapflags + map->zone_reload(); map->flags_init(); // Reprocess npc files and reload constants @@ -4980,7 +4981,6 @@ static int npc_reload(void) instance->reload(); - map->zone_reload(); map->zone_init(); npc->motd = npc->name2id("HerculesMOTD"); /* [Ind/Hercules] */ diff --git a/src/map/pc.c b/src/map/pc.c index b8a6912ee..78b773550 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -399,7 +399,7 @@ static int pc_banding(struct map_session_data *sd, uint16 skill_lv) for( j = 0; j < i; j++ ) { bsd = map->id2sd(b_sd[j]); if( bsd != NULL ) { - status->set_hp(&bsd->bl,hp,0); // Set hp + status->set_hp(&bsd->bl, hp, STATUS_HEAL_DEFAULT); // Set hp if( (sc = status->get_sc(&bsd->bl)) != NULL && sc->data[SC_BANDING] ) { sc->data[SC_BANDING]->val2 = c; // Set the counter. It doesn't count your self. status_calc_bl(&bsd->bl, status->sc2scb_flag(SC_BANDING)); // Set atk and def. @@ -523,10 +523,9 @@ static int pc_setrestartvalue(struct map_session_data *sd, int type) if (type&1) { //Normal resurrection - st->hp = 1; //Otherwise status->heal may fail if dead. - status->heal(&sd->bl, bst->hp, 0, 1); + status->heal(&sd->bl, bst->hp, 0, STATUS_HEAL_FORCED | STATUS_HEAL_ALLOWREVIVE); if( st->sp < bst->sp ) - status->set_sp(&sd->bl, bst->sp, 1); + status->set_sp(&sd->bl, bst->sp, STATUS_HEAL_FORCED); } else { //Just for saving on the char-server (with values as if respawned) sd->status.hp = bst->hp; sd->status.sp = (st->sp < bst->sp) ? bst->sp : st->sp; @@ -8827,7 +8826,7 @@ static int pc_itemheal(struct map_session_data *sd, int itemid, int hp, int sp) } } - return status->heal(&sd->bl, hp, sp, 1); + return status->heal(&sd->bl, hp, sp, STATUS_HEAL_FORCED); } /*========================================== @@ -10878,7 +10877,7 @@ static void pc_regen(struct map_session_data *sd, unsigned int diff_tick) } if (hp > 0 || sp > 0) - status->heal(&sd->bl, hp, sp, 0); + status->heal(&sd->bl, hp, sp, STATUS_HEAL_DEFAULT); return; } diff --git a/src/map/script.c b/src/map/script.c index 8c09bb8d8..41f21cd72 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -6855,7 +6855,7 @@ static BUILDIN(heal) hp=script_getnum(st,2); sp=script_getnum(st,3); - status->heal(&sd->bl, hp, sp, 1); + status->heal(&sd->bl, hp, sp, STATUS_HEAL_FORCED); return true; } /*========================================== @@ -18781,7 +18781,7 @@ static BUILDIN(setunitdata) md->level = val; break; case UDT_HP: - status->set_hp(bl, (unsigned int) val, 0); + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); clif->charnameack(0, &md->bl); break; case UDT_MAXHP: @@ -18789,7 +18789,7 @@ static BUILDIN(setunitdata) clif->charnameack(0, &md->bl); break; case UDT_SP: - status->set_sp(bl, (unsigned int) val, 0); + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXSP: md->status.max_sp = (unsigned int) val; @@ -18950,13 +18950,13 @@ static BUILDIN(setunitdata) hd->homunculus.level = (short) val; break; case UDT_HP: - status->set_hp(bl, (unsigned int) val, 0); + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXHP: hd->homunculus.max_hp = val; break; case UDT_SP: - status->set_sp(bl, (unsigned int) val, 0); + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXSP: hd->homunculus.max_sp = val; @@ -19089,13 +19089,13 @@ static BUILDIN(setunitdata) pd->pet.level = (short) val; break; case UDT_HP: - status->set_hp(bl, (unsigned int) val, 0); + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXHP: pd->status.max_hp = (unsigned int) val; break; case UDT_SP: - status->set_sp(bl, (unsigned int) val, 0); + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXSP: pd->status.max_sp = (unsigned int) val; @@ -19223,13 +19223,13 @@ static BUILDIN(setunitdata) mc->base_status.size = (unsigned char) val; break; case UDT_HP: - status->set_hp(bl, (unsigned int) val, 0); + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXHP: mc->base_status.max_hp = (unsigned int) val; break; case UDT_SP: - status->set_sp(bl, (unsigned int) val, 0); + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXSP: mc->base_status.max_sp = (unsigned int) val; @@ -19357,13 +19357,13 @@ static BUILDIN(setunitdata) ed->base_status.size = (unsigned char) val; break; case UDT_HP: - status->set_hp(bl, (unsigned int) val, 0); + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXHP: ed->base_status.max_hp = (unsigned int) val; break; case UDT_SP: - status->set_sp(bl, (unsigned int) val, 0); + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXSP: ed->base_status.max_sp = (unsigned int) val; @@ -19489,13 +19489,13 @@ static BUILDIN(setunitdata) nd->level = (unsigned short) val; break; case UDT_HP: - status->set_hp(bl, (unsigned int) val, 0); + status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXHP: nd->status.max_hp = (unsigned int) val; break; case UDT_SP: - status->set_sp(bl, (unsigned int) val, 0); + status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT); break; case UDT_MAXSP: nd->status.max_sp = (unsigned int) val; @@ -20806,7 +20806,7 @@ static BUILDIN(mercenary_heal) hp = script_getnum(st,2); sp = script_getnum(st,3); - status->heal(&sd->md->bl, hp, sp, 0); + status->heal(&sd->md->bl, hp, sp, STATUS_HEAL_DEFAULT); return true; } diff --git a/src/map/skill.c b/src/map/skill.c index 9857badbe..8410a77d0 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -2361,11 +2361,11 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_ ) { // Soul Drain should only work on targeted spells [Skotlex] if( pc_issit(sd) ) pc->setstand(sd); // Character stuck in attacking animation while 'sitting' fix. [Skotlex] - if( skill->get_nk(skill_id)&NK_SPLASH && skill->area_temp[1] != bl->id ) + if (skill->get_nk(skill_id)&NK_SPLASH && skill->area_temp[1] != bl->id) { ; - else { + } else { clif->skill_nodamage(src,bl,HW_SOULDRAIN,rate,1); - status->heal(src, 0, status->get_lv(bl)*(95+15*rate)/100, 2); + status->heal(src, 0, status->get_lv(bl)*(95+15*rate)/100, STATUS_HEAL_SHOWEFFECT); } } @@ -2388,9 +2388,9 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_ sc->data[SC_SOULLINK]->val3 = 0; //Clear bounced spell check. } } - if( hp || sp ) { + if (hp != 0 || sp != 0) { // updated to force healing to allow healing through berserk - status->heal(src, hp, sp, battle_config.show_hp_sp_gain ? 3 : 1); + status->heal(src, hp, sp, STATUS_HEAL_FORCED | (battle_config.show_hp_sp_gain ? STATUS_HEAL_SHOWEFFECT : STATUS_HEAL_DEFAULT)); } } @@ -2899,7 +2899,7 @@ static int skill_attack(int attack_type, struct block_list *src, struct block_li sp = sp * sc->data[SC_MAGICROD]->val2 / 100; if(skill_id == WZ_WATERBALL && skill_lv > 1) sp = sp/((skill_lv|1)*(skill_lv|1)); //Estimate SP cost of a single water-ball - status->heal(bl, 0, sp, 2); + status->heal(bl, 0, sp, STATUS_HEAL_SHOWEFFECT); } } @@ -4477,7 +4477,7 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl if( skill_id == MO_EXTREMITYFIST ) { mbl = src; i = 3; // for Asura(from caster) - status->set_sp(src, 0, 0); + status->set_sp(src, 0, STATUS_HEAL_DEFAULT); status_change_end(src, SC_EXPLOSIONSPIRITS, INVALID_TIMER); status_change_end(src, SC_BLADESTOP, INVALID_TIMER); #ifdef RENEWAL @@ -4487,9 +4487,9 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl status_change_end(src, SC_NJ_NEN, INVALID_TIMER); status_change_end(src, SC_HIDING, INVALID_TIMER); #ifdef RENEWAL - status->set_hp(src, max(status_get_max_hp(src)/100, 1), 0); + status->set_hp(src, max(status_get_max_hp(src)/100, 1), STATUS_HEAL_DEFAULT); #else // not RENEWAL - status->set_hp(src, 1, 0); + status->set_hp(src, 1, STATUS_HEAL_DEFAULT); #endif // RENEWAL } dir = map->calc_dir(src,bl->x,bl->y); @@ -4603,7 +4603,7 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl heal = skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, sflag); if (skill_id == NPC_VAMPIRE_GIFT && heal > 0) { clif->skill_nodamage(NULL, src, AL_HEAL, heal, 1); - status->heal(src,heal,0,0); + status->heal(src, heal, 0, STATUS_HEAL_DEFAULT); } if (skill_id == SU_SCRATCH && status->get_lv(src) >= 30 && (rnd() % 100 < (int)(status->get_lv(src) / 30) + 10)) // TODO: Need activation chance. skill->addtimerskill(src, tick + skill->get_delay(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag); @@ -4971,7 +4971,7 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl src, src, bl, skill_id, skill_lv, tick, flag); if (heal > 0){ clif->skill_nodamage(NULL, src, AL_HEAL, heal, 1); - status->heal(src, heal, 0, 0); + status->heal(src, heal, 0, STATUS_HEAL_DEFAULT); } } break; @@ -5082,7 +5082,7 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl heal = 0; // Don't absorb heal from Ice Walls or other skill units. if( heal && rnd()%100 < rate ) { - status->heal(src, heal, 0, 0); + status->heal(src, heal, 0, STATUS_HEAL_DEFAULT); clif->skill_nodamage(NULL, src, AL_HEAL, heal, 1); } } @@ -5843,7 +5843,7 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data) //When Asura fails... (except when it fails from Fog of Wall) //Consume SP/spheres skill->consume_requirement(sd,ud->skill_id, ud->skill_lv,1); - status->set_sp(src, 0, 0); + status->set_sp(src, 0, STATUS_HEAL_DEFAULT); sc = &sd->sc; if (sc->count) { //End states @@ -6126,7 +6126,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * clif->skill_nodamage (src, bl, skill_id, heal, 1); if( tsc && tsc->data[SC_AKAITSUKI] && heal && skill_id != HLIF_HEAL ) heal = ~heal + 1; - heal_get_jobexp = status->heal(bl,heal,0,0); + heal_get_jobexp = status->heal(bl, heal, 0, STATUS_HEAL_DEFAULT); if(sd && dstsd && heal > 0 && sd != dstsd && battle_config.heal_exp > 0){ heal_get_jobexp = heal_get_jobexp * battle_config.heal_exp / 100; @@ -6159,8 +6159,8 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * clif->updatestatus(sd,SP_BASEEXP); clif->updatestatus(sd,SP_JOBEXP); } - status->set_hp(src, 1, 0); - status->set_sp(src, 0, 0); + status->set_hp(src, 1, STATUS_HEAL_DEFAULT); + status->set_sp(src, 0, STATUS_HEAL_DEFAULT); break; } else if (status->isdead(bl) && flag&1) { //Revive skill->area_temp[0]++; //Count it in, then fall-through to the Resurrection code. @@ -6333,7 +6333,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * break; case SA_INSTANTDEATH: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - status->set_hp(bl,1,0); + status->set_hp(bl, 1, STATUS_HEAL_DEFAULT); break; case SA_QUESTION: case SA_GRAVITY: @@ -6911,7 +6911,8 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * if (dstsd && dstsd->charm_type != CHARM_TYPE_NONE && dstsd->charm_count > 0) { pc->del_charm(dstsd, dstsd->charm_count, dstsd->charm_type); } - if (sp) status->heal(src, 0, sp, 3); + if (sp != 0) + status->heal(src, 0, sp, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT); clif->skill_nodamage(src,bl,skill_id,skill_lv,sp?1:0); } break; @@ -7273,7 +7274,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * case NV_FIRSTAID: clif->skill_nodamage(src,bl,skill_id,5,1); - status->heal(bl,5,0,0); + status->heal(bl, 5, 0, STATUS_HEAL_DEFAULT); break; case AL_CURE: @@ -7350,7 +7351,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * case MER_SCAPEGOAT: if( mer && mer->master ) { - status->heal(&mer->master->bl, mer->battle_status.hp, 0, 2); + status->heal(&mer->master->bl, mer->battle_status.hp, 0, STATUS_HEAL_SHOWEFFECT); status->damage(src, src, mer->battle_status.max_hp, 0, 0, 1); } break; @@ -7667,7 +7668,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * if( tsc && tsc->data[SC_EXTREMITYFIST2] ) sp = 0; #endif - status->heal(bl,(int)hp,sp,0); + status->heal(bl, (int)hp, sp, STATUS_HEAL_DEFAULT); } break; case AM_CP_WEAPON: @@ -7842,7 +7843,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * sp = skill->get_sp(skill_id,skill_lv); sp = sp * tsc->data[SC_MAGICROD]->val2 / 100; if(sp < 1) sp = 1; - status->heal(bl,0,sp,2); + status->heal(bl, 0, sp, STATUS_HEAL_SHOWEFFECT); status_percent_damage(bl, src, 0, -20, false); //20% max SP damage. } else { struct unit_data *ud = unit->bl2ud(bl); @@ -7874,8 +7875,8 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * if (sp) //Recover some of the SP used sp = sp*(25*(skill_lv-1))/100; - if(hp || sp) - status->heal(src, hp, sp, 2); + if (hp != 0 || sp != 0) + status->heal(src, hp, sp, STATUS_HEAL_SHOWEFFECT); } } break; @@ -8118,14 +8119,14 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * { int hp_rate = skill_lv == 0 ? 0 : skill->get_hp_rate(skill_id, skill_lv); int gain_hp = tstatus->max_hp*abs(hp_rate)/100; // The earned is the same % of the target HP than it cost the caster. [Skotlex] - clif->skill_nodamage(src,bl,skill_id,status->heal(bl, gain_hp, 0, 0),1); + clif->skill_nodamage(src, bl, skill_id, status->heal(bl, gain_hp, 0, STATUS_HEAL_DEFAULT), 1); } break; case WE_FEMALE: { int sp_rate = skill_lv == 0 ? 0 : skill->get_sp_rate(skill_id, skill_lv); int gain_sp = tstatus->max_sp*abs(sp_rate)/100;// The earned is the same % of the target SP than it cost the caster. [Skotlex] - clif->skill_nodamage(src,bl,skill_id,status->heal(bl, 0, gain_sp, 0),1); + clif->skill_nodamage(src, bl, skill_id, status->heal(bl, 0, gain_sp, STATUS_HEAL_DEFAULT), 1); } break; @@ -8165,7 +8166,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * break; } clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - status->heal(bl,0,sp,2); + status->heal(bl, 0, sp, STATUS_HEAL_SHOWEFFECT); } break; @@ -8320,7 +8321,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * } dstmd->state.soul_change_flag = 1; sp2 = sstatus->max_sp * 3 /100; - status->heal(src, 0, sp2, 2); + status->heal(src, 0, sp2, STATUS_HEAL_SHOWEFFECT); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; } @@ -8332,8 +8333,8 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * if( tsc && tsc->data[SC_EXTREMITYFIST2] ) sp1 = tstatus->sp; #endif // RENEWAL - status->set_sp(src, sp2, 3); - status->set_sp(bl, sp1, 3); + status->set_sp(src, sp2, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT); + status->set_sp(bl, sp1, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } break; @@ -8371,7 +8372,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * clif->skill_nodamage(NULL,bl,AL_HEAL,hp,1); if(sp > 0) clif->skill_nodamage(NULL,bl,MG_SRECOVERY,sp,1); - status->heal(bl,hp,sp,0); + status->heal(bl, hp, sp, STATUS_HEAL_DEFAULT); } break; // Full Chemical Protection @@ -8460,7 +8461,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * sc_start(src,bl,SC_INCATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); break; case 5: // 2000HP heal, random teleported - status->heal(src, 2000, 0, 0); + status->heal(src, 2000, 0, STATUS_HEAL_DEFAULT); if( !map_flag_vs(bl->m) ) unit->warp(bl, -1,-1,-1, CLR_TELEPORT); break; @@ -8754,7 +8755,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * //Eh? why double skill packet? clif->skill_nodamage(src,bl,AL_HEAL,hp,1); clif->skill_nodamage(src,bl,skill_id,hp,1); - status->heal(bl, hp, 0, 0); + status->heal(bl, hp, 0, STATUS_HEAL_DEFAULT); } break; // Homun single-target support skills [orn] @@ -8901,7 +8902,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * int heal = status_get_max_hp(bl) * 25 / 100; clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - status->heal(bl,heal,0,1); + status->heal(bl, heal, 0, STATUS_HEAL_FORCED); status->change_clear_buffs(bl,4); } break; @@ -8955,7 +8956,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * value = status_get_max_hp(bl) * 25 / 100; status->change_clear_buffs(bl,4); skill->area_temp[5] &= ~0x20; - status->heal(bl,value,0,1); + status->heal(bl, value, 0, STATUS_HEAL_FORCED); type = SC_REFRESH; }else if( skill->area_temp[5]&0x40 ){ skill->area_temp[5] &= ~0x40; @@ -9140,7 +9141,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * clif->skill_nodamage(bl, bl, skill_id, heal, 1); if( tsc && tsc->data[SC_AKAITSUKI] && heal ) heal = ~heal + 1; - status->heal(bl, heal, 0, 1); + status->heal(bl, heal, 0, STATUS_HEAL_FORCED); } } else if( sd ) party->foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); @@ -9416,7 +9417,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * pc->setmadogear(sd, false); clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); skill->castend_damage_id(src, src, skill_id, skill_lv, tick, flag); - status->set_sp(src, 0, 0); + status->set_sp(src, 0, STATUS_HEAL_DEFAULT); } break; @@ -9455,7 +9456,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * case 5: hp = 23; break; } heal = tstatus->max_hp * hp / 100; - status->heal(bl,heal,0,2); + status->heal(bl, heal, 0, STATUS_HEAL_SHOWEFFECT); clif->skill_nodamage(src, bl, skill_id, skill_lv, heal); } break; @@ -9533,7 +9534,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * int sp = 100 * skill_lv; if( dstmd ) sp = dstmd->level * 2; if( status_zap(bl,0,sp) ) - status->heal(src,0,sp/2,3);//What does flag 3 do? [Rytech] + status->heal(src, 0, sp / 2, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT); } if ( tsc && tsc->data[SC__UNLUCKY] && skill_id == SC_UNLUCKY) { //If the target was successfully inflected with the Unlucky status, give 1 of 3 random status's. @@ -9657,7 +9658,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * case 3: sc_start(src, bl, SC_SHIELDSPELL_REF, 100, opt, INFINITE_DURATION); // HP Recovery val = sstatus->max_hp * ((status->get_lv(src) / 10) + (shield->refine + 1)) / 100; - status->heal(bl, val, 0, 2); + status->heal(bl, val, 0, STATUS_HEAL_SHOWEFFECT); status_change_end(bl,SC_SHIELDSPELL_REF,INVALID_TIMER); break; } @@ -9800,7 +9801,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * } heal = 120 * skill_lv + status_get_max_hp(bl) * (2 + skill_lv) / 100; - status->heal(bl, heal, 0, 0); + status->heal(bl, heal, 0, STATUS_HEAL_DEFAULT); if( (tsc && tsc->opt1) && (rnd()%100 < ((skill_lv * 5) + (status_get_dex(src) + status->get_lv(src)) / 4) - (1 + (rnd() % 10))) ) { status_change_end(bl, SC_STONE, INVALID_TIMER); @@ -9871,7 +9872,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * heal = 1; status->fixed_revive(bl, heal, 0); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - status->set_sp(bl, 0, 0); + status->set_sp(bl, 0, STATUS_HEAL_DEFAULT); } } break; @@ -10208,7 +10209,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * } e_hp = ed->battle_status.max_hp * 10 / 100; e_sp = ed->battle_status.max_sp * 10 / 100; - status->heal(&ed->bl,e_hp,e_sp,3); + status->heal(&ed->bl, e_hp, e_sp, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT); clif->skill_nodamage(src,&ed->bl,skill_id,skill_lv,1); } break; @@ -10518,7 +10519,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * } } heal = 5 * status->get_lv(&hd->bl) + status->base_matk(&hd->bl, &hd->battle_status, status->get_lv(&hd->bl)); - status->heal(bl, heal, 0, 0); + status->heal(bl, heal, 0, STATUS_HEAL_DEFAULT); clif->skill_nodamage(src, src, skill_id, skill_lv, clif->skill_nodamage(src, bl, AL_HEAL, heal, 1)); status->change_start(src, src, type, 1000, skill_lv, 0, 0, 0, skill->get_time(skill_id,skill_lv), SCFLAG_NOAVOID|SCFLAG_FIXEDTICK|SCFLAG_FIXEDRATE); status->change_start(src, bl, type, 1000, skill_lv, 0, 0, 0, skill->get_time(skill_id,skill_lv), SCFLAG_NOAVOID|SCFLAG_FIXEDTICK|SCFLAG_FIXEDRATE); @@ -12800,7 +12801,7 @@ static int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *b clif->skill_nodamage(&src->bl, bl, AL_HEAL, heal, 1); if (tsc && tsc->data[SC_AKAITSUKI] && heal) heal = ~heal + 1; - status->heal(bl, heal, 0, 0); + status->heal(bl, heal, 0, STATUS_HEAL_DEFAULT); if (diff >= 500) sg->val1--; } @@ -12821,7 +12822,7 @@ static int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *b if (status->isimmune(bl)) heal = 0; clif->skill_nodamage(&src->bl, bl, AL_HEAL, heal, 1); - status->heal(bl, heal, 0, 0); + status->heal(bl, heal, 0, STATUS_HEAL_DEFAULT); } break; @@ -13032,7 +13033,7 @@ static int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *b if( tsc && tsc->data[SC_AKAITSUKI] && heal ) heal = ~heal + 1; clif->skill_nodamage(&src->bl, bl, AL_HEAL, heal, 1); - status->heal(bl, heal, 0, 0); + status->heal(bl, heal, 0, STATUS_HEAL_DEFAULT); } } break; @@ -13086,7 +13087,7 @@ static int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *b case 0: // Heal 1~9999 HP heal = rnd() %9999+1; clif->skill_nodamage(ss,bl,AL_HEAL,heal,1); - status->heal(bl,heal,0,0); + status->heal(bl, heal, 0, STATUS_HEAL_DEFAULT); break; case 1: // End all negative status status->change_clear_buffs(bl,2); @@ -13231,7 +13232,7 @@ static int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *b } hp = tstatus->max_hp * hp / 100; sp = tstatus->max_sp * sp / 100; - status->heal(bl, hp, sp, 2); + status->heal(bl, hp, sp, STATUS_HEAL_SHOWEFFECT); sc_start(ss, bl, type, 100, sg->skill_lv, (sg->interval * 3) + 100); } // Reveal hidden players every 5 seconds. @@ -13353,7 +13354,7 @@ static int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *b clif->skill_nodamage(&src->bl, bl, AL_HEAL, hp, 0); if( tsc && tsc->data[SC_AKAITSUKI] && hp ) hp = ~hp + 1; - status->heal(bl, hp, 0, 0); + status->heal(bl, hp, 0, STATUS_HEAL_DEFAULT); sc_start(ss, bl, type, 100, sg->skill_lv, sg->interval + 100); } break; @@ -13367,13 +13368,13 @@ static int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *b int hp = tstatus->max_hp / 100; //+1% each 5s if ((sg->val3) % 5) { //each 5s if (tstatus->def_ele == skill->get_ele(sg->skill_id,sg->skill_lv)) { - status->heal(bl, hp, 0, 2); + status->heal(bl, hp, 0, STATUS_HEAL_SHOWEFFECT); } else if( (sg->unit_id == UNT_FIRE_INSIGNIA && tstatus->def_ele == ELE_EARTH) || (sg->unit_id == UNT_WATER_INSIGNIA && tstatus->def_ele == ELE_FIRE) || (sg->unit_id == UNT_WIND_INSIGNIA && tstatus->def_ele == ELE_WATER) || (sg->unit_id == UNT_EARTH_INSIGNIA && tstatus->def_ele == ELE_WIND) ) { - status->heal(bl, -hp, 0, 0); + status->heal(bl, -hp, 0, STATUS_HEAL_DEFAULT); } } sg->val3++; //timer diff --git a/src/map/status.c b/src/map/status.c index 370432ce7..edcdd515d 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -1240,10 +1240,15 @@ static void status_copy(struct status_data *a, const struct status_data *b) memcpy((void*)&a->max_hp, (const void*)&b->max_hp, sizeof(struct status_data)-(sizeof(a->hp)+sizeof(a->sp))); } -//Sets HP to given value. Flag is the flag passed to status->heal in case -//final value is higher than current (use 2 to make a healing effect display -//on players) It will always succeed (overrides Berserk block), but it can't kill. -static int status_set_hp(struct block_list *bl, unsigned int hp, int flag) +/** + * Sets HP to the given value. + * + * @param bl The target unit. + * @param hp The desired HP value. + * @param flag Additional options. @see enum status_heal_flag. STATUS_HEAL_FORCED is always implied. + * @return The amount of HP gained. + */ +static int status_set_hp(struct block_list *bl, unsigned int hp, enum status_heal_flag flag) { struct status_data *st; if (hp < 1) return 0; @@ -1254,14 +1259,19 @@ static int status_set_hp(struct block_list *bl, unsigned int hp, int flag) if (hp > st->max_hp) hp = st->max_hp; if (hp == st->hp) return 0; if (hp > st->hp) - return status->heal(bl, hp - st->hp, 0, 1|flag); + return status->heal(bl, hp - st->hp, 0, STATUS_HEAL_FORCED | flag); return status_zap(bl, st->hp - hp, 0); } -//Sets SP to given value. Flag is the flag passed to status->heal in case -//final value is higher than current (use 2 to make a healing effect display -//on players) -static int status_set_sp(struct block_list *bl, unsigned int sp, int flag) +/** + * Sets SP to the given value. + * + * @param bl The target unit. + * @param hp The desired SP value. + * @param flag Additional options. @see enum status_heal_flag. STATUS_HEAL_FORCED is always implied. + * @return The amount of SP gained. + */ +static int status_set_sp(struct block_list *bl, unsigned int sp, enum status_heal_flag flag) { struct status_data *st; @@ -1272,7 +1282,7 @@ static int status_set_sp(struct block_list *bl, unsigned int sp, int flag) if (sp > st->max_sp) sp = st->max_sp; if (sp == st->sp) return 0; if (sp > st->sp) - return status->heal(bl, 0, sp - st->sp, 1|flag); + return status->heal(bl, 0, sp - st->sp, STATUS_HEAL_FORCED | flag); return status_zap(bl, 0, st->sp - sp); } @@ -1304,12 +1314,12 @@ static int status_damage(struct block_list *src, struct block_list *target, int6 sp = 0; //Not a valid SP target. if (hp < 0) { //Assume absorbed damage. - status->heal(target, -hp, 0, 1); + status->heal(target, -hp, 0, STATUS_HEAL_FORCED); hp = 0; } if (sp < 0) { - status->heal(target, 0, -sp, 1); + status->heal(target, 0, -sp, STATUS_HEAL_FORCED); sp = 0; } @@ -1527,9 +1537,16 @@ static int status_damage(struct block_list *src, struct block_list *target, int6 return (int)(hp+sp); } -//Heals a character. If flag&1, this is forced healing (otherwise stuff like Berserk can block it) -//If flag&2, when the player is healed, show the HP/SP heal effect. -static int status_heal(struct block_list *bl, int64 in_hp, int64 in_sp, int flag) +/** + * Heals a character. + * + * @param bl The target unit. + * @param in_hp Amount of HP to recover. + * @param in_sp Amount of SP to recover. + * @param flag Additional options, @see enum status_heal_flag. + * @return The amount of HP + SP healed. + */ +static int status_heal(struct block_list *bl, int64 in_hp, int64 in_sp, enum status_heal_flag flag) { struct status_data *st; struct status_change *sc; @@ -1538,7 +1555,9 @@ static int status_heal(struct block_list *bl, int64 in_hp, int64 in_sp, int flag nullpo_ret(bl); st = status->get_status_data(bl); - if (st == &status->dummy || !st->hp) + if (st == &status->dummy) + return 0; + if (st->hp == 0 && (flag & STATUS_HEAL_ALLOWREVIVE) != 0) return 0; /* From here onwards, we consider it a 32-type as the client does not support higher and the value doesn't get through percentage modifiers */ @@ -1555,10 +1574,10 @@ static int status_heal(struct block_list *bl, int64 in_hp, int64 in_sp, int flag hp = 0; } - if(hp) { - if( sc && sc->data[SC_BERSERK] ) { - if( flag&1 ) - flag &= ~2; + if (hp != 0) { + if (sc && sc->data[SC_BERSERK] != NULL) { + if ((flag & STATUS_HEAL_FORCED) != 0) + flag &= ~STATUS_HEAL_SHOWEFFECT; else hp = 0; } @@ -1593,7 +1612,7 @@ static int status_heal(struct block_list *bl, int64 in_hp, int64 in_sp, int flag // send hp update to client switch(bl->type) { - case BL_PC: pc->heal(BL_UCAST(BL_PC, bl), hp, sp, (flag&2) ? 1 : 0); break; + case BL_PC: pc->heal(BL_UCAST(BL_PC, bl), hp, sp, (flag & STATUS_HEAL_SHOWEFFECT) != 0 ? 1 : 0); break; case BL_MOB: mob->heal(BL_UCAST(BL_MOB, bl), hp); break; case BL_HOM: homun->healed(BL_UCAST(BL_HOM, bl)); break; case BL_MER: mercenary->heal(BL_UCAST(BL_MER, bl), hp, sp); break; @@ -1648,18 +1667,18 @@ static int status_percent_change(struct block_list *src, struct block_list *targ if (flag) status->damage(src, target, INT_MAX, 0, 0, (!src||src==target?5:1)); else - status->heal(target, INT_MAX, 0, 0); + status->heal(target, INT_MAX, 0, STATUS_HEAL_DEFAULT); } if (sp > INT_MAX) { sp -= INT_MAX; if (flag) status->damage(src, target, 0, INT_MAX, 0, (!src||src==target?5:1)); else - status->heal(target, 0, INT_MAX, 0); + status->heal(target, 0, INT_MAX, STATUS_HEAL_DEFAULT); } if (flag) return status->damage(src, target, hp, sp, 0, (!src||src==target?5:1)); - return status->heal(target, hp, sp, 0); + return status->heal(target, hp, sp, STATUS_HEAL_DEFAULT); } static int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per_sp) @@ -2330,6 +2349,51 @@ static unsigned int status_get_base_maxhp(const struct map_session_data *sd, con return (unsigned int)cap_value(val,0,UINT_MAX); } +/** + * Calculates the HP that a character will have after death, on respawn. + * + * @param sd The character to calculate. + * @param st The character's status data. + */ +static unsigned int status_get_restart_hp(const struct map_session_data *sd, const struct status_data *st) +{ + unsigned int hp = 0; + + if (sd->special_state.restart_full_recover) + return st->max_hp; + + if ((sd->job & MAPID_BASEMASK) == MAPID_NOVICE && (sd->job & JOBL_2) == 0 && battle_config.restart_hp_rate < 50) + hp = st->max_hp / 2; + else + hp = APPLY_RATE(st->max_hp, battle_config.restart_hp_rate); + + if (hp > 0) + return hp; + + return 1; +} + +/** + * Calculates the SP that a character will have after death, on respawn. + * + * @param sd The character to calculate. + * @param st The character's status data. + */ +static unsigned int status_get_restart_sp(const struct map_session_data *sd, const struct status_data *st) +{ + unsigned int sp = 0; + + if (sd->special_state.restart_full_recover) + return st->max_sp; + + sp = APPLY_RATE(st->max_sp, battle_config.restart_sp_rate); + + if (sp > 0) + return sp; + + return 1; // the minimum for the respawn setting is SP:1 +} + static void status_calc_pc_additional(struct map_session_data *sd, enum e_status_calc_opt opt) { /* Just used for Plugin to give bonuses. */ @@ -2884,20 +2948,8 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o // ----- RESPAWN HP/SP ----- // //Calc respawn hp and store it on base_status - if (sd->special_state.restart_full_recover) - { - bstatus->hp = bstatus->max_hp; - bstatus->sp = bstatus->max_sp; - } else { - status->calc_pc_recover_hp(sd, bstatus); - if(!bstatus->hp) - bstatus->hp = 1; - - bstatus->sp = APPLY_RATE(bstatus->max_sp, battle_config.restart_sp_rate); - - if( !bstatus->sp ) /* the minimum for the respawn setting is SP:1 */ - bstatus->sp = 1; - } + bstatus->hp = status->get_restart_hp(sd, bstatus); + bstatus->sp = status->get_restart_sp(sd, bstatus); // ----- MISC CALCULATION ----- status->calc_misc(&sd->bl, bstatus, sd->status.base_level); @@ -9410,10 +9462,10 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en return 0; PER( 100 / (status_get_max_hp(bl) / hp), lv ); - status->heal(bl, (!(hp%2) ? (6-lv) *4 / 100 : -(lv*4) / 100), 0, 1); + status->heal(bl, (!(hp%2) ? (6-lv) *4 / 100 : -(lv*4) / 100), 0, STATUS_HEAL_FORCED); PER( 100 / (status_get_max_sp(bl) / sp), lv ); - status->heal(bl, 0,(!(sp%2) ? (6-lv) *3 / 100 : -(lv*3) / 100), 1); + status->heal(bl, 0,(!(sp%2) ? (6-lv) *3 / 100 : -(lv*3) / 100), STATUS_HEAL_FORCED); } #undef PER break; @@ -9646,8 +9698,8 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en switch (type) { case SC_BERSERK: if (!(sce->val2)) { //don't heal if already set - status->heal(bl, st->max_hp, 0, 1); //Do not use percent_heal as this healing must override BERSERK's block. - status->set_sp(bl, 0, 0); //Damage all SP + status->heal(bl, st->max_hp, 0, STATUS_HEAL_FORCED); //Do not use percent_heal as this healing must override BERSERK's block. + status->set_sp(bl, 0, STATUS_HEAL_DEFAULT); //Damage all SP } sce->val2 = 5 * st->max_hp / 100; break; @@ -10973,7 +11025,7 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, status_percent_heal(bl, 100, 0); status_change_end(bl, SC__BLOODYLUST, INVALID_TIMER); } else if(st->hp > 100 && sce->val2) //If val2 is removed, no HP penalty (dispelled?) [Skotlex] - status->set_hp(bl, 100, 0); + status->set_hp(bl, 100, STATUS_HEAL_DEFAULT); if(sc->data[SC_ENDURE] && sc->data[SC_ENDURE]->val4 == 2) { sc->data[SC_ENDURE]->val4 = 0; status_change_end(bl, SC_ENDURE, INVALID_TIMER); @@ -11025,8 +11077,8 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid, if (tid == INVALID_TIMER) break; // "lose almost all their HP and SP" on natural expiration. - status->set_hp(bl, 10, 0); - status->set_sp(bl, 10, 0); + status->set_hp(bl, 10, STATUS_HEAL_DEFAULT); + status->set_sp(bl, 10, STATUS_HEAL_DEFAULT); break; case SC_AUTOTRADE: if (tid == INVALID_TIMER) @@ -11437,8 +11489,8 @@ static int kaahi_heal_timer(int tid, int64 tick, int id, intptr_t data) hp = st->max_hp - st->hp; if (hp > sce->val2) hp = sce->val2; - if (hp) - status->heal(bl, hp, 0, 2); + if (hp != 0) + status->heal(bl, hp, 0, STATUS_HEAL_SHOWEFFECT); sce->val4 = INVALID_TIMER; return 1; } @@ -11644,7 +11696,7 @@ static int status_change_timer(int tid, int64 tick, int id, intptr_t data) int hp = 0; if (st->hp < st->max_hp) hp = (sce->val1 < 0) ? (int)(sd->status.max_hp * -1 * sce->val1 / 100.) : sce->val1 ; - status->heal(bl, hp, 0, 2); + status->heal(bl, hp, 0, STATUS_HEAL_SHOWEFFECT); sc_timer_next((sce->val2 * 1000) + tick, status->change_timer, bl->id, data); return 0; } @@ -11793,7 +11845,7 @@ static int status_change_timer(int tid, int64 tick, int id, intptr_t data) break; case SC_ABUNDANCE: if(--(sce->val4) > 0) { - status->heal(bl,0,60,0); + status->heal(bl, 0, 60, STATUS_HEAL_DEFAULT); sc_timer_next(10000+tick, status->change_timer, bl->id, data); } break; @@ -11909,7 +11961,7 @@ static int status_change_timer(int tid, int64 tick, int id, intptr_t data) heal = ~heal + 1; map->freeblock_lock(); - status->heal(bl, heal, 0, 2); + status->heal(bl, heal, 0, STATUS_HEAL_SHOWEFFECT); if( sc->data[type] ) { sc_timer_next(5000 + tick, status->change_timer, bl->id, data); } @@ -12032,7 +12084,7 @@ static int status_change_timer(int tid, int64 tick, int id, intptr_t data) if ( sc->data[type] ) { sc_timer_next(1000 + tick, status->change_timer, bl->id, data); } - status->heal(src, damage*(5 + 5 * sce->val1)/100, 0, 0); // 5 + 5% per level + status->heal(src, damage*(5 + 5 * sce->val1)/100, 0, STATUS_HEAL_DEFAULT); // 5 + 5% per level map->freeblock_unlock(); return 0; } @@ -12049,7 +12101,7 @@ static int status_change_timer(int tid, int64 tick, int id, intptr_t data) case SC_DEEP_SLEEP: if( --(sce->val4) >= 0 ) {// Recovers 3% of the player's MaxHP/MaxSP every 2 seconds. - status->heal(bl, st->max_hp * 3 / 100, st->max_sp * 3 / 100, 2); + status->heal(bl, st->max_hp * 3 / 100, st->max_sp * 3 / 100, STATUS_HEAL_SHOWEFFECT); sc_timer_next(2000 + tick, status->change_timer, bl->id, data); return 0; } @@ -12059,7 +12111,7 @@ static int status_change_timer(int tid, int64 tick, int id, intptr_t data) if( --(sce->val4) >= 0 ) { if( !status->charge(bl,0,sce->val3) ) break; - status->heal(bl, sce->val2, 0, 1); + status->heal(bl, sce->val2, 0, STATUS_HEAL_FORCED); sc_timer_next(1000 + tick, status->change_timer, bl->id, data); return 0; } @@ -12067,7 +12119,7 @@ static int status_change_timer(int tid, int64 tick, int id, intptr_t data) case SC_SONG_OF_MANA: if( --(sce->val4) >= 0 ) { - status->heal(bl,0,sce->val3,3); + status->heal(bl, 0, sce->val3, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT); sc_timer_next(5000 + tick, status->change_timer, bl->id, data); return 0; } @@ -12261,7 +12313,7 @@ static int status_change_timer(int tid, int64 tick, int id, intptr_t data) return 0; case SC_MEIKYOUSISUI: if( --(sce->val4) > 0 ) { - status->heal(bl, st->max_hp * (sce->val1+1) / 100, st->max_sp * sce->val1 / 100, 0); + status->heal(bl, st->max_hp * (sce->val1+1) / 100, st->max_sp * sce->val1 / 100, STATUS_HEAL_DEFAULT); sc_timer_next(1000 + tick, status->change_timer, bl->id, data); return 0; } @@ -12297,7 +12349,7 @@ static int status_change_timer(int tid, int64 tick, int id, intptr_t data) break; case SC_FRIGG_SONG: if( --(sce->val4) > 0 ) { - status->heal(bl, sce->val3, 0, 0); + status->heal(bl, sce->val3, 0, STATUS_HEAL_DEFAULT); sc_timer_next(1000 + tick, status->change_timer, bl->id, data); return 0; } @@ -12879,7 +12931,7 @@ static int status_natural_heal(struct block_list *bl, va_list args) sregen->tick.hp += val; while(sregen->tick.hp >= (unsigned int)battle_config.natural_heal_skill_interval) { sregen->tick.hp -= battle_config.natural_heal_skill_interval; - if(status->heal(bl, sregen->hp, 0, 3) < sregen->hp) { + if (status->heal(bl, sregen->hp, 0, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT) < sregen->hp) { //Full flag&=~(RGN_HP|RGN_SHP); break; @@ -12894,7 +12946,7 @@ static int status_natural_heal(struct block_list *bl, va_list args) sregen->tick.sp += val; while(sregen->tick.sp >= (unsigned int)battle_config.natural_heal_skill_interval) { sregen->tick.sp -= battle_config.natural_heal_skill_interval; - if(status->heal(bl, 0, sregen->sp, 3) < sregen->sp) { + if (status->heal(bl, 0, sregen->sp, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT) < sregen->sp) { //Full flag&=~(RGN_SP|RGN_SSP); break; @@ -12943,7 +12995,7 @@ static int status_natural_heal(struct block_list *bl, va_list args) val += regen->hp; regen->tick.hp -= battle_config.natural_healhp_interval; } while(regen->tick.hp >= (unsigned int)battle_config.natural_healhp_interval); - if (status->heal(bl, val, 0, 1) < val) + if (status->heal(bl, val, 0, STATUS_HEAL_FORCED) < val) flag&=~RGN_SHP; //full. } } @@ -12962,7 +13014,7 @@ static int status_natural_heal(struct block_list *bl, va_list args) val += regen->sp; regen->tick.sp -= battle_config.natural_healsp_interval; } while(regen->tick.sp >= (unsigned int)battle_config.natural_healsp_interval); - if (status->heal(bl, 0, val, 1) < val) + if (status->heal(bl, 0, val, STATUS_HEAL_FORCED) < val) flag&=~RGN_SSP; //full. } } @@ -12979,7 +13031,7 @@ static int status_natural_heal(struct block_list *bl, va_list args) while(sregen->tick.hp >= (unsigned int)battle_config.natural_heal_skill_interval) { sregen->tick.hp -= battle_config.natural_heal_skill_interval; - if(status->heal(bl, sregen->hp, 0, 3) < sregen->hp) + if (status->heal(bl, sregen->hp, 0, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT) < sregen->hp) break; //Full } } @@ -13004,7 +13056,7 @@ static int status_natural_heal(struct block_list *bl, va_list args) } } sregen->tick.sp -= battle_config.natural_heal_skill_interval; - if(status->heal(bl, 0, val, 3) < val) + if (status->heal(bl, 0, val, STATUS_HEAL_FORCED | STATUS_HEAL_SHOWEFFECT) < val) break; //Full } } @@ -13729,6 +13781,8 @@ void status_defaults(void) status->base_atk = status_base_atk; status->get_base_maxhp = status_get_base_maxhp; status->get_base_maxsp = status_get_base_maxsp; + status->get_restart_hp = status_get_restart_hp; + status->get_restart_sp = status_get_restart_sp; status->calc_npc_ = status_calc_npc_; status->calc_str = status_calc_str; status->calc_agi = status_calc_agi; diff --git a/src/map/status.h b/src/map/status.h index e7cd5e94c..17af22703 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -99,6 +99,16 @@ enum scstart_flag { SCFLAG_ALL = SCFLAG_NONE|SCFLAG_NOAVOID|SCFLAG_FIXEDTICK|SCFLAG_LOADED|SCFLAG_FIXEDRATE|SCFLAG_NOICON }; +/** + * Flags to be used with status->heal() and related functions. + */ +enum status_heal_flag { + STATUS_HEAL_DEFAULT = 0x00, ///< Default + STATUS_HEAL_FORCED = 0x01, ///< Forced healing (bypassing Berserk and similar) + STATUS_HEAL_SHOWEFFECT = 0x02, ///< Show the HP/SP heal effect + STATUS_HEAL_ALLOWREVIVE = 0x04, ///< Force resurrection in case of dead targets. +}; + // Status changes listing. These code are for use by the server. typedef enum sc_type { SC_NONE = -1, @@ -1900,7 +1910,7 @@ enum e_joint_break /** * Mob mode definitions. [Skotlex] * - * @see doc/mob_db_mode_list.txt for a description of each mode. + * @see doc/mob_db_mode_list.md for a description of each mode. */ enum e_mode { @@ -2309,9 +2319,9 @@ struct status_interface { int (*charge) (struct block_list* bl, int64 hp, int64 sp); int (*percent_change) (struct block_list *src,struct block_list *target,signed char hp_rate, signed char sp_rate, int flag); //Used to set the hp/sp of an object to an absolute value (can't kill) - int (*set_hp) (struct block_list *bl, unsigned int hp, int flag); - int (*set_sp) (struct block_list *bl, unsigned int sp, int flag); - int (*heal) (struct block_list *bl,int64 hp,int64 sp, int flag); + int (*set_hp) (struct block_list *bl, unsigned int hp, enum status_heal_flag flag); + int (*set_sp) (struct block_list *bl, unsigned int sp, enum status_heal_flag flag); + int (*heal) (struct block_list *bl,int64 hp,int64 sp, enum status_heal_flag flag); int (*revive) (struct block_list *bl, unsigned char per_hp, unsigned char per_sp); int (*fixed_revive) (struct block_list *bl, unsigned int per_hp, unsigned int per_sp); struct regen_data * (*get_regen_data) (struct block_list *bl); @@ -2384,6 +2394,8 @@ struct status_interface { unsigned short (*base_atk) (const struct block_list *bl, const struct status_data *st); unsigned int (*get_base_maxhp) (const struct map_session_data *sd, const struct status_data *st); unsigned int (*get_base_maxsp) (const struct map_session_data *sd, const struct status_data *st); + unsigned int (*get_restart_hp) (const struct map_session_data *sd, const struct status_data *st); + unsigned int (*get_restart_sp) (const struct map_session_data *sd, const struct status_data *st); int (*calc_npc_) (struct npc_data *nd, enum e_status_calc_opt opt); unsigned short (*calc_str) (struct block_list *bl, struct status_change *sc, int str); unsigned short (*calc_agi) (struct block_list *bl, struct status_change *sc, int agi); diff --git a/src/map/unit.c b/src/map/unit.c index 9174bdccd..371be03db 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1836,7 +1836,7 @@ static int unit_set_target(struct unit_data *ud, int target_id) struct block_list* target; if (ud->target && (target = map->id2bl(ud->target)) != NULL && (ux = unit->bl2ud(target)) != NULL && ux->target_count > 0) --ux->target_count; - if (target_id && (target = map->id2bl(target_id)) != NULL && (ux = unit->bl2ud(target)) != NULL) + if (target_id && (target = map->id2bl(target_id)) != NULL && (ux = unit->bl2ud(target)) != NULL && ux->target_count < UCHAR_MAX) ++ux->target_count; } |