summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorplaytester <playtester@54d463be-8e91-2dee-dedb-b68131a5f0ec>2013-03-16 20:53:23 +0000
committershennetsind <ind@henn.et>2013-04-11 16:19:35 -0300
commit931058402a47abd14f022c12bdf29c68e261204d (patch)
tree56312028151b6f4729476757aa81ddceb9104fdd
parent278e9949a662dd320c5fc408f585da4600526154 (diff)
downloadhercules-931058402a47abd14f022c12bdf29c68e261204d.tar.gz
hercules-931058402a47abd14f022c12bdf29c68e261204d.tar.bz2
hercules-931058402a47abd14f022c12bdf29c68e261204d.tar.xz
hercules-931058402a47abd14f022c12bdf29c68e261204d.zip
- Strongly improved the structure of status_get_sc_def so it's a lot easier to apply official formulas and make sure the checks are applied in the correct order
- In the process, fixed the effect of luk on status changes and removed the static 3% resistance that has been proven to not exist (97 vit, 1 luk can get stunned on officials) - As there is no general luk resistance as it depends on each status change, removed the luk_status_def configurations - Updated the success chance of Decrease Agi to the formula that was extracted from Aegis (blevel/5 + int/5 + skill_lv*3 + 50) Note: I tested all the status changes thoroughly, but as this is a quite large update, it would be nice if someone could cross-check it. Note2: Renewal status resistances (for pre-renewal status changes) are currently not implemented in rAthena at all. They need to be added in another update. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@17201 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r--conf/battle/status.conf8
-rw-r--r--src/map/battle.c2
-rw-r--r--src/map/battle.h2
-rw-r--r--src/map/status.c211
4 files changed, 122 insertions, 101 deletions
diff --git a/conf/battle/status.conf b/conf/battle/status.conf
index 6efe973b7..5341b606b 100644
--- a/conf/battle/status.conf
+++ b/conf/battle/status.conf
@@ -27,14 +27,6 @@ debuff_on_logout: 3
pc_status_def_rate: 100
mob_status_def_rate: 100
-// Required luk to gain inmunity to status changes.
-// Luk increases resistance by closing the gap between natural resist and max
-// linearly. This setting indicates required luk to gain complete immunity.
-// Eg: 40 vit -> 40% resist. 150 luk -> +50% of the missing gap.
-// So 40% + (50% of 60%) = 70%
-pc_luk_status_def: 300
-mob_luk_status_def: 300
-
// Maximum resistance to status changes. (100 = 100%)
// NOTE: Cards and equipment can go over this limit, so it only applies to natural resist.
pc_max_status_def: 100
diff --git a/src/map/battle.c b/src/map/battle.c
index c8af6badc..81c616928 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -5782,8 +5782,6 @@ static const struct _battle_data {
{ "status_cast_cancel", &battle_config.sc_castcancel, BL_NUL, BL_NUL, BL_ALL, },
{ "pc_status_def_rate", &battle_config.pc_sc_def_rate, 100, 0, INT_MAX, },
{ "mob_status_def_rate", &battle_config.mob_sc_def_rate, 100, 0, INT_MAX, },
- { "pc_luk_status_def", &battle_config.pc_luk_sc_def, 300, 1, INT_MAX, },
- { "mob_luk_status_def", &battle_config.mob_luk_sc_def, 300, 1, INT_MAX, },
{ "pc_max_status_def", &battle_config.pc_max_sc_def, 100, 0, INT_MAX, },
{ "mob_max_status_def", &battle_config.mob_max_sc_def, 100, 0, INT_MAX, },
{ "sg_miracle_skill_ratio", &battle_config.sg_miracle_skill_ratio, 1, 0, 10000, },
diff --git a/src/map/battle.h b/src/map/battle.h
index 54f941de8..8b1f757f5 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -381,8 +381,6 @@ struct Battle_Config {
int sc_castcancel; // [Skotlex]
int pc_sc_def_rate; // [Skotlex]
int mob_sc_def_rate;
- int pc_luk_sc_def;
- int mob_luk_sc_def;
int pc_max_sc_def;
int mob_max_sc_def;
diff --git a/src/map/status.c b/src/map/status.c
index 1ed8d91b5..72643e3c8 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -6078,7 +6078,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 +6132,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 +6246,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 +6308,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;
}
/*==========================================