Jelajahi Sumber

Improved Icewall walk block implementation
- Moved the configuration setting "icewall_walk_block" to monster.conf
- Split the configuration into mob_icewall_walk_block and boss_icewall_walk_block so it can be configured for bosses separately
- Expanded the configuration
* If the value is set to 1, monsters on an ice wall cell will behave like trapped monsters, that means they won't be able to move at all, they will use idle skills and if they are attacked while nobody is in their attack range, they will use their rudeattacked skills; this is equal to official behavior of bosses
* If the value is set to 2-255, it will behave as before but monsters in the AI loop now use both idle and chase skills, but will no longer use their rudeattacked skills even if attacked from range; this is equal to official behavior of normal monsters
* Official values would be "220" for normal monsters (loop until Icewall expiration) and "1" for bosses (behave like trapped monster) on most official servers, but as some official servers have a less exploitable implementation (from looping AI only a limited amount of times up to outright blocking Icewall on all maps with bosses), we decided for less exploitable default values for now which are 75 for normal monsters (loop 15-35 seconds) and 0 for bosses (impossible to trap in Icewall)
- Cleaned up the rudeattacked code a little so it's easier to read

Playtester 10 tahun lalu
induk
melakukan
b43b855d21
7 mengubah file dengan 56 tambahan dan 23 penghapusan
  1. 16 0
      conf/battle/monster.conf
  2. 0 9
      conf/battle/skill.conf
  3. 2 1
      src/map/battle.c
  4. 2 1
      src/map/battle.h
  5. 11 9
      src/map/mob.c
  6. 1 0
      src/map/skill.h
  7. 24 3
      src/map/unit.c

+ 16 - 0
conf/battle/monster.conf

@@ -216,3 +216,19 @@ mvp_tomb_enabled: yes
 // This is only invoked under the 'monster' command, @monsterbig, and @monstersmall. (Note 1)
 // This is only invoked under the 'monster' command, @monsterbig, and @monstersmall. (Note 1)
 // Default: no
 // Default: no
 mob_size_influence: no
 mob_size_influence: no
+
+// How should a monster be trapped by an icewall casted directly on it?
+// On official servers, monsters can only leave an icewall to the west and south. If their target is north or east of
+// them they will continously try to chase it but fail doing so. This brings them into a loop during which they will use
+// idle and chase skills. Boss monsters on the other hand will behave like a trapped monster, do not move and will use
+// idle and rudeattacked skills (when attacked).
+// 0: Monster won't be stuck in icewall at all.
+// 1: Monster will behave like a trapped monster.
+// 2-255: Number of loops a monster will go through the behavior described above before it frees itself from icewall.
+// NOTE: On some servers, normal monsters can free themselves after 15-35 second depending on their speed. On other
+// servers, they will be stuck inside icewall until it expires. Also, many official servers (e.g. iRO) have casting
+// icewall completely blocked on all maps that have boss monsters on them.
+// Default (least exploitable): mob - 75, boss - 0
+// Default (most official): mob - 220, boss - 1
+mob_icewall_walk_block: 75
+boss_icewall_walk_block: 0

+ 0 - 9
conf/battle/skill.conf

@@ -313,12 +313,3 @@ cart_revo_knockback: yes
 
 
 // On official servers, Arrow Shower blow direction always rely on skill placed location to target instead of caster to target
 // On official servers, Arrow Shower blow direction always rely on skill placed location to target instead of caster to target
 arrow_shower_knockback: yes
 arrow_shower_knockback: yes
-
-// How many attempts should a monster need until it can escape from an icewall casted directly on it?
-// On official servers, monsters can only leave an icewall to the west and south. If their target is north or east of them
-// they will continously try to chase it but fail doing so. This brings them into a loop during which they will cast idle
-// and rudeattacked skills (if attacked). Official servers have a safety system that eventually allows monsters to escape
-// when their walk routine failed many times in row so they won't stay on the loop endlessly. The time for this seems to be
-// around 15 seconds for fast monsters and 35 seconds for slow monsters, this equals about 75 attempts.
-// Set this to 0 if you don't want monsters to be stuck in icewalls at all.
-icewall_walk_block: 75

+ 2 - 1
src/map/battle.c

