Преглед на файлове

- Added bonuses bSPRegenRate, bHPRegenRate. They behave like the opposite of bHPLossRate/bSPLossRate, making you gain x Hp/Sp every y ms.
- Added bonus bIgnoreMdefRate, used to ignore a % of the target's mdef when using magic attacks (bonus2 will ignore part of the mdef of all targets, bonus3 receives a race argument)
- You can now use bonus2 bCastRate to adjust the cast rate of a single skill.
- Cleaned the code for bleeding (hp-loss) and extended it to handle regen as well.
- Some small cleanups in the pc_bonus functions
- Removed bonus3 bHpLossRate since it was doing nothing and is not used.
- Corrected bGetZeny bonus to be like in Aegis. The amount received is from 1 to the given amount, you can use negative zeny values to use an amount dependant on mob's level (amount*lv).
- Updated doc/item_bonus.txt with all these changes
- Anti-Magic/Stone-Skin now increase/decrease def/mdef only and in an absolute mode (+20*lv rather than +20%*lv). Also the duration is greatly decreased (x/15) when used on players.
- Now when a player uses a strip skill without having it in the skill tree (auto-casted) the duration will be 0, the equipment will be stripped without causing the status change that blocks reequipping.


git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@11112 54d463be-8e91-2dee-dedb-b68131a5f0ec

skotlex преди 17 години
родител
ревизия
88e0559d2c
променени са 10 файла, в които са добавени 197 реда и са изтрити 82 реда
  1. 22 0
      Changelog-Trunk.txt
  2. 3 3
      db/const.txt
  3. 9 3
      doc/item_bonus.txt
  4. 14 2
      src/map/battle.c
  5. 12 15
      src/map/map.h
  6. 6 2
      src/map/mob.c
  7. 95 39
      src/map/pc.c
  8. 1 0
      src/map/pc.h
  9. 16 4
      src/map/skill.c
  10. 19 14
      src/map/status.c

+ 22 - 0
Changelog-Trunk.txt

@@ -3,6 +3,28 @@ Date	Added
 AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
+2007/09/03
+	* Added bonuses bSPRegenRate, bHPRegenRate. They behave like the opposite
+	  of bHPLossRate/bSPLossRate, making you gain x Hp/Sp every y ms.
+	* Added bonus bIgnoreMdefRate, used to ignore a % of the target's mdef when
+	  using magic attacks (bonus2 will ignore part of the mdef of all targets,
+	  bonus3 receives a race argument)
+	* You can now use bonus2 bCastRate to adjust the cast rate of a single
+	  skill.
+	* Cleaned the code for bleeding (hp-loss) and extended it to handle regen
+	  as well.
+	* Some small cleanups in the pc_bonus functions.
+	* Removed bonus3 bHpLossRate since it was doing nothing and is not used.
+	* Corrected bGetZeny bonus to be like in Aegis. The amount received is from
+	  1 to the given amount, you can use negative zeny values to use an amount
+	  dependant on mob's level (amount*lv).
+	* Updated doc/item_bonus.txt with all these changes.
+	* Anti-Magic/Stone-Skin now increase/decrease def/mdef only and in an
+	  absolute mode (+20*lv rather than +20%*lv). Also the duration is greatly
+	  decreased (x/15) when used on players.
+	* Now when a player uses a strip skill without having it in the skill tree
+	  (auto-casted) the duration will be 0, the equipment will be stripped
+	  without causing the status change that blocks reequipping.
 2007/09/02
 	* Added @whereis command (displays normal spawn maps for given mobs).
 	  Defaults to a lv10 command. [Skotlex]

+ 3 - 3
db/const.txt

@@ -305,7 +305,7 @@ bIgnoreDefEle	1026
 bIgnoreDefRace	1027
 bAtkRate	1028
 bSpeedAddRate	1029
-
+bSPRegenRate	1030
 bMagicAtkDef	1031
 bMiscAtkDef	1032
 bIgnoreMdefEle	1033
@@ -361,6 +361,7 @@ bWeaponAtkRate	1082
 bDelayrate	1083
 bHPDrainRateRace	1084
 bSPDrainRateRace	1085
+bIgnoreMdefRate	1086
 
 bRestartFullRecover	2000
 bNoCastCancel	2001
@@ -370,7 +371,6 @@ bNoWeaponDamage	2004
 bNoGemStone	2005
 bNoCastCancel2	2006
 bNoMiscDamage	2007
-
 bUnbreakableWeapon	2008
 bUnbreakableArmor	2009
 bUnbreakableHelm	2010
@@ -385,7 +385,7 @@ bSkillAtk	2018
 bUnstripable	2019
 bAddDamageByClass	2020
 bSPGainValue	2021
-
+bHPRegenRate	2022
 bHPLossRate	2023
 bAddRace2	2024
 bHPGainValue	2025

+ 9 - 3
doc/item_bonus.txt

