Quellcode durchsuchen

- Added new check conditions to prevent abuse from no-delay .act files (bugreport:4249)

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@15105 54d463be-8e91-2dee-dedb-b68131a5f0ec
epoque11 vor 13 Jahren
Ursprung
Commit
a5be723648
6 geänderte Dateien mit 49 neuen und 10 gelöschten Zeilen
  1. 8 0
      conf/battle/skill.conf
  2. 3 2
      src/map/battle.c
  3. 1 0
      src/map/battle.h
  4. 1 0
      src/map/pc.c
  5. 1 0
      src/map/pc.h
  6. 35 8
      src/map/skill.c

+ 8 - 0
conf/battle/skill.conf

@@ -52,6 +52,14 @@ no_skill_delay: 2
 // At what dex does the cast time become zero (instacast)?
 castrate_dex_scale: 150
 
+// What level of leniency should the skill system give for skills when
+// accounting attack motion (ASPD) for casting skills (Note 2, between 0 and 100)
+//
+// NOTE: Setting this to 100% may cause some issues with valid skills not being cast.
+//       The time difference between client and server varies so allowing 90% leniency
+//       should be enough to forgive very small margins of error.
+skill_amotion_leniency: 90
+
 // Will normal attacks be able to ignore the delay after skills? (Note 1)
 skill_delay_attack_enable: yes
 

+ 3 - 2
src/map/battle.c

@@ -4590,8 +4590,9 @@ static const struct _battle_data {
 	/**
 	 * rAthena
 	 **/
-	{ "max_third_parameter",                &battle_config.max_third_parameter,                 20,     0,      INT_MAX,        },
-	{ "atcommand_max_stat_bypass",          &battle_config.atcommand_max_stat_bypass,            0,      0,      100,            },           
+	{ "max_third_parameter",                &battle_config.max_third_parameter,             20,     0,      INT_MAX,        },
+	{ "atcommand_max_stat_bypass",          &battle_config.atcommand_max_stat_bypass,       0,      0,      100,            },          
+	{ "skill_amotion_leniency",             &battle_config.skill_amotion_leniency,          90,     0,      100				},
 };
 
 

+ 1 - 0
src/map/battle.h

@@ -116,6 +116,7 @@ extern struct Battle_Config
 	int left_cardfix_to_right;
 	int skill_add_range;
 	int skill_out_range_consume;
+	int skill_amotion_leniency;
 	int skillrange_by_distance; //[Skotlex]
 	int use_weapon_skill_range; //[Skotlex]
 	int pc_damage_delay_rate;

+ 1 - 0
src/map/pc.c

@@ -844,6 +844,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
 	sd->canusecashfood_tick = tick;
 	sd->canequip_tick = tick;
 	sd->cantalk_tick = tick;
+	sd->canskill_tick = tick;
 	sd->cansendmail_tick = tick;
 
 	for(i = 0; i < MAX_SKILL_LEVEL; i++)

+ 1 - 0
src/map/pc.h

@@ -208,6 +208,7 @@ struct map_session_data {
 	unsigned int canusecashfood_tick;
 	unsigned int canequip_tick;	// [Inkfish]
 	unsigned int cantalk_tick;
+	unsigned int canskill_tick; // used to prevent abuse from no-delay ACT files
 	unsigned int cansendmail_tick; // [Mail System Flood Protection]
 	unsigned int ks_floodprotect_tick; // [Kill Steal Protection]
 	

+ 35 - 8
src/map/skill.c

@@ -433,6 +433,15 @@ int skillnotok (int skillid, struct map_session_data *sd)
 	if( skillid == AL_TELEPORT && sd->skillitem == skillid && sd->skillitemlv > 2 )
 		return 0; // Teleport lv 3 bypasses this check.[Inkfish]
 
+	// Epoque:
+	// This code will compare the player's attack motion value which is influenced by ASPD before
+	// allowing a skill to be cast. This is to prevent no-delay ACT files from spamming skills such as
+	// AC_DOUBLE which do not have a skill delay and are not regarded in terms of attack motion.
+	if( sd->canskill_tick && DIFF_TICK(gettick(), sd->canskill_tick) < (sd->battle_status.amotion * (100 + battle_config.skill_amotion_leniency) / 100) )
+	{// attempted to cast a skill before the attack motion has finished
+		return 1;
+	}
+
 	if (sd->blockskill[i] > 0)
 		return 1;
 
@@ -3832,15 +3841,21 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
 	}
 
 	map_freeblock_unlock();
-
+	
 	if( sd && !(flag&1) )
-	{
-		if( sd->state.arrow_atk ) //Consume arrow on last invocation to this skill.
+	{// ensure that the skill last-cast tick is recorded
+		sd->canskill_tick = gettick();
+
+		if( sd->state.arrow_atk )
+		{// consume arrow on last invocation to this skill.
 			battle_consume_ammo(sd, skillid, skilllv);
+		}
+
+		// perform auto-cast routines and skill requirement consumption
 		skill_onskillusage(sd, bl, skillid, tick);
 		skill_consume_requirement(sd,skillid,skilllv,2);
 	}
-
+	
 	return 0;
 }
 
@@ -7090,9 +7105,15 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 	}
 
 	if( sd && !(flag&1) )
-	{
-		if( sd->state.arrow_atk ) //Consume arrow on last invocation to this skill.
+	{// ensure that the skill last-cast tick is recorded
+		sd->canskill_tick = gettick();
+
+		if( sd->state.arrow_atk )
+		{// consume arrow on last invocation to this skill.
 			battle_consume_ammo(sd, skillid, skilllv);
+		}
+
+		// perform auto-cast routines and skill requirement consumption
 		skill_onskillusage(sd, bl, skillid, tick);
 		skill_consume_requirement(sd,skillid,skilllv,2);
 	}
@@ -8078,9 +8099,15 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
 	status_change_end(src, SC_MAGICPOWER, INVALID_TIMER);
 
 	if( sd )
-	{
-		if( sd->state.arrow_atk && !(flag&1) ) //Consume arrow if a ground skill was not invoked. [Skotlex]
+	{// ensure that the skill last-cast tick is recorded
+		sd->canskill_tick = gettick();
+
+		if( sd->state.arrow_atk && !(flag&1) )
+		{// consume arrow if this is a ground skill
 			battle_consume_ammo(sd, skillid, skilllv);
+		}
+
+		// perform auto-cast routines and skill requirement consumption
 		skill_onskillusage(sd, NULL, skillid, tick);
 		skill_consume_requirement(sd,skillid,skilllv,2);
 	}