Ver Fonte

- Fixed HVAN_INSTRUCT int bonuses.
- Renamed mob_db's "adelay" column to ThinkTime and made the mob.c code use it instead of MIN_MOBTHINKTIME. The adelay of mobs will also be equal to their thinktime unless their thinktime is less than their attack motion.
- Cleaned the mob_db reading code a bit.


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

skotlex há 18 anos atrás
pai
commit
a7cd3bf966
8 ficheiros alterados com 123 adições e 112 exclusões
  1. 5 0
      Changelog-Trunk.txt
  2. 1 1
      db/mob_db.txt
  3. 1 1
      db/mob_db2.txt
  4. 1 1
      db/mob_db_a.txt
  5. 108 104
      src/map/mob.c
  6. 1 0
      src/map/mob.h
  7. 4 3
      src/map/skill.c
  8. 2 2
      src/map/status.c

+ 5 - 0
Changelog-Trunk.txt

@@ -4,6 +4,11 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 2006/12/04
+	* Fixed HVAN_INSTRUCT int bonuses. [Skotlex]
+	* Renamed mob_db's "adelay" column to ThinkTime and made the mob.c code use
+	  it instead of MIN_MOBTHINKTIME. The adelay of mobs will also be equal to
+	  their thinktime unless their thinktime is less than their attack motion.
+	  [Skotlex]
 	* Added a static +100 Hp to ninjas and gunslingers since it's required for
 	  the best approximated hp growth algorythm. [Skotlex]
 	* Knockback will again use the fixpos packet instead of the slide packet

+ 1 - 1
db/mob_db.txt

@@ -1,7 +1,7 @@
 // Monster Database
 //
 // Structure of Database :
-// ID,Sprite_Name,kROName,iROName,LV,HP,SP,EXP,JEXP,Range1,ATK1,ATK2,DEF,MDEF,STR,AGI,VIT,INT,DEX,LUK,Range2,Range3,Scale,Race,Element,Mode,Speed,ADelay,aMotion,dMotion,MEXP,ExpPer,MVP1id,MVP1per,MVP2id,MVP2per,MVP3id,MVP3per,Drop1id,Drop1per,Drop2id,Drop2per,Drop3id,Drop3per,Drop4id,Drop4per,Drop5id,Drop5per,Drop6id,Drop6per,Drop7id,Drop7per,Drop8id,Drop8per,Drop9id,Drop9per,DropCardid,DropCardper
+// ID,Sprite_Name,kROName,iROName,LV,HP,SP,EXP,JEXP,Range1,ATK1,ATK2,DEF,MDEF,STR,AGI,VIT,INT,DEX,LUK,Range2,Range3,Scale,Race,Element,Mode,Speed,ThinkTime,aMotion,dMotion,MEXP,ExpPer,MVP1id,MVP1per,MVP2id,MVP2per,MVP3id,MVP3per,Drop1id,Drop1per,Drop2id,Drop2per,Drop3id,Drop3per,Drop4id,Drop4per,Drop5id,Drop5per,Drop6id,Drop6per,Drop7id,Drop7per,Drop8id,Drop8per,Drop9id,Drop9per,DropCardid,DropCardper
 // Note: Keep the Sprite_Name field as it is (in the game client). You may change Name,JName field tough
 
 1001,SCORPION,Scorpion,Scorpion,24,1109,0,287,176,1,80,135,30,0,1,24,24,5,52,5,10,12,0,4,23,149,200,1564,864,576,0,0,0,0,0,0,0,0,990,70,904,5500,757,57,943,210,7041,100,508,200,625,20,0,0,0,0,4068,1

+ 1 - 1
db/mob_db2.txt

@@ -1,7 +1,7 @@
 // Monsters Additional Database
 //
 // Structure of Database :
