summaryrefslogtreecommitdiff
path: root/src/map/status.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/status.c')
-rw-r--r--src/map/status.c232
1 files changed, 135 insertions, 97 deletions
diff --git a/src/map/status.c b/src/map/status.c
index 5d41acbe0..3892d94cc 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -1503,6 +1503,10 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin
if( skill_id == map[src->m].zone->disabled_skills[i]->nameid && (map[src->m].zone->disabled_skills[i]->type&src->type) ) {
if( src->type == BL_PC )
clif->msg((TBL_PC*)src, SKILL_CANT_USE_AREA); // This skill cannot be used within this area
+ else if( src->type == BL_MOB && map[src->m].zone->disabled_skills[i]->subtype != MZS_NONE ) {
+ if( (status->mode&MD_BOSS) && !(map[src->m].zone->disabled_skills[i]->subtype&MZS_BOSS) )
+ break;
+ }
return 0;
}
}
@@ -2335,7 +2339,8 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
memset(&status->max_hp, 0, sizeof(struct status_data)-(sizeof(status->hp)+sizeof(status->sp)));
//FIXME: Most of these stuff should be calculated once, but how do I fix the memset above to do that? [Skotlex]
- status->speed = DEFAULT_WALK_SPEED;
+ if (!sd->state.permanent_speed)
+ status->speed = DEFAULT_WALK_SPEED;
//Give them all modes except these (useful for clones)
status->mode = MD_MASK&~(MD_BOSS|MD_PLANT|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK);
@@ -4988,6 +4993,9 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha
if( sc == NULL )
return cap_value(speed,10,USHRT_MAX);
+ if (sd && sd->state.permanent_speed)
+ return (short)cap_value(speed,10,USHRT_MAX);
+
if( sd && sd->ud.skilltimer != INVALID_TIMER && (pc_checkskill(sd,SA_FREECAST) > 0 || sd->ud.skill_id == LG_EXEEDBREAK) )
{
if( sd->ud.skill_id == LG_EXEEDBREAK )
@@ -6078,7 +6086,12 @@ void status_change_init(struct block_list *bl)
//the flag values are the same as in status_change_start.
int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int tick, int flag)
{
- int sc_def = 0, tick_def = 0;
+ //Percentual resistance: 10000 = 100% Resist
+ //Example: 50% -> sc_def=5000 -> 25%; 5000ms -> tick_def=5000 -> 2500ms
+ int sc_def = 0, tick_def = -1; //-1 = use sc_def
+ //Linear resistance substracted from rate and tick after percentual resistance was applied
+ //Example: 25% -> sc_def2=2000 -> 5%; 2500ms -> tick_def2=2000 -> 500ms
+ int sc_def2 = 0, tick_def2 = -1; //-1 = use sc_def2
struct status_data* status;
struct status_change* sc;
struct map_session_data *sd;
@@ -6127,67 +6140,72 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti
if( sc && !sc->count )
sc = NULL;
switch (type) {
- case SC_STUN:
- case SC_POISON:
- if( sc && sc->data[SC__UNLUCKY] )
- return tick;
- case SC_DPOISON:
- case SC_SILENCE:
- case SC_BLEEDING:
- sc_def = 3 +status->vit;
- break;
- case SC_SLEEP:
- sc_def = 3 +status->int_;
- break;
- case SC_DEEPSLEEP:
- tick_def = status->int_ / 10 + status_get_lv(bl) * 65 / 1000; // Seems to be -1 sec every 10 int and -5% chance every 10 int.
- sc_def = 5 * status->int_ /10;
- break;
- case SC_DECREASEAGI:
- case SC_ADORAMUS://Arch Bishop
- if (sd) tick>>=1; //Half duration for players.
- case SC_STONE:
- case SC_FREEZE:
- sc_def = 3 +status->mdef;
- break;
- case SC_CURSE:
- //Special property: inmunity when luk is greater than level or zero
- if (status->luk > status_get_lv(bl) || status->luk == 0)
- return 0;
- else
- sc_def = 3 +status->luk;
- tick_def = status->vit;
- break;
- case SC_BLIND:
- if( sc && sc->data[SC__UNLUCKY] )
- return tick;
- sc_def = 3 +(status->vit + status->int_)/2;
- break;
- case SC_CONFUSION:
- sc_def = 3 +(status->str + status->int_)/2;
- break;
- case SC_ANKLE:
- if(status->mode&MD_BOSS) // Lasts 5 times less on bosses
- tick /= 5;
- sc_def = status->agi / 2;
- break;
- case SC_MAGICMIRROR:
- case SC_ARMORCHANGE:
- if (sd) //Duration greatly reduced for players.
- tick /= 15;
- //No defense against it (buff).
- rate -= (status_get_lv(bl) / 5 + status->vit / 4 + status->agi / 10)*100; // Lineal Reduction of Rate
- break;
+ case SC_STUN:
+ case SC_POISON:
+ if( sc && sc->data[SC__UNLUCKY] )
+ return tick;
+ case SC_DPOISON:
+ case SC_SILENCE:
+ case SC_BLEEDING:
+ sc_def = status->vit*100;
+ sc_def2 = status->luk*10;
+ break;
+ case SC_SLEEP:
+ sc_def = status->int_*100;
+ sc_def2 = status->luk*10;
+ break;
+ case SC_DEEPSLEEP:
+ sc_def = status->int_*50;
+ tick_def = status->int_*10 + status_get_lv(bl) * 65 / 10; //Seems to be -1 sec every 10 int and -5% chance every 10 int.
+ break;
+ case SC_DECREASEAGI:
+ case SC_ADORAMUS: //Arch Bishop
+ if (sd) tick>>=1; //Half duration for players.
+ case SC_STONE:
+ //Impossible to reduce duration with stats
+ tick_def = 0;
+ tick_def2 = 0;
+ case SC_FREEZE:
+ sc_def = status->mdef*100;
+ sc_def2 = status->luk*10;
+ break;
+ case SC_CURSE:
+ //Special property: inmunity when luk is greater than level or zero
+ if (status->luk > status_get_lv(bl) || status->luk == 0)
+ return 0;
+ sc_def = status->luk*100;
+ sc_def2 = status->luk*10;
+ tick_def = status->vit*100;
+ break;
+ case SC_BLIND:
+ if( sc && sc->data[SC__UNLUCKY] )
+ return tick;
+ sc_def = (status->vit + status->int_)*50;
+ sc_def2 = status->luk*10;
+ break;
+ case SC_CONFUSION:
+ sc_def = (status->str + status->int_)*50;
+ sc_def2 = status->luk*10;
+ break;
+ case SC_ANKLE:
+ if(status->mode&MD_BOSS) // Lasts 5 times less on bosses
+ tick /= 5;
+ sc_def = status->agi*50;
+ break;
+ case SC_MAGICMIRROR:
+ case SC_ARMORCHANGE:
+ if (sd) //Duration greatly reduced for players.
+ tick /= 15;
+ sc_def2 = status_get_lv(bl)*20 + status->vit*25 + status->agi*10; // Lineal Reduction of Rate
+ tick_def2 = 0; //No duration reduction
+ break;
case SC_MARSHOFABYSS:
//5 second (Fixed) + 25 second - {( INT + LUK ) / 20 second }
- tick -= (status->int_ + status->luk) / 20 * 1000;
+ tick_def2 = (status->int_ + status->luk)*50;
break;
case SC_STASIS:
//5 second (fixed) + { Stasis Skill level * 5 - (Target's VIT + DEX) / 20 }
- tick -= (status->vit + status->dex) / 20 * 1000;
- break;
- case SC_WHITEIMPRISON:
- if( tick == 5000 ) // 100% on caster
+ tick_def2 = (status->vit + status->dex)*50;
break;
if( bl->type == BL_PC )
tick -= (status_get_lv(bl) / 5 + status->vit / 4 + status->agi / 10)*100;
@@ -6236,51 +6254,58 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti
if (sd) {
- if (battle_config.pc_sc_def_rate != 100)
+ if (battle_config.pc_sc_def_rate != 100) {
sc_def = sc_def*battle_config.pc_sc_def_rate/100;
+ sc_def2 = sc_def2*battle_config.pc_sc_def_rate/100;
+ }
- if (sc_def < battle_config.pc_max_sc_def)
- sc_def += (battle_config.pc_max_sc_def - sc_def)*
- status->luk/battle_config.pc_luk_sc_def;
- else
- sc_def = battle_config.pc_max_sc_def;
+ sc_def = min(sc_def, battle_config.pc_max_sc_def*100);
+ sc_def2 = min(sc_def2, battle_config.pc_max_sc_def*100);
- if (tick_def) {
- if (battle_config.pc_sc_def_rate != 100)
- tick_def = tick_def*battle_config.pc_sc_def_rate/100;
+ if (tick_def > 0 && battle_config.pc_sc_def_rate != 100) {
+ tick_def = tick_def*battle_config.pc_sc_def_rate/100;
+ tick_def2 = tick_def2*battle_config.pc_sc_def_rate/100;
}
-
} else {
- if (battle_config.mob_sc_def_rate != 100)
+ if (battle_config.mob_sc_def_rate != 100) {
sc_def = sc_def*battle_config.mob_sc_def_rate/100;
+ sc_def2 = sc_def2*battle_config.mob_sc_def_rate/100;
+ }
- if (sc_def < battle_config.mob_max_sc_def)
- sc_def += (battle_config.mob_max_sc_def - sc_def)*
- status->luk/battle_config.mob_luk_sc_def;
- else
- sc_def = battle_config.mob_max_sc_def;
+ sc_def = min(sc_def, battle_config.mob_max_sc_def*100);
+ sc_def2 = min(sc_def2, battle_config.mob_max_sc_def*100);
- if (tick_def) {
- if (battle_config.mob_sc_def_rate != 100)
- tick_def = tick_def*battle_config.mob_sc_def_rate/100;
+ if (tick_def > 0 && battle_config.mob_sc_def_rate != 100) {
+ tick_def = tick_def*battle_config.mob_sc_def_rate/100;
+ tick_def2 = tick_def2*battle_config.mob_sc_def_rate/100;
}
}
if (sc) {
if (sc->data[SC_SCRESIST])
- sc_def += sc->data[SC_SCRESIST]->val1; //Status resist
+ sc_def += sc->data[SC_SCRESIST]->val1*100; //Status resist
else if (sc->data[SC_SIEGFRIED])
- sc_def += sc->data[SC_SIEGFRIED]->val3; //Status resistance.
+ sc_def += sc->data[SC_SIEGFRIED]->val3*100; //Status resistance.
}
//When no tick def, reduction is the same for both.
- if( !tick_def && type != SC_STONE ) //Recent tests show duration of petrify isn't reduced by MDEF. [Inkfish]
+ if(tick_def < 0)
tick_def = sc_def;
+ if(tick_def2 < 0)
+ tick_def2 = sc_def2;
//Natural resistance
if (!(flag&8)) {
- rate -= rate*sc_def/100;
+ rate -= rate*sc_def/10000;
+ rate -= sc_def2;
+
+ //Minimum chances
+ switch (type) {
+ case SC_BITE:
+ rate = max(rate, 5000); //Minimum of 50%
+ break;
+ }
//Item resistance (only applies to rate%)
if(sd && SC_COMMON_MIN <= type && type <= SC_COMMON_MAX)
@@ -6291,22 +6316,38 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti
rate -= rate*sd->sc.data[SC_COMMONSC_RESIST]->val1/100;
}
}
+
if (!(rnd()%10000 < rate))
return 0;
- //Why would a status start with no duration? Presume it has
- //duration defined elsewhere.
- if (!tick) return 1;
+ //Even if a status change doesn't have a duration, it should still trigger
+ if (tick < 1) return 1;
//Rate reduction
- if (flag&2)
+ if (flag&2)
return tick;
- tick -= tick*tick_def/100;
- // Changed to 5 seconds according to recent tests [Playtester]
- if (type == SC_ANKLE && tick < 5000)
- tick = 5000;
- return tick<=0?0:tick;
+ tick -= tick*tick_def/10000;
+ tick -= tick_def2;
+
+ //Minimum durations
+ switch (type) {
+ case SC_ANKLE:
+ case SC_MARSHOFABYSS:
+ case SC_STASIS:
+ tick = max(tick, 5000); //Minimum duration 5s
+ break;
+ case SC_BURNING:
+ case SC_FREEZING:
+ tick = max(tick, 10000); //Minimum duration 10s
+ break;
+ default:
+ //Skills need to trigger even if the duration is reduced below 1ms
+ tick = max(tick, 1);
+ break;
+ }
+
+ return tick;
}
/*==========================================
@@ -6552,11 +6593,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
opt_flag = 0; //Reuse to check success condition.
if(sd->bonus.unstripable_equip&EQP_WEAPON)
return 0;
- i = sd->equip_index[EQI_HAND_L];
- if (i>=0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON) {
- opt_flag|=1;
- pc_unequipitem(sd,i,3); //L-hand weapon
- }
i = sd->equip_index[EQI_HAND_R];
if (i>=0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON) {
@@ -7258,7 +7294,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_MERC_QUICKEN:
val2 = 300;
break;
-#ifndef RENEWAL
+#ifndef RENEWAL_ASPD
case SC_SPEARQUICKEN:
val2 = 200+10*val1;
break;
@@ -8966,7 +9002,6 @@ int status_change_clear(struct block_list* bl, int type) {
sc->opt1 = 0;
sc->opt2 = 0;
sc->opt3 = 0;
- sc->option &= OPTION_MASK;
if( type == 0 || type == 2 )
clif->changeoption(bl);
@@ -9853,6 +9888,9 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
if (--(sce->val4) >= 0) {
int hp = rnd()%600 + 200;
struct block_list* src = map_id2bl(sce->val2);
+ if( src && bl && bl->type == BL_MOB ) {
+ mob_log_damage((TBL_MOB*)bl,src,sd||hp<status->hp?hp:status->hp-1);
+ }
map_freeblock_lock();
status_fix_damage(src, bl, sd||hp<status->hp?hp:status->hp-1, 1);
if( sc->data[type] ) {