Cone of Effect attacks #77

This commit is contained in:
Ziggy
2021-03-14 17:45:07 +01:00
parent ed5bbed580
commit 2c8fabe50b
4 changed files with 67 additions and 0 deletions

View File

@@ -126,6 +126,7 @@ public class CommandLoader extends DataLoader {
.withAnimations(WeaponType.POLEARM_SABER, getAnimationList(set.getText("anim_polearmlightsaber")))
.withAttackType(AttackType.valueOf(set.getText("attackType")))
.withConeLength(set.getReal("coneLength"))
.withConeWidth(set.getReal("coneWidth"))
.withAddedDamage((int) set.getInt("addedDamage"))
.withPercentAddFromWeapon(set.getReal("percentAddFromWeapon"))
.withBypassArmor(set.getReal("bypassArmor"))

View File

@@ -61,6 +61,7 @@ public class CombatCommand extends Command {
private final int delayAttackLoops;
private final DelayAttackEggPosition eggPosition;
private final double coneLength;
private final double coneWidth;
private final HealAttrib healAttrib;
private final String specialLine;
@@ -91,6 +92,7 @@ public class CombatCommand extends Command {
this.delayAttackLoops = builder.delayAttackLoops;
this.eggPosition = builder.eggPosition;
this.coneLength = builder.coneLength;
this.coneWidth = builder.coneWidth;
this.healAttrib = builder.healAttrib;
this.specialLine = builder.specialLine;
}
@@ -212,6 +214,10 @@ public class CombatCommand extends Command {
return coneLength;
}
public double getConeWidth() {
return coneWidth;
}
public HealAttrib getHealAttrib() {
return healAttrib;
}
@@ -256,6 +262,7 @@ public class CombatCommand extends Command {
private int delayAttackLoops;
private DelayAttackEggPosition eggPosition;
private double coneLength;
private double coneWidth;
private HealAttrib healAttrib;
private String specialLine;
@@ -393,6 +400,11 @@ public class CombatCommand extends Command {
return this;
}
public CombatCommandBuilder withConeWidth(double coneWidth) {
this.coneWidth = coneWidth;
return this;
}
public CombatCommandBuilder withHealAttrib(HealAttrib healAttrib) {
this.healAttrib = healAttrib;
return this;

View File

@@ -30,6 +30,7 @@ package com.projectswg.holocore.services.gameplay.combat.command;
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;
@@ -82,12 +83,64 @@ enum CombatCommandAttack implements CombatCommandHitType {
// TODO AoE based on Location instead of delay egg
}
break;
case CONE:
doCombatCone(source, target, info, weapon, command);
break;
default:
break;
}
}
}
private void doCombatCone(CreatureObject source, SWGObject target, AttackInfo info, WeaponObject weapon, CombatCommand command) {
double coneLength = command.getConeLength();
double coneWidth = command.getConeWidth();
Location sourceWorldLocation = source.getWorldLocation();
Location targetWorldLocation = target.getWorldLocation();
double dirX = targetWorldLocation.getX() - sourceWorldLocation.getX();
double dirZ = targetWorldLocation.getZ() - sourceWorldLocation.getZ();
Set<SWGObject> objectsToCheck = source.getObjectsAware();
// TODO line of sight checks between the attacker and each target
Set<CreatureObject> targets = objectsToCheck.stream()
.filter(CreatureObject.class::isInstance)
.map(CreatureObject.class::cast)
.filter(candidate -> !target.equals(source)) // Make sure the attacker can't damage themselves
.filter(source::isAttackable)
.filter(candidate -> canPerform(source, target, command) == CombatStatus.SUCCESS)
.filter(candidate -> sourceWorldLocation.distanceTo(candidate.getLocation()) <= coneLength)
.filter(candidate -> {
Location candidateWorldLocation = candidate.getWorldLocation();
return isInConeAngle(sourceWorldLocation, candidateWorldLocation, coneLength, coneWidth, dirX, dirZ);
})
.collect(Collectors.toSet());
doCombat(source, targets, weapon, info, command);
}
private boolean isInConeAngle(Location attackerLocation, Location targetLocation, double coneLength, double coneWidth, double directionX, double directionZ) {
double radius = coneWidth / 2d;
double angle = 2 * Math.atan(coneLength / radius);
double targetX = targetLocation.getX() - attackerLocation.getX();
double targetZ = targetLocation.getZ() - attackerLocation.getZ();
double targetAngle = Math.atan2(targetZ, targetX) - Math.atan2(directionZ, directionX);
double degrees = targetAngle * 180 / Math.PI;
double coneAngle = angle / 2;
if (degrees > coneAngle || degrees < -coneAngle) {
return false;
}
return true;
}
private static void doCombatSingle(CreatureObject source, SWGObject target, AttackInfo info, WeaponObject weapon, CombatCommand command) {
Set<CreatureObject> targets = new HashSet<>();

View File

@@ -125,6 +125,7 @@ public class CombatCommandCommon {
switch (c.getAttackType()) {
case AREA:
case CONE:
case TARGET_AREA:
return canPerformArea(source, c);
case SINGLE_TARGET: