Przeglądaj źródła

Autobonus in combos and monster target drop
- Fixed Autobonus not working in combos (bugreport:8300)
* Combos will now have a "pos" variable that saves the combination of equipment slots used
* Autobonus now works with combined positions rather than just a single position
* Autobonus should now also work with all equipment slots instead of just the first 15
* This does NOT fix problems with multiple auto-bonuses activating at the same time
- Monsters will now stop instantly if their target is completely non-existent
* This is mainly for looters that had their loot taken
* Hide and most other situations still use the configuration setting monster_chase_refresh

Playtester 10 lat temu
rodzic
commit
b6b6b1366a
10 zmienionych plików z 92 dodań i 32 usunięć
  1. 1 1
      conf/battle/monster.conf
  2. 2 0
      src/map/itemdb.c
  3. 3 2
      src/map/mob.c
  4. 29 8
      src/map/pc.c
  5. 4 3
      src/map/pc.h
  6. 42 15
      src/map/script.c
  7. 1 1
      src/map/script.h
  8. 6 0
      src/map/status.c
  9. 1 0
      src/map/status.h
  10. 3 2
      src/map/unit.c

+ 1 - 1
conf/battle/monster.conf

@@ -58,7 +58,7 @@ monster_ai: 0
 // x: Every x cells moved
 // Regardless of this setting, a monster will always rethink its chase if it has 
 // reached its target. Increase this value if you want to make monsters continue
-// moving after they lost their target (hide, loot picked, etc.).
+// moving after they lost their target (hide, no line of sight, etc.).
 monster_chase_refresh: 3
 
 // Should mobs be able to be warped (add as needed)?

+ 2 - 0
src/map/itemdb.c

@@ -1632,8 +1632,10 @@ void itemdb_reload(void) {
 		if( sd->combos.count ) {
 			aFree(sd->combos.bonus);
 			aFree(sd->combos.id);
+			aFree(sd->combos.pos);
 			sd->combos.bonus = NULL;
 			sd->combos.id = NULL;
+			sd->combos.pos = NULL;
 			sd->combos.count = 0;
 			if( pc_load_combo(sd) > 0 )
 				status_calc_pc(sd, SCO_FORCE);

+ 3 - 2
src/map/mob.c

@@ -1446,8 +1446,9 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick)
 		)) {	//No valid target
 			if (mob_warpchase(md, tbl))
 				return true; //Chasing this target.
-			if(md->ud.walktimer != INVALID_TIMER && (!can_move || md->ud.walkpath.path_pos <= battle_config.mob_chase_refresh))
-				return true; //Walk at least "mob_chase_refresh" cells before dropping the target
+			if(md->ud.walktimer != INVALID_TIMER && (!can_move || md->ud.walkpath.path_pos <= battle_config.mob_chase_refresh)
+				&& (tbl || md->ud.walkpath.path_pos == 0))
+				return true; //Walk at least "mob_chase_refresh" cells before dropping the target unless target is non-existent
 			mob_unlocktarget(md, tick); //Unlock target
 			tbl = NULL;
 		}

+ 29 - 8
src/map/pc.c

@@ -2113,7 +2113,7 @@ static void pc_bonus_item_drop(struct s_add_drop *drop, const short max, unsigne
 	drop[i].rate = rate;
 }
 