@@ -7911,7 +7911,8 @@ static const struct _battle_data {
 	{ "devotion_rdamage_skill_only",        &battle_config.devotion_rdamage_skill_only,     1,      0,      1,              },
 	{ "devotion_rdamage_skill_only",        &battle_config.devotion_rdamage_skill_only,     1,      0,      1,              },
 	{ "max_extended_aspd",                  &battle_config.max_extended_aspd,               193,    100,    199,            },
 	{ "max_extended_aspd",                  &battle_config.max_extended_aspd,               193,    100,    199,            },
 	{ "monster_chase_refresh",              &battle_config.mob_chase_refresh,               1,      0,      30,             },
 	{ "monster_chase_refresh",              &battle_config.mob_chase_refresh,               1,      0,      30,             },
-	{ "icewall_walk_block",                 &battle_config.icewall_walk_block,              75,     0,      255,            }
+	{ "mob_icewall_walk_block",             &battle_config.mob_icewall_walk_block,          75,     0,      255,            },
+	{ "boss_icewall_walk_block",            &battle_config.boss_icewall_walk_block,         0,      0,      255,            },
 };
 };
 
 
 #ifndef STATS_OPT_OUT
 #ifndef STATS_OPT_OUT

+ 2 - 1
src/map/battle.h

@@ -573,7 +573,8 @@ extern struct Battle_Config
 	int devotion_rdamage_skill_only;
 	int devotion_rdamage_skill_only;
 	int max_extended_aspd;
 	int max_extended_aspd;
 	int mob_chase_refresh; //How often a monster should refresh its chase [Playtester]
 	int mob_chase_refresh; //How often a monster should refresh its chase [Playtester]
-	int icewall_walk_block; //How long a monster should stay trapped in icewall [Playtester]
+	int mob_icewall_walk_block; //How a normal monster should be trapped in icewall [Playtester]
+	int boss_icewall_walk_block; //How a boss monster should be trapped in icewall [Playtester]
 } battle_config;
 } battle_config;
 
 
 void do_init_battle(void);
 void do_init_battle(void);

+ 11 - 9
src/map/mob.c

@@ -1459,13 +1459,14 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick)
 		if( md->attacked_id == md->target_id )
 		if( md->attacked_id == md->target_id )
 		{	//Rude attacked check.
 		{	//Rude attacked check.
 			if( !battle_check_range(&md->bl, tbl, md->status.rhw.range)
 			if( !battle_check_range(&md->bl, tbl, md->status.rhw.range)
-			   &&  ( //Can't attack back and can't reach back.
+			&&  ( //Can't attack back and can't reach back.
 					(!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1)
 					(!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1)
-					|| md->sc.data[SC_BITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNSTRAP]
-					|| md->sc.data[SC__MANHOLE])) // Not yet confirmed if boss will teleport once it can't reach target.
-					|| !mob_can_reach(md, tbl, md->min_chase, MSS_RUSH)
-					|| md->walktoxy_fail_count > 0
+						|| md->sc.data[SC_BITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNSTRAP]
+						|| md->sc.data[SC__MANHOLE] // Not yet confirmed if boss will teleport once it can't reach target.
+						|| md->walktoxy_fail_count > 0)
 					)
 					)
+					|| !mob_can_reach(md, tbl, md->min_chase, MSS_RUSH)
+				)
 			&&  md->state.attacked_count++ >= RUDE_ATTACKED_COUNT
 			&&  md->state.attacked_count++ >= RUDE_ATTACKED_COUNT
 			&&  !mobskill_use(md, tick, MSC_RUDEATTACKED) // If can't rude Attack
 			&&  !mobskill_use(md, tick, MSC_RUDEATTACKED) // If can't rude Attack
 			&&  can_move && unit_escape(&md->bl, tbl, rnd()%10 +1)) // Attempt escape
 			&&  can_move && unit_escape(&md->bl, tbl, rnd()%10 +1)) // Attempt escape
@@ -1485,11 +1486,12 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick)
 				|| (!battle_check_range(&md->bl, abl, md->status.rhw.range) // Not on Melee Range and ...
 				|| (!battle_check_range(&md->bl, abl, md->status.rhw.range) // Not on Melee Range and ...
 				&& ( // Reach check
 				&& ( // Reach check
 					(!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1)
 					(!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1)
-					|| md->sc.data[SC_BITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNSTRAP]
-					|| md->sc.data[SC__MANHOLE])) // Not yet confirmed if boss will teleport once it can't reach target.
-					|| !mob_can_reach(md, abl, dist+md->db->range3, MSS_RUSH)
-					|| md->walktoxy_fail_count > 0
+						|| md->sc.data[SC_BITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNSTRAP]
+						|| md->sc.data[SC__MANHOLE] // Not yet confirmed if boss will teleport once it can't reach target.
+						|| md->walktoxy_fail_count > 0)
 					)
 					)