-// ID,Sprite_Name,kROName,iROName,LV,HP,SP,EXP,JEXP,Range1,ATK1,ATK2,DEF,MDEF,STR,AGI,VIT,INT,DEX,LUK,Range2,Range3,Scale,Race,Element,Mode,Speed,ADelay,aMotion,dMotion,MEXP,ExpPer,MVP1id,MVP1per,MVP2id,MVP2per,MVP3id,MVP3per,Drop1id,Drop1per,Drop2id,Drop2per,Drop3id,Drop3per,Drop4id,Drop4per,Drop5id,Drop5per,Drop6id,Drop6per,Drop7id,Drop7per,Drop8id,Drop8per,Drop9id,Drop9per,DropCardid,DropCardper
+// ID,Sprite_Name,kROName,iROName,LV,HP,SP,EXP,JEXP,Range1,ATK1,ATK2,DEF,MDEF,STR,AGI,VIT,INT,DEX,LUK,Range2,Range3,Scale,Race,Element,Mode,Speed,ThinkTime,aMotion,dMotion,MEXP,ExpPer,MVP1id,MVP1per,MVP2id,MVP2per,MVP3id,MVP3per,Drop1id,Drop1per,Drop2id,Drop2per,Drop3id,Drop3per,Drop4id,Drop4per,Drop5id,Drop5per,Drop6id,Drop6per,Drop7id,Drop7per,Drop8id,Drop8per,Drop9id,Drop9per,DropCardid,DropCardper
 
 // Crusader quest monsters with poring stats (No drops)
 1910,C_GHOUL,Ghoul,Ghoul,1,50,0,2,1,1,7,10,0,5,1,1,1,1,6,30,10,12,1,3,21,131,400,1872,672,480,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

+ 1 - 1
db/mob_db_a.txt

@@ -1,7 +1,7 @@
 // Monster Database
 //
 // Structure of Database :
-// ID,Sprite_Name,kROName,iROName,LV,HP,SP,EXP,JEXP,Range1,ATK1,ATK2,DEF,MDEF,STR,AGI,VIT,INT,DEX,LUK,Range2,Range3,Scale,Race,Element,Mode,Speed,ADelay,aMotion,dMotion,MEXP,ExpPer,MVP1id,MVP1per,MVP2id,MVP2per,MVP3id,MVP3per,Drop1id,Drop1per,Drop2id,Drop2per,Drop3id,Drop3per,Drop4id,Drop4per,Drop5id,Drop5per,Drop6id,Drop6per,Drop7id,Drop7per,Drop8id,Drop8per,Drop9id,Drop9per,DropCardid,DropCardper
+// ID,Sprite_Name,kROName,iROName,LV,HP,SP,EXP,JEXP,Range1,ATK1,ATK2,DEF,MDEF,STR,AGI,VIT,INT,DEX,LUK,Range2,Range3,Scale,Race,Element,Mode,Speed,ThinkTime,aMotion,dMotion,MEXP,ExpPer,MVP1id,MVP1per,MVP2id,MVP2per,MVP3id,MVP3per,Drop1id,Drop1per,Drop2id,Drop2per,Drop3id,Drop3per,Drop4id,Drop4per,Drop5id,Drop5per,Drop6id,Drop6per,Drop7id,Drop7per,Drop8id,Drop8per,Drop9id,Drop9per,DropCardid,DropCardper
 // Note: Keep the Sprite_Name field as it is (in the game client). You may change Name,JName field tough
 
 1001,SCORPION,Scorpion,Scorpion,24,1109,0,287,176,1,80,135,30,0,1,24,24,5,52,5,10,12,0,4,23,149,200,1564,864,576,0,0,0,0,0,0,0,0,990,70,904,5500,757,57,943,210,7041,100,508,200,625,20,0,0,0,0,4068,1

+ 108 - 104
src/map/mob.c

@@ -641,8 +641,7 @@ int mob_spawn (struct mob_data *md)
 	int i=0;
 	unsigned int c =0, tick = gettick();
 
-	md->last_spawntime = tick;
-	md->last_thinktime = tick -MIN_MOBTHINKTIME;
+	md->last_spawntime = md->last_thinktime = tick;
 	if (md->bl.prev != NULL)
 		unit_remove_map(&md->bl,2);
 	else
@@ -1066,7 +1065,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
 	if(md->bl.prev == NULL || md->status.hp <= 0)
 		return 1;
 		
