mirror of
https://github.com/ProjectSWGCore/NGECore2.git
synced 2026-08-02 03:15:52 -04:00
More work on combat, added 2 obj Controller packets, added /setspeed, fixed object permissions
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
package services.combat;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import resources.objects.creature.CreatureObject;
|
||||
import resources.objects.tangible.TangibleObject;
|
||||
@@ -53,14 +54,147 @@ public class CombatService implements INetworkDispatch {
|
||||
|
||||
}
|
||||
|
||||
public void doCombat(CreatureObject attacker, TangibleObject target, WeaponObject weapon, CombatCommand command) {
|
||||
public void doCombat(CreatureObject attacker, TangibleObject target, WeaponObject weapon, CombatCommand command, int actionCounter) {
|
||||
|
||||
if(!attemptCombat(attacker, target))
|
||||
return;
|
||||
|
||||
if(!applySpecialCost(attacker, weapon, command))
|
||||
return;
|
||||
|
||||
if(!attemptCombat(attacker, target))
|
||||
return;
|
||||
|
||||
if(command.getAttackType() == 1)
|
||||
doSingleTargetCombat(attacker, target, weapon, command, actionCounter);
|
||||
else if(command.getAttackType() == 0 || command.getAttackType() == 2 || command.getAttackType() == 3)
|
||||
doAreaCombat(attacker, target, weapon, command, actionCounter);
|
||||
|
||||
}
|
||||
|
||||
private void doAreaCombat(CreatureObject attacker, TangibleObject target, WeaponObject weapon, CombatCommand command, int actionCounter) {
|
||||
if(target instanceof CreatureObject) {
|
||||
doAreaCombat(attacker, (CreatureObject) target, weapon, command, actionCounter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void doSingleTargetCombat(CreatureObject attacker, TangibleObject target, WeaponObject weapon, CombatCommand command, int actionCounter) {
|
||||
if(target instanceof CreatureObject) {
|
||||
doSingleTargetCombat(attacker, (CreatureObject) target, weapon, command, actionCounter);
|
||||
return;
|
||||
}
|
||||
|
||||
float damage = calculateDamage(attacker, target, weapon, command);
|
||||
}
|
||||
|
||||
private void doAreaCombat(CreatureObject attacker, CreatureObject target, WeaponObject weapon, CombatCommand command, int actionCounter) {
|
||||
|
||||
}
|
||||
|
||||
private void doSingleTargetCombat(CreatureObject attacker, CreatureObject target, WeaponObject weapon, CombatCommand command, int actionCounter) {
|
||||
|
||||
float damage = calculateDamage(attacker, target, weapon, command);
|
||||
|
||||
byte hitType = getHitType(attacker, target, weapon, command);
|
||||
|
||||
switch(hitType) {
|
||||
|
||||
case HitType.MISS:
|
||||
damage = 0;
|
||||
break;
|
||||
|
||||
case HitType.DODGE:
|
||||
damage = 0;
|
||||
break;
|
||||
|
||||
case HitType.PARRY:
|
||||
damage = 0;
|
||||
break;
|
||||
|
||||
case HitType.CRITICAL:
|
||||
damage *= 1.5f;
|
||||
break;
|
||||
|
||||
}
|
||||
byte mitigationType = -1;
|
||||
if(hitType == HitType.CRITICAL || hitType == HitType.HIT || hitType == HitType.STRIKETHROUGH) {
|
||||
mitigationType = doMitigationRolls(attacker, target, weapon, command, hitType);
|
||||
|
||||
if(mitigationType == HitType.GLANCE) {
|
||||
damage *= 0.4f;
|
||||
} else if(mitigationType == HitType.EVASION) {
|
||||
float evasionValue = (attacker.getSkillMod("combat_evasion_value").getBase() / 4) / 100;
|
||||
|
||||
damage *= (1 - evasionValue);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
damage *= (1 - getArmorReduction(attacker, target, weapon, command, hitType));
|
||||
if(mitigationType == HitType.BLOCK) {
|
||||
|
||||
float blockValue = (attacker.getSkillMod("strength_modified").getBase() * attacker.getSkillMod("combat_block_value").getBase()) / 2 + 25;
|
||||
damage -= blockValue;
|
||||
|
||||
}
|
||||
|
||||
applyDamage(attacker, target, (int) damage);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private float getArmorReduction(CreatureObject attacker, CreatureObject target, WeaponObject weapon, CombatCommand command, byte hitType) {
|
||||
|
||||
int elementalType = 1;
|
||||
|
||||
if(command.getPercentFromWeapon() > 0) {
|
||||
|
||||
// TODO: elemental mitigation and damage
|
||||
|
||||
if(weapon.getStringAttribute("cat_wpn_damage.wpn_damage_type").equals("@obj_attr_n:armor_eff_kinetic"))
|
||||
elementalType = ElementalType.KINETIC;
|
||||
else if(weapon.getStringAttribute("cat_wpn_damage.wpn_damage_type").equals("@obj_attr_n:armor_eff_energy"))
|
||||
elementalType = ElementalType.ENERGY;
|
||||
|
||||
} else {
|
||||
|
||||
elementalType = command.getElementalType();
|
||||
|
||||
}
|
||||
|
||||
int baseArmor = 0;
|
||||
|
||||
switch(elementalType) {
|
||||
|
||||
case ElementalType.KINETIC:
|
||||
baseArmor = target.getSkillMod("kinetic").getBase();
|
||||
case ElementalType.ENERGY:
|
||||
baseArmor = target.getSkillMod("energy").getBase();
|
||||
case ElementalType.HEAT:
|
||||
baseArmor = target.getSkillMod("heat").getBase();
|
||||
case ElementalType.COLD:
|
||||
baseArmor = target.getSkillMod("cold").getBase();
|
||||
case ElementalType.ACID:
|
||||
baseArmor = target.getSkillMod("acid").getBase();
|
||||
case ElementalType.ELECTRICITY:
|
||||
baseArmor = target.getSkillMod("electricity").getBase();
|
||||
|
||||
}
|
||||
|
||||
float mitigation = (float) (90 * (1 - Math.exp(-0.000125 * baseArmor)) + baseArmor / 9000);
|
||||
|
||||
if(hitType == HitType.STRIKETHROUGH) {
|
||||
|
||||
float stMaxValue = attacker.getSkillMod("combat_strikethrough_value").getBase() / 2;
|
||||
float stMinValue = stMaxValue / 2;
|
||||
|
||||
float stValue = new Random().nextInt((int) (stMaxValue - stMinValue + 1)) + stMinValue;
|
||||
stValue /= 100;
|
||||
mitigation *= stValue;
|
||||
}
|
||||
|
||||
return mitigation / 100;
|
||||
|
||||
}
|
||||
|
||||
private boolean attemptCombat(CreatureObject attacker, TangibleObject target) {
|
||||
@@ -106,5 +240,235 @@ public class CombatService implements INetworkDispatch {
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private float calculateDamage(CreatureObject attacker, CreatureObject target, WeaponObject weapon, CombatCommand command) {
|
||||
|
||||
float rawDamage = command.getAddedDamage();
|
||||
|
||||
if(command.getPercentFromWeapon() > 0 && weapon != attacker.getSlottedObject("default_weapon")) {
|
||||
|
||||
float weaponMinDmg = weapon.getIntAttribute("cat_wpn_damage.wpn_damage_min");
|
||||
float weaponMaxDmg = weapon.getIntAttribute("cat_wpn_damage.wpn_damage_max");
|
||||
|
||||
float weaponDmg = new Random().nextInt((int) (weaponMaxDmg - weaponMinDmg + 1)) + weaponMinDmg;
|
||||
weaponDmg *= command.getPercentFromWeapon();
|
||||
rawDamage += weaponDmg;
|
||||
|
||||
if(weapon.isMelee() && attacker.getSkillMod("strength_modified") != null) {
|
||||
|
||||
if(attacker.getSkillMod("strength_modified").getBase() > 0) {
|
||||
rawDamage += ((attacker.getSkillMod("strength_modified").getBase() / 100) * 33);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if(command.getPercentFromWeapon() > 0) {
|
||||
|
||||
float weaponMinDmg = 50;
|
||||
float weaponMaxDmg = 100;
|
||||
|
||||
float weaponDmg = new Random().nextInt((int) (weaponMaxDmg - weaponMinDmg + 1)) + weaponMinDmg;
|
||||
weaponDmg *= command.getPercentFromWeapon();
|
||||
rawDamage += weaponDmg;
|
||||
|
||||
if(weapon.isMelee() && attacker.getSkillMod("strength_modified") != null) {
|
||||
|
||||
if(attacker.getSkillMod("strength_modified").getBase() > 0) {
|
||||
rawDamage += ((attacker.getSkillMod("strength_modified").getBase() / 100) * 33);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(target.getSkillMod("damage_decrease_percentage") != null) {
|
||||
rawDamage *= (target.getSkillMod("damage_decrease_percentage").getBase() / 100);
|
||||
}
|
||||
|
||||
return rawDamage;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private float calculateDamage(CreatureObject attacker, TangibleObject target, WeaponObject weapon, CombatCommand command) {
|
||||
|
||||
float rawDamage = command.getAddedDamage();
|
||||
|
||||
if(command.getPercentFromWeapon() > 0 && weapon != attacker.getSlottedObject("default_weapon")) {
|
||||
|
||||
float weaponMinDmg = weapon.getIntAttribute("cat_wpn_damage.wpn_damage_min");
|
||||
float weaponMaxDmg = weapon.getIntAttribute("cat_wpn_damage.wpn_damage_max");
|
||||
|
||||
float weaponDmg = new Random().nextInt((int) (weaponMaxDmg - weaponMinDmg + 1)) + weaponMinDmg;
|
||||
weaponDmg *= command.getPercentFromWeapon();
|
||||
rawDamage += weaponDmg;
|
||||
|
||||
if(weapon.isMelee() && attacker.getSkillMod("strength_modified") != null) {
|
||||
|
||||
if(attacker.getSkillMod("strength_modified").getBase() > 0) {
|
||||
rawDamage += ((attacker.getSkillMod("strength_modified").getBase() / 100) * 33);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if(command.getPercentFromWeapon() > 0) {
|
||||
|
||||
float weaponMinDmg = 50;
|
||||
float weaponMaxDmg = 100;
|
||||
|
||||
float weaponDmg = new Random().nextInt((int) (weaponMaxDmg - weaponMinDmg + 1)) + weaponMinDmg;
|
||||
weaponDmg *= command.getPercentFromWeapon();
|
||||
rawDamage += weaponDmg;
|
||||
|
||||
if(weapon.isMelee() && attacker.getSkillMod("strength_modified") != null) {
|
||||
|
||||
if(attacker.getSkillMod("strength_modified").getBase() > 0) {
|
||||
rawDamage += ((attacker.getSkillMod("strength_modified").getBase() / 100) * 33);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return rawDamage;
|
||||
|
||||
}
|
||||
|
||||
public byte getHitType(CreatureObject attacker, CreatureObject target, WeaponObject weapon, CombatCommand command) {
|
||||
|
||||
Random rand = new Random();
|
||||
float r;
|
||||
|
||||
// negation rolls(parry, miss and dodge) can only roll on single target attacks, strikethrough also only rolls on single target attacks
|
||||
if(command.getAttackType() == 1) {
|
||||
|
||||
if(weapon.isRanged()) {
|
||||
float missChance = 0.5f;
|
||||
if(attacker.getSkillMod("strength_modified").getBase() > 0) {
|
||||
float missNegation = (float) ((attacker.getSkillMod("strength_modified").getBase() / 100) * 0.1);
|
||||
if(missNegation > 0.4f)
|
||||
missNegation = 0.4f;
|
||||
missChance -= missNegation;
|
||||
}
|
||||
r = rand.nextFloat();
|
||||
if(r <= missChance)
|
||||
return HitType.MISS;
|
||||
}
|
||||
float dodgeChance = target.getSkillMod("display_only_dodge").getBase() / 10000;
|
||||
|
||||
r = rand.nextFloat();
|
||||
if(r <= dodgeChance)
|
||||
return HitType.DODGE;
|
||||
|
||||
|
||||
WeaponObject weapon2 = (WeaponObject) core.objectService.getObject(((CreatureObject) target).getWeaponId());
|
||||
if(weapon2 != null && weapon2.isMelee()) {
|
||||
|
||||
float parryChance = target.getSkillMod("display_only_parry").getBase() / 10000;
|
||||
|
||||
r = rand.nextFloat();
|
||||
if(r <= parryChance)
|
||||
return HitType.PARRY;
|
||||
|
||||
}
|
||||
|
||||
float stChance = attacker.getSkillMod("display_only_strikethrough").getBase() / 10000;
|
||||
|
||||
r = rand.nextFloat();
|
||||
if(r <= stChance)
|
||||
return HitType.STRIKETHROUGH;
|
||||
|
||||
}
|
||||
|
||||
float critChance = attacker.getSkillMod("display_only_critical").getBase() / 10000;
|
||||
|
||||
r = rand.nextFloat();
|
||||
if(r <= critChance)
|
||||
return HitType.CRITICAL;
|
||||
|
||||
// TODO: Punishing blow once AI is implemented
|
||||
|
||||
return HitType.HIT;
|
||||
|
||||
}
|
||||
|
||||
public byte doMitigationRolls(CreatureObject attacker, CreatureObject target, WeaponObject weapon, CombatCommand command, byte hitType) {
|
||||
|
||||
Random rand = new Random();
|
||||
float r;
|
||||
|
||||
float blockChance = target.getSkillMod("display_only_block").getBase() / 10000;
|
||||
|
||||
r = rand.nextFloat();
|
||||
if(r <= blockChance)
|
||||
return HitType.BLOCK;
|
||||
|
||||
if(command.getAttackType() == 0 || command.getAttackType() == 2 || command.getAttackType() == 3) {
|
||||
|
||||
float evasionChance = target.getSkillMod("display_only_evasion").getBase() / 10000;
|
||||
|
||||
r = rand.nextFloat();
|
||||
if(r <= evasionChance)
|
||||
return HitType.EVASION;
|
||||
|
||||
}
|
||||
|
||||
if(hitType == HitType.HIT) {
|
||||
|
||||
float glanceChance = target.getSkillMod("display_only_glancing_blow").getBase() / 10000;
|
||||
|
||||
r = rand.nextFloat();
|
||||
if(r <= glanceChance)
|
||||
return HitType.GLANCE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
public void applyDamage(CreatureObject attacker, CreatureObject target, int damage) {
|
||||
|
||||
if(target.getHealth() - damage <= 0) {
|
||||
target.setHealth(1);
|
||||
target.setPosture((byte) 13);
|
||||
if(target.getSlottedObject("ghost") != null)
|
||||
attacker.sendSystemMessage("You incapacitate " + target.getCustomName() + ".", (byte) 0);
|
||||
return;
|
||||
}
|
||||
target.setHealth(target.getHealth() - damage);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public enum HitType{;
|
||||
|
||||
public static final byte MISS = 0;
|
||||
public static final byte DODGE = 1;
|
||||
public static final byte PARRY = 2;
|
||||
public static final byte STRIKETHROUGH = 3;
|
||||
public static final byte CRITICAL = 4;
|
||||
public static final byte PUNISHING = 5;
|
||||
public static final byte HIT = 6;
|
||||
public static final byte BLOCK = 7;
|
||||
public static final byte EVASION = 8;
|
||||
public static final byte GLANCE = 9;
|
||||
|
||||
}
|
||||
|
||||
public enum ElementalType {;
|
||||
|
||||
public static final int KINETIC = 1;
|
||||
public static final int ENERGY = 2;
|
||||
public static final int BLAST = 4;
|
||||
public static final int STUN = 8;
|
||||
public static final int HEAT = 32;
|
||||
public static final int COLD = 64;
|
||||
public static final int ACID = 128;
|
||||
public static final int ELECTRICITY = 256;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user