+					|| !mob_can_reach(md, abl, dist+md->db->range3, MSS_RUSH)
+				   )
 				) )
 				) )
 			{ // Rude attacked
 			{ // Rude attacked
 				if (md->state.attacked_count++ >= RUDE_ATTACKED_COUNT
 				if (md->state.attacked_count++ >= RUDE_ATTACKED_COUNT

+ 1 - 0
src/map/skill.h

@@ -96,6 +96,7 @@ enum e_skill_inf3 {
 };
 };
 
 
 /// Walk intervals at which chase-skills are attempted to be triggered.
 /// Walk intervals at which chase-skills are attempted to be triggered.
+/// If you change this, make sure it's an odd value (for icewall block behavior).
 #define WALK_SKILL_INTERVAL 5
 #define WALK_SKILL_INTERVAL 5
 
 
 /// Flags passed to skill_attack/skill_area_sub
 /// Flags passed to skill_attack/skill_area_sub

+ 24 - 3
src/map/unit.c

@@ -320,6 +320,7 @@ static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data
 {
 {
 	int i;
 	int i;
 	int x,y,dx,dy;
 	int x,y,dx,dy;
+	unsigned char icewall_walk_block;
 	uint8 dir;
 	uint8 dir;
 	struct block_list *bl;
 	struct block_list *bl;
 	struct unit_data *ud;
 	struct unit_data *ud;
@@ -366,19 +367,29 @@ static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data
 	dx = dirx[(int)dir];
 	dx = dirx[(int)dir];
 	dy = diry[(int)dir];
 	dy = diry[(int)dir];
 
 
+	//Get icewall walk block depending on boss mode (players can't be trapped)
+	if(md && md->status.mode&MD_BOSS)
+		icewall_walk_block = battle_config.boss_icewall_walk_block;
+	else if(md)
+		icewall_walk_block = battle_config.mob_icewall_walk_block;
+	else
+		icewall_walk_block = 0;
+
 	//Monsters will walk into an icewall from the west and south if they already started walking
 	//Monsters will walk into an icewall from the west and south if they already started walking
 	if(map_getcell(bl->m,x+dx,y+dy,CELL_CHKNOPASS) 
 	if(map_getcell(bl->m,x+dx,y+dy,CELL_CHKNOPASS) 
-		&& (battle_config.icewall_walk_block == 0 || !map_getcell(bl->m,x+dx,y+dy,CELL_CHKICEWALL) || dx < 0 || dy < 0))
+		&& (icewall_walk_block == 0 || !map_getcell(bl->m,x+dx,y+dy,CELL_CHKICEWALL) || dx < 0 || dy < 0))
 		return unit_walktoxy_sub(bl);
 		return unit_walktoxy_sub(bl);
 
 
 	//Monsters can only leave icewalls to the west and south
 	//Monsters can only leave icewalls to the west and south
 	//But if movement fails more than icewall_walk_block times, they can ignore this rule
 	//But if movement fails more than icewall_walk_block times, they can ignore this rule
-	if(md && md->walktoxy_fail_count < battle_config.icewall_walk_block && map_getcell(bl->m,x,y,CELL_CHKICEWALL) && (dx > 0 || dy > 0)) {
+	if(md && md->walktoxy_fail_count < icewall_walk_block && map_getcell(bl->m,x,y,CELL_CHKICEWALL) && (dx > 0 || dy > 0)) {
 		//Needs to be done here so that rudeattack skills are invoked
 		//Needs to be done here so that rudeattack skills are invoked
 		md->walktoxy_fail_count++;
 		md->walktoxy_fail_count++;
 		clif_fixpos(bl);
 		clif_fixpos(bl);
+		//Monsters in this situation first use a chase skill, then unlock target and then use an idle skill
+		if (!(++ud->walk_count%WALK_SKILL_INTERVAL))
+			mobskill_use(md, tick, -1);
 		mob_unlocktarget(md, tick);
 		mob_unlocktarget(md, tick);
-		//Use idle skill at this point
 		if (!(++ud->walk_count%WALK_SKILL_INTERVAL))
 		if (!(++ud->walk_count%WALK_SKILL_INTERVAL))
 			mobskill_use(md, tick, -1);
 			mobskill_use(md, tick, -1);
 		return 0;
 		return 0;
@@ -1281,6 +1292,16 @@ int unit_can_move(struct block_list *bl) {
 			return 0;
 			return 0;
 	}
 	}
 
 
+	// Icewall walk block special trapped monster mode
+	if(bl->type == BL_MOB) {
+		struct mob_data *md = BL_CAST(BL_MOB, bl);
+		if(md && ((md->status.mode&MD_BOSS && battle_config.boss_icewall_walk_block == 1 && map_getcell(bl->m,bl->x,bl->y,CELL_CHKICEWALL))
+			|| (!(md->status.mode&MD_BOSS) && battle_config.mob_icewall_walk_block == 1 && map_getcell(bl->m,bl->x,bl->y,CELL_CHKICEWALL)))) {
+			md->walktoxy_fail_count = 1; //Make sure rudeattacked skills are invoked
+			return 0;
+		}
+	}
+
 	return 1;
 	return 1;
 }
 }