-	if (DIFF_TICK(tick, md->last_thinktime) < MIN_MOBTHINKTIME)
+	if (DIFF_TICK(tick, md->last_thinktime) < md->db->min_thinktime)
 		return 0;
 	md->last_thinktime = tick;
 
@@ -1351,7 +1350,7 @@ static int mob_ai_sub_lazy(DBKey key,void * data,va_list ap)
 
 	tick=va_arg(ap,unsigned int);
 
-	if(DIFF_TICK(tick,md->last_thinktime)<MIN_MOBTHINKTIME*10)
+	if(DIFF_TICK(tick,md->last_thinktime)< 10*md->db->min_thinktime)
 		return 0;
 
 	md->last_thinktime=tick;
@@ -3186,6 +3185,7 @@ static int mob_readdb(void)
 	char line[1024];
 	char *filename[]={ "mob_db.txt","mob_db2.txt" };
 	struct status_data *status;
+	struct mob_db *db;
 	int class_, i, fi, k;
 	struct mob_data data;
 	memset(&data, 0, sizeof(struct mob_data));
@@ -3232,35 +3232,36 @@ static int mob_readdb(void)
 			}
 			if (mob_db_data[class_] == NULL)
 				mob_db_data[class_] = aCalloc(1, sizeof (struct mob_data));
+			db = mob_db_data[class_];
 
-			mob_db_data[class_]->vd.class_ = class_;
-			memcpy(mob_db_data[class_]->sprite, str[1], NAME_LENGTH-1);
-			memcpy(mob_db_data[class_]->jname, str[2], NAME_LENGTH-1);
-			memcpy(mob_db_data[class_]->name, str[3], NAME_LENGTH-1);
-			mob_db_data[class_]->lv = atoi(str[4]);
-			if (mob_db_data[class_]->lv < 1)
-				mob_db_data[class_]->lv = 1;
+			db->vd.class_ = class_;
+			memcpy(db->sprite, str[1], NAME_LENGTH-1);
+			memcpy(db->jname, str[2], NAME_LENGTH-1);
+			memcpy(db->name, str[3], NAME_LENGTH-1);
+			db->lv = atoi(str[4]);
+			if (db->lv < 1)
+				db->lv = 1;
 
-			status = &mob_db_data[class_]->status;
+			status = &db->status;
 
 			status->max_hp = atoi(str[5]);
 			status->max_sp = atoi(str[6]);
 
 			exp = (double)atoi(str[7]) * (double)battle_config.base_exp_rate / 100.;
 			if (exp < 0)
-				mob_db_data[class_]->base_exp = 0;
+				db->base_exp = 0;
 			if (exp > UINT_MAX)
-				mob_db_data[class_]->base_exp = UINT_MAX;
+				db->base_exp = UINT_MAX;
 			else
-				mob_db_data[class_]->base_exp = (unsigned int)exp;
+				db->base_exp = (unsigned int)exp;
 
 			exp = (double)atoi(str[8]) * (double)battle_config.job_exp_rate / 100.;
 			if (exp < 0)
-				mob_db_data[class_]->job_exp = 0;
+				db->job_exp = 0;
 			else if (exp > UINT_MAX)
-				mob_db_data[class_]->job_exp = UINT_MAX;
+				db->job_exp = UINT_MAX;
 			else
-			mob_db_data[class_]->job_exp = (unsigned int)exp;
+				db->job_exp = (unsigned int)exp;
 			
 			status->rhw.range=atoi(str[9]);
 			status->rhw.atk=atoi(str[10]);
@@ -3281,23 +3282,23 @@ static int mob_readdb(void)
 			if (status->dex < 1) status->dex = 1;
 			if (status->luk < 1) status->luk = 1;
 
