Răsfoiți Sursa

Fixing casting animation

Added first unit test.
Moved calculations to Formulas class.
Fixes #7
Zoey76 8 ani în urmă
părinte
comite
df12148411

+ 2 - 1
.gitignore

@@ -4,4 +4,5 @@
 .DS_Store
 *.log
 .project
-.classpath
+.classpath
+/test-output/

+ 2 - 0
build.gradle

@@ -28,6 +28,8 @@ dependencies {
 	compile 'org.slf4j:slf4j-jdk14:1.7.21'
 	compile fileTree(dir: 'dist/libs', include: '*.jar')
 	testCompile 'org.testng:testng:6.9.10'
+	testCompile 'org.mockito:mockito-all:2.0.2-beta'
+	testCompile 'com.beust:jcommander:1.48'
 }
 
 def generalManifest = manifest {

+ 4 - 23
src/main/java/com/l2jserver/gameserver/model/actor/L2Character.java

@@ -1760,26 +1760,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
 		int magicId = skill.getId();
 		
 		// Get the Base Casting Time of the Skills.
-		double skillAnimTime = skill.getHitTime();
-		
-		if (!skill.isChanneling() || (skill.getChannelingSkillId() == 0))
-		{
-			// Calculate the Casting Time of the "Non-Static" Skills (with caster PAtk/MAtkSpd).
-			if (!skill.isStatic())
-			{
-				skillAnimTime = Formulas.calcAtkSpd(skill.isMagic() ? getMAtkSpd() : getPAtkSpd(), skillAnimTime);
-			}
-			// Calculate the Casting Time of Magic Skills (reduced in 40% if using SPS/BSPS)
-			if (skill.isMagic() && (isChargedShot(ShotType.SPIRITSHOTS) || isChargedShot(ShotType.BLESSED_SPIRITSHOTS)))
-			{
-				skillAnimTime = (int) (skillAnimTime / 1.4);
-			}
-		}
-		
-		if ((skillAnimTime < 500) && (skill.getHitTime() > 500))
-		{
-			skillAnimTime = 500;
-		}
+		double skillAnimTime = Formulas.calcCastTime(this, skill);
 		
 		// queue herbs and potions
 		if (isCastingSimultaneouslyNow() && simultaneously)
@@ -1962,7 +1943,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
 					future.cancel(true);
 					_skillCast2 = null;
 				}
-				_skillCast2 = ThreadPoolManager.getInstance().scheduleEffect(mut, (int) skillAnimTime);
+				_skillCast2 = ThreadPoolManager.getInstance().scheduleEffect(mut, (int) skillAnimTime - 400);
 			}
 			else
 			{
@@ -1972,7 +1953,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
 					future.cancel(true);
 					_skillCast = null;
 				}
-				_skillCast = ThreadPoolManager.getInstance().scheduleEffect(mut, (int) skillAnimTime);
+				_skillCast = ThreadPoolManager.getInstance().scheduleEffect(mut, (int) skillAnimTime - 400);
 			}
 		}
 		else