@@ -62,8 +62,6 @@ bonus bDoubleRate,n;			Double Attack probability n% (works with all weapons | on
 bonus bDoubleAddRate,n;			Double Attack probability + n% (works with all weapons)
 bonus bPerfectHitRate,n;		On-target impact attack probability n% (only the highest among all is applied)
 bonus bPerfectHitAddRate,n;		On-target impact attack probability + n%
-bonus bGetZenyNum,n;			When killing the monster with physical attack, rand () ?? of %n+1 is obtained, (only the highest among all is applied)
-bonus bAddGetZenyNum,n;			When killing the monster with physical attack, rand () ?? of %n+1 is obtained, (n is done +)
 bonus bCriticalDef,n;			Critical ? and others the trap it is, probability + n%
 bonus bNearAtkDef,n;			Adds n% damage reduction against melee physical attacks
 bonus bLongAtkDef,n;			Adds n% damage reduction against ranged physical attacks
@@ -77,6 +75,7 @@ bonus bIgnoreMDefRace;			Disregard MDEF against enemies of race n
 							n: 0=Formless, 1=Undead, 2=Brute, 3=Plant, 4=Insect, 5=Fish, 6=Demon, 7=Demi-Human, 8=Angel, 9=Dragon, 10=Boss monster, 11=Other than (normal monster) boss monster
 bonus bIgnoreMDefEle;			Disregard MDEF against enemies of element n
 							n: 0=Neutral, 1=Water, 2=Earth, 3=Fire, 4=Wind, 5=Poison, 6=Holy, 7=Dark, 8=Spirit, 9=Undead
+bonus bIgnoreMdefRate,n;		Disregard n% of the target's MDEF
 bonus bDefRatioAtkRace,n;		n race if defensive power is high the high extent big damage is given, (defense disregard) :
 							n: 0=Formless, 1=Undead, 2=Brute, 3=Plant, 4=Insect, 5=Fish, 6=Demon, 7=Demi-Human, 8=Angel, 9=Dragon, 10=Boss monster, 11=Other than (normal monster) boss monster
 bonus bDefRatioAtkEle,n;		n attribute if defensive power is high the high extent big damage is given, (defense disregard) :
@@ -101,6 +100,7 @@ bonus2 bAddEff,e,x;			Adds a x/10000 chance to cause effect e to the target when
 							e: Eff_Blind, Eff_Sleep, Eff_Poison, Eff_Freeze, Eff_Silence, Eff_Stan, Eff_Curse, Eff_Confusion, Eff_Stone, Eff_Bleeding
 bonus2 bResEff,e,x;			Adds a x/10000 tolerance to effect e (e.g. x=100 makes 1% tolerance, x=10000 makes 100% tolerance, etc)
 							e: Eff_Blind, Eff_Sleep, Eff_Poison, Eff_Freeze, Eff_Silence, Eff_Stan, Eff_Curse, Eff_Confusion, Eff_Stone, Eff_Bleeding
+bonus2 bCastrate,n,x;			Adjust casting time of skill n by x%
 bonus2 bAddSize,n,x;			In n size the damage addition of x%
 							n: 0=Small  1=Medium  2=Large
 bonus2 bMagicAddSize,n,x;		In n size the magic damage addition of x%
@@ -123,12 +123,17 @@ bonus2 bAddDamageClass,n,x;		In monster of class n the damage addition of x% (on
 bonus2 bAddMagicDamageClass,n,x;	In monster of class n in case of the magical damage addition and prayer of x% in n occupation the magical damage addition of x%
 bonus2 bAddDefClass,n,x;		In monster of class n the damage reduction of x% (only physical attack), in case of prayer in n occupation the damage reduction of x%
 bonus2 bAddMDefClass,n,x;		In monster of class n in case of the magical damage reduction and prayer of x% in n occupation the magical damage reduction of x%
+bonus2 bIgnoreMdefRate,n,x;	Disregard n% of the target's MDEF if the target belongs to race x;
 bonus2 bHPDrainRate,n,x;		it obtained to the enemy -- ? ME ? JI -- n/10 % probability -- x % -- HP -- absorption (+ n and x are carried out)
 bonus2 bSPDrainRate,n,x;		it obtained to the enemy -- ? ME ? JI -- n/10 % probability -- x % -- SP -- absorption (+ n and x are carried out)
 bonus2 bSPVanishRate,n,x;		Add the (n/10)% chance of decreasing enemy's SP (player) amount by x% when attacking
 bonus2 bAddMonsterDropItem,n,x;		When killing any monsters with physical attack, the probability which drops item n +x% (the item which the monster drops unrelated ones)
 									if 'x' is negative value, then it's a part of formula
 										chance = -x*(killed_mob_level/10)+1
+bonus2 bGetZenyNum,n,x;			When killing a monster, there is a x% chance of gaining 1~n zeny (only the highest among all is applied). If n < 0, the max zeny to gain is -n*monster level.
+bonus2 bAddGetZenyNum,n,x;		Same as bGetZenyNum, but the rates and zeny to gain stack.
+gaining
+
 bonus3 bAddMonsterDropItem,n,x,y;	When killing monsters from race x with physical attack, the probability which drops item n +y% (the item which the monster drops unrelated ones)
 						0=Formless, 1=Undead, 2=Brute, 3=Plant, 4=Insect, 5=Fish, 6=Demon, 7=Demi-Human, 8=Angel, 9=Dragon, 10=Boss monster, 11=Other than (normal monster) boss monster
 									if 'x' is negative value, then it's a part of formula
@@ -156,6 +161,7 @@ bonus bIgnoreDefMob,n;			Ignore monster's DEF when attacking.
 bonus bDamageWhenUnequip,n;		You lose n HP when the item is unequipped
 bonus2 bCriticalAddRace,n,r;		Critical + n vs. enemies of race r
 					r: 0=Formless, 1=Undead, 2=Brute, 3=Plant, 4=Insect, 5=Fish, 6=Demon, 7=Demi-Human, 8=Angel, 9=Dragon, 10=Boss monster, 11=Other than (normal monster) boss monster
+bonus2 bHPRegenRate,n,x;		Gain n HP every x milliseconds
 bonus2 bHPLossRate,n,x;			Lose n HP every x milliseconds
 bonus2 bAddEffWhenHit,n,x;		n% chance to cause x state to the enemy when
 					being hit by physical damage
@@ -167,7 +173,6 @@ bonus2 bAddDamageByClass,n,x;		When being hit by monster of class n increase
 					damage taken by x%
 bonus2 bAddRace2,n,x;			Increase damage by x% vs. enemies of race n
 					(Check db/mob_race2_db.txt)
-bonus3 bHPLossRate,n,x,y;		Lose n amount of hp every x amount of time
 					y: 0=Don't show damage 1=Show damage
 bonus3 bAutoSpellWhenHit,x,y,n;		n/10% chance to cast skill x of level y on
 					attacker (except if it is a self-skill) when being hit by a
@@ -236,6 +241,7 @@ bonus2 bAddItemHealRate,n,x;		Increases HP recovered by n type items by x%,
 
 bonus bLoseSPWhenUnequip,n;		Lose n SP when the item is unequipped
 
+bonus2 bSPRegenRate,n,x;		Gain n SP every x milliseconds
 bonus2 bSPLossRate,n,x;			Lose n SP every x milliseconds
 bonus2 bExpAddRace,n,x;			Increase exp gained by x% vs. enemies of race n
 bonus2 bSPGainRace,n,x;			When killing a monster of race n by physical

+ 14 - 2
src/map/battle.c

@@ -2333,10 +2333,22 @@ struct Damage battle_calc_magic_attack(
 		}
 
 		if(!flag.imdef){
+			int mdef = tstatus->mdef;
+			int mdef2= tstatus->mdef2;
+			if(sd) {
+				i = sd->ignore_mdef[is_boss(target)?RC_BOSS:RC_NONBOSS];
+				i+= sd->ignore_mdef[tstatus->race];
+				if (i)
+				{
+					if (i > 100) i = 100;
+					mdef -= mdef * i/100;
+					mdef2-= mdef2* i/100;
+				}
+			}
 			if(battle_config.magic_defense_type)
-				ad.damage = ad.damage - tstatus->mdef*battle_config.magic_defense_type - tstatus->mdef2;
+				ad.damage = ad.damage - mdef*battle_config.magic_defense_type - mdef2;
 			else
-				ad.damage = ad.damage * (100-tstatus->mdef)/100 - tstatus->mdef2;
+				ad.damage = ad.damage * (100-mdef)/100 - mdef2;
 		}
 
 		if(skill_num == CR_GRANDCROSS || skill_num == NPC_GRANDDARKNESS)

+ 12 - 15
src/map/map.h

@@ -659,6 +659,7 @@ struct map_session_data {
 	int magic_addsize[3];
 	int critaddrace[RC_MAX];
 	int expaddrace[RC_MAX];
+	int ignore_mdef[RC_MAX];
 	int itemgrouphealrate[MAX_ITEMGROUP];
 	short sp_gain_race[RC_MAX];
 	// zeroed arrays end here.
@@ -671,8 +672,14 @@ struct map_session_data {
 		unsigned char flag;
 	} addeff[MAX_PC_BONUS], addeff2[MAX_PC_BONUS];
 	struct { //skillatk raises bonus dmg% of skills, skillheal increases heal%, skillblown increases bonus blewcount for some skills.
-		short id, val;
-	} skillatk[MAX_PC_BONUS], skillheal[5], skillblown[MAX_PC_BONUS];
+		unsigned short id;
+		short val;
+	} skillatk[MAX_PC_BONUS], skillheal[5], skillblown[MAX_PC_BONUS], skillcast[MAX_PC_BONUS];
+	struct {
+		short value;
+		int rate;
+		int tick;
+	} hp_loss, sp_loss, hp_regen, sp_regen;
 	struct {
 		short class_, rate;
 	}	add_def[MAX_PC_BONUS], add_mdef[MAX_PC_BONUS],
@@ -704,17 +711,12 @@ struct map_session_data {
 	int random_attack_increase_add,random_attack_increase_per; // [Valaris]
 	int break_weapon_rate,break_armor_rate;
 	int crit_atk_rate;
-	int hp_loss_rate;
-	int sp_loss_rate;
 	int classchange; // [Valaris]
 	int speed_add_rate, aspd_add;
 	unsigned int setitem_hash, setitem_hash2; //Split in 2 because shift operations only work on int ranges. [Skotlex]
 	
 	short splash_range, splash_add_range;
 	short add_steal_rate;
-	short hp_loss_value;
-	short sp_loss_value;
-	short hp_loss_type;
 	short sp_gain_value, hp_gain_value;
 	short sp_vanish_rate;
 	short sp_vanish_per;	
@@ -733,9 +735,6 @@ struct map_session_data {
 	int matk_rate;
 	int critical_rate,hit_rate,flee_rate,flee2_rate,def_rate,def2_rate,mdef_rate,mdef2_rate;
 
-	int hp_loss_tick;
-	int sp_loss_tick;
-
 	int itemid;
 	short itemindex;	//Used item's index in sd->inventory [Skotlex]
 
@@ -1171,7 +1170,7 @@ enum _sp {
 	SP_CRITICAL_DEF,SP_NEAR_ATK_DEF,SP_LONG_ATK_DEF, // 1019-1021
 	SP_DOUBLE_RATE, SP_DOUBLE_ADD_RATE, SP_SKILL_HEAL, SP_MATK_RATE, // 1022-1025
 	SP_IGNORE_DEF_ELE,SP_IGNORE_DEF_RACE, // 1026-1027
-	SP_ATK_RATE,SP_SPEED_ADDRATE,SP_FREE3, // 1028-1030
+	SP_ATK_RATE,SP_SPEED_ADDRATE,SP_SP_REGEN_RATE, // 1028-1030
 	SP_MAGIC_ATK_DEF,SP_MISC_ATK_DEF, // 1031-1032
 	SP_IGNORE_MDEF_ELE,SP_IGNORE_MDEF_RACE, // 1033-1034
 	SP_MAGIC_ADDELE,SP_MAGIC_ADDRACE,SP_MAGIC_ADDSIZE, // 1035-1037
@@ -1187,6 +1186,7 @@ enum _sp {
 	SP_HP_DRAIN_VALUE,SP_SP_DRAIN_VALUE, // 1079-1080
 	SP_WEAPON_ATK,SP_WEAPON_ATK_RATE, // 1081-1082
 	SP_DELAYRATE,SP_HP_DRAIN_RATE_RACE,SP_SP_DRAIN_RATE_RACE, // 1083-1085
+	SP_IGNORE_MDEF_RATE, //1086
 	
 	SP_RESTART_FULL_RECOVER=2000,SP_NO_CASTCANCEL,SP_NO_SIZEFIX,SP_NO_MAGIC_DAMAGE,SP_NO_WEAPON_DAMAGE,SP_NO_GEMSTONE, // 2000-2005
 	SP_NO_CASTCANCEL2,SP_NO_MISC_DAMAGE,SP_UNBREAKABLE_WEAPON,SP_UNBREAKABLE_ARMOR, SP_UNBREAKABLE_HELM, // 2006-2010
@@ -1194,15 +1194,12 @@ enum _sp {
 
 	SP_CRIT_ATK_RATE, SP_CRITICAL_ADDRACE, SP_NO_REGEN, SP_ADDEFF_WHENHIT, SP_AUTOSPELL_WHENHIT, // 2013-2017
 	SP_SKILL_ATK, SP_UNSTRIPABLE, SP_ADD_DAMAGE_BY_CLASS, // 2018-2020
-	SP_SP_GAIN_VALUE, SP_FREE, SP_HP_LOSS_RATE, SP_ADDRACE2, SP_HP_GAIN_VALUE, // 2021-2025
+	SP_SP_GAIN_VALUE, SP_HP_REGEN_RATE, SP_HP_LOSS_RATE, SP_ADDRACE2, SP_HP_GAIN_VALUE, // 2021-2025
 	SP_SUBSIZE, SP_HP_DRAIN_VALUE_RACE, SP_ADD_ITEM_HEAL_RATE, SP_SP_DRAIN_VALUE_RACE, SP_EXP_ADDRACE,	// 2026-2030
 	SP_SP_GAIN_RACE, SP_SUBRACE2, SP_ADDEFF_WHENHIT_SHORT,	// 2031-2033
 	SP_UNSTRIPABLE_WEAPON,SP_UNSTRIPABLE_ARMOR,SP_UNSTRIPABLE_HELM,SP_UNSTRIPABLE_SHIELD,  // 2034-2037
 	SP_INTRAVISION, SP_ADD_MONSTER_DROP_ITEMGROUP, SP_SP_LOSS_RATE, // 2038-2040
 	SP_ADD_SKILL_BLOW, SP_SP_VANISH_RATE //2041
-	//Before adding another, note that these are free:
-	//1030 (SP_FREE3, previous AspdAddRate)
-	//2022 (SP_FREE, previous bDefIgnoreMob)
 };
 
 enum _look {

+ 6 - 2
src/map/mob.c

@@ -2033,9 +2033,13 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 				}
 			}
 			
-			// process script-granted zeny bonus (get_zeny_num per level +/-10%) [Skotlex]
+			// process script-granted zeny bonus (get_zeny_num) [Skotlex]
 			if(sd->get_zeny_num && rand()%100 < sd->get_zeny_rate)
-				pc_getzeny(sd,md->level*sd->get_zeny_num*(90+rand()%21)/100);
+			{
+				i = sd->get_zeny_num > 0?sd->get_zeny_num:-md->level*sd->get_zeny_num;
+				if (!i) i = 1;
+				pc_getzeny(sd, 1+rand()%i);
+			}
 		}
 		
 		// process items looted by the mob

+ 95 - 39
src/map/pc.c

@@ -1632,6 +1632,12 @@ int pc_bonus(struct map_session_data *sd,int type,int val)
 		if(sd->state.lr_flag != 2)
 			sd->misc_def_rate += val;
 		break;
+	case SP_IGNORE_MDEF_RATE:
+		if(sd->state.lr_flag != 2) {
+			sd->ignore_mdef[RC_NONBOSS] += val;
+			sd->ignore_mdef[RC_BOSS] += val;
+		}
+		break;
 	case SP_IGNORE_MDEF_ELE:
 		if(val >= ELE_MAX) {
 			if(battle_config.error_log)
@@ -2203,7 +2209,7 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
 			break;
 		}
 		if(sd->state.lr_flag != 2)
-			pc_bonus_addeff(sd->addeff2, MAX_PC_BONUS, type2, val, 0,
+			pc_bonus_addeff(sd->addeff2, ARRAYLENGTH(sd->addeff2), type2, val, 0,
 				ATF_SHORT|ATF_TARGET);
 		break;
 	case SP_SKILL_ATK:
@@ -2239,21 +2245,39 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
 		}
 		break;
 	case SP_ADD_SKILL_BLOW:
-		for (i = 0; i < MAX_PC_BONUS && sd->skillblown[i].id != 0 && sd->skillblown[i].id != type2; i++);
-		if (i == MAX_PC_BONUS)
+		if(sd->state.lr_flag == 2)
+			break;
+		for (i = 0; i < ARRAYLENGTH(sd->skillblown) && sd->skillblown[i].id && sd->skillblown[i].id != type2; i++);
+		if (i == ARRAYLENGTH(sd->skillblown))
 		{	//Better mention this so the array length can be updated. [Skotlex]
-			ShowDebug("run_script: bonus2 bSkillBlown reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", MAX_PC_BONUS, type2, val);
+			ShowDebug("run_script: bonus2 bSkillBlown reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillblown), type2, val);
 			break;
 		}
-		if(sd->state.lr_flag != 2) {
-			if (sd->skillblown[i].id == type2)
-				sd->skillblown[i].val += val;
-			else {
-				sd->skillblown[i].id = type2;
-				sd->skillblown[i].val = val;
-			}
+		if(sd->skillblown[i].id == type2)
+			sd->skillblown[i].val += val;
+		else {
+			sd->skillblown[i].id = type2;
+			sd->skillblown[i].val = val;
 		}
 		break;
+
+	case SP_CASTRATE:
+		if(sd->state.lr_flag == 2)
+			break;
+		for (i = 0; i < ARRAYLENGTH(sd->skillcast) && sd->skillcast[i].id && sd->skillblown[i].id != type2; i++);
+		if (i == ARRAYLENGTH(sd->skillcast))
+		{	//Better mention this so the array length can be updated. [Skotlex]
+			ShowDebug("run_script: bonus2 bCastRate reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillcast), type2, val);
+			break;
+		}
+		if(sd->skillcast[i].id == type2)
+			sd->skillcast[i].val += val;
+		else {
+			sd->skillcast[i].id = type2;
+			sd->skillcast[i].val = val;
+		}
+		break;
+
 	case SP_ADD_DAMAGE_BY_CLASS:
 		if(sd->state.lr_flag != 2) {
 			for(i=0;i<sd->add_dmg_count;i++) {
@@ -2271,8 +2295,14 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
 		break;
 	case SP_HP_LOSS_RATE:
 		if(sd->state.lr_flag != 2) {
-			sd->hp_loss_value = type2;
-			sd->hp_loss_rate = val;
+			sd->hp_loss.value = type2;
+			sd->hp_loss.rate = val;
+		}
+		break;
+	case SP_HP_REGEN_RATE:
+		if(sd->state.lr_flag != 2) {
+			sd->hp_regen.value = type2;
+			sd->hp_regen.rate = val;
 		}
 		break;
 	case SP_ADDRACE2:
@@ -2325,8 +2355,14 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
 		break;
 	case SP_SP_LOSS_RATE:
 		if(sd->state.lr_flag != 2) {
-			sd->sp_loss_value = type2;
-			sd->sp_loss_rate = val;
+			sd->sp_loss.value = type2;
+			sd->sp_loss.rate = val;
+		}
+		break;
+	case SP_SP_REGEN_RATE:
+		if(sd->state.lr_flag != 2) {
+			sd->sp_regen.value = type2;
+			sd->sp_regen.rate = val;
 		}
 		break;
 	case SP_HP_DRAIN_VALUE_RACE:
@@ -2345,6 +2381,10 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
 			sd->left_weapon.sp_drain[type2].value += val;
 		}
 		break;
+	case SP_IGNORE_MDEF_RATE:
+		if(sd->state.lr_flag != 2)
+			sd->ignore_mdef[type2] += val;
+		break;
 
 	default:
 		if(battle_config.error_log)
@@ -2371,13 +2411,6 @@ int pc_bonus3(struct map_session_data *sd,int type,int type2,int type3,int val)
 		if(sd->state.lr_flag != 2)
 			pc_bonus_autospell(sd->autospell2, MAX_PC_BONUS, skill_get_inf(type2)&INF_SELF_SKILL?-type2:type2, type3, val, 0, current_equip_card_id);
 		break;
-	case SP_HP_LOSS_RATE:
-		if(sd->state.lr_flag != 2) {
-			sd->hp_loss_value = type2;
-			sd->hp_loss_rate = type3;
-			sd->hp_loss_type = val;
-		}
-		break;
 	case SP_SP_DRAIN_RATE:
 		if(!sd->state.lr_flag) {
 			sd->right_weapon.sp_drain[RC_NONBOSS].rate += type2;
@@ -4919,7 +4952,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 	if (sd->menuskill_id)
 		sd->menuskill_id = sd->menuskill_val = 0;
 	//Reset ticks.
-	sd->hp_loss_tick = sd->sp_loss_tick = 0;
+	sd->hp_loss.tick = sd->sp_loss.tick = sd->hp_regen.tick = sd->sp_regen.tick = 0;
 
 	pc_setglobalreg(sd,"PC_DIE_COUNTER",++sd->die_counter);
 
@@ -6828,25 +6861,19 @@ void pc_bleeding (struct map_session_data *sd, unsigned int diff_tick)
 {
 	int hp = 0, sp = 0;
 
-	if (sd->hp_loss_value > 0) {
-		sd->hp_loss_tick += diff_tick;
-		if (sd->hp_loss_tick >= sd->hp_loss_rate) {
-			do {
-				hp += sd->hp_loss_value;
-				sd->hp_loss_tick -= sd->hp_loss_rate;
-			} while (sd->hp_loss_tick >= sd->hp_loss_rate);
-			sd->hp_loss_tick = 0;
+	if (sd->hp_loss.value) {
+		sd->hp_loss.tick += diff_tick;
+		while (sd->hp_loss.tick >= sd->hp_loss.rate) {
+			hp += sd->hp_loss.value;
+			sd->hp_loss.tick -= sd->hp_loss.rate;
 		}
 	}
 	
-	if (sd->sp_loss_value > 0) {
-		sd->sp_loss_tick += diff_tick;
-		if (sd->sp_loss_tick >= sd->sp_loss_rate) {
-			do {
-				sp += sd->sp_loss_value;
-				sd->sp_loss_tick -= sd->sp_loss_rate;
-			} while (sd->sp_loss_tick >= sd->sp_loss_rate);
-			sd->sp_loss_tick = 0;
+	if (sd->sp_loss.value) {
+		sd->sp_loss.tick += diff_tick;
+		while (sd->sp_loss.tick >= sd->sp_loss.rate) {
+			sp += sd->sp_loss.value;
+			sd->sp_loss.tick -= sd->sp_loss.rate;
 		}
 	}
 
@@ -6856,6 +6883,35 @@ void pc_bleeding (struct map_session_data *sd, unsigned int diff_tick)
 	return;
 }
 
+//Character regen. Flag is used to know which types of regen can take place.
+//&1: HP regen
+//&2: SP regen
+void pc_regen (struct map_session_data *sd, unsigned int diff_tick, int flag)
+{
+	int hp = 0, sp = 0;
+
+	if (sd->hp_regen.value && flag&1) {
+		sd->hp_regen.tick += diff_tick;
+		while (sd->hp_regen.tick >= sd->hp_regen.rate) {
+			hp += sd->hp_regen.value;
+			sd->hp_regen.tick -= sd->hp_regen.rate;
+		}
+	}
+	
+	if (sd->sp_regen.value && flag&2) {
+		sd->sp_regen.tick += diff_tick;
+		while (sd->sp_regen.tick >= sd->sp_regen.rate) {
+			sp += sd->sp_regen.value;
+			sd->sp_regen.tick -= sd->sp_regen.rate;
+		}
+	}
+
+	if (hp > 0 || sp > 0)
+		status_heal(&sd->bl, hp, sp, 2);
+
+	return;
+}
+
 /*==========================================
  * ƒZ?ƒuƒ|ƒCƒ“ƒg‚̕ۑ¶
  *------------------------------------------*/

+ 1 - 0
src/map/pc.h

@@ -264,6 +264,7 @@ struct map_session_data *pc_get_mother(struct map_session_data *sd);
 struct map_session_data *pc_get_child(struct map_session_data *sd);
 
 void pc_bleeding (struct map_session_data *sd, unsigned int diff_tick);
+void pc_regen (struct map_session_data *sd, unsigned int diff_tick, int flag);
 
 int pc_set_gm_level(int account_id, int level);
 void pc_setstand(struct map_session_data *sd);

+ 16 - 4
src/map/skill.c

@@ -4604,8 +4604,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 			type = EQP_WEAPON|EQP_SHIELD|EQP_ARMOR|EQP_HELM;
 			break;
 		}
+		//Note that autospells don't use a duration
 		if (!clif_skill_nodamage(src,bl,skillid,skilllv,
-				skill_strip_equip(bl, type, i, skilllv, skill_get_time(skillid,skilllv)))
+				skill_strip_equip(bl, type, i, skilllv, 
+				sd&&!pc_checkskill(sd, skillid)?0:skill_get_time(skillid,skilllv)))
 			&& sd)
 			clif_skill_fail(sd,skillid,0,0); //Nothing stripped.
 		break;
@@ -8789,10 +8791,20 @@ int skill_castfix (struct block_list *bl, int skill_id, int skill_lv)
 	}
 
 	// calculate cast time reduced by item/card bonuses
-	if (!(skill_get_castnodex(skill_id, skill_lv)&4))
-		if (sd && sd->castrate != 100)
+	if (!(skill_get_castnodex(skill_id, skill_lv)&4) && sd)
+	{
+		int i;
+		if (sd->castrate != 100)
 			time = time * sd->castrate / 100;
-
+		for(i = 0; i < ARRAYLENGTH(sd->skillcast) && sd->skillcast[i].id; i++)
+		{
+			if (sd->skillcast[i].id == skill_id)
+			{
+				time+= time * sd->skillcast[i].val / 100;
+				break;
+			}
+		}
+	}
 	// config cast time multiplier
 	if (battle_config.cast_rate != 100)
 		time = time * battle_config.cast_rate / 100;

+ 19 - 14
src/map/status.c

@@ -384,7 +384,7 @@ void initChangeTables(void)
 	add_sc(NPC_MAGICMIRROR, SC_MAGICMIRROR);
 	set_sc(NPC_SLOWCAST, SC_SLOWCAST, SI_SLOWCAST, SCB_NONE);
 	set_sc(NPC_CRITICALWOUND, SC_CRITICALWOUND, SI_CRITICALWOUND, SCB_NONE);
-	set_sc(NPC_STONESKIN, SC_ARMORCHANGE, SI_BLANK, SCB_DEF|SCB_MDEF|SCB_DEF2|SCB_MDEF2);
+	set_sc(NPC_STONESKIN, SC_ARMORCHANGE, SI_BLANK, SCB_DEF|SCB_MDEF);
 	add_sc(NPC_ANTIMAGIC, SC_ARMORCHANGE);
 	add_sc(NPC_WIDECURSE, SC_CURSE);
 	add_sc(NPC_WIDESTUN, SC_STUN);
@@ -1657,6 +1657,7 @@ int status_calc_pc(struct map_session_data* sd,int first)
 		+ sizeof(sd->magic_addsize)
 		+ sizeof(sd->critaddrace)
 		+ sizeof(sd->expaddrace)
+		+ sizeof(sd->ignore_mdef)
 		+ sizeof(sd->itemgrouphealrate)
 		+ sizeof(sd->sp_gain_race)
 		);
@@ -1697,6 +1698,7 @@ int status_calc_pc(struct map_session_data* sd,int first)
 		+ sizeof(sd->skillatk)
 		+ sizeof(sd->skillheal)
 		+ sizeof(sd->skillblown)
+		+ sizeof(sd->skillcast)
 		+ sizeof(sd->add_def)
 		+ sizeof(sd->add_mdef)
 		+ sizeof(sd->add_dmg)
@@ -1734,8 +1736,6 @@ int status_calc_pc(struct map_session_data* sd,int first)
 		+ sizeof(sd->break_weapon_rate)
 		+ sizeof(sd->break_armor_rate)
 		+ sizeof(sd->crit_atk_rate)
-		+ sizeof(sd->hp_loss_rate)
-		+ sizeof(sd->sp_loss_rate)
 		+ sizeof(sd->classchange)
 		+ sizeof(sd->speed_add_rate)
 		+ sizeof(sd->aspd_add)
@@ -1745,9 +1745,6 @@ int status_calc_pc(struct map_session_data* sd,int first)
 		+ sizeof(sd->splash_range)
 		+ sizeof(sd->splash_add_range)
 		+ sizeof(sd->add_steal_rate)
-		+ sizeof(sd->hp_loss_value)
-		+ sizeof(sd->sp_loss_value)
-		+ sizeof(sd->hp_loss_type)
 		+ sizeof(sd->hp_gain_value)
 		+ sizeof(sd->sp_gain_value)
 		+ sizeof(sd->sp_vanish_rate)
@@ -3556,7 +3553,7 @@ static signed char status_calc_def(struct block_list *bl, struct status_change *
 	if(sc->data[SC_STEELBODY].timer!=-1)
 		return 90;
 	if(sc->data[SC_ARMORCHANGE].timer!=-1)
-		def += def * sc->data[SC_ARMORCHANGE].val2/100;
+		def += sc->data[SC_ARMORCHANGE].val2;
 	if(sc->data[SC_DRUMBATTLE].timer!=-1)
 		def += sc->data[SC_DRUMBATTLE].val3;
 	if(sc->data[SC_DEFENCE].timer != -1)	//[orn]
@@ -3592,8 +3589,6 @@ static signed short status_calc_def2(struct block_list *bl, struct status_change
 		return 0;
 	if(sc->data[SC_ETERNALCHAOS].timer!=-1)
 		return 0;
-	if(sc->data[SC_ARMORCHANGE].timer!=-1)
-		def2 += def2 * sc->data[SC_ARMORCHANGE].val2/100;
 	if(sc->data[SC_SUN_COMFORT].timer!=-1)
 		def2 += sc->data[SC_SUN_COMFORT].val2;
 	if(sc->data[SC_ANGELUS].timer!=-1)
@@ -3633,7 +3628,7 @@ static signed char status_calc_mdef(struct block_list *bl, struct status_change
 	if(sc->data[SC_SKA].timer != -1) // [marquis007]
 		return 90;
 	if(sc->data[SC_ARMORCHANGE].timer!=-1)
-		mdef += mdef * sc->data[SC_ARMORCHANGE].val3/100;
+		mdef += sc->data[SC_ARMORCHANGE].val3;
 	if(sc->data[SC_STONE].timer!=-1 && sc->opt1 == OPT1_STONE)
 		mdef += 25*mdef/100;
 	if(sc->data[SC_FREEZE].timer!=-1)
@@ -3651,8 +3646,6 @@ static signed short status_calc_mdef2(struct block_list *bl, struct status_chang
 
 	if(sc->data[SC_BERSERK].timer!=-1)
 		return 0;
-	if(sc->data[SC_ARMORCHANGE].timer!=-1)
-		mdef2 += mdef2 * sc->data[SC_ARMORCHANGE].val3/100;
 	if(sc->data[SC_MINDBREAKER].timer!=-1)
 		mdef2 -= mdef2 * sc->data[SC_MINDBREAKER].val3/100;
 
@@ -4466,6 +4459,10 @@ int status_get_sc_def(struct block_list *bl, int type, int rate, int tick, int f
 			tick /= 5;
 		sc_def = status->agi;
 		break;
+	case SC_ARMORCHANGE:
+		if (sd) //Duration greatly reduced for players.
+			tick /= 15;
+		//No defense against it.
 	default:
 		//Effect that cannot be reduced? Likely a buff.
 		if (!(rand()%10000 < rate))
@@ -4711,6 +4708,7 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
 			}
 			if (!opt_flag) return 0;
 		}
+		if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC
 		break;
 	case SC_STRIPSHIELD:
 		if (sd) {
@@ -4723,6 +4721,7 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
 				return 0;
 			pc_unequipitem(sd,i,3);
 		}
+		if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC
 		break;
 	case SC_STRIPARMOR:
 		if (sd) {
@@ -4734,6 +4733,7 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
 				return 0;
 			pc_unequipitem(sd,i,3);
 		}
+		if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC
 		break;
 	case SC_STRIPHELM:
 		if (sd) {
@@ -4745,6 +4745,7 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
 				return 0;
 			pc_unequipitem(sd,i,3);
 		}
+		if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC
 		break;
 	}
 
@@ -7132,8 +7133,8 @@ static int status_natural_heal(DBKey key,void * data,va_list ap)
 	))
 		flag=0;
 
-	if (sd && (sd->hp_loss_value > 0 || sd->sp_loss_value > 0))
-		pc_bleeding(sd, natural_heal_diff_tick);
+	if (sd && (sd->hp_loss.value || sd->sp_loss.value))
+			pc_bleeding(sd, natural_heal_diff_tick);
 
 	if(flag&(RGN_SHP|RGN_SSP) && regen->ssregen &&
 		(vd = status_get_viewdata(bl)) && vd->dead_sit == 2)
@@ -7236,6 +7237,10 @@ static int status_natural_heal(DBKey key,void * data,va_list ap)
 		}
 	}
 
+	//Bonus skill-like regen
+	if (sd && (sd->hp_regen.value || sd->sp_regen.value))
+		pc_regen(sd, natural_heal_diff_tick, (flag&RGN_SHP?1:0)|(flag&RGN_SSP?2:0));
+
 	if (!regen->sregen)
 		return flag;