-			mob_db_data[class_]->range2=atoi(str[20]);
-			mob_db_data[class_]->range3=atoi(str[21]);
+			db->range2=atoi(str[20]);
+			db->range3=atoi(str[21]);
 			if (battle_config.view_range_rate!=100)
 			{
-				mob_db_data[class_]->range2=
-					mob_db_data[class_]->range2
+				db->range2=
+					db->range2
 					*battle_config.view_range_rate/100;
-				if (mob_db_data[class_]->range2<1)
-					mob_db_data[class_]->range2=1;
+				if (db->range2<1)
+					db->range2=1;
 			}
 			if (battle_config.chase_range_rate!=100)
 			{
-				mob_db_data[class_]->range3=
-					mob_db_data[class_]->range3
+				db->range3=
+					db->range3
 					*battle_config.chase_range_rate/100;
-				if (mob_db_data[class_]->range3<mob_db_data[class_]->range2)
-					mob_db_data[class_]->range3=mob_db_data[class_]->range2;
+				if (db->range3<db->range2)
+					db->range3=db->range2;
 			}
 			status->size=atoi(str[22]);
 			status->race=atoi(str[23]);
@@ -3317,25 +3318,26 @@ static int mob_readdb(void)
 			status->mode=atoi(str[25]);
 			status->speed=atoi(str[26]);
 			status->aspd_rate = 1000;
-			status->adelay=atoi(str[27]);
-			status->amotion=atoi(str[28]);
+			db->min_thinktime=atoi(str[27]);
+			status->adelay = status->amotion=atoi(str[28]);
+			if (db->min_thinktime > status->adelay)
+				status->adelay = db->min_thinktime;
+			if (db->min_thinktime < MIN_MOBTHINKTIME)
+				db->min_thinktime = MIN_MOBTHINKTIME;
 			status->dmotion=atoi(str[29]);
-			//If the attack animation is longer than the delay, the client crops the attack animation!
-			if (status->adelay < status->amotion)
-				status->adelay = status->amotion;
 			if(battle_config.monster_damage_delay_rate != 100)
 				status->dmotion = status->dmotion*battle_config.monster_damage_delay_rate/100;
 
-			data.level = mob_db_data[class_]->lv;
+			data.level = db->lv;
 			memcpy(&data.status, status, sizeof(struct status_data));
-			status_calc_misc(&data.bl, status, mob_db_data[class_]->lv);
+			status_calc_misc(&data.bl, status, db->lv);
 			// MVP EXP Bonus, Chance: MEXP,ExpPer
-			mob_db_data[class_]->mexp=atoi(str[30])*battle_config.mvp_exp_rate/100;
-			mob_db_data[class_]->mexpper=atoi(str[31]);
+			db->mexp=atoi(str[30])*battle_config.mvp_exp_rate/100;
+			db->mexpper=atoi(str[31]);
 			//Now that we know if it is an mvp or not,
 			//apply battle_config modifiers [Skotlex]
 			maxhp = (double)status->max_hp;