@@ -5692,7 +5673,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
 	// Quest event ON_SPELL_FNISHED
 	protected void notifyQuestEventSkillFinished(Skill skill, L2Object target)
 	{
-	
+		
 	}
 	
 	/**

+ 1 - 1
src/main/java/com/l2jserver/gameserver/model/skills/Skill.java

@@ -69,7 +69,7 @@ import com.l2jserver.gameserver.network.serverpackets.SystemMessage;
 import com.l2jserver.gameserver.util.Util;
 import com.l2jserver.util.Rnd;
 
-public final class Skill implements IIdentifiable
+public class Skill implements IIdentifiable
 {
 	private static final Logger _log = Logger.getLogger(Skill.class.getName());
 	

+ 23 - 8
src/main/java/com/l2jserver/gameserver/model/stats/Formulas.java

@@ -1182,15 +1182,30 @@ public final class Formulas
 		return (int) (470000 / rate);
 	}
 	
-	/**
-	 * Calculate delay (in milliseconds) for skills cast
-	 * @param speed
-	 * @param skillTime
-	 * @return
-	 */
-	public static final double calcAtkSpd(double speed, double skillTime)
+	public static double calcCastTime(L2Character character, Skill skill)
 	{
-		return (skillTime / speed) * 333;
+		double skillAnimTime = skill.getHitTime();
+		if (!skill.isChanneling() || (skill.getChannelingSkillId() == 0))
+		{
+			// Calculate the Casting Time of the "Non-Static" Skills (with caster PAtk/MAtkSpd).
+			if (!skill.isStatic())
+			{
+				final double speed = skill.isMagic() ? character.getMAtkSpd() : character.getPAtkSpd();
+				skillAnimTime = (skillAnimTime / speed) * 333;
+			}
+			
+			// Calculate the Casting Time of Magic Skills (reduced in 40% if using SPS/BSPS)
+			if (skill.isMagic() && (character.isChargedShot(ShotType.SPIRITSHOTS) || character.isChargedShot(ShotType.BLESSED_SPIRITSHOTS)))
+			{
+				skillAnimTime = (int) (skillAnimTime / 1.4);
+			}
+			
+			if ((skillAnimTime < 500) && (skill.getHitTime() > 500))
+			{
+				skillAnimTime = 500.0;
+			}
+		}
+		return skillAnimTime;
 	}
 	
 	/**

+ 94 - 0
src/test/java/com/l2jserver/gameserver/model/stats/FormulasTest.java

@@ -0,0 +1,94 @@
+package com.l2jserver.gameserver.model.stats;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import com.l2jserver.gameserver.enums.ShotType;
+import com.l2jserver.gameserver.model.actor.L2Character;
+import com.l2jserver.gameserver.model.skills.Skill;
+
+/**
+ * Formulas test.
+ * @author Zoey76
+ */
+public class FormulasTest
+{
+	private static final String PROVIDE_SPEED_SKILL_TIME = "PROVIDE_SPEED_SKILL_TIME";
+	
+	private static final int HP_REGENERATE_PERIOD_CHARACTER = 3000;
+	
+	private static final int HP_REGENERATE_PERIOD_DOOR = 300000;
+	
+	@Mock
+	private L2Character character;
+	
+	@Mock
+	private Skill skill;
+	
+	@BeforeClass
+	public void setUp()
+	{
+		MockitoAnnotations.initMocks(this);
+	}
+	
+	@Test
+	public void testGetRegeneratePeriod()
+	{
+		Mockito.when(character.isDoor()).thenReturn(true);
+		
+		Assert.assertEquals(Formulas.getRegeneratePeriod(character), HP_REGENERATE_PERIOD_DOOR);
+		
+		Mockito.when(character.isDoor()).thenReturn(false);
+		
+		Assert.assertEquals(Formulas.getRegeneratePeriod(character), HP_REGENERATE_PERIOD_CHARACTER);
+	}
+	
+	@Test(dataProvider = PROVIDE_SPEED_SKILL_TIME)
+	public void testCalcAtkSpd(int hitTime, boolean isChanneling, int channelingSkillId, boolean isStatic, boolean isMagic, //
+		int mAtkSpeed, double pAtkSpeed, boolean isChargedSpiritshots, boolean isChargedBlessedSpiritShots, double expected)
+	{
+		Mockito.when(skill.getHitTime()).thenReturn(hitTime);
+		Mockito.when(skill.isChanneling()).thenReturn(isChanneling);
+		Mockito.when(skill.getChannelingSkillId()).thenReturn(channelingSkillId);
+		Mockito.when(skill.isStatic()).thenReturn(isStatic);
+		Mockito.when(skill.isMagic()).thenReturn(isMagic);
+		Mockito.when(character.getMAtkSpd()).thenReturn(mAtkSpeed);
+		Mockito.when(character.getPAtkSpd()).thenReturn(pAtkSpeed);
+		Mockito.when(character.isChargedShot(ShotType.SPIRITSHOTS)).thenReturn(isChargedSpiritshots);
+		Mockito.when(character.isChargedShot(ShotType.BLESSED_SPIRITSHOTS)).thenReturn(isChargedBlessedSpiritShots);
+		
+		Assert.assertEquals(Formulas.calcCastTime(character, skill), expected);
+	}
+	
+	@DataProvider(name = PROVIDE_SPEED_SKILL_TIME)
+	private Iterator<Object[]> provide()
+	{
+		final Set<Object[]> result = new HashSet<>();
+		// @formatter:off
+		// TODO(Zoey76): Take care of the "bad" values.
+		result.add(new Object[]{ 0, true, 1, false, false, 0, 0.0, false, false, 0.0 });
+		result.add(new Object[]{ 0, true, 0, false, false, 0, 0.0, false, false, Double.NaN });
+		result.add(new Object[]{ 0, false, 1, false, false, 0, 0.0, false, false, Double.NaN });
+		result.add(new Object[]{ 0, false, 0, false, true, 500, 0.0, false, false, 0.0 });
+		result.add(new Object[]{ 600, false, 0, false, true, 500, 0.0, false, false, 500.0 });
+		result.add(new Object[]{ 3000, false, 0, false, true, 600, 0.0, false, false, 1665.0 });
+		result.add(new Object[]{ 0, false, 0, false, false, 0, 500.0, false, false, 0.0 });
+		result.add(new Object[]{ 600, false, 0, false, false, 0, 500.0, false, false, 500.0 });
+		result.add(new Object[]{ 3000, false, 0, false, false, 0, 600.0, false, false, 1665.0 });
+		result.add(new Object[]{ 1400, false, 0, false, true, 0, 0.0, true, false, 2.147483647E9 });
+		result.add(new Object[]{ 1400, false, 0, false, true, 0, 0.0, false, true, 2.147483647E9 });	
+		result.add(new Object[]{ 1400, false, 0, true, true, 0, 0.0, true, false, 1000.0 });
+		result.add(new Object[]{ 1400, false, 0, true, true, 0, 0.0, false, true, 1000.0 });
+		// @formatter:on
+		return result.iterator();
+	}
+}