Selaa lähdekoodia

- 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://svn.code.sf.net/p/rathena/svn/trunk@17201 54d463be-8e91-2dee-dedb-b68131a5f0ec

playtester 12 vuotta sitten
vanhempi
commit
a3dc2d9cf4
5 muutettua tiedostoa jossa 167 lisäystä ja 145 poistoa
  1. 0 8
      conf/battle/status.conf
  2. 0 2
      src/map/battle.c
  3. 0 2
      src/map/battle.h
  4. 1 1
      src/map/skill.c
  5. 166 132
      src/map/status.c

+ 0 - 8
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

+ 0 - 2
src/map/battle.c

@@ -5849,8 +5849,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,          },

+ 0 - 2
src/map/battle.h

@@ -415,8 +415,6 @@ extern 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;
 

+ 1 - 1
src/map/skill.c

@@ -5063,7 +5063,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 	case AL_DECAGI:
 	case MER_DECAGI:
 		clif_skill_nodamage (src, bl, skill_id, skill_lv,
-			sc_start(bl, type, (40 + skill_lv * 2 + (status_get_lv(src) + sstatus->int_)/5), skill_lv, skill_get_time(skill_id,skill_lv)));
+			sc_start(bl, type, (50 + skill_lv * 3 + (status_get_lv(src) + sstatus->int_)/5), skill_lv, skill_get_time(skill_id,skill_lv)));
 		break;
 
 	case AL_CRUCIS:

+ 166 - 132
src/map/status.c

@@ -6195,7 +6195,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;
@@ -6244,160 +6249,173 @@ 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;
-		else
-			tick -= (status->vit + status->luk) / 20 * 1000;
-		break;
-	case SC_BURNING:
-		// From iROwiki : http://forums.irowiki.org/showpost.php?p=577240&postcount=583
-		tick -= 50*status->luk + 60*status->int_ + 170*status->vit;
-		tick = max(tick,10000); // Minimum Duration 10s.
-		break;
-	case SC_FREEZING:
-		tick -= 1000 * ((status->vit + status->dex) / 20);
-		tick = max(tick,10000); // Minimum Duration 10s.
-		break;
-	case SC_OBLIVIONCURSE: // 100% - (100 - 0.8 x INT)
-		sc_def = 100 - ( 100 - status->int_* 8 / 10 );
-		sc_def = max(sc_def, 5); // minimum of 5%
-		break;
-	case SC_BITE: // {(Base Success chance) - (Target's AGI / 4)}
-		rate -= status->agi*1000/4;
-		rate = max(rate,50000); // minimum of 50%
-		break;
-	case SC_ELECTRICSHOCKER:
-		if( bl->type == BL_MOB )
-			tick -= 1000 * (status->agi/10);
-		break;
-	case SC_CRYSTALIZE:
-		tick -= (1000*(status->vit/10))+(status_get_lv(bl)/50);
-		break;
-	case SC_MANDRAGORA:
-		sc_def = (status->vit+status->luk)/5;
-		break;
-	case SC_KYOUGAKU:
-		tick -= 30*status->int_;
-		break;
-        case SC_PARALYSIS:
-		tick -= 50 * (status->vit + status->luk); //(1000/20);
-		break;
-	default:
-		//Effect that cannot be reduced? Likely a buff.
-		if (!(rnd()%10000 < rate))
-			return 0;
-		return tick?tick:1;
+		case SC_WHITEIMPRISON:
+			if( tick == 5000 ) // 100% on caster
+				break;
+			if( bl->type == BL_PC )
+				tick_def2 = status_get_lv(bl)*20 + status->vit*25 + status->agi*10;
+			else
+				tick_def2 = (status->vit + status->luk)*50;
+			break;
+		case SC_BURNING:
+			// From iROwiki : http://forums.irowiki.org/showpost.php?p=577240&postcount=583
+			tick_def2 = 50*status->luk + 60*status->int_ + 170*status->vit;
+			break;
+		case SC_FREEZING:
+			tick_def2 = (status->vit + status->dex)*50;
+			break;
+		case SC_OBLIVIONCURSE: // 100% - (100 - 0.8 x INT)
+			sc_def = status->int_*80;
+			sc_def = max(sc_def, 500); // minimum of 5% resist
+			break;
+		case SC_BITE: // {(Base Success chance) - (Target's AGI / 4)}
+			sc_def2 = status->agi*25;
+			tick_def2 = 0; //No duration reduction
+			break;
+		case SC_ELECTRICSHOCKER:
+			if( bl->type == BL_MOB )
+				tick_def2 = status->agi*100;
+			break;
+		case SC_CRYSTALIZE:
+			tick_def2 = status->vit*100 + status_get_lv(bl)*20;
+			break;
+		case SC_MANDRAGORA:
+			sc_def = (status->vit + status->luk)*20;
+			break;
+		case SC_KYOUGAKU:
+			tick_def2 = 30*status->int_;
+			break;
+		case SC_PARALYSIS:
+			tick_def2 = (status->vit + status->luk)*50;
+			break;
+		default:
+			//Effect that cannot be reduced? Likely a buff.
+			if (!(rnd()%10000 < rate))
+				return 0;
+			return max(1,tick);
 	}
 
 	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)
@@ -6408,22 +6426,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;
 }
 
 /*==========================================