-			if (mob_db_data[class_]->mexp > 0)
+			if (db->mexp > 0)
 			{	//Mvp
 				if (battle_config.mvp_hp_rate != 100) 
 					maxhp = maxhp * (double)battle_config.mvp_hp_rate /100.;
@@ -3352,21 +3354,21 @@ static int mob_readdb(void)
 			// MVP Drops: MVP1id,MVP1per,MVP2id,MVP2per,MVP3id,MVP3per
 			for(i=0;i<3;i++){
 				struct item_data *id;
-				mob_db_data[class_]->mvpitem[i].nameid=atoi(str[32+i*2]);
-				if (!mob_db_data[class_]->mvpitem[i].nameid) {
+				db->mvpitem[i].nameid=atoi(str[32+i*2]);
+				if (!db->mvpitem[i].nameid) {
 					//No item....
-					mob_db_data[class_]->mvpitem[i].p = 0;
+					db->mvpitem[i].p = 0;
 					continue;
 				}
-				mob_db_data[class_]->mvpitem[i].p= mob_drop_adjust(atoi(str[33+i*2]), battle_config.item_rate_mvp,
+				db->mvpitem[i].p= mob_drop_adjust(atoi(str[33+i*2]), battle_config.item_rate_mvp,
 					battle_config.item_drop_mvp_min, battle_config.item_drop_mvp_max);
 
 				//calculate and store Max available drop chance of the MVP item
-				if (mob_db_data[class_]->mvpitem[i].p) {
-					id = itemdb_search(mob_db_data[class_]->mvpitem[i].nameid);
-					if (id->maxchance==10000 || (id->maxchance < mob_db_data[class_]->mvpitem[i].p/10+1) ) {
+				if (db->mvpitem[i].p) {
+					id = itemdb_search(db->mvpitem[i].nameid);
+					if (id->maxchance==10000 || (id->maxchance < db->mvpitem[i].p/10+1) ) {
 					//item has bigger drop chance or sold in shops
-						id->maxchance = mob_db_data[class_]->mvpitem[i].p/10+1; //reduce MVP drop info to not spoil common drop rate
+						id->maxchance = db->mvpitem[i].p/10+1; //reduce MVP drop info to not spoil common drop rate
 					}			
 				}
 			}
@@ -3376,13 +3378,13 @@ static int mob_readdb(void)
 				unsigned short ratemin,ratemax;
 				struct item_data *id;
 				k=38+i*2;
-				mob_db_data[class_]->dropitem[i].nameid=atoi(str[k]);
-				if (!mob_db_data[class_]->dropitem[i].nameid) {
+				db->dropitem[i].nameid=atoi(str[k]);
+				if (!db->dropitem[i].nameid) {
 					//No drop.
-					mob_db_data[class_]->dropitem[i].p = 0;
+					db->dropitem[i].p = 0;
 					continue;
 				}
-				type = itemdb_type(mob_db_data[class_]->dropitem[i].nameid);
+				type = itemdb_type(db->dropitem[i].nameid);
 				rate = atoi(str[k+1]);
 				if (class_ >= 1324 && class_ <= 1363)
 				{	//Treasure box drop rates [Skotlex]
@@ -3436,19 +3438,19 @@ static int mob_readdb(void)
 					ratemax = battle_config.item_drop_common_max;
 					break;
 				}
-				mob_db_data[class_]->dropitem[i].p = mob_drop_adjust(rate, rate_adjust, ratemin, ratemax);
+				db->dropitem[i].p = mob_drop_adjust(rate, rate_adjust, ratemin, ratemax);
 
 				//calculate and store Max available drop chance of the item
-				if (mob_db_data[class_]->dropitem[i].p &&
+				if (db->dropitem[i].p &&
 					(class_ < 1324 || class_ > 1363) //Skip treasure chests.
 				) {
-					id = itemdb_search(mob_db_data[class_]->dropitem[i].nameid);
-					if (id->maxchance==10000 || (id->maxchance < mob_db_data[class_]->dropitem[i].p) ) {
+					id = itemdb_search(db->dropitem[i].nameid);
+					if (id->maxchance==10000 || (id->maxchance < db->dropitem[i].p) ) {
 					//item has bigger drop chance or sold in shops
-						id->maxchance = mob_db_data[class_]->dropitem[i].p;
+						id->maxchance = db->dropitem[i].p;
 					}
 					for (k = 0; k< MAX_SEARCH; k++) {
-						if (id->mob[k].chance < mob_db_data[class_]->dropitem[i].p && id->mob[k].id != class_)
+						if (id->mob[k].chance < db->dropitem[i].p && id->mob[k].id != class_)
 							break;
 					}
 					if (k == MAX_SEARCH)
@@ -3456,7 +3458,7 @@ static int mob_readdb(void)
 				
 					if (id->mob[k].id != class_)
 						memmove(&id->mob[k+1], &id->mob[k], (MAX_SEARCH-k-1)*sizeof(id->mob[0]));
-					id->mob[k].chance = mob_db_data[class_]->dropitem[i].p;
+					id->mob[k].chance = db->dropitem[i].p;
 					id->mob[k].id = class_;
 				}
 			}
@@ -3900,6 +3902,7 @@ static int mob_read_sqldb(void)
 	double exp, maxhp;
 	long unsigned int ln = 0;
 	struct status_data *status;
+	struct mob_db *db;
 	char *mob_db_name[] = { mob_db_db, mob_db2_db };
 	struct mob_data data;
 	memset(&data, 0, sizeof(struct mob_data));
@@ -3930,37 +3933,37 @@ static int mob_read_sqldb(void)
 					continue;
 				}
 				if (mob_db_data[class_] == NULL)
-					mob_db_data[class_] = aCalloc(1, sizeof (struct mob_data));
-				
+					db_data[class_] = aCalloc(1, sizeof (struct mob_data));
+				db = mob_db_data[class_];
 				ln++;
 
-				mob_db_data[class_]->vd.class_ = class_;
-				memcpy(mob_db_data[class_]->sprite, TO_STR(1), NAME_LENGTH-1);
-				memcpy(mob_db_data[class_]->jname, TO_STR(2), NAME_LENGTH-1);
-				memcpy(mob_db_data[class_]->name, TO_STR(3), NAME_LENGTH-1);
-				mob_db_data[class_]->lv = TO_INT(4);
-				if (mob_db_data[class_]->lv < 1)
-					mob_db_data[class_]->lv = 1;
+				db->vd.class_ = class_;
+				memcpy(db->sprite, TO_STR(1), NAME_LENGTH-1);
+				memcpy(db->jname, TO_STR(2), NAME_LENGTH-1);
+				memcpy(db->name, TO_STR(3), NAME_LENGTH-1);
+				db->lv = TO_INT(4);
+				if (db->lv < 1)
+					db->lv = 1;
 
-				status = &mob_db_data[class_]->status;
+				status = &db->status;
 				status->max_hp = TO_INT(5);
 				status->max_sp = TO_INT(6);
 
 				exp = (double)TO_INT(7) * (double)battle_config.base_exp_rate / 100.;
 				if (exp < 0)
-					mob_db_data[class_]->base_exp = 0;
+					db->base_exp = 0;
 				else if (exp > UINT_MAX)
-					mob_db_data[class_]->base_exp = UINT_MAX;
+					db->base_exp = UINT_MAX;
 				else
-					mob_db_data[class_]->base_exp = (unsigned int)exp;
+					db->base_exp = (unsigned int)exp;
 
 				exp = (double)TO_INT(8) * (double)battle_config.job_exp_rate / 100.;
 				if (exp < 0)
-					mob_db_data[class_]->job_exp = 0;
+					db->job_exp = 0;
 				else if (exp > UINT_MAX)
-					mob_db_data[class_]->job_exp = UINT_MAX;
+					db->job_exp = UINT_MAX;
 				else
-					mob_db_data[class_]->job_exp = (unsigned int)exp;
+					db->job_exp = (unsigned int)exp;
 				
 				status->rhw.range = TO_INT(9);
 				status->rhw.atk = TO_INT(10);
@@ -3981,8 +3984,8 @@ static int mob_read_sqldb(void)
 				if (status->dex < 1) status->dex = 1;
 				if (status->luk < 1) status->luk = 1;
 
-				mob_db_data[class_]->range2 = TO_INT(20);
-				mob_db_data[class_]->range3 = TO_INT(21);
+				db->range2 = TO_INT(20);
+				db->range3 = TO_INT(21);
 				status->size = TO_INT(22);
 				status->race = TO_INT(23);
 				i = TO_INT(24); //Element
@@ -4001,26 +4004,27 @@ static int mob_read_sqldb(void)
 				status->mode = TO_INT(25);
 				status->speed = TO_INT(26);
 				status->aspd_rate = 1000;
-				status->adelay = TO_INT(27);
-				status->amotion = TO_INT(28);
+				db->min_thinktime = TO_INT(27);
+				status->adelay = status->amotion = TO_INT(28);
+				if (db->min_thinktime > status->adelay)
+					status->adelay = db->min_thinktime;
+				if (db->min_thinktime < MIN_MOBTHINKTIME)
+					db->min_thinktime = MIN_MOBTHINKTIME;
 				status->dmotion = TO_INT(29);
-				//If the attack animation is longer than the delay, the client crops the attack animation!
-				if (status->adelay < status->amotion)
-					status->adelay = status->amotion;
 				if(battle_config.monster_damage_delay_rate != 100)
 					status->dmotion = status->dmotion*battle_config.monster_damage_delay_rate/100;
 
-				data.level = mob_db_data[class_]->lv;
+				data.level = db->lv;
 				memcpy(&data.status, status, sizeof(struct status_data));
-				status_calc_misc(&data.bl, status, mob_db_data[class_]->lv);
+				status_calc_misc(&data.bl, status, db->lv);
 				
 				// MVP EXP Bonus, Chance: MEXP,ExpPer
-				mob_db_data[class_]->mexp = TO_INT(30) * battle_config.mvp_exp_rate / 100;
-				mob_db_data[class_]->mexpper = TO_INT(31);
+				db->mexp = TO_INT(30) * battle_config.mvp_exp_rate / 100;
+				db->mexpper = TO_INT(31);
 				//Now that we know if it is an mvp or not,
 				//apply battle_config modifiers [Skotlex]
 				maxhp = (double)status->max_hp;
-				if (mob_db_data[class_]->mexp > 0)
+				if (db->mexp > 0)
 				{	//Mvp
 					if (battle_config.mvp_hp_rate != 100) 
 						maxhp = maxhp * (double)battle_config.mvp_hp_rate /100.;
@@ -4038,21 +4042,21 @@ static int mob_read_sqldb(void)
 				// MVP Drops: MVP1id,MVP1per,MVP2id,MVP2per,MVP3id,MVP3per
 				for (i=0; i<3; i++) {
 					struct item_data *id;
-					mob_db_data[class_]->mvpitem[i].nameid = TO_INT(32+i*2);
-					if (!mob_db_data[class_]->mvpitem[i].nameid) {
+					db->mvpitem[i].nameid = TO_INT(32+i*2);
+					if (!db->mvpitem[i].nameid) {
 						//No item....
-						mob_db_data[class_]->mvpitem[i].p = 0;
+						db->mvpitem[i].p = 0;
 						continue;
 					}
-					mob_db_data[class_]->mvpitem[i].p = mob_drop_adjust(TO_INT(33+i*2),
+					db->mvpitem[i].p = mob_drop_adjust(TO_INT(33+i*2),
 						battle_config.item_rate_mvp, battle_config.item_drop_mvp_min, battle_config.item_drop_mvp_max);
 
 					//calculate and store Max available drop chance of the MVP item
-					id = itemdb_search(mob_db_data[class_]->mvpitem[i].nameid);
-					if (mob_db_data[class_]->mvpitem[i].p) {
-						if (id->maxchance==10000 || (id->maxchance < mob_db_data[class_]->mvpitem[i].p/10+1) ) {
+					id = itemdb_search(db->mvpitem[i].nameid);
+					if (db->mvpitem[i].p) {
+						if (id->maxchance==10000 || (id->maxchance < db->mvpitem[i].p/10+1) ) {
 						//item has bigger drop chance or sold in shops
-							id->maxchance = mob_db_data[class_]->mvpitem[i].p/10+1; //reduce MVP drop info to not spoil common drop rate
+							id->maxchance = db->mvpitem[i].p/10+1; //reduce MVP drop info to not spoil common drop rate
 						}			
 					}
 				}
@@ -4062,13 +4066,13 @@ static int mob_read_sqldb(void)
 					unsigned short ratemin, ratemax;
 					struct item_data *id;
 					k=38+i*2;
-					mob_db_data[class_]->dropitem[i].nameid=TO_INT(k);
-					if (!mob_db_data[class_]->dropitem[i].nameid) {
+					db->dropitem[i].nameid=TO_INT(k);
+					if (!db->dropitem[i].nameid) {
 						//No drop.
-						mob_db_data[class_]->dropitem[i].p = 0;
+						db->dropitem[i].p = 0;
 						continue;
 					}
-					type = itemdb_type(mob_db_data[class_]->dropitem[i].nameid);
+					type = itemdb_type(db->dropitem[i].nameid);
 					rate = TO_INT(k+1);
 					if (class_ >= 1324 && class_ <= 1363)
 					{	//Treasure box drop rates [Skotlex]
@@ -4121,24 +4125,24 @@ static int mob_read_sqldb(void)
 						ratemax = battle_config.item_drop_common_max;
 						break;
 					}
-					mob_db_data[class_]->dropitem[i].p = mob_drop_adjust(rate, rate_adjust, ratemin, ratemax);
+					db->dropitem[i].p = mob_drop_adjust(rate, rate_adjust, ratemin, ratemax);
 
 					//calculate and store Max available drop chance of the item
-					if (mob_db_data[class_]->dropitem[i].p) {
-						id = itemdb_search(mob_db_data[class_]->dropitem[i].nameid);
-						if (id->maxchance==10000 || (id->maxchance < mob_db_data[class_]->dropitem[i].p) ) {
+					if (db->dropitem[i].p) {
+						id = itemdb_search(db->dropitem[i].nameid);
+						if (id->maxchance==10000 || (id->maxchance < db->dropitem[i].p) ) {
 						//item has bigger drop chance or sold in shops
-							id->maxchance = mob_db_data[class_]->dropitem[i].p;
+							id->maxchance = db->dropitem[i].p;
 						}			
 						for (k = 0; k< MAX_SEARCH; k++) {
-							if (id->mob[k].chance < mob_db_data[class_]->dropitem[i].p && id->mob[k].id != class_)
+							if (id->mob[k].chance < db->dropitem[i].p && id->mob[k].id != class_)
 								break;
 						}
 						if (k == MAX_SEARCH)
 							continue;
 						if (id->mob[k].id != class_)
 							memmove(&id->mob[k+1], &id->mob[k], (MAX_SEARCH-k-1)*sizeof(id->mob[0]));
-						id->mob[k].chance = mob_db_data[class_]->dropitem[i].p;
+						id->mob[k].chance = db->dropitem[i].p;
 						id->mob[k].id = class_;
 					}
 				}

+ 1 - 0
src/map/mob.h

@@ -58,6 +58,7 @@ struct mob_db {
 	char sprite[NAME_LENGTH],name[NAME_LENGTH],jname[NAME_LENGTH];
 	unsigned int base_exp,job_exp;
 	unsigned int mexp,mexpper;
+	unsigned int min_thinktime; //Min think time, Recharge Time as aegis calls it.
 	int range2,range3;
 	short race2;	// celest
 	unsigned short lv;

+ 4 - 3
src/map/skill.c

@@ -5675,8 +5675,8 @@ int skill_castend_id (int tid, unsigned int tick, int id, int data)
 			break;
 
 		if(md) {
-			if(ud->skillid != NPC_EMOTION)//Set afterskill delay.
-				md->last_thinktime=tick + (tid==-1?md->status.adelay:md->status.amotion);
+			if(tid != -1) //Set afterskill delay.
+				md->last_thinktime=tick + md->status.amotion;
 			if(battle_config.mob_ai&0x200) { //pass on delay to same skill.
 				int i;
 				for (i = 0; i < md->db->maxskill; i++)
@@ -5866,7 +5866,8 @@ int skill_castend_pos (int tid, unsigned int tick, int id, int data)
 			break;
 
 		if(md) {
-			md->last_thinktime=tick + (tid==-1?md->status.adelay:md->status.amotion);
+			if (tid != -1)
+				md->last_thinktime=tick +md->status.amotion;
 			if(battle_config.mob_ai&0x200) { //pass on delay to same skill.
 				int i;
 				for (i = 0; i < md->db->maxskill; i++)

+ 2 - 2
src/map/status.c

@@ -2398,8 +2398,8 @@ int status_calc_homunculus(struct homun_data *hd, int first)
 	
 	if((skill = merc_hom_checkskill(hd,HVAN_INSTRUCT)) > 0)
 	{
-		status->int_ += 1 +skill/2 -skill/4 +skill/5;
-		status->str  += 1 +2*(skill/3) +skill/4;
+		status->int_ += 1 +skill/2 +skill/4 +skill/5;
+		status->str  += 1 +skill/3 +skill/3 +skill/4;
 	}
 
 	if((skill=merc_hom_checkskill(hd,HAMI_SKIN)) > 0)