Removed some NGE combat logic that would sometimes cause server errors when rolled (dodge, parry...)

This commit is contained in:
Ziggy
2022-04-23 16:22:51 +02:00
parent e125d4bdcd
commit 3dc8d25b75
8 changed files with 9 additions and 249 deletions
-2
View File
@@ -1,2 +0,0 @@
line comment cooldown damage critical action_cost freeshot swift
TEXT TEXT TEXT TEXT TEXT TEXT TEXT TEXT
@@ -71,7 +71,6 @@ abstract class DataLoader {
fun zoneInsertions(): TerrainZoneInsertionLoader = ServerData.zoneInsertions
fun travelCosts(): TravelCostLoader = ServerData.travelCosts
fun vehicles(): VehicleLoader = ServerData.vehicles
fun specialLines(): SpecialLineLoader = ServerData.specialLines
fun staticPvpZones(): StaticPvpZoneLoader = ServerData.staticPvpZones
fun dynamicSpawns(): DynamicSpawnLoader = ServerData.dynamicSpawns
fun terrainLevels(): TerrainLevelLoader = ServerData.terrainLevels
@@ -43,7 +43,6 @@ object ServerData {
* Combat
*/
val buffs by SoftDataLoaderDelegate(::BuffLoader)
val specialLines by SoftDataLoaderDelegate(::SpecialLineLoader)
val factions by SoftDataLoaderDelegate(::FactionLoader)
/*
@@ -1,82 +0,0 @@
package com.projectswg.holocore.resources.support.data.server_info.loader;
import com.projectswg.holocore.resources.support.data.server_info.SdbLoader;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class SpecialLineLoader extends DataLoader {
private final Map<String, SpecialLineInfo> specialLineMap;
SpecialLineLoader() {
specialLineMap = new HashMap<>();
}
@Nullable
public SpecialLineInfo getSpecialLine(String name) {
return specialLineMap.get(name);
}
@Override
public void load() throws IOException {
try (SdbLoader.SdbResultSet set = SdbLoader.load(new File("serverdata/command/special_lines.sdb"))) {
while (set.next()) {
SpecialLineInfo specialLineInfo = new SpecialLineInfo(set);
specialLineMap.put(specialLineInfo.getSpecialLineName(), specialLineInfo);
}
}
}
public static class SpecialLineInfo {
private final String specialLineName;
private final String cooldownModName;
private final String addedDamageModName; // Added damage is also used for healing abilities
private final String criticalChanceModName;
private final String actionCostModName;
private final String freeshotModName;
private final String swiftModName;
SpecialLineInfo(SdbLoader.SdbResultSet set) {
specialLineName = set.getText("line");
cooldownModName = set.getText("cooldown");
addedDamageModName = set.getText("damage");
criticalChanceModName = set.getText("critical");
actionCostModName = set.getText("action_cost");
freeshotModName = set.getText("freeshot");
swiftModName = set.getText("swift");
}
public String getSpecialLineName() {
return specialLineName;
}
public String getCooldownModName() {
return cooldownModName;
}
public String getAddedDamageModName() {
return addedDamageModName;
}
public String getCriticalChanceModName() {
return criticalChanceModName;
}
public String getActionCostModName() {
return actionCostModName;
}
public String getFreeshotModName() {
return freeshotModName;
}
public String getSwiftModName() {
return swiftModName;
}
}
}
@@ -31,7 +31,6 @@ import com.projectswg.common.data.RGB;
import com.projectswg.common.data.combat.*;
import com.projectswg.common.data.encodables.oob.StringId;
import com.projectswg.common.data.location.Location;
import com.projectswg.common.network.packets.swg.zone.object_controller.Animation;
import com.projectswg.common.network.packets.swg.zone.object_controller.ShowFlyText;
import com.projectswg.common.network.packets.swg.zone.object_controller.combat.CombatAction;
import com.projectswg.common.network.packets.swg.zone.object_controller.combat.CombatAction.Defender;
@@ -41,12 +40,10 @@ import com.projectswg.holocore.resources.support.global.commands.CombatCommand;
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
import com.projectswg.holocore.resources.support.objects.swg.weapon.WeaponObject;
import com.projectswg.holocore.resources.support.objects.swg.weapon.WeaponType;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import static com.projectswg.holocore.services.gameplay.combat.command.CombatCommandCommon.*;
@@ -145,22 +142,6 @@ enum CombatCommandAttack implements CombatCommandHitType {
CreatureObject creatureTarget = (CreatureObject) target;
targets.add(creatureTarget);
// Let the defender roll single target defences against the attack of the attacker
if (isAttackParried(source, creatureTarget, weapon)) {
info.setParry(true);
info.setSuccess(false);
} else if (isAttackDodged(source, creatureTarget)) {
// The defender dodged the attack from the target
info.setDodge(true);
info.setSuccess(false); // This means that the attack did no damage to the target at all
long targetObjectId = target.getObjectId();
// Play dodge animation on the creature that's dodging for everyone that can see the creature
target.sendObservers(new Animation(targetObjectId, "dodge"));
} else if (isAttackGlanced(source, creatureTarget)) {
info.setGlancing(true);
}
}
doCombat(source, targets, weapon, info, command);
@@ -171,9 +152,6 @@ enum CombatCommandAttack implements CombatCommandHitType {
SWGObject originParent = origin.getParent();
Collection<SWGObject> objectsToCheck = originParent == null ? origin.getObjectsAware() : originParent.getContainedObjects();
// TODO block
// TODO evasion if no block
Set<CreatureObject> targets = objectsToCheck.stream()
.filter(CreatureObject.class::isInstance)
.map(CreatureObject.class::cast)
@@ -193,26 +171,9 @@ enum CombatCommandAttack implements CombatCommandHitType {
source.updateLastCombatTime();
CombatAction action = createCombatAction(source, weapon, TrailLocation.WEAPON, command);
boolean devastating = isAttackDevastating(source, command);
double weaponDamageBoost = 1.0; // Damage increase of the weapon
double addedDamageBoost = 1.0; // Damage increase of the command
if (devastating) {
// Show Devastation flytext above the source for every target
ShowFlyText devastationFlyText = new ShowFlyText(source.getObjectId(), new StringId("combat_effects", "devastation"), ShowFlyText.Scale.MEDIUM, new RGB(255, 255, 255));
source.sendSelf(devastationFlyText);
for (CreatureObject target : targets) {
target.sendSelf(devastationFlyText);
}
weaponDamageBoost += 0.5; // 50% damage boost from devastation
}
// Apply special line damage boost
addedDamageBoost += CombatCommandCommon.getAddedDamageBoost(source, command);
for (CreatureObject target : targets) {
target.updateLastCombatTime();
@@ -342,67 +303,5 @@ enum CombatCommandAttack implements CombatCommandHitType {
return mitigation / 100;
}
private static boolean isAttackParried(CreatureObject source, CreatureObject target, WeaponObject attackerWeapon) {
WeaponObject defenderWeapon = target.getEquippedWeapon();
WeaponType defenderWeaponType = defenderWeapon.getType();
WeaponType attackerWeaponType = attackerWeapon.getType();
// If the defender is wielding a lightsaber, parry can always be rolled, regardless of what the attacker is wielding
// If both attacker and defender are wielding melee weapons, parry can be rolled
if (defenderWeaponType.isLightsaber() || (defenderWeaponType.isMelee() && attackerWeaponType.isMelee())) {
double parryChance = (target.getSkillModValue("display_only_parry") - source.getSkillModValue("display_only_parry_reduction")) / 100d;
double roll = ThreadLocalRandom.current().nextDouble(100); // Generate number between 0 and 100
return roll <= parryChance; // If parry chance is 25%, then the roll should be between 0 and 25 (both inclusive)
} else {
return false;
}
}
private static boolean isAttackDodged(CreatureObject source, CreatureObject target) {
double dodgeChance = (target.getSkillModValue("display_only_dodge") - source.getSkillModValue("display_only_opp_dodge_reduction")) / 100d;
double roll = ThreadLocalRandom.current().nextDouble(100); // Generate number between 0 and 100
return roll <= dodgeChance; // If dodge chance is 25%, then the roll should be between 0 and 25 (both inclusive)
}
private static boolean isAttackGlanced(CreatureObject source, CreatureObject target) {
double glanceChance = target.getSkillModValue("display_only_glancing_blow") / 100d;
WeaponObject sourceEquippedWeapon = source.getEquippedWeapon();
WeaponType weaponType = sourceEquippedWeapon.getType();
if (weaponType.isMelee()) {
glanceChance += target.getSkillModValue("expertise_glancing_blow_melee");
}
if (weaponType.isRanged()) {
glanceChance += target.getSkillModValue("expertise_glancing_blow_ranged");
}
double roll = ThreadLocalRandom.current().nextDouble(100); // Generate number between 0 and 100
return roll <= glanceChance; // If glance chance is 25%, then the roll should be between 0 and 25 (both inclusive)
}
private static boolean isAttackDevastating(CreatureObject source, CombatCommand command) {
if (command.getPercentAddFromWeapon() == 0) {
// If this ability doesn't use weapon damage it does not qualify for a devastation roll
return false;
}
WeaponObject weapon = source.getEquippedWeapon();
WeaponType type = weapon.getType();
if (!WeaponType.HEAVY_WEAPON.equals(type) && !WeaponType.DIRECTIONAL_TARGET_WEAPON.equals(type)) {
// If the weapon type isn't a heavy weapon and isn't a flamethrower, then the weapon cannot roll a devastation
return false;
}
double devastationChance = source.getSkillModValue("expertise_devastation_bonus") / 10d;
double roll = ThreadLocalRandom.current().nextDouble(100); // Generate number between 0 and 100
return roll <= devastationChance; // If devastation chance is 20%, then the roll should be between 0 and 20 (both inclusive)
}
}
@@ -29,24 +29,21 @@ package com.projectswg.holocore.services.gameplay.combat.command;
import com.projectswg.common.data.CRC;
import com.projectswg.common.data.RGB;
import com.projectswg.common.data.combat.*;
import com.projectswg.common.data.encodables.oob.OutOfBandPackage;
import com.projectswg.common.data.encodables.oob.ProsePackage;
import com.projectswg.common.data.combat.AttackInfo;
import com.projectswg.common.data.combat.CombatStatus;
import com.projectswg.common.data.combat.TrailLocation;
import com.projectswg.common.data.encodables.oob.StringId;
import com.projectswg.common.network.packets.swg.zone.object_controller.ShowFlyText;
import com.projectswg.common.network.packets.swg.zone.object_controller.ShowFlyText.Scale;
import com.projectswg.common.network.packets.swg.zone.object_controller.combat.CombatAction;
import com.projectswg.common.network.packets.swg.zone.object_controller.combat.CombatSpam;
import com.projectswg.holocore.intents.gameplay.combat.buffs.BuffIntent;
import com.projectswg.holocore.resources.support.data.server_info.loader.ServerData;
import com.projectswg.holocore.resources.support.data.server_info.loader.SpecialLineLoader;
import com.projectswg.holocore.resources.support.global.commands.CombatCommand;
import com.projectswg.holocore.resources.support.global.commands.Command;
import com.projectswg.holocore.resources.support.objects.swg.SWGObject;
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject;
import com.projectswg.holocore.resources.support.objects.swg.tangible.TangibleObject;
import com.projectswg.holocore.resources.support.objects.swg.weapon.WeaponObject;
import com.projectswg.holocore.resources.support.objects.swg.weapon.WeaponType;
import java.util.concurrent.ThreadLocalRandom;
@@ -183,14 +180,4 @@ public class CombatCommandCommon {
obj.sendSelf(new ShowFlyText(obj.getObjectId(), text, scale, c, flags));
}
static double getAddedDamageBoost(CreatureObject source, CombatCommand command) {
SpecialLineLoader.SpecialLineInfo specialLine = ServerData.INSTANCE.getSpecialLines().getSpecialLine(command.getSpecialLine());
if (specialLine != null) {
String damageModName = specialLine.getAddedDamageModName();
return source.getSkillModValue(damageModName) / 100d;
}
return 0;
}
}
@@ -63,9 +63,6 @@ enum CombatCommandHeal implements CombatCommandHitType {
healAmount *= healingPotency;
}
// Apply special line heal boost
healAmount += CombatCommandCommon.getAddedDamageBoost(source, combatCommand);
switch (combatCommand.getAttackType()) {
case SINGLE_TARGET: {
switch (combatCommand.getTargetType()) {
@@ -27,24 +27,14 @@
package com.projectswg.holocore.services.gameplay.combat.command
import com.projectswg.common.data.RGB
import com.projectswg.common.data.combat.CombatStatus
import com.projectswg.common.data.combat.HitType
import com.projectswg.common.data.encodables.oob.StringId
import com.projectswg.common.network.packets.swg.zone.object_controller.ShowFlyText
import com.projectswg.holocore.intents.support.global.command.ExecuteCommandIntent
import com.projectswg.holocore.resources.support.data.server_info.loader.DataLoader
import com.projectswg.holocore.resources.support.data.server_info.loader.SpecialLineLoader.SpecialLineInfo
import com.projectswg.holocore.resources.support.global.commands.CombatCommand
import com.projectswg.holocore.resources.support.objects.swg.creature.CreatureObject
import com.projectswg.holocore.services.gameplay.combat.command.CombatCommandCommon.handleStatus
import me.joshlarson.jlcommon.control.IntentHandler
import me.joshlarson.jlcommon.control.Service
import me.joshlarson.jlcommon.log.Log
import java.util.EnumMap
import java.util.concurrent.ThreadLocalRandom
import com.projectswg.holocore.services.gameplay.combat.command.CombatCommandCommon.handleStatus
import java.util.*
class CombatCommandService : Service() {
@@ -80,38 +70,11 @@ class CombatCommandService : Service() {
val command = eci.command as CombatCommand
val source = eci.source
val specialLine = DataLoader.specialLines().getSpecialLine(command.specialLine)
var actionCost = command.actionCost * command.attackRolls
// TODO future: reduce actionCost with general ACR, weapon ACR and ability ACR
if (specialLine != null && source.getSkillModValue(specialLine.freeshotModName) > ThreadLocalRandom.current().nextInt(0, 100)) {
source.sendSelf(ShowFlyText(source.objectId, StringId("spam", "freeshot"), ShowFlyText.Scale.MEDIUM, RGB(255, 255, 255), ShowFlyText.Flag.IS_FREESHOT))
} else {
if (specialLine != null)
actionCost = reduceActionCost(source, actionCost, specialLine.actionCostModName)
if (actionCost > source.action)
return
source.modifyAction(-command.actionCost.toInt())
}
source.modifyAction((-command.actionCost).toInt())
val hitType = hitTypeMap[command.hitType]
hitType?.handle(source, eci.target, command, eci.arguments) ?: handleStatus(source, CombatStatus.UNKNOWN)
}
/**
* Calculates a new action cost based on the given action cost and a skill mod name.
* @param source to read the skillmod value from
* @param actionCost that has been calculated so far
* @param skillModName name of the skillmod to read from `source`
* @return new action cost that has been increased or reduced, depending on whether the skillmod value is
* positive or negative
*/
private fun reduceActionCost(source: CreatureObject, actionCost: Double, skillModName: String): Double {
val actionCostModValue = source.getSkillModValue(skillModName)
return actionCost + actionCost * actionCostModValue / 100
}
}