mirror of
https://github.com/ProjectSWGCore/Holocore.git
synced 2026-01-15 23:05:45 -05:00
Cone of Effect attacks #77
This commit is contained in:
@@ -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"))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<>();
|
||||
|
||||
|
||||
@@ -125,6 +125,7 @@ public class CombatCommandCommon {
|
||||
|
||||
switch (c.getAttackType()) {
|
||||
case AREA:
|
||||
case CONE:
|
||||
case TARGET_AREA:
|
||||
return canPerformArea(source, c);
|
||||
case SINGLE_TARGET:
|
||||
|
||||
Reference in New Issue
Block a user