-bool pc_addautobonus(struct s_autobonus *bonus,char max,const char *script,short rate,unsigned int dur,short flag,const char *other_script,unsigned short pos,bool onskill)
+bool pc_addautobonus(struct s_autobonus *bonus,char max,const char *script,short rate,unsigned int dur,short flag,const char *other_script,unsigned int pos,bool onskill)
 {
 	int i;
 
@@ -2159,14 +2159,19 @@ void pc_delautobonus(struct map_session_data* sd, struct s_autobonus *autobonus,
 	{
 		if( autobonus[i].active != INVALID_TIMER )
 		{
-			if( restore && sd->state.autobonus&autobonus[i].pos )
+			if( restore && (sd->state.autobonus&autobonus[i].pos) == autobonus[i].pos)
 			{
 				if( autobonus[i].bonus_script )
 				{
 					int j;
-					ARR_FIND( 0, EQI_MAX, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus[i].pos );
-					if( j < EQI_MAX )
-						script_run_autobonus(autobonus[i].bonus_script,sd->bl.id,sd->equip_index[j]);
+					unsigned int equip_pos = 0;
+					//Create a list of all equipped positions to see if all items needed for the autobonus are still present [Playtester]
+					for(j = 0; j < EQI_MAX; j++) {
+						if(sd->equip_index[j] >= 0)
+							equip_pos |= sd->status.inventory[sd->equip_index[j]].equip;
+					}
+					if((equip_pos&autobonus[i].pos) == autobonus[i].pos)
+						script_run_autobonus(autobonus[i].bonus_script,sd,autobonus[i].pos);
 				}
 				continue;
 			}
@@ -2193,9 +2198,14 @@ void pc_exeautobonus(struct map_session_data *sd,struct s_autobonus *autobonus)
 	if( autobonus->other_script )
 	{
 		int j;
-		ARR_FIND( 0, EQI_MAX, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus->pos );
-		if( j < EQI_MAX )
-			script_run_autobonus(autobonus->other_script,sd->bl.id,sd->equip_index[j]);
+		unsigned int equip_pos = 0;
+		//Create a list of all equipped positions to see if all items needed for the autobonus are still present [Playtester]
+		for(j = 0; j < EQI_MAX; j++) {
+			if(sd->equip_index[j] >= 0)
+				equip_pos |= sd->status.inventory[sd->equip_index[j]].equip;
+		}
+		if((equip_pos&autobonus->pos) == autobonus->pos)
+			script_run_autobonus(autobonus->other_script,sd,autobonus->pos);
 	}
 
 	autobonus->active = add_timer(gettick()+autobonus->duration, pc_endautobonus, sd->bl.id, (intptr_t)autobonus);
@@ -8923,6 +8933,7 @@ static int pc_checkcombo(struct map_session_data *sd, struct item_data *data) {
 		} *combo_idx;
 		int idx, j;
 		int nb_itemCombo;
+		unsigned int pos = 0;
 		/* ensure this isn't a duplicate combo */
 		if( sd->combos.bonus != NULL ) {
 			int x;
@@ -8967,6 +8978,7 @@ static int pc_checkcombo(struct map_session_data *sd, struct item_data *data) {
 							continue;
 					}
 					combo_idx[j].idx = index;
+					pos |= sd->status.inventory[index].equip;
 					found = true;
 					break;
 				} else { //Cards
@@ -8994,6 +9006,7 @@ static int pc_checkcombo(struct map_session_data *sd, struct item_data *data) {
 							continue;
 						combo_idx[j].idx = index;
 						combo_idx[j].card[z] = id;
+						pos |= sd->status.inventory[index].equip;
 						found = true;
  						break;
  					}
@@ -9011,15 +9024,19 @@ static int pc_checkcombo(struct map_session_data *sd, struct item_data *data) {
 		if( sd->combos.bonus == NULL ) {
 			CREATE(sd->combos.bonus, struct script_code *, 1);
 			CREATE(sd->combos.id, unsigned short, 1);
+			CREATE(sd->combos.pos, unsigned int, 1);
 			sd->combos.count = 1;
 		} else {
 			RECREATE(sd->combos.bonus, struct script_code *, ++sd->combos.count);
 			RECREATE(sd->combos.id, unsigned short, sd->combos.count);
+			RECREATE(sd->combos.pos, unsigned int, sd->combos.count);
 		}
 		/* we simply copy the pointer */
 		sd->combos.bonus[idx] = data->combos[i]->script;
 		/* save this combo's id */
 		sd->combos.id[idx] = data->combos[i]->id;
+		/* save pos of combo*/
+		sd->combos.pos[idx] = pos;
 		success++;
 	}
 	return success;
@@ -9046,6 +9063,7 @@ static int pc_removecombo(struct map_session_data *sd, struct item_data *data )
 
 		sd->combos.bonus[x] = NULL;
 		sd->combos.id[x] = 0;
+		sd->combos.pos[x] = 0;
 		retval++;
 
 		/* check if combo requirements still fit */
@@ -9060,6 +9078,7 @@ static int pc_removecombo(struct map_session_data *sd, struct item_data *data )
 			if( cursor != j ) {
 				sd->combos.bonus[cursor] = sd->combos.bonus[j];
 				sd->combos.id[cursor]    = sd->combos.id[j];
+				sd->combos.pos[cursor]   = sd->combos.pos[j];
 			}
 			cursor++;
 		}
@@ -9068,8 +9087,10 @@ static int pc_removecombo(struct map_session_data *sd, struct item_data *data )
 		if( (sd->combos.count = cursor) == 0 ) {
 			aFree(sd->combos.bonus);
 			aFree(sd->combos.id);
+			aFree(sd->combos.pos);
 			sd->combos.bonus = NULL;
 			sd->combos.id = NULL;
+			sd->combos.pos = NULL;
 			return retval; /* we also can return at this point for we have no more combos to check */
 		}
 	}

+ 4 - 3
src/map/pc.h

@@ -129,7 +129,7 @@ struct s_autobonus {
 	unsigned int duration;
 	char *bonus_script, *other_script;
 	int active;
-	unsigned short pos;
+	unsigned int pos;
 };
 
 struct skill_cooldown_entry {
@@ -220,7 +220,7 @@ struct map_session_data {
 		unsigned short autolootid[AUTOLOOTITEM_SIZE]; // [Zephyrus]
 		unsigned short autoloottype;
 		unsigned int autolooting : 1; //performance-saver, autolooting state for @alootid
-		unsigned short autobonus; //flag to indicate if an autobonus is activated. [Inkfish]
+		unsigned int autobonus; //flag to indicate if an autobonus is activated. [Inkfish]
 		unsigned int gmaster_flag : 1;
 		unsigned int prevend : 1;//used to flag wheather you've spent 40sp to open the vending or not.
 		unsigned int warping : 1;//states whether you're in the middle of a warp processing
@@ -563,6 +563,7 @@ struct map_session_data {
 	struct s_combos {
 		struct script_code **bonus;/* the script */
 		unsigned short *id;/* array of combo ids */
+		unsigned int *pos;/* array of positions*/
 		unsigned char count;
 	} combos;
 
@@ -902,7 +903,7 @@ bool pc_adoption(struct map_session_data *p1_sd, struct map_session_data *p2_sd,
 
 void pc_updateweightstatus(struct map_session_data *sd);
 
-bool pc_addautobonus(struct s_autobonus *bonus,char max,const char *script,short rate,unsigned int dur,short atk_type,const char *o_script,unsigned short pos,bool onskill);
+bool pc_addautobonus(struct s_autobonus *bonus,char max,const char *script,short rate,unsigned int dur,short atk_type,const char *o_script,unsigned int pos,bool onskill);
 void pc_exeautobonus(struct map_session_data* sd,struct s_autobonus *bonus);
 int pc_endautobonus(int tid, unsigned int tick, int id, intptr_t data);
 void pc_delautobonus(struct map_session_data* sd,struct s_autobonus *bonus,char max,bool restore);

+ 42 - 15
src/map/script.c

@@ -308,6 +308,8 @@ const char* parse_syntax(const char* p);
 static int parse_syntax_for_flag = 0;
 
 extern short current_equip_item_index; //for New CARDS Scripts. It contains Inventory Index of the EQUIP_SCRIPT caller item. [Lupus]
+extern unsigned int current_equip_combo_pos;
+
 int potion_flag=0; //For use on Alchemist improved potions/Potion Pitcher. [Skotlex]
 int potion_hp=0, potion_per_hp=0, potion_sp=0, potion_per_sp=0;
 int potion_target=0;
@@ -4044,14 +4046,24 @@ static int db_script_free_code_sub(DBKey key, DBData *data, va_list ap)
 	return 0;
 }
 
-void script_run_autobonus(const char *autobonus, int id, int pos)
+void script_run_autobonus(const char *autobonus, struct map_session_data *sd, unsigned int pos)
 {
 	struct script_code *script = (struct script_code *)strdb_get(autobonus_db, autobonus);
 
 	if( script )
 	{
-		current_equip_item_index = pos;
-		run_script(script,0,id,0);
+		int j;
+		ARR_FIND( 0, EQI_MAX, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == pos );
+		if( j < EQI_MAX ) {
+			//Single item autobonus
+			current_equip_item_index = sd->equip_index[j];
+			current_equip_combo_pos = 0;
+		} else {
+			//Combo autobonus
+			current_equip_item_index = -1;
+			current_equip_combo_pos = pos;
+		}
+		run_script(script,0,sd->bl.id,0);
 	}
 }
 
@@ -8455,7 +8467,7 @@ BUILDIN_FUNC(bonus)
 
 BUILDIN_FUNC(autobonus)
 {
-	unsigned int dur;
+	unsigned int dur, pos;
 	short rate;
 	short atk_type = 0;
 	TBL_PC* sd;
@@ -8465,13 +8477,18 @@ BUILDIN_FUNC(autobonus)
 	if( sd == NULL )
 		return 0; // no player attached
 
-	if( sd->state.autobonus&sd->status.inventory[current_equip_item_index].equip )
+	if (current_equip_combo_pos)
+		pos = current_equip_combo_pos;
+	else
+		pos = sd->status.inventory[current_equip_item_index].equip;
+
+	if((sd->state.autobonus&pos) == pos)
 		return 0;
 
 	rate = script_getnum(st,3);
 	dur = script_getnum(st,4);
 	bonus_script = script_getstr(st,2);
-	if( !rate || !dur || !bonus_script )
+	if( !rate || !dur || !pos || !bonus_script )
 		return 0;
 
 	if( script_hasdata(st,5) )
@@ -8480,7 +8497,7 @@ BUILDIN_FUNC(autobonus)
 		other_script = script_getstr(st,6);
 
 	if( pc_addautobonus(sd->autobonus,ARRAYLENGTH(sd->autobonus),
-		bonus_script,rate,dur,atk_type,other_script,sd->status.inventory[current_equip_item_index].equip,false) )
+		bonus_script,rate,dur,atk_type,other_script,pos,false) )
 	{
 		script_add_autobonus(bonus_script);
 		if( other_script )
@@ -8492,7 +8509,7 @@ BUILDIN_FUNC(autobonus)
 
 BUILDIN_FUNC(autobonus2)
 {
-	unsigned int dur;
+	unsigned int dur, pos;
 	short rate;
 	short atk_type = 0;
 	TBL_PC* sd;
@@ -8502,13 +8519,18 @@ BUILDIN_FUNC(autobonus2)
 	if( sd == NULL )
 		return 0; // no player attached
 
-	if( sd->state.autobonus&sd->status.inventory[current_equip_item_index].equip )
+	if (current_equip_combo_pos)
+		pos = current_equip_combo_pos;
+	else
+		pos = sd->status.inventory[current_equip_item_index].equip;
+
+	if((sd->state.autobonus&pos) == pos)
 		return 0;
 
 	rate = script_getnum(st,3);
 	dur = script_getnum(st,4);
 	bonus_script = script_getstr(st,2);
-	if( !rate || !dur || !bonus_script )
+	if( !rate || !dur || !pos || !bonus_script )
 		return 0;
 
 	if( script_hasdata(st,5) )
@@ -8517,7 +8539,7 @@ BUILDIN_FUNC(autobonus2)
 		other_script = script_getstr(st,6);
 
 	if( pc_addautobonus(sd->autobonus2,ARRAYLENGTH(sd->autobonus2),
-		bonus_script,rate,dur,atk_type,other_script,sd->status.inventory[current_equip_item_index].equip,false) )
+		bonus_script,rate,dur,atk_type,other_script,pos,false) )
 	{
 		script_add_autobonus(bonus_script);
 		if( other_script )
@@ -8529,7 +8551,7 @@ BUILDIN_FUNC(autobonus2)
 
 BUILDIN_FUNC(autobonus3)
 {
-	unsigned int dur;
+	unsigned int dur, pos;
 	short rate,atk_type;
 	TBL_PC* sd;
 	const char *bonus_script, *other_script = NULL;
@@ -8539,7 +8561,12 @@ BUILDIN_FUNC(autobonus3)
 	if( sd == NULL )
 		return 0; // no player attached
 
-	if( sd->state.autobonus&sd->status.inventory[current_equip_item_index].equip )
+	if (current_equip_combo_pos)
+		pos = current_equip_combo_pos;
+	else
+		pos = sd->status.inventory[current_equip_item_index].equip;
+
+	if((sd->state.autobonus&pos) == pos)
 		return 0;
 
 	rate = script_getnum(st,3);
@@ -8548,14 +8575,14 @@ BUILDIN_FUNC(autobonus3)
 	get_val(st, data); // Convert into value in case of a variable
 	atk_type = ( data_isstring(data) ? skill_name2id(script_getstr(st,5)) : script_getnum(st,5) );
 	bonus_script = script_getstr(st,2);
-	if( !rate || !dur || !atk_type || !bonus_script )
+	if( !rate || !dur || !pos || !atk_type || !bonus_script )
 		return 0;
 
 	if( script_hasdata(st,6) )
 		other_script = script_getstr(st,6);
 
 	if( pc_addautobonus(sd->autobonus3,ARRAYLENGTH(sd->autobonus3),
-		bonus_script,rate,dur,atk_type,other_script,sd->status.inventory[current_equip_item_index].equip,true) )
+		bonus_script,rate,dur,atk_type,other_script,pos,true) )
 	{
 		script_add_autobonus(bonus_script);
 		if( other_script )

+ 1 - 1
src/map/script.h

@@ -176,7 +176,7 @@ void script_free_state(struct script_state* st);
 
 struct DBMap* script_get_label_db(void);
 struct DBMap* script_get_userfunc_db(void);
-void script_run_autobonus(const char *autobonus,int id, int pos);
+void script_run_autobonus(const char *autobonus, struct map_session_data *sd, unsigned int pos);
 
 bool script_get_constant(const char* name, int* value);
 void script_set_constant(const char* name, int value, bool isparameter);

+ 6 - 0
src/map/status.c

@@ -61,6 +61,7 @@ static struct eri *sc_data_ers; /// For sc_data entries
 static struct status_data dummy_status;
 
 short current_equip_item_index; /// Contains inventory index of an equipped item. To pass it into the EQUP_SCRIPT [Lupus]
+unsigned int current_equip_combo_pos; /// For combo items we need to save the position of all involved items here
 int current_equip_card_id; /// To prevent card-stacking (from jA) [Skotlex]
 // We need it for new cards 15 Feb 2005, to check if the combo cards are insrerted into the CURRENT weapon only to avoid cards exploits
 
@@ -2957,6 +2958,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 	// Parse equipment
 	for (i = 0; i < EQI_MAX; i++) {
 		current_equip_item_index = index = sd->equip_index[i]; // We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus]
+		current_equip_combo_pos = 0;
 		if (index < 0)
 			continue;
 		if (i == EQI_AMMO)
@@ -3065,6 +3067,9 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 			bool no_run = false;
 			struct item_combo *combo = NULL;
 
+			current_equip_item_index = -1;
+			current_equip_combo_pos = sd->combos.pos[i];
+
 			if (!sd->combos.bonus[i] || !(combo = itemdb_combo_exists(sd->combos.id[i])))
 				continue;
 			// Check combo items
@@ -3094,6 +3099,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 	// Parse Cards
 	for (i = 0; i < EQI_MAX; i++) {
 		current_equip_item_index = index = sd->equip_index[i]; // We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus]
+		current_equip_combo_pos = 0;
 		if (index < 0)
 			continue;
 		if (i == EQI_AMMO)

+ 1 - 0
src/map/status.h

@@ -1536,6 +1536,7 @@ enum e_joint_break
 };
 
 extern short current_equip_item_index;
+extern unsigned int current_equip_combo_pos;
 extern int current_equip_card_id;
 
 //Mode definitions to clear up code reading. [Skotlex]

+ 3 - 2
src/map/unit.c

@@ -1067,7 +1067,7 @@ int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag)
  * @param flag
  *		0x1 - Offensive (not set: self skill, e.g. Backslide)
  *		0x2 - Knockback type (not set: Stop type, e.g. Ankle Snare)
- *      0x4 - Boss attack
+ *		0x4 - Boss attack
  * @return reason for immunity
  *		0 - can be knocked back / stopped
  *		1 - at WOE/BG map;
@@ -1075,7 +1075,7 @@ int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag)
  *		3 - target is MD_KNOCKBACK_IMMUNE|MD_BOSS;
  *		4 - target is in Basilica area;
  *		5 - target has 'special_state.no_knockback';
- *      6 - target is trap that cannot be knocked back
+ *		6 - target is trap that cannot be knocked back
  */
 int unit_blown_immune(struct block_list* bl, int flag)
 {
@@ -3131,6 +3131,7 @@ int unit_free(struct block_list *bl, clr_type clrtype)
 			if( sd->combos.count ) {
 				aFree(sd->combos.bonus);
 				aFree(sd->combos.id);
+				aFree(sd->combos.pos);
 				sd->combos.count = 0